-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add feature to fetch contract storage into dictionary #3
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I implemented it returning
dict[bytes, bytes]
, but needed to deserialize the value to check it in thebalance_of
tests, which let me to think if it would be worth it to implement a storage wrapper with deserialize util methods and use it as the return type instead ofdict[bytes, bytes]
.
I think for the storage keys
this could well work for most use-cases, however storage values
can really be anything. From simple bytes to complete serialized objects (our Props - Puppet contract comes to mind that serializes a whole User
class).
I was thinking to add 2 arguments to get_storage()
that accept a keys_post_processor
and values_post_processor
function. It could look e.g. like this for a simple values
storage: dict[types.UInt160, types.BigInteger] = await self.get_storage(
prefix=self.balance_prefix,
remove_prefix=True,
key_post_processor=lambda x: types.UInt160(data=x),
value_post_processor=lambda x: types.BigInteger(x)
)
or for more complex things you can do
def deserialize_to_user(data: bytes) -> User:
# process the data
return User()
storage: dict[types.UInt160, User] = await self.get_storage(
prefix=self.balance_prefix,
remove_prefix=True,
key_post_processor=lambda x: types.UInt160(data=x),
value_post_processor=deserialize_to_user
)
Can you elaborate a bit more on how your storage wrapper idea would work? Perhaps the ideas can be combined.
fyi; I added a |
Sorry for the late response for this. I suggested a wrapper because I saw many blockchain-related wrappers being used in the project, but I actually think that your suggestion here
would be much more useful and flexible for what the user may use the storage for. Maybe we can include the simple processors (i.e. bytes to Integer, bytes to str, the default neo default serialization from bytes to array/map) in our package so the user can only import and use them. Something like: storage: dict[types.UInt160, list] = await self.get_storage(
prefix=self.balance_prefix,
remove_prefix=True,
key_post_processor=deserialize_as_uint160,
value_post_processor=deserialize_as_array
) |
Yes we can add some utility functions e.g. a module def as_uint160(data: bytes) -> UInt160:
if len(data) != 20:
raise ValueError("invalid data length")
return UInt160(data)
def as_public_key(data: bytes) -> ECPoint:
if len(data) == 33:
return ECpoint.deserialize_from_bytes(data)
elif len(data) == 66:
# handle uncompressed
else:
raise ValueError("invalid public key")
etc and then use as s: dict[types.UInt160, list] = await self.get_storage(
prefix=self.balance_prefix,
remove_prefix=True,
key_post_processor=storage.as_uint160,
value_post_processor=storage.as_public_key
) this is very similar to how the unwrap helpers work on the mamba side |
Included
get_storage
method inSmartContractTestCase
and included some tests checking the storage in nep17 exampleboa-test-constructor/examples/nep17/test_nep17.py
Lines 74 to 86 in 80180b1
I implemented it returning
dict[bytes, bytes]
, but needed to deserialize the value to check it in thebalance_of
tests, which let me to think if it would be worth it to implement a storage wrapper with deserialize util methods and use it as the return type instead ofdict[bytes, bytes]
.