Compare commits

...

239 Commits

Author SHA1 Message Date
Tim
5b4af55017 feat: add reqwest-rustls to support otlp endpoints with https (#23495) 2026-04-14 14:09:09 +00:00
Dan Cline
b8ab2c628e chore(cli): add binary name and chain detection in tempo download log (#23356)
Co-authored-by: Derek Cofausper <256792747+decofe@users.noreply.github.com>
Co-authored-by: Emma Jamieson-Hoare <21029500+emmajam@users.noreply.github.com>
2026-04-14 13:23:29 +00:00
Brian Picciano
766f4317a6 chore(bench): reduce default blocks to 200, warmup to 20 for big-blocks (#23494)
Co-authored-by: mediocregopher <mediocregopher@users.noreply.github.com>
Co-authored-by: Amp <amp@ampcode.com>
2026-04-14 13:13:21 +00:00
Derek Cofausper
c20d897efe fix(node): downgrade prune config log from warn to info (#23493)
Co-authored-by: Brian Picciano <933154+mediocregopher@users.noreply.github.com>
2026-04-14 11:43:43 +00:00
Brian Picciano
ad1e8f2cea feat(bench): BAL capture, replay, and inline payload decoding (#23434)
Co-authored-by: Soubhik Singha Mahapatra <soubhiksmp2004@gmail.com>
Co-authored-by: Soubhik Singha Mahapatra <160333583+Soubhik-10@users.noreply.github.com>
Co-authored-by: Brian Picciano <933154+mediocregopher@users.noreply.github.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: steven <corderosteven6@gmail.com>
Co-authored-by: Derek Cofausper <256792747+decofe@users.noreply.github.com>
2026-04-14 11:23:13 +00:00
Derek Cofausper
51309ff55c fix(bench): retry on all transport errors (#23491)
Co-authored-by: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com>
Co-authored-by: Alexey Shekhirin <github@shekhirin.com>
2026-04-14 10:42:05 +00:00
Soubhik Singha Mahapatra
e0aac5015f chore(BAL): added newPayloadV5 and getPayloadV6 (#23486)
Co-authored-by: Ishika Choudhury <117741714+Rimeeeeee@users.noreply.github.com>
2026-04-14 08:57:42 +00:00
Ishika Choudhury
3b8290439a chore(BAL): added helper functions for building (#23490) 2026-04-14 08:49:49 +00:00
yottaes
1a2836ff53 feat(rpc): support transactionReceipts subscription in eth_subscribe (#23485)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2026-04-14 08:42:01 +00:00
MagicJoshh
bce7368a82 fix(engine): use IndexSet for deterministic block buffer child ordering (#22676) 2026-04-13 19:18:23 +00:00
MagicJoshh
1e461ef281 fix(trie): terminate depth-first iterator on database error (#22709) 2026-04-13 17:48:07 +00:00
Ishika Choudhury
a5113622fd chore(BAL): added fcuv4 and EngineApiMessageVersion6 (#23480)
Co-authored-by: Soubhik Singha Mahapatra <soubhiksmp2004@gmail.com>
2026-04-13 14:47:28 +00:00
stevencartavia
bfb7ab72f7 chore: bump alloy to 2.0.0 (#23407)
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2026-04-13 13:51:19 +00:00
Matthias Seitz
3d5c29c179 feat(net): add enforce_enr_fork_id to DefaultNetworkArgs (#23477) 2026-04-13 13:00:59 +00:00
Ignacio Hagopian
a05960ab07 feat(stateless): make witness generation conform to the draft specs (#22289)
Signed-off-by: jsign <jsign.uy@gmail.com>
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
Co-authored-by: Brian Picciano <me@mediocregopher.com>
2026-04-13 13:34:00 +02:00
John Chase
6b499151d8 perf(txpool): use FxHashMap/FxHashSet for TxHash-heavy containers (#23037) 2026-04-13 11:22:21 +02:00
Matthias Seitz
a9bd38a43e perf(trie): parallelize merge_ancestors_into_overlay (#21473)
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com>
2026-04-12 15:27:30 +02:00
github-actions[bot]
a544d244d8 chore(deps): weekly cargo update (#23464)
Co-authored-by: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com>
2026-04-12 12:25:36 +02:00
Derek Cofausper
a550b7a7d3 perf(tracing): also disable target attribute in OTLP spans (#23462)
Co-authored-by: Arsenii Kulikov <62447812+klkvr@users.noreply.github.com>
Co-authored-by: Arsenii Kulikov <klkvrr@gmail.com>
2026-04-11 16:54:06 +00:00
Derek Cofausper
7035bbcf3a refactor(examples): replace mev-share-sse with reqwest bytes_stream in beacon-api-sse (#23458)
Co-authored-by: Matthias Seitz <19890894+mattsse@users.noreply.github.com>
2026-04-11 10:33:34 +00:00
Tamjid Ahmed
0c278f5fab feat(eth-wire): introduce configurable maximum ETH message size acros… (#22668)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2026-04-11 06:23:12 +00:00
Arsh
03dd1c3ae2 fix(txpool): do not mark ExceedsFeeCap as a bad transaction (#23450) 2026-04-11 05:13:05 +00:00
Dan Cline
6aa2234d9a chore(cli): make --resumable default (#23451) 2026-04-11 04:49:16 +00:00
Derek Cofausper
5ae8f0bc54 perf(engine): downgrade sparse trie spans to trace (#23448)
Co-authored-by: Arsenii Kulikov <62447812+klkvr@users.noreply.github.com>
2026-04-11 00:24:25 +00:00
Derek Cofausper
e3536f768e perf(tracing): disable location and inactivity tracking in OTLP span export (#23447)
Co-authored-by: Arsenii Kulikov <62447812+klkvr@users.noreply.github.com>
2026-04-10 19:23:34 +00:00
Derek Cofausper
ff1a78e1ce ci: remove PGO from CI workflows (#23405)
Co-authored-by: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com>
2026-04-10 19:17:42 +00:00
Matthias Seitz
fc3f465321 fix(net): seed peer range from handshake status (#23446)
Co-authored-by: Weixie Cui <cuiweixie@gmail.com>
2026-04-10 14:06:10 +00:00
cui
b0956b12ae fix(rpc): paginate ots_getBlockTransactions in block order (#23442)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2026-04-10 13:32:28 +00:00
cui
a774920b78 fix(provider): size block_range buffer for inclusive span (#23443) 2026-04-10 13:07:59 +00:00
cui
77d5f86b42 fix(consensus): always validate minimum gas limit (#23441) 2026-04-10 12:55:11 +00:00
Hwangjae Lee
e118963b8f fix(rpc): preserve nested bundle structure in mev_simBundle logs (#20565)
Signed-off-by: Hwangjae Lee <meetrick@gmail.com>
Co-authored-by: Derek Cofausper <256792747+decofe@users.noreply.github.com>
Co-authored-by: Matthias Seitz <19890894+mattsse@users.noreply.github.com>
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2026-04-10 12:54:27 +00:00
Derek Cofausper
64f6117dc0 docs(trie): replace stale MultiProofTask references with SparseTrieCacheTask (#22780)
Co-authored-by: Matthias Seitz <19890894+mattsse@users.noreply.github.com>
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2026-04-10 11:30:42 +00:00
Emma Jamieson-Hoare
53fe0a077a bench: add release regression mode (#23416)
Co-authored-by: Amp <amp@ampcode.com>
2026-04-10 11:13:24 +00:00
Brian Picciano
828965c39d perf(engine): improve BAL prewarm sparse-trie streaming (#23423)
Co-authored-by: Derek Cofausper <256792747+decofe@users.noreply.github.com>
Co-authored-by: Brian Picciano <933154+mediocregopher@users.noreply.github.com>
Co-authored-by: Amp <amp@ampcode.com>
2026-04-10 10:11:16 +00:00
Emma Jamieson-Hoare
53e1ec81b3 docs: update README for Reth 2.0 (#23424)
Co-authored-by: Amp <amp@ampcode.com>
2026-04-10 09:25:31 +00:00
dependabot[bot]
608c96791f chore(deps): bump tokio from 1.51.0 to 1.51.1 in the cargo-weekly group (#23410)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-10 07:22:23 +00:00
Derek Cofausper
13ae241a0d ci: bump MSRV job runner to depot-ubuntu-latest-8 (#23432)
Co-authored-by: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com>
2026-04-10 06:45:30 +00:00
Alexey Shekhirin
cecbb4cc8c fix(cli): use recent speed instead of all-time average for download ETA (#23425) 2026-04-10 00:29:54 +00:00
Alexey Shekhirin
0ed4739482 fix(download): show error on retry and reset counter on progress (#23426) 2026-04-10 00:29:45 +00:00
Emma Jamieson-Hoare
76bdfb30ff chore: update README logo to Reth v2.0 branding (#23421)
Co-authored-by: Amp <amp@ampcode.com>
2026-04-09 14:10:24 +00:00
Tim
d68dc8306b fix: add no-list in order to avoid prefix matching (#23420) 2026-04-09 13:44:39 +00:00
Derek Cofausper
3b5045021d chore(engine): rename to_multi_proof to to_sparse_trie_task in prewarm (#23418)
Co-authored-by: Brian Picciano <933154+mediocregopher@users.noreply.github.com>
2026-04-09 13:17:45 +00:00
dependabot[bot]
20c75ab0e5 chore(deps): bump actions/deploy-pages from 4 to 5 (#23408)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-09 11:08:59 +00:00
Derek Cofausper
44bcf5e9d4 chore: remove migrate-trie-to-packed example (#23385)
Co-authored-by: Sergei Shulepov <2205845+pepyakin@users.noreply.github.com>
Co-authored-by: Sergei Shulepov <s.pepyakin@gmail.com>
2026-04-09 13:12:52 +02:00
Arsenii Kulikov
ac3120703a fix: properly validate authorities in the pool (#23406) 2026-04-09 10:55:55 +00:00
Matthias Seitz
c9866e2c85 fix(pruning): avoid unused import warning in checkpoint (#23412) 2026-04-09 12:54:57 +02:00
Soubhik Singha Mahapatra
5f2f4908ae feat: implement Bal Client for eth 71 (#22605)
Co-authored-by: Ishika Choudhury <117741714+Rimeeeeee@users.noreply.github.com>
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2026-04-09 10:12:45 +00:00
Derek Cofausper
f29c83dee9 chore(ci): add set -x to all GHA bash scripts (#23413)
Co-authored-by: Sergei Shulepov <2205845+pepyakin@users.noreply.github.com>
2026-04-09 10:04:32 +00:00
Derek Cofausper
d56b1be103 ci(bench): always send Slack notification for nightly bench runs (#23417)
Co-authored-by: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com>
2026-04-09 09:56:03 +00:00
Derek Cofausper
346f0e5851 fix(ci): handle stale minio cache in bench build script (#23415)
Co-authored-by: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com>
2026-04-09 09:55:54 +00:00
Matthias Seitz
91b8e1a8ae perf(storage): use sort_unstable in safe paths (#23386) 2026-04-09 07:48:35 +00:00
Arsenii Kulikov
3d5057b97a refactor: support modifying next_available_nonce_for (#23409) 2026-04-09 04:22:48 +00:00
Brian Picciano
b27b3e0e2c fix(reth-bb): use noop consensus (#23399)
Co-authored-by: Brian Picciano <933154+mediocregopher@users.noreply.github.com>
Co-authored-by: Amp <amp@ampcode.com>
2026-04-09 02:37:40 +00:00
Alexey Shekhirin
5bfe2c8b13 chore: add reth 2.0 banner image (#23402) 2026-04-08 18:29:42 +02:00
Tim
e4cf0ab09b fix: add full recover fallback (#23390) 2026-04-08 14:37:55 +00:00
Brian Picciano
3248af34a9 fix(engine): disable payload state hook when BAL is present (#23393)
Co-authored-by: Brian Picciano <933154+mediocregopher@users.noreply.github.com>
Co-authored-by: Amp <amp@ampcode.com>
2026-04-08 14:27:57 +00:00
Derek Cofausper
e6f1c2c6b9 fix: add --kill to all schelk recover calls (#23384)
Co-authored-by: Sergei Shulepov <2205845+pepyakin@users.noreply.github.com>
2026-04-08 10:45:03 +00:00
Derek Cofausper
83e6677078 refactor(engine): use Mutex instead of RwLock in PayloadExecutionCache (#23387)
Co-authored-by: Sergei Shulepov <2205845+pepyakin@users.noreply.github.com>
2026-04-08 09:28:41 +00:00
Kenil shah
390def905d perf: use sort_unstable in CLI, networking, and RPC hot paths (#23364)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2026-04-08 08:09:09 +00:00
Crypto Nomad
c924902b89 perf(provider): avoid full receipt clone in tx-range query (#23187)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2026-04-08 07:48:06 +00:00
Derek Cofausper
ed8bfca9ac fix: use named systemd scope for reliable reth cleanup in benchmarks (#23374)
Co-authored-by: Sergei Shulepov <2205845+pepyakin@users.noreply.github.com>
2026-04-07 16:57:56 +00:00
Derek Cofausper
4178e63011 fix(ci): pin CPU frequency to nominal clock in bench workflow (#23370)
Co-authored-by: Sergei Shulepov <2205845+pepyakin@users.noreply.github.com>
2026-04-07 13:00:29 +00:00
Derek Cofausper
eb4c15e5e3 chore: remove changelog workflow and .changelog directory (#23376)
Co-authored-by: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com>
2026-04-07 12:27:32 +00:00
Emma Jamieson-Hoare
9320216ff2 chore: 2.0 release branch (#23372) 2026-04-07 11:57:37 +00:00
Tim
01d851ce4a fix: unmount schelk volume before recover in snapshot script (#23371) 2026-04-07 10:42:07 +00:00
Ishika Choudhury
2155fb7223 chore: added block_access_list_raw rpc (#23363) 2026-04-07 12:45:55 +02:00
figtracer
a539daf0d0 feat(trie): add DecodedMultiProofV2::from_witness constructor (#23362) 2026-04-07 10:19:31 +00:00
Arsenii Kulikov
6b176abc5d feat: expose EVM config on EthTransactionValidator (#23369) 2026-04-07 10:18:03 +00:00
Arsenii Kulikov
0e4f143172 feat: catch-up for read-only ProviderFactorys (#23357) 2026-04-06 19:47:00 +00:00
github-actions[bot]
1a7288373e chore(deps): weekly cargo update (#23359)
Co-authored-by: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com>
2026-04-05 06:35:25 +00:00
Arsenii Kulikov
adc960162f refactor(rocksdb): use secondary instances for read only providers (#23346) 2026-04-03 17:48:56 +00:00
Derek Cofausper
f3e813cfea fix(ci): fix Grafana URL year-2082 when ABBA disabled (#23348)
Co-authored-by: Dan Cline <6798349+Rjected@users.noreply.github.com>
2026-04-03 17:20:00 +00:00
figtracer
86faf54ac5 feat(revm): add ExecutionWitnessRecord::into_execution_witness helper (#23345) 2026-04-03 11:04:07 +00:00
Emma Jamieson-Hoare
c82d43594e feat(bench): upload nightly regression results to ClickHouse (#23344)
Co-authored-by: Amp <amp@ampcode.com>
2026-04-02 12:26:36 +00:00
joshieDo
4a6f9cd5c9 fix(provider): cap storage_v2 unwind history by MDBX tip (#23335)
Co-authored-by: Amp <amp@ampcode.com>
2026-04-02 11:19:41 +00:00
Soubhik Singha Mahapatra
7ecbea5847 feat: add bal rpc methods (#23330)
Co-authored-by: Ishika Choudhury <117741714+Rimeeeeee@users.noreply.github.com>
2026-04-02 11:07:37 +00:00
AKABABA-ETH
aa5effbffe perf(rpc): pre-allocate vectors in eth_feeHistory (#23334)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2026-04-02 10:41:50 +00:00
Satoshi Nakamoto
abab6781b2 fix(rpc): apply count only after after is consumed (#23338)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2026-04-02 10:39:02 +00:00
dependabot[bot]
079d496c8a chore(deps): bump actions/configure-pages from 5 to 6 (#23336)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-02 10:28:39 +00:00
dependabot[bot]
00336b3e2a chore(deps): bump the cargo-weekly group with 3 updates (#23337)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-02 10:28:39 +00:00
AlexYue
8b8430ac41 docs(libmdbx): fix typo writeable -> writable (#23339) 2026-04-02 10:02:33 +00:00
Brian Picciano
8c223dbe99 chore(nix): update nixpkgs to 25.11 and refresh all flake inputs (#23342)
Co-authored-by: Brian Picciano <933154+mediocregopher@users.noreply.github.com>
2026-04-02 09:33:01 +00:00
Derek Cofausper
abdba93fc6 chore: remove unused return value from dispatch_with_chunking (#23341)
Co-authored-by: Sergei Shulepov <2205845+pepyakin@users.noreply.github.com>
2026-04-02 09:08:15 +00:00
Derek Cofausper
08a33da36e chore: migrate allow(clippy:: to expect(clippy:: (#23340)
Co-authored-by: Sergei Shulepov <2205845+pepyakin@users.noreply.github.com>
2026-04-02 08:34:48 +00:00
Matthias Seitz
1f84158137 chore: move alloy-rlp to dev-dependencies in reth-execution-types (#23333) 2026-04-01 18:01:34 +02:00
Matthias Seitz
357188f918 fix(net): avoid itertools Format panic in tracing log (#23331) 2026-04-01 17:32:45 +02:00
Matthias Seitz
082c36ebee chore: allow "writeable" in typos config (#23332) 2026-04-01 17:26:25 +02:00
Brian Picciano
0031445779 feat(engine): include backpressure in reported persistence_wait, make wait-time mimic CL slot time (#23308)
Co-authored-by: Brian Picciano <933154+mediocregopher@users.noreply.github.com>
Co-authored-by: Amp <amp@ampcode.com>
2026-04-01 13:35:10 +00:00
Tim
3661c96c70 Fix: Use repository to track hourly reth-bench runs instead of github actions cache (#23306) 2026-04-01 13:28:59 +00:00
Matthias Seitz
90dfaac5e2 refactor(reth-bench): make payload handling ethereum-only (#23324)
Co-authored-by: Derek Cofausper <256792747+decofe@users.noreply.github.com>
Co-authored-by: Matthias Seitz <19890894+mattsse@users.noreply.github.com>
2026-04-01 12:02:42 +00:00
Brian Picciano
17544f847b fix(bench): add warmup step for big blocks mode (#23323)
Co-authored-by: Brian Picciano <933154+mediocregopher@users.noreply.github.com>
Co-authored-by: Amp <amp@ampcode.com>
2026-04-01 11:22:00 +00:00
Ivan Wang
1bdc577f19 fix(rpc): admin_nodeInfo.id now returns keccak256 node ID matching go-ethereum format (#23319) 2026-04-01 10:19:51 +00:00
Sergei Shulepov
b58827ec2d perf: reduce cacheline ping pong in workers availability (#23321) 2026-04-01 10:04:16 +00:00
Ivan Wang
239c2625a4 fix(rpc): remove 0x prefix from admin_peers id to match go-ethereum format (#23318) 2026-04-01 07:53:21 +00:00
joshieDo
f8efc76880 refactor(storage): remove changeset count APIs (#23310)
Co-authored-by: Amp <amp@ampcode.com>
2026-03-31 18:45:30 +00:00
stevencartavia
ef3cda7b66 feat: integrate reth-rpc-traits and remove IntoRpcTx (#23288) 2026-03-31 15:42:48 +00:00
Debjit Bhowal
23b68fcc38 feat(client): add era type override functionality to EraClient (#23307) 2026-03-31 15:33:46 +00:00
onbjerg
3802a31991 feat(download): make snapshot API URL overridable (#23303) 2026-03-31 15:12:15 +00:00
Brian Picciano
eab36bd18f chore(grafana): add sparse trie idle metrics to grafana overview (#23302)
Co-authored-by: Brian Picciano <933154+mediocregopher@users.noreply.github.com>
2026-03-31 13:03:39 +00:00
Brian Picciano
afbb3986d7 feat: add reth-bb binary with multi-segment big block execution support (#23140)
Co-authored-by: Brian Picciano <933154+mediocregopher@users.noreply.github.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: amp[bot] <noreply@ampcode.com>
2026-03-31 12:45:12 +00:00
Matthias Seitz
0f7cd0fd98 chore: check trie-debug in zepter (#23304) 2026-03-31 12:36:19 +00:00
Arsenii Kulikov
f0d07c38be chore: bump alloy-evm (#23289) 2026-03-30 17:51:09 +00:00
Sergei Shulepov
930f2a6eb2 feat(engine): backpressure, take 2. (#23280) 2026-03-30 15:19:55 +00:00
figtracer
69bde3a5cc feat(trie): add SparseStateTrie::update_account_stateless for stateless validation (#23272) 2026-03-30 12:10:03 +00:00
figtracer
949fe33066 feat(db): add create_test_provider_factory_with_chain_spec_and_db_args (#23270) 2026-03-30 10:57:32 +00:00
John Chase
fc6462b5ba fix(nat): resolve DNS for ExternalAddr in external_addr_with (#23269) 2026-03-30 10:49:45 +00:00
0xWeakSheep
dae2485b04 test(txpool): add regression for parked basefee ancestor handling (#23277) 2026-03-30 10:28:56 +00:00
Crypto Nomad
dc22ece4d2 fix(cli): use HeaderTy for stage dump headers (#23274) 2026-03-30 10:27:21 +00:00
MagicJoshh
540f513a88 fix(net): prefer peer-reported block number in session activation (#23275) 2026-03-30 10:26:45 +00:00
Brian Picciano
43dfe6ed84 feat(trie): Record trie cursor metrics (#23252)
Co-authored-by: Brian Picciano <933154+mediocregopher@users.noreply.github.com>
2026-03-30 07:45:23 +00:00
github-actions[bot]
0f89525111 chore(deps): weekly cargo update (#23267)
Co-authored-by: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com>
2026-03-29 06:19:38 +00:00
DaniPopes
49339780c0 perf: use FastInstant for remaining metrics timing (#23265) 2026-03-29 06:01:22 +00:00
Dan Cline
27781443a6 chore(cli): add more WARN logging before we retry a download (#23258) 2026-03-28 04:59:16 +00:00
Arsenii Kulikov
afdf905295 feat: add a method to get payload resolve future (#23256) 2026-03-28 04:58:07 +00:00
Derek Cofausper
d2d2f34409 refactor(engine): remove op PayloadAttributesBuilder impl and op feature from engine-local (#23255)
Co-authored-by: Matthias Seitz <19890894+mattsse@users.noreply.github.com>
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2026-03-27 18:25:28 +00:00
Matt Stam
4f34ac7e10 fix(consensus): retry block subscription on initial connection failure (#23233) 2026-03-27 16:55:59 +00:00
joshieDo
29bab063b7 feat(engine): share sparse trie pipeline with payload builder (#23246)
Co-authored-by: Amp <amp@ampcode.com>
2026-03-27 16:35:03 +00:00
Derek Cofausper
9d360728f3 refactor(payload): remove op ExecutionPayload impl and op feature from payload-primitives (#23253)
Co-authored-by: Matthias Seitz <19890894+mattsse@users.noreply.github.com>
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2026-03-27 16:03:58 +00:00
Arsenii Kulikov
9db411efce chore: relax rpc converter impls (#23254) 2026-03-27 17:19:24 +01:00
Marco Lombardi
3208a4a615 fix(engine): avoid double decrement in account cache size (#23249) 2026-03-27 07:42:32 +00:00
AKABABA-ETH
7096d6ce1a fix(trie): use Entry API in MultiProofTargets::extend_inner (#23247) 2026-03-27 06:31:12 +00:00
Arsenii Kulikov
e3dbdbb115 feat: share execution cache with payload builder (#23242) 2026-03-26 16:03:07 +00:00
Muzry
0cbd0aa4cf chore(engine): return -38003 for FCUv2 payloadAttributes mismatch (#22924) 2026-03-26 14:07:18 +00:00
Sergei Shulepov
dba8b21aa7 fix(trie): before prune call root (#23243) 2026-03-26 12:31:13 +00:00
Matthias Seitz
ef0095b565 chore: bump alloy 1.8.2 (#23241) 2026-03-26 11:20:59 +01:00
Tim
b3dd2e246d feat: add hourly main regression bench (#23219) 2026-03-26 09:51:00 +00:00
stevencartavia
eb663aeaac chore(docker): bump lighthouse v8.1.3 (#23239) 2026-03-26 04:47:27 +00:00
Alexey Shekhirin
7f4a9a05ef fix(cli): use storage.v2 flag for storage settings (#23236) 2026-03-25 21:57:42 +00:00
DaniPopes
d3c3466c44 chore: make EvmConfig generic in examples (#23229) 2026-03-25 19:28:26 +00:00
Matthias Seitz
fb62487148 chore: bump alloy 1.8.1 (#23228) 2026-03-25 15:36:27 +00:00
Brian Picciano
401e751088 bench(ci): reuse cached big-block fixtures and select snapshot from manifest (#23193)
Co-authored-by: Brian Picciano <933154+mediocregopher@users.noreply.github.com>
Co-authored-by: Amp <amp@ampcode.com>
2026-03-25 15:16:43 +00:00
Derek Cofausper
7d31bb176c chore: remove deprecated reth-primitives crate (#23220)
Co-authored-by: Matthias Seitz <19890894+mattsse@users.noreply.github.com>
2026-03-25 14:51:16 +00:00
Sergei Shulepov
50ce26f719 fix(trie): preserve prune invariants across sparse trie impls (#23226) 2026-03-25 14:41:34 +00:00
Derek Cofausper
4094d677e4 feat: enable jemalloc override_allocator_on_supported_platforms (#23214)
Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com>
2026-03-25 14:38:31 +00:00
Arsenii Kulikov
a37f91e6c0 refactor(tests): use FCU for requesting new payloads (#23222) 2026-03-25 14:22:59 +00:00
Alexey Shekhirin
78b97e81b7 fix(engine): do not report metrics for already seen payloads (#23227) 2026-03-25 14:17:50 +00:00
Emma Jamieson-Hoare
aedda7f6ad fix(engine): emit slow block log immediately after execution (#23225)
Co-authored-by: Amp <amp@ampcode.com>
2026-03-25 14:07:31 +00:00
stevencartavia
acc7b56e31 perf(payload): avoid tx clone in block building loop (#23180)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2026-03-25 13:18:33 +00:00
dependabot[bot]
87077ddcde chore(deps): bump the cargo-weekly group across 1 directory with 2 updates (#23211)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2026-03-25 11:40:59 +00:00
Derek Cofausper
5a66d0064c refactor(engine): extract PayloadExecutionCache into reth-execution-cache crate (#23209)
Co-authored-by: Arsenii Kulikov <62447812+klkvr@users.noreply.github.com>
2026-03-25 11:08:01 +00:00
Derek Cofausper
6183361f83 refactor: replace reth-primitives-traits with git dep to reth-core (#23210)
Co-authored-by: Arsenii Kulikov <62447812+klkvr@users.noreply.github.com>
2026-03-25 10:33:06 +00:00
Derek Cofausper
e91a900dd7 feat(engine): log in-flight persistence action in persist_until_complete (#23204)
Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com>
2026-03-25 09:30:00 +00:00
Matthias Seitz
33ec89994e feat(txpool): add TransactionValidationTaskExecutor::spawn (#23196) 2026-03-25 08:28:56 +00:00
Sergei Shulepov
80094e1bda fix(trie): avoid boundary parent unwrap panic in parallel sparse reveal (#23171) 2026-03-25 07:12:19 +00:00
Derek Cofausper
2e5730b6b5 chore(cli): suppress unused tracy_client dependency warning (#23212)
Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com>
2026-03-25 01:05:26 +00:00
Arsenii Kulikov
677d07041e refactor: use reth-core deps (#23186) 2026-03-24 21:56:25 +00:00
AKABABA-ETH
8606df3075 fix: remove apt-get upgrade from hive Dockerfile (#23206) 2026-03-24 18:12:36 +00:00
Arsenii Kulikov
cf83b198d3 refactor: remove PayloadBuilderAttributes (#23202) 2026-03-24 17:57:05 +00:00
DaniPopes
52ab4223a0 chore(meta): rename CLAUDE.md to AGENTS.md, symlink CLAUDE.md to it (#23203) 2026-03-24 17:51:51 +00:00
Matthias Seitz
15338b8113 chore: remove unused Extended type and op feature from primitives-traits (#23198) 2026-03-24 14:06:33 +00:00
Matthias Seitz
b3f5e62494 fix(init): track actual byte size instead of account count in dump_state (#23190) 2026-03-24 09:13:32 +00:00
Arsenii Kulikov
7b4c07338e refactor: simplify compact impls for scale types (#23185) 2026-03-23 23:20:10 +00:00
Arsenii Kulikov
bbed2e9ebf chore: unify InMemorySize (#23184)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2026-03-23 21:02:33 +00:00
Derek Cofausper
8c6e67bbaa fix(download): retry on extraction failure in resumable modular downloads (#23054)
Co-authored-by: Dan Cline <6798349+Rjected@users.noreply.github.com>
2026-03-23 19:51:13 +00:00
Derek Cofausper
8bb96ace64 refactor: remove SerdeBincodeCompat trait, use RLP for block serialization (#23158)
Co-authored-by: Arsenii Kulikov <62447812+klkvr@users.noreply.github.com>
Co-authored-by: Arsenii Kulikov <klkvrr@gmail.com>
2026-03-23 18:45:30 +00:00
Derek Cofausper
81dc5e2136 perf: disable readahead on slot-preimage MDBX environment (#23183)
Co-authored-by: joshieDo <93316087+joshieDo@users.noreply.github.com>
2026-03-23 18:26:42 +00:00
Derek Cofausper
ad00546081 feat(bench): add --wait-for-persistence flag (#23176)
Co-authored-by: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com>
2026-03-23 16:11:13 +00:00
Arsenii Kulikov
cc0c29e449 fix: always reinsert reorged blocks (#23175) 2026-03-23 14:15:36 +00:00
Derek Cofausper
bdcc262bbb chore(bench): tag tim and alexey on nightly bench failures (#23174)
Co-authored-by: Emma Jamieson-Hoare <21029500+emmajam@users.noreply.github.com>
2026-03-23 14:04:45 +00:00
Emma Jamieson-Hoare
0c90359be6 chore: fix build hive jobs (#23169)
Co-authored-by: Amp <amp@ampcode.com>
2026-03-23 14:04:12 +00:00
Alexey Shekhirin
b8aca9586a fix(cli): --storage.v2 without explicit true/false (#23173) 2026-03-23 13:42:21 +00:00
figtracer
fbbadab3be feat(net): include discv5 ENR data in admin_nodeInfo response (#23170) 2026-03-23 13:16:20 +00:00
figtracer
e0d40df3df perf(net): size-based backpressure for session broadcast messages (#22849) 2026-03-23 12:15:34 +00:00
Derek Cofausper
ff217592bc feat(tree): add idle time metrics to SparseTrieCacheTask and hashing task (#23136)
Co-authored-by: Brian Picciano <933154+mediocregopher@users.noreply.github.com>
Co-authored-by: Brian Picciano <me@mediocregopher.com>
Co-authored-by: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com>
Co-authored-by: Dan Cline <6798349+Rjected@users.noreply.github.com>
Co-authored-by: Alexey Shekhirin <github@shekhirin.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: YK <46377366+yongkangc@users.noreply.github.com>
Co-authored-by: YK <chiayongkang@hotmail.com>
Co-authored-by: amp[bot] <noreply@ampcode.com>
2026-03-23 11:52:33 +00:00
Derek Cofausper
a9b6969e77 fix: avoid OOM during init-state by dropping prefix sets (#23166)
Co-authored-by: Matthias Seitz <19890894+mattsse@users.noreply.github.com>
2026-03-23 11:37:48 +00:00
Emma Jamieson-Hoare
4338fb2631 chore(ci): ping AI agent on nightly Docker build failure (#23168)
Co-authored-by: Amp <amp@ampcode.com>
2026-03-23 11:14:42 +00:00
Crypto Nomad
cc6d14a2ca perf(rpc): avoid cloning InvalidBlock sealed block (#23162) 2026-03-23 10:54:11 +00:00
Derek Cofausper
cfab0c6371 chore(engine): downgrade yielded transaction log to trace (#22597)
Co-authored-by: Amp <amp@ampcode.com>
2026-03-23 10:26:21 +00:00
Matthias Seitz
bc7d585506 docs(consensus): document the validation pipeline and trait hierarchy (#22869) 2026-03-23 09:54:55 +00:00
Derek Cofausper
4bfc0083c9 docs: clarify transaction pool link wording (#23160)
Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com>
2026-03-22 21:41:38 +00:00
MagicJoshh
3d1dc4d9e2 fix(rpc): return error instead of empty response for missing blocks in debug_getRaw (#22675)
Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com>
2026-03-22 21:31:38 +00:00
Arsenii Kulikov
c9e9db184e fix: gracefully shut down engine (#23159) 2026-03-22 19:52:53 +00:00
Matthias Seitz
2d2778fa24 revert: "fix(engine/tree): continue sync-target progression for already-seen downloaded blocks" (#23157) 2026-03-22 17:17:35 +00:00
Arsenii Kulikov
7551d9c5dd refactor: remove bincode usage from HeaderStage (#23156) 2026-03-22 17:04:18 +00:00
stevencartavia
182f39db67 perf(engine): clone block body instead of full block for tx root task (#23147) 2026-03-22 04:08:55 +00:00
github-actions[bot]
e738bd34b3 chore(deps): weekly cargo update (#23148)
Co-authored-by: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com>
2026-03-22 01:14:35 +00:00
stevencartavia
6fb5337786 perf(rpc): avoid cloning block env in pending block builder (#23144)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2026-03-21 04:51:47 +00:00
stevencartavia
f1c71d0c2e perf(rpc): remove redundant block id resolution in debug_trace_block (#23128) 2026-03-21 04:17:59 +00:00
Matthias Seitz
76e45117da chore(deps): allow lru advisory and bump rustls-webpki (#23145) 2026-03-21 05:04:27 +01:00
stevencartavia
40eb2d63e8 refactor(rpc): simplify block_transaction_count (#23139) 2026-03-20 14:44:01 +00:00
Derek Cofausper
b5581bd6c2 perf(engine): downgrade prewarm per-tx span from debug to trace (#23138)
Co-authored-by: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com>
Co-authored-by: Dan Cline <6798349+Rjected@users.noreply.github.com>
Co-authored-by: Alexey Shekhirin <github@shekhirin.com>
Co-authored-by: Brian Picciano <me@mediocregopher.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: YK <46377366+yongkangc@users.noreply.github.com>
Co-authored-by: YK <chiayongkang@hotmail.com>
Co-authored-by: Brian Picciano <933154+mediocregopher@users.noreply.github.com>
2026-03-20 14:22:23 +00:00
Brian Picciano
439f1f9af2 chore(bench): eliminate gas ramp step from big block benchmarks (#23088)
Co-authored-by: Derek Cofausper <256792747+decofe@users.noreply.github.com>
Co-authored-by: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com>
Co-authored-by: Dan Cline <6798349+Rjected@users.noreply.github.com>
Co-authored-by: Alexey Shekhirin <github@shekhirin.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: YK <46377366+yongkangc@users.noreply.github.com>
Co-authored-by: YK <chiayongkang@hotmail.com>
Co-authored-by: Brian Picciano <933154+mediocregopher@users.noreply.github.com>
2026-03-20 13:27:55 +00:00
Tim
303ea0ff61 feat: bench-scheduled support v2 snapshot (#23133) 2026-03-20 13:27:02 +00:00
Derek Cofausper
70ed24ac38 refactor(bench): use alloy RetryBackoffLayer for RPC block fetch retries (#23137)
Co-authored-by: Brian Picciano <933154+mediocregopher@users.noreply.github.com>
2026-03-20 13:00:01 +00:00
Derek Cofausper
43e08f1539 refactor(engine): make arena sparse trie the default and remove flag (#23131)
Co-authored-by: Brian Picciano <933154+mediocregopher@users.noreply.github.com>
2026-03-20 12:25:57 +00:00
Sergei Shulepov
3c63fb6b1f perf(trie): fused prune+compact with accurate memory_size (#23124)
Co-authored-by: Amp <amp@ampcode.com>
2026-03-20 12:14:06 +00:00
Arsenii Kulikov
72d0e04d85 fix: change DEFAULT_IGNORE_GAS_PRICE (#23134) 2026-03-20 11:41:22 +00:00
Matthias Seitz
9906da5504 fix: addr shadowing (#23135) 2026-03-20 11:27:29 +00:00
stevencartavia
cf3028a52f perf(rpc): avoid storage access clone (#23129) 2026-03-20 11:15:35 +00:00
Derek Cofausper
6259cb86f8 test(rocksdb): add storage history pruning regression test (#23087)
Co-authored-by: Dan Cline <6798349+Rjected@users.noreply.github.com>
Co-authored-by: YK <46377366+yongkangc@users.noreply.github.com>
2026-03-20 04:29:39 +00:00
Derek Cofausper
89ad00601e chore: remove reth-bench-compare (#23123)
Co-authored-by: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com>
Co-authored-by: Alexey Shekhirin <github@shekhirin.com>
2026-03-19 18:27:08 +00:00
Derek Cofausper
88bc262bd1 feat(bench): add wait_for_* arguments to reth_newPayload (#22784)
Co-authored-by: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com>
Co-authored-by: Alexey Shekhirin <github@shekhirin.com>
2026-03-19 17:55:05 +00:00
Derek Cofausper
d63518d18c feat(node-core): add DefaultLogArgs for customizable log defaults (#23122)
Co-authored-by: Matthias Seitz <19890894+mattsse@users.noreply.github.com>
2026-03-19 16:22:55 +00:00
Matthias Seitz
b8baaf6aa7 chore(tracing): filter noisy rustls and tungstenite logs (#23121) 2026-03-19 15:46:53 +00:00
Derek Cofausper
2a94eedd61 feat(storage): return --storage.v2 flag (#23120)
Co-authored-by: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com>
Co-authored-by: Alexey Shekhirin <github@shekhirin.com>
2026-03-19 15:18:51 +00:00
Alexey Shekhirin
20cce0a6df perf(reth-bench): fetch RPC blocks in parallel (#23117) 2026-03-19 14:50:15 +00:00
Derek Cofausper
6736b2ad65 test(rocksdb): add historical account balance and nonce queries (#23079)
Co-authored-by: Dan Cline <6798349+Rjected@users.noreply.github.com>
2026-03-19 13:53:53 +00:00
Sergei Shulepov
1e17f7cf67 refactor(trie): don't bother about recycling subtries (#23115) 2026-03-19 12:16:21 +00:00
Derek Cofausper
bd476289fa fix(stages): overwrite Destroyed revert slots when injecting preimages (#23114)
Co-authored-by: joshieDo <93316087+joshieDo@users.noreply.github.com>
2026-03-19 11:51:31 +00:00
stevencartavia
7f12c9d993 perf(rpc): avoid redundant receipt cache lookup in eth_getTransactionReceipt (#23074) 2026-03-19 11:20:44 +00:00
dependabot[bot]
7758afd75d chore(deps): bump actions/upload-artifact from 6 to 7 (#22966)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-19 11:16:42 +00:00
Derek Cofausper
eae7813aca chore(bench): use reth download for snapshot management (#23004)
Co-authored-by: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com>
Co-authored-by: Dan Cline <6798349+Rjected@users.noreply.github.com>
Co-authored-by: Alexey Shekhirin <github@shekhirin.com>
Co-authored-by: YK <46377366+yongkangc@users.noreply.github.com>
Co-authored-by: YK <chiayongkang@hotmail.com>
2026-03-19 10:41:14 +00:00
Brian Picciano
bab6c3fe0f feat(trie): Use proof v2 in TrieWitness (#22922)
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Alexey Shekhirin <github@shekhirin.com>
2026-03-19 10:16:56 +00:00
stevencartavia
fe611ab379 perf(rpc): avoid header clone in logs_for_filter (#23106) 2026-03-19 10:11:43 +00:00
Sergei Shulepov
12c7a2f005 fix(arena): recreate arena not shrink. (#23073)
Co-authored-by: Amp <amp@ampcode.com>
2026-03-19 09:51:05 +00:00
Derek Cofausper
1bedd68278 fix(provider): open RocksDB read-only in ProviderFactoryBuilder::open_read_only (#23109)
Co-authored-by: YK <46377366+yongkangc@users.noreply.github.com>
2026-03-19 09:08:07 +00:00
Derek Cofausper
dd51a75a78 chore(ci): remove pull_request trigger from bench-scheduled (#23105)
Co-authored-by: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com>
2026-03-19 00:46:24 +00:00
Ayush Baluni
a14db7f0ca fix(net): disable Discv5 ENR auto-update when NAT disabled or explicit addr set (#23075) 2026-03-18 21:47:31 +00:00
Derek Cofausper
c91845ae44 feat(prune): make minimum pruning distance configurable (#23082)
Co-authored-by: Dan Cline <6798349+Rjected@users.noreply.github.com>
2026-03-18 21:07:43 +00:00
Derek Cofausper
f61098ec00 fix(provider): gate rocksdb jemalloc behind feature flag (#23061)
Co-authored-by: Dan Cline <6798349+Rjected@users.noreply.github.com>
2026-03-18 18:53:30 +00:00
Tim
240fcf164e feat: add nightly bench runs (#23095) 2026-03-18 18:26:50 +00:00
Derek Cofausper
365b6274da ci(bench): add otlp toggle argument (#23092)
Co-authored-by: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com>
2026-03-18 17:14:52 +00:00
Sergei Shulepov
ab90477ed6 fix(trie): another branch collapse edge-case (#23089)
Co-authored-by: Amp <amp@ampcode.com>
2026-03-18 17:09:16 +00:00
Arsenii Kulikov
2778a063ad fix: use zero gas price for empty blocks (#23094) 2026-03-18 17:04:50 +00:00
Dan Cline
a83d5453bd fix(provider): fix race between save_blocks and rocksdb pruning (#23081) 2026-03-18 16:58:14 +00:00
Chase Wright
ce1d091ad2 fix(ethstats): Re-enable TLS in tokio-tungstenite (#23090)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2026-03-18 16:57:13 +00:00
AKABABA-ETH
10b1b4522c fix(p2p): apply sessions config from reth.toml in p2p subcommand (#23078) 2026-03-18 12:36:26 +00:00
Derek Cofausper
7bf9241fe6 fix(provider): disable read transaction timeout during check_consistency (#23083)
Co-authored-by: Arsenii Kulikov <62447812+klkvr@users.noreply.github.com>
Co-authored-by: Alexey Shekhirin <github@shekhirin.com>
2026-03-18 12:07:25 +00:00
Artyom Bakhtin
1a0e982ead fix(metrics): Rename more instances of invalid save_blocks_block_count (#22915)
Signed-off-by: bakhtin <a@bakhtin.net>
2026-03-18 11:59:24 +00:00
Nicolas SSS
d148f39cca refactor(chainspec): remove unused once_cell_set utility (#23043) 2026-03-18 11:54:16 +00:00
Crypto Nomad
7c53936634 fix(rpc): export EthConfigApi in aggregate modules (#23068) 2026-03-18 13:12:34 +01:00
stevencartavia
a9ff59fc64 perf(rpc): avoid request clone in eth_createAccessList (#23085) 2026-03-18 10:58:19 +00:00
stevencartavia
5de969a1be perf(rpc): avoid cloning tx in pending block builder (#23077) 2026-03-18 09:45:44 +00:00
Derek Cofausper
ae2c916f61 refactor(storage): use RocksReadSnapshot for read-only compatible RocksDB reads (#23067)
Co-authored-by: Tim <12827757+laibe@users.noreply.github.com>
Co-authored-by: joshieDo <93316087+joshieDo@users.noreply.github.com>
Co-authored-by: Amp <amp@ampcode.com>
2026-03-17 18:03:08 +00:00
Brian Picciano
6097cf9ee7 fix(trie): Fix branch collapse edge-cases in ArenaParallelSparseTrie (#23053)
Signed-off-by: Delweng <delweng@gmail.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: stevencartavia <112043913+stevencartavia@users.noreply.github.com>
Co-authored-by: Derek Cofausper <256792747+decofe@users.noreply.github.com>
Co-authored-by: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com>
Co-authored-by: MagicJoshh <subhshubham398@gmail.com>
Co-authored-by: Delweng <delweng@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com>
Co-authored-by: Huber <HuberyJulianay@gmail.com>
Co-authored-by: Sergei Shulepov <2205845+pepyakin@users.noreply.github.com>
Co-authored-by: Olivier Dupont <olivierdupontvier@gmail.com>
Co-authored-by: YK <chiayongkang@hotmail.com>
Co-authored-by: Crypto Nomad <cryptonomadkripto@gmail.com>
Co-authored-by: ligt <me@ligt.dev>
Co-authored-by: Sergei Shulepov <pep@tempo.xyz>
2026-03-17 17:10:23 +00:00
stevencartavia
75fa61377a perf(rpc): avoid redundant next_env_attributes call in simulate_v1 (#23064) 2026-03-17 16:15:55 +00:00
Derek Cofausper
de3033d285 fix(provider): add ensure_canonical_block guard to history_by_block_hash (#22876)
Co-authored-by: Matthias Seitz <19890894+mattsse@users.noreply.github.com>
Co-authored-by: joshieDo <93316087+joshieDo@users.noreply.github.com>
2026-03-17 16:11:32 +00:00
Delweng
55ed7d5bb5 perf(engine): check hashmap instead of clone (#23071)
Signed-off-by: Delweng <delweng@gmail.com>
2026-03-17 14:00:45 +00:00
Derek Cofausper
a0b0d8854c fix(storage): preserve genesis history entries in RocksDB consistency check (#23033)
Co-authored-by: Arsenii Kulikov <62447812+klkvr@users.noreply.github.com>
Co-authored-by: Arsenii Kulikov <klkvrr@gmail.com>
2026-03-17 12:35:04 +00:00
Brian Picciano
5e744326a4 feat(trie): proof_v2 prefix set support (#22946)
Co-authored-by: Amp <amp@ampcode.com>
2026-03-17 12:03:25 +00:00
Delweng
0aff4cc8da fix(net): treat malformed blob sidecar responses as peer misbehavior (#23035)
Signed-off-by: Delweng <delweng@gmail.com>
2026-03-17 10:59:50 +00:00
theo
58142d5e16 chore: remove op-revm dep (#23059) 2026-03-17 10:33:41 +00:00
Derek Cofausper
b7eb508484 feat(fs-util): add remove_file_if_exists helper (#23065)
Co-authored-by: Matthias Seitz <19890894+mattsse@users.noreply.github.com>
2026-03-17 10:32:53 +00:00
MagicJoshh
d8ae156f64 fix(rpc): export Client traits instead of Server in clients module (#23058) 2026-03-17 09:43:43 +00:00
Brian Picciano
35dc30561f perf(trie): call update_subtrie_hashes after every update (#23052) 2026-03-16 17:16:05 +00:00
ligt
5e1e994d11 chore(engine-tree): simplify return type of canonical_block_by_hash (#23048) 2026-03-16 11:56:42 +00:00
Crypto Nomad
ce850c4fc3 fix(rpc): clone EthSigner trait objects with generic tx request (#23050) 2026-03-16 11:11:55 +00:00
Olivier Dupont
89bc38be1c fix(rpc): remove redundant TransportRpcModuleConfig clone in builder (#22945)
Co-authored-by: YK <chiayongkang@hotmail.com>
2026-03-16 10:22:26 +00:00
Derek Cofausper
acdbd065e2 chore(bench): add rich job summary matching Slack output (#23046)
Co-authored-by: Sergei Shulepov <2205845+pepyakin@users.noreply.github.com>
2026-03-16 10:12:35 +00:00
609 changed files with 18565 additions and 26798 deletions

View File

@@ -1,4 +0,0 @@
---
---
Added site-level meta description for SEO.

View File

@@ -1,5 +0,0 @@
---
reth-transaction-pool: patch
---
Renamed and documented validation methods for clarity. `validate_one_no_state` and `validate_one_against_state` are now public methods `validate_stateless` and `validate_stateful` with improved documentation explaining their respective validation phases.

View File

@@ -1,10 +0,0 @@
---
reth-engine-primitives: patch
reth-engine-tree: patch
reth-node-core: patch
reth-trie-parallel: minor
---
Removed legacy proof calculation system and V2-specific configuration flags.
Removed the legacy (non-V2) proof calculation code paths, simplified multiproof task architecture by removing the dual-mode system, and cleaned up V2-specific CLI flags (`--engine.disable-proof-v2`, `--engine.disable-trie-cache`) that are no longer needed. The codebase now exclusively uses V2 proofs with the sparse trie cache.

View File

@@ -1,5 +0,0 @@
---
reth-trie-sparse: patch
---
Refactored sparse trie node state tracking to use RLP nodes instead of hashes. Replaced `Option<B256>` hash fields with `SparseNodeState` enum that tracks either dirty nodes or cached RLP nodes with optional database storage flags. Added debug assertions to validate leaf path lengths and improved pruning logic to use node paths directly instead of path-hash tuples.

View File

@@ -1,20 +0,0 @@
# Changelogs configuration for reth
# https://github.com/wevm/changelogs
# How to bump packages that depend on changed packages
dependent_bump = "patch"
[changelog]
# Generate per-crate changelogs (vs single root changelog)
format = "per-crate"
# Fixed groups: all always share the same version
# reth binaries share version
[[fixed]]
members = ["reth"]
# Packages to ignore (internal/test-only crates)
ignore = [
"reth-testing-utils",
"reth-bench",
]

View File

@@ -1,5 +0,0 @@
---
reth-trie-sparse: patch
---
Fixed a bug in `merge_subtrie_updates` where source insertions did not cancel destination removals (and vice versa), causing inconsistent trie updates accumulated across multiple `root()` calls without intermediate `take_updates()`. Added a test covering the cross-cancellation behavior.

View File

@@ -1,5 +0,0 @@
---
reth-transaction-pool: minor
---
Added support for optional custom stateless and stateful validation hooks in `EthTransactionValidator` via `set_additional_stateless_validation` and `set_additional_stateful_validation` methods. Also implemented a manual `Debug` impl to handle the non-`Debug` function pointer fields.

View File

@@ -1,17 +0,0 @@
---
reth: minor
reth-cli-commands: minor
reth-e2e-test-utils: minor
reth-ethereum-cli: minor
reth-node-core: minor
reth-optimism-bin: minor
reth-optimism-cli: minor
reth-prune: patch
reth-stages: patch
reth-storage-api: minor
reth-storage-db-api: minor
reth-storage-db-common: patch
reth-storage-provider: patch
---
Introduced `--storage.v2` flag to control storage mode defaults, replacing the `edge` feature flag with `rocksdb` feature. The new flag enables v2 storage settings (static files + RocksDB routing) while individual `--static-files.*` and `--rocksdb.*` flags can still override defaults. Updated feature gates from `edge` to `rocksdb` across all affected crates.

View File

@@ -1,5 +0,0 @@
---
reth-tasks: patch
---
Added panic handler to all rayon thread pools that logs panics via `tracing::error` instead of aborting the process.

View File

@@ -1,5 +0,0 @@
---
reth: patch
---
Removed Windows platform support from the codebase, including the Windows cross-compilation Dockerfile, build targets in Cross.toml and Makefile, and Windows-specific options in the bug report template.

View File

@@ -1,5 +0,0 @@
---
reth-network: minor
---
Added reason label to backed_off_peers metric. The metric now tracks backed off peers by reason (too_many_peers, graceful_close, connection_error) to improve observability.

View File

@@ -1,5 +0,0 @@
---
reth-network-types: patch
---
Increased default maximum concurrent outbound dials from 15 to 30.

View File

@@ -1,5 +0,0 @@
---
reth-trie-sparse: patch
---
Refactored arena trie internals by adding a `BranchChildIdx::sibling()` helper, deduplicating `Index`/`NodeArena` type aliases, and replacing `is_empty()` with a `drop_root()` method. Fixed a bug where `cursor.pop()` was called before checking if the leaf was the root node, which could cause incorrect dirty-state propagation.

View File

@@ -1,5 +0,0 @@
---
reth-trie-sparse: patch
---
Added recording of `SetRoot` operation in `ParallelSparseTrie::set_root` when the `trie-debug` feature is enabled.

View File

@@ -1,5 +0,0 @@
---
reth-trie-sparse-parallel: patch
---
Fixed parallel sparse trie to skip revealing disconnected leaves by checking parent branch reachability before inserting leaf nodes.

View File

@@ -1,5 +0,0 @@
---
ef-tests: patch
---
Removed reth-stateless crate and stateless validation from ef-tests.

View File

@@ -1,6 +0,0 @@
---
reth-rpc-convert: minor
reth-storage-rpc-provider: minor
---
Replaced the separate `TryFromBlockResponse`, `TryFromReceiptResponse`, and `TryFromTransactionResponse` traits with a unified `RpcResponseConverter` trait and default `EthRpcConverter` implementation. Removed the `op-alloy-network` dependency and refactored `RpcBlockchainProvider` to store a dynamic converter instance instead of relying on per-type trait bounds.

View File

@@ -1,6 +0,0 @@
---
reth-engine-tree: patch
reth-trie-sparse-parallel: patch
---
Added tracing spans and debug logs to sparse trie operations for better observability during parallel state root computation.

View File

@@ -1,6 +0,0 @@
---
reth-exex: patch
reth-exex-types: patch
---
Added configurable backfill thresholds to ExEx notifications stream and added regression tests for state provider parity between pipeline and backfill execution paths.

View File

@@ -1,5 +0,0 @@
---
reth-payload-builder: minor
---
Added observability metrics for payload resolve latency and new payload job creation latency to the payload builder service.

View File

@@ -1,4 +0,0 @@
---
---
Added WebSocket subscription integration tests for eth_subscribe.

View File

@@ -1,5 +0,0 @@
---
reth-transaction-pool: minor
---
Added `consensus_ref` method to `PoolTransaction` trait for borrowing consensus transactions without cloning.

View File

@@ -1,4 +0,0 @@
---
---
Improved nightly Docker build failure Slack notification with more detailed formatting and context.

View File

@@ -1,10 +0,0 @@
---
reth-chain-state: minor
reth-engine-primitives: minor
reth-engine-tree: minor
reth-node-core: minor
reth-node-events: minor
reth: patch
---
Added configurable slow block logging (`--engine.slow-block-threshold`) that emits a structured `warn!` log with detailed timing, state-operation counts, and cache hit-rate metrics for blocks whose total processing time exceeds the threshold. Introduced `ExecutionTimingStats`, `CacheStats`, `StateProviderStats`, and `SlowBlockInfo` types to carry execution statistics from block validation through persistence, and refactored `PersistenceResult` to carry commit duration alongside the last persisted block.

View File

@@ -1,5 +0,0 @@
---
reth-rpc-eth-types: patch
---
Updated `eth_simulateV1` revert error code from `-32000` to `3` to be consistent with `eth_call`, per [execution-apis#748](https://github.com/ethereum/execution-apis/pull/748).

View File

@@ -1,5 +0,0 @@
---
reth-engine-tree: patch
---
Reordered cache size calculations in `ExecutionCache::new` to group related operations together.

View File

@@ -1,7 +0,0 @@
---
reth: patch
reth-cli-commands: patch
reth-node-core: patch
---
Removed experimental ress protocol support for stateless Ethereum nodes.

View File

@@ -1,6 +0,0 @@
---
reth-trie-db: minor
reth-engine-tree: minor
---
Added `PendingChangeset` and `PendingChangesetGuard` to `ChangesetCache` so concurrent readers wait for an in-progress computation instead of falling back to the expensive DB-based path. The guard automatically cancels the pending entry on drop (e.g. task panic), ensuring waiters always make progress.

View File

@@ -1,5 +0,0 @@
---
reth-engine-tree: patch
---
Added sub-phase timing histograms to the sparse trie event loop, tracking channel wait, proof coalescing, multiproof reveal, and trie update durations separately.

View File

@@ -1,5 +0,0 @@
---
reth-node-builder: patch
---
Removed biased select in engine service loop to allow fair scheduling of shutdown requests alongside event processing.

View File

@@ -1,5 +0,0 @@
---
reth-transaction-pool: patch
---
Fixed swapped arguments in `blob_tx_priority` function calls, correcting the parameter order to match the function signature.

View File

@@ -1,4 +0,0 @@
---
---
Improved documentation overview page with better structure and clarity.

View File

@@ -1,5 +0,0 @@
---
reth: patch
---
Re-enabled changelog workflow to run automatically on pull requests.

View File

@@ -1,5 +0,0 @@
---
reth-node-events: patch
---
Updated consensus engine log message to be more accurate about received updates.

View File

@@ -1,8 +0,0 @@
---
reth-engine-primitives: minor
reth-engine-tree: minor
reth-node-core: minor
reth-trie-parallel: minor
---
Added `--engine.proof-jitter` CLI option behind the `trie-debug` feature flag. When set, each proof worker sleeps for a random duration up to the specified value before starting proof computation, useful for stress-testing timing-sensitive proof logic.

View File

@@ -1,6 +0,0 @@
---
reth-rpc-eth-api: minor
reth-rpc-server-types: minor
---
Added `eth_getStorageValues` RPC method for batch storage slot retrieval across multiple addresses.

View File

@@ -1,6 +0,0 @@
---
reth-chainspec: minor
reth-network-peers: minor
---
Removed OP stack bootnodes from default chain configurations and network peers module.

View File

@@ -1,5 +0,0 @@
---
reth-rpc-convert: patch
---
Updated `alloy-evm` dependency to git revision `9bc2dba` and adapted `TxEnvConverter` impl to the updated `TryIntoTxEnv` trait signature that now includes a `Spec` generic parameter.

View File

@@ -1,6 +0,0 @@
---
reth-trie: patch
reth-trie-sparse: patch
---
Refactored test harness for sparse trie tests by extracting `TrieTestHarness` into a shared `reth-trie` test utility, replacing duplicated inline harness code across multiple test modules. Updated `proof_v2` return type to include an optional root hash, and converted `original_root` and `storage` from public fields to accessor methods.

View File

@@ -1,5 +0,0 @@
---
reth-trie: patch
---
Removed the local `increment_and_strip_trailing_zeros` function and `PATH_ALL_ZEROS` static in `proof_v2`, replacing them with the equivalent `Nibbles::next_without_prefix` and `Nibbles::is_zeroes` builtins. Also replaced manual `.get()` calls on `state_mask`/`hash_mask` with direct field access and switched to `Nibbles::unpack_array` over the unsafe `unpack_unchecked`.

View File

@@ -1,9 +0,0 @@
---
reth-network-api: minor
reth-network-types: minor
reth-network: minor
reth-node-core: minor
reth: minor
---
Added optional ENR fork ID enforcement to filter out peers from incompatible networks during peer discovery, controlled by the `--enforce-enr-fork-id` CLI flag.

View File

@@ -1,5 +0,0 @@
---
reth-primitives: patch
---
Moved feature-referenced dependencies from dev-dependencies to optional dependencies to ensure they are available when their corresponding features are enabled.

View File

@@ -1,5 +0,0 @@
---
reth-engine-tree: patch
---
Fixed `compare_trie_updates` to return `bool` indicating whether differences were found, and updated the caller to properly use the return value instead of treating all successful comparisons as having no differences.

View File

@@ -1,7 +0,0 @@
---
reth-cli-commands: minor
reth-node-core: minor
reth: patch
---
Made v2 storage the default for all new databases, deprecating the `--storage.v2` flag to a hidden no-op kept for backwards compatibility. Updated CLI reference docs to remove the now-hidden flag from all command help pages.

View File

@@ -1,5 +0,0 @@
---
reth-node-core: minor
---
Added `with_dev_block_time` helper method to `NodeConfig` for configuring dev miner block production interval.

View File

@@ -1,5 +0,0 @@
---
reth-transaction-pool: minor
---
Added `IntoIter: Send` bounds to `validate_transactions` and `validate_transactions_with_origin` in the `TransactionValidator` trait, avoiding unnecessary `Vec` collects. Simplified default `validate_transactions_with_origin` to delegate to `validate_transactions`.

View File

@@ -1,5 +0,0 @@
---
reth-db-api: patch
---
Changed `StoredNibblesSubKey` encoding to use a stack-allocated `[u8; 65]` array instead of a heap-allocated `Vec<u8>`, avoiding unnecessary heap allocation.

View File

@@ -1,7 +0,0 @@
---
reth-engine-tree: patch
reth-trie-sparse: patch
reth-tasks: patch
---
Offloaded deallocation of expensive proof node buffers to a persistent background thread (`Runtime::spawn_drop`) to avoid blocking state root computation or lock-holding code.

View File

@@ -1,5 +0,0 @@
---
reth-storage-api: patch
---
Added `Arc` to `auto_impl` derive for storage-api traits to support automatic `Arc` wrapper implementations.

View File

@@ -1,8 +0,0 @@
---
reth: patch
reth-engine-tree: patch
reth-node-builder: patch
reth-trie-sparse: minor
---
Added `trie-debug` feature for recording sparse trie mutations to aid in debugging state root mismatches.

View File

@@ -1,6 +0,0 @@
---
reth-static-file-types: patch
reth-provider: patch
---
Move changeset offsets from segment header to external `.csoff` sidecar file for incremental writes and crash recovery.

View File

@@ -1,5 +0,0 @@
---
reth-provider: patch
---
Removed unused staging types from ProviderFactoryBuilder.

View File

@@ -1,6 +0,0 @@
---
reth-trie-sparse: patch
reth-engine-tree: patch
---
Removed the `skip_proof_node_filtering` flag, `revealed_account_paths`/`revealed_paths` tracking, and the `filter_revealed_v2_proof_nodes` function from the sparse trie implementation. Also removed the corresponding skipped-nodes metrics, simplifying the proof node reveal path to always pass nodes directly to the sparse trie without pre-filtering.

View File

@@ -1,5 +0,0 @@
---
reth-trie-sparse: minor
---
Added a comprehensive generic `SparseTrie` test suite covering `set_root`, `reveal_nodes`, `update_leaves`, `root`, `take_updates`, `commit_updates`, `prune`, `wipe`/`clear`, `get_leaf_value`, `find_leaf`, `size_hint`, and integration lifecycle scenarios. Tests are stamped out for all concrete `SparseTrie` implementations via a macro.

View File

@@ -1,5 +0,0 @@
---
reth-provider: patch
---
Fixed sender pruning during block reorg to skip when sender_recovery is fully pruned, preventing a fatal crash when no sender data exists in static files.

View File

@@ -1,7 +0,0 @@
---
reth-network-types: minor
reth-network: minor
reth-node-core: patch
---
Added `PersistedPeerInfo` struct to persist richer peer metadata (kind, fork ID, reputation) to disk. Updated `PeersConfig::with_basic_nodes_from_file` to support both the new `PersistedPeerInfo` format and the legacy `Vec<NodeRecord>` format with automatic conversion, and updated `write_peers_to_file` to exclude backed-off and banned peers.

View File

@@ -1,5 +0,0 @@
---
reth: patch
---
Added automated changelog generation infrastructure using wevm/changelogs-rs with Claude Code integration. Configured per-crate changelog format with fixed version groups for reth binaries and exclusions for internal test utilities.

View File

@@ -1,5 +0,0 @@
---
reth-trie-sparse: minor
---
Removed `SerialSparseTrie` from the workspace, consolidating on `ParallelSparseTrie` as the single sparse trie implementation in `reth-trie-sparse`.

View File

@@ -1,5 +0,0 @@
---
reth-cli-commands: minor
---
Added `reth_version` field to `SnapshotManifest` to record the Reth version that produced a snapshot. The field is optional and populated automatically during manifest generation.

View File

@@ -1,5 +0,0 @@
---
reth-network: minor
---
Added `fork_id` as a tiebreaker in peer selection when reputations are equal, preferring peers with a discovered `fork_id` as it indicates fork compatibility. Added a test to verify the tiebreaker behavior.

View File

@@ -1,5 +0,0 @@
---
reth-trie-sparse: patch
---
Fixed a bug where trie nodes could appear in both `updated_nodes` and `removed_nodes` simultaneously by removing entries from `removed_nodes` when a node is inserted as updated.

View File

@@ -1,8 +0,0 @@
---
reth-trie-common: minor
reth-trie: minor
reth-trie-parallel: minor
reth-engine-tree: patch
---
Moved `ProofV2Target`, `MultiProofTargetsV2`, and `ChunkedMultiProofTargetsV2` from `reth-trie-parallel::targets_v2` into a new `reth-trie-common::target_v2` module, making these types available at a lower level without pulling in the full parallel trie crate. Added a `multiproof_v2` method to `Proof` in `reth-trie` that generates a state multiproof using the V2 proof calculator with synchronous account value encoding.

View File

@@ -1,14 +0,0 @@
---
reth-engine-tree: patch
reth-evm-ethereum: patch
reth-evm: patch
reth-primitives-traits: patch
reth-revm: patch
reth-rpc-eth-api: patch
reth-rpc-eth-types: patch
reth-provider: patch
example-custom-evm: patch
example-precompile-cache: patch
---
Bumped revm to v35.0.0, revm-inspectors to 0.35.0, and alloy-evm to 0.29.0. Updated call sites throughout the codebase to align with the new APIs, including `ExecutionResult` field changes (`gas_used``gas.used()`/`gas.final_refunded()`), removal of `.without_state_clear()`, updated `EthPrecompiles::new(spec)` constructor, and updated `block_hashes.lowest()` access.

View File

@@ -1,9 +0,0 @@
---
reth-trie-sparse: minor
reth-engine-primitives: minor
reth-engine-tree: minor
reth-node-core: minor
reth-trie-common: patch
---
Added an arena-based sparse trie implementation (`ArenaParallelSparseTrie`) using `slotmap` arena allocation for node storage, enabling parallel subtrie mutation without per-node hashing overhead. Added `ConfigurableSparseTrie` enum to switch between the arena and hash-map implementations, and a `--engine.enable-arena-sparse-trie` CLI flag to opt in at runtime.

View File

@@ -1,5 +0,0 @@
---
reth: patch
---
Updated Alloy dependencies from 1.5.2 to 1.6.1.

View File

@@ -1,4 +0,0 @@
---
---
Expanded CLI integration tests with subcommand help coverage, config TOML validation, genesis JSON validation, and send transaction round-trip test for dev mode.

View File

@@ -1,6 +0,0 @@
---
reth-engine-local: minor
reth-node-builder: minor
---
Added trigger-based `MiningMode` variant that allows blocks to be built on-demand via custom streams, and exposed `with_mining_mode` method on `DebugNodeLauncherFuture` to override default mining configuration.

View File

@@ -1,5 +0,0 @@
---
reth-network: minor
---
Added direction labels to `closed_sessions` and `pending_session_failures` metrics. Operators can now distinguish session closures and failures by direction (`active`, `incoming_pending`, `outgoing_pending` for closed sessions; `inbound`, `outbound` for pending session failures).

View File

@@ -1,4 +0,0 @@
---
---
Moved Kurtosis CI failure notifications to the hive Slack channel.

View File

@@ -1,7 +0,0 @@
---
reth-rpc-api: minor
reth-rpc-builder: patch
reth-rpc: minor
---
Added `subscribeFinalizedChainNotifications` RPC endpoint that buffers committed chain notifications and emits them once a new finalized block is received.

View File

@@ -1,5 +0,0 @@
---
reth-transaction-pool: patch
---
Fixed a bug where transactions from the same sender were added to the pending subpool out of nonce order. Ensured `process_updates` runs before `add_new_transaction` so that lower-nonce promotions are enqueued before the newly inserted higher-nonce transaction, preserving correct ordering for live `BestTransactions` iterators.

View File

@@ -1,7 +0,0 @@
---
reth-trie: major
reth-trie-db: major
reth-provider: minor
---
Added `MaskedTrieCursorFactory` and `MaskedTrieCursor` to handle prefix-set-based hash invalidation at the cursor layer, replacing the `DatabaseTrieWitness` trait abstraction. Removed `with_prefix_sets_mut` from `TrieWitness` and deleted `DatabaseTrieWitness` — callers should now wrap their cursor factory with `MaskedTrieCursorFactory` to apply prefix sets during witness/proof computation.

View File

@@ -1,6 +0,0 @@
---
reth-trie: minor
reth-trie-parallel: minor
---
Added `root_node` and `storage_root_node` methods to proof calculators for efficient root-only calculations. These methods directly return the root node without requiring dummy targets, replacing the previous workaround of passing fake targets to proof generation.

View File

@@ -1,5 +0,0 @@
---
reth-trie: patch
---
Fixed a potential panic in `ProofCalculator` by clearing internal computation state (`branch_stack`, `child_stack`, `branch_path`, etc.) after errors, preventing stale state from causing `usize` underflow panics when the calculator is reused. Added a test verifying correct behavior after simulated mid-computation errors.

View File

@@ -12,7 +12,7 @@ workflows:
# Check that `A` activates the features of `B`.
"propagate-feature",
# These are the features to check:
"--features=std,op,dev,asm-keccak,jemalloc,jemalloc-prof,tracy-allocator,tracy,serde-bincode-compat,serde,test-utils,arbitrary,bench,alloy-compat,min-error-logs,min-warn-logs,min-info-logs,min-debug-logs,min-trace-logs,otlp,otlp-logs,js-tracer,portable,keccak-cache-global",
"--features=std,op,dev,asm-keccak,jemalloc,jemalloc-prof,tracy-allocator,tracy,serde-bincode-compat,serde,test-utils,arbitrary,bench,alloy-compat,min-error-logs,min-warn-logs,min-info-logs,min-debug-logs,min-trace-logs,otlp,otlp-logs,js-tracer,portable,keccak-cache-global,trie-debug",
# Do not try to add a new section to `[features]` of `A` only because `B` exposes that feature. There are edge-cases where this is still needed, but we can add them manually.
"--left-side-feature-missing=ignore",
# Ignore the case that `A` it outside of the workspace. Otherwise it will report errors in external dependencies that we have no influence on.

View File

@@ -20,11 +20,6 @@
# include dist directory, where the reth binary is located after compilation
!/dist
# include PGO build helper used by Dockerfile.depot
!/.github
!/.github/scripts
!/.github/scripts/build_pgo_bolt.sh
# include licenses
!LICENSE-*

106
.github/scripts/bench-job-summary.js vendored Normal file
View File

@@ -0,0 +1,106 @@
// Generates a rich GitHub Actions job summary for reth-bench results.
//
// Reads from environment:
// BENCH_WORK_DIR Directory containing summary.json
// BENCH_PR PR number (may be empty)
// BENCH_ACTOR GitHub user who triggered the bench
// BENCH_CORES CPU core limit (0 = all)
// BENCH_WARMUP_BLOCKS Number of warmup blocks
// BENCH_SAMPLY 'true' if samply profiling was enabled
// BENCH_ABBA 'true' if ABBA interleaved order was used
//
// Usage from actions/github-script:
// const jobSummary = require('./.github/scripts/bench-job-summary.js');
// await jobSummary({ core, context, chartSha, grafanaUrl, runId });
const fs = require('fs');
const { verdict, loadSamplyUrls, blocksLabel, metricRows, waitTimeRows } = require('./bench-utils');
module.exports = async function ({ core, context, chartSha, grafanaUrl, runId }) {
let summary;
try {
summary = JSON.parse(fs.readFileSync(process.env.BENCH_WORK_DIR + '/summary.json', 'utf8'));
} catch (e) {
await core.summary.addRaw('⚠️ Benchmark completed but failed to load summary.').write();
return;
}
const repo = `${context.repo.owner}/${context.repo.repo}`;
const prNumber = process.env.BENCH_PR;
const actor = process.env.BENCH_ACTOR;
const commitUrl = `https://github.com/${repo}/commit`;
const { emoji, label } = verdict(summary.changes);
const baselineLink = `[\`${summary.baseline.name}\`](${commitUrl}/${summary.baseline.ref})`;
const featureLink = `[\`${summary.feature.name}\`](${commitUrl}/${summary.feature.ref})`;
const diffUrl = `https://github.com/${repo}/compare/${summary.baseline.ref}...${summary.feature.ref}`;
// Header & metadata
const metaParts = [];
if (prNumber) metaParts.push(`**[PR #${prNumber}](https://github.com/${repo}/pull/${prNumber})**`);
metaParts.push(`triggered by @${actor}`);
let md = `# ${emoji} ${label}\n\n`;
md += metaParts.join(' · ') + '\n\n';
md += `**Baseline:** ${baselineLink}\n`;
md += `**Feature:** ${featureLink} ([diff](${diffUrl}))\n`;
md += blocksLabel(summary).map(p => `**${p.key}:** ${p.value}`).join(' · ') + '\n\n';
// Main comparison table
const rows = metricRows(summary);
md += `| Metric | Baseline | Feature | Change |\n`;
md += `|--------|----------|---------|--------|\n`;
for (const r of rows) {
md += `| ${r.label} | ${r.baseline} | ${r.feature} | ${r.change} |\n`;
}
md += '\n';
// Wait time breakdown
const wtRows = waitTimeRows(summary);
if (wtRows.length > 0) {
md += `### Wait Time Breakdown\n\n`;
md += `| Metric | Baseline | Feature |\n`;
md += `|--------|----------|--------|\n`;
for (const r of wtRows) {
md += `| ${r.title} | ${r.baseline} | ${r.feature} |\n`;
}
md += '\n';
}
// Charts
if (chartSha) {
const prNum = prNumber || '0';
const baseUrl = `https://raw.githubusercontent.com/decofe/reth-bench-charts/${chartSha}/pr/${prNum}/${runId}`;
const charts = [
{ file: 'latency_throughput.png', label: 'Latency, Throughput & Diff' },
{ file: 'wait_breakdown.png', label: 'Wait Time Breakdown' },
{ file: 'gas_vs_latency.png', label: 'Gas vs Latency' },
];
md += `### Charts\n\n`;
for (const chart of charts) {
md += `<details><summary>${chart.label}</summary>\n\n`;
md += `![${chart.label}](${baseUrl}/${chart.file})\n\n`;
md += `</details>\n\n`;
}
}
// Samply profiles
const samplyUrls = loadSamplyUrls(process.env.BENCH_WORK_DIR);
const samplyLinks = Object.entries(samplyUrls).map(([run, url]) => `- **${run}**: [Firefox Profiler](${url})`);
if (samplyLinks.length > 0) {
md += `### Samply Profiles\n\n${samplyLinks.join('\n')}\n\n`;
}
// Grafana
if (grafanaUrl) {
md += `### Grafana Dashboard\n\n[View real-time metrics](${grafanaUrl})\n\n`;
}
// Node errors
try {
const errors = fs.readFileSync(process.env.BENCH_WORK_DIR + '/errors.md', 'utf8');
if (errors.trim()) md += '\n' + errors + '\n';
} catch {}
await core.summary.addRaw(md).write();
};

View File

@@ -11,17 +11,28 @@
# optional branch-sha is the PR head commit for cache key
#
# Outputs:
# baseline: <source-dir>/target/profiling/reth
# feature: <source-dir>/target/profiling/reth, reth-bench installed to cargo bin
# baseline: <source-dir>/target/profiling/reth (or reth-bb if BENCH_BIG_BLOCKS=true)
# feature: <source-dir>/target/profiling/reth (or reth-bb), reth-bench installed to cargo bin
#
# Required: mc (MinIO client) with a configured alias
set -euo pipefail
# Optional env: BENCH_BIG_BLOCKS (true/false) — build reth-bb instead of reth
set -euxo pipefail
MC="mc"
MODE="$1"
SOURCE_DIR="$2"
COMMIT="$3"
BIG_BLOCKS="${BENCH_BIG_BLOCKS:-false}"
# The node binary to build: reth-bb for big blocks, reth otherwise
if [ "$BIG_BLOCKS" = "true" ]; then
NODE_BIN="reth-bb"
NODE_PKG="-p reth-bb"
else
NODE_BIN="reth"
NODE_PKG="--bin reth"
fi
# Tracy support: when BENCH_TRACY is "on" or "full", add Tracy cargo features
# and frame pointers for accurate stack traces.
EXTRA_FEATURES=""
@@ -62,18 +73,18 @@ case "$MODE" in
mkdir -p "${SOURCE_DIR}/target/profiling"
CACHE_VALID=false
if $MC stat "${BUCKET}/reth" &>/dev/null; then
echo "Cache hit for baseline (${COMMIT}), downloading binary..."
$MC cp "${BUCKET}/reth" "${SOURCE_DIR}/target/profiling/reth"
chmod +x "${SOURCE_DIR}/target/profiling/reth"
if verify_binary "${SOURCE_DIR}/target/profiling/reth" "${COMMIT}"; then
if $MC stat --no-list "${BUCKET}/${NODE_BIN}" &>/dev/null; then
echo "Cache hit for baseline (${COMMIT}), downloading ${NODE_BIN}..."
if $MC cp "${BUCKET}/${NODE_BIN}" "${SOURCE_DIR}/target/profiling/${NODE_BIN}" && \
chmod +x "${SOURCE_DIR}/target/profiling/${NODE_BIN}" && \
verify_binary "${SOURCE_DIR}/target/profiling/${NODE_BIN}" "${COMMIT}"; then
CACHE_VALID=true
else
echo "Cached baseline binary is stale, rebuilding..."
echo "Cached baseline binary is stale or download failed, rebuilding..."
fi
fi
if [ "$CACHE_VALID" = false ]; then
echo "Building baseline (${COMMIT}) from source..."
echo "Building baseline ${NODE_BIN} (${COMMIT}) from source..."
cd "${SOURCE_DIR}"
FEATURES_ARG=""
WORKSPACE_ARG=""
@@ -84,8 +95,8 @@ case "$MODE" in
fi
# shellcheck disable=SC2086
RUSTFLAGS="-C target-cpu=native${EXTRA_RUSTFLAGS}" \
cargo build --profile profiling --bin reth $WORKSPACE_ARG $FEATURES_ARG
$MC cp target/profiling/reth "${BUCKET}/reth"
cargo build --profile profiling $NODE_PKG $WORKSPACE_ARG $FEATURES_ARG
$MC cp "target/profiling/${NODE_BIN}" "${BUCKET}/${NODE_BIN}"
fi
;;
@@ -94,32 +105,34 @@ case "$MODE" in
BUCKET="minio/reth-binaries/${BRANCH_SHA}${BUILD_SUFFIX}"
CACHE_VALID=false
if $MC stat "${BUCKET}/reth" &>/dev/null && $MC stat "${BUCKET}/reth-bench" &>/dev/null; then
if $MC stat --no-list "${BUCKET}/${NODE_BIN}" &>/dev/null && $MC stat --no-list "${BUCKET}/reth-bench" &>/dev/null; then
echo "Cache hit for ${BRANCH_SHA}, downloading binaries..."
mkdir -p "${SOURCE_DIR}/target/profiling"
$MC cp "${BUCKET}/reth" "${SOURCE_DIR}/target/profiling/reth"
$MC cp "${BUCKET}/reth-bench" /home/ubuntu/.cargo/bin/reth-bench
chmod +x "${SOURCE_DIR}/target/profiling/reth" /home/ubuntu/.cargo/bin/reth-bench
if verify_binary "${SOURCE_DIR}/target/profiling/reth" "${COMMIT}"; then
if $MC cp "${BUCKET}/${NODE_BIN}" "${SOURCE_DIR}/target/profiling/${NODE_BIN}" && \
$MC cp "${BUCKET}/reth-bench" /home/ubuntu/.cargo/bin/reth-bench && \
chmod +x "${SOURCE_DIR}/target/profiling/${NODE_BIN}" /home/ubuntu/.cargo/bin/reth-bench && \
verify_binary "${SOURCE_DIR}/target/profiling/${NODE_BIN}" "${COMMIT}"; then
CACHE_VALID=true
else
echo "Cached feature binary is stale, rebuilding..."
echo "Cached feature binary is stale or download failed, rebuilding..."
fi
fi
if [ "$CACHE_VALID" = false ]; then
echo "Building feature (${COMMIT}) from source..."
echo "Building feature ${NODE_BIN} (${COMMIT}) from source..."
cd "${SOURCE_DIR}"
rustup show active-toolchain || rustup default stable
if [ -n "$EXTRA_FEATURES" ]; then
# Can't use `make profiling` when adding features; build explicitly
# --workspace is needed for cross-package feature syntax (tracy-client/ondemand)
RUSTFLAGS="-C target-cpu=native${EXTRA_RUSTFLAGS}" \
cargo build --profile profiling --workspace --bin reth --features "${EXTRA_FEATURES}"
cargo build --profile profiling --workspace $NODE_PKG --features "${EXTRA_FEATURES}"
else
make profiling
# shellcheck disable=SC2086
RUSTFLAGS="-C target-cpu=native${EXTRA_RUSTFLAGS}" \
cargo build --profile profiling $NODE_PKG
fi
make install-reth-bench
$MC cp target/profiling/reth "${BUCKET}/reth"
$MC cp "target/profiling/${NODE_BIN}" "${BUCKET}/${NODE_BIN}"
$MC cp "$(which reth-bench)" "${BUCKET}/reth-bench"
fi
;;

View File

@@ -26,7 +26,7 @@
#
# The script delegates to the existing bench-reth-*.sh scripts in the reth
# repo for the actual build, snapshot, and run steps.
set -euo pipefail
set -euxo pipefail
# ── PATH ──────────────────────────────────────────────────────────────
# Ensure cargo and user-local bins (mc, uv) are visible
@@ -399,12 +399,9 @@ upload_tracy() {
# ── Step 6: Pre-flight cleanup ───────────────────────────────────────
echo "▸ Pre-flight cleanup..."
pkill -f bench-metrics-proxy 2>/dev/null || true
sudo pkill -9 reth 2>/dev/null || true
sleep 1
if mountpoint -q "$SCHELK_MOUNT" 2>/dev/null; then
sudo umount -l "$SCHELK_MOUNT" 2>/dev/null || true
sudo schelk recover -y 2>/dev/null || true
fi
sudo systemctl stop "${RETH_SCOPE:-reth-bench.scope}" 2>/dev/null || true
sudo systemctl reset-failed "${RETH_SCOPE:-reth-bench.scope}" 2>/dev/null || true
sudo schelk recover -y --kill || sudo schelk full-recover -y || true
echo
# ── Step 7: Interleaved benchmark runs (B-F-F-B) ────────────────────

View File

@@ -7,21 +7,28 @@
#
# Required env: SCHELK_MOUNT, BENCH_RPC_URL, BENCH_BLOCKS, BENCH_WARMUP_BLOCKS
# Optional env: BENCH_BIG_BLOCKS (true/false), BENCH_WORK_DIR (for big blocks path)
# BENCH_RETH_NEW_PAYLOAD (true/false, default true)
# BENCH_BAL (false/true/feature/baseline; only used with big blocks)
# BENCH_WAIT_TIME (duration like 500ms, default empty)
# BENCH_BASELINE_ARGS (extra reth node args for baseline runs)
# BENCH_FEATURE_ARGS (extra reth node args for feature runs)
# BENCH_OTLP_TRACES_ENDPOINT (OTLP HTTP endpoint for traces, e.g. https://host/insert/opentelemetry/v1/traces)
# BENCH_OTLP_LOGS_ENDPOINT (OTLP HTTP endpoint for logs, e.g. https://host/insert/opentelemetry/v1/logs)
set -euo pipefail
# BENCH_OTLP_DISABLED (true to skip OTLP export even if endpoints are set)
set -euxo pipefail
LABEL="$1"
BINARY="$2"
OUTPUT_DIR="$3"
DATADIR="$SCHELK_MOUNT/datadir"
DATADIR_NAME="datadir"
if [ "${BENCH_BIG_BLOCKS:-false}" = "true" ]; then
DATADIR_NAME="datadir-big-blocks"
fi
DATADIR="$SCHELK_MOUNT/$DATADIR_NAME"
mkdir -p "$OUTPUT_DIR"
LOG="${OUTPUT_DIR}/node.log"
RETH_SCOPE="${RETH_SCOPE:-reth-bench.scope}"
cleanup() {
kill "$TAIL_PID" 2>/dev/null || true
# Stop tracy-capture first (SIGINT makes it disconnect and flush to disk)
@@ -42,7 +49,7 @@ cleanup() {
fi
wait "$TRACY_PID" 2>/dev/null || true
fi
if [ -n "${RETH_PID:-}" ] && sudo kill -0 "$RETH_PID" 2>/dev/null; then
if sudo systemctl is-active "$RETH_SCOPE" >/dev/null 2>&1; then
if [ "${BENCH_SAMPLY:-false}" = "true" ]; then
# Send SIGINT to the inner reth process by exact name (not -f which
# would also match samply's cmdline containing "reth"). Samply will
@@ -60,31 +67,28 @@ cleanup() {
echo "Samply still running after 120s, sending SIGTERM..."
sudo pkill -x samply 2>/dev/null || true
fi
else
sudo kill "$RETH_PID"
for i in $(seq 1 30); do
sudo kill -0 "$RETH_PID" 2>/dev/null || break
sleep 1
done
fi
sudo kill -9 "$RETH_PID" 2>/dev/null || true
# Stop the entire systemd scope — kills all processes in the cgroup.
# This is reliable regardless of process reparenting or PID wrapper issues.
sudo systemctl stop "$RETH_SCOPE" 2>/dev/null || true
sleep 1
fi
sudo systemctl reset-failed "$RETH_SCOPE" 2>/dev/null || true
# Fix ownership of reth-created files (reth runs as root)
sudo chown -R "$(id -un):$(id -gn)" "$OUTPUT_DIR" 2>/dev/null || true
if mountpoint -q "$SCHELK_MOUNT"; then
sudo umount -l "$SCHELK_MOUNT" || true
sudo schelk recover -y || true
fi
# Let schelk recover the mounted volume in place so dm-era can restore only
# the changed blocks and clean up its own state.
sudo schelk recover -y --kill || true
}
TAIL_PID=
TRACY_PID=
trap cleanup EXIT
# Clean up stale schelk state from a previous cancelled run.
# If schelk thinks it's still mounted (e.g. a cancelled run skipped cleanup),
# recover first to reset state.
sudo schelk recover -y -k || true
# Clean up stale state from a previous cancelled run.
# Stop any leftover reth process in the scope, then recover schelk state.
sudo systemctl stop "$RETH_SCOPE" 2>/dev/null || true
sudo systemctl reset-failed "$RETH_SCOPE" 2>/dev/null || true
sudo schelk recover -y --kill || true
# Mount
sudo schelk mount -y
@@ -120,9 +124,12 @@ RETH_ARGS=(
--no-persist-peers
)
# Big blocks mode requires the testing API and skip-invalid-transactions
if [ "$BIG_BLOCKS" = "true" ]; then
RETH_ARGS+=(--http.api eth,net,web3,reth,testing --testing.skip-invalid-transactions)
# Gate flag on binary support (older baselines may not have it).
# Uses --help which exits immediately via clap without node init.
SYNC_STATE_IDLE=false
if "$BINARY" node --help 2>/dev/null | grep -qF -- '--debug.startup-sync-state-idle'; then
RETH_ARGS+=(--debug.startup-sync-state-idle)
SYNC_STATE_IDLE=true
fi
# Append per-label extra node args (baseline or feature)
@@ -142,11 +149,13 @@ if [ -n "${BENCH_METRICS_ADDR:-}" ]; then
fi
# OTLP traces and logs export
if [ -n "${BENCH_OTLP_TRACES_ENDPOINT:-}" ]; then
RETH_ARGS+=(--tracing-otlp="${BENCH_OTLP_TRACES_ENDPOINT}" --tracing-otlp.service-name=reth-bench)
fi
if [ -n "${BENCH_OTLP_LOGS_ENDPOINT:-}" ]; then
RETH_ARGS+=(--logs-otlp="${BENCH_OTLP_LOGS_ENDPOINT}" --logs-otlp.filter=debug)
if [ "${BENCH_OTLP_DISABLED:-false}" != "true" ]; then
if [ -n "${BENCH_OTLP_TRACES_ENDPOINT:-}" ]; then
RETH_ARGS+=(--tracing-otlp="${BENCH_OTLP_TRACES_ENDPOINT}" --tracing-otlp.service-name=reth-bench)
fi
if [ -n "${BENCH_OTLP_LOGS_ENDPOINT:-}" ]; then
RETH_ARGS+=(--logs-otlp="${BENCH_OTLP_LOGS_ENDPOINT}" --logs-otlp.filter=debug)
fi
fi
# Tracy profiling: add --log.tracy flags and set environment
@@ -173,19 +182,19 @@ echo "Memory limit: $(( MEM_LIMIT / 1024 / 1024 ))MB (95% of $(( TOTAL_MEM_KB /
if [ "${BENCH_SAMPLY:-false}" = "true" ]; then
RETH_ARGS+=(--log.samply)
SAMPLY="$(which samply)"
sudo systemd-run --scope -p MemoryMax="$MEM_LIMIT" -p AllowedCPUs="$RETH_CPUS" \
sudo systemd-run --quiet --scope --collect --unit="$RETH_SCOPE" \
-p MemoryMax="$MEM_LIMIT" -p AllowedCPUs="$RETH_CPUS" \
env "${SUDO_ENV[@]}" nice -n -20 \
"$SAMPLY" record --save-only --presymbolicate --rate 10000 \
--output "$OUTPUT_DIR/samply-profile.json.gz" \
-- "$BINARY" "${RETH_ARGS[@]}" \
> "$LOG" 2>&1 &
else
sudo systemd-run --scope -p MemoryMax="$MEM_LIMIT" -p AllowedCPUs="$RETH_CPUS" \
sudo systemd-run --quiet --scope --collect --unit="$RETH_SCOPE" \
-p MemoryMax="$MEM_LIMIT" -p AllowedCPUs="$RETH_CPUS" \
env "${SUDO_ENV[@]}" nice -n -20 "$BINARY" "${RETH_ARGS[@]}" \
> "$LOG" 2>&1 &
fi
RETH_PID=$!
stdbuf -oL tail -f "$LOG" | sed -u "s/^/[reth] /" &
TAIL_PID=$!
@@ -194,7 +203,7 @@ for i in $(seq 1 60); do
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
> /dev/null 2>&1; then
echo "reth (${LABEL}) is ready after ${i}s"
echo "reth (${LABEL}) RPC is up after ${i}s"
break
fi
if [ "$i" -eq 60 ]; then
@@ -205,28 +214,83 @@ for i in $(seq 1 60); do
sleep 1
done
# Wait for the pipeline to finish (eth_syncing returns false) so the
# engine is in live mode and can accept newPayload calls.
# Only possible when --debug.startup-sync-state-idle is supported.
if [ "$SYNC_STATE_IDLE" = "true" ]; then
for i in $(seq 1 300); do
SYNC_RESULT=$(curl -sf http://127.0.0.1:8545 -X POST \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","method":"eth_syncing","params":[],"id":1}' 2>/dev/null || true)
if [ -n "$SYNC_RESULT" ] && jq -e '.result == false' <<< "$SYNC_RESULT" > /dev/null 2>&1; then
echo "reth (${LABEL}) pipeline finished after ${i}s, engine is live"
break
fi
if [ "$i" -eq 300 ]; then
echo "::error::reth (${LABEL}) pipeline did not finish within 300s"
cat "$LOG"
exit 1
fi
sleep 1
done
else
echo "reth (${LABEL}) binary does not support --debug.startup-sync-state-idle, skipping sync wait"
fi
# Run reth-bench with high priority but as the current user so output
# files are not root-owned (avoids EACCES on next checkout).
BENCH_NICE="sudo nice -n -20 sudo -u $(id -un)"
# Build optional flags
EXTRA_BENCH_ARGS=()
if [ "${BENCH_RETH_NEW_PAYLOAD:-true}" != "false" ]; then
EXTRA_BENCH_ARGS+=(--reth-new-payload)
fi
EXTRA_BENCH_ARGS=(--reth-new-payload)
if [ -n "${BENCH_WAIT_TIME:-}" ]; then
EXTRA_BENCH_ARGS+=(--wait-time "$BENCH_WAIT_TIME")
fi
if [ "$BIG_BLOCKS" = "true" ]; then
# Big blocks mode: replay pre-generated payloads with gas ramp
BIG_BLOCKS_DIR="${BENCH_WORK_DIR}/big-blocks"
# Count gas ramp blocks for reporting
GAS_RAMP_COUNT=$(find "$BIG_BLOCKS_DIR/gas-ramp-dir" -name '*.json' | wc -l)
echo "$GAS_RAMP_COUNT" > "$OUTPUT_DIR/gas_ramp_blocks.txt"
echo "Gas ramp blocks: $GAS_RAMP_COUNT"
# Big blocks mode: replay pre-generated payloads
BIG_BLOCKS_DIR="${BENCH_BIG_BLOCKS_DIR:-${BENCH_WORK_DIR}/big-blocks}"
BENCH_BAL_MODE="${BENCH_BAL:-false}"
# Start tracy-capture so profile only covers the benchmark
BB_BENCH_ARGS=(--reth-new-payload)
if [ -n "${BENCH_WAIT_TIME:-}" ]; then
BB_BENCH_ARGS+=(--wait-time "$BENCH_WAIT_TIME")
fi
case "$BENCH_BAL_MODE" in
false)
;;
true)
BB_BENCH_ARGS+=(--bal)
;;
baseline)
if [[ "$LABEL" == baseline* ]]; then
BB_BENCH_ARGS+=(--bal)
fi
;;
feature)
if [[ "$LABEL" == feature* ]]; then
BB_BENCH_ARGS+=(--bal)
fi
;;
*)
echo "::error::Unknown BENCH_BAL value: $BENCH_BAL_MODE"
exit 1
;;
esac
# Warmup
WARMUP="${BENCH_WARMUP_BLOCKS:-50}"
if [ "$WARMUP" -gt 0 ] 2>/dev/null; then
echo "Running big blocks warmup (${WARMUP} payloads)..."
$BENCH_NICE "$RETH_BENCH" replay-payloads \
"${BB_BENCH_ARGS[@]}" \
--count "$WARMUP" \
--payload-dir "$BIG_BLOCKS_DIR/payloads" \
--engine-rpc-url http://127.0.0.1:8551 \
--jwt-secret "$DATADIR/jwt.hex" 2>&1 | sed -u "s/^/[bench] /"
fi
# Start tracy-capture after warmup so profile only covers the benchmark
if [ "${BENCH_TRACY:-off}" != "off" ]; then
echo "Starting tracy-capture..."
tracy-capture -f -o "$OUTPUT_DIR/tracy-profile.tracy" &
@@ -234,10 +298,19 @@ if [ "$BIG_BLOCKS" = "true" ]; then
sleep 0.5 # give tracy-capture time to connect
fi
echo "Running big blocks benchmark (replay-payloads)..."
# Benchmark — skip warmup payloads so they aren't measured
BB_SKIP=0
if [ "$WARMUP" -gt 0 ] 2>/dev/null; then
BB_SKIP="$WARMUP"
fi
if [ "${BENCH_BLOCKS:-0}" -gt 0 ] 2>/dev/null; then
BB_BENCH_ARGS+=(--count "$BENCH_BLOCKS")
fi
echo "Running big blocks benchmark (replay-payloads, skip=${BB_SKIP})..."
$BENCH_NICE "$RETH_BENCH" replay-payloads \
"${EXTRA_BENCH_ARGS[@]}" \
--gas-ramp-dir "$BIG_BLOCKS_DIR/gas-ramp-dir" \
"${BB_BENCH_ARGS[@]}" \
--skip "$BB_SKIP" \
--payload-dir "$BIG_BLOCKS_DIR/payloads" \
--engine-rpc-url http://127.0.0.1:8551 \
--jwt-secret "$DATADIR/jwt.hex" \

View File

@@ -1,69 +1,93 @@
#!/usr/bin/env bash
#
# Downloads the latest nightly snapshot into the schelk volume with
# progress reporting to the GitHub PR comment.
# Downloads the latest snapshot into the schelk volume using
# `reth download` with progress reporting to the GitHub PR comment.
#
# Skips the download if the local ETag marker matches the remote one.
# Skips the download if the manifest content hasn't changed since
# the last successful download (checked via SHA-256 of the manifest).
#
# Usage: bench-reth-snapshot.sh [--check]
# --check Only check if a download is needed; exits 0 if up-to-date, 1 if not.
# --check Only check if a download is needed; exits 0 if up-to-date, 10 if not.
#
# Required env:
# SCHELK_MOUNT schelk mount point (e.g. /reth-bench)
# BENCH_RETH_BINARY path to the reth binary
# GITHUB_TOKEN token for GitHub API calls (only for download)
# BENCH_COMMENT_ID PR comment ID to update (optional)
# BENCH_REPO owner/repo (e.g. paradigmxyz/reth)
# BENCH_JOB_URL link to the Actions job
# BENCH_ACTOR user who triggered the benchmark
# BENCH_CONFIG config summary line
set -euo pipefail
set -euxo pipefail
BUCKET="minio/reth-snapshots/reth-1-minimal-nightly-previous.tar.zst"
DATADIR="$SCHELK_MOUNT/datadir"
ETAG_FILE="$HOME/.reth-bench-snapshot-etag"
# Get remote metadata via JSON for reliable parsing
MC_STAT=$(mc stat --json "$BUCKET" 2>/dev/null || true)
REMOTE_ETAG=$(echo "$MC_STAT" | jq -r '.etag // empty')
if [ -z "$REMOTE_ETAG" ]; then
echo "::warning::Failed to get ETag from mc stat, will re-download"
REMOTE_ETAG="unknown-$(date +%s)"
MC="mc"
BUCKET="minio/reth-snapshots"
# Allow overriding the snapshot name (e.g. for big-blocks mode where the
# big-blocks manifest specifies which base snapshot to use).
SNAPSHOT_NAME="${BENCH_SNAPSHOT_NAME:-reth-1-minimal-stable}"
MANIFEST_PATH="${SNAPSHOT_NAME}/manifest.json"
DATADIR_NAME="datadir"
HASH_MODE_SUFFIX=""
if [ "${BENCH_BIG_BLOCKS:-false}" = "true" ]; then
DATADIR_NAME="datadir-big-blocks"
HASH_MODE_SUFFIX="-big-blocks"
fi
DATADIR="$SCHELK_MOUNT/$DATADIR_NAME"
HASH_FILE="$HOME/.reth-bench-snapshot-hash${HASH_MODE_SUFFIX}"
LOCAL_ETAG=""
[ -f "$ETAG_FILE" ] && LOCAL_ETAG=$(cat "$ETAG_FILE")
# Fetch manifest and compute content hash for reliable freshness check
MANIFEST_CONTENT=$($MC cat "${BUCKET}/${MANIFEST_PATH}" 2>/dev/null) || {
echo "::error::Failed to fetch snapshot manifest from ${BUCKET}/${MANIFEST_PATH}"
exit 2
}
REMOTE_HASH=$(echo "$MANIFEST_CONTENT" | sha256sum | awk '{print $1}')
if [ "$REMOTE_ETAG" = "$LOCAL_ETAG" ]; then
echo "Snapshot is up-to-date (ETag: ${REMOTE_ETAG})"
if [ "${1:-}" = "--check" ]; then
exit 0
fi
LOCAL_HASH=""
[ -f "$HASH_FILE" ] && LOCAL_HASH=$(cat "$HASH_FILE")
if [ "$REMOTE_HASH" = "$LOCAL_HASH" ]; then
echo "Snapshot is up-to-date (manifest hash: ${REMOTE_HASH:0:16}…)"
exit 0
fi
echo "Snapshot needs update (local: ${LOCAL_ETAG:-<none>}, remote: ${REMOTE_ETAG})"
echo "Snapshot needs update (local: ${LOCAL_HASH:+${LOCAL_HASH:0:16}}${LOCAL_HASH:-<none>}, remote: ${REMOTE_HASH:0:16})"
if [ "${1:-}" = "--check" ]; then
exit 10
fi
RETH="${BENCH_RETH_BINARY:?BENCH_RETH_BINARY must be set}"
if [ ! -x "$RETH" ]; then
echo "::error::reth binary not found or not executable at $RETH"
exit 1
fi
# Get compressed size for progress tracking
TOTAL_BYTES=$(echo "$MC_STAT" | jq -r '.size // empty')
if [ -z "$TOTAL_BYTES" ] || [ "$TOTAL_BYTES" = "0" ]; then
echo "::error::Failed to get snapshot size from mc stat"
# Resolve the MinIO HTTP endpoint from the mc alias so reth can
# fetch archives over HTTP (the manifest's embedded base_url points
# to the cluster-internal address which is unreachable from runners).
MINIO_ENDPOINT=$($MC alias list minio --json 2>/dev/null | jq -r '.URL // empty') || true
if [ -z "$MINIO_ENDPOINT" ]; then
echo "::error::Failed to resolve MinIO endpoint from mc alias 'minio'"
exit 1
fi
echo "Snapshot size: $TOTAL_BYTES bytes ($(numfmt --to=iec "$TOTAL_BYTES"))"
BASE_URL="${MINIO_ENDPOINT}/reth-snapshots/${SNAPSHOT_NAME}"
# Prepare mount
mountpoint -q "$SCHELK_MOUNT" && sudo schelk recover -y || true
# Rewrite manifest's base_url with the runner-reachable endpoint
MANIFEST_TMP=$(mktemp --suffix=.json)
trap 'rm -f -- "$MANIFEST_TMP"' EXIT
echo "$MANIFEST_CONTENT" \
| jq --arg base "$BASE_URL" '.base_url = $base' > "$MANIFEST_TMP"
# Prepare mount. If a previous run left the volume mounted, recover first.
sudo schelk recover -y --kill || true
sudo schelk mount -y
sudo rm -rf "$DATADIR"
sudo mkdir -p "$DATADIR"
# reth download runs as current user (not root), needs write access
sudo chown -R "$(id -u):$(id -g)" "$DATADIR"
update_comment() {
local pct="$1"
local status="$1"
[ -z "${BENCH_COMMENT_ID:-}" ] && return 0
local status="Building binaries & downloading snapshot… ${pct}%"
local body
body="$(printf 'cc @%s\n\n🚀 Benchmark started! [View job](%s)\n\n⏳ **Status:** %s\n\n%s' \
"$BENCH_ACTOR" "$BENCH_JOB_URL" "$status" "$BENCH_CONFIG")"
@@ -75,53 +99,31 @@ update_comment() {
> /dev/null 2>&1 || true
}
# Track compressed bytes flowing through the pipe
DL_BYTES_FILE=$(mktemp)
echo 0 > "$DL_BYTES_FILE"
update_comment "Downloading snapshot…"
# Start progress reporter in background
(
while true; do
sleep 10
CURRENT=$(cat "$DL_BYTES_FILE" 2>/dev/null || echo 0)
if [ "$TOTAL_BYTES" -gt 0 ]; then
PCT=$(( CURRENT * 100 / TOTAL_BYTES ))
[ "$PCT" -gt 100 ] && PCT=100
echo "Snapshot download: $(numfmt --to=iec "$CURRENT") / $(numfmt --to=iec "$TOTAL_BYTES") (${PCT}%)"
update_comment "$PCT"
fi
done
) &
PROGRESS_PID=$!
trap 'kill $PROGRESS_PID 2>/dev/null || true; rm -f "$DL_BYTES_FILE"' EXIT
# Download using reth download (manifest-path with rewritten base_url)
"$RETH" download \
--manifest-path "$MANIFEST_TMP" \
-y \
--minimal \
--datadir "$DATADIR"
# Download and extract; python byte counter tracks compressed bytes received
mc cat "$BUCKET" | python3 -c "
import sys
count = 0
while True:
data = sys.stdin.buffer.read(1048576)
if not data:
break
count += len(data)
sys.stdout.buffer.write(data)
with open('$DL_BYTES_FILE', 'w') as f:
f.write(str(count))
" | pzstd -d -p 6 | sudo tar -xf - -C "$DATADIR"
# Stop progress reporter
kill $PROGRESS_PID 2>/dev/null || true
wait $PROGRESS_PID 2>/dev/null || true
update_comment "100"
update_comment "Downloading snapshot… done"
echo "Snapshot download complete"
# Sanity check: verify expected directories exist
if [ ! -d "$DATADIR/db" ] || [ ! -d "$DATADIR/static_files" ]; then
echo "::error::Snapshot download did not produce expected directory layout (missing db/ or static_files/)"
ls -la "$DATADIR" || true
exit 1
fi
# Promote the new snapshot to become the schelk baseline (virgin volume).
# This copies changed blocks from scratch → virgin so that future
# `schelk recover` calls restore to this new state.
sync
sudo schelk promote -y
# Save ETag marker
echo "$REMOTE_ETAG" > "$ETAG_FILE"
echo "Snapshot promoted to schelk baseline (ETag: ${REMOTE_ETAG})"
# Save manifest hash
echo "$REMOTE_HASH" > "$HASH_FILE"
echo "Snapshot promoted to schelk baseline (manifest hash: ${REMOTE_HASH:0:16})"

View File

@@ -290,6 +290,14 @@ def fmt_s(v: float) -> str:
return f"{v:.2f}s"
def display_bal_mode(bal_mode: str | None) -> str | None:
if not bal_mode or bal_mode == "false":
return None
if bal_mode == "both":
return "true"
return bal_mode
def significance(pct: float, ci_pct: float, lower_is_better: bool) -> str:
"""Return significance label: 'good', 'bad', or 'neutral'."""
significant = abs(pct) > ci_pct
@@ -351,6 +359,9 @@ def generate_comparison_table(
feature_name: str,
feature_sha: str,
big_blocks: bool = False,
warmup_blocks: str | None = None,
wait_time: str | None = None,
bal_mode: str | None = None,
) -> str:
"""Generate a markdown comparison table between baseline and feature."""
n = paired["blocks"]
@@ -391,8 +402,16 @@ def generate_comparison_table(
f"| Mgas/s | {fmt_mgas(run1['mean_mgas_s'])} | {fmt_mgas(run2['mean_mgas_s'])} | {change_str(gas_pct, mgas_ci_pct, lower_is_better=False)} |",
f"| Wall Clock | {fmt_s(run1['wall_clock_s'])} | {fmt_s(run2['wall_clock_s'])} | {change_str(wall_pct, wall_ci_pct, lower_is_better=True)} |",
"",
f"*{n} {'big blocks' if big_blocks else 'blocks'}*",
]
meta_parts = [f"{n} {'big blocks' if big_blocks else 'blocks'}"]
if warmup_blocks:
meta_parts.append(f"{warmup_blocks} warmup")
if wait_time:
meta_parts.append(f"wait time: {wait_time}")
display_mode = display_bal_mode(bal_mode)
if big_blocks and display_mode:
meta_parts.append(f"BAL: {display_mode}")
lines.append(f"*{', '.join(meta_parts)}*")
return "\n".join(lines)
@@ -472,7 +491,9 @@ def main():
parser.add_argument("--feature-ref", "--branch-sha", "--feature-sha", default=None, help="Feature commit SHA")
parser.add_argument("--behind-baseline", "--behind-main", type=int, default=0, help="Commits behind baseline")
parser.add_argument("--big-blocks", action="store_true", default=False, help="Big blocks mode")
parser.add_argument("--gas-ramp-blocks", type=int, default=0, help="Number of gas ramp blocks (big blocks mode)")
parser.add_argument("--warmup-blocks", default=None, help="Number of warmup blocks")
parser.add_argument("--wait-time", default=None, help="Wait time interval used between blocks")
parser.add_argument("--bal-mode", default=None, help="BAL mode (true, feature, baseline)")
parser.add_argument("--grafana-url", default=None, help="Grafana dashboard URL for this benchmark run")
args = parser.parse_args()
@@ -512,6 +533,7 @@ def main():
baseline_name = args.baseline_name or "baseline"
feature_name = args.feature_name or "feature"
feature_sha = args.feature_ref or "unknown"
bal_mode = display_bal_mode(args.bal_mode)
comparison_table = generate_comparison_table(
baseline_stats,
@@ -523,6 +545,9 @@ def main():
feature_name=feature_name,
feature_sha=feature_sha,
big_blocks=args.big_blocks,
warmup_blocks=args.warmup_blocks,
wait_time=args.wait_time,
bal_mode=bal_mode,
)
print(f"Generated comparison ({paired_stats['n']} paired blocks, "
f"mean diff {paired_stats['mean_diff_ms']:+.3f}ms ± {paired_stats['ci_ms']:.3f}ms)")
@@ -554,7 +579,9 @@ def main():
summary = {
"blocks": paired_stats["blocks"],
"big_blocks": args.big_blocks,
"gas_ramp_blocks": args.gas_ramp_blocks,
"warmup_blocks": args.warmup_blocks,
"wait_time": args.wait_time,
"bal_mode": bal_mode,
"baseline": {
"name": baseline_name,
"ref": baseline_ref,

336
.github/scripts/bench-scheduled-refs.sh vendored Executable file
View File

@@ -0,0 +1,336 @@
#!/usr/bin/env bash
#
# Resolves baseline and feature refs for scheduled benchmark runs.
#
# Supports three modes:
# nightly — Queries the latest successful scheduled docker.yml run via
# GitHub API to find the nightly Docker image commit. Compares
# with the last successful feature ref to detect staleness.
# hourly — Compares origin/main HEAD against the last successfully
# benchmarked commit (falls back to HEAD~1 on first run).
# Checks for in-progress sibling runs to avoid overlap.
# release — Compares the latest GitHub release tag against the current
# nightly Docker build. Baseline is the release tag commit,
# feature is the nightly commit.
#
# Usage: bench-scheduled-refs.sh <force> <mode>
# force — "true" to run even if no new commit (bypass skip logic)
# mode — "nightly", "hourly", or "release"
#
# Outputs (via GITHUB_OUTPUT):
# baseline-ref — commit SHA for baseline
# feature-ref — commit SHA for feature
# should-skip — "true" if no new commit since last run or sibling in progress
# is-stale — "true" if latest nightly build is >24h old (nightly only)
# stale-age-hours — age of the nightly build in hours (nightly only)
# nightly-created — ISO timestamp of the nightly build (nightly only)
# release-tag — release tag name (release mode only, e.g. "v2.0.0")
#
# Reads:
# state/nightly-last-feature-ref (nightly, from decofe/reth-bench-charts repo)
# state/hourly-last-feature-ref (hourly, from decofe/reth-bench-charts repo)
# state/release-last-feature-ref (release, from decofe/reth-bench-charts repo)
#
# Requires: gh (GitHub CLI), jq, date, git (hourly mode), curl, DEREK_TOKEN env
set -euxo pipefail
FORCE="${1:-false}"
MODE="${2:-nightly}"
REPO="${GITHUB_REPOSITORY:-paradigmxyz/reth}"
echo "Mode: $MODE, Force: $FORCE"
# ==========================================================================
# Hourly mode: compare origin/main HEAD vs HEAD~1
# ==========================================================================
if [ "$MODE" = "hourly" ]; then
# --- Step 1: Resolve feature ref from git ---
echo "::group::Resolving hourly refs from git"
git fetch origin main --depth=2 --quiet
FEATURE_REF=$(git rev-parse origin/main)
echo "Feature (HEAD): $FEATURE_REF"
echo "::endgroup::"
# --- Step 2: Check for in-progress sibling runs ---
echo "::group::Checking for in-progress sibling runs"
CURRENT_RUN_ID="${GITHUB_RUN_ID:-0}"
IN_PROGRESS=$(gh run list \
-R "$REPO" \
--workflow=bench-scheduled.yml \
--status=in_progress \
--json databaseId \
--jq "[.[] | select(.databaseId != $CURRENT_RUN_ID)] | length")
SHOULD_SKIP="false"
if [ "$IN_PROGRESS" -gt 0 ]; then
echo "::warning::Previous bench run still in progress ($IN_PROGRESS sibling run(s) found). Skipping."
SHOULD_SKIP="true"
# Output a flag so the workflow can send a Slack alert
echo "long-running=true" >> "$GITHUB_OUTPUT"
else
echo "No in-progress sibling runs"
echo "long-running=false" >> "$GITHUB_OUTPUT"
fi
echo "::endgroup::"
# --- Step 3: Read last successful feature ref from charts repo ---
echo "::group::Reading persisted state"
LAST_FEATURE_REF=""
STATE_URL="https://raw.githubusercontent.com/decofe/reth-bench-charts/state/state/hourly-last-feature-ref"
if RAW=$(curl -sfL -H "Authorization: token ${DEREK_TOKEN}" "$STATE_URL"); then
LAST_FEATURE_REF=$(echo "$RAW" | tr -d '[:space:]')
echo "Previous feature ref: $LAST_FEATURE_REF"
else
echo "No persisted state found (first run)"
fi
echo "::endgroup::"
# --- Step 4: Determine baseline and skip logic ---
echo "::group::Resolving baseline and skip logic"
if [ "$SHOULD_SKIP" = "true" ]; then
BASELINE_REF=$(git rev-parse origin/main~1)
echo "Already marked skip (sibling in progress)"
elif [ -z "$LAST_FEATURE_REF" ]; then
# First run: no previous state, fall back to HEAD~1
BASELINE_REF=$(git rev-parse origin/main~1)
echo "First run — using HEAD~1 as baseline"
elif [ "$LAST_FEATURE_REF" = "$FEATURE_REF" ]; then
BASELINE_REF="$LAST_FEATURE_REF"
if [ "$FORCE" = "true" ] || [ "$FORCE" = "--force" ]; then
echo "No new commits on main, but force=true — running anyway"
else
SHOULD_SKIP="true"
echo "No new commits on main since last run — will skip"
fi
else
# Normal case: use last benchmarked commit as baseline
BASELINE_REF="$LAST_FEATURE_REF"
echo "New commit(s) on main detected — comparing against last benchmarked commit"
fi
echo "Baseline: $BASELINE_REF"
echo "Feature: $FEATURE_REF"
echo "Skip: $SHOULD_SKIP"
echo "::endgroup::"
# --- Step 5: Write outputs ---
{
echo "baseline-ref=$BASELINE_REF"
echo "feature-ref=$FEATURE_REF"
echo "should-skip=$SHOULD_SKIP"
echo "is-stale=false"
echo "stale-age-hours=0"
echo "nightly-created="
} >> "$GITHUB_OUTPUT"
exit 0
fi
# ==========================================================================
# Release mode: compare latest GitHub release tag vs current nightly build
# ==========================================================================
if [ "$MODE" = "release" ]; then
# --- Step 1: Resolve feature ref from latest nightly Docker build ---
echo "::group::Querying latest nightly docker build"
RUNS_JSON=$(gh run list \
-R "$REPO" \
--workflow=docker.yml \
--event=schedule \
--status=completed \
--limit 5 \
--json headSha,createdAt,conclusion)
LATEST=$(echo "$RUNS_JSON" | jq -r '[.[] | select(.conclusion == "success")] | first // empty')
if [ -z "$LATEST" ]; then
echo "::error::No successful scheduled docker.yml run found in the last 5 runs"
exit 1
fi
FEATURE_REF=$(echo "$LATEST" | jq -r '.headSha')
echo "Nightly commit (feature): $FEATURE_REF"
echo "::endgroup::"
# --- Step 2: Resolve baseline ref from latest GitHub release ---
echo "::group::Resolving latest release tag"
RELEASE_JSON=$(gh release view --repo "$REPO" --json tagName,targetCommitish,publishedAt 2>/dev/null || echo "{}")
RELEASE_TAG=$(echo "$RELEASE_JSON" | jq -r '.tagName // empty')
if [ -z "$RELEASE_TAG" ]; then
echo "::error::No release found on $REPO"
exit 1
fi
# Resolve the tag to a commit SHA
BASELINE_REF=$(gh api "repos/$REPO/git/ref/tags/$RELEASE_TAG" --jq '.object.sha' 2>/dev/null || true)
# If tag points to an annotated tag object, dereference to the commit
if [ -n "$BASELINE_REF" ]; then
OBJ_TYPE=$(gh api "repos/$REPO/git/tags/$BASELINE_REF" --jq '.object.type' 2>/dev/null || echo "commit")
if [ "$OBJ_TYPE" = "commit" ]; then
BASELINE_REF=$(gh api "repos/$REPO/git/tags/$BASELINE_REF" --jq '.object.sha' 2>/dev/null || echo "$BASELINE_REF")
fi
fi
if [ -z "$BASELINE_REF" ]; then
echo "::error::Could not resolve release tag $RELEASE_TAG to a commit"
exit 1
fi
echo "Release tag: $RELEASE_TAG"
echo "Release commit (baseline): $BASELINE_REF"
echo "::endgroup::"
# --- Step 3: Read last successful feature ref from charts repo ---
echo "::group::Reading persisted state"
LAST_FEATURE_REF=""
STATE_URL="https://raw.githubusercontent.com/decofe/reth-bench-charts/state/state/release-last-feature-ref"
if RAW=$(curl -sfL -H "Authorization: token ${DEREK_TOKEN}" "$STATE_URL"); then
LAST_FEATURE_REF=$(echo "$RAW" | tr -d '[:space:]')
echo "Previous feature ref: $LAST_FEATURE_REF"
else
echo "No persisted state found (first run)"
fi
echo "::endgroup::"
# --- Step 4: Skip logic ---
echo "::group::Resolving skip logic"
SHOULD_SKIP="false"
if [ -n "$LAST_FEATURE_REF" ] && [ "$LAST_FEATURE_REF" = "$FEATURE_REF" ]; then
if [ "$FORCE" = "true" ] || [ "$FORCE" = "--force" ]; then
echo "No new nightly, but force=true — running anyway"
else
SHOULD_SKIP="true"
echo "No new nightly since last release regression run — will skip"
fi
else
echo "New nightly detected or first run"
fi
echo "Baseline: $BASELINE_REF ($RELEASE_TAG)"
echo "Feature: $FEATURE_REF"
echo "Skip: $SHOULD_SKIP"
echo "::endgroup::"
# --- Step 5: Write outputs ---
{
echo "baseline-ref=$BASELINE_REF"
echo "feature-ref=$FEATURE_REF"
echo "should-skip=$SHOULD_SKIP"
echo "is-stale=false"
echo "stale-age-hours=0"
echo "nightly-created="
echo "long-running=false"
echo "release-tag=$RELEASE_TAG"
} >> "$GITHUB_OUTPUT"
exit 0
fi
# ==========================================================================
# Nightly mode: query latest Docker nightly build (original logic)
# ==========================================================================
# --- Step 1: Query latest successful scheduled docker.yml run ---
echo "::group::Querying latest nightly docker build"
RUNS_JSON=$(gh run list \
-R "$REPO" \
--workflow=docker.yml \
--event=schedule \
--status=completed \
--limit 5 \
--json headSha,createdAt,conclusion)
# Find the most recent successful run
LATEST=$(echo "$RUNS_JSON" | jq -r '[.[] | select(.conclusion == "success")] | first // empty')
if [ -z "$LATEST" ]; then
echo "::error::No successful scheduled docker.yml run found in the last 5 runs"
echo "Runs found: $RUNS_JSON"
exit 1
fi
FEATURE_REF=$(echo "$LATEST" | jq -r '.headSha')
CREATED_AT=$(echo "$LATEST" | jq -r '.createdAt')
echo "Latest nightly commit: $FEATURE_REF"
echo "Built at: $CREATED_AT"
echo "::endgroup::"
# --- Step 2: Staleness check ---
echo "::group::Checking staleness"
NOW_EPOCH=$(date +%s)
# Handle both GNU date (-d) and BSD date (-j -f) for cross-platform compat
CREATED_EPOCH=$(date -d "$CREATED_AT" +%s 2>/dev/null || \
date -j -f "%Y-%m-%dT%H:%M:%SZ" "$CREATED_AT" +%s 2>/dev/null || \
date -j -f "%Y-%m-%dT%T%z" "$CREATED_AT" +%s 2>/dev/null || \
{ echo "::error::Cannot parse date: $CREATED_AT"; exit 1; })
AGE_SECONDS=$(( NOW_EPOCH - CREATED_EPOCH ))
AGE_HOURS=$(( AGE_SECONDS / 3600 ))
IS_STALE="false"
if [ "$AGE_HOURS" -gt 24 ]; then
IS_STALE="true"
echo "::warning::STALE NIGHTLY: Build is ${AGE_HOURS}h old (>24h threshold)"
echo "This indicates the nightly docker build failed — no new image was produced"
else
echo "Nightly build age: ${AGE_HOURS}h (within 24h threshold)"
fi
echo "::endgroup::"
# --- Step 3: Read last successful feature ref from charts repo ---
echo "::group::Reading persisted state"
LAST_FEATURE_REF=""
STATE_URL="https://raw.githubusercontent.com/decofe/reth-bench-charts/state/state/nightly-last-feature-ref"
if RAW=$(curl -sfL -H "Authorization: token ${DEREK_TOKEN}" "$STATE_URL"); then
LAST_FEATURE_REF=$(echo "$RAW" | tr -d '[:space:]')
echo "Previous feature ref: $LAST_FEATURE_REF"
else
echo "No persisted state found (first run)"
fi
echo "::endgroup::"
# --- Step 4: Determine baseline and skip logic ---
echo "::group::Resolving refs"
SHOULD_SKIP="false"
BASELINE_REF="$FEATURE_REF" # default for first run
if [ "$IS_STALE" = "true" ]; then
# Stale = error path, don't skip (will alert and fail downstream)
SHOULD_SKIP="false"
BASELINE_REF="${LAST_FEATURE_REF:-$FEATURE_REF}"
echo "Stale nightly detected — will alert and fail"
elif [ -z "$LAST_FEATURE_REF" ]; then
# First run: baseline = feature (self-comparison to establish baseline)
BASELINE_REF="$FEATURE_REF"
echo "First run — will benchmark nightly against itself to establish baseline"
elif [ "$LAST_FEATURE_REF" = "$FEATURE_REF" ]; then
# No new nightly since last successful run
if [ "$FORCE" = "true" ] || [ "$FORCE" = "--force" ]; then
echo "No new nightly, but force=true — running anyway"
BASELINE_REF="$LAST_FEATURE_REF"
else
SHOULD_SKIP="true"
echo "No new nightly since last run — will skip"
fi
else
# Normal case: new nightly available
BASELINE_REF="$LAST_FEATURE_REF"
echo "New nightly detected"
fi
echo "Baseline: $BASELINE_REF"
echo "Feature: $FEATURE_REF"
echo "Skip: $SHOULD_SKIP"
echo "Stale: $IS_STALE"
echo "::endgroup::"
# --- Step 5: Write outputs ---
{
echo "baseline-ref=$BASELINE_REF"
echo "feature-ref=$FEATURE_REF"
echo "should-skip=$SHOULD_SKIP"
echo "is-stale=$IS_STALE"
echo "stale-age-hours=$AGE_HOURS"
echo "nightly-created=$CREATED_AT"
} >> "$GITHUB_OUTPUT"

View File

@@ -18,6 +18,7 @@
const fs = require('fs');
const path = require('path');
const { fmtChange, fmtMs, verdict, loadSamplyUrls, blocksLabel, metricRows, waitTimeRows } = require('./bench-utils');
const SLACK_API = 'https://slack.com/api/chat.postMessage';
@@ -61,41 +62,17 @@ function cell(text) {
return { type: 'raw_text', text: s || ' ' };
}
// Slack shortcodes for verdict (Block Kit header doesn't support unicode emoji)
const SLACK_VERDICT = {
'⚠️': ':warning:',
'❌': ':x:',
'✅': ':white_check_mark:',
'⚪': ':white_circle:',
};
function buildSuccessBlocks({ summary, prNumber, actor, actorSlackId, jobUrl, repo, samplyUrls }) {
const b = summary.baseline.stats;
const f = summary.feature.stats;
const c = summary.changes;
const sigEmoji = { good: '\u2705', bad: '\u274c', neutral: '\u26aa' };
function fmtMs(v) { return v.toFixed(2) + 'ms'; }
function fmtMgas(v) { return v.toFixed(2); }
function fmtS(v) { return v.toFixed(2) + 's'; }
function fmtChange(ch) {
if (!ch.pct && !ch.ci_pct) return ' ';
const pctStr = `${ch.pct >= 0 ? '+' : ''}${ch.pct.toFixed(2)}%`;
const ciStr = ch.ci_pct ? ` (\u00b1${ch.ci_pct.toFixed(2)}%)` : '';
return `${pctStr}${ciStr} ${sigEmoji[ch.sig]}`;
}
// Overall result for header
const vals = Object.values(c);
const hasBad = vals.some(v => v.sig === 'bad');
const hasGood = vals.some(v => v.sig === 'good');
let headerEmoji, headerResult;
if (hasBad && hasGood) {
headerEmoji = ':warning:';
headerResult = 'Mixed Results';
} else if (hasBad) {
headerEmoji = ':x:';
headerResult = 'Regression';
} else if (hasGood) {
headerEmoji = ':white_check_mark:';
headerResult = 'Improvement';
} else {
headerEmoji = ':white_circle:';
headerResult = 'No Difference';
}
const { emoji, label } = verdict(summary.changes);
const headerEmoji = SLACK_VERDICT[emoji] || emoji;
const prUrl = prNumber ? `https://github.com/${repo}/pull/${prNumber}` : '';
const commitUrl = `https://github.com/${repo}/commit`;
@@ -120,19 +97,7 @@ function buildSuccessBlocks({ summary, prNumber, actor, actorSlackId, jobUrl, re
if (fl1) featureLine += ` | <${fl1}|Samply 1>`;
if (fl2) featureLine += ` | <${fl2}|Samply 2>`;
const cores = process.env.BENCH_CORES || '0';
const countsParts = [];
if (summary.big_blocks) {
const gasRamp = summary.gas_ramp_blocks || 0;
if (gasRamp > 0) countsParts.push(`*Gas Ramp:* ${gasRamp}`);
countsParts.push(`*Big Blocks:* ${summary.blocks}`);
} else {
const warmup = summary.warmup_blocks || process.env.BENCH_WARMUP_BLOCKS || '';
if (warmup) countsParts.push(`*Warmup:* ${warmup}`);
countsParts.push(`*Blocks:* ${summary.blocks}`);
}
if (cores !== '0') countsParts.push(`*Cores:* ${cores}`);
const countsLine = countsParts.join(' | ');
const countsLine = blocksLabel(summary).map(p => `*${p.key}:* ${p.value}`).join(' | ');
const baselineArgs = process.env.BENCH_BASELINE_ARGS || '';
const featureArgs = process.env.BENCH_FEATURE_ARGS || '';
@@ -159,10 +124,17 @@ function buildSuccessBlocks({ summary, prNumber, actor, actorSlackId, jobUrl, re
},
];
// Build table rows from shared metricRows
const rows = metricRows(summary);
const tableRows = [
[cell('Metric'), cell('Baseline'), cell('Feature'), cell('Change')],
...rows.map(r => [cell(r.label), cell(r.baseline), cell(r.feature), cell(r.change || ' ')]),
];
const blocks = [
{
type: 'header',
text: { type: 'plain_text', text: `${headerEmoji} ${headerResult}`, emoji: true },
text: { type: 'plain_text', text: `${headerEmoji} ${label}`, emoji: true },
},
{
type: 'section',
@@ -176,16 +148,7 @@ function buildSuccessBlocks({ summary, prNumber, actor, actorSlackId, jobUrl, re
{ align: 'right' },
{ align: 'right' },
],
rows: [
[cell('Metric'), cell('Baseline'), cell('Feature'), cell('Change')],
[cell('Mean'), cell(fmtMs(b.mean_ms)), cell(fmtMs(f.mean_ms)), cell(fmtChange(c.mean))],
[cell('StdDev'), cell(fmtMs(b.stddev_ms)), cell(fmtMs(f.stddev_ms)), cell(' ')],
[cell('P50'), cell(fmtMs(b.p50_ms)), cell(fmtMs(f.p50_ms)), cell(fmtChange(c.p50))],
[cell('P90'), cell(fmtMs(b.p90_ms)), cell(fmtMs(f.p90_ms)), cell(fmtChange(c.p90))],
[cell('P99'), cell(fmtMs(b.p99_ms)), cell(fmtMs(f.p99_ms)), cell(fmtChange(c.p99))],
[cell('Mgas/s'), cell(fmtMgas(b.mean_mgas_s)), cell(fmtMgas(f.mean_mgas_s)), cell(fmtChange(c.mgas_s))],
[cell('Wall Clock'), cell(fmtS(b.wall_clock_s)), cell(fmtS(f.wall_clock_s)), cell(fmtChange(c.wall_clock))],
],
rows: tableRows,
},
{
type: 'actions',
@@ -195,16 +158,12 @@ function buildSuccessBlocks({ summary, prNumber, actor, actorSlackId, jobUrl, re
// Wait times as a separate table block (sent as threaded reply due to Slack one-table limit)
const threadBlocks = [];
const waitTimes = summary.wait_times || {};
const waitKeys = Object.keys(waitTimes);
if (waitKeys.length > 0) {
const waitRows = [
const wtRows = waitTimeRows(summary);
if (wtRows.length > 0) {
const waitTableRows = [
[cell('Wait Time'), cell('Baseline'), cell('Feature')],
...wtRows.map(r => [cell(r.title), cell(r.baseline), cell(r.feature)]),
];
for (const key of waitKeys) {
const wt = waitTimes[key];
waitRows.push([cell(wt.title), cell(fmtMs(wt.baseline.mean_ms)), cell(fmtMs(wt.feature.mean_ms))]);
}
threadBlocks.push({
type: 'table',
column_settings: [
@@ -212,7 +171,7 @@ function buildSuccessBlocks({ summary, prNumber, actor, actorSlackId, jobUrl, re
{ align: 'right' },
{ align: 'right' },
],
rows: waitRows,
rows: waitTableRows,
});
}
@@ -274,16 +233,7 @@ async function success({ core, context }) {
const jobUrl = process.env.BENCH_JOB_URL ||
`${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
// Load samply profile URLs (files exist when samply profiling was enabled)
const samplyUrls = {};
for (const run of ['baseline-1', 'baseline-2', 'feature-1', 'feature-2']) {
try {
const url = fs.readFileSync(
path.join(process.env.BENCH_WORK_DIR, run, 'samply-profile-url.txt'), 'utf8'
).trim();
if (url) samplyUrls[run] = url;
} catch {}
}
const samplyUrls = loadSamplyUrls(process.env.BENCH_WORK_DIR);
const slackUsers = loadSlackUsers(process.env.GITHUB_WORKSPACE || '.');
const actorSlackId = slackUsers[actor];

View File

@@ -20,5 +20,6 @@
"SuperFluffy": "U095BKHB2Q4",
"kamsz": "U0A2563UBRD",
"zerosnacks": "U09FARPMN74",
"samczsun": "U096R14E4H3"
"samczsun": "U096R14E4H3",
"laibe": "U09FARE0B9Q"
}

150
.github/scripts/bench-upload-clickhouse.py vendored Executable file
View File

@@ -0,0 +1,150 @@
#!/usr/bin/env python3
"""Upload bench-scheduled summary.json results to ClickHouse.
Reads the summary JSON produced by bench-reth-summary.py and inserts a row
into the bench_dual_comparisons table so the PM dashboard can display results.
Usage:
bench-upload-clickhouse.py \
--summary <summary.json> \
--workflow-name <name> \
--chain <chain>
Environment variables:
CLICKHOUSE_HOST ClickHouse host URL
CLICKHOUSE_USER ClickHouse username
CLICKHOUSE_PASSWORD ClickHouse password
CLICKHOUSE_DATABASE ClickHouse database (default: "default")
"""
import argparse
import json
import os
import sys
import urllib.request
import urllib.error
def main():
parser = argparse.ArgumentParser(description="Upload benchmark results to ClickHouse")
parser.add_argument("--summary", required=True, help="Path to summary.json")
parser.add_argument("--workflow-name", required=True, help="Workflow name for ClickHouse")
parser.add_argument("--chain", default="mainnet", help="Chain name")
parser.add_argument("--grafana-url", default="", help="Grafana dashboard URL")
parser.add_argument("--github-diff-url", default="", help="GitHub diff URL")
parser.add_argument("--job-url", default="", help="CI job URL")
args = parser.parse_args()
ch_host = os.environ.get("CLICKHOUSE_HOST", "")
ch_user = os.environ.get("CLICKHOUSE_USER", "")
ch_password = os.environ.get("CLICKHOUSE_PASSWORD", "")
ch_database = os.environ.get("CLICKHOUSE_DATABASE", "default")
ch_table = "bench_dual_comparisons"
if not ch_host or not ch_user or not ch_password:
print("Missing ClickHouse credentials, skipping upload", file=sys.stderr)
sys.exit(0)
with open(args.summary) as f:
summary = json.load(f)
baseline = summary["baseline"]
feature = summary["feature"]
b_stats = baseline["stats"]
f_stats = feature["stats"]
changes = summary["changes"]
blocks = summary["blocks"]
# Extract wait time data
wait_times = summary.get("wait_times", {})
def wait_mean(field):
wt = wait_times.get(field, {})
b = wt.get("baseline", {}).get("mean_ms", 0.0)
f = wt.get("feature", {}).get("mean_ms", 0.0)
return b, f
b_persist, f_persist = wait_mean("persistence_wait_us")
b_exec_cache, f_exec_cache = wait_mean("execution_cache_wait_us")
b_sparse, f_sparse = wait_mean("sparse_trie_wait_us")
# gas_per_second: summary uses mean_mgas_s (Mgas/s), ClickHouse stores gas/s
b_gas_per_second = b_stats["mean_mgas_s"] * 1_000_000
f_gas_per_second = f_stats["mean_mgas_s"] * 1_000_000
mean_change = changes.get("mean", {}).get("pct", 0.0)
gas_change = changes.get("mgas_s", {}).get("pct", 0.0)
latency_improved = 1 if mean_change < 0 else 0
throughput_improved = 1 if gas_change > 0 else 0
big_blocks = "true" if summary.get("big_blocks", False) else "false"
warmup_blocks = summary.get("warmup_blocks", 0) or 0
def esc(s):
return str(s).replace("'", "\\'")
insert = f"""
INSERT INTO {ch_database}.{ch_table} (
workflow_name, chain,
baseline_ref, baseline_commit,
feature_ref, feature_commit,
blocks,
baseline_total_latency_ms, baseline_gas_per_second,
baseline_latency_mean_ms, baseline_latency_median_ms,
baseline_latency_p90_ms, baseline_latency_p99_ms,
feature_total_latency_ms, feature_gas_per_second,
feature_latency_mean_ms, feature_latency_median_ms,
feature_latency_p90_ms, feature_latency_p99_ms,
mean_latency_change_percent, gas_per_second_change_percent,
latency_improved, throughput_improved,
warmup_blocks, big_blocks,
grafana_benchmark_url, github_diff_url, argo_workflow_url,
baseline_persistence_wait_mean_ms, baseline_execution_cache_wait_mean_ms,
baseline_sparse_trie_wait_mean_ms,
feature_persistence_wait_mean_ms, feature_execution_cache_wait_mean_ms,
feature_sparse_trie_wait_mean_ms
) VALUES (
'{esc(args.workflow_name)}', '{esc(args.chain)}',
'{esc(baseline["ref"])}', '{esc(baseline["ref"])}',
'{esc(feature["ref"])}', '{esc(feature["ref"])}',
{blocks},
{b_stats.get("wall_clock_s", 0) * 1000}, {b_gas_per_second},
{b_stats["mean_ms"]}, {b_stats["p50_ms"]},
{b_stats["p90_ms"]}, {b_stats["p99_ms"]},
{f_stats.get("wall_clock_s", 0) * 1000}, {f_gas_per_second},
{f_stats["mean_ms"]}, {f_stats["p50_ms"]},
{f_stats["p90_ms"]}, {f_stats["p99_ms"]},
{mean_change}, {gas_change},
{latency_improved}, {throughput_improved},
{warmup_blocks}, '{big_blocks}',
'{esc(args.grafana_url)}', '{esc(args.github_diff_url)}', '{esc(args.job_url)}',
{b_persist}, {b_exec_cache}, {b_sparse},
{f_persist}, {f_exec_cache}, {f_sparse}
);
"""
# Build ClickHouse HTTP URL (credentials via headers, never in URL)
host = ch_host.rstrip("/")
if not host.startswith("http"):
host = f"https://{host}:8443"
url = f"{host}/?database={ch_database}"
req = urllib.request.Request(url, data=insert.encode("utf-8"), method="POST")
req.add_header("Content-Type", "text/plain")
req.add_header("X-ClickHouse-User", ch_user)
req.add_header("X-ClickHouse-Key", ch_password)
try:
with urllib.request.urlopen(req) as resp:
body = resp.read().decode("utf-8")
if body.strip():
print(f"ClickHouse response: {body}")
print(f"Successfully uploaded benchmark results to ClickHouse ({args.workflow_name})")
except urllib.error.HTTPError as e:
body = e.read().decode("utf-8")
print(f"ClickHouse upload failed ({e.code}): {body}", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()

111
.github/scripts/bench-utils.js vendored Normal file
View File

@@ -0,0 +1,111 @@
// Shared utilities for reth-bench result rendering.
//
// Used by bench-job-summary.js and bench-slack-notify.js.
const fs = require('fs');
const path = require('path');
const SIG_EMOJI = { good: '✅', bad: '❌', neutral: '⚪' };
function fmtMs(v) { return v.toFixed(2) + 'ms'; }
function fmtMgas(v) { return v.toFixed(2); }
function fmtS(v) { return v.toFixed(2) + 's'; }
function fmtChange(ch) {
if (!ch || (!ch.pct && !ch.ci_pct)) return '';
const pctStr = `${ch.pct >= 0 ? '+' : ''}${ch.pct.toFixed(2)}%`;
const ciStr = ch.ci_pct ? `${ch.ci_pct.toFixed(2)}%)` : '';
return `${pctStr}${ciStr} ${SIG_EMOJI[ch.sig]}`;
}
function verdict(changes) {
const vals = Object.values(changes);
const hasBad = vals.some(v => v.sig === 'bad');
const hasGood = vals.some(v => v.sig === 'good');
if (hasBad && hasGood) return { emoji: '⚠️', label: 'Mixed Results' };
if (hasBad) return { emoji: '❌', label: 'Regression' };
if (hasGood) return { emoji: '✅', label: 'Improvement' };
return { emoji: '⚪', label: 'No Difference' };
}
function loadSamplyUrls(workDir) {
const urls = {};
for (const run of ['baseline-1', 'baseline-2', 'feature-1', 'feature-2']) {
try {
const url = fs.readFileSync(path.join(workDir, run, 'samply-profile-url.txt'), 'utf8').trim();
if (url) urls[run] = url;
} catch {}
}
return urls;
}
function balModeLabel(mode) {
switch (mode) {
case 'true':
case 'feature':
case 'baseline':
return mode;
case 'both':
return 'true';
default:
return '';
}
}
function blocksLabel(summary) {
const parts = [];
if (summary.big_blocks) {
parts.push({ key: 'Big Blocks', value: summary.blocks });
const balMode = balModeLabel(summary.bal_mode || summary.bal || process.env.BENCH_BAL || 'false');
if (balMode) parts.push({ key: 'BAL', value: balMode });
} else {
const warmup = summary.warmup_blocks || process.env.BENCH_WARMUP_BLOCKS || '';
if (warmup) parts.push({ key: 'Warmup', value: warmup });
parts.push({ key: 'Blocks', value: summary.blocks });
}
const cores = process.env.BENCH_CORES || '0';
if (cores !== '0') parts.push({ key: 'Cores', value: cores });
if (summary.wait_time) parts.push({ key: 'Wait time', value: summary.wait_time });
return parts;
}
// The 7 metric rows shared by all renderers.
// Returns an array of { label, baseline, feature, change } objects.
function metricRows(summary) {
const b = summary.baseline.stats;
const f = summary.feature.stats;
const c = summary.changes;
return [
{ label: 'Mean', baseline: fmtMs(b.mean_ms), feature: fmtMs(f.mean_ms), change: fmtChange(c.mean) },
{ label: 'StdDev', baseline: fmtMs(b.stddev_ms), feature: fmtMs(f.stddev_ms), change: '' },
{ label: 'P50', baseline: fmtMs(b.p50_ms), feature: fmtMs(f.p50_ms), change: fmtChange(c.p50) },
{ label: 'P90', baseline: fmtMs(b.p90_ms), feature: fmtMs(f.p90_ms), change: fmtChange(c.p90) },
{ label: 'P99', baseline: fmtMs(b.p99_ms), feature: fmtMs(f.p99_ms), change: fmtChange(c.p99) },
{ label: 'Mgas/s', baseline: fmtMgas(b.mean_mgas_s), feature: fmtMgas(f.mean_mgas_s), change: fmtChange(c.mgas_s) },
{ label: 'Wall Clock', baseline: fmtS(b.wall_clock_s), feature: fmtS(f.wall_clock_s), change: fmtChange(c.wall_clock) },
];
}
// Wait time rows: one row per metric showing mean values.
function waitTimeRows(summary) {
const waitTimes = summary.wait_times || {};
const rows = [];
for (const key of Object.keys(waitTimes)) {
const wt = waitTimes[key];
rows.push({ title: wt.title, baseline: fmtMs(wt.baseline.mean_ms), feature: fmtMs(wt.feature.mean_ms) });
}
return rows;
}
module.exports = {
SIG_EMOJI,
fmtMs,
fmtMgas,
fmtS,
fmtChange,
verdict,
loadSamplyUrls,
blocksLabel,
metricRows,
waitTimeRows,
};

View File

@@ -1,414 +0,0 @@
#!/usr/bin/env bash
#
# Full PGO+BOLT optimized build for reth using real reth-bench workloads.
#
# Phases:
# 1. Build PGO-instrumented reth, run reth-bench → collect PGO profiles
# 2. Build BOLT-instrumented reth (with PGO), run reth-bench → collect BOLT profiles
# 3. Build final PGO+BOLT optimized binary
#
# Required environment variables:
# DATADIR - Path to reth datadir (must already contain chain data)
# RPC_URL - Source RPC URL for reth-bench to fetch payloads from
#
# Optional environment variables:
# PGO_BLOCKS - Number of blocks for PGO profiling (default: 20)
# BOLT_BLOCKS - Number of blocks for BOLT profiling (default: 20)
# SKIP_BOLT - Temporarily skip BOLT phases (default: false)
# STRIP_SYMBOLS - Strip debug symbols from output binary (default: true)
# COLLECT_PGO_ONLY - Stop after producing merged.profdata (default: false)
# PGO_PROFDATA - Path to pre-collected merged.profdata (optional)
# PROFILE - Cargo profile (default: maxperf-symbols)
# FEATURES - Cargo features (default: jemalloc,asm-keccak,min-debug-logs)
# TARGET - Target triple (default: auto-detected)
# EXTRA_RUSTFLAGS - Additional RUSTFLAGS (e.g. -C target-cpu=x86-64-v3)
#
# Output:
# target/$PROFILE_DIR/reth — final optimized binary
set -euo pipefail
gha_section_start() {
local title="$1"
if [ -n "${GITHUB_ACTIONS:-}" ]; then
echo "::group::$title"
else
echo ""
echo "=== $title ==="
fi
}
gha_section_end() {
if [ -n "${GITHUB_ACTIONS:-}" ]; then
echo "::endgroup::"
fi
}
cd "$(dirname "$0")/../.."
# ── Configuration ──────────────────────────────────────────────────────────────
PGO_BLOCKS="${PGO_BLOCKS:-20}"
BOLT_BLOCKS="${BOLT_BLOCKS:-20}"
SKIP_BOLT="${SKIP_BOLT:-false}"
STRIP_SYMBOLS="${STRIP_SYMBOLS:-true}"
COLLECT_PGO_ONLY="${COLLECT_PGO_ONLY:-false}"
PROFILE="${PROFILE:-maxperf-symbols}"
FEATURES="${FEATURES:-jemalloc,asm-keccak,min-debug-logs}"
TARGET="${TARGET:-$(rustc -Vv | grep host | cut -d' ' -f2)}"
BASE_RUSTFLAGS="${RUSTFLAGS:-}"
EXTRA_RUSTFLAGS="${EXTRA_RUSTFLAGS:-}"
COMBINED_RUSTFLAGS="$BASE_RUSTFLAGS $EXTRA_RUSTFLAGS"
PGO_PROFDATA="${PGO_PROFDATA:-}"
DATADIR="${DATADIR:-}"
RPC_URL="${RPC_URL:-}"
SKIP_BOLT_BOOL=false
if [[ "${SKIP_BOLT,,}" == "true" || "$SKIP_BOLT" == "1" ]]; then
SKIP_BOLT_BOOL=true
fi
STRIP_SYMBOLS_BOOL=false
if [[ "${STRIP_SYMBOLS,,}" == "true" || "$STRIP_SYMBOLS" == "1" ]]; then
STRIP_SYMBOLS_BOOL=true
fi
COLLECT_PGO_ONLY_BOOL=false
if [[ "${COLLECT_PGO_ONLY,,}" == "true" || "$COLLECT_PGO_ONLY" == "1" ]]; then
COLLECT_PGO_ONLY_BOOL=true
fi
USE_PRECOLLECTED_PGO=false
if [ -n "$PGO_PROFDATA" ]; then
if [ ! -f "$PGO_PROFDATA" ]; then
echo "error: PGO_PROFDATA points to a missing file: $PGO_PROFDATA"
exit 1
fi
USE_PRECOLLECTED_PGO=true
fi
NEEDS_BENCH_WORKLOAD=true
if [ "$USE_PRECOLLECTED_PGO" = true ] && [ "$SKIP_BOLT_BOOL" = true ]; then
NEEDS_BENCH_WORKLOAD=false
fi
if [ "$NEEDS_BENCH_WORKLOAD" = true ]; then
: "${DATADIR:?DATADIR must be set to the reth data directory}"
: "${RPC_URL:?RPC_URL must be set}"
fi
if [[ "$PROFILE" == dev ]]; then
PROFILE_DIR=debug
else
PROFILE_DIR=$PROFILE
fi
MANIFEST_PATH="bin/reth"
LLVM_VERSION=$(rustc -Vv | grep -oP 'LLVM version: \K\d+')
PGO_DIR="$PWD/target/pgo-profiles"
BOLT_DIR="$PWD/target/bolt-profiles"
CARGO_ARGS=(--profile "$PROFILE" --features "$FEATURES" --manifest-path "$MANIFEST_PATH/Cargo.toml" --bin "reth" --locked)
# Enable debug symbols for BOLT (requires symbols to reorder code).
# Strip them at the end.
PROFILE_UPPER=$(echo "$PROFILE" | tr '[:lower:]-' '[:upper:]_')
export "CARGO_PROFILE_${PROFILE_UPPER}_STRIP=debuginfo"
gha_section_start "Full PGO+BOLT Build"
echo "Binary: reth"
echo "Manifest: $MANIFEST_PATH"
echo "Target: $TARGET"
echo "Profile: $PROFILE"
echo "Features: $FEATURES"
echo "LLVM: $LLVM_VERSION"
echo "PGO blocks: $PGO_BLOCKS"
echo "BOLT blocks: $BOLT_BLOCKS"
echo "Skip BOLT: $SKIP_BOLT"
echo "Strip symbols: $STRIP_SYMBOLS"
echo "Collect only: $COLLECT_PGO_ONLY"
echo "PGO profdata: ${PGO_PROFDATA:-<collect with reth-bench>}"
echo "RUSTFLAGS: ${BASE_RUSTFLAGS:-<unset>}"
echo "EXTRA_RUSTFLAGS: ${EXTRA_RUSTFLAGS:-<unset>}"
if [ "$NEEDS_BENCH_WORKLOAD" = true ]; then
echo "Datadir: $DATADIR"
echo "RPC URL: $RPC_URL"
else
echo "Datadir: <not required>"
echo "RPC URL: <not required>"
fi
gha_section_end
# ── Prerequisites ──────────────────────────────────────────────────────────────
gha_section_start "Installing prerequisites"
rustup component add llvm-tools-preview
LLVM_PROFDATA=$(find "$(rustc --print sysroot)" -name llvm-profdata -type f | head -1)
if [ -z "$LLVM_PROFDATA" ]; then
echo "error: llvm-profdata not found"
exit 1
fi
install_bolt() {
if command -v llvm-bolt &>/dev/null; then
echo "BOLT already installed"
return
fi
echo "Installing BOLT from apt.llvm.org..."
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc >/dev/null
CODENAME=$(lsb_release -cs)
echo "deb http://apt.llvm.org/$CODENAME/ llvm-toolchain-$CODENAME-$LLVM_VERSION main" | sudo tee /etc/apt/sources.list.d/llvm.list >/dev/null
sudo apt-get update -qq
sudo apt-get install -y -qq "bolt-$LLVM_VERSION"
sudo ln -sf "/usr/bin/llvm-bolt-$LLVM_VERSION" /usr/local/bin/llvm-bolt
sudo ln -sf "/usr/bin/merge-fdata-$LLVM_VERSION" /usr/local/bin/merge-fdata
}
if [ "$SKIP_BOLT_BOOL" = true ]; then
echo "Skipping BOLT installation (SKIP_BOLT=$SKIP_BOLT)"
else
install_bolt
fi
gha_section_end
if [ "$NEEDS_BENCH_WORKLOAD" = true ]; then
# Build reth-bench once (non-instrumented) — reused for both phases.
gha_section_start "Building reth-bench"
RUSTFLAGS="$COMBINED_RUSTFLAGS" \
cargo build --profile "$PROFILE" --features "$FEATURES" \
--manifest-path bin/reth-bench/Cargo.toml --bin reth-bench --locked
RETH_BENCH_BIN="$(find target -name reth-bench -type f -executable | head -1)"
echo "reth-bench: $RETH_BENCH_BIN"
gha_section_end
else
gha_section_start "Building reth-bench"
echo "Skipping reth-bench build (pre-collected PGO with SKIP_BOLT=true)"
gha_section_end
fi
# ── Helpers ────────────────────────────────────────────────────────────────────
RETH_PID=
cleanup() {
if [ -n "${RETH_PID:-}" ] && kill -0 "$RETH_PID" 2>/dev/null; then
echo "Stopping reth (pid $RETH_PID)..."
sudo kill "$RETH_PID" 2>/dev/null || true
for i in $(seq 1 60); do
sudo kill -0 "$RETH_PID" 2>/dev/null || break
if [ $((i % 10)) -eq 0 ]; then
echo " waiting... (${i}s)"
fi
sleep 1
done
sudo kill -9 "$RETH_PID" 2>/dev/null || true
fi
}
trap cleanup EXIT
# Start reth, wait for RPC, run reth-bench, then stop reth.
# Arguments: $1 = reth binary path, $2 = number of blocks, $3 = log label
run_bench_workload() {
local reth_bin="$1" blocks="$2" label="$3"
local http_port=8545 authrpc_port=8551
echo "--- Starting reth ($label) ---"
sudo "$reth_bin" node \
--datadir "$DATADIR" \
--log.file.directory "/tmp/reth-${label}-logs" \
--engine.accept-execution-requests-hash \
--http --http.port "$http_port" \
--authrpc.port "$authrpc_port" \
--disable-discovery --no-persist-peers \
> "/tmp/reth-${label}.log" 2>&1 &
RETH_PID=$!
echo "Waiting for reth RPC..."
for i in $(seq 1 120); do
if curl -sf "http://127.0.0.1:$http_port" -X POST \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
> /dev/null 2>&1; then
echo "reth is ready after ${i}s"
break
fi
if [ "$i" -eq 120 ]; then
echo "error: reth failed to start within 120s"
cat "/tmp/reth-${label}.log"
exit 1
fi
sleep 1
done
echo "Running reth-bench ($blocks blocks)..."
"$RETH_BENCH_BIN" new-payload-fcu \
--rpc-url "$RPC_URL" \
--engine-rpc-url "http://127.0.0.1:$authrpc_port" \
--jwt-secret "$DATADIR/jwt.hex" \
--advance "$blocks" \
--reth-new-payload 2>&1 | sed -u "s/^/[$label] /"
echo "Stopping reth ($label)..."
sudo kill "$RETH_PID" 2>/dev/null || true
for i in $(seq 1 60); do
sudo kill -0 "$RETH_PID" 2>/dev/null || break
sleep 1
done
sudo kill -9 "$RETH_PID" 2>/dev/null || true
RETH_PID=
}
publish_binary() {
local source_bin="$1"
for out in "target/$TARGET/$PROFILE_DIR" "target/$PROFILE_DIR"; do
local destination="$out/reth"
mkdir -p "$out"
# Skip copying when source and destination resolve to the same inode.
if [ -e "$destination" ] && [ "$source_bin" -ef "$destination" ]; then
continue
fi
cp "$source_bin" "$destination"
done
}
if [ "$USE_PRECOLLECTED_PGO" = true ]; then
gha_section_start "Phase 1: Using Pre-Collected PGO Profile"
rm -rf "$PGO_DIR"
mkdir -p "$PGO_DIR"
cp "$PGO_PROFDATA" "$PGO_DIR/merged.profdata"
echo "Using pre-collected profile: $PGO_PROFDATA"
echo "PGO profile: $PGO_DIR/merged.profdata ($(ls -lh "$PGO_DIR/merged.profdata" | awk '{print $5}'))"
gha_section_end
else
# ── Phase 1: PGO profile collection ───────────────────────────────────────
gha_section_start "Phase 1: PGO Profile Collection"
rm -rf "$PGO_DIR"
mkdir -p "$PGO_DIR"
echo "Building PGO-instrumented binary..."
RUSTFLAGS="-Cprofile-generate=$PGO_DIR -Crelocation-model=pic $COMBINED_RUSTFLAGS" \
cargo build "${CARGO_ARGS[@]}" --target "$TARGET"
PGO_RETH_BIN="$PWD/target/$TARGET/$PROFILE_DIR/reth"
echo "Instrumented binary: $PGO_RETH_BIN ($(ls -lh "$PGO_RETH_BIN" | awk '{print $5}'))"
run_bench_workload "$PGO_RETH_BIN" "$PGO_BLOCKS" "pgo"
# Fix ownership if reth ran as root.
sudo chown -R "$(id -un):$(id -gn)" "$PGO_DIR" 2>/dev/null || true
# Merge PGO profiles.
echo "Merging PGO profiles..."
PROFRAW_COUNT=$(find "$PGO_DIR" -name '*.profraw' | wc -l)
echo "Found $PROFRAW_COUNT .profraw files"
if [ "$PROFRAW_COUNT" -eq 0 ]; then
echo "error: no .profraw files — instrumented binary did not produce profiles"
exit 1
fi
"$LLVM_PROFDATA" merge -o "$PGO_DIR/merged.profdata" "$PGO_DIR"/*.profraw
echo "PGO profile: $PGO_DIR/merged.profdata ($(ls -lh "$PGO_DIR/merged.profdata" | awk '{print $5}'))"
gha_section_end
fi
if [ "$COLLECT_PGO_ONLY_BOOL" = true ]; then
gha_section_start "PGO Collection Complete"
echo "COLLECT_PGO_ONLY=true, skipping PGO/BOLT optimized binary build"
echo "Profile: $PGO_DIR/merged.profdata"
gha_section_end
exit 0
fi
if [ "$SKIP_BOLT_BOOL" = true ]; then
gha_section_start "BOLT Phase Skipped"
echo "SKIP_BOLT=$SKIP_BOLT, building PGO-only binary"
echo "Building PGO-optimized binary..."
RUSTFLAGS="-Cprofile-use=$PGO_DIR/merged.profdata $COMBINED_RUSTFLAGS" \
cargo build "${CARGO_ARGS[@]}" --target "$TARGET"
BUILT_BIN="$PWD/target/$TARGET/$PROFILE_DIR/reth"
if [ "$STRIP_SYMBOLS_BOOL" = true ]; then
echo "Stripping debug symbols..."
strip "$BUILT_BIN"
else
echo "Skipping strip (STRIP_SYMBOLS=$STRIP_SYMBOLS)"
fi
publish_binary "$BUILT_BIN"
gha_section_end
else
# ── Phase 2: BOLT profile collection (with PGO) ──────────────────────────
gha_section_start "Phase 2: BOLT Profile Collection (with PGO)"
rm -rf "$BOLT_DIR"
mkdir -p "$BOLT_DIR"
echo "Building BOLT-instrumented binary with PGO..."
# --emit-relocs preserves relocation entries in the binary, required by llvm-bolt -instrument
RUSTFLAGS="-Cprofile-use=$PGO_DIR/merged.profdata -Clink-arg=-Wl,--emit-relocs $COMBINED_RUSTFLAGS" \
cargo build "${CARGO_ARGS[@]}" --target "$TARGET"
# Instrument with BOLT
BUILT_BIN="$PWD/target/$TARGET/$PROFILE_DIR/reth"
BOLT_INSTRUMENTED_BIN="$BUILT_BIN-bolt-instrumented"
echo "Instrumenting binary with BOLT..."
# --skip-funcs: skip compiler-generated drop_in_place functions that BOLT can't handle
# as split functions in relocation mode (triggered by --emit-relocs)
llvm-bolt "$BUILT_BIN" \
-instrument \
--instrumentation-file-append-pid \
--instrumentation-file="$BOLT_DIR/prof" \
--skip-funcs='.*drop_in_place.*' \
-o "$BOLT_INSTRUMENTED_BIN"
echo "BOLT-instrumented binary: $BOLT_INSTRUMENTED_BIN ($(ls -lh "$BOLT_INSTRUMENTED_BIN" | awk '{print $5}'))"
run_bench_workload "$BOLT_INSTRUMENTED_BIN" "$BOLT_BLOCKS" "bolt"
# Fix ownership for BOLT profiles
sudo chown -R "$(id -un):$(id -gn)" "$BOLT_DIR" 2>/dev/null || true
# Merge BOLT profiles
echo "Merging BOLT profiles..."
FDATA_COUNT=$(find "$BOLT_DIR" -name '*.fdata' | wc -l)
echo "Found $FDATA_COUNT .fdata files"
if [ "$FDATA_COUNT" -eq 0 ]; then
echo "error: no .fdata files — BOLT-instrumented binary did not produce profiles"
exit 1
fi
merge-fdata "$BOLT_DIR"/*.fdata > "$BOLT_DIR/merged.fdata"
echo "BOLT profile: $BOLT_DIR/merged.fdata ($(ls -lh "$BOLT_DIR/merged.fdata" | awk '{print $5}'))"
gha_section_end
# ── Phase 3: Final optimized build ───────────────────────────────────────
gha_section_start "Phase 3: Final PGO+BOLT Optimized Build"
echo "Building PGO-optimized binary..."
# --emit-relocs preserves relocation entries in the binary, required by llvm-bolt for code reordering
RUSTFLAGS="-Cprofile-use=$PGO_DIR/merged.profdata -Clink-arg=-Wl,--emit-relocs $COMBINED_RUSTFLAGS" \
cargo build "${CARGO_ARGS[@]}" --target "$TARGET"
BUILT_BIN="$PWD/target/$TARGET/$PROFILE_DIR/reth"
OPTIMIZED_BIN="$BUILT_BIN-bolt-optimized"
echo "Optimizing with BOLT..."
llvm-bolt "$BUILT_BIN" \
-o "$OPTIMIZED_BIN" \
--data "$BOLT_DIR/merged.fdata" \
-reorder-blocks=ext-tsp \
-reorder-functions=cdsort \
-split-functions \
-split-all-cold \
-dyno-stats \
-icf=1 \
-use-gnu-stack \
--skip-funcs='.*drop_in_place.*'
if [ "$STRIP_SYMBOLS_BOOL" = true ]; then
echo "Stripping debug symbols..."
strip "$OPTIMIZED_BIN"
else
echo "Skipping strip (STRIP_SYMBOLS=$STRIP_SYMBOLS)"
fi
publish_binary "$OPTIMIZED_BIN"
gha_section_end
fi
gha_section_start "Build Complete"
ls -lh "target/$PROFILE_DIR/reth"
echo "Output: target/$PROFILE_DIR/reth"
gha_section_end

View File

@@ -1,10 +1,7 @@
#!/usr/bin/env bash
set -uo pipefail
set -uxo pipefail
crates_to_check=(
reth-codecs-derive
reth-primitives
reth-primitives-traits
reth-network-peers
reth-trie-common
reth-trie-sparse

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env bash
set -uo pipefail
set -uxo pipefail
readarray -t crates < <(
cargo metadata --format-version=1 --no-deps | jq -r '.packages[].name' | grep '^reth' | sort
@@ -22,6 +22,7 @@ exclude_crates=(
reth-downloaders
reth-e2e-test-utils
reth-engine-service
reth-execution-cache
reth-engine-tree
reth-engine-util
reth-eth-wire
@@ -55,6 +56,7 @@ exclude_crates=(
reth-ress-provider
# The following are not supposed to be working
reth # all of the crates below
reth-bb # binary-only, uses tokio features unsupported on wasm
reth-storage-rpc-provider
reth-invalid-block-hooks # reth-provider
reth-libmdbx # mdbx

View File

@@ -7,7 +7,7 @@ FROM lukemathwalker/cargo-chef:latest-rust-1 AS chef
WORKDIR /app
# Install system dependencies
RUN apt-get update && apt-get -y upgrade && apt-get install -y libclang-dev pkg-config
RUN apt-get update && apt-get install -y libclang-dev pkg-config
#
# We prepare the build plan

View File

@@ -11,8 +11,14 @@ go build .
# Run each hive command in the background for each simulator and wait
echo "Building images"
# TODO: test code has been moved from https://github.com/ethereum/execution-spec-tests to https://github.com/ethereum/execution-specs we need to pin eels branch with `--sim.buildarg branch=<release-branch-name>` once we have the fusaka release tagged on the new repo
./hive -client reth --sim "ethereum/eels" --sim.buildarg fixtures=https://github.com/ethereum/execution-spec-tests/releases/download/v5.3.0/fixtures_develop.tar.gz -sim.timelimit 1s || true &
./hive -client reth --sim "ethereum/eels/consume-engine" \
--sim.buildarg fixtures=https://github.com/ethereum/execution-spec-tests/releases/download/v5.3.0/fixtures_develop.tar.gz \
--sim.buildarg branch=forks/osaka \
--sim.timelimit 1s || true &
./hive -client reth --sim "ethereum/eels/consume-rlp" \
--sim.buildarg fixtures=https://github.com/ethereum/execution-spec-tests/releases/download/v5.3.0/fixtures_develop.tar.gz \
--sim.buildarg branch=forks/osaka \
--sim.timelimit 1s || true &
./hive -client reth --sim "ethereum/engine" -sim.timelimit 1s || true &
./hive -client reth --sim "devp2p" -sim.timelimit 1s || true &
./hive -client reth --sim "ethereum/rpc-compat" -sim.timelimit 1s || true &

View File

@@ -1,9 +1,6 @@
# tracked by https://github.com/paradigmxyz/reth/issues/13879
rpc-compat:
- debug_getRawBlock/get-invalid-number (reth)
- debug_getRawHeader/get-invalid-number (reth)
- debug_getRawReceipts/get-invalid-number (reth)
- debug_getRawReceipts/get-block-n (reth)
- debug_getRawTransaction/get-invalid-hash (reth)
- eth_getStorageAt/get-storage-invalid-key-too-large (reth)

View File

@@ -21,7 +21,6 @@ engine-cancun:
# Affects all clients, not just reth. Tracked: https://github.com/ethereum/hive/issues/1382
- Invalid Missing Ancestor Syncing ReOrg, Timestamp, EmptyTxs=False, CanonicalReOrg=False, Invalid P8 (Cancun) (reth)
- Invalid Missing Ancestor Syncing ReOrg, Timestamp, EmptyTxs=False, CanonicalReOrg=True, Invalid P8 (Cancun) (reth)
- Multiple New Payloads Extending Canonical Chain, Wait for Canonical Payload (Cancun) (reth)
engine-api:
- Transaction Re-Org, Re-Org Out (Paris) (reth)
- Transaction Re-Org, Re-Org to Different Block (Paris) (reth)
@@ -31,5 +30,3 @@ engine-api:
- Invalid Missing Ancestor Syncing ReOrg, Transaction Signature, EmptyTxs=False, CanonicalReOrg=True, Invalid P9 (Paris) (reth)
- Invalid Missing Ancestor Syncing ReOrg, Transaction Signature, EmptyTxs=False, CanonicalReOrg=False, Invalid P9 (Paris) (reth)
- Invalid Missing Ancestor ReOrg, StateRoot, EmptyTxs=True, Invalid P10 (Paris) (reth)
- Multiple New Payloads Extending Canonical Chain, Wait for Canonical Payload (Paris) (reth)
- Multiple New Payloads Extending Canonical Chain, Set Head to First Payload Received (Paris) (reth)

View File

@@ -13,7 +13,13 @@ if [[ "${sim}" == *"eels"* ]]; then
fi
run_hive() {
hive --sim "${sim}" --sim.limit "${limit}" --sim.parallelism "${parallelism}" --client reth 2>&1 | tee /tmp/log || true
hive \
--sim "${sim}" \
--sim.limit "${limit}" \
--sim.limit.exact=false \
--sim.parallelism "${parallelism}" \
--client reth \
2>&1 | tee /tmp/log || true
}
check_log() {

View File

@@ -2,7 +2,7 @@
# Installs Geth (https://geth.ethereum.org) in $HOME/bin for x86_64 Linux.
set -eo pipefail
set -exo pipefail
GETH_BUILD=${GETH_BUILD:-"1.13.4-3f907d6a"}

View File

@@ -7,7 +7,7 @@
# Environment:
# DRY_RUN=true - Skip actual verification, just print what would be checked.
set -euo pipefail
set -euxo pipefail
TARGETS="${1:-}"
REGISTRY="${2:-}"

1002
.github/workflows/bench-scheduled.yml vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -12,10 +12,25 @@ on:
workflow_dispatch:
inputs:
blocks:
description: "Number of blocks to benchmark (or 'big' for big blocks mode)"
description: "Number of blocks to benchmark"
required: false
default: "500"
default: "200"
type: string
big_blocks:
description: "Use big blocks mode (pre-generated merged payloads with reth-bb)"
required: false
default: "false"
type: boolean
bal:
description: "Replay block access lists during big-block benchmarks"
required: false
default: "false"
type: choice
options:
- "false"
- "true"
- "feature"
- "baseline"
warmup:
description: "Number of warmup blocks"
required: false
@@ -32,7 +47,7 @@ on:
default: ""
type: string
wait_time:
description: "Fixed wait time between blocks (e.g. 500ms, 1s)"
description: "Minimum interval between block submissions (e.g. 500ms, 1s)"
required: false
default: ""
type: string
@@ -51,11 +66,6 @@ on:
required: false
default: "false"
type: boolean
reth_newPayload:
description: "Use reth_newPayload RPC (server-side timing)"
required: false
default: "true"
type: boolean
cores:
description: "Limit reth to N CPU cores (0 = all available)"
required: false
@@ -71,11 +81,14 @@ on:
required: false
default: "true"
type: boolean
otlp:
description: "Export OTLP traces and logs"
required: false
default: "true"
type: boolean
env:
CARGO_TERM_COLOR: always
BASELINE: base
SEED: reth
RUSTC_WRAPPER: "sccache"
BENCH_RUNNERS: 2
@@ -105,11 +118,12 @@ jobs:
no-slack: ${{ steps.args.outputs.no-slack }}
cores: ${{ steps.args.outputs.cores }}
big-blocks: ${{ steps.args.outputs.big-blocks }}
reth-new-payload: ${{ steps.args.outputs.reth-new-payload }}
bal: ${{ steps.args.outputs.bal }}
wait-time: ${{ steps.args.outputs.wait-time }}
baseline-args: ${{ steps.args.outputs.baseline-args }}
feature-args: ${{ steps.args.outputs.feature-args }}
abba: ${{ steps.args.outputs.abba }}
otlp: ${{ steps.args.outputs.otlp }}
comment-id: ${{ steps.ack.outputs.comment-id }}
steps:
- name: Check org membership
@@ -137,20 +151,25 @@ jobs:
with:
github-token: ${{ secrets.DEREK_PAT }}
script: |
let pr, actor, blocks, warmup, baseline, feature, samply, cores, bigBlocks;
const validBalModes = new Set(['false', 'true', 'feature', 'baseline']);
const usage = '`@decofe bench [blocks=N] [big-blocks[=true|false]] [bal=true|false|feature|baseline] [warmup=N] [baseline=REF] [feature=REF] [samply] [no-slack] [cores=N] [abba=true|false] [otlp=true|false] [wait-time=DURATION] [baseline-args="..."] [feature-args="..."]`';
let pr, actor, blocks, warmup, baseline, feature, samply, cores, bigBlocks, bal;
let explicitWarmup = false;
if (context.eventName === 'workflow_dispatch') {
actor = '${{ github.actor }}';
blocks = '${{ github.event.inputs.blocks }}' || '500';
blocks = '${{ github.event.inputs.blocks }}' || '200';
warmup = '${{ github.event.inputs.warmup }}' || '100';
if (warmup !== '100') explicitWarmup = true;
baseline = '${{ github.event.inputs.baseline }}';
feature = '${{ github.event.inputs.feature }}';
samply = '${{ github.event.inputs.samply }}' === 'true' ? 'true' : 'false';
var noSlack = '${{ github.event.inputs.no_slack }}' !== 'false' ? 'true' : 'false';
cores = '${{ github.event.inputs.cores }}' || '0';
bigBlocks = blocks === 'big' ? 'true' : 'false';
var rethNewPayload = '${{ github.event.inputs.reth_newPayload }}' !== 'false' ? 'true' : 'false';
bigBlocks = '${{ github.event.inputs.big_blocks }}' === 'true' ? 'true' : 'false';
bal = '${{ github.event.inputs.bal }}' || 'false';
var abba = '${{ github.event.inputs.abba }}' !== 'false' ? 'true' : 'false';
var otlp = '${{ github.event.inputs.otlp }}' !== 'false' ? 'true' : 'false';
var waitTime = '${{ github.event.inputs.wait_time }}' || '';
var baselineNodeArgs = '${{ github.event.inputs.baseline_args }}' || '';
var featureNodeArgs = '${{ github.event.inputs.feature_args }}' || '';
@@ -173,14 +192,14 @@ jobs:
actor = context.payload.comment.user.login;
const body = context.payload.comment.body.trim();
const intArgs = new Set(['warmup', 'cores']);
const intOrKeywordArgs = new Map([['blocks', new Set(['big'])]]);
const intArgs = new Set(['warmup', 'cores', 'blocks']);
const refArgs = new Set(['baseline', 'feature']);
const boolArgs = new Set(['samply', 'no-slack']);
const boolDefaultTrue = new Set(['reth_newPayload', 'abba']);
const boolArgs = new Set(['samply', 'no-slack', 'big-blocks']);
const boolDefaultTrue = new Set(['abba', 'otlp']);
const enumArgs = new Map([['bal', validBalModes]]);
const durationArgs = new Set(['wait-time']);
const stringArgs = new Set(['baseline-args', 'feature-args']);
const defaults = { blocks: '500', warmup: '100', baseline: '', feature: '', samply: 'false', 'no-slack': 'false', cores: '0', reth_newPayload: 'true', abba: 'true', 'wait-time': '', 'baseline-args': '', 'feature-args': '' };
const defaults = { blocks: '200', warmup: '100', baseline: '', feature: '', samply: 'false', 'no-slack': 'false', 'big-blocks': 'false', bal: 'false', cores: '0', abba: 'true', otlp: 'true', 'wait-time': '', 'baseline-args': '', 'feature-args': '' };
const unknown = [];
const invalid = [];
const args = body.replace(/^(?:@decofe|derek) bench\s*/, '');
@@ -207,7 +226,7 @@ jobs:
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
value = value.slice(1, -1);
}
if (boolDefaultTrue.has(key)) {
if (boolArgs.has(key) || boolDefaultTrue.has(key)) {
if (value === 'true' || value === 'false') {
defaults[key] = value;
} else {
@@ -219,20 +238,18 @@ jobs:
} else {
invalid.push(`\`${key}=${value}\` (must be a duration like 500ms, 1s, 2m)`);
}
} else if (enumArgs.has(key)) {
if (enumArgs.get(key).has(value)) {
defaults[key] = value;
} else {
invalid.push(`\`${key}=${value}\` (must be true, false, feature, or baseline)`);
}
} else if (intArgs.has(key)) {
if (!/^\d+$/.test(value)) {
invalid.push(`\`${key}=${value}\` (must be a positive integer)`);
} else {
defaults[key] = value;
}
} else if (intOrKeywordArgs.has(key)) {
const keywords = intOrKeywordArgs.get(key);
if (keywords.has(value)) {
defaults[key] = value;
} else if (/^\d+$/.test(value)) {
defaults[key] = value;
} else {
invalid.push(`\`${key}=${value}\` (must be a positive integer or one of: ${[...keywords].join(', ')})`);
if (key === 'warmup') explicitWarmup = true;
}
} else if (refArgs.has(key)) {
if (!value) {
@@ -250,7 +267,7 @@ jobs:
if (unknown.length) errors.push(`Unknown argument(s): \`${unknown.join('`, `')}\``);
if (invalid.length) errors.push(`Invalid value(s): ${invalid.join(', ')}`);
if (errors.length) {
const msg = `❌ **Invalid bench command**\n\n${errors.join('\n')}\n\n**Usage:** \`@decofe bench [blocks=N|big] [warmup=N] [baseline=REF] [feature=REF] [samply] [no-slack] [cores=N] [reth_newPayload=true|false] [abba=true|false] [wait-time=DURATION] [baseline-args="..."] [feature-args="..."]\``;
const msg = `❌ **Invalid bench command**\n\n${errors.join('\n')}\n\n**Usage:** ${usage}`;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
@@ -267,14 +284,38 @@ jobs:
samply = defaults.samply;
var noSlack = defaults['no-slack'];
cores = defaults.cores;
bigBlocks = blocks === 'big' ? 'true' : 'false';
var rethNewPayload = defaults.reth_newPayload;
bigBlocks = defaults['big-blocks'];
bal = defaults.bal;
var abba = defaults.abba;
var otlp = defaults.otlp;
var waitTime = defaults['wait-time'];
var baselineNodeArgs = defaults['baseline-args'];
var featureNodeArgs = defaults['feature-args'];
}
// Default warmup to 20 for big-blocks mode unless explicitly set
if (bigBlocks === 'true' && !explicitWarmup) {
warmup = '20';
}
if (!validBalModes.has(bal)) {
core.setFailed(`Invalid bal mode: ${bal}`);
return;
}
if (bal !== 'false' && bigBlocks !== 'true') {
const msg = `❌ **Invalid bench command**\n\n\`bal\` requires \`big-blocks=true\`.\n\n**Usage:** ${usage}`;
if (context.eventName === 'issue_comment') {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: msg,
});
}
core.setFailed(msg);
return;
}
// Resolve display names for baseline/feature
let baselineName = baseline || 'main';
let featureName = feature;
@@ -303,11 +344,12 @@ jobs:
core.setOutput('no-slack', noSlack);
core.setOutput('cores', cores);
core.setOutput('big-blocks', bigBlocks);
core.setOutput('reth-new-payload', rethNewPayload);
core.setOutput('bal', bal);
core.setOutput('wait-time', waitTime);
core.setOutput('baseline-args', baselineNodeArgs);
core.setOutput('feature-args', featureNodeArgs);
core.setOutput('abba', abba);
core.setOutput('otlp', otlp);
- name: Acknowledge request
id: ack
@@ -367,14 +409,16 @@ jobs:
const samply = '${{ steps.args.outputs.samply }}' === 'true';
const noSlack = '${{ steps.args.outputs.no-slack }}' === 'true';
const bigBlocks = '${{ steps.args.outputs.big-blocks }}' === 'true';
const bal = '${{ steps.args.outputs.bal }}' || 'false';
const samplyNote = samply ? ', samply: `enabled`' : '';
const noSlackNote = noSlack ? ', no-slack' : '';
const balNote = bigBlocks && bal !== 'false' ? `, BAL: \`${bal}\`` : '';
const cores = '${{ steps.args.outputs.cores }}';
const coresNote = cores && cores !== '0' ? `, cores: \`${cores}\`` : '';
const rethNP = '${{ steps.args.outputs.reth-new-payload }}' !== 'false';
const rethNPNote = !rethNP ? ', reth_newPayload: `disabled`' : '';
const abbaEnabled = '${{ steps.args.outputs.abba }}' !== 'false';
const abbaNote = !abbaEnabled ? ', abba: `disabled`' : '';
const otlpEnabled = '${{ steps.args.outputs.otlp }}' !== 'false';
const otlpNote = !otlpEnabled ? ', otlp: `disabled`' : '';
const waitTimeVal = '${{ steps.args.outputs.wait-time }}';
const waitTimeNote = waitTimeVal ? `, wait-time: \`${waitTimeVal}\`` : '';
const baselineArgsVal = '${{ steps.args.outputs.baseline-args }}';
@@ -382,7 +426,7 @@ jobs:
const featureArgsVal = '${{ steps.args.outputs.feature-args }}';
const featureArgsNote = featureArgsVal ? `, feature-args: \`${featureArgsVal}\`` : '';
const blocksDesc = bigBlocks ? 'blocks: `big`' : `${blocks} blocks, ${warmup} warmup blocks`;
const config = `**Config:** ${blocksDesc}, baseline: \`${baseline}\`, feature: \`${feature}\`${samplyNote}${noSlackNote}${coresNote}${rethNPNote}${abbaNote}${waitTimeNote}${baselineArgsNote}${featureArgsNote}`;
const config = `**Config:** ${blocksDesc}, baseline: \`${baseline}\`, feature: \`${feature}\`${samplyNote}${noSlackNote}${balNote}${coresNote}${abbaNote}${otlpNote}${waitTimeNote}${baselineArgsNote}${featureArgsNote}`;
const { data: comment } = await github.rest.issues.createComment({
owner: context.repo.owner,
@@ -409,14 +453,16 @@ jobs:
const samply = '${{ steps.args.outputs.samply }}' === 'true';
const noSlack = '${{ steps.args.outputs.no-slack }}' === 'true';
const bigBlocks = '${{ steps.args.outputs.big-blocks }}' === 'true';
const bal = '${{ steps.args.outputs.bal }}' || 'false';
const samplyNote = samply ? ', samply: `enabled`' : '';
const noSlackNote = noSlack ? ', no-slack' : '';
const balNote = bigBlocks && bal !== 'false' ? `, BAL: \`${bal}\`` : '';
const cores = '${{ steps.args.outputs.cores }}';
const coresNote = cores && cores !== '0' ? `, cores: \`${cores}\`` : '';
const rethNP = '${{ steps.args.outputs.reth-new-payload }}' !== 'false';
const rethNPNote = !rethNP ? ', reth_newPayload: `disabled`' : '';
const abbaEnabled = '${{ steps.args.outputs.abba }}' !== 'false';
const abbaNote = !abbaEnabled ? ', abba: `disabled`' : '';
const otlpEnabled = '${{ steps.args.outputs.otlp }}' !== 'false';
const otlpNote = !otlpEnabled ? ', otlp: `disabled`' : '';
const waitTimeVal = '${{ steps.args.outputs.wait-time }}';
const waitTimeNote = waitTimeVal ? `, wait-time: \`${waitTimeVal}\`` : '';
const baselineArgsVal = '${{ steps.args.outputs.baseline-args }}';
@@ -424,7 +470,7 @@ jobs:
const featureArgsVal = '${{ steps.args.outputs.feature-args }}';
const featureArgsNote = featureArgsVal ? `, feature-args: \`${featureArgsVal}\`` : '';
const blocksDesc = bigBlocks ? 'blocks: `big`' : `${blocks} blocks, ${warmup} warmup blocks`;
const config = `**Config:** ${blocksDesc}, baseline: \`${baseline}\`, feature: \`${feature}\`${samplyNote}${noSlackNote}${coresNote}${rethNPNote}${abbaNote}${waitTimeNote}${baselineArgsNote}${featureArgsNote}`;
const config = `**Config:** ${blocksDesc}, baseline: \`${baseline}\`, feature: \`${feature}\`${samplyNote}${noSlackNote}${balNote}${coresNote}${abbaNote}${otlpNote}${waitTimeNote}${baselineArgsNote}${featureArgsNote}`;
const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
const numRunners = parseInt(process.env.BENCH_RUNNERS) || 1;
@@ -481,6 +527,7 @@ jobs:
env:
BENCH_RPC_URL: https://ethereum.reth.rs/rpc
SCHELK_MOUNT: /reth-bench
RETH_SCOPE: reth-bench.scope
BENCH_WORK_DIR: ${{ github.workspace }}/bench-work
BENCH_PR: ${{ needs.reth-bench-ack.outputs.pr }}
BENCH_ACTOR: ${{ needs.reth-bench-ack.outputs.actor }}
@@ -489,16 +536,18 @@ jobs:
BENCH_SAMPLY: ${{ needs.reth-bench-ack.outputs.samply }}
BENCH_CORES: ${{ needs.reth-bench-ack.outputs.cores }}
BENCH_BIG_BLOCKS: ${{ needs.reth-bench-ack.outputs.big-blocks }}
BENCH_RETH_NEW_PAYLOAD: ${{ needs.reth-bench-ack.outputs.reth-new-payload }}
BENCH_BAL: ${{ needs.reth-bench-ack.outputs.bal }}
BENCH_WAIT_TIME: ${{ needs.reth-bench-ack.outputs.wait-time }}
BENCH_BASELINE_ARGS: ${{ needs.reth-bench-ack.outputs.baseline-args }}
BENCH_FEATURE_ARGS: ${{ needs.reth-bench-ack.outputs.feature-args }}
BENCH_ABBA: ${{ needs.reth-bench-ack.outputs.abba }}
BENCH_OTLP: ${{ needs.reth-bench-ack.outputs.otlp }}
BENCH_COMMENT_ID: ${{ needs.reth-bench-ack.outputs.comment-id }}
BENCH_NO_SLACK: ${{ needs.reth-bench-ack.outputs.no-slack }}
BENCH_NODE_BIN: ${{ needs.reth-bench-ack.outputs.big-blocks == 'true' && 'reth-bb' || 'reth' }}
BENCH_METRICS_ADDR: "127.0.0.1:9100"
BENCH_OTLP_TRACES_ENDPOINT: ${{ secrets.BENCH_OTLP_TRACES_ENDPOINT }}
BENCH_OTLP_LOGS_ENDPOINT: ${{ secrets.BENCH_OTLP_LOGS_ENDPOINT }}
BENCH_OTLP_TRACES_ENDPOINT: ${{ needs.reth-bench-ack.outputs.otlp != 'false' && secrets.BENCH_OTLP_TRACES_ENDPOINT || '' }}
BENCH_OTLP_LOGS_ENDPOINT: ${{ needs.reth-bench-ack.outputs.otlp != 'false' && secrets.BENCH_OTLP_LOGS_ENDPOINT || '' }}
steps:
- name: Clean up previous bench-work
run: sudo rm -rf "$BENCH_WORK_DIR" 2>/dev/null || true
@@ -551,14 +600,16 @@ jobs:
const samply = process.env.BENCH_SAMPLY === 'true';
const noSlack = process.env.BENCH_NO_SLACK === 'true';
const bigBlocks = process.env.BENCH_BIG_BLOCKS === 'true';
const bal = process.env.BENCH_BAL || 'false';
const samplyNote = samply ? ', samply: `enabled`' : '';
const noSlackNote = noSlack ? ', no-slack' : '';
const balNote = bigBlocks && bal !== 'false' ? `, BAL: \`${bal}\`` : '';
const cores = process.env.BENCH_CORES || '0';
const coresNote = cores && cores !== '0' ? `, cores: \`${cores}\`` : '';
const rethNP = (process.env.BENCH_RETH_NEW_PAYLOAD || 'true') !== 'false';
const rethNPNote = !rethNP ? ', reth_newPayload: `disabled`' : '';
const abbaEnabled = (process.env.BENCH_ABBA || 'true') !== 'false';
const abbaNote = !abbaEnabled ? ', abba: `disabled`' : '';
const otlpEnabled = (process.env.BENCH_OTLP || 'true') !== 'false';
const otlpNote = !otlpEnabled ? ', otlp: `disabled`' : '';
const waitTimeVal = process.env.BENCH_WAIT_TIME || '';
const waitTimeNote = waitTimeVal ? `, wait-time: \`${waitTimeVal}\`` : '';
const baselineArgsVal = process.env.BENCH_BASELINE_ARGS || '';
@@ -566,7 +617,7 @@ jobs:
const featureArgsVal = process.env.BENCH_FEATURE_ARGS || '';
const featureArgsNote = featureArgsVal ? `, feature-args: \`${featureArgsVal}\`` : '';
const blocksDesc = bigBlocks ? 'blocks: `big`' : `${blocks} blocks, ${warmup} warmup blocks`;
core.exportVariable('BENCH_CONFIG', `**Config:** ${blocksDesc}, baseline: \`${baseline}\`, feature: \`${feature}\`${samplyNote}${noSlackNote}${coresNote}${rethNPNote}${abbaNote}${waitTimeNote}${baselineArgsNote}${featureArgsNote}`);
core.exportVariable('BENCH_CONFIG', `**Config:** ${blocksDesc}, baseline: \`${baseline}\`, feature: \`${feature}\`${samplyNote}${noSlackNote}${balNote}${coresNote}${abbaNote}${otlpNote}${waitTimeNote}${baselineArgsNote}${featureArgsNote}`);
const { buildBody } = require('./.github/scripts/bench-update-status.js');
await github.rest.issues.updateComment({
@@ -709,14 +760,52 @@ jobs:
core.setOutput('feature-ref', featureRef);
core.setOutput('feature-name', featureName);
- name: Check big-blocks freshness
if: env.BENCH_BIG_BLOCKS == 'true'
id: big-blocks-check
run: |
set -euo pipefail
MC="mc --config-dir /home/ubuntu/.mc"
MANIFEST="minio/reth-snapshots/reth-1-minimal-stable-big-blocks.json"
HASH_FILE="$HOME/.reth-bench-big-blocks-hash"
echo "Fetching big-blocks manifest from $MANIFEST..."
BB_MANIFEST=$($MC cat "$MANIFEST" 2>/dev/null) || {
echo "::error::Failed to fetch big-blocks manifest from $MANIFEST"
exit 1
}
BASE_SNAPSHOT=$(echo "$BB_MANIFEST" | jq -r '.base_snapshot // empty')
if [ -z "$BASE_SNAPSHOT" ]; then
echo "::error::Big-blocks manifest missing base_snapshot field"
exit 1
fi
echo "Big-blocks base snapshot: $BASE_SNAPSHOT"
echo "BENCH_SNAPSHOT_NAME=${BASE_SNAPSHOT}" >> "$GITHUB_ENV"
REMOTE_HASH=$(echo "$BB_MANIFEST" | sha256sum | awk '{print $1}')
LOCAL_HASH=""
[ -f "$HASH_FILE" ] && LOCAL_HASH=$(cat "$HASH_FILE")
if [ "$REMOTE_HASH" = "$LOCAL_HASH" ]; then
echo "Big blocks up-to-date (hash: ${REMOTE_HASH:0:16}…)"
echo "needed=false" >> "$GITHUB_OUTPUT"
else
echo "Big blocks need update (local: ${LOCAL_HASH:+${LOCAL_HASH:0:16}…}${LOCAL_HASH:-<none>}, remote: ${REMOTE_HASH:0:16}…)"
echo "needed=true" >> "$GITHUB_OUTPUT"
echo "remote-hash=${REMOTE_HASH}" >> "$GITHUB_OUTPUT"
fi
- name: Check if snapshot needs update
id: snapshot-check
run: |
if .github/scripts/bench-reth-snapshot.sh --check; then
echo "needed=false" >> "$GITHUB_OUTPUT"
else
echo "needed=true" >> "$GITHUB_OUTPUT"
fi
set +e
.github/scripts/bench-reth-snapshot.sh --check
rc=$?
set -e
case "$rc" in
0) echo "needed=false" >> "$GITHUB_OUTPUT" ;;
10) echo "needed=true" >> "$GITHUB_OUTPUT" ;;
*) echo "::error::Snapshot check failed (exit $rc)"
exit "$rc" ;;
esac
- name: Update status (snapshot needed)
if: env.BENCH_COMMENT_ID && steps.snapshot-check.outputs.needed == 'true'
@@ -725,7 +814,7 @@ jobs:
github-token: ${{ secrets.DEREK_PAT }}
script: |
const s = require('./.github/scripts/bench-update-status.js');
await s({github, context, status: 'Building binaries & downloading snapshot...'});
await s({github, context, status: 'Building binaries (snapshot update pending)...'});
- name: Prepare source dirs
run: |
@@ -745,12 +834,11 @@ jobs:
fi
git -C ../reth-feature checkout "$FEATURE_REF"
- name: Build binaries and download snapshot in parallel
- name: Build binaries
id: build
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BENCH_REPO: ${{ github.repository }}
SNAPSHOT_NEEDED: ${{ steps.snapshot-check.outputs.needed }}
run: |
BASELINE_DIR="$(cd ../reth-baseline && pwd)"
FEATURE_DIR="$(cd ../reth-feature && pwd)"
@@ -760,28 +848,47 @@ jobs:
.github/scripts/bench-reth-build.sh feature "${FEATURE_DIR}" "${{ steps.refs.outputs.feature-ref }}" &
PID_FEATURE=$!
PID_SNAPSHOT=
if [ "$SNAPSHOT_NEEDED" = "true" ]; then
.github/scripts/bench-reth-snapshot.sh &
PID_SNAPSHOT=$!
fi
FAIL=0
wait $PID_BASELINE || FAIL=1
wait $PID_FEATURE || FAIL=1
[ -n "$PID_SNAPSHOT" ] && { wait $PID_SNAPSHOT || FAIL=1; }
if [ $FAIL -ne 0 ]; then
echo "::error::One or more parallel tasks failed (builds / snapshot download)"
echo "::error::One or more build tasks failed"
exit 1
fi
- name: Download snapshot
id: snapshot-download
if: steps.snapshot-check.outputs.needed == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BENCH_REPO: ${{ github.repository }}
BENCH_RETH_BINARY: ${{ github.workspace }}/../reth-feature/target/profiling/${{ needs.reth-bench-ack.outputs.big-blocks == 'true' && 'reth-bb' || 'reth' }}
run: .github/scripts/bench-reth-snapshot.sh
# System tuning for reproducible benchmarks
- name: System setup
run: |
# Switch amd-pstate to passive mode so the kernel governor
# controls frequency directly (EPP is ignored in passive).
echo passive | sudo tee /sys/devices/system/cpu/amd_pstate/status 2>/dev/null || true
sudo cpupower frequency-set -g performance || true
# Disable turbo boost (Intel and AMD paths)
echo 1 | sudo tee /sys/devices/system/cpu/intel_pstate/no_turbo 2>/dev/null || true
echo 0 | sudo tee /sys/devices/system/cpu/cpufreq/boost 2>/dev/null || true
# Pin all cores to the nominal (base) frequency from CPPC.
NOMINAL_KHZ=""
if [ -f /sys/devices/system/cpu/cpu0/acpi_cppc/nominal_freq ]; then
NOMINAL_MHZ=$(cat /sys/devices/system/cpu/cpu0/acpi_cppc/nominal_freq)
NOMINAL_KHZ=$((NOMINAL_MHZ * 1000))
elif [ -f /sys/devices/system/cpu/cpu0/cpufreq/base_frequency ]; then
NOMINAL_KHZ=$(cat /sys/devices/system/cpu/cpu0/cpufreq/base_frequency)
fi
if [ -n "$NOMINAL_KHZ" ] && [ "$NOMINAL_KHZ" -gt 0 ] 2>/dev/null; then
echo "Pinning all cores to nominal frequency: $((NOMINAL_KHZ / 1000)) MHz"
for f in /sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq; do
echo "$NOMINAL_KHZ" | sudo tee "$f" > /dev/null
done
for f in /sys/devices/system/cpu/cpu*/cpufreq/scaling_min_freq; do
echo "$NOMINAL_KHZ" | sudo tee "$f" > /dev/null
done
fi
sudo swapoff -a || true
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space || true
# Disable SMT (hyperthreading)
@@ -811,18 +918,17 @@ jobs:
lscpu | grep -E 'Model name|CPU\(s\)|MHz|NUMA'
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
echo "scaling_min_freq: $(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq)"
echo "scaling_max_freq: $(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq)"
cat /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null || cat /sys/kernel/mm/transparent_hugepages/enabled 2>/dev/null || echo "THP: unknown"
free -h
# Clean up any leftover state
- name: Pre-flight cleanup
run: |
sudo pkill -9 reth || true
sleep 1
if mountpoint -q "$SCHELK_MOUNT"; then
sudo umount -l "$SCHELK_MOUNT" || true
sudo schelk recover -y || true
fi
sudo systemctl stop "$RETH_SCOPE" 2>/dev/null || true
sudo systemctl reset-failed "$RETH_SCOPE" 2>/dev/null || true
sudo schelk recover -y --kill || sudo schelk full-recover -y || true
rm -rf "$BENCH_WORK_DIR"
mkdir -p "$BENCH_WORK_DIR"
@@ -830,20 +936,40 @@ jobs:
if: env.BENCH_BIG_BLOCKS == 'true'
run: |
set -euo pipefail
BIG_BLOCKS_DIR="$HOME/.reth-bench-big-blocks"
echo "BENCH_BIG_BLOCKS_DIR=${BIG_BLOCKS_DIR}" >> "$GITHUB_ENV"
if [ "${{ steps.big-blocks-check.outputs.needed }}" = "false" ]; then
echo "Big blocks cached at $BIG_BLOCKS_DIR, skipping download"
echo "Payload files: $(find "$BIG_BLOCKS_DIR/payloads" -name '*.json' | wc -l)"
exit 0
fi
MC="mc --config-dir /home/ubuntu/.mc"
BUCKET="minio/reth-snapshots/reth-1-minimal-nightly-previous-big-blocks.tar.zst"
BIG_BLOCKS_DIR="${BENCH_WORK_DIR}/big-blocks"
MANIFEST="minio/reth-snapshots/reth-1-minimal-stable-big-blocks.json"
rm -rf "$BIG_BLOCKS_DIR"; mkdir -p "$BIG_BLOCKS_DIR"
echo "Downloading big blocks from $BUCKET..."
$MC cat "$BUCKET" | pzstd -d -p 6 | tar -xf - -C "$BIG_BLOCKS_DIR"
# Download and parse manifest
echo "Downloading manifest from $MANIFEST..."
$MC cat "$MANIFEST" > "$BIG_BLOCKS_DIR/manifest.json"
UPLOAD_PATH=$(jq -r '.upload_path' "$BIG_BLOCKS_DIR/manifest.json")
COUNT=$(jq -r '.count' "$BIG_BLOCKS_DIR/manifest.json")
TARGET_GAS=$(jq -r '.target_gas' "$BIG_BLOCKS_DIR/manifest.json")
echo "Manifest: count=$COUNT, target_gas=$TARGET_GAS, archive=$UPLOAD_PATH"
# Download and extract archive
ARCHIVE="minio/$UPLOAD_PATH"
echo "Downloading big blocks from $ARCHIVE..."
$MC cat "$ARCHIVE" | pzstd -d -p 6 | tar -xf - -C "$BIG_BLOCKS_DIR"
echo "Big blocks downloaded to $BIG_BLOCKS_DIR"
# Verify expected directory structure
if [ ! -d "$BIG_BLOCKS_DIR/gas-ramp-dir" ] || [ ! -d "$BIG_BLOCKS_DIR/payloads" ]; then
echo "::error::Big blocks archive missing expected gas-ramp-dir/ or payloads/ directories"
if [ ! -d "$BIG_BLOCKS_DIR/payloads" ]; then
echo "::error::Big blocks archive missing expected payloads/ directory"
ls -laR "$BIG_BLOCKS_DIR"
exit 1
fi
echo "Payload files: $(find "$BIG_BLOCKS_DIR/payloads" -name '*.json' | wc -l)"
# Save manifest hash for freshness check on next run
echo "${{ steps.big-blocks-check.outputs.remote-hash }}" > "$HOME/.reth-bench-big-blocks-hash"
- name: Start metrics proxy
run: |
@@ -882,10 +1008,12 @@ jobs:
BASELINE_REF: ${{ steps.refs.outputs.baseline-ref }}
OTEL_RESOURCE_ATTRIBUTES: "benchmark_id=${{ env.BENCH_ID }},benchmark_run=baseline-1,run_type=baseline,git_ref=${{ steps.refs.outputs.baseline-ref }}"
run: |
LAST_RUN_START=$(date +%s)
echo "BENCH_LAST_RUN_START=${LAST_RUN_START}" >> "$GITHUB_ENV"
cat > "$BENCH_LABELS_FILE" <<LABELS
{"benchmark_run":"baseline-1","run_type":"baseline","git_ref":"${BASELINE_REF}","bench_sha":"${BASELINE_REF}","benchmark_id":"${BENCH_ID}","run_start_epoch":"$(date +%s)","reference_epoch":"${BENCH_REFERENCE_EPOCH}"}
{"benchmark_run":"baseline-1","run_type":"baseline","git_ref":"${BASELINE_REF}","bench_sha":"${BASELINE_REF}","benchmark_id":"${BENCH_ID}","run_start_epoch":"${LAST_RUN_START}","reference_epoch":"${BENCH_REFERENCE_EPOCH}"}
LABELS
taskset -c 0 .github/scripts/bench-reth-run.sh baseline ../reth-baseline/target/profiling/reth "$BENCH_WORK_DIR/baseline-1"
taskset -c 0 .github/scripts/bench-reth-run.sh baseline "../reth-baseline/target/profiling/${BENCH_NODE_BIN}" "$BENCH_WORK_DIR/baseline-1"
- name: "Run benchmark: feature (1/2)"
id: run-feature-1
@@ -893,10 +1021,12 @@ jobs:
FEATURE_REF: ${{ steps.refs.outputs.feature-ref }}
OTEL_RESOURCE_ATTRIBUTES: "benchmark_id=${{ env.BENCH_ID }},benchmark_run=feature-1,run_type=feature,git_ref=${{ steps.refs.outputs.feature-ref }}"
run: |
LAST_RUN_START=$(date +%s)
echo "BENCH_LAST_RUN_START=${LAST_RUN_START}" >> "$GITHUB_ENV"
cat > "$BENCH_LABELS_FILE" <<LABELS
{"benchmark_run":"feature-1","run_type":"feature","git_ref":"${FEATURE_REF}","bench_sha":"${FEATURE_REF}","benchmark_id":"${BENCH_ID}","run_start_epoch":"$(date +%s)","reference_epoch":"${BENCH_REFERENCE_EPOCH}"}
{"benchmark_run":"feature-1","run_type":"feature","git_ref":"${FEATURE_REF}","bench_sha":"${FEATURE_REF}","benchmark_id":"${BENCH_ID}","run_start_epoch":"${LAST_RUN_START}","reference_epoch":"${BENCH_REFERENCE_EPOCH}"}
LABELS
taskset -c 0 .github/scripts/bench-reth-run.sh feature ../reth-feature/target/profiling/reth "$BENCH_WORK_DIR/feature-1"
taskset -c 0 .github/scripts/bench-reth-run.sh feature "../reth-feature/target/profiling/${BENCH_NODE_BIN}" "$BENCH_WORK_DIR/feature-1"
- name: "Run benchmark: feature (2/2)"
if: env.BENCH_ABBA != 'false'
@@ -905,10 +1035,12 @@ jobs:
FEATURE_REF: ${{ steps.refs.outputs.feature-ref }}
OTEL_RESOURCE_ATTRIBUTES: "benchmark_id=${{ env.BENCH_ID }},benchmark_run=feature-2,run_type=feature,git_ref=${{ steps.refs.outputs.feature-ref }}"
run: |
LAST_RUN_START=$(date +%s)
echo "BENCH_LAST_RUN_START=${LAST_RUN_START}" >> "$GITHUB_ENV"
cat > "$BENCH_LABELS_FILE" <<LABELS
{"benchmark_run":"feature-2","run_type":"feature","git_ref":"${FEATURE_REF}","bench_sha":"${FEATURE_REF}","benchmark_id":"${BENCH_ID}","run_start_epoch":"$(date +%s)","reference_epoch":"${BENCH_REFERENCE_EPOCH}"}
{"benchmark_run":"feature-2","run_type":"feature","git_ref":"${FEATURE_REF}","bench_sha":"${FEATURE_REF}","benchmark_id":"${BENCH_ID}","run_start_epoch":"${LAST_RUN_START}","reference_epoch":"${BENCH_REFERENCE_EPOCH}"}
LABELS
taskset -c 0 .github/scripts/bench-reth-run.sh feature ../reth-feature/target/profiling/reth "$BENCH_WORK_DIR/feature-2"
taskset -c 0 .github/scripts/bench-reth-run.sh feature "../reth-feature/target/profiling/${BENCH_NODE_BIN}" "$BENCH_WORK_DIR/feature-2"
- name: "Run benchmark: baseline (2/2)"
if: env.BENCH_ABBA != 'false'
@@ -922,7 +1054,7 @@ jobs:
cat > "$BENCH_LABELS_FILE" <<LABELS
{"benchmark_run":"baseline-2","run_type":"baseline","git_ref":"${BASELINE_REF}","bench_sha":"${BASELINE_REF}","benchmark_id":"${BENCH_ID}","run_start_epoch":"${LAST_RUN_START}","reference_epoch":"${BENCH_REFERENCE_EPOCH}"}
LABELS
taskset -c 0 .github/scripts/bench-reth-run.sh baseline ../reth-baseline/target/profiling/reth "$BENCH_WORK_DIR/baseline-2"
taskset -c 0 .github/scripts/bench-reth-run.sh baseline "../reth-baseline/target/profiling/${BENCH_NODE_BIN}" "$BENCH_WORK_DIR/baseline-2"
- name: Stop metrics proxy & generate Grafana URL
id: metrics
@@ -1051,11 +1183,15 @@ jobs:
fi
if [ "${BENCH_BIG_BLOCKS:-false}" = "true" ]; then
SUMMARY_ARGS="$SUMMARY_ARGS --big-blocks"
# Read gas ramp blocks count from first baseline run (same for all runs)
GAS_RAMP_FILE="$BENCH_WORK_DIR/baseline-1/gas_ramp_blocks.txt"
if [ -f "$GAS_RAMP_FILE" ]; then
SUMMARY_ARGS="$SUMMARY_ARGS --gas-ramp-blocks $(cat "$GAS_RAMP_FILE" | tr -d '[:space:]')"
fi
fi
if [ -n "${BENCH_WARMUP_BLOCKS:-}" ]; then
SUMMARY_ARGS="$SUMMARY_ARGS --warmup-blocks $BENCH_WARMUP_BLOCKS"
fi
if [ -n "${BENCH_WAIT_TIME:-}" ]; then
SUMMARY_ARGS="$SUMMARY_ARGS --wait-time $BENCH_WAIT_TIME"
fi
if [ -n "${BENCH_BAL:-}" ] && [ "${BENCH_BAL}" != "false" ]; then
SUMMARY_ARGS="$SUMMARY_ARGS --bal-mode $BENCH_BAL"
fi
GRAFANA_URL='${{ steps.metrics.outputs.grafana-url }}'
if [ -n "$GRAFANA_URL" ]; then
@@ -1195,11 +1331,22 @@ jobs:
comment_id: parseInt(ackCommentId),
body,
});
} else {
// No PR — write results to job summary
await core.summary.addRaw(body).write();
}
- name: Write job summary
if: success()
uses: actions/github-script@v8
with:
script: |
const jobSummary = require('./.github/scripts/bench-job-summary.js');
await jobSummary({
core,
context,
chartSha: '${{ steps.push-charts.outputs.sha }}',
grafanaUrl: '${{ steps.metrics.outputs.grafana-url }}',
runId: '${{ github.run_id }}',
});
- name: Send Slack notification (success)
if: success() && env.BENCH_NO_SLACK != 'true'
uses: actions/github-script@v8
@@ -1219,7 +1366,8 @@ jobs:
script: |
const abba = (process.env.BENCH_ABBA || 'true') !== 'false';
const steps_status = [
['building binaries${{ steps.snapshot-check.outputs.needed == 'true' && ' & downloading snapshot' || '' }}', '${{ steps.build.outcome }}'],
['building binaries', '${{ steps.build.outcome }}'],
['downloading snapshot', '${{ steps.snapshot-download.outcome }}'],
['running baseline benchmark (1/2)', '${{ steps.run-baseline-1.outcome }}'],
['running feature benchmark (1/2)', '${{ steps.run-feature-1.outcome }}'],
...(abba ? [['running feature benchmark (2/2)', '${{ steps.run-feature-2.outcome }}']] : []),
@@ -1254,7 +1402,8 @@ jobs:
script: |
const abba = (process.env.BENCH_ABBA || 'true') !== 'false';
const steps_status = [
['building binaries${{ steps.snapshot-check.outputs.needed == 'true' && ' & downloading snapshot' || '' }}', '${{ steps.build.outcome }}'],
['building binaries', '${{ steps.build.outcome }}'],
['downloading snapshot', '${{ steps.snapshot-download.outcome }}'],
['running baseline benchmark (1/2)', '${{ steps.run-baseline-1.outcome }}'],
['running feature benchmark (1/2)', '${{ steps.run-feature-1.outcome }}'],
...(abba ? [['running feature benchmark (2/2)', '${{ steps.run-feature-2.outcome }}']] : []),
@@ -1281,4 +1430,14 @@ jobs:
- name: Restore system settings
if: always()
run: |
# Restore frequency scaling to full range
for f in /sys/devices/system/cpu/cpu*/cpufreq/scaling_min_freq; do
cat "$(dirname "$f")/cpuinfo_min_freq" | sudo tee "$f" > /dev/null 2>&1 || true
done
for f in /sys/devices/system/cpu/cpu*/cpufreq/scaling_max_freq; do
cat "$(dirname "$f")/cpuinfo_max_freq" | sudo tee "$f" > /dev/null 2>&1 || true
done
# Restore amd-pstate to active (EPP) mode with powersave governor
echo active | sudo tee /sys/devices/system/cpu/amd_pstate/status 2>/dev/null || true
sudo cpupower frequency-set -g powersave 2>/dev/null || true
sudo systemctl start irqbalance cron atd 2>/dev/null || true

View File

@@ -47,7 +47,7 @@ jobs:
echo "Vocs Build Complete"
- name: Setup Pages
uses: actions/configure-pages@v5
uses: actions/configure-pages@v6
- name: Upload artifact
uses: actions/upload-pages-artifact@v4
@@ -74,4 +74,4 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
uses: actions/deploy-pages@v5

Some files were not shown because too many files have changed in this diff Show More