UNPKG

hardhat

Version:

Hardhat is an extensible developer tool that helps smart contract developers increase productivity by reliably bringing together the tools they want.

119 lines (93 loc) 2.87 kB
import { IntervalMiningConfig } from "./node-types"; enum MiningTimerState { STOP, RUNNING, } /* eslint-disable @nomicfoundation/hardhat-internal-rules/only-hardhat-error */ /** * Timer used to periodically call the given mining function. * * `_blockTime` can be a number or a pair of numbers (of milliseconds). If it * is a number, it will call the given function repeatedly every `_blockTime` * milliseconds. If it is a pair of numbers, then after each call it will * randomly choose how much to wait until the next call. * * `_mineFunction` is the function to call. It can be async, and it is assumed * that it will never throw. */ export class MiningTimer { private _state = MiningTimerState.STOP; private _timeout: NodeJS.Timeout | null = null; constructor( private _blockTime: IntervalMiningConfig, private readonly _mineFunction: () => Promise<any> ) { this._validateBlockTime(_blockTime); } public getBlockTime(): IntervalMiningConfig { return this._blockTime; } public enabled(): boolean { return this._blockTime !== 0; } public setBlockTime(blockTime: IntervalMiningConfig): void { this._validateBlockTime(blockTime); if (blockTime === 0) { this.stop(); return; } this._blockTime = blockTime; if (this._state === MiningTimerState.RUNNING) { this.stop(); } this.start(); } public start(): void { if (this._state === MiningTimerState.RUNNING || !this.enabled()) { return; } const blockTime = this._getNextBlockTime(); this._state = MiningTimerState.RUNNING; this._timeout = setTimeout(() => this._loop(), blockTime); } public stop(): void { if (this._state === MiningTimerState.STOP) { return; } this._state = MiningTimerState.STOP; if (this._timeout !== null) { clearTimeout(this._timeout); } } private _validateBlockTime(blockTime: IntervalMiningConfig) { if (Array.isArray(blockTime)) { const [rangeStart, rangeEnd] = blockTime; if (rangeEnd < rangeStart) { throw new Error("Invalid block time range"); } } else { if (blockTime < 0) { throw new Error("Block time cannot be negative"); } } } private async _loop() { if (this._state === MiningTimerState.STOP) { return; } await this._mineFunction(); const blockTime = this._getNextBlockTime(); this._timeout = setTimeout(() => { this._loop(); // eslint-disable-line @typescript-eslint/no-floating-promises }, blockTime); } private _getNextBlockTime(): number { if (Array.isArray(this._blockTime)) { const [minBlockTime, maxBlockTime] = this._blockTime; return ( minBlockTime + Math.floor(Math.random() * (maxBlockTime - minBlockTime)) ); } return this._blockTime; } }