A P2P data store class. Keeps a block and transaction store and responds correctly to getdata and getheaders requests.
| 640 | |
| 641 | |
| 642 | class P2PDataStore(P2PInterface): |
| 643 | """A P2P data store class. |
| 644 | |
| 645 | Keeps a block and transaction store and responds correctly to getdata and getheaders requests.""" |
| 646 | |
| 647 | def __init__(self): |
| 648 | super().__init__() |
| 649 | # store of blocks. key is block hash, value is a CBlock object |
| 650 | self.block_store = {} |
| 651 | self.last_block_hash = '' |
| 652 | # store of txs. key is txid, value is a CTransaction object |
| 653 | self.tx_store = {} |
| 654 | self.getdata_requests = [] |
| 655 | |
| 656 | def on_getdata(self, message): |
| 657 | """Check for the tx/block in our stores and if found, reply with an inv message.""" |
| 658 | for inv in message.inv: |
| 659 | self.getdata_requests.append(inv.hash) |
| 660 | if (inv.type & MSG_TYPE_MASK) == MSG_TX and inv.hash in self.tx_store.keys(): |
| 661 | self.send_message(msg_tx(self.tx_store[inv.hash])) |
| 662 | elif (inv.type & MSG_TYPE_MASK) == MSG_BLOCK and inv.hash in self.block_store.keys(): |
| 663 | self.send_message(msg_block(self.block_store[inv.hash])) |
| 664 | else: |
| 665 | logger.debug('getdata message type {} received.'.format(hex(inv.type))) |
| 666 | |
| 667 | def on_getheaders(self, message): |
| 668 | """Search back through our block store for the locator, and reply with a headers message if found.""" |
| 669 | |
| 670 | locator, hash_stop = message.locator, message.hashstop |
| 671 | |
| 672 | # Assume that the most recent block added is the tip |
| 673 | if not self.block_store: |
| 674 | return |
| 675 | |
| 676 | headers_list = [self.block_store[self.last_block_hash]] |
| 677 | while headers_list[-1].sha256 not in locator.vHave: |
| 678 | # Walk back through the block store, adding headers to headers_list |
| 679 | # as we go. |
| 680 | prev_block_hash = headers_list[-1].hashPrevBlock |
| 681 | if prev_block_hash in self.block_store: |
| 682 | prev_block_header = CBlockHeader(self.block_store[prev_block_hash]) |
| 683 | headers_list.append(prev_block_header) |
| 684 | if prev_block_header.sha256 == hash_stop: |
| 685 | # if this is the hashstop header, stop here |
| 686 | break |
| 687 | else: |
| 688 | logger.debug('block hash {} not found in block store'.format(hex(prev_block_hash))) |
| 689 | break |
| 690 | |
| 691 | # Truncate the list if there are too many headers |
| 692 | headers_list = headers_list[:-MAX_HEADERS_RESULTS - 1:-1] |
| 693 | response = msg_headers(headers_list) |
| 694 | |
| 695 | if response is not None: |
| 696 | self.send_message(response) |
| 697 | |
| 698 | def send_blocks_and_test(self, blocks, node, *, success=True, force_send=False, reject_reason=None, expect_disconnect=False, timeout=60): |
| 699 | """Send blocks to test node and test whether the tip advances. |
no outgoing calls