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 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
def scenario(wallets, **kw): global reveal_block global preorder_block res = testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey, tx_only=True, expect_fail=True) ns_preorder_txhex = res['transaction'] # change the burn address ns_preorder_tx = virtualchain.btc_tx_deserialize(ns_preorder_txhex) ns_preorder_tx['outs'][2]['script'] = virtualchain.btc_make_payment_script( wallets[2].addr) for i in ns_preorder_tx['ins']: i['script'] = '' utxos = testlib.get_utxos(wallets[0].addr) ns_preorder_txhex = virtualchain.btc_tx_serialize(ns_preorder_tx) ns_preorder_txhex_signed = virtualchain.tx_sign_all_unsigned_inputs( wallets[0].privkey, utxos, ns_preorder_txhex) print ns_preorder_txhex_signed res = testlib.broadcast_transaction(ns_preorder_txhex_signed) if 'error' in res: print res return False print res testlib.next_block(**kw) num_ops = virtualchain.lib.indexer.StateEngine.get_block_statistics( testlib.get_current_block(**kw)) if num_ops['num_parsed_ops'] != 1: print 'processed ops: {}'.format(num_ops) return False # try again, but use the right burn address testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) preorder_block = testlib.get_current_block(**kw) + 1 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) reveal_block = testlib.get_current_block(**kw) + 1 testlib.next_block(**kw)
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 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
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
def check_utxo_consumption(name_or_ns, payment_wallet, owner_wallet, data_wallet, operations, recipient_address, **kw): global small_unspents wallet = testlib.blockstack_client_initialize_wallet( "0123456789abcdef", payment_wallet.privkey, owner_wallet.privkey, data_wallet.privkey) test_proxy = testlib.TestAPIProxy() blockstack_client.set_default_proxy(test_proxy) # estimate the fee for the operation sequence fees = testlib.blockstack_cli_price(name_or_ns, "0123456789abcdef", recipient_address=recipient_address, operations=operations) if 'error' in fees: return fees print "without UTXOs:" print simplejson.dumps(fees, indent=4, sort_keys=True) # make a few small UTXOs for the payment address # count up the number of UTXOs that exist for this payment address payment_utxos = testlib.get_utxos(payment_wallet.addr) expected_utxo_count = len(payment_utxos) for i in xrange(0, 1): senders = wallets for sender in senders: if sender.privkey == payment_wallet.privkey: continue res = testlib.send_funds(sender.privkey, 10000, payment_wallet.addr) if 'error' in res: print simplejson.dumps(res, indent=4, sort_keys=True) return res expected_utxo_count += 1 small_unspents.append(res['transaction_hash']) testlib.next_block(**kw) # estimate the fee with all the UTXOs fees_utxos = testlib.blockstack_cli_price( name_or_ns, "0123456789abcdef", recipient_address=recipient_address, operations=operations) if 'error' in fees_utxos: return fees_utxos print "with UTXOs:" print simplejson.dumps(fees_utxos, indent=4, sort_keys=True) # all our operations should have similar fees, regardless of the UTXO set for tx_fee_key in ['{}_tx_fee'.format(op) for op in operations]: fee_diff = abs(fees[tx_fee_key]['satoshis'] - fees_utxos[tx_fee_key]['satoshis']) if fee_diff > 5500: print 'tx fees for {} disagree by {}'.format(tx_fee_key, fee_diff) return {'error': 'No appreciable fee change'} return {'status': True, 'expected_utxo_count': expected_utxo_count}
def scenario(wallets, **kw): global debug, consensus, small_unspents res = check_utxo_consumption( "test", wallets[0], wallets[1], wallets[2], ['namespace_preorder', 'namespace_reveal', 'namespace_ready'], wallets[1].addr, **kw) if 'error' in res: return False expected_utxo_count = res['expected_utxo_count'] # do the preorder resp = testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) if debug or 'error' in resp: print simplejson.dumps(resp, indent=4) testlib.next_block(**kw) # verify that all the small UTXOs are NOT consumed bitcoind = testlib.connect_bitcoind() bitcoind.ping() txdata = bitcoind.getrawtransaction(resp['transaction_hash'], 1) if len(txdata['vin']) != 1: print simplejson.dumps(txdata, indent=4) print "wrong number of inputs: {} != 1".format(len(txdata['vin'])) return False if spent_small_transaction(resp['transaction_hash']): return False # finish ordering the namespace resp = 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) if debug or 'error' in resp: print simplejson.dumps(resp, indent=4) if spent_small_transaction(resp['transaction_hash']): return False testlib.next_block(**kw) resp = testlib.blockstack_namespace_ready("test", wallets[1].privkey) if debug or 'error' in resp: print simplejson.dumps(resp, indent=4) if spent_small_transaction(resp['transaction_hash']): return False testlib.next_block(**kw) res = check_utxo_consumption( "foo.test", wallets[2], wallets[3], wallets[4], ['preorder', 'register', 'update', 'transfer'], wallets[4].addr, **kw) if 'error' in res: return False expected_utxo_count = res['expected_utxo_count'] resp = testlib.blockstack_name_preorder("foo.test", wallets[2].privkey, wallets[3].addr) if debug or 'error' in resp: print simplejson.dumps(resp, indent=4) if spent_small_transaction(resp['transaction_hash']): return False testlib.next_block(**kw) # verify that all the small UTXOs are NOT consumed bitcoind = testlib.connect_bitcoind() bitcoind.ping() txdata = bitcoind.getrawtransaction(resp['transaction_hash'], 1) if len(txdata['vin']) != 1: print simplejson.dumps(txdata, indent=4) print "wrong number of inputs: {} != {}".format( len(txdata['vin']), expected_utxo_count) return False # proceed to register resp = testlib.blockstack_name_register("foo.test", wallets[2].privkey, wallets[3].addr) if debug or 'error' in resp: print simplejson.dumps(resp, indent=4) if spent_small_transaction(resp['transaction_hash']): return False testlib.next_block(**kw) # verify that all the UTXOs are consumed bitcoind = testlib.connect_bitcoind() bitcoind.ping() txdata = bitcoind.getrawtransaction(resp['transaction_hash'], 1) if len(txdata['vin']) != 1: print simplejson.dumps(txdata, indent=4) print "wrong number of inputs: {} != {}".format( len(txdata['vin']), expected_utxo_count) return False # make a few small UTXOs for the preorder payment addr for i in xrange(0, 3): res = testlib.send_funds(wallets[1].privkey, 10000, testlib.get_default_payment_wallet().addr) if 'error' in res: print simplejson.dumps(res, indent=4, sort_keys=True) return False testlib.next_block(**kw) small_unspents.append(res['transaction_hash']) utxos = testlib.get_utxos(testlib.get_default_payment_wallet().addr) assert len(utxos) > 3 resp = testlib.blockstack_name_update("foo.test", "11" * 20, wallets[3].privkey) if debug or 'error' in resp: print simplejson.dumps(resp, indent=4) if spent_small_transaction(resp['transaction_hash']): return False consensus = testlib.get_consensus_at(testlib.get_current_block(**kw), **kw) testlib.next_block(**kw) # inspect the transaction: only 3 UTXOs should have been consumed (2 owner UTXOs and 1 payment UTXO) txdata = testlib.connect_bitcoind().getrawtransaction( resp['transaction_hash'], 1) if len(txdata['vin']) != 3: print simplejson.dumps(txdata, indent=4) print "too many inputs" return False # make a few more small UTXOs for the preorder payment addr for i in xrange(0, 3): res = testlib.send_funds(wallets[1].privkey, 10000, testlib.get_default_payment_wallet().addr) if 'error' in res: print simplejson.dumps(res, indent=4, sort_keys=True) return False testlib.next_block(**kw) small_unspents.append(res['transaction_hash']) utxos = testlib.get_utxos(testlib.get_default_payment_wallet().addr) assert len(utxos) > 3 resp = testlib.blockstack_name_transfer("foo.test", wallets[4].addr, True, wallets[3].privkey) if debug or 'error' in resp: print simplejson.dumps(resp, indent=4) # inspect the transaction: only 2 UTXOs should have been consumed (1 owner UTXO and 1 payment UTXO) txdata = testlib.connect_bitcoind().getrawtransaction( resp['transaction_hash'], 1) if len(txdata['vin']) != 2: print simplejson.dumps(txdata, indent=4) print "too many inputs" return False if spent_small_transaction(resp['transaction_hash']): return False testlib.next_block(**kw) # make a few more small UTXOs for the preorder payment addr for i in xrange(0, 3): res = testlib.send_funds(wallets[1].privkey, 10000, testlib.get_default_payment_wallet().addr) if 'error' in res: print simplejson.dumps(res, indent=4, sort_keys=True) return False testlib.next_block(**kw) small_unspents.append(res['transaction_hash']) utxos = testlib.get_utxos(testlib.get_default_payment_wallet().addr) assert len(utxos) > 3 resp = testlib.blockstack_name_renew("foo.test", wallets[4].privkey) if debug or 'error' in resp: print simplejson.dumps(resp, indent=4) # inspect the transaction: only 3 UTXOs should have been consumed (2 owner UTXO and 1 payment UTXO) # NOTE: produces two UTXOs: an "owner" utxo and the change for the owner address txdata = testlib.connect_bitcoind().getrawtransaction( resp['transaction_hash'], 1) if len(txdata['vin']) != 3: print simplejson.dumps(txdata, indent=4) print "too many inputs" return False if spent_small_transaction(resp['transaction_hash']): return False testlib.next_block(**kw) # make a few more small UTXOs for the preorder payment addr for i in xrange(0, 3): res = testlib.send_funds(wallets[1].privkey, 10000, testlib.get_default_payment_wallet().addr) if 'error' in res: print simplejson.dumps(res, indent=4, sort_keys=True) return False testlib.next_block(**kw) small_unspents.append(res['transaction_hash']) utxos = testlib.get_utxos(testlib.get_default_payment_wallet().addr) assert len(utxos) > 3 resp = testlib.blockstack_name_revoke("foo.test", wallets[4].privkey) if debug or 'error' in resp: print simplejson.dumps(resp, indent=4) # inspect the transaction: only 3 UTXOs should have been consumed (2 owner UTXO and 1 payment UTXO) txdata = testlib.connect_bitcoind().getrawtransaction( resp['transaction_hash'], 1) if len(txdata['vin']) != 3: print simplejson.dumps(txdata, indent=4) print "too many inputs" return False if spent_small_transaction(resp['transaction_hash']): return False testlib.next_block(**kw) '''
def scenario(wallets, **kw): segwit_addr_1 = get_segwit_address(wallets[1].privkey) segwit_addr_1_tb = get_segwit_address(wallets[1].privkey, hrp='tb') segwit_addr_0_tb = get_segwit_address(wallets[0].privkey, hrp='tb') print segwit_addr_0_tb print segwit_addr_1_tb pubk = virtualchain.lib.ecdsalib.ecdsa_private_key( wallets[1].privkey, compressed=True).public_key().to_hex() addrhash = virtualchain.lib.hashing.bin_hash160( pubk.decode('hex')).encode('hex') a = 'tb1pzjpqjwmz5d5e9qkey6vphmtkvh5rsn9225xsgg79' namespace_preorder_name_hash = blockstack.lib.hashing.hash_name( 'test', virtualchain.make_payment_script(wallets[0].addr), a) print 'hash of {} + {} + {} = {}'.format( 'test', virtualchain.make_payment_script(wallets[0].addr), a, namespace_preorder_name_hash) resp = testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey, tx_only=True) tx = virtualchain.btc_tx_deserialize(resp['transaction']) new_tx = { 'locktime': 0, 'version': 1, 'ins': tx['ins'], 'outs': tx['outs'], } for inp in new_tx['ins']: inp['script'] = '' inp['witness_script'] = '' print 'script before: {}'.format(tx['outs'][0]['script']) patched_script = virtualchain.make_data_script( 'id*'.encode('hex') + namespace_preorder_name_hash + tx['outs'][0]['script'].decode('hex')[25:].encode('hex')) print 'script after : {}'.format(patched_script) new_tx['outs'][0] = {'script': patched_script, 'value': 0} unsigned_txhex = virtualchain.btc_tx_serialize(new_tx) print 'unsigned: {}'.format(unsigned_txhex) addr = virtualchain.address_reencode( virtualchain.get_privkey_address(wallets[0].privkey)) 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( wallets[0].privkey, prev_outputs, unsigned_txhex) print 'signed: {}'.format(signed_txhex) res = testlib.broadcast_transaction(signed_txhex) assert 'error' not in res testlib.next_block(**kw) # should fail resp = 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, tx_only=True) resp = replace_output_with_bech32(resp['transaction'], 1, wallets[0].privkey, addrhash) testlib.next_block(**kw)
def scenario(wallets, **kw): global pk 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)) # 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 * 4, wallets[0].privkey) testlib.send_funds(wallets[0].privkey, btc_price * 10, addr) # fund with enough bitcoin testlib.next_block(**kw) # preorder/register using Stacks---Stacks should still be used since that's what the transaction indicates testlib.blockstack_name_preorder("foo.test", pk, wallets[3].addr, price={ 'units': 'STACKS', 'amount': stacks_price }) testlib.next_block(**kw) testlib.send_funds(wallets[0].privkey, btc_price * 10, addr) testlib.blockstack_name_register("foo.test", pk, wallets[3].addr) testlib.next_block(**kw) # preorder/register using Bitcoin--Stacks should NOT be used since that's what the transaction indicates testlib.blockstack_name_preorder("bar.test", pk, wallets[3].addr, price={ 'units': 'BTC', 'amount': btc_price }) testlib.next_block(**kw) testlib.blockstack_name_register('bar.test', pk, wallets[3].addr) testlib.next_block(**kw) balance_before = testlib.get_addr_balances(addr)[addr]['STACKS'] # pay with Stacks and Bitcoin. Preorder should succeed, and register should also succeed since we're paying enough stacks. Underpay bitcoin res = testlib.blockstack_name_preorder('baz.test', pk, wallets[3].addr, 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'][2]['script'] = virtualchain.btc_make_payment_script( blockstack.lib.config.BLOCKSTACK_BURN_ADDRESS) tx['outs'][2]['value'] = btc_price - 1 tx['outs'][1]['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( pk, testlib.get_utxos(addr), txhex) 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(addr)[addr]['STACKS'] if balance_after != balance_before - stacks_price: print 'baz.test cost {}'.format(balance_before - balance_after) return False # should succeed, since we paid enough stacks (Bitcoin is not considered) testlib.blockstack_name_register('baz.test', pk, wallets[3].addr) testlib.next_block(**kw) balance_before = testlib.get_addr_balances(addr)[addr]['STACKS'] # register a name where we pay not enough stacks, but enough bitcoin. preorder should succeed, but register should fail since we tried to use stacks res = testlib.blockstack_name_preorder('goo.test', pk, wallets[3].addr, price={ 'units': 'STACKS', 'amount': stacks_price - 1 }, tx_only=True, expect_success=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'][2]['script'] = virtualchain.btc_make_payment_script( blockstack.lib.config.BLOCKSTACK_BURN_ADDRESS) tx['outs'][2]['value'] = btc_price tx['outs'][1]['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( pk, testlib.get_utxos(addr), txhex) 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(addr)[addr]['STACKS'] if balance_after != balance_before - stacks_price + 1: print 'goo.test paid {}'.format(balance_before - balance_after) return False # should fail, since we tried to pay in stacks and didn't pay enough testlib.blockstack_name_register('goo.test', pk, wallets[3].addr) testlib.next_block(**kw) testlib.expect_snv_fail_at('goo.test', testlib.get_current_block(**kw)) if testlib.get_state_engine().get_name('goo.test') is not None: print 'registered goo.test' return False balance_before = testlib.get_addr_balances(addr)[addr]['STACKS'] # underpay in both Stacks and Bitcoin. # both stacks and bitcoin will be burned. # preorder should succeed, but register should fail. res = testlib.blockstack_name_preorder('nop.test', pk, wallets[3].addr, price={ 'units': 'STACKS', 'amount': stacks_price - 1 }, safety_checks=False, tx_only=True, expect_success=True) txhex = res['transaction'] tx = virtualchain.btc_tx_deserialize(txhex) # up the burn amount to the name price, but just under btc_price = blockstack.lib.scripts.price_name( 'nop', namespace, testlib.get_current_block(**kw)) tx['outs'][2]['script'] = virtualchain.btc_make_payment_script( blockstack.lib.config.BLOCKSTACK_BURN_ADDRESS) tx['outs'][2]['value'] = btc_price - 1 tx['outs'][1]['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( pk, testlib.get_utxos(addr), txhex) print txhex_signed res = testlib.broadcast_transaction(txhex_signed) if 'error' in res: print res return False testlib.next_block(**kw) # should fail, since we didn't pay enough stacks and tried to pay in stacks res = testlib.blockstack_name_register('nop.test', pk, wallets[3].addr) testlib.next_block(**kw) testlib.expect_snv_fail_at('nop.test', testlib.get_current_block(**kw)) # preorder should still have debited balance_after = testlib.get_addr_balances(addr)[addr]['STACKS'] if balance_after != balance_before - stacks_price + 1: print 'paid {} for nop.test'.format(balance_before - balance_after) return False