def create_p2sh(): ''' This method creates a P2SH address containing a CHECKLOCKTIMEVERIFY plus a P2PKH locking funds with a key up to specific blockchain height Arguments: pubKey: public key for the P2PKH part of the redeem script lockBlocks: absolute lock (set to blockchain height) Returns: lock_block_height: the specific blockchain height lock (in blocks) new_addr_privk: the private key of created P2SH address p2sh_addr: the new P2SH address ''' # Setup the network setup('regtest') # Initialize proxy for RPC calls rpcuser = "******" rpcpassword = "******" rpc_con = AuthServiceProxy("http://%s:%[email protected]:18443" % (rpcuser, rpcpassword)) # ***** Accept a public (or optionally a private) key for the P2PKH part of # the redeem script # Create a new Bitcoin Address (P2PKH) # Call the node's getnewaddress JSON-RPC method # Returns the address' Public Key new_addr_pubk = rpc_con.getnewaddress() # ***** Accept a future time expressed either in block height or in UNIX # Epoch time # Numbers of blockchain height corresponding to absolute lock time lock_block_height = 103 # Get the corresponding private key from the wallet # Call the node's dumpprivkey JSON-RPC method new_addr_privk = rpc_con.dumpprivkey(new_addr_pubk) # Get information about current blockchain height # Call the node's getblockcount JSON-RPC method current_block_height = rpc_con.getblockcount() if (lock_block_height < current_block_height): print( '\n***BEWARE*** Given lock (%d blocks) is lower than current blockchain height (%d blocks)' % (lock_block_height, current_block_height)) else: print('Current blockchain height: %d blocks' % current_block_height) print('Fund\'s lock is set to: %d blocks' % lock_block_height) # Setting up an appropriate sequence to provide the script seq = Sequence(TYPE_ABSOLUTE_TIMELOCK, lock_block_height) # Secret key corresponding to the pubkey needed for the P2SH (P2PKH) transaction p2pkh_sk = PrivateKey(new_addr_privk) # Get the P2PKH address (from the public key) p2pkh_addr = p2pkh_sk.get_public_key().get_address() 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 p2sh_addr = P2shAddress.from_script(redeem_script) # VERY IMPORTANT: I must insert P2SH address into my wallet rpc_con.importaddress(p2sh_addr.to_address()) # ***** Display the P2SH address print( '\nNewly created P2SH address with absolute lock set to %d blockchain height:' % lock_block_height) print(p2sh_addr.to_address()) return (lock_block_height, new_addr_privk, p2sh_addr.to_address())
def test_p2sh_creation(self): script = Script([self.pub.to_hex(), 'OP_CHECKSIG']) addr = P2shAddress.from_script(script) self.assertTrue(addr.to_string(), self.p2sh_address)
def test_p2sh_p2wsh_creation_1multisig(self): p2wpkh_key = PrivateKey.from_wif('cNn8itYxAng4xR4eMtrPsrPpDpTdVNuw7Jb6kfhFYZ8DLSZBCg37') script = Script(['OP_1', p2wpkh_key.get_public_key().to_hex(), 'OP_1', 'OP_CHECKMULTISIG']) p2wsh_addr = P2wshAddress.from_script(script) p2sh_p2wsh_addr = P2shAddress.from_script(p2wsh_addr.to_script_pub_key()) self.assertTrue(p2sh_p2wsh_addr.to_address(), self.correct_p2sh_p2wsh_address)
def main(): #Connect to the regtest network setup('regtest') proxy = NodeProxy('user', 'bitcoin').get_proxy() #Accept absolute future block amount User current_blocks = proxy.getblockcount() absolute_blocks = int( input( f'\nPlease input the future block height. The current block height is: {current_blocks}.\nIt must match the one in the redeem script from which the P2SH address (with the locked funds) was derived\n' )) #Accept the Private Key from User sk = PrivateKey( input( '\nPlease enter your Private Key (used to create the address from which the P2SH Address was derived)\n' )) #Accept the P2SH Address with the funds p2sh_addr = input( '\nPlease enter the P2SH address which has the locked funds\n') #Import the address into the wallet proxy.importaddress(f'{p2sh_addr}') print( f'\nThe P2SH address {p2sh_addr} has been imported into the wallet.\n') #Get all UTXOs for this address all_utxos = proxy.listunspent(1, 9999999, [f'{p2sh_addr}']) print(f'\nAll the UTXO Objects for this address are:\n{all_utxos}\n') #Calculate total funds available. Aggregate all UTXO amounts. def totalFunds(): total = Decimal(0) for utxo in all_utxos: total += Decimal(utxo["amount"]) return total total_funds = totalFunds() print("Total funds available: ", total_funds) #Instantiate the timelock sequence seq = Sequence(TYPE_ABSOLUTE_TIMELOCK, absolute_blocks) #Create an array of inputs from these UTXOs def getInputs(): inputs = [] count = 0 for utxo in all_utxos: #create inputs and append them into an array #First, create an input utxo = all_utxos[count] txin = TxInput(utxo["txid"], utxo["vout"], sequence=seq.for_input_sequence()) #then, append it to the array inputs.append(txin) ++count return inputs inputs = getInputs() print(f'The inputs created from these outputs are:\n {inputs}') #Use User's Secret Key (Accepted above) to recreate the Public Key pk = sk.get_public_key() #We recreate the P2PKH Addr to recreate the other half of the redeemScript p2pkh_addr = pk.get_address() #We recreate the redeem script redeem_script = Script([ absolute_blocks, 'OP_CHECKLOCKTIMEVERIFY', 'OP_DROP', 'OP_DUP', 'OP_HASH160', p2pkh_addr.to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG' ]) #Confirm that the P2SH address is the same one to which funds were sent by receating the P2SH from this redeem script addr = P2shAddress.from_script(redeem_script).to_string() print( f'\nCheck if this is the address with the locked funds:\n{addr} vs what you input above {p2sh_addr}' ) #Accept the receiving P2PKH from User destination_addr = P2pkhAddress( input( '\nPlease enter the address you want to send the locked funds to:\n' )) #Calculate txn size to estimate fee from inputs only so we subtract it from funds tx_test = Transaction(inputs, [], Locktime(absolute_blocks).for_transaction()) tx_size = tx_test.get_size() # 0.0001 is an appropriate fee per byte so we use that est_tx_fee = tx_size / 1000 * 0.0001 #Create a txout transferring total locked funds (minus estimated fees). txout = TxOutput(to_satoshis(total_funds - Decimal(est_tx_fee)), destination_addr.to_script_pub_key()) #Create Txn. Passing in the inputs, output, and the future absolute lock time tx = Transaction(inputs, [txout], Locktime(absolute_blocks).for_transaction()) #Print the newly created txn print(f'\nThe raw unsigned txn is: {tx.serialize()}\n') #Calulate the Appropriate Transaction Fee According to Txn Size. #First, get the fee estimate from network. Useful only for mainnet and testnet. def getFee(): fee = proxy.estimatesmartfee(5, "ECONOMICAL") if fee["errors"]: print( 'Network data not enough to calculate fee. Setting default fee: 0.0001 BTC' ) return 0.0001 else: return fee["feerate"] #Then, calculate the size of our Txn and then multiply it by the per-byte fee est_fee = getFee() #per byte tx_size = tx.get_size() print(f'\nThe transaction size is:\n{tx_size} bytes') tx_fee = tx_size / 1000 * est_fee print(f'\nThe recommended fee for this transaction is:\n{tx_fee}') #Need to sign all inputs def signInputs(): input_index = 0 for input in inputs: #Use the Secret Key corresponding to the P2SH to create the signature for the txn/ sign all inputs #Redeem script is passed to replace the scriptSig inputSig = sk.sign_input(tx, input_index, redeem_script) input.script_sig = Script( [inputSig, pk.to_hex(), redeem_script.to_hex()]) ++input_index signInputs() signed_tx = tx.serialize() #Print the signed raw txn, ready to be checked for validity print(f"\nRaw signed transaction:\n{signed_tx}") print( f"\nTransaction ready to be broadcast. Transaction Id: {tx.get_txid()}" ) #Test for validity isValid = proxy.testmempoolaccept([f'{signed_tx}']) print(f'\nTransaction validity check result:\n{isValid}') #Broadcast txn #needs signed_tx if isValid[0]["allowed"]: if input('\nSend transaction to network? Y / N: ') == 'Y': sent_tx_id = proxy.sendrawtransaction(f'{signed_tx}') print( f'\n***The transaction with id {sent_tx_id} has been sent to the network***' ) else: print( f'\nUser decided not to send the funds and exited the program.' ) exit() else: reason = isValid[0]["reject-reason"] print(f'\nThe signed raw transaction is invalid. Reason: {reason}')
def main(): # always remember to setup the network setup('testnet') # # This script creates a P2SH address containing a P2PK script and sends # some funds to it # # # create transaction output using P2SH scriptPubKey (locking script) # (the recipient will give us the final address but for now we create it # for demonstration purposes) # # secret key corresponding to the pubkey needed for the P2SH (P2PK) transaction p2pk_sk = PrivateKey( 'cRvyLwCPLU88jsyj94L7iJjQX5C2f8koG4G2gevN4BeSGcEvfKe9') p2pk_pk = p2pk_sk.get_public_key().to_hex() redeem_script = Script([p2pk_pk, 'OP_CHECKSIG']) #TESTE_SUZANA addressObj = P2shAddress.from_script(redeem_script) print("addressObj=" + addressObj.to_address()) #TESTE_SUZANA # you can initially spend a specific UTXO that you know (e.g. with the txid after you send some funds to the address). Then if everything works you can use the address to find all tx in that address and spend them. Make sure the timelock works and that you can spend the funds as expected. # The 2nd program should display the raw signed transaction that is to be sent to a bitcoin node plus _send_ the transaction to a node. The last part is not possible with the bitcoin-utils library since I have not impl. a node proxy yet. So you have to use another lib or finish with the cli commands (commented out of course) that I have to run in order to send the raw tx to a bitcoin node. # The P2SH addr could be recalculated in 2nd program since we have the redeem script! Providing the P2SH addr saves you from this small calculation and 'connects' the 2 programs :-) # Re fees, I would rather you calculate the 'appropriate' fee and explain in comments how/why you did it this way. Ideally, you would consult an online service to get an estimate of the appropriate fee. This is minor for assignment purposes but major for production systems. #https://bitcoin.stackexchange.com/questions/83650/how-does-nsequence-check-sequence-verify-work #The 2nd program requires a private key as well... that is what unlock the funds. ##### NAO PRECISA PARA O ASSIGNMENT DAQUI EM DIANTE ####### # create transaction input from tx id of UTXO (contained 0.1 tBTC) txin = TxInput( '76464c2b9e2af4d63ef38a77964b3b77e629dddefc5cb9eb1a3645b1608b790f', 0) # address we are spending from from_addr = P2pkhAddress('n4bkvTyU1dVdzsrhWBqBw8fEMbHjJvtmJR') # secret key of address that we are trying to spent sk = PrivateKey('cTALNpTpRbbxTCJ2A5Vq88UxT44w1PE2cYqiB3n4hRvzyCev1Wwo') #SUZANA ---- ASSINA COM P2SH do SCRIPT txout = TxOutput(0.09, redeem_script.to_p2sh_script_pub_key()) # no change address - the remaining 0.01 tBTC will go to miners) # create transaction from inputs/outputs -- default locktime is used tx = Transaction([txin], [txout]) # print raw transaction print("\nRaw unsigned transaction:\n" + tx.serialize()) # use the private key corresponding to the address that contains the # UTXO we are trying to spend to create the signature for the txin sig = sk.sign_input(tx, 0, from_addr.to_script_pub_key()) #print(sig) # get public key as hex pk = sk.get_public_key() pk = pk.to_hex() #print (pk) # set the scriptSig (unlocking script) txin.script_sig = Script([sig, pk]) signed_tx = tx.serialize() # print raw signed transaction ready to be broadcasted print("\nRaw signed transaction:\n" + signed_tx) print("\nTxId:", tx.get_txid())
def test_p2sh_p2wpkh_creation_pubkey(self): addr = PrivateKey.from_wif('cTmyBsxMQ3vyh4J3jCKYn2Au7AhTKvqeYuxxkinsg6Rz3BBPrYKK').get_public_key().get_segwit_address() p2sh_addr = P2shAddress.from_script(addr.to_script_pub_key()) self.assertTrue(p2sh_addr.to_address(), self.correct_p2sh_p2wpkh_address)
pubkey = privkey.get_public_key() # # 2) accept a future time expressed either in block height or in UNIX Epoch time # blockheight = proxy.getblockcount() + 1 print("future time in absolute block height: " + str(blockheight)) # get address from public key address = pubkey.get_address() # get hash of address hash = address.to_hash160() # create redeem script script = Script([ blockheight, 'OP_CHECKLOCKTIMEVERIFY', 'OP_DROP', 'OP_DUP', 'OP_HASH160', hash, 'OP_EQUALVERIFY', 'OP_CHECKSIG' ]) print("redeem script: " + str(script.get_script())) # get P2SH address P2SHaddress = P2shAddress.from_script(script) # # 3) display the P2SH address # print("p2sh address: " + P2SHaddress.to_string())
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 private key, a future time expressed either in block height or in UNIX Epoch time and ' 'the P2SH address to send the funds') parser.add_argument('key', help="Add the private key.") parser.add_argument( '-param', type=int, help="Add the number of blocks or the time expressed in seconds.") parser.add_argument('-to_address', type=str, help="Add the adress that will sent/spend") args = parser.parse_args() # set values key = args.key absolute_param = args.param send_address = args.to_address # set Locktime seq = Sequence(TYPE_ABSOLUTE_TIMELOCK, absolute_param) locktime = Locktime(absolute_param) # set proxy username = "******" password = "******" proxy = NodeProxy(username, password).get_proxy() # secret key corresponding to the pubkey needed for the P2SH (P2PKH) transaction p2pkh_sk = PrivateKey(key) p2pkh_pk = p2pkh_sk.get_public_key() # get the address (from the public key) p2pkh_addr = p2pkh_pk.get_address() # print("Private key: " + p2pkh_sk. to_wif(compressed=True)) # 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' ]) # accept a P2SH address to get the funds from addr = P2shAddress.from_script(redeem_script) print("The P2SH address to get the funds from is : " + addr.to_string()) # check if the P2SH address has any UTXOs to get funds from proxy.importaddress(addr.to_string(), "P2SH to get the funds from") minconf = 0 maxconf = 99999999 my_list = proxy.listunspent(minconf, maxconf, [addr.to_string()]) # Gather all funds that the P2SH address received to send to the P2PKH address provided txin_list = [] btc_to_send = 0 for i in my_list: txin = TxInput(i['txid'], i['vout'], sequence=seq.for_input_sequence()) txin_list.append(txin) btc_to_send = btc_to_send + i['amount'] if btc_to_send == 0: print("No btc found to send") quit() # accept a P2PKH address to send the funds to to_addr = P2pkhAddress(send_address) print("The P2PKH address to send the funds to is : " + to_addr.to_string()) # calculate the appropriate fees with respect to the size of the transaction response = requests.get("https://mempool.space/api/v1/fees/recommended") fee_per_byte = response.json()['fastestFee'] print("Fastest fee per byte is : %d " % fee_per_byte) # calculate transaction size as described at # https://bitcoin.stackexchange.com/questions/1195/how-to-calculate-transaction-size-before-sending-legacy-non-segwit-p2pkh-p2sh tx_size = len(my_list) * 180 + 34 + 10 + len(my_list) total_fees = tx_size * fee_per_byte / (1024 * 10**8) print('Total fees are : ', total_fees) # Calculate the final amount amount = btc_to_send - total_fees # print(amount) # Create transaction output txout = TxOutput(to_satoshis(amount), to_addr.to_script_pub_key()) # Create transaction after the inputs and the outputs tx = Transaction(txin_list, [txout], locktime.for_transaction()) # For each transaction - when dealing with multiple inputs, you will need to sign all of them for i, txin in enumerate(my_list): sig = p2pkh_sk.sign_input(tx, i, redeem_script) # print(sig) # set the scriptSig (unlocking script) -- unlock the P2PKH (sig, pk) plus # the redeem script, since it is a P2SH txin.script_sig = Script( [sig, p2pkh_pk.to_hex(), redeem_script.to_hex()]) # display the raw signed transaction, ready to be broadcasted signed_tx = tx.serialize() print("\nRaw signed transaction:\n" + signed_tx) # display the raw unsigned transaction print("\nRaw unsigned transaction:\n" + tx.serialize()) # display the transaction id print("\nTxId:", tx.get_txid()) # verify that the transaction is valid and will be accepted by the Bitcoin nodes # if the transaction is valid, send it to the blockchain is_valid = proxy.testmempoolaccept([signed_tx]) # print(is_valid) if is_valid[0]['allowed']: print("Transaction is valid!") print("Sending transaction to blockchain..") proxy.sendrawtransaction(signed_tx) else: print("Transaction not valid") quit()
def test_p2shaddress_to_script_pub_key(self): script = Script([self.pub.to_hex(), 'OP_CHECKSIG']) fromScript = Script.to_p2sh_script_pub_key(script).to_hex() addr = P2shAddress.from_script(script) fromP2shAddress = addr.to_script_pub_key().to_hex() self.assertTrue(fromScript, fromP2shAddress)
def generate(): # Tells the library what network we are using setup() if not mnemonic_phrase: # Generate mnemonic from random 192-bit entropy entropy_bytes = Bip39EntropyGenerator( Bip39EntropyBitLen.BIT_LEN_192).Generate() mnemonic = Bip39MnemonicGenerator.FromEntropy(entropy_bytes) print("Generated random mnemonic:\n" + mnemonic) else: print("Using included mnemonic.") mnemonic = mnemonic_phrase # Get seed bytes from mnemonic seed_bytes = Bip39SeedGenerator(mnemonic).Generate() bip44_mst = Bip44.FromSeed( seed_bytes, Bip44Coins.BITCOIN) # Could add in multi currency support # Derive account 0 for Bitcoin: m/44'/0'/0' bip44_acc = bip44_mst.Purpose() \ .Coin() \ .Account(0) # Derive the external chain: m/44'/0'/0'/0 bip44_change = bip44_acc.Change(Bip44Changes.CHAIN_EXT) with open(output_dest, 'w') as output_file: # Open the output file output_file.write("address, public_key" + (", private_key" if privates else "") + "\n") # Go through each address for i in range(number): bip44_addr = bip44_change.AddressIndex(i) # create segwit address addr3 = PrivateKey.from_wif(bip44_addr.PrivateKey().ToWif( )).get_public_key().get_segwit_address() # wrap in P2SH address addr4 = P2shAddress.from_script(addr3.to_script_pub_key()) if addr4.to_string() == compare: print("Found it!") print("Path: m/44'/0'/0'/0/" + str(i)) break #print("P2SH(P2WPKH):", addr4.to_string()) if (i % int(number / 10)) == 0: print('Finished {}'.format(i)) out = "{0}, {1}".format(addr4.to_string(), bip44_addr.PublicKey().ToExtended() ) # Public addresses not including private if (privates): # Include the private keys out = "{0}, {1}, {2}".format( addr4.to_string(), bip44_addr.PublicKey().RawCompressed().ToHex(), bip44_addr.PrivateKey().ToWif()) #bip44_addr.PublicKey().ToAddress() # This is the regular address (not P2SH(P2WPKH)) # Print extended keys and address if (verbose): print(out) output_file.write(out + "\n")
def main(): # always remember to setup the network setup('testnet') # # This script creates a P2SH address containing a P2PK script and sends # some funds to it # # # create transaction output using P2SH scriptPubKey (locking script) # (the recipient will give us the final address but for now we create it # for demonstration purposes) # # secret key corresponding to the pubkey needed for the P2SH (P2PK) transaction p2pk_sk = PrivateKey( 'cRvyLwCPLU88jsyj94L7iJjQX5C2f8koG4G2gevN4BeSGcEvfKe9') p2pk_pk = p2pk_sk.get_public_key().to_hex() redeem_script = Script([p2pk_pk, 'OP_CHECKSIG']) #TESTE_SUZANA addressObj = P2shAddress.from_script(redeem_script) print("addressObj=" + addressObj.to_address()) #TESTE_SUZANA # create transaction input from tx id of UTXO (contained 0.1 tBTC) txin = TxInput( '76464c2b9e2af4d63ef38a77964b3b77e629dddefc5cb9eb1a3645b1608b790f', 0) # address we are spending from from_addr = P2pkhAddress('n4bkvTyU1dVdzsrhWBqBw8fEMbHjJvtmJR') # secret key of address that we are trying to spent sk = PrivateKey('cTALNpTpRbbxTCJ2A5Vq88UxT44w1PE2cYqiB3n4hRvzyCev1Wwo') #SUZANA ---- ASSINA COM P2SH do SCRIPT txout = TxOutput(0.09, redeem_script.to_p2sh_script_pub_key()) # no change address - the remaining 0.01 tBTC will go to miners) # create transaction from inputs/outputs -- default locktime is used tx = Transaction([txin], [txout]) # print raw transaction print("\nRaw unsigned transaction:\n" + tx.serialize()) # use the private key corresponding to the address that contains the # UTXO we are trying to spend to create the signature for the txin sig = sk.sign_input(tx, 0, from_addr.to_script_pub_key()) #print(sig) # get public key as hex pk = sk.get_public_key() pk = pk.to_hex() #print (pk) # set the scriptSig (unlocking script) txin.script_sig = Script([sig, pk]) signed_tx = tx.serialize() # print raw signed transaction ready to be broadcasted print("\nRaw signed transaction:\n" + signed_tx) print("\nTxId:", tx.get_txid())