Skip to content
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

ABI parser #115

Merged
merged 36 commits into from
Jan 31, 2024
Merged

ABI parser #115

merged 36 commits into from
Jan 31, 2024

Conversation

DanielSchiavini
Copy link
Collaborator

Fixes #106

What I did

  • Implement a separate ABI parser independent from Vyper
  • Implement function overloading
  • Test that it works with Solidity code, dynamic arrays, protected keywords and tuple types

How I did it

By writing a new ABI parser

How to verify it

Tests included

Description for the changelog

  • Implement new ABI parser

Cute Animal Picture

image

@@ -48,7 +54,7 @@ def marshal_to_python(self, computation, abi_type: list[str]) -> tuple[Any, ...]
:param computation: the computation object returned by `execute_code`
:param abi_type: the ABI type of the return value.
"""
if computation.is_error:
if computation.is_error or (abi_type and not computation.output):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't really like the truthy uses here. actually it seems the issue is that abi decoding could fail, right? can we skip this check and then just catch the exception from abi_decode() a few lines down? that would handle other abi decoding errors too, not sure if that's a good thing or not.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to raise proper errors when there is no bytecode deployed in that address.
This test:

def test_no_bytecode(get_filepath):

If we don't do this here, you get a DecodeError: Error decoding '0x' as '(uint8)' - Value length is not the expected size of 32 bytes - which gives no information to the user.
With this check the error changes to BoaError: (unknown location in <crvusd_abi.json interface at 0x0000000000000000000000000000000000000000 (WARNING: no bytecode at this address!)> crvusd_abi.decimals() -> ['uint8'])

I think using truthy here makes sense, since it doesn't matter whether abi_type/computation.output are None or ''

boa/util/abi.py Outdated


def is_abi_encodable(abi_type: str, data: Any) -> bool:
return is_encodable(abi_type, data)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how does is_encodable work?

Copy link
Collaborator Author

@DanielSchiavini DanielSchiavini Jan 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well this function is just a wrapper around the eth_abi function as you can see.

However, I'm looking into their implementation and they just try and catch 😓

So I think it makes sense to stick with eth.codecs and do the try/catch ourselves

Comment on lines 159 to 164
case multiple:
raise Exception(
f"Ambiguous call to {self.name}. "
f"Arguments can be encoded to multiple overloads: "
f"{', '.join(f.signature for f in multiple)}."
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm will it be possible to call functions with multiple overloads?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this implementation, it's possible only if there is a single matching overload for which the arguments are encodable.

When there're multiple overloads matching the arguments it's impossible, as this test shows:

"Ambiguous call to f. Arguments can be encoded to multiple overloads: (int8), (uint256)."

The approach we initially discussed of comparing exact types was not possible since we are calling the ABI from Python, so we don't have the distinct types from the EVM.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think it might be useful to be able to force boa to choose one of the functions

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but this is kind of a corner case

Copy link
Member

@charles-cooper charles-cooper left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looking pretty good! the new design looks good. left some feedback on some style things.

:param abi_type: the ABI type of the return value.
"""
# when there's no contract in the address, the computation output is empty
is_missing_output = bool(abi_type and not computation.output)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we should handle the exception as a general abi decode handler

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and probably not go thru the handle_error machinery because that expects to come from a VM error



@pytest.fixture()
def load_via_abi():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can just be a utility function, not a fixture

Copy link
Member

@charles-cooper charles-cooper left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm! just change that load_from_abi to a utility function and i think we are good to go

@charles-cooper charles-cooper merged commit ee27020 into vyperlang:master Jan 31, 2024
6 of 7 checks passed
@DanielSchiavini DanielSchiavini deleted the abi-parsing branch January 31, 2024 15:59
@DanielSchiavini DanielSchiavini self-assigned this Mar 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

fix ABI parsing bugs
2 participants