def make_outputs( data, inputs, new_name_owner_address, change_address, tx_fee=0, pay_fee=True):
    """
    Builds the outputs for a name transfer operation.
    Raise ValueError if there are not enough inputs to make the transaction
    """
    
    dust_fee = None
    op_fee = None
    dust_value = DEFAULT_DUST_FEE
    
    if pay_fee:
        dust_fee = (len(inputs) + 2) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE + tx_fee
        op_fee = DEFAULT_DUST_FEE
    
    else:
        dust_fee = 0
        op_fee = 0
    
    return [
        # main output
        {"script": virtualchain.make_data_script(str(data)),
         "value": 0},
        # new name owner output
        {"script": virtualchain.make_payment_script(new_name_owner_address),
         "value": dust_value},
        # change output
        {"script": virtualchain.make_payment_script(change_address),
         "value": virtualchain.calculate_change_amount(inputs, op_fee, dust_fee)}
    ]
def make_outputs( data, inputs, change_addr, fee, tx_fee, pay_fee=True ):
    """
    Make outputs for a namespace preorder:
    [0] OP_RETURN with the name 
    [1] change address with the NAME_PREORDER sender's address
    [2] pay-to-address with the *burn address* with the fee
    Raise ValueError if there are not enough inputs to make the transaction
    """
    
    dust_fee = DEFAULT_OP_RETURN_FEE + (len(inputs) + 2) * DEFAULT_DUST_FEE + tx_fee
    op_fee = max(fee, DEFAULT_DUST_FEE)
    
    bill = op_fee
   
    if not pay_fee:
        # subsidized
        dust_fee = 0
        op_fee = 0
        bill = 0
    
    return [
        # main output
        {"script": virtualchain.make_data_script(str(data)),
         "value": 0},
        
        # change address
        {"script": virtualchain.make_payment_script( change_addr ),
         "value": virtualchain.calculate_change_amount(inputs, bill, dust_fee)},
        
        # burn address
        {"script": virtualchain.make_payment_script(BLOCKSTACK_BURN_ADDRESS),
         "value": op_fee}
    ]
def make_outputs( data, inputs, recipient_address, sender_address, update_hash_b58, tx_fee):
    """
    Builds the outputs for a name import:
    * [0] is the OP_RETURN 
    * [1] is the new owner (recipient)
    * [2] is the update hash
    * [3] is the change sent to the original owner

    Raise ValueError if there are not enough inputs to make the transaction
    """
    
    dust_fee = DEFAULT_OP_RETURN_FEE + (len(inputs) + 3) * DEFAULT_DUST_FEE + tx_fee
    op_fee = 2 * DEFAULT_DUST_FEE
    dust_value = DEFAULT_DUST_FEE
    
    return [
        # main output
        {"script": virtualchain.make_data_script(str(data)),
         "value": 0},
    
        # recipient output
        {"script": virtualchain.make_payment_script(recipient_address),
         "value": dust_value},
        
        # update hash output
        {"script": virtualchain.make_payment_script(update_hash_b58),
         "value": dust_value},
        
        # change output
        {"script": virtualchain.make_payment_script(sender_address),
         "value": virtualchain.calculate_change_amount(inputs, op_fee, dust_fee)}
    ]
def mktx( amt, tx_fee, recipient_addr, privkey, message=None ):
    """
    Make the transaction with the given fee
    """
    change_addr = virtualchain.BitcoinPrivateKey(privkey).public_key().address()
    inputs = testlib.get_unspents(change_addr)
    change = virtualchain.calculate_change_amount(inputs, amt, tx_fee)

    outputs = [
        {'script': virtualchain.make_payment_script(recipient_addr),
         'value': amt},
    ]

    if change > 0:
        # need change and tx fee
        outputs.append( 
            {'script': virtualchain.make_payment_script(change_addr),
              "value": change}
        )

    if message:
        outputs = [
            {"script": virtualchain.make_data_script(binascii.hexlify(message)),
             "value": 0} ] + outputs

    serialized_tx = blockstack_client.tx.serialize_tx(inputs, outputs)
    signed_tx = blockstack_client.tx.sign_tx(serialized_tx, privkey)
    return signed_tx
def mktx(satoshis, fee):

    outputs = None
    if satoshis is None:
        # send all
        satoshis = sum([u['value'] for u in utxos])

        print 'WARN: sending all of {} ({}) to {}'.format(payment_addr, satoshis, recipient_addr)

        outputs = [
            {'script': virtualchain.make_payment_script(payment_addr),
             'value': virtualchain.calculate_change_amount(utxos, 0, fee)},
        ]
        
    else:
        outputs = [
            {"script": virtualchain.make_payment_script(payment_addr),
             "value": satoshis},
        
            {"script": virtualchain.make_payment_script(recipient_addr),
             "value": virtualchain.calculate_change_amount(utxos, satoshis, fee)},
        ]

    txobj = {
        'ins': utxos,
        'outs': outputs,
        'locktime': 0,
        'version': 1
    }

    # log.debug("serialize tx: {}".format(json.dumps(txobj, indent=4, sort_keys=True)))
    txstr = virtualchain.btc_tx_serialize(txobj)
    signed_txstr = virtualchain.tx_sign_all_unsigned_inputs(privkey, utxos, txstr)
    return signed_txstr
def check( state_engine ):

    # not revealed, but ready 
    ns = state_engine.get_namespace_reveal( "test" )
    if ns is not None:
        return False 

    ns = state_engine.get_namespace( "test" )
    if ns is None:
        return False 

    if ns['namespace_id'] != 'test':
        return False 

    names = ['foo.test', 'bar.test', 'baz.test']
    name_preorder_wallets = [wallets[2], wallets[3], wallets[4]]
    name_register_wallets = [wallets[5], wallets[6], wallets[7]]
    name_transfer_wallets = [wallets[6], wallets[7], wallets[5]]

    for i in xrange(0, len(names)):

        name = names[i]
        name_preorder_wallet = name_preorder_wallets[i]
        name_register_wallet = name_register_wallets[i]
        name_transfer_wallet = name_transfer_wallets[i]

        # not preordered
        preorder = state_engine.get_name_preorder( name, virtualchain.make_payment_script(name_preorder_wallet.addr), name_register_wallet.addr )
        if preorder is not None:
            print "%s still preordered" % name
            return False
        
        # registered 
        name_rec = state_engine.get_name( name )
        if name_rec is None:
            print "not registered %s" % name
            return False 

        # updated, and data is gone (since revoked)
        if name_rec['value_hash'] is not None:
            print "invalid value hash %s: %s" % (name, name_rec['value_hash'])
            return False 

        # owned by the right transfer wallet 
        if name_rec['address'] != name_transfer_wallet.addr or name_rec['sender'] != virtualchain.make_payment_script(name_transfer_wallet.addr):
            print "%s owned by %s" % (name, name_transfer_wallet.addr)
            return False

        # revoked 
        if not name_rec['revoked']:
            print "%s not revoked" % name
            return False 

    return True
def make_transaction(name, preorder_addr, register_addr, fee, consensus_hash, blockchain_client, tx_fee=0, subsidize=False, safety=True):
    """
    Builds and broadcasts a preorder transaction.
    """

    preorder_addr = str(preorder_addr)
    register_addr = str(register_addr)
    name = str(name)
    consensus_hash = str(consensus_hash)
    fee = int(fee)
    tx_fee = int(tx_fee)

    assert is_name_valid(name)
    assert len(consensus_hash) == LENGTH_CONSENSUS_HASH * 2

    inputs = None
    private_key_obj = None
    script_pubkey = None    # to be mixed into preorder hash
    
    pay_fee = True
    if subsidize:
        pay_fee = False

    # tx only
    inputs = tx_get_unspents( preorder_addr, blockchain_client )
    if safety:
        assert len(inputs) > 0, "No UTXOs for {}".format(preorder_addr)
        
    script_pubkey = virtualchain.make_payment_script( preorder_addr )

    nulldata = build( name, script_pubkey, register_addr, consensus_hash)
    outputs = make_outputs(nulldata, inputs, preorder_addr, fee, tx_fee, pay_fee=pay_fee)
    
    return (inputs, outputs)
def check( state_engine ):

    # not revealed, but ready 
    ns = state_engine.get_namespace_reveal( "test" )
    if ns is not None:
        print "namespace reveal exists"
        return False 

    ns = state_engine.get_namespace( "test" )
    if ns is None:
        print "no namespace"
        return False 

    if ns['namespace_id'] != 'test':
        print "wrong namespace"
        return False 

    # not preordered
    preorder = state_engine.get_name_preorder( "foo.test", pybitcoin.make_pay_to_address_script(wallets[4].addr), wallets[3].addr, include_failed=True )
    if preorder is not None:
        print "preorder exists"
        return False
    
    # registered 
    name_rec_foo = state_engine.get_name( "foo.test" )
    if name_rec_foo is None:
        print "name does not exist"
        return False 

    # owned by
    if name_rec_foo['address'] != wallets[0].addr or name_rec_foo['sender'] != virtualchain.make_payment_script(wallets[0].addr):
        print "sender is wrong"
        return False 

    return True
def make_outputs( data, inputs, change_address, tx_fee, pay_fee=True ):
    """
    Make outputs for a revoke.
    Raise ValueError if there are not enough inputs to make the transaction
    """

    dust_fee = None
    op_fee = None
    dust_value = None 
    
    if pay_fee:
        dust_fee = (len(inputs) + 1) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE + tx_fee
        op_fee = DEFAULT_DUST_FEE
        dust_value = DEFAULT_DUST_FEE
    
    else:
        # will be subsidized
        dust_fee = 0
        op_fee = 0
        dust_value = 0
   
    return [
        # main output
        {"script": virtualchain.make_data_script(str(data)),
         "value": 0},
        
        # change output
        {"script": virtualchain.make_payment_script(change_address),
         "value": virtualchain.calculate_change_amount(inputs, op_fee, dust_fee)}
    ]
def make_transaction( namespace_id, register_addr, fee, consensus_hash, preorder_addr, blockchain_client, tx_fee=0, safety=True ):
   """
   Propagate a namespace.
   
   Arguments:
   namespace_id         human-readable (i.e. base-40) name of the namespace
   register_addr        the addr of the key that will reveal the namespace (mixed into the preorder to prevent name preimage attack races).  Must be a p2pkh address
   private_key          the Bitcoin address that created this namespace, and can populate it.
   """

   namespace_id = str(namespace_id)
   register_addr = str(register_addr)
   fee = int(fee)
   consensus_hash = str(consensus_hash)
   preorder_addr = str(preorder_addr)
   tx_fee = int(tx_fee)

   assert is_namespace_valid(namespace_id)
   assert len(consensus_hash) == LENGTH_CONSENSUS_HASH * 2
   assert keylib.b58check.b58check_version_byte( preorder_addr ) == virtualchain.version_byte, "Only p2pkh reveal addresses are supported (got {})".format(preorder_addr)

   script_pubkey = virtualchain.make_payment_script( preorder_addr )
   nulldata = build( namespace_id, script_pubkey, register_addr, consensus_hash )
   
   # get inputs and from address
   inputs = tx_get_unspents( preorder_addr, blockchain_client )
   if safety:
       assert len(inputs) > 0

   # build custom outputs here
   outputs = make_outputs(nulldata, inputs, preorder_addr, fee, tx_fee )
   
   return (inputs, outputs)
def check( state_engine ):

    global synchronized
    if not synchronized:
        print "not synchronized"
        return False

    # not revealed, but ready 
    ns = state_engine.get_namespace_reveal( "test" )
    if ns is not None:
        print "namespace not ready"
        return False 

    ns = state_engine.get_namespace( "test" )
    if ns is None:
        print "no namespace"
        return False 

    if ns['namespace_id'] != 'test':
        print "wrong namespace"
        return False 

    for i in xrange(0, 10):
        name = 'foo_{}.test'.format(i)
        # not preordered
        preorder = state_engine.get_name_preorder( name, virtualchain.make_payment_script(wallets[2].addr), wallets[3].addr )
        if preorder is not None:
            print "still have preorder"
            return False
        
        # registered 
        name_rec = state_engine.get_name( name )
        if name_rec is None:
            print "name does not exist"
            return False 

        # owned 
        if name_rec['address'] != wallets[3].addr or name_rec['sender'] != virtualchain.make_payment_script(wallets[3].addr):
            print "name has wrong owner"
            return False 

        # updated 
        if name_rec['value_hash'] is None:
            print "wrong value hash: %s" % name_rec['value_hash']
            return False 

    return True
def check( state_engine ):

    global zonefile_hash

    # not revealed, but ready 
    ns = state_engine.get_namespace_reveal( "test" )
    if ns is not None:
        print "namespace reveal exists"
        return False 

    ns = state_engine.get_namespace( "test" )
    if ns is None:
        print "no namespace"
        return False 

    if ns['namespace_id'] != 'test':
        print "wrong namespace"
        return False 
    
    # registered 
    name_rec = state_engine.get_name( "foo.test" )
    if name_rec is None:
        print "name does not exist"
        return False 

    # revoked
    if not name_rec['revoked']:
        print "not revoked"
        return False

    # owned by
    owner_address = wallets[4].addr
    if name_rec['address'] != owner_address or name_rec['sender'] != virtualchain.make_payment_script(owner_address):
        print "sender is wrong"
        return False 

    # no zonefile hash
    if name_rec['value_hash'] is not None:
        print "still have value hash"
        return False

    # doesn't show up in listing
    names_owned = testlib.blockstack_cli_names()
    if 'error' in names_owned:
        print "rpc names: %s" % names_owned['error']
        return False

    if len(names_owned['names_owned']) != 0:
        print "owned: %s" % names_owned['names_owned']
        return False

    # all queues are drained 
    queue_info = testlib.blockstack_client_queue_state()
    if len(queue_info) > 0:
        print "Still in queue:\n%s" % json.dumps(queue_info, indent=4, sort_keys=True)
        return False

    return True
def check( state_engine ):

    global wallet_keys, error, index_file_data, resource_data
    
    config_path = os.environ.get("BLOCKSTACK_CLIENT_CONFIG")
    assert config_path

    if error:
        print "Key operation failed."
        return False

    # not revealed, but ready 
    ns = state_engine.get_namespace_reveal( "test" )
    if ns is not None:
        print "namespace not ready"
        return False 

    ns = state_engine.get_namespace( "test" )
    if ns is None:
        print "no namespace"
        return False 

    if ns['namespace_id'] != 'test':
        print "wrong namespace"
        return False 

    names = ['foo.test', 'bar.test']
    wallet_keys_list = [wallet_keys]
    test_proxy = testlib.TestAPIProxy()
    
    owners = [3, 4]

    for i in xrange(0, len(names)):
        name = names[i]
        wallet_payer = 5
        wallet_owner = owners[i]
        wallet_data_pubkey = 4

        # not preordered
        preorder = state_engine.get_name_preorder( name, virtualchain.make_payment_script(wallets[wallet_payer].addr), wallets[wallet_owner].addr )
        if preorder is not None:
            print "still have preorder"
            return False
    
        # registered 
        name_rec = state_engine.get_name( name )
        if name_rec is None:
            print "name does not exist"
            return False 

        # owned 
        if name_rec['address'] != wallets[wallet_owner].addr or name_rec['sender'] != virtualchain.make_payment_script(wallets[wallet_owner].addr):
            print "name {} has wrong owner".format(name)
            return False 

    return True
def check( state_engine ):

    # not revealed, but ready 
    ns = state_engine.get_namespace_reveal( "test" )
    if ns is not None:
        print "namespace reveal exists"
        return False 

    ns = state_engine.get_namespace( "test" )
    if ns is None:
        print "no namespace"
        return False 

    if ns['namespace_id'] != 'test':
        print "wrong namespace"
        return False 
   
    names = ['foo.test', 'bar.test', 'baz.test', 'goo.test']
    addresses = [wallets[2].addr, wallets[3].addr, wallets[4].addr, wallets[5].addr]
    zonefiles = ["Hello foo.test!", "Hello bar.test!", "Hello baz.test!", "Hello goo.test!"]

    for i in xrange(0, len(names)):
        name = names[i]
        owner_address = addresses[i]
        zonefile = zonefiles[i]

        # registered 
        name_rec = state_engine.get_name( name )
        if name_rec is None:
            print "name {} does not exist".format(name)
            return False 

        # owned by the right address 
        if name_rec['address'] != owner_address or name_rec['sender'] != virtualchain.make_payment_script(owner_address):
            print "sender is wrong for {}".format(name)
            return False 

        # has the right zone file
        zf = testlib.blockstack_get_zonefile(name_rec['value_hash'], parse=False)
        if zf is None:
            print "no zonefile for {}".format(name)
            return False

        if zf != zonefile:
            print "zonefile mismatch: expected {}, got {}".format(zonefile, zf)
            return False

    # all queues are drained 
    queue_info = testlib.blockstack_client_queue_state()
    if len(queue_info) > 0:
        print "Still in queue:\n%s" % json.dumps(queue_info, indent=4, sort_keys=True)
        return False

    return True
def check( state_engine ):

    global zonefile_hash

    # not revealed, but ready 
    ns = state_engine.get_namespace_reveal( "test" )
    if ns is not None:
        print "namespace reveal exists"
        return False 

    ns = state_engine.get_namespace( "test" )
    if ns is None:
        print "no namespace"
        return False 

    if ns['namespace_id'] != 'test':
        print "wrong namespace"
        return False 
    
    # registered 
    name_rec = state_engine.get_name( "foo.test" )
    if name_rec is None:
        print "name does not exist"
        return False 

    # owned by
    owner_address = wallets[3].addr
    if name_rec['address'] != owner_address or name_rec['sender'] != virtualchain.make_payment_script(owner_address):
        print "sender is wrong"
        return False 

    # value hash 
    if name_rec['value_hash'] != zonefile_hash:
        print "wrong zonefile hash: %s != %s" % (name_rec['value_hash'], zonefile_hash)
        return False

    # replicated?
    zonefile = testlib.blockstack_get_zonefile( zonefile_hash )
    if 'error' in zonefile:
        print "zonefile error: %s" % zonefile['error']
        return False

    # right hash?
    if blockstack_client.hash_zonefile( zonefile ) != zonefile_hash:
        print "wrong zonefile: %s != %s" % (blockstack_client.hash_zonefile(zonefile), zonefile_hash)
        return False

    # all queues are drained 
    queue_info = testlib.blockstack_client_queue_state()
    if len(queue_info) > 0:
        print "Still in queue:\n%s" % json.dumps(queue_info, indent=4, sort_keys=True)
        return False

    return True
def check( state_engine ):

    # not revealed, but ready 
    ns = state_engine.get_namespace_reveal( "test" )
    if ns is not None:
        return False 

    ns = state_engine.get_namespace( "test" )
    if ns is None:
        return False 

    if ns['namespace_id'] != 'test':
        return False 

    names = ['foo.test', 'bar.test', 'baz.test']
    name_preorder_wallets = [wallets[2], wallets[3], wallets[4]]
    name_register_wallets = [wallets[5], wallets[6], wallets[7]]
    name_transfer_wallets = [wallets[6], wallets[7], wallets[5]]

    for i in xrange(0, len(names)):

        name = names[i]
        name_preorder_wallet = name_preorder_wallets[i]
        name_register_wallet = name_register_wallets[i]
        name_transfer_wallet = name_transfer_wallets[i]

        # not preordered
        preorder = state_engine.get_name_preorder( name, pybitcoin.make_pay_to_address_script(name_preorder_wallet.addr), name_register_wallet.addr )
        if preorder is not None:
            return False
        
        # registered 
        name_rec = state_engine.get_name( name )
        if name_rec is None:
            return False 

        # data is gone
        if name_rec['value_hash'] is not None:
            return False 

        # owned by the right transfer wallet 
        if name_rec['address'] != name_transfer_wallet.addr or name_rec['sender'] != virtualchain.make_payment_script(name_transfer_wallet.addr):
            return False

        # renewed 
        if name_rec['last_renewed'] == name_rec['first_registered']:
            return False 

        # revoked 
        if not name_rec['revoked']:
            return False 

    return True
def check( state_engine ):

    # not revealed, but ready 
    ns = state_engine.get_namespace_reveal( "test" )
    if ns is not None:
        print "'test' not revealed"
        return False 

    ns = state_engine.get_namespace( "test" )
    if ns is None:
        print "'test' not found"
        return False 

    if ns['namespace_id'] != 'test':
        print "'test' not returned"
        return False 

    # not preordered
    preorder = state_engine.get_name_preorder( "foo.test", virtualchain.make_payment_script(wallets[2].addr), wallets[3].addr )
    if preorder is not None:
        print "'foo.test' still preordered"
        return False
    
    # registered 
    name_rec = state_engine.get_name( "foo.test" )
    if name_rec is None:
        print "'foo.test' not registered"
        return False 

    # updated, and data is preserved
    if name_rec['value_hash'] != '11' * 20:
        print "'foo.test' invalid value hash"
        return False 

    # transferred 
    if name_rec['address'] != wallets[4].addr or name_rec['sender'] != virtualchain.make_payment_script(wallets[4].addr):
        print "'foo.test' invalid owner"
        return False 

    return True
def make_outputs( nulldata, inputs, change_addr, tx_fee=0 ):
   """
   Make namespace-ready outputs
   """
   return [
        { "script": virtualchain.make_data_script(str(nulldata)),
          "value": 0
        },
        # change output
        { "script": virtualchain.make_payment_script(change_addr),
          "value": virtualchain.calculate_change_amount(inputs, 0, tx_fee + DEFAULT_OP_RETURN_FEE)
        }
    ]
def check(state_engine):

    # not revealed, but ready
    ns = state_engine.get_namespace_reveal("test")
    if ns is not None:
        print "namespace reveal exists"
        return False

    ns = state_engine.get_namespace("test")
    if ns is None:
        print "no namespace"
        return False

    if ns['namespace_id'] != 'test':
        print "wrong namespace"
        return False

    # not preordered
    preorder = state_engine.get_name_preorder(
        "foo.test", virtualchain.make_payment_script(wallets[2].addr),
        wallets[3].addr)
    if preorder is not None:
        print "preorder exists"
        return False

    # registered
    name_rec = state_engine.get_name("foo.test")
    if name_rec is None:
        print "name does not exist"
        return False

    # owned by
    if name_rec['address'] != wallets[3].addr or name_rec[
            'sender'] != virtualchain.make_payment_script(wallets[3].addr):
        print "sender is wrong"
        return False

    return True
예제 #20
0
def check(state_engine):

    # not revealed, but ready
    ns = state_engine.get_namespace_reveal("test")
    if ns is not None:
        return False

    ns = state_engine.get_namespace("test")
    if ns is None:
        return False

    if ns['namespace_id'] != 'test':
        return False

    for i in xrange(1, 4):
        name = 'foo{}.test'.format(i)

        # not preordered
        preorder = state_engine.get_name_preorder(
            name, virtualchain.make_payment_script(wallets[2].addr),
            wallets[3].addr)
        if preorder is not None:
            print 'still have preorder: {}'.format(preorder)
            return False

        # registered
        name_rec = state_engine.get_name(name)
        if name_rec is None:
            print 'did not get name {}'.format(name)
            return False

        # owned by
        if name_rec['address'] != wallets[3].addr or name_rec[
                'sender'] != virtualchain.make_payment_script(wallets[3].addr):
            print 'wrong address for {}: {}'.format(name, name_rec)
            return False

    return True
예제 #21
0
def make_transaction(name,
                     preorder_addr,
                     register_addr,
                     fee,
                     consensus_hash,
                     blockchain_client,
                     tx_fee=0,
                     subsidize=False,
                     safety=True,
                     min_payment_confs=TX_MIN_CONFIRMATIONS):
    """
    Builds and broadcasts a preorder transaction.
    """

    preorder_addr = str(preorder_addr)
    register_addr = str(register_addr)
    name = str(name)
    consensus_hash = str(consensus_hash)
    fee = int(fee)
    tx_fee = int(tx_fee)

    assert is_name_valid(name)
    assert len(consensus_hash) == LENGTH_CONSENSUS_HASH * 2

    inputs = None
    private_key_obj = None
    script_pubkey = None  # to be mixed into preorder hash

    pay_fee = True
    if subsidize:
        pay_fee = False

    # tx only
    inputs = tx_get_unspents(preorder_addr,
                             blockchain_client,
                             min_confirmations=min_payment_confs)
    if safety:
        assert len(inputs) > 0, "No UTXOs for {}".format(preorder_addr)

    script_pubkey = virtualchain.make_payment_script(preorder_addr)

    nulldata = build(name, script_pubkey, register_addr, consensus_hash)
    outputs = make_outputs(nulldata,
                           inputs,
                           preorder_addr,
                           fee,
                           tx_fee,
                           pay_fee=pay_fee)

    return (inputs, outputs)
def check(state_engine):

    global zonefile_hash

    # not revealed, but ready
    ns = state_engine.get_namespace_reveal("test")
    if ns is not None:
        print "namespace reveal exists"
        return False

    ns = state_engine.get_namespace("test")
    if ns is None:
        print "no namespace"
        return False

    if ns['namespace_id'] != 'test':
        print "wrong namespace"
        return False

    # registered
    name_rec = state_engine.get_name("foo.test")
    if name_rec is None:
        print "name does not exist"
        return False

    # owned by
    owner_address = wallets[4].addr
    if name_rec['address'] != owner_address or name_rec[
            'sender'] != virtualchain.make_payment_script(owner_address):
        print "sender is wrong"
        return False

    # all queues are drained
    queue_info = testlib.blockstack_client_queue_state()
    if len(queue_info) > 0:
        print "Still in queue:\n%s" % json.dumps(
            queue_info, indent=4, sort_keys=True)
        return False

    # doesn't show up in listing
    names_owned = testlib.blockstack_cli_names()
    if 'error' in names_owned:
        print "rpc names: %s" % names_owned['error']
        return False

    if len(names_owned['names_owned']) > 0:
        print "still owned: %s" % names_owned['names_owned']
        return False

    return True
예제 #23
0
def mktx(satoshis, fee):

    outputs = None
    if satoshis is None:
        # send all
        satoshis = sum([u['value'] for u in utxos])

        print 'WARN: sending all of {} ({}) to {}'.format(
            payment_addr, satoshis, recipient_addr)

        outputs = [
            {
                'script': virtualchain.make_payment_script(payment_addr),
                'value': virtualchain.calculate_change_amount(utxos, 0, fee)
            },
        ]

    else:
        outputs = [
            {
                "script": virtualchain.make_payment_script(payment_addr),
                "value": satoshis
            },
            {
                "script": virtualchain.make_payment_script(recipient_addr),
                "value":
                virtualchain.calculate_change_amount(utxos, satoshis, fee)
            },
        ]

    txobj = {'ins': utxos, 'outs': outputs, 'locktime': 0, 'version': 1}

    # log.debug("serialize tx: {}".format(json.dumps(txobj, indent=4, sort_keys=True)))
    txstr = virtualchain.btc_tx_serialize(txobj)
    signed_txstr = virtualchain.tx_sign_all_unsigned_inputs(
        privkey, utxos, txstr)
    return signed_txstr
예제 #24
0
def check(state_engine):

    global last_first_block, first_preorder

    # not revealed, but ready
    ns = state_engine.get_namespace_reveal("test")
    if ns is not None:
        return False

    ns = state_engine.get_namespace("test")
    if ns is None:
        return False

    if ns['namespace_id'] != 'test':
        return False

    # not preordered
    preorder = state_engine.get_name_preorder(
        "foo.test", virtualchain.make_payment_script(wallets[2].addr),
        wallets[3].addr)
    if preorder is not None:
        return False

    # not preordered
    preorder = state_engine.get_name_preorder(
        "foo.test", virtualchain.make_payment_script(wallets[3].addr),
        wallets[4].addr)
    if preorder is not None:
        return False

    # not registered
    name_rec = state_engine.get_name("foo.test")
    if name_rec is not None:
        print 'registered by accident'
        return False

    return True
예제 #25
0
def check( state_engine ):

    # not revealed, but ready 
    ns = state_engine.get_namespace_reveal( "test" )
    if ns is not None:
        return False 

    ns = state_engine.get_namespace( "test" )
    if ns is None:
        return False 

    if ns['namespace_id'] != 'test':
        return False 

    # all preordered
    preorder = state_engine.get_name_preorder( "foo.test", virtualchain.make_payment_script(wallets[2].addr), wallets[3].addr )
    if preorder is None:
        return False
    
    preorder = state_engine.get_name_preorder( "foo.test", virtualchain.make_payment_script(wallets[4].addr), wallets[5].addr )
    if preorder is None:
        return False 

    preorder = state_engine.get_name_preorder( "foo.test", virtualchain.make_payment_script(wallets[0].addr), wallets[1].addr )
    if preorder is None:
        return False
    
    preorder = state_engine.get_name_preorder( "foo.test", virtualchain.make_payment_script(wallets[5].addr), wallets[2].addr )
    if preorder is None:
        return False
    
    # neone registered 
    name = state_engine.get_name( "foo.test" )
    if name is not None:
        return False 

    return True
예제 #26
0
def check( state_engine ):

    global owner_address, payment_address

    # not revealed, but ready 
    ns = state_engine.get_namespace_reveal( "test" )
    if ns is not None:
        print "namespace not ready"
        return False 

    ns = state_engine.get_namespace( "test" )
    if ns is None:
        print "no namespace"
        return False 

    if ns['namespace_id'] != 'test':
        print "wrong namespace"
        return False 

    # not preordered
    preorder = state_engine.get_name_preorder( "foo.test", virtualchain.make_payment_script(payment_address), owner_address )
    if preorder is not None:
        print "still have preorder"
        return False
    
    # registered 
    name_rec = state_engine.get_name( "foo.test" )
    if name_rec is None:
        print "name does not exist"
        return False 

    # owned 
    if name_rec['address'] != owner_address or name_rec['sender'] != virtualchain.make_payment_script(owner_address):
        print "name has wrong owner"
        return False 

    return True
def check( state_engine ):

    global owner_address, payment_address

    # not revealed, but ready 
    ns = state_engine.get_namespace_reveal( "test" )
    if ns is not None:
        print "namespace not ready"
        return False 

    ns = state_engine.get_namespace( "test" )
    if ns is None:
        print "no namespace"
        return False 

    if ns['namespace_id'] != 'test':
        print "wrong namespace"
        return False 

    # not preordered
    preorder = state_engine.get_name_preorder( "foo.test", virtualchain.make_payment_script(payment_address), owner_address )
    if preorder is not None:
        print "still have preorder"
        return False
    
    # registered 
    name_rec = state_engine.get_name( "foo.test" )
    if name_rec is None:
        print "name does not exist"
        return False 

    # owned 
    if name_rec['address'] != owner_address or name_rec['sender'] != virtualchain.make_payment_script(owner_address):
        print "name has wrong owner"
        return False 

    return True
def check( state_engine ):

    global first_name_block 

    # not revealed, but ready 
    ns = state_engine.get_namespace_reveal( "test" )
    if ns is not None:
        return False 

    ns = state_engine.get_namespace( "test" )
    if ns is None:
        return False 

    if ns['namespace_id'] != 'test':
        return False 

    # not preordered 
    for i in xrange(0, len(wallets)):
        preorder = state_engine.get_name_preorder( "foo.test", virtualchain.make_payment_script(wallets[i].addr), wallets[(i+1)%5].addr )
        if preorder is not None:
            print "preordered"
            return False
    
    # this is still preordered under this address
    preorder = state_engine.get_name_preorder( "foo.test", virtualchain.make_payment_script(wallets[3].addr), wallets[0].addr )
    if preorder is not None:
        print 'not preordered'
        return False

    # not registered 
    name_rec = state_engine.get_name( "foo.test" )
    if name_rec is not None:
        print "name still registered"
        return False 

    return True
예제 #29
0
def make_outputs(data, inputs, sender_addr, fee, tx_fee):
    """
    Make outputs for a name preorder:
    [0] OP_RETURN with the name 
    [1] address with the NAME_PREORDER sender's address
    [2] pay-to-address with the *burn address* with the fee
    Raise ValueError if there are not enough inputs to make the transaction
    """

    op_fee = max(fee, DEFAULT_DUST_FEE)
    dust_fee = (len(inputs) +
                2) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE + tx_fee
    dust_value = DEFAULT_DUST_FEE

    bill = op_fee

    return [
        # main output
        {
            "script_hex": make_op_return_script(str(data), format='hex'),
            "value": 0
        },

        # change address (can be subsidy key)
        {
            "script_hex": virtualchain.make_payment_script(sender_addr),
            "value": calculate_change_amount(inputs, bill, dust_fee)
        },

        # burn address
        {
            "script_hex":
            virtualchain.make_payment_script(BLOCKSTACK_BURN_ADDRESS),
            "value": op_fee
        }
    ]
def check(state_engine):

    # not revealed, but ready
    ns = state_engine.get_namespace_reveal("test")
    if ns is not None:
        return False

    ns = state_engine.get_namespace("test")
    if ns is None:
        return False

    if ns['namespace_id'] != 'test':
        return False

    # not preordered
    preorder = state_engine.get_name_preorder(
        "foo.test", virtualchain.make_payment_script(wallets[2].addr),
        wallets[3].addr)
    if preorder is not None:
        return False

    # registered
    name_rec = state_engine.get_name("foo.test")
    if name_rec is None:
        return False

    # owned
    if name_rec['address'] != wallets[3].addr or name_rec[
            'sender'] != virtualchain.make_payment_script(wallets[3].addr):
        return False

    # updated, but not the stale update hash
    if name_rec['value_hash'] != '11' * 20:
        return False

    return True
예제 #31
0
def make_outputs(nulldata, inputs, change_addr, fee=0, format='bin'):
    """
   Make namespace-ready outputs
   """
    return [
        {
            "script_hex": make_op_return_script(nulldata, format=format),
            "value": 0
        },
        # change output
        {
            "script_hex": virtualchain.make_payment_script(change_addr),
            "value": calculate_change_amount(inputs, 0, fee)
        }
    ]
예제 #32
0
def make_outputs( data, inputs, sender_addr, burn_addr, fee, tx_fee, pay_fee=True ):
    """
    Make outputs for a name preorder:
    [0] OP_RETURN with the name 
    [1] address with the NAME_PREORDER sender's address
    [2] pay-to-address with the *burn address* with the fee
    Raise ValueError if there are not enough inputs to make the transaction
    """
    
    op_fee = max(fee, DEFAULT_DUST_FEE)
    dust_fee = (len(inputs) + 2) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE + tx_fee
    dust_value = DEFAULT_DUST_FEE
     
    bill = 0

    if pay_fee:
        bill = op_fee

    else:
        op_fee = 0
        bill = 0
        dust_fee = 0
    
    return [
        # main output
        {"script": virtualchain.make_data_script(str(data)),
         "value": 0},
        
        # change address (can be subsidy key)
        {"script": virtualchain.make_payment_script(str(sender_addr)),
         "value": virtualchain.calculate_change_amount(inputs, bill, dust_fee)},
        
        # burn address
        {"script": virtualchain.make_payment_script(str(burn_addr)),
         "value": op_fee}
    ]
예제 #33
0
def make_outputs( data, inputs, reveal_addr, change_addr, tx_fee):
    """
    Make outputs for a register:
    [0] OP_RETURN with the name 
    [1] pay-to-address with the *reveal_addr*, not the sender's address.
    [2] change address with the NAMESPACE_PREORDER sender's address
    Raise ValueError if there are not enough inputs to make the transaction
    """
    
    total_to_send = DEFAULT_OP_RETURN_FEE + DEFAULT_DUST_FEE
    
    return [
        # main output
        {"script": virtualchain.make_data_script(str(data)),
         "value": 0},
    
        # register address
        {"script": virtualchain.make_payment_script(reveal_addr),
         "value": DEFAULT_DUST_FEE},
        
        # change address
        {"script": virtualchain.make_payment_script(change_addr),
         "value": virtualchain.calculate_change_amount(inputs, total_to_send, DEFAULT_DUST_FEE * (len(inputs) + 2) + DEFAULT_OP_RETURN_FEE + tx_fee)},
    ]
예제 #34
0
def check(state_engine):

    global zonefile_hash

    # not revealed, but ready
    ns = state_engine.get_namespace_reveal("test")
    if ns is not None:
        print "namespace reveal exists"
        return False

    ns = state_engine.get_namespace("test")
    if ns is None:
        print "no namespace"
        return False

    if ns['namespace_id'] != 'test':
        print "wrong namespace"
        return False

    # registered but revoked
    name_rec = state_engine.get_name("foo.test")
    if name_rec is None:
        print "name doesn't exist"
        return False

    if not name_rec['revoked']:
        print "name not revoked"
        return False

    # owned by
    owner_address = wallets[3].addr
    if name_rec['address'] != owner_address or name_rec[
            'sender'] != virtualchain.make_payment_script(owner_address):
        print "sender is wrong"
        return False

    if name_rec['value_hash'] is not None:
        print "still have zonefile"
        return False

    # all queues are drained
    queue_info = testlib.ysi_client_queue_state()
    if len(queue_info) > 0:
        print "Still in queue:\n%s" % json.dumps(
            queue_info, indent=4, sort_keys=True)
        return False

    return True
def check(state_engine):

    # not revealed, but ready
    ns = state_engine.get_namespace_reveal("test")
    if ns is not None:
        print "'test' not revealed"
        return False

    ns = state_engine.get_namespace("test")
    if ns is None:
        print "'test' not found"
        return False

    if ns['namespace_id'] != 'test':
        print "'test' not returned"
        return False

    # not preordered
    preorder = state_engine.get_name_preorder(
        "foo.test", virtualchain.make_payment_script(wallets[2].addr),
        wallets[3].addr)
    if preorder is not None:
        print "'foo.test' still preordered"
        return False

    # registered
    name_rec = state_engine.get_name("foo.test")
    if name_rec is None:
        print "'foo.test' not registered"
        return False

    # renewed
    if name_rec['last_renewed'] <= name_rec['first_registered']:
        print "not renewed"
        return False

    # updated, and data is preserved
    if name_rec['value_hash'] != '11' * 20:
        print "'foo.test' invalid value hash"
        return False

    # transferred
    if name_rec['address'] != wallets[4].addr:
        print "'foo.test' invalid owner"
        return False

    return True
def check(state_engine):

    global snv_block_id, last_consensus

    # not revealed, but ready
    ns = state_engine.get_namespace_reveal("test")
    if ns is not None:
        return False

    ns = state_engine.get_namespace("test")
    if ns is None:
        return False

    if ns['namespace_id'] != 'test':
        return False

    # not preordered
    preorder = state_engine.get_name_preorder(
        "foo.test", virtualchain.make_payment_script(wallets[2].addr),
        wallets[3].addr)
    if preorder is not None:
        return False

    # not registered
    name_rec = state_engine.get_name("foo.test")
    if name_rec is not None:
        print "Not expired:"
        print json.dumps(name_rec, indent=4)
        return False

    #  snv lookup works
    test_proxy = testlib.TestAPIProxy()
    ysi_client.set_default_proxy(test_proxy)

    snv_rec = ysi_client.snv_lookup("foo.test",
                                    snv_block_id,
                                    last_consensus,
                                    proxy=test_proxy)
    if 'error' in snv_rec:
        print json.dumps(snv_rec, indent=4)
        print "Expected (%s, %s) from (%s, %s)" % (snv_block_id, snv_consensus,
                                                   lastblock, lastconsensus)
        return False

    print snv_rec
    return True
예제 #37
0
def make_outputs(nulldata, inputs, change_addr, tx_fee=0):
    """
   Make namespace-ready outputs
   """
    return [
        {
            "script": virtualchain.make_data_script(str(nulldata)),
            "value": 0
        },
        # change output
        {
            "script":
            virtualchain.make_payment_script(change_addr),
            "value":
            virtualchain.calculate_change_amount(
                inputs, 0, tx_fee + DEFAULT_OP_RETURN_FEE)
        }
    ]
예제 #38
0
def tx_make_subsidization_output(payer_utxo_inputs, payer_address, op_fee, dust_fee):
    """
    Given the set of utxo inputs for both the client and payer, as well as the client's
    desired tx outputs, generate the inputs and outputs that will cause the payer to pay
    the operation's fees and dust fees.

    The client should send its own address as an input, with the same amount of BTC as the output.

    Return the payer output to include in the transaction on success, which should pay for the operation's
    fee and dust.

    Raise ValueError it here aren't enough inputs to subsidize
    """

    return {
        'script': virtualchain.make_payment_script(payer_address),
        'value': virtualchain.calculate_change_amount(payer_utxo_inputs, op_fee, int(round(dust_fee)))
    }
def tx_make_subsidization_output(payer_utxo_inputs, payer_address, op_fee, dust_fee):
    """
    Given the set of utxo inputs for both the client and payer, as well as the client's
    desired tx outputs, generate the inputs and outputs that will cause the payer to pay
    the operation's fees and dust fees.

    The client should send its own address as an input, with the same amount of BTC as the output.

    Return the payer output to include in the transaction on success, which should pay for the operation's
    fee and dust.

    Raise ValueError it here aren't enough inputs to subsidize
    """

    return {
        'script': virtualchain.make_payment_script(payer_address),
        'value': virtualchain.calculate_change_amount(payer_utxo_inputs, op_fee, int(round(dust_fee)))
    }
예제 #40
0
def make_transaction(namespace_id,
                     register_addr,
                     fee,
                     consensus_hash,
                     preorder_addr,
                     blockchain_client,
                     tx_fee=0,
                     safety=True):
    """
   Propagate a namespace.
   
   Arguments:
   namespace_id         human-readable (i.e. base-40) name of the namespace
   register_addr        the addr of the key that will reveal the namespace (mixed into the preorder to prevent name preimage attack races).  Must be a p2pkh address
   private_key          the Bitcoin address that created this namespace, and can populate it.
   """

    namespace_id = str(namespace_id)
    register_addr = str(register_addr)
    fee = int(fee)
    consensus_hash = str(consensus_hash)
    preorder_addr = str(preorder_addr)
    tx_fee = int(tx_fee)

    assert is_namespace_valid(namespace_id)
    assert len(consensus_hash) == LENGTH_CONSENSUS_HASH * 2
    assert keylib.b58check.b58check_version_byte(
        preorder_addr
    ) == virtualchain.version_byte, "Only p2pkh reveal addresses are supported (got {})".format(
        preorder_addr)

    script_pubkey = virtualchain.make_payment_script(preorder_addr)
    nulldata = build(namespace_id, script_pubkey, register_addr,
                     consensus_hash)

    # get inputs and from address
    inputs = tx_get_unspents(preorder_addr, blockchain_client)
    if safety:
        assert len(inputs) > 0

    # build custom outputs here
    outputs = make_outputs(nulldata, inputs, preorder_addr, fee, tx_fee)

    return (inputs, outputs)
예제 #41
0
def check(state_engine):

    # not revealed, but ready
    ns = state_engine.get_namespace_reveal("test")
    if ns is not None:
        return False

    ns = state_engine.get_namespace("test")
    if ns is None:
        return False

    if ns['namespace_id'] != 'test':
        return False

    # not preordered
    for i in xrange(0, len(wallets)):
        preorder = state_engine.get_name_preorder(
            "foo.test", virtualchain.make_payment_script(wallets[i].addr),
            wallets[(i + 1) % 5].addr)
        if preorder is not None:
            print "preordered"
            return False

    # registered, but revoked
    name_rec = state_engine.get_name("foo.test")
    if name_rec is None:
        print "no name"
        return False

    if not name_rec['revoked']:
        print "not revoked"
        return False

    if name_rec['value_hash'] is not None:
        print "still have value hash"
        return False

    # renewed (12 blocks later, starting from renewal time)
    if name_rec['last_renewed'] - 12 != name_rec['first_registered']:
        print name_rec['last_renewed']
        print name_rec['first_registered']
        return False

    return True
def check(state_engine):

    global fail_blocks

    # not revealed, but ready
    ns = state_engine.get_namespace_reveal("test")
    if ns is not None:
        return False

    ns = state_engine.get_namespace("test")
    if ns is None:
        return False

    if ns['namespace_id'] != 'test':
        return False

    # not preordered
    preorder = state_engine.get_name_preorder(
        "foo.test", virtualchain.make_payment_script(wallets[2].addr),
        wallets[3].addr)
    if preorder is not None:
        return False

    # not registered
    name_rec = state_engine.get_name("foo.test")
    if name_rec is not None:
        return False

    # at each of the fail blocks, confirm that the name has not changed from the initial revocation
    for fb in fail_blocks:
        historic_name_rec = state_engine.get_name_at("foo.test",
                                                     fb,
                                                     include_expired=True)
        if historic_name_rec is None or len(historic_name_rec) == 0:
            print "no name at %s" % fb
            return False

        historic_name_rec = historic_name_rec[0]
        if historic_name_rec['opcode'] != 'NAME_REGISTRATION':
            print "accepted opcode %s at %s" % (historic_name_rec['opcode'],
                                                fb)
            return False

    return True
예제 #43
0
def make_outputs( data, inputs, change_address, tx_fee ):
    """
    Make outputs for an announcement.
    Raise ValueError if there are not enough inputs to make the transaction
    """

    dust_fee = (len(inputs) + 1) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE + tx_fee
    op_fee = DEFAULT_DUST_FEE
    dust_value = DEFAULT_DUST_FEE
    
    return [
        # main output
        {"script_hex": make_op_return_script(str(data), format='hex'),
         "value": 0},
        
        # change output
        {"script_hex": virtualchain.make_payment_script(change_address),
         "value": calculate_change_amount(inputs, op_fee, dust_fee)}
    ]
예제 #44
0
def make_outputs(data,
                 inputs,
                 change_address,
                 tx_fee,
                 pay_fee=True,
                 dust_included=False):
    """
    Make outputs for an update.
    Raise ValueError if there are not enough inputs to make the transaction
    """

    dust_fee = None
    op_fee = None
    dust_value = None

    total_tx_fee = tx_fee
    if pay_fee:
        if not dust_included:
            total_tx_fee += (len(inputs) +
                             1) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE
        op_fee = DEFAULT_DUST_FEE
        dust_value = DEFAULT_DUST_FEE
    else:
        # will be subsidized
        total_tx_fee = 0
        op_fee = 0
        dust_value = 0

    return [
        # main output
        {
            "script": virtualchain.make_data_script(str(data)),
            "value": 0
        },

        # change output
        {
            "script":
            virtualchain.make_payment_script(change_address),
            "value":
            virtualchain.calculate_change_amount(inputs, op_fee, total_tx_fee)
        }
    ]
예제 #45
0
def make_outputs( data, inputs, change_address, tx_fee, pay_fee=True ):
    """
    Make outputs for an announcement.
    Raise ValueError if there are not enough inputs to make the transaction
    """

    dust_fee = (len(inputs) + 1) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE + tx_fee
    op_fee = DEFAULT_DUST_FEE

    if not pay_fee:
        op_fee = 0
        dust_fee = 0
    
    return [
        # main output
        {"script": virtualchain.make_data_script(str(data)),
         "value": 0},
        
        # change output
        {"script": virtualchain.make_payment_script(change_address),
         "value": virtualchain.calculate_change_amount(inputs, op_fee, dust_fee)}
    ]
예제 #46
0
def check( state_engine ):

    global wallet_keys, error, index_file_data, resource_data
    config_path = os.environ.get("BLOCKSTACK_CLIENT_CONFIG")
    assert config_path


    names  = ['bar.test']
    owners = [ new_addr ]
    payers = [ wallets[1].addr ]

    test_proxy = testlib.TestAPIProxy()

    for i in xrange(0, len(names)):
        name = names[i]
        wallet_payer = 5
        wallet_owner = 3 + i
    for name, wallet_payer, wallet_owner in zip(names, payers, owners):
        # not preordered
        preorder = state_engine.get_name_preorder(
            name,
            virtualchain.make_payment_script(wallet_payer),
            wallet_owner)
        if preorder is not None:
            print "still have preorder"
            return False

        # registered
        name_rec = state_engine.get_name( name )
        if name_rec is None:
            print "name does not exist"
            return False

        # owned
        if name_rec['address'] != owners[i]:
            print "name {} has wrong owner".format(name)
            return False

    return True
예제 #47
0
def tx_sign_singlesig(tx, idx, private_key_info, hashcode=bitcoin.SIGHASH_ALL):
    """
    Sign a p2pkh input
    Return the signed transaction

    TODO: move to virtualchain

    NOTE: implemented here instead of bitcoin, since bitcoin.sign() can cause a stack overflow
    while converting the private key to a public key.
    """
    pk = virtualchain.BitcoinPrivateKey(str(private_key_info))
    pubk = pk.public_key()

    pub = pubk.to_hex()
    addr = pubk.address()

    script = virtualchain.make_payment_script(addr)
    sig = tx_make_input_signature(tx, idx, script, private_key_info, hashcode)

    txobj = bitcoin.deserialize(str(tx))
    txobj['ins'][idx]['script'] = bitcoin.serialize_script([sig, pub])
    return bitcoin.serialize(txobj)
def check(state_engine):

    # not revealed, but ready
    ns = state_engine.get_namespace_reveal("test")
    if ns is not None:
        return False

    ns = state_engine.get_namespace("test")
    if ns is None:
        return False

    if ns['namespace_id'] != 'test':
        return False

    # all foo's should succeed
    for i in xrange(0, 25):
        namerec = state_engine.get_name("foo%s.test" % i)
        if namerec is None:
            print "missing foo%s.test" % i
            return False

        if namerec['address'] != wallets[3].addr or namerec[
                'sender'] != virtualchain.make_payment_script(wallets[3].addr):
            print "foo%s.test not owned by %s" % (i, wallets[3].addr)
            return False

    # last foo should fail
    namerec = state_engine.get_name("foo26.test")
    if namerec is not None:
        print "foo26.test exists"
        return False

    # bar should not be registered
    namerec = state_engine.get_name("bar.test")
    if namerec is not None:
        print "bar.test exists"
        return False

    return True
def scenario( wallets, **kw ):

    testlib.blockstack_namespace_preorder( "test", wallets[1].addr, wallets[0].privkey )
    testlib.next_block( **kw )

    testlib.blockstack_namespace_reveal( "test", wallets[1].addr, 52595, 250, 4, [6,5,4,3,2,1,0,0,0,0,0,0,0,0,0,0], 10, 10, wallets[0].privkey )
    testlib.next_block( **kw )

    testlib.blockstack_namespace_ready( "test", wallets[1].privkey )
    testlib.next_block( **kw )

    testlib.blockstack_name_preorder( "foo.test", wallets[2].privkey, wallets[3].addr, wallet=wallets[3] )
    testlib.next_block( **kw )

    # should fail, since multisig isn't enabled yet
    testlib.blockstack_name_register( "foo.test", wallets[2].privkey, wallets[3].addr, wallet=wallets[3] )
    testlib.next_block( **kw )
    
    testlib.expect_snv_fail_at( "foo.test", testlib.get_current_block(**kw))

    # foo.test should be preordered (in both 0.13 and 0.14)
    state_engine = testlib.get_state_engine()
    preorder = state_engine.get_name_preorder("foo.test", virtualchain.make_payment_script(wallets[2].addr), wallets[3].addr)
    if preorder is None:
        print "foo.test not preordered"
        return False

    # epoch changes here

    testlib.blockstack_name_preorder( "bar.test", wallets[3].privkey, wallets[4].addr )
    testlib.next_block( **kw )

    testlib.blockstack_name_register( "foo.test", wallets[2].privkey, wallets[3].addr, wallet=wallets[3] )
    testlib.next_block( **kw )

    testlib.blockstack_name_register( "bar.test", wallets[3].privkey, wallets[4].addr )
    testlib.next_block( **kw )
예제 #50
0
def check(state_engine):

    global zonefile_hash

    # not revealed, but ready
    ns = state_engine.get_namespace_reveal("test")
    if ns is not None:
        print "namespace reveal exists"
        return False

    ns = state_engine.get_namespace("test")
    if ns is None:
        print "no namespace"
        return False

    if ns['namespace_id'] != 'test':
        print "wrong namespace"
        return False

    # registered
    name_rec = state_engine.get_name("foo.test")
    if name_rec is None:
        print "name does not exist"
        return False

    # owned by
    owner_address = wallets[4].addr
    if name_rec['address'] != owner_address or name_rec[
            'sender'] != virtualchain.make_payment_script(owner_address):
        print "sender is wrong"
        return False

    # value hash
    if name_rec['value_hash'] != zonefile_hash:
        print "wrong zonefile hash: %s != %s" % (name_rec['value_hash'],
                                                 zonefile_hash)
        return False

    # replicated?
    zonefile = testlib.blockstack_get_zonefile(zonefile_hash)
    if 'error' in zonefile:
        print "zonefile error: %s" % zonefile['error']
        return False

    # right hash?
    if blockstack_client.hash_zonefile(zonefile) != zonefile_hash:
        print "wrong zonefile: %s != %s" % (
            blockstack_client.hash_zonefile(zonefile), zonefile_hash)
        return False

    # latest key?
    if not zonefile.has_key("txt"):
        print "no txt:\n%s" % json.dumps(zonefile, indent=4, sort_keys=True)
        return False

    if len(zonefile['txt']) != 2:
        print "wrong number of txt records:\n%s" % json.dumps(
            zonefile, indent=4, sort_keys=True)
        return False

    for txtrec in zonefile['txt']:
        if txtrec['name'] == 'pubkey':
            if new_data_pubkey not in txtrec['txt']:
                print "wrong pubkey:\n%s" % json.dumps(
                    zonefile, indent=4, sort_keys=True)
                print "missing %s" % new_data_pubkey
                return False

    names_owned = testlib.blockstack_cli_names()
    if 'error' in names_owned:
        print "rpc names: %s" % names_owned['error']
        return False

    # we still own the name
    if len(names_owned['names_owned']) != 1:
        print "owned: %s" % names_owned['names_owned']
        return False

    # all queues are drained
    queue_info = testlib.blockstack_client_queue_state()
    if len(queue_info) > 0:
        print "Still in queue:\n%s" % json.dumps(
            queue_info, indent=4, sort_keys=True)
        return False

    return True
예제 #51
0
def check(state_engine):

    global update_blocks, transfer_blocks, update_hashes, transfer_recipients

    # not revealed, but ready
    ns = state_engine.get_namespace_reveal("test")
    if ns is not None:
        return False

    ns = state_engine.get_namespace("test")
    if ns is None:
        return False

    if ns['namespace_id'] != 'test':
        return False

    # not preordered
    preorder = state_engine.get_name_preorder(
        "foo.test", virtualchain.make_payment_script(wallets[2].addr),
        wallets[3].addr)
    if preorder is not None:
        print json.dumps(name_rec, indent=4)
        return False

    # registered to new owner
    name_rec = state_engine.get_name("foo.test")
    if name_rec is None:
        print "name rec is None"
        return False

    # updated
    if name_rec['value_hash'] != '04' * 20:
        print "invalid value hash"
        return False

    # transferred
    if name_rec['address'] != wallets[4].addr or name_rec[
            'sender'] != virtualchain.make_payment_script(wallets[4].addr):
        print json.dumps(name_rec, indent=4)
        return False

    # historically updated and transferred
    if len(transfer_blocks) != len(update_blocks):
        print "test bug: did not transfer or update the right amount of times"
        return False

    for i in xrange(0, len(transfer_blocks)):
        transfer_block = transfer_blocks[i]
        transfer_recipient = transfer_recipients[i]

        historic_name_rec = state_engine.get_name_at("foo.test",
                                                     transfer_block,
                                                     include_expired=True)
        if historic_name_rec is None or len(historic_name_rec) == 0:
            print "no name at %s" % transfer_block
            return False

        historic_name_rec = historic_name_rec[0]
        if historic_name_rec['opcode'] != 'NAME_TRANSFER':
            print "was not transfered at %s" % transfer_block
            return False

        if historic_name_rec[
                'address'] != transfer_recipient or historic_name_rec[
                    'sender'] != virtualchain.make_payment_script(
                        transfer_recipient):
            print "wrong address/sender, got %s, %s" % (
                historic_name_rec['address'], historic_name_rec['sender'])
            return False

    for i in xrange(0, len(update_blocks)):
        update_block = update_blocks[i]
        update_hash = update_hashes[i]

        historic_name_rec = state_engine.get_name_at("foo.test",
                                                     update_block,
                                                     include_expired=True)
        if historic_name_rec is None or len(historic_name_rec) == 0:
            print "No name at %s" % update_block
            return False

        historic_name_rec = historic_name_rec[0]
        if historic_name_rec['opcode'] != 'NAME_UPDATE':
            print "was not updated at %s" % update_block
            return False

        if historic_name_rec.get('value_hash', None) != update_hash:
            print "wrong update hash: expected %s, got %s" % (
                update_hash, historic_name_rec.get('value_hash', None))
            return False

    return True
def check( state_engine ):

    global synchronized, atlasdb_path, value_hashes, working_dir, atlas_dir

    if not synchronized:
        print "not synchronized"
        return False

    # not revealed, but ready 
    ns = state_engine.get_namespace_reveal( "test" )
    if ns is not None:
        print "namespace not ready"
        return False 

    ns = state_engine.get_namespace( "test" )
    if ns is None:
        print "no namespace"
        return False 

    if ns['namespace_id'] != 'test':
        print "wrong namespace"
        return False 

    for i in xrange(0, 10):
        name = 'foo_{}.test'.format(i)
        # not preordered
        preorder = state_engine.get_name_preorder( name, virtualchain.make_payment_script(wallets[2].addr), wallets[3].addr )
        if preorder is not None:
            print "still have preorder"
            return False
        
        # registered 
        name_rec = state_engine.get_name( name )
        if name_rec is None:
            print "name does not exist"
            return False 

        # owned 
        if name_rec['address'] != wallets[3].addr or name_rec['sender'] != virtualchain.make_payment_script(wallets[3].addr):
            print "name has wrong owner"
            return False 

        # updated 
        if name_rec['value_hash'] is None:
            print "wrong value hash: %s" % name_rec['value_hash']
            return False 

    for i in xrange(0, len(value_hashes)):
        name = 'foo_{}.test'.format(i)
        value_hash = value_hashes[i]

        # atlas logic tried storage (either this node or the atlas peer)
        zfinfo = blockstack.atlasdb_get_zonefile( value_hash, path=atlasdb_path )
        if not zfinfo['tried_storage']:

            zfinfo2 = blockstack.atlasdb_get_zonefile( value_hash, path=os.path.join(atlas_dir, "localhost:17000/atlas.db") )
            if not zfinfo2['tried_storage']:
                print "didn't get zonefile from storage: test node: %s, atlas peer: %s" % (zfinfo, zfinfo2)
                return False

        # zonefile stored to disk?
        zfdata = blockstack_client.zonefile.load_name_zonefile(name, value_hash, storage_drivers=['disk'])
        if zfdata is None:
            print "failed to load zonefile %s from disk" % value_hash
            return False

        # zonefile cached?
        cached_zonefile = blockstack.lib.storage.get_cached_zonefile( value_hash, zonefile_dir=zonefile_dir )
        if cached_zonefile is None:
            print "no cached zonefile %s in %s" % (value_hash, zonefile_dir)
            return False
        
        if cached_zonefile != zfdata:
            print "zonefile mismatch"
            print "from disk:\n%s\n" % json.dumps(zfdata, indent=4, sort_keys=True)
            print "from cache:\n%s\n" % json.dumps(cached_zonefile, indent=4, sort_keys=True)
            return False
        
    return True
def check( state_engine ):

    global zonefile_hash, error

    if error:
        print "exiting with error"
        return False

    # not revealed, but ready 
    ns = state_engine.get_namespace_reveal( "test" )
    if ns is not None:
        print "namespace reveal exists"
        return False 

    ns = state_engine.get_namespace( "test" )
    if ns is None:
        print "no namespace"
        return False 

    if ns['namespace_id'] != 'test':
        print "wrong namespace"
        return False 
    
    # registered 
    name_rec = state_engine.get_name( "foo.test" )
    if name_rec is None:
        print "name does not exist"
        return False 

    # owned by
    owner_address = wallets[3].addr
    if name_rec['address'] != owner_address or name_rec['sender'] != virtualchain.make_payment_script(owner_address):
        print "sender is wrong"
        return False 

    # value hash 
    if name_rec['value_hash'] != zonefile_hash:
        print "wrong zonefile hash: %s != %s" % (name_rec['value_hash'], zonefile_hash)
        return False

    # replicated?
    zonefile = testlib.blockstack_get_zonefile( zonefile_hash )
    if 'error' in zonefile:
        print "zonefile error: %s" % zonefile['error']
        return False

    # right hash?
    if blockstack_client.hash_zonefile( zonefile ) != zonefile_hash:
        print "wrong zonefile: %s != %s" % (blockstack_client.hash_zonefile(zonefile), zonefile_hash)
        return False

    # all queues are drained 
    queue_info = testlib.blockstack_client_queue_state()
    if len(queue_info) > 0:
        print "Still in queue:\n%s" % json.dumps(queue_info, indent=4, sort_keys=True)
        return False

    # renewed?

    # final balance is correct?
    name_fee = blockstack_server.price_name( "foo", ns, new_expire_block )
    preorder_dust_fees = 3 * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE
    register_dust_fees = 4 * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE
    renewal_dust_fees = 3 * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE

    total_fee = name_fee * 2 + preorder_dust_fees + register_dust_fees + renewal_dust_fees 
    payment_address = wallets[2].addr
    
    # TODO: check
    return True
def check( state_engine ):

    # not revealed, but ready 
    ns = state_engine.get_namespace_reveal( "test" )
    if ns is not None:
        print "namespace reveal exists"
        return False 

    ns = state_engine.get_namespace( "test" )
    if ns is None:
        print "no namespace"
        return False 

    if ns['namespace_id'] != 'test':
        print "wrong namespace"
        return False 
    
    # registered 
    name_rec = state_engine.get_name( "foo.test" )
    if name_rec is None:
        print "name does not exist"
        return False 

    # owned by the right address 
    owner_address = wallets[3].addr
    if name_rec['address'] != owner_address or name_rec['sender'] != virtualchain.make_payment_script(owner_address):
        print "sender is wrong"
        print "%s != %s or %s != %s" % (name_rec['address'], owner_address, name_rec['sender'], virtualchain.make_payment_script(owner_address))
        return False 

    # all queues are drained 
    queue_info = testlib.blockstack_client_queue_state()
    if len(queue_info) > 0:
        print "Still in queue:\n%s" % json.dumps(queue_info, indent=4, sort_keys=True)
        return False

    # have an update hash 
    if 'value_hash' not in name_rec or name_rec.get('value_hash', None) is None:
        print "No value hash"
        return False 

    # have a zonefile 
    zonefile = testlib.blockstack_get_zonefile( name_rec['value_hash'] )
    if zonefile is None or 'error' in zonefile:
        if zonefile is not None:
            print "zonefile lookup error: %s" % zonefile['error']
        else:
            print "no zonefile returned"
        return False

    # hashes to this zonefile 
    if blockstack_client.hash_zonefile( zonefile ) != name_rec['value_hash']:
        print "wrong zonefile: %s != %s" % (blockstack_client.hash_zonefile(zonefile), name_rec['value_hash'])
        return False

    # verify that the profile is there 
    profile = testlib.blockstack_get_profile( "foo.test" )
    if profile is None or 'error' in profile:
        if profile is None:
            print "no profile returned"
        else:
            print "profile lookup error: %s" % profile['error']

        return False

    return True
def check( state_engine ):

    original_price = 6400000
    curr_price = original_price * blockstack_server.lib.config.get_epoch_price_multiplier( 262, "test" )

    # not revealed, but ready 
    ns = state_engine.get_namespace_reveal( "test" )
    if ns is not None:
        print "namespace reveal exists"
        return False 

    ns = state_engine.get_namespace( "test" )
    if ns is None:
        print "no namespace"
        return False 

    if ns['namespace_id'] != 'test':
        print "wrong namespace"
        return False 

    # not preordered
    preorder = state_engine.get_name_preorder( "foo.test", virtualchain.make_payment_script(wallets[2].addr), wallets[3].addr, include_failed=True )
    if preorder is not None:
        print "preorder exists"
        return False
    
    # not preordered
    preorder = state_engine.get_name_preorder( "foo.test", virtualchain.make_payment_script(wallets[3].addr), wallets[4].addr, include_failed=True )
    if preorder is not None:
        print "preorder exists"
        return False

    # registered 
    name_rec_foo = state_engine.get_name( "foo.test" )
    if name_rec_foo is None:
        print "name does not exist"
        return False 

    # registered 
    name_rec_bar = state_engine.get_name( "bar.test" )
    if name_rec_bar is None:
        print "name does not exist"
        return False 

    # owned by
    if name_rec_foo['address'] != wallets[3].addr or name_rec_foo['sender'] != virtualchain.make_payment_script(wallets[3].addr):
        print "sender is wrong"
        return False 

    # owned by
    if name_rec_bar['address'] != wallets[4].addr or name_rec_bar['sender'] != virtualchain.make_payment_script(wallets[4].addr):
        print "sender is wrong"
        return False 

    # paid epoch 1 fee
    if abs(name_rec_foo['op_fee'] - original_price) >= 10e-8:
        print "foo paid %s, expected %s" % (name_rec_foo['op_fee'], original_price)
        return False

    # paid epoch 2 fee
    if abs(name_rec_bar['op_fee'] - curr_price) >= 10e-8:
        print "bar paid %s, expected %s" % (name_rec_bar['op_fee'], curr_price)
        return False

    return True
def make_outputs( data, change_inputs, register_addr, change_addr, tx_fee, renewal_fee=None, pay_fee=True):
    """
    Make outputs for a register:
    [0] OP_RETURN with the name 
    [1] pay-to-address with the *register_addr*, not the sender's address.
    [2] change address with the NAME_PREORDER sender's address
    [3] (OPTIONAL) renewal fee, sent to the burn address
    Raise ValueError if there are not enough inputs to make the transaction
    """
    
    dust_fee = None
    dust_value = DEFAULT_DUST_FEE
    op_fee = None
    bill = None 
    
    if pay_fee:
        
        # sender pays
        if renewal_fee is not None:
            # renewing
            dust_fee = (len(change_inputs) + 3) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE + tx_fee
            op_fee = max(renewal_fee, DEFAULT_DUST_FEE)
            bill = op_fee
            
        else:
            # registering
            dust_fee = (len(change_inputs) + 2) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE + tx_fee
            op_fee = 0
            bill = DEFAULT_DUST_FEE * 2
            
    else:
        
        # subsidized by another address
        if renewal_fee is not None:
            # renewing
            dust_fee = 0
            op_fee = max(renewal_fee, DEFAULT_DUST_FEE)
            bill = 0
            
        else:
            # registering
            dust_fee = 0
            op_fee = 0
            bill = 0
  
    outputs = [
        # main output
        {"script": virtualchain.make_data_script(str(data)),
         "value": 0},
    
        # register address
        {"script": virtualchain.make_payment_script(register_addr),
         "value": dust_value},
        
        # change address (can be the subsidy address)
        {"script": virtualchain.make_payment_script(change_addr),
         "value": virtualchain.calculate_change_amount(change_inputs, bill, dust_fee)},
    ]
    
    if renewal_fee is not None:
        outputs.append(
            
            # burn address (when renewing)
            {"script": virtualchain.make_payment_script(BLOCKSTACK_BURN_ADDRESS),
             "value": op_fee}
        )

    return outputs
def check( state_engine ):

    global zonefile_hash

    # not revealed, but ready 
    ns = state_engine.get_namespace_reveal( "test" )
    if ns is not None:
        print "namespace reveal exists"
        return False 

    ns = state_engine.get_namespace( "test" )
    if ns is None:
        print "no namespace"
        return False 

    if ns['namespace_id'] != 'test':
        print "wrong namespace"
        return False 
    
    # registered 
    name_rec = state_engine.get_name( "foo.test" )
    if name_rec is None:
        print "name does not exist"
        return False 

    # owned by
    owner_address = wallets[4].addr
    if name_rec['address'] != owner_address or name_rec['sender'] != virtualchain.make_payment_script(owner_address):
        print "sender is wrong"
        return False 

    # value hash 
    if name_rec['value_hash'] != zonefile_hash:
        print "wrong zonefile hash: %s != %s" % (name_rec['value_hash'], zonefile_hash)
        return False

    # replicated?
    zonefile = testlib.blockstack_get_zonefile( zonefile_hash )
    if 'error' in zonefile:
        print "zonefile error: %s" % zonefile['error']
        return False

    # right hash?
    if blockstack_client.hash_zonefile( zonefile ) != zonefile_hash:
        print "wrong zonefile: %s != %s" % (blockstack_client.hash_zonefile(zonefile), zonefile_hash)
        return False

    # latest key?
    if not zonefile.has_key("txt"):
        print "no txt:\n%s" % json.dumps(zonefile, indent=4, sort_keys=True)
        return False 

    if len(zonefile['txt']) != 2:
        print "wrong number of txt records:\n%s" % json.dumps(zonefile, indent=4, sort_keys=True)
        return False

    for txtrec in zonefile['txt']:
        if txtrec['name'] == 'pubkey':
            if new_data_pubkey not in txtrec['txt']:
                print "wrong pubkey:\n%s" % json.dumps(zonefile, indent=4, sort_keys=True)
                print "missing %s" % new_data_pubkey
                return False

    names_owned = testlib.blockstack_cli_names()
    if 'error' in names_owned:
        print "rpc names: %s" % names_owned['error']
        return False

    # we still own the name
    if len(names_owned['names_owned']) != 1:
        print "owned: %s" % names_owned['names_owned']
        return False

    # all queues are drained 
    queue_info = testlib.blockstack_client_queue_state()
    if len(queue_info) > 0:
        print "Still in queue:\n%s" % json.dumps(queue_info, indent=4, sort_keys=True)
        return False

    return True