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

Conversation

Projects
None yet
2 participants
@banteg
Contributor

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

@banteg banteg force-pushed the banteg:function-decoder branch from 914c7c2 to d21e838 Aug 6, 2018

@carver carver force-pushed the banteg:function-decoder branch from fbece10 to 122b592 Aug 7, 2018

@carver

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`.

This comment has been minimized.

@carver

carver Aug 7, 2018

Collaborator

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)

This comment has been minimized.

@carver

carver Aug 7, 2018

Collaborator

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})

This comment has been minimized.

@carver

carver Aug 7, 2018

Collaborator

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.

This comment has been minimized.

@banteg

banteg Aug 8, 2018

Contributor

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

'0xf0fdf8340000000000000000000000000000000000000000000000000000000000000001',
'a',
[1],
{'': 1},

This comment has been minimized.

@carver

carver Aug 7, 2018

Collaborator

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):

This comment has been minimized.

@carver

carver Aug 7, 2018

Collaborator

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

@banteg banteg force-pushed the banteg:function-decoder branch from 5c6c400 to 2cf7c34 Aug 8, 2018

@banteg

This comment has been minimized.

Contributor

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

This comment has been minimized.

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

27 of 28 checks passed

ci/circleci: py35-integration-parity-http CircleCI is running your tests
Details
ci/circleci: doctest Your tests passed on CircleCI!
Details
ci/circleci: lint Your tests passed on CircleCI!
Details
ci/circleci: py35-core Your tests passed on CircleCI!
Details
ci/circleci: py35-ens Your tests passed on CircleCI!
Details
ci/circleci: py35-integration-ethtester-pyethereum Your tests passed on CircleCI!
Details
ci/circleci: py35-integration-ethtester-pyevm Your tests passed on CircleCI!
Details
ci/circleci: py35-integration-goethereum-http-1.7.2 Your tests passed on CircleCI!
Details
ci/circleci: py35-integration-goethereum-http-1.8.1 Your tests passed on CircleCI!
Details
ci/circleci: py35-integration-goethereum-ipc-1.7.2 Your tests passed on CircleCI!
Details
ci/circleci: py35-integration-goethereum-ipc-1.8.1 Your tests passed on CircleCI!
Details
ci/circleci: py35-integration-goethereum-ws-1.7.2 Your tests passed on CircleCI!
Details
ci/circleci: py35-integration-goethereum-ws-1.8.1 Your tests passed on CircleCI!
Details
ci/circleci: py35-integration-parity-ipc Your tests passed on CircleCI!
Details
ci/circleci: py35-integration-parity-ws Your tests passed on CircleCI!
Details
ci/circleci: py36-core Your tests passed on CircleCI!
Details
ci/circleci: py36-ens Your tests passed on CircleCI!
Details
ci/circleci: py36-integration-ethtester-pyethereum Your tests passed on CircleCI!
Details
ci/circleci: py36-integration-ethtester-pyevm Your tests passed on CircleCI!
Details
ci/circleci: py36-integration-goethereum-http-1.7.2 Your tests passed on CircleCI!
Details
ci/circleci: py36-integration-goethereum-http-1.8.1 Your tests passed on CircleCI!
Details
ci/circleci: py36-integration-goethereum-ipc-1.7.2 Your tests passed on CircleCI!
Details
ci/circleci: py36-integration-goethereum-ipc-1.8.1 Your tests passed on CircleCI!
Details
ci/circleci: py36-integration-goethereum-ws-1.7.2 Your tests passed on CircleCI!
Details
ci/circleci: py36-integration-goethereum-ws-1.8.1 Your tests passed on CircleCI!
Details
ci/circleci: py36-integration-parity-http Your tests passed on CircleCI!
Details
ci/circleci: py36-integration-parity-ipc Your tests passed on CircleCI!
Details
ci/circleci: py36-integration-parity-ws Your tests passed on CircleCI!
Details
@carver

This comment has been minimized.

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