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 output(value: int, address: str) -> tx.TxOut: ''' int, str -> TxOut accepts base58 or bech32 addresses ''' script = addr.to_output_script(address) value_bytes = utils.i2le_padded(value, 8) return tb._make_output(value_bytes, script)
def address_to_electrum_scripthash(address: str) -> str: '''Electrum is lame and uses backwards sha hashes of output scripts Args: address (str): a valid bitcoin address Returns: (str): the electrum-formatted scripthash in hex ''' try: e = addr.to_output_script(address) except ValueError: raise scripthash = rutils.sha256(e) return scripthash[::-1].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
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, sig=sig, pubkey=sender_pubkey, sequence=sequence) tx_signed = unsigned_tx.copy(tx_ins=[signed_input]) print('tx_signed') print(tx_signed.hex())
tx_out = simple.output(input_value - tx_fee, receiving_address) # Completely optional memo tx_return_output = tb.make_op_return_output( 'made with ❤ by riemann'.encode('utf-8')) # Generate Unsigned Tx # Create unsigned transaction tx = simple.unsigned_tx([tx_in], [tx_out, tx_return_output]) # Generate Signed Tx # https://blockchain.info/tx/1e7acd3d4715054c8fb0fdea25c5c704986006d2c6f30b0782e9b36a7ee072ef # With the p2pkh output script from address, create the the sighash to be signed sighash = tx.sighash_all(index=0, script=addresses.to_output_script(address)) # Declare SIGHASH_ALL type SIGHASH_ALL = 0x01 # Sign the tx with private key # Assumes private_key is of type class bitcoin.wallet.CKey from python-bitcoinlib sig = private_key.sign(sighash) + bytes([SIGHASH_ALL]) # Recreate tx input with script signature tx_signed_input = simple.p2pkh_input(outpoint=tx_outpoint, sig=sig.hex(), pubkey=public_key, sequence=0xFFFFFFFE) # Recreate tx with the signed tx input
import riemann from riemann import simple, utils from riemann.encoding import addresses as addr from riemann.script import serialization as ser riemann.select_network('zcash_sapling_main') prevout_addr_1 = 't1S3kN4zusjHtDEwfdaCMgk132bqo9DaYW4' prevout_addr_2 = 't1VQCUYzApF5eWf4UFAGdWwaFEpBfG2su1A' # This is the script code of the prevout being spent # We length prefix it # Needed for sighash later script_code_1 = b'\x19' + addr.to_output_script(prevout_addr_1) script_code_2 = b'\x19' + addr.to_output_script(prevout_addr_2) # Make inputs for our tx # We're spending the 1st output of a45216... # And the 0th output of ae9ee9... tx_in_1 = simple.unsigned_input( 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