A P2P data store class. Keeps a block and transaction store and responds correctly to getdata and getheaders requests.
| 419 | |
| 420 | |
| 421 | class P2PDataStore(P2PInterface): |
| 422 | """A P2P data store class. |
| 423 | |
| 424 | Keeps a block and transaction store and responds correctly to getdata and getheaders requests.""" |
| 425 | |
| 426 | def __init__(self): |
| 427 | super().__init__() |
| 428 | self.reject_code_received = None |
| 429 | self.reject_reason_received = None |
| 430 | # store of blocks. key is block hash, value is a CBlock object |
| 431 | self.block_store = {} |
| 432 | self.last_block_hash = '' |
| 433 | # store of txs. key is txid, value is a CTransaction object |
| 434 | self.tx_store = {} |
| 435 | self.getdata_requests = [] |
| 436 | |
| 437 | def on_getdata(self, message): |
| 438 | """Check for the tx/block in our stores and if found, reply with an inv message.""" |
| 439 | for inv in message.inv: |
| 440 | self.getdata_requests.append(inv.hash) |
| 441 | if (inv.type & MSG_TYPE_MASK) == MSG_TX and inv.hash in self.tx_store.keys(): |
| 442 | self.send_message(msg_tx(self.tx_store[inv.hash])) |
| 443 | elif (inv.type & MSG_TYPE_MASK) == MSG_BLOCK and inv.hash in self.block_store.keys(): |
| 444 | self.send_message(msg_block(self.block_store[inv.hash])) |
| 445 | else: |
| 446 | logger.debug('getdata message type {} received.'.format(hex(inv.type))) |
| 447 | |
| 448 | def on_getheaders(self, message): |
| 449 | """Search back through our block store for the locator, and reply with a headers message if found.""" |
| 450 | |
| 451 | locator, hash_stop = message.locator, message.hashstop |
| 452 | |
| 453 | # Assume that the most recent block added is the tip |
| 454 | if not self.block_store: |
| 455 | return |
| 456 | |
| 457 | headers_list = [self.block_store[self.last_block_hash]] |
| 458 | maxheaders = 2000 |
| 459 | while headers_list[-1].sha256 not in locator.vHave: |
| 460 | # Walk back through the block store, adding headers to headers_list |
| 461 | # as we go. |
| 462 | prev_block_hash = headers_list[-1].hashPrevBlock |
| 463 | if prev_block_hash in self.block_store: |
| 464 | prev_block_header = CBlockHeader(self.block_store[prev_block_hash]) |
| 465 | headers_list.append(prev_block_header) |
| 466 | if prev_block_header.sha256 == hash_stop: |
| 467 | # if this is the hashstop header, stop here |
| 468 | break |
| 469 | else: |
| 470 | logger.debug('block hash {} not found in block store'.format(hex(prev_block_hash))) |
| 471 | break |
| 472 | |
| 473 | # Truncate the list if there are too many headers |
| 474 | headers_list = headers_list[:-maxheaders - 1:-1] |
| 475 | response = msg_headers(headers_list) |
| 476 | |
| 477 | if response is not None: |
| 478 | self.send_message(response) |
no outgoing calls
no test coverage detected