Given a hex-encoded transaction, decode it into an object
    with the following structure:
    {
        ins: [
            {
                outpoint: { hash: ..., index: ... }, 
                script: ...,
                sequence: ...,
                witness_script: ...,        # not included if not segwit
            }, ...
        ]
        outs: [
            {
                value: ...,
                script: ...
            }, ...
        ],
        version: ..., 
        locktime: ...
    }
    
    Derived from pybitcointools (https://github.com/vbuterin/pybitcointools) written by Vitalik Buterin
    Throws an exception if there are remaining bytes

def btc_tx_deserialize(_tx, **blockchain_opts):
    """
    Given a hex-encoded transaction, decode it into an object
    with the following structure:
    {
        ins: [
            {
                outpoint: { hash: ..., index: ... }, 
                script: ...,
                sequence: ...,
                witness_script: ...,        # not included if not segwit
            }, ...
        ]
        outs: [
            {
                value: ...,
                script: ...
            }, ...
        ],
        version: ..., 
        locktime: ...
    }
    
    Derived from pybitcointools (https://github.com/vbuterin/pybitcointools) written by Vitalik Buterin
    Throws an exception if there are remaining bytes
    """

    tx = None
    if isinstance(_tx, str) and re.match('^[0-9a-fA-F]*$', _tx):
        # convert from hex to bin, safely
        tx = binascii.unhexlify(_tx)
    else:
        tx = _tx[:]

    # pointer to byte offset in _tx (as an array due to Python scoping rules)
    ptr = [0]
    
    # top-level tx
    obj = {"ins": [], "outs": [], 'version': None, 'locktime': None}

    # get version
    obj["version"] = read_as_int(ptr, tx, 4)

    # segwit? (bip143)
    # 5th byte will be 0 and 6th byte will be flags (nonzero) if so
    bip143 = peek_bytes(ptr, tx, 2)
    if ord(bip143[0]) == 0 and ord(bip143[1]) != 0:
        # segwit
        # consume marker
        read_bytes(ptr, tx, 2)

        # get the rest of the body
        body = read_tx_body(ptr, tx)
        obj['ins'] = body['ins']
        obj['outs'] = body['outs']
     
        # read witnesses for each input
        witness_scripts = read_tx_witnesses(ptr, tx, len(obj['ins']))
      
        if len(witness_scripts) != len(obj['ins']):
            raise ValueError('Invald number of witnesses in {}'.format(_tx))

        for i in xrange(0, len(witness_scripts)):
            obj['ins'][i]['witness_script'] = witness_scripts[i]
        
    else:
        # non-segwit
        body = read_tx_body(ptr, tx)
        obj['ins'] = body['ins']
        obj['outs'] = body['outs']

    # locktime
    obj["locktime"] = read_as_int(ptr, tx, 4)

    if not ptr[0] == len(tx):
        # log.warning('Did not parse entire tx ({} bytes remaining)'.format(len(tx) - ptr[0]))
        raise ValueError('Did not parse entire tx ({} bytes remaining)'.format(len(tx) - ptr[0]))

    # hexlify each byte field 
    obj = encoding.json_changebase(obj, lambda x: encoding.safe_hexlify(x))
    return obj