def mktx( amt, tx_fee, recipient_addr, privkey, message=None ): """ Make the transaction with the given fee """ change_addr = virtualchain.BitcoinPrivateKey(privkey).public_key().address() inputs = testlib.get_unspents(change_addr) change = virtualchain.calculate_change_amount(inputs, amt, tx_fee) outputs = [ {'script': virtualchain.make_payment_script(recipient_addr), 'value': amt}, ] if change > 0: # need change and tx fee outputs.append( {'script': virtualchain.make_payment_script(change_addr), "value": change} ) if message: outputs = [ {"script": virtualchain.make_data_script(binascii.hexlify(message)), "value": 0} ] + outputs serialized_tx = blockstack_client.tx.serialize_tx(inputs, outputs) signed_tx = blockstack_client.tx.sign_tx(serialized_tx, privkey) return signed_tx
def make_outputs( data, inputs, recipient_address, sender_address, update_hash_b58, tx_fee): """ Builds the outputs for a name import: * [0] is the OP_RETURN * [1] is the new owner (recipient) * [2] is the update hash * [3] is the change sent to the original owner Raise ValueError if there are not enough inputs to make the transaction """ dust_fee = DEFAULT_OP_RETURN_FEE + (len(inputs) + 3) * DEFAULT_DUST_FEE + tx_fee op_fee = 2 * DEFAULT_DUST_FEE dust_value = DEFAULT_DUST_FEE return [ # main output {"script": virtualchain.make_data_script(str(data)), "value": 0}, # recipient output {"script": virtualchain.make_payment_script(recipient_address), "value": dust_value}, # update hash output {"script": virtualchain.make_payment_script(update_hash_b58), "value": dust_value}, # change output {"script": virtualchain.make_payment_script(sender_address), "value": virtualchain.calculate_change_amount(inputs, op_fee, dust_fee)} ]
def make_outputs(data, inputs, reveal_addr, change_addr, tx_fee): """ Make outputs for a register: [0] OP_RETURN with the name [1] pay-to-address with the *reveal_addr*, not the sender's address. [2] change address with the NAMESPACE_PREORDER sender's address Raise ValueError if there are not enough inputs to make the transaction """ total_to_send = DEFAULT_OP_RETURN_FEE + DEFAULT_DUST_FEE return [ # main output { "script": virtualchain.make_data_script(str(data)), "value": 0 }, # register address { "script": virtualchain.make_payment_script(reveal_addr), "value": DEFAULT_DUST_FEE }, # change address { "script": virtualchain.make_payment_script(change_addr), "value": virtualchain.calculate_change_amount( inputs, total_to_send, DEFAULT_DUST_FEE * (len(inputs) + 2) + DEFAULT_OP_RETURN_FEE + tx_fee) }, ]
def make_outputs( data, inputs, change_address, tx_fee, pay_fee=True ): """ Make outputs for a revoke. Raise ValueError if there are not enough inputs to make the transaction """ dust_fee = None op_fee = None dust_value = None if pay_fee: dust_fee = (len(inputs) + 1) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE + tx_fee op_fee = DEFAULT_DUST_FEE dust_value = DEFAULT_DUST_FEE else: # will be subsidized dust_fee = 0 op_fee = 0 dust_value = 0 return [ # main output {"script": virtualchain.make_data_script(str(data)), "value": 0}, # change output {"script": virtualchain.make_payment_script(change_address), "value": virtualchain.calculate_change_amount(inputs, op_fee, dust_fee)} ]
def make_outputs( data, inputs, new_name_owner_address, change_address, tx_fee=0, pay_fee=True): """ Builds the outputs for a name transfer operation. Raise ValueError if there are not enough inputs to make the transaction """ dust_fee = None op_fee = None dust_value = DEFAULT_DUST_FEE if pay_fee: dust_fee = (len(inputs) + 2) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE + tx_fee op_fee = DEFAULT_DUST_FEE else: dust_fee = 0 op_fee = 0 return [ # main output {"script": virtualchain.make_data_script(str(data)), "value": 0}, # new name owner output {"script": virtualchain.make_payment_script(new_name_owner_address), "value": dust_value}, # change output {"script": virtualchain.make_payment_script(change_address), "value": virtualchain.calculate_change_amount(inputs, op_fee, dust_fee)} ]
def make_outputs( data, inputs, change_addr, fee, tx_fee, pay_fee=True ): """ Make outputs for a namespace preorder: [0] OP_RETURN with the name [1] change address with the NAME_PREORDER sender's address [2] pay-to-address with the *burn address* with the fee Raise ValueError if there are not enough inputs to make the transaction """ dust_fee = DEFAULT_OP_RETURN_FEE + (len(inputs) + 2) * DEFAULT_DUST_FEE + tx_fee op_fee = max(fee, DEFAULT_DUST_FEE) bill = op_fee if not pay_fee: # subsidized dust_fee = 0 op_fee = 0 bill = 0 return [ # main output {"script": virtualchain.make_data_script(str(data)), "value": 0}, # change address {"script": virtualchain.make_payment_script( change_addr ), "value": virtualchain.calculate_change_amount(inputs, bill, dust_fee)}, # burn address {"script": virtualchain.make_payment_script(BLOCKSTACK_BURN_ADDRESS), "value": op_fee} ]
def make_outputs( data, inputs, new_name_owner_address, change_address, tx_fee=0, pay_fee=True, dust_included = False): """ Builds the outputs for a name transfer operation. Raise ValueError if there are not enough inputs to make the transaction """ dust_fee = None op_fee = None dust_value = DEFAULT_DUST_FEE if pay_fee: total_tx_fee = tx_fee if not dust_included: total_tx_fee += (len(inputs) + 2) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE op_fee = DEFAULT_DUST_FEE else: total_tx_fee = 0 op_fee = 0 return [ # main output {"script": virtualchain.make_data_script(str(data)), "value": 0}, # new name owner output {"script": virtualchain.make_payment_script(new_name_owner_address), "value": dust_value}, # change output {"script": virtualchain.make_payment_script(change_address), "value": virtualchain.calculate_change_amount(inputs, op_fee, total_tx_fee)} ]
def make_outputs( data, inputs, change_address, tx_fee, pay_fee=True ): """ Make outputs for a revoke. Raise ValueError if there are not enough inputs to make the transaction """ dust_fee = None op_fee = None dust_value = None if pay_fee: dust_fee = (len(inputs) + 1) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE + tx_fee op_fee = DEFAULT_DUST_FEE dust_value = DEFAULT_DUST_FEE else: # will be subsidized dust_fee = 0 op_fee = 0 dust_value = 0 return [ # main output {"script": virtualchain.make_data_script(str(data)), "value": 0}, # change output {"script": virtualchain.make_payment_script(change_address), "value": virtualchain.calculate_change_amount(inputs, op_fee, dust_fee)} ]
def make_outputs(data, inputs, sender_addr, burn_addr, fee, tx_fee, pay_fee=True, dust_included=False): """ Make outputs for a name preorder: [0] OP_RETURN with the name [1] address with the NAME_PREORDER sender's address [2] pay-to-address with the *burn address* with the fee Raise ValueError if there are not enough inputs to make the transaction """ op_fee = max(fee, DEFAULT_DUST_FEE) total_tx_fee = tx_fee if not dust_included: total_tx_fee += (len(inputs) + 2) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE dust_value = DEFAULT_DUST_FEE bill = 0 if pay_fee: bill = op_fee else: op_fee = 0 bill = 0 total_tx_fee = 0 return [ # main output { "script": virtualchain.make_data_script(str(data)), "value": 0 }, # change address (can be subsidy key) { "script": virtualchain.make_payment_script(str(sender_addr)), "value": virtualchain.calculate_change_amount(inputs, bill, total_tx_fee) }, # burn address { "script": virtualchain.make_payment_script(str(burn_addr)), "value": op_fee } ]
def make_outputs( nulldata, inputs, change_addr, tx_fee=0 ): """ Make namespace-ready outputs """ return [ { "script": virtualchain.make_data_script(str(nulldata)), "value": 0 }, # change output { "script": virtualchain.make_payment_script(change_addr), "value": virtualchain.calculate_change_amount(inputs, 0, tx_fee + DEFAULT_OP_RETURN_FEE) } ]
def make_outputs(nulldata, inputs, change_addr, tx_fee=0): """ Make namespace-ready outputs """ return [ { "script": virtualchain.make_data_script(str(nulldata)), "value": 0 }, # change output { "script": virtualchain.make_payment_script(change_addr), "value": virtualchain.calculate_change_amount( inputs, 0, tx_fee + DEFAULT_OP_RETURN_FEE) } ]
def make_outputs(data, inputs, change_addr, fee, tx_fee, pay_fee=True): """ Make outputs for a namespace preorder: [0] OP_RETURN with the name [1] change address with the NAME_PREORDER sender's address [2] pay-to-address with the *burn address* with the fee Raise ValueError if there are not enough inputs to make the transaction """ dust_fee = DEFAULT_OP_RETURN_FEE + (len(inputs) + 2) * DEFAULT_DUST_FEE + tx_fee op_fee = max(fee, DEFAULT_DUST_FEE) bill = op_fee if not pay_fee: # subsidized dust_fee = 0 op_fee = 0 bill = 0 return [ # main output { "script": virtualchain.make_data_script(str(data)), "value": 0 }, # change address { "script": virtualchain.make_payment_script(change_addr), "value": virtualchain.calculate_change_amount(inputs, bill, dust_fee) }, # burn address { "script": virtualchain.make_payment_script(BLOCKSTACK_BURN_ADDRESS), "value": op_fee } ]
def make_outputs( data, inputs, reveal_addr, change_addr, tx_fee): """ Make outputs for a register: [0] OP_RETURN with the name [1] pay-to-address with the *reveal_addr*, not the sender's address. [2] change address with the NAMESPACE_PREORDER sender's address Raise ValueError if there are not enough inputs to make the transaction """ total_to_send = DEFAULT_OP_RETURN_FEE + DEFAULT_DUST_FEE return [ # main output {"script": virtualchain.make_data_script(str(data)), "value": 0}, # register address {"script": virtualchain.make_payment_script(reveal_addr), "value": DEFAULT_DUST_FEE}, # change address {"script": virtualchain.make_payment_script(change_addr), "value": virtualchain.calculate_change_amount(inputs, total_to_send, DEFAULT_DUST_FEE * (len(inputs) + 2) + DEFAULT_OP_RETURN_FEE + tx_fee)}, ]
def make_outputs(data, change_inputs, register_addr, change_addr, tx_fee, renewal_fee=None, pay_fee=True): """ Make outputs for a register: [0] OP_RETURN with the name [1] pay-to-address with the *register_addr*, not the sender's address. [2] change address with the NAME_PREORDER sender's address [3] (OPTIONAL) renewal fee, sent to the burn address Raise ValueError if there are not enough inputs to make the transaction """ dust_fee = None dust_value = DEFAULT_DUST_FEE op_fee = None bill = None if pay_fee: # sender pays if renewal_fee is not None: # renewing dust_fee = (len(change_inputs) + 3) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE + tx_fee op_fee = max(renewal_fee, DEFAULT_DUST_FEE) bill = op_fee else: # registering dust_fee = (len(change_inputs) + 2) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE + tx_fee op_fee = 0 bill = DEFAULT_DUST_FEE * 2 else: # subsidized by another address if renewal_fee is not None: # renewing dust_fee = 0 op_fee = max(renewal_fee, DEFAULT_DUST_FEE) bill = 0 else: # registering dust_fee = 0 op_fee = 0 bill = 0 outputs = [ # main output { "script": virtualchain.make_data_script(str(data)), "value": 0 }, # register address { "script": virtualchain.make_payment_script(register_addr), "value": dust_value }, # change address (can be the subsidy address) { "script": virtualchain.make_payment_script(change_addr), "value": virtualchain.calculate_change_amount(change_inputs, bill, dust_fee) }, ] if renewal_fee is not None: outputs.append( # burn address (when renewing) { "script": virtualchain.make_payment_script(BLOCKSTACK_BURN_ADDRESS), "value": op_fee }) return outputs
def 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 make_outputs(data, change_inputs, register_addr, change_addr, tx_fee, renewal_fee=None, burn_address=BLOCKSTACK_BURN_ADDRESS, pay_fee=True, dust_included=False): """ Make outputs for a register: [0] OP_RETURN with the name, and possibly a value hash [1] pay-to-address with the *register_addr*, not the sender's address. If renewing, this is the new owner address. [2] change address with the NAME_PREORDER or NAME_RENEWAL's subsidizer's sender's address [3] (OPTIONAL) renewal fee, sent to the burn address Raise ValueError if there are not enough inputs to make the transaction """ dust_fee = None dust_value = DEFAULT_DUST_FEE op_fee = None bill = None if pay_fee: # sender pays total_tx_fee = tx_fee if renewal_fee is not None: # renewing dust_fee = (len(change_inputs) + 3) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE op_fee = max(renewal_fee, DEFAULT_DUST_FEE) bill = op_fee else: # registering dust_fee = (len(change_inputs) + 2) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE op_fee = 0 bill = DEFAULT_DUST_FEE * 2 if not dust_included: total_tx_fee += dust_fee else: # subsidized by another address bill = 0 total_tx_fee = 0 if renewal_fee is not None: # renewing op_fee = max(renewal_fee, DEFAULT_DUST_FEE) else: # registering op_fee = 0 payload = str(data) outputs = [ # main output { "script": virtualchain.make_data_script(payload), "value": 0 }, # register/new-owner address { "script": virtualchain.make_payment_script(str(register_addr)), "value": dust_value }, # change address (can be the subsidy address) { "script": virtualchain.make_payment_script(str(change_addr)), "value": virtualchain.calculate_change_amount(change_inputs, bill, total_tx_fee) }, ] if renewal_fee is not None: outputs.append( # burn address (when renewing) { "script": virtualchain.make_payment_script(str(burn_address)), "value": op_fee }) return outputs
def parse_nameop( opcode, payload, fake_pubkey, recipient=None, recipient_address=None, import_update_hash=None, burn_address=None, reveal_address=None ): opcode_name = OPCODE_NAMES[opcode] pubk = virtualchain.BitcoinPublicKey(fake_pubkey) address = pubk.address() script_pubkey = virtualchain.make_payment_script( address ) senders = [{ "script_pubkey": script_pubkey, "script_type": "pubkeyhash", "addresses": [ address ] }] # just enough to get the public key inputs = [{ 'script': 'ignored {}'.format(fake_pubkey).encode('hex') }] script = "OP_RETURN %s" % payload try: scripthex = virtualchain.make_data_script(binascii.hexlify(payload)) except: if len(payload) == 0: scripthex = "6a" else: print 'failed on {}'.format(payload) raise outputs = [{ 'script': scripthex, 'value': 0 }] if recipient_address is not None: script = "OP_DUP OP_HASH160 %s OP_EQUALVERIFY OP_CHECKSIG" % binascii.hexlify( virtualchain.lib.hashing.bin_double_sha256( fake_pubkey ) ) scripthex = virtualchain.make_payment_script( recipient_address ) outputs.append( { 'script': scripthex, "value": 10000000 }) if import_update_hash is not None: script = "OP_DUP OP_HASH160 %s OP_EQUALVERIFY OP_CHECKSIG" % import_update_hash scripthex = virtualchain.make_payment_script( virtualchain.hex_hash160_to_address( import_update_hash ) ) outputs.append( { "script": scripthex, "value": 10000000 }) elif burn_address is not None: scripthex = virtualchain.make_payment_script( burn_address ) outputs.append( { "script": scripthex, "value": 10000000 }) elif reveal_address is not None: scripthex = virtualchain.make_payment_script( reveal_address ) outputs.append( { "script": scripthex, "value": 10000000 }) try: op = op_extract( opcode_name, payload, senders, inputs, outputs, 488501, 0, "00" * 64 ) except AssertionError, ae: # failed to parse return None
def make_outputs( data, change_inputs, register_addr, change_addr, tx_fee, renewal_fee=None, pay_fee=True): """ Make outputs for a register: [0] OP_RETURN with the name [1] pay-to-address with the *register_addr*, not the sender's address. [2] change address with the NAME_PREORDER sender's address [3] (OPTIONAL) renewal fee, sent to the burn address Raise ValueError if there are not enough inputs to make the transaction """ dust_fee = None dust_value = DEFAULT_DUST_FEE op_fee = None bill = None if pay_fee: # sender pays if renewal_fee is not None: # renewing dust_fee = (len(change_inputs) + 3) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE + tx_fee op_fee = max(renewal_fee, DEFAULT_DUST_FEE) bill = op_fee else: # registering dust_fee = (len(change_inputs) + 2) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE + tx_fee op_fee = 0 bill = DEFAULT_DUST_FEE * 2 else: # subsidized by another address if renewal_fee is not None: # renewing dust_fee = 0 op_fee = max(renewal_fee, DEFAULT_DUST_FEE) bill = 0 else: # registering dust_fee = 0 op_fee = 0 bill = 0 outputs = [ # main output {"script": virtualchain.make_data_script(str(data)), "value": 0}, # register address {"script": virtualchain.make_payment_script(register_addr), "value": dust_value}, # change address (can be the subsidy address) {"script": virtualchain.make_payment_script(change_addr), "value": virtualchain.calculate_change_amount(change_inputs, bill, dust_fee)}, ] if renewal_fee is not None: outputs.append( # burn address (when renewing) {"script": virtualchain.make_payment_script(BLOCKSTACK_BURN_ADDRESS), "value": op_fee} ) return outputs