def createTxState(tx_in: TxInput, pubkey_left: PublicKey, pubkey_right: PublicKey, pubkey_pay_right: PublicKey, pubkey_mulsig_left: PublicKey, pubkey_mulsig_right: PublicKey, lock_val: float, left_val: float, right_val: float, T: int, delta: int) -> Transaction: """ Move coins from left user balance to a new "lock" output. Before: 'a' coins to L, 'b' coins to R. After: 'a - c' coins to L, 'b' coins to R, 'c' coins locked. :param tx_in: reference to channel open transaction :param pubkey_left: public key owned by left user to receive his coins from channel :param pubkey_right: public key owned by right user to receive his coins from channel :param pubkey_pay_right: public key owned by right user for payment after time T :param pubkey_mulsig_left: public key owned by left user for refund if enable-refund tx is published :param pubkey_mulsig_right: public key owned by right user for refund if enable-refund tx is published :param lock_val: amount of coins to lock: 'c' :param left_val: coins or left user: '******' :param right_val: coins or right user: '******' :param T: locked funds can pe paid after this time wherever right user wants :param delta: upper bound on time for transaction to be confirmed by the network :return: tx_state """ out_lock_script = getTxStateLockScript(T, delta, pubkey_pay_right, pubkey_mulsig_left, pubkey_mulsig_right) tx_out_lock = TxOutput(lock_val, out_lock_script) tx_out_left = TxOutput(left_val, P2pkhAddress(pubkey_left.get_address().to_string()).to_script_pub_key()) tx_out_right = TxOutput(right_val, P2pkhAddress(pubkey_right.get_address().to_string()).to_script_pub_key()) tx = Transaction([tx_in], [tx_out_lock, tx_out_left, tx_out_right]) return tx
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 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 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 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'])