odanado / cloud-cryptographic-wallet

cloud-cryptographic-wallet is a set of packages to connect crypto libraries with key management systems of various cloud services. This set of packages allows you to perform signatures and issue transactions without the need to manage private keys.
MIT License
91 stars 19 forks source link

Unhandled errors of Web3ProviderEngine crash the Node.js process #845

Open serejke opened 1 year ago

serejke commented 1 year ago

Problem

KmsProvider creates Web3ProviderEngine

https://github.com/odanado/cloud-cryptographic-wallet/blob/8e1ac042c944ca586ab14e1caf5323fd281c4b45/aws-kms-packages/aws-kms-provider/src/provider.ts#L50

but does not set .on(error, ...) handler by default, nor does it expose the engine to do so on clients. When the PollingBlockTracker of the Web3ProviderEngine encounters an error, the whole Node.js process crashes according to unhandled EventEmitter spec:

When an error occurs within an EventEmitter instance, the typical action is for an 'error' event to be emitted. These are treated as special cases within Node.js.

If an EventEmitter does not have at least one listener registered for the 'error' event, and an 'error' event is emitted, the error is thrown, a stack trace is printed, and the Node.js process exits.

We've experienced this issue in our fork of https://github.com/ava-labs/avalanche-faucet. Two reasons of failures:

    ^

Error [ERR_UNHANDLED_ERROR]: Unhandled error. ({
  code: -32603,
  message: 'Unknown Error: ',
  data: { originalError: {} }
})
    at new NodeError (node:internal/errors:377:5)
    at Web3ProviderEngine.emit (node:events:516:17)
    at /avalanche-faucet/node_modules/web3-provider-engine/index.js:54:14
    at afterRequest (/avalanche-faucet/node_modules/web3-provider-engine/index.js:148:21)
    at /avalanche-faucet/node_modules/web3-provider-engine/index.js:174:21
    at /avalanche-faucet/node_modules/web3-provider-engine/index.js:232:9
    at /avalanche-faucet/node_modules/async/internal/once.js:12:16
    at replenish (/avalanche-faucet/node_modules/async/internal/eachOfLimit.js:61:25)
    at /avalanche-faucet/node_modules/async/internal/eachOfLimit.js:71:9
    at eachLimit (/avalanche-faucet/node_modules/async/eachLimit.js:43:36)
    at /avalanche-faucet/node_modules/async/internal/doLimit.js:9:16
    at end (/avalanche-faucet/node_modules/web3-provider-engine/index.js:211:5)
    at Request._callback (/avalanche-faucet/node_modules/web3-provider-engine/subproviders/rpc.js:58:18)
    at self.callback (/avalanche-faucet/node_modules/request/request.js:185:22)
    at Request.emit (node:events:527:28)
    at Request.<anonymous> (/avalanche-faucet/node_modules/request/request.js:1154:10) {
  code: 'ERR_UNHANDLED_ERROR',
  context: {
    code: -32603,
    message: 'Unknown Error: ',
    data: { originalError: {} }
  }
}

Node.js v18.2.0

or

/avalanche-faucet/node_modules/@metamask/safe-event-emitter/index.js:11
            throw err;
            ^

Error: PollingBlockTracker - encountered an error while attempting to update latest block:
undefined
    at PollingBlockTracker._synchronize (/avalanche-faucet/node_modules/eth-block-tracker/dist/PollingBlockTracker.js:43:32)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
Emitted 'error' event on Web3ProviderEngine instance at:
    at safeApply (/avalanche-faucet/node_modules/@metamask/safe-event-emitter/index.js:6:17)
    at PollingBlockTracker.emit (/avalanche-faucet/node_modules/@metamask/safe-event-emitter/index.js:54:13)
    at PollingBlockTracker._synchronize (/avalanche-faucet/node_modules/eth-block-tracker/dist/PollingBlockTracker.js:45:26)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

Node.js v18.2.0

Solution

Provide the default subscription to .on('error', (e) => console.error(e)) and expose API to override it.