def create(url, mymoney, theirmoney, fees=10000): """Open a payment channel. After this method returns, a payment channel will have been established with the node identified by url, in which you can send mymoney satoshis and recieve theirmoney satoshis. Any blockchain fees involved in the setup and teardown of the channel should be collected at this time. """ bob = jsonrpcproxy.Proxy(url+'channel/') # Choose inputs and change output coins, change = select_coins(mymoney + 2 * fees) pubkey = get_pubkey() my_out_addr = g.bit.getnewaddress() # Tell Bob we want to open a channel transaction, redeem, their_out_addr = bob.open_channel( g.addr, theirmoney, mymoney, fees, coins, change, pubkey, my_out_addr) # Sign and send the anchor transaction = g.bit.signrawtransaction(transaction) assert transaction['complete'] transaction = transaction['tx'] g.bit.sendrawtransaction(transaction) # Set up the channel in the DB channel = Channel(url, CMutableTxIn(CMutableOutPoint(transaction.GetHash(), 0), AnchorScriptSig(1, b'', redeem)), CMutableTxOut(mymoney, my_out_addr), CMutableTxOut(theirmoney, their_out_addr)) # Exchange signatures for the inital commitment transaction channel.anchor.scriptSig.sig = \ bob.update_anchor(g.addr, transaction.GetHash(), channel.sig_for_them()) channel.put() # Event: channel opened CHANNEL_OPENED.send('channel', address=url)
def submit_opreturn(rpc_connection, address, data): from bitcoin.core import CTxIn, CMutableTxOut, CScript, CMutableTransaction, COIN, CENT, b2x, b2lx from bitcoin.core.script import OP_CHECKSIG, OP_RETURN txouts = [] unspent = sorted([y for y in rpc_connection.listunspent(0) if str(y['address']) == address], key=lambda x: hash(x['amount'])) txins = [CTxIn(unspent[-1]['outpoint'])] value_in = unspent[-1]['amount'] change_pubkey = rpc_connection.validateaddress(address)['pubkey'] change_out = CMutableTxOut(int(value_in - 2*CENT), CScript([change_pubkey, OP_CHECKSIG])) digest_outs = [CMutableTxOut(CENT, CScript([OP_RETURN, data]))] txouts = [change_out] + digest_outs tx = CMutableTransaction(txins, txouts) print tx.serialize().encode('hex') r = rpc_connection.signrawtransaction(tx) assert r['complete'] tx = r['tx'] #print b2x(tx.serialize()) #print len(tx.serialize()), 'bytes' print(b2lx(rpc_connection.sendrawtransaction(tx)))
def open_channel(address, mymoney, theirmoney, fees, their_coins, their_change, their_pubkey, their_out_addr): # pylint: disable=too-many-arguments """Open a payment channel.""" # Get inputs and change output coins, change = select_coins(mymoney + 2 * fees) # Make the anchor script anchor_output_script = anchor_script(get_pubkey(), their_pubkey) anchor_output_address = anchor_output_script.to_p2sh_scriptPubKey() # Construct the anchor utxo payment = CMutableTxOut(mymoney + theirmoney + 2 * fees, anchor_output_address) # Anchor tx transaction = CMutableTransaction( their_coins + coins, [payment, change, their_change]) # Half-sign transaction = g.bit.signrawtransaction(transaction)['tx'] # Create channel in DB channel = Channel(address, CMutableTxIn(CMutableOutPoint(transaction.GetHash(), 0), AnchorScriptSig(0, b'', anchor_output_script)), CMutableTxOut(mymoney, g.bit.getnewaddress()), CMutableTxOut(theirmoney, their_out_addr)) channel.put() # Event: channel opened CHANNEL_OPENED.send('channel', address=address) return (transaction, anchor_output_script, channel.our.scriptPubKey)
def __init__(self, address): self.address = address self.state = 'begin' self.anchor = CMutableTxIn() self.our = CMutableTxOut() self.their = CMutableTxOut() self.cmd_id = None
def test_json_roundtrip(self): VALUES = [ 42, 0, -42, 2100000000000000, -2100000000000000, "basic string", "\u1111Unicode", "\U00010000Wide Unicode", "\x00\n\t\r\nEscape codes", "\"'\"Quotes", "", None, b"\x00\x01\xFFBinary data", b"", CBase58Data.from_bytes(b'\x00\x01\xFF', 42), P2SHBitcoinAddress.from_bytes(b'\x00\x01\xFF'), P2PKHBitcoinAddress.from_bytes(b'\x00\x01\xFF'), CMutableTxIn(COutPoint(b'\x00' * 16 + b'\xFF' * 16, 42), CScript(b'\x00\x01\xFF'), 42), CMutableTxOut(42, CScript(b'\x00\x01\xFF')), CMutableTransaction([ CMutableTxIn(COutPoint(b'\x00' * 32, 42), CScript(b'\x00\x01\xFF'), 42), CMutableTxIn(COutPoint(b'\xFF' * 32, 42), CScript(b'\xFF\x01\x00'), 43) ], [ CMutableTxOut(42, CScript(b'\x00\x01\xFF')), CMutableTxOut(43, CScript(b'\xFF\x01\x00')) ], 42, 3), [ 1, b'\x00\x01\xFF', "List Test", ], { 'a': 1, 'key': b'\xFF\x01\x00', 1: 'Dictionary Test' }, [ { 3: [ 0, 1, 2, ], }, [ [ b'\xFFRecursion Test', ], ], ], ] for value in VALUES: self.assertEqual(from_json(to_json(value)), value)
def commitment(self, ours=False): """Return an unsigned commitment transaction.""" first = CMutableTxOut(self.our_balance, self.our_addr.to_scriptPubKey()) second = CMutableTxOut(self.their_balance, self.their_addr.to_scriptPubKey()) if not ours: first, second = second, first return CMutableTransaction([CMutableTxIn(self.anchor_point)], [first, second])
def add_output(self, tx_out=None, output_index=None): """Add an output at output_index, or append one if output_index is None.""" if tx_out is None: tx_out = CMutableTxOut() elif tx_out.__class__ == CTxOut: tx_out = CMutableTxOut.from_txout(tx_out) if output_index is None: output_index = len(self.vout) self.beginInsertRows(QModelIndex(), output_index, output_index) self.vout.insert(output_index, tx_out) self.endInsertRows()
def main(): proxy = bitcoin.rpc.Proxy() assert len(sys.argv) > 1 digests = [] for f in sys.argv[1:]: try: with open(f, 'rb') as fd: digests.append(Hash(fd.read())) except FileNotFoundError as exp: if len(f)/2 in (20, 32): digests.append(x(f)) else: raise exp except IOError as exp: print(exp, file=sys.stderr) continue for digest in digests: unspent = sorted(proxy.listunspent(0), key=lambda _x: hash(_x['amount'])) txins = [CTxIn(unspent[-1]['outpoint'])] value_in = unspent[-1]['amount'] change_addr = proxy.getnewaddress() change_pubkey = proxy.validateaddress(change_addr)['pubkey'] change_out = CMutableTxOut(params.MAX_MONEY, CScript([change_pubkey, OP_CHECKSIG])) digest_outs = [CMutableTxOut(0, CScript([OP_RETURN, digest]))] txouts = [change_out] + digest_outs tx = CMutableTransaction(txins, txouts) FEE_PER_BYTE = 0.00025*COIN/1000 while True: tx.vout[0].nValue = int(value_in - max(len(tx.serialize()) * FEE_PER_BYTE, 0.00011*COIN)) r = proxy.signrawtransaction(tx) assert r['complete'] tx = r['tx'] if value_in - tx.vout[0].nValue >= len(tx.serialize()) * FEE_PER_BYTE: print(b2x(tx.serialize())) print(len(tx.serialize()), 'bytes', file=sys.stderr) print(b2lx(proxy.sendrawtransaction(tx))) break
def partial_spend_p2sh(redeemScript, rein, daddr=None, alt_amount=None, alt_daddr=None): if daddr is None: daddr = rein.user.daddr txin_redeemScript = CScript(x(redeemScript)) txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey() txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey) (txins, total_value) = unspent_txins(txin_p2sh_address, rein.testnet) if len(txins) == 0: raise ValueError( 'Primary escrow is empty. Please inform client to add funds.') txins_str = "" txins_obj = [] for txid, vout in txins: txins_str += " " + txid + "-" + str(vout) txins_obj.append(CMutableTxIn(COutPoint(lx(txid), vout))) fee = float(PersistConfig.get(rein, 'fee', 0.001)) amount = round(total_value - fee, 8) if alt_amount: amount = round(amount - alt_amount, 8) if amount <= 0. or alt_amount > total_value - fee: click.echo("amount: " + str(amount) + " alt_amount: " + str(alt_amount) + " total_value: " + str(total_value)) raise ValueError( 'Primary escrow balance too low. Please inform client to add funds.' ) txouts = [] txout = CMutableTxOut(amount * COIN, CBitcoinAddress(daddr).to_scriptPubKey()) txouts.append(txout) if alt_amount: txout_alt = CMutableTxOut( round(alt_amount, 8) * COIN, CBitcoinAddress(alt_daddr).to_scriptPubKey()) txouts.append(txout_alt) tx = CMutableTransaction(txins_obj, txouts) ntxins = len(txins_obj) seckey = CBitcoinSecret(rein.user.dkey) sig = "" for i in range(0, ntxins): sighash = SignatureHash(txin_redeemScript, tx, i, SIGHASH_ALL) sig += " " + b2x(seckey.sign(sighash)) + "01" if alt_amount: return (txins_str[1:], "{:.8f}".format(amount), daddr, "{:.8f}".format(alt_amount), alt_daddr, sig[1:]) return (txins_str[1:], "{:.8f}".format(amount), daddr, sig[1:])
def settlement(self): """Generate the settlement transaction.""" # Put outputs in the order of the inputs, so that both versions are the same first = CMutableTxOut(self.our_balance, self.our_addr.to_scriptPubKey()) second = CMutableTxOut(self.their_balance, self.their_addr.to_scriptPubKey()) if self.anchor_index == 0: pass elif self.anchor_index == 1: first, second = second, first else: raise Exception("Unknown index", self.anchor_index) return CMutableTransaction([CMutableTxIn(self.anchor_point)], [first, second])
def make_unsigned(cls, outpoints, outputs, tx_fee=TRANSACTION_FEE, testnet=False, out_value=None): """ Build an unsigned transaction. Args: outpoints: A `list` of `dict` objects which contain a txid, vout, value, and scriptPubkey. outputs: If a single address the full value of the inputs (minus the tx fee) will be sent there. Otherwise it should be a `list` of `dict` objects containing address and value. tx_fee: The Bitcoin network fee to be paid on this transaction. testnet: Should this transaction be built for testnet? out_value: used if you want to specify a specific output value otherwise the full value of the inputs (minus the tx fee) will be used. """ # build the inputs from the outpoints object SelectParams("testnet" if testnet else "mainnet") txins = [] in_value = 0 for outpoint in outpoints: in_value += outpoint["value"] txin = CMutableTxIn( COutPoint(lx(outpoint["txid"]), outpoint["vout"])) txin.scriptSig = CScript(x(outpoint["scriptPubKey"])) txins.append(txin) # build the outputs txouts = [] if isinstance(outputs, list): for output in outputs: value = output["value"] address = output["address"] txouts.append( CMutableTxOut(value, CBitcoinAddress(address).to_scriptPubKey())) else: value = out_value if out_value is not None else (in_value - tx_fee) txouts.append( CMutableTxOut(value, CBitcoinAddress(outputs).to_scriptPubKey())) # make the transaction tx = CMutableTransaction(txins, txouts) return BitcoinTransaction(tx)
def refund(self, contract): fundtx = self.find_transaction_to_address(contract.p2sh) print("Fund tx found in refund: ", fundtx) refundPubKey = self.find_refundAddr(contract) print('refundPubKey: {0}'.format(refundPubKey)) redeemScript = CScript(x(contract.redeemScript)) txin = CMutableTxIn(fundtx['outpoint']) txout = CMutableTxOut(fundtx['amount'] - FEE, refundPubKey.to_scriptPubKey()) # Create the unsigned raw transaction. tx = CMutableTransaction([txin], [txout]) # Set nSequence and nLockTime txin.nSequence = 0 tx.nLockTime = contract.redeemblocknum sighash = SignatureHash(redeemScript, tx, 0, SIGHASH_ALL) privkey = self.bitcoind.dumpprivkey(refundPubKey) sig = privkey.sign(sighash) + bytes([SIGHASH_ALL]) # Sign without secret txin.scriptSig = CScript([sig, privkey.pub, OP_FALSE, redeemScript]) # txin.nSequence = 2185 txin_scriptPubKey = redeemScript.to_p2sh_scriptPubKey() print('Raw redeem transaction hex: {0}'.format(b2x(tx.serialize()))) res = VerifyScript(txin.scriptSig, txin_scriptPubKey, tx, 0, (SCRIPT_VERIFY_P2SH,)) print("Script verified, sending raw transaction... (NOT)", res) txid = self.bitcoind.sendrawtransaction(tx) refund_tx = b2x(lx(b2x(txid))) fund_tx = str(fundtx['outpoint']) return {"refund_tx": refund_tx, "fund_tx": fund_tx}
def refund(proxy, refundGuy, contract): redeemScript = CScript(x(contract['redeemScript'])) txin = CMutableTxIn(fundtx['outpoint']) txout = CMutableTxOut(fundtx['amount'] - FEE, refundGuy['addr'].to_scriptPubKey()) tx = CMutableTransaction([txin], [txout]) txin.nSequence = 0 tx.nLockTime = contract['redeemblocknum'] sighash = SignatureHash(redeemScript, tx, 0, SIGHASH_ALL) sig = refundGuy['key'].sign(sighash) + bytes([SIGHASH_ALL]) txin.scriptSig = CScript([sig, refundGuy['key'].pub, OP_FALSE, redeemScript]) txin_scriptPubKey = redeemScript.to_p2sh_scriptPubKey() print('Raw redeem transaction hex: {0}'.format(b2x(tx.serialize()))) res = VerifyScript(txin.scriptSig, txin_scriptPubKey, tx, 0, (SCRIPT_VERIFY_P2SH,)) print("Script verified, sending raw transaction... (NOT)", res) txid = proxy.sendrawtransaction(tx) refund_tx = b2x(lx(b2x(txid))) fund_tx = str(fundtx['outpoint']) return {"refund_tx": refund_tx, "fund_tx": fund_tx}
def open_channel(address, mymoney, theirmoney, fees, their_coins, their_change, their_pubkey, their_out_addr): # pylint: disable=too-many-arguments, line-too-long """Open a payment channel.""" # Get inputs and change output coins, change = select_coins(mymoney + 2 * fees) # Make the anchor script anchor_output_script = anchor_script(get_pubkey(), their_pubkey) # Construct the anchor utxo payment = CMutableTxOut(mymoney + theirmoney + 2 * fees, anchor_output_script.to_p2sh_scriptPubKey()) # Anchor tx transaction = CMutableTransaction(their_coins + coins, [payment, change, their_change]) # Half-sign transaction = g.bit.signrawtransaction(transaction)['tx'] # Create channel in DB our_addr = g.bit.getnewaddress() channel = Channel( address=address, anchor_point=COutPoint(transaction.GetHash(), 0), anchor_index=0, their_sig=b'', anchor_redeem=anchor_output_script, our_balance=mymoney, our_addr=our_addr, their_balance=theirmoney, their_addr=their_out_addr, ) database.session.add(channel) database.session.commit() # Event: channel opened CHANNEL_OPENED.send('channel', address=address) return (transaction, anchor_output_script, our_addr)
def open_channel(self, my_money, their_money, fees, their_coins, their_change, their_pubkey, their_addr): """Respond to a requested open.""" assert self.state == 'begin' # Get inputs and change output coins, change = self.select_coins(my_money + 2 * fees) # Make the anchor script anchor_output_script = self.anchor_script(self.private_key.pub, their_pubkey) # Construct the anchor utxo payment = CMutableTxOut(my_money + their_money + 2 * fees, anchor_output_script.to_p2sh_scriptPubKey()) # Anchor tx transaction = CMutableTransaction(their_coins + coins, [payment, change, their_change]) # Half-sign transaction = self.bitcoind.signrawtransaction(transaction)['tx'] # Create channel in DB self.anchor.prevout = CMutableOutPoint(transaction.GetHash(), 0) self.anchor.scriptSig = AnchorScriptSig(0, b'', anchor_output_script) self.our.nValue = my_money self.our.scriptPubKey = self.bitcoind.getnewaddress() self.their.nValue = their_money self.their.scriptPubKey = their_addr # Event: channel opened channel_opened.send(self.cmd_id, address=self.address) self.bob.open_accept(transaction, anchor_output_script, self.our.scriptPubKey) self.state = 'open_wait_1.5'
def set_tx(self, tx): """Reset the model to reflect tx.""" self.beginResetModel() self.vout = [] for o in tx.vout: self.vout.append(CMutableTxOut.from_txout(o)) self.endResetModel()
def add_output(): new_output = CMutableTxOut(0) self.outputs_tree.add_output(new_output) update_enabled_widgets() if len(self.outputs_tree.get_outputs()) > 0: self.outputs_tree.view.selectRow(self.outputs_tree.model.rowCount() - 1)
def bump_feerate(bitcoind, tx, feerate_add, prevouts_amount=None): """Bump the feerate of a CTransaction. :param bitcoind: The bitcoind RPC connection, to access the wallet. :param tx: The CTransaction which is to be bumped. :param feerate_add: How much to increase the feerate, in sat/vbyte. :param prevouts_amount: The sum of the value of all the consumed outputs. :return: (CTransaction) The modified transaction. """ # Work on a copy vin = [CMutableTxIn.from_txin(txin) for txin in tx.vin] vout = [CMutableTxOut.from_txout(txout) for txout in tx.vout] # FIXME: Add this to python-bitcoinlib wit = CTxWitness([ CTxInWitness.from_txinwitness(txinwit) for txinwit in tx.wit.vtxinwit ]) mut_tx = CMutableTransaction(vin, vout, witness=wit, nLockTime=tx.nLockTime, nVersion=tx.nVersion) fees = fees_to_add(bitcoind, mut_tx, feerate_add, prevouts_amount) if bitcoind.getbalance() * COIN > fees: return add_input(bitcoind, mut_tx, fees) raise Exception("Could not bump fees, no suitable utxo available!")
def partial_spend_p2sh_mediator(redeemScript, rein, mediator_address, mediator_sig=False): txin_redeemScript = CScript(x(redeemScript)) txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey() txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey) (txins, total_value) = unspent_txins(txin_p2sh_address, rein.testnet) if len(txins) == 0: raise ValueError('No unspent txins found') txins_str = "" txins_obj = [] for txid, vout in txins: txins_str += " " + txid + "-" + str(vout) txins_obj.append(CMutableTxIn(COutPoint(lx(txid), vout))) fee = 0.00025 amount = round(total_value - fee, 8) if amount <= 0: raise ValueError('Not enough value in the inputs') if mediator_sig: txout = CMutableTxOut( amount * COIN, CBitcoinAddress(mediator_address).to_scriptPubKey()) tx = CMutableTransaction(txins_obj, [txout]) seckey = CBitcoinSecret(rein.user.dkey) ntxins = len(txins_obj) sig = "" for i in range(0, ntxins): sighash = SignatureHash(txin_redeemScript, tx, i, SIGHASH_ALL) sig += " " + b2x(seckey.sign(sighash) + x("01")) return (txins_str[1:], "{:.8f}".format(amount), str(mediator_address), sig[1:]) return (txins_str[1:], "{:.8f}".format(amount), str(mediator_address))
def redeem(proxy, redeemerGuy, contract, fundtx, secret): print('redeemPubKey', redeemerGuy['addr']) # TODO: Compare with script on blockchain? redeemScript = CScript(x(contract['redeemScript'])) txin = CMutableTxIn(fundtx['outpoint']) txout = CMutableTxOut(fundtx['amount'] - FEE, redeemerGuy['addr'].to_scriptPubKey()) # Create the unsigned raw transaction. tx = CMutableTransaction([txin], [txout]) sighash = SignatureHash(redeemScript, tx, 0, SIGHASH_ALL) # TODO: protect privkey better, separate signing from rawtx creation #privkey = self.bitcoind.dumpprivkey(self.redeemPubKey) sig = redeemerGuy['key'].sign(sighash) + bytes([SIGHASH_ALL]) preimage = secret.encode('utf-8') # preimage = x(secret) txin.scriptSig = CScript([sig, redeemerGuy['key'].pub, preimage, OP_TRUE, redeemScript]) # print("txin.scriptSig", b2x(txin.scriptSig)) txin_scriptPubKey = redeemScript.to_p2sh_scriptPubKey() print('Raw redeem transaction hex: ', b2x(tx.serialize())) VerifyScript(txin.scriptSig, txin_scriptPubKey, tx, 0, (SCRIPT_VERIFY_P2SH,)) print("Script verified, sending raw transaction...") txid = proxy.sendrawtransaction(tx) fund_tx = str(fundtx['outpoint']) redeem_tx = b2x(lx(b2x(txid))) return {"redeem_tx": redeem_tx, "fund_tx": fund_tx}
def spend_p2sh_mediator(redeemScript, txins_str, amounts, daddrs, sig, rein): txin_redeemScript = CScript(x(redeemScript)) txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey() txins_obj = [] for txin_str in txins_str.split(): txin_list = txin_str.split("-") txins_obj.append( CMutableTxIn(COutPoint(lx(txin_list[0]), int(txin_list[1])))) txouts = [] len_amounts = len(amounts) for i in range(0, len_amounts): txouts.append( CMutableTxOut( round(amounts[i], 8) * COIN, CBitcoinAddress(daddrs[i]).to_scriptPubKey())) tx = CMutableTransaction(txins_obj, txouts) seckey = CBitcoinSecret(rein.user.dkey) ntxins = len(txins_obj) sig_list = [] for s in sig.split(): sig_list.append(x(s)) sig2_str = "" for i in range(0, ntxins): sighash = SignatureHash(txin_redeemScript, tx, i, SIGHASH_ALL) sig2 = seckey.sign(sighash) + x("01") sig2_str += " " + b2x(sig2) txins_obj[i].scriptSig = CScript( [OP_0, sig2, sig_list[i], txin_redeemScript]) VerifyScript(txins_obj[i].scriptSig, txin_scriptPubKey, tx, i, (SCRIPT_VERIFY_P2SH, )) tx_bytes = tx.serialize() hash = sha256(sha256(tx_bytes).digest()).digest() txid = b2x(hash[::-1]) txid_causeway = broadcast_tx(b2x(tx_bytes), rein) return (txid, sig2_str[1:])
def build_spending_tx(script_sig, credit_tx): tx = Transaction(version=1, locktime=0) txin = CMutableTxIn(CMutableOutPoint(credit_tx.GetHash(), 0), script_sig) tx.vin = [txin] txout = CMutableTxOut(0, Script()) tx.vout = [txout] return tx
def create_trx(op_return_val, issuing_transaction_fee, issuing_address, tx_outs, tx_inputs): """ :param op_return_val: :param issuing_transaction_fee: :param issuing_address: :param tx_outs: :param tx_input: :return: """ cert_out = CMutableTxOut(0, CScript([OP_RETURN, op_return_val])) tx_ins = [] value_in = 0 for tx_input in tx_inputs: tx_ins.append(CTxIn(COutPoint(tx_input.tx_hash, tx_input.tx_out_index))) value_in += tx_input.coin_value # send change back to our address amount = value_in - issuing_transaction_fee if amount > 0: change_out = create_transaction_output(issuing_address, amount) tx_outs = tx_outs + [change_out] tx_outs = tx_outs + [cert_out] transaction = CMutableTransaction(tx_ins, tx_outs) return transaction
def create_transaction_output(output_): """ transform the transaction output into hex code :param output__: unsigned transaction output :return: output formatted as transaction hex code """ return CMutableTxOut(output_['value'], CBitcoinAddress(output_['address']).to_scriptPubKey())
def build_crediting_tx(script_pubkey): tx = Transaction(version=1, locktime=0) txin = CMutableTxIn() txin.scriptSig = Script.from_human('0x00 0x00') tx.vin = [txin] txout = CMutableTxOut(0, script_pubkey) tx.vout = [txout] return tx
def create_transaction_output(address, transaction_fee): """ Create a single transaction output :param address: :param transaction_fee: :return: """ addr = CBitcoinAddress(address) tx_out = CMutableTxOut(transaction_fee, addr.to_scriptPubKey()) return tx_out
def test_create_transaction_object_2(inputs_2, outputs_2): r = PaymentService.create_transaction_object(inputs=inputs_2, outputs=outputs_2) tx_in: List[CMutableTxIn] = [ CMutableTxIn(COutPoint(lx('4521418569de2f78d5d2d3c535567ac9c48c95314c53a67788d4dcdc9a8d915b'), 0)), CMutableTxIn(COutPoint(lx('0bb4abea99101197cf2ddf43a2af1e73f868887d5f4a3619241cbb67413a34e7'), 0)), ] pk1 = CBitcoinAddress('34s7MXyL5sEbgsto6SRdvV3YYUu8XVs4xg').to_scriptPubKey() pk2 = CBitcoinAddress('16moGJwkzWhNC1pfnfJptKj9G1ogQz16xd').to_scriptPubKey() pk3 = CBitcoinAddress('17A16QmavnUfCW11DAApiJxp7ARnxN5pGX').to_scriptPubKey() tx_out: List[CMutableTxOut] = [ CMutableTxOut(100000, pk1), CMutableTxOut(2000, pk2), CMutableTxOut(20000000, pk3), ] expected = CMutableTransaction(tx_in, tx_out) assert b2x(r.serialize()) == b2x(expected.serialize())
def create_transaction_output(address, output_value): """ Create a single transaction output :param address: :param output_value: :return: """ bitcoin_address = CBitcoinAddress(address) tx_out = CMutableTxOut(output_value, bitcoin_address.to_scriptPubKey()) return tx_out
def generate_tx(self): tx_chain = self.get_next_tx_chain() txid = lx(tx_chain.current_unspent_tx) txins = [ CMutableTxIn(COutPoint(txid, 0)), CMutableTxIn(COutPoint(txid, 1)) ] txin_seckeys = [tx_chain.seckey, self._spent_to.seckey] amount_in = tx_chain.amount tx_chain.amount -= int(config.transaction_fee / 2) txout1 = CMutableTxOut( tx_chain.amount, CBitcoinAddress(tx_chain.address).to_scriptPubKey()) txout2 = CMutableTxOut( tx_chain.amount, CBitcoinAddress(self._spent_to.address).to_scriptPubKey()) tx = CMutableTransaction(txins, [txout1, txout2], nVersion=2) for i, txin in enumerate(txins): txin_scriptPubKey = CScript([ OP_DUP, OP_HASH160, Hash160(txin_seckeys[i].pub), OP_EQUALVERIFY, OP_CHECKSIG ]) sighash = SignatureHash(txin_scriptPubKey, tx, i, SIGHASH_ALL) sig = txin_seckeys[i].sign(sighash) + bytes([SIGHASH_ALL]) txin.scriptSig = CScript([sig, txin_seckeys[i].pub]) tx_serialized = tx.serialize() logging.debug('{} trying to sendrawtransaction' ' (in=2x{} out=2x{} fee={} bytes={})' ' using tx_chain number={}'.format( self._name, amount_in, txout1.nValue, (amount_in * 2) - (txout1.nValue * 2), len(tx_serialized), self._current_tx_chain_index)) tx_hash = self.execute_rpc('sendrawtransaction', b2x(tx_serialized)) tx_chain.current_unspent_tx = tx_hash logging.info( '{} sendrawtransaction was successful; tx got hash={}'.format( self._name, tx_hash))
def build_outputs(self): if not self.secret_hash: self.generate_hash() self.set_locktime(number_of_hours=self.init_hours) else: self.set_locktime(number_of_hours=self.participate_hours) self.build_atomic_swap_contract() contract_p2sh = self.contract.to_p2sh_scriptPubKey() self.tx_out_list = [ CMutableTxOut(to_base_units(self.value), contract_p2sh), ] if self.utxo_value > self.value: change = self.utxo_value - self.value self.tx_out_list.append( CMutableTxOut( to_base_units(change), CBitcoinAddress(self.sender_address).to_scriptPubKey()))
if args.testnet: bitcoin.SelectParams('testnet') rpc = bitcoin.rpc.Proxy() args.dust = int(args.dust * COIN) feeperbyte1 = args.fee1 / 1000 * COIN feeperbyte2 = args.fee2 / 1000 * COIN # Construct payment tx payment_address = CBitcoinAddress(args.address) payment_txout = CMutableTxOut(int(args.amount * COIN), payment_address.to_scriptPubKey()) change_txout = CMutableTxOut(0, rpc.getnewaddress().to_scriptPubKey()) tx = CMutableTransaction() tx.vout.append(change_txout) tx.vout.append(payment_txout) # Add all undesirable txouts meant to reduce propagation if args.op_return: op_ret_txout = CMutableTxOut(0, CScript([OP_RETURN, b'\x00unsuccessful double-spend attempt\x00'])) tx.vout.append(op_ret_txout) if args.multisig: multisig_txout = CMutableTxOut(args.dust, CScript([1, x('0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71'), b'\x00'*33, 2, OP_CHECKMULTISIG]))
for vout in tx.vout: try: addr = CBitcoinAddress.from_scriptPubKey(vout.scriptPubKey) except ValueError: continue if rpc.validateaddress(addr)['ismine']: change_txout = vout break if change_txout is None: # No suitable change txout; no txout was an address in our wallet. # # Create a new txout for use as change. addr = rpc.getrawchangeaddress() change_txout = CMutableTxOut(0, addr.to_scriptPubKey()) tx.vout.append(change_txout) min_change_txout_nValue = 0 if args.first_seen_safe: min_change_txout_nValue = change_txout.nValue logging.debug('First-seen-safe enabled: will not reduce change txout value below %s BTC' % \ str_money_value(min_change_txout_nValue)) # Find total value in value_in = 0 for vin in tx.vin: prevout_tx = rpc.getrawtransaction(vin.prevout.hash) value_in += prevout_tx.vout[vin.prevout.n].nValue value_out = sum([vout.nValue for vout in tx.vout])