faster-eth-abi 5.2.25__cp311-cp311-musllinux_1_2_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. faster_eth_abi/__init__.py +17 -0
  2. faster_eth_abi/_codec.cpython-311-x86_64-linux-musl.so +0 -0
  3. faster_eth_abi/_codec.py +83 -0
  4. faster_eth_abi/_decoding.cpython-311-x86_64-linux-musl.so +0 -0
  5. faster_eth_abi/_decoding.py +371 -0
  6. faster_eth_abi/_encoding.cpython-311-x86_64-linux-musl.so +0 -0
  7. faster_eth_abi/_encoding.py +514 -0
  8. faster_eth_abi/_grammar.cpython-311-x86_64-linux-musl.so +0 -0
  9. faster_eth_abi/_grammar.py +389 -0
  10. faster_eth_abi/abi.cpython-311-x86_64-linux-musl.so +0 -0
  11. faster_eth_abi/abi.py +17 -0
  12. faster_eth_abi/base.py +45 -0
  13. faster_eth_abi/codec.py +2809 -0
  14. faster_eth_abi/constants.cpython-311-x86_64-linux-musl.so +0 -0
  15. faster_eth_abi/constants.py +7 -0
  16. faster_eth_abi/decoding.py +555 -0
  17. faster_eth_abi/encoding.py +738 -0
  18. faster_eth_abi/exceptions.cpython-311-x86_64-linux-musl.so +0 -0
  19. faster_eth_abi/exceptions.py +127 -0
  20. faster_eth_abi/from_type_str.cpython-311-x86_64-linux-musl.so +0 -0
  21. faster_eth_abi/from_type_str.py +141 -0
  22. faster_eth_abi/grammar.py +179 -0
  23. faster_eth_abi/io.cpython-311-x86_64-linux-musl.so +0 -0
  24. faster_eth_abi/io.py +137 -0
  25. faster_eth_abi/packed.cpython-311-x86_64-linux-musl.so +0 -0
  26. faster_eth_abi/packed.py +19 -0
  27. faster_eth_abi/py.typed +0 -0
  28. faster_eth_abi/registry.py +758 -0
  29. faster_eth_abi/tools/__init__.cpython-311-x86_64-linux-musl.so +0 -0
  30. faster_eth_abi/tools/__init__.py +3 -0
  31. faster_eth_abi/tools/_strategies.cpython-311-x86_64-linux-musl.so +0 -0
  32. faster_eth_abi/tools/_strategies.py +247 -0
  33. faster_eth_abi/typing.py +4627 -0
  34. faster_eth_abi/utils/__init__.cpython-311-x86_64-linux-musl.so +0 -0
  35. faster_eth_abi/utils/__init__.py +0 -0
  36. faster_eth_abi/utils/localcontext.cpython-311-x86_64-linux-musl.so +0 -0
  37. faster_eth_abi/utils/localcontext.py +49 -0
  38. faster_eth_abi/utils/numeric.cpython-311-x86_64-linux-musl.so +0 -0
  39. faster_eth_abi/utils/numeric.py +117 -0
  40. faster_eth_abi/utils/padding.cpython-311-x86_64-linux-musl.so +0 -0
  41. faster_eth_abi/utils/padding.py +22 -0
  42. faster_eth_abi/utils/string.cpython-311-x86_64-linux-musl.so +0 -0
  43. faster_eth_abi/utils/string.py +19 -0
  44. faster_eth_abi/utils/validation.cpython-311-x86_64-linux-musl.so +0 -0
  45. faster_eth_abi/utils/validation.py +18 -0
  46. faster_eth_abi-5.2.25.dist-info/METADATA +134 -0
  47. faster_eth_abi-5.2.25.dist-info/RECORD +50 -0
  48. faster_eth_abi-5.2.25.dist-info/WHEEL +5 -0
  49. faster_eth_abi-5.2.25.dist-info/top_level.txt +2 -0
  50. faster_eth_abi__mypyc.cpython-311-x86_64-linux-musl.so +0 -0
@@ -0,0 +1,17 @@
1
+ from importlib.metadata import (
2
+ version as __version,
3
+ )
4
+ from typing import (
5
+ Final,
6
+ )
7
+
8
+ from faster_eth_abi.abi import (
9
+ decode,
10
+ encode,
11
+ is_encodable,
12
+ is_encodable_type,
13
+ )
14
+
15
+ __all__ = ["decode", "encode", "is_encodable", "is_encodable_type"]
16
+
17
+ __version__: Final = __version("faster-eth-abi")
@@ -0,0 +1,83 @@
1
+ """Internal codec helpers for encoding and decoding sequences of values using the head-tail mechanism.
2
+
3
+ Provides encode_c and decode_c functions for binary serialization and deserialization of values
4
+ according to ABI type specifications.
5
+ """
6
+
7
+ from typing import (
8
+ TYPE_CHECKING,
9
+ Any,
10
+ Iterable,
11
+ Tuple,
12
+ )
13
+
14
+ from eth_typing import (
15
+ Decodable,
16
+ TypeStr,
17
+ )
18
+
19
+ from faster_eth_abi.utils.validation import (
20
+ validate_bytes_param,
21
+ validate_list_like_param,
22
+ )
23
+
24
+ if TYPE_CHECKING:
25
+ from faster_eth_abi.codec import (
26
+ ABIDecoder,
27
+ ABIEncoder,
28
+ )
29
+
30
+
31
+ def encode_c(
32
+ self: "ABIEncoder",
33
+ types: Iterable[TypeStr],
34
+ args: Iterable[Any],
35
+ ) -> bytes:
36
+ """
37
+ Encodes the python values in ``args`` as a sequence of binary values of
38
+ the ABI types in ``types`` via the head-tail mechanism.
39
+
40
+ :param types: A list or tuple of string representations of the ABI types
41
+ that will be used for encoding e.g. ``('uint256', 'bytes[]',
42
+ '(int,int)')``
43
+ :param args: A list or tuple of python values to be encoded.
44
+
45
+ :returns: The head-tail encoded binary representation of the python
46
+ values in ``args`` as values of the ABI types in ``types``.
47
+ """
48
+ validate_list_like_param(args, "args")
49
+
50
+ encoder = self._registry.get_tuple_encoder(*types)
51
+
52
+ return encoder.encode(args)
53
+
54
+
55
+ def decode_c(
56
+ self: "ABIDecoder",
57
+ types: Iterable[TypeStr],
58
+ data: Decodable,
59
+ strict: bool = True,
60
+ ) -> Tuple[Any, ...]:
61
+ """
62
+ Decodes the binary value ``data`` as a sequence of values of the ABI types
63
+ in ``types`` via the head-tail mechanism into a tuple of equivalent python
64
+ values.
65
+
66
+ :param types: A list or tuple of string representations of the ABI types that
67
+ will be used for decoding e.g. ``('uint256', 'bytes[]', '(int,int)')``
68
+ :param data: The binary value to be decoded.
69
+ :param strict: If ``False``, dynamic-type decoders will ignore validations such
70
+ as making sure the data is padded to a multiple of 32 bytes or checking that
71
+ padding bytes are zero / empty. ``False`` is how the Solidity ABI decoder
72
+ currently works. However, ``True`` is the default for the faster-eth-abi
73
+ library.
74
+
75
+ :returns: A tuple of equivalent python values for the ABI values
76
+ represented in ``data``.
77
+ """
78
+ validate_bytes_param(data, "data")
79
+
80
+ decoder = self._registry.get_tuple_decoder(*types, strict=strict)
81
+ stream = self.stream_class(data)
82
+
83
+ return decoder(stream)
@@ -0,0 +1,371 @@
1
+ """Private helpers for decoding logic, intended for C compilation.
2
+
3
+ This file exists because the original decoding.py is not ready to be fully compiled to C.
4
+ This module contains functions and logic that we wish to compile.
5
+ """
6
+ import decimal
7
+ from typing import (
8
+ TYPE_CHECKING,
9
+ Any,
10
+ Dict,
11
+ Final,
12
+ Tuple,
13
+ )
14
+
15
+ from faster_eth_utils import (
16
+ big_endian_to_int,
17
+ )
18
+
19
+ from faster_eth_abi.exceptions import (
20
+ InsufficientDataBytes,
21
+ InvalidPointer,
22
+ NonEmptyPaddingBytes,
23
+ )
24
+ from faster_eth_abi.io import (
25
+ ContextFramesBytesIO,
26
+ )
27
+ from faster_eth_abi.typing import (
28
+ T,
29
+ )
30
+ from faster_eth_abi.utils.localcontext import (
31
+ DECIMAL_CONTEXT,
32
+ )
33
+ from faster_eth_abi.utils.numeric import (
34
+ ceil32,
35
+ )
36
+
37
+ if TYPE_CHECKING:
38
+ from .decoding import (
39
+ BaseArrayDecoder,
40
+ ByteStringDecoder,
41
+ DynamicArrayDecoder,
42
+ FixedByteSizeDecoder,
43
+ HeadTailDecoder,
44
+ SignedFixedDecoder,
45
+ SignedIntegerDecoder,
46
+ SizedArrayDecoder,
47
+ StringDecoder,
48
+ TupleDecoder,
49
+ UnsignedFixedDecoder,
50
+ )
51
+
52
+
53
+ Decimal: Final = decimal.Decimal
54
+
55
+
56
+ # Helpers
57
+ def decode_uint_256(stream: ContextFramesBytesIO) -> int:
58
+ """
59
+ A faster version of :func:`~decoding.decode_uint_256` in decoding.py.
60
+
61
+ It recreates the logic from the UnsignedIntegerDecoder, but we can
62
+ skip a lot because we know the value of many vars.
63
+ """
64
+ # read data from stream
65
+ if len(data := stream.read(32)) == 32:
66
+ return big_endian_to_int(data)
67
+ raise InsufficientDataBytes(f"Tried to read 32 bytes, only got {len(data)} bytes.")
68
+
69
+
70
+ def get_value_byte_size(decoder: "FixedByteSizeDecoder[Any]") -> int:
71
+ return decoder.value_bit_size // 8
72
+
73
+
74
+ # HeadTailDecoder
75
+ def decode_head_tail(self: "HeadTailDecoder[T]", stream: ContextFramesBytesIO) -> T:
76
+ # Decode the offset and move the stream cursor forward 32 bytes
77
+ start_pos = decode_uint_256(stream)
78
+ # Jump ahead to the start of the value
79
+ stream.push_frame(start_pos)
80
+
81
+ # assertion check for mypy
82
+ tail_decoder = self.tail_decoder
83
+ if tail_decoder is None:
84
+ raise AssertionError("`tail_decoder` is None")
85
+ # Decode the value
86
+ value: T = tail_decoder(stream)
87
+ # Return the cursor
88
+ stream.pop_frame()
89
+
90
+ return value
91
+
92
+
93
+ # TupleDecoder
94
+ def decode_tuple(
95
+ self: "TupleDecoder[T]", stream: ContextFramesBytesIO
96
+ ) -> Tuple[T, ...]:
97
+ # NOTE: the original implementation would do this but it's
98
+ # kinda wasteful, so we rebuilt the logic within this function
99
+ # validate_pointers_tuple(self, stream)
100
+
101
+ current_location = stream.tell()
102
+ if self._no_head_tail:
103
+ # TODO: if all(isinstance(d, TupleDecoder) for d in self._decoders)
104
+ # return tuple(decode_tuple(stream) for _ in range(len(self.decoders))
105
+ # and other types with compiled decode funcs
106
+ return tuple(decoder(stream) for decoder in self.decoders)
107
+
108
+ end_of_offsets = current_location + 32 * self.len_of_head
109
+ total_stream_length = len(stream.getbuffer())
110
+ items = []
111
+ for decoder, is_head_tail in zip(self.decoders, self._is_head_tail):
112
+ if is_head_tail:
113
+ # the next 32 bytes are a pointer that we should validate
114
+ # checkpoint the stream location so we can reset it after validation
115
+ step_location = stream.tell()
116
+
117
+ offset = decode_uint_256(stream)
118
+ indicated_idx = current_location + offset
119
+ if indicated_idx < end_of_offsets or indicated_idx >= total_stream_length:
120
+ # the pointer is indicating its data is located either within the
121
+ # offsets section of the stream or beyond the end of the stream,
122
+ # both of which are invalid
123
+ raise InvalidPointer(
124
+ "Invalid pointer in tuple at location "
125
+ f"{stream.tell() - 32} in payload"
126
+ )
127
+
128
+ # reset the stream so we can decode
129
+ stream.seek(step_location)
130
+
131
+ items.append(decoder(stream))
132
+
133
+ # return the stream to its original location for actual decoding
134
+ stream.seek(current_location)
135
+
136
+ return tuple(items)
137
+
138
+
139
+ def validate_pointers_tuple(
140
+ self: "TupleDecoder[Any]",
141
+ stream: ContextFramesBytesIO,
142
+ ) -> None:
143
+ """
144
+ Verify that all pointers point to a valid location in the stream.
145
+ """
146
+ current_location = stream.tell()
147
+ if self._no_head_tail:
148
+ for decoder in self.decoders:
149
+ decoder(stream)
150
+ else:
151
+ end_of_offsets = current_location + 32 * self.len_of_head
152
+ total_stream_length = len(stream.getbuffer())
153
+ for decoder, is_head_tail in zip(self.decoders, self._is_head_tail):
154
+ if not is_head_tail:
155
+ # the next 32 bytes are not a pointer,
156
+ # so progress the stream per the decoder
157
+ decoder(stream)
158
+ else:
159
+ # the next 32 bytes are a pointer
160
+ offset = decode_uint_256(stream)
161
+ indicated_idx = current_location + offset
162
+ if (
163
+ indicated_idx < end_of_offsets
164
+ or indicated_idx >= total_stream_length
165
+ ):
166
+ # the pointer is indicating its data is located either within the
167
+ # offsets section of the stream or beyond the end of the stream,
168
+ # both of which are invalid
169
+ raise InvalidPointer(
170
+ "Invalid pointer in tuple at location "
171
+ f"{stream.tell() - 32} in payload"
172
+ )
173
+ # return the stream to its original location for actual decoding
174
+ stream.seek(current_location)
175
+
176
+
177
+ # BaseArrayDecoder
178
+ def validate_pointers_array(
179
+ self: "BaseArrayDecoder[Any]", stream: ContextFramesBytesIO, array_size: int
180
+ ) -> None:
181
+ """
182
+ Verify that all pointers point to a valid location in the stream.
183
+ """
184
+ current_location = stream.tell()
185
+ end_of_offsets = current_location + 32 * array_size
186
+ total_stream_length = len(stream.getbuffer())
187
+ for _ in range(array_size):
188
+ offset = decode_uint_256(stream)
189
+ indicated_idx = current_location + offset
190
+ if indicated_idx < end_of_offsets or indicated_idx >= total_stream_length:
191
+ # the pointer is indicating its data is located either within the
192
+ # offsets section of the stream or beyond the end of the stream,
193
+ # both of which are invalid
194
+ raise InvalidPointer(
195
+ "Invalid pointer in array at location "
196
+ f"{stream.tell() - 32} in payload"
197
+ )
198
+ stream.seek(current_location)
199
+
200
+
201
+ # SizedArrayDecoder
202
+ def decode_sized_array(
203
+ self: "SizedArrayDecoder[T]", stream: ContextFramesBytesIO
204
+ ) -> Tuple[T, ...]:
205
+ item_decoder = self.item_decoder
206
+ if item_decoder is None:
207
+ raise AssertionError("`item_decoder` is None")
208
+
209
+ array_size = self.array_size
210
+
211
+ if item_decoder.is_dynamic:
212
+ validate_pointers_array(self, stream, array_size)
213
+
214
+ return tuple(item_decoder(stream) for _ in range(array_size))
215
+
216
+
217
+ # DynamicArrayDecoder
218
+ def decode_dynamic_array(
219
+ self: "DynamicArrayDecoder[T]", stream: ContextFramesBytesIO
220
+ ) -> Tuple[T, ...]:
221
+ if self.item_decoder is None:
222
+ raise AssertionError("`item_decoder` is None")
223
+
224
+ array_size = decode_uint_256(stream)
225
+ stream.push_frame(32)
226
+
227
+ item_decoder = self.item_decoder
228
+ if item_decoder is None:
229
+ raise AssertionError("`item_decoder` is None")
230
+
231
+ if item_decoder.is_dynamic:
232
+ validate_pointers_array(self, stream, array_size)
233
+
234
+ try:
235
+ return tuple(item_decoder(stream) for _ in range(array_size))
236
+ finally:
237
+ stream.pop_frame()
238
+
239
+
240
+ # FixedByteSizeDecoder
241
+ def read_fixed_byte_size_data_from_stream(
242
+ self: "FixedByteSizeDecoder[Any]",
243
+ stream: ContextFramesBytesIO,
244
+ ) -> bytes:
245
+ data_byte_size = self.data_byte_size
246
+ if len(data := stream.read(data_byte_size)) == data_byte_size:
247
+ return data
248
+ raise InsufficientDataBytes(
249
+ f"Tried to read {data_byte_size} bytes, only got {len(data)} bytes."
250
+ )
251
+
252
+
253
+ def split_data_and_padding_fixed_byte_size(
254
+ self: "FixedByteSizeDecoder[Any]",
255
+ raw_data: bytes,
256
+ ) -> Tuple[bytes, bytes]:
257
+ value_byte_size = get_value_byte_size(self)
258
+ padding_size = self.data_byte_size - value_byte_size
259
+
260
+ if self.is_big_endian:
261
+ if padding_size == 0:
262
+ return raw_data, b""
263
+ padding_bytes = raw_data[:padding_size]
264
+ data = raw_data[padding_size:]
265
+ else:
266
+ data = raw_data[:value_byte_size]
267
+ padding_bytes = raw_data[value_byte_size:]
268
+
269
+ return data, padding_bytes
270
+
271
+
272
+ def validate_padding_bytes_fixed_byte_size(
273
+ self: "FixedByteSizeDecoder[T]",
274
+ value: T,
275
+ padding_bytes: bytes,
276
+ ) -> None:
277
+ if padding_bytes != get_expected_padding_bytes(self, b"\x00"):
278
+ raise NonEmptyPaddingBytes(f"Padding bytes were not empty: {padding_bytes!r}")
279
+
280
+
281
+ _expected_padding_bytes_cache: Final[
282
+ Dict["FixedByteSizeDecoder[Any]", Dict[bytes, bytes]]
283
+ ] = {}
284
+
285
+
286
+ def get_expected_padding_bytes(
287
+ self: "FixedByteSizeDecoder[Any]", chunk: bytes
288
+ ) -> bytes:
289
+ instance_cache = _expected_padding_bytes_cache.setdefault(self, {})
290
+ expected_padding_bytes = instance_cache.get(chunk)
291
+ if expected_padding_bytes is None:
292
+ value_byte_size = get_value_byte_size(self)
293
+ padding_size = self.data_byte_size - value_byte_size
294
+ expected_padding_bytes = chunk * padding_size
295
+ instance_cache[chunk] = expected_padding_bytes
296
+ return expected_padding_bytes
297
+
298
+
299
+ def validate_padding_bytes_signed_integer(
300
+ self: "SignedIntegerDecoder",
301
+ value: int,
302
+ padding_bytes: bytes,
303
+ ) -> None:
304
+ if value >= 0:
305
+ expected_padding_bytes = get_expected_padding_bytes(self, b"\x00")
306
+ else:
307
+ expected_padding_bytes = get_expected_padding_bytes(self, b"\xff")
308
+
309
+ if padding_bytes != expected_padding_bytes:
310
+ raise NonEmptyPaddingBytes(f"Padding bytes were not empty: {padding_bytes!r}")
311
+
312
+
313
+ # BooleanDecoder
314
+ def decoder_fn_boolean(data: bytes) -> bool:
315
+ if data == b"\x00":
316
+ return False
317
+ elif data == b"\x01":
318
+ return True
319
+ raise NonEmptyPaddingBytes(f"Boolean must be either 0x0 or 0x1. Got: {data!r}")
320
+
321
+
322
+ # UnignedFixedDecoder
323
+ def decode_unsigned_fixed(self: "UnsignedFixedDecoder", data: bytes) -> decimal.Decimal:
324
+ value = big_endian_to_int(data)
325
+
326
+ with DECIMAL_CONTEXT:
327
+ decimal_value = Decimal(value) / self.denominator
328
+
329
+ return decimal_value
330
+
331
+
332
+ # SignedFixedDecoder
333
+ def decode_signed_fixed(self: "SignedFixedDecoder", data: bytes) -> decimal.Decimal:
334
+ value = big_endian_to_int(data)
335
+ if value >= self.neg_threshold:
336
+ value -= self.neg_offset
337
+
338
+ with DECIMAL_CONTEXT:
339
+ decimal_value = Decimal(value) / self.denominator
340
+
341
+ return decimal_value
342
+
343
+
344
+ # ByteStringDecoder
345
+ def read_bytestring_from_stream(
346
+ self: "ByteStringDecoder[Any]", stream: ContextFramesBytesIO
347
+ ) -> bytes:
348
+ data_length = decode_uint_256(stream)
349
+ padded_length = ceil32(data_length)
350
+
351
+ data = stream.read(padded_length)
352
+
353
+ if self.strict:
354
+ if len(data) < padded_length:
355
+ raise InsufficientDataBytes(
356
+ f"Tried to read {padded_length} bytes, only got {len(data)} bytes"
357
+ )
358
+
359
+ padding_bytes = data[data_length:]
360
+ if padding_bytes != b"\x00" * (padded_length - data_length):
361
+ raise NonEmptyPaddingBytes(
362
+ f"Padding bytes were not empty: {padding_bytes!r}"
363
+ )
364
+
365
+ return data[:data_length]
366
+
367
+
368
+ # StringDecoder
369
+ def decode_string(self: "StringDecoder", stream: ContextFramesBytesIO) -> str:
370
+ data = read_bytestring_from_stream(self, stream)
371
+ return self.decoder_fn(data, self.bytes_errors)