コード例 #1
0
def check_register(state_engine, nameop, block_id, checked_ops):
    """
    Verify the validity of a registration nameop.
    * the name must be well-formed
    * the namespace must be ready
    * the name does not collide
    * the name was preordered by the same sender as the last preorder
    * the Bitcoin or Stacks fee paid by the preorder must be high enough (for some namespace-version-specific definition of "high enough")

    NAME_REGISTRATION is not allowed during a namespace import, so the namespace must be ready.

    Return True if accepted.
    Return False if not.
    """

    from ..nameset import BlockstackDB

    name = nameop['name']
    sender = nameop['sender']

    # address mixed into the preorder
    register_addr = nameop.get('recipient_address', None)
    if register_addr is None:
        log.warning("No registration address given")
        return False

    recipient = nameop.get('recipient', None)
    if recipient is None:
        log.warning("No recipient script given")
        return False

    # name must be well-formed
    if not is_name_valid(name):
        log.warning("Malformed name '%s'" % name)
        return False

    epoch_features = get_epoch_features(block_id)

    name_fee = None
    namespace = None
    preorder_hash = None
    preorder_block_number = None
    name_block_number = None
    consensus_hash = None
    fee_block_id = None  # block ID at which the fee was paid
    fee_vtxindex = None  # vtxindex at which the fee was paid
    burn_address = None  # preorder/renew burn address
    token_address = None  # if we're paying in tokens, this is the token account to debit
    opcode = nameop['opcode']
    first_registered = nameop['first_registered']

    # name must be well-formed
    if not is_b40(name) or "+" in name or name.count(".") > 1:
        log.warning("Malformed name '%s': non-base-38 characters" % name)
        return False

    # name must not be revoked
    if state_engine.is_name_revoked(name):
        log.warning("Name '%s' is revoked" % name)
        return False

    namespace_id = get_namespace_from_name(name)

    # namespace must exist and be ready
    if not state_engine.is_namespace_ready(namespace_id):
        log.warning("Namespace '%s' is not ready" % namespace_id)
        return False

    # get namespace...
    namespace = state_engine.get_namespace(namespace_id)

    # cannot exceed quota
    num_names = get_num_names_owned(state_engine, checked_ops, recipient)
    if num_names >= MAX_NAMES_PER_SENDER:
        log.warning("Recipient '%s' has exceeded quota" % recipient)
        return False

    # if multisig is not enabled in this epoch, and the recipient
    # address is a p2sh address, then reject the transaction.
    # this if for compatibility with 0.13
    if virtualchain.is_multisig_address(
            register_addr) and not epoch_has_multisig(block_id):
        log.warning(
            "Multisig registration address %s, but this epoch (%s) does not support multisig"
            % (register_addr, get_epoch_number(block_id)))
        return False

    # get preorder...
    preorder = state_engine.get_name_preorder(name, sender, register_addr)
    old_name_rec = state_engine.get_name(name, include_expired=True)

    if preorder is None:
        # not preordered
        log.warning("Name '%s' does not exist, or is not preordered by %s" %
                    (name, sender))
        return False

    # bugfix?
    if EPOCH_FEATURE_FIX_PREORDER_EXPIRE in epoch_features:
        # preorder must not be expired
        if preorder['block_number'] + NAME_PREORDER_EXPIRE < block_id:
            log.warning("Preorder {} is expired".format(
                preorder['preorder_hash']))
            return False

    # can't be registered already
    if state_engine.is_name_registered(name):
        log.warning("Name '%s' is already registered" % name)
        return False

    # name can't be registered if it was reordered before its namespace was ready
    if not namespace.has_key('ready_block') or preorder[
            'block_number'] < namespace['ready_block']:
        log.warning("Name '%s' preordered before namespace '%s' was ready" %
                    (name, namespace_id))
        return False

    # name must be preordered by the same sender
    if preorder['sender'] != sender:
        log.warning("Name '%s' was not preordered by %s" % (name, sender))
        return False

    # fee was included in the preorder (even if it's just dust)
    if not 'op_fee' in preorder:
        log.warning("Name '%s' preorder did not pay the fee" % (name))
        return False

    name_fee = preorder['op_fee']
    preorder_hash = preorder['preorder_hash']
    preorder_block_number = preorder['block_number']
    fee_block_id = preorder_block_number
    fee_vtxindex = preorder['vtxindex']

    burn_address = preorder['burn_address']
    token_address = preorder[
        'address']  # note that the *preorderer* pays for a registration in tokens, just as it is with BTC

    # pass along the preorder
    state_create_put_preorder(nameop, preorder)

    if old_name_rec is None:
        # Case 1(a): registered for the first time ever
        log.debug("Registering name '%s'" % name)
        name_block_number = preorder['block_number']

    else:
        # Case 1(b): name expired, and is now re-registered
        log.debug("Re-registering name '%s'" % name)

        # push back preorder block number to the original preorder
        name_block_number = old_name_rec['block_number']

    # check name payment
    payment_res = check_payment(state_engine, "NAME_REGISTRATION", nameop,
                                fee_block_id, token_address, burn_address,
                                name_fee, block_id)
    if not payment_res['status']:
        log.warning(
            "Name '{}' did not receive the appropriate payment".format(name))
        return False

    log.debug('payment res: {}'.format(payment_res))

    # extract payment info
    token_fee = payment_res['tokens_paid']
    token_units = payment_res['token_units']

    if token_units == 'BTC':
        # name was paid for in the preorder by burning BTC, not by spending Stacks
        # if we paid tokens *as well*, then figure out how many and record it
        assert token_fee == name_fee, 'Tokens paid in BTC does not match tokens paid in transaction ({} != {})'.format(
            token_fee, name_fee)

        # sanity check
        res = get_stacks_payment(state_engine, nameop, "NAME_REGISTRATION")
        assert not res['status'], "BUG: we paid in BTC but also Stacks"

        token_fee = 0

    else:
        if EPOCH_FEATURE_NAMEOPS_COST_TOKENS not in epoch_features:
            # can't do this---tokens aren't active yet
            log.warning(
                'Tried to pay for {} in Stacks before Stacks exist'.format(
                    name))
            return False

        # name was paid for in the preorder by burning Stacks
        assert token_fee is not None
        assert token_units == TOKEN_TYPE_STACKS

        # sanity check
        res = get_stacks_payment(state_engine, nameop, "NAME_REGISTRATION")
        assert res['status'], "BUG: we paid in Stacks but did not"
        assert res['tokens_paid'] == token_fee
        assert res['token_units'] == token_units

    nameop['opcode'] = opcode
    nameop['op_fee'] = name_fee
    nameop['token_fee'] = '{}'.format(
        token_fee)  # NOTE: use a string to prevent integer overflow
    nameop['preorder_hash'] = preorder_hash
    nameop['importer'] = None
    nameop['importer_address'] = None
    nameop['consensus_hash'] = consensus_hash
    nameop['revoked'] = False
    nameop['namespace_block_number'] = namespace['block_number']
    nameop['first_registered'] = first_registered
    nameop['last_renewed'] = block_id
    nameop['preorder_block_number'] = preorder_block_number
    nameop['block_number'] = name_block_number

    # not consensus-bearing, but required for SNV
    nameop['last_creation_op'] = NAME_PREORDER

    # propagate new sender information
    nameop['sender'] = nameop['recipient']
    nameop['address'] = nameop['recipient_address']
    del nameop['recipient']
    del nameop['recipient_address']

    value_hash = nameop['value_hash']

    if value_hash is not None:
        # deny value hash if we're not in an epoch that supports register/update in one nameop
        if EPOCH_FEATURE_OP_REGISTER_UPDATE not in epoch_features:
            log.warning(
                "Name '{}' has a zone file hash, but this is not supported in this epoch"
                .format(nameop['name']))
            return False

        log.debug("Adding value hash {} for name '{}'".format(
            value_hash, nameop['name']))

    nameop['value_hash'] = value_hash
    return True
コード例 #2
0
def check_register( state_engine, nameop, block_id, checked_ops ):
    """
    Verify the validity of a registration nameop.
    * the name must be well-formed
    * the namespace must be ready
    * the name does not collide
    * either the name was preordered by the same sender, or the name exists and is owned by this sender (the name cannot be registered and owned by someone else)
    * the mining fee must be high enough.
    * if the name was expired, then merge the preorder information from the expired preorder (since this is a state-creating operation,
    we set the __preorder__ and __prior_history__ fields to preserve this).

    NAME_REGISTRATION is not allowed during a namespace import, so the namespace must be ready.

    Return True if accepted.
    Return False if not.
    """

    from ..nameset import BlockstackDB 

    name = nameop['name']
    sender = nameop['sender']

    # address mixed into the preorder
    register_addr = nameop.get('recipient_address', None)
    if register_addr is None:
        log.debug("No registration address given")
        return False

    recipient = nameop.get('recipient', None)
    if recipient is None:
        log.debug("No recipient script given")
        return False

    name_fee = None
    namespace = None
    preorder_hash = None
    preorder_block_number = None 
    name_block_number = None
    consensus_hash = None
    transfer_send_block_id = None
    fee_block_id = None         # block ID at which the fee was paid
    opcode = nameop['opcode']
    first_registered = nameop['first_registered']

    # name must be well-formed
    if not is_b40( name ) or "+" in name or name.count(".") > 1:
        log.debug("Malformed name '%s': non-base-38 characters" % name)
        return False

    # name must not be revoked
    if state_engine.is_name_revoked( name ):
        log.debug("Name '%s' is revoked" % name)
        return False

    namespace_id = get_namespace_from_name( name )

    # namespace must exist and be ready
    if not state_engine.is_namespace_ready( namespace_id ):
        log.debug("Namespace '%s' is not ready" % namespace_id)
        return False

    # get namespace...
    namespace = state_engine.get_namespace( namespace_id )

    # cannot exceed quota
    num_names = get_num_names_owned( state_engine, checked_ops, recipient )
    if num_names >= MAX_NAMES_PER_SENDER:
        log.debug("Recipient '%s' has exceeded quota" % recipient)
        return False

    # if multisig is not enabled in this epoch, and the recipient
    # address is a p2sh address, then reject the transaction.
    # this if for compatibility with 0.13
    if virtualchain.is_multisig_address( register_addr ) and not epoch_has_multisig( block_id ):
        log.debug("Multisig registration address %s, but this epoch (%s) does not support multisig" % (register_addr, get_epoch_number(block_id)))
        return False

    # get preorder...
    preorder = state_engine.get_name_preorder( name, sender, register_addr )
    old_name_rec = state_engine.get_name( name, include_expired=True )

    if preorder is not None:
        # Case 1(a-b): registering or re-registering from a preorder

        # can't be registered already 
        if state_engine.is_name_registered( name ):
            log.debug("Name '%s' is already registered" % name)
            return False 

        # name can't be registered if it was reordered before its namespace was ready
        if not namespace.has_key('ready_block') or preorder['block_number'] < namespace['ready_block']:
           log.debug("Name '%s' preordered before namespace '%s' was ready" % (name, namespace_id))
           return False

        # name must be preordered by the same sender
        if preorder['sender'] != sender:
           log.debug("Name '%s' was not preordered by %s" % (name, sender))
           return False

        # fee was included in the preorder
        if not 'op_fee' in preorder:
           log.debug("Name '%s' preorder did not pay the fee" % (name))
           return False

        name_fee = preorder['op_fee']
        preorder_hash = preorder['preorder_hash']
        preorder_block_number = preorder['block_number']
        fee_block_id = preorder_block_number

        # pass along the preorder
        state_create_put_preorder( nameop, preorder )

        if old_name_rec is None:
            # Case 1(a): registered for the first time ever 
            log.debug("Registering name '%s'" % name)
            name_block_number = preorder['block_number']
            state_create_put_prior_history( nameop, None )
        
        else:
            # Case 1(b): name expired, and is now re-registered
            log.debug("Re-registering name '%s'" % name )
        
            # push back preorder block number to the original preorder
            name_block_number = old_name_rec['block_number']
            transfer_send_block_id = old_name_rec['transfer_send_block_id']

            # re-registering
            prior_hist = prior_history_create( nameop, old_name_rec, preorder_block_number, state_engine, extra_backup_fields=['consensus_hash','preorder_hash','transfer_send_block_id','op_fee','last_creation_op']) 
            state_create_put_prior_history( nameop, prior_hist )


    elif state_engine.is_name_registered( name ):
        # Case 2: we're renewing

        # name must be owned by the recipient already
        if not state_engine.is_name_owner( name, recipient ):
            log.debug("Renew: Name '%s' is registered but not owned by recipient %s" % (name, recipient))
            return False

        # name must be owned by the sender
        if not state_engine.is_name_owner( name, sender ):
            log.debug("Renew: Name '%s' is registered but not owned by sender %s" % (name, sender))
            return False

        # fee borne by the renewal
        if not 'op_fee' in nameop:
            log.debug("Renew: Name '%s' is registered but renewal did not pay the fee" % (name))
            return False
        
        log.debug("Renewing name '%s'" % name )

        prev_name_rec = state_engine.get_name( name )
        
        first_registered = prev_name_rec['first_registered']
        preorder_block_number = prev_name_rec['preorder_block_number']
        name_block_number = prev_name_rec['block_number']
        name_fee = nameop['op_fee']
        preorder_hash = prev_name_rec['preorder_hash']
        transfer_send_block_id = prev_name_rec['transfer_send_block_id']
        fee_block_id = block_id
        opcode = "NAME_RENEWAL"     # will cause this operation to be re-checked under check_renewal()

        # pass along prior history 
        prior_hist = prior_history_create( nameop, old_name_rec, block_id, state_engine, extra_backup_fields=['consensus_hash','preorder_hash','transfer_send_block_id','op_fee','last_creation_op'])
        state_create_put_prior_history( nameop, prior_hist )
        state_create_put_preorder( nameop, None ) 

    else:
        # Case 3: has never existed, and not preordered
        log.debug("Name '%s' does not exist, or is not preordered by %s" % (name, sender))
        return False

    # check name fee
    name_without_namespace = get_name_from_fq_name( name )

    # fee must be high enough (either the preorder paid the right fee at the preorder block height,
    # or the renewal paid the right fee at the renewal height)
    if name_fee < price_name( name_without_namespace, namespace, fee_block_id ):
        log.debug("Name '%s' costs %s, but paid %s" % (name, price_name( name_without_namespace, namespace, block_id ), name_fee ))
        return False
  
    nameop['opcode'] = opcode
    nameop['op_fee'] = name_fee
    nameop['preorder_hash'] = preorder_hash
    nameop['importer'] = None
    nameop['importer_address'] = None
    nameop['consensus_hash'] = consensus_hash
    nameop['revoked'] = False
    nameop['namespace_block_number'] = namespace['block_number']
    nameop['first_registered'] = first_registered
    nameop['last_renewed'] = block_id
    nameop['preorder_block_number'] = preorder_block_number
    nameop['block_number'] = name_block_number

    # not consensus-bearing, but required for SNV
    nameop['transfer_send_block_id'] = transfer_send_block_id
    nameop['last_creation_op'] = NAME_PREORDER 

    # propagate new sender information
    nameop['sender'] = nameop['recipient']
    nameop['address'] = nameop['recipient_address']
    del nameop['recipient']
    del nameop['recipient_address']

    # regster/renewal
    return True
コード例 #3
0
ファイル: register.py プロジェクト: nokiam9/blockstack-core
def check_register( state_engine, nameop, block_id, checked_ops ):
    """
    Verify the validity of a registration nameop.
    * the name must be well-formed
    * the namespace must be ready
    * the name does not collide
    * either the name was preordered by the same sender, or the name exists and is owned by this sender (the name cannot be registered and owned by someone else)
    * the mining fee must be high enough.
    * if the name was expired, then merge the preorder information from the expired preorder (since this is a state-creating operation,
    we set the __preorder__ /* and __prior_history__ fields *./ to preserve this).

    NAME_REGISTRATION is not allowed during a namespace import, so the namespace must be ready.

    Return True if accepted.
    Return False if not.
    """

    from ..nameset import BlockstackDB 

    name = nameop['name']
    sender = nameop['sender']

    # address mixed into the preorder
    register_addr = nameop.get('recipient_address', None)
    if register_addr is None:
        log.debug("No registration address given")
        return False

    recipient = nameop.get('recipient', None)
    if recipient is None:
        log.debug("No recipient script given")
        return False

    if not is_name_valid(name):
        log.debug('Invalid name')
        return False

    epoch_features = get_epoch_features(block_id)

    name_fee = None
    namespace = None
    preorder_hash = None
    preorder_block_number = None 
    name_block_number = None
    consensus_hash = None
    fee_block_id = None         # block ID at which the fee was paid
    burn_address = None         # preorder/renew burn address
    opcode = nameop['opcode']
    first_registered = nameop['first_registered']

    # name must be well-formed
    if not is_b40( name ) or "+" in name or name.count(".") > 1:
        log.debug("Malformed name '%s': non-base-38 characters" % name)
        return False

    # name must not be revoked
    if state_engine.is_name_revoked( name ):
        log.debug("Name '%s' is revoked" % name)
        return False

    namespace_id = get_namespace_from_name( name )

    # namespace must exist and be ready
    if not state_engine.is_namespace_ready( namespace_id ):
        log.debug("Namespace '%s' is not ready" % namespace_id)
        return False

    # get namespace...
    namespace = state_engine.get_namespace( namespace_id )

    # cannot exceed quota
    num_names = get_num_names_owned( state_engine, checked_ops, recipient )
    if num_names >= MAX_NAMES_PER_SENDER:
        log.debug("Recipient '%s' has exceeded quota" % recipient)
        return False

    # if multisig is not enabled in this epoch, and the recipient
    # address is a p2sh address, then reject the transaction.
    # this if for compatibility with 0.13
    if virtualchain.is_multisig_address( register_addr ) and not epoch_has_multisig( block_id ):
        log.debug("Multisig registration address %s, but this epoch (%s) does not support multisig" % (register_addr, get_epoch_number(block_id)))
        return False

    # get preorder...
    preorder = state_engine.get_name_preorder( name, sender, register_addr )
    old_name_rec = state_engine.get_name( name, include_expired=True )

    # TODO: verify that the preorder is fresh.

    if preorder is not None:
        # Case 1(a-b): registering or re-registering from a preorder

        # can't be registered already 
        if state_engine.is_name_registered( name ):
            log.debug("Name '%s' is already registered" % name)
            return False 

        # name can't be registered if it was reordered before its namespace was ready
        if not namespace.has_key('ready_block') or preorder['block_number'] < namespace['ready_block']:
           log.debug("Name '%s' preordered before namespace '%s' was ready" % (name, namespace_id))
           return False

        # name must be preordered by the same sender
        if preorder['sender'] != sender:
           log.debug("Name '%s' was not preordered by %s" % (name, sender))
           return False

        # fee was included in the preorder
        if not 'op_fee' in preorder:
           log.debug("Name '%s' preorder did not pay the fee" % (name))
           return False

        name_fee = preorder['op_fee']
        preorder_hash = preorder['preorder_hash']
        preorder_block_number = preorder['block_number']
        fee_block_id = preorder_block_number
        burn_address = preorder['burn_address']

        # pass along the preorder
        state_create_put_preorder( nameop, preorder )

        if old_name_rec is None:
            # Case 1(a): registered for the first time ever 
            log.debug("Registering name '%s'" % name)
            name_block_number = preorder['block_number']
        
        else:
            # Case 1(b): name expired, and is now re-registered
            log.debug("Re-registering name '%s'" % name )
        
            # push back preorder block number to the original preorder
            name_block_number = old_name_rec['block_number']

    elif state_engine.is_name_registered( name ):
        # Case 2: we're renewing
        assert 'burn_address' in nameop, 'BUG: no burn address set in nameop'

        # pre F-day 2017: name must be owned by the recipient already
        # post F-day 2017: recipient can be anybody
        if EPOCH_FEATURE_OP_RENEW_TRANSFER_UPDATE not in epoch_features:
            # pre F-day 2017
            if not state_engine.is_name_owner( name, recipient ):
                log.debug("Renew: Name '%s' is registered but not owned by recipient %s" % (name, recipient))
                return False

        # name must be owned by the sender
        if not state_engine.is_name_owner( name, sender ):
            log.debug("Renew: Name '%s' is registered but not owned by sender %s" % (name, sender))
            return False

        # fee borne by the renewal
        if not 'op_fee' in nameop or nameop['op_fee'] is None:
            log.debug("Renew: Name '%s' is registered but renewal did not pay the fee" % (name))
            return False
        
        log.debug("Renewing name '%s'" % name )
        if not state_engine.is_name_owner( name, recipient ):
            log.debug("Transferring name '{}' to {}".format(name, recipient))

        prev_name_rec = state_engine.get_name( name )
        
        first_registered = prev_name_rec['first_registered']
        preorder_block_number = prev_name_rec['preorder_block_number']
        name_block_number = prev_name_rec['block_number']
        name_fee = nameop['op_fee']
        preorder_hash = prev_name_rec['preorder_hash']
        # transfer_send_block_id = prev_name_rec['transfer_send_block_id']
        fee_block_id = block_id

        burn_address = nameop['burn_address']
        opcode = "NAME_RENEWAL"     # will cause this operation to be re-checked under check_renewal()

        state_create_put_preorder( nameop, None ) 

    else:
        # Case 3: has never existed, and not preordered
        log.debug("Name '%s' does not exist, or is not preordered by %s" % (name, sender))
        return False

    assert name_fee is not None

    # check name fee
    name_without_namespace = get_name_from_fq_name( name )

    # fee must be high enough (either the preorder paid the right fee at the preorder block height,
    # or the renewal paid the right fee at the renewal height)
    if name_fee < price_name( name_without_namespace, namespace, fee_block_id ):
        log.debug("Name '%s' costs %s, but paid %s" % (name, price_name( name_without_namespace, namespace, block_id ), name_fee ))
        return False
 
    # fee must be paid to the right address, at the right time.
    # pre F-day 2017: this *must* be the burn address, and the namespace *must* be version 1
    # post F-day 2017: this *may* be the namespace creator's address
    if not check_burn_address(namespace, burn_address, fee_block_id):
        log.debug("Invalid burn address {}".format(burn_address))
        return False

    nameop['opcode'] = opcode
    nameop['op_fee'] = name_fee
    nameop['preorder_hash'] = preorder_hash
    nameop['importer'] = None
    nameop['importer_address'] = None
    nameop['consensus_hash'] = consensus_hash
    nameop['revoked'] = False
    nameop['namespace_block_number'] = namespace['block_number']
    nameop['first_registered'] = first_registered
    nameop['last_renewed'] = block_id
    nameop['preorder_block_number'] = preorder_block_number
    nameop['block_number'] = name_block_number

    # not consensus-bearing, but required for SNV
    # nameop['transfer_send_block_id'] = transfer_send_block_id
    nameop['last_creation_op'] = NAME_PREORDER 

    # propagate new sender information
    nameop['sender'] = nameop['recipient']
    nameop['address'] = nameop['recipient_address']
    del nameop['recipient']
    del nameop['recipient_address']

    value_hash = nameop['value_hash']

    if value_hash is not None:
        # deny value hash if we're not in an epoch that supports register/update in one nameop
        if opcode == 'NAME_REGISTRATION' and EPOCH_FEATURE_OP_REGISTER_UPDATE not in epoch_features:
            log.debug("Name '{}' has a zone file hash, but this is not supported in this epoch".format(nameop['name']))
            return False

        log.debug("Adding value hash {} for name '{}'".format(value_hash, nameop['name']))
        
    nameop['value_hash'] = value_hash

    if opcode == 'NAME_REGISTRATION' and 'burn_address' in nameop: 
        # not used in NAME_REGISTRATION (but is used in NAME_RENEWAL)
        del nameop['burn_address']

    # regster/renewal
    return True