@metamask-previews/eth-block-tracker 14.0.0-preview-468843ab
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/LICENSE +20 -0
- package/README.md +91 -0
- package/dist/BlockTracker.cjs +3 -0
- package/dist/BlockTracker.cjs.map +1 -0
- package/dist/BlockTracker.d.cts +9 -0
- package/dist/BlockTracker.d.cts.map +1 -0
- package/dist/BlockTracker.d.mts +9 -0
- package/dist/BlockTracker.d.mts.map +1 -0
- package/dist/BlockTracker.mjs +2 -0
- package/dist/BlockTracker.mjs.map +1 -0
- package/dist/PollingBlockTracker.cjs +352 -0
- package/dist/PollingBlockTracker.cjs.map +1 -0
- package/dist/PollingBlockTracker.d.cts +65 -0
- package/dist/PollingBlockTracker.d.cts.map +1 -0
- package/dist/PollingBlockTracker.d.mts +65 -0
- package/dist/PollingBlockTracker.d.mts.map +1 -0
- package/dist/PollingBlockTracker.mjs +352 -0
- package/dist/PollingBlockTracker.mjs.map +1 -0
- package/dist/index.cjs +18 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +3 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -0
- package/dist/logging-utils.cjs +7 -0
- package/dist/logging-utils.cjs.map +1 -0
- package/dist/logging-utils.d.cts +5 -0
- package/dist/logging-utils.d.cts.map +1 -0
- package/dist/logging-utils.d.mts +5 -0
- package/dist/logging-utils.d.mts.map +1 -0
- package/dist/logging-utils.mjs +4 -0
- package/dist/logging-utils.mjs.map +1 -0
- package/package.json +81 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [14.0.0]
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- **BREAKING:** Update minimum Node.js version from `^18.16.0` to `^18.18.0` ([#6865](https://github.com/MetaMask/core/pull/6865))
|
|
15
|
+
- This package was migrated from `MetaMask/eth-block-tracker` to the
|
|
16
|
+
`MetaMask/core` monorepo ([#6865](https://github.com/MetaMask/core/pull/6865))
|
|
17
|
+
- See [`MetaMask/eth-block-tracker`](https://github.com/MetaMask/eth-block-tracker/blob/main/CHANGELOG.md)
|
|
18
|
+
for the original changelog.
|
|
19
|
+
|
|
20
|
+
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/eth-block-tracker@14.0.0...HEAD
|
|
21
|
+
[14.0.0]: https://github.com/MetaMask/core/releases/tag/@metamask/eth-block-tracker@14.0.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2018 MetaMask
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
package/README.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# `@metamask/eth-block-tracker`
|
|
2
|
+
|
|
3
|
+
This module walks the Ethereum blockchain, keeping track of the latest block. It uses a web3 provider as a data source and will continuously poll for the next block.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
`yarn add @metamask/eth-block-tracker`
|
|
8
|
+
|
|
9
|
+
or
|
|
10
|
+
|
|
11
|
+
`npm install @metamask/eth-block-tracker`
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
const createInfuraProvider = require('@metamask/eth-json-rpc-infura');
|
|
17
|
+
const { PollingBlockTracker } = require('@metamask/eth-block-tracker');
|
|
18
|
+
|
|
19
|
+
const provider = createInfuraProvider({
|
|
20
|
+
network: 'mainnet',
|
|
21
|
+
projectId: process.env.INFURA_PROJECT_ID,
|
|
22
|
+
});
|
|
23
|
+
const blockTracker = new PollingBlockTracker({ provider });
|
|
24
|
+
|
|
25
|
+
blockTracker.on('sync', ({ newBlock, oldBlock }) => {
|
|
26
|
+
if (oldBlock) {
|
|
27
|
+
console.log(`sync #${Number(oldBlock)} -> #${Number(newBlock)}`);
|
|
28
|
+
} else {
|
|
29
|
+
console.log(`first sync #${Number(newBlock)}`);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## API
|
|
35
|
+
|
|
36
|
+
### Methods
|
|
37
|
+
|
|
38
|
+
#### new PollingBlockTracker({ provider, pollingInterval, retryTimeout, keepEventLoopActive, usePastBlocks })
|
|
39
|
+
|
|
40
|
+
- Creates a new block tracker with `provider` as a data source and `pollingInterval` (ms) timeout between polling for the latest block.
|
|
41
|
+
- If an error is encountered when fetching blocks, it will wait `retryTimeout` (ms) before attempting again.
|
|
42
|
+
- If `keepEventLoopActive` is `false`, in Node.js it will [unref the polling timeout](https://nodejs.org/api/timers.html#timers_timeout_unref), allowing the process to exit during the polling interval. Defaults to `true`, meaning the process will be kept alive.
|
|
43
|
+
- If `usePastBlocks` is `true`, block numbers less than the current block number can used and emitted. Defaults to `false`, meaning that only block numbers greater than the current block number will be used and emitted.
|
|
44
|
+
|
|
45
|
+
#### getCurrentBlock()
|
|
46
|
+
|
|
47
|
+
Synchronously returns the current block. May be `null`.
|
|
48
|
+
|
|
49
|
+
```js
|
|
50
|
+
console.log(blockTracker.getCurrentBlock());
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
#### async getLatestBlock()
|
|
54
|
+
|
|
55
|
+
Asynchronously returns the latest block. if not immediately available, it will fetch one.
|
|
56
|
+
|
|
57
|
+
#### async checkForLatestBlock()
|
|
58
|
+
|
|
59
|
+
Tells the block tracker to ask for a new block immediately, in addition to its normal polling interval. Useful if you received a hint of a new block (e.g. via `tx.blockNumber` from `getTransactionByHash`). Will resolve to the new latest block when done polling.
|
|
60
|
+
|
|
61
|
+
### Events
|
|
62
|
+
|
|
63
|
+
#### latest
|
|
64
|
+
|
|
65
|
+
The `latest` event is emitted for whenever a new latest block is detected. This may mean skipping blocks if there were two created since the last polling period.
|
|
66
|
+
|
|
67
|
+
```js
|
|
68
|
+
blockTracker.on('latest', (newBlock) => console.log(newBlock));
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
#### sync
|
|
72
|
+
|
|
73
|
+
The `sync` event is emitted the same as "latest" but includes the previous block.
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
blockTracker.on('sync', ({ newBlock, oldBlock }) =>
|
|
77
|
+
console.log(newBlock, oldBlock),
|
|
78
|
+
);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
#### error
|
|
82
|
+
|
|
83
|
+
The `error` event means an error occurred while polling for the latest block.
|
|
84
|
+
|
|
85
|
+
```js
|
|
86
|
+
blockTracker.on('error', (err) => console.error(err));
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Contributing
|
|
90
|
+
|
|
91
|
+
This package is part of a monorepo. Instructions for contributing can be found in the [monorepo README](https://github.com/MetaMask/core#readme).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BlockTracker.cjs","sourceRoot":"","sources":["../src/BlockTracker.ts"],"names":[],"mappings":"","sourcesContent":["import type SafeEventEmitter from '@metamask/safe-event-emitter';\n\nexport type BlockTracker = SafeEventEmitter & {\n destroy(): Promise<void>;\n\n isRunning(): boolean;\n\n getCurrentBlock(): string | null;\n\n getLatestBlock(): Promise<string>;\n\n checkForLatestBlock(): Promise<string>;\n};\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type SafeEventEmitter from "@metamask/safe-event-emitter";
|
|
2
|
+
export type BlockTracker = SafeEventEmitter & {
|
|
3
|
+
destroy(): Promise<void>;
|
|
4
|
+
isRunning(): boolean;
|
|
5
|
+
getCurrentBlock(): string | null;
|
|
6
|
+
getLatestBlock(): Promise<string>;
|
|
7
|
+
checkForLatestBlock(): Promise<string>;
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=BlockTracker.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BlockTracker.d.cts","sourceRoot":"","sources":["../src/BlockTracker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,gBAAgB,qCAAqC;AAEjE,MAAM,MAAM,YAAY,GAAG,gBAAgB,GAAG;IAC5C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzB,SAAS,IAAI,OAAO,CAAC;IAErB,eAAe,IAAI,MAAM,GAAG,IAAI,CAAC;IAEjC,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAElC,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CACxC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type SafeEventEmitter from "@metamask/safe-event-emitter";
|
|
2
|
+
export type BlockTracker = SafeEventEmitter & {
|
|
3
|
+
destroy(): Promise<void>;
|
|
4
|
+
isRunning(): boolean;
|
|
5
|
+
getCurrentBlock(): string | null;
|
|
6
|
+
getLatestBlock(): Promise<string>;
|
|
7
|
+
checkForLatestBlock(): Promise<string>;
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=BlockTracker.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BlockTracker.d.mts","sourceRoot":"","sources":["../src/BlockTracker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,gBAAgB,qCAAqC;AAEjE,MAAM,MAAM,YAAY,GAAG,gBAAgB,GAAG;IAC5C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzB,SAAS,IAAI,OAAO,CAAC;IAErB,eAAe,IAAI,MAAM,GAAG,IAAI,CAAC;IAEjC,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAElC,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CACxC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BlockTracker.mjs","sourceRoot":"","sources":["../src/BlockTracker.ts"],"names":[],"mappings":"","sourcesContent":["import type SafeEventEmitter from '@metamask/safe-event-emitter';\n\nexport type BlockTracker = SafeEventEmitter & {\n destroy(): Promise<void>;\n\n isRunning(): boolean;\n\n getCurrentBlock(): string | null;\n\n getLatestBlock(): Promise<string>;\n\n checkForLatestBlock(): Promise<string>;\n};\n"]}
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
5
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
6
|
+
};
|
|
7
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
8
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
9
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
10
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
11
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
12
|
+
};
|
|
13
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
|
+
};
|
|
16
|
+
var _PollingBlockTracker_instances, _PollingBlockTracker_internalEventListeners, _PollingBlockTracker_pendingLatestBlock, _PollingBlockTracker_pendingFetch, _PollingBlockTracker_addInternalListener, _PollingBlockTracker_removeInternalListener, _PollingBlockTracker_rejectPendingLatestBlock;
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.PollingBlockTracker = void 0;
|
|
19
|
+
const safe_event_emitter_1 = __importDefault(require("@metamask/safe-event-emitter"));
|
|
20
|
+
const utils_1 = require("@metamask/utils");
|
|
21
|
+
const json_rpc_random_id_1 = __importDefault(require("json-rpc-random-id"));
|
|
22
|
+
const logging_utils_1 = require("./logging-utils.cjs");
|
|
23
|
+
const log = (0, logging_utils_1.createModuleLogger)(logging_utils_1.projectLogger, 'polling-block-tracker');
|
|
24
|
+
const createRandomId = (0, json_rpc_random_id_1.default)();
|
|
25
|
+
const sec = 1000;
|
|
26
|
+
const blockTrackerEvents = ['sync', 'latest'];
|
|
27
|
+
class PollingBlockTracker extends safe_event_emitter_1.default {
|
|
28
|
+
constructor(opts = {}) {
|
|
29
|
+
// parse + validate args
|
|
30
|
+
if (!opts.provider) {
|
|
31
|
+
throw new Error('PollingBlockTracker - no provider specified.');
|
|
32
|
+
}
|
|
33
|
+
super();
|
|
34
|
+
_PollingBlockTracker_instances.add(this);
|
|
35
|
+
_PollingBlockTracker_internalEventListeners.set(this, []);
|
|
36
|
+
_PollingBlockTracker_pendingLatestBlock.set(this, void 0);
|
|
37
|
+
_PollingBlockTracker_pendingFetch.set(this, void 0);
|
|
38
|
+
// config
|
|
39
|
+
this._blockResetDuration = opts.blockResetDuration || 20 * sec;
|
|
40
|
+
this._usePastBlocks = opts.usePastBlocks || false;
|
|
41
|
+
// state
|
|
42
|
+
this._currentBlock = null;
|
|
43
|
+
this._isRunning = false;
|
|
44
|
+
// bind functions for internal use
|
|
45
|
+
this._onNewListener = this._onNewListener.bind(this);
|
|
46
|
+
this._onRemoveListener = this._onRemoveListener.bind(this);
|
|
47
|
+
this._resetCurrentBlock = this._resetCurrentBlock.bind(this);
|
|
48
|
+
// listen for handler changes
|
|
49
|
+
this._setupInternalEvents();
|
|
50
|
+
// config
|
|
51
|
+
this._provider = opts.provider;
|
|
52
|
+
this._pollingInterval = opts.pollingInterval || 20 * sec;
|
|
53
|
+
this._retryTimeout = opts.retryTimeout || this._pollingInterval / 10;
|
|
54
|
+
this._keepEventLoopActive =
|
|
55
|
+
opts.keepEventLoopActive === undefined ? true : opts.keepEventLoopActive;
|
|
56
|
+
this._setSkipCacheFlag = opts.setSkipCacheFlag || false;
|
|
57
|
+
}
|
|
58
|
+
async destroy() {
|
|
59
|
+
this._cancelBlockResetTimeout();
|
|
60
|
+
super.removeAllListeners();
|
|
61
|
+
this._maybeEnd();
|
|
62
|
+
}
|
|
63
|
+
isRunning() {
|
|
64
|
+
return this._isRunning;
|
|
65
|
+
}
|
|
66
|
+
getCurrentBlock() {
|
|
67
|
+
return this._currentBlock;
|
|
68
|
+
}
|
|
69
|
+
async getLatestBlock({ useCache = true, } = {}) {
|
|
70
|
+
// return if available
|
|
71
|
+
if (this._currentBlock && useCache) {
|
|
72
|
+
return this._currentBlock;
|
|
73
|
+
}
|
|
74
|
+
if (__classPrivateFieldGet(this, _PollingBlockTracker_pendingLatestBlock, "f")) {
|
|
75
|
+
return await __classPrivateFieldGet(this, _PollingBlockTracker_pendingLatestBlock, "f").promise;
|
|
76
|
+
}
|
|
77
|
+
const { promise, resolve, reject } = (0, utils_1.createDeferredPromise)({
|
|
78
|
+
suppressUnhandledRejection: true,
|
|
79
|
+
});
|
|
80
|
+
__classPrivateFieldSet(this, _PollingBlockTracker_pendingLatestBlock, { reject, promise }, "f");
|
|
81
|
+
if (this._isRunning) {
|
|
82
|
+
try {
|
|
83
|
+
// If tracker is running, wait for next block with timeout
|
|
84
|
+
const onLatestBlock = (value) => {
|
|
85
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_removeInternalListener).call(this, onLatestBlock);
|
|
86
|
+
this.removeListener('latest', onLatestBlock);
|
|
87
|
+
resolve(value);
|
|
88
|
+
};
|
|
89
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_addInternalListener).call(this, onLatestBlock);
|
|
90
|
+
this.once('latest', onLatestBlock);
|
|
91
|
+
return await promise;
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
reject(error);
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
__classPrivateFieldSet(this, _PollingBlockTracker_pendingLatestBlock, undefined, "f");
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
// If tracker isn't running, just fetch directly
|
|
103
|
+
try {
|
|
104
|
+
const latestBlock = await this._updateLatestBlock();
|
|
105
|
+
resolve(latestBlock);
|
|
106
|
+
return latestBlock;
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
reject(error);
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
// We want to rate limit calls to this method if we made a direct fetch
|
|
114
|
+
// for the block number because the BlockTracker was not running. We
|
|
115
|
+
// achieve this by delaying the unsetting of the #pendingLatestBlock promise.
|
|
116
|
+
setTimeout(() => {
|
|
117
|
+
__classPrivateFieldSet(this, _PollingBlockTracker_pendingLatestBlock, undefined, "f");
|
|
118
|
+
}, this._pollingInterval);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// dont allow module consumer to remove our internal event listeners
|
|
123
|
+
removeAllListeners(eventName) {
|
|
124
|
+
// perform default behavior, preserve fn arity
|
|
125
|
+
if (eventName) {
|
|
126
|
+
super.removeAllListeners(eventName);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
super.removeAllListeners();
|
|
130
|
+
}
|
|
131
|
+
// re-add internal events
|
|
132
|
+
this._setupInternalEvents();
|
|
133
|
+
// trigger stop check just in case
|
|
134
|
+
this._onRemoveListener();
|
|
135
|
+
return this;
|
|
136
|
+
}
|
|
137
|
+
_setupInternalEvents() {
|
|
138
|
+
// first remove listeners for idempotence
|
|
139
|
+
this.removeListener('newListener', this._onNewListener);
|
|
140
|
+
this.removeListener('removeListener', this._onRemoveListener);
|
|
141
|
+
// then add them
|
|
142
|
+
this.on('newListener', this._onNewListener);
|
|
143
|
+
this.on('removeListener', this._onRemoveListener);
|
|
144
|
+
}
|
|
145
|
+
_onNewListener(eventName) {
|
|
146
|
+
// `newListener` is called *before* the listener is added
|
|
147
|
+
if (blockTrackerEvents.includes(eventName)) {
|
|
148
|
+
// TODO: Handle dangling promise
|
|
149
|
+
this._maybeStart();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
_onRemoveListener() {
|
|
153
|
+
// `removeListener` is called *after* the listener is removed
|
|
154
|
+
if (this._getBlockTrackerEventCount() > 0) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
this._maybeEnd();
|
|
158
|
+
}
|
|
159
|
+
_maybeStart() {
|
|
160
|
+
if (this._isRunning) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
this._isRunning = true;
|
|
164
|
+
// cancel setting latest block to stale
|
|
165
|
+
this._cancelBlockResetTimeout();
|
|
166
|
+
this._start();
|
|
167
|
+
this.emit('_started');
|
|
168
|
+
}
|
|
169
|
+
_maybeEnd() {
|
|
170
|
+
if (!this._isRunning) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
this._isRunning = false;
|
|
174
|
+
this._setupBlockResetTimeout();
|
|
175
|
+
this._end();
|
|
176
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_rejectPendingLatestBlock).call(this, new Error('Block tracker destroyed'));
|
|
177
|
+
this.emit('_ended');
|
|
178
|
+
}
|
|
179
|
+
_getBlockTrackerEventCount() {
|
|
180
|
+
return (blockTrackerEvents
|
|
181
|
+
.map((eventName) => this.listeners(eventName))
|
|
182
|
+
.flat()
|
|
183
|
+
// internal listeners are not included in the count
|
|
184
|
+
.filter((listener) => __classPrivateFieldGet(this, _PollingBlockTracker_internalEventListeners, "f").every((internalListener) => !Object.is(internalListener, listener))).length);
|
|
185
|
+
}
|
|
186
|
+
_shouldUseNewBlock(newBlock) {
|
|
187
|
+
const currentBlock = this._currentBlock;
|
|
188
|
+
if (!currentBlock) {
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
const newBlockInt = hexToInt(newBlock);
|
|
192
|
+
const currentBlockInt = hexToInt(currentBlock);
|
|
193
|
+
return ((this._usePastBlocks && newBlockInt < currentBlockInt) ||
|
|
194
|
+
newBlockInt > currentBlockInt);
|
|
195
|
+
}
|
|
196
|
+
_newPotentialLatest(newBlock) {
|
|
197
|
+
if (!this._shouldUseNewBlock(newBlock)) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
this._setCurrentBlock(newBlock);
|
|
201
|
+
}
|
|
202
|
+
_setCurrentBlock(newBlock) {
|
|
203
|
+
const oldBlock = this._currentBlock;
|
|
204
|
+
this._currentBlock = newBlock;
|
|
205
|
+
this.emit('latest', newBlock);
|
|
206
|
+
this.emit('sync', { oldBlock, newBlock });
|
|
207
|
+
}
|
|
208
|
+
_setupBlockResetTimeout() {
|
|
209
|
+
// clear any existing timeout
|
|
210
|
+
this._cancelBlockResetTimeout();
|
|
211
|
+
// clear latest block when stale
|
|
212
|
+
this._blockResetTimeout = setTimeout(this._resetCurrentBlock, this._blockResetDuration);
|
|
213
|
+
// nodejs - dont hold process open
|
|
214
|
+
if (this._blockResetTimeout.unref) {
|
|
215
|
+
this._blockResetTimeout.unref();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
_cancelBlockResetTimeout() {
|
|
219
|
+
if (this._blockResetTimeout) {
|
|
220
|
+
clearTimeout(this._blockResetTimeout);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
_resetCurrentBlock() {
|
|
224
|
+
this._currentBlock = null;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Checks for the latest block, updates the internal state, and returns the
|
|
228
|
+
* value immediately rather than waiting for the next polling interval.
|
|
229
|
+
*
|
|
230
|
+
* @deprecated Use {@link getLatestBlock} instead.
|
|
231
|
+
* @returns A promise that resolves to the latest block number.
|
|
232
|
+
*/
|
|
233
|
+
async checkForLatestBlock() {
|
|
234
|
+
await this._updateLatestBlock();
|
|
235
|
+
return await this.getLatestBlock();
|
|
236
|
+
}
|
|
237
|
+
_start() {
|
|
238
|
+
// Intentionally not awaited as this starts the polling via a timeout chain.
|
|
239
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
240
|
+
this._updateAndQueue();
|
|
241
|
+
}
|
|
242
|
+
_end() {
|
|
243
|
+
this._clearPollingTimeout();
|
|
244
|
+
}
|
|
245
|
+
async _updateLatestBlock() {
|
|
246
|
+
// fetch + set latest block
|
|
247
|
+
const latestBlock = await this._fetchLatestBlock();
|
|
248
|
+
this._newPotentialLatest(latestBlock);
|
|
249
|
+
if (!this._isRunning) {
|
|
250
|
+
// Ensure the one-time update is eventually reset once it's stale
|
|
251
|
+
this._setupBlockResetTimeout();
|
|
252
|
+
}
|
|
253
|
+
// _newPotentialLatest() ensures that this._currentBlock is not null
|
|
254
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
255
|
+
return this._currentBlock;
|
|
256
|
+
}
|
|
257
|
+
async _fetchLatestBlock() {
|
|
258
|
+
// If there's already a pending fetch, reuse it
|
|
259
|
+
if (__classPrivateFieldGet(this, _PollingBlockTracker_pendingFetch, "f")) {
|
|
260
|
+
return await __classPrivateFieldGet(this, _PollingBlockTracker_pendingFetch, "f").promise;
|
|
261
|
+
}
|
|
262
|
+
// Create a new deferred promise for this request
|
|
263
|
+
const { promise, resolve, reject } = (0, utils_1.createDeferredPromise)({
|
|
264
|
+
suppressUnhandledRejection: true,
|
|
265
|
+
});
|
|
266
|
+
__classPrivateFieldSet(this, _PollingBlockTracker_pendingFetch, { reject, promise }, "f");
|
|
267
|
+
try {
|
|
268
|
+
const req = {
|
|
269
|
+
jsonrpc: '2.0',
|
|
270
|
+
id: createRandomId(),
|
|
271
|
+
method: 'eth_blockNumber',
|
|
272
|
+
params: [],
|
|
273
|
+
};
|
|
274
|
+
if (this._setSkipCacheFlag) {
|
|
275
|
+
req.skipCache = true;
|
|
276
|
+
}
|
|
277
|
+
log('Making request', req);
|
|
278
|
+
const result = await this._provider.request(req);
|
|
279
|
+
log('Got result', result);
|
|
280
|
+
resolve(result);
|
|
281
|
+
return result;
|
|
282
|
+
}
|
|
283
|
+
catch (error) {
|
|
284
|
+
log('Encountered error fetching block', (0, utils_1.getErrorMessage)(error));
|
|
285
|
+
reject(error);
|
|
286
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_rejectPendingLatestBlock).call(this, error);
|
|
287
|
+
throw error;
|
|
288
|
+
}
|
|
289
|
+
finally {
|
|
290
|
+
__classPrivateFieldSet(this, _PollingBlockTracker_pendingFetch, undefined, "f");
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* The core polling function that runs after each interval.
|
|
295
|
+
* Updates the latest block and then queues the next update.
|
|
296
|
+
*/
|
|
297
|
+
async _updateAndQueue() {
|
|
298
|
+
let interval = this._pollingInterval;
|
|
299
|
+
try {
|
|
300
|
+
await this._updateLatestBlock();
|
|
301
|
+
}
|
|
302
|
+
catch (error) {
|
|
303
|
+
try {
|
|
304
|
+
this.emit('error', error);
|
|
305
|
+
}
|
|
306
|
+
catch {
|
|
307
|
+
console.error(`Error updating latest block: ${(0, utils_1.getErrorMessage)(error)}`);
|
|
308
|
+
}
|
|
309
|
+
interval = this._retryTimeout;
|
|
310
|
+
}
|
|
311
|
+
if (!this._isRunning) {
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
this._clearPollingTimeout();
|
|
315
|
+
const timeoutRef = setTimeout(() => {
|
|
316
|
+
// Intentionally not awaited as this just continues the polling loop.
|
|
317
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
318
|
+
this._updateAndQueue();
|
|
319
|
+
}, interval);
|
|
320
|
+
if (timeoutRef.unref && !this._keepEventLoopActive) {
|
|
321
|
+
timeoutRef.unref();
|
|
322
|
+
}
|
|
323
|
+
this._pollingTimeout = timeoutRef;
|
|
324
|
+
this.emit('_waitingForNextIteration');
|
|
325
|
+
}
|
|
326
|
+
_clearPollingTimeout() {
|
|
327
|
+
if (this._pollingTimeout) {
|
|
328
|
+
clearTimeout(this._pollingTimeout);
|
|
329
|
+
this._pollingTimeout = undefined;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
exports.PollingBlockTracker = PollingBlockTracker;
|
|
334
|
+
_PollingBlockTracker_internalEventListeners = new WeakMap(), _PollingBlockTracker_pendingLatestBlock = new WeakMap(), _PollingBlockTracker_pendingFetch = new WeakMap(), _PollingBlockTracker_instances = new WeakSet(), _PollingBlockTracker_addInternalListener = function _PollingBlockTracker_addInternalListener(listener) {
|
|
335
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_internalEventListeners, "f").push(listener);
|
|
336
|
+
}, _PollingBlockTracker_removeInternalListener = function _PollingBlockTracker_removeInternalListener(listener) {
|
|
337
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_internalEventListeners, "f").splice(__classPrivateFieldGet(this, _PollingBlockTracker_internalEventListeners, "f").indexOf(listener), 1);
|
|
338
|
+
}, _PollingBlockTracker_rejectPendingLatestBlock = function _PollingBlockTracker_rejectPendingLatestBlock(error) {
|
|
339
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_pendingLatestBlock, "f")?.reject(error);
|
|
340
|
+
__classPrivateFieldSet(this, _PollingBlockTracker_pendingLatestBlock, undefined, "f");
|
|
341
|
+
};
|
|
342
|
+
/**
|
|
343
|
+
* Converts a number represented as a string in hexadecimal format into a native
|
|
344
|
+
* number.
|
|
345
|
+
*
|
|
346
|
+
* @param hexInt - The hex string.
|
|
347
|
+
* @returns The number.
|
|
348
|
+
*/
|
|
349
|
+
function hexToInt(hexInt) {
|
|
350
|
+
return Number.parseInt(hexInt, 16);
|
|
351
|
+
}
|
|
352
|
+
//# sourceMappingURL=PollingBlockTracker.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PollingBlockTracker.cjs","sourceRoot":"","sources":["../src/PollingBlockTracker.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SafeEventEmitterProvider } from '@metamask/eth-json-rpc-provider';\nimport SafeEventEmitter from '@metamask/safe-event-emitter';\nimport {\n createDeferredPromise,\n type DeferredPromise,\n getErrorMessage,\n type JsonRpcRequest,\n} from '@metamask/utils';\nimport getCreateRandomId from 'json-rpc-random-id';\n\nimport type { BlockTracker } from './BlockTracker';\nimport { projectLogger, createModuleLogger } from './logging-utils';\n\nconst log = createModuleLogger(projectLogger, 'polling-block-tracker');\nconst createRandomId = getCreateRandomId();\nconst sec = 1000;\n\nconst blockTrackerEvents: (string | symbol)[] = ['sync', 'latest'];\n\nexport type PollingBlockTrackerOptions = {\n provider?: SafeEventEmitterProvider;\n pollingInterval?: number;\n retryTimeout?: number;\n keepEventLoopActive?: boolean;\n setSkipCacheFlag?: boolean;\n blockResetDuration?: number;\n usePastBlocks?: boolean;\n};\n\ntype ExtendedJsonRpcRequest = {\n skipCache?: boolean;\n} & JsonRpcRequest<[]>;\n\ntype InternalListener = (value: string) => void;\n\nexport class PollingBlockTracker\n extends SafeEventEmitter\n implements BlockTracker\n{\n private _isRunning: boolean;\n\n private readonly _blockResetDuration: number;\n\n private readonly _usePastBlocks: boolean;\n\n private _currentBlock: string | null;\n\n private _blockResetTimeout?: ReturnType<typeof setTimeout>;\n\n private _pollingTimeout?: ReturnType<typeof setTimeout>;\n\n private readonly _provider: SafeEventEmitterProvider;\n\n private readonly _pollingInterval: number;\n\n private readonly _retryTimeout: number;\n\n private readonly _keepEventLoopActive: boolean;\n\n private readonly _setSkipCacheFlag: boolean;\n\n readonly #internalEventListeners: InternalListener[] = [];\n\n #pendingLatestBlock?: Omit<DeferredPromise<string>, 'resolve'>;\n\n #pendingFetch?: Omit<DeferredPromise<string>, 'resolve'>;\n\n constructor(opts: PollingBlockTrackerOptions = {}) {\n // parse + validate args\n if (!opts.provider) {\n throw new Error('PollingBlockTracker - no provider specified.');\n }\n\n super();\n\n // config\n this._blockResetDuration = opts.blockResetDuration || 20 * sec;\n this._usePastBlocks = opts.usePastBlocks || false;\n // state\n this._currentBlock = null;\n this._isRunning = false;\n\n // bind functions for internal use\n this._onNewListener = this._onNewListener.bind(this);\n this._onRemoveListener = this._onRemoveListener.bind(this);\n this._resetCurrentBlock = this._resetCurrentBlock.bind(this);\n\n // listen for handler changes\n this._setupInternalEvents();\n\n // config\n this._provider = opts.provider;\n this._pollingInterval = opts.pollingInterval || 20 * sec;\n this._retryTimeout = opts.retryTimeout || this._pollingInterval / 10;\n this._keepEventLoopActive =\n opts.keepEventLoopActive === undefined ? true : opts.keepEventLoopActive;\n this._setSkipCacheFlag = opts.setSkipCacheFlag || false;\n }\n\n async destroy() {\n this._cancelBlockResetTimeout();\n super.removeAllListeners();\n this._maybeEnd();\n }\n\n isRunning(): boolean {\n return this._isRunning;\n }\n\n getCurrentBlock(): string | null {\n return this._currentBlock;\n }\n\n async getLatestBlock({\n useCache = true,\n }: { useCache?: boolean } = {}): Promise<string> {\n // return if available\n if (this._currentBlock && useCache) {\n return this._currentBlock;\n }\n\n if (this.#pendingLatestBlock) {\n return await this.#pendingLatestBlock.promise;\n }\n\n const { promise, resolve, reject } = createDeferredPromise<string>({\n suppressUnhandledRejection: true,\n });\n this.#pendingLatestBlock = { reject, promise };\n\n if (this._isRunning) {\n try {\n // If tracker is running, wait for next block with timeout\n const onLatestBlock = (value: string) => {\n this.#removeInternalListener(onLatestBlock);\n this.removeListener('latest', onLatestBlock);\n resolve(value);\n };\n\n this.#addInternalListener(onLatestBlock);\n this.once('latest', onLatestBlock);\n\n return await promise;\n } catch (error) {\n reject(error);\n throw error;\n } finally {\n this.#pendingLatestBlock = undefined;\n }\n } else {\n // If tracker isn't running, just fetch directly\n try {\n const latestBlock = await this._updateLatestBlock();\n resolve(latestBlock);\n return latestBlock;\n } catch (error) {\n reject(error);\n throw error;\n } finally {\n // We want to rate limit calls to this method if we made a direct fetch\n // for the block number because the BlockTracker was not running. We\n // achieve this by delaying the unsetting of the #pendingLatestBlock promise.\n setTimeout(() => {\n this.#pendingLatestBlock = undefined;\n }, this._pollingInterval);\n }\n }\n }\n\n // dont allow module consumer to remove our internal event listeners\n removeAllListeners(eventName?: string | symbol) {\n // perform default behavior, preserve fn arity\n if (eventName) {\n super.removeAllListeners(eventName);\n } else {\n super.removeAllListeners();\n }\n\n // re-add internal events\n this._setupInternalEvents();\n // trigger stop check just in case\n this._onRemoveListener();\n\n return this;\n }\n\n private _setupInternalEvents(): void {\n // first remove listeners for idempotence\n this.removeListener('newListener', this._onNewListener);\n this.removeListener('removeListener', this._onRemoveListener);\n // then add them\n this.on('newListener', this._onNewListener);\n this.on('removeListener', this._onRemoveListener);\n }\n\n private _onNewListener(eventName: string | symbol): void {\n // `newListener` is called *before* the listener is added\n if (blockTrackerEvents.includes(eventName)) {\n // TODO: Handle dangling promise\n this._maybeStart();\n }\n }\n\n private _onRemoveListener(): void {\n // `removeListener` is called *after* the listener is removed\n if (this._getBlockTrackerEventCount() > 0) {\n return;\n }\n this._maybeEnd();\n }\n\n private _maybeStart() {\n if (this._isRunning) {\n return;\n }\n\n this._isRunning = true;\n // cancel setting latest block to stale\n this._cancelBlockResetTimeout();\n this._start();\n this.emit('_started');\n }\n\n private _maybeEnd() {\n if (!this._isRunning) {\n return;\n }\n\n this._isRunning = false;\n this._setupBlockResetTimeout();\n this._end();\n this.#rejectPendingLatestBlock(new Error('Block tracker destroyed'));\n this.emit('_ended');\n }\n\n private _getBlockTrackerEventCount(): number {\n return (\n blockTrackerEvents\n .map((eventName) => this.listeners(eventName))\n .flat()\n // internal listeners are not included in the count\n .filter((listener) =>\n this.#internalEventListeners.every(\n (internalListener) => !Object.is(internalListener, listener),\n ),\n ).length\n );\n }\n\n private _shouldUseNewBlock(newBlock: string) {\n const currentBlock = this._currentBlock;\n if (!currentBlock) {\n return true;\n }\n const newBlockInt = hexToInt(newBlock);\n const currentBlockInt = hexToInt(currentBlock);\n\n return (\n (this._usePastBlocks && newBlockInt < currentBlockInt) ||\n newBlockInt > currentBlockInt\n );\n }\n\n private _newPotentialLatest(newBlock: string): void {\n if (!this._shouldUseNewBlock(newBlock)) {\n return;\n }\n this._setCurrentBlock(newBlock);\n }\n\n private _setCurrentBlock(newBlock: string): void {\n const oldBlock = this._currentBlock;\n this._currentBlock = newBlock;\n this.emit('latest', newBlock);\n this.emit('sync', { oldBlock, newBlock });\n }\n\n private _setupBlockResetTimeout(): void {\n // clear any existing timeout\n this._cancelBlockResetTimeout();\n // clear latest block when stale\n this._blockResetTimeout = setTimeout(\n this._resetCurrentBlock,\n this._blockResetDuration,\n );\n\n // nodejs - dont hold process open\n if (this._blockResetTimeout.unref) {\n this._blockResetTimeout.unref();\n }\n }\n\n private _cancelBlockResetTimeout(): void {\n if (this._blockResetTimeout) {\n clearTimeout(this._blockResetTimeout);\n }\n }\n\n private _resetCurrentBlock(): void {\n this._currentBlock = null;\n }\n\n /**\n * Checks for the latest block, updates the internal state, and returns the\n * value immediately rather than waiting for the next polling interval.\n *\n * @deprecated Use {@link getLatestBlock} instead.\n * @returns A promise that resolves to the latest block number.\n */\n async checkForLatestBlock() {\n await this._updateLatestBlock();\n return await this.getLatestBlock();\n }\n\n private _start() {\n // Intentionally not awaited as this starts the polling via a timeout chain.\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this._updateAndQueue();\n }\n\n private _end() {\n this._clearPollingTimeout();\n }\n\n private async _updateLatestBlock(): Promise<string> {\n // fetch + set latest block\n const latestBlock = await this._fetchLatestBlock();\n this._newPotentialLatest(latestBlock);\n\n if (!this._isRunning) {\n // Ensure the one-time update is eventually reset once it's stale\n this._setupBlockResetTimeout();\n }\n\n // _newPotentialLatest() ensures that this._currentBlock is not null\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return this._currentBlock!;\n }\n\n private async _fetchLatestBlock(): Promise<string> {\n // If there's already a pending fetch, reuse it\n if (this.#pendingFetch) {\n return await this.#pendingFetch.promise;\n }\n\n // Create a new deferred promise for this request\n const { promise, resolve, reject } = createDeferredPromise<string>({\n suppressUnhandledRejection: true,\n });\n this.#pendingFetch = { reject, promise };\n\n try {\n const req: ExtendedJsonRpcRequest = {\n jsonrpc: '2.0',\n id: createRandomId(),\n method: 'eth_blockNumber',\n params: [] as [],\n };\n if (this._setSkipCacheFlag) {\n req.skipCache = true;\n }\n\n log('Making request', req);\n const result = await this._provider.request<[], string>(req);\n log('Got result', result);\n resolve(result);\n return result;\n } catch (error) {\n log('Encountered error fetching block', getErrorMessage(error));\n reject(error);\n this.#rejectPendingLatestBlock(error);\n throw error;\n } finally {\n this.#pendingFetch = undefined;\n }\n }\n\n /**\n * The core polling function that runs after each interval.\n * Updates the latest block and then queues the next update.\n */\n private async _updateAndQueue() {\n let interval = this._pollingInterval;\n\n try {\n await this._updateLatestBlock();\n } catch (error: unknown) {\n try {\n this.emit('error', error);\n } catch {\n console.error(`Error updating latest block: ${getErrorMessage(error)}`);\n }\n\n interval = this._retryTimeout;\n }\n\n if (!this._isRunning) {\n return;\n }\n\n this._clearPollingTimeout();\n\n const timeoutRef = setTimeout(() => {\n // Intentionally not awaited as this just continues the polling loop.\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n this._updateAndQueue();\n }, interval);\n\n if (timeoutRef.unref && !this._keepEventLoopActive) {\n timeoutRef.unref();\n }\n\n this._pollingTimeout = timeoutRef;\n\n this.emit('_waitingForNextIteration');\n }\n\n _clearPollingTimeout() {\n if (this._pollingTimeout) {\n clearTimeout(this._pollingTimeout);\n this._pollingTimeout = undefined;\n }\n }\n\n #addInternalListener(listener: InternalListener) {\n this.#internalEventListeners.push(listener);\n }\n\n #removeInternalListener(listener: InternalListener) {\n this.#internalEventListeners.splice(\n this.#internalEventListeners.indexOf(listener),\n 1,\n );\n }\n\n #rejectPendingLatestBlock(error: unknown) {\n this.#pendingLatestBlock?.reject(error);\n this.#pendingLatestBlock = undefined;\n }\n}\n\n/**\n * Converts a number represented as a string in hexadecimal format into a native\n * number.\n *\n * @param hexInt - The hex string.\n * @returns The number.\n */\nfunction hexToInt(hexInt: string): number {\n return Number.parseInt(hexInt, 16);\n}\n"]}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { SafeEventEmitterProvider } from "@metamask/eth-json-rpc-provider";
|
|
2
|
+
import SafeEventEmitter from "@metamask/safe-event-emitter";
|
|
3
|
+
import type { BlockTracker } from "./BlockTracker.cjs";
|
|
4
|
+
export type PollingBlockTrackerOptions = {
|
|
5
|
+
provider?: SafeEventEmitterProvider;
|
|
6
|
+
pollingInterval?: number;
|
|
7
|
+
retryTimeout?: number;
|
|
8
|
+
keepEventLoopActive?: boolean;
|
|
9
|
+
setSkipCacheFlag?: boolean;
|
|
10
|
+
blockResetDuration?: number;
|
|
11
|
+
usePastBlocks?: boolean;
|
|
12
|
+
};
|
|
13
|
+
export declare class PollingBlockTracker extends SafeEventEmitter implements BlockTracker {
|
|
14
|
+
#private;
|
|
15
|
+
private _isRunning;
|
|
16
|
+
private readonly _blockResetDuration;
|
|
17
|
+
private readonly _usePastBlocks;
|
|
18
|
+
private _currentBlock;
|
|
19
|
+
private _blockResetTimeout?;
|
|
20
|
+
private _pollingTimeout?;
|
|
21
|
+
private readonly _provider;
|
|
22
|
+
private readonly _pollingInterval;
|
|
23
|
+
private readonly _retryTimeout;
|
|
24
|
+
private readonly _keepEventLoopActive;
|
|
25
|
+
private readonly _setSkipCacheFlag;
|
|
26
|
+
constructor(opts?: PollingBlockTrackerOptions);
|
|
27
|
+
destroy(): Promise<void>;
|
|
28
|
+
isRunning(): boolean;
|
|
29
|
+
getCurrentBlock(): string | null;
|
|
30
|
+
getLatestBlock({ useCache, }?: {
|
|
31
|
+
useCache?: boolean;
|
|
32
|
+
}): Promise<string>;
|
|
33
|
+
removeAllListeners(eventName?: string | symbol): this;
|
|
34
|
+
private _setupInternalEvents;
|
|
35
|
+
private _onNewListener;
|
|
36
|
+
private _onRemoveListener;
|
|
37
|
+
private _maybeStart;
|
|
38
|
+
private _maybeEnd;
|
|
39
|
+
private _getBlockTrackerEventCount;
|
|
40
|
+
private _shouldUseNewBlock;
|
|
41
|
+
private _newPotentialLatest;
|
|
42
|
+
private _setCurrentBlock;
|
|
43
|
+
private _setupBlockResetTimeout;
|
|
44
|
+
private _cancelBlockResetTimeout;
|
|
45
|
+
private _resetCurrentBlock;
|
|
46
|
+
/**
|
|
47
|
+
* Checks for the latest block, updates the internal state, and returns the
|
|
48
|
+
* value immediately rather than waiting for the next polling interval.
|
|
49
|
+
*
|
|
50
|
+
* @deprecated Use {@link getLatestBlock} instead.
|
|
51
|
+
* @returns A promise that resolves to the latest block number.
|
|
52
|
+
*/
|
|
53
|
+
checkForLatestBlock(): Promise<string>;
|
|
54
|
+
private _start;
|
|
55
|
+
private _end;
|
|
56
|
+
private _updateLatestBlock;
|
|
57
|
+
private _fetchLatestBlock;
|
|
58
|
+
/**
|
|
59
|
+
* The core polling function that runs after each interval.
|
|
60
|
+
* Updates the latest block and then queues the next update.
|
|
61
|
+
*/
|
|
62
|
+
private _updateAndQueue;
|
|
63
|
+
_clearPollingTimeout(): void;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=PollingBlockTracker.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PollingBlockTracker.d.cts","sourceRoot":"","sources":["../src/PollingBlockTracker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,wCAAwC;AAChF,OAAO,gBAAgB,qCAAqC;AAS5D,OAAO,KAAK,EAAE,YAAY,EAAE,2BAAuB;AASnD,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,CAAC,EAAE,wBAAwB,CAAC;IACpC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAQF,qBAAa,mBACX,SAAQ,gBACR,YAAW,YAAY;;IAEvB,OAAO,CAAC,UAAU,CAAU;IAE5B,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IAE7C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAU;IAEzC,OAAO,CAAC,aAAa,CAAgB;IAErC,OAAO,CAAC,kBAAkB,CAAC,CAAgC;IAE3D,OAAO,CAAC,eAAe,CAAC,CAAgC;IAExD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA2B;IAErD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAE1C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IAEvC,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAU;IAE/C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAU;gBAQhC,IAAI,GAAE,0BAA+B;IAgC3C,OAAO;IAMb,SAAS,IAAI,OAAO;IAIpB,eAAe,IAAI,MAAM,GAAG,IAAI;IAI1B,cAAc,CAAC,EACnB,QAAe,GAChB,GAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,OAAO,CAAC,MAAM,CAAC;IAuDhD,kBAAkB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM;IAgB9C,OAAO,CAAC,oBAAoB;IAS5B,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,WAAW;IAYnB,OAAO,CAAC,SAAS;IAYjB,OAAO,CAAC,0BAA0B;IAclC,OAAO,CAAC,kBAAkB;IAc1B,OAAO,CAAC,mBAAmB;IAO3B,OAAO,CAAC,gBAAgB;IAOxB,OAAO,CAAC,uBAAuB;IAe/B,OAAO,CAAC,wBAAwB;IAMhC,OAAO,CAAC,kBAAkB;IAI1B;;;;;;OAMG;IACG,mBAAmB;IAKzB,OAAO,CAAC,MAAM;IAMd,OAAO,CAAC,IAAI;YAIE,kBAAkB;YAelB,iBAAiB;IAsC/B;;;OAGG;YACW,eAAe;IAoC7B,oBAAoB;CAsBrB"}
|