ensure that a namespace preorder paid the right amount of STACKs when it is revealed (but only if we're in the STACKs epochs)

This commit is contained in:
Jude Nelson
2018-03-22 19:21:25 -04:00
parent 584293fc8a
commit 867834b409

View File

@@ -25,7 +25,7 @@ from ..config import *
from ..hashing import *
from ..scripts import *
from ..nameset import *
import traceback
from binascii import hexlify, unhexlify
import json
@@ -61,7 +61,7 @@ FIELDS = [
# fields this operation changes
# everything but the block number
MUTATE_FIELDS = filter( lambda f: f not in ["block_number"], FIELDS )
MUTATE_FIELDS = filter( lambda f: f not in ["block_number"], FIELDS ) + ['token_fee']
def namespacereveal_sanity_check( namespace_id, version, lifetime, coeff, base, bucket_exponents, nonalpha_discount, no_vowel_discount ):
"""
@@ -76,7 +76,7 @@ def namespacereveal_sanity_check( namespace_id, version, lifetime, coeff, base,
if len(namespace_id) > LENGTHS['blockchain_id_namespace_id']:
raise Exception("Invalid namespace ID length for '%s' (expected length between 1 and %s)" % (namespace_id, LENGTHS['blockchain_id_namespace_id']))
if version not in [NAMESPACE_VERSION_PAY_TO_BURN, NAMESPACE_VERSION_PAY_TO_CREATOR]:
if version not in [NAMESPACE_VERSION_PAY_TO_BURN, NAMESPACE_VERSION_PAY_TO_CREATOR, NAMESPACE_VERSION_PAY_WITH_STACKS]:
raise Exception("Invalid namespace version bits {:x}".format(version))
if lifetime < 0 or lifetime > (2**32 - 1):
@@ -171,7 +171,26 @@ def check( state_engine, nameop, block_id, checked_ops ):
# must be a version we support
# pre F-day 2017: only support names that send payment to the burn address
# post F-day 2017: support both pay-to-burn and pay-to-creator
# 2018 phase 1: support paying for names with STACKs tokens
namespace_version_bits = int(nameop['version'])
if namespace_version_bits == NAMESPACE_VERSION_PAY_TO_CREATOR:
# need to be in post F-day 2017 or later
if EPOCH_FEATURE_NAMESPACE_BURN_TO_CREATOR not in epoch_features:
log.debug("pay-to-creator is not supported in this epoch")
return False
elif namespace_version_bits == NAMESPACE_VERSION_PAY_WITH_STACKS:
# need to be in 2018 phase 1 or later
if EPOCH_FEATURE_NAMESPACE_PAY_WITH_STACKS not in epoch_features:
log.debug("pay-with-STACKs-tokens is not supported in this epoch")
return False
elif namespace_version_bits != NAMESPACE_VERSION_PAY_TO_BURN:
# not supported at all
log.debug("Unsupported namespace version {:x}".format(namespace_version_bits))
return False
'''
if EPOCH_FEATURE_NAMESPACE_BURN_TO_CREATOR in epoch_features:
# post F-day 2017
# can send to burn address or namespace preorder address
@@ -185,19 +204,54 @@ def check( state_engine, nameop, block_id, checked_ops ):
if namespace_version_bits != NAMESPACE_VERSION_PAY_TO_BURN:
log.debug("Namespace '%s' requires version %s, but this blockstack is version %s" % (namespace_id, nameop['version'], NAMESPACE_VERSION_PAY_TO_BURN))
return False
'''
units = get_epoch_namespace_price_units(block_id)
tokens_paid = 0
# check fee...
if not 'op_fee' in namespace_preorder:
log.debug("Namespace '%s' preorder did not pay the fee" % (namespace_id))
return False
if units == 'STACKS':
if EPOCH_FEATURE_STACKS_BUY_NAMESPACES not in epoch_features:
traceback.print_stack()
log.fatal("Namespaces must be bought in STACKs, but this epoch does not support it!")
os.abort()
namespace_fee = namespace_preorder['op_fee']
# must buy namespaces with STACKs
# how much did the NAMESPACE_PREORDER pay?
if not 'token_fee' in namespace_preorder:
log.debug("Namespace {} did not pay the token fee".format(namespace_id))
return False
# must have paid enough
if namespace_fee < price_namespace( namespace_id, block_id ):
# not enough money
log.debug("Namespace '%s' costs %s, but sender paid %s" % (namespace_id, price_namespace(namespace_id, block_id), namespace_fee ))
return False
tokens_paid = namespace_preorder['token_fee']
assert isinstance(tokens_paid, (int,long))
token_namespace_fee = price_namespace(namespace_id, block_id, units)
if token_namespace_fee is None:
log.debug("Invalid namespace ID {}".format(namespace_id))
return False
if tokens_paid < token_namespace_fee:
# not enough!
log.debug("Namespace buyer {} has {} tokens, but '{}' costs {} tokens".format(token_address, account_balance, token_name_fee))
return False
elif units == 'BTC':
# must buy namespaces with Bitcoin
# check fee...
if not 'op_fee' in namespace_preorder:
log.debug("Namespace '%s' preorder did not pay the fee" % (namespace_id))
return False
namespace_fee = namespace_preorder['op_fee']
# must have paid enough
if namespace_fee < price_namespace(namespace_id, block_id, units):
# not enough money
log.debug("Namespace '%s' costs %s, but sender paid %s" % (namespace_id, price_namespace(namespace_id, block_id), namespace_fee ))
return False
else:
traceback.print_stack()
log.fatal("Unknown payment unit {}".format(units))
os.abort()
# is this the first time this namespace has been revealed?
old_namespace = state_engine.get_namespace_op_state( namespace_id, block_id, include_expired=True )
@@ -208,7 +262,6 @@ def check( state_engine, nameop, block_id, checked_ops ):
# revealed for the first time
log.debug("Revealing for the first time: '%s'" % namespace_id)
namespace_block_number = namespace_preorder['block_number']
# state_create_put_prior_history( nameop, None )
else:
# revealed for the 2nd or later time
@@ -217,19 +270,16 @@ def check( state_engine, nameop, block_id, checked_ops ):
# push back preorder block number to the original preorder
namespace_block_number = old_namespace['block_number']
# re-revealing
# prior_hist = prior_history_create( nameop, old_namespace, preorder_block_number, state_engine, extra_backup_fields=['consensus_hash','preorder_hash'])
# state_create_put_prior_history( nameop, prior_hist )
# record preorder
nameop['block_number'] = namespace_block_number # namespace_preorder['block_number']
nameop['block_number'] = namespace_block_number
nameop['reveal_block'] = block_id
state_create_put_preorder( nameop, namespace_preorder )
# NOTE: not fed into the consensus hash, but necessary for database constraints:
nameop['ready_block'] = 0
nameop['op_fee'] = namespace_preorder['op_fee']
nameop['token_fee'] = '{}'.format(tokens_paid) # NOTE: avoids overflow
# can begin import
return True