def parse(bin_payload, block_height):
    """
    Parse a name preorder.
    NOTE: bin_payload *excludes* the leading 3 bytes (magic + op) returned by build.

    Record format:
    
    0     2  3                                              23             39
    |-----|--|----------------------------------------------|--------------|
    magic op  hash(name.ns_id,script_pubkey,register_addr)   consensus hash
    
    Record format when burning STACKs (STACKS Phase 1):
    0     2  3                                              23                 39                            47                      66
    |-----|--|----------------------------------------------|------------------|-----------------------------|-----------------------|
    magic op  hash(name.ns_id,script_pubkey,register_addr)   consensus hash     tokens to burn (big-endian)  token units (0-padded)

    Returns {
        opcode: NAME_PREORDER,
        preorder_hash: the hash of the name, scriptPubKey, and register address
        consensus_hash: the consensus hash
        token_fee: the amount of tokens to burn (will be None if not given)
        token_units: the type of tokens to burn (will be None if not given)
    }
    """
    
    epoch_features = get_epoch_features(block_height)

    if len(bin_payload) < LENGTHS['preorder_name_hash'] + LENGTHS['consensus_hash']:
        log.warning("Invalid payload {}: expected at least {} bytes".format(bin_payload.encode('hex'), LENGTHS['preorder_name_hash'] + LENGTHS['consensus_hash']))
        return None 

    name_hash = hexlify( bin_payload[0:LENGTHS['preorder_name_hash']] )
    consensus_hash = hexlify( bin_payload[LENGTHS['preorder_name_hash']: LENGTHS['preorder_name_hash'] + LENGTHS['consensus_hash']] )
    tokens_burned = None
    token_units = None

    if len(bin_payload) > LENGTHS['preorder_name_hash'] + LENGTHS['consensus_hash']:
        # only acceptable if there's a token burn
        if EPOCH_FEATURE_NAMEOPS_COST_TOKENS not in epoch_features:
            # not enabled yet
            log.warning("Invalid payload {}: expected {} bytes".format(bin_payload.encode('hex'), LENGTHS['preorder_name_hash'] + LENGTHS['consensus_hash']))
            return None

        if len(bin_payload) != LENGTHS['preorder_name_hash'] + LENGTHS['consensus_hash'] + LENGTHS['tokens_burnt'] + LENGTHS['namespace_id']:
            # invalid
            log.warning("Invalid payload {}: expected {} bytes".format(bin_payload.encode('hex'), LENGTHS['preorder_name_hash'] + LENGTHS['consensus_hash'] + LENGTHS['tokens_burnt']))
            return None

        at_tokens_burnt = LENGTHS['preorder_name_hash'] + LENGTHS['consensus_hash']
        at_token_units = LENGTHS['preorder_name_hash'] + LENGTHS['consensus_hash'] + LENGTHS['tokens_burnt']

        bin_tokens_burnt = bin_payload[at_tokens_burnt: at_tokens_burnt + LENGTHS['tokens_burnt']]
        bin_token_units = bin_payload[at_token_units: at_token_units + LENGTHS['namespace_id']]

        tokens_burned = int(bin_tokens_burnt.encode('hex'), 16)
        token_units = bin_token_units.strip('\x00')

    return {
        'opcode': 'NAME_PREORDER',
        'preorder_hash': name_hash,
        'consensus_hash': consensus_hash,
        'token_fee': tokens_burned,
        'token_units': token_units,
    }
Parse a name preorder.
    NOTE: bin_payload *excludes* the leading 3 bytes (magic + op) returned by build.

    Record format:
    
    0     2  3                                              23             39
    |-----|--|----------------------------------------------|--------------|
    magic op  hash(name.ns_id,script_pubkey,register_addr)   consensus hash
    
    Record format when burning STACKs (STACKS Phase 1):
    0     2  3                                              23                 39                            47                      66
    |-----|--|----------------------------------------------|------------------|-----------------------------|-----------------------|
    magic op  hash(name.ns_id,script_pubkey,register_addr)   consensus hash     tokens to burn (big-endian)  token units (0-padded)

    Returns {
        opcode: NAME_PREORDER,
        preorder_hash: the hash of the name, scriptPubKey, and register address
        consensus_hash: the consensus hash
        token_fee: the amount of tokens to burn (will be None if not given)
        token_units: the type of tokens to burn (will be None if not given)
    }