-
Notifications
You must be signed in to change notification settings - Fork 29
feat(clients): executionGroups on endpoints + buildoor testing-build playbook #233
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
qu0b
wants to merge
11
commits into
master
Choose a base branch
from
qu0b/execution-groups
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
bf3bcf7
feat(clients): executionGroups on endpoints + buildoor testing-build …
qu0b 7b9e0ad
ci: pin staticcheck to v0.7.0
qu0b f1662d2
fix: honest client-group semantics + a tally check that waits
qu0b c016864
fix(lint): avoid shadowing err in the client group check
qu0b f9f6c20
docs(playbook): the intake must be the only endpoint spamoor can pick
qu0b b054f32
fix(playbook): scenarioYaml refill amounts are wei, not ETH
qu0b e0c8b3d
fix(playbook): quote the wei refill values
qu0b aae4eef
fix(playbook): a configVars jq expression must start with a dot
qu0b 7aabb42
fix: align endpoints with their spamoor clients; correct the simple form
qu0b 8d74f06
fix: trim client group names, as spamoor's parser does
qu0b 5151810
fix(lint): avoid shadowing err in the group tests
qu0b File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| package txmgr | ||
|
|
||
| import ( | ||
| "slices" | ||
| "testing" | ||
|
|
||
| "github.com/ethpandaops/assertoor/pkg/clients/execution" | ||
| "github.com/ethpandaops/spamoor/spamoor" | ||
| ) | ||
|
|
||
| // spamoor trims group names in its own parser, so the check must trim too: | ||
| // otherwise a stray space makes the two disagree and a removal that never | ||
| // took effect passes verification — the silent under-isolation this guard | ||
| // exists to prevent. | ||
| func TestNormalizedGroupsMatchesSpamoorParsing(t *testing.T) { | ||
| config := &execution.ClientConfig{ | ||
| Name: "intake", | ||
| URL: "http://localhost:8545", | ||
| Groups: []string{" builder ", "", " ", "-default "}, | ||
| } | ||
|
|
||
| got := normalizedGroups(config) | ||
| if want := []string{"builder", "-default"}; !slices.Equal(got, want) { | ||
| t.Fatalf("normalizedGroups = %v, want %v", got, want) | ||
| } | ||
|
|
||
| client, err := spamoor.NewClient(&spamoor.ClientOptions{ | ||
| RpcHost: "group(" + got[0] + ")" + config.URL, | ||
| }) | ||
| if err != nil { | ||
| t.Fatalf("unexpected error: %v", err) | ||
| } | ||
|
|
||
| if !client.HasGroup("builder") { | ||
| t.Error("spamoor did not apply the trimmed group name") | ||
| } | ||
|
|
||
| if err := verifyClientGroups(&execution.ClientConfig{Name: "intake", Groups: []string{" builder "}}, client); err != nil { | ||
| t.Errorf("verification must accept the same trimmed name spamoor applied: %v", err) | ||
| } | ||
| } | ||
|
|
||
| // A configured group the linked spamoor did not apply must stop startup. | ||
| func TestVerifyClientGroupsRejectsAnUnappliedEntry(t *testing.T) { | ||
| client, err := spamoor.NewClient(&spamoor.ClientOptions{RpcHost: "group(builder)http://localhost:8545"}) | ||
| if err != nil { | ||
| t.Fatalf("unexpected error: %v", err) | ||
| } | ||
|
|
||
| if applied := verifyClientGroups(&execution.ClientConfig{Name: "intake", Groups: []string{"builder"}}, client); applied != nil { | ||
| t.Errorf("an applied group must verify: %v", applied) | ||
| } | ||
|
|
||
| // The pinned spamoor keeps the client in "default", so a removal that was | ||
| // ignored has to be an error rather than silent under-isolation. | ||
| ignored := verifyClientGroups(&execution.ClientConfig{Name: "intake", Groups: []string{"-default"}}, client) | ||
| if client.HasGroup("default") && ignored == nil { | ||
| t.Error("an ignored removal must fail verification") | ||
| } | ||
|
|
||
| if err := verifyClientGroups(&execution.ClientConfig{Name: "intake", Groups: []string{"absent"}}, client); err == nil { | ||
| t.Error("a group the client is not in must fail verification") | ||
| } | ||
| } |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,168 @@ | ||
| id: buildoor-testing-build | ||
| name: "buildoor testing build: planned transactions land on chain exactly" | ||
| description: | | ||
| Switches a buildoor to its testing build source (blocks built from the | ||
| builder's private tx intake through geth's testing_buildBlockV1), feeds the | ||
| intake with a spamoor scenario, and requires that every buildoor block after | ||
| the switch verified as an exact tx plan match: same transactions, same | ||
| order, same count. A single mismatch, missed payload or unknown block fails | ||
| the test. | ||
|
|
||
| Endpoint setup. While the builder is on the testing source its blocks are | ||
| the ONLY way a transaction gets included: anything sent to a normal EL sits | ||
| in the public txpool forever, because buildoor builds solely from its | ||
| intake. That includes spamoor's own wallet funding and refills, which use | ||
| the group-less "default" selection rather than this scenario's client_group. | ||
|
|
||
| So every endpoint spamoor may pick must be the intake. The simple form is to | ||
| give this playbook a config where the intake is the only execution endpoint | ||
| (it proxies all reads to the EL, so the client checks still work). It still | ||
| needs the group this test's clientGroup names, since a scenario selecting a | ||
| group no client is in gets no client at all: | ||
|
|
||
| endpoints: | ||
| - name: buildoor-intake | ||
| executionUrl: http://buildoor:8080/rpc | ||
| consensusUrl: http://beacon:5052 | ||
| executionGroups: [builder] | ||
|
|
||
| With several execution endpoints, keep the intake in "default" and take the | ||
| others out of it, so the scenario reaches every node it needs while funding | ||
| can only land somewhere that gets built (needs a spamoor with group removal, | ||
| ethpandaops/spamoor#283): | ||
|
|
||
| endpoints: | ||
| - name: buildoor-intake | ||
| executionUrl: http://buildoor:8080/rpc | ||
| consensusUrl: http://beacon:5052 | ||
| executionGroups: [builder] | ||
| - name: node-2 | ||
| executionUrl: http://node2:8545 | ||
| consensusUrl: http://beacon2:5052 | ||
| executionGroups: ["-default"] | ||
|
|
||
| The buildoor geth must serve the testing namespace (--http.api ...,testing). | ||
| version: 1.0.0 | ||
| tags: [buildoor, epbs, load, testing-build] | ||
| timeout: 30m | ||
| config: | ||
| buildoorUrl: "http://buildoor:8080" | ||
| spamoorPrivkey: "" | ||
| clientGroup: "builder" | ||
|
qu0b marked this conversation as resolved.
|
||
| minVerifiedBlocks: 6 | ||
| minTxsPerBlock: 20 | ||
| throughput: 300 | ||
| baseFeeGwei: 100 | ||
| # spamoor's scenarioYaml takes these in WEI (the --refill-* CLI flags take | ||
| # ETH, the YAML fields do not). Too small and the wallets are "funded" with | ||
| # dust, pass the balance check, and every transaction is then skipped for | ||
| # insufficient funds. | ||
| # Quoted: jq evaluates configVars as float64, so an unquoted 5e19 reaches | ||
| # spamoor as "5e+19" and fails its uint256 parse. | ||
| refillAmountWei: "50000000000000000000" # 50 ETH | ||
| refillBalanceWei: "10000000000000000000" # 10 ETH | ||
| tasks: | ||
| - name: check_clients_are_healthy | ||
| title: "Check if at least one client is ready" | ||
| timeout: 5m | ||
| config: | ||
| minClientCount: 1 | ||
|
|
||
| - name: check_http_json | ||
| title: "Switch buildoor to the testing build source" | ||
| timeout: 1m | ||
| configVars: | ||
| url: ".buildoorUrl + \"/api/config/testing\"" | ||
| config: | ||
| method: POST | ||
| body: | ||
| source: testing | ||
| fill_gas_pct: 100 | ||
| policy: fifo | ||
| expectStatus: 200 | ||
| failOnCheckMiss: true | ||
| assertions: | ||
| - name: updated | ||
| query: ".status" | ||
| operator: eq | ||
| value: "updated" | ||
|
|
||
| - name: run_task_background | ||
| title: "Feed the intake and verify buildoor's blocks" | ||
| config: | ||
| onBackgroundComplete: fail | ||
| backgroundTask: | ||
| name: run_spamoor_scenario | ||
| title: "spamoor eoatx into the builder intake" | ||
| configVars: | ||
| privateKey: "spamoorPrivkey" | ||
| scenarioYaml: ". as $v | {throughput: $v.throughput, max_pending: ($v.throughput * 10), max_wallets: 30, base_fee: $v.baseFeeGwei, tip_fee: 2, refill_amount: $v.refillAmountWei, refill_balance: $v.refillBalanceWei, rebroadcast: 30, client_group: $v.clientGroup}" | ||
| config: | ||
| scenarioName: eoatx | ||
| foregroundTask: | ||
| name: run_tasks | ||
| title: "Verify" | ||
| config: | ||
| tasks: | ||
| - name: check_consensus_block_proposals | ||
| title: "buildoor proposes ${minVerifiedBlocks} blocks with >= ${minTxsPerBlock} transactions" | ||
| timeout: 20m | ||
| configVars: | ||
| blockCount: "minVerifiedBlocks" | ||
| minTransactionCount: "minTxsPerBlock" | ||
| config: | ||
| checkLookback: 64 | ||
| extraDataPattern: "^buildoor" | ||
|
|
||
| # Two checks on purpose. The tally lags the proposals it counts (the | ||
| # verifier fetches the block from the EL after inclusion), and an | ||
| # unsatisfied assertion is a FAILURE rather than a wait under | ||
| # failOnCheckMiss - so the count is polled without it, and only the | ||
| # must-be-zero counters fail fast. | ||
| - name: check_http_json | ||
| title: "Wait for ${minVerifiedBlocks} verified tx plans" | ||
| timeout: 5m | ||
| configVars: | ||
| url: ".buildoorUrl + \"/api/buildoor/tx-queue\"" | ||
| assertions: >- | ||
| . as $v | [ | ||
| {name: "enough-matches", query: ".plan_checks.match", operator: "gte", value: $v.minVerifiedBlocks} | ||
| ] | ||
| config: | ||
| pollInterval: 5s | ||
|
|
||
| - name: check_http_json | ||
| title: "No tx plan was mismatched, missed or unverifiable" | ||
| timeout: 1m | ||
| configVars: | ||
| url: ".buildoorUrl + \"/api/buildoor/tx-queue\"" | ||
| # Cumulative counters, so this covers the whole run, not just now. | ||
| # Leading "." matters: assertoor prepends one to a configVars | ||
| # expression that lacks it, turning a bare [..] into an index. | ||
| assertions: >- | ||
| . | [ | ||
| {name: "no-mismatch", query: ".plan_checks.mismatch", operator: "eq", value: 0}, | ||
| {name: "no-missing-blocks", query: ".plan_checks.block_not_found", operator: "eq", value: 0}, | ||
| {name: "no-missed-payloads", query: ".plan_checks.missed", operator: "eq", value: 0} | ||
| ] | ||
| config: | ||
| failOnCheckMiss: true | ||
|
qu0b marked this conversation as resolved.
|
||
|
|
||
| - name: check_consensus_forks | ||
| title: "No forks" | ||
| timeout: 1m | ||
| config: | ||
| minCheckEpochCount: 1 | ||
| maxForkDistance: 1 | ||
|
|
||
| cleanupTasks: | ||
| - name: check_http_json | ||
| title: "Switch buildoor back to the pool build source" | ||
| timeout: 1m | ||
| configVars: | ||
| url: ".buildoorUrl + \"/api/config/testing\"" | ||
| config: | ||
| method: POST | ||
| body: | ||
| source: pool | ||
| expectStatus: 200 | ||
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.