ethers-io / ethers.js

Complete Ethereum library and wallet implementation in JavaScript.
https://ethers.org/
MIT License
7.96k stars 1.85k forks source link

Intermittent "noNetwork" error when connecting to geth node via websocket - not related to internet connectivity #1779

Open 0xVegtam opened 3 years ago

0xVegtam commented 3 years ago

Describe the bug

I am trying to use a WebSocketProvider to connect to a personal geth node and stream pending transactions from the mempool to print on the console. I am doing this to setup some boilerplate stuff prior to beginning a new project. I have found that intermittently when running I will get "noNetwork" events raised by ethers which cause the program to crash despite the running computer never losing internet connectivity and the geth node being up and available the entire time. Running the script multiple times results in receiving the noNetwork event randomly, sometimes almost immediately others after several minutes of running. From what I can tell, the running machine never loses internet connectivity and I am able to use the internet and connect to my geth node and verify that it is properly synced and exposed so I am confident that I am not being rate limited.

Reproduction steps I am using this code snippet to elicit the error:

        //Watch for all new transactions
        this.provider.on("pending", async (tx: string) => {
            // Get transaction info from the discovered hash
            this.provider.getTransaction(tx).then((parsed: Transaction) => {
                if (parsed !== null && parsed.to === ROUTER_ADDRESSES[0]) {
                    const decodedTx = uniswapFnDecoder.decodeFn(parsed.data);
                    if (decodedTx.signature in UNISWAP_ROUTER_SIGHASHS) {
                        const tradeInfo: UniswappyV2Trade = {
                            amountIn: decodedTx.amountIn, 
                            amountOutMin: decodedTx.amountOutMin, 
                            path: decodedTx.path,
                            startingTokenAddress: decodedTx.path[0],
                            targetTokenAddress: decodedTx.path[decodedTx.path.length - 1], 
                            to: decodedTx.to, 
                            deadline: decodedTx.deadline,
                            signature: decodedTx.signature, 
                            sighash: decodedTx.sighash, 
                            tx: parsed,
                        }
                        console.log(tradeInfo);
                    }
                }

            });
        });

        // On block remove transactions included in the block that are tracked the mempool
        this.provider.on('block', async (blockNumber: number) => {
            const newBlock = this.flashbotsProvider.getBlock(blockNumber).then((data) => {
                this._removeCompletedTxs(data.transactions)
            });
        });

    async _addTransaction(trade: UniswappyV2Trade){
        if (trade.tx.hash) {
            const obj = {
                transaction: trade,
                timeDiscovered: Date.now()
            };
            this.mempool[trade.tx.hash] = obj;
            return(obj);
        }
        return null;
    }

    async _removeCompletedTxs(newlyMinedTxs: Array<string>) {
        /*
         * Function removes transactions that have been included in the most
         * recent block from the mempool
         */
        for (const tx in newlyMinedTxs) {
            try {
                delete this.mempool[newlyMinedTxs[tx]];
            } catch {
                continue;
            }
        }
        return;
    }

Error message/noNetwork event that I get looks like this:

/node_modules/@ethersproject/logger/src.ts/index.ts:213
        const error: any = new Error(message);
                           ^
Error: could not detect network (event="noNetwork", code=NETWORK_ERROR, version=providers/5.3.1)
    at Logger.makeError (/Users/vegtam/devspace/crypto-bots/sandwicher/node_modules/@ethersproject/logger/src.ts/index.ts:213:28)
    at Logger.throwError (/Users/vegtam/devspace/crypto-bots/sandwicher/node_modules/@ethersproject/logger/src.ts/index.ts:225:20)
    at FlashbotsBundleProvider.<anonymous> (/Users/vegtam/devspace/crypto-bots/sandwicher/node_modules/@ethersproject/providers/src.ts/json-rpc-provider.ts:379:23)
    at step (/Users/vegtam/devspace/crypto-bots/sandwicher/node_modules/@ethersproject/providers/lib/json-rpc-provider.js:48:23)
    at Object.throw (/Users/vegtam/devspace/crypto-bots/sandwicher/node_modules/@ethersproject/providers/lib/json-rpc-provider.js:29:53)
    at rejected (/Users/vegtam/devspace/crypto-bots/sandwicher/node_modules/@ethersproject/providers/lib/json-rpc-provider.js:21:65)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this   ##command.

Environment:

I am running my own geth node (1.10.5) on AWS - ports properly exposed, node synced and is usable.

Script running on OSX 11.3 M1 mac

Using these packages:

  "devDependencies": {
    "@types/jasmine": "^3.6.2",
    "@types/lodash": "^4.14.165",
    "@types/node": "^16.3.1",
    "@typescript-eslint/eslint-plugin": "^4.9.1",
    "@typescript-eslint/parser": "^4.9.1",
    "eslint": "^7.15.0",
    "ethers": "^5.0.23",
    "hardhat": "^2.4.3",
    "jasmine": "^3.6.3",
    "nyc": "^15.1.0"
  },
  "peerDependencies": {
    "ethers": "^5.0.23"
  },
  "dependencies": {
    "@flashbots/ethers-provider-bundle": "^0.3.1",
    "@uniswap/sdk": "^3.0.3",
    "@uniswap/sdk-core": "^3.0.0",
    "coingecko-api": "^1.0.10",
    "dotenv": "^10.0.0",
    "ethereum-tx-decoder": "^3.0.0",
    "isomorphic-fetch": "^3.0.0",
    "jsbi": "^3.1.4",
    "lodash": "^4.17.21",
    "ts-node": "^10.1.0",
    "tslib": "^2.3.0",
    "typescript": "^4.1.2",
    "winston": "^3.3.3"
  }
ricmoo commented 3 years ago

Are you shutting the node down and bringing it back up between launches?

This error is usually caused by a node’s RPC engine not being up yet. It only occurs (I think; I’llI dig into the code) when the first call to eth_chainId does not return a meaningful value.

0xVegtam commented 3 years ago

between launches, no. The node is running on a remote server and is running (seemingly) fine and untouched throughout any issues/regardless of what is done on the local machine.

but in my mind that sounds like that wouldn't be an issue if the node is up and running already right?

Can you think of a reason why that would happen after some time of execution with no problem? I would expect the eth_chainnId call to fail at the start before the script starts receiving mempool objects since the node potentially would still be starting up.

Regardless though, is it possible to avoid that call by hardcoding the chainID? Could be worth trying

tejareddy8888 commented 3 years ago

Hey Guys, Do we have an update on this issue, As We do not have EIP1559 gas data fetched from web3. We were planning to switch to ethersjs. As etherjs does have this functionality.

When I changed it to ethers using the WebSocketProvider, It does not support tunneling and I faced the same above mentioned issue , I wanted to pass the tunneling agent as below in web3 but ethers Networkish object does not have many properties, Let me know if you working on this or any new update on this.

Web3.providers.WebsocketProvider(URL, {
        requestOptions: {
          agent: httpsOverHttp({
      proxy: {
        host: HOSTNAME,
        port: PORT,
      },
    }),
        },
      });