faster-eth-abi 5.2.9__cp312-cp312-win_amd64.whl → 5.2.11__cp312-cp312-win_amd64.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.
Potentially problematic release.
This version of faster-eth-abi might be problematic. Click here for more details.
- 29859a9e7da9d19bb98c__mypyc.cp312-win_amd64.pyd +0 -0
- faster_eth_abi/_codec.cp312-win_amd64.pyd +0 -0
- faster_eth_abi/_codec.py +0 -4
- faster_eth_abi/_decoding.cp312-win_amd64.pyd +0 -0
- faster_eth_abi/_decoding.py +46 -0
- faster_eth_abi/_encoding.cp312-win_amd64.pyd +0 -0
- faster_eth_abi/_encoding.py +12 -5
- faster_eth_abi/_grammar.cp312-win_amd64.pyd +0 -0
- faster_eth_abi/_grammar.py +349 -0
- faster_eth_abi/abi.cp312-win_amd64.pyd +0 -0
- faster_eth_abi/codec.py +8 -9
- faster_eth_abi/constants.cp312-win_amd64.pyd +0 -0
- faster_eth_abi/decoding.py +11 -31
- faster_eth_abi/from_type_str.cp312-win_amd64.pyd +0 -0
- faster_eth_abi/from_type_str.py +3 -1
- faster_eth_abi/grammar.py +10 -308
- faster_eth_abi/packed.cp312-win_amd64.pyd +0 -0
- faster_eth_abi/registry.py +37 -24
- faster_eth_abi/tools/__init__.cp312-win_amd64.pyd +0 -0
- faster_eth_abi/tools/_strategies.cp312-win_amd64.pyd +0 -0
- faster_eth_abi/tools/_strategies.py +9 -5
- faster_eth_abi/utils/__init__.cp312-win_amd64.pyd +0 -0
- faster_eth_abi/utils/numeric.cp312-win_amd64.pyd +0 -0
- faster_eth_abi/utils/numeric.py +51 -20
- faster_eth_abi/utils/padding.cp312-win_amd64.pyd +0 -0
- faster_eth_abi/utils/string.cp312-win_amd64.pyd +0 -0
- faster_eth_abi/utils/validation.cp312-win_amd64.pyd +0 -0
- {faster_eth_abi-5.2.9.dist-info → faster_eth_abi-5.2.11.dist-info}/METADATA +1 -1
- faster_eth_abi-5.2.11.dist-info/RECORD +46 -0
- faster_eth_abi-5.2.11.dist-info/top_level.txt +2 -0
- 76f9a3652d4d2667c55c__mypyc.cp312-win_amd64.pyd +0 -0
- faster_eth_abi-5.2.9.dist-info/RECORD +0 -44
- faster_eth_abi-5.2.9.dist-info/top_level.txt +0 -2
- {faster_eth_abi-5.2.9.dist-info → faster_eth_abi-5.2.11.dist-info}/WHEEL +0 -0
- {faster_eth_abi-5.2.9.dist-info → faster_eth_abi-5.2.11.dist-info}/licenses/LICENSE +0 -0
|
Binary file
|
|
Binary file
|
faster_eth_abi/_codec.py
CHANGED
|
@@ -39,8 +39,6 @@ def encode_c(
|
|
|
39
39
|
:returns: The head-tail encoded binary representation of the python
|
|
40
40
|
values in ``args`` as values of the ABI types in ``types``.
|
|
41
41
|
"""
|
|
42
|
-
# validate encode types and args
|
|
43
|
-
validate_list_like_param(types, "types")
|
|
44
42
|
validate_list_like_param(args, "args")
|
|
45
43
|
|
|
46
44
|
encoder = self._registry.get_tuple_encoder(*types)
|
|
@@ -71,8 +69,6 @@ def decode_c(
|
|
|
71
69
|
:returns: A tuple of equivalent python values for the ABI values
|
|
72
70
|
represented in ``data``.
|
|
73
71
|
"""
|
|
74
|
-
# validate decode types and data
|
|
75
|
-
validate_list_like_param(types, "types")
|
|
76
72
|
validate_bytes_param(data, "data")
|
|
77
73
|
|
|
78
74
|
decoder = self._registry.get_tuple_decoder(*types, strict=strict)
|
|
Binary file
|
faster_eth_abi/_decoding.py
CHANGED
|
@@ -10,6 +10,7 @@ from faster_eth_utils import (
|
|
|
10
10
|
|
|
11
11
|
from faster_eth_abi.exceptions import (
|
|
12
12
|
InsufficientDataBytes,
|
|
13
|
+
NonEmptyPaddingBytes,
|
|
13
14
|
)
|
|
14
15
|
from faster_eth_abi.io import (
|
|
15
16
|
BytesIO,
|
|
@@ -26,6 +27,7 @@ if TYPE_CHECKING:
|
|
|
26
27
|
)
|
|
27
28
|
|
|
28
29
|
|
|
30
|
+
# Helpers
|
|
29
31
|
def decode_uint_256(stream: ContextFramesBytesIO) -> int:
|
|
30
32
|
"""
|
|
31
33
|
This function is a faster version of decode_uint_256 in decoding.py.
|
|
@@ -39,6 +41,10 @@ def decode_uint_256(stream: ContextFramesBytesIO) -> int:
|
|
|
39
41
|
raise InsufficientDataBytes(f"Tried to read 32 bytes, only got {len(data)} bytes.")
|
|
40
42
|
|
|
41
43
|
|
|
44
|
+
def get_value_byte_size(decoder: "FixedByteSizeDecoder") -> int:
|
|
45
|
+
return decoder.value_bit_size // 8
|
|
46
|
+
|
|
47
|
+
|
|
42
48
|
# HeadTailDecoder
|
|
43
49
|
def decode_head_tail(self: "HeadTailDecoder", stream: ContextFramesBytesIO) -> Any:
|
|
44
50
|
# Decode the offset and move the stream cursor forward 32 bytes
|
|
@@ -107,3 +113,43 @@ def read_fixed_byte_size_data_from_stream(
|
|
|
107
113
|
raise InsufficientDataBytes(
|
|
108
114
|
f"Tried to read {data_byte_size} bytes, only got {len(data)} bytes."
|
|
109
115
|
)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def split_data_and_padding_fixed_byte_size(
|
|
119
|
+
self: "FixedByteSizeDecoder",
|
|
120
|
+
raw_data: bytes,
|
|
121
|
+
) -> Tuple[bytes, bytes]:
|
|
122
|
+
value_byte_size = get_value_byte_size(self)
|
|
123
|
+
padding_size = self.data_byte_size - value_byte_size
|
|
124
|
+
|
|
125
|
+
if self.is_big_endian:
|
|
126
|
+
if padding_size == 0:
|
|
127
|
+
return raw_data, b""
|
|
128
|
+
padding_bytes = raw_data[:padding_size]
|
|
129
|
+
data = raw_data[padding_size:]
|
|
130
|
+
else:
|
|
131
|
+
data = raw_data[:value_byte_size]
|
|
132
|
+
padding_bytes = raw_data[value_byte_size:]
|
|
133
|
+
|
|
134
|
+
return data, padding_bytes
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def validate_padding_bytes_fixed_byte_size(
|
|
138
|
+
self: "FixedByteSizeDecoder",
|
|
139
|
+
value: Any,
|
|
140
|
+
padding_bytes: bytes,
|
|
141
|
+
) -> None:
|
|
142
|
+
value_byte_size = get_value_byte_size(self)
|
|
143
|
+
padding_size = self.data_byte_size - value_byte_size
|
|
144
|
+
|
|
145
|
+
if padding_bytes != b"\x00" * padding_size:
|
|
146
|
+
raise NonEmptyPaddingBytes(f"Padding bytes were not empty: {padding_bytes!r}")
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
# BooleanDecoder
|
|
150
|
+
def decoder_fn_boolean(data: bytes) -> bool:
|
|
151
|
+
if data == b"\x00":
|
|
152
|
+
return False
|
|
153
|
+
elif data == b"\x01":
|
|
154
|
+
return True
|
|
155
|
+
raise NonEmptyPaddingBytes(f"Boolean must be either 0x0 or 0x1. Got: {data!r}")
|
|
Binary file
|
faster_eth_abi/_encoding.py
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
from itertools import (
|
|
2
|
-
accumulate,
|
|
3
|
-
)
|
|
4
1
|
from typing import (
|
|
5
2
|
TYPE_CHECKING,
|
|
6
3
|
Any,
|
|
@@ -35,7 +32,12 @@ def encode_tuple(
|
|
|
35
32
|
tail_chunks.append(b"")
|
|
36
33
|
|
|
37
34
|
head_length = sum(32 if item is None else len(item) for item in raw_head_chunks)
|
|
38
|
-
tail_offsets =
|
|
35
|
+
tail_offsets = [0]
|
|
36
|
+
total_offset = 0
|
|
37
|
+
for item in tail_chunks[:-1]:
|
|
38
|
+
total_offset += len(item)
|
|
39
|
+
tail_offsets.append(total_offset)
|
|
40
|
+
|
|
39
41
|
head_chunks = tuple(
|
|
40
42
|
encode_uint_256(head_length + offset) if chunk is None else chunk
|
|
41
43
|
for chunk, offset in zip(raw_head_chunks, tail_offsets)
|
|
@@ -77,7 +79,12 @@ def encode_elements(item_encoder: "BaseEncoder", value: Sequence[Any]) -> bytes:
|
|
|
77
79
|
return b"".join(tail_chunks)
|
|
78
80
|
|
|
79
81
|
head_length = 32 * len(value)
|
|
80
|
-
tail_offsets =
|
|
82
|
+
tail_offsets = [0]
|
|
83
|
+
total_offset = 0
|
|
84
|
+
for item in tail_chunks[:-1]:
|
|
85
|
+
total_offset += len(item)
|
|
86
|
+
tail_offsets.append(total_offset)
|
|
87
|
+
|
|
81
88
|
head_chunks = tuple(
|
|
82
89
|
encode_uint_256(head_length + offset) for offset in tail_offsets
|
|
83
90
|
)
|
|
Binary file
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from typing import (
|
|
3
|
+
Any,
|
|
4
|
+
Final,
|
|
5
|
+
NewType,
|
|
6
|
+
NoReturn,
|
|
7
|
+
Optional,
|
|
8
|
+
Sequence,
|
|
9
|
+
Tuple,
|
|
10
|
+
TypeVar,
|
|
11
|
+
Union,
|
|
12
|
+
final,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
from eth_typing.abi import (
|
|
16
|
+
TypeStr,
|
|
17
|
+
)
|
|
18
|
+
from mypy_extensions import (
|
|
19
|
+
mypyc_attr,
|
|
20
|
+
)
|
|
21
|
+
from parsimonious.nodes import (
|
|
22
|
+
Node,
|
|
23
|
+
)
|
|
24
|
+
from typing_extensions import (
|
|
25
|
+
Self,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
from faster_eth_abi.exceptions import (
|
|
29
|
+
ABITypeError,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
TYPE_ALIASES: Final = {
|
|
34
|
+
"int": "int256",
|
|
35
|
+
"uint": "uint256",
|
|
36
|
+
"fixed": "fixed128x18",
|
|
37
|
+
"ufixed": "ufixed128x18",
|
|
38
|
+
"function": "bytes24",
|
|
39
|
+
"byte": "bytes1",
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
TYPE_ALIAS_RE: Final = re.compile(
|
|
43
|
+
rf"\b({'|'.join(map(re.escape, TYPE_ALIASES.keys()))})\b"
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
IntSubtype = NewType("IntSubtype", int)
|
|
48
|
+
FixedSubtype = NewType("FixedSubtype", Tuple[int, int])
|
|
49
|
+
Subtype = Union[IntSubtype, FixedSubtype]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@mypyc_attr(allow_interpreted_subclasses=True)
|
|
53
|
+
class ABIType:
|
|
54
|
+
"""
|
|
55
|
+
Base class for results of type string parsing operations.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
__slots__ = ("arrlist", "node")
|
|
59
|
+
|
|
60
|
+
def __init__(
|
|
61
|
+
self, arrlist: Optional[Sequence[str]] = None, node: Optional[Node] = None
|
|
62
|
+
) -> None:
|
|
63
|
+
self.arrlist: Final = arrlist
|
|
64
|
+
"""
|
|
65
|
+
The list of array dimensions for a parsed type. Equal to ``None`` if
|
|
66
|
+
type string has no array dimensions.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
self.node: Final = node
|
|
70
|
+
"""
|
|
71
|
+
The parsimonious ``Node`` instance associated with this parsed type.
|
|
72
|
+
Used to generate error messages for invalid types.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
def __repr__(self) -> str: # pragma: no cover
|
|
76
|
+
return f"<{type(self).__qualname__} {self.to_type_str()!r}>"
|
|
77
|
+
|
|
78
|
+
def __eq__(self, other: Any) -> bool:
|
|
79
|
+
# Two ABI types are equal if their string representations are equal
|
|
80
|
+
return type(self) is type(other) and self.to_type_str() == other.to_type_str()
|
|
81
|
+
|
|
82
|
+
def to_type_str(self) -> TypeStr: # pragma: no cover
|
|
83
|
+
"""
|
|
84
|
+
Returns the string representation of an ABI type. This will be equal to
|
|
85
|
+
the type string from which it was created.
|
|
86
|
+
"""
|
|
87
|
+
raise NotImplementedError("Must implement `to_type_str`")
|
|
88
|
+
|
|
89
|
+
@property
|
|
90
|
+
def item_type(self) -> Self:
|
|
91
|
+
"""
|
|
92
|
+
If this type is an array type, equal to an appropriate
|
|
93
|
+
:class:`~faster_eth_abi.grammar.ABIType` instance for the array's items.
|
|
94
|
+
"""
|
|
95
|
+
raise NotImplementedError("Must implement `item_type`")
|
|
96
|
+
|
|
97
|
+
def validate(self) -> None: # pragma: no cover
|
|
98
|
+
"""
|
|
99
|
+
Validates the properties of an ABI type against the solidity ABI spec:
|
|
100
|
+
|
|
101
|
+
https://solidity.readthedocs.io/en/develop/abi-spec.html
|
|
102
|
+
|
|
103
|
+
Raises :class:`~faster_eth_abi.exceptions.ABITypeError` if validation fails.
|
|
104
|
+
"""
|
|
105
|
+
raise NotImplementedError("Must implement `validate`")
|
|
106
|
+
|
|
107
|
+
@final
|
|
108
|
+
def invalidate(self, error_msg: str) -> NoReturn:
|
|
109
|
+
# Invalidates an ABI type with the given error message. Expects that a
|
|
110
|
+
# parsimonious node was provided from the original parsing operation
|
|
111
|
+
# that yielded this type.
|
|
112
|
+
node = self.node
|
|
113
|
+
|
|
114
|
+
raise ABITypeError(
|
|
115
|
+
f"For '{node.text}' type at column {node.start + 1} "
|
|
116
|
+
f"in '{node.full_text}': {error_msg}"
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
@final
|
|
120
|
+
@property
|
|
121
|
+
def is_array(self) -> bool:
|
|
122
|
+
"""
|
|
123
|
+
Equal to ``True`` if a type is an array type (i.e. if it has an array
|
|
124
|
+
dimension list). Otherwise, equal to ``False``.
|
|
125
|
+
"""
|
|
126
|
+
return self.arrlist is not None
|
|
127
|
+
|
|
128
|
+
@property
|
|
129
|
+
def is_dynamic(self) -> bool:
|
|
130
|
+
"""
|
|
131
|
+
Equal to ``True`` if a type has a dynamically sized encoding.
|
|
132
|
+
Otherwise, equal to ``False``.
|
|
133
|
+
"""
|
|
134
|
+
raise NotImplementedError("Must implement `is_dynamic`")
|
|
135
|
+
|
|
136
|
+
@final
|
|
137
|
+
@property
|
|
138
|
+
def _has_dynamic_arrlist(self) -> bool:
|
|
139
|
+
return self.is_array and any(len(dim) == 0 for dim in self.arrlist)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
TComp = TypeVar("TComp", bound=ABIType)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@mypyc_attr(allow_interpreted_subclasses=True)
|
|
146
|
+
class TupleType(ABIType):
|
|
147
|
+
"""
|
|
148
|
+
Represents the result of parsing a tuple type string e.g. "(int,bool)".
|
|
149
|
+
"""
|
|
150
|
+
|
|
151
|
+
__slots__ = ("components",)
|
|
152
|
+
|
|
153
|
+
def __init__(
|
|
154
|
+
self,
|
|
155
|
+
components: Tuple[TComp, ...],
|
|
156
|
+
arrlist: Optional[Sequence[str]] = None,
|
|
157
|
+
*,
|
|
158
|
+
node: Optional[Node] = None,
|
|
159
|
+
) -> None:
|
|
160
|
+
super().__init__(arrlist, node)
|
|
161
|
+
|
|
162
|
+
self.components: Final = components
|
|
163
|
+
"""
|
|
164
|
+
A tuple of :class:`~faster_eth_abi.grammar.ABIType` instances for each of the
|
|
165
|
+
tuple type's components.
|
|
166
|
+
"""
|
|
167
|
+
|
|
168
|
+
def to_type_str(self) -> TypeStr:
|
|
169
|
+
arrlist = self.arrlist
|
|
170
|
+
|
|
171
|
+
if isinstance(arrlist, tuple):
|
|
172
|
+
arrlist = "".join(map(repr, map(list, arrlist)))
|
|
173
|
+
else:
|
|
174
|
+
arrlist = ""
|
|
175
|
+
|
|
176
|
+
return f"({','.join(c.to_type_str() for c in self.components)}){arrlist}"
|
|
177
|
+
|
|
178
|
+
@property
|
|
179
|
+
def item_type(self) -> Self:
|
|
180
|
+
if not self.is_array:
|
|
181
|
+
raise ValueError(
|
|
182
|
+
f"Cannot determine item type for non-array type '{self.to_type_str()}'"
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
arrlist = self.arrlist[:-1] or None # type: ignore [index]
|
|
186
|
+
cls = type(self)
|
|
187
|
+
if cls is TupleType:
|
|
188
|
+
return TupleType(self.components, arrlist, node=self.node) # type: ignore [return-value]
|
|
189
|
+
else:
|
|
190
|
+
return cls(self.components, arrlist, node=self.node)
|
|
191
|
+
|
|
192
|
+
def validate(self) -> None:
|
|
193
|
+
for c in self.components:
|
|
194
|
+
c.validate()
|
|
195
|
+
|
|
196
|
+
@property
|
|
197
|
+
def is_dynamic(self) -> bool:
|
|
198
|
+
if self._has_dynamic_arrlist:
|
|
199
|
+
return True
|
|
200
|
+
|
|
201
|
+
return any(c.is_dynamic for c in self.components)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
@mypyc_attr(allow_interpreted_subclasses=True)
|
|
205
|
+
class BasicType(ABIType):
|
|
206
|
+
"""
|
|
207
|
+
Represents the result of parsing a basic type string e.g. "uint", "address",
|
|
208
|
+
"ufixed128x19[][2]".
|
|
209
|
+
"""
|
|
210
|
+
|
|
211
|
+
__slots__ = ("base", "sub")
|
|
212
|
+
|
|
213
|
+
def __init__(
|
|
214
|
+
self,
|
|
215
|
+
base: str,
|
|
216
|
+
sub: Optional[Subtype] = None,
|
|
217
|
+
arrlist: Optional[Sequence] = None,
|
|
218
|
+
*,
|
|
219
|
+
node: Optional[Node] = None,
|
|
220
|
+
) -> None:
|
|
221
|
+
super().__init__(arrlist, node)
|
|
222
|
+
|
|
223
|
+
self.base: Final = base
|
|
224
|
+
"""The base of a basic type e.g. "uint" for "uint256" etc."""
|
|
225
|
+
|
|
226
|
+
self.sub: Final = sub
|
|
227
|
+
"""
|
|
228
|
+
The sub type of a basic type e.g. ``256`` for "uint256" or ``(128, 18)``
|
|
229
|
+
for "ufixed128x18" etc. Equal to ``None`` if type string has no sub
|
|
230
|
+
type.
|
|
231
|
+
"""
|
|
232
|
+
|
|
233
|
+
def to_type_str(self) -> TypeStr:
|
|
234
|
+
sub, arrlist = self.sub, self.arrlist
|
|
235
|
+
|
|
236
|
+
if isinstance(sub, int):
|
|
237
|
+
substr = str(sub)
|
|
238
|
+
elif isinstance(sub, tuple):
|
|
239
|
+
substr = "x".join(map(str, sub))
|
|
240
|
+
else:
|
|
241
|
+
substr = ""
|
|
242
|
+
|
|
243
|
+
if isinstance(arrlist, tuple):
|
|
244
|
+
return self.base + substr + "".join(map(repr, map(list, arrlist)))
|
|
245
|
+
else:
|
|
246
|
+
return self.base + substr
|
|
247
|
+
|
|
248
|
+
@property
|
|
249
|
+
def item_type(self) -> Self:
|
|
250
|
+
if not self.is_array:
|
|
251
|
+
raise ValueError(
|
|
252
|
+
f"Cannot determine item type for non-array type '{self.to_type_str()}'"
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
cls = type(self)
|
|
256
|
+
arrlist = self.arrlist[:-1] or None # type: ignore [index]
|
|
257
|
+
if cls is BasicType:
|
|
258
|
+
return BasicType(self.base, self.sub, arrlist, node=self.node) # type: ignore [return-value]
|
|
259
|
+
else:
|
|
260
|
+
return cls(self.base, self.sub, arrlist, node=self.node)
|
|
261
|
+
|
|
262
|
+
@property
|
|
263
|
+
def is_dynamic(self) -> bool:
|
|
264
|
+
if self._has_dynamic_arrlist:
|
|
265
|
+
return True
|
|
266
|
+
|
|
267
|
+
base = self.base
|
|
268
|
+
if base == "string":
|
|
269
|
+
return True
|
|
270
|
+
|
|
271
|
+
if base == "bytes" and self.sub is None:
|
|
272
|
+
return True
|
|
273
|
+
|
|
274
|
+
return False
|
|
275
|
+
|
|
276
|
+
def validate(self) -> None:
|
|
277
|
+
base, sub = self.base, self.sub
|
|
278
|
+
|
|
279
|
+
# Check validity of string type
|
|
280
|
+
if base == "string":
|
|
281
|
+
if sub is not None:
|
|
282
|
+
self.invalidate("string type cannot have suffix")
|
|
283
|
+
|
|
284
|
+
# Check validity of bytes type
|
|
285
|
+
elif base == "bytes":
|
|
286
|
+
if not (sub is None or isinstance(sub, int)):
|
|
287
|
+
self.invalidate(
|
|
288
|
+
"bytes type must have either no suffix or a numerical suffix"
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
if isinstance(sub, int) and sub > 32:
|
|
292
|
+
self.invalidate("maximum 32 bytes for fixed-length bytes")
|
|
293
|
+
|
|
294
|
+
# Check validity of integer type
|
|
295
|
+
elif base in ("int", "uint"):
|
|
296
|
+
if not isinstance(sub, int):
|
|
297
|
+
self.invalidate("integer type must have numerical suffix")
|
|
298
|
+
|
|
299
|
+
if sub < 8 or sub > 256:
|
|
300
|
+
self.invalidate("integer size out of bounds (max 256 bits)")
|
|
301
|
+
|
|
302
|
+
if sub % 8 != 0:
|
|
303
|
+
self.invalidate("integer size must be multiple of 8")
|
|
304
|
+
|
|
305
|
+
# Check validity of fixed type
|
|
306
|
+
elif base in ("fixed", "ufixed"):
|
|
307
|
+
if not isinstance(sub, tuple):
|
|
308
|
+
self.invalidate(
|
|
309
|
+
"fixed type must have suffix of form <bits>x<exponent>, "
|
|
310
|
+
"e.g. 128x19",
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
bits, minus_e = sub
|
|
314
|
+
|
|
315
|
+
if bits < 8 or bits > 256:
|
|
316
|
+
self.invalidate("fixed size out of bounds (max 256 bits)")
|
|
317
|
+
|
|
318
|
+
if bits % 8 != 0:
|
|
319
|
+
self.invalidate("fixed size must be multiple of 8")
|
|
320
|
+
|
|
321
|
+
if minus_e < 1 or minus_e > 80:
|
|
322
|
+
self.invalidate(
|
|
323
|
+
f"fixed exponent size out of bounds, {minus_e} must be in 1-80"
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
# Check validity of hash type
|
|
327
|
+
elif base == "hash":
|
|
328
|
+
if not isinstance(sub, int):
|
|
329
|
+
self.invalidate("hash type must have numerical suffix")
|
|
330
|
+
|
|
331
|
+
# Check validity of address type
|
|
332
|
+
elif base == "address":
|
|
333
|
+
if sub is not None:
|
|
334
|
+
self.invalidate("address cannot have suffix")
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
def normalize(type_str: TypeStr) -> TypeStr:
|
|
338
|
+
"""
|
|
339
|
+
Normalizes a type string into its canonical version e.g. the type string
|
|
340
|
+
'int' becomes 'int256', etc.
|
|
341
|
+
|
|
342
|
+
:param type_str: The type string to be normalized.
|
|
343
|
+
:returns: The canonical version of the input type string.
|
|
344
|
+
"""
|
|
345
|
+
return TYPE_ALIAS_RE.sub(__normalize, type_str)
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def __normalize(match: "re.Match[str]") -> str:
|
|
349
|
+
return TYPE_ALIASES[match.group(0)]
|
|
Binary file
|
faster_eth_abi/codec.py
CHANGED
|
@@ -18,6 +18,7 @@ from faster_eth_abi.decoding import (
|
|
|
18
18
|
)
|
|
19
19
|
from faster_eth_abi.exceptions import (
|
|
20
20
|
EncodingError,
|
|
21
|
+
MultipleEntriesFound,
|
|
21
22
|
)
|
|
22
23
|
from faster_eth_abi.registry import (
|
|
23
24
|
ABIRegistry,
|
|
@@ -74,20 +75,18 @@ class ABIEncoder(BaseABICoder):
|
|
|
74
75
|
:returns: ``True`` if ``arg`` is encodable as a value of the ABI type
|
|
75
76
|
``typ``. Otherwise, ``False``.
|
|
76
77
|
"""
|
|
77
|
-
|
|
78
|
+
try:
|
|
79
|
+
encoder = self._registry.get_encoder(typ)
|
|
80
|
+
except MultipleEntriesFound:
|
|
81
|
+
raise
|
|
82
|
+
except:
|
|
78
83
|
return False
|
|
79
84
|
|
|
80
|
-
|
|
81
|
-
|
|
85
|
+
validate = getattr(encoder, "validate_value", encoder)
|
|
82
86
|
try:
|
|
83
|
-
|
|
87
|
+
validate(arg)
|
|
84
88
|
except EncodingError:
|
|
85
89
|
return False
|
|
86
|
-
except AttributeError:
|
|
87
|
-
try:
|
|
88
|
-
encoder(arg)
|
|
89
|
-
except EncodingError:
|
|
90
|
-
return False
|
|
91
90
|
|
|
92
91
|
return True
|
|
93
92
|
|
|
Binary file
|
faster_eth_abi/decoding.py
CHANGED
|
@@ -19,7 +19,11 @@ from faster_eth_abi._decoding import (
|
|
|
19
19
|
decode_head_tail,
|
|
20
20
|
decode_sized_array,
|
|
21
21
|
decode_tuple,
|
|
22
|
+
decoder_fn_boolean,
|
|
23
|
+
get_value_byte_size,
|
|
22
24
|
read_fixed_byte_size_data_from_stream,
|
|
25
|
+
split_data_and_padding_fixed_byte_size,
|
|
26
|
+
validate_padding_bytes_fixed_byte_size,
|
|
23
27
|
)
|
|
24
28
|
from faster_eth_abi.base import (
|
|
25
29
|
BaseCoder,
|
|
@@ -303,29 +307,14 @@ class FixedByteSizeDecoder(SingleDecoder):
|
|
|
303
307
|
return read_fixed_byte_size_data_from_stream(self, stream)
|
|
304
308
|
|
|
305
309
|
def split_data_and_padding(self, raw_data: bytes) -> Tuple[bytes, bytes]:
|
|
306
|
-
|
|
307
|
-
padding_size = self.data_byte_size - value_byte_size
|
|
308
|
-
|
|
309
|
-
if self.is_big_endian:
|
|
310
|
-
padding_bytes = raw_data[:padding_size]
|
|
311
|
-
data = raw_data[padding_size:]
|
|
312
|
-
else:
|
|
313
|
-
data = raw_data[:value_byte_size]
|
|
314
|
-
padding_bytes = raw_data[value_byte_size:]
|
|
315
|
-
|
|
316
|
-
return data, padding_bytes
|
|
310
|
+
return split_data_and_padding_fixed_byte_size(self, raw_data)
|
|
317
311
|
|
|
318
312
|
def validate_padding_bytes(self, value: Any, padding_bytes: bytes) -> None:
|
|
319
|
-
|
|
320
|
-
padding_size = self.data_byte_size - value_byte_size
|
|
321
|
-
|
|
322
|
-
if padding_bytes != b"\x00" * padding_size:
|
|
323
|
-
raise NonEmptyPaddingBytes(
|
|
324
|
-
f"Padding bytes were not empty: {padding_bytes!r}"
|
|
325
|
-
)
|
|
313
|
+
validate_padding_bytes_fixed_byte_size(self, value, padding_bytes)
|
|
326
314
|
|
|
327
315
|
def _get_value_byte_size(self) -> int:
|
|
328
|
-
|
|
316
|
+
# This is unused, but it is kept in to preserve the eth-abi api
|
|
317
|
+
return get_value_byte_size(self)
|
|
329
318
|
|
|
330
319
|
|
|
331
320
|
class Fixed32ByteSizeDecoder(FixedByteSizeDecoder):
|
|
@@ -336,16 +325,7 @@ class BooleanDecoder(Fixed32ByteSizeDecoder):
|
|
|
336
325
|
value_bit_size = 8
|
|
337
326
|
is_big_endian = True
|
|
338
327
|
|
|
339
|
-
|
|
340
|
-
def decoder_fn(data: bytes) -> bool:
|
|
341
|
-
if data == b"\x00":
|
|
342
|
-
return False
|
|
343
|
-
elif data == b"\x01":
|
|
344
|
-
return True
|
|
345
|
-
else:
|
|
346
|
-
raise NonEmptyPaddingBytes(
|
|
347
|
-
f"Boolean must be either 0x0 or 0x1. Got: {data!r}"
|
|
348
|
-
)
|
|
328
|
+
decoder_fn = staticmethod(decoder_fn_boolean)
|
|
349
329
|
|
|
350
330
|
@parse_type_str("bool")
|
|
351
331
|
def from_type_str(cls, abi_type, registry):
|
|
@@ -392,7 +372,7 @@ class SignedIntegerDecoder(Fixed32ByteSizeDecoder):
|
|
|
392
372
|
return value
|
|
393
373
|
|
|
394
374
|
def validate_padding_bytes(self, value: Any, padding_bytes: bytes) -> None:
|
|
395
|
-
value_byte_size = self
|
|
375
|
+
value_byte_size = get_value_byte_size(self)
|
|
396
376
|
padding_size = self.data_byte_size - value_byte_size
|
|
397
377
|
|
|
398
378
|
if value >= 0:
|
|
@@ -471,7 +451,7 @@ class SignedFixedDecoder(BaseFixedDecoder):
|
|
|
471
451
|
return decimal_value
|
|
472
452
|
|
|
473
453
|
def validate_padding_bytes(self, value: Any, padding_bytes: bytes) -> None:
|
|
474
|
-
value_byte_size = self
|
|
454
|
+
value_byte_size = get_value_byte_size(self)
|
|
475
455
|
padding_size = self.data_byte_size - value_byte_size
|
|
476
456
|
|
|
477
457
|
if value >= 0:
|
|
Binary file
|