UNPKG

@atomiqlabs/chain-evm

Version:

EVM specific base implementation

337 lines (336 loc) 16 kB
"use strict"; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); 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"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); 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"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var _SocketSubscriber_provider, _SocketSubscriber_filter, _SocketSubscriber_filterId, _SocketSubscriber_paused, _SocketSubscriber_emitPromise, _SocketEventSubscriber_logFilter, _SocketProvider_callbacks, _SocketProvider_subs, _SocketProvider_pending, _SocketProvider_connected; Object.defineProperty(exports, "__esModule", { value: true }); exports.SocketProvider = exports.SocketEventSubscriber = exports.SocketPendingSubscriber = exports.SocketBlockSubscriber = exports.SocketSubscriber = void 0; /** * Generic long-lived socket provider. * * Sub-classing notes * - a sub-class MUST call the `_start()` method once connected * - a sub-class MUST override the `_write(string)` method * - a sub-class MUST call `_processMessage(string)` for each message * * @_subsection: api/providers/abstract-provider:Socket Providers [about-socketProvider] */ const ethers_1 = require("ethers"); /** * A **SocketSubscriber** uses a socket transport to handle events and * should use [[_emit]] to manage the events. */ class SocketSubscriber { /** * The filter. */ get filter() { return JSON.parse(__classPrivateFieldGet(this, _SocketSubscriber_filter, "f")); } /** * Creates a new **SocketSubscriber** attached to %%provider%% listening * to %%filter%%. */ constructor(provider, filter) { _SocketSubscriber_provider.set(this, void 0); _SocketSubscriber_filter.set(this, void 0); _SocketSubscriber_filterId.set(this, void 0); _SocketSubscriber_paused.set(this, void 0); _SocketSubscriber_emitPromise.set(this, void 0); __classPrivateFieldSet(this, _SocketSubscriber_provider, provider, "f"); __classPrivateFieldSet(this, _SocketSubscriber_filter, JSON.stringify(filter), "f"); __classPrivateFieldSet(this, _SocketSubscriber_filterId, null, "f"); __classPrivateFieldSet(this, _SocketSubscriber_paused, null, "f"); __classPrivateFieldSet(this, _SocketSubscriber_emitPromise, null, "f"); } start() { __classPrivateFieldSet(this, _SocketSubscriber_filterId, __classPrivateFieldGet(this, _SocketSubscriber_provider, "f").send("eth_subscribe", this.filter).then((filterId) => { ; __classPrivateFieldGet(this, _SocketSubscriber_provider, "f")._register(filterId, this); return filterId; }), "f"); } stop() { (__classPrivateFieldGet(this, _SocketSubscriber_filterId, "f")).then((filterId) => { if (__classPrivateFieldGet(this, _SocketSubscriber_provider, "f").destroyed) { return; } __classPrivateFieldGet(this, _SocketSubscriber_provider, "f").send("eth_unsubscribe", [filterId]); }); __classPrivateFieldSet(this, _SocketSubscriber_filterId, null, "f"); } // @TODO: pause should trap the current blockNumber, unsub, and on resume use getLogs // and resume pause(dropWhilePaused) { (0, ethers_1.assert)(dropWhilePaused, "preserve logs while paused not supported by SocketSubscriber yet", "UNSUPPORTED_OPERATION", { operation: "pause(false)" }); __classPrivateFieldSet(this, _SocketSubscriber_paused, !!dropWhilePaused, "f"); } resume() { __classPrivateFieldSet(this, _SocketSubscriber_paused, null, "f"); } /** * @_ignore: */ _handleMessage(message) { if (__classPrivateFieldGet(this, _SocketSubscriber_filterId, "f") == null) { return; } if (__classPrivateFieldGet(this, _SocketSubscriber_paused, "f") === null) { let emitPromise = __classPrivateFieldGet(this, _SocketSubscriber_emitPromise, "f"); if (emitPromise == null) { emitPromise = this._emit(__classPrivateFieldGet(this, _SocketSubscriber_provider, "f"), message); } else { emitPromise = emitPromise.then(async () => { await this._emit(__classPrivateFieldGet(this, _SocketSubscriber_provider, "f"), message); }); } __classPrivateFieldSet(this, _SocketSubscriber_emitPromise, emitPromise.then(() => { if (__classPrivateFieldGet(this, _SocketSubscriber_emitPromise, "f") === emitPromise) { __classPrivateFieldSet(this, _SocketSubscriber_emitPromise, null, "f"); } }), "f"); } } /** * Sub-classes **must** override this to emit the events on the * provider. */ async _emit(provider, message) { throw new Error("sub-classes must implemente this; _emit"); } } exports.SocketSubscriber = SocketSubscriber; _SocketSubscriber_provider = new WeakMap(), _SocketSubscriber_filter = new WeakMap(), _SocketSubscriber_filterId = new WeakMap(), _SocketSubscriber_paused = new WeakMap(), _SocketSubscriber_emitPromise = new WeakMap(); /** * A **SocketBlockSubscriber** listens for ``newHeads`` events and emits * ``"block"`` events. */ class SocketBlockSubscriber extends SocketSubscriber { /** * @_ignore: */ constructor(provider) { super(provider, ["newHeads"]); } async _emit(provider, message) { provider.emit("block", parseInt(message.number)); } } exports.SocketBlockSubscriber = SocketBlockSubscriber; /** * A **SocketPendingSubscriber** listens for pending transacitons and emits * ``"pending"`` events. */ class SocketPendingSubscriber extends SocketSubscriber { /** * @_ignore: */ constructor(provider) { super(provider, ["newPendingTransactions"]); } async _emit(provider, message) { provider.emit("pending", message); } } exports.SocketPendingSubscriber = SocketPendingSubscriber; /** * A **SocketEventSubscriber** listens for event logs. */ class SocketEventSubscriber extends SocketSubscriber { /** * The filter. */ get logFilter() { return JSON.parse(__classPrivateFieldGet(this, _SocketEventSubscriber_logFilter, "f")); } /** * @_ignore: */ constructor(provider, filter) { super(provider, ["logs", filter]); _SocketEventSubscriber_logFilter.set(this, void 0); __classPrivateFieldSet(this, _SocketEventSubscriber_logFilter, JSON.stringify(filter), "f"); } async _emit(provider, message) { provider.emit(this.logFilter, provider._wrapLog(message, provider._network)); } } exports.SocketEventSubscriber = SocketEventSubscriber; _SocketEventSubscriber_logFilter = new WeakMap(); /** * A **SocketProvider** is backed by a long-lived connection over a * socket, which can subscribe and receive real-time messages over * its communication channel. */ class SocketProvider extends ethers_1.JsonRpcApiProvider { /** * Creates a new **SocketProvider** connected to %%network%%. * * If unspecified, the network will be discovered. */ constructor(network, _options) { // Copy the options const options = Object.assign({}, (_options != null) ? _options : {}); // Support for batches is generally not supported for // connection-base providers; if this changes in the future // the _send should be updated to reflect this (0, ethers_1.assertArgument)(options.batchMaxCount == null || options.batchMaxCount === 1, "sockets-based providers do not support batches", "options.batchMaxCount", _options); options.batchMaxCount = 1; // Socket-based Providers (generally) cannot change their network, // since they have a long-lived connection; but let people override // this if they have just cause. if (options.staticNetwork == null) { options.staticNetwork = true; } super(network, options); this.requestTimeoutSeconds = 10; _SocketProvider_callbacks.set(this, void 0); // Maps each filterId to its subscriber _SocketProvider_subs.set(this, void 0); // If any events come in before a subscriber has finished // registering, queue them _SocketProvider_pending.set(this, void 0); _SocketProvider_connected.set(this, void 0); __classPrivateFieldSet(this, _SocketProvider_callbacks, new Map(), "f"); __classPrivateFieldSet(this, _SocketProvider_subs, new Map(), "f"); __classPrivateFieldSet(this, _SocketProvider_pending, new Map(), "f"); } // This value is only valid after _start has been called /* get _network(): Network { if (this.#network == null) { throw new Error("this shouldn't happen"); } return this.#network.clone(); } */ _getSubscriber(sub) { switch (sub.type) { case "close": return new ethers_1.UnmanagedSubscriber("close"); case "block": return new SocketBlockSubscriber(this); case "pending": return new SocketPendingSubscriber(this); case "event": return new SocketEventSubscriber(this, sub.filter); case "orphan": // Handled auto-matically within AbstractProvider // when the log.removed = true if (sub.filter.orphan === "drop-log") { return new ethers_1.UnmanagedSubscriber("drop-log"); } } return super._getSubscriber(sub); } /** * Register a new subscriber. This is used internalled by Subscribers * and generally is unecessary unless extending capabilities. */ _register(filterId, subscriber) { __classPrivateFieldGet(this, _SocketProvider_subs, "f").set(filterId, subscriber); const pending = __classPrivateFieldGet(this, _SocketProvider_pending, "f").get(filterId); if (pending) { for (const message of pending) { subscriber._handleMessage(message); } __classPrivateFieldGet(this, _SocketProvider_pending, "f").delete(filterId); } } async _send(payload) { // WebSocket provider doesn't accept batches (0, ethers_1.assertArgument)(!Array.isArray(payload), "WebSocket does not support batch send", "payload", payload); if (!__classPrivateFieldGet(this, _SocketProvider_connected, "f") && payload.method === "eth_subscribe") return Promise.reject((0, ethers_1.makeError)("WebSocket not connected!", "NETWORK_ERROR")); // Wait until the socket is connected before writing to it await this._waitUntilReady(); if (!__classPrivateFieldGet(this, _SocketProvider_connected, "f") && payload.method === "eth_subscribe") return Promise.reject((0, ethers_1.makeError)("WebSocket not connected!", "NETWORK_ERROR")); // Prepare a promise to respond to const promise = new Promise((resolve, reject) => { const timeout = setTimeout(() => { if (__classPrivateFieldGet(this, _SocketProvider_callbacks, "f").delete(payload.id)) { reject((0, ethers_1.makeError)("Request timed out!", "NETWORK_ERROR")); } }, this.requestTimeoutSeconds * 1000); __classPrivateFieldGet(this, _SocketProvider_callbacks, "f").set(payload.id, { payload, resolve, reject, timeout }); }); // Write the request to the socket if (__classPrivateFieldGet(this, _SocketProvider_connected, "f")) await this._write(JSON.stringify(payload)); return [await promise]; } _connected() { __classPrivateFieldSet(this, _SocketProvider_connected, true, "f"); this.resume(); this._forEachSubscriber(subscriber => subscriber.start()); __classPrivateFieldGet(this, _SocketProvider_callbacks, "f").forEach(val => { this._write(JSON.stringify(val.payload)); }); } _disconnected() { __classPrivateFieldSet(this, _SocketProvider_connected, false, "f"); this.pause(true); __classPrivateFieldGet(this, _SocketProvider_callbacks, "f").forEach(val => { clearTimeout(val.timeout); val.reject((0, ethers_1.makeError)("WebSocket disconnected!", "NETWORK_ERROR")); }); __classPrivateFieldGet(this, _SocketProvider_callbacks, "f").clear(); } /** * Sub-classes **must** call this with messages received over their * transport to be processed and dispatched. */ async _processMessage(message) { const result = (JSON.parse(message)); if (result && typeof (result) === "object" && "id" in result) { const callback = __classPrivateFieldGet(this, _SocketProvider_callbacks, "f").get(result.id); if (callback == null) { this.emit("error", (0, ethers_1.makeError)("received result for unknown id", "UNKNOWN_ERROR", { reasonCode: "UNKNOWN_ID", result })); return; } __classPrivateFieldGet(this, _SocketProvider_callbacks, "f").delete(result.id); clearTimeout(callback.timeout); callback.resolve(result); } else if (result && result.method === "eth_subscription") { const filterId = result.params.subscription; const subscriber = __classPrivateFieldGet(this, _SocketProvider_subs, "f").get(filterId); if (subscriber) { subscriber._handleMessage(result.params.result); } else { let pending = __classPrivateFieldGet(this, _SocketProvider_pending, "f").get(filterId); if (pending == null) { pending = []; __classPrivateFieldGet(this, _SocketProvider_pending, "f").set(filterId, pending); } pending.push(result.params.result); } } else { this.emit("error", (0, ethers_1.makeError)("received unexpected message", "UNKNOWN_ERROR", { reasonCode: "UNEXPECTED_MESSAGE", result })); return; } } /** * Sub-classes **must** override this to send %%message%% over their * transport. */ async _write(message) { throw new Error("sub-classes must override this"); } } exports.SocketProvider = SocketProvider; _SocketProvider_callbacks = new WeakMap(), _SocketProvider_subs = new WeakMap(), _SocketProvider_pending = new WeakMap(), _SocketProvider_connected = new WeakMap();