UNPKG

@kaiachain/web3js-ext

Version:
139 lines (135 loc) 6.37 kB
"use strict"; /* This file is part of web3.js. web3.js is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. web3.js is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see <http://www.gnu.org/licenses/>. */ // Taken from https://github.com/web3/web3.js/blob/v4.3.0/packages/web3-eth/src/utils/reject_if_block_timeout.ts Object.defineProperty(exports, "__esModule", { value: true }); exports.rejectIfBlockTimeout = rejectIfBlockTimeout; const web3_errors_1 = require("web3-errors"); const web3_eth_1 = require("web3-eth"); const web3_utils_1 = require("web3-utils"); function resolveByPolling(web3Context, starterBlockNumber, transactionHash) { const pollingInterval = web3Context.transactionPollingInterval; const [intervalId, promiseToError] = (0, web3_utils_1.rejectIfConditionAtInterval)(async () => { let lastBlockNumber; try { lastBlockNumber = await (0, web3_eth_1.getBlockNumber)(web3Context, web3_eth_1.NUMBER_DATA_FORMAT); } catch (error) { console.warn("An error happen while trying to get the block number", error); return undefined; } const numberOfBlocks = lastBlockNumber - starterBlockNumber; if (numberOfBlocks >= web3Context.transactionBlockTimeout) { return new web3_errors_1.TransactionBlockTimeoutError({ starterBlockNumber, numberOfBlocks, transactionHash, }); } return undefined; }, pollingInterval); const clean = () => { clearInterval(intervalId); }; return [promiseToError, { clean }]; } async function resolveBySubscription(web3Context, starterBlockNumber, transactionHash) { // The following variable will stay true except if the data arrived, // or if watching started after an error had occurred. let needToWatchLater = true; let subscription; let resourceCleaner; // internal helper function function revertToPolling(reject, previousError) { if (previousError) { console.warn("error happened at subscription. So revert to polling...", previousError); } resourceCleaner.clean(); needToWatchLater = false; const [promiseToError, newResourceCleaner] = resolveByPolling(web3Context, starterBlockNumber, transactionHash); resourceCleaner.clean = newResourceCleaner.clean; promiseToError.catch((error) => reject(error)); } try { subscription = (await web3Context.subscriptionManager?.subscribe("newHeads")); resourceCleaner = { clean: () => { // Remove the subscription, if it was not removed somewhere // else by calling, for example, subscriptionManager.clear() if (subscription.id) { web3Context.subscriptionManager ?.removeSubscription(subscription) .then(() => { // Subscription ended successfully }) .catch(() => { // An error happened while ending subscription. But no need to take any action. }); } }, }; } catch (error) { return resolveByPolling(web3Context, starterBlockNumber, transactionHash); } const promiseToError = new Promise((_, reject) => { try { subscription.on("data", (lastBlockHeader) => { needToWatchLater = false; if (!lastBlockHeader?.number) { return; } const numberOfBlocks = Number(BigInt(lastBlockHeader.number) - BigInt(starterBlockNumber)); if (numberOfBlocks >= web3Context.transactionBlockTimeout) { // Transaction Block Timeout is known to be reached by subscribing to new heads reject(new web3_errors_1.TransactionBlockTimeoutError({ starterBlockNumber, numberOfBlocks, transactionHash, })); } }); subscription.on("error", (error) => { revertToPolling(reject, error); }); } catch (error) { revertToPolling(reject, error); } // Fallback to polling if tx receipt didn't arrived in "blockHeaderTimeout" [10 seconds] setTimeout(() => { if (needToWatchLater) { revertToPolling(reject); } }, web3Context.blockHeaderTimeout * 1000); }); return [promiseToError, resourceCleaner]; } /* TODO: After merge, there will be constant block mining time (exactly 12 second each block, except slot missed that currently happens in <1% of slots. ) so we can optimize following function for POS NWs, we can skip checking getBlockNumber(); after interval and calculate only based on time that certain num of blocked are mined after that for internal double check, can do one getBlockNumber() call and timeout. */ async function rejectIfBlockTimeout(web3Context, transactionHash) { const { provider } = web3Context.requestManager; let callingRes; const starterBlockNumber = await (0, web3_eth_1.getBlockNumber)(web3Context, web3_eth_1.NUMBER_DATA_FORMAT); // TODO: once https://github.com/web3/web3.js/issues/5521 is implemented, remove checking for `enableExperimentalFeatures.useSubscriptionWhenCheckingBlockTimeout` if (provider.supportsSubscriptions?.() && web3Context.enableExperimentalFeatures.useSubscriptionWhenCheckingBlockTimeout) { callingRes = await resolveBySubscription(web3Context, starterBlockNumber, transactionHash); } else { callingRes = resolveByPolling(web3Context, starterBlockNumber, transactionHash); } return callingRes; }