Issues (130)

Serializer/Block/PartialMerkleTreeSerializer.php (1 issue)

1
<?php
2
3
declare(strict_types=1);
4
5
namespace BitWasp\Bitcoin\Serializer\Block;
6
7
use BitWasp\Bitcoin\Block\PartialMerkleTree;
8
use BitWasp\Buffertools\Buffer;
9
use BitWasp\Buffertools\BufferInterface;
10
use BitWasp\Buffertools\Parser;
11
use BitWasp\Buffertools\Template;
12
use BitWasp\Buffertools\TemplateFactory;
13
14
class PartialMerkleTreeSerializer
15
{
16
    /**
17
     * @var \BitWasp\Buffertools\Template
18
     */
19
    private $template;
20
21
    /**
22
     * PartialMerkleTreeSerializer constructor.
23
     */
24 4
    public function __construct()
25
    {
26 4
        $this->template = $this->getTemplate();
27 4
    }
28
29
    /**
30
     * @return Template
31
     */
32 4
    public function getTemplate(): Template
33
    {
34 4
        return (new TemplateFactory())
35 4
            ->uint32le()
36 4
            ->vector(function (Parser $parser) {
37 2
                return $parser->readBytes(32);
38 4
            })
39 4
            ->vector(function (Parser $parser) {
40 2
                return $parser->readBytes(1);
41 4
            })
42 4
            ->getTemplate();
43
    }
44
45
    /**
46
     * @param int $last
47
     * @param BufferInterface[] $vBytes
48
     * @return array
49
     */
50 2
    private function buffersToBitArray($last, array $vBytes): array
51
    {
52 2
        $size = count($vBytes) * 8;
53 2
        $vBits = [];
54
55 2
        for ($p = 0; $p < $size; $p++) {
56 2
            $byteIndex = (int)floor($p / 8);
57 2
            $byte = ord($vBytes[$byteIndex]->getBinary());
58 2
            $vBits[$p] = (int) (($byte & (1 << ($p % 8))) !== 0);
59
        }
60
61 2
        return array_slice($vBits, 0, $last);
62
    }
63
64
    /**
65
     * @param Parser $parser
66
     * @return PartialMerkleTree
67
     */
68 2
    public function fromParser(Parser $parser): PartialMerkleTree
69
    {
70 2
        list ($txCount, $vHash, $vBits) = $this->template->parse($parser);
71
72 2
        return new PartialMerkleTree(
73 2
            (int)$txCount,
74 2
            $vHash,
75 2
            $this->buffersToBitArray($txCount, $vBits)
76
        );
77
    }
78
79
    /**
80
     * @param BufferInterface $buffer
81
     * @return PartialMerkleTree
82
     */
83 1
    public function parse(BufferInterface $buffer): PartialMerkleTree
84
    {
85 1
        return $this->fromParser(new Parser($buffer));
86
    }
87
88
    /**
89
     * @param array $bits
90
     * @return array
91
     */
92 4
    private function bitsToBuffers(array $bits): array
93
    {
94 4
        $vBuffers = str_split(str_pad('', (int)((count($bits)+7)/8), '0', STR_PAD_LEFT));
95 4
        $nBits = count($bits);
96
97 4
        for ($p = 0; $p < $nBits; $p++) {
98 4
            $index = (int)floor($p / 8);
99 4
            $vBuffers[$index] |= $bits[$p] << ($p % 8);
100
        }
101
102 4
        foreach ($vBuffers as &$value) {
103 4
            $value = Buffer::int($value);
104
        }
105 4
        unset($value);
106
107 4
        return $vBuffers;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $vBuffers could return the type true which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
108
    }
109
110
    /**
111
     * @param PartialMerkleTree $tree
112
     * @return BufferInterface
113
     */
114 4
    public function serialize(PartialMerkleTree $tree): BufferInterface
115
    {
116 4
        return $this->template->write([
117 4
            $tree->getTxCount(),
118 4
            $tree->getHashes(),
119 4
            $this->bitsToBuffers($tree->getFlagBits())
120
        ]);
121
    }
122
}
123