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

FallbackProvider throwing quorum not met error when rpc response is an error #4862

Open
longbigbronzeelephantfish1 opened this issue Oct 12, 2024 · 0 comments
Assignees
Labels
investigate Under investigation and may be a bug. v6 Issues regarding v6

Comments

@longbigbronzeelephantfish1

Ethers Version

6.13.4

Search Terms

fallbackprovider, quorum

Describe the Problem

When the FallbackProvider is sent call requests concurrently, the jsonrpc id sent to different rpc providers for the same request will differ, and if the response for the request is an error (e.g. execution reverted), it will cause the FallbackProvider to throw a SERVER_ERROR: quorum not met error.

The checkQuorum function in the FallbackProvider is comparing the entire error object which includes the sent payload which contains the differing id. I'm thinking errors should be compared by the actual error object (runner.result.error.info.error) returned by the rpc rather than the entire ethers error object.

image
Inside the normalizeResult function of the FallbackProvider, it compares the entire error object which includes the differing id rather than just the error response from the rpc.

Reproducible example: https://github.com/longbigbronzeelephantfish1/ethers-fallback-provider-bug

Code Snippet

// let's create 5 providers for bsc mainnet
    const providers = [
      "https://rpc.ankr.com/bsc",
      "https://bsc.blockpi.network/v1/rpc/public",
      "https://bsc-rpc.publicnode.com",
      "https://1rpc.io/bnb",
      "https://bsc.drpc.org",
    ];

    const provider1 = new JsonRpcProvider(providers[0]);
    const provider2 = new JsonRpcProvider(providers[1]);
    const provider3 = new JsonRpcProvider(providers[2]);
    const provider4 = new JsonRpcProvider(providers[3]);
    const provider5 = new JsonRpcProvider(providers[4]);

    // let's call different providers different number of times to throw the id off
    await provider1.getBlockNumber();

    await provider2.getBlockNumber();
    await provider2.getBlockNumber();

    await provider3.getBlockNumber();
    await provider3.getBlockNumber();
    await provider3.getBlockNumber();

    await provider4.getBlockNumber();
    await provider4.getBlockNumber();
    await provider4.getBlockNumber();
    await provider4.getBlockNumber();

    await provider5.getBlockNumber();
    await provider5.getBlockNumber();
    await provider5.getBlockNumber();
    await provider5.getBlockNumber();
    await provider5.getBlockNumber();

    // now we create a fallback provider with all the providers
    const fallbackProvider = new FallbackProvider([
      provider1,
      provider2,
      provider3,
      provider4,
      provider5,
    ]);

    // abi of a ERC20 contract
    // totalSupply is valid so it will return a value
    // hello doesn't exist so it will throw a call exception
    const abi = [
      "function totalSupply() view returns (uint256)",
      "function hello() view returns (uint256)",
    ];

    // BUSD contract on bsc mainnet
    const contract = new Contract(
      "0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56",
      abi,
      fallbackProvider
    );

    // totalSupply will return us the value correctly
    const firstResult = await contract
      .getFunction("totalSupply")
      .staticCallResult();
    console.log(firstResult);

    // hello will throw a quorum not met error
    const secondResult = await contract.getFunction("hello").staticCallResult();
    console.log(secondResult);

Contract ABI

const abi = [
      "function totalSupply() view returns (uint256)",
      "function hello() view returns (uint256)",
    ];

Errors

errors.ts:694 
 Uncaught (in promise) 
Error: quorum not met (request="%sub-requests", info={ "request": { "blockTag": "latest", "method": "call", "transaction": { "data": "0x19ff1d21", "to": "0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56" } }, "results": [ "{\"error\":{\"code\":\"CALL_EXCEPTION\",\"action\":\"call\",\"data\":null,\"reason\":null,\"transaction\":{\"to\":\"0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56\",\"data\":\"0x19ff1d21\"},\"invocation\":null,\"revert\":null,\"shortMessage\":\"missing revert data\",\"info\":{\"error\":{\"code\":-32000,\"message\":\"execution reverted\"},\"payload\":{\"method\":\"eth_call\",\"params\":[{\"to\":\"0xe9e7cea3dedca5984780bafc599bd69add087d56\",\"data\":\"0x19ff1d21\"},\"latest\"],\"id\":8,\"jsonrpc\":\"2.0\"}}}}", "{\"error\":{\"code\":\"CALL_EXCEPTION\",\"action\":\"call\",\"data\":null,\"reason\":null,\"transaction\":{\"to\":\"0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56\",\"data\":\"0x19ff1d21\"},\"invocation\":null,\"revert\":null,\"shortMessage\":\"missing revert data\",\"info\":{\"error\":{\"code\":-32000,\"message\":\"execution reverted\"},\"payload\":{\"method\":\"eth_call\",\"params\":[{\"to\":\"0xe9e7cea3dedca5984780bafc599bd69add087d56\",\"data\":\"0x19ff1d21\"},\"latest\"],\"id\":7,\"jsonrpc\":\"2.0\"}}}}", "{\"error\":{\"code\":\"CALL_EXCEPTION\",\"action\":\"call\",\"data\":null,\"reason\":null,\"transaction\":{\"to\":\"0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56\",\"data\":\"0x19ff1d21\"},\"invocation\":null,\"revert\":null,\"shortMessage\":\"missing revert data\",\"info\":{\"error\":{\"code\":-32000,\"message\":\"execution reverted\"},\"payload\":{\"method\":\"eth_call\",\"params\":[{\"to\":\"0xe9e7cea3dedca5984780bafc599bd69add087d56\",\"data\":\"0x19ff1d21\"},\"latest\"],\"id\":8,\"jsonrpc\":\"2.0\"}}}}", "{\"error\":{\"code\":\"CALL_EXCEPTION\",\"action\":\"call\",\"data\":null,\"reason\":null,\"transaction\":{\"to\":\"0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56\",\"data\":\"0x19ff1d21\"},\"invocation\":null,\"revert\":null,\"shortMessage\":\"missing revert data\",\"info\":{\"error\":{\"code\":-32000,\"message\":\"execution reverted\"},\"payload\":{\"method\":\"eth_call\",\"params\":[{\"to\":\"0xe9e7cea3dedca5984780bafc599bd69add087d56\",\"data\":\"0x19ff1d21\"},\"latest\"],\"id\":10,\"jsonrpc\":\"2.0\"}}}}", "{\"error\":{\"code\":\"CALL_EXCEPTION\",\"action\":\"call\",\"data\":null,\"reason\":null,\"transaction\":{\"to\":\"0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56\",\"data\":\"0x19ff1d21\"},\"invocation\":null,\"revert\":null,\"shortMessage\":\"missing revert data\",\"info\":{\"error\":{\"message\":\"execution reverted\",\"code\":-32000},\"payload\":{\"method\":\"eth_call\",\"params\":[{\"to\":\"0xe9e7cea3dedca5984780bafc599bd69add087d56\",\"data\":\"0x19ff1d21\"},\"latest\"],\"id\":6,\"jsonrpc\":\"2.0\"}}}}" ] }, code=SERVER_ERROR, version=6.13.4)
    at makeError (errors.ts:694:21)
    at assert (errors.ts:715:25)
    at FallbackProvider.waitForQuorum_fn (provider-fallback.ts:695:9)
    at async FallbackProvider.waitForQuorum_fn (provider-fallback.ts:705:16)
    at async FallbackProvider.waitForQuorum_fn (provider-fallback.ts:705:16)
    at async FallbackProvider.waitForQuorum_fn (provider-fallback.ts:705:16)
    at async FallbackProvider.waitForQuorum_fn (provider-fallback.ts:705:16)
    at async FallbackProvider.waitForQuorum_fn (provider-fallback.ts:705:16)
    at async FallbackProvider.waitForQuorum_fn (provider-fallback.ts:705:16)
    at async FallbackProvider.waitForQuorum_fn (provider-fallback.ts:705:16)

Environment

Ethereum (mainnet/ropsten/rinkeby/goerli), Altcoin - Please specify (e.g. Polygon), Browser (Chrome, Safari, etc)

Environment (Other)

No response

@longbigbronzeelephantfish1 longbigbronzeelephantfish1 added investigate Under investigation and may be a bug. v6 Issues regarding v6 labels Oct 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
investigate Under investigation and may be a bug. v6 Issues regarding v6
Projects
None yet
Development

No branches or pull requests

2 participants