Extract and return a dict of fields from the underlying blockchain transaction data
    that are useful to this operation.

    Required (+ parse):
    sender:  the script_pubkey (as a hex string) of the principal that sent the name preorder transaction
    address:  the address from the sender script
    recipient:  the script_pubkey (as a hex string) of the principal that is meant to receive the name
    recipient_address:  the address from the recipient script

    Optional:
    sender_pubkey_hex: the public key of the sender

def tx_extract( payload, senders, inputs, outputs, block_id, vtxindex, txid ):
    """
    Extract and return a dict of fields from the underlying blockchain transaction data
    that are useful to this operation.

    Required (+ parse):
    sender:  the script_pubkey (as a hex string) of the principal that sent the name preorder transaction
    address:  the address from the sender script
    recipient:  the script_pubkey (as a hex string) of the principal that is meant to receive the name
    recipient_address:  the address from the recipient script

    Optional:
    sender_pubkey_hex: the public key of the sender
    """
  
    sender_script = None 
    sender_address = None 
    sender_pubkey_hex = None

    recipient = None 
    recipient_address = None 
    burn_address = None
    op_fee = None

    op = NAME_REGISTRATION
    opcode = 'NAME_REGISTRATION'

    try:
       # first 2 outputs matter (op_return, owner addr)
       assert check_tx_output_types(outputs[:2], block_id)

       recipient = get_registration_recipient_from_outputs( outputs )
       recipient_address = virtualchain.script_hex_to_address( recipient )

       assert recipient is not None 
       assert recipient_address is not None

       # by construction, the first input comes from the principal
       # who sent the registration transaction...
       assert len(senders) > 0
       assert 'script_pubkey' in senders[0].keys()
       assert 'addresses' in senders[0].keys()

       sender_script = str(senders[0]['script_pubkey'])
       sender_address = str(senders[0]['addresses'][0])

       assert sender_script is not None 
       assert sender_address is not None

       if str(senders[0]['script_type']) == 'pubkeyhash':
          sender_pubkey_hex = get_public_key_hex_from_tx( inputs, sender_address )

       if len(outputs) >= 4:
          # renewing
          burn_info = get_renew_burn_info(outputs)
          burn_address = burn_info['burn_address']
          op_fee = burn_info['op_fee']

          op = '{}{}'.format(NAME_RENEWAL, NAME_RENEWAL)
          opcode = 'NAME_RENEWAL'

    except Exception, e:
       log.exception(e)
       raise Exception("Failed to extract")

    parsed_payload = parse( payload, block_id )
    assert parsed_payload is not None 

    ret = {
       "value_hash": None,
       "sender": sender_script,
       "address": sender_address,
       "recipient": recipient,
       "recipient_address": recipient_address,
       "revoked": False,
       "last_renewed": block_id,
       "vtxindex": vtxindex,
       "txid": txid,
       "op": op,
       "opcode": opcode,
    }

    if opcode == 'NAME_REGISTRATION':
        # registration
        if parsed_payload['token_fee'] is not None:
            # registration shouldn't have this field
            assert parsed_payload['token_fee'] == 0

        ret.update({ 
           'name': parsed_payload['name'],
           'value_hash': parsed_payload['value_hash'],
           "first_registered": block_id,
           "last_renewed": block_id,
         })


    else:
        # renewal
        assert parsed_payload['token_fee'] is not None
        ret.update({
           'name': parsed_payload['name'],
           'value_hash': parsed_payload['value_hash'],
           'op_fee': op_fee,
           "burn_address": burn_address,
           'token_fee': parsed_payload['token_fee'],
        })

    # NOTE: will get deleted if this is a renew
    if sender_pubkey_hex is not None:
        ret['sender_pubkey'] = sender_pubkey_hex
    else:
        ret['sender_pubkey'] = None

    return ret