def send_subsidized( client_privkey, resp, **kw ): unsigned_tx = resp['subsidized_tx'] if client_privkey is not None: # sign all unsigned inputs tx = testlib.tx_sign_all_unsigned_inputs( unsigned_tx, client_privkey ) else: # already subsidized tx = unsigned_tx testlib.broadcast_transaction( tx )
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 _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 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): 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 scenario(wallets, **kw): # send a data-bearing transaction without 'id' tx = mktx(5500, 5500, wallets[1].addr, wallets[0].privkey, "eg") if 'error' in tx: print tx return False res = testlib.broadcast_transaction(tx) if 'error' in res: print res return False testlib.next_block(**kw) # send a data-bearing transaction with only 'id' tx = mktx(5500, 5500, wallets[1].addr, wallets[0].privkey, "id") if 'error' in tx: print tx return False res = testlib.broadcast_transaction(tx) if 'error' in res: print res return False testlib.next_block(**kw) # send a data-bearing transaction with an invalid opcode after 'id' tx = mktx(5500, 5500, wallets[1].addr, wallets[0].privkey, "id{") if 'error' in tx: print tx return False res = testlib.broadcast_transaction(tx) if 'error' in res: print res return False 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): 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 last_block # send a data-bearing transaction without 'id'. we shouldn't pick it up. tx = mktx(5500, 5500, wallets[1].addr, wallets[0].privkey, "eg") if 'error' in tx: print tx return False res = testlib.broadcast_transaction(tx) if 'error' in res: print res return False testlib.next_block(**kw) # send a data-bearing transaction with only 'id'. we should ignore it. tx = mktx(5500, 5500, wallets[1].addr, wallets[0].privkey, "id") if 'error' in tx: print tx return False res = testlib.broadcast_transaction(tx) if 'error' in res: print res return False testlib.next_block(**kw) # send a data-bearing transaction with an invalid opcode after 'id'. we should ignore it. tx = mktx(5500, 5500, wallets[1].addr, wallets[0].privkey, "id{") if 'error' in tx: print tx return False res = testlib.broadcast_transaction(tx) if 'error' in res: print res return False testlib.next_block(**kw) all_tests = {} # lifted from nameop_parsing_stacks, minus the "valid" tests # namespace preorder wire format # 0 2 3 23 39 47 # |-----|---|--------------------------------------|----------------|--------------------------| # magic op hash(ns_id,script_pubkey,reveal_addr) consensus hash token fee (little-endian) namespace_preorders = { "too_short": "%s%s%s" % ("11" * 20, "33" * 15, '00' * 7), "too_long": "%s%s%s" % ("11" * 20, "22" * 16, '00' * 9), "no_stacks": "%s%s" % ("11" * 20, "22" * 16) } all_tests["*"] = compile_test("*", namespace_preorders) # namespace reveal wire format # 0 2 3 7 8 9 10 11 12 13 14 15 16 17 18 20 39 # |-----|---|--------|-----|-----|----|----|----|----|----|-----|-----|-----|--------|----------|-------------------------| # magic op life coeff. base 1-2 3-4 5-6 7-8 9-10 11-12 13-14 15-16 nonalpha version namespace ID # bucket exponents no-vowel # discounts namespace_reveals = { "non-b38": "%s%s%s%s%s%s%s%s%s%s%s%s%s%s" % ("11111111", "02", "03", "40", "41", "42", "43", "44", "45", "46", "47", "15", "0001", binascii.hexlify("Hello")), "period2": "%s%s%s%s%s%s%s%s%s%s%s%s%s%s" % ("11111111", "02", "03", "40", "41", "42", "43", "44", "45", "46", "47", "15", "0001", binascii.hexlify("He.l.lo")), "period": "%s%s%s%s%s%s%s%s%s%s%s%s%s%s" % ("11111111", "02", "03", "40", "41", "42", "43", "44", "45", "46", "47", "15", "0001", binascii.hexlify(".")), "no-plus": "%s%s%s%s%s%s%s%s%s%s%s%s%s%s" % ("11111111", "02", "03", "40", "41", "42", "43", "44", "45", "46", "47", "15", "0001", binascii.hexlify("hel+lo")), "null_name": "%s%s%s%s%s%s%s%s%s%s%s%s%s%s" % ("11111111", "02", "03", "40", "41", "42", "43", "44", "45", "46", "47", "15", "0001", binascii.hexlify("")), "too_long": "%s%s%s%s%s%s%s%s%s%s%s%s%s%s" % ("11111111", "02", "03", "40", "41", "42", "43", "44", "45", "46", "47", "15", "0001", binascii.hexlify("hellohellohellohello")) } all_tests["&"] = compile_test("&", namespace_reveals) # namespace ready wire format # 0 2 3 4 23 # |-----|--|--|------------| # magic op . ns_id namespace_readys = { "non-b38": binascii.hexlify(".Hello"), "period": binascii.hexlify("."), "period2": binascii.hexlify(".hel.lo"), "no-plus": binascii.hexlify(".hel+lo"), "null_name": binascii.hexlify(""), "no-period": binascii.hexlify("hello"), "too_long": binascii.hexlify(".hellohellohellohello") } all_tests["!"] = compile_test("!", namespace_readys) # name preorder wire format # 0 2 3 23 39 47 66 # |-----|--|--------------------------------------|--------------|-----------|-------------| # magic op hash160(fqn,scriptPubkey,registerAddr) consensus hash token burn token type # (optional) (optional) name_preorders = { "too_short": "%s%s" % ("11" * 20, "33" * 15), "stacks_incomplete_short": "%s%s00" % ("11" * 20, "22" * 16), "stacks_incomplete_long": "%s%s%s" % ("11" * 20, "22" * 16, '00' * 7), "stacks_no_token_type": "%s%s%s" % ("11" * 20, "22" * 16, '00' * 8), "stacks_incomplete_token_type_short": "%s%s%s%s" % ("11" * 20, "22" * 16, '00' * 8, binascii.hexlify('a')), "stacks_incomplete_token_type_long": "%s%s%s%s" % ("11" * 20, "22" * 16, '00' * 8, binascii.hexlify('abcdefghijklmnopqr')), "stacks_too_long": "%s%s%s%s" % ("11" * 20, "22" * 16, '00' * 8, binascii.hexlify('abcdefghijklmnopqrst')), } all_tests["?"] = compile_test("?", name_preorders) # name register/renew wire format (pre F-day 2017) # 0 2 3 39 # |----|--|-----------------------------| # magic op name.ns_id (37 bytes) # name register/renew wire format (post F-day 2017) # 0 2 3 39 59 # |----|--|----------------------------------|-------------------| # magic op name.ns_id (37 bytes, 0-padded) value hash # With renewal payment in a token: # 0 2 3 39 59 67 # |----|--|----------------------------------|-------------------|------------------------------| # magic op name.ns_id (37 bytes, 0-padded) zone file hash tokens burned (little-endian) name_registrations = { "null_name": binascii.hexlify(""), "non-b38": binascii.hexlify("Hello.test"), "no-namespace": binascii.hexlify("hello"), "null-namespace": binascii.hexlify("hello."), "2period": binascii.hexlify("hello.tes.t"), "no-plus": binascii.hexlify("hel+lo.test"), "too-long": binascii.hexlify("hellohellohellohellohellohellohel.test"), "null_name_2": binascii.hexlify("\x00" * 37 + "\x11" * 20), "non-b38_2": binascii.hexlify("Hello.test" + "\x00" * 27 + "\x11" * 20), "no-namespace_2": binascii.hexlify("hello" + "\x00" * 32 + "\x11" * 20), "null-namespace_2": binascii.hexlify("hello." + "\x00" * 31 + "\x11" * 20), "2period_2": binascii.hexlify("hello.tes.t" + "\x00" * 26 + "\x11" * 20), "no-plus_2": binascii.hexlify("hel+lo.test" + "\x00" * 26 + "\x11" * 20), "too-long_2": binascii.hexlify("hellohellohellohellohellohellohel.test" + "\x11" * 20), "no_hash": binascii.hexlify("hello.test" + "\x00" * 27), "hash_too_long": binascii.hexlify("hello.test" + "\x00" * 27 + "\x11" * 21), "padding_too_short": binascii.hexlify("hello.test" + "\x00" * 26 + "\x11" * 21), "op_too_short": binascii.hexlify("hello.test" + "\x00" * 26 + "\x11" * 20), "stacks_too_short_1": binascii.hexlify("hello.test" + '\00' * 27 + '\x11' * 20 + '\x00'), "stacks_too_short_7": binascii.hexlify("hello.test" + '\00' * 27 + '\x11' * 20 + '\x00' * 7), "stacks_too_long": binascii.hexlify("hello.test" + '\00' * 27 + '\x11' * 20 + '\x00' * 9), } all_tests[":"] = compile_test(":", name_registrations) # name update wire format # 0 2 3 19 39 # |-----|--|-----------------------------------|-----------------------| # magic op hash128(name.ns_id,consensus hash) hash160(data) name_updates = { "too_short": "%s%s" % ("11" * 16, "33" * 19), "too_long": "%s%s00" % ("11" * 16, "22" * 20), } all_tests["+"] = compile_test("+", name_updates) # name transfer wire format # 0 2 3 4 20 36 # |-----|--|----|-------------------|---------------| # magic op keep hash128(name.ns_id) consensus hash # data? name_transfers = { "too_short": "%s%s%s" % (binascii.hexlify(">"), "11" * 16, "33" * 15), "too_long": "%s%s%s00" % (binascii.hexlify(">"), "11" * 16, "22" * 16), "too_short2": "%s%s%s" % (binascii.hexlify("~"), "11" * 16, "33" * 15), "too_long2": "%s%s%s00" % (binascii.hexlify("~"), "11" * 16, "22" * 16), "invalid-opcode": "%s%s%s" % (binascii.hexlify("!"), "11" * 16, "22" * 16) } all_tests[">"] = compile_test(">", name_transfers) # name revoke wire format # 0 2 3 39 # |----|--|-----------------------------| # magic op name.ns_id (37 bytes) name_revokes = { "null_name": binascii.hexlify(""), "non-b38": binascii.hexlify("Hello.test"), "no-namespace": binascii.hexlify("hello"), "null-namespace": binascii.hexlify("hello."), "2period": binascii.hexlify("hello.tes.t"), "no-plus": binascii.hexlify("hel+lo.test"), "too-long": binascii.hexlify("hellohellohellohellohellohellohel.test") } all_tests["~"] = compile_test("~", name_revokes) # name import wire format # 0 2 3 39 # |----|--|-----------------------------| # magic op name.ns_id (37 bytes) name_imports = { "null_name": binascii.hexlify(""), "non-b38": binascii.hexlify("Hello.test"), "no-namespace": binascii.hexlify("hello"), "null-namespace": binascii.hexlify("hello."), "2period": binascii.hexlify("hello.tes.t"), "no-plus": binascii.hexlify("hel+lo.test"), "too-long": binascii.hexlify("hellohellohellohellohellohellohel.test") } all_tests[";"] = compile_test(";", name_imports) # announce wire format # 0 2 3 23 # |----|--|-----------------------------| # magic op message hash (160-bit) announces = {"too-short": "11" * 19, "too-long": "11" * 21} all_tests["#"] = compile_test("#", announces) for opcode in all_tests.keys(): print '\n\n' print 'Running tests for {}'.format(opcode) print '\n\n' # queue tests for test_name in all_tests[opcode].keys(): payload = all_tests[opcode][test_name] print '\ntest {}: {}\n'.format(test_name, payload) tx = mktx(5500, 5500, wallets[1].addr, wallets[0].privkey, payload.decode('hex')) if 'error' in tx: print tx return False print 'tx: {}'.format(tx) res = testlib.broadcast_transaction(tx) if 'error' in res: print res return False # feed through virtualchain. they should all be rejected by the parser testlib.next_block(**kw) last_block = testlib.get_current_block(**kw)
def scenario(wallets, **kw): namespace_price_old_btc_2 = { 'units': 'BTC', 'amount': blockstack.lib.scripts.price_namespace('old_btc_2', 694, 'BTC') } namespace_price_stacks_too_early_1_btc = { 'units': 'BTC', 'amount': blockstack.lib.scripts.price_namespace('stacks_too_early_1', 690, 'BTC') } namespace_price_stacks_too_early_2_stacks = { 'units': 'STACKS', 'amount': blockstack.lib.scripts.price_namespace('stacks_too_early_1', 694, 'STACKS') } testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) testlib.blockstack_namespace_preorder( "stacks_too_early_1", wallets[1].addr, wallets[0].privkey, safety_checks=False, price=namespace_price_stacks_too_early_1_btc, tx_fee=50000) testlib.blockstack_namespace_preorder("old_btc_1", wallets[1].addr, wallets[0].privkey) btc_too_late_tx = testlib.blockstack_namespace_preorder('btc_too_late', wallets[1].addr, wallets[2].privkey, tx_only=True) print '' print btc_too_late_tx print '' testlib.next_block(**kw) # end of 689 # should be accepted 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) # the stacks_too_early namespace cannot be revealed (i.e. its preorder got rejected) testlib.blockstack_namespace_reveal( "stacks_too_early_1", 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, safety_checks=False, tx_fee=50000) testlib.next_block(**kw) # end of 690 testlib.expect_snv_fail_at('stacks_too_early_1', testlib.get_current_block(**kw)) res = testlib.blockstack_cli_get_namespace_blockchain_record('test') if 'error' in res: print 'test was not revealed' print res return False res = testlib.blockstack_cli_get_namespace_blockchain_record( 'stacks_too_early_1') if 'error' not in res: print 'stacks too early 1 was revealed' print res return False testlib.blockstack_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) # end of 691 testlib.next_block(**kw) # end of 692 # should succeed---last block we can pay in BTC testlib.blockstack_namespace_preorder("old_btc_2", wallets[1].addr, wallets[0].privkey, price=namespace_price_old_btc_2) # should be rejected---this is one block early testlib.blockstack_namespace_preorder( "stacks_too_early_2", wallets[1].addr, wallets[0].privkey, safety_checks=False, price=namespace_price_stacks_too_early_2_stacks, tx_fee=50000, expect_reject=True) testlib.next_block(**kw) # end of 693 testlib.expect_snv_fail_at('stacks_too_early_2', testlib.get_current_block(**kw)) # should succeed even though preordered with BTC testlib.blockstack_namespace_reveal( "old_btc_1", 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) # should fail -- no preorder testlib.blockstack_namespace_reveal( "stacks_too_early_2", 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, safety_checks=False, tx_fee=50000) # should be rejected---it's a block too late testlib.broadcast_transaction(btc_too_late_tx['transaction']) testlib.next_block(**kw) # end of 694 testlib.expect_snv_fail_at('stacks_too_early_2', testlib.get_current_block(**kw)) res = testlib.blockstack_cli_get_namespace_blockchain_record( 'stacks_too_early_2') if 'error' not in res: print 'stacks too early 2 was revealed' print res return False res = testlib.blockstack_cli_get_namespace_blockchain_record('old_btc_1') if 'error' in res: print 'old_btc_1 not revealed' print res return False # should succeed, even though we're in the STACKS epoch testlib.blockstack_namespace_reveal( "old_btc_2", 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) # should fail, since the preorer for btc_too_late was sent too late testlib.blockstack_namespace_reveal( "btc_too_late", 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[2].privkey, version_bits=blockstack.NAMESPACE_VERSION_PAY_WITH_STACKS) testlib.next_block(**kw) # end of 695 testlib.expect_snv_fail_at('btc_too_late', testlib.get_current_block(**kw)) res = testlib.blockstack_cli_get_namespace_blockchain_record('old_btc_2') if 'error' in res: print 'failed to reveal btc 2' print res return False res = testlib.blockstack_cli_get_namespace_blockchain_record( 'btc_too_late') if 'error' not in res: print 'revealed btc_too_late' print res return False
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
def scenario(wallets, **kw): testlib.blockstack_namespace_preorder("test", wallets[1].addr, wallets[0].privkey) res = testlib.blockstack_namespace_preorder("teststacks", wallets[1].addr, wallets[3].privkey, safety_checks=False, price={ 'units': 'STACKS', 'amount': 64000000 }, tx_only=True) ns_preorder_tx_stacks = res['transaction'] res = testlib.blockstack_namespace_preorder('test2', wallets[1].addr, wallets[2].privkey, tx_only=True) ns_preorder_tx = res['transaction'] testlib.broadcast_transaction(ns_preorder_tx_stacks) testlib.next_block(**kw) # end of 689 # should have only accepted one operation block_stats = virtualchain.lib.indexer.StateEngine.get_block_statistics( testlib.get_current_block(**kw)) if block_stats['num_parsed_ops'] != 1: print 'invalid number of parsed ops: {}'.format( block_stats['num_parsed_ops']) return False # try to register a Stacks transaction (should fail) testlib.blockstack_namespace_reveal( "teststacks", 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[3].privkey) testlib.next_block(**kw) # end of 690, begin Stacks testlib.expect_snv_fail_at('teststacks', testlib.get_current_block(**kw)) # should not be accepted, since no stacks are paid testlib.broadcast_transaction(ns_preorder_tx) # should succeed, even though preordered after the Stacks token activation 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) # end of 690 testlib.blockstack_namespace_ready("test", wallets[1].privkey) testlib.next_block(**kw) # should fail testlib.blockstack_namespace_reveal( "test2", 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[2].privkey) testlib.next_block(**kw)