Skip to content
This repository has been archived by the owner on Feb 26, 2024. It is now read-only.

eth_call not behaving as it should in alpha version #1547

Closed
0xng opened this issue Nov 12, 2021 · 2 comments · Fixed by #1980
Closed

eth_call not behaving as it should in alpha version #1547

0xng opened this issue Nov 12, 2021 · 2 comments · Fixed by #1980
Assignees
Milestone

Comments

@0xng
Copy link

0xng commented Nov 12, 2021

In our project we are using the alpha version of Ganache to create forks and then call eth_call through Ganache's request method. We have noticed two strange behaviours:

  • Calling eth_call this way is dramatically slower than calling it directly (118s vs 0.7s)
  • The returned data is not right

We wrote the following code so you can replicate it and see the behaviour in action. We are running it with:

  • An archive node
  • ethers 5.5.1
  • ganache 7.0.0-alpha.1

Code to replicate the behaviour:

import Ganache from 'ganache';
import { providers } from 'ethers';

const archiveNodeRPC = 'https://YOUR_ARCHIVE_NODE.SOMETHING';
const callParams = {
  tx: {
    data: '0x6433a9ea0000000000000000000000002150b45626199cfa5089368bdca30cd0bfb152d60000000000000000000000000000000000000000000000000000000000000080f7709b14a0f5e8bd2d0c1e3fc53c6a443f512aa29eeb905321172bf2b1fe39be0000000000000000000000000000000000000000000000000000000000cf6ae5000000000000000000000000000000000000000000000000000000000000002436df7ea50000000000000000000000007900c70a377f89df29d1d1939469ae3b74c5b74000000000000000000000000000000000000000000000000000000000',
    to: '0x0a61c2146A7800bdC278833F21EBf56Cd660EE2a',
    from: '0x9429cd74A3984396f3117d51cde46ea8e0e21487',
  },
  block: 13593317
};
const chainId = 1;

(async () => {
  console.log('*** Comparing direct static call and through Ganache Alpha v7 ***');
  console.log('');
  
  console.log('Sending eth_call directly to RPC');
  let dateBefore = Date.now();
    const testProvider = new providers.JsonRpcProvider({ url: archiveNodeRPC }, chainId);
    const directResponse = await testProvider.call(
    callParams.tx,
    callParams.block
  );
  console.log(`Response`, directResponse);
  console.log(`Time taken: ${Date.now() - dateBefore}`);
  
  console.log('');
  
  console.log('Sending eth_call through Ganache');
  dateBefore = Date.now();
  const provider = Ganache.provider({ fork: archiveNodeRPC });
  const ganacheResponse = await provider.request({
    method: 'eth_call',
    params: [callParams.tx, callParams.block],
  });
  console.log(`Response`, ganacheResponse);
  console.log(`Time taken: ${Date.now() - dateBefore}`);
})();
@davidmurdoch davidmurdoch added this to the 7.0.0 milestone Nov 12, 2021
@davidmurdoch davidmurdoch self-assigned this Nov 12, 2021
@davidmurdoch
Copy link
Member

davidmurdoch commented Nov 12, 2021

Thanks for the issue! I've confirmed that this is still a bug against the develop branch.

Interestingly, ganache doesn't forward eth_call's to blocks before the fork to the original node, but instead executes everything locally. This means we have to fetch any state that the transaction interacts with at runtime.

A couple of reasons for doing this

  1. we currently apply ganache's hardfork rules, not historical rules to eth_call. This will change for "known chains" once fix: make forking chainId aware #1537 is merged.
  2. We plan on allowing users to alter historical state, which requires we run the transaction locally.
  3. remote nodes usually have an upper bound for how long an eth_call call is permitted to run. Ganache doesn't currently limit the execution time.

But I agree with you... waiting 200x longer than you should is annoying just for handling these little edge cases! So I think we should solve them by:

  1. merging fix: make forking chainId aware #1537
  2. setting a "dirtyState" flag and only running locally if historical state has been altered.
  3. try the eth_call via the remote node first (or simultaneously), and fall back to local only if it fails due to timeout reasons.

As for the actual bug here... I'm not sure what is causing the difference in results, as the hardfork rules should match in this case. I'll likely need to diff a transaction trace between ganache and a geth to find where we go wrong.

Thanks again for opening the issue. Hopefully we can get to the bottom of it soon!

@davidmurdoch
Copy link
Member

I believe the problem here is that Ganache is using the wrong block baseFee when executing the eth_call's message. Ganache calculates the next blocks's base fee, instead of just using the specified block's base fee. This is a bug and will be fixed in a future release.

The reproduction steps you provided were very helpful. They eventually lead me to here: https://etherscan.io/address/0xcb12ac8649ea06cbb15e29032163938d5f86d8ad#code#F1#L83. It is at this point that Ganache calculates the wrong value due to to the incorrect block.baseFee (https://etherscan.io/address/0xcb12ac8649ea06cbb15e29032163938d5f86d8ad#code#F1#L79).

Your bug report will also lead to improvements in Truffle debugger, as when tracking this down I uncovered additional bugs there: trufflesuite/truffle#4582 and trufflesuite/truffle#4584

I'm sorry it took me so long to get this figured out, but thank you for opening this issue and improving Truffle Suite by doing so!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants