eth-block-tracker
Advanced tools
Comparing version 7.1.0 to 8.0.0
export * from './PollingBlockTracker'; | ||
export * from './SubscribeBlockTracker'; | ||
export * from './BlockTracker'; |
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
var desc = Object.getOwnPropertyDescriptor(m, k); | ||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
desc = { enumerable: true, get: function() { return m[k]; } }; | ||
} | ||
Object.defineProperty(o, k2, desc); | ||
}) : (function(o, m, k, k2) { | ||
@@ -15,2 +19,3 @@ if (k2 === undefined) k2 = k; | ||
__exportStar(require("./SubscribeBlockTracker"), exports); | ||
__exportStar(require("./BlockTracker"), exports); | ||
//# sourceMappingURL=index.js.map |
import type { SafeEventEmitterProvider } from '@metamask/eth-json-rpc-provider'; | ||
import { BaseBlockTracker } from './BaseBlockTracker'; | ||
import SafeEventEmitter from '@metamask/safe-event-emitter'; | ||
import type { BlockTracker } from './BlockTracker'; | ||
export interface PollingBlockTrackerOptions { | ||
@@ -12,12 +13,34 @@ provider?: SafeEventEmitterProvider; | ||
} | ||
export declare class PollingBlockTracker extends BaseBlockTracker { | ||
private _provider; | ||
private _pollingInterval; | ||
private _retryTimeout; | ||
private _keepEventLoopActive; | ||
private _setSkipCacheFlag; | ||
export declare class PollingBlockTracker extends SafeEventEmitter implements BlockTracker { | ||
private _isRunning; | ||
private readonly _blockResetDuration; | ||
private readonly _usePastBlocks; | ||
private _currentBlock; | ||
private _blockResetTimeout?; | ||
private readonly _provider; | ||
private readonly _pollingInterval; | ||
private readonly _retryTimeout; | ||
private readonly _keepEventLoopActive; | ||
private readonly _setSkipCacheFlag; | ||
constructor(opts?: PollingBlockTrackerOptions); | ||
destroy(): Promise<void>; | ||
isRunning(): boolean; | ||
getCurrentBlock(): string | null; | ||
getLatestBlock(): Promise<string>; | ||
removeAllListeners(eventName?: string | symbol): this; | ||
private _setupInternalEvents; | ||
private _onNewListener; | ||
private _onRemoveListener; | ||
private _maybeStart; | ||
private _maybeEnd; | ||
private _getBlockTrackerEventCount; | ||
private _shouldUseNewBlock; | ||
private _newPotentialLatest; | ||
private _setCurrentBlock; | ||
private _setupBlockResetTimeout; | ||
private _cancelBlockResetTimeout; | ||
private _resetCurrentBlock; | ||
checkForLatestBlock(): Promise<string>; | ||
protected _start(): Promise<void>; | ||
protected _end(): Promise<void>; | ||
private _start; | ||
private _end; | ||
private _synchronize; | ||
@@ -24,0 +47,0 @@ private _updateLatestBlock; |
@@ -7,5 +7,5 @@ "use strict"; | ||
exports.PollingBlockTracker = void 0; | ||
const safe_event_emitter_1 = __importDefault(require("@metamask/safe-event-emitter")); | ||
const json_rpc_random_id_1 = __importDefault(require("json-rpc-random-id")); | ||
const pify_1 = __importDefault(require("pify")); | ||
const BaseBlockTracker_1 = require("./BaseBlockTracker"); | ||
const logging_utils_1 = require("./logging-utils"); | ||
@@ -15,5 +15,6 @@ const log = (0, logging_utils_1.createModuleLogger)(logging_utils_1.projectLogger, 'polling-block-tracker'); | ||
const sec = 1000; | ||
class PollingBlockTracker extends BaseBlockTracker_1.BaseBlockTracker { | ||
const calculateSum = (accumulator, currentValue) => accumulator + currentValue; | ||
const blockTrackerEvents = ['sync', 'latest']; | ||
class PollingBlockTracker extends safe_event_emitter_1.default { | ||
constructor(opts = {}) { | ||
var _a; | ||
// parse + validate args | ||
@@ -23,4 +24,16 @@ if (!opts.provider) { | ||
} | ||
super(Object.assign(Object.assign({}, opts), { blockResetDuration: (_a = opts.blockResetDuration) !== null && _a !== void 0 ? _a : opts.pollingInterval })); | ||
super(); | ||
// config | ||
this._blockResetDuration = opts.blockResetDuration || 20 * sec; | ||
this._usePastBlocks = opts.usePastBlocks || false; | ||
// state | ||
this._currentBlock = null; | ||
this._isRunning = false; | ||
// bind functions for internal use | ||
this._onNewListener = this._onNewListener.bind(this); | ||
this._onRemoveListener = this._onRemoveListener.bind(this); | ||
this._resetCurrentBlock = this._resetCurrentBlock.bind(this); | ||
// listen for handler changes | ||
this._setupInternalEvents(); | ||
// config | ||
this._provider = opts.provider; | ||
@@ -33,2 +46,124 @@ this._pollingInterval = opts.pollingInterval || 20 * sec; | ||
} | ||
async destroy() { | ||
this._cancelBlockResetTimeout(); | ||
await this._maybeEnd(); | ||
super.removeAllListeners(); | ||
} | ||
isRunning() { | ||
return this._isRunning; | ||
} | ||
getCurrentBlock() { | ||
return this._currentBlock; | ||
} | ||
async getLatestBlock() { | ||
// return if available | ||
if (this._currentBlock) { | ||
return this._currentBlock; | ||
} | ||
// wait for a new latest block | ||
const latestBlock = await new Promise((resolve) => this.once('latest', resolve)); | ||
// return newly set current block | ||
return latestBlock; | ||
} | ||
// dont allow module consumer to remove our internal event listeners | ||
removeAllListeners(eventName) { | ||
// perform default behavior, preserve fn arity | ||
if (eventName) { | ||
super.removeAllListeners(eventName); | ||
} | ||
else { | ||
super.removeAllListeners(); | ||
} | ||
// re-add internal events | ||
this._setupInternalEvents(); | ||
// trigger stop check just in case | ||
this._onRemoveListener(); | ||
return this; | ||
} | ||
_setupInternalEvents() { | ||
// first remove listeners for idempotence | ||
this.removeListener('newListener', this._onNewListener); | ||
this.removeListener('removeListener', this._onRemoveListener); | ||
// then add them | ||
this.on('newListener', this._onNewListener); | ||
this.on('removeListener', this._onRemoveListener); | ||
} | ||
_onNewListener(eventName) { | ||
// `newListener` is called *before* the listener is added | ||
if (blockTrackerEvents.includes(eventName)) { | ||
// TODO: Handle dangling promise | ||
this._maybeStart(); | ||
} | ||
} | ||
_onRemoveListener() { | ||
// `removeListener` is called *after* the listener is removed | ||
if (this._getBlockTrackerEventCount() > 0) { | ||
return; | ||
} | ||
this._maybeEnd(); | ||
} | ||
async _maybeStart() { | ||
if (this._isRunning) { | ||
return; | ||
} | ||
this._isRunning = true; | ||
// cancel setting latest block to stale | ||
this._cancelBlockResetTimeout(); | ||
await this._start(); | ||
this.emit('_started'); | ||
} | ||
async _maybeEnd() { | ||
if (!this._isRunning) { | ||
return; | ||
} | ||
this._isRunning = false; | ||
this._setupBlockResetTimeout(); | ||
await this._end(); | ||
this.emit('_ended'); | ||
} | ||
_getBlockTrackerEventCount() { | ||
return blockTrackerEvents | ||
.map((eventName) => this.listenerCount(eventName)) | ||
.reduce(calculateSum); | ||
} | ||
_shouldUseNewBlock(newBlock) { | ||
const currentBlock = this._currentBlock; | ||
if (!currentBlock) { | ||
return true; | ||
} | ||
const newBlockInt = hexToInt(newBlock); | ||
const currentBlockInt = hexToInt(currentBlock); | ||
return ((this._usePastBlocks && newBlockInt < currentBlockInt) || | ||
newBlockInt > currentBlockInt); | ||
} | ||
_newPotentialLatest(newBlock) { | ||
if (!this._shouldUseNewBlock(newBlock)) { | ||
return; | ||
} | ||
this._setCurrentBlock(newBlock); | ||
} | ||
_setCurrentBlock(newBlock) { | ||
const oldBlock = this._currentBlock; | ||
this._currentBlock = newBlock; | ||
this.emit('latest', newBlock); | ||
this.emit('sync', { oldBlock, newBlock }); | ||
} | ||
_setupBlockResetTimeout() { | ||
// clear any existing timeout | ||
this._cancelBlockResetTimeout(); | ||
// clear latest block when stale | ||
this._blockResetTimeout = setTimeout(this._resetCurrentBlock, this._blockResetDuration); | ||
// nodejs - dont hold process open | ||
if (this._blockResetTimeout.unref) { | ||
this._blockResetTimeout.unref(); | ||
} | ||
} | ||
_cancelBlockResetTimeout() { | ||
if (this._blockResetTimeout) { | ||
clearTimeout(this._blockResetTimeout); | ||
} | ||
} | ||
_resetCurrentBlock() { | ||
this._currentBlock = null; | ||
} | ||
// trigger block polling | ||
@@ -102,3 +237,3 @@ async checkForLatestBlock() { | ||
*/ | ||
function timeout(duration, unref) { | ||
async function timeout(duration, unref) { | ||
return new Promise((resolve) => { | ||
@@ -112,2 +247,12 @@ const timeoutRef = setTimeout(resolve, duration); | ||
} | ||
/** | ||
* Converts a number represented as a string in hexadecimal format into a native | ||
* number. | ||
* | ||
* @param hexInt - The hex string. | ||
* @returns The number. | ||
*/ | ||
function hexToInt(hexInt) { | ||
return Number.parseInt(hexInt, 16); | ||
} | ||
//# sourceMappingURL=PollingBlockTracker.js.map |
import type { SafeEventEmitterProvider } from '@metamask/eth-json-rpc-provider'; | ||
import { BaseBlockTracker } from './BaseBlockTracker'; | ||
import SafeEventEmitter from '@metamask/safe-event-emitter'; | ||
import type { BlockTracker } from './BlockTracker'; | ||
export interface SubscribeBlockTrackerOptions { | ||
@@ -8,11 +9,33 @@ provider?: SafeEventEmitterProvider; | ||
} | ||
export declare class SubscribeBlockTracker extends BaseBlockTracker { | ||
private _provider; | ||
export declare class SubscribeBlockTracker extends SafeEventEmitter implements BlockTracker { | ||
private _isRunning; | ||
private readonly _blockResetDuration; | ||
private readonly _usePastBlocks; | ||
private _currentBlock; | ||
private _blockResetTimeout?; | ||
private readonly _provider; | ||
private _subscriptionId; | ||
constructor(opts?: SubscribeBlockTrackerOptions); | ||
destroy(): Promise<void>; | ||
isRunning(): boolean; | ||
getCurrentBlock(): string | null; | ||
getLatestBlock(): Promise<string>; | ||
removeAllListeners(eventName?: string | symbol): this; | ||
private _setupInternalEvents; | ||
private _onNewListener; | ||
private _onRemoveListener; | ||
private _maybeStart; | ||
private _maybeEnd; | ||
private _getBlockTrackerEventCount; | ||
private _shouldUseNewBlock; | ||
private _newPotentialLatest; | ||
private _setCurrentBlock; | ||
private _setupBlockResetTimeout; | ||
private _cancelBlockResetTimeout; | ||
private _resetCurrentBlock; | ||
checkForLatestBlock(): Promise<string>; | ||
protected _start(): Promise<void>; | ||
protected _end(): Promise<void>; | ||
private _start; | ||
private _end; | ||
private _call; | ||
private _handleSubData; | ||
} |
@@ -7,6 +7,9 @@ "use strict"; | ||
exports.SubscribeBlockTracker = void 0; | ||
const safe_event_emitter_1 = __importDefault(require("@metamask/safe-event-emitter")); | ||
const json_rpc_random_id_1 = __importDefault(require("json-rpc-random-id")); | ||
const BaseBlockTracker_1 = require("./BaseBlockTracker"); | ||
const createRandomId = (0, json_rpc_random_id_1.default)(); | ||
class SubscribeBlockTracker extends BaseBlockTracker_1.BaseBlockTracker { | ||
const sec = 1000; | ||
const calculateSum = (accumulator, currentValue) => accumulator + currentValue; | ||
const blockTrackerEvents = ['sync', 'latest']; | ||
class SubscribeBlockTracker extends safe_event_emitter_1.default { | ||
constructor(opts = {}) { | ||
@@ -17,8 +20,141 @@ // parse + validate args | ||
} | ||
// BaseBlockTracker constructor | ||
super(opts); | ||
super(); | ||
// config | ||
this._blockResetDuration = opts.blockResetDuration || 20 * sec; | ||
this._usePastBlocks = opts.usePastBlocks || false; | ||
// state | ||
this._currentBlock = null; | ||
this._isRunning = false; | ||
// bind functions for internal use | ||
this._onNewListener = this._onNewListener.bind(this); | ||
this._onRemoveListener = this._onRemoveListener.bind(this); | ||
this._resetCurrentBlock = this._resetCurrentBlock.bind(this); | ||
// listen for handler changes | ||
this._setupInternalEvents(); | ||
// config | ||
this._provider = opts.provider; | ||
this._subscriptionId = null; | ||
} | ||
async destroy() { | ||
this._cancelBlockResetTimeout(); | ||
await this._maybeEnd(); | ||
super.removeAllListeners(); | ||
} | ||
isRunning() { | ||
return this._isRunning; | ||
} | ||
getCurrentBlock() { | ||
return this._currentBlock; | ||
} | ||
async getLatestBlock() { | ||
// return if available | ||
if (this._currentBlock) { | ||
return this._currentBlock; | ||
} | ||
// wait for a new latest block | ||
const latestBlock = await new Promise((resolve) => this.once('latest', resolve)); | ||
// return newly set current block | ||
return latestBlock; | ||
} | ||
// dont allow module consumer to remove our internal event listeners | ||
removeAllListeners(eventName) { | ||
// perform default behavior, preserve fn arity | ||
if (eventName) { | ||
super.removeAllListeners(eventName); | ||
} | ||
else { | ||
super.removeAllListeners(); | ||
} | ||
// re-add internal events | ||
this._setupInternalEvents(); | ||
// trigger stop check just in case | ||
this._onRemoveListener(); | ||
return this; | ||
} | ||
_setupInternalEvents() { | ||
// first remove listeners for idempotence | ||
this.removeListener('newListener', this._onNewListener); | ||
this.removeListener('removeListener', this._onRemoveListener); | ||
// then add them | ||
this.on('newListener', this._onNewListener); | ||
this.on('removeListener', this._onRemoveListener); | ||
} | ||
_onNewListener(eventName) { | ||
// `newListener` is called *before* the listener is added | ||
if (blockTrackerEvents.includes(eventName)) { | ||
// TODO: Handle dangling promise | ||
this._maybeStart(); | ||
} | ||
} | ||
_onRemoveListener() { | ||
// `removeListener` is called *after* the listener is removed | ||
if (this._getBlockTrackerEventCount() > 0) { | ||
return; | ||
} | ||
this._maybeEnd(); | ||
} | ||
async _maybeStart() { | ||
if (this._isRunning) { | ||
return; | ||
} | ||
this._isRunning = true; | ||
// cancel setting latest block to stale | ||
this._cancelBlockResetTimeout(); | ||
await this._start(); | ||
this.emit('_started'); | ||
} | ||
async _maybeEnd() { | ||
if (!this._isRunning) { | ||
return; | ||
} | ||
this._isRunning = false; | ||
this._setupBlockResetTimeout(); | ||
await this._end(); | ||
this.emit('_ended'); | ||
} | ||
_getBlockTrackerEventCount() { | ||
return blockTrackerEvents | ||
.map((eventName) => this.listenerCount(eventName)) | ||
.reduce(calculateSum); | ||
} | ||
_shouldUseNewBlock(newBlock) { | ||
const currentBlock = this._currentBlock; | ||
if (!currentBlock) { | ||
return true; | ||
} | ||
const newBlockInt = hexToInt(newBlock); | ||
const currentBlockInt = hexToInt(currentBlock); | ||
return ((this._usePastBlocks && newBlockInt < currentBlockInt) || | ||
newBlockInt > currentBlockInt); | ||
} | ||
_newPotentialLatest(newBlock) { | ||
if (!this._shouldUseNewBlock(newBlock)) { | ||
return; | ||
} | ||
this._setCurrentBlock(newBlock); | ||
} | ||
_setCurrentBlock(newBlock) { | ||
const oldBlock = this._currentBlock; | ||
this._currentBlock = newBlock; | ||
this.emit('latest', newBlock); | ||
this.emit('sync', { oldBlock, newBlock }); | ||
} | ||
_setupBlockResetTimeout() { | ||
// clear any existing timeout | ||
this._cancelBlockResetTimeout(); | ||
// clear latest block when stale | ||
this._blockResetTimeout = setTimeout(this._resetCurrentBlock, this._blockResetDuration); | ||
// nodejs - dont hold process open | ||
if (this._blockResetTimeout.unref) { | ||
this._blockResetTimeout.unref(); | ||
} | ||
} | ||
_cancelBlockResetTimeout() { | ||
if (this._blockResetTimeout) { | ||
clearTimeout(this._blockResetTimeout); | ||
} | ||
} | ||
_resetCurrentBlock() { | ||
this._currentBlock = null; | ||
} | ||
async checkForLatestBlock() { | ||
@@ -51,3 +187,3 @@ return await this.getLatestBlock(); | ||
} | ||
_call(method, ...params) { | ||
async _call(method, ...params) { | ||
return new Promise((resolve, reject) => { | ||
@@ -78,2 +214,12 @@ this._provider.sendAsync({ | ||
exports.SubscribeBlockTracker = SubscribeBlockTracker; | ||
/** | ||
* Converts a number represented as a string in hexadecimal format into a native | ||
* number. | ||
* | ||
* @param hexInt - The hex string. | ||
* @returns The number. | ||
*/ | ||
function hexToInt(hexInt) { | ||
return Number.parseInt(hexInt, 16); | ||
} | ||
//# sourceMappingURL=SubscribeBlockTracker.js.map |
{ | ||
"name": "eth-block-tracker", | ||
"version": "7.1.0", | ||
"version": "8.0.0", | ||
"description": "A block tracker for the Ethereum blockchain. Keeps track of the latest block.", | ||
@@ -28,7 +28,7 @@ "repository": { | ||
"dependencies": { | ||
"@metamask/eth-json-rpc-provider": "^1.0.0", | ||
"@metamask/eth-json-rpc-provider": "^2.1.0", | ||
"@metamask/safe-event-emitter": "^3.0.0", | ||
"@metamask/utils": "^5.0.1", | ||
"@metamask/utils": "^8.1.0", | ||
"json-rpc-random-id": "^1.0.1", | ||
"pify": "^3.0.0" | ||
"pify": "^5.0.0" | ||
}, | ||
@@ -38,31 +38,32 @@ "devDependencies": { | ||
"@metamask/auto-changelog": "^3.0.0", | ||
"@metamask/eslint-config": "^9.0.0", | ||
"@metamask/eslint-config-jest": "^9.0.0", | ||
"@metamask/eslint-config-nodejs": "^9.0.0", | ||
"@metamask/eslint-config-typescript": "^9.0.1", | ||
"@types/jest": "^27.4.1", | ||
"@metamask/eslint-config": "^12.0.0", | ||
"@metamask/eslint-config-jest": "^12.0.0", | ||
"@metamask/eslint-config-nodejs": "^12.0.0", | ||
"@metamask/eslint-config-typescript": "^12.0.0", | ||
"@metamask/json-rpc-engine": "^7.1.1", | ||
"@types/jest": "^29.1.2", | ||
"@types/json-rpc-random-id": "^1.0.1", | ||
"@types/node": "^17.0.23", | ||
"@types/pify": "^5.0.1", | ||
"@typescript-eslint/eslint-plugin": "^4.20.0", | ||
"@typescript-eslint/parser": "^4.20.0", | ||
"eslint": "^7.23.0", | ||
"@typescript-eslint/eslint-plugin": "^5.61.0", | ||
"@typescript-eslint/parser": "^5.61.0", | ||
"eslint": "^8.21.0", | ||
"eslint-config-prettier": "^8.1.0", | ||
"eslint-import-resolver-typescript": "^2.7.1", | ||
"eslint-plugin-import": "^2.22.1", | ||
"eslint-plugin-jest": "^24.1.3", | ||
"eslint-plugin-jsdoc": "^36.1.0", | ||
"eslint-plugin-node": "^11.1.0", | ||
"eslint-plugin-prettier": "^3.3.1", | ||
"jest": "^27.5.1", | ||
"json-rpc-engine": "^6.1.0", | ||
"prettier": "^2.2.1", | ||
"eslint-plugin-jest": "^27.1.5", | ||
"eslint-plugin-jsdoc": "^39.9.1", | ||
"eslint-plugin-n": "^15.7.0", | ||
"eslint-plugin-prettier": "^4.2.1", | ||
"eslint-plugin-promise": "^6.1.1", | ||
"jest": "^29.1.2", | ||
"prettier": "^2.7.1", | ||
"prettier-plugin-packagejson": "^2.2.11", | ||
"rimraf": "^3.0.2", | ||
"ts-jest": "^27.1.4", | ||
"ts-jest": "^29.1.1", | ||
"ts-node": "^10.7.0", | ||
"typescript": "~4.4.0" | ||
"typescript": "~4.8.4" | ||
}, | ||
"engines": { | ||
"node": ">=14.0.0" | ||
"node": ">=16.20 || ^18.16" | ||
}, | ||
@@ -69,0 +70,0 @@ "publishConfig": { |
@@ -93,3 +93,3 @@ # eth-block-tracker | ||
- Install [Node.js](https://nodejs.org) version 14 | ||
- Install [Node.js](https://nodejs.org) version 16 or greater | ||
- If you are using [nvm](https://github.com/creationix/nvm#installation) (recommended) running `nvm use` will automatically choose the right node version for you. | ||
@@ -96,0 +96,0 @@ - Install [Yarn v1](https://yarnpkg.com/en/docs/install) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
64135
600
29
18
1
+ Added@metamask/eth-json-rpc-provider@2.3.2(transitive)
+ Addedpify@5.0.0(transitive)
- Removed@metamask/eth-json-rpc-provider@1.0.1(transitive)
- Removed@metamask/utils@5.0.2(transitive)
- Removedpify@3.0.0(transitive)
- Removedsuperstruct@1.0.4(transitive)
Updated@metamask/utils@^8.1.0
Updatedpify@^5.0.0