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

A problem that the result return 0x frequently when using contract method with eth_call, such as decimals, balanceOf, and so on. #19186

Closed
perterest opened this issue Mar 1, 2019 · 13 comments · Fixed by #19737
Assignees

Comments

@perterest
Copy link

perterest commented Mar 1, 2019

Hi there,

I use postman tool to call RPC API:

to query the decimals for BNB contract 0xB8c77482e45F1F44dE1745F52C74426C631bDD52

{ "jsonrpc": "2.0", "method": "eth_call", "params": [ { "to": "0xB8c77482e45F1F44dE1745F52C74426C631bDD52", "data": "0x313ce567" }, "latest" ], "id": 1 }

The postman return:
{ "jsonrpc": "2.0", "id": 1, "result": "0x" }

or sometimes:

{ "jsonrpc": "2.0", "id": 1, "result": "0x0000000000000000000000000000000000000000000000000000000000000012" }

I expect always return:

{ "jsonrpc": "2.0", "id": 1, "result": "0x0000000000000000000000000000000000000000000000000000000000000012" }

Geth version: 1.9.0-unstable
OS & Version: Ubuntu

I don't know what is the root cause, please anyone can help me?

Thanks so much.

@perterest
Copy link
Author

anyone help me ?

@AusIV
Copy link
Contributor

AusIV commented Mar 1, 2019

I actually ran into this last night independently. Digging in, I've come to believe that the problem is here:

https://github.com/ethereum/go-ethereum/blob/master/internal/ethapi/api.go#L749

When you make an RPC call to eth_call, it sets a non-configurable 5 second timeout for the EVM processing. If you're using a light client with high latency to peers, or a full client under heavy load, it may take longer than 5 seconds for the EVM to calculate the response. In that case, I believe DoCall() is returning failed=true, but the eth_call method ignores the fact that it failed and returns the "result" anyway.

I want to look around and see if there are other issues related to this, but I may put together a pull request to try to address it.

@AusIV
Copy link
Contributor

AusIV commented Mar 1, 2019

Digging deeper, DoCall() is not giving eth_call anything it can use to establish that an error occurred. failed=false even when a timeout occurs.

@AusIV
Copy link
Contributor

AusIV commented Mar 1, 2019

I've made a PR that will cause the 5 second timeout to result in an error, rather than returning a null response. That's not a complete solution, as I think there ought to be room for people running a node to configure the timeout for eth_calls, but at least it won't yield incorrect results.

@yinhaibo
Copy link

yinhaibo commented Mar 3, 2019

I have changed default timeout value, but the request also return 0x0, and the response time only 500ms, so I think some wrong on other place...

And I found traceTx cannot work in current master version, "execution timeout" was returned.
So, I disable timeout function to debug new transaction in current version:
comment L745-L750 lines: api_tracer.go

@axon-consultancy
Copy link

I have the same problem, when the request is run over IPC the result is always as expected. When run over HTTP the response is (sometimes) invalid. An example (rinkeby):

λ  deliver-oracle-assets master ✗ date; curl -d @$HOME/tmp/test 127.0.0.1:7777 -H"Content-Type: application/json"
Mon Mar 11 14:20:03 CET 2019
{"jsonrpc":"2.0","id":1,"result":"0x000000000000000000000000000000000000000000000000000000000037ee7d"}
λ  deliver-oracle-assets master ✗ date; curl -d @$HOME/tmp/test 127.0.0.1:7777 -H"Content-Type: application/json"
Mon Mar 11 14:20:03 CET 2019
{"jsonrpc":"2.0","id":1,"result":"0x000000000000000000000000000000000000000000000000000000000037ee7d"}
λ  deliver-oracle-assets master ✗ date; curl -d @$HOME/tmp/test 127.0.0.1:7777 -H"Content-Type: application/json"
Mon Mar 11 14:20:04 CET 2019
{"jsonrpc":"2.0","id":1,"result":"0x"}
λ  deliver-oracle-assets master ✗ date; curl -d @$HOME/tmp/test 127.0.0.1:7777 -H"Content-Type: application/json"
Mon Mar 11 14:20:05 CET 2019
{"jsonrpc":"2.0","id":1,"result":"0x000000000000000000000000000000000000000000000000000000000037ee7d"}
λ  deliver-oracle-assets master ✗ date; curl -d @$HOME/tmp/test 127.0.0.1:7777 -H"Content-Type: application/json"
Mon Mar 11 14:20:06 CET 2019
{"jsonrpc":"2.0","id":1,"result":"0x"}

The request in case you want to reply it:

{"jsonrpc":"2.0","id":1,"method":"eth_call","params":[{"data":"0x73fc8420","from":"0x0000000000000000000000000000000000000000","to":"0xe320e5dce85fc135d1f1d5dadd0c5bc411c0ab5b"},"latest"]}

@axon-consultancy
Copy link

It looks like there is a race condition in rpc/handler.go. HTTP uses rpc.Server#serveSingleRequest.

This method does roughly the following steps:

  1. defer h.close(...), among other things close will cancel the root context that is passed later to the handle[Batch,Msg] functions
  2. call handle[Batch,Msg], this will execute the callback in a new go-routine
  3. returns and executes the deferred h.close which cancels the context

Deferred methods are relatively slow and sometimes the EVM is able to assemble the result before the context is cancelled and the caller gets the result. Sometimes the context is cancelled before the result is assembled causing the client to receive 0x "no data" which is the default value and neither a valid data nor an quantity results for the RPC interface.

Two temporary workarounds are calling h.callWG.Wait() after h.handle[Batch|Msg] or switching the order of the lines:

h.cancelRoot()
h.callWG.Wait()

in handler.close().
Both workarounds disable the root context cancelling and are not proper solutions.

Don't know what the proper solution is to fix this. Maybe handle[Batch,Msg] should wait till either the callback is executed, or untill some kind of timeout, or untill the root ctx is cancelled before returning. If anyone can give advice what the proper solution would be I can try to create a PR.

@fjl ping since git indicates that this was changed in 245f314 although I haven't fully looked into it, so I might be wrong.

@qiongxiaoz
Copy link

qiongxiaoz commented Mar 27, 2019

I have the same problem. I have two synchronous machines. The height is similar, but some of the results are different, like this.
curl "192.168.1.106:8545" -X POST -H 'content-type: application/json' --data curl "192.168.1.106:8545" -X POST -H 'content-type: application/json' --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"to": "0xffa93aacf49297d51e211817452839052fdfb961","data": "0x70a082310000000000000000000000006642f5281822026ebdf76c06ba062878d8b7b653"},"latest"],"id":1}'
{"jsonrpc":"2.0","id":1,"result":"0x00000000000000000000000000000000000000000001188b2b6a7e62bd720000"}

curl "192.168.1.104:8545" -X POST -H 'content-type: application/json' --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"to": "0xffa93aacf49297d51e211817452839052fdfb961","data": "0x70a082310000000000000000000000006642f5281822026ebdf76c06ba062878d8b7b653"},"latest"],"id":1}'
{"jsonrpc":"2.0","id":1,"result":"0x"}

I'm confused.

@AusIV
Copy link
Contributor

AusIV commented Apr 11, 2019

@qiongxiaoz - Can you add time in front of you curl commands? I'm curious how long it's taking to serve those requests.

@kazaff
Copy link

kazaff commented Apr 16, 2019

Did this bug have been fixed?

@qiongxiaoz
Copy link

@AusIV
The time is short and the result is returned instantly. I can use eth.call in the console to query the data, but use the curl command eth_call method to return 0x, I don't know why. Fortunately, I have two servers, so it doesn't affect my use.

@Fierozen
Copy link

Fierozen commented May 2, 2019

I experienced many of the problems mentioned in this thread. While there may be some other problem with geth that needs to be addressed, this should be checked if you are having some of the problems mentioned here. For all solc versions, in both geth and parity:
When invoking the compiler, the evmVersion must be set to the correct level depending on the Solidity version. In my case, the Docker image of geth must still use evmVersion : 'byzantium', while the parity version, as explained on their web site, is using the latest, 'petersburg'.

So using Solidity 5.7, with geth in that Docker, I set the evmVersion with this:

result = compile_standard({ \
    'language': 'Solidity',

    'sources': {
        fileName: {
            'content': contract_source,
        },
    },
    'settings': {
        'evmVersion': 'byzantium',
        'outputSelection': {
            "*": {"*": ["*"]},
        }

see the following for full explanation:

https://solidity.readthedocs.io/en/v0.5.8/using-the-compiler.html#setting-the-evm-version-to-target

@DiveInto
Copy link

DiveInto commented Jun 7, 2019

same issue here with latest geth: v1.8.27

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 a pull request may close this issue.

9 participants