| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- from typing import (
- Any,
- Iterable,
- Tuple,
- cast,
- )
- from eth_typing.abi import (
- Decodable,
- TypeStr,
- )
- 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,
- )
- from eth_abi.utils.validation import (
- validate_bytes_param,
- validate_list_like_param,
- )
- class BaseABICoder:
- """
- Base class for porcelain coding APIs. These are classes which wrap
- instances of :class:`~eth_abi.registry.ABIRegistry` to provide last-mile
- coding functionality.
- """
- def __init__(self, registry: ABIRegistry):
- """
- Constructor.
- :param registry: The registry providing the encoders to be used when
- encoding values.
- """
- self._registry = registry
- class ABIEncoder(BaseABICoder):
- """
- Wraps a registry to provide last-mile encoding functionality.
- """
- def encode(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: A list or tuple of string representations of the ABI types
- that will be used for encoding e.g. ``('uint256', 'bytes[]',
- '(int,int)')``
- :param args: A list or tuple 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``.
- """
- # validate encode types and args
- validate_list_like_param(types, "types")
- validate_list_like_param(args, "args")
- 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``.
- """
- if not self.is_encodable_type(typ):
- return 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 is_encodable_type(self, typ: TypeStr) -> bool:
- """
- Returns ``True`` if values for the ABI type ``typ`` can be encoded by
- this codec.
- :param typ: A string representation for the ABI type that will be
- checked for encodability e.g. ``'uint256'``, ``'bytes[]'``,
- ``'(int,int)'``, etc.
- :returns: ``True`` if values for ``typ`` can be encoded by this codec.
- Otherwise, ``False``.
- """
- return self._registry.has_encoder(typ)
- class ABIDecoder(BaseABICoder):
- """
- Wraps a registry to provide last-mile decoding functionality.
- """
- stream_class = ContextFramesBytesIO
- def decode(
- self,
- types: Iterable[TypeStr],
- data: Decodable,
- strict: bool = True,
- ) -> 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: A list or tuple 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.
- :param strict: If ``False``, dynamic-type decoders will ignore validations such
- as making sure the data is padded to a multiple of 32 bytes or checking that
- padding bytes are zero / empty. ``False`` is how the Solidity ABI decoder
- currently works. However, ``True`` is the default for the eth-abi library.
- :returns: A tuple of equivalent python values for the ABI values
- represented in ``data``.
- """
- # validate decode types and data
- validate_list_like_param(types, "types")
- validate_bytes_param(data, "data")
- decoders = [
- self._registry.get_decoder(type_str, strict=strict) for type_str in types
- ]
- decoder = TupleDecoder(decoders=decoders)
- stream = self.stream_class(data)
- return cast(Tuple[Any, ...], decoder(stream))
- class ABICodec(ABIEncoder, ABIDecoder):
- pass
|