def into_transaction(self, dust_secret: CBitcoinSecret, dust_outpoint: OutPointWithTx, feerate): if dust_outpoint.prevout.scriptPubKey != pubkey_to_P2PKH_scriptPubkey( dust_secret.pub): print(b2x(dust_outpoint.prevout.scriptPubKey)) print(b2x(pubkey_to_P2PKH_scriptPubkey(dust_secret.pub))) raise Exception("Outpoint has incorrect scriptPubKey") sum_in = dust_outpoint.prevout.nValue fees = int(tx_size(1, 2) / 1000 * feerate) refund = sum_in - fees - self._life_signal_amount print('fee: %f' % fees) print('amount: %f' % (sum_in - fees)) redeemScript = self.redeemScript unsigned_tx = CTransaction([CTxIn(dust_outpoint.outpoint)], [ CTxOut(self._life_signal_amount, redeemScript.to_p2sh_scriptPubKey()), CTxOut(refund, pubkey_to_P2PKH_scriptPubkey(dust_secret.pub)) ]) # spend the dust input sighash = SignatureHash(dust_outpoint.prevout.scriptPubKey, unsigned_tx, 0, SIGHASH_ALL) sig = dust_secret.sign(sighash) + bytes([SIGHASH_ALL]) sigScript = CScript([sig, dust_secret.pub]) signed_input = [CTxIn(unsigned_tx.vin[0].prevout, sigScript)] return CTransaction(signed_input, unsigned_tx.vout, unsigned_tx.nLockTime)
def spend_command(args): args.addr = CBitcoinAddress(args.addr) redeemScript = hodl_redeemScript(args.privkey, args.nLockTime) scriptPubKey = redeemScript.to_p2sh_scriptPubKey() proxy = bitcoin.rpc.Proxy() prevouts = [] for prevout in args.prevouts: try: txid, n = prevout.split(':') txid = lx(txid) n = int(n) outpoint = COutPoint(txid, n) except ValueError: args.parser.error('Invalid output: %s' % prevout) try: prevout = proxy.gettxout(outpoint) except IndexError: args.parser.error('Outpoint %s not found' % outpoint) prevout = prevout['txout'] if prevout.scriptPubKey != scriptPubKey: args.parser.error('Outpoint not correct scriptPubKey') prevouts.append((outpoint, prevout)) sum_in = sum(prev_txout.nValue for outpoint, prev_txout in prevouts) tx_size = ( 4 + # version field 2 + # # of txins len(prevouts) * 153 + # txins, including sigs 1 + # # of txouts 34 + # txout 4 # nLockTime field ) feerate = int(proxy._call('estimatefee', 1) * COIN) # satoshi's per KB if feerate <= 0: feerate = 10000 fees = int(tx_size / 1000 * feerate) unsigned_tx = CTransaction( [CTxIn(outpoint, nSequence=0) for outpoint, prevout in prevouts], [CTxOut(sum_in - fees, args.addr.to_scriptPubKey())], args.nLockTime) signed_tx = CTransaction([ CTxIn(txin.prevout, spend_hodl_redeemScript(args.privkey, args.nLockTime, unsigned_tx, i), nSequence=0) for i, txin in enumerate(unsigned_tx.vin) ], unsigned_tx.vout, unsigned_tx.nLockTime) print(b2x(signed_tx.serialize()))
def accuse(self, dust_op: OutPointWithTx, wallet_op: OutPointWithTx, user_index, secret_sgx): ls_tx = self._life_signals[user_index].into_transaction( secret_sgx, dust_op, feerate) # FIXME: hardcode zero here because life signal is always the first output in a life signal tx nOut_for_ls = 0 ls = self._life_signals[user_index] if ls_tx.vout[ nOut_for_ls].scriptPubKey != ls.redeemScript.to_p2sh_scriptPubKey( ): raise Exception("SGX can't spend the life signal") if wallet_op.prevout.scriptPubKey != self.scriptPubkey(): raise Exception("wallet utxo mismatch") print('ls value: %f' % ls_tx.vout[nOut_for_ls].nValue) sum_in = ls_tx.vout[0].nValue + wallet_op.prevout.nValue fees = int(tx_size(2, 1) / 1000 * feerate) print('fee: %f' % fees) print('amount: %f' % (sum_in - fees)) # note: nVersion=2 is required by CSV unsigned_tx = CTransaction([ CTxIn(COutPoint(ls_tx.GetTxid(), nOut_for_ls), nSequence=ls.relative_timeout), CTxIn(wallet_op.outpoint) ], [ CTxOut(wallet_op.prevout.nValue, self.scriptPubkey(exclude_indices=(user_index, ))) ], nVersion=2) # spend the life signal lifesignal_sigScript = self._life_signals[ user_index].scriptSig_by_key2(unsigned_tx, 0) # spend the wallet wallet_sigScript = self._scriptSig_by_sgx(secret_sgx, unsigned_tx, 1) # return the life signal as well as both transactions return ls, ls_tx, CTransaction([ CTxIn(unsigned_tx.vin[0].prevout, scriptSig=lifesignal_sigScript, nSequence=ls.relative_timeout), CTxIn(wallet_op.outpoint, wallet_sigScript) ], unsigned_tx.vout, unsigned_tx.nLockTime, unsigned_tx.nVersion)
def test_is_coinbase(self): tx = CTransaction() self.assertFalse(tx.is_coinbase()) tx.vin.append(CTxIn()) # IsCoinBase() in reference client doesn't check if vout is empty self.assertTrue(tx.is_coinbase()) tx.vin[0].prevout.n = 0 self.assertFalse(tx.is_coinbase()) tx.vin[0] = CTxIn() tx.vin.append(CTxIn()) self.assertFalse(tx.is_coinbase())
def native(self): tx_hex = self.output.transaction_hash # Convert a little-endian hex string to bytes txid = lx(tx_hex) vout = self.output.index outpoint = COutPoint(txid, vout) return CTxIn(outpoint)
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 build_bounce_tx(self, txid_hex): #Generate p2sh script pub key. redeem_script = self.fund_redeem_script(self.my) redeem_script_hash160 = self.hash160_script(redeem_script) txin_script_pub_key = CScript( [OP_HASH160, redeem_script_hash160["bin"], OP_EQUAL]) #Generate address to receive bounce. if "bounce" not in self.key_pairs: self.key_pairs["bounce"] = self.key_pair_from_address( self.jsonrpc[self.my].getnewaddress(), self.my) #Setup tx inputs and outputs. txid = lx(txid_hex) vout = 0 txin = CTxIn(COutPoint(txid, vout), CScript(), 0) #Sequence number 0. txout = CTxOut( (self.send_amount - decimal.Decimal(coinbend.config["mining_fee"]["standard"])) * COIN, CBitcoinAddress( self.key_pairs["bounce"]["addr"]["base58"]).to_scriptPubKey()) #Locktime is unsigned int 4, unix timestamp in little endian format. #(Conversion to little endian is handled by the library already.) nlock_time = datetime.datetime.now() + datetime.timedelta( seconds=self.future_minutes * 60) nlock_time = int(nlock_time.strftime("%s")) #Create unsigned transaction. tx = CTransaction([txin], [txout], nlock_time) return b2x(tx.serialize())
def add_input(self, serial_id: int, prevtx: str, prevtx_vout: int, max_witness_len: int, script: str, sequence: int, privkey: str = None) -> None: # Find the txid of the transaction prev_tx = CTransaction.deserialize(bytes.fromhex(prevtx)) txin = CTxIn(COutPoint(prev_tx.GetTxid(), prevtx_vout), nSequence=sequence) # Get the previous output for its outscript + value prev_vout = prev_tx.vout[prevtx_vout] self.inputs.append({ 'input': txin, 'serial_id': serial_id, 'sats': prev_vout.nValue, 'prev_outscript': prev_vout.scriptPubKey.hex(), 'redeemscript': script, 'max_witness_len': max_witness_len, 'privkey': privkey, })
def __init__(self, hash=b'\x00' * 32, vin=CTxIn(), sig=b'\x00' * 65, height=0): """Create a new transaction lock hash is the transaction id being locked vin is the masternode funding address sig is the masternodes signature for the lock height is the block the lock is effective If their contents are not already immutable, immutable copies will be made. """ if not len(hash) == 32: raise ValueError( 'CTransactionLock: hash must be exactly 32 bytes; got %d bytes' % len(hash)) # noqa object.__setattr__(self, 'hash', hash) object.__setattr__(self, 'vin', vin) if not len(sig) == 65: raise ValueError( 'CTransactionLock: sig must be exactly 65 bytes; got %d bytes' % len(sig)) # noqa object.__setattr__(self, 'sig', sig) object.__setattr__(self, 'height', height)
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 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 creates_add_input(bitcoind, tx): """Creates and add an input to a CMutableTransaction, SIGHASH_ALL. :returns: The txid of the first stage fee bumping tx (for convenience) """ # First we get some coins privkey = CKey(os.urandom(32)) scriptPubKey = CScript([OP_0, Hash160(privkey.pub)]) address = CBitcoinAddress.from_scriptPubKey(scriptPubKey) # Let's say we want to increase the fees by 5000 sats amount = 5000 # Bitcoind is nice and will create the first stage transaction first_txid = bitcoind.rpc.sendtoaddress(str(address), amount / COIN) vout_index = get_output_index( bitcoind.rpc.getrawtransaction(first_txid, 1), amount) # === We don't generate a block yet ! === tx.vin.append( CTxIn(COutPoint(lx(first_txid), vout_index), nSequence=0xfffffffe)) # Sign the new input with ALL tx_hash = SignatureHash(address.to_redeemScript(), tx, 1, SIGHASH_ALL, amount, SIGVERSION_WITNESS_V0) sig = privkey.sign(tx_hash) + bytes([SIGHASH_ALL]) tx.wit.vtxinwit.append(CTxInWitness(CScriptWitness([sig, privkey.pub]))) return first_txid
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 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 add_input(self, serial_id: int, prevtx: str, prevtx_vout: int, script_sig: str, sequence: int, privkey: str = None) -> None: # the dummy runner sends empty info, skip if len(prevtx) == 0: return # Find the txid of the transaction prev_tx = CTransaction.deserialize(bytes.fromhex(prevtx)) txin = CTxIn(COutPoint(prev_tx.GetTxid(), prevtx_vout), nSequence=sequence) # Get the previous output for its outscript + value prev_vout = prev_tx.vout[prevtx_vout] self.inputs.append({'input': txin, 'serial_id': serial_id, 'sats': prev_vout.nValue, 'prev_outscript': prev_vout.scriptPubKey.hex(), 'redeemscript': script_sig, 'privkey': privkey, })
def withdrawfromvault(self, fromvaultaddress, toaddress, amount): vault = self.getvault(fromvaultaddress) received = self.chaindb.listreceivedbyvault(fromvaultaddress) received = received.values()[0] if received['value'] < amount + 2 * utils.calculate_fees(None): self.logger.warning("Insufficient funds in vault, exiting, return") return # create transaction tx = CTransaction() # to the receiver txout = CTxOut() txout.nValue = amount txout.scriptPubKey = utils.address_to_pay_to_pubkey_hash(toaddress) tx.vout.append(txout) # from the sender nValueIn = 0 nValueOut = amount txin = CTxIn() txin.prevout = COutPoint() txin.prevout.hash = received['txhash'] txin.prevout.n = received['n'] txin.scriptSig = received['scriptPubKey'] tx.vin.append(txin) # calculate nValueIn nValueIn = received['value'] # calculate the total excess amount excessAmount = nValueIn - nValueOut # calculate the fees fees = 2 * utils.calculate_fees(tx) # create change transaction, if there is any change left if excessAmount > fees: change_txout = CTxOut() change_txout.nValue = excessAmount - fees account = self.getaccount() changeaddress = fromvaultaddress self.logger.debug("Change address: %s" % changeaddress) change_txout.scriptPubKey = \ utils.vault_address_to_pay_to_vault_script(changeaddress) tx.vout.append(change_txout) # calculate txhash tx.calc_sha256() txhash = str(tx.sha256) key = CKey() key.set_pubkey(vault['public_key']) key.set_privkey(vault['private_key']) signature = key.sign(txhash) vaultscript = utils.create_vault_script(vault['address'], \ vault['master_address'], vault['timeout'], vault['maxfees']) scriptSig = chr(OP_VAULT_WITHDRAW) + chr(len(signature)) + signature + \ chr(len(vaultscript)) + vaultscript self.logger.debug("Adding signature: %s" % binascii.hexlify(scriptSig)) txin.scriptSig = scriptSig return tx
def appeal(self, user_index, user_secret: CBitcoinSecret, lifesignal_op: OutPointWithTx): ls = self._life_signals[user_index] if lifesignal_op.prevout.scriptPubKey != ls.redeemScript.to_p2sh_scriptPubKey( ): raise Exception("mismatch scriptPubkey") # spend the life signal into a black hole unsigned_tx = CTransaction([CTxIn(lifesignal_op.outpoint)], [CTxOut(0, CScript([True]))], nVersion=2) return CTransaction([ CTxIn(lifesignal_op.outpoint, scriptSig=ls.scriptSig_by_key1(user_secret, unsigned_tx, 0)) ], unsigned_tx.vout, nVersion=2)
def overridevaulttx(self, fromvaultaddress, toaddress): vault = self.getvault(fromvaultaddress) # select the input addresses received = self.chaindb.listallreceivedbyvault(fromvaultaddress) if not received: self.logger.warning("Empty vault, exiting, return") return None, None received = received.values()[0] if received['value'] < 2 * utils.calculate_fees(None): self.logger.warning("Insufficient funds in vault, exiting, return") return None, None # calculate remaining amount amount = received['value'] - 2 * utils.calculate_fees(None) # create transaction tx = CTransaction() # to the receiver txout = CTxOut() txout.nValue = amount txout.scriptPubKey = utils.address_to_pay_to_pubkey_hash(toaddress) tx.vout.append(txout) # from the sender nValueIn = 0 nValueOut = amount txin = CTxIn() txin.prevout = COutPoint() txin.prevout.hash = received['txhash'] txin.prevout.n = received['n'] txin.scriptSig = received['scriptPubKey'] tx.vin.append(txin) # calculate nValueIn nValueIn = received['value'] # calculate the total excess amount excessAmount = nValueIn - nValueOut # calculate the fees fees = utils.calculate_fees(tx) # calculate txhash tx.calc_sha256() txhash = str(tx.sha256) key = CKey() key.set_pubkey(vault['public_key']) key.set_privkey(vault['private_key']) signature = key.sign(txhash) # get the script vaultscript = utils.create_vault_script(vault['address'], \ vault['master_address'], vault['timeout'], vault['maxfees']) scriptSig = chr(OP_VAULT_OVERRIDE) + chr(len(vault['master_public_key'])) + \ vault['master_public_key'] + chr(len(signature)) + signature + \ chr(len(vaultscript)) + vaultscript self.logger.debug("Adding signature: %s" % binascii.hexlify(scriptSig)) txin.scriptSig = scriptSig return amount, tx
def add_input(): try: outpoint = COutPoint(lx(str(input_prev_tx.text())), input_prev_vout.get_amount()) in_script = Script.from_human(str(input_script.toPlainText())) new_input = CTxIn(outpoint, in_script.get_hex().decode('hex'), input_sequence.get_amount()) except Exception as e: self.status_message(str(e), True) return else: self.inputs_tree.add_input(new_input) rm_input_edit.setRange(0, len(self.inputs_tree.get_inputs()) - 1)
def create_unvault_spend(unvault_txid, unvault_vout, txout): """Creates a transaction spending from an unvault transaction. :param unvault_txid: The id of the unvaulting transaction. :param unvault_vout: The index of the unvault output in this transaction. :param txout: The txo (a CTxOut) to spend the coins to. :return: The unsigned transaction, a CMutableTransaction. """ txin = CTxIn(COutPoint(unvault_txid, unvault_vout)) return CMutableTransaction([txin], [txout], nVersion=2)
def get_inputs(self): vin = [] for i in range(self.model.rowCount()): prev_hash, prev_vout = str(self.model.item(i, 0).text()).split(':') in_script = str(self.model.item(i, 1).data(RawRole).toString()) sequence = int(self.model.item(i, 2).text()) outpoint = COutPoint(lx(prev_hash), int(prev_vout)) i_input = CTxIn(outpoint, in_script.decode('hex'), sequence) vin.append(i_input) return vin
def test_init_with_field_keyword_args(self): ins = ( CTxIn(COutPoint(lx('537ecb89e5ed7e872f988447432e6791c0a58b069c4ec8647e1683a383e867a3'), 0), x('473044022043b9aee9187effd7e6c7bc444b09162570f17e36b4a9c02cf722126cc0efa3d502200b3ba14c809fa9a6f7f835cbdbbb70f2f43f6b30beaf91eec6b8b5981c80cea50121025edf500f18f9f2b3f175f823fa996fbb2ec52982a9aeb1dc2e388a651054fb0f')) ) outs = ( CTxOut(114263, x('76a91495efca2c6a6f0e0f0ce9530219b48607a962e77788ac')), CTxOut(2125893, x('76a914f28abfb465126d6772dcb4403b9e1ad2ea28a03488ac')) ) fields_data = {'Timestamp': 1432478808} tx = Transaction(ins, outs, 0, 2, peercoin_fields, fields_data) self.assertEqual(tx.fields, peercoin_fields) self.assertEqual(tx.Timestamp, 1432478808)
def bump_delay(self, tx, vin, delay): assert 0 < delay < 2**16 if tx.nVersion < 2: tx.nVersion = 2 seq = tx.vin[vin].nSequence assert seq == 0xFFFFFFFF or seq & 0x80000000 == 0 if seq == 0xFFFFFFFF: d = 0 d = seq & 0xFFFF if d < delay: d = delay otx = tx.vin[vin] tx.vin[vin] = CTxIn(otx.prevout, otx.scriptSig, d)
def __create_new_timestamp_tx_template(self, outpoint, txout_value, change_scriptPubKey): """Create a new timestamp transaction template The transaction created will have one input and two outputs, with the timestamp output set to an invalid dummy. The fee is set to zero, but nSequence is set to opt-in to transaction replacement, so you can find an appropriate fee iteratively. """ return CTransaction([CTxIn(outpoint, nSequence=0xfffffffd)], [CTxOut(txout_value, change_scriptPubKey), CTxOut(-1, CScript())])
def create_unvault_spend(unvault_txid, unvault_vout, txout, rbf=False): """Creates a transaction spending from an unvault transaction. :param unvault_txid: The id of the unvaulting transaction. :param unvault_vout: The index of the unvault output in this transaction. :param txout: The txo (a CTxOut) to spend the coins to. :param rbf: If set to True, signal RBF. :return: The unsigned transaction, a CMutableTransaction. """ sequence = 0xfffffffe if rbf else 0xffffffff txin = CTxIn(COutPoint(unvault_txid, unvault_vout), nSequence=sequence) return CMutableTransaction([txin], [txout], nVersion=2)
def create_spend_vault_txout(vault_txid, vault_vout, txout): """Creates a transaction spending a vault txout. Note that this transaction only ever has one input and one output. :param vault_txid: The id of the transaction funding the vault, as bytes. :param vault_vout: The index of the vault output in this transaction. :param txout: The CTxOut to pay to. :return: The *unsigned* transaction, a CMutableTransaction. """ tmp_txin = CTxIn(COutPoint(vault_txid, vault_vout)) return CMutableTransaction([tmp_txin], [txout], nVersion=2)
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 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 create_trx(op_return_val, issuing_transaction_cost, issuing_address, txouts, tx_input): cert_out = CMutableTxOut(0, CScript([OP_RETURN, op_return_val])) txins = [CTxIn(tx_input.outpoint)] value_in = tx_input.amount # send change back to our address amount = value_in - issuing_transaction_cost.total if amount > 0: change_out = create_transaction_output(issuing_address, amount) txouts = txouts + [change_out] txouts = txouts + [cert_out] tx = CMutableTransaction(txins, txouts) return tx
def create_spend_vault_txout(vault_txid, vault_vout, txout, rbf=False): """Creates a transaction spending a vault txout. Note that this transaction only ever has one input and one output. :param vault_txid: The id of the transaction funding the vault, as bytes. :param vault_vout: The index of the vault output in this transaction. :param txout: The CTxOut to pay to. :param rbf: If set to true, signal for RBF. :return: The *unsigned* transaction, a CMutableTransaction. """ sequence = 0xfffffffe if rbf else 0xffffffff tmp_txin = CTxIn(COutPoint(vault_txid, vault_vout), nSequence=sequence) return CMutableTransaction([tmp_txin], [txout], nVersion=2)