A P2P data store class. Keeps a block and transaction store and responds correctly to getdata and getheaders requests.
| 824 | |
| 825 | |
| 826 | class P2PDataStore(P2PInterface): |
| 827 | """A P2P data store class. |
| 828 | |
| 829 | Keeps a block and transaction store and responds correctly to getdata and getheaders requests.""" |
| 830 | |
| 831 | def __init__(self): |
| 832 | super().__init__() |
| 833 | # store of blocks. key is block hash, value is a CBlock object |
| 834 | self.block_store = {} |
| 835 | self.last_block_hash = '' |
| 836 | # store of txs. key is txid, value is a CTransaction object |
| 837 | self.tx_store = {} |
| 838 | self.getdata_requests = [] |
| 839 | |
| 840 | def on_getdata(self, message): |
| 841 | """Check for the tx/block in our stores and if found, reply with MSG_TX or MSG_BLOCK.""" |
| 842 | for inv in message.inv: |
| 843 | self.getdata_requests.append(inv.hash) |
| 844 | invtype = inv.type & MSG_TYPE_MASK |
| 845 | if (invtype == MSG_TX or invtype == MSG_WTX) and inv.hash in self.tx_store.keys(): |
| 846 | self.send_without_ping(msg_tx(self.tx_store[inv.hash])) |
| 847 | elif invtype == MSG_BLOCK and inv.hash in self.block_store.keys(): |
| 848 | self.send_without_ping(msg_block(self.block_store[inv.hash])) |
| 849 | else: |
| 850 | logger.debug('getdata message type {} received.'.format(hex(inv.type))) |
| 851 | |
| 852 | def on_getheaders(self, message): |
| 853 | """Search back through our block store for the locator, and reply with a headers message if found.""" |
| 854 | |
| 855 | locator, hash_stop = message.locator, message.hashstop |
| 856 | |
| 857 | # Assume that the most recent block added is the tip |
| 858 | if not self.block_store: |
| 859 | return |
| 860 | |
| 861 | headers_list = [self.block_store[self.last_block_hash]] |
| 862 | while headers_list[-1].hash_int not in locator.vHave: |
| 863 | # Walk back through the block store, adding headers to headers_list |
| 864 | # as we go. |
| 865 | prev_block_hash = headers_list[-1].hashPrevBlock |
| 866 | if prev_block_hash in self.block_store: |
| 867 | prev_block_header = CBlockHeader(self.block_store[prev_block_hash]) |
| 868 | headers_list.append(prev_block_header) |
| 869 | if prev_block_header.hash_int == hash_stop: |
| 870 | # if this is the hashstop header, stop here |
| 871 | break |
| 872 | else: |
| 873 | logger.debug('block hash {} not found in block store'.format(hex(prev_block_hash))) |
| 874 | break |
| 875 | |
| 876 | # Truncate the list if there are too many headers |
| 877 | headers_list = headers_list[:-MAX_HEADERS_RESULTS - 1:-1] |
| 878 | response = msg_headers(headers_list) |
| 879 | |
| 880 | if response is not None: |
| 881 | self.send_without_ping(response) |
| 882 | |
| 883 | def send_blocks_and_test(self, blocks, node, *, success=True, force_send=False, reject_reason=None, expect_disconnect=False, timeout=60, is_decoy=False): |
no outgoing calls