You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Problem: creating a filter or subscription is one cheap RPC call that then holds server-side
memory (map entry, timer, growing slice, or a goroutine + channel) for up to the 5-minute expiry
(filters) or the life of the connection (subscriptions) — with no limit today on how many a single
client can accumulate. That's unbounded-allocation exposure (CWE-770): a client can create them
faster than they can expire and sustain memory growth indefinitely. Not solved by this epic's
backpressure decisions, which only protect the block-commit hot path from a slow existing
subscriber — they say nothing about how many can exist.
(caps both the filter registry and the subscription registry those issues create).
Scope:
Filters: a global cap on total concurrently-open filters (block + log combined), not a
per-client one. fxevm's JSON-RPC surface has no auth/session concept today, and filters are
explicitly connection-independent by design (Server-side filters (block + log) #331,
decision 9) — there's no real client identity to attribute a per-client cap to without adding an auth layer,
which is out of scope here. A global cap is the achievable granularity: eth_newBlockFilter/eth_newFilter
return a standard JSON-RPC error once the cap is hit, existing filters are unaffected, and a freed slot
(via uninstall or expiry) becomes available again. Configurable, with a conservative default —
the exact number matters less than the cap existing and being tunable.
Subscriptions: a per-connection cap, which is naturally attributable — each WS connection
already has its own notifier/context, so counting NewHeads() calls per connection is direct,
no new identity concept needed. A legitimate client only ever needs one newHeads subscription
per connection, so the default can be small. A global cap across all connections is worth adding
too, as defense in depth against many-connections-each-with-one-subscription, but the
per-connection cap is the one that actually stops a single misbehaving client.
Explicitly not attempting per-IP or per-identity attribution beyond "this WS connection" — that
needs real auth/session infrastructure this epic doesn't have and shouldn't invent as a
side-effect of a resource-cap fix.
Acceptance criteria / testing:
Create the configured max number of filters, assert the next one errors cleanly; uninstall one,
assert a new one can now be created (cap is on concurrent count, not lifetime total).
Same shape for subscriptions, scoped to one connection: open the per-connection max, assert the
next eth_subscribe("newHeads") on that same connection errors; a different connection can
still open its own subscriptions independently.
Existing, legitimate single-filter/single-subscription usage (i.e. everything the other issues in this epic
already test) is completely unaffected by a reasonable default cap — this is a regression risk
worth its own explicit test, not just an assumption.
Part IV of #329.
Problem: creating a filter or subscription is one cheap RPC call that then holds server-side
memory (map entry, timer, growing slice, or a goroutine + channel) for up to the 5-minute expiry
(filters) or the life of the connection (subscriptions) — with no limit today on how many a single
client can accumulate. That's unbounded-allocation exposure (CWE-770): a client can create them
faster than they can expire and sustain memory growth indefinitely. Not solved by this epic's
backpressure decisions, which only protect the block-commit hot path from a slow existing
subscriber — they say nothing about how many can exist.
Depends on:
(caps both the filter registry and the subscription registry those issues create).
Scope:
per-client one. fxevm's JSON-RPC surface has no auth/session concept today, and filters are
explicitly connection-independent by design (Server-side filters (block + log) #331,
decision 9) — there's no real client identity to attribute a per-client cap to without adding an auth layer,
which is out of scope here. A global cap is the achievable granularity:
eth_newBlockFilter/eth_newFilterreturn a standard JSON-RPC error once the cap is hit, existing filters are unaffected, and a freed slot
(via uninstall or expiry) becomes available again. Configurable, with a conservative default —
the exact number matters less than the cap existing and being tunable.
already has its own
notifier/context, so countingNewHeads()calls per connection is direct,no new identity concept needed. A legitimate client only ever needs one
newHeadssubscriptionper connection, so the default can be small. A global cap across all connections is worth adding
too, as defense in depth against many-connections-each-with-one-subscription, but the
per-connection cap is the one that actually stops a single misbehaving client.
needs real auth/session infrastructure this epic doesn't have and shouldn't invent as a
side-effect of a resource-cap fix.
Acceptance criteria / testing:
assert a new one can now be created (cap is on concurrent count, not lifetime total).
next
eth_subscribe("newHeads")on that same connection errors; a different connection canstill open its own subscriptions independently.
already test) is completely unaffected by a reasonable default cap — this is a regression risk
worth its own explicit test, not just an assumption.