def tx_decb(self, block_id, vk_p): txs_hashes = self.get_block_txs( block_id) # Get the hash of transactions inside this block for tx_hash in txs_hashes: raw_tx = self.proxy.getrawtransaction( tx_hash) # get the raw transaction from the hash of the tx decoded_tx = self.proxy.decoderawtransaction( raw_tx) # decode the raw transaction and get the json format # check to see if the tx has 1 input and two outputs and is of type pay2pubkeyhash if len(decoded_tx['vin']) != 1 or len(decoded_tx['vout']) != 2: continue if decoded_tx['vout'][0]['scriptPubKey'][ 'hex'][:6] != '76a914' or decoded_tx['vout'][0][ 'scriptPubKey']['hex'][-4:] != '88ac': # pay2pubkeyhash continue if decoded_tx['vout'][1]['scriptPubKey'][ 'hex'][:4] != 'a914' or decoded_tx['vout'][1][ 'scriptPubKey']['hex'][-2:] != '87': # pay2scripthash continue try: vk_p_compressed = decoded_tx['vin'][0]['scriptSig']['hex'][ -66:] ct_r1 = decoded_tx['vout'][0]['scriptPubKey']['hex'][6:-4] ct_r2 = decoded_tx['vout'][1]['scriptPubKey']['hex'][4:-2] if vk_p_compressed == PublicKey('04' + vk_p).to_hex(compressed=True): print("Found the transaction with response message") return ct_r1 + ct_r2 except: continue return None
def tx_decf(self, tx_hash): raw_tx = self.proxy.getrawtransaction( tx_hash) # get the raw transaction from the hash of the tx decoded_tx = self.proxy.decoderawtransaction( raw_tx) # decode the raw transaction and get the json format # check to see if the tx has 1 input and two outputs and is of type pay2pubkeyhash and pay2scripthash if len(decoded_tx['vin']) != 1 or len(decoded_tx['vout']) != 2: return -1, -1 if decoded_tx['vout'][0]['scriptPubKey'][ 'hex'][:6] != '76a914' or decoded_tx['vout'][0][ 'scriptPubKey']['hex'][-4:] != '88ac': #pay2pubkeyhash return -1, -1 if decoded_tx['vout'][1]['scriptPubKey'][ 'hex'][:4] != 'a914' or decoded_tx['vout'][1]['scriptPubKey'][ 'hex'][-2:] != '87': #pay2scripthash return -1, -1 try: vk_u_compressed = decoded_tx['vin'][0]['scriptSig']['hex'][-66:] vk_u = PublicKey(vk_u_compressed).to_hex(compressed=False)[2:] ct_c = decoded_tx['vout'][1]['scriptPubKey']['hex'][4:-2] return vk_u, ct_c except: return -1, -1
def create_HODL_address(key, lock, is_priv=False): setup(os.getenv("BUY_LAMBO_BTC_NET", "regtest")) # Get public key (given or found from private key) public_key = PrivateKey(key).get_public_key() if is_priv else PublicKey(key) # Get address from public key address_from_key = public_key.get_address() # Set lock sequence prefix seq = Sequence(TYPE_ABSOLUTE_TIMELOCK, lock) # create the redeem script - needed to sign the transaction redeem_script = Script( [ seq.for_script(), "OP_CHECKLOCKTIMEVERIFY", "OP_DROP", "OP_DUP", "OP_HASH160", address_from_key.to_hash160(), "OP_EQUALVERIFY", "OP_CHECKSIG", ] ) # create a P2SH address from a redeem script addr = P2shAddress.from_script(redeem_script) print("Time-locked address: {}".format(addr.to_string()))
def _tx_encf(self, vk_p, ct_c, sk_u, txin_id, txin_index): # create transaction input from tx id of UTXO txin = TxInput(txin_id, txin_index) # having the vk_p from the shared key generate the corresponding address for decoder to use to respond vk_p = PublicKey(vk_p) addr_p = vk_p.get_address().to_string() # create transaction output using P2PKH scriptPubKey for paying address paying_addr = P2pkhAddress(addr_p) paying_txout = TxOutput(0.00002, paying_addr.to_script_pub_key()) # create an output where the address is the ciphertext cipher_txout = TxOutput(0.00001, Script(['OP_HASH160', ct_c, 'OP_EQUAL'])) # create transaction from inputs/outputs -- default locktime is used tx = Transaction([txin], [paying_txout, cipher_txout]) #print("\nRaw unsigned transaction:\n" + tx.serialize()) # use private key corresponding to the address that contains the UTXO we are trying to spend to sign the input vk_u = sk_u.get_public_key() addr_u = vk_u.get_address().to_string() # note that we pass the scriptPubkey as one of the inputs of sign_input because it is used to replace # the scriptSig of the UTXO we are trying to spend when creating the transaction digest from_addr = P2pkhAddress(addr_u) sig = sk_u.sign_input( tx, 0, from_addr.to_script_pub_key()) # 0 is for the index of the input # set the scriptSig (unlocking script) vk_u = vk_u.to_hex() txin.script_sig = Script([sig, vk_u]) signed_tx = tx.serialize() print("Users input address: ", addr_u) print("Decoder paying address: ", addr_p) print("\nRaw signed transaction:\n" + signed_tx) return signed_tx
def tx_decf(self, tx_hash): decoded_tx = self.get_tx(tx_hash) #--------------------get the public key of the user------------------------------ if len(decoded_tx['vin']) != 1 or len( decoded_tx['vShieldedOutput']) != 2: return -1, -1 try: vk_u_compressed = decoded_tx['vin'][0]['scriptSig']['hex'][-66:] vk_u = PublicKey(vk_u_compressed).to_hex(compressed=False)[2:] except: return -1, -1 #--------------------get the ciphertext------------------------------------------ cmd = os.popen(zcash_cli + " " + conf_file + ' z_listreceivedbyaddress ' + public_address_decoder_shielded) tx_json = json.loads(cmd.read())[-1] ct_c = tx_json['memo'][:self.challenge_len * 2] self.tx_addr_dict[tx_hash] = bytes.fromhex( tx_json['memo'][self.challenge_len * 2:self.challenge_len * 2 + self.address_len]).decode() return vk_u, ct_c
def main(): # always remember to setup the network setup('regtest') # # This script creates a P2SH address containing a CHECKLOCKTIMEVERIFY plus a P2PKH locking funds with a key as # well as for an absolute amount of blocks or an absolute amount of seconds since the transaction. # parser = argparse.ArgumentParser( description='Give the public key, a future time expressed either in block height or in UNIX Epoch time and ' 'the P2SH address will be displayed') parser.add_argument('pubkey', help="Add the public key.") parser.add_argument('-param', type=int, help="Add the number of blocks or the time expressed in seconds.") args = parser.parse_args() # set values key = args.pubkey absolute_param = args.param p2pkh_pk = PublicKey(key) # set Locktime seq = Sequence(TYPE_ABSOLUTE_TIMELOCK, absolute_param) locktime = Locktime(absolute_param) # get the address (from the public key) p2pkh_addr = p2pkh_pk.get_address() # print("Public key: " + p2pkh_pk.to_hex(compressed=True)) # print("P2PKH Address: " + p2pkh_addr.to_string()) # create the redeem script redeem_script = Script( [seq.for_script(), 'OP_CHECKLOCKTIMEVERIFY', 'OP_DROP', 'OP_DUP', 'OP_HASH160', p2pkh_addr.to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG']) # create a P2SH address from a redeem script addr = P2shAddress.from_script(redeem_script) print("The P2SH address is : " + addr.to_string())
def create_p2sh(proxy, block_height=10, address_pubk=None): """ Creates a P2SH address with an absolute block locktime. :param proxy: JSON RPC proxy for connecting to the network. :param block_height: Block height the lock is valid for. Default value is 10. :param address_pubk: Public key of the address locking the funds. If None, a new address will be created. """ # if a public key is not specified, create a new address and display its keys for future use if not address_pubk: print('Public key not provided. Created a new address.') address = proxy.getnewaddress() print('Address:', address) address_privk = proxy.dumpprivkey(address) print('Private key:', address_privk) address_pubk = proxy.getaddressinfo(address)['pubkey'] print('Public key:', address_pubk) # create the public key object p2pkh_pk = PublicKey(address_pubk) # create sequence for the redeem script seq = Sequence(TYPE_ABSOLUTE_TIMELOCK, block_height) # create the redeem script redeem_script = Script([ seq.for_script(), 'OP_CHECKLOCKTIMEVERIFY', 'OP_DROP', 'OP_DUP', 'OP_HASH160', p2pkh_pk.to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG' ]) # create the P2SH address from the redeem script p2sh_addr = P2shAddress.from_script(redeem_script) # insert the P2SH address into the wallet proxy.importaddress(p2sh_addr.to_string()) # display the P2SH address print('Created P2SH address:', p2sh_addr.to_string())
def test_pubkey_to_hash160(self): pub = PublicKey(self.public_key_hex) self.assertEqual(pub.get_address().to_hash160(), pub.to_hash160())
def test_get_uncompressed_address(self): pub = PublicKey(self.public_key_hex) self.assertEqual( pub.get_address(compressed=False).to_string(), self.address)
def test_pubkey_uncompressed(self): pub = PublicKey(self.public_key_hex) self.assertEqual(pub.to_hex(compressed=False), self.public_key_hex)
def test_pubkey_creation(self): pub1 = PublicKey(self.public_key_hex) self.assertEqual(pub1.to_bytes(), self.public_key_bytes) pub2 = PublicKey(self.public_key_hexc) self.assertEqual(pub2.to_bytes(), self.public_key_bytes)
def _fill_pdf_metadata(out_file, issuer, issuer_address, column_fields, data, global_columns, verify_issuer, conf, interactive=False): # create version version = 2 # create issuer object (json) issuer = { "name": issuer, "identity": { "address": issuer_address, "verification": json.loads(verify_issuer)['methods'] } } # create metadata object (json) and add metadata metadata = {} # add custom metadata if column_fields: metadata_fields = json.loads(column_fields)['columns'] for f in metadata_fields: key = list(f)[0] if key in data: field_properties = f[key] field_properties['value'] = data[key] metadata[key] = field_properties # add global field metadata if global_columns: global_fields = json.loads(global_columns)['fields'] for g in global_fields: key = list(g)[0] # note that global fields override column data metadata[key] = g[key] # now look at special owner name/pubkey columns explicitly in code # TODO we should probably check if the public key is valid owner = None owner_address = None owner_pk = None if '__OWNER_PK__' in data and data[ '__OWNER_PK__'] and '__OWNER_ADDRESS__' in data and data[ '__OWNER_ADDRESS__']: # TODO maybe just calculate address from public key? owner_address = data['__OWNER_ADDRESS__'] owner_pk = data['__OWNER_PK__'] owner = { "name": data['__OWNER_NAME__'], "owner_address": data['__OWNER_ADDRESS__'], # TODO needed? - can be derived "pk": owner_pk } # add the metadata pdf_metadata = PdfDict(version=version, issuer=json.dumps(issuer), metadata=json.dumps(metadata), owner=json.dumps(owner), owner_proof='', chainpoint_proof='') else: # add the metadata (without dumps(owner) to keep owner empty) pdf_metadata = PdfDict(version=version, issuer=json.dumps(issuer), metadata=json.dumps(metadata), owner='', owner_proof='', chainpoint_proof='') pdf = PdfReader(out_file) if pdf.Info: pdf.Info.update(pdf_metadata) else: pdf.Info = pdf_metadata PdfWriter().write(out_file, pdf) # if owner exists then need to add owner_proof # hash pdf, sign hash message using node and add in owner_proof if owner: ##import time ##start = time.time() sha256_hash = None with open(out_file, 'rb') as pdf: sha256_hash = hashlib.sha256(pdf.read()).hexdigest() if (conf.testnet): setup('testnet') else: setup('mainnet') host, port = conf.full_node_url.split( ':') #TODO: update when NodeProxy accepts full url! proxy = NodeProxy(conf.full_node_rpc_user, conf.full_node_rpc_password, host, port).get_proxy() # Due to an old unresolved issue still pending in Bitcoin v0.20.0 # signmessage does not support signing with bech32 key. # To resolve we use the public key to get the base58check encoding that # signmessage is happy with so that we can sign! if (owner_address.startswith('bc') or owner_address.startswith('tb')): owner_address = PublicKey(owner_pk).get_address().to_string() # NOTE that address (the encoding) might have changed here from bech32 # to legacy... take care if you use it again in this function! sig = proxy.signmessage(owner_address, sha256_hash) # add owner_proof to metadata pdf_metadata = PdfDict(owner_proof=sig) pdf = PdfReader(out_file) pdf.Info.update(pdf_metadata) PdfWriter().write(out_file, pdf) ##end = time.time() ##print(end-start, " seconds") ##exit() if interactive: # print progress print('.', end="", flush=True)
def spend_p2sh_cltv_p2pkh(proxy, block_height, sender_priv_key, p2sh_addr, rec_addr): """ Spends funds from a P2SH address with an absolute locktime to a P2PKH receiver address. :param proxy: JSON RPC proxy for connecting to the network. :param block_height: Block height the lock is valid for. :param sender_priv_key: Private key of the address locking the funds. :param p2sh_addr: P2SH address containing the funds. :param rec_addr: P2PKH address receiving the funds. """ # mine 100 blocks and send bitcoin to the P2SH address proxy.generatetoaddress(100, p2sh_addr) # mine 100 blocks to make mined bitcoin spendable, emulates 'bitcoin-cli -generate 100' for _ in range(100): proxy.generatetoaddress(1, proxy.getnewaddress()) # retrieve unspent UTXOs for the P2SH address p2sh_addr_unspent = proxy.listunspent(0, 99999999, [p2sh_addr]) # create absolute-block locking sequence for the transaction inputs seq = Sequence(TYPE_ABSOLUTE_TIMELOCK, block_height) # create transaction inputs for unspent UTXOs # and calculate the total unspent bitcoins they contain tx_inputs = [] total_unspent = 0 for utxo in p2sh_addr_unspent: tx_inputs.append( TxInput(utxo['txid'], utxo['vout'], sequence=seq.for_input_sequence())) total_unspent += utxo['amount'] print("Unspent bitcoin in address {} : {}".format(p2sh_addr, total_unspent)) # get the public key of the receiving address for the funds to be sent to rec_pub_key = proxy.getaddressinfo(rec_addr)['pubkey'] rec_pk = PublicKey(rec_pub_key) # calculate fee satoshis_per_kb = requests \ .get('https://api.blockcypher.com/v1/btc/test3') \ .json()['medium_fee_per_kb'] # formula: |inputs| * 180 + 34 * |outputs| +- |inputs| tx_size = len(tx_inputs) * 180 + 34 * 1 + 10 + len(tx_inputs) # we calculate fees in terms of bitcoin fee = (tx_size / 1024) * (satoshis_per_kb / 10e8) # create the transaction output tx_output = TxOutput(to_satoshis(Decimal(total_unspent) - Decimal(fee)), rec_pk.get_address().to_script_pub_key()) # set a lock time in blocks for the transaction lock = Locktime(block_height) # create the transaction tx = Transaction(tx_inputs, [tx_output], lock.for_transaction()) unsigned_tx = tx.serialize() print('Raw unsigned transaction:', unsigned_tx) # we need to rebuild the redeem script from the P2SH private key # make the locking P2PKH address private key sender_sk = PrivateKey(sender_priv_key) # retrieve the public key of the locking address sender_pk = sender_sk.get_public_key() # rebuild the redeem script redeem_script = Script([ seq.for_script(), 'OP_CHECKLOCKTIMEVERIFY', 'OP_DROP', 'OP_DUP', 'OP_HASH160', sender_pk.get_address().to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG' ]) # for every input of the transaction for i, txin in enumerate(tx.inputs): # create the signature for redeeming the funds sig = sender_sk.sign_input(tx, i, redeem_script) # and sign the input txin.script_sig = Script( [sig, sender_pk.to_hex(), redeem_script.to_hex()]) signed_tx = tx.serialize() print('Raw signed transaction:', signed_tx) print('Transaction ID:', tx.get_txid()) # verify that the transaction is valid ver = proxy.testmempoolaccept([signed_tx]) if ver[0]['allowed']: # if the transaction is valid send the transaction to the blockchain print('Transaction is valid.') proxy.sendrawtransaction(signed_tx) print('{} Bitcoin sent to address {}'.format( Decimal(total_unspent) - Decimal(fee), rec_addr)) else: # otherwise, display the reason the transaction failed print('Transaction rejected. Reason:', ver[0]['reject-reason'])