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
![]() |
|||
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 |