def txid_to_block_data(txid, bitcoind_proxy, proxy=None): """ Given a txid, get its block's data. Use SPV to verify the information we receive from the (untrusted) bitcoind host. @bitcoind_proxy must be a BitcoindConnection (from virtualchain.lib.session) Return the (block hash, block data, txdata) on success Return (None, None, None) on error """ proxy = get_default_proxy() if proxy is None else proxy timeout = 1.0 while True: try: untrusted_tx_data = bitcoind_proxy.getrawtransaction(txid, 1) untrusted_block_hash = untrusted_tx_data['blockhash'] untrusted_block_data = bitcoind_proxy.getblock( untrusted_block_hash) break except (OSError, IOError) as ie: log.exception(ie) log.error('Network error; retrying...') timeout = timeout * 2 + random.randint(0, timeout) continue except Exception as e: log.exception(e) return None, None, None # first, can we trust this block? is it in the SPV headers? untrusted_block_header_hex = virtualchain.block_header_to_hex( untrusted_block_data, untrusted_block_data['previousblockhash']) block_id = SPVClient.block_header_index( proxy.spv_headers_path, ('{}00'.format(untrusted_block_header_hex)).decode('hex')) if block_id < 0: # bad header log.error('Block header "{}" is not in the SPV headers ({})'.format( untrusted_block_header_hex, proxy.spv_headers_path)) return None, None, None # block header is trusted. Is the transaction data consistent with it? verified_block_header = virtualchain.block_verify(untrusted_block_data) if not verified_block_header: msg = ('Block transaction IDs are not consistent ' 'with the Merkle root of the trusted header') log.error(msg) return None, None, None # verify block hash verified_block_hash = virtualchain.block_header_verify( untrusted_block_data, untrusted_block_data['previousblockhash'], untrusted_block_hash) if not verified_block_hash: log.error('Block hash is not consistent with block header') return None, None, None # we trust the block hash, block data, and txids block_hash = untrusted_block_hash block_data = untrusted_block_data tx_data = untrusted_tx_data return block_hash, block_data, tx_data
break except (OSError, IOError), ie: log.exception(ie) log.error("Network error; retrying...") timeout = timeout * 2 + random.randint(0, timeout) continue except Exception, e: log.exception(e) return (None, None, None) # first, can we trust this block? is it in the SPV headers? untrusted_block_header_hex = virtualchain.block_header_to_hex( untrusted_block_data, untrusted_block_data['previousblockhash']) block_id = SPVClient.block_header_index(proxy.spv_headers_path, (untrusted_block_header_hex + "00").decode('hex')) if block_id < 0: # bad header log.error("Block header '%s' is not in the SPV headers (%s)" % (untrusted_block_header_hex, proxy.spv_headers_path)) return (None, None, None) # block header is trusted. Is the transaction data consistent with it? if not virtualchain.block_verify(untrusted_block_data): log.error( "Block transaction IDs are not consistent with the trusted header's Merkle root" ) return (None, None, None) # verify block hash