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 # until a certain block_height is reached # # set values block_height = 140 seq = Sequence(TYPE_ABSOLUTE_TIMELOCK, block_height) # secret key corresponding to the pubkey needed for the P2SH (P2PKH) transaction p2pkh_sk = PrivateKey('cSbKZh6a6wNUAQ8pr2KLKeZCQ4eJnFmN35wtReaoU4kCP97XQu6W') # get the address (from the public key) p2pkh_addr = p2pkh_sk.get_public_key().get_address() # 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(addr.to_string())
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 main(): # always remember to setup the network setup('testnet') # # This script creates a P2SH address containing a CHECKSEQUENCEVERIFY plus # a P2PKH locking funds with a key as well as for 20 blocks # # set values relative_blocks = 20 seq = Sequence(TYPE_RELATIVE_TIMELOCK, relative_blocks) # secret key corresponding to the pubkey needed for the P2SH (P2PKH) transaction p2pkh_sk = PrivateKey( 'cRvyLwCPLU88jsyj94L7iJjQX5C2f8koG4G2gevN4BeSGcEvfKe9') # get the address (from the public key) p2pkh_addr = p2pkh_sk.get_public_key().get_address() # create the redeem script redeem_script = Script([ seq.for_script(), 'OP_CHECKSEQUENCEVERIFY', '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(addr.to_string())
def setUp(self): setup('testnet') self.txin = TxInput( "76464c2b9e2af4d63ef38a77964b3b77e629dddefc5cb9eb1a3645b1608b790f", 0) self.from_addr = P2pkhAddress('n4bkvTyU1dVdzsrhWBqBw8fEMbHjJvtmJR') self.sk = PrivateKey( 'cTALNpTpRbbxTCJ2A5Vq88UxT44w1PE2cYqiB3n4hRvzyCev1Wwo') self.p2pk_sk = PrivateKey( 'cRvyLwCPLU88jsyj94L7iJjQX5C2f8koG4G2gevN4BeSGcEvfKe9') self.p2pk_redeem_script = Script( [self.p2pk_sk.get_public_key().to_hex(), 'OP_CHECKSIG']) self.txout = TxOutput(to_satoshis(0.09), self.p2pk_redeem_script.to_p2sh_script_pub_key()) self.create_p2sh_and_send_result = '02000000010f798b60b145361aebb95cfcdedd29e6773b4b96778af33ed6f42a9e2b4c4676000000006b483045022100fd3a3fd4aeec5db0f3f9c5c5ef7f60f37920be7464a80edacbc3b6b9d0624173022031ce309330e60b19d39cec8c5597460c840adcdd66f7dbbf896eef3ec42b472f012102d82c9860e36f15d7b72aa59e29347f951277c21cd4d34822acdeeadbcff8a546ffffffff01405489000000000017a9142910fc0b1b7ab6c9789c5a67c22c5bcde5b903908700000000' self.txin_spend = TxInput( '7db363d5a7fabb64ccce154e906588f1936f34481223ea8c1f2c935b0a0c945b', 0) # self.p2pk_sk , self.p2pk_redeem_script from above self.to_addr = self.from_addr self.txout2 = TxOutput(to_satoshis(0.08), self.to_addr.to_script_pub_key()) self.spend_p2sh_result = '02000000015b940c0a5b932c1f8cea231248346f93f18865904e15cecc64bbfaa7d563b37d000000006c47304402204984c2089bf55d5e24851520ea43c431b0d79f90d464359899f27fb40a11fbd302201cc2099bfdc18c3a412afb2ef1625abad8a2c6b6ae0bf35887b787269a6f2d4d01232103a2fef1829e0742b89c218c51898d9e7cb9d51201ba2bf9d9e9214ebb6af32708acffffffff0100127a00000000001976a914fd337ad3bf81e086d96a68e1f8d6a0a510f8c24a88ac00000000' # P2SH(CSV+P2PKH) self.sk_csv_p2pkh = PrivateKey( 'cRvyLwCPLU88jsyj94L7iJjQX5C2f8koG4G2gevN4BeSGcEvfKe9') self.seq = Sequence(TYPE_RELATIVE_TIMELOCK, 200) self.txin_seq = TxInput( 'f557c623e55f0affc696b742630770df2342c4aac395e0ed470923247bc51b95', 0, sequence=self.seq.for_input_sequence()) self.another_addr = P2pkhAddress('n4bkvTyU1dVdzsrhWBqBw8fEMbHjJvtmJR') self.spend_p2sh_csv_p2pkh_result = '0200000001951bc57b24230947ede095c3aac44223df70076342b796c6ff0a5fe523c657f5000000008a483045022100c123775e69ec27094f7940facb9ad769c09f48a7fc88250a2fce67bd92c9b4cf02204ebdbed84af46e584fe6db9a23c420b7370879e883b555e119465f84bf34d82f012103a2fef1829e0742b89c218c51898d9e7cb9d51201ba2bf9d9e9214ebb6af327081e02c800b27576a914c3f8e5b0f8455a2b02c29c4488a550278209b66988acc80000000100ab9041000000001976a914fd337ad3bf81e086d96a68e1f8d6a0a510f8c24a88ac00000000'
def get_CSV_Seq_Value(cls, epochlockperiod, blockslockPeriod): """ bip related conversion for correct csv sequencing """ # keep only the first 16 bits by stripping the rest epochlockperiod &= cls.SEQUENCE_LOCKTIME_MASK if epochlockperiod > 0: print('lock seconds: ' + str(epochlockperiod)) return Sequence(TYPE_RELATIVE_TIMELOCK, epochlockperiod) elif blockslockPeriod >= 0: print('blocks to lock: ' + str(blockslockPeriod)) # blocks even if zero as a default parameter to the csv script return Sequence(TYPE_RELATIVE_TIMELOCK, blockslockPeriod) else: return 0
def getTxEROutputLockScript(pubkey: PublicKey, rel_timelock: int) -> Script: """ Create lock script for output of enable-refund transaction :param pubkey: public key owned by corresponding payment participant :param rel_timelock: relative lock on outputs. Should be same for all outputs of transaction :return: lock script """ seq = Sequence(TYPE_RELATIVE_TIMELOCK, rel_timelock) return Script([seq.for_script(), 'OP_CHECKSEQUENCEVERIFY', 'OP_DROP', 'OP_DUP', 'OP_HASH160', pubkey.to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG'])
def get_redeem_script_from_conf(cls, pub_key_obj): """ Great when method name are self explanatory """ csv_args = cls.get_relative_time_seconds_blocks() seq_number_in_hex = Sequence(TYPE_RELATIVE_TIMELOCK, csv_args) print("seconds to wait: " + str(csv_args[0]) + ", blocks to wait: " + str(csv_args[1])) print('sequence number in little endian format: ' + seq_number_in_hex) redeem_script = cls.get_redeem_script(seq_number_in_hex, pub_key_obj) to_P2SH_addr = P2shAddress.from_script(redeem_script) print('Redeem script generated P2SH addr: ' + to_P2SH_addr.to_address() + "\n") return redeem_script
def get_redeem_script_from_conf(cls, pub_key_obj): """ Return a P2SH address for a redemption scription encaptulating CHECKSEQUENCEVERIFY + P2PKH script with a paying to public address possibly locked up to x blocks read from program.conf [relative_blocks_to_wait] """ blocks_wait = Common.get_conf_wait_blocks() seq_number_in_hex = Sequence(TYPE_RELATIVE_TIMELOCK, blocks_wait) redeem_script = cls.get_redeem_csv_script(seq_number_in_hex, pub_key_obj) to_P2SH_addr = P2shAddress.from_script(redeem_script) print('Redeem script generated P2SH addr: ' + to_P2SH_addr.to_string() + "\n") return redeem_script
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 main() : setup('testnet') relative_blocks = 20 seq = Sequence(TYPE_RELATIVE_TIMELOCK, relative_blocks) p2pkh_sk = PrivateKey('cRvyLwCPLU88jsyj94L7iJjQX5C2f8koG4G2gevN4BeSGcEvfKe9') p2pkh_addr = p2pkh_sk.get_public_key().get_address() print("Address : " + p2pkh_addr.to_string()) redeem_script = Script([seq.for_script(), 'OP_CHECKSEQUENCEVERIFY', 'OP_DROP', 'OP_DUP', 'OP_HASH160' , p2pkh_addr.to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG']) addr = P2shAddress.from_script(redeem_script) print(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 create_spending_signed_trx(p2pkh_addr_to_str, priv_key_from_obj): """ Gather related data and generate the single transation that transfers the btc value of the found UTXO transactions. """ p2pkh_addr_to_obj = P2pkhAddress(p2pkh_addr_to_str) blocks_wait = Common.get_conf_wait_blocks() seq = Sequence(TYPE_RELATIVE_TIMELOCK, blocks_wait) redeem_script = Common.get_redeem_script_from_conf( get_redeem_pub_key_obj()) p2sh_paid_to_addr = P2shAddress.from_script(redeem_script).to_string() utxo_results = get_input_trx_from_utxo(priv_key_from_obj, p2sh_paid_to_addr, seq, redeem_script) # No sense in creating a transaction with 0 UTXOs if utxo_results[0] > 0 and len(utxo_results[1]) > 0: signed_tx = get_signed_trx(utxo_results, p2pkh_addr_to_obj, priv_key_from_obj, redeem_script) # print raw signed transaction ready to be broadcasted print("\nSigned raw transaction:\n" + signed_tx) trasmit_finalized_trx(signed_tx) else: print("\nNo UTXOs found. Nothing to do!\n")
# ***** Send all funds that the P2SH address received to the P2PKH address provided # Didn't manage to sign a multi-input transaction so instead I will create a # single-input transaction spending only the first UTXO found for the P2SH address # Prepare the elements needed for the transaction # Create the Inputs # I will use the data from the first UTXO in_txid, in_amount = list(p2sh_utxos.items())[0] vout = 0 # Set sequence values for inputs as in part 1 seq = Sequence(TYPE_ABSOLUTE_TIMELOCK, lock_block_height) txin = TxInput(in_txid, vout, sequence=seq.for_input_sequence()) # Create the Output # I will spend the whole input amount minus a fixed fee. No change output needed # Clear amount to transfer in_amount = float(in_amount) out_amount = round(in_amount-fixed_fee, 8) txout = TxOutput(out_amount, rec_p2pkh_addr.to_script_pub_key()) # Lock time (in blocks) to be used in transaction lock_time = Locktime(lock_block_height).for_transaction() # Compose transaction (Raw Unsigned Transaction) p2sh_out_tx = Transaction(inputs=[txin], outputs=[txout], locktime=lock_time)
def main(): # always remember to setup the network setup('regtest') # RPC credentials for communicating with the node rpcuser = '******' rpcpass = '******' proxy = NodeProxy(rpcuser, rpcpass).get_proxy() # set values block_height = 140 # secret key needed to spend P2PKH that is wrapped by P2SH p2pkh_sk = PrivateKey( 'cSbKZh6a6wNUAQ8pr2KLKeZCQ4eJnFmN35wtReaoU4kCP97XQu6W') # this is the P2SH address the funds have been locked in p2shaddress = '2NGWStpuXtke1VXCTgNnzUgWbun7eY2f3nH' # this is the address the funds will be sent to to_addr = P2pkhAddress('mnS1ng5D1hdvLkYAK2oS8R1C4e37aQdVoC') seq = Sequence(TYPE_ABSOLUTE_TIMELOCK, block_height) lock = Locktime(block_height) # import the address as watch-only print('importaddress') proxy.importaddress(p2shaddress, "P2SH absolute timelock", True) # find all UTXOs for this address. 10.000.000 should be enough print('listunspent') list_unspent = proxy.listunspent(0, 9999999, [p2shaddress]) # create transaction inputs for all UTXOs. Calculate the total amount of # bitcoins they contain txin_list = [] total_amount = 0 for i in list_unspent: txin = TxInput(i['txid'], i['vout'], sequence=seq.for_input_sequence()) txin_list.append(txin) total_amount = total_amount + i['amount'] if total_amount == 0: print("No funds to move") sys.exit(0) # derive public key and adddress from the private key p2pkh_pk = p2pkh_sk.get_public_key().to_hex() p2pkh_addr = p2pkh_sk.get_public_key().get_address() # create the redeem script - needed to sign the transaction redeem_script = Script([ seq.for_script(), 'OP_CHECKLOCKTIMEVERIFY', 'OP_DROP', 'OP_DUP', 'OP_HASH160', p2pkh_addr.to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG' ]) # get fees using API. Although we may be running in regtest, we'll use the # fees as if we were using testnet (fees are in satoshis) url = 'https://api.blockcypher.com/v1/btc/test3' resp = requests.get(url) fee_per_kb = resp.json()['medium_fee_per_kb'] # calculate transaction size according to: # in*180 + out*34 + 10 plus or minus 'in' # https://bitcoin.stackexchange.com/questions/1195/how-to-calculate-transaction-size-before-sending-legacy-non-segwit-p2pkh-p2sh # we'll play it safe and use the upper bound tx_size = len(txin_list) * 180 + 34 + 10 + len(txin_list) fees = tx_size * fee_per_kb / (1024 * 10**8) print('fees:', fees) # create the output txout = TxOutput( Decimal(total_amount) - Decimal(fees), to_addr.to_script_pub_key()) # create transaction from inputs/outputs tx = Transaction(txin_list, [txout], lock.for_transaction()) # use the private key corresponding to the address that contains the # UTXO we are trying to spend to create the signatures for all txins - # note that the redeem script is passed to replace the scriptSig for i, txin in enumerate(txin_list): sig = p2pkh_sk.sign_input(tx, i, redeem_script) # 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, redeem_script.to_hex()]) # serialize the transaction signed_tx = tx.serialize() # test if the transaction will be accepted by the mempool print('testmempoolaccept') res = proxy.testmempoolaccept([signed_tx]) print(res) if not res[0]['allowed']: print("Transaction not valid") sys.exit(1) # print raw transaction print("\nRaw unsigned transaction:\n" + tx.serialize()) # print raw signed transaction ready to be broadcasted print("\nRaw signed transaction:\n" + signed_tx) print("\nTxId:", tx.get_txid())
# The string representation of this address starts with m on n, because it is a Bitcoin testnet address address = priv.get_public_key().get_address() address.to_string() address.to_hash160() address._is_address_valid(address.to_string()) # True address._is_address_valid(address.to_hash160()) # False # 3. Create an input sequence for a relative timelock of 10 blocks. # Notes: Locktime defines the earliest time that a transaction can be added to the blockchain. # If locktime is < 500.000.000 it is interpreted as a block height, else it is interpreted as UNIX Epoch timestamp help(Sequence) relative_blocks = 10 seq = Sequence(seq_type=TYPE_RELATIVE_TIMELOCK, value=relative_blocks) seq.is_type_block # True seq.value # 10 # Note: I will use regtest node (from scratch) so the relative_blocks restriction can be tested. # 4. What is the redeem script? Create it. # Redeem script is a special type of script. # - The hash of the redeem script used to lock the outputs of a transaction. # - Then the redeem script used to unlock these UTXOs. redeem_script = Script([seq.for_script(), 'OP_CHECKSEQUENCEVERIFY', 'OP_DROP', 'OP_DUP', 'OP_HASH160', address.to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG']) # Script code explanation: # - add on top of the stack the relative_blocks number (10) and the check if this sequence have been verified, ie the locktime have been pass. (T/F)
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 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'])
def load_data_json(priv=False, pub=False, pub_hash=False, timelock_csv=False, timelock_tx=False, timelock_log=False, p2pk=False): """loads parameters used to create P2SH address and spending transactions from the data.json file - initiates/converts applicable objects/data returns : dict of data for the Attributes specified - e.g {'priv_key': object, 'pub': object, 'pub_hash': 'string'} """ # reads user data from data.json with open('data.json', 'r') as json_file: data = json.load(json_file) usr_inputs = data['csv_timelock']['inputs'] # initiates key objects if priv or pub or pub_hash: usr_priv = usr_inputs['priv_key'] usr_pub = usr_inputs['pub_key'] if priv and not usr_priv: errors.missing_data('private key') elif usr_priv: priv_key = PrivateKey.from_wif(usr_priv) pub_key = priv_key.get_public_key() elif usr_pub: pub_key = PublicKey.from_hex(usr_pub) else: # prints error msg & raises systemExit errors.missing_data('public key') # loads timelock condition and converts format if timelock_csv or timelock_tx or timelock_log: lock_height = usr_inputs['block_lock'] if lock_height: seq = Sequence(TYPE_RELATIVE_TIMELOCK, lock_height) timelock_script = seq.for_script() timelock_txin = seq.for_input_sequence() else: # prints error msg & raises systemExit errors.missing_data('timelock period') # initaites P2pkhAddress object if p2pk: address = usr_inputs['p2pkh_address'] if address: p2pkh_address = P2pkhAddress.from_address(address) else: # prints error msg & raises systemExit errors.missing_data('P2PKH address') # fills return outputs with specified data from func arguments outputs = {} if priv: outputs['priv_key'] = priv_key if pub: outputs['pub_key'] = pub_key if pub_hash: outputs['pub_key_hash'] = pub_key.to_hash160() if timelock_csv: outputs['timelock_csv'] = timelock_script if timelock_tx: outputs['timelock_tx'] = timelock_txin if timelock_log: outputs['timelock_log'] = lock_height if p2pk: outputs['p2pk_addr'] = p2pkh_address return outputs
def buy_lambo(key, lock, from_addr, to_addr): setup(os.getenv("BUY_LAMBO_BTC_NET", "regtest")) # Create a proxy to JSON-RPC api chain = NodeProxy(os.getenv("BUY_LAMBO_RPC_USER", "rpcuser"), os.getenv("BUY_LAMBO_RPC_PASSWORD", "rpcpassword")).get_proxy() # Try executing a command to see if node is running try: chain.getblockcount() except Exception: print("Error: Node isn't working!") return # Check addresses if not chain.validateaddress(from_addr)["isvalid"]: print("Error: `from_addr` is not a valid address!") return if not chain.validateaddress(to_addr)["isvalid"]: print("Error: `to_addr` is not a valid address!") return # Set lock sequence prefix seq = Sequence(TYPE_ABSOLUTE_TIMELOCK, lock) # Get public key (found from private key) private_key = PrivateKey(key) public_key = private_key.get_public_key() # Add address to wallet so we can get utxos from bitcoin core chain.importaddress(from_addr) # Get UTXOs utxos = chain.listunspent(1, 9999999, [from_addr]) # Create inputs txin = [] total_btc = Decimal(0) for utxo in utxos: # Note that for each input we set the correct nSequence txin.append( TxInput(utxo["txid"], utxo["vout"], sequence=seq.for_input_sequence())) total_btc = total_btc + utxo["amount"] if total_btc == 0: return print("\nThere aren't any UTXOs :(.") # Create a fee-less output txout = TxOutput(total_btc - Decimal(0.1), P2pkhAddress(to_addr).to_script_pub_key()) # Create dummy transaction (to calculate size) tx = Transaction([TxInput.copy(inpt) for inpt in txin], [txout], locktime=Locktime(lock).for_transaction()) # create the redeem script - needed to sign the transaction redeem_script = Script([ seq.for_script(), "OP_CHECKLOCKTIMEVERIFY", "OP_DROP", "OP_DUP", "OP_HASH160", public_key.get_address().to_hash160(), "OP_EQUALVERIFY", "OP_CHECKSIG", ]) # use the private key corresponding to the address that contains the # UTXO we are trying to spend to create the signature for the txin - # note that the redeem script is passed to replace the scriptSig for ind, txinput in enumerate(tx.inputs): sig = private_key.sign_input(tx, ind, redeem_script) txinput.script_sig = Script( [sig, public_key.to_hex(), redeem_script.to_hex()]) # Calculate fees sat_per_byte = requests.get( "https://bitcoinfees.earn.com/api/v1/fees/recommended").json( )["fastestFee"] fee = Decimal( max((len(bytes.fromhex(tx.serialize())) * sat_per_byte) / SATOSHIS_PER_BITCOIN, 0)) if fee == 0: print("WARNING: There isn't enough balance to calculate fees.") # Create final tx with correct txout value txout = TxOutput(total_btc - fee, P2pkhAddress(to_addr).to_script_pub_key()) tx = Transaction([TxInput.copy(inpt) for inpt in tx.inputs], [txout], locktime=Locktime(lock).for_transaction()) for ind, txinput in enumerate(tx.inputs): sig = private_key.sign_input(tx, ind, redeem_script) txinput.script_sig = Script( [sig, public_key.to_hex(), redeem_script.to_hex()]) signed_tx = tx.serialize() # print raw transaction print("\nRaw unsigned transaction:\n{}".format( Transaction(txin, [txout]).serialize())) # print raw signed transaction ready to be broadcasted print("\nRaw signed transaction:\n{}".format(signed_tx)) print("\nTxId: {}".format(tx.get_txid())) # Check if is valid and send it if chain.testmempoolaccept([signed_tx])[0]["allowed"]: chain.sendrawtransaction(signed_tx) print("\nSent to Block-chain! Have fun with those {} BTC.".format( total_btc - fee)) else: print("\nCan't send (yet)!") print("Reason: `{}`".format( chain.testmempoolaccept([signed_tx])[0]["reject-reason"]))
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 main(): setup.setup('testnet') eps = 200 # value owned by each participant in enable-refund transaction. Could be 1 satoshi delta = 10 # upper bound for tx to be confirmed T = 2100200 # funds for payment locked until this time t_channel = 35 # upper bound for closing a channel id_in_channel_left = Id('616c26241bb007883f13aff556bb07d28374b52b81aa675f30dcf35c04103da4') tx_in_channel_left = TxInput('14c5b01c28a133fb55c03cfd756d70ccdacbdc0229c4a96d49c65c25df53afb5', 0) id_in_channel_right = Id('f74b11ae3ca8d2c2d0424296f0de316198b4fda2ca984b5e3c6681abd2c72b2c') tx_in_channel_right = TxInput('14c5b01c28a133fb55c03cfd756d70ccdacbdc0229c4a96d49c65c25df53afb5', 1) id_channel_left = Id('e6ad38d70bf775e7e74bcd598e9282141dac09f79374565c3ebdf61e4f9ef4ed') id_channel_right = Id('a3dbcea1e46edecbd1da13231f385ebe7f2beea382e3f7227c4c00d21b7e8455') tx_channel = createOpenChannelTx(tx_in_channel_left, tx_in_channel_right, to_satoshis(0.000009), to_satoshis(0.000009), id_channel_left.public_key, id_channel_right.public_key) tx_channel = signOpenChannelTxLeft(tx_channel, id_in_channel_left) tx_channel = signOpenChannelTxRight(tx_channel, id_in_channel_right) print_tx(tx_channel, 'tx channel open') tx_channel_id = '7b2ff59b6070a70249fd3f06efd1e0944d69597e5871e72098304adae94e7316' id_er_in = Id('89270091320614b25f88b84497ff4e4a017cbf1d25c1462b1352ea44f45708db') tx_er_input = TxInput('14c5b01c28a133fb55c03cfd756d70ccdacbdc0229c4a96d49c65c25df53afb5', 3) id_er_u1 = Id('3223c869874bad6933f14d1bf3bc9354125641e0aef3484dcf313c24a18655c7') id_er_u2 = Id('ac54ff9bc498ac9fa15f1e76a670fa0acdc85316fb6a97fc161f3871ab59e3bd') id_er_u3 = Id('05b91a17dbe63db245c6a2ba84a9a2b01ed86b494b61cc2dad5a0a44fe6ddc0e') tx_er_rel_timelock = t_channel + 2 * delta tx_er = createTxER(tx_er_input, [id_er_u1.public_key, id_er_u2.public_key, id_er_u3.public_key], tx_er_rel_timelock, eps) signTxER(tx_er, id_er_in) print_tx(tx_er, 'tx_er, 3 out') tx_er_id = '1e3c3465793126d4115f49750fab61a66c20bfbece436016d00066730704969b' id_state_left = Id('ce7bca0ec8d38f945390e64627f4b669eca9afd2bae77d036421ce96b6767728') # left can receive a - c coins id_state_right = Id('ad5813d9719179da0e561aa22295017559b247a3bb325ce438bc8247bf79962e') # right can receive b coins id_refund_mulsig_left = Id('e34d37fdeb88addac291ae0fa084f33490d756d8298e7219b0d4f073616dd251') # left will receive c coins if publish tx_refund (using tx_er output) id_refund_mulsig_right = Id('4d87652d513e0f7a5be51894b7fa862c8ca3ea8ef222f6b6ea7ed6a949f67672') # left will receive c coins if publish tx_refund (using tx_er output) id_pay_right = Id('0a08c11255f48d66b0d1dcab0e3b9479a7e1275d078663fde3dc9fd92355e784') # right will receive c coins after T if publish tx_pay tx_state_in = TxInput(tx_channel_id, 0) state_lock_script = getTxStateLockScript(T, delta, id_pay_right.public_key, id_refund_mulsig_left.public_key, id_refund_mulsig_right.public_key) lock_amount = to_satoshis(0.00000500) tx_state = createTxState(tx_state_in, id_state_left.public_key, id_state_right.public_key, id_pay_right.public_key, id_refund_mulsig_left.public_key, id_refund_mulsig_right.public_key, lock_amount, to_satoshis(0.00000300), to_satoshis(0.00000100), T, delta) sig_tx_state_left = getChannelStateScriptSigLeft(tx_state, id_channel_left, id_channel_right.public_key) sig_tx_state_right = getChannelStateScriptSigRight(tx_state, id_channel_right, id_channel_left.public_key) tx_state = signChannelStateTx(tx_state, sig_tx_state_left, sig_tx_state_right) print_tx(tx_state, 'tx state') tx_state_id = '229caba8498d320c60b78f347ad70ff8e324bd39a9318e3a94a788dc53f1516f' tx_er_for_refund_input = TxInput(tx_er_id, 0, sequence=Sequence(TYPE_RELATIVE_TIMELOCK, tx_er_rel_timelock).for_input_sequence()) tx_state_lock_input = TxInput(tx_state_id, 0, sequence=Sequence(TYPE_RELATIVE_TIMELOCK, delta).for_input_sequence()) id_refund_receiver = Id('e2bd3bf28c7e0994ef87a8d61b67f4f926ab2e315bc9f1e55da2394a594b4e66') # new address for refund id_pay_receiver = Id('9d2b4722df4e870ef4fd6a7be03b39c9a056bf0562852018e0c995cbc0d5756c') # new address for pay to right tx_refund, sig_left = createTxRefund(tx_er_for_refund_input, tx_state_lock_input, id_er_u1, id_refund_mulsig_left, state_lock_script, id_refund_receiver, lock_amount, to_satoshis(0.00000600), eps, tx_er_rel_timelock) sig_right = txRefundGetRightSignature(tx_refund, id_refund_mulsig_right, state_lock_script) tx_refund = signTxRefundStateInput(tx_refund, sig_left, sig_right) print_tx(tx_refund, 'tx refund') tx_pay = createTxPayAndSign(tx_state_lock_input, id_pay_right, state_lock_script, id_pay_receiver, lock_amount, to_satoshis(0.00000600)) print_tx(tx_pay, 'tx pay')
def main(): # always remember to setup the network setup('testnet') # # This script spends from a P2SH address containing a CSV+P2PKH script as # created from examples/create_p2sh_csv_p2pkh.py # # We assume that some 11.1 tBTC have been send to that address and that we know # the txid and the specific UTXO index (or vout). # # set values relative_blocks = 20 txid = '76c102821b916a625bd3f0c3c6e35d5c308b7c23e78b8866b06a3a466041db0a' vout = 0 seq = Sequence(TYPE_RELATIVE_TIMELOCK, relative_blocks) # create transaction input from tx id of UTXO (contained 11.1 tBTC) txin = TxInput(txid, vout, sequence=seq.for_input_sequence()) # secret key needed to spend P2PKH that is wrapped by P2SH p2pkh_sk = PrivateKey( 'cRvyLwCPLU88jsyj94L7iJjQX5C2f8koG4G2gevN4BeSGcEvfKe9') p2pkh_pk = p2pkh_sk.get_public_key().to_hex() p2pkh_addr = p2pkh_sk.get_public_key().get_address() # create the redeem script - needed to sign the transaction redeem_script = Script([ seq.for_script(), 'OP_CHECKSEQUENCEVERIFY', 'OP_DROP', 'OP_DUP', 'OP_HASH160', p2pkh_addr.to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG' ]) # to confirm that address is the same as the one that the funds were sent #addr = P2shAddress.from_script(redeem_script) #print(addr.to_address()) # send/spend to any random address to_addr = P2pkhAddress('n4bkvTyU1dVdzsrhWBqBw8fEMbHjJvtmJR') txout = TxOutput(11, to_addr.to_script_pub_key()) # no change address - the remaining 0.1 tBTC will go to miners) # create transaction from inputs/outputs 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 - # note that the redeem script is passed to replace the scriptSig sig = p2pkh_sk.sign_input(tx, 0, 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, redeem_script.to_hex()]) 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 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}')