Skip to content

Commit f0f50e2

Browse files
committed
Merge branch 'guptamukund22-code'
2 parents 2ebc6df + 1f43192 commit f0f50e2

2 files changed

Lines changed: 50 additions & 57 deletions

File tree

bitcoinutils/transactions.py

Lines changed: 49 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -143,50 +143,45 @@ def __repr__(self):
143143
@staticmethod
144144
def from_raw(txinputrawhex: str, cursor: int = 0, has_segwit: bool = False):
145145
"""
146-
Imports a TxInput from a Transaction's hexadecimal data using struct for parsing.
146+
Imports a TxInput from a Transaction's hexadecimal data
147147
148-
Args:
149-
txinputrawhex (str): The hexadecimal raw string of the Transaction.
150-
cursor (int): The position at which the algorithm will start to read the data.
151-
has_segwit (bool): Indicates if the Tx Input is SegWit enabled.
152-
153-
Returns:
154-
tuple: (TxInput object, new cursor position)
155-
156-
Raises:
157-
Exception: If the transaction hash or script is malformed.
148+
Attributes
149+
----------
150+
txinputrawhex : string (hex)
151+
The hexadecimal raw string of the Transaction
152+
cursor : int
153+
The cursor of which the algorithm will start to read the data
154+
has_segwit : boolean
155+
Is the Tx Input segwit or not
158156
"""
159157
txinputraw = h_to_b(txinputrawhex)
160158

161-
# Unpack transaction ID (hash) and output index
162-
txid_format = "<32sI"
163-
txid, vout = struct.unpack_from(txid_format, txinputraw, cursor)
164-
txid = txid[::-1].hex() # Reverse to match usual hexadecimal order
165-
cursor += struct.calcsize(txid_format)
159+
# Unpack transaction ID (hash) in bytes and output index
160+
txid, vout = struct.unpack_from('<32sI', txinputraw, cursor)
161+
txid = txid[::-1] # Reverse to match usual hexadecimal order
162+
cursor += 36 # 32 bytes for txid and 4 bytes for vout
166163

167164
# Read the unlocking script size using parse_compact_size
168-
unlocking_script_size, size = parse_compact_size(txinputraw, cursor)
165+
unlocking_script_size, size = parse_compact_size(txinputraw[cursor:])
169166
cursor += size
170167

171-
# Read the unlocking script
172-
script_format = f"{unlocking_script_size}s"
173-
unlocking_script, = struct.unpack_from(script_format, txinputraw, cursor)
168+
# Read the unlocking script in bytes
169+
unlocking_script = struct.unpack_from(f'{unlocking_script_size}s', txinputraw, cursor)[0]
174170
cursor += unlocking_script_size
175171

176-
# Read the sequence number
177-
sequence_format = "<I"
178-
sequence, = struct.unpack_from(sequence_format, txinputraw, cursor)
179-
cursor += struct.calcsize(sequence_format)
172+
# Read the sequence number in bytes
173+
sequence, = struct.unpack_from('<4s', txinputraw, cursor)
174+
cursor += 4
180175

181-
# If coinbase input, handle differently
182-
if txid == 64 * "0":
176+
# If coinbase input (utxo will be all zeros), handle script differently
177+
if txid.hex() == '00' * 32:
183178
script_sig = Script([unlocking_script.hex()]) # Treat as single element for coinbase
184179
else:
185180
script_sig = Script.from_raw(unlocking_script.hex(), has_segwit=has_segwit)
186181

187182
# Create the TxInput instance
188183
tx_input = TxInput(
189-
txid=txid,
184+
txid=txid.hex(),
190185
txout_index=vout,
191186
script_sig=script_sig,
192187
sequence=sequence
@@ -306,13 +301,13 @@ def from_raw(txoutputrawhex: str, cursor: int = 0, has_segwit: bool = False):
306301
"""
307302
txoutputraw = h_to_b(txoutputrawhex)
308303

309-
# Unpack the output value (amount)
304+
# Unpack the amount of the TxOutput directly in bytes
310305
amount_format = "<Q" # Little-endian unsigned long long (8 bytes)
311306
amount, = struct.unpack_from(amount_format, txoutputraw, cursor)
312307
cursor += struct.calcsize(amount_format)
313308

314309
# Read the locking script size using parse_compact_size
315-
lock_script_size, size = parse_compact_size(txoutputraw, cursor)
310+
lock_script_size, size = parse_compact_size(txoutputraw[cursor:])
316311
cursor += size
317312

318313
# Read the locking script
@@ -328,6 +323,7 @@ def from_raw(txoutputrawhex: str, cursor: int = 0, has_segwit: bool = False):
328323

329324
return tx_output, cursor
330325

326+
331327
def __str__(self) -> str:
332328
return str({"amount": self.amount, "script_pubkey": self.script_pubkey})
333329

@@ -532,75 +528,72 @@ def __init__(
532528
@staticmethod
533529
def from_raw(rawtxhex: str):
534530
"""
535-
Imports a Transaction from hexadecimal data
531+
Imports a Transaction from hexadecimal data.
536532
537533
Attributes
538534
----------
539535
rawtxhex : string (hex)
540-
The hexadecimal raw string of the Transaction
536+
The hexadecimal raw string of the Transaction.
541537
"""
542538
rawtx = h_to_b(rawtxhex)
543-
cursor = 0
544539

545-
# Unpack version (4 bytes)
546-
version, = struct.unpack_from('<I', rawtx, cursor)
547-
cursor += 4
540+
# Read version (4 bytes)
541+
version = rawtx[0:4]
542+
cursor = 4
548543

549544
# Detect and handle SegWit
550-
flag = None
551545
has_segwit = False
552-
if rawtx[cursor] == 0x00 and rawtx[cursor + 1] == 0x01:
553-
flag = rawtx[cursor + 1]
546+
if rawtx[cursor:cursor + 2] == b'\x00\x01':
554547
has_segwit = True
555-
cursor += 2 # Skip past the marker and flag bytes
548+
cursor += 2 # Skipping past the marker and flag bytes
556549

557550
# Read the number of inputs
558-
n_inputs, size = parse_compact_size(rawtx, cursor)
551+
n_inputs, size = parse_compact_size(rawtx[cursor:])
559552
cursor += size
560553
inputs = []
561554

562555
# Read inputs
563556
for _ in range(n_inputs):
564-
inp, cursor = TxInput.from_raw(rawtxhex, cursor, has_segwit)
557+
inp, cursor = TxInput.from_raw(rawtx.hex(), cursor, has_segwit)
565558
inputs.append(inp)
566559

567-
# Read the number of outputs
568-
n_outputs, size = parse_compact_size(rawtx, cursor)
560+
# Read the number of outputs using parse_compact_size
561+
n_outputs, size = parse_compact_size(rawtx[cursor:])
569562
cursor += size
570563
outputs = []
571564

572565
# Read outputs
573566
for _ in range(n_outputs):
574-
output, cursor = TxOutput.from_raw(rawtxhex, cursor, has_segwit)
567+
output, cursor = TxOutput.from_raw(rawtx.hex(), cursor, has_segwit)
575568
outputs.append(output)
576569

577570
# Handle witnesses if SegWit is enabled
578571
witnesses = []
579572
if has_segwit:
580573
for _ in range(n_inputs):
581-
n_items, size = parse_compact_size(rawtx, cursor)
574+
n_items, size = parse_compact_size(rawtx[cursor:])
582575
cursor += size
583-
witness_stack = []
584-
for __ in range(n_items):
585-
item_size, size = parse_compact_size(rawtx, cursor)
576+
witnesses_tmp = []
577+
for _ in range(n_items):
578+
item_size, size = parse_compact_size(rawtx[cursor:])
586579
cursor += size
587580
witness_data = rawtx[cursor:cursor + item_size]
588581
cursor += item_size
589-
witness_stack.append(witness_data.hex())
590-
witnesses.append(TxWitnessInput(stack=witness_stack))
582+
witnesses_tmp.append(witness_data.hex())
583+
if witnesses_tmp:
584+
witnesses.append(TxWitnessInput(stack=witnesses_tmp))
591585

592-
# Unpack locktime (4 bytes)
593-
locktime, = struct.unpack_from('<I', rawtx, cursor)
594-
cursor += 4
586+
# Read locktime (4 bytes)
587+
locktime = rawtx[cursor:cursor + 4]
595588

596-
# Construct and return the Transaction object
589+
#Returning the Transaction object
597590
return Transaction(
598-
version=version,
599591
inputs=inputs,
600592
outputs=outputs,
593+
version=version,
601594
locktime=locktime,
602595
has_segwit=has_segwit,
603-
witnesses=witnesses
596+
witnesses=witnesses,
604597
)
605598

606599
def __str__(self) -> str:

bitcoinutils/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ def parse_compact_size(data: bytes) -> tuple:
220220
return (struct.unpack('<I', data[1:5])[0], 5)
221221
elif first_byte == 0xff:
222222
return (struct.unpack('<Q', data[1:9])[0], 9)
223-
223+
224224
def get_transaction_length(data: bytes) -> int:
225225
"""
226226
Return length of a transaction, including handling for SegWit transactions.

0 commit comments

Comments
 (0)