Verify that a token transfer operation is permitted.
    * the token feature must exist
    * the sender must be unlocked---i.e. able to send at this point
    * the sender must have enough balance of the given token to send the amount requested
    * the token value must be positive
    * the consensus hash must be valid

    Return True if accepted
    Return False if not

def check( state_engine, token_op, block_id, checked_ops ):
    """
    Verify that a token transfer operation is permitted.
    * the token feature must exist
    * the sender must be unlocked---i.e. able to send at this point
    * the sender must have enough balance of the given token to send the amount requested
    * the token value must be positive
    * the consensus hash must be valid

    Return True if accepted
    Return False if not
    """

    epoch_features = get_epoch_features(block_id)
    if EPOCH_FEATURE_TOKEN_TRANSFER not in epoch_features:
        log.warning("Token transfers are not enabled in this epoch")
        return False

    consensus_hash = token_op['consensus_hash']
    address = token_op['address']
    recipient_address = token_op['recipient_address']
    token_type = token_op['token_units']
    token_value = token_op['token_fee']

    # token value must be positive
    if token_value <= 0:
        log.warning("Zero-value token transfer from {}".format(address))
        return False

    # can't send to ourselves 
    if address == recipient_address:
        log.warning('Cannot transfer token from the account to itself ({})'.format(address))
        return False

    # consensus hash must be valid
    if not state_engine.is_consensus_hash_valid(block_id, consensus_hash):
        log.warning('Invalid consensus hash {}'.format(consensus_hash))
        return False

    # sender account must exist
    account_info = state_engine.get_account(address, token_type)
    if account_info is None:
        log.warning("No account for {} ({})".format(address, token_type))
        return False

    # sender must not be transfer-locked
    if block_id < account_info['lock_transfer_block_id']:
        log.warning('Account {} is blocked from transferring tokens until block height {}'.format(address, account_info['lock_transfer_block_id']))
        return False

    # sender must have enough balance of the token  
    account_balance = state_engine.get_account_balance(account_info)
    if account_balance < token_value:
        log.warning('Account {} has {} {}; tried to send {}'.format(address, account_balance, token_type, token_value))
        return False
    
    receiver_account = state_engine.get_account(recipient_address, token_type)
    if receiver_account is not None:
        if not receiver_account['receive_whitelisted']:
            log.warning('Receiver account {} is not whitelisted'.format(recipient_address))
            return False

    log.debug("Account {} will pay {} {} to {}".format(address, token_value, token_type, recipient_address))

    # will execute a debit against the sender address
    token_operation_put_account_payment_info(token_op, address, token_type, token_value)

    # will execute a credit against the receiver address 
    token_operation_put_account_credit_info(token_op, recipient_address, token_type, token_value)

    # preserve token_fee as a string to prevent overflow
    token_op['token_fee'] = '{}'.format(token_op['token_fee'])
    return True