def createFundingTx(self, funder_amount, funder_pubkey, fundee_pubkey, change_address=None): if not self.input_utxo_specified: sys.exit("Did not specify source of funds.") msig_addr, funding_redeem_script = createMultiSigAddress(funder_pubkey, fundee_pubkey, verbose=self.verbose) # create tx input tx_ins = [tb.make_legacy_input(outpoint=self.outpoint, stack_script=b"", redeem_script=self.scriptsig, sequence=0xFFFFFFFF)] if self.verbose: print("Input: ", tx_ins) tx_outs = [simple.output(address=msig_addr, value=funder_amount)] if self.verbose: print("Output: ", tx_outs) need_change_output = True if self.utxo_amount > funder_amount else False if need_change_output: change_output_amount = self.utxo_amount - funder_amount - self.network_fee tx_outs += [simple.output(address=self.change_address, value=change_output_amount)] if BITCOIN in self.network: unsigned_tx = simple.unsigned_legacy_tx(tx_ins, tx_outs) elif ZCASH in self.network: unsigned_tx = simple.unsigned_legacy_tx(tx_ins, tx_outs) script_code1 = b'\x19' + addresses.to_output_script(msig_addr) # TODO: computing sighash_all => verify that this is done correctly sighash = unsigned_tx.sighash_all(index=0, script=script_code1, prevout_value=utils.i2le_padded(funder_amount, 8)) # NOTE: for dual-funded channel, funder_bal = funder_amount + fundee_amount funding_tx = {'funding_tx_id': unsigned_tx.tx_id.hex(), 'funding_bal': funder_amount, 'funding_address': str(msig_addr), 'funding_witness_script': funding_redeem_script} return funding_tx, unsigned_tx.hex()
def createCommitmentTransaction(funding_tx, cust_pubkey, rev_pubkey, merch_pubkey, cust_amount, merch_amount): funding_tx_id = funding_tx.get("funding_tx_id") funding_bal = funding_tx.get("funding_bal") funding_addr = funding_tx.get('funding_address') print("<= Create Commitment Transaction =>") # compute the funding tx outpoint funding_tx_outpoint = simple.outpoint(funding_tx_id, 0) # get the funding tx outpoint as the transaction input tx_ins = [simple.unsigned_input(funding_tx_outpoint)] # the commitment tx has two outputs: (1) customer and (2) merchant cust_redeem_script = ln_redeem_script.format(rev_pubkey=rev_pubkey, merch_pubkey=merch_pubkey, cust_pubkey=cust_pubkey, timeout=uint32_to_bytes(1440)) # 1 day - timeout if debug: print("Cust redeem script: ", cust_redeem_script) cust_address = addresses.make_p2sh_address(cust_redeem_script) tx_out_1 = simple.output(cust_amount, cust_address) # customer encoded_merch_pubkey = bytes.fromhex(merch_pubkey) merch_address = addresses.make_p2pkh_address(encoded_merch_pubkey) tx_out_2 = simple.output(merch_amount, merch_address) # merchant unsigned_tx = simple.unsigned_legacy_tx(tx_ins, [tx_out_1, tx_out_2]) # script code of prevout being spent (from funding tx) prevout_script_code = b'\x19' + addresses.to_output_script(funding_addr) sighash = unsigned_tx.sighash_all(index=0, script_code=prevout_script_code, prevout_value=utils.i2le_padded(funding_bal, 8)) print("sighash hex: ", sighash.hex()) return unsigned_tx.hex()
def createSingleFundingTransaction(network, funder_outpoint, funder_amount, funder_pubkey, fundee_pubkey): """network -> bitcoin or zcash script -> { stack_script : , redeem_script : if spending a P2SH, then this should be set } funder_outpoint -> specific tx output consisting of (txid, output-index) funder_amount -> amount from unspent tx funder_pubkey -> pub key for the funder fundee_pubkey -> pub key of the fundee (or counterparty) """ # create the multi-signature address # fee = 10000 msig_addr, funding_redeem_script = createMultiSigAddress(funder_pubkey, fundee_pubkey) print("Output address: ", msig_addr) print("Redeem script: ", funding_redeem_script) # for closing # create tx input _redeem_script = bytes.fromhex("48304502210090587b6201e166ad6af0227d3036a9454223d49a1f11839c1a362184340ef0240220577f7cd5cca78719405cbf1de7414ac027f0239ef6e214c90fcaab0454d84b3b012103535b32d5eb0a6ed0982a0479bbadc9868d9836f6ba94dd5a63be16d875069184") #tx_ins = [simple.unsigned_input(outpoint=funder_outpoint, redeem_script=_redeem_script)] tx_ins = [tb.make_legacy_input(outpoint=funder_outpoint, stack_script=b"", redeem_script=_redeem_script, sequence=0xFFFFFFFF)] print("Input: ", tx_ins) tx_outs = [simple.output(address=msig_addr, value=funder_amount)] print("Output: ", tx_outs) if network == "bitcoin": unsigned_tx = simple.unsigned_legacy_tx(tx_ins, tx_outs) elif network == "zcash": unsigned_tx = simple.unsigned_legacy_tx(tx_ins, tx_outs) script_code1 = b'\x19' + addresses.to_output_script(msig_addr) # TODO: computing sighash_all => verify that this is done correctly sighash = unsigned_tx.sighash_all(index=0, script=script_code1, prevout_value=utils.i2le_padded(funder_amount, 8)) # TODO: add signing of the sighash print("sighash hex: ", sighash.hex()) # NOTE: for dual-funded channel, funder_bal = funder_amount + fundee_amount funding_tx = {'funding_tx_id': unsigned_tx.tx_id.hex(), 'funding_bal': funder_amount, 'funding_addr': str(msig_addr)} return funding_tx, unsigned_tx.hex(), funding_redeem_script
def test_unsigned_legacy_tx(self): outpoint = simple.outpoint( tx_id=helpers.P2PKH['human']['ins'][0]['hash'], index=helpers.P2PKH['human']['ins'][0]['index']) tx_in = simple.unsigned_input( outpoint=outpoint, sequence=helpers.P2PKH['human']['ins'][0]['sequence']) tx_out = simple.output(helpers.P2PKH['human']['outs'][0]['value'], helpers.P2PKH['human']['outs'][0]['addr']) tx_return_output = txn.make_op_return_output( helpers.P2PKH['human']['outs'][1]['memo']) tx = simple.unsigned_legacy_tx(tx_ins=[tx_in], tx_outs=[tx_out, tx_return_output]) self.assertEqual(tx, helpers.P2PKH['ser']['tx']['unsigned'])
index = 0 sender_outpoint = simple.outpoint(tx_id, index) sender_value = 1000 fee = 10 sender_input = simple.unsigned_input(sender_outpoint, sequence=sequence) # Sender Output sender_output = simple.output(value=sender_value - fee, address=receiver_addr) # OP_RETURN output riemann_note = 'made with ❤ by riemann'.encode('utf-8') op_return_output = tx_builder.make_op_return_output(riemann_note) unsigned_tx = simple.unsigned_legacy_tx( tx_ins=[sender_input], tx_outs=[sender_output, op_return_output], version=version, lock_time=locktime) sighash_all = 0x01 sighash = unsigned_tx.sighash_all( index=0, script=addr.to_output_script(sender_addr)) # Using instance of CKey from python-bitcoinlib to sign: # sig = sender.sign(sighash) + bytes([sighash_all]) # sig = sig.hex() sig = '30450221009e8c7f85d6491169df139f25d26633efe48e98738331a37a1694d655dccebdbd02201a6444cfb364e91279f8c9a8b09cdbdeb4bf6cc0f00f53b9356f852c3b3151dc01' # noqa: E501 signed_input = simple.p2pkh_input( outpoint=sender_outpoint,
simple.outpoint( 'a45216a60855f053d63eb78a91429f85c6218541e876be95b17f8743635a0d3e', 1)) # noqa: E501 tx_in_2 = simple.unsigned_input( simple.outpoint( 'ae9ee9ddeae0f0de07837f25b638ac8a723104753008d9c672e57b1d58e1c863', 0)) # noqa: E501 # Make an output for our tx. # Our prevouts are worth 0.01845001 and 0.00002 ZEC # We want to pay 0.0001 ZEC tx_out = simple.output(1845001 + 2000 - 10000, 't1fRswMu1vopHpWVisgxTtkJSVs8ZCrDZtz') # noqa: E501 # Make the transaction unsigned_tx = simple.unsigned_legacy_tx([tx_in_1, tx_in_2], [tx_out]) # Calculate the sighashes sighash_1 = unsigned_tx.sighash_all(index=0, script_code=script_code_1, prevout_value=utils.i2le_padded( 1845001, 8)) sighash_2 = unsigned_tx.sighash_all(index=1, script_code=script_code_2, prevout_value=utils.i2le_padded(2000, 8)) # Sign the transaction with your private keys elsewhere pubkey_1 = '' pubkey_2 = '' sig_1 = ''