Ethers.js: Issues: "failed to meet quorum" on homestead network only.

Created on 19 Oct 2020  Ā·  8Comments  Ā·  Source: ethers-io/ethers.js

@ricmoo I'm still having this issue after fresh install version 5.0.12.
It's no issue happens if I add an event listener on rinkeby network but homestead got this error.

filters :

[homestead] register listenner: [ partnerowner1 : 0xBb993EBccB72F523f068220Ed557aDAE3CdA2cd4 ]

filters {
  address: '0xdac17f958d2ee523a2206206994597c13d831ec7',
  topics: [
    '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
    null,
    '0x000000000000000000000000bb993ebccb72f523f068220ed557adae3cda2cd4'
  ]
}

and this is what I got:

Error: failed to meet quorum (method="getBlockNumber", params={}, results=[{"weight":1,"start":1603061155831,"result":11078005},{"weight":1,"start":1603061155831,"result":11082697},{"weight":1,"start":1603061156585,"result":11082697},{"weight":1,"start":1603061156585,"result":11082697}], provider="[object Object]", code=SERVER_ERROR, version=providers/5.0.12)

additional log

 {
  reason: 'failed to meet quorum',
  code: 'SERVER_ERROR',
  method: 'getBlockNumber',
  params: {},
  results: [
    { weight: 1, start: 1603061697719, result: 11078005 },
    { weight: 1, start: 1603061697719, result: 11082737 },
    { weight: 1, start: 1603061698474, result: 11082737 },
    { weight: 1, start: 1603061698474, result: 11082737 }
  ],
  provider: FallbackProvider {
    _isProvider: true,
    _events: [ [Event] ],
    _emitted: { block: 11082736 },
    formatter: Formatter { formats: [Object] },
    anyNetwork: false,
    _network: {
      name: 'homestead',
      chainId: 1,
      ensAddress: '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e',
      _defaultProvider: [Function]
    },
    _maxInternalBlockNumber: 11082736,
    _lastBlockNumber: 11082736,
    _pollingInterval: 4000,
    _fastQueryDate: 1603061693718,
    providerConfigs: [ [Object], [Object], [Object], [Object] ],
    quorum: 2,
    _highestBlockNumber: 11082736,
    _internalBlockNumber: Promise { <rejected> [Circular] },
    _poller: Timeout {
      _idleTimeout: 4000,
      _idlePrev: [TimersList],
      _idleNext: [Timeout],
      _idleStart: 28586,
      _onTimeout: [Function: bound ],
      _timerArgs: undefined,
      _repeat: 4000,
      _destroyed: false,
      [Symbol(refed)]: true,
      [Symbol(kHasPrimitive)]: false,
      [Symbol(asyncId)]: 438,
      [Symbol(triggerId)]: 0
    },
    _bootstrapPoll: null,
    _fastBlockNumber: 11082736,
    _fastBlockNumberPromise: Promise { 11082736 }
  }

Most helpful comment

Increasing it beyond the sum of providers / 2 could start to impact its quorum error rate.

Basically, the goal of the FallbackProvider is to create a provider with many backends.

The defaultProvider creates a FallbackProvider backed by multiple third-party backends (such as INFURA and Alchemy). But since using a third-party service means you must trust that service, multiple backends are queried at random, to ensure a quorum of them agree. That way if a backend is lying (through malice or being out-of-sync) it will be ā€œout-votedā€ by honest, synced nodes. If a quorum is not reached initially, additional nodes are queries until a quorum is reached.

So, if you use eth_call to lookup an ENS name and the first node says address A and the second address B, then a third will be queried. If it answers with address B, the default quorum has been reached and address B is returned.

So, but specifying a quorum of 1, you are saying you will accept any answer that comes back and that you trust any backend. If you do this, I recommend pulling the CloudflareProvider out of the list of providers as it is regularly out-of-sync. I might make this the default behaviour; if a person is selecting a quorum of 1, remove Cloudflare. I have had relatively issue with any of the other third-party services.

Hope that helps a bit. :)

All 8 comments

That looks like quorum should certainly have been met. I’ll look into this shortly.

@ricmoo I found this block of code that may cause this error.
I read your code and workaround by add { quorum: 1 } into option and the error it's gone.

That should be fine. You want to use a quorum of at least 2 in production.

I think there must be some logic issue on the custom blockNumber validation rules. It’s been a while since I have dug into that though, so I’ll set up some reproduction scripts later.

at least it fixed my issue, the error hurt my logs.
I'm so sorry that I don't have much experience on concept of quorum, so it's not easy for me to help about this issue.
Hope you can find the root cause and fix it soon!

No worries, I’ll look into it. I am planing to re-factor the FallbackProvider overall.

Reducing it to 1 will eliminate the error in you code, but reduces the security and resilience. If any backend is out of sync or has been compromised, your app may behave incorrectly...

No worries, I’ll look into it. I am planing to re-factor the FallbackProvider overall.

Reducing it to 1 will eliminate the error in you code, but reduces the security and resilience. If any backend is out of sync or has been compromised, your app may behave incorrectly...

I have no choice in this case until have your fix. Actually may I increase it more than 3 or something else? Honestly I don't understand what quorum does there. If you have time please lighten me up, thanks!

Increasing it beyond the sum of providers / 2 could start to impact its quorum error rate.

Basically, the goal of the FallbackProvider is to create a provider with many backends.

The defaultProvider creates a FallbackProvider backed by multiple third-party backends (such as INFURA and Alchemy). But since using a third-party service means you must trust that service, multiple backends are queried at random, to ensure a quorum of them agree. That way if a backend is lying (through malice or being out-of-sync) it will be ā€œout-votedā€ by honest, synced nodes. If a quorum is not reached initially, additional nodes are queries until a quorum is reached.

So, if you use eth_call to lookup an ENS name and the first node says address A and the second address B, then a third will be queried. If it answers with address B, the default quorum has been reached and address B is returned.

So, but specifying a quorum of 1, you are saying you will accept any answer that comes back and that you trust any backend. If you do this, I recommend pulling the CloudflareProvider out of the list of providers as it is regularly out-of-sync. I might make this the default behaviour; if a person is selecting a quorum of 1, remove Cloudflare. I have had relatively issue with any of the other third-party services.

Hope that helps a bit. :)

thanks for your explaination @ricmoo , very clear!
Currently i'm starting getDefaultProvider with 3 configs of INFURA, ALCHEMY and ETHERSCAN. I'll recheck if CloudflareProvider was created regardless the option didn't mention it, I'll remove it manually.
Btw, if I have time I gonna help you a little bit by adding function to query provider, now if I wanted to get etherscanProvider, I have to look up like this :

esProvider  = ProviderInstance.Providersconfigs.find(provider => provider.provider.apiKey === ETHERSCAN_API_KEY);

It was broken my code once since I ran version 4 and apiKey was a randomKey instead of mine, then the function getHistory stop working (esProvider === null)

Was this page helpful?
0 / 5 - 0 ratings