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

Structs as args #1115

Merged
merged 15 commits into from
Jan 13, 2019
Merged

Structs as args #1115

merged 15 commits into from
Jan 13, 2019

Conversation

charles-cooper
Copy link
Member

@charles-cooper charles-cooper commented Dec 3, 2018

- What I did

Partially implement #1019 - structs as arguments and return values.

WIP Checklist

  • Fix ABI output for function args
  • Fix units
  • Fix ABI output for nested structs/tuples
  • Tests

- How I did it

Add packing / unpacking code for structs

- How to verify it

See tests

- Description for the changelog

Ability to pass structs as args and return values. Structs which contain other structs or structs which contain bytearrays not supported.

vyper/parser/expr.py Outdated Show resolved Hide resolved
vyper/parser/expr.py Outdated Show resolved Hide resolved
vyper/parser/expr.py Outdated Show resolved Hide resolved
@fubuloubu
Copy link
Member

Is emitting a struct in an event possible?

@charles-cooper
Copy link
Member Author

Not in this PR. I think that structs in events needs a bit more thought. Since each byte costs 8 gas, we probably should use the packed ABI encoding. I'm not sure what solidity produces / what web3 expects.

@fubuloubu
Copy link
Member

Moved that convo to #1170

@charles-cooper
Copy link
Member Author

Ok, based on the latest meeting, I rebased this PR and reduced the scope. For now, nested structs will not work with the ABI, and neither will struct arguments. Also, I opted to disallow passing structs with dynamic members for now, otherwise this PR will get too large. Should be ready for review (pending CI)!

@fubuloubu
Copy link
Member

CI failed, but I also think this feature needs way more tests lol

@fubuloubu
Copy link
Member

Also, can you add issues to track what was deemed out of scope?

@charles-cooper
Copy link
Member Author

@fubuloubu I can add some typechecking tests. Any other specific tests you think should be in here?

@fubuloubu
Copy link
Member

Anything with the ABI should be pretty throughly tested. That boundary a lot of things can go wrong haha.

@charles-cooper charles-cooper changed the title WIP: Structs as args Structs as args Jan 4, 2019
@fubuloubu
Copy link
Member

@jacqueswww when merged, can you cut as 0.1.0b7?

@jacqueswww
Copy link
Contributor

@fubuloubu I want a few more bug fixes in first, but b7 will be soon. In the meantime just peg the commit hash in your requirements.

@charles-cooper charles-cooper mentioned this pull request Jan 4, 2019
Copy link
Contributor

@jacqueswww jacqueswww left a comment

Choose a reason for hiding this comment

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

LGTM, this is great addition to vyper! :) @charles-cooper I think the one test that this still needs is if one wants to use a struct in an extract contract interface?

@fubuloubu
Copy link
Member

fubuloubu commented Jan 11, 2019

Testing this. It compiles, but I'm having difficulties getting the ABI to work with Web3py. What's the best way to do this?

File: https://github.com/GunClear/plasma-cash-vyper/blob/struct-args/contracts/RootChain.vy

@jacqueswww
Copy link
Contributor

jacqueswww commented Jan 11, 2019

@fubuloubu I don't think web3py is ready for those types of nested tuples (yet).
You could probably patch web3py with the latest eth-abi and try interpreting in that way?

@fubuloubu
Copy link
Member

v5 has eth-abi be right? That works for me.

v2 outputs the struct definitions right?

@jacqueswww
Copy link
Contributor

I think I will just merge this for now - as I am scared of branches diverging too much. Will create a ticket for the outstanding test.

@jacqueswww jacqueswww merged commit e5c95b2 into vyperlang:master Jan 13, 2019
@fubuloubu
Copy link
Member

Follow-up: ABI v2 doesn't seem to work with this :(

@charles-cooper
Copy link
Member Author

@fubuloubu uh oh! Can you provide a reproducible case?

@fubuloubu
Copy link
Member

fubuloubu commented Jan 15, 2019

dependencies:
pip install "py-evm>=0.2.0b39"
pip install "eth-tester>=0.1.0b36"
pip install "web3>=5.0.0a2"
pip install git+https://github.com/ethereum/vyper.git

>>> import vyper
>>> from web3 import Web3, EthereumTesterProvider

>>> w3 = Web3(EthereumTesterProvider())

>>> interface = vyper.compile_code("""
... struct MyStruct:
...     a: address
...     b: bytes32
... 
... @public
... def a(s: MyStruct) -> address:
...     return s.a
... 
... @public
... def b(s: MyStruct) -> bytes32:
...     return s.b
... """, output_formats=['abi', 'bytecode', 'bytecode_runtime'])

>>> txn_hash = w3.eth.contract(**interface).constructor().transact()
>>> address = w3.eth.waitForTransactionReceipt(txn_hash)['contractAddress']
>>> contract = w3.eth.contract(address, **interface)

>>> contract.functions.a(contract.address, b'\x00' * 32).call()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/bryant/.pyenv/versions/test/lib/python3.6/site-packages/web3/contract.py", line 1003, in __call__
    clone._set_function_info()
  File "/home/bryant/.pyenv/versions/test/lib/python3.6/site-packages/web3/contract.py", line 1012, in _set_function_info
    self.kwargs
  File "/home/bryant/.pyenv/versions/test/lib/python3.6/site-packages/web3/_utils/contracts.py", line 128, in find_matching_fn_abi
    raise ValidationError(message)
web3.exceptions.ValidationError:
Could not identify the intended function with name `a`, positional argument(s) of type `(<class 'str'>, <class 'bytes'>)` and keyword argument(s) of type `{}`.
Found 1 function(s) with the name `a`: ['a((address,bytes32))']
Function invocation failed due to improper number of arguments.

>>> contract.functions.a((contract.address, b'\x00' * 32)).call()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/bryant/.pyenv/versions/test/lib/python3.6/site-packages/web3/contract.py", line 1003, in __call__
    clone._set_function_info()
  File "/home/bryant/.pyenv/versions/test/lib/python3.6/site-packages/web3/contract.py", line 1012, in _set_function_info
    self.kwargs
  File "/home/bryant/.pyenv/versions/test/lib/python3.6/site-packages/web3/_utils/contracts.py", line 97, in find_matching_fn_abi
    function_candidates = pipe(abi, *filters)
  File "cytoolz/functoolz.pyx", line 589, in cytoolz.functoolz.pipe
  File "cytoolz/functoolz.pyx", line 565, in cytoolz.functoolz.c_pipe
  File "/home/bryant/.pyenv/versions/test/lib/python3.6/site-packages/web3/_utils/abi.py", line 203, in filter_by_encodability
    in contract_abi
  File "/home/bryant/.pyenv/versions/test/lib/python3.6/site-packages/web3/_utils/abi.py", line 204, in <listcomp>
    if check_if_arguments_can_be_encoded(function_abi, args, kwargs)
  File "/home/bryant/.pyenv/versions/test/lib/python3.6/site-packages/web3/_utils/abi.py", line 221, in check_if_arguments_can_be_encoded
    for _type, arg in zip(types, arguments)
  File "/home/bryant/.pyenv/versions/test/lib/python3.6/site-packages/web3/_utils/abi.py", line 221, in <genexpr>
    for _type, arg in zip(types, arguments)
  File "/home/bryant/.pyenv/versions/test/lib/python3.6/site-packages/web3/_utils/abi.py", line 166, in is_encodable
    base, sub, arrlist = process_type(_type)
  File "/home/bryant/.pyenv/versions/test/lib/python3.6/site-packages/web3/_utils/abi.py", line 136, in process_type
    type_str_repr,
ValueError: Cannot process type '(address,bytes32)': tuple types not supported

@charles-cooper
Copy link
Member Author

@fubuloubu that looks like a bug. Could you please create an issue?

@fubuloubu
Copy link
Member

A think it's a bug against web3py v5 if it doesn't implement the full abi V2 spec yet.

How did you decide what the ABI output should be in moving forward with this PR? Basically follow Solidity?

@charles-cooper
Copy link
Member Author

@fubuloubu Oh that's right. I even said so in my comments above (and apparently promptly forgot!)

To answer your question, I wanted to follow Solidity but tuples are not supported by eth-abi yet. The signature should be ABI-encoded as

...
    "name": "b",
    "inputs": [
      {
        "type": "tuple",
        "components": [
          { "type": "address", "name": "s_a"},
          {"type": "bytes32", "name" "s_b"}],
        "name": "s"
      }
    ],
...

and something similar for outputs. But that doesn't work, so for now I kept the input/output encoding the same as before (tuple inputs are encoded as (address,bytes32) and outputs are encoded as an array "outputs": [{ "type": "address", "name": "s_a"},{"type": "bytes32", "name" "s_b"}]) so as to keep tests passing.

@fubuloubu
Copy link
Member

I really wished the ABI had entries for structs, so we can just reference structs in different places instead of this tuple nonsense lol

@charles-cooper charles-cooper deleted the cmc-struct-args branch September 24, 2019 11:48
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.

3 participants