From b7d5901bff366b5e4709f6d622dfb3f31e983ab5 Mon Sep 17 00:00:00 2001 From: evalir Date: Thu, 5 Feb 2026 15:10:05 +0100 Subject: [PATCH 1/9] feat(submit): pylon blob preloading integration --- Cargo.lock | 153 +++++++++++++++++----------------- Cargo.toml | 6 +- bin/builder.rs | 21 ++++- src/config.rs | 14 +++- src/tasks/submit/flashbots.rs | 97 ++++++++++----------- src/tasks/submit/mod.rs | 4 + src/tasks/submit/prep.rs | 41 ++++----- src/tasks/submit/pylon.rs | 66 +++++++++++++++ src/test_utils.rs | 1 + 9 files changed, 245 insertions(+), 158 deletions(-) create mode 100644 src/tasks/submit/pylon.rs diff --git a/Cargo.lock b/Cargo.lock index 789ae78f..df1f9ac0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -97,9 +97,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f07ea118327e6ff9a1cba5ae26c0a9a9744bec1dd6734ed75b5b46fc9be6d077" +checksum = "c62f44203459c0fdeae67338c2b264c761c614d460feca0b0a230058435e3c1d" dependencies = [ "alloy-consensus", "alloy-contract", @@ -139,9 +139,9 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86debde32d8dbb0ab29e7cc75ae1a98688ac7a4c9da54b3a9b14593b9b3c46d3" +checksum = "c622b1418d86afba7116e2617280859d4a2737e06e6e4dd4694a7a96ae8aff79" dependencies = [ "alloy-eips", "alloy-primitives", @@ -167,9 +167,9 @@ dependencies = [ [[package]] name = "alloy-consensus-any" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d6cb2e7efd385b333f5a77b71baaa2605f7e22f1d583f2879543b54cbce777c" +checksum = "90eeb45e8554a35ade97344552df4f6cdb000a53da955916f573b1998a81f791" dependencies = [ "alloy-consensus", "alloy-eips", @@ -182,9 +182,9 @@ dependencies = [ [[package]] name = "alloy-contract" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668859fcdb42eee289de22a9d01758c910955bb6ecda675b97276f99ce2e16b0" +checksum = "363d9d618d98952b07e50defdf3f8bc59ae24b7ba6161397a2e380370fd3ebf3" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -296,9 +296,9 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be47bf1b91674a5f394b9ed3c691d764fb58ba43937f1371550ff4bc8e59c295" +checksum = "2cbd6558e8a2fe9de811faae7ccc0b3d2a4c71b1cd77e57e5c89cba20693420b" dependencies = [ "alloy-eip2124", "alloy-eip2930", @@ -344,9 +344,9 @@ dependencies = [ [[package]] name = "alloy-genesis" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a59f6f520c323111650d319451de1edb1e32760029a468105b9d7b0f7c11bdf2" +checksum = "91dd00b84d8c9b9fd055254a147e4521cca0a8f19da808fd3376e4bd6f292d43" dependencies = [ "alloy-eips", "alloy-primitives", @@ -398,9 +398,9 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a24c81a56d684f525cd1c012619815ad3a1dd13b0238f069356795d84647d3c" +checksum = "95ae5cbb425b6e72f99e24860506809e4908113b76ede8de1333996edccbf38c" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -413,9 +413,9 @@ dependencies = [ [[package]] name = "alloy-network" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786c5b3ad530eaf43cda450f973fe7fb1c127b4c8990adf66709dafca25e3f6f" +checksum = "5abea24fba6bfb859954d1ebfaaebf77886b802ec559cbe7fd16f992a31d41ec" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -439,9 +439,9 @@ dependencies = [ [[package]] name = "alloy-network-primitives" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ed40adf21ae4be786ef5eb62db9c692f6a30f86d34452ca3f849d6390ce319" +checksum = "905f7628888eed587274dbea536168f64f6a401b377cd77b9fe91866ce1478a0" dependencies = [ "alloy-consensus", "alloy-eips", @@ -452,9 +452,9 @@ dependencies = [ [[package]] name = "alloy-node-bindings" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f15cffc63c421d33d77f6d30d7d18ef090a44ecf32205f5bfa12d4e565360a" +checksum = "d60ff34bfb17d2401381b8f177257bcda467d77eb26c7f4084695923d41b5821" dependencies = [ "alloy-genesis", "alloy-hardforks 0.2.13", @@ -505,9 +505,9 @@ dependencies = [ [[package]] name = "alloy-provider" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3ca4c15818be7ac86208aff3a91b951d14c24e1426e66624e75f2215ba5e2cc" +checksum = "991d0ccc0ed7a1d083e96f251627ad6d551769cff7ad2d07b0d0b335e99cba63" dependencies = [ "alloy-chains", "alloy-consensus", @@ -554,9 +554,9 @@ dependencies = [ [[package]] name = "alloy-pubsub" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9eb9c9371738ac47f589e40aae6e418cb5f7436ad25b87575a7f94a60ccf43b" +checksum = "295dba19c629c431554f4e2918b43bf02bce7464990631e67304e2a3362d9c3f" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -598,9 +598,9 @@ dependencies = [ [[package]] name = "alloy-rpc-client" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe0addad5b8197e851062b49dc47157444bced173b601d91e3f9b561a060a50" +checksum = "edc1343d06dd354cee121763e7fb243db3b7962d747df0c231ce13c249f48efd" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -624,9 +624,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d17d4645a717f0527e491f44f6f7a75c221b9c00ccf79ddba2d26c8e0df4c3" +checksum = "03c4079f59cc4753389e2eb0e20cd2a98ddfc58f8bcec33b98d86e8d8c701f82" dependencies = [ "alloy-primitives", "alloy-rpc-types-anvil", @@ -643,9 +643,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-admin" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded79e60d8fd0d7c851044f8b2f2dd7fa8dfa467c577d620595d4de3c31eff7e" +checksum = "ebf8f659abddbafb74dab174204aa4e9e2785425bd3899eb948d1d9fae2c9bfd" dependencies = [ "alloy-genesis", "alloy-primitives", @@ -655,9 +655,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-anvil" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2593ce5e1fd416e3b094e7671ef361f22e6944545e0e62ee309b6dfbd702225d" +checksum = "a816be17cfbcb36a08a8b88bc2157ee1aa2ea258fb2c48a5ba6a3e3729a7f031" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -667,9 +667,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-any" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0e98aabb013a71a4b67b52825f7b503e5bb6057fb3b7b2290d514b0b0574b57" +checksum = "8405d1a23dbd570679196289c9c6ea23e8f3d69f24a9a942002a45bb4b2a844c" dependencies = [ "alloy-consensus-any", "alloy-rpc-types-eth", @@ -678,9 +678,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-beacon" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a647a4e3acf49182135c2333d6f9b11ab8684559ff43ef1958ed762cfe9fe0e" +checksum = "645d3eafd5b909d23e6248ecaadbaf66f464db5097a5794615784c1370df12bf" dependencies = [ "alloy-eips", "alloy-primitives", @@ -698,9 +698,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-debug" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a1dd760b6a798ee045ab6a7bbd1a02ad8bd6a64d8e18d6e41732f4fc4a4fe5c" +checksum = "4ca2e88ed4e5e88955d5988eb32b9c5483912a3af7936436b0e5f5f3da512880" dependencies = [ "alloy-primitives", "derive_more", @@ -710,9 +710,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-engine" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc871ae69688e358cf242a6a7ee6b6e0476a03fd0256434c68daedaec086ec4" +checksum = "fc7bf1ae6bf74b82e033888db62466cde2cd279ca9ff601b601f5b315314fb4e" dependencies = [ "alloy-consensus", "alloy-eips", @@ -731,9 +731,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5899af8417dcf89f40f88fa3bdb2f3f172605d8e167234311ee34811bbfdb0bf" +checksum = "9be559930a667c9343b1f21179be4f1a5a345c8caf7ef506eb216ad507de4ffb" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -753,9 +753,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-mev" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4c9229424e77bd97e629fba44dbfdadebe5bfadbb1e53ad4acbc955610b6c7" +checksum = "da494d19924be84bbeeacd1c77ce117b67f8db46fd784a046db2cc26f3ffa407" dependencies = [ "alloy-consensus", "alloy-eips", @@ -768,9 +768,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-trace" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "410a80e9ac786a2d885adfd7da3568e8f392da106cb5432f00eb4787689d281a" +checksum = "2fc955f47f331437ee9072a486088bdd2ee8230eea4df059566108fc900896ca" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -782,9 +782,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-txpool" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a8074654c0292783d504bfa1f2691a69f420154ee9a7883f9212eaf611e60cd" +checksum = "3820522d80137bac38db35ad7af40c275fdce107c7ba25fd94659b53e3d46768" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -794,9 +794,9 @@ dependencies = [ [[package]] name = "alloy-serde" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feb73325ee881e42972a5a7bc85250f6af89f92c6ad1222285f74384a203abeb" +checksum = "617076af047ac9ffec0e8a3ef48fccbf6eb9d5aee6b302476346f729e469c804" dependencies = [ "alloy-primitives", "arbitrary", @@ -806,9 +806,9 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bea4c8f30eddb11d7ab56e83e49c814655daa78ca708df26c300c10d0189cbc" +checksum = "3540dd7ff91763cd60760438442a10392f8f04f41fb3c4981323f3c34d96ccb2" dependencies = [ "alloy-primitives", "async-trait", @@ -821,9 +821,9 @@ dependencies = [ [[package]] name = "alloy-signer-aws" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51f6ae79701edb2c21b5f9ff007ae0228168b36e5ca25a20873b2db2cda4ad31" +checksum = "6c9cdc832ab4353af07656e4dfc2c2bc59264a424f90f4a6cee6bd1caa0a8af4" dependencies = [ "alloy-consensus", "alloy-network", @@ -840,9 +840,9 @@ dependencies = [ [[package]] name = "alloy-signer-local" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28bd71507db58477151a6fe6988fa62a4b778df0f166c3e3e1ef11d059fe5fa" +checksum = "a382f4fc60d1155fa684fe68870e18a265043b0f3a11c7a2b5072447cb5fbafc" dependencies = [ "alloy-consensus", "alloy-network", @@ -932,9 +932,9 @@ dependencies = [ [[package]] name = "alloy-transport" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b321f506bd67a434aae8e8a7dfe5373bf66137c149a5f09c9e7dfb0ca43d7c91" +checksum = "6ac0e7b6ebe03a97143d0bae318212b876306d669cc9b25071184d2e85877b4a" dependencies = [ "alloy-json-rpc", "auto_impl", @@ -955,12 +955,13 @@ dependencies = [ [[package]] name = "alloy-transport-http" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bf12879a20e1261cd39c3b101856f52d18886907a826e102538897f0d2b66e" +checksum = "a19f6f46ab490750059b0d32ce74323ebe7bb6d8137073523dfef754c3af2252" dependencies = [ "alloy-json-rpc", "alloy-transport", + "itertools 0.14.0", "reqwest", "serde_json", "tower", @@ -970,9 +971,9 @@ dependencies = [ [[package]] name = "alloy-transport-ipc" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75f2334d400249e9672a1ec402536bab259e27a66201a94c3c9b3f1d3bae241" +checksum = "8e0b477248bf29d1a990a10bc8ab494a7f39c3d1720bb1d6c8eae4649a28df56" dependencies = [ "alloy-json-rpc", "alloy-pubsub", @@ -990,9 +991,9 @@ dependencies = [ [[package]] name = "alloy-transport-ws" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527a0d9c8bbc5c3215b03ad465d4ae8775384ff5faec7c41f033f087c851a9f9" +checksum = "4feacef4309079e77763aaa6581090c748500a56faae3edb5928464ec3c0f769" dependencies = [ "alloy-pubsub", "alloy-transport", @@ -1028,9 +1029,9 @@ dependencies = [ [[package]] name = "alloy-tx-macros" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a91d6b4c2f6574fdbcb1611e460455c326667cf5b805c6bd1640dad8e8ee4d2" +checksum = "5f5bfa1887d55418bd22c922c5ae679f2c0dbda5cba03d1300bd7299e9602350" dependencies = [ "darling 0.21.3", "proc-macro2", @@ -4950,8 +4951,6 @@ dependencies = [ [[package]] name = "init4-bin-base" version = "0.18.0-rc.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "185fbd1b6320603134ec222356f6014806e589a1ef73532882609fa23766b5cd" dependencies = [ "alloy", "async-trait", @@ -4986,8 +4985,6 @@ dependencies = [ [[package]] name = "init4-from-env-derive" version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9c78527fcfeaecc9805e5736a7592a26ecad3b7845eb273c8c1710de0dbb0c" dependencies = [ "proc-macro2", "quote", @@ -7185,9 +7182,9 @@ dependencies = [ [[package]] name = "rapidhash" -version = "4.2.2" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71ec30b38a417407efe7676bad0ca6b78f995f810185ece9af3bd5dc561185a9" +checksum = "84816e4c99c467e92cf984ee6328caa976dfecd33a673544489d79ca2caaefe5" dependencies = [ "rand 0.9.2", "rustversion", @@ -10543,9 +10540,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "ryu-js" @@ -12289,9 +12286,9 @@ checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" [[package]] name = "unicode-segmentation" @@ -13376,9 +13373,9 @@ dependencies = [ [[package]] name = "zmij" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff05f8caa9038894637571ae6b9e29466c1f4f829d26c9b28f869a29cbe3445" +checksum = "4de98dfa5d5b7fef4ee834d0073d560c9ca7b6c46a71d058c48db7960f8cfaf7" [[package]] name = "zstd" diff --git a/Cargo.toml b/Cargo.toml index 43c70347..02120ee2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ name = "zenith-builder-example" path = "bin/builder.rs" [dependencies] -init4-bin-base = { version = "0.18.0-rc.8", features = ["perms", "aws"] } +init4-bin-base = { version = "0.18.0-rc.8", features = ["perms", "aws", "pylon"] } signet-constants = { version = "0.16.0-rc.8" } signet-sim = { version = "0.16.0-rc.8" } @@ -63,7 +63,7 @@ alloy-hardforks = "0.4.0" alloy-chains = "0.2" # comment / uncomment for local dev -# [patch.crates-io] +[patch.crates-io] # signet-constants = { path = "../signet-sdk/crates/constants" } # signet-types = { path = "../signet-sdk/crates/types" } # signet-zenith = { path = "../signet-sdk/crates/zenith" } @@ -73,4 +73,4 @@ alloy-chains = "0.2" # signet-journal = { path = "../signet-sdk/crates/journal" } # signet-tx-cache = { path = "../signet-sdk/crates/tx-cache" } # signet-bundle = { path = "../signet-sdk/crates/bundle" } -# init4-bin-base = { path = "../bin-base" } +init4-bin-base = { path = "../bin-base" } diff --git a/bin/builder.rs b/bin/builder.rs index adf26997..1f268ba3 100644 --- a/bin/builder.rs +++ b/bin/builder.rs @@ -1,8 +1,11 @@ use builder::{ service::serve_builder, tasks::{ - block::sim::SimulatorTask, cache::CacheTasks, env::EnvTask, metrics::MetricsTask, - submit::FlashbotsTask, + block::sim::SimulatorTask, + cache::CacheTasks, + env::EnvTask, + metrics::MetricsTask, + submit::{FlashbotsTask, PylonTask}, }, }; use init4_bin_base::deps::tracing::{info, info_span}; @@ -32,10 +35,17 @@ async fn main() -> eyre::Result<()> { let (block_env, env_jh) = env_task.spawn(); let (tx_channel, metrics_jh) = metrics_task.spawn(); + // Set up the pylon task + let pylon_client = builder::config().connect_pylon(); + let pylon_task = PylonTask::new(pylon_client); + let (pylon_sender, pylon_jh) = pylon_task.spawn(); + // Set up the cache, submit, and simulator tasks let cache_tasks = CacheTasks::new(block_env.clone()); - let (submit_task, simulator_task) = - tokio::try_join!(FlashbotsTask::new(tx_channel.clone()), SimulatorTask::new(block_env),)?; + let (submit_task, simulator_task) = tokio::try_join!( + FlashbotsTask::new(tx_channel.clone(), pylon_sender), + SimulatorTask::new(block_env), + )?; // Spawn the cache, submit, and simulator tasks let cache_system = cache_tasks.spawn(); @@ -65,6 +75,9 @@ async fn main() -> eyre::Result<()> { _ = submit_jh => { info!("submit finished"); }, + _ = pylon_jh => { + info!("pylon task finished"); + }, _ = metrics_jh => { info!("metrics finished"); }, diff --git a/src/config.rs b/src/config.rs index 1296ccc0..79c125a5 100644 --- a/src/config.rs +++ b/src/config.rs @@ -12,7 +12,7 @@ use alloy::{ }; use eyre::Result; use init4_bin_base::{ - perms::{Authenticator, OAuthConfig, SharedToken}, + perms::{Authenticator, OAuthConfig, SharedToken, pylon}, utils::{ calc::SlotCalculator, from_env::FromEnv, @@ -25,6 +25,9 @@ use signet_zenith::Zenith; use std::borrow::Cow; use tokio::join; +/// Pylon client type for blob sidecar submission. +pub type PylonClient = pylon::PylonClient; + /// Type alias for the provider used to simulate against rollup state. pub type RuProvider = RootProvider; @@ -168,6 +171,10 @@ pub struct BuilderConfig { /// The signet system constants. pub constants: SignetSystemConstants, + + /// URL for the Pylon blob server API. + #[from_env(var = "PYLON_URL", desc = "URL for the Pylon blob server API")] + pub pylon_url: url::Url, } impl BuilderConfig { @@ -285,4 +292,9 @@ impl BuilderConfig { ((gas_limit as u128 * (self.max_host_gas_coefficient.unwrap_or(80) as u128)) / 100u128) as u64 } + + /// Connect to the Pylon blob server. + pub fn connect_pylon(&self) -> PylonClient { + PylonClient::new(self.pylon_url.clone(), self.oauth_token()) + } } diff --git a/src/tasks/submit/flashbots.rs b/src/tasks/submit/flashbots.rs index 6b3d998c..12bdfc79 100644 --- a/src/tasks/submit/flashbots.rs +++ b/src/tasks/submit/flashbots.rs @@ -7,7 +7,7 @@ use crate::{ }; use alloy::{ consensus::TxEnvelope, - eips::Encodable2718, + eips::{Encodable2718, eip7594::BlobTransactionSidecarEip7594}, primitives::{Bytes, TxHash}, providers::ext::MevApi, rpc::types::mev::EthSendBundle, @@ -32,12 +32,17 @@ pub struct FlashbotsTask { signer: LocalOrAws, /// Channel for sending hashes of outbound transactions. outbound: mpsc::UnboundedSender, + /// Channel for sending sidecars to the Pylon task. + pylon_sender: mpsc::UnboundedSender<(TxHash, BlobTransactionSidecarEip7594)>, } impl FlashbotsTask { /// Returns a new `FlashbotsTask` instance that receives `SimResult` types from the given /// channel and handles their preparation, submission to the Flashbots network. - pub async fn new(outbound: mpsc::UnboundedSender) -> eyre::Result { + pub async fn new( + outbound: mpsc::UnboundedSender, + pylon_sender: mpsc::UnboundedSender<(TxHash, BlobTransactionSidecarEip7594)>, + ) -> eyre::Result { let config = crate::config(); let (quincey, host_provider, flashbots, builder_key) = tokio::try_join!( @@ -49,54 +54,28 @@ impl FlashbotsTask { let zenith = config.connect_zenith(host_provider); - Ok(Self { config, quincey, zenith, flashbots, signer: builder_key, outbound }) + Ok(Self { config, quincey, zenith, flashbots, signer: builder_key, outbound, pylon_sender }) } - /// Prepares a MEV bundle from a simulation result. - /// - /// This function serves as an entry point for bundle preparation and is left - /// for forward compatibility when adding different bundle preparation methods. - pub async fn prepare(&self, sim_result: &SimResult) -> eyre::Result { - // This function is left for forwards compatibility when we want to add - // different bundle preparation methods in the future. - self.prepare_bundle(sim_result).await - } - - /// Prepares a MEV bundle containing the host transactions and the rollup block. - /// - /// This method orchestrates the bundle preparation by: - /// 1. Preparing and signing the submission transaction - /// 2. Tracking the transaction hash for monitoring - /// 3. Encoding the transaction for bundle inclusion - /// 4. Constructing the complete bundle body - #[instrument(skip_all, level = "debug")] - async fn prepare_bundle(&self, sim_result: &SimResult) -> eyre::Result { - // Prepare and sign the transaction - let block_tx = self.prepare_signed_transaction(sim_result).await?; - - // Track the outbound transaction - self.track_outbound_tx(&block_tx); - - // Encode the transaction - let tx_bytes = block_tx.encoded_2718().into(); - - // Build the bundle body with the block_tx bytes as the last transaction in the bundle. + /// Builds a MEV bundle from a signed transaction envelope and simulation result. + fn build_bundle(&self, envelope: &TxEnvelope, sim_result: &SimResult) -> EthSendBundle { + let tx_bytes: Bytes = envelope.encoded_2718().into(); let txs = self.build_bundle_body(sim_result, tx_bytes); - // Create the MEV bundle (valid only in the specific host block) - Ok(EthSendBundle { - txs, - block_number: sim_result.host_block_number(), - ..Default::default() - }) + EthSendBundle { txs, block_number: sim_result.host_block_number(), ..Default::default() } } /// Prepares and signs the submission transaction for the rollup block. /// /// Creates a `SubmitPrep` instance to build the transaction, then fills /// and signs it using the host provider. + /// + /// Returns the signed transaction envelope and the sidecar (for forwarding to Pylon). #[instrument(skip_all, level = "debug")] - async fn prepare_signed_transaction(&self, sim_result: &SimResult) -> eyre::Result { + async fn prepare_signed_transaction( + &self, + sim_result: &SimResult, + ) -> eyre::Result<(TxEnvelope, alloy::eips::eip7594::BlobTransactionSidecarEip7594)> { let prep = SubmitPrep::new( &sim_result.block, self.host_provider(), @@ -104,7 +83,7 @@ impl FlashbotsTask { self.config.clone(), ); - let tx = prep.prep_transaction(sim_result.prev_host()).await?; + let (tx, sidecar) = prep.prep_transaction(sim_result.prev_host()).await?; let sendable = self .host_provider() @@ -115,7 +94,7 @@ impl FlashbotsTask { let tx_envelope = sendable.try_into_envelope()?; debug!(tx_hash = ?tx_envelope.hash(), "prepared signed rollup block transaction envelope"); - Ok(tx_envelope) + Ok((tx_envelope, sidecar)) } /// Tracks the outbound transaction hash and increments submission metrics. @@ -174,17 +153,23 @@ impl FlashbotsTask { } span_debug!(span, "flashbots task received block"); - // Prepare a MEV bundle with the configured call type from the sim result - let result = self.prepare(&sim_result).instrument(span.clone()).await; + // Prepare and sign the transaction + let (envelope, sidecar) = + match self.prepare_signed_transaction(&sim_result).instrument(span.clone()).await { + Ok(result) => result, + Err(error) => { + counter!("signet.builder.flashbots.bundle_prep_failures").increment(1); + span_debug!(span, %error, "bundle preparation failed"); + continue; + } + }; + + // Extract tx_hash and track the outbound transaction + let tx_hash = *envelope.tx_hash(); + self.track_outbound_tx(&envelope); - let bundle = match result { - Ok(bundle) => bundle, - Err(error) => { - counter!("signet.builder.flashbots.bundle_prep_failures").increment(1); - span_debug!(span, %error, "bundle preparation failed"); - continue; - } - }; + // Build the bundle + let bundle = self.build_bundle(&envelope, &sim_result); // Make a child span to cover submission, or use the current span // if debug is not enabled. @@ -193,9 +178,10 @@ impl FlashbotsTask { // Send the bundle to Flashbots, instrumenting the send future so // all events inside the async send are attributed to the submit - // span. + // span. Only send sidecar to Pylon if Flashbots accepts. let flashbots = self.flashbots().to_owned(); let signer = self.signer.clone(); + let pylon_sender = self.pylon_sender.clone(); tokio::spawn( async move { @@ -209,6 +195,11 @@ impl FlashbotsTask { hash = resp.map(|r| r.bundle_hash.to_string()), "Submitted MEV bundle to Flashbots, received OK response" ); + + // Only send sidecar to Pylon after Flashbots accepts + if let Err(e) = pylon_sender.send((tx_hash, sidecar)) { + debug!("pylon channel closed: {}", e); + } } Err(err) => { counter!("signet.builder.flashbots.submission_failures").increment(1); @@ -216,7 +207,7 @@ impl FlashbotsTask { } } } - .instrument(submit_span.clone()), + .instrument(submit_span), ); } } diff --git a/src/tasks/submit/mod.rs b/src/tasks/submit/mod.rs index b9a7d4c5..b8b8e7ae 100644 --- a/src/tasks/submit/mod.rs +++ b/src/tasks/submit/mod.rs @@ -5,5 +5,9 @@ pub use flashbots::FlashbotsTask; mod prep; pub use prep::{Bumpable, SubmitPrep}; +/// Submission logic for Pylon blob server +pub mod pylon; +pub use pylon::PylonTask; + mod sim_err; pub use sim_err::{SimErrorResp, SimRevertKind}; diff --git a/src/tasks/submit/prep.rs b/src/tasks/submit/prep.rs index 4e262af0..1732a569 100644 --- a/src/tasks/submit/prep.rs +++ b/src/tasks/submit/prep.rs @@ -56,6 +56,12 @@ impl<'a> SubmitPrep<'a> { } } + /// Encodes the rollup block into an EIP-7594 sidecar. + #[instrument(skip(self), level = "debug")] + fn build_sidecar(&self) -> eyre::Result { + self.block.encode_blob::().build_7594().map_err(Into::into) + } + /// Construct a quincey signature request for the block. fn sig_request(&self) -> &SignRequest { self.sig_request.get_or_init(|| { @@ -103,12 +109,6 @@ impl<'a> SubmitPrep<'a> { self.quincey_resp().await.map(|resp| &resp.sig).map(utils::extract_signature_components) } - /// Encodes the rollup block into an EIP-7594 sidecar. - #[instrument(skip(self), level = "debug")] - async fn build_sidecar(&self) -> eyre::Result { - self.block.encode_blob::().build_7594().map_err(Into::into) - } - /// Build a signature and header input for the host chain transaction. async fn build_input(&self) -> eyre::Result { let (v, r, s) = self.quincey_signature().await?; @@ -125,30 +125,33 @@ impl<'a> SubmitPrep<'a> { Ok(call.abi_encode().into()) } - /// Create a new transaction request for the host chain. - async fn new_tx_request(&self) -> eyre::Result { + /// Prepares a transaction for submission to the host chain. + /// + /// Returns the bumpable transaction request and the sidecar, which can be + /// forwarded to other tasks (e.g., Pylon) for further processing. + pub async fn prep_transaction( + self, + prev_host: &Header, + ) -> eyre::Result<(Bumpable, BlobTransactionSidecarEip7594)> { let nonce_fut = self .provider .get_transaction_count(self.provider.default_signer_address()) .into_future() .map(|res| res.map_err(Into::into)); - let (nonce, sidecar, input) = - try_join!(nonce_fut, self.build_sidecar(), self.build_input())?; + let (nonce, input) = try_join!(nonce_fut, self.build_input())?; + + // Build the sidecar once + let sidecar = self.build_sidecar()?; - let tx = TransactionRequest::default() - .with_blob_sidecar(sidecar) + // Clone for the transaction request, keep original for return + let req = TransactionRequest::default() + .with_blob_sidecar(sidecar.clone()) .with_input(input) .with_to(self.config.constants.host_zenith()) .with_nonce(nonce); - Ok(tx) - } - - /// Prepares a transaction for submission to the host chain. - pub async fn prep_transaction(self, prev_host: &Header) -> eyre::Result { - let req = self.new_tx_request().in_current_span().await?; - Ok(Bumpable::new(req, prev_host)) + Ok((Bumpable::new(req, prev_host), sidecar)) } } diff --git a/src/tasks/submit/pylon.rs b/src/tasks/submit/pylon.rs new file mode 100644 index 00000000..e04cd991 --- /dev/null +++ b/src/tasks/submit/pylon.rs @@ -0,0 +1,66 @@ +//! Pylon Task handles submitting blob sidecars to the Pylon blob server +//! for data availability. + +use crate::config::PylonClient; +use alloy::{eips::eip7594::BlobTransactionSidecarEip7594, primitives::TxHash}; +use init4_bin_base::deps::metrics::counter; +use tokio::{sync::mpsc, task::JoinHandle}; +use tracing::{debug, error}; + +/// Task that submits blob sidecars to the Pylon blob server. +#[derive(Debug)] +pub struct PylonTask { + /// Pylon client for posting sidecars. + client: PylonClient, +} + +impl PylonTask { + /// Create a new PylonTask with the given client. + pub const fn new(client: PylonClient) -> Self { + Self { client } + } + + /// Main task loop that processes sidecar submissions to Pylon. + /// + /// Receives `(TxHash, BlobTransactionSidecarEip7594)` tuples from the + /// inbound channel and submits them to the Pylon blob server. + async fn task_future( + self, + mut inbound: mpsc::UnboundedReceiver<(TxHash, BlobTransactionSidecarEip7594)>, + ) { + debug!("starting pylon task"); + + loop { + let Some((tx_hash, sidecar)) = inbound.recv().await else { + debug!("upstream task gone - exiting pylon task"); + break; + }; + + let client = self.client.clone(); + + tokio::spawn(async move { + match client.post_sidecar(tx_hash, sidecar).await { + Ok(()) => { + counter!("signet.builder.pylon.posted").increment(1); + debug!(%tx_hash, "posted sidecar to pylon"); + } + Err(err) => { + counter!("signet.builder.pylon.failures").increment(1); + error!(%tx_hash, %err, "pylon submission failed"); + } + } + }); + } + } + + /// Spawns the Pylon task in a new Tokio task. + /// + /// Returns a sender for submitting sidecars and a join handle for the task. + pub fn spawn( + self, + ) -> (mpsc::UnboundedSender<(TxHash, BlobTransactionSidecarEip7594)>, JoinHandle<()>) { + let (sender, receiver) = mpsc::unbounded_channel(); + let handle = tokio::spawn(self.task_future(receiver)); + (sender, handle) + } +} diff --git a/src/test_utils.rs b/src/test_utils.rs index cb9d3e75..20119f41 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -56,6 +56,7 @@ pub fn setup_test_config() -> &'static BuilderConfig { block_query_cutoff_buffer: 3000, max_host_gas_coefficient: Some(80), constants: SignetSystemConstants::parmigiana(), + pylon_url: "http://localhost:8081".parse().unwrap(), } }) } From b8feb2ec91314a3143e44e09e290b0c76f8db57e Mon Sep 17 00:00:00 2001 From: evalir Date: Thu, 5 Feb 2026 16:07:36 +0100 Subject: [PATCH 2/9] chore: revert --- bin/builder.rs | 21 ++------ src/config.rs | 14 +---- src/tasks/submit/flashbots.rs | 97 +++++++++++++++++++---------------- src/tasks/submit/mod.rs | 4 -- src/tasks/submit/prep.rs | 41 +++++++-------- src/tasks/submit/pylon.rs | 66 ------------------------ src/test_utils.rs | 1 - 7 files changed, 77 insertions(+), 167 deletions(-) delete mode 100644 src/tasks/submit/pylon.rs diff --git a/bin/builder.rs b/bin/builder.rs index 1f268ba3..adf26997 100644 --- a/bin/builder.rs +++ b/bin/builder.rs @@ -1,11 +1,8 @@ use builder::{ service::serve_builder, tasks::{ - block::sim::SimulatorTask, - cache::CacheTasks, - env::EnvTask, - metrics::MetricsTask, - submit::{FlashbotsTask, PylonTask}, + block::sim::SimulatorTask, cache::CacheTasks, env::EnvTask, metrics::MetricsTask, + submit::FlashbotsTask, }, }; use init4_bin_base::deps::tracing::{info, info_span}; @@ -35,17 +32,10 @@ async fn main() -> eyre::Result<()> { let (block_env, env_jh) = env_task.spawn(); let (tx_channel, metrics_jh) = metrics_task.spawn(); - // Set up the pylon task - let pylon_client = builder::config().connect_pylon(); - let pylon_task = PylonTask::new(pylon_client); - let (pylon_sender, pylon_jh) = pylon_task.spawn(); - // Set up the cache, submit, and simulator tasks let cache_tasks = CacheTasks::new(block_env.clone()); - let (submit_task, simulator_task) = tokio::try_join!( - FlashbotsTask::new(tx_channel.clone(), pylon_sender), - SimulatorTask::new(block_env), - )?; + let (submit_task, simulator_task) = + tokio::try_join!(FlashbotsTask::new(tx_channel.clone()), SimulatorTask::new(block_env),)?; // Spawn the cache, submit, and simulator tasks let cache_system = cache_tasks.spawn(); @@ -75,9 +65,6 @@ async fn main() -> eyre::Result<()> { _ = submit_jh => { info!("submit finished"); }, - _ = pylon_jh => { - info!("pylon task finished"); - }, _ = metrics_jh => { info!("metrics finished"); }, diff --git a/src/config.rs b/src/config.rs index 79c125a5..1296ccc0 100644 --- a/src/config.rs +++ b/src/config.rs @@ -12,7 +12,7 @@ use alloy::{ }; use eyre::Result; use init4_bin_base::{ - perms::{Authenticator, OAuthConfig, SharedToken, pylon}, + perms::{Authenticator, OAuthConfig, SharedToken}, utils::{ calc::SlotCalculator, from_env::FromEnv, @@ -25,9 +25,6 @@ use signet_zenith::Zenith; use std::borrow::Cow; use tokio::join; -/// Pylon client type for blob sidecar submission. -pub type PylonClient = pylon::PylonClient; - /// Type alias for the provider used to simulate against rollup state. pub type RuProvider = RootProvider; @@ -171,10 +168,6 @@ pub struct BuilderConfig { /// The signet system constants. pub constants: SignetSystemConstants, - - /// URL for the Pylon blob server API. - #[from_env(var = "PYLON_URL", desc = "URL for the Pylon blob server API")] - pub pylon_url: url::Url, } impl BuilderConfig { @@ -292,9 +285,4 @@ impl BuilderConfig { ((gas_limit as u128 * (self.max_host_gas_coefficient.unwrap_or(80) as u128)) / 100u128) as u64 } - - /// Connect to the Pylon blob server. - pub fn connect_pylon(&self) -> PylonClient { - PylonClient::new(self.pylon_url.clone(), self.oauth_token()) - } } diff --git a/src/tasks/submit/flashbots.rs b/src/tasks/submit/flashbots.rs index 12bdfc79..6b3d998c 100644 --- a/src/tasks/submit/flashbots.rs +++ b/src/tasks/submit/flashbots.rs @@ -7,7 +7,7 @@ use crate::{ }; use alloy::{ consensus::TxEnvelope, - eips::{Encodable2718, eip7594::BlobTransactionSidecarEip7594}, + eips::Encodable2718, primitives::{Bytes, TxHash}, providers::ext::MevApi, rpc::types::mev::EthSendBundle, @@ -32,17 +32,12 @@ pub struct FlashbotsTask { signer: LocalOrAws, /// Channel for sending hashes of outbound transactions. outbound: mpsc::UnboundedSender, - /// Channel for sending sidecars to the Pylon task. - pylon_sender: mpsc::UnboundedSender<(TxHash, BlobTransactionSidecarEip7594)>, } impl FlashbotsTask { /// Returns a new `FlashbotsTask` instance that receives `SimResult` types from the given /// channel and handles their preparation, submission to the Flashbots network. - pub async fn new( - outbound: mpsc::UnboundedSender, - pylon_sender: mpsc::UnboundedSender<(TxHash, BlobTransactionSidecarEip7594)>, - ) -> eyre::Result { + pub async fn new(outbound: mpsc::UnboundedSender) -> eyre::Result { let config = crate::config(); let (quincey, host_provider, flashbots, builder_key) = tokio::try_join!( @@ -54,28 +49,54 @@ impl FlashbotsTask { let zenith = config.connect_zenith(host_provider); - Ok(Self { config, quincey, zenith, flashbots, signer: builder_key, outbound, pylon_sender }) + Ok(Self { config, quincey, zenith, flashbots, signer: builder_key, outbound }) } - /// Builds a MEV bundle from a signed transaction envelope and simulation result. - fn build_bundle(&self, envelope: &TxEnvelope, sim_result: &SimResult) -> EthSendBundle { - let tx_bytes: Bytes = envelope.encoded_2718().into(); + /// Prepares a MEV bundle from a simulation result. + /// + /// This function serves as an entry point for bundle preparation and is left + /// for forward compatibility when adding different bundle preparation methods. + pub async fn prepare(&self, sim_result: &SimResult) -> eyre::Result { + // This function is left for forwards compatibility when we want to add + // different bundle preparation methods in the future. + self.prepare_bundle(sim_result).await + } + + /// Prepares a MEV bundle containing the host transactions and the rollup block. + /// + /// This method orchestrates the bundle preparation by: + /// 1. Preparing and signing the submission transaction + /// 2. Tracking the transaction hash for monitoring + /// 3. Encoding the transaction for bundle inclusion + /// 4. Constructing the complete bundle body + #[instrument(skip_all, level = "debug")] + async fn prepare_bundle(&self, sim_result: &SimResult) -> eyre::Result { + // Prepare and sign the transaction + let block_tx = self.prepare_signed_transaction(sim_result).await?; + + // Track the outbound transaction + self.track_outbound_tx(&block_tx); + + // Encode the transaction + let tx_bytes = block_tx.encoded_2718().into(); + + // Build the bundle body with the block_tx bytes as the last transaction in the bundle. let txs = self.build_bundle_body(sim_result, tx_bytes); - EthSendBundle { txs, block_number: sim_result.host_block_number(), ..Default::default() } + // Create the MEV bundle (valid only in the specific host block) + Ok(EthSendBundle { + txs, + block_number: sim_result.host_block_number(), + ..Default::default() + }) } /// Prepares and signs the submission transaction for the rollup block. /// /// Creates a `SubmitPrep` instance to build the transaction, then fills /// and signs it using the host provider. - /// - /// Returns the signed transaction envelope and the sidecar (for forwarding to Pylon). #[instrument(skip_all, level = "debug")] - async fn prepare_signed_transaction( - &self, - sim_result: &SimResult, - ) -> eyre::Result<(TxEnvelope, alloy::eips::eip7594::BlobTransactionSidecarEip7594)> { + async fn prepare_signed_transaction(&self, sim_result: &SimResult) -> eyre::Result { let prep = SubmitPrep::new( &sim_result.block, self.host_provider(), @@ -83,7 +104,7 @@ impl FlashbotsTask { self.config.clone(), ); - let (tx, sidecar) = prep.prep_transaction(sim_result.prev_host()).await?; + let tx = prep.prep_transaction(sim_result.prev_host()).await?; let sendable = self .host_provider() @@ -94,7 +115,7 @@ impl FlashbotsTask { let tx_envelope = sendable.try_into_envelope()?; debug!(tx_hash = ?tx_envelope.hash(), "prepared signed rollup block transaction envelope"); - Ok((tx_envelope, sidecar)) + Ok(tx_envelope) } /// Tracks the outbound transaction hash and increments submission metrics. @@ -153,23 +174,17 @@ impl FlashbotsTask { } span_debug!(span, "flashbots task received block"); - // Prepare and sign the transaction - let (envelope, sidecar) = - match self.prepare_signed_transaction(&sim_result).instrument(span.clone()).await { - Ok(result) => result, - Err(error) => { - counter!("signet.builder.flashbots.bundle_prep_failures").increment(1); - span_debug!(span, %error, "bundle preparation failed"); - continue; - } - }; - - // Extract tx_hash and track the outbound transaction - let tx_hash = *envelope.tx_hash(); - self.track_outbound_tx(&envelope); + // Prepare a MEV bundle with the configured call type from the sim result + let result = self.prepare(&sim_result).instrument(span.clone()).await; - // Build the bundle - let bundle = self.build_bundle(&envelope, &sim_result); + let bundle = match result { + Ok(bundle) => bundle, + Err(error) => { + counter!("signet.builder.flashbots.bundle_prep_failures").increment(1); + span_debug!(span, %error, "bundle preparation failed"); + continue; + } + }; // Make a child span to cover submission, or use the current span // if debug is not enabled. @@ -178,10 +193,9 @@ impl FlashbotsTask { // Send the bundle to Flashbots, instrumenting the send future so // all events inside the async send are attributed to the submit - // span. Only send sidecar to Pylon if Flashbots accepts. + // span. let flashbots = self.flashbots().to_owned(); let signer = self.signer.clone(); - let pylon_sender = self.pylon_sender.clone(); tokio::spawn( async move { @@ -195,11 +209,6 @@ impl FlashbotsTask { hash = resp.map(|r| r.bundle_hash.to_string()), "Submitted MEV bundle to Flashbots, received OK response" ); - - // Only send sidecar to Pylon after Flashbots accepts - if let Err(e) = pylon_sender.send((tx_hash, sidecar)) { - debug!("pylon channel closed: {}", e); - } } Err(err) => { counter!("signet.builder.flashbots.submission_failures").increment(1); @@ -207,7 +216,7 @@ impl FlashbotsTask { } } } - .instrument(submit_span), + .instrument(submit_span.clone()), ); } } diff --git a/src/tasks/submit/mod.rs b/src/tasks/submit/mod.rs index b8b8e7ae..b9a7d4c5 100644 --- a/src/tasks/submit/mod.rs +++ b/src/tasks/submit/mod.rs @@ -5,9 +5,5 @@ pub use flashbots::FlashbotsTask; mod prep; pub use prep::{Bumpable, SubmitPrep}; -/// Submission logic for Pylon blob server -pub mod pylon; -pub use pylon::PylonTask; - mod sim_err; pub use sim_err::{SimErrorResp, SimRevertKind}; diff --git a/src/tasks/submit/prep.rs b/src/tasks/submit/prep.rs index 1732a569..4e262af0 100644 --- a/src/tasks/submit/prep.rs +++ b/src/tasks/submit/prep.rs @@ -56,12 +56,6 @@ impl<'a> SubmitPrep<'a> { } } - /// Encodes the rollup block into an EIP-7594 sidecar. - #[instrument(skip(self), level = "debug")] - fn build_sidecar(&self) -> eyre::Result { - self.block.encode_blob::().build_7594().map_err(Into::into) - } - /// Construct a quincey signature request for the block. fn sig_request(&self) -> &SignRequest { self.sig_request.get_or_init(|| { @@ -109,6 +103,12 @@ impl<'a> SubmitPrep<'a> { self.quincey_resp().await.map(|resp| &resp.sig).map(utils::extract_signature_components) } + /// Encodes the rollup block into an EIP-7594 sidecar. + #[instrument(skip(self), level = "debug")] + async fn build_sidecar(&self) -> eyre::Result { + self.block.encode_blob::().build_7594().map_err(Into::into) + } + /// Build a signature and header input for the host chain transaction. async fn build_input(&self) -> eyre::Result { let (v, r, s) = self.quincey_signature().await?; @@ -125,33 +125,30 @@ impl<'a> SubmitPrep<'a> { Ok(call.abi_encode().into()) } - /// Prepares a transaction for submission to the host chain. - /// - /// Returns the bumpable transaction request and the sidecar, which can be - /// forwarded to other tasks (e.g., Pylon) for further processing. - pub async fn prep_transaction( - self, - prev_host: &Header, - ) -> eyre::Result<(Bumpable, BlobTransactionSidecarEip7594)> { + /// Create a new transaction request for the host chain. + async fn new_tx_request(&self) -> eyre::Result { let nonce_fut = self .provider .get_transaction_count(self.provider.default_signer_address()) .into_future() .map(|res| res.map_err(Into::into)); - let (nonce, input) = try_join!(nonce_fut, self.build_input())?; - - // Build the sidecar once - let sidecar = self.build_sidecar()?; + let (nonce, sidecar, input) = + try_join!(nonce_fut, self.build_sidecar(), self.build_input())?; - // Clone for the transaction request, keep original for return - let req = TransactionRequest::default() - .with_blob_sidecar(sidecar.clone()) + let tx = TransactionRequest::default() + .with_blob_sidecar(sidecar) .with_input(input) .with_to(self.config.constants.host_zenith()) .with_nonce(nonce); - Ok((Bumpable::new(req, prev_host), sidecar)) + Ok(tx) + } + + /// Prepares a transaction for submission to the host chain. + pub async fn prep_transaction(self, prev_host: &Header) -> eyre::Result { + let req = self.new_tx_request().in_current_span().await?; + Ok(Bumpable::new(req, prev_host)) } } diff --git a/src/tasks/submit/pylon.rs b/src/tasks/submit/pylon.rs deleted file mode 100644 index e04cd991..00000000 --- a/src/tasks/submit/pylon.rs +++ /dev/null @@ -1,66 +0,0 @@ -//! Pylon Task handles submitting blob sidecars to the Pylon blob server -//! for data availability. - -use crate::config::PylonClient; -use alloy::{eips::eip7594::BlobTransactionSidecarEip7594, primitives::TxHash}; -use init4_bin_base::deps::metrics::counter; -use tokio::{sync::mpsc, task::JoinHandle}; -use tracing::{debug, error}; - -/// Task that submits blob sidecars to the Pylon blob server. -#[derive(Debug)] -pub struct PylonTask { - /// Pylon client for posting sidecars. - client: PylonClient, -} - -impl PylonTask { - /// Create a new PylonTask with the given client. - pub const fn new(client: PylonClient) -> Self { - Self { client } - } - - /// Main task loop that processes sidecar submissions to Pylon. - /// - /// Receives `(TxHash, BlobTransactionSidecarEip7594)` tuples from the - /// inbound channel and submits them to the Pylon blob server. - async fn task_future( - self, - mut inbound: mpsc::UnboundedReceiver<(TxHash, BlobTransactionSidecarEip7594)>, - ) { - debug!("starting pylon task"); - - loop { - let Some((tx_hash, sidecar)) = inbound.recv().await else { - debug!("upstream task gone - exiting pylon task"); - break; - }; - - let client = self.client.clone(); - - tokio::spawn(async move { - match client.post_sidecar(tx_hash, sidecar).await { - Ok(()) => { - counter!("signet.builder.pylon.posted").increment(1); - debug!(%tx_hash, "posted sidecar to pylon"); - } - Err(err) => { - counter!("signet.builder.pylon.failures").increment(1); - error!(%tx_hash, %err, "pylon submission failed"); - } - } - }); - } - } - - /// Spawns the Pylon task in a new Tokio task. - /// - /// Returns a sender for submitting sidecars and a join handle for the task. - pub fn spawn( - self, - ) -> (mpsc::UnboundedSender<(TxHash, BlobTransactionSidecarEip7594)>, JoinHandle<()>) { - let (sender, receiver) = mpsc::unbounded_channel(); - let handle = tokio::spawn(self.task_future(receiver)); - (sender, handle) - } -} diff --git a/src/test_utils.rs b/src/test_utils.rs index 20119f41..cb9d3e75 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -56,7 +56,6 @@ pub fn setup_test_config() -> &'static BuilderConfig { block_query_cutoff_buffer: 3000, max_host_gas_coefficient: Some(80), constants: SignetSystemConstants::parmigiana(), - pylon_url: "http://localhost:8081".parse().unwrap(), } }) } From 26447b353827f71ba8a3ad6452a8f0cfcb6ae7a5 Mon Sep 17 00:00:00 2001 From: evalir Date: Thu, 5 Feb 2026 16:36:59 +0100 Subject: [PATCH 3/9] chore: slim down to fire and forget --- src/config.rs | 14 ++++++++- src/tasks/submit/flashbots.rs | 59 +++++++++++++++++++++++++++++------ src/test_utils.rs | 1 + 3 files changed, 63 insertions(+), 11 deletions(-) diff --git a/src/config.rs b/src/config.rs index 1296ccc0..79c125a5 100644 --- a/src/config.rs +++ b/src/config.rs @@ -12,7 +12,7 @@ use alloy::{ }; use eyre::Result; use init4_bin_base::{ - perms::{Authenticator, OAuthConfig, SharedToken}, + perms::{Authenticator, OAuthConfig, SharedToken, pylon}, utils::{ calc::SlotCalculator, from_env::FromEnv, @@ -25,6 +25,9 @@ use signet_zenith::Zenith; use std::borrow::Cow; use tokio::join; +/// Pylon client type for blob sidecar submission. +pub type PylonClient = pylon::PylonClient; + /// Type alias for the provider used to simulate against rollup state. pub type RuProvider = RootProvider; @@ -168,6 +171,10 @@ pub struct BuilderConfig { /// The signet system constants. pub constants: SignetSystemConstants, + + /// URL for the Pylon blob server API. + #[from_env(var = "PYLON_URL", desc = "URL for the Pylon blob server API")] + pub pylon_url: url::Url, } impl BuilderConfig { @@ -285,4 +292,9 @@ impl BuilderConfig { ((gas_limit as u128 * (self.max_host_gas_coefficient.unwrap_or(80) as u128)) / 100u128) as u64 } + + /// Connect to the Pylon blob server. + pub fn connect_pylon(&self) -> PylonClient { + PylonClient::new(self.pylon_url.clone(), self.oauth_token()) + } } diff --git a/src/tasks/submit/flashbots.rs b/src/tasks/submit/flashbots.rs index 6b3d998c..a8610baa 100644 --- a/src/tasks/submit/flashbots.rs +++ b/src/tasks/submit/flashbots.rs @@ -1,13 +1,13 @@ //! Flashbots Task receives simulated blocks from an upstream channel and //! submits them to the Flashbots relay as bundles. use crate::{ - config::{BuilderConfig, FlashbotsProvider, HostProvider, ZenithInstance}, + config::{BuilderConfig, FlashbotsProvider, HostProvider, PylonClient, ZenithInstance}, quincey::Quincey, tasks::{block::sim::SimResult, submit::SubmitPrep}, }; use alloy::{ consensus::TxEnvelope, - eips::Encodable2718, + eips::{Encodable2718, eip7594::BlobTransactionSidecarEip7594}, primitives::{Bytes, TxHash}, providers::ext::MevApi, rpc::types::mev::EthSendBundle, @@ -32,6 +32,8 @@ pub struct FlashbotsTask { signer: LocalOrAws, /// Channel for sending hashes of outbound transactions. outbound: mpsc::UnboundedSender, + /// Pylon client for blob sidecar submission. + pylon: PylonClient, } impl FlashbotsTask { @@ -48,15 +50,21 @@ impl FlashbotsTask { )?; let zenith = config.connect_zenith(host_provider); + let pylon = config.connect_pylon(); - Ok(Self { config, quincey, zenith, flashbots, signer: builder_key, outbound }) + Ok(Self { config, quincey, zenith, flashbots, signer: builder_key, outbound, pylon }) } /// Prepares a MEV bundle from a simulation result. /// /// This function serves as an entry point for bundle preparation and is left /// for forward compatibility when adding different bundle preparation methods. - pub async fn prepare(&self, sim_result: &SimResult) -> eyre::Result { + /// + /// Returns the bundle, tx hash, and the blob sidecar for Pylon submission. + pub async fn prepare( + &self, + sim_result: &SimResult, + ) -> eyre::Result<(EthSendBundle, TxHash, BlobTransactionSidecarEip7594)> { // This function is left for forwards compatibility when we want to add // different bundle preparation methods in the future. self.prepare_bundle(sim_result).await @@ -69,14 +77,30 @@ impl FlashbotsTask { /// 2. Tracking the transaction hash for monitoring /// 3. Encoding the transaction for bundle inclusion /// 4. Constructing the complete bundle body + /// + /// Returns the bundle, tx hash, and the blob sidecar for Pylon submission. #[instrument(skip_all, level = "debug")] - async fn prepare_bundle(&self, sim_result: &SimResult) -> eyre::Result { + async fn prepare_bundle( + &self, + sim_result: &SimResult, + ) -> eyre::Result<(EthSendBundle, TxHash, BlobTransactionSidecarEip7594)> { // Prepare and sign the transaction let block_tx = self.prepare_signed_transaction(sim_result).await?; // Track the outbound transaction self.track_outbound_tx(&block_tx); + // Get tx hash for Pylon submission + let tx_hash = *block_tx.tx_hash(); + + // Clone the sidecar from the envelope for Pylon submission + // We always build EIP-7594 sidecars, so this is guaranteed to exist + let sidecar = block_tx + .as_eip4844() + .and_then(|tx| tx.tx().sidecar()) + .and_then(|s| s.clone().into_eip7594()) + .expect("sidecar is guaranteed to exist for blob transactions"); + // Encode the transaction let tx_bytes = block_tx.encoded_2718().into(); @@ -84,11 +108,13 @@ impl FlashbotsTask { let txs = self.build_bundle_body(sim_result, tx_bytes); // Create the MEV bundle (valid only in the specific host block) - Ok(EthSendBundle { + let bundle = EthSendBundle { txs, block_number: sim_result.host_block_number(), ..Default::default() - }) + }; + + Ok((bundle, tx_hash, sidecar)) } /// Prepares and signs the submission transaction for the rollup block. @@ -177,8 +203,8 @@ impl FlashbotsTask { // Prepare a MEV bundle with the configured call type from the sim result let result = self.prepare(&sim_result).instrument(span.clone()).await; - let bundle = match result { - Ok(bundle) => bundle, + let (bundle, tx_hash, sidecar) = match result { + Ok(result) => result, Err(error) => { counter!("signet.builder.flashbots.bundle_prep_failures").increment(1); span_debug!(span, %error, "bundle preparation failed"); @@ -193,9 +219,10 @@ impl FlashbotsTask { // Send the bundle to Flashbots, instrumenting the send future so // all events inside the async send are attributed to the submit - // span. + // span. If Flashbots accepts, submit sidecar to Pylon. let flashbots = self.flashbots().to_owned(); let signer = self.signer.clone(); + let pylon = self.pylon.clone(); tokio::spawn( async move { @@ -209,6 +236,18 @@ impl FlashbotsTask { hash = resp.map(|r| r.bundle_hash.to_string()), "Submitted MEV bundle to Flashbots, received OK response" ); + + // Fire and forget pylon submission + match pylon.post_sidecar(tx_hash, sidecar).await { + Ok(()) => { + counter!("signet.builder.pylon.posted").increment(1); + debug!(%tx_hash, "posted sidecar to pylon"); + } + Err(err) => { + counter!("signet.builder.pylon.failures").increment(1); + error!(%tx_hash, %err, "pylon submission failed"); + } + } } Err(err) => { counter!("signet.builder.flashbots.submission_failures").increment(1); diff --git a/src/test_utils.rs b/src/test_utils.rs index cb9d3e75..20119f41 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -56,6 +56,7 @@ pub fn setup_test_config() -> &'static BuilderConfig { block_query_cutoff_buffer: 3000, max_host_gas_coefficient: Some(80), constants: SignetSystemConstants::parmigiana(), + pylon_url: "http://localhost:8081".parse().unwrap(), } }) } From 4c1011f853b5ae90c7e5b82751b06a7fc105293d Mon Sep 17 00:00:00 2001 From: evalir Date: Fri, 6 Feb 2026 14:38:39 +0100 Subject: [PATCH 4/9] chore: simplify --- src/tasks/submit/flashbots.rs | 58 ++++++++++++----------------------- 1 file changed, 19 insertions(+), 39 deletions(-) diff --git a/src/tasks/submit/flashbots.rs b/src/tasks/submit/flashbots.rs index a8610baa..3ea76830 100644 --- a/src/tasks/submit/flashbots.rs +++ b/src/tasks/submit/flashbots.rs @@ -7,7 +7,7 @@ use crate::{ }; use alloy::{ consensus::TxEnvelope, - eips::{Encodable2718, eip7594::BlobTransactionSidecarEip7594}, + eips::Encodable2718, primitives::{Bytes, TxHash}, providers::ext::MevApi, rpc::types::mev::EthSendBundle, @@ -59,12 +59,7 @@ impl FlashbotsTask { /// /// This function serves as an entry point for bundle preparation and is left /// for forward compatibility when adding different bundle preparation methods. - /// - /// Returns the bundle, tx hash, and the blob sidecar for Pylon submission. - pub async fn prepare( - &self, - sim_result: &SimResult, - ) -> eyre::Result<(EthSendBundle, TxHash, BlobTransactionSidecarEip7594)> { + pub async fn prepare(&self, sim_result: &SimResult) -> eyre::Result { // This function is left for forwards compatibility when we want to add // different bundle preparation methods in the future. self.prepare_bundle(sim_result).await @@ -77,30 +72,14 @@ impl FlashbotsTask { /// 2. Tracking the transaction hash for monitoring /// 3. Encoding the transaction for bundle inclusion /// 4. Constructing the complete bundle body - /// - /// Returns the bundle, tx hash, and the blob sidecar for Pylon submission. #[instrument(skip_all, level = "debug")] - async fn prepare_bundle( - &self, - sim_result: &SimResult, - ) -> eyre::Result<(EthSendBundle, TxHash, BlobTransactionSidecarEip7594)> { + async fn prepare_bundle(&self, sim_result: &SimResult) -> eyre::Result { // Prepare and sign the transaction let block_tx = self.prepare_signed_transaction(sim_result).await?; // Track the outbound transaction self.track_outbound_tx(&block_tx); - // Get tx hash for Pylon submission - let tx_hash = *block_tx.tx_hash(); - - // Clone the sidecar from the envelope for Pylon submission - // We always build EIP-7594 sidecars, so this is guaranteed to exist - let sidecar = block_tx - .as_eip4844() - .and_then(|tx| tx.tx().sidecar()) - .and_then(|s| s.clone().into_eip7594()) - .expect("sidecar is guaranteed to exist for blob transactions"); - // Encode the transaction let tx_bytes = block_tx.encoded_2718().into(); @@ -108,15 +87,12 @@ impl FlashbotsTask { let txs = self.build_bundle_body(sim_result, tx_bytes); // Create the MEV bundle (valid only in the specific host block) - let bundle = EthSendBundle { + Ok(EthSendBundle { txs, block_number: sim_result.host_block_number(), ..Default::default() - }; - - Ok((bundle, tx_hash, sidecar)) + }) } - /// Prepares and signs the submission transaction for the rollup block. /// /// Creates a `SubmitPrep` instance to build the transaction, then fills @@ -202,9 +178,8 @@ impl FlashbotsTask { // Prepare a MEV bundle with the configured call type from the sim result let result = self.prepare(&sim_result).instrument(span.clone()).await; - - let (bundle, tx_hash, sidecar) = match result { - Ok(result) => result, + let bundle = match result { + Ok(bundle) => bundle, Err(error) => { counter!("signet.builder.flashbots.bundle_prep_failures").increment(1); span_debug!(span, %error, "bundle preparation failed"); @@ -212,6 +187,10 @@ impl FlashbotsTask { } }; + // Due to the way the bundle is built, the block transaction is the last transaction in the bundle. + // We'll use this to forward the tx to pylon, which will preload the sidecar. + let block_tx = bundle.txs.last().unwrap().clone(); + // Make a child span to cover submission, or use the current span // if debug is not enabled. let _guard = span.enter(); @@ -219,7 +198,7 @@ impl FlashbotsTask { // Send the bundle to Flashbots, instrumenting the send future so // all events inside the async send are attributed to the submit - // span. If Flashbots accepts, submit sidecar to Pylon. + // span. If Flashbots accepts, submit envelope to Pylon. let flashbots = self.flashbots().to_owned(); let signer = self.signer.clone(); let pylon = self.pylon.clone(); @@ -237,15 +216,16 @@ impl FlashbotsTask { "Submitted MEV bundle to Flashbots, received OK response" ); - // Fire and forget pylon submission - match pylon.post_sidecar(tx_hash, sidecar).await { + match pylon.post_sidecar(block_tx).await { Ok(()) => { - counter!("signet.builder.pylon.posted").increment(1); - debug!(%tx_hash, "posted sidecar to pylon"); + counter!("signet.builder.pylon.sidecars_submitted") + .increment(1); + debug!("posted sidecar to pylon"); } Err(err) => { - counter!("signet.builder.pylon.failures").increment(1); - error!(%tx_hash, %err, "pylon submission failed"); + counter!("signet.builder.pylon.submission_failures") + .increment(1); + error!(%err, "pylon submission failed"); } } } From 98c14bfadea11358e85065fce658f573d9864dc1 Mon Sep 17 00:00:00 2001 From: evalir Date: Fri, 6 Feb 2026 14:39:48 +0100 Subject: [PATCH 5/9] chore: docs --- src/tasks/submit/flashbots.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tasks/submit/flashbots.rs b/src/tasks/submit/flashbots.rs index 3ea76830..af9cf10e 100644 --- a/src/tasks/submit/flashbots.rs +++ b/src/tasks/submit/flashbots.rs @@ -187,7 +187,7 @@ impl FlashbotsTask { } }; - // Due to the way the bundle is built, the block transaction is the last transaction in the bundle. + // Due to the way the bundle is built, the block transaction is the last transaction in the bundle, and will always exist. // We'll use this to forward the tx to pylon, which will preload the sidecar. let block_tx = bundle.txs.last().unwrap().clone(); From 284803bd790c3cb2d8879089f8cec6198429d803 Mon Sep 17 00:00:00 2001 From: evalir Date: Fri, 6 Feb 2026 14:43:10 +0100 Subject: [PATCH 6/9] chore: move build_bundle_body to `SimResult` --- src/tasks/block/sim.rs | 17 ++++++++++++++++- src/tasks/submit/flashbots.rs | 27 ++------------------------- 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/src/tasks/block/sim.rs b/src/tasks/block/sim.rs index 3963dc43..ea3cfe3e 100644 --- a/src/tasks/block/sim.rs +++ b/src/tasks/block/sim.rs @@ -5,7 +5,7 @@ use crate::{ config::{BuilderConfig, HostProvider, RuProvider}, tasks::env::SimEnv, }; -use alloy::consensus::Header; +use alloy::{consensus::Header, eips::Encodable2718, primitives::Bytes}; use init4_bin_base::{ deps::metrics::{counter, histogram}, utils::calc::SlotCalculator, @@ -62,6 +62,21 @@ impl SimResult { pub fn clone_span(&self) -> Span { self.sim_env.clone_span() } + + /// Constructs the MEV bundle body from host transactions and the submission transaction. + /// + /// Combines all host transactions from the rollup block with the prepared rollup block + /// submission transaction, wrapping each as a non-revertible bundle item. + /// + /// The rollup block transaction is always included and placed last in the bundle. + pub fn build_bundle_body(&self, block_tx_bytes: Bytes) -> Vec { + self.block + .host_transactions() + .iter() + .map(|tx| tx.encoded_2718().into()) + .chain(std::iter::once(block_tx_bytes)) + .collect() + } } /// A task that builds blocks based on incoming [`SimEnv`]s and a simulation diff --git a/src/tasks/submit/flashbots.rs b/src/tasks/submit/flashbots.rs index af9cf10e..caee876c 100644 --- a/src/tasks/submit/flashbots.rs +++ b/src/tasks/submit/flashbots.rs @@ -6,10 +6,7 @@ use crate::{ tasks::{block::sim::SimResult, submit::SubmitPrep}, }; use alloy::{ - consensus::TxEnvelope, - eips::Encodable2718, - primitives::{Bytes, TxHash}, - providers::ext::MevApi, + consensus::TxEnvelope, eips::Encodable2718, primitives::TxHash, providers::ext::MevApi, rpc::types::mev::EthSendBundle, }; use init4_bin_base::{deps::metrics::counter, utils::signer::LocalOrAws}; @@ -84,7 +81,7 @@ impl FlashbotsTask { let tx_bytes = block_tx.encoded_2718().into(); // Build the bundle body with the block_tx bytes as the last transaction in the bundle. - let txs = self.build_bundle_body(sim_result, tx_bytes); + let txs = sim_result.build_bundle_body(tx_bytes); // Create the MEV bundle (valid only in the specific host block) Ok(EthSendBundle { @@ -132,26 +129,6 @@ impl FlashbotsTask { } } - /// Constructs the MEV bundle body from host transactions and the submission transaction. - /// - /// Combines all host transactions from the rollup block with the prepared rollup block - /// submission transaction, wrapping each as a non-revertible bundle item. - /// - /// The rollup block transaction is placed last in the bundle. - fn build_bundle_body( - &self, - sim_result: &SimResult, - tx_bytes: alloy::primitives::Bytes, - ) -> Vec { - sim_result - .block - .host_transactions() - .iter() - .map(|tx| tx.encoded_2718().into()) - .chain(std::iter::once(tx_bytes)) - .collect() - } - /// Main task loop that processes simulation results and submits bundles to Flashbots. /// /// Receives `SimResult`s from the inbound channel, prepares MEV bundles, and submits From c53b448b35c3b5a770ea20e84ab7ee81ca959a98 Mon Sep 17 00:00:00 2001 From: evalir Date: Mon, 9 Feb 2026 14:04:12 +0100 Subject: [PATCH 7/9] chore: fix compile errors --- src/tasks/cache/bundle.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/tasks/cache/bundle.rs b/src/tasks/cache/bundle.rs index eed88506..70395819 100644 --- a/src/tasks/cache/bundle.rs +++ b/src/tasks/cache/bundle.rs @@ -1,6 +1,6 @@ //! Bundler service responsible for fetching bundles and sending them to the simulator. use crate::config::BuilderConfig; -use init4_bin_base::perms::tx_cache::BuilderTxCache; +use init4_bin_base::perms::tx_cache::{BuilderTxCache, BuilderTxCacheError}; use signet_tx_cache::{TxCacheError, types::TxCacheBundle}; use tokio::{ sync::mpsc::{UnboundedReceiver, UnboundedSender, unbounded_channel}, @@ -51,7 +51,7 @@ impl BundlePoller { } /// Checks the bundle cache for new bundles. - pub async fn check_bundle_cache(&self) -> Result, TxCacheError> { + pub async fn check_bundle_cache(&self) -> Result, BuilderTxCacheError> { let res = self.tx_cache.get_bundles(None).await; match res { @@ -59,12 +59,12 @@ impl BundlePoller { trace!(count = ?bundles.bundles.len(), "found bundles"); Ok(bundles.bundles) } - Err(TxCacheError::NotOurSlot) => { - trace!("Not our slot to fetch bundles"); - Err(TxCacheError::NotOurSlot) - } Err(err) => { - error!(?err, "Failed to fetch bundles from tx-cache"); + if matches!(&err, BuilderTxCacheError::TxCache(TxCacheError::NotOurSlot)) { + trace!("Not our slot to fetch bundles"); + } else { + error!(?err, "Failed to fetch bundles from tx-cache"); + } Err(err) } } From e37007567904e637974a76f197413f6041a1db78 Mon Sep 17 00:00:00 2001 From: evalir Date: Mon, 9 Feb 2026 14:08:45 +0100 Subject: [PATCH 8/9] chore: docs --- src/tasks/submit/flashbots.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tasks/submit/flashbots.rs b/src/tasks/submit/flashbots.rs index caee876c..651b480d 100644 --- a/src/tasks/submit/flashbots.rs +++ b/src/tasks/submit/flashbots.rs @@ -175,7 +175,7 @@ impl FlashbotsTask { // Send the bundle to Flashbots, instrumenting the send future so // all events inside the async send are attributed to the submit - // span. If Flashbots accepts, submit envelope to Pylon. + // span. If Flashbots accepts it, submit the envelope to Pylon. let flashbots = self.flashbots().to_owned(); let signer = self.signer.clone(); let pylon = self.pylon.clone(); From fb4b0e151661485da29f7579c88dd88edef84c9c Mon Sep 17 00:00:00 2001 From: evalir Date: Mon, 9 Feb 2026 18:52:22 +0100 Subject: [PATCH 9/9] chore: use final client --- Cargo.lock | 6 +++++- Cargo.toml | 6 +++--- src/tasks/submit/flashbots.rs | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index df1f9ac0..3f75dc6f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4950,7 +4950,9 @@ dependencies = [ [[package]] name = "init4-bin-base" -version = "0.18.0-rc.8" +version = "0.18.0-rc.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fe89ed003118f165bd3a1a9dc49b25417766b7f52fd87c380d425b8ea0ff60f" dependencies = [ "alloy", "async-trait", @@ -4985,6 +4987,8 @@ dependencies = [ [[package]] name = "init4-from-env-derive" version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9c78527fcfeaecc9805e5736a7592a26ecad3b7845eb273c8c1710de0dbb0c" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 02120ee2..da5b0eb6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ name = "zenith-builder-example" path = "bin/builder.rs" [dependencies] -init4-bin-base = { version = "0.18.0-rc.8", features = ["perms", "aws", "pylon"] } +init4-bin-base = { version = "0.18.0-rc.9", features = ["perms", "aws", "pylon"] } signet-constants = { version = "0.16.0-rc.8" } signet-sim = { version = "0.16.0-rc.8" } @@ -63,7 +63,7 @@ alloy-hardforks = "0.4.0" alloy-chains = "0.2" # comment / uncomment for local dev -[patch.crates-io] +# [patch.crates-io] # signet-constants = { path = "../signet-sdk/crates/constants" } # signet-types = { path = "../signet-sdk/crates/types" } # signet-zenith = { path = "../signet-sdk/crates/zenith" } @@ -73,4 +73,4 @@ alloy-chains = "0.2" # signet-journal = { path = "../signet-sdk/crates/journal" } # signet-tx-cache = { path = "../signet-sdk/crates/tx-cache" } # signet-bundle = { path = "../signet-sdk/crates/bundle" } -init4-bin-base = { path = "../bin-base" } +# init4-bin-base = { path = "../bin-base" } diff --git a/src/tasks/submit/flashbots.rs b/src/tasks/submit/flashbots.rs index 651b480d..8e70f665 100644 --- a/src/tasks/submit/flashbots.rs +++ b/src/tasks/submit/flashbots.rs @@ -193,7 +193,7 @@ impl FlashbotsTask { "Submitted MEV bundle to Flashbots, received OK response" ); - match pylon.post_sidecar(block_tx).await { + match pylon.post_blob_tx(block_tx).await { Ok(()) => { counter!("signet.builder.pylon.sidecars_submitted") .increment(1);