Exemple #1
0
def serial_number_to_tx(serial_number, bitcoind_proxy, proxy=None):
    """
    Convert a serial number into its transaction in the blockchain.
    Use an untrusted bitcoind connection to get the list of transactions,
    and use trusted SPV headers to ensure that the transaction obtained is on the main chain.
    @bitcoind_proxy must be a BitcoindConnection (from virtualchain.lib.session)

    Return the SPV-verified transaction object (as a dict) on success
    Return None on error
    """

    proxy = get_default_proxy() if proxy is None else proxy

    parts = serial_number.split('-')
    block_id, tx_index = int(parts[0]), int(parts[1])

    timeout = 1.0
    while True:
        try:
            block_hash = bitcoind_proxy.getblockhash(block_id)
            block_data = bitcoind_proxy.getblock(block_hash)
            break
        except Exception as e:
            log.error('Unable to obtain block data; retrying...')
            time.sleep(timeout)
            timeout = timeout * 2 + random.random() * timeout

    rc = SPVClient.sync_header_chain(proxy.spv_headers_path,
                                     bitcoind_proxy.opts['bitcoind_server'],
                                     block_id)

    if not rc:
        msg = 'Failed to synchronize SPV header chain up to {}'
        log.error(msg.format(block_id))
        return None

    # verify block header
    rc = SPVClient.block_header_verify(proxy.spv_headers_path, block_id,
                                       block_hash, block_data)
    if not rc:
        msg = 'Failed to verify block header for {} against SPV headers'
        log.error(msg.format(block_id))
        return None

    # verify block txs
    rc = SPVClient.block_verify(block_data, block_data['tx'])
    if not rc:
        msg = 'Failed to verify block transaction IDs for {} against SPV headers'
        log.error(msg.format(block_id))
        return None

    # sanity check
    if tx_index >= len(block_data['tx']):
        msg = 'Serial number {} references non-existant transaction {} (out of {} txs)'
        log.error(msg.format(serial_number, tx_index, len(block_data['tx'])))
        return None

    # obtain transaction
    txid = block_data['tx'][tx_index]
    tx = bitcoind_proxy.getrawtransaction(txid, 1)

    # verify tx
    rc = SPVClient.tx_verify(block_data['tx'], tx)
    if not rc:
        msg = 'Failed to verify block transaction {} against SPV headers'
        log.error(msg.format(txid))
        return None

    # verify tx index
    if tx_index != SPVClient.tx_index(block_data['tx'], tx):
        msg = ('TX index mismatch: serial number identifies '
               'transaction number {} ({}), but got transaction {}')

        log.error(
            msg.format(
                tx_index, block_data['tx'][tx_index],
                block_data['tx'][SPVClient.tx_index(block_data['tx'], tx)]))
        return None

    # success!
    return tx
Exemple #2
0
            % (serial_number, tx_index, len(block_data['tx'])))
        return None

    # obtain transaction
    txid = block_data['tx'][tx_index]
    tx = bitcoind_proxy.getrawtransaction(txid, 1)

    # verify tx
    rc = SPVClient.tx_verify(block_data['tx'], tx)
    if not rc:
        log.error("Failed to verify block transaction %s against SPV headers" %
                  txid)
        return None

    # verify tx index
    if tx_index != SPVClient.tx_index(block_data['tx'], tx):
        log.error("TX index mismatch: serial number identifies transaction number %s (%s), but got transaction %s" % \
                (tx_index, block_data['tx'][tx_index], block_data['tx'][ SPVClient.tx_index(block_data['tx'], tx) ]))
        return None

    # success!
    return tx


def parse_tx_op_return(tx):
    """
    Given a transaction, locate its OP_RETURN and parse
    out its opcode and payload.
    Return (opcode, payload) on success
    Return (None, None) if there is no OP_RETURN, or if it's not a blockchain ID operation.
    """