@metamask-previews/eth-block-tracker 15.0.0-preview-565dfca2 → 15.0.0-preview-3fa1672
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/dist/PollingBlockTracker.cjs +205 -209
- package/dist/PollingBlockTracker.cjs.map +1 -1
- package/dist/PollingBlockTracker.d.cts +0 -33
- package/dist/PollingBlockTracker.d.cts.map +1 -1
- package/dist/PollingBlockTracker.d.mts +0 -33
- package/dist/PollingBlockTracker.d.mts.map +1 -1
- package/dist/PollingBlockTracker.mjs +204 -208
- package/dist/PollingBlockTracker.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1,19 +1,19 @@
|
|
|
1
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
2
|
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
8
3
|
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
9
4
|
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
10
5
|
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
6
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
12
7
|
};
|
|
8
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
9
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
10
|
+
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");
|
|
11
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
|
+
};
|
|
13
13
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
14
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
15
|
};
|
|
16
|
-
var _PollingBlockTracker_instances, _PollingBlockTracker_internalEventListeners, _PollingBlockTracker_pendingLatestBlock, _PollingBlockTracker_pendingFetch, _PollingBlockTracker_addInternalListener, _PollingBlockTracker_removeInternalListener, _PollingBlockTracker_rejectPendingLatestBlock;
|
|
16
|
+
var _PollingBlockTracker_instances, _PollingBlockTracker_isRunning, _PollingBlockTracker_blockResetDuration, _PollingBlockTracker_usePastBlocks, _PollingBlockTracker_currentBlock, _PollingBlockTracker_blockResetTimeout, _PollingBlockTracker_pollingTimeout, _PollingBlockTracker_provider, _PollingBlockTracker_pollingInterval, _PollingBlockTracker_retryTimeout, _PollingBlockTracker_keepEventLoopActive, _PollingBlockTracker_setSkipCacheFlag, _PollingBlockTracker_internalEventListeners, _PollingBlockTracker_pendingLatestBlock, _PollingBlockTracker_pendingFetch, _PollingBlockTracker_onNewListener, _PollingBlockTracker_onRemoveListener, _PollingBlockTracker_resetCurrentBlock, _PollingBlockTracker_setupInternalEvents, _PollingBlockTracker_onNewListenerUnbound, _PollingBlockTracker_onRemoveListenerUnbound, _PollingBlockTracker_maybeStart, _PollingBlockTracker_maybeEnd, _PollingBlockTracker_getBlockTrackerEventCount, _PollingBlockTracker_shouldUseNewBlock, _PollingBlockTracker_newPotentialLatest, _PollingBlockTracker_setCurrentBlock, _PollingBlockTracker_setupBlockResetTimeout, _PollingBlockTracker_cancelBlockResetTimeout, _PollingBlockTracker_resetCurrentBlockUnbound, _PollingBlockTracker_start, _PollingBlockTracker_end, _PollingBlockTracker_updateLatestBlock, _PollingBlockTracker_fetchLatestBlock, _PollingBlockTracker_updateAndQueue, _PollingBlockTracker_clearPollingTimeout, _PollingBlockTracker_addInternalListener, _PollingBlockTracker_removeInternalListener, _PollingBlockTracker_rejectPendingLatestBlock;
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
exports.PollingBlockTracker = void 0;
|
|
19
19
|
const safe_event_emitter_1 = __importDefault(require("@metamask/safe-event-emitter"));
|
|
@@ -32,44 +32,57 @@ class PollingBlockTracker extends safe_event_emitter_1.default {
|
|
|
32
32
|
}
|
|
33
33
|
super();
|
|
34
34
|
_PollingBlockTracker_instances.add(this);
|
|
35
|
+
_PollingBlockTracker_isRunning.set(this, void 0);
|
|
36
|
+
_PollingBlockTracker_blockResetDuration.set(this, void 0);
|
|
37
|
+
_PollingBlockTracker_usePastBlocks.set(this, void 0);
|
|
38
|
+
_PollingBlockTracker_currentBlock.set(this, void 0);
|
|
39
|
+
_PollingBlockTracker_blockResetTimeout.set(this, void 0);
|
|
40
|
+
_PollingBlockTracker_pollingTimeout.set(this, void 0);
|
|
41
|
+
_PollingBlockTracker_provider.set(this, void 0);
|
|
42
|
+
_PollingBlockTracker_pollingInterval.set(this, void 0);
|
|
43
|
+
_PollingBlockTracker_retryTimeout.set(this, void 0);
|
|
44
|
+
_PollingBlockTracker_keepEventLoopActive.set(this, void 0);
|
|
45
|
+
_PollingBlockTracker_setSkipCacheFlag.set(this, void 0);
|
|
35
46
|
_PollingBlockTracker_internalEventListeners.set(this, []);
|
|
36
47
|
_PollingBlockTracker_pendingLatestBlock.set(this, void 0);
|
|
37
48
|
_PollingBlockTracker_pendingFetch.set(this, void 0);
|
|
49
|
+
_PollingBlockTracker_onNewListener.set(this, void 0);
|
|
50
|
+
_PollingBlockTracker_onRemoveListener.set(this, void 0);
|
|
51
|
+
_PollingBlockTracker_resetCurrentBlock.set(this, void 0);
|
|
38
52
|
// config
|
|
39
|
-
this
|
|
40
|
-
this
|
|
53
|
+
__classPrivateFieldSet(this, _PollingBlockTracker_blockResetDuration, opts.blockResetDuration ?? 20 * sec, "f");
|
|
54
|
+
__classPrivateFieldSet(this, _PollingBlockTracker_usePastBlocks, opts.usePastBlocks ?? false, "f");
|
|
41
55
|
// state
|
|
42
|
-
this
|
|
43
|
-
this
|
|
56
|
+
__classPrivateFieldSet(this, _PollingBlockTracker_currentBlock, null, "f");
|
|
57
|
+
__classPrivateFieldSet(this, _PollingBlockTracker_isRunning, false, "f");
|
|
44
58
|
// bind functions for internal use
|
|
45
|
-
this
|
|
46
|
-
this
|
|
47
|
-
this
|
|
59
|
+
__classPrivateFieldSet(this, _PollingBlockTracker_onNewListener, __classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_onNewListenerUnbound).bind(this), "f");
|
|
60
|
+
__classPrivateFieldSet(this, _PollingBlockTracker_onRemoveListener, __classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_onRemoveListenerUnbound).bind(this), "f");
|
|
61
|
+
__classPrivateFieldSet(this, _PollingBlockTracker_resetCurrentBlock, __classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_resetCurrentBlockUnbound).bind(this), "f");
|
|
48
62
|
// listen for handler changes
|
|
49
|
-
this.
|
|
63
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_setupInternalEvents).call(this);
|
|
50
64
|
// config
|
|
51
|
-
this
|
|
52
|
-
this
|
|
53
|
-
this
|
|
54
|
-
this.
|
|
55
|
-
|
|
56
|
-
this._setSkipCacheFlag = opts.setSkipCacheFlag || false;
|
|
65
|
+
__classPrivateFieldSet(this, _PollingBlockTracker_provider, opts.provider, "f");
|
|
66
|
+
__classPrivateFieldSet(this, _PollingBlockTracker_pollingInterval, opts.pollingInterval ?? 20 * sec, "f");
|
|
67
|
+
__classPrivateFieldSet(this, _PollingBlockTracker_retryTimeout, opts.retryTimeout ?? __classPrivateFieldGet(this, _PollingBlockTracker_pollingInterval, "f") / 10, "f");
|
|
68
|
+
__classPrivateFieldSet(this, _PollingBlockTracker_keepEventLoopActive, opts.keepEventLoopActive ?? true, "f");
|
|
69
|
+
__classPrivateFieldSet(this, _PollingBlockTracker_setSkipCacheFlag, opts.setSkipCacheFlag ?? false, "f");
|
|
57
70
|
}
|
|
58
71
|
async destroy() {
|
|
59
|
-
this.
|
|
72
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_cancelBlockResetTimeout).call(this);
|
|
60
73
|
super.removeAllListeners();
|
|
61
|
-
this.
|
|
74
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_maybeEnd).call(this);
|
|
62
75
|
}
|
|
63
76
|
isRunning() {
|
|
64
|
-
return this
|
|
77
|
+
return __classPrivateFieldGet(this, _PollingBlockTracker_isRunning, "f");
|
|
65
78
|
}
|
|
66
79
|
getCurrentBlock() {
|
|
67
|
-
return this
|
|
80
|
+
return __classPrivateFieldGet(this, _PollingBlockTracker_currentBlock, "f");
|
|
68
81
|
}
|
|
69
82
|
async getLatestBlock({ useCache = true, } = {}) {
|
|
70
83
|
// return if available
|
|
71
|
-
if (this
|
|
72
|
-
return this
|
|
84
|
+
if (__classPrivateFieldGet(this, _PollingBlockTracker_currentBlock, "f") && useCache) {
|
|
85
|
+
return __classPrivateFieldGet(this, _PollingBlockTracker_currentBlock, "f");
|
|
73
86
|
}
|
|
74
87
|
if (__classPrivateFieldGet(this, _PollingBlockTracker_pendingLatestBlock, "f")) {
|
|
75
88
|
return await __classPrivateFieldGet(this, _PollingBlockTracker_pendingLatestBlock, "f").promise;
|
|
@@ -78,7 +91,7 @@ class PollingBlockTracker extends safe_event_emitter_1.default {
|
|
|
78
91
|
suppressUnhandledRejection: true,
|
|
79
92
|
});
|
|
80
93
|
__classPrivateFieldSet(this, _PollingBlockTracker_pendingLatestBlock, { reject, promise }, "f");
|
|
81
|
-
if (this
|
|
94
|
+
if (__classPrivateFieldGet(this, _PollingBlockTracker_isRunning, "f")) {
|
|
82
95
|
try {
|
|
83
96
|
// If tracker is running, wait for next block with timeout
|
|
84
97
|
const onLatestBlock = (value) => {
|
|
@@ -101,7 +114,7 @@ class PollingBlockTracker extends safe_event_emitter_1.default {
|
|
|
101
114
|
else {
|
|
102
115
|
// If tracker isn't running, just fetch directly
|
|
103
116
|
try {
|
|
104
|
-
const latestBlock = await this.
|
|
117
|
+
const latestBlock = await __classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_updateLatestBlock).call(this);
|
|
105
118
|
resolve(latestBlock);
|
|
106
119
|
return latestBlock;
|
|
107
120
|
}
|
|
@@ -115,11 +128,11 @@ class PollingBlockTracker extends safe_event_emitter_1.default {
|
|
|
115
128
|
// achieve this by delaying the unsetting of the #pendingLatestBlock promise.
|
|
116
129
|
setTimeout(() => {
|
|
117
130
|
__classPrivateFieldSet(this, _PollingBlockTracker_pendingLatestBlock, undefined, "f");
|
|
118
|
-
}, this
|
|
131
|
+
}, __classPrivateFieldGet(this, _PollingBlockTracker_pollingInterval, "f"));
|
|
119
132
|
}
|
|
120
133
|
}
|
|
121
134
|
}
|
|
122
|
-
//
|
|
135
|
+
// Don't allow module consumer to remove our internal event listeners.
|
|
123
136
|
removeAllListeners(eventName) {
|
|
124
137
|
// perform default behavior, preserve fn arity
|
|
125
138
|
if (eventName) {
|
|
@@ -129,209 +142,192 @@ class PollingBlockTracker extends safe_event_emitter_1.default {
|
|
|
129
142
|
super.removeAllListeners();
|
|
130
143
|
}
|
|
131
144
|
// re-add internal events
|
|
132
|
-
this.
|
|
145
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_setupInternalEvents).call(this);
|
|
133
146
|
// trigger stop check just in case
|
|
134
|
-
this.
|
|
147
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_onRemoveListener, "f").call(this);
|
|
135
148
|
return this;
|
|
136
149
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
if (blockTrackerEvents.includes(eventName)) {
|
|
148
|
-
// TODO: Handle dangling promise
|
|
149
|
-
this._maybeStart();
|
|
150
|
-
}
|
|
150
|
+
/**
|
|
151
|
+
* Checks for the latest block, updates the internal state, and returns the
|
|
152
|
+
* value immediately rather than waiting for the next polling interval.
|
|
153
|
+
*
|
|
154
|
+
* @deprecated Use {@link getLatestBlock} instead.
|
|
155
|
+
* @returns A promise that resolves to the latest block number.
|
|
156
|
+
*/
|
|
157
|
+
async checkForLatestBlock() {
|
|
158
|
+
await __classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_updateLatestBlock).call(this);
|
|
159
|
+
return await this.getLatestBlock();
|
|
151
160
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
161
|
+
}
|
|
162
|
+
exports.PollingBlockTracker = PollingBlockTracker;
|
|
163
|
+
_PollingBlockTracker_isRunning = new WeakMap(), _PollingBlockTracker_blockResetDuration = new WeakMap(), _PollingBlockTracker_usePastBlocks = new WeakMap(), _PollingBlockTracker_currentBlock = new WeakMap(), _PollingBlockTracker_blockResetTimeout = new WeakMap(), _PollingBlockTracker_pollingTimeout = new WeakMap(), _PollingBlockTracker_provider = new WeakMap(), _PollingBlockTracker_pollingInterval = new WeakMap(), _PollingBlockTracker_retryTimeout = new WeakMap(), _PollingBlockTracker_keepEventLoopActive = new WeakMap(), _PollingBlockTracker_setSkipCacheFlag = new WeakMap(), _PollingBlockTracker_internalEventListeners = new WeakMap(), _PollingBlockTracker_pendingLatestBlock = new WeakMap(), _PollingBlockTracker_pendingFetch = new WeakMap(), _PollingBlockTracker_onNewListener = new WeakMap(), _PollingBlockTracker_onRemoveListener = new WeakMap(), _PollingBlockTracker_resetCurrentBlock = new WeakMap(), _PollingBlockTracker_instances = new WeakSet(), _PollingBlockTracker_setupInternalEvents = function _PollingBlockTracker_setupInternalEvents() {
|
|
164
|
+
// first remove listeners for idempotence
|
|
165
|
+
this.removeListener('newListener', __classPrivateFieldGet(this, _PollingBlockTracker_onNewListener, "f"));
|
|
166
|
+
this.removeListener('removeListener', __classPrivateFieldGet(this, _PollingBlockTracker_onRemoveListener, "f"));
|
|
167
|
+
// then add them
|
|
168
|
+
this.on('newListener', __classPrivateFieldGet(this, _PollingBlockTracker_onNewListener, "f"));
|
|
169
|
+
this.on('removeListener', __classPrivateFieldGet(this, _PollingBlockTracker_onRemoveListener, "f"));
|
|
170
|
+
}, _PollingBlockTracker_onNewListenerUnbound = function _PollingBlockTracker_onNewListenerUnbound(eventName) {
|
|
171
|
+
// `newListener` is called *before* the listener is added
|
|
172
|
+
if (blockTrackerEvents.includes(eventName)) {
|
|
173
|
+
// TODO: Handle dangling promise
|
|
174
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_maybeStart).call(this);
|
|
158
175
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
this._isRunning = true;
|
|
164
|
-
// cancel setting latest block to stale
|
|
165
|
-
this._cancelBlockResetTimeout();
|
|
166
|
-
this._start();
|
|
167
|
-
this.emit('_started');
|
|
176
|
+
}, _PollingBlockTracker_onRemoveListenerUnbound = function _PollingBlockTracker_onRemoveListenerUnbound() {
|
|
177
|
+
// `removeListener` is called *after* the listener is removed
|
|
178
|
+
if (__classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_getBlockTrackerEventCount).call(this) > 0) {
|
|
179
|
+
return;
|
|
168
180
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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');
|
|
181
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_maybeEnd).call(this);
|
|
182
|
+
}, _PollingBlockTracker_maybeStart = function _PollingBlockTracker_maybeStart() {
|
|
183
|
+
if (__classPrivateFieldGet(this, _PollingBlockTracker_isRunning, "f")) {
|
|
184
|
+
return;
|
|
178
185
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
186
|
+
__classPrivateFieldSet(this, _PollingBlockTracker_isRunning, true, "f");
|
|
187
|
+
// cancel setting latest block to stale
|
|
188
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_cancelBlockResetTimeout).call(this);
|
|
189
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_start).call(this);
|
|
190
|
+
this.emit('_started');
|
|
191
|
+
}, _PollingBlockTracker_maybeEnd = function _PollingBlockTracker_maybeEnd() {
|
|
192
|
+
if (!__classPrivateFieldGet(this, _PollingBlockTracker_isRunning, "f")) {
|
|
193
|
+
return;
|
|
185
194
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
+
__classPrivateFieldSet(this, _PollingBlockTracker_isRunning, false, "f");
|
|
196
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_setupBlockResetTimeout).call(this);
|
|
197
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_end).call(this);
|
|
198
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_rejectPendingLatestBlock).call(this, new Error('Block tracker destroyed'));
|
|
199
|
+
this.emit('_ended');
|
|
200
|
+
}, _PollingBlockTracker_getBlockTrackerEventCount = function _PollingBlockTracker_getBlockTrackerEventCount() {
|
|
201
|
+
return (blockTrackerEvents
|
|
202
|
+
.map((eventName) => this.listeners(eventName))
|
|
203
|
+
.flat()
|
|
204
|
+
// internal listeners are not included in the count
|
|
205
|
+
.filter((listener) => __classPrivateFieldGet(this, _PollingBlockTracker_internalEventListeners, "f").every((internalListener) => !Object.is(internalListener, listener))).length);
|
|
206
|
+
}, _PollingBlockTracker_shouldUseNewBlock = function _PollingBlockTracker_shouldUseNewBlock(newBlock) {
|
|
207
|
+
const currentBlock = __classPrivateFieldGet(this, _PollingBlockTracker_currentBlock, "f");
|
|
208
|
+
if (!currentBlock) {
|
|
209
|
+
return true;
|
|
195
210
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
211
|
+
const newBlockInt = hexToInt(newBlock);
|
|
212
|
+
const currentBlockInt = hexToInt(currentBlock);
|
|
213
|
+
return ((__classPrivateFieldGet(this, _PollingBlockTracker_usePastBlocks, "f") && newBlockInt < currentBlockInt) ||
|
|
214
|
+
newBlockInt > currentBlockInt);
|
|
215
|
+
}, _PollingBlockTracker_newPotentialLatest = function _PollingBlockTracker_newPotentialLatest(newBlock) {
|
|
216
|
+
if (!__classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_shouldUseNewBlock).call(this, newBlock)) {
|
|
217
|
+
return;
|
|
201
218
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
219
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_setCurrentBlock).call(this, newBlock);
|
|
220
|
+
}, _PollingBlockTracker_setCurrentBlock = function _PollingBlockTracker_setCurrentBlock(newBlock) {
|
|
221
|
+
const oldBlock = __classPrivateFieldGet(this, _PollingBlockTracker_currentBlock, "f");
|
|
222
|
+
__classPrivateFieldSet(this, _PollingBlockTracker_currentBlock, newBlock, "f");
|
|
223
|
+
this.emit('latest', newBlock);
|
|
224
|
+
this.emit('sync', { oldBlock, newBlock });
|
|
225
|
+
}, _PollingBlockTracker_setupBlockResetTimeout = function _PollingBlockTracker_setupBlockResetTimeout() {
|
|
226
|
+
// clear any existing timeout
|
|
227
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_cancelBlockResetTimeout).call(this);
|
|
228
|
+
// clear latest block when stale
|
|
229
|
+
__classPrivateFieldSet(this, _PollingBlockTracker_blockResetTimeout, setTimeout(__classPrivateFieldGet(this, _PollingBlockTracker_resetCurrentBlock, "f"), __classPrivateFieldGet(this, _PollingBlockTracker_blockResetDuration, "f")), "f");
|
|
230
|
+
// nodejs - dont hold process open
|
|
231
|
+
if (__classPrivateFieldGet(this, _PollingBlockTracker_blockResetTimeout, "f").unref) {
|
|
232
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_blockResetTimeout, "f").unref();
|
|
207
233
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
this
|
|
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
|
-
}
|
|
234
|
+
}, _PollingBlockTracker_cancelBlockResetTimeout = function _PollingBlockTracker_cancelBlockResetTimeout() {
|
|
235
|
+
if (__classPrivateFieldGet(this, _PollingBlockTracker_blockResetTimeout, "f")) {
|
|
236
|
+
clearTimeout(__classPrivateFieldGet(this, _PollingBlockTracker_blockResetTimeout, "f"));
|
|
217
237
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
238
|
+
}, _PollingBlockTracker_resetCurrentBlockUnbound = function _PollingBlockTracker_resetCurrentBlockUnbound() {
|
|
239
|
+
__classPrivateFieldSet(this, _PollingBlockTracker_currentBlock, null, "f");
|
|
240
|
+
}, _PollingBlockTracker_start = function _PollingBlockTracker_start() {
|
|
241
|
+
// Intentionally not awaited as this starts the polling via a timeout chain.
|
|
242
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
243
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_updateAndQueue).call(this);
|
|
244
|
+
}, _PollingBlockTracker_end = function _PollingBlockTracker_end() {
|
|
245
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_clearPollingTimeout).call(this);
|
|
246
|
+
}, _PollingBlockTracker_updateLatestBlock = async function _PollingBlockTracker_updateLatestBlock() {
|
|
247
|
+
// fetch + set latest block
|
|
248
|
+
const latestBlock = await __classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_fetchLatestBlock).call(this);
|
|
249
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_newPotentialLatest).call(this, latestBlock);
|
|
250
|
+
if (!__classPrivateFieldGet(this, _PollingBlockTracker_isRunning, "f")) {
|
|
251
|
+
// Ensure the one-time update is eventually reset once it's stale
|
|
252
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_setupBlockResetTimeout).call(this);
|
|
222
253
|
}
|
|
223
|
-
|
|
224
|
-
|
|
254
|
+
// _newPotentialLatest() ensures that this._currentBlock is not null
|
|
255
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
256
|
+
return __classPrivateFieldGet(this, _PollingBlockTracker_currentBlock, "f");
|
|
257
|
+
}, _PollingBlockTracker_fetchLatestBlock = async function _PollingBlockTracker_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;
|
|
225
261
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
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 (__classPrivateFieldGet(this, _PollingBlockTracker_setSkipCacheFlag, "f")) {
|
|
275
|
+
req.skipCache = true;
|
|
276
|
+
}
|
|
277
|
+
log('Making request', req);
|
|
278
|
+
const result = await __classPrivateFieldGet(this, _PollingBlockTracker_provider, "f").request(req);
|
|
279
|
+
log('Got result', result);
|
|
280
|
+
resolve(result);
|
|
281
|
+
return result;
|
|
236
282
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
this.
|
|
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;
|
|
241
288
|
}
|
|
242
|
-
|
|
243
|
-
this
|
|
289
|
+
finally {
|
|
290
|
+
__classPrivateFieldSet(this, _PollingBlockTracker_pendingFetch, undefined, "f");
|
|
244
291
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
255
|
-
return this._currentBlock;
|
|
292
|
+
}, _PollingBlockTracker_updateAndQueue =
|
|
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 function _PollingBlockTracker_updateAndQueue() {
|
|
298
|
+
let interval = __classPrivateFieldGet(this, _PollingBlockTracker_pollingInterval, "f");
|
|
299
|
+
try {
|
|
300
|
+
await __classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_updateLatestBlock).call(this);
|
|
256
301
|
}
|
|
257
|
-
|
|
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");
|
|
302
|
+
catch (error) {
|
|
267
303
|
try {
|
|
268
|
-
|
|
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;
|
|
304
|
+
this.emit('error', error);
|
|
282
305
|
}
|
|
283
|
-
catch
|
|
284
|
-
|
|
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");
|
|
306
|
+
catch {
|
|
307
|
+
console.error(`Error updating latest block: ${(0, utils_1.getErrorMessage)(error)}`);
|
|
291
308
|
}
|
|
309
|
+
interval = __classPrivateFieldGet(this, _PollingBlockTracker_retryTimeout, "f");
|
|
292
310
|
}
|
|
293
|
-
|
|
294
|
-
|
|
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');
|
|
311
|
+
if (!__classPrivateFieldGet(this, _PollingBlockTracker_isRunning, "f")) {
|
|
312
|
+
return;
|
|
325
313
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
314
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_clearPollingTimeout).call(this);
|
|
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
|
+
__classPrivateFieldGet(this, _PollingBlockTracker_instances, "m", _PollingBlockTracker_updateAndQueue).call(this);
|
|
319
|
+
}, interval);
|
|
320
|
+
if (timeoutRef.unref && !__classPrivateFieldGet(this, _PollingBlockTracker_keepEventLoopActive, "f")) {
|
|
321
|
+
timeoutRef.unref();
|
|
331
322
|
}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
323
|
+
__classPrivateFieldSet(this, _PollingBlockTracker_pollingTimeout, timeoutRef, "f");
|
|
324
|
+
this.emit('_waitingForNextIteration');
|
|
325
|
+
}, _PollingBlockTracker_clearPollingTimeout = function _PollingBlockTracker_clearPollingTimeout() {
|
|
326
|
+
if (__classPrivateFieldGet(this, _PollingBlockTracker_pollingTimeout, "f")) {
|
|
327
|
+
clearTimeout(__classPrivateFieldGet(this, _PollingBlockTracker_pollingTimeout, "f"));
|
|
328
|
+
__classPrivateFieldSet(this, _PollingBlockTracker_pollingTimeout, undefined, "f");
|
|
329
|
+
}
|
|
330
|
+
}, _PollingBlockTracker_addInternalListener = function _PollingBlockTracker_addInternalListener(listener) {
|
|
335
331
|
__classPrivateFieldGet(this, _PollingBlockTracker_internalEventListeners, "f").push(listener);
|
|
336
332
|
}, _PollingBlockTracker_removeInternalListener = function _PollingBlockTracker_removeInternalListener(listener) {
|
|
337
333
|
__classPrivateFieldGet(this, _PollingBlockTracker_internalEventListeners, "f").splice(__classPrivateFieldGet(this, _PollingBlockTracker_internalEventListeners, "f").indexOf(listener), 1);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PollingBlockTracker.cjs","sourceRoot":"","sources":["../src/PollingBlockTracker.ts"],"names":[],"mappings":"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","sourcesContent":["import type { InternalProvider } from '@metamask/eth-json-rpc-provider';\nimport type {\n ContextConstraint,\n MiddlewareContext,\n} from '@metamask/json-rpc-engine/v2';\nimport SafeEventEmitter from '@metamask/safe-event-emitter';\nimport { createDeferredPromise, getErrorMessage } from '@metamask/utils';\nimport type { DeferredPromise, JsonRpcRequest } 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 Context extends ContextConstraint = MiddlewareContext,\n> = {\n provider?: InternalProvider<Context>;\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 Context extends ContextConstraint = MiddlewareContext,\n >\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: InternalProvider<Context>;\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<Context> = {}) {\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"]}
|
|
1
|
+
{"version":3,"file":"PollingBlockTracker.cjs","sourceRoot":"","sources":["../src/PollingBlockTracker.ts"],"names":[],"mappings":"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","sourcesContent":["import type { InternalProvider } from '@metamask/eth-json-rpc-provider';\nimport type {\n ContextConstraint,\n MiddlewareContext,\n} from '@metamask/json-rpc-engine/v2';\nimport SafeEventEmitter from '@metamask/safe-event-emitter';\nimport { createDeferredPromise, getErrorMessage } from '@metamask/utils';\nimport type { DeferredPromise, JsonRpcRequest } 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 Context extends ContextConstraint = MiddlewareContext,\n> = {\n provider?: InternalProvider<Context>;\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 Context extends ContextConstraint = MiddlewareContext,\n >\n extends SafeEventEmitter\n implements BlockTracker\n{\n #isRunning: boolean;\n\n readonly #blockResetDuration: number;\n\n readonly #usePastBlocks: boolean;\n\n #currentBlock: string | null;\n\n #blockResetTimeout?: ReturnType<typeof setTimeout>;\n\n #pollingTimeout?: ReturnType<typeof setTimeout>;\n\n readonly #provider: InternalProvider<Context>;\n\n readonly #pollingInterval: number;\n\n readonly #retryTimeout: number;\n\n readonly #keepEventLoopActive: boolean;\n\n readonly #setSkipCacheFlag: boolean;\n\n readonly #internalEventListeners: InternalListener[] = [];\n\n #pendingLatestBlock?: Omit<DeferredPromise<string>, 'resolve'>;\n\n #pendingFetch?: Omit<DeferredPromise<string>, 'resolve'>;\n\n readonly #onNewListener: (eventName: string | symbol) => void;\n\n readonly #onRemoveListener: () => void;\n\n readonly #resetCurrentBlock: () => void;\n\n constructor(opts: PollingBlockTrackerOptions<Context> = {}) {\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.#onNewListenerUnbound.bind(this);\n this.#onRemoveListener = this.#onRemoveListenerUnbound.bind(this);\n this.#resetCurrentBlock = this.#resetCurrentBlockUnbound.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 = opts.keepEventLoopActive ?? true;\n this.#setSkipCacheFlag = opts.setSkipCacheFlag ?? false;\n }\n\n async destroy(): Promise<void> {\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): void => {\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 // Don't allow module consumer to remove our internal event listeners.\n removeAllListeners(eventName?: string | symbol): this {\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 #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 #onNewListenerUnbound(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 #onRemoveListenerUnbound(): void {\n // `removeListener` is called *after* the listener is removed\n if (this.#getBlockTrackerEventCount() > 0) {\n return;\n }\n this.#maybeEnd();\n }\n\n #maybeStart(): void {\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 #maybeEnd(): void {\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 #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 #shouldUseNewBlock(newBlock: string): boolean {\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 #newPotentialLatest(newBlock: string): void {\n if (!this.#shouldUseNewBlock(newBlock)) {\n return;\n }\n this.#setCurrentBlock(newBlock);\n }\n\n #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 #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 #cancelBlockResetTimeout(): void {\n if (this.#blockResetTimeout) {\n clearTimeout(this.#blockResetTimeout);\n }\n }\n\n #resetCurrentBlockUnbound(): 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(): Promise<string> {\n await this.#updateLatestBlock();\n return await this.getLatestBlock();\n }\n\n #start(): void {\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 #end(): void {\n this.#clearPollingTimeout();\n }\n\n 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 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 async #updateAndQueue(): Promise<void> {\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(): void {\n if (this.#pollingTimeout) {\n clearTimeout(this.#pollingTimeout);\n this.#pollingTimeout = undefined;\n }\n }\n\n #addInternalListener(listener: InternalListener): void {\n this.#internalEventListeners.push(listener);\n }\n\n #removeInternalListener(listener: InternalListener): void {\n this.#internalEventListeners.splice(\n this.#internalEventListeners.indexOf(listener),\n 1,\n );\n }\n\n #rejectPendingLatestBlock(error: unknown): void {\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"]}
|