@@ -159,37 +159,37 @@ def from_raw(txinputrawhex: str, cursor: int = 0, has_segwit: bool = False):
159159 txinputraw = h_to_b (txinputrawhex )
160160
161161 # Unpack transaction ID (hash) and output index
162- txid_format = "<32sI "
162+ txid_format = "<32s4s "
163163 txid , vout = struct .unpack_from (txid_format , txinputraw , cursor )
164164 txid = txid [::- 1 ].hex () # Reverse to match usual hexadecimal order
165- cursor += struct . calcsize ( txid_format )
165+ cursor += 36 # Advance cursor by 32 bytes for txid and 4 bytes for vout
166166
167167 # Read the unlocking script size using parse_compact_size
168- unlocking_script_size , size = parse_compact_size (txinputraw , cursor )
168+ unlocking_script_size , size = vi_to_int (txinputraw [ cursor : cursor + 8 ] )
169169 cursor += size
170170
171- # Read the unlocking script
171+ # Read the unlocking script, keeping it in bytes
172172 script_format = f"{ unlocking_script_size } s"
173173 unlocking_script , = struct .unpack_from (script_format , txinputraw , cursor )
174174 cursor += unlocking_script_size
175175
176- # Read the sequence number
177- sequence_format = "<I "
176+ # Read the sequence number, maintaining byte format
177+ sequence_format = "<4s "
178178 sequence , = struct .unpack_from (sequence_format , txinputraw , cursor )
179- cursor += struct . calcsize ( sequence_format )
179+ cursor += 4
180180
181181 # If coinbase input, handle differently
182- if txid == 64 * "0" :
182+ if txid == 64 * '0' :
183183 script_sig = Script ([unlocking_script .hex ()]) # Treat as single element for coinbase
184184 else :
185185 script_sig = Script .from_raw (unlocking_script .hex (), has_segwit = has_segwit )
186186
187187 # Create the TxInput instance
188188 tx_input = TxInput (
189189 txid = txid ,
190- txout_index = vout ,
190+ txout_index = int . from_bytes ( vout , 'little' ), # Convert vout from bytes to integer when needed
191191 script_sig = script_sig ,
192- sequence = sequence
192+ sequence = sequence # Keep sequence as bytes
193193 )
194194
195195 return tx_input , cursor
@@ -293,36 +293,38 @@ def to_bytes(self) -> bytes:
293293 @staticmethod
294294 def from_raw (txoutputrawhex : str , cursor : int = 0 , has_segwit : bool = False ):
295295 """
296- Imports a TxOutput from a Transaction's hexadecimal data
296+ Imports a TxOutput from a Transaction's hexadecimal data using struct for parsing.
297297
298- Attributes
299- ----------
300- txoutputrawhex : string (hex)
301- The hexadecimal raw string of the Transaction
302- cursor : int
303- The cursor of which the algorithm will start to read the data
304- has_segwit : boolean
305- Is the Tx Output segwit or not
298+ Args:
299+ txoutputrawhex (str): The hexadecimal raw string of the Transaction.
300+ cursor (int): The position at which the algorithm will start to read the data.
301+ has_segwit (bool): Indicates if the Tx Output is SegWit enabled.
302+
303+ Returns:
304+ tuple: (TxOutput object, new cursor position)
305+
306+ Raises:
307+ Exception: If the amount or script is malformed.
306308 """
307309 txoutputraw = h_to_b (txoutputrawhex )
308310
309- # Unpack the output value (amount)
310- amount_format = "<Q " # Little-endian unsigned long long (8 bytes)
311- amount , = struct .unpack_from (amount_format , txoutputraw , cursor )
311+ # Unpack the output value (amount) keeping it in bytes
312+ amount_format = "<8s " # Little-endian unsigned long long (8 bytes)
313+ amount_bytes , = struct .unpack_from (amount_format , txoutputraw , cursor )
312314 cursor += struct .calcsize (amount_format )
313315
314- # Read the locking script size using parse_compact_size
315- lock_script_size , size = parse_compact_size (txoutputraw , cursor )
316+ # Read the locking script size using parse_compact_size, assuming it returns bytes length in int
317+ lock_script_size , size = vi_to_int (txoutputraw [ cursor : cursor + 9 ] )
316318 cursor += size
317319
318- # Read the locking script
320+ # Read the locking script, maintaining it in bytes
319321 script_format = f"{ lock_script_size } s"
320322 lock_script , = struct .unpack_from (script_format , txoutputraw , cursor )
321323 cursor += lock_script_size
322324
323325 # Create the TxOutput instance
324326 tx_output = TxOutput (
325- amount = amount ,
327+ amount = int . from_bytes ( amount_bytes , 'little' ), # Convert amount from bytes to integer when needed
326328 script_pubkey = Script .from_raw (lock_script .hex (), has_segwit = has_segwit )
327329 )
328330
@@ -532,18 +534,22 @@ def __init__(
532534 @staticmethod
533535 def from_raw (rawtxhex : str ):
534536 """
535- Imports a Transaction from hexadecimal data
537+ Imports a Transaction from hexadecimal data using struct for parsing.
536538
537- Attributes
538- ----------
539- rawtxhex : string (hex)
540- The hexadecimal raw string of the Transaction
539+ Args:
540+ rawtxhex (str): The hexadecimal raw string of the Transaction.
541+
542+ Returns:
543+ Transaction: A fully parsed Transaction object.
544+
545+ Raises:
546+ Exception: If the transaction data is malformed.
541547 """
542548 rawtx = h_to_b (rawtxhex )
543549 cursor = 0
544550
545- # Unpack version (4 bytes)
546- version , = struct .unpack_from ('<I ' , rawtx , cursor )
551+ # Unpack version (4 bytes) and keep it in bytes
552+ version , = struct .unpack_from ('<4s ' , rawtx , cursor )
547553 cursor += 4
548554
549555 # Detect and handle SegWit
@@ -555,54 +561,55 @@ def from_raw(rawtxhex: str):
555561 cursor += 2 # Skip past the marker and flag bytes
556562
557563 # Read the number of inputs
558- n_inputs , size = parse_compact_size (rawtx , cursor )
564+ n_inputs , size = vi_to_int (rawtx [ cursor : cursor + 9 ] )
559565 cursor += size
560566 inputs = []
561567
562568 # Read inputs
563569 for _ in range (n_inputs ):
564- inp , cursor = TxInput .from_raw (rawtxhex , cursor , has_segwit )
570+ inp , cursor = TxInput .from_raw (rawtx . hex () , cursor , has_segwit )
565571 inputs .append (inp )
566572
567573 # Read the number of outputs
568- n_outputs , size = parse_compact_size (rawtx , cursor )
574+ n_outputs , size = vi_to_int (rawtx [ cursor : cursor + 9 ] )
569575 cursor += size
570576 outputs = []
571577
572578 # Read outputs
573579 for _ in range (n_outputs ):
574- output , cursor = TxOutput .from_raw (rawtxhex , cursor , has_segwit )
580+ output , cursor = TxOutput .from_raw (rawtx . hex () , cursor , has_segwit )
575581 outputs .append (output )
576582
577583 # Handle witnesses if SegWit is enabled
578584 witnesses = []
579585 if has_segwit :
580586 for _ in range (n_inputs ):
581- n_items , size = parse_compact_size (rawtx , cursor )
587+ n_items , size = vi_to_int (rawtx [ cursor : cursor + 9 ] )
582588 cursor += size
583589 witness_stack = []
584590 for __ in range (n_items ):
585- item_size , size = parse_compact_size (rawtx , cursor )
591+ item_size , size = vi_to_int (rawtx [ cursor : cursor + 9 ] )
586592 cursor += size
587593 witness_data = rawtx [cursor :cursor + item_size ]
588594 cursor += item_size
589595 witness_stack .append (witness_data .hex ())
590596 witnesses .append (TxWitnessInput (stack = witness_stack ))
591597
592- # Unpack locktime (4 bytes)
593- locktime , = struct .unpack_from ('<I ' , rawtx , cursor )
598+ # Unpack locktime (4 bytes) and keep it in bytes
599+ locktime , = struct .unpack_from ('<4s ' , rawtx , cursor )
594600 cursor += 4
595601
596602 # Construct and return the Transaction object
597603 return Transaction (
598- version = version ,
599604 inputs = inputs ,
600605 outputs = outputs ,
606+ version = version ,
601607 locktime = locktime ,
602608 has_segwit = has_segwit ,
603609 witnesses = witnesses
604610 )
605611
612+
606613 def __str__ (self ) -> str :
607614 return str (
608615 {
0 commit comments