feat(client): group(-name) removes a client from a group - #283
Open
qu0b wants to merge 2 commits into
Open
Conversation
Every client starts in the implicit "default" group and group(name) only appends, so a client with group(builder) is in both "builder" and "default". Group-less selections — wallet funding and refills, contract deployments, and any scenario without --client-group — all resolve to "default", so a client put in a named group still receives that traffic and cannot be reserved for the scenarios that ask for it. A "-name" token inside group(...) removes a group, making group(private,-default) the way to reserve an endpoint. This matters when the endpoint is not an ordinary node: a private transaction intake, a builder submission endpoint, or a rate-limited provider where stray funding or deploy transactions must not land. Additive behaviour is unchanged. Removing every group is refused: such a client is unselectable by every path while GetClientGroups still reports "default". Claude-Session: https://claude.ai/code/session_01P3LSEorv3qsJrWb12ZKHNo
…hout its group Claude-Session: https://claude.ai/code/session_01P3LSEorv3qsJrWb12ZKHNo
qu0b
added a commit
to ethpandaops/assertoor
that referenced
this pull request
Sep 3, 2026
Review findings on the executionGroups field and the playbook: - The claim that an endpoint in a named group "only receives transactions from scenarios that ask for it" was false. spamoor seeds every client with the "default" group and group() only appends, and group-less selections (wallet funding, refills, deployments, scenarios without client_group) all resolve to "default" — so a named endpoint still receives that traffic. The field docs, the global-config example and the playbook now say so, and show "-default" as the way to actually reserve an endpoint. - verifyClientGroups fails at startup when the linked spamoor ignores a configured group entry, so a removal that is silently dropped can never degrade isolation unnoticed. Group removal needs spamoor > v1.2.2 (ethpandaops/spamoor#283). - The playbook's tx-queue check asserted the match count and the must-be-zero counters in one task with failOnCheckMiss, where an unsatisfied assertion is a failure rather than a wait — so it could fail on the first poll while buildoor was still tallying the last block. Split into a polled wait for the count and a fail-fast guard on the zero counters. Claude-Session: https://claude.ai/code/session_01P3LSEorv3qsJrWb12ZKHNo
pk910
approved these changes
Sep 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
group(-name)removes a client from a groupThe problem
Every client starts in the implicit
defaultgroup andgroup(name)only appends, so a client configured withgroup(builder)is in bothbuilderanddefault.defaultis not just one group among many. It is the group every selection that names none resolves to: wallet funding and refills, contract deployment, root-wallet operations, and any scenario run without--client-group. So putting a client in a named group does not keep group-less traffic away from it, and there is currently no way to reserve an endpoint for the scenarios that ask for it.That matters whenever the endpoint is not an ordinary node:
The change
A
-nametoken insidegroup(...)removes a group instead of adding one:Removal is order independent and works across repeated prefixes, so
group(-default,builder)andgroup(builder)group(-default)both yield[builder].Additive behaviour is unchanged:
group(builder)still gives[default, builder], so nothing existing shifts.Removing every group is refused at construction. Such a client is unselectable by every code path (
HasGroupwalks the actual list) whileGetClientGroupsstill reports["default"], so it would look configured and silently never receive a transaction.Tests
Table test over the parsing (additive, comma-separated, duplicates, removal in either order and across prefixes, removing an absent group, the two refusal cases), plus a selection-level test asserting the property that actually matters: a reserved client is never returned by group-less
GetClient()and only byGetClient(WithClientGroup("private")), while an additive client still serves both.Context
This came out of wiring assertoor at a buildoor private transaction intake (ethpandaops/assertoor#233, ethpandaops/buildoor#186), where the built block is verified to hold exactly the transactions the operator planned. Without a way to leave
default, wallet-funding transactions land in that intake and end up in the measured blocks. assertoor fails at startup when the linked spamoor ignores a removal entry, rather than running with weaker isolation than configured, so it can adopt this the moment it ships.https://claude.ai/code/session_01P3LSEorv3qsJrWb12ZKHNo