1 | <?php |
||
49 | class NetworkMessageSerializer |
||
50 | { |
||
51 | /** |
||
52 | * @var NetworkInterface |
||
53 | */ |
||
54 | private $network; |
||
55 | |||
56 | /** |
||
57 | * @var \BitWasp\Bitcoin\Math\Math |
||
58 | */ |
||
59 | private $math; |
||
60 | |||
61 | /** |
||
62 | * @var TransactionSerializer |
||
63 | */ |
||
64 | private $txSerializer; |
||
65 | |||
66 | /** |
||
67 | * @var BlockHeaderSerializer |
||
68 | */ |
||
69 | private $headerSerializer; |
||
70 | |||
71 | /** |
||
72 | * @var GetDataSerializer |
||
73 | */ |
||
74 | private $getDataSerializer; |
||
75 | |||
76 | /** |
||
77 | * @var InvSerializer |
||
78 | */ |
||
79 | private $invSerializer; |
||
80 | |||
81 | /** |
||
82 | * @var BlockSerializer |
||
83 | */ |
||
84 | private $blockSerializer; |
||
85 | |||
86 | /** |
||
87 | * @var FilteredBlockSerializer |
||
88 | */ |
||
89 | private $filteredBlockSerializer; |
||
90 | |||
91 | /** |
||
92 | * @var HeadersSerializer |
||
93 | */ |
||
94 | private $headersSerializer; |
||
95 | |||
96 | /** |
||
97 | * @var FilterAddSerializer |
||
98 | */ |
||
99 | private $filterAddSerializer; |
||
100 | |||
101 | /** |
||
102 | * @var FilterLoadSerializer |
||
103 | */ |
||
104 | private $filterLoadSerializer; |
||
105 | |||
106 | /** |
||
107 | * @var MerkleBlockSerializer |
||
108 | */ |
||
109 | private $merkleBlockSerializer; |
||
110 | |||
111 | /** |
||
112 | * @var PingSerializer |
||
113 | */ |
||
114 | private $pingSerializer; |
||
115 | |||
116 | /** |
||
117 | * @var AlertSerializer |
||
118 | */ |
||
119 | private $alertSerializer; |
||
120 | |||
121 | /** |
||
122 | * @var InventorySerializer |
||
123 | */ |
||
124 | private $inventorySerializer; |
||
125 | |||
126 | /** |
||
127 | * @var NotFoundSerializer |
||
128 | */ |
||
129 | private $notFoundSerializer; |
||
130 | |||
131 | /** |
||
132 | * @var RejectSerializer |
||
133 | */ |
||
134 | private $rejectSerializer; |
||
135 | |||
136 | /** |
||
137 | * @var BlockLocatorSerializer |
||
138 | */ |
||
139 | private $blockLocatorSerializer; |
||
140 | |||
141 | /** |
||
142 | * @var GetBlocksSerializer |
||
143 | */ |
||
144 | private $getBlocksSerializer; |
||
145 | |||
146 | /** |
||
147 | * @var GetHeadersSerializer |
||
148 | */ |
||
149 | private $getHeadersSerializer; |
||
150 | |||
151 | /** |
||
152 | * @var PongSerializer |
||
153 | */ |
||
154 | private $pongSerializer; |
||
155 | |||
156 | /** |
||
157 | * @var VersionSerializer |
||
158 | */ |
||
159 | private $versionSerializer; |
||
160 | |||
161 | /** |
||
162 | * @var FeeFilterSerializer |
||
163 | */ |
||
164 | private $feeFilterSerializer; |
||
165 | |||
166 | /** |
||
167 | * @var AddrSerializer |
||
168 | */ |
||
169 | private $addrSerializer; |
||
170 | |||
171 | /** |
||
172 | * @param NetworkInterface $network |
||
173 | */ |
||
174 | 84 | public function __construct(NetworkInterface $network) |
|
201 | |||
202 | /** |
||
203 | * @return \BitWasp\Buffertools\Template |
||
204 | */ |
||
205 | 84 | private function getHeaderTemplate() |
|
214 | |||
215 | /** |
||
216 | * @param Parser $parser |
||
217 | * @return NetworkMessage |
||
218 | * @throws \BitWasp\Buffertools\Exceptions\ParserOutOfRange |
||
219 | * @throws \Exception |
||
220 | */ |
||
221 | 52 | public function fromParser(Parser & $parser) |
|
222 | { |
||
223 | 52 | list ($netBytes, $command, $payloadSize, $checksum) = $this->getHeaderTemplate()->parse($parser); |
|
224 | /** @var Buffer $netBytes */ |
||
225 | /** @var Buffer $command */ |
||
226 | /** @var int|string $payloadSize */ |
||
227 | /** @var Buffer $checksum */ |
||
228 | |||
229 | 52 | if ($netBytes->getHex() !== $this->network->getNetMagicBytes()) { |
|
230 | 2 | throw new \RuntimeException('Invalid magic bytes for network'); |
|
231 | } |
||
232 | |||
233 | $buffer = $payloadSize > 0 |
||
234 | 50 | ? $parser->readBytes($payloadSize) |
|
235 | 50 | : new Buffer('', 0, $this->math); |
|
236 | |||
237 | // Compare payload checksum against header value |
||
238 | 50 | if (Hash::sha256d($buffer)->slice(0, 4)->getBinary() !== $checksum->getBinary()) { |
|
239 | 2 | throw new \RuntimeException('Invalid packet checksum'); |
|
240 | } |
||
241 | |||
242 | 48 | $cmd = trim($command->getBinary()); |
|
243 | switch ($cmd) { |
||
244 | 48 | case Message::VERSION: |
|
245 | 2 | $payload = $this->versionSerializer->parse($buffer); |
|
246 | 2 | break; |
|
247 | 46 | case Message::VERACK: |
|
248 | 2 | $payload = new VerAck(); |
|
249 | 2 | break; |
|
250 | 44 | case Message::SENDHEADERS: |
|
251 | 2 | $payload = new SendHeaders(); |
|
252 | 2 | break; |
|
253 | 42 | case Message::ADDR: |
|
254 | 2 | $payload = $this->addrSerializer->parse($buffer); |
|
255 | 2 | break; |
|
256 | 40 | case Message::INV: |
|
257 | 2 | $payload = $this->invSerializer->parse($buffer); |
|
258 | 2 | break; |
|
259 | 38 | case Message::GETDATA: |
|
260 | 2 | $payload = $this->getDataSerializer->parse($buffer); |
|
261 | 2 | break; |
|
262 | 36 | case Message::NOTFOUND: |
|
263 | 2 | $payload = $this->notFoundSerializer->parse($buffer); |
|
264 | 2 | break; |
|
265 | 34 | case Message::GETBLOCKS: |
|
266 | 2 | $payload = $this->getBlocksSerializer->parse($buffer); |
|
267 | 2 | break; |
|
268 | 32 | case Message::GETHEADERS: |
|
269 | 2 | $payload = $this->getHeadersSerializer->parse($buffer); |
|
270 | 2 | break; |
|
271 | 30 | case Message::TX: |
|
272 | 2 | $payload = new Tx($this->txSerializer->parse($buffer)); |
|
273 | 2 | break; |
|
274 | 28 | case Message::BLOCK: |
|
275 | 2 | $payload = new Block($this->blockSerializer->parse($buffer)); |
|
276 | 2 | break; |
|
277 | 26 | case Message::HEADERS: |
|
278 | 2 | $payload = $this->headersSerializer->parse($buffer); |
|
279 | 2 | break; |
|
280 | 24 | case Message::GETADDR: |
|
281 | 2 | $payload = new GetAddr(); |
|
282 | 2 | break; |
|
283 | 22 | case Message::MEMPOOL: |
|
284 | 2 | $payload = new MemPool(); |
|
285 | 2 | break; |
|
286 | 20 | case Message::FEEFILTER: |
|
287 | 2 | $payload = $this->feeFilterSerializer->parse($buffer); |
|
288 | 2 | break; |
|
289 | 18 | case Message::FILTERLOAD: |
|
290 | 2 | $payload = $this->filterLoadSerializer->parse($buffer); |
|
291 | 2 | break; |
|
292 | 16 | case Message::FILTERADD: |
|
293 | 2 | $payload = $this->filterAddSerializer->parse($buffer); |
|
294 | 2 | break; |
|
295 | 14 | case Message::FILTERCLEAR: |
|
296 | 2 | $payload = new FilterClear(); |
|
297 | 2 | break; |
|
298 | 12 | case Message::MERKLEBLOCK: |
|
299 | 2 | $payload = $this->merkleBlockSerializer->parse($buffer); |
|
300 | 2 | break; |
|
301 | 10 | case Message::PING: |
|
302 | 2 | $payload = $this->pingSerializer->parse($buffer); |
|
303 | 2 | break; |
|
304 | 8 | case Message::PONG: |
|
305 | 2 | $payload = $this->pongSerializer->parse($buffer); |
|
306 | 2 | break; |
|
307 | 6 | case Message::REJECT: |
|
308 | 2 | $payload = $this->rejectSerializer->parse($buffer); |
|
309 | 2 | break; |
|
310 | 4 | case Message::ALERT: |
|
311 | 2 | $payload = $this->alertSerializer->parse($buffer); |
|
312 | 2 | break; |
|
313 | 2 | default: |
|
314 | 2 | throw new \RuntimeException('Invalid command'); |
|
315 | 2 | } |
|
316 | |||
317 | 46 | return new NetworkMessage( |
|
318 | 46 | $this->network, |
|
319 | $payload |
||
320 | 46 | ); |
|
321 | } |
||
322 | |||
323 | /** |
||
324 | * @param NetworkMessage $object |
||
325 | * @return Buffer |
||
326 | */ |
||
327 | 84 | public function serialize(NetworkMessage $object) |
|
340 | |||
341 | /** |
||
342 | * @param $data |
||
343 | * @return NetworkMessage |
||
344 | * @throws \Exception |
||
345 | */ |
||
346 | 54 | public function parse($data) |
|
350 | } |
||
351 |