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

Function input decoder #991

Merged
merged 7 commits into from Aug 8, 2018
Merged

Function input decoder #991

merged 7 commits into from Aug 8, 2018

Conversation

banteg
Copy link
Contributor

@banteg banteg commented Aug 6, 2018

What was wrong?

There was no trivial method to decode function input parameters.

How was it fixed?

This adds Contract.decode_function_input which is a counterpart to Contract.encodeABI.

>>> data = '338b5dea00000000000000000000000042d6622dece394b54999fbd73d108123806f6a180000000000000000000000000000000000000000000000000000000000000032'
>>> contract.decode_function_input(data)
(<Function depositToken(address,uint256)>,
 {'token': '0x42d6622dece394b54999fbd73d108123806f6a18', 'amount': 50})

Works like a charm ✨

Cute Animal Picture

My bunny loves Ethereum

Copy link
Collaborator

@carver carver left a comment

Choose a reason for hiding this comment

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

Thanks for adding docs and tests right up front!

It's a nice, simple implementation 👍

It's also worth thinking about what should happen during a function selector hash collision.

Most importantly, there are probably some other types worth testing. I added a test example of addresses, which should be returned checksummed, and strings which should be returned as type str.

One approach to solving the address checksum and string tests would be to use map_abi_data() with BASE_RETURN_NORMALIZERS.

I also added the round-trip test (that you can re-generate the transaction data by reusing the method and arguments).


.. py:classmethod:: Contract.decode_function_input(data)

Decodes function input data and returns :py:class:`ContractFunction` and decoded parameters as :py:class:`dict`.
Copy link
Collaborator

Choose a reason for hiding this comment

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

This could be a little clearer to newbies that we're talking about the data field of a transaction. Something like:

Decodes the transaction data used to invoke a smart contract function, and returns...

.. code-block:: python

>>> data = '338b5dea00000000000000000000000042d6622dece394b54999fbd73d108123806f6a180000000000000000000000000000000000000000000000000000000000000032'
>>> contract.decode_function_input(data)
Copy link
Collaborator

Choose a reason for hiding this comment

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

The example code could drive the point home with:

>>> transaction = w3.eth.getTransaction(...)
>>> transaction.data
'338b5dea00000000000000000000000042d6622dece394b54999fbd73d108123806f6a180000000000000000000000000000000000000000000000000000000000000032'
>>> contract.decode_function_input(transaction.data)

>>> data = '338b5dea00000000000000000000000042d6622dece394b54999fbd73d108123806f6a180000000000000000000000000000000000000000000000000000000000000032'
>>> contract.decode_function_input(data)
(<Function depositToken(address,uint256)>,
{'token': '0x42d6622dece394b54999fbd73d108123806f6a18', 'amount': 50})
Copy link
Collaborator

Choose a reason for hiding this comment

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

The official docs aren't a good place to advertise a live token (even subtly). :)

Something like ENS (no one profiting) or TheDAO (not live) could be good.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ENS example actually sounds great, I'll update the docs.

'0xf0fdf8340000000000000000000000000000000000000000000000000000000000000001',
'a',
[1],
{'': 1},
Copy link
Collaborator

@carver carver Aug 7, 2018

Choose a reason for hiding this comment

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

These expected values would be easier to read if the input arguments were named descriptively, like {'intarg': 1}.

Side note: I am even wondering if we should throw a validation error on an ABI with an empty variable name -- it would probably cause problems elsewhere (not suggesting adding that to this PR).

),
),
)
def test_contract_abi_decoding(web3, abi, data, method, arguments, expected):
Copy link
Collaborator

@carver carver Aug 7, 2018

Choose a reason for hiding this comment

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

Do you want to add a test against arguments? It's currently unused. Maybe it can just be dropped.

@banteg
Copy link
Contributor Author

banteg commented Aug 8, 2018

Thanks for pointing out the normalizers feature and adding the tests for additional data types. I updated the code, so now all the tests pass.

I also updated the wording in documentation and replaced the example with the infamous The DAO transaction.

@carver
Copy link
Collaborator

carver commented Aug 8, 2018

Unrelated test failure: occasionally parity integration tests are flaky.

@carver carver merged commit 3a924fc into ethereum:master Aug 8, 2018
@carver
Copy link
Collaborator

carver commented Aug 8, 2018

Very nice, thanks for the contribution!

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.

None yet

2 participants