1+ import re
2+ from binascii import unhexlify
3+ from typing import Optional
4+ from crypto .enums .constants import Constants
15from crypto .transactions .types .abstract_transaction import AbstractTransaction
26from crypto .transactions .types .transfer import Transfer
37from crypto .transactions .types .evm_call import EvmCall
48from crypto .transactions .types .vote import Vote
59from crypto .transactions .types .unvote import Unvote
610from crypto .transactions .types .validator_registration import ValidatorRegistration
711from crypto .transactions .types .validator_resignation import ValidatorResignation
8- from binascii import unhexlify , hexlify
912
10- from binary .unsigned_integer .reader import (
11- read_bit8 ,
12- read_bit32 ,
13- read_bit64 ,
14- )
1513from crypto .enums .abi_function import AbiFunction
1614from crypto .utils .abi_decoder import AbiDecoder
15+ from crypto .utils .rlp_decoder import RlpDecoder
1716
1817class Deserializer :
1918 SIGNATURE_SIZE = 64
@@ -23,77 +22,39 @@ def __init__(self, serialized: str):
2322 self .serialized = unhexlify (serialized ) if isinstance (serialized , str ) else serialized
2423 self .pointer = 0
2524
25+ self .encoded_rlp = '0x' + serialized [2 :]
26+
2627 @staticmethod
2728 def new (serialized : str ):
2829 return Deserializer (serialized )
2930
3031 def deserialize (self ) -> AbstractTransaction :
31- data = {}
32+ decoded_rlp = RlpDecoder .decode (self .encoded_rlp )
33+
34+ data = {
35+ 'network' : Deserializer .parse_number (decoded_rlp [0 ]),
36+ 'nonce' : Deserializer .parse_big_number (decoded_rlp [1 ]),
37+ 'gasPrice' : Deserializer .parse_number (decoded_rlp [3 ]),
38+ 'gasLimit' : Deserializer .parse_number (decoded_rlp [4 ]),
39+ 'recipientAddress' : Deserializer .parse_address (decoded_rlp [5 ]),
40+ 'value' : Deserializer .parse_big_number (decoded_rlp [6 ]),
41+ 'data' : Deserializer .parse_hex (decoded_rlp [7 ]),
42+ }
43+
44+ if len (decoded_rlp ) == 12 :
45+ data ['v' ] = Deserializer .parse_number (decoded_rlp [9 ]) + Constants .ETHEREUM_RECOVERY_ID_OFFSET .value
46+ data ['r' ] = Deserializer .parse_hex (decoded_rlp [10 ])
47+ data ['s' ] = Deserializer .parse_hex (decoded_rlp [11 ])
3248
33- self .deserialize_common (data )
34- self .deserialize_data (data )
3549 transaction = self .guess_transaction_from_data (data )
36- self .deserialize_signatures (data )
3750
3851 transaction .data = data
3952 transaction .recover_sender ()
4053
41- transaction .data ['id' ] = transaction .hash ( skip_signature = False ). hex ()
54+ transaction .data ['id' ] = transaction .get_id ()
4255
4356 return transaction
4457
45- def read_bytes (self , length : int ) -> bytes :
46- result = self .serialized [self .pointer :self .pointer + length ]
47- self .pointer += length
48- return result
49-
50- def deserialize_common (self , data : dict ):
51- data ['network' ] = read_bit8 (self .serialized , self .pointer )
52- self .pointer += 1
53-
54- nonce = read_bit64 (self .serialized , self .pointer )
55- data ['nonce' ] = str (nonce )
56- self .pointer += 8
57-
58- gas_price = read_bit32 (self .serialized , self .pointer )
59- data ['gasPrice' ] = gas_price
60- self .pointer += 4
61-
62- gas_limit = read_bit32 (self .serialized , self .pointer )
63- data ['gasLimit' ] = gas_limit
64- self .pointer += 4
65-
66- data ['value' ] = '0'
67-
68- def deserialize_data (self , data : dict ):
69- value = int .from_bytes (self .serialized [self .pointer :self .pointer + 32 ], byteorder = 'big' )
70- self .pointer += 32
71-
72- data ['value' ] = str (value )
73-
74- recipient_marker = read_bit8 (self .serialized , self .pointer )
75- self .pointer += 1
76-
77- if recipient_marker == 1 :
78- recipient_address_bytes = self .read_bytes (20 )
79- recipient_address = '0x' + hexlify (recipient_address_bytes ).decode ()
80- data ['recipientAddress' ] = recipient_address
81-
82- payload_length = read_bit32 (self .serialized , self .pointer )
83- self .pointer += 4
84-
85- payload_hex = ''
86- if payload_length > 0 :
87- payload_bytes = self .read_bytes (payload_length )
88- payload_hex = hexlify (payload_bytes ).decode ()
89-
90- data ['data' ] = payload_hex
91-
92- def deserialize_signatures (self , data : dict ):
93- signature_length = self .SIGNATURE_SIZE + self .RECOVERY_SIZE
94- signature_bytes = self .read_bytes (signature_length )
95- data ['signature' ] = hexlify (signature_bytes ).decode ()
96-
9758 def guess_transaction_from_data (self , data : dict ) -> AbstractTransaction :
9859 if data ['value' ] != '0' :
9960 return Transfer (data )
@@ -115,7 +76,7 @@ def guess_transaction_from_data(self, data: dict) -> AbstractTransaction:
11576 else :
11677 return EvmCall (data )
11778
118- def decode_payload (self , data : dict ) -> dict :
79+ def decode_payload (self , data : dict ) -> Optional [ dict ] :
11980 payload = data .get ('data' , '' )
12081
12182 if payload == '' :
@@ -126,4 +87,21 @@ def decode_payload(self, data: dict) -> dict:
12687 return decoder .decode_function_data (payload )
12788 except Exception as e :
12889 print (f"Error decoding payload: { str (e )} " )
129- return None
90+
91+ return None
92+
93+ @staticmethod
94+ def parse_number (value : str ) -> int :
95+ return 0 if value == '0x' else int (value , 16 )
96+
97+ @staticmethod
98+ def parse_big_number (value : str ) -> str :
99+ return str (Deserializer .parse_number (value ))
100+
101+ @staticmethod
102+ def parse_hex (value : str ) -> str :
103+ return re .sub (r'^0x' , '' , value )
104+
105+ @staticmethod
106+ def parse_address (value : str ) -> Optional [str ]:
107+ return None if value == '0x' else value
0 commit comments