Closed pipermerriam closed 6 years ago
My suggestion for the callbacks to error if more than one returns True
needs to be evaluated. My inclination was to go with a strict rule set with no ambiguity, otherwise, we'd need to do something like giving priority based on the order that things were registered and that feels wrong to me.
@pipermerriam I suppose we'll need to include some registration callbacks by default to handle types which must instantiate an encoder/decoder with parameters from the "sub" and "array" parts. Given this, and assuming multiple matching callbacks would cause an error, how would we handle the case in which someone wants to override a default callback?
@davesque probably either:
@pipermerriam @carver
I talked briefly about the need to settle on some API by which encoder/decoder classes can accept a type string that was matched to them by the registry (and, for tuple types, probably also a reference to the registry itself). Here's one possible way I can imagine doing that:
# base.py:
class FromTypeStr:
"""
A mixin for any class which should be able to create an appropriate
instance of itself for the given type string and type registry.
"""
@classmethod
def from_type_str(cls, type_str, registry):
raise NotImplementedError('Must implement `from_type_str`')
# registry.py:
class ABIRegistry:
...
def _get_encoder(self, type_str: str):
encoder = self._encoders.find(type_str)
if issubclass(encoder, base.FromTypeStr):
return encoder.from_type_str(type_str, self)
return encoder
# encoding.py:
class UnsignedIntegerEncoder(FromTypeStr, NumberEncoder):
...
@classmethod
def from_type_str(cls, type_str, registry):
result = parser.parse(type_str)
if not something_this_parser_can_handle(result):
raise ValueError('...')
sub = ...
return cls.as_encoder(value_bit_size=int(sub))
Above, we have a mixin class which can be used to determine if a value stored in the registry is an encoder/decoder class that requires some extra steps to be made into a callable which will work for a type string.
Thoughts?
Yup, this looks about how I imagined it. :+1:
@carver Do we ever bother using the abc
module? In this case, I'm not sure it gets us much since we're never really going to try instantiating an encoder or decoder class until we call from_type_str
. So we'd get a NotImplementedError
before the abc
machinery caused a TypeError
.
Actually, never mind. There's effectively no reason as I see it to use an abstract base class in this case.
@davesque should we close this? maybe close it and open up specific issues for anything remaining if there are remaining tasks.
Yep, I guess I forgot there was an issue ticket for it.
What was wrong?
The way
eth-abi
is structured, it cannot be extended without changes to the core library. This is problematic because new ABI types are likely to be created (as seen here).How can it be fixed?
We'll create a new
ABIRegistry
class with the following functionality.Then, within the codebase, we make a default registry to expose all of the built-in encoders and decoders.
Implementation details.
validation
The
register
method should raise an exception if the same static type is registered twice.determining which encoder/decoder to use
Internally, the
ABIRegistry
will need to implement a dynamic version of theeth_abi.encoding.get_single_encoder
andeth_abi.decoding.get_single_decoder
. The logic for these functions should be as follows.