def scenario(wallets, **kw):

    # pass 100 stacks around in a circle.
    new_keys = [wallets[0].privkey] + [
        virtualchain.lib.ecdsalib.ecdsa_private_key().to_hex()
        for i in range(0, 3)
    ]
    for i in range(0, 3 * len(new_keys)):

        new_addr = virtualchain.get_privkey_address(new_keys[(i + 1) %
                                                             len(new_keys)])
        cur_addr = virtualchain.get_privkey_address(new_keys[i %
                                                             len(new_keys)])

        initial_new_balance_info = json.loads(
            testlib.nodejs_cli('balance', new_addr))
        initial_cur_balance_info = json.loads(
            testlib.nodejs_cli('balance', cur_addr))

        print '\n initial new balance info: {} \n'.format(
            initial_new_balance_info)

        if 'STACKS' not in initial_new_balance_info:
            initial_new_balance_info['STACKS'] = 0

        if i > 0:
            testlib.send_funds(wallets[0].privkey, 800000, cur_addr)

        testlib.send_funds(wallets[0].privkey, 800000, new_addr)

        testlib.blockstack_send_tokens(new_addr, 'STACKS', 100,
                                       new_keys[i % len(new_keys)])
        testlib.next_block(**kw)

        balance_info = json.loads(testlib.nodejs_cli('balance', new_addr))
        assert int(balance_info['STACKS']) == 100 + int(
            initial_new_balance_info['STACKS'])

        if (i + 1) % len(new_keys) != 0:
            assert int(balance_info['STACKS']) == 100

        balance_info = json.loads(testlib.nodejs_cli('balance', cur_addr))
        assert int(balance_info['STACKS']) == int(
            initial_cur_balance_info['STACKS']) - 100

        if i % len(new_keys) != 0:
            assert int(balance_info['STACKS']) == 0

    # each *new* address has 6 history items -- three spends, three receives
    for new_key in new_keys[1:]:
        new_addr = virtualchain.get_privkey_address(new_key)
        history = requests.get(
            'http://localhost:16268/v1/accounts/{}/history?page=0'.format(
                new_addr)).json()

        # should have gotten 3 debits for 100, and 3 credits for 100
        assert int(history[0]['credit_value']) == 300, history
        assert int(history[0]['debit_value']) == 300, history

        assert len(history) == 6, history
def make_wallet_keys(data_privkey=None, owner_privkey=None, payment_privkey=None):
    """
    For testing.  DO NOT USE
    """

    ret = {
        'owner_privkey': None,
        'data_privkey': None,
        'payment_privkey': None,
    }

    if data_privkey is not None:
        if not virtualchain.is_singlesig(data_privkey):
            raise ValueError('Invalid data key info')

        pk_data = ecdsa_private_key(data_privkey).to_hex()
        ret['data_privkey'] = pk_data

    if owner_privkey is not None:
        if virtualchain.is_multisig(owner_privkey):
            pks = owner_privkey['private_keys']
            m, _ = virtualchain.parse_multisig_redeemscript(owner_privkey['redeem_script'])
            assert m <= len(pks)

            multisig_info = virtualchain.make_multisig_info(m, pks)
            ret['owner_privkey'] = multisig_info
            ret['owner_addresses'] = [virtualchain.get_privkey_address(multisig_info)]

        elif virtualchain.is_singlesig(owner_privkey):
            pk_owner = ecdsa_private_key(owner_privkey).to_hex()
            ret['owner_privkey'] = pk_owner
            ret['owner_addresses'] = [virtualchain.get_privkey_address(pk_owner)]

        else:
            raise ValueError('Invalid owner key info')

    if payment_privkey is None:
        return ret

    if virtualchain.is_multisig(payment_privkey):
        pks = payment_privkey['private_keys']
        m, _ = virtualchain.parse_multisig_redeemscript(payment_privkey['redeem_script'])
        assert m <= len(pks)

        multisig_info = virtualchain.make_multisig_info(m, pks)
        ret['payment_privkey'] = multisig_info
        ret['payment_addresses'] = [virtualchain.get_privkey_address(multisig_info)]

    elif virtualchain.is_singlesig(payment_privkey):
        pk_payment = ecdsa_private_key(payment_privkey).to_hex()
        ret['payment_privkey'] = pk_payment
        ret['payment_addresses'] = [virtualchain.get_privkey_address(pk_payment)]

    else:
        raise ValueError('Invalid payment key info')

    ret['data_pubkey'] = ecdsa_private_key(ret['data_privkey']).public_key().to_hex()
    ret['data_pubkeys'] = [ret['data_pubkey']]

    return ret
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
    addr = virtualchain.address_reencode(virtualchain.get_privkey_address(pk))
    addr2 = virtualchain.address_reencode(
        virtualchain.get_privkey_address(pk2))
    preorder = state_engine.get_name_preorder(
        "foo.test", virtualchain.make_payment_script(addr), addr2)
    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'] != addr2 or name_rec[
            'sender'] != virtualchain.make_payment_script(addr2):
        print "sender is wrong"
        return False

    # paid with Stacks
    stacks_price = blockstack.lib.scripts.price_name_stacks(
        'foo', ns, state_engine.lastblock)
    if name_rec['token_fee'] != stacks_price:
        print 'paid wrong token fee'
        print 'expected {} ({}), got {} ({})'.format(
            stacks_price, type(stacks_price), name_rec['token_fee'],
            type(name_rec['token_fee']))
        return False

    if name_rec['op_fee'] > 5500:  # dust minimum
        print 'paid in BTC ({})'.format(name_rec['op_fee'])
        return False

    # renewed on third attempt
    if name_rec['first_registered'] + 3 != name_rec['last_renewed']:
        print 'renewed at the wrong time: {} + 3 != {}'.format(
            name_rec['first_registered'], name_rec['last_renewed'])
        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 

    # not preordered
    addr = virtualchain.address_reencode(virtualchain.get_privkey_address(pk))
    addr2 = virtualchain.address_reencode(virtualchain.get_privkey_address(pk2))
    preorder = state_engine.get_name_preorder( "foo.test", virtualchain.make_payment_script(addr), wallets[3].addr )
    if preorder is not None:
        print "preorder exists for foo.test"
        return False
    
    # not registered 
    name_rec = state_engine.get_name( "foo.test" )
    if name_rec is not None:
        print "name exists"
        return False 

    # not preordered
    preorder = state_engine.get_name_preorder('bar.test', virtualchain.make_payment_script(addr2), wallets[3].addr)
    if preorder is not None:
        print 'preorder exists for bar.test'
        return False

    # registered
    name_rec = state_engine.get_name('bar.test')
    if name_rec is None:
        print 'bar.test 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 'bar.test not owned'
        return False

    # overpaid
    if name_rec['op_fee'] > 5500 or name_rec['token_fee'] != blockstack.lib.scripts.price_name_stacks('bar', ns, state_engine.lastblock) + 1:
        print 'bar.test improperly paid'
        return False

    return True
def make_wallet(password, config_path=CONFIG_PATH, payment_privkey_info=None, owner_privkey_info=None, data_privkey_info=None, test_legacy=False, encrypt=True):
    """
    Make a new, encrypted wallet structure.
    The owner and payment keys will be 2-of-3 multisig key bundles.
    The data keypair will be a single-key bundle.

    Return the new wallet on success.
    Return {'error': ...} on failure
    """
    
    if test_legacy and not BLOCKSTACK_TEST:
        raise Exception("Not in testing but tried to make a legacy wallet")

    # default to 2-of-3 multisig key info if data isn't given
    payment_privkey_info = virtualchain.make_multisig_wallet(2, 3) if payment_privkey_info is None and not test_legacy else payment_privkey_info
    owner_privkey_info = virtualchain.make_multisig_wallet(2, 3) if owner_privkey_info is None and not test_legacy else owner_privkey_info
    data_privkey_info = ecdsa_private_key().to_hex() if data_privkey_info is None and not test_legacy else data_privkey_info

    decrypted_wallet = {
        'owner_addresses': [virtualchain.get_privkey_address(owner_privkey_info)],
        'owner_privkey': owner_privkey_info,
        'payment_addresses': [virtualchain.get_privkey_address(payment_privkey_info)],
        'payment_privkey': payment_privkey_info,
        'data_pubkey': ecdsa_private_key(data_privkey_info).public_key().to_hex(),
        'data_pubkeys': [ecdsa_private_key(data_privkey_info).public_key().to_hex()],
        'data_privkey': data_privkey_info,
        'version': SERIES_VERSION,
    }
    
    if not test_legacy:
        jsonschema.validate(decrypted_wallet, WALLET_SCHEMA_CURRENT)

    if encrypt:
        encrypted_wallet = encrypt_wallet(decrypted_wallet, password, test_legacy=test_legacy)
        if 'error' in encrypted_wallet:
            return encrypted_wallet

        # sanity check
        try:
            jsonschema.validate(encrypted_wallet, ENCRYPTED_WALLET_SCHEMA_CURRENT)
        except ValidationError as ve:
            if test_legacy:
                # no data key is permitted 
                assert BLOCKSTACK_TEST
                jsonschema.validate(encrypted_wallet, ENCRYPTED_WALLET_SCHEMA_CURRENT_NODATAKEY)
            else:
                raise

        return encrypted_wallet

    else:
        return decrypted_wallet
Пример #6
0
def make_wallet(password, config_path=CONFIG_PATH, payment_privkey_info=None, owner_privkey_info=None, data_privkey_info=None, test_legacy=False, encrypt=True):
    """
    Make a new, encrypted wallet structure.
    The owner and payment keys will be 2-of-3 multisig key bundles.
    The data keypair will be a single-key bundle.

    Return the new wallet on success.
    Return {'error': ...} on failure
    """
    
    if test_legacy and not BLOCKSTACK_TEST:
        raise Exception("Not in testing but tried to make a legacy wallet")

    # default to 2-of-3 multisig key info if data isn't given
    payment_privkey_info = virtualchain.make_multisig_wallet(2, 3) if payment_privkey_info is None and not test_legacy else payment_privkey_info
    owner_privkey_info = virtualchain.make_multisig_wallet(2, 3) if owner_privkey_info is None and not test_legacy else owner_privkey_info
    data_privkey_info = ecdsa_private_key().to_hex() if data_privkey_info is None and not test_legacy else data_privkey_info

    decrypted_wallet = {
        'owner_addresses': [virtualchain.get_privkey_address(owner_privkey_info)],
        'owner_privkey': owner_privkey_info,
        'payment_addresses': [virtualchain.get_privkey_address(payment_privkey_info)],
        'payment_privkey': payment_privkey_info,
        'data_pubkey': ecdsa_private_key(data_privkey_info).public_key().to_hex(),
        'data_pubkeys': [ecdsa_private_key(data_privkey_info).public_key().to_hex()],
        'data_privkey': data_privkey_info,
        'version': SERIES_VERSION,
    }
    
    if not test_legacy:
        jsonschema.validate(decrypted_wallet, WALLET_SCHEMA_CURRENT)

    if encrypt:
        encrypted_wallet = encrypt_wallet(decrypted_wallet, password, test_legacy=test_legacy)
        if 'error' in encrypted_wallet:
            return encrypted_wallet

        # sanity check
        try:
            jsonschema.validate(encrypted_wallet, ENCRYPTED_WALLET_SCHEMA_CURRENT)
        except ValidationError as ve:
            if test_legacy:
                # no data key is permitted 
                assert BLOCKSTACK_TEST
                jsonschema.validate(encrypted_wallet, ENCRYPTED_WALLET_SCHEMA_CURRENT_NODATAKEY)
            else:
                raise

        return encrypted_wallet

    else:
        return decrypted_wallet
Пример #7
0
def scenario( wallets, **kw ):
    global pk, pk2

    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, version_bits=blockstack.lib.config.NAMESPACE_VERSION_PAY_TO_CREATOR)
    testlib.next_block( **kw )

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

    # pay for a name in a v1 namespace with Stacks
    addr = virtualchain.address_reencode(virtualchain.get_privkey_address(pk))
    addr2 = virtualchain.address_reencode(virtualchain.get_privkey_address(pk2))

    # calculate the cost of doing so
    namespace = testlib.get_state_engine().get_namespace('test')
    stacks_price = blockstack.lib.scripts.price_name_stacks('foo', namespace, testlib.get_current_block(**kw))
    btc_price = blockstack.lib.scripts.price_name('foo', namespace, testlib.get_current_block(**kw))

    print ''
    print 'price of {} in Stacks is {}'.format('foo.test', stacks_price)
    print 'price of {} in BTC is {}'.format('foo.test', btc_price)
    print ''

    testlib.blockstack_send_tokens(addr, "STACKS", stacks_price + 2, wallets[0].privkey)
    testlib.blockstack_send_tokens(addr2, "STACKS", stacks_price + 1, wallets[0].privkey)
    testlib.send_funds(wallets[0].privkey, 3*btc_price, addr)
    testlib.send_funds(wallets[0].privkey, 3*btc_price, addr2)
    testlib.next_block(**kw)

    # preorder/register using Stacks
    testlib.blockstack_name_preorder( "foo.test", pk, addr2)
    testlib.blockstack_name_preorder( "bar.test", pk2, addr)
    testlib.next_block( **kw )

    testlib.blockstack_name_register( "foo.test", pk, addr2 )
    testlib.blockstack_name_register( "bar.test", pk2, addr )
    testlib.next_block( **kw )
    testlib.next_block( **kw )
    testlib.next_block( **kw )
    testlib.next_block( **kw ) # end of pay to namespace creator

    # renew using more stacks than we have (should fail)
    # bar.test should succeed
    testlib.blockstack_name_renew('foo.test', pk2, price={'units': 'STACKS', 'amount': stacks_price + 2}, expect_fail=True, safety_checks=False)
    testlib.blockstack_name_renew('bar.test', pk, price={'units': 'STACKS', 'amount': stacks_price + 1})
    testlib.next_block(**kw)
    testlib.expect_snv_fail_at('foo.test', testlib.get_current_block(**kw))
Пример #8
0
def convert_funds_to_segwit(payment_key, tx_fee):
    # convert payment key to bech32
    addr = virtualchain.address_reencode(virtualchain.get_privkey_address(payment_key))
    pubk = virtualchain.lib.ecdsalib.ecdsa_private_key(payment_key, compressed=True).public_key().to_hex()
    addrhash = virtualchain.lib.hashing.bin_hash160(pubk.decode('hex')).encode('hex')
    segwit_addr = virtualchain.segwit_addr_encode(addrhash.decode('hex'), hrp='bcrt')
    
    # fund the segwit address, and then use the same payment key to send the transaction 
    fund_inputs = testlib.get_utxos(addr)
    fund_outputs = [
        {"script": '0014' + addrhash,
         "value": sum(inp['value'] for inp in fund_inputs) - tx_fee},
    ]
    fund_prev_outputs = [{'out_script': inp['out_script'], 'value': inp['value']} for inp in fund_inputs]
    fund_serialized_tx = testlib.serialize_tx(fund_inputs, fund_outputs)
    fund_signed_tx = virtualchain.tx_sign_all_unsigned_inputs(payment_key, fund_prev_outputs, fund_serialized_tx)

    print fund_signed_tx

    res = testlib.broadcast_transaction(fund_signed_tx)
    assert 'error' not in res, res

    res.update({
        'utxos': fund_outputs
    })
    return res
Пример #9
0
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
    addr = virtualchain.address_reencode(virtualchain.get_privkey_address(pk))
    preorder = state_engine.get_name_preorder( "foo.test", virtualchain.make_payment_script(addr), wallets[3].addr )
    if preorder is not None:
        print "preorder exists"
        return False
    
    # not registered 
    name_rec = state_engine.get_name( "foo.test" )
    if name_rec is not None:
        print "name exists"
        return False 

    return True
    def _tx_pay_btc(txhex, privk, burn_price, burn_addr=blockstack.lib.config.BLOCKSTACK_BURN_ADDRESS):
        tx = virtualchain.btc_tx_deserialize(txhex)

        # up the burn amount 
        tx['outs'][3]['script'] = virtualchain.btc_make_payment_script(burn_addr)
        tx['outs'][3]['value'] = burn_price

        tx['outs'][4]['value'] -= burn_price

        # re-sign 
        for i in tx['ins']:
            i['script'] = ''

        txhex = virtualchain.btc_tx_serialize(tx)
        _addr = virtualchain.address_reencode(virtualchain.get_privkey_address(privk))
        txhex_signed = virtualchain.tx_sign_all_unsigned_inputs(privk, testlib.get_utxos(_addr), txhex)

        # re-sign the last output with the payment key
        tx_signed = virtualchain.btc_tx_deserialize(txhex_signed)
        tx_signed['ins'][-1]['script'] = ''
        txhex_signed = virtualchain.tx_sign_all_unsigned_inputs(testlib.get_default_payment_wallet().privkey, testlib.get_utxos(testlib.get_default_payment_wallet().addr), virtualchain.btc_tx_serialize(tx_signed))
        
        print txhex_signed

        res = testlib.broadcast_transaction(txhex_signed)
        assert 'error' not in res
        return res
def scenario( wallets, **kw ):

    global wallet_keys, wallet_keys_2, error, index_file_data, resource_data

    empty_key = ECPrivateKey().to_hex()

    wallet_keys = testlib.ysi_client_initialize_wallet(
        "0123456789abcdef", wallets[1].privkey, wallets[2].privkey, wallets[0].privkey)
    test_proxy = testlib.TestAPIProxy()
    ysi_client.set_default_proxy( test_proxy )

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

    testlib.ysi_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.ysi_namespace_ready( "test", wallets[1].privkey )
    testlib.next_block( **kw )

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()

    testlib.next_block( **kw )

    config_path = os.environ.get("BLOCKSTACK_CLIENT_CONFIG", None)

    config_dir = os.path.dirname(config_path)
    conf = ysi_client.get_config(config_path)
    assert conf

    api_pass = conf['api_password']

    # let's do a withdraw of all
    res = testlib.ysi_REST_call('POST', '/v1/wallet/balance', None, api_pass=api_pass, data= {
        'address' : virtualchain.get_privkey_address(empty_key),
        })
    if 'error' in res['response']:
        res['test'] = 'Failed to perform withdraw'
        print json.dumps(res)
        error = True
        return False
    for i in xrange (0, 1):
        testlib.next_block( **kw )
    print 'Waiting for the withdraw to go through'
    res = testlib.ysi_REST_call('GET', '/v1/wallet/balance/0', None, api_pass=api_pass)
    if 'error' in res['response']:
        res['test'] = 'Failed to get wallet balance'
        print json.dumps(res)
        error = True
        return False

    res = testlib.ysi_REST_call('GET', '/v1/wallet/balance/0', None, api_pass=api_pass)
    if 'error' in res['response']:
        res['test'] = 'Failed to get wallet balance'
        print json.dumps(res)
        error = True
        return False
def scenario( wallets, **kw ):
    global pk, pk2

    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, version_bits=blockstack.lib.config.NAMESPACE_VERSION_PAY_TO_CREATOR)
    testlib.next_block( **kw )

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

    # pay for a name in a v1 namespace with Stacks
    addr = virtualchain.address_reencode(virtualchain.get_privkey_address(pk))
    addr2 = virtualchain.address_reencode(virtualchain.get_privkey_address(pk2))

    # calculate the cost of doing so
    namespace = testlib.get_state_engine().get_namespace('test')
    stacks_price = blockstack.lib.scripts.price_name_stacks('foo', namespace, testlib.get_current_block(**kw))
    btc_price = blockstack.lib.scripts.price_name('foo', namespace, testlib.get_current_block(**kw))

    print ''
    print 'price of {} in Stacks is {}'.format('foo.test', stacks_price)
    print ''

    testlib.blockstack_send_tokens(addr, "STACKS", stacks_price + 1, wallets[0].privkey)
    testlib.blockstack_send_tokens(addr2, "STACKS", stacks_price + 1, wallets[0].privkey)
    testlib.send_funds(wallets[0].privkey, btc_price - 5500 - 1, addr)  # deliberately insufficient funds for ordering the name in BTC
    testlib.send_funds(wallets[0].privkey, btc_price - 5500 - 1, addr2)  # deliberately insufficient funds for ordering the name in BTC
    testlib.next_block(**kw)
    testlib.next_block(**kw)
    testlib.next_block(**kw)
    testlib.next_block(**kw)    # move beyond pay-to-creator requirement

    # preorder/register using Stacks, but overpay (foo.test fails, bar.test succeeds)
    testlib.blockstack_name_preorder( "foo.test", pk, wallets[3].addr, price={'units': 'STACKS', 'amount': stacks_price + 2}, expect_fail=True, safety_checks=False)
    testlib.blockstack_name_preorder( "bar.test", pk2, wallets[3].addr, price={'units': 'STACKS', 'amount': stacks_price + 1})
    testlib.next_block( **kw )
    testlib.expect_snv_fail_at('foo.test', testlib.get_current_block(**kw))

    testlib.send_funds(wallets[0].privkey, btc_price - 5500 - 1, addr)  # deliberately insufficient funds for ordering the name in BTC
    testlib.send_funds(wallets[0].privkey, btc_price - 5500 - 1, addr2)  # deliberately insufficient funds for ordering the name in BTC
    testlib.blockstack_name_register( "foo.test", pk, wallets[3].addr ) # should fail
    testlib.blockstack_name_register( "bar.test", pk2, wallets[3].addr ) # should succeed
    testlib.next_block( **kw )
    testlib.expect_snv_fail_at('foo.test', testlib.get_current_block(**kw))
Пример #13
0
def send_as_segwit_bech32(txhex, payment_key):
    print 'txhex: {}'.format(txhex)

    # get op-return data
    tx = virtualchain.btc_tx_deserialize(txhex)
    payload = tx['outs'][0]['script']
    
    print json.dumps(tx, indent=4, sort_keys=True)

    # convert payment key to bech32
    addr = virtualchain.address_reencode(virtualchain.get_privkey_address(payment_key))
    pubk = virtualchain.lib.ecdsalib.ecdsa_private_key(payment_key, compressed=True).public_key().to_hex()
    addrhash = virtualchain.lib.hashing.bin_hash160(pubk.decode('hex')).encode('hex')
    segwit_addr = virtualchain.segwit_addr_encode(addrhash.decode('hex'), hrp='bcrt')
    
    print 'privk = {}'.format(payment_key)
    print 'pubk = {}'.format(pubk)
    print 'addr = {}'.format(addr)
    print 'segwit addr = {}'.format(segwit_addr)
    print 'script = 00{}'.format(addrhash)

    tx_fee = 5500
    res = convert_funds_to_segwit(payment_key, tx_fee)
    fund_outputs = res['utxos']
    fund_txid = res['tx_hash']

    new_tx = {
        'locktime': 0,
        'version': 2,
        'ins': [
            {'outpoint': {'hash': fund_txid, 'index': 0},
             'script': '',
             'witness_script': '',
             'sequence': 4294967295},
        ],
        'outs': [
            {'script': tx['outs'][0]['script'],
             'value': tx['outs'][0]['value']},
            {'script': '0014' + addrhash,
             'value': fund_outputs[0]['value'] - tx_fee * 2},
            {'script': tx['outs'][2]['script'],
             'value': tx['outs'][2]['value']}
        ]
    }

    unsigned_txhex = virtualchain.btc_tx_serialize(new_tx)
    print 'unsigned: {}'.format(unsigned_txhex)

    pk_segwit = virtualchain.make_segwit_info(payment_key)
    print json.dumps(pk_segwit, indent=4, sort_keys=True)

    signed_txhex = virtualchain.tx_sign_input(unsigned_txhex, 0, fund_outputs[0]['script'], fund_outputs[0]['value'], pk_segwit, segwit=True, scriptsig_type='p2wpkh')
    print 'signed: {}'.format(signed_txhex)

    res = testlib.broadcast_transaction(signed_txhex)
    assert 'error' not in res

    return res
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,
        version_bits=blockstack.NAMESPACE_VERSION_PAY_WITH_STACKS)
    testlib.next_block(**kw)

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

    balances = testlib.get_wallet_balances(wallets[2])
    assert balances[wallets[2].addr][STACKS] == 0

    # should fail--not enough stacks
    testlib.blockstack_name_preorder("foo.test",
                                     wallets[2].privkey,
                                     wallets[3].addr,
                                     safety_checks=False,
                                     expect_fail=True)
    testlib.next_block(**kw)

    name_cost = testlib.blockstack_get_name_token_cost('foo.test')
    assert name_cost['units'] == STACKS
    assert name_cost['amount'] > 0

    # send tokens and preorder multiple times in the block
    # should all succeed, BUT: force them to go in order through UTXO chaining
    for i in range(0, 5):
        name_recipient_privkey = wallets[-(i + 1)].privkey
        name_recipient_addr = virtualchain.address_reencode(
            virtualchain.get_privkey_address(name_recipient_privkey))

        testlib.blockstack_send_tokens(name_recipient_addr, "STACKS",
                                       name_cost['amount'], wallets[0].privkey)
        testlib.send_funds(wallets[0].privkey, 1000000, name_recipient_addr)
        testlib.blockstack_name_preorder("foo_{}.test".format(i),
                                         name_recipient_privkey,
                                         wallets[3].addr,
                                         safety_checks=False)
        testlib.blockstack_name_register("foo_{}.test".format(i),
                                         name_recipient_privkey,
                                         wallets[3].addr,
                                         safety_checks=False)

    testlib.next_block(**kw)
def scenario( wallets, **kw ):
    global pk, pk2

    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 )

    # pay for a name in a v1 namespace with Stacks
    addr = virtualchain.address_reencode(virtualchain.get_privkey_address(pk))
    addr2 = virtualchain.address_reencode(virtualchain.get_privkey_address(pk2))

    # calculate the cost of doing so
    namespace = testlib.get_state_engine().get_namespace('test')
    stacks_price = blockstack.lib.scripts.price_name_stacks('foo', namespace, testlib.get_current_block(**kw))
    btc_price = blockstack.lib.scripts.price_name('foo', namespace, testlib.get_current_block(**kw))

    print ''
    print 'price of {} in Stacks is {}'.format('foo.test', stacks_price)
    print 'price of {} in BTC is {}'.format('foo.test', btc_price)
    print ''

    testlib.blockstack_send_tokens(addr, "STACKS", stacks_price + 1, wallets[0].privkey)
    testlib.blockstack_send_tokens(addr2, "STACKS", stacks_price + 1, wallets[0].privkey)
    testlib.send_funds(wallets[0].privkey, 2*btc_price, addr)
    testlib.send_funds(wallets[0].privkey, 2*btc_price, addr2)
    testlib.next_block(**kw)

    # preorder/register using Stacks
    testlib.blockstack_name_preorder( "foo.test", pk, addr2, price={'units': 'STACKS', 'amount': stacks_price + 1})
    testlib.next_block( **kw )

    testlib.blockstack_name_register( "foo.test", pk, addr2 )
    testlib.next_block( **kw )

    # renew using Stacks
    testlib.blockstack_name_renew('foo.test', pk2, price={'units': 'STACKS', 'amount': stacks_price + 1})
    testlib.next_block(**kw)
Пример #16
0
def decrypt_private_key_info(privkey_info, password):
    """
    LEGACY COMPATIBILITY CODE

    Decrypt a particular private key info bundle.
    It can be either a single-signature private key, or a multisig key bundle.
    Return {'address': ..., 'private_key_info': ...} on success.
    Return {'error': ...} on error.
    """

    from .backend.crypto.utils import aes_decrypt

    ret = {}
    if is_encrypted_multisig(privkey_info):
        ret = decrypt_multisig_info(privkey_info, password)
        if 'error' in ret:
            return {
                'error':
                'Failed to decrypt multisig wallet: {}'.format(ret['error'])
            }

        address = virtualchain.get_privkey_address(ret)
        return {'address': address, 'private_key_info': ret}

    if is_encrypted_singlesig(privkey_info):
        try:
            hex_password = hexlify(password)
            pk = aes_decrypt(privkey_info, hex_password)
            pk = ecdsa_private_key(pk).to_hex()
        except Exception as e:
            if BLOCKSTACK_TEST:
                log.exception(e)

            return {'error': 'Invalid password'}

        address = virtualchain.get_privkey_address(pk)
        return {'address': address, 'private_key_info': pk}

    return {'error': 'Invalid encrypted private key info'}
Пример #17
0
    def _convert_key(given_privkey, key_type):
        if virtualchain.is_multisig(given_privkey):
            pks = given_privkey['private_keys']
            m, _ = virtualchain.parse_multisig_redeemscript(
                given_privkey['redeem_script'])
            assert m <= len(pks)

            multisig_info = virtualchain.make_multisig_info(m, pks)
            ret['{}_privkey'.format(key_type)] = multisig_info
            ret['{}_addresses'.format(key_type)] = [
                virtualchain.get_privkey_address(multisig_info)
            ]

        elif virtualchain.is_singlesig(given_privkey):
            pk = ecdsa_private_key(given_privkey).to_hex()
            ret['{}_privkey'.format(key_type)] = pk
            ret['{}_addresses'.format(key_type)] = [
                virtualchain.get_privkey_address(pk)
            ]

        elif virtualchain.btc_is_singlesig_segwit(given_privkey):
            pk = virtualchain.make_segwit_info(
                virtualchain.get_singlesig_privkey(given_privkey))
            ret['{}_privkey'.format(key_type)] = pk
            ret['{}_addresses'.format(key_type)] = [pk['address']]

        elif virtualchain.btc_is_multisig_segwit(given_privkey):
            pks = given_privkey['private_keys']
            m, _ = virtualchain.parse_multisig_redeemscript(
                given_privkey['redeem_script'])
            assert m <= len(pks)

            pk = virtualchain.make_multisig_segwit_info(m, pks)
            ret['{}_privkey'.format(key_type)] = pk
            ret['{}_addresses'.format(key_type)] = [pk['address']]

        else:
            raise ValueError('Invalid owner key info')
def tx_get_address_and_utxos(private_key_info, utxo_client, address=None):
    """
    Get information about a private key (or a set of private keys used for multisig).
    Return (payer_address, payer_utxos) on success.
    UTXOs will be in BTC, not satoshis!
    """

    if private_key_info is None:
        # just go with the address 
        unspents = get_unspents(address, utxo_client)
        return addr, unspents 

    addr = virtualchain.get_privkey_address(private_key_info)
    payer_utxos = get_unspents(addr, utxo_client)
    return addr, payer_utxos
def decrypt_private_key_info(privkey_info, password):
    """
    LEGACY COMPATIBILITY CODE

    Decrypt a particular private key info bundle.
    It can be either a single-signature private key, or a multisig key bundle.
    Return {'address': ..., 'private_key_info': ...} on success.
    Return {'error': ...} on error.
    """

    from .backend.crypto.utils import aes_decrypt

    ret = {}
    if is_encrypted_multisig(privkey_info):
        ret = decrypt_multisig_info(privkey_info, password)
        if 'error' in ret:
            return {'error': 'Failed to decrypt multisig wallet: {}'.format(ret['error'])}

        address = virtualchain.get_privkey_address(ret)
        return {'address': address, 'private_key_info': ret}

    if is_encrypted_singlesig(privkey_info):
        try:
            hex_password = hexlify(password)
            pk = aes_decrypt(privkey_info, hex_password)
            pk = ecdsa_private_key(pk).to_hex()
        except Exception as e:
            if BLOCKSTACK_TEST:
                log.exception(e)

            return {'error': 'Invalid password'}

        address = virtualchain.get_privkey_address(pk)
        return {'address': address, 'private_key_info': pk}

    return {'error': 'Invalid encrypted private key info'}
Пример #20
0
def tx_get_address_and_utxos(private_key_info, utxo_client, address=None):
    """
    Get information about a private key (or a set of private keys used for multisig).
    Return (payer_address, payer_utxos) on success.
    UTXOs will be in BTC, not satoshis!
    """

    if private_key_info is None:
        # just go with the address
        unspents = get_unspents(address, utxo_client)
        return address, unspents

    addr = virtualchain.get_privkey_address(private_key_info)
    payer_utxos = get_unspents(addr, utxo_client)
    return addr, payer_utxos
def scenario( wallets, **kw ):

    # try to spend tokens to ourselves
    testlib.blockstack_send_tokens(wallets[0].addr, "STACKS", 100000, wallets[0].privkey, safety_checks=False, expect_fail=True)
    testlib.next_block(**kw) # end of 689

    assert virtualchain.lib.indexer.StateEngine.get_block_statistics(testlib.get_current_block(**kw))['num_processed_ops'] == 0

    # try to spend more tokens than we have 
    testlib.blockstack_send_tokens(wallets[1].addr, "STACKS", 600001, wallets[0].privkey, safety_checks=False, expect_fail=True)
    testlib.next_block(**kw)

    assert virtualchain.lib.indexer.StateEngine.get_block_statistics(testlib.get_current_block(**kw))['num_processed_ops'] == 0

    # try to spend tokens that don't exist
    testlib.blockstack_send_tokens(wallets[1].addr, "noop", 600000, wallets[0].privkey, safety_checks=False, expect_fail=True)
    testlib.next_block(**kw)

    assert virtualchain.lib.indexer.StateEngine.get_block_statistics(testlib.get_current_block(**kw))['num_processed_ops'] == 0
   
    # try to spend tokens with an invalid consensus hash (note that this is epoch 4)
    testlib.blockstack_send_tokens(wallets[1].addr, "STACKS", 600000, wallets[0].privkey, consensus_hash='00' * 16, safety_checks=False, expect_fail=True)
    testlib.next_block(**kw)
    
    assert virtualchain.lib.indexer.StateEngine.get_block_statistics(testlib.get_current_block(**kw))['num_processed_ops'] == 0

    # try to spend tokens from an account that doesn't exist
    pk = virtualchain.lib.ecdsalib.ecdsa_private_key().to_hex()
    addr = virtualchain.address_reencode(virtualchain.get_privkey_address(pk))
    testlib.send_funds(wallets[0].privkey, 10240000, addr)

    testlib.blockstack_send_tokens(wallets[1].addr, "STACKS", 100000, pk, safety_checks=False, expect_fail=True)
    testlib.next_block(**kw)

    assert virtualchain.lib.indexer.StateEngine.get_block_statistics(testlib.get_current_block(**kw))['num_processed_ops'] == 0

    # try to send 0 tokens
    testlib.blockstack_send_tokens(wallets[1].addr, "STACKS", 0, wallets[0].privkey, safety_checks=False, expect_fail=True)
    testlib.next_block(**kw)

    assert virtualchain.lib.indexer.StateEngine.get_block_statistics(testlib.get_current_block(**kw))['num_processed_ops'] == 0
Пример #22
0
def replace_output_with_bech32(txhex, output_index, payment_key, addrhash):
    print 'txhex: {}'.format(txhex)
    tx = virtualchain.btc_tx_deserialize(txhex)

    new_tx = {
        'locktime': 0,
        'version': 1,
        'ins': tx['ins'],
        'outs': tx['outs'],
    }

    for inp in new_tx['ins']:
        inp['script'] = ''
        inp['witness_script'] = ''

    new_tx['outs'][output_index] = {
        'script': '0014' + addrhash,
        'value': tx['outs'][output_index]['value']
    }

    unsigned_txhex = virtualchain.btc_tx_serialize(new_tx)
    print 'unsigned: {}'.format(unsigned_txhex)

    addr = virtualchain.address_reencode(
        virtualchain.get_privkey_address(payment_key))
    utxos = testlib.get_utxos(addr)
    prev_outputs = [{
        'out_script': inp['out_script'],
        'value': inp['value']
    } for inp in utxos]

    signed_txhex = virtualchain.tx_sign_all_unsigned_inputs(
        payment_key, prev_outputs, unsigned_txhex)

    print 'signed: {}'.format(signed_txhex)

    res = testlib.broadcast_transaction(signed_txhex)
    assert 'error' not in res

    return res
    def _tx_pay_btc(txhex, privk, btc_paid, burn_addr):
        tx = virtualchain.btc_tx_deserialize(txhex)

        # up the burn amount 
        btc_price = blockstack.lib.scripts.price_name('baz', namespace, testlib.get_current_block(**kw))
        tx['outs'][2]['script'] = virtualchain.btc_make_payment_script(burn_addr)
        tx['outs'][2]['value'] = btc_paid

        tx['outs'][1]['value'] -= btc_paid

        # re-sign 
        for i in tx['ins']:
            i['script'] = ''

        txhex = virtualchain.btc_tx_serialize(tx)
        _addr = virtualchain.address_reencode(virtualchain.get_privkey_address(privk))
        txhex_signed = virtualchain.tx_sign_all_unsigned_inputs(privk, testlib.get_utxos(_addr), txhex)
        
        print txhex_signed
        res = testlib.broadcast_transaction(txhex_signed)
        assert 'error' not in res, res['error']
        return res
def encrypt_wallet(decrypted_wallet, password, test_legacy=False):
    """
    Encrypt the wallet.
    Return the encrypted dict on success
    Return {'error': ...} on error
    """
    
    if test_legacy:
        assert BLOCKSTACK_TEST, 'test_legacy only works in test mode'

    # must be conformant to the current schema
    if not test_legacy:
        jsonschema.validate(decrypted_wallet, WALLET_SCHEMA_CURRENT)

    owner_address = virtualchain.get_privkey_address(decrypted_wallet['owner_privkey'])
    payment_address = virtualchain.get_privkey_address(decrypted_wallet['payment_privkey'])
    data_pubkey = None
    data_privkey_info = None

    if decrypted_wallet.has_key('data_privkey'):

        # make sure data key is hex encoded
        data_privkey_info = decrypted_wallet.get('data_privkey', None)
        if not test_legacy:
            assert data_privkey_info

        if data_privkey_info:
            if not is_singlesig_hex(data_privkey_info):
                data_privkey_info = ecdsa_private_key(data_privkey_info).to_hex()

            if not virtualchain.is_singlesig(data_privkey_info):
                log.error('Invalid data private key')
                return {'error': 'Invalid data private key'}
        
        data_pubkey = ecdsa_private_key(data_privkey_info).public_key().to_hex()

            
    wallet = {
        'owner_addresses': [owner_address],
        'payment_addresses': decrypted_wallet['payment_addresses'],
        'version': decrypted_wallet['version'],
        'enc': None,        # to be filled in
    }

    if data_pubkey:
        wallet['data_pubkey'] = data_pubkey
        wallet['data_pubkeys'] = [data_pubkey]
    
    wallet_enc = {
        'owner_privkey': decrypted_wallet['owner_privkey'],
        'payment_privkey': decrypted_wallet['payment_privkey'],
    }

    if data_privkey_info:
        wallet_enc['data_privkey'] = data_privkey_info

    # extra sanity check: make sure that when re-combined with the wallet,
    # we're still valid 
    recombined_wallet = copy.deepcopy(wallet)
    recombined_wallet.update(wallet_enc)
    try:
        jsonschema.validate(recombined_wallet, WALLET_SCHEMA_CURRENT)
    except ValidationError as ve:
        if test_legacy:
            # no data key is allowed if we're testing the absence of a data key 
            jsonschema.validate(recombined_wallet, WALLET_SCHEMA_CURRENT_NODATAKEY)
        else:
            raise

    # good to go!
    # encrypt secrets 
    wallet_secret_str = json.dumps(wallet_enc, sort_keys=True)
    password_hex = hexlify(password)
    encrypted_secret_str = aes_encrypt(wallet_secret_str, password_hex)

    # fulfill wallet
    wallet['enc'] = encrypted_secret_str
    
    # sanity check
    try:
        jsonschema.validate(wallet, ENCRYPTED_WALLET_SCHEMA_CURRENT)
    except ValidationError as ve:
        if test_legacy:
            jsonschema.validate(wallet, ENCRYPTED_WALLET_SCHEMA_CURRENT_NODATAKEY)
        else:
            raise

    return wallet
def scenario(wallets, **kw):
    global pk

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

    # all names below are the same price
    testlib.blockstack_namespace_reveal(
        "test",
        wallets[1].addr,
        52595,
        250,
        4, [6, 6, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        1,
        1,
        wallets[0].privkey,
        version_bits=blockstack.lib.config.NAMESPACE_VERSION_PAY_TO_CREATOR)
    testlib.next_block(**kw)

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

    # pay for a name in a v1 namespace with Stacks
    addr = virtualchain.address_reencode(virtualchain.get_privkey_address(pk))

    # calculate the cost of doing so
    namespace = testlib.get_state_engine().get_namespace('test')
    stacks_price = blockstack.lib.scripts.price_name_stacks(
        'foo', namespace, testlib.get_current_block(**kw))
    btc_price = blockstack.lib.scripts.price_name(
        'foo', namespace, testlib.get_current_block(**kw))

    print ''
    print 'price of {} in Stacks is {}'.format('foo.test', stacks_price)
    print ''

    testlib.blockstack_send_tokens(addr, "STACKS", stacks_price * 5,
                                   wallets[0].privkey)
    testlib.send_funds(wallets[0].privkey, btc_price * 10, addr)
    testlib.next_block(**kw)

    # preorder/register using Stacks (preorders should fail since we're using the wrong burn address for tokens)
    testlib.blockstack_name_preorder("foo.test",
                                     pk,
                                     wallets[3].addr,
                                     price={
                                         'units': 'STACKS',
                                         'amount': stacks_price
                                     },
                                     burn_addr=wallets[0].addr,
                                     safety_checks=False,
                                     expect_fail=True)
    testlib.blockstack_name_preorder("bar.test",
                                     pk,
                                     wallets[3].addr,
                                     price={
                                         'units': 'STACKS',
                                         'amount': stacks_price - 1
                                     },
                                     burn_addr=wallets[0].addr,
                                     safety_checks=False,
                                     expect_fail=True)
    testlib.next_block(**kw)

    op_info = virtualchain.lib.indexer.StateEngine.get_block_statistics(
        testlib.get_current_block(**kw))
    if op_info['num_processed_ops'] > 0:
        print 'handled ops this block'
        print op_info
        return False

    # preorder/register using Stacks (preorders should be accepted, but bar2 will fail to register)
    testlib.blockstack_name_preorder(
        "foo2.test",
        pk,
        wallets[2].addr,
        price={
            'units': 'STACKS',
            'amount': stacks_price
        },
        burn_addr=blockstack.lib.config.BLOCKSTACK_BURN_ADDRESS,
        safety_checks=False)
    testlib.blockstack_name_preorder(
        "bar2.test",
        pk,
        wallets[2].addr,
        price={
            'units': 'STACKS',
            'amount': stacks_price - 1
        },
        burn_addr=blockstack.lib.config.BLOCKSTACK_BURN_ADDRESS,
        safety_checks=False)
    testlib.next_block(**kw)

    # preorder/register using Stacks (preorders should succeed now, but bar3.test will fail to register since we're not paying enough stacks)
    testlib.blockstack_name_register(
        "bar2.test", pk, wallets[2].addr
    )  # should fail at this point, since the preorder sent to the wrong burn address
    testlib.blockstack_name_register(
        "foo2.test", pk, wallets[2].addr
    )  # should fail at this point, since the preorder sent to the wrong burn address

    testlib.blockstack_name_preorder(
        "foo3.test",
        pk,
        wallets[2].addr,
        price={
            'units': 'STACKS',
            'amount': stacks_price
        },
        burn_addr=blockstack.lib.config.BLOCKSTACK_BURN_ADDRESS,
        safety_checks=False)
    testlib.blockstack_name_preorder(
        "bar3.test",
        pk,
        wallets[2].addr,
        price={
            'units': 'STACKS',
            'amount': stacks_price - 1
        },
        burn_addr=blockstack.lib.config.BLOCKSTACK_BURN_ADDRESS,
        safety_checks=False)
    testlib.next_block(**kw)
    testlib.expect_snv_fail_at('bar2.test', testlib.get_current_block(**kw))
    testlib.expect_snv_fail_at('foo2.test', testlib.get_current_block(**kw))

    # tokens are not yet accepted
    if testlib.get_state_engine().get_name('bar2.test'):
        print 'registered bar2.test'
        return False

    if testlib.get_state_engine().get_name('foo2.test'):
        print 'registered foo2.test'
        return False

    # preorder/register using Stacks (should succeed without safety checks or overrides)
    testlib.blockstack_name_preorder("foo.test",
                                     pk,
                                     wallets[2].addr,
                                     price={
                                         'units': 'STACKS',
                                         'amount': stacks_price
                                     })
    testlib.next_block(**kw)

    testlib.blockstack_name_register("foo.test", pk,
                                     wallets[2].addr)  # should succeed
    testlib.blockstack_name_register("bar2.test", pk,
                                     wallets[2].addr)  # should fail
    testlib.blockstack_name_register("foo2.test", pk,
                                     wallets[2].addr)  # should succeed
    testlib.blockstack_name_register("bar3.test", pk,
                                     wallets[2].addr)  # should fail
    testlib.blockstack_name_register("foo3.test", pk,
                                     wallets[2].addr)  # should succeed
    testlib.next_block(**kw)
    testlib.expect_snv_fail_at('bar2.test', testlib.get_current_block(**kw))
    testlib.expect_snv_fail_at('bar3.test', testlib.get_current_block(**kw))

    if testlib.get_state_engine().get_name('bar2.test'):
        print 'registered bar2.test'
        return False

    if testlib.get_state_engine().get_name('bar3.test'):
        print 'registered bar3.test'
        return False
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

    if ns['version'] != blockstack.lib.config.NAMESPACE_VERSION_PAY_TO_CREATOR:
        print 'wrong version'
        return False

    addr = virtualchain.address_reencode(virtualchain.get_privkey_address(pk))

    for name in [
            'foo.test', 'bar2.test', 'foo2.test', 'bar3.test', 'foo3.test'
    ]:
        # not preordered, unless bar2.test
        stacks_price = blockstack.lib.scripts.price_name_stacks(
            name.split('.')[0], ns, state_engine.lastblock)
        preorder = state_engine.get_name_preorder(
            name, virtualchain.make_payment_script(addr), wallets[2].addr)
        if name == 'bar2.test' or name == 'bar3.test':
            if preorder is None:
                print 'missing {} preorder'.format(name)
                return False

            if preorder['token_fee'] != stacks_price - 1:
                print 'wrong token fee for {}'.format(name)
                return False

            if preorder['op_fee'] > 5500:
                print 'paid too much btc'
                return False

            continue

        else:
            if preorder is not None:
                print "preorder exists for {}".format(name)
                return False

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

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

        # paid with Stacks in all 3 cases, and not Bitcoin
        if name_rec['token_fee'] != stacks_price:
            print 'paid wrong token fee'
            print 'expected {} ({}), got {} ({})'.format(
                stacks_price, type(stacks_price), name_rec['token_fee'],
                type(name_rec['token_fee']))
            return False

        if name_rec['op_fee'] > 5500:  # dust minimum
            print 'paid in BTC ({})'.format(name_rec['op_fee'])
            return False

    return True
Пример #27
0
    testlib.Wallet( "5J39aXEeHh9LwfQ4Gy5Vieo7sbqiUMBXkPH7SaMHixJhSSBpAqz", 100000000000 ),
    testlib.Wallet( "5K9LmMQskQ9jP1p7dyieLDAeB6vsAj4GK8dmGNJAXS1qHDqnWhP", 100000000000 ),
    testlib.Wallet( "5KcNen67ERBuvz2f649t9F2o1ddTjC5pVUEqcMtbxNgHqgxG2gZ", 100000000000 ),
    testlib.Wallet( "5KMbNjgZt29V6VNbcAmebaUT2CZMxqSridtM46jv4NkKTP8DHdV", 100000000000 ),
]

consensus = "17ac43c1d8549c3181b200f1bf97eb7d"
wallet_keys = None
wallet_keys_2 = None
error = False

index_file_data = "<html><head></head><body>foo.test hello world</body></html>"
resource_data = "hello world"

new_key = "cPo24qGYz76xSbUCug6e8LzmzLGJPZoowQC7fCVPLN2tzCUJgfcW"
new_addr = virtualchain.get_privkey_address(new_key)  # "mqnupoveYRrSHmrxFT9nQQEZt3RLsetbBQ"

insanity_key = "cSCyE5Q1AFVyDAL8LkHo1sFMVqmwdvFcCbGJ71xEvto2Nrtzjm67"

def scenario( wallets, **kw ):

    global wallet_keys, wallet_keys_2, error, index_file_data, resource_data

    wallet_keys = testlib.blockstack_client_initialize_wallet( "0123456789abcdef", wallets[5].privkey, wallets[3].privkey, wallets[4].privkey )
    test_proxy = testlib.TestAPIProxy()
    blockstack_client.set_default_proxy( test_proxy )

    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.Wallet( "5J39aXEeHh9LwfQ4Gy5Vieo7sbqiUMBXkPH7SaMHixJhSSBpAqz", 100000000000 ),
    testlib.Wallet( "5K9LmMQskQ9jP1p7dyieLDAeB6vsAj4GK8dmGNJAXS1qHDqnWhP", 100000000000 ),
    testlib.Wallet( "5KcNen67ERBuvz2f649t9F2o1ddTjC5pVUEqcMtbxNgHqgxG2gZ", 100000000000 ),
    testlib.Wallet( "5KMbNjgZt29V6VNbcAmebaUT2CZMxqSridtM46jv4NkKTP8DHdV", 100000000000 ),
]

consensus = "17ac43c1d8549c3181b200f1bf97eb7d"
wallet_keys = None
wallet_keys_2 = None
error = False

index_file_data = "<html><head></head><body>foo.test hello world</body></html>"
resource_data = "hello world"

new_key = "cPo24qGYz76xSbUCug6e8LzmzLGJPZoowQC7fCVPLN2tzCUJgfcW"
new_addr = virtualchain.get_privkey_address(new_key)
# "mqnupoveYRrSHmrxFT9nQQEZt3RLsetbBQ"

insanity_key = "cSCyE5Q1AFVyDAL8LkHo1sFMVqmwdvFcCbGJ71xEvto2Nrtzjm67"

def scenario( wallets, **kw ):

    global wallet_keys, wallet_keys_2, error, index_file_data, resource_data

    wallet_keys = testlib.blockstack_client_initialize_wallet( "0123456789abcdef", wallets[5].privkey, wallets[3].privkey, wallets[4].privkey )
    test_proxy = testlib.TestAPIProxy()
    blockstack_client.set_default_proxy( test_proxy )

    testlib.blockstack_namespace_preorder( "test", wallets[1].addr, wallets[0].privkey )
    testlib.next_block( **kw )
Пример #29
0
def scenario(wallets, **kw):

    global wallet_keys, wallet_keys_2, error, index_file_data, resource_data

    empty_key = ECPrivateKey().to_hex()

    wallet_keys = testlib.ysi_client_initialize_wallet("0123456789abcdef",
                                                       empty_key, empty_key,
                                                       empty_key)
    test_proxy = testlib.TestAPIProxy()
    ysi_client.set_default_proxy(test_proxy)

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

    testlib.ysi_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.ysi_namespace_ready("test", wallets[1].privkey)
    testlib.next_block(**kw)

    # tell serialization-checker that value_hash can be ignored here
    print "BLOCKSTACK_SERIALIZATION_CHECK_IGNORE value_hash"
    sys.stdout.flush()

    testlib.next_block(**kw)

    config_path = os.environ.get("BLOCKSTACK_CLIENT_CONFIG", None)

    config_dir = os.path.dirname(config_path)
    conf = ysi_client.get_config(config_path)
    assert conf

    api_pass = conf['api_password']

    payment_key = wallets[1].privkey

    # make zonefile for recipient
    driver_urls = ysi_client.storage.make_mutable_data_urls(
        'bar.test', use_only=['dht', 'disk'])
    zonefile = ysi_client.zonefile.make_empty_zonefile('bar.test',
                                                       wallets[4].pubkey_hex,
                                                       urls=driver_urls)
    zonefile_txt = ysi_zones.make_zone_file(zonefile,
                                            origin='bar.test',
                                            ttl=3600)

    no_key_postage = {'name': 'bar.test', 'zonefile': zonefile_txt}
    key_postage = dict(no_key_postage)
    key_postage['payment_key'] = payment_key
    key_postage['owner_key'] = new_key

    res = testlib.ysi_REST_call('POST',
                                '/v1/names',
                                None,
                                api_pass=api_pass,
                                data=no_key_postage)
    if 'error' not in res['response']:
        print "Successfully registered user with should-have-been-bad keys"
        print res
        return False

    # let's do a small withdraw
    res = testlib.ysi_REST_call(
        'POST',
        '/v1/wallet/balance',
        None,
        api_pass=api_pass,
        data={
            'address': virtualchain.get_privkey_address(empty_key),
            'amount': int(1e4),
            'payment_key': payment_key
        })
    if 'error' in res['response']:
        res['test'] = 'Failed to perform withdraw'
        print json.dumps(res)
        error = True
        return False
    for i in xrange(0, 1):
        testlib.next_block(**kw)
    print 'Waiting for the withdraw to go through'
    res = testlib.ysi_REST_call('GET',
                                '/v1/wallet/balance/0',
                                None,
                                api_pass=api_pass)
    if 'error' in res['response']:
        res['test'] = 'Failed to get wallet balance'
        print json.dumps(res)
        error = True
        return False

    if int(res['response']['balance']['satoshis']) <= 0:
        res['test'] = 'Wallet balance did not increment!'
        print json.dumps(res)
        error = True
        return False

    res = testlib.ysi_REST_call('POST',
                                '/v1/names',
                                None,
                                api_pass=api_pass,
                                data=key_postage)
    if 'error' in res['response']:
        res['test'] = 'Failed to register user'
        print json.dumps(res)
        error = True
        return False

    print "Registering bar.test"
    for i in xrange(0, 6):
        testlib.next_block(**kw)
    if not res:
        return False
    # wait for the preorder to get confirmed
    for i in xrange(0, 4):
        testlib.next_block(**kw)
    # wait for register to go through
    print 'Wait for register to be submitted'
    time.sleep(10)

    # wait for the register to get confirmed
    for i in xrange(0, 6):
        testlib.next_block(**kw)

    res = testlib.verify_in_queue(None,
                                  'bar.test',
                                  'register',
                                  None,
                                  api_pass=api_pass)
    if not res:
        return False

    for i in xrange(0, 4):
        testlib.next_block(**kw)

    print 'Wait for update to be submitted'
    time.sleep(10)

    # wait for update to get confirmed
    for i in xrange(0, 6):
        testlib.next_block(**kw)

    res = testlib.verify_in_queue(None,
                                  'bar.test',
                                  'update',
                                  None,
                                  api_pass=api_pass)
    if not res:
        print res
        print "update error in first update"
        return False

    for i in xrange(0, 4):
        testlib.next_block(**kw)

    print 'Wait for zonefile to be sent'
    time.sleep(10)

    res = testlib.ysi_REST_call("GET",
                                "/v1/names/bar.test",
                                None,
                                api_pass=api_pass)
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get name bar.test'
        print json.dumps(res)
        return False

    print res['response']

    zonefile_hash = res['response']['zonefile_hash']

    # should still be registered
    if res['response']['status'] != 'registered':
        print "register not complete"
        print json.dumps(res)
        return False

    # do we have the history for the name?
    res = testlib.ysi_REST_call("GET",
                                "/v1/names/bar.test/history",
                                None,
                                api_pass=api_pass)
    if 'error' in res or res['http_status'] != 200:
        res['test'] = "Failed to get name history for foo.test"
        print json.dumps(res)
        return False

    # valid history?
    hist = res['response']
    if len(hist.keys()) != 3:
        res['test'] = 'Failed to get update history'
        res['history'] = hist
        print json.dumps(res, indent=4, sort_keys=True)
        return False

    # get the zonefile
    res = testlib.ysi_REST_call(
        "GET",
        "/v1/names/bar.test/zonefile/{}".format(zonefile_hash),
        None,
        api_pass=api_pass)
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get name zonefile'
        print json.dumps(res)
        return False

    # same zonefile we put?
    if res['response']['zonefile'] != zonefile_txt:
        res['test'] = 'mismatched zonefile, expected\n{}\n'.format(
            zonefile_txt)
        print json.dumps(res)
        return False

    # okay, now let's try to do an update.
    # make zonefile for recipient
    driver_urls = ysi_client.storage.make_mutable_data_urls(
        'bar.test', use_only=['http', 'disk'])
    zonefile = ysi_client.zonefile.make_empty_zonefile('bar.test',
                                                       wallets[3].pubkey_hex,
                                                       urls=driver_urls)
    zonefile_txt = ysi_zones.make_zone_file(zonefile,
                                            origin='bar.test',
                                            ttl=3600)

    # let's do this update.
    res = testlib.ysi_REST_call('PUT',
                                '/v1/names/bar.test/zonefile',
                                None,
                                api_pass=api_pass,
                                data={
                                    'zonefile': zonefile_txt,
                                    'owner_key': new_key,
                                    'payment_key': payment_key
                                })
    if 'error' in res or res['http_status'] != 202:
        res['test'] = 'Failed to register user'
        print json.dumps(res)
        error = True
        return False
    else:
        print "Submitted update!"
        print res

    print 'Wait for update to be submitted'
    time.sleep(10)

    # wait for update to get confirmed
    for i in xrange(0, 6):
        testlib.next_block(**kw)

    res = testlib.verify_in_queue(None,
                                  'bar.test',
                                  'update',
                                  None,
                                  api_pass=api_pass)
    if not res:
        print "update error in second update"
        print res
        return False

    for i in xrange(0, 4):
        testlib.next_block(**kw)

    # wait for zonefile to propagate
    time.sleep(10)

    res = testlib.ysi_REST_call("GET",
                                "/v1/names/bar.test",
                                None,
                                api_pass=api_pass)
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get name bar.test'
        print json.dumps(res)
        return False

    zonefile_hash = res['response']['zonefile_hash']
    # get the zonefile
    res = testlib.ysi_REST_call(
        "GET",
        "/v1/names/bar.test/zonefile/{}".format(zonefile_hash),
        None,
        api_pass=api_pass)
    if 'error' in res or res['http_status'] != 200:
        res['test'] = 'Failed to get name zonefile'
        print json.dumps(res)
        return False

    # same zonefile we put?
    if res['response']['zonefile'] != zonefile_txt:
        res['test'] = 'mismatched zonefile, expected\n{}\n'.format(
            zonefile_txt)
        print json.dumps(res)
        return False
Пример #30
0
def scenario(wallets, **kw):
    global pk, pk2

    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, 6, 6, 6, 6, 6, 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)

    # pay for a name in a v1 namespace with Stacks
    addr = virtualchain.address_reencode(virtualchain.get_privkey_address(pk))
    addr2 = virtualchain.address_reencode(
        virtualchain.get_privkey_address(pk2))

    # calculate the cost of doing so
    namespace = testlib.get_state_engine().get_namespace('test')
    stacks_price = blockstack.lib.scripts.price_name_stacks(
        'baz', namespace, testlib.get_current_block(**kw))
    btc_price = blockstack.lib.scripts.price_name(
        'baz', namespace, testlib.get_current_block(**kw))

    print ''
    print 'price of {} in Stacks is {}'.format('baz.test', stacks_price)
    print 'price of {} in BTC is {}'.format('baz.test', btc_price)
    print ''

    testlib.blockstack_send_tokens(addr, "STACKS", stacks_price,
                                   wallets[0].privkey)
    testlib.blockstack_send_tokens(addr2, "STACKS", stacks_price * 2,
                                   wallets[0].privkey)
    testlib.send_funds(wallets[0].privkey, 10 * btc_price, addr)
    testlib.send_funds(wallets[0].privkey, 10 * btc_price, addr2)
    testlib.next_block(**kw)

    # preorder/register using Stacks
    testlib.blockstack_name_preorder("baz.test",
                                     wallets[2].privkey,
                                     addr2,
                                     price={
                                         'units': 'STACKS',
                                         'amount': stacks_price
                                     })
    testlib.blockstack_name_preorder("goo.test",
                                     wallets[2].privkey,
                                     addr2,
                                     price={
                                         'units': 'STACKS',
                                         'amount': stacks_price
                                     })
    testlib.blockstack_name_preorder("nop.test",
                                     wallets[2].privkey,
                                     addr2,
                                     price={
                                         'units': 'STACKS',
                                         'amount': stacks_price
                                     })
    testlib.next_block(**kw)

    testlib.blockstack_name_register("baz.test", wallets[2].privkey, addr2)
    testlib.blockstack_name_register("goo.test", wallets[2].privkey, addr2)
    testlib.blockstack_name_register("nop.test", wallets[2].privkey, addr2)
    testlib.next_block(**kw)

    balance_before = testlib.get_addr_balances(addr2)[addr2]['STACKS']

    # pay with both Stacks and Bitcoin
    # should favor Stacks payment over Bitcoin payment if we pay enough stacks.
    # Stacks should have been burned, as well as BTC.
    res = testlib.blockstack_name_renew('baz.test',
                                        pk2,
                                        price={
                                            'units': 'STACKS',
                                            'amount': stacks_price
                                        },
                                        tx_only=True,
                                        expect_success=True)
    txhex = res['transaction']
    tx = virtualchain.btc_tx_deserialize(txhex)

    # up the burn amount
    btc_price = blockstack.lib.scripts.price_name(
        'baz', namespace, testlib.get_current_block(**kw))
    tx['outs'][3]['script'] = virtualchain.btc_make_payment_script(
        blockstack.lib.config.BLOCKSTACK_BURN_ADDRESS)
    tx['outs'][3]['value'] = btc_price

    tx['outs'][4]['value'] -= btc_price

    # re-sign
    for i in tx['ins']:
        i['script'] = ''

    txhex = virtualchain.btc_tx_serialize(tx)
    txhex_signed = virtualchain.tx_sign_all_unsigned_inputs(
        pk2, testlib.get_utxos(addr2), txhex)

    # re-sign the last output with the payment key
    tx_signed = virtualchain.btc_tx_deserialize(txhex_signed)
    tx_signed['ins'][-1]['script'] = ''
    txhex_signed = virtualchain.tx_sign_all_unsigned_inputs(
        testlib.get_default_payment_wallet().privkey,
        testlib.get_utxos(testlib.get_default_payment_wallet().addr),
        virtualchain.btc_tx_serialize(tx_signed))

    print txhex_signed

    res = testlib.broadcast_transaction(txhex_signed)
    if 'error' in res:
        print res
        return False

    testlib.next_block(**kw)

    # should have paid in Stacks
    balance_after = testlib.get_addr_balances(addr2)[addr2]['STACKS']
    if balance_after != balance_before - stacks_price:
        print 'baz.test cost {}'.format(balance_before - balance_after)
        return False

    balance_before = testlib.get_addr_balances(addr2)[addr2]['STACKS']

    # try to renew a name where we pay not enough stacks, but enough bitcoin.
    # should be rejected.
    res = testlib.blockstack_name_renew('goo.test',
                                        pk2,
                                        price={
                                            'units': 'STACKS',
                                            'amount': stacks_price - 1
                                        },
                                        tx_only=True)
    txhex = res['transaction']
    tx = virtualchain.btc_tx_deserialize(txhex)

    # up the burn amount to the name price
    btc_price = blockstack.lib.scripts.price_name(
        'goo', namespace, testlib.get_current_block(**kw))
    tx['outs'][3]['script'] = virtualchain.btc_make_payment_script(
        blockstack.lib.config.BLOCKSTACK_BURN_ADDRESS)
    tx['outs'][3]['value'] = btc_price

    tx['outs'][4]['value'] -= btc_price

    # re-sign
    for i in tx['ins']:
        i['script'] = ''

    txhex = virtualchain.btc_tx_serialize(tx)
    txhex_signed = virtualchain.tx_sign_all_unsigned_inputs(
        pk2, testlib.get_utxos(addr2), txhex)

    # re-sign the last output with the payment key
    tx_signed = virtualchain.btc_tx_deserialize(txhex_signed)
    tx_signed['ins'][-1]['script'] = ''
    txhex_signed = virtualchain.tx_sign_all_unsigned_inputs(
        testlib.get_default_payment_wallet().privkey,
        testlib.get_utxos(testlib.get_default_payment_wallet().addr),
        virtualchain.btc_tx_serialize(tx_signed))

    print txhex_signed

    res = testlib.broadcast_transaction(txhex_signed)
    if 'error' in res:
        print res
        return False

    testlib.next_block(**kw)

    # should NOT have paid in Stacks
    balance_after = testlib.get_addr_balances(addr2)[addr2]['STACKS']
    if balance_after != balance_before:
        print 'goo.test paid {}'.format(balance_before - balance_after)
        return False

    balance_before = testlib.get_addr_balances(addr2)[addr2]['STACKS']

    # underpay in both Stacks and Bitcoin.
    # only bitcoin will be burned; transaction will not be processed
    res = testlib.blockstack_name_renew('nop.test',
                                        pk2,
                                        price={
                                            'units': 'STACKS',
                                            'amount': stacks_price - 1
                                        },
                                        tx_only=True)
    txhex = res['transaction']
    tx = virtualchain.btc_tx_deserialize(txhex)

    # up the burn amount to the name price
    btc_price = blockstack.lib.scripts.price_name(
        'goo', namespace, testlib.get_current_block(**kw))
    tx['outs'][3]['script'] = virtualchain.btc_make_payment_script(
        blockstack.lib.config.BLOCKSTACK_BURN_ADDRESS)
    tx['outs'][3]['value'] = btc_price - 1

    tx['outs'][4]['value'] -= btc_price + 1

    # re-sign
    for i in tx['ins']:
        i['script'] = ''

    txhex = virtualchain.btc_tx_serialize(tx)
    txhex_signed = virtualchain.tx_sign_all_unsigned_inputs(
        pk2, testlib.get_utxos(addr2), txhex)

    # re-sign the last output with the payment key
    tx_signed = virtualchain.btc_tx_deserialize(txhex_signed)
    tx_signed['ins'][-1]['script'] = ''
    txhex_signed = virtualchain.tx_sign_all_unsigned_inputs(
        testlib.get_default_payment_wallet().privkey,
        testlib.get_utxos(testlib.get_default_payment_wallet().addr),
        virtualchain.btc_tx_serialize(tx_signed))

    print txhex_signed

    res = testlib.broadcast_transaction(txhex_signed)
    if 'error' in res:
        print res
        return False

    testlib.next_block(**kw)
    testlib.expect_snv_fail_at('nop.test', testlib.get_current_block(**kw))

    balance_after = testlib.get_addr_balances(addr2)[addr2]['STACKS']
    if balance_after != balance_before:
        print 'paid {} for nop.test'.format(balance_before - balance_after)
        return False
Пример #31
0
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

    # name should exist, but not be renewed
    addr2 = virtualchain.address_reencode(
        virtualchain.get_privkey_address(pk2))
    name_rec = state_engine.get_name('nop.test')
    if name_rec is None:
        print 'name record does not exist for nop.test'
        return False

    if name_rec['first_registered'] != name_rec['last_renewed']:
        print 'name nop.test was renewed'
        return False

    # name should exist, but not be renewed
    addr2 = virtualchain.address_reencode(
        virtualchain.get_privkey_address(pk2))
    name_rec = state_engine.get_name('goo.test')
    if name_rec is None:
        print 'name record does not exist for goo.test'
        return False

    if name_rec['first_registered'] != name_rec['last_renewed']:
        print 'name goo.test was renewed'
        return False

    for name in ['baz.test']:
        # not preordered
        preorder = state_engine.get_name_preorder(
            name, virtualchain.make_payment_script(wallets[2].addr), addr2)
        if preorder is not None:
            print "preorder exists"
            return False

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

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

    # paid for baz.test with Stacks, but nevertheless burned Bitcoin
    # however, baz.test's burn output is equal to the bitcoin price
    for name in ['baz']:
        name_rec = state_engine.get_name(name + '.test')
        stacks_price = blockstack.lib.scripts.price_name_stacks(
            name, ns, state_engine.lastblock)
        if name_rec['token_fee'] != stacks_price:
            print 'paid wrong token fee for {}.test'.format(name)
            print 'expected {} ({}), got {} ({})'.format(
                stacks_price, type(stacks_price), name_rec['token_fee'],
                type(name_rec['token_fee']))
            return False

        if name_rec['op_fee'] != blockstack.lib.scripts.price_name(
                name, ns, state_engine.lastblock):
            print 'paid wrong BTC for baz.test ({})'.format(name_rec['op_fee'])
            return False

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

    # pass 100 stacks around in a circle.
    new_keys = [wallets[0].privkey] + [
        virtualchain.lib.ecdsalib.ecdsa_private_key().to_hex()
        for i in range(0, 4)
    ]
    for k in range(0, 4):
        for j in range(0, len(new_keys)):
            i = j

            new_addr = virtualchain.get_privkey_address(
                new_keys[(i + 1) % len(new_keys)])
            cur_addr = virtualchain.get_privkey_address(
                new_keys[i % len(new_keys)])

            initial_new_balance_info = json.loads(
                testlib.nodejs_cli('balance', new_addr))
            initial_cur_balance_info = json.loads(
                testlib.nodejs_cli('balance', cur_addr))

            print '\n initial new balance info: {} \n'.format(
                initial_new_balance_info)

            if 'STACKS' not in initial_new_balance_info:
                initial_new_balance_info['STACKS'] = 0

            if i > 0:
                testlib.send_funds(wallets[0].privkey, 500000, cur_addr)

            testlib.send_funds(wallets[0].privkey, 500000, new_addr)

            testlib.blockstack_send_tokens(new_addr,
                                           'STACKS',
                                           100,
                                           new_keys[i % len(new_keys)],
                                           safety_checks=False)

            # consolidate
            utxos = testlib.get_utxos(wallets[0].addr)
            if len(utxos) > 1:
                balance = testlib.get_balance(wallets[0].addr)
                testlib.send_funds(wallets[0].privkey,
                                   balance - 5500,
                                   wallets[0].addr,
                                   change=False)

            utxos = testlib.get_utxos(new_addr)
            if len(utxos) > 1:
                balance = testlib.get_balance(new_addr)
                testlib.send_funds(new_keys[(i + 1) % len(new_keys)],
                                   balance - 5500,
                                   new_addr,
                                   change=False)

        testlib.next_block(**kw)

        for j in range(0, len(new_keys)):
            i = j

            new_addr = virtualchain.get_privkey_address(
                new_keys[(i + 1) % len(new_keys)])
            cur_addr = virtualchain.get_privkey_address(
                new_keys[i % len(new_keys)])

            if j == len(new_keys) - 1:
                if (i + 1) % len(new_keys) != 0:
                    # last address should have 100 stacks, unless new_addr is wallets[0]
                    balance_info = json.loads(
                        testlib.nodejs_cli('balance', new_addr))
                    assert int(balance_info['STACKS']) == 100

            else:
                if i % len(new_keys) != 0:
                    # every other address, except wallets[0], should have 0 balance
                    balance_info = json.loads(
                        testlib.nodejs_cli('balance', cur_addr))
                    assert int(balance_info['STACKS']) == 0

        # consolidate
        for j in range(0, len(new_keys)):
            cur_addr = virtualchain.get_privkey_address(
                new_keys[i % len(new_keys)])
            utxos = testlib.get_utxos(cur_addr)
            if len(utxos) > 1:
                balance = testlib.get_balance(cur_addr)
                testlib.send_funds(new_keys[i % len(new_keys)],
                                   balance - 5500,
                                   cur_addr,
                                   change=False)

        testlib.next_block(**kw)

    # each *new* address has 4 history items -- four spends, four receives
    for new_key in new_keys[1:]:
        new_addr = virtualchain.get_privkey_address(new_key)
        history = requests.get(
            'http://localhost:16268/v1/accounts/{}/history?page=0'.format(
                new_addr)).json()

        # should have gotten 4 debits for 100, and 4 credits for 100
        assert int(history[0]['credit_value']) == 400, history
        assert int(history[0]['debit_value']) == 400, history

        assert len(history) == 8, history
Пример #33
0
def make_wallet_keys(data_privkey=None,
                     owner_privkey=None,
                     payment_privkey=None):
    """
    For testing.  DO NOT USE
    """

    ret = {
        'owner_privkey': None,
        'data_privkey': None,
        'payment_privkey': None,
    }

    if data_privkey is not None:
        if not virtualchain.is_singlesig(data_privkey):
            raise ValueError('Invalid data key info')

        pk_data = ecdsa_private_key(data_privkey).to_hex()
        ret['data_privkey'] = pk_data

    if owner_privkey is not None:
        if virtualchain.is_multisig(owner_privkey):
            pks = owner_privkey['private_keys']
            m, _ = virtualchain.parse_multisig_redeemscript(
                owner_privkey['redeem_script'])
            assert m <= len(pks)

            multisig_info = virtualchain.make_multisig_info(m, pks)
            ret['owner_privkey'] = multisig_info
            ret['owner_addresses'] = [
                virtualchain.get_privkey_address(multisig_info)
            ]

        elif virtualchain.is_singlesig(owner_privkey):
            pk_owner = ecdsa_private_key(owner_privkey).to_hex()
            ret['owner_privkey'] = pk_owner
            ret['owner_addresses'] = [
                virtualchain.get_privkey_address(pk_owner)
            ]

        else:
            raise ValueError('Invalid owner key info')

    if payment_privkey is None:
        return ret

    if virtualchain.is_multisig(payment_privkey):
        pks = payment_privkey['private_keys']
        m, _ = virtualchain.parse_multisig_redeemscript(
            payment_privkey['redeem_script'])
        assert m <= len(pks)

        multisig_info = virtualchain.make_multisig_info(m, pks)
        ret['payment_privkey'] = multisig_info
        ret['payment_addresses'] = [
            virtualchain.get_privkey_address(multisig_info)
        ]

    elif virtualchain.is_singlesig(payment_privkey):
        pk_payment = ecdsa_private_key(payment_privkey).to_hex()
        ret['payment_privkey'] = pk_payment
        ret['payment_addresses'] = [
            virtualchain.get_privkey_address(pk_payment)
        ]

    else:
        raise ValueError('Invalid payment key info')

    ret['data_pubkey'] = ecdsa_private_key(
        ret['data_privkey']).public_key().to_hex()
    ret['data_pubkeys'] = [ret['data_pubkey']]

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

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

    # names last for 10 blocks
    testlib.blockstack_namespace_reveal(
        "id", wallets[1].addr, 10, 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("id", wallets[1].privkey)
    testlib.next_block(**kw)

    names_to_preorder_and_renew = '/tmp/testdata.txt'
    if os.path.exists(names_to_preorder_and_renew):
        name_infos = []
        with open(names_to_preorder_and_renew, 'r') as f:
            while True:
                name_line = f.readline()
                if len(name_line) == 0:
                    break

                name_line = name_line.strip()
                m = re.match('^([^ ]+)[ ]+([^ ]+)[ ]+([^ ]+)$', name_line)
                if m:
                    name, addr, pkey = m.groups()
                    name_infos.append({
                        'name': name.strip(),
                        'addr': addr.strip(),
                        'owner_privkey': pkey.strip()
                    })
                else:
                    name, addr = name_line.split(' ', 1)
                    name_infos.append({
                        'name': name.strip(),
                        'addr': addr.strip()
                    })

        for i, name_info in enumerate(name_infos):
            owner_addr = None
            if name_info.has_key('owner_privkey'):
                owner_addr = virtualchain.get_privkey_address(
                    name_info['owner_privkey'])
            else:
                print name_info['addr']
                owner_addr = virtualchain.address_reencode(name_info['addr'])

            testlib.blockstack_name_preorder(name_info['name'],
                                             wallets[(i % 8) + 2].privkey,
                                             owner_addr,
                                             safety_checks=False,
                                             tx_fee=300 * 1000)

        testlib.next_block(**kw)

        for i, name_info in enumerate(name_infos):
            owner_addr = None
            if name_info.has_key('owner_privkey'):
                owner_addr = virtualchain.get_privkey_address(
                    name_info['owner_privkey'])
            else:
                owner_addr = virtualchain.address_reencode(name_info['addr'])

            zonefile_hash = make_zonefile_hash(name_info['name'], owner_addr)
            testlib.blockstack_name_register(name_info['name'],
                                             wallets[(i % 8) + 2].privkey,
                                             owner_addr,
                                             zonefile_hash=zonefile_hash,
                                             safety_checks=False,
                                             tx_fee=300 * 1000)

        testlib.next_block(**kw)

    wallet = testlib.blockstack_client_initialize_wallet(
        "0123456789abcdef", wallets[2].privkey, wallets[3].privkey,
        wallets[4].privkey)

    print >> sys.stderr, "We're a go!"
Пример #35
0
def encrypt_wallet(decrypted_wallet, password, test_legacy=False):
    """
    Encrypt the wallet.
    Return the encrypted dict on success
    Return {'error': ...} on error
    """
    
    if test_legacy:
        assert BLOCKSTACK_TEST, 'test_legacy only works in test mode'

    # must be conformant to the current schema
    if not test_legacy:
        jsonschema.validate(decrypted_wallet, WALLET_SCHEMA_CURRENT)

    owner_address = virtualchain.get_privkey_address(decrypted_wallet['owner_privkey'])
    payment_address = virtualchain.get_privkey_address(decrypted_wallet['payment_privkey'])
    data_pubkey = None
    data_privkey_info = None

    if decrypted_wallet.has_key('data_privkey'):

        # make sure data key is hex encoded
        data_privkey_info = decrypted_wallet.get('data_privkey', None)
        if not test_legacy:
            assert data_privkey_info

        if data_privkey_info:
            if not is_singlesig_hex(data_privkey_info):
                data_privkey_info = ecdsa_private_key(data_privkey_info).to_hex()

            if not virtualchain.is_singlesig(data_privkey_info):
                log.error('Invalid data private key')
                return {'error': 'Invalid data private key'}
        
        data_pubkey = ecdsa_private_key(data_privkey_info).public_key().to_hex()

            
    wallet = {
        'owner_addresses': [owner_address],
        'payment_addresses': decrypted_wallet['payment_addresses'],
        'version': decrypted_wallet['version'],
        'enc': None,        # to be filled in
    }

    if data_pubkey:
        wallet['data_pubkey'] = data_pubkey
        wallet['data_pubkeys'] = [data_pubkey]
    
    wallet_enc = {
        'owner_privkey': decrypted_wallet['owner_privkey'],
        'payment_privkey': decrypted_wallet['payment_privkey'],
    }

    if data_privkey_info:
        wallet_enc['data_privkey'] = data_privkey_info

    # extra sanity check: make sure that when re-combined with the wallet,
    # we're still valid 
    recombined_wallet = copy.deepcopy(wallet)
    recombined_wallet.update(wallet_enc)
    try:
        jsonschema.validate(recombined_wallet, WALLET_SCHEMA_CURRENT)
    except ValidationError as ve:
        if test_legacy:
            # no data key is allowed if we're testing the absence of a data key 
            jsonschema.validate(recombined_wallet, WALLET_SCHEMA_CURRENT_NODATAKEY)
        else:
            raise

    # good to go!
    # encrypt secrets 
    wallet_secret_str = json.dumps(wallet_enc, sort_keys=True)
    password_hex = hexlify(password)
    encrypted_secret_str = aes_encrypt(wallet_secret_str, password_hex)

    # fulfill wallet
    wallet['enc'] = encrypted_secret_str
    
    # sanity check
    try:
        jsonschema.validate(wallet, ENCRYPTED_WALLET_SCHEMA_CURRENT)
    except ValidationError as ve:
        if test_legacy:
            jsonschema.validate(wallet, ENCRYPTED_WALLET_SCHEMA_CURRENT_NODATAKEY)
        else:
            raise

    return wallet