-
Notifications
You must be signed in to change notification settings - Fork 269
/
abi.py
146 lines (114 loc) · 4.55 KB
/
abi.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
from typing import (
Any,
Iterable,
Tuple,
)
from eth_typing.abi import (
Decodable,
TypeStr,
)
from eth_utils import (
is_bytes,
)
from eth_abi.decoding import (
ContextFramesBytesIO,
TupleDecoder,
)
from eth_abi.encoding import (
TupleEncoder,
)
from eth_abi.exceptions import (
EncodingError,
)
from eth_abi.registry import (
ABIRegistry,
registry as default_registry,
)
class ABIEncoder:
def __init__(self, registry: ABIRegistry = default_registry):
self._registry = registry
def encode_single(self, typ: TypeStr, arg: Any) -> bytes:
"""
Encodes the python value ``arg`` as a binary value of the ABI type ``typ``.
:param typ: The string representation of the ABI type that will be used for
encoding e.g. ``'uint256'``, ``'bytes[]'``, ``'(int,int)'``, etc.
:param arg: The python value to be encoded.
:returns: The binary representation of the python value ``arg`` as a value
of the ABI type ``typ``.
"""
encoder = self._registry.get_encoder(typ)
return encoder(arg)
def encode_abi(self, types: Iterable[TypeStr], args: Iterable[Any]) -> bytes:
"""
Encodes the python values in ``args`` as a sequence of binary values of the
ABI types in ``types`` via the head-tail mechanism.
:param types: An iterable of string representations of the ABI types that
will be used for encoding e.g. ``('uint256', 'bytes[]', '(int,int)')``
:param args: An iterable of python values to be encoded.
:returns: The head-tail encoded binary representation of the python values
in ``args`` as values of the ABI types in ``types``.
"""
encoders = [
self._registry.get_encoder(type_str)
for type_str in types
]
encoder = TupleEncoder(encoders=encoders)
return encoder(args)
def is_encodable(self, typ: TypeStr, arg: Any) -> bool:
"""
Determines if the python value ``arg`` is encodable as a value of the ABI
type ``typ``.
:param typ: A string representation for the ABI type against which the
python value ``arg`` will be checked e.g. ``'uint256'``, ``'bytes[]'``,
``'(int,int)'``, etc.
:param arg: The python value whose encodability should be checked.
:returns: ``True`` if ``arg`` is encodable as a value of the ABI type
``typ``. Otherwise, ``False``.
"""
encoder = self._registry.get_encoder(typ)
try:
encoder.validate_value(arg)
except EncodingError:
return False
except AttributeError:
try:
encoder(arg)
except EncodingError:
return False
return True
def decode_single(self, typ: TypeStr, data: Decodable) -> Any:
"""
Decodes the binary value ``data`` of the ABI type ``typ`` into its
equivalent python value.
:param typ: The string representation of the ABI type that will be used for
decoding e.g. ``'uint256'``, ``'bytes[]'``, ``'(int,int)'``, etc.
:param data: The binary value to be decoded.
:returns: The equivalent python value of the ABI value represented in
``data``.
"""
if not is_bytes(data):
raise TypeError("The `data` value must be of bytes type. Got {0}".format(type(data)))
decoder = self._registry.get_decoder(typ)
stream = ContextFramesBytesIO(data)
return decoder(stream)
def decode_abi(self, types: Iterable[TypeStr], data: Decodable) -> Tuple[Any, ...]:
"""
Decodes the binary value ``data`` as a sequence of values of the ABI types
in ``types`` via the head-tail mechanism into a tuple of equivalent python
values.
:param types: An iterable of string representations of the ABI types that
will be used for decoding e.g. ``('uint256', 'bytes[]', '(int,int)')``
:param data: The binary value to be decoded.
:returns: A tuple of equivalent python values for the ABI values
represented in ``data``.
"""
if not is_bytes(data):
raise TypeError("The `data` value must be of bytes type. Got {0}".format(type(data)))
decoders = [
self._registry.get_decoder(type_str)
for type_str in types
]
decoder = TupleDecoder(decoders=decoders)
stream = ContextFramesBytesIO(data)
return decoder(stream)
encoder = ABIEncoder()