diff --git a/ethers/providers/jsonrpc/subscriptions.nim b/ethers/providers/jsonrpc/subscriptions.nim index 95a7a25..fc9dea9 100644 --- a/ethers/providers/jsonrpc/subscriptions.nim +++ b/ethers/providers/jsonrpc/subscriptions.nim @@ -140,7 +140,7 @@ type # We need to keep around the filters that are used to create log filters on the RPC node # as there might be a time when they need to be recreated as RPC node might prune/forget # about them - filters: Table[JsonNode, EventFilter] + logFilters: Table[JsonNode, EventFilter] # Used when filters are recreated to translate from the id that user # originally got returned to new filter id @@ -167,8 +167,15 @@ proc new*(_: type JsonRpcSubscriptions, raise e except CatchableError as e: if "filter not found" in e.msg: - let filter = subscriptions.filters[originalId] - let newId = await subscriptions.client.eth_newFilter(filter) + var newId: JsonNode + # Log filters are stored in logFilters, block filters are not persisted + # there is they do not need any specific data for their recreation. + # We use this to determine if the filter was log or block filter here. + if subscriptions.logFilters.hasKey(originalId): + let filter = subscriptions.logFilters[originalId] + newId = await subscriptions.client.eth_newFilter(filter) + else: + newId = await subscriptions.client.eth_newBlockFilter() subscriptions.subscriptionMapping[originalId] = newId return await getChanges(originalId) else: @@ -225,14 +232,14 @@ method subscribeLogs(subscriptions: PollingSubscriptions, let id = await subscriptions.client.eth_newFilter(filter) subscriptions.callbacks[id] = callback - subscriptions.filters[id] = filter + subscriptions.logFilters[id] = filter subscriptions.subscriptionMapping[id] = id return id method unsubscribe*(subscriptions: PollingSubscriptions, id: JsonNode) {.async.} = - subscriptions.filters.del(id) + subscriptions.logFilters.del(id) subscriptions.callbacks.del(id) let sub = subscriptions.subscriptionMapping[id] subscriptions.subscriptionMapping.del(id) diff --git a/testmodule/providers/jsonrpc/rpc_mock.nim b/testmodule/providers/jsonrpc/rpc_mock.nim index 5142a82..b4411e7 100644 --- a/testmodule/providers/jsonrpc/rpc_mock.nim +++ b/testmodule/providers/jsonrpc/rpc_mock.nim @@ -25,6 +25,11 @@ proc start*(server: MockRpcHttpServer) = server.filters.add filterId return filterId + server.srv.router.rpc("eth_newBlockFilter") do() -> string: + let filterId = "0x" & (array[16, byte].example).toHex + server.filters.add filterId + return filterId + server.srv.router.rpc("eth_getFilterChanges") do(id: string) -> seq[string]: if id notin server.filters: raise (ref ApplicationError)(code: -32000, msg: "filter not found") diff --git a/testmodule/providers/jsonrpc/testJsonRpcSubscriptions.nim b/testmodule/providers/jsonrpc/testJsonRpcSubscriptions.nim index 08061a6..5f96ce3 100644 --- a/testmodule/providers/jsonrpc/testJsonRpcSubscriptions.nim +++ b/testmodule/providers/jsonrpc/testJsonRpcSubscriptions.nim @@ -124,25 +124,25 @@ suite "HTTP polling subscriptions - filter not found": await client.close() await mockServer.stop() - test "filter not found error recreates filter": + test "filter not found error recreates log filter": let filter = EventFilter(address: Address.example, topics: @[array[32, byte].example]) let emptyHandler = proc(log: Log) = discard - check subscriptions.filters.len == 0 + check subscriptions.logFilters.len == 0 check subscriptions.subscriptionMapping.len == 0 let id = await subscriptions.subscribeLogs(filter, emptyHandler) - check subscriptions.filters[id] == filter + check subscriptions.logFilters[id] == filter check subscriptions.subscriptionMapping[id] == id - check subscriptions.filters.len == 1 + check subscriptions.logFilters.len == 1 check subscriptions.subscriptionMapping.len == 1 mockServer.invalidateFilter(id) check eventually subscriptions.subscriptionMapping[id] != id - test "recreated filter can be still unsubscribed using the original id": + test "recreated log filter can be still unsubscribed using the original id": let filter = EventFilter(address: Address.example, topics: @[array[32, byte].example]) let emptyHandler = proc(log: Log) = discard let id = await subscriptions.subscribeLogs(filter, emptyHandler) @@ -151,5 +151,26 @@ suite "HTTP polling subscriptions - filter not found": await subscriptions.unsubscribe(id) - check not subscriptions.filters.hasKey id + check not subscriptions.logFilters.hasKey id + check not subscriptions.subscriptionMapping.hasKey id + + test "filter not found error recreates block filter": + let emptyHandler = proc(blck: Block) = discard + + check subscriptions.subscriptionMapping.len == 0 + let id = await subscriptions.subscribeBlocks(emptyHandler) + check subscriptions.subscriptionMapping[id] == id + + mockServer.invalidateFilter(id) + + check eventually subscriptions.subscriptionMapping[id] != id + + test "recreated block filter can be still unsubscribed using the original id": + let emptyHandler = proc(blck: Block) = discard + let id = await subscriptions.subscribeBlocks(emptyHandler) + mockServer.invalidateFilter(id) + check eventually subscriptions.subscriptionMapping[id] != id + + await subscriptions.unsubscribe(id) + check not subscriptions.subscriptionMapping.hasKey id