def get_fees( inputs, outputs ): """ Get (dust fee, op fee) for namespace reveal (op fee is 0) """ dust_fee = 0 op_fee = 0 if len(outputs) != 3: log.debug("len(outputs) == %s" % len(outputs)) return (None, None) # 0: op_return if not virtualchain.tx_output_has_data( outputs[0] ): log.debug("output[0] is not an OP_RETURN") return (None, None) # 1: reveal address if virtualchain.script_hex_to_address( outputs[1]["script"] ) is None: log.debug("output[1] is not a valid script") return (None, None) # 2: change address if virtualchain.script_hex_to_address( outputs[2]["script"] ) is None: log.debug("output[2] is not a valid script") return (None, None) # should match make_outputs() dust_fee = (len(inputs) + 2) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE return (dust_fee, op_fee)
def get_fees( inputs, outputs ): """ Given a transaction's outputs, look up its fees: * the first output should be an OP_RETURN with the transfer info * the second output should be the new owner's address, with a DEFAULT_DUST_FEE * the third output should be the change address Return (dust fees, operation fees) on success Return (None, None) on invalid output listing """ if len(outputs) != 3: return (None, None) # 0: op_return if not virtualchain.tx_output_has_data( outputs[0] ): return (None, None) if outputs[0]["value"] != 0: return (None, None) # 1: transfer address if virtualchain.script_hex_to_address( outputs[1]["script"] ) is None: return (None, None) # 2: change address if virtualchain.script_hex_to_address( outputs[2]["script"] ) is None: return (None, None) # should match make_outputs() # the +2 comes from 2 new outputs dust_fee = (len(inputs) + 2) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE op_fee = DEFAULT_DUST_FEE return (dust_fee, op_fee)
def get_fees( inputs, outputs ): """ Given a transaction's outputs, look up its fees: * the first output must be an OP_RETURN, and it must have a fee of 0. * the second output must be the reveal address, and it must have a dust fee * the third must be the change address * the fourth, if given, must be a burned fee sent to the burn address Return (dust fees, operation fees) on success Return (None, None) on invalid output listing """ dust_fee = 0 op_fee = 0 if len(outputs) != 3 and len(outputs) != 4: log.debug("len(outputs) == %s" % len(outputs)) return (None, None) # 0: op_return if not virtualchain.tx_output_has_data( outputs[0] ): log.debug("output[0] is not an OP_RETURN") return (None, None) # 1: reveal address if virtualchain.script_hex_to_address( outputs[1]["script"] ) is None: log.debug("output[1] is not a standard script") return (None, None) # 2: change address if virtualchain.script_hex_to_address( outputs[2]["script"] ) is None: log.debug("output[2] is not a a standard script") return (None, None) # 3: burn address, if given if len(outputs) == 4: addr_hash = virtualchain.script_hex_to_address( outputs[3]["script"] ) if addr_hash is None: log.debug("output[3] is not a standard script") return (None, None) if addr_hash != BLOCKSTACK_BURN_ADDRESS: log.debug("output[3] is not the burn address %s (got %s)" % (BLOCKSTACK_BURN_ADDRESS, addr_hash)) return (None, None) # should match make_outputs(). # the +3 comes from 1 owner UTXO + 2 new outputs dust_fee = (len(inputs) + 3) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE op_fee = outputs[3]["value"] else: # should match make_outputs(). # the +2 comes from 1 owner UTXO + 1 new output dust_fee = (len(inputs) + 2) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE return (dust_fee, op_fee)
def get_fees( inputs, outputs ): """ Given a transaction's outputs, look up its fees: * there should be two outputs: the OP_RETURN and change address Return (dust fees, operation fees) on success Return (None, None) on invalid output listing """ if len(outputs) != 2: return (None, None) # 0: op_return if not virtualchain.tx_output_has_data( outputs[0] ): return (None, None) if outputs[0]["value"] != 0: return (None, None) # 1: change address if virtualchain.script_hex_to_address( outputs[1]["script"] ) is None: return (None, None) # should match make_outputs(). # the +1 comes from one new output dust_fee = (len(inputs) + 1) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE op_fee = 0 return (dust_fee, op_fee)
def get_fees( inputs, outputs ): """ Given a transaction's outputs, look up its fees: * the first output must be an OP_RETURN, and it must have a fee of 0. # the second must be the change address * the third must be a burn fee to the burn address. Return (dust fees, operation fees) on success Return (None, None) on invalid output listing """ if len(outputs) != 3: log.debug("Expected 3 outputs; got %s" % len(outputs)) return (None, None) # 0: op_return if not virtualchain.tx_output_has_data( outputs[0] ): log.debug("outputs[0] is not an OP_RETURN") return (None, None) if outputs[0]["value"] != 0: log.debug("outputs[0] has value %s'" % outputs[0]["value"]) return (None, None) # 1: change address if virtualchain.script_hex_to_address( outputs[1]["script"] ) is None: log.error("outputs[1] has no decipherable change address") return (None, None) # 2: burn address addr_hash = virtualchain.script_hex_to_address( outputs[2]["script"] ) if addr_hash is None: log.error("outputs[2] has no decipherable burn address") return (None, None) if addr_hash != BLOCKSTACK_BURN_ADDRESS: log.error("outputs[2] is not the burn address (%s)" % BLOCKSTACK_BURN_ADDRESS) return (None, None) # should match make_outputs() # the +2 comes from 2 new outputs dust_fee = (len(inputs) + 2) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE op_fee = outputs[2]["value"] return (dust_fee, op_fee)
def get_fees( inputs, outputs ): """ Get (dust fee, op fee) for namespace preorder. op fee is the namespace cost (burnt) dust fee is the total cost that our outputs must sum to """ if len(outputs) != 3: log.debug("Expected 3 outputs; got %s" % len(outputs)) return (None, None) # 0: op_return if not virtualchain.tx_output_has_data( outputs[0] ): log.debug("outputs[0] is not an OP_RETURN") return (None, None) if outputs[0]["value"] != 0: log.debug("outputs[0] has value %s'" % outputs[0]["value"]) return (None, None) # 1: change address if virtualchain.script_hex_to_address( outputs[1]["script"] ) is None: log.error("outputs[1] has no decipherable change address") return (None, None) # 2: burn address addr_hash = virtualchain.script_hex_to_address( outputs[2]["script"] ) if addr_hash is None: log.error("outputs[2] has no decipherable burn address") return (None, None) if addr_hash != BLOCKSTACK_BURN_ADDRESS: log.error("outputs[2] is not the burn address (%s)" % BLOCKSTACK_BURN_ADDRESS) return (None, None) # should match make_outputs() dust_fee = (len(inputs) + 2) * DEFAULT_DUST_FEE + DEFAULT_OP_RETURN_FEE op_fee = outputs[2]["value"] return (dust_fee, op_fee)
def tx_extract( payload, senders, inputs, outputs, block_id, vtxindex, txid ): """ Extract and return a dict of fields from the underlying blockchain transaction data that are useful to this operation. Required (+ parse): sender: the script_pubkey (as a hex string) of the principal that sent the name preorder transaction address: the address from the sender script recipient: the script_pubkey (as a hex string) of the principal that is meant to receive the name recipient_address: the address from the recipient script Optional: sender_pubkey_hex: the public key of the sender """ sender_script = None sender_address = None sender_pubkey_hex = None recipient = None recipient_address = None try: recipient = get_registration_recipient_from_outputs( outputs ) recipient_address = virtualchain.script_hex_to_address( recipient ) assert recipient is not None assert recipient_address is not None # by construction, the first input comes from the principal # who sent the registration transaction... assert len(senders) > 0 assert 'script_pubkey' in senders[0].keys() assert 'addresses' in senders[0].keys() sender_script = str(senders[0]['script_pubkey']) sender_address = str(senders[0]['addresses'][0]) assert sender_script is not None assert sender_address is not None if str(senders[0]['script_type']) == 'pubkeyhash': sender_pubkey_hex = get_public_key_hex_from_tx( inputs, sender_address ) except Exception, e: log.exception(e) raise Exception("Failed to extract")
def get_renew_burn_info( outputs ): """ There are four poutputs: the OP_RETURN, the registration (owner) address, the change address (i.e. from the preorderer), and the burn address with the renewal fee. Get the burn address and value """ if len(outputs) < 4: raise Exception("Malformed renew outputs: don't have 4") burn_addr = virtualchain.script_hex_to_address(outputs[3]['script']) if burn_addr is None: raise Exception("Malformed renew inputs: burn output is a nonstandard script") op_fee = outputs[3]['value'] return {'burn_address': burn_addr, 'op_fee': op_fee}
def tx_extract(payload, senders, inputs, outputs, block_id, vtxindex, txid): """ Extract and return a dict of fields from the underlying blockchain transaction data that are useful to this operation. """ sender_script = None sender_address = None sender_pubkey_hex = None recipient_script = None recipient_address = None try: # first two outputs matter to us assert check_tx_output_types(outputs[:2], block_id) recipient_script = get_reveal_recipient_from_outputs(outputs) recipient_address = virtualchain.script_hex_to_address( recipient_script) assert recipient_script is not None assert recipient_address is not None # by construction, the first input comes from the principal # who sent the reveal transaction... assert len(senders) > 0 assert 'script_pubkey' in senders[0].keys() assert 'addresses' in senders[0].keys() sender_script = str(senders[0]['script_pubkey']) sender_address = str(senders[0]['addresses'][0]) assert sender_script is not None assert sender_address is not None if str(senders[0]['script_type']) == 'pubkeyhash': sender_pubkey_hex = get_public_key_hex_from_tx( inputs, sender_address) except Exception, e: log.exception(e) raise Exception("No reveal address")
def scenario(wallets, **kw): 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') addrscript = 'a914' + addrhash + '87' a = virtualchain.script_hex_to_address(addrscript) namespace_preorder_name_hash = blockstack.lib.hashing.hash_name( 'test', virtualchain.make_payment_script(wallets[0].addr), wallets[2].addr) print 'hash of {} + {} + {} = {}'.format( 'test', virtualchain.make_payment_script(wallets[0].addr), wallets[2].addr, namespace_preorder_name_hash) resp = testlib.blockstack_namespace_preorder("test", wallets[2].addr, wallets[0].privkey) testlib.next_block(**kw) resp = testlib.blockstack_namespace_reveal( "test", wallets[2].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) # should fail resp = testlib.blockstack_name_import("foo.test", wallets[0].addr, "11" * 20, wallets[2].privkey, safety_checks=False) testlib.next_block(**kw) testlib.expect_snv_fail_at('foo.test', testlib.get_current_block(**kw)) resp = testlib.blockstack_namespace_ready('test', wallets[2].privkey, safety_checks=False) testlib.next_block(**kw)
def tx_extract(payload, senders, inputs, outputs, block_id, vtxindex, txid): """ Extract and return a dict of fields from the underlying blockchain transaction data that are useful to this operation. Required (+ parse): sender: the script_pubkey (as a hex string) of the principal that sent the name preorder transaction address: the address from the sender script recipient: the script_pubkey (as a hex string) of the principal that is meant to receive the name recipient_address: the address from the recipient script Optional: sender_pubkey_hex: the public key of the sender """ sender_script = None sender_address = None sender_pubkey_hex = None recipient = None recipient_address = None burn_address = None op_fee = None op = NAME_REGISTRATION opcode = 'NAME_REGISTRATION' try: # first 2 outputs matter (op_return, owner addr) assert check_tx_output_types(outputs[:2], block_id) recipient = get_registration_recipient_from_outputs(outputs) recipient_address = virtualchain.script_hex_to_address(recipient) assert recipient is not None assert recipient_address is not None # by construction, the first input comes from the principal # who sent the registration transaction... assert len(senders) > 0 assert 'script_pubkey' in senders[0].keys() assert 'addresses' in senders[0].keys() sender_script = str(senders[0]['script_pubkey']) sender_address = str(senders[0]['addresses'][0]) assert sender_script is not None assert sender_address is not None if str(senders[0]['script_type']) == 'pubkeyhash': sender_pubkey_hex = get_public_key_hex_from_tx( inputs, sender_address) if len(outputs) >= 4: # renewing burn_info = get_renew_burn_info(outputs) burn_address = burn_info['burn_address'] op_fee = burn_info['op_fee'] op = '{}{}'.format(NAME_RENEWAL, NAME_RENEWAL) opcode = 'NAME_RENEWAL' except Exception, e: log.exception(e) raise Exception("Failed to extract")