def close_tx(self, fee: int, privkey_dest: str) -> str: """Create a (mutual) close tx""" txin = CTxIn(COutPoint(bytes.fromhex(self.txid), self.output_index)) out_privkey = privkey_expand(privkey_dest) txout = CTxOut(self.amount - fee, CScript([script.OP_0, Hash160(coincurve.PublicKey.from_secret(out_privkey.secret).format())])) tx = CMutableTransaction(vin=[txin], vout=[txout]) sighash = script.SignatureHash(self.redeemscript(), tx, inIdx=0, hashtype=script.SIGHASH_ALL, amount=self.amount, sigversion=script.SIGVERSION_WITNESS_V0) sigs = [key.sign(sighash, hasher=None) for key in self.funding_privkeys_for_tx()] # BOLT #3: # ## Closing Transaction # ... # * `txin[0]` witness: `0 <signature_for_pubkey1> <signature_for_pubkey2>` witness = CScriptWitness([bytes(), sigs[0] + bytes([script.SIGHASH_ALL]), sigs[1] + bytes([script.SIGHASH_ALL]), self.redeemscript()]) tx.wit = CTxWitness([CTxInWitness(witness)]) return tx.serialize().hex()
def as_tx(self): sum_in = sum(prevtx.nValue for _, prevtx, _ in self.prevouts) sig_size = sum(redeemer.spendbytes for _, _, redeemer in self.prevouts) tx_size = ( 4 + # version field 2 + # # of txins len(self.prevouts) * 41 + # txins, excluding sigs sig_size + # txins, sigs only 1 + # # of txouts 34 + # txout 4 # nLockTime field ) feerate = int(self.proxy._call('estimatefee', 1) * COIN) # satoshi's per KB if feerate <= 0: feerate = 10000 fees = int(tx_size * feerate / 1000) tx = CMutableTransaction( [CTxIn(outpoint, nSequence=0) for outpoint, _, _ in self.prevouts], [CTxOut(sum_in - fees, self.payto.to_scriptPubKey())], 0) for n, (_, _, redeemer) in enumerate(self.prevouts): redeemer.mutate_spend(tx, n) unsigned_tx = CTransaction.from_tx(tx) for n, (_, _, redeemer) in enumerate(self.prevouts): txin = CMutableTxIn.from_txin(tx.vin[n]) txin.scriptSig = redeemer.sign_spend(unsigned_tx, n) tx.vin[n] = CTxIn.from_txin(txin) print(b2x(tx.serialize()))
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 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 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 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 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 as_tx(self): sum_in = sum(prevtx.nValue for _,prevtx,_ in self.prevouts) sig_size = sum(redeemer.spendbytes for _,_,redeemer in self.prevouts) tx_size = (4 + # version field 2 + # # of txins len(self.prevouts) * 41 + # txins, excluding sigs sig_size + # txins, sigs only 1 + # # of txouts 34 + # txout 4 # nLockTime field ) feerate = int(self.proxy._call('estimatefee', 1) * COIN) # satoshi's per KB if feerate <= 0: feerate = 10000 fees = int(tx_size * feerate / 1000) tx = CMutableTransaction( [CTxIn(outpoint, nSequence=0) for outpoint,_,_ in self.prevouts], [CTxOut(sum_in - fees, self.payto.to_scriptPubKey())], 0) for n,(_,_,redeemer) in enumerate(self.prevouts): redeemer.mutate_spend(tx, n) unsigned_tx = CTransaction.from_tx(tx) for n,(_,_,redeemer) in enumerate(self.prevouts): txin = CMutableTxIn.from_txin(tx.vin[n]) txin.scriptSig = redeemer.sign_spend(unsigned_tx, n) tx.vin[n] = CTxIn.from_txin(txin) print(b2x(tx.serialize()))
def main(): ''' Our main function. ''' SelectParams('mainnet') decoded_transaction = eval(open('transaction_to_sign.txt').read()) # pylint: disable=eval-used txin_txid = lx(decoded_transaction['vin'][0]['txid']) txin_vout = 0 tx_in = CMutableTxIn(COutPoint(txin_txid, txin_vout)) tx_out = [] for idx in range(len(decoded_transaction['vout'])): satoshis = int(COIN * decoded_transaction['vout'][idx]['value']) script_pub_key = CScript(bytes.fromhex(decoded_transaction['vout'][idx]['scriptPubKey']['hex'])) tx_out.append(CMutableTxOut(satoshis, script_pub_key)) tx_to_spend = CMutableTransaction([tx_in], tx_out) priv_1 = CBitcoinSecret.from_secret_bytes(bytes.fromhex(PRIV_HEX_1)) priv_2 = CBitcoinSecret.from_secret_bytes(bytes.fromhex(PRIV_HEX_2)) txin_redeem_script = CScript(bytes.fromhex(decoded_transaction['vin'][0]['scriptSig']['hex'])) # Input 0 is fixed. sighash = SignatureHash(txin_redeem_script, tx_to_spend, 0, SIGHASH_ALL) signatures = [] for priv in [priv_1, priv_2]: signatures.append(priv.sign(sighash) + bytes([SIGHASH_ALL])) tx_in.scriptSig = CScript([CScriptOp(0x00), signatures[0], signatures[1], txin_redeem_script]) # script_pub_key Defined in cycle. VerifyScript(tx_in.scriptSig, txin_redeem_script, tx_to_spend, 0, (SCRIPT_VERIFY_P2SH,)) print(b2x(tx_to_spend.serialize()))
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 test_emergency_txout(bitcoind): """Test mostly the emergency tx locktime""" amount = Decimal("50") - Decimal("500") / Decimal(COIN) privkeys = [CKey(os.urandom(32)) for _ in range(4)] pubkeys = [k.pub for k in privkeys] txo = emergency_txout(pubkeys, COIN * amount) addr = str(CBitcoinAddress.from_scriptPubKey(txo.scriptPubKey)) # This makes a transaction with only one vout txid = bitcoind.pay_to(addr, amount) new_amount = amount - Decimal("500") / Decimal(COIN) addr = bitcoind.getnewaddress() txin = CTxIn(COutPoint(lx(txid), 0), nSequence=4464) txout = CTxOut(new_amount * COIN, CBitcoinAddress(addr).to_scriptPubKey()) tx = CMutableTransaction([txin], [txout], nVersion=2) tx_hash = SignatureHash(emergency_script(pubkeys), tx, 0, SIGHASH_ALL, int(amount * COIN), SIGVERSION_WITNESS_V0) sigs = [k.sign(tx_hash) + bytes([SIGHASH_ALL]) for k in privkeys] witness_script = [bytes(0), *sigs, emergency_script(pubkeys)] tx.wit = CTxWitness([CTxInWitness(CScriptWitness(witness_script))]) # 1 month of locktime bitcoind.generate_block(4464 - 2) with pytest.raises(VerifyRejectedError, match="non-BIP68-final"): bitcoind.send_tx(tx.serialize().hex()) bitcoind.generate_block(1) bitcoind.send_tx(tx.serialize().hex()) assert bitcoind.has_utxo(addr)
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 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 submit_opreturn(rpc_raw, 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 - 1 * CENT), CScript([change_pubkey, OP_CHECKSIG])) digest_outs = [CMutableTxOut(0, CScript([OP_RETURN, data]))] txouts = [change_out] + digest_outs tx = CMutableTransaction(txins, txouts) tx_hex = tx.serialize().encode("hex") print "decoderawtransaction", tx_hex transaction_decoded = rpc_raw.decoderawtransaction(tx_hex) print json.dumps(transaction_decoded, indent=4, default=json_custom_parser) r = rpc_connection.signrawtransaction(tx) assert r["complete"] tx = r["tx"] # print b2x(tx.serialize()) # print len(tx.serialize()), 'bytes' sent_tx_id = rpc_connection.sendrawtransaction(tx) return b2lx(sent_tx_id)
def test_sendrawtransaction(self): num_outputs = 5 given_transaction = CMutableTransaction([], [make_txout() for x in range(0, num_outputs)]) expected_txid = b2lx(given_transaction.GetHash()) given_transaction_hex = b2x(given_transaction.serialize()) proxy = FakeBitcoinProxy() resulting_txid = proxy.sendrawtransaction(given_transaction_hex) self.assertEqual(resulting_txid, expected_txid)
def put(self): """Persist self.""" commitment = CMutableTransaction([self.anchor], [self.our, self.their]) commitment = CMutableTransaction.from_tx(commitment) commitment.vin[0].scriptSig = commitment.vin[0].scriptSig.to_script() for tx_out in commitment.vout: tx_out.scriptPubKey = tx_out.scriptPubKey.to_scriptPubKey() with g.dat: g.dat.execute("INSERT OR REPLACE INTO CHANNELS VALUES (?, ?)", (self.address, commitment.serialize()))
def test_fundrawtransaction_adds_output(self): num_outputs = 5 unfunded_transaction = CMutableTransaction([], [make_txout() for x in range(0, num_outputs)]) proxy = FakeBitcoinProxy() funded_transaction_hex = proxy.fundrawtransaction(b2x(unfunded_transaction.serialize()))["hex"] funded_transaction = CMutableTransaction.deserialize(x(funded_transaction_hex)) self.assertTrue(len(funded_transaction.vout) > num_outputs) self.assertEqual(len(funded_transaction.vout), num_outputs + 1)
def unsigned_settlement(self): """Generate the settlement transaction.""" # Put outputs in the order of the inputs, so that both versions are the same if self.anchor.scriptSig.my_index == 0: transaction = CMutableTransaction([self.anchor], [self.our, self.their]) elif self.anchor.scriptSig.my_index == 1: transaction = CMutableTransaction([self.anchor], [self.their, self.our]) else: raise Exception("Unknown index", self.anchor.scriptSig.my_index) return CMutableTransaction.from_tx(transaction)
def test_create_transaction_object_1(inputs_1, outputs_1): r = PaymentService.create_transaction_object(inputs=inputs_1, outputs=outputs_1) tx_in: List[CMutableTxIn] = [ CMutableTxIn(COutPoint(lx('4521418569de2f78d5d2d3c535567ac9c48c95314c53a67788d4dcdc9a8d915b'), 0))] pk = CBitcoinAddress('16moGJwkzWhNC1pfnfJptKj9G1ogQz16xd').to_scriptPubKey() tx_out: List[CMutableTxOut] = [CMutableTxOut(100000, pk)] expected = CMutableTransaction(tx_in, tx_out) assert b2x(r.serialize()) == b2x(expected.serialize())
def test_fundrawtransaction_hex_hash(self): unfunded_transaction = CMutableTransaction([], [make_txout() for x in range(0, 5)]) proxy = FakeBitcoinProxy() funded_transaction_hex = proxy.fundrawtransaction(b2x(unfunded_transaction.serialize()))["hex"] funded_transaction = CMutableTransaction.deserialize(x(funded_transaction_hex)) self.assertTrue(unfunded_transaction is not funded_transaction) self.assertEqual(type(funded_transaction), type(unfunded_transaction)) self.assertNotEqual(len(funded_transaction.vin), 0) self.assertTrue(len(funded_transaction.vin) > len(unfunded_transaction.vin)) self.assertEqual(type(funded_transaction.vin[0]), CTxIn)
def redeem_contract(self, contract, secret): print("Parsing script for redeem_contract...") scriptarray = self.parse_script(contract.redeemScript) redeemblocknum = scriptarray[8] redeemPubKey = P2PKHBitcoinAddress.from_bytes(x(scriptarray[6])) refundPubKey = P2PKHBitcoinAddress.from_bytes(x(scriptarray[13])) p2sh = contract.p2sh #checking there are funds in the address amount = self.check_funds(p2sh) if(amount == 0): print("address ", p2sh, " not funded") quit() fundtx = self.find_transaction_to_address(p2sh) amount = fundtx['amount'] / COIN # print("Found fund_tx: ", fundtx) p2sh = P2SHBitcoinAddress(p2sh) if fundtx['address'] == p2sh: print("Found {0} in p2sh {1}, redeeming...".format(amount, p2sh)) blockcount = self.bitcoind.getblockcount() print("\nCurrent blocknum at time of redeem on Zcash:", blockcount) if blockcount < int(redeemblocknum): print('redeemPubKey', redeemPubKey) zec_redeemScript = CScript(x(contract.redeemScript)) txin = CMutableTxIn(fundtx['outpoint']) txout = CMutableTxOut(fundtx['amount'] - FEE, redeemPubKey.to_scriptPubKey()) # Create the unsigned raw transaction. tx = CMutableTransaction([txin], [txout]) sighash = SignatureHash(zec_redeemScript, tx, 0, SIGHASH_ALL) # TODO: protect privkey better, separate signing from rawtx creation privkey = self.bitcoind.dumpprivkey(redeemPubKey) sig = privkey.sign(sighash) + bytes([SIGHASH_ALL]) preimage = secret.encode('utf-8') txin.scriptSig = CScript([sig, privkey.pub, preimage, OP_TRUE, zec_redeemScript]) # print("txin.scriptSig", b2x(txin.scriptSig)) txin_scriptPubKey = zec_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 = self.bitcoind.sendrawtransaction(tx) fund_tx = str(fundtx['outpoint']) redeem_tx = b2x(lx(b2x(txid))) return {"redeem_tx": redeem_tx, "fund_tx": fund_tx} else: print("nLocktime exceeded, refunding") print('refundPubKey', refundPubKey) txid = self.bitcoind.sendtoaddress(refundPubKey, fundtx['amount'] - FEE) fund_tx = str(fundtx['outpoint']) refund_tx = b2x(lx(b2x(txid))) return {"refund_tx": refund_tx, "fund_tx": fund_tx} else: print("No contract for this p2sh found in database", p2sh)
def sig_for_them(self): """Generate a signature for the mirror commitment transaction.""" transaction = CMutableTransaction([self.anchor], [self.their, self.our]) transaction = CMutableTransaction.from_tx(transaction) # copy # convert scripts to CScript transaction.vin[0].scriptSig = transaction.vin[0].scriptSig.to_script() for tx_out in transaction.vout: tx_out.scriptPubKey = tx_out.scriptPubKey.to_scriptPubKey() # sign sighash = SignatureHash(self.anchor.scriptSig.redeem, transaction, 0, SIGHASH_ALL) sig = g.seckey.sign(sighash) + bytes([SIGHASH_ALL]) return sig
def build_tx(self) -> str: # Sort inputs by serial number ins = [x['input'] for x in sorted(self.inputs, key=lambda k: k['serial_id'])] # Sort outputs by serial number outs = [x['output'] for x in sorted(self.outputs, key=lambda k: k['serial_id'])] self.tx = CMutableTransaction(ins, outs, nVersion=2, nLockTime=self.locktime) self.txid = self.tx.GetTxid().hex() return self.tx.serialize().hex()
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 from_utxo(txid_in: str, tx_index_in: int, sats: int, privkey: str, fee: int, local_node_privkey: str, local_funding_privkey: str, remote_node_privkey: str, remote_funding_privkey: str, chain_hash: str = regtest_hash) -> Tuple['Funding', str]: """Make a funding transaction by spending this utxo using privkey: return Funding, tx.""" # Create dummy one to start: we will fill in txid at the end. funding = Funding('', 0, sats - fee, local_node_privkey, local_funding_privkey, remote_node_privkey, remote_funding_privkey, chain_hash) # input private key. inkey = privkey_expand(privkey) inkey_pub = coincurve.PublicKey.from_secret(inkey.secret) # use RBF'able input (requirement for dual-funded things) txin = CTxIn(COutPoint(bytes.fromhex(txid_in), tx_index_in), nSequence=0xFFFFFFFD) txout = CTxOut( sats - fee, CScript([script.OP_0, sha256(funding.redeemscript()).digest()])) tx = CMutableTransaction([txin], [txout], nVersion=2, nLockTime=funding.locktime) # now fill in funding txid. funding.txid = tx.GetTxid().hex() funding.tx = tx # while we're here, sign the transaction. address = P2WPKHBitcoinAddress.from_scriptPubKey( CScript([script.OP_0, Hash160(inkey_pub.format())])) sighash = script.SignatureHash(address.to_redeemScript(), tx, 0, script.SIGHASH_ALL, amount=sats, sigversion=script.SIGVERSION_WITNESS_V0) sig = inkey.sign(sighash, hasher=None) + bytes([script.SIGHASH_ALL]) tx.wit = CTxWitness( [CTxInWitness(CScriptWitness([sig, inkey_pub.format()]))]) return funding, tx.serialize().hex()
def redeem_after_timelock(contract): p2sh = contract.p2sh fundtx = find_transaction_to_address(p2sh) amount = fundtx['amount'] / COIN if (fundtx['address'].__str__() != p2sh): print("no fund transaction found to the contract p2sh address ", p2sh) quit() print("Found fundtx:", fundtx) # Parsing redeemblocknum from the redeemscript of the p2sh redeemblocknum = find_redeemblocknum(contract) blockcount = bitcoind.getblockcount() print("Current block:", blockcount, "Can redeem from block:", redeemblocknum) if (still_locked(contract)): print("too early for redeeming with timelock try again at block", redeemblocknum, "or later") return 0 print("Found {0} in p2sh {1}, redeeming...".format(amount, p2sh)) redeemPubKey = find_refundAddr(contract) print('refundPubKey', redeemPubKey) redeemScript = CScript(x(contract.redeemScript)) txin = CMutableTxIn(fundtx['outpoint']) txout = CMutableTxOut(fundtx['amount'] - FEE, redeemPubKey.to_scriptPubKey()) # Create the unsigned raw transaction. txin.nSequence = 0 tx = CMutableTransaction([txin], [txout]) tx.nLockTime = redeemblocknum sighash = SignatureHash(redeemScript, tx, 0, SIGHASH_ALL) # TODO: figure out how to better protect privkey privkey = bitcoind.dumpprivkey(redeemPubKey) sig = privkey.sign(sighash) + bytes([SIGHASH_ALL]) txin.scriptSig = CScript([sig, privkey.pub, OP_FALSE, redeemScript]) # exit() # print("txin.scriptSig", b2x(txin.scriptSig)) txin_scriptPubKey = redeemScript.to_p2sh_scriptPubKey() # print('Redeem txhex', b2x(tx.serialize())) VerifyScript(txin.scriptSig, txin_scriptPubKey, tx, 0, (SCRIPT_VERIFY_P2SH, )) print("script verified, sending raw tx") txid = bitcoind.sendrawtransaction(tx) print("Txid of submitted redeem tx: ", b2x(lx(b2x(txid)))) return b2x(lx(b2x(txid)))
def signed_commitment(self): """Return the fully signed commitment transaction.""" transaction = CMutableTransaction([self.anchor], [self.our, self.their]) transaction = CMutableTransaction.from_tx(transaction) for tx_out in transaction.vout: tx_out.scriptPubKey = tx_out.scriptPubKey.to_scriptPubKey() sighash = SignatureHash(self.anchor.scriptSig.redeem, transaction, 0, SIGHASH_ALL) sig = g.seckey.sign(sighash) + bytes([SIGHASH_ALL]) transaction.vin[0].scriptSig = transaction.vin[0].scriptSig.to_script(sig) # verify signing worked VerifyScript(transaction.vin[0].scriptSig, self.anchor.scriptSig.redeem.to_p2sh_scriptPubKey(), transaction, 0, (SCRIPT_VERIFY_P2SH,)) return transaction
def get_unsigned_tx(funding_tx, redeem_script, address, amount, lock_time=0, n_sequence=0, vout=0): """ Returns a raw transaction and it's signature hash that pays to address from funding_tx Arguments: funding_tx (str): the 'input' tx redeem_script (str): The redeem script address (str): The output address that would receive `amount` lock_time (int, optional): The time the tx should be locked to n_sequence (int, optional): The sequence number to use in tx vout (int, optional): The index of the output point of `funding_tx` Returns: A tuple containing: 1/ The serial tx 2/ The tx hash """ # Set P2SH funding tx in little-endian fx = lx(funding_tx) # nSequence must be any number less than 0xffffffff to enable nLockTime txin = CMutableTxIn(COutPoint(fx, vout), nSequence=n_sequence) # if(nlock_time != 0): # txin = CMutableTxIn(COutPoint(fx, vout), nSequence=n_sequence) # else: # txin = CMutableTxIn(COutPoint(fx, vout)) # Convert amount to Satoshi's amount *= COIN # Create the txout to address script_pubkey = CBitcoinAddress(address).to_scriptPubKey() txout = CMutableTxOut(amount, script_pubkey) # Create the unsigned transaction. tx = CMutableTransaction([txin], [txout], nLockTime=lock_time) # Calculte TX sig hash sighash = SignatureHash(CScript(redeem_script), tx, 0, SIGHASH_ALL) return (tx.serialize(), sighash)
def fundrawtransaction(self, given_transaction, *args, **kwargs): """ Make up some inputs for the given transaction. """ # just use any txid here vintxid = lx("99264749804159db1e342a0c8aa3279f6ef4031872051a1e52fb302e51061bef") if isinstance(given_transaction, str): given_bytes = x(given_transaction) elif isinstance(given_transaction, CMutableTransaction): given_bytes = given_transaction.serialize() else: raise FakeBitcoinProxyException("Wrong type passed to fundrawtransaction.") # this is also a clever way to not cause a side-effect in this function transaction = CMutableTransaction.deserialize(given_bytes) for vout_counter in range(0, self._num_fundrawtransaction_inputs): txin = CMutableTxIn(COutPoint(vintxid, vout_counter)) transaction.vin.append(txin) # also allocate a single output (for change) txout = make_txout() transaction.vout.append(txout) transaction_hex = b2x(transaction.serialize()) return {"hex": transaction_hex, "fee": 5000000}
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 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 spend_escrow(self, payer_sig, redeemer_sig, serial_tx, redeem_script): ''' Sends a transaction fulfilling the redeem script of escrow tx ''' # Read in transaction temp_tx = CTransaction.deserialize(serial_tx) tx = CMutableTransaction.from_tx(temp_tx) txin = tx.vin[0] # Set script sig txin.scriptSig = CScript([ OP_FALSE, payer_sig + '\x01', redeemer_sig + '\x01', OP_TRUE, redeem_script ]) # Verify script redeem_script = CScript(redeem_script) serial_tx = tx.serialize() VerifyScript(txin.scriptSig, redeem_script.to_p2sh_scriptPubKey(), tx, 0, [SCRIPT_VERIFY_P2SH]) serial_tx = tx.serialize() if not self.test: # txid = self.proxy.sendrawtransaction(tx) txid = b2lx(Hash(serial_tx)) else: txid = b2lx(Hash(serial_tx)) self.logger.info("spend_escrow: TXID is %s", txid) self.logger.info("spend_escrow: RAW TX is %s", b2x(serial_tx)) return serial_tx
def refund_tx(self, payer_sig, serial_tx, redeem_script): ''' Sends a transaction refunding the funder of the P2SH address. ''' # Read in transaction temp_tx = CTransaction.deserialize(serial_tx) tx = CMutableTransaction.from_tx(temp_tx) txin = tx.vin[0] # Set script sig txin.scriptSig = CScript([payer_sig + '\x01', OP_FALSE, redeem_script]) # Verify script redeem_script = CScript(redeem_script) VerifyScript(txin.scriptSig, redeem_script.to_p2sh_scriptPubKey(), tx, 0, [SCRIPT_VERIFY_P2SH]) serial_tx = tx.serialize() if not self.test: # txid = self.self.proxy.sendrawtransaction(tx) txid = b2lx(Hash(serial_tx)) else: txid = b2lx(Hash(serial_tx)) self.logger.info("refund_tx: TXID is %s", txid) self.logger.info("refund_tx: RAW TX is %s", b2x(serial_tx)) return serial_tx
def maketx(tx): #txid from blockr. bitcoind does not support tx index! txid = lx(tx) vout = 0 outp = COutPoint(txid, vout) print ("output: %s"%outp) # Create the txin structure, which includes the outpoint txin = CMutableTxIn(outp) print (txin) txin_scriptPubKey = CScript([OP_DUP, OP_HASH160, Hash160(seckey.pub), OP_EQUALVERIFY, OP_CHECKSIG]) print (txin_scriptPubKey) amount = 0.001*COIN txout = CMutableTxOut(amount, CBitcoinAddress(a).to_scriptPubKey()) print (txout) # Create the unsigned transaction. newtx = CMutableTransaction([txin], [txout]) print (newtx) sighash = SignatureHash(txin_scriptPubKey, newtx, 0, SIGHASH_ALL) print (sighash) # Now sign it. We have to append the type of signature we want to the end, in # this case the usual SIGHASH_ALL. sig = seckey.sign(sighash) + bytes([SIGHASH_ALL]) print (sig) # Set the scriptSig of our transaction input appropriately. txin.scriptSig = CScript([sig, seckey.pub]) try: VerifyScript(txin.scriptSig, txin_scriptPubKey, newtx, 0, (SCRIPT_VERIFY_P2SH,)) except: pass print ('*'*20) print(b2x(newtx.serialize())) """
def get(cls, address): """Get a Channel with the specified address.""" row = g.dat.execute( "SELECT * from CHANNELS WHERE address = ?", (address,)).fetchone() if row is None: raise Exception("Unknown address", address) address, commitment = row commitment = CMutableTransaction.deserialize(commitment) commitment = CMutableTransaction.from_tx(commitment) assert len(commitment.vin) == 1 assert len(commitment.vout) == 2 commitment.vin[0].scriptSig = AnchorScriptSig.from_script( commitment.vin[0].scriptSig) for tx_out in commitment.vout: tx_out.scriptPubKey = CBitcoinAddress.from_scriptPubKey(tx_out.scriptPubKey) return cls(address, commitment.vin[0], commitment.vout[0], commitment.vout[1])
def _build_certificate_transactions(wallet, issuing_address, revocation_address, certificate_metadata, fees, tail): """Make transactions for the certificates. """ logging.info('Creating tx of certificate for recipient uid: %s ...', certificate_metadata.uid) with open(certificate_metadata.certificate_hash_file_name, 'rb') as in_file: # this is the recipient-specific hash that will be recorded on the # blockchain hashed_certificate = in_file.read() cert_out = CMutableTxOut(0, CScript([OP_RETURN, hashed_certificate])) # send a transaction to the recipient's public key, and to a revocation # address txouts = create_recipient_outputs( certificate_metadata.pubkey, revocation_address, fees.min_per_output) # define transaction inputs unspent_outputs = wallet.get_unspent_outputs(issuing_address) last_input = unspent_outputs[tail] txins = [CTxIn(last_input.outpoint)] value_in = last_input.amount # very important! If we don't send the excess change back to ourselves, # some lucky miner gets it! amount = value_in - fees.cost_per_transaction if amount > 0: change_out = create_transaction_output(issuing_address, amount) txouts = txouts + [change_out] txouts = txouts + [cert_out] tx = CMutableTransaction(txins, txouts) # this is the transaction for a recipient, unsigned hextx = hexlify(tx.serialize()) with open(certificate_metadata.unsigned_tx_file_name, 'wb') as out_file: out_file.write(bytes(hextx, 'utf-8')) logging.info( 'Created unsigned tx for recipient; last_input=%s', last_input) return last_input
def sendrawtransaction(self, given_transaction): """ Pretend to broadcast and relay the transaction. Return the txid of the given transaction. """ if isinstance(given_transaction, str): given_bytes = x(given_transaction) elif isinstance(given_transaction, CMutableTransaction): given_bytes = given_transaction.serialize() else: raise FakeBitcoinProxyException("Wrong type passed to sendrawtransaction.") transaction = CMutableTransaction.deserialize(given_bytes) return b2lx(transaction.GetHash())
def signrawtransaction(self, given_transaction): """ This method does not actually sign the transaction, but it does return a transaction based on the given transaction. """ if isinstance(given_transaction, str): given_bytes = x(given_transaction) elif isinstance(given_transaction, CMutableTransaction): given_bytes = given_transaction.serialize() else: raise FakeBitcoinProxyException("Wrong type passed to signrawtransaction.") transaction = CMutableTransaction.deserialize(given_bytes) transaction_hex = b2x(transaction.serialize()) return {"hex": transaction_hex}
def from_serialized(cls, serialized_tx, testnet=False): tx = CMutableTransaction.stream_deserialize(BytesIO(serialized_tx)) return BitcoinTransaction(tx, 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])) tx.vout.append(multisig_txout)
def test_send_script_spend(self): """ Run more in-depth execution checks on the script generated for the send transaction """ sender_private_key = CBitcoinSecret.from_secret_bytes(x('4f65da9b656de4036076911707d2b2dbf065689245b8674faa8790e36d7e5850')) sender_public_key = sender_private_key.pub recipient_private_key = CBitcoinSecret.from_secret_bytes(x('cfe8e33672f7045f020210f3c7afbca660e053e4c9415c542ff185e97b175cf0')) recipient_public_key = recipient_private_key.pub secret = x('88d6e51f777b0b8dc0f429da9f372fbc') secret_hash = Hash(secret) send_to_key = CBitcoinSecret.from_secret_bytes(x('15a249b4c09286b877d4708191f1ee8de09903bae034dd9dc8e3286451fa1c80')) send_to_address = P2PKHBitcoinAddress.from_pubkey(send_to_key.pub) random_tx_id = x('8390b4c8198198c6447da1a6fad498209436a785459936b95a1e3b63618c1d8a') value = 10 * COIN send_tx_script_pub_key = build_send_out_script(sender_public_key, recipient_public_key, secret_hash) send_txins = [CMutableTxIn(COutPoint(random_tx_id, 0))] send_txouts = [CMutableTxOut(value, send_tx_script_pub_key)] send_tx = CMutableTransaction(send_txins, send_txouts) # Test the standard spend transaction txins = [CMutableTxIn(COutPoint(Hash(send_tx.serialize()), 0))] txouts = [CMutableTxOut(value, send_to_address.to_scriptPubKey())] recv_tx = CMutableTransaction(txins, txouts) sighash = SignatureHash(send_tx_script_pub_key, recv_tx, 0, SIGHASH_ALL) recipient_sig = recipient_private_key.sign(sighash) + (b'\x01') # bytes([SIGHASH_ALL]) recv_tx.vin[0].scriptSig = CScript([secret, 0, recipient_sig, recipient_public_key]) VerifyScript(recv_tx.vin[0].scriptSig, send_tx.vout[0].scriptPubKey, recv_tx, 0, (SCRIPT_VERIFY_P2SH,)) # Test a refund transaction refund_tx = CMutableTransaction(txins, txouts) sighash = SignatureHash(send_tx_script_pub_key, refund_tx, 0, SIGHASH_ALL) sender_sig = sender_private_key.sign(sighash) + (b'\x01') # bytes([SIGHASH_ALL]) recipient_sig = recipient_private_key.sign(sighash) + (b'\x01') # bytes([SIGHASH_ALL]) refund_tx.vin[0].scriptSig = CScript([sender_sig, sender_public_key, 1, recipient_sig, recipient_public_key]) VerifyScript(refund_tx.vin[0].scriptSig, send_tx_script_pub_key, refund_tx, 0, (SCRIPT_VERIFY_P2SH,)) # Test invalid transactions are rejected invalid_tx = CMutableTransaction(txins, txouts) sighash = SignatureHash(send_tx_script_pub_key, invalid_tx, 0, SIGHASH_ALL) sender_sig = sender_private_key.sign(sighash) + (b'\x01') # bytes([SIGHASH_ALL]) recipient_sig = recipient_private_key.sign(sighash) + (b'\x01') # bytes([SIGHASH_ALL]) invalid_tx.vin[0].scriptSig = CScript([]) with self.assertRaises(MissingOpArgumentsError): VerifyScript(invalid_tx.vin[0].scriptSig, send_tx_script_pub_key, invalid_tx, 0, (SCRIPT_VERIFY_P2SH,)) invalid_tx.vin[0].scriptSig = CScript([recipient_sig, recipient_public_key, 0]) with self.assertRaises(VerifyOpFailedError): VerifyScript(invalid_tx.vin[0].scriptSig, send_tx_script_pub_key, invalid_tx, 0, (SCRIPT_VERIFY_P2SH,)) invalid_tx.vin[0].scriptSig = CScript([recipient_sig, recipient_public_key, 1]) with self.assertRaises(VerifyOpFailedError): VerifyScript(invalid_tx.vin[0].scriptSig, send_tx_script_pub_key, invalid_tx, 0, (SCRIPT_VERIFY_P2SH,)) invalid_tx.vin[0].scriptSig = CScript([recipient_sig, recipient_public_key, 1, recipient_sig, recipient_public_key]) with self.assertRaises(VerifyOpFailedError): VerifyScript(invalid_tx.vin[0].scriptSig, send_tx_script_pub_key, invalid_tx, 0, (SCRIPT_VERIFY_P2SH,)) invalid_tx.vin[0].scriptSig = CScript([sender_sig, sender_public_key, 1, sender_sig, sender_public_key]) with self.assertRaises(VerifyOpFailedError): VerifyScript(invalid_tx.vin[0].scriptSig, send_tx_script_pub_key, invalid_tx, 0, (SCRIPT_VERIFY_P2SH,))
try: args.txid = lx(args.txid) except ValueError as err: parser.error('Invalid txid: %s' % str(err)) if len(args.txid) != 32: parser.error('Invalid txid: Wrong length.') try: rpc.gettransaction(args.txid) except IndexError as err: parser.exit('Invalid txid: Not in wallet.') txinfo = rpc.getrawtransaction(args.txid, True) tx = CMutableTransaction.from_tx(txinfo['tx']) if 'confirmations' in txinfo and txinfo['confirmations'] > 0: parser.exit("Transaction already mined; %d confirmations." % txinfo['confirmations']) # Find a txout that was being used for change change_txout = None for vout in tx.vout: try: addr = CBitcoinAddress.from_scriptPubKey(vout.scriptPubKey) except ValueError: continue if rpc.validateaddress(addr)['ismine']: change_txout = vout break
# transaction hashes are shown little-endian rather than the usual big-endian. # There's also a corresponding x() convenience function that takes big-endian # hex and converts it to bytes. txid = lx('bff785da9f8169f49be92fa95e31f0890c385bfb1bd24d6b94d7900057c617ae') vout = 0 # Create the txin structure, which includes the outpoint. The scriptSig # defaults to being empty. txin = CMutableTxIn(COutPoint(txid, vout)) # Create the txout. This time we create the scriptPubKey from a Bitcoin # address. txout = CMutableTxOut(0.0005*COIN, CBitcoinAddress('323uf9MgLaSn9T7vDaK1cGAZ2qpvYUuqSp').to_scriptPubKey()) # Create the unsigned transaction. tx = CMutableTransaction([txin], [txout]) # Calculate the signature hash for that transaction. Note how the script we use # is the redeemScript, not the scriptPubKey. That's because when the CHECKSIG # operation happens EvalScript() will be evaluating the redeemScript, so the # corresponding SignatureHash() function will use that same script when it # replaces the scriptSig in the transaction being hashed with the script being # executed. sighash = SignatureHash(txin_redeemScript, tx, 0, SIGHASH_ALL) # Now sign it. We have to append the type of signature we want to the end, in # this case the usual SIGHASH_ALL. sig = seckey.sign(sighash) + bytes([SIGHASH_ALL]) # Set the scriptSig of our transaction input appropriately. txin.scriptSig = CScript([sig, txin_redeemScript])
if unspent_tx.vout[0].nValue < args.amount: continue if check_full_rbf_optin(unspent_tx): tx1 = unspent_tx logging.info('Found unconfirmed full-RBF tx1 %s' % b2lx(txid)) break else: txids_seen.add(txid) else: logging.info('No unconfirmed full-RBF tx1 found; creating new tx') tx2 = CMutableTransaction.from_tx(tx1) if tx1 is not None else CMutableTransaction() # There might be a better way to fund the new outputs, so delete all but the # first input. Of course, we can't delete all the inputs - the new transaction # wouldn't conflict with the old one and you'd pay everyone twice! tx2.vin = tx2.vin[0:1] if not args.first_seen_safe and len(tx2.vout) > 0: # Delete the change output. # # Unfortunately there isn't any way to ask Bitcoin Core if a given address # is a change address; if you're sending yourself funds to test the feature # it's not possible to distinguish change from send-to-self outputs. # # So instead we always build transactions such that the first output is # change, and we delete only that output. Not pretty - you don't want to do