From d0ed91840c9f51c7ce9061ebb1d36727dbdd51a4 Mon Sep 17 00:00:00 2001 From: Richard Moore Date: Sat, 4 Feb 2023 03:12:04 -0500 Subject: [PATCH] Fix Subscriber model when removed within emit callback. --- src.ts/providers/abstract-provider.ts | 2 + src.ts/providers/subscriber-connection.ts | 9 ++++ src.ts/providers/subscriber-filterid.ts | 14 +++++- src.ts/providers/subscriber-polling.ts | 21 ++++++++- src.ts/providers/subscriber.ts | 56 ----------------------- 5 files changed, 43 insertions(+), 59 deletions(-) delete mode 100644 src.ts/providers/subscriber.ts diff --git a/src.ts/providers/abstract-provider.ts b/src.ts/providers/abstract-provider.ts index 1478badf79..fb2d64e0d9 100644 --- a/src.ts/providers/abstract-provider.ts +++ b/src.ts/providers/abstract-provider.ts @@ -161,6 +161,8 @@ type Sub = { nameMap: Map addressableMap: WeakMap; listeners: Array<{ listener: Listener, once: boolean }>; + // @TODO: get rid of this, as it is (and has to be) + // tracked in subscriber started: boolean; subscriber: Subscriber; }; diff --git a/src.ts/providers/subscriber-connection.ts b/src.ts/providers/subscriber-connection.ts index 239134f908..2e9f73b38a 100644 --- a/src.ts/providers/subscriber-connection.ts +++ b/src.ts/providers/subscriber-connection.ts @@ -27,15 +27,21 @@ export class BlockConnectionSubscriber implements Subscriber { #provider: ConnectionRpcProvider; #blockNumber: number; + #running: boolean; + #filterId: null | number; constructor(provider: ConnectionRpcProvider) { this.#provider = provider; this.#blockNumber = -2; + this.#running = false; this.#filterId = null; } start(): void { + if (this.#running) { return; } + this.#running = true; + this.#filterId = this.#provider._subscribe([ "newHeads" ], (result: any) => { const blockNumber = getNumber(result.number); const initial = (this.#blockNumber === -2) ? blockNumber: (this.#blockNumber + 1) @@ -47,6 +53,9 @@ export class BlockConnectionSubscriber implements Subscriber { } stop(): void { + if (!this.#running) { return; } + this.#running = false; + if (this.#filterId != null) { this.#provider._unsubscribe(this.#filterId); this.#filterId = null; diff --git a/src.ts/providers/subscriber-filterid.ts b/src.ts/providers/subscriber-filterid.ts index fa352d8745..f440e78d4c 100644 --- a/src.ts/providers/subscriber-filterid.ts +++ b/src.ts/providers/subscriber-filterid.ts @@ -26,6 +26,8 @@ export class FilterIdSubscriber implements Subscriber { #filterIdPromise: null | Promise; #poller: (b: number) => Promise; + #running: boolean; + #network: null | Network; #hault: boolean; @@ -36,6 +38,8 @@ export class FilterIdSubscriber implements Subscriber { this.#filterIdPromise = null; this.#poller = this.#poll.bind(this); + this.#running = false; + this.#network = null; this.#hault = false; @@ -91,9 +95,17 @@ export class FilterIdSubscriber implements Subscriber { } } - start(): void { this.#poll(-2); } + start(): void { + if (this.#running) { return; } + this.#running = true; + + this.#poll(-2); + } stop(): void { + if (!this.#running) { return; } + this.#running = false; + this.#hault = true; this.#teardown(); this.#provider.off("block", this.#poller); diff --git a/src.ts/providers/subscriber-polling.ts b/src.ts/providers/subscriber-polling.ts index 3fcf3c72fd..76c0529fdb 100644 --- a/src.ts/providers/subscriber-polling.ts +++ b/src.ts/providers/subscriber-polling.ts @@ -76,13 +76,13 @@ export class PollingBlockSubscriber implements Subscriber { } start(): void { - if (this.#poller) { throw new Error("subscriber already running"); } + if (this.#poller) { return; } this.#poller = this.#provider._setTimeout(this.#poll.bind(this), this.#interval); this.#poll(); } stop(): void { - if (!this.#poller) { throw new Error("subscriber not running"); } + if (!this.#poller) { return; } this.#provider._clearTimeout(this.#poller); this.#poller = null; } @@ -105,9 +105,11 @@ export class PollingBlockSubscriber implements Subscriber { export class OnBlockSubscriber implements Subscriber { #provider: AbstractProvider; #poll: (b: number) => void; + #running: boolean; constructor(provider: AbstractProvider) { this.#provider = provider; + this.#running = false; this.#poll = (blockNumber: number) => { this._poll(blockNumber, this.#provider); } @@ -118,11 +120,17 @@ export class OnBlockSubscriber implements Subscriber { } start(): void { + if (this.#running) { return; } + this.#running = true; + this.#poll(-2); this.#provider.on("block", this.#poll); } stop(): void { + if (!this.#running) { return; } + this.#running = false; + this.#provider.off("block", this.#poll); } @@ -178,6 +186,8 @@ export class PollingEventSubscriber implements Subscriber { #filter: EventFilter; #poller: (b: number) => void; + #running: boolean; + // The most recent block we have scanned for events. The value -2 // indicates we still need to fetch an initial block number #blockNumber: number; @@ -186,6 +196,7 @@ export class PollingEventSubscriber implements Subscriber { this.#provider = provider; this.#filter = copy(filter); this.#poller = this.#poll.bind(this); + this.#running = false; this.#blockNumber = -2; } @@ -215,6 +226,9 @@ export class PollingEventSubscriber implements Subscriber { } start(): void { + if (this.#running) { return; } + this.#running = true; + if (this.#blockNumber === -2) { this.#provider.getBlockNumber().then((blockNumber) => { this.#blockNumber = blockNumber; @@ -224,6 +238,9 @@ export class PollingEventSubscriber implements Subscriber { } stop(): void { + if (!this.#running) { return; } + this.#running = false; + this.#provider.off("block", this.#poller); } diff --git a/src.ts/providers/subscriber.ts b/src.ts/providers/subscriber.ts deleted file mode 100644 index 6b200387f3..0000000000 --- a/src.ts/providers/subscriber.ts +++ /dev/null @@ -1,56 +0,0 @@ - -/* -import { defineProperties } from "@ethersproject/properties"; -export type EventCommon = "block" | "debug" | "blockObject"; - -export type Event = EventCommon | string | { address?: string, topics: Array> } - -export type EventLike = Event | Array; - -export function getTag(eventName: Event): string { - if (typeof(eventName) === "string") { return eventName; } - - if (typeof(eventName) === "object") { - return (eventName.address || "*") + (eventName.topics || []).map((topic) => { - if (typeof(topic) === "string") { return topic; } - return topic.join("|"); - }).join("&"); - } - - throw new Error("FOO"); -} - -export function getEvent(tag: string): Event { -} - -let nextId = 1; - -export class Subscriber { - readonly id!: number; - readonly tag!: string; - - #paused: boolean; - #blockNumber: number; - - constructor(tag: string) { - this.#paused = false; - this.#blockNumber = -1; - defineProperties(this, { id: nextId++, tag }); - } - - get blockNumber(): number { - return this.#blockNumber; - } - _setBlockNumber(blockNumber: number): void { this.#blockNumber = blockNumber; } - - setup(): void { } - teardown(): void { } - - isPaused(): boolean { return this.#paused; } - pause(): void { this.#paused = true; } - resume(): void { this.#paused = false; } - - resubscribeInfo(): string { return this.tag; } - resubscribe(info: string): boolean { return true; } -} -*/