Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions bitcoinutils/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ def from_raw(txoutputrawhex: Union[str, bytes], cursor: int = 0, has_segwit: boo
txoutputraw = txoutputrawhex
else:
raise TypeError("Input must be a hexadecimal string or bytes")


# Unpack the amount of the TxOutput directly in bytes
amount_format = "<Q" # Little-endian unsigned long long (8 bytes)
Expand Down Expand Up @@ -493,6 +493,8 @@ class Transaction:
Calculates the tx segwit size
copy()
creates a copy of the object (classmethod)
set_witness(txin_index, witness)
sets the witness for a particular input index
get_transaction_digest(txin_index, script, sighash)
returns the transaction input's digest that is to be signed according
get_transaction_segwit_digest(txin_index, script, amount, sighash)
Expand Down Expand Up @@ -552,7 +554,7 @@ def from_raw(rawtxhex: Union[str, bytes]):
rawtx = rawtxhex
else:
raise TypeError("Input must be a hexadecimal string or bytes")


# Read version (4 bytes)
version = rawtx[0:4]
Expand Down Expand Up @@ -639,6 +641,26 @@ def copy(cls, tx: "Transaction") -> "Transaction":
wits = [TxWitnessInput.copy(witness) for witness in tx.witnesses]
return cls(ins, outs, tx.locktime, tx.version, tx.has_segwit, wits)

# this sets empty witness slots (if necessary)
# makes length of witness equal to the number of inputs, to prevent expliclty defining empty witness inputs
# for non segwit inputs
def set_witness(self, txin_index: int, witness: TxWitnessInput):
"""Safely set a witness at the specified index"""
if not self.has_segwit:
raise RuntimeError(
"Transaction should be segwit in order to set segwit slots"
)
witness_len = len(self.witnesses)
input_len = len(self.inputs)
if witness_len < input_len:
# append empty witness inputs if input_len>witness_len
for _ in range(input_len - witness_len):
self.witnesses.append(TxWitnessInput([]))

if txin_index < 0 or txin_index >= len(self.inputs):
raise IndexError("txin_index out of range")
self.witnesses[txin_index] = witness

def get_transaction_digest(
self, txin_index: int, script: Script, sighash: int = SIGHASH_ALL
):
Expand Down
8 changes: 3 additions & 5 deletions examples/spend_multi_input_p2tr_and_p2pkh.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,10 @@ def main():
sig2 = priv2.sign_input(tx, 1, utxos_script_pubkeys[1])
sig3 = priv3.sign_taproot_input(tx, 2, utxos_script_pubkeys, amounts)

tx.witnesses.append(TxWitnessInput([sig1]))
#set witness sets the witness at a particular input index
tx.set_witness(0, TxWitnessInput([sig1]))
txin2.script_sig = Script([sig2, pub2.to_hex()])
# the second input is not segwit but we still need to add an empty
# witness input script
tx.witnesses.append(TxWitnessInput([]))
tx.witnesses.append(TxWitnessInput([sig3]))
tx.set_witness(2, TxWitnessInput([sig3]))

# print raw signed transaction ready to be broadcasted
print("\nRaw signed transaction:\n" + tx.serialize())
Expand Down
2 changes: 1 addition & 1 deletion run_all_examples.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/bash

for fil in ./examples/*.py; do
for fil in ./examples/*.py; do
python $fil;
sleep 2;
done
Expand Down