codec.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. from typing import (
  2. Any,
  3. Iterable,
  4. Tuple,
  5. cast,
  6. )
  7. from eth_typing.abi import (
  8. Decodable,
  9. TypeStr,
  10. )
  11. from eth_abi.decoding import (
  12. ContextFramesBytesIO,
  13. TupleDecoder,
  14. )
  15. from eth_abi.encoding import (
  16. TupleEncoder,
  17. )
  18. from eth_abi.exceptions import (
  19. EncodingError,
  20. )
  21. from eth_abi.registry import (
  22. ABIRegistry,
  23. )
  24. from eth_abi.utils.validation import (
  25. validate_bytes_param,
  26. validate_list_like_param,
  27. )
  28. class BaseABICoder:
  29. """
  30. Base class for porcelain coding APIs. These are classes which wrap
  31. instances of :class:`~eth_abi.registry.ABIRegistry` to provide last-mile
  32. coding functionality.
  33. """
  34. def __init__(self, registry: ABIRegistry):
  35. """
  36. Constructor.
  37. :param registry: The registry providing the encoders to be used when
  38. encoding values.
  39. """
  40. self._registry = registry
  41. class ABIEncoder(BaseABICoder):
  42. """
  43. Wraps a registry to provide last-mile encoding functionality.
  44. """
  45. def encode(self, types: Iterable[TypeStr], args: Iterable[Any]) -> bytes:
  46. """
  47. Encodes the python values in ``args`` as a sequence of binary values of
  48. the ABI types in ``types`` via the head-tail mechanism.
  49. :param types: A list or tuple of string representations of the ABI types
  50. that will be used for encoding e.g. ``('uint256', 'bytes[]',
  51. '(int,int)')``
  52. :param args: A list or tuple of python values to be encoded.
  53. :returns: The head-tail encoded binary representation of the python
  54. values in ``args`` as values of the ABI types in ``types``.
  55. """
  56. # validate encode types and args
  57. validate_list_like_param(types, "types")
  58. validate_list_like_param(args, "args")
  59. encoders = [self._registry.get_encoder(type_str) for type_str in types]
  60. encoder = TupleEncoder(encoders=encoders)
  61. return encoder(args)
  62. def is_encodable(self, typ: TypeStr, arg: Any) -> bool:
  63. """
  64. Determines if the python value ``arg`` is encodable as a value of the
  65. ABI type ``typ``.
  66. :param typ: A string representation for the ABI type against which the
  67. python value ``arg`` will be checked e.g. ``'uint256'``,
  68. ``'bytes[]'``, ``'(int,int)'``, etc.
  69. :param arg: The python value whose encodability should be checked.
  70. :returns: ``True`` if ``arg`` is encodable as a value of the ABI type
  71. ``typ``. Otherwise, ``False``.
  72. """
  73. if not self.is_encodable_type(typ):
  74. return False
  75. encoder = self._registry.get_encoder(typ)
  76. try:
  77. encoder.validate_value(arg)
  78. except EncodingError:
  79. return False
  80. except AttributeError:
  81. try:
  82. encoder(arg)
  83. except EncodingError:
  84. return False
  85. return True
  86. def is_encodable_type(self, typ: TypeStr) -> bool:
  87. """
  88. Returns ``True`` if values for the ABI type ``typ`` can be encoded by
  89. this codec.
  90. :param typ: A string representation for the ABI type that will be
  91. checked for encodability e.g. ``'uint256'``, ``'bytes[]'``,
  92. ``'(int,int)'``, etc.
  93. :returns: ``True`` if values for ``typ`` can be encoded by this codec.
  94. Otherwise, ``False``.
  95. """
  96. return self._registry.has_encoder(typ)
  97. class ABIDecoder(BaseABICoder):
  98. """
  99. Wraps a registry to provide last-mile decoding functionality.
  100. """
  101. stream_class = ContextFramesBytesIO
  102. def decode(
  103. self,
  104. types: Iterable[TypeStr],
  105. data: Decodable,
  106. strict: bool = True,
  107. ) -> Tuple[Any, ...]:
  108. """
  109. Decodes the binary value ``data`` as a sequence of values of the ABI types
  110. in ``types`` via the head-tail mechanism into a tuple of equivalent python
  111. values.
  112. :param types: A list or tuple of string representations of the ABI types that
  113. will be used for decoding e.g. ``('uint256', 'bytes[]', '(int,int)')``
  114. :param data: The binary value to be decoded.
  115. :param strict: If ``False``, dynamic-type decoders will ignore validations such
  116. as making sure the data is padded to a multiple of 32 bytes or checking that
  117. padding bytes are zero / empty. ``False`` is how the Solidity ABI decoder
  118. currently works. However, ``True`` is the default for the eth-abi library.
  119. :returns: A tuple of equivalent python values for the ABI values
  120. represented in ``data``.
  121. """
  122. # validate decode types and data
  123. validate_list_like_param(types, "types")
  124. validate_bytes_param(data, "data")
  125. decoders = [
  126. self._registry.get_decoder(type_str, strict=strict) for type_str in types
  127. ]
  128. decoder = TupleDecoder(decoders=decoders)
  129. stream = self.stream_class(data)
  130. return cast(Tuple[Any, ...], decoder(stream))
  131. class ABICodec(ABIEncoder, ABIDecoder):
  132. pass