From 5c5d6a8936ff4dc00e35b9201e358575c6c94071 Mon Sep 17 00:00:00 2001 From: Naman Garg <0708ng@gmail.com> Date: Thu, 5 Sep 2024 09:11:09 +0530 Subject: [PATCH 01/30] feat(sidecar): constraints client init --- bolt-sidecar/src/api/builder.rs | 4 +- bolt-sidecar/src/api/spec.rs | 34 +++++++++++-- bolt-sidecar/src/client/mevboost.rs | 58 +++++++++++++++++++---- bolt-sidecar/src/client/test_util/mod.rs | 13 ++++- bolt-sidecar/src/driver.rs | 6 +-- bolt-sidecar/src/lib.rs | 2 +- bolt-sidecar/src/primitives/constraint.rs | 5 +- bolt-sidecar/src/primitives/mod.rs | 26 +++++++++- 8 files changed, 125 insertions(+), 23 deletions(-) diff --git a/bolt-sidecar/src/api/builder.rs b/bolt-sidecar/src/api/builder.rs index 70eaa22e6..9164e86ed 100644 --- a/bolt-sidecar/src/api/builder.rs +++ b/bolt-sidecar/src/api/builder.rs @@ -26,7 +26,7 @@ use super::spec::{ STATUS_PATH, }; use crate::{ - client::mevboost::MevBoostClient, + client::mevboost::ConstraintClient, primitives::{GetPayloadResponse, PayloadFetcher, SignedBuilderBid}, }; @@ -233,7 +233,7 @@ where "Starting builder proxy..." ); - let mev_boost = MevBoostClient::new(config.mevboost_url); + let mev_boost = ConstraintClient::new(config.mevboost_url); let server = Arc::new(BuilderProxyServer::new(mev_boost, payload_fetcher)); let router = Router::new() diff --git a/bolt-sidecar/src/api/spec.rs b/bolt-sidecar/src/api/spec.rs index 373f292ec..ede8b0eca 100644 --- a/bolt-sidecar/src/api/spec.rs +++ b/bolt-sidecar/src/api/spec.rs @@ -9,7 +9,10 @@ use ethereum_consensus::{ }; use serde::{Deserialize, Serialize, Serializer}; -use crate::primitives::{BatchedSignedConstraints, GetPayloadResponse, SignedBuilderBid}; +use crate::primitives::{ + BatchedSignedConstraints, GetPayloadResponse, SignedBuilderBid, SignedDelegation, + SignedRevocation, +}; use super::builder::GetHeaderParams; @@ -22,7 +25,14 @@ pub const GET_HEADER_PATH: &str = "/eth/v1/builder/header/:slot/:parent_hash/:pu /// The path to the builder API get payload endpoint. pub const GET_PAYLOAD_PATH: &str = "/eth/v1/builder/blinded_blocks"; /// The path to the constraints API submit constraints endpoint. -pub const CONSTRAINTS_PATH: &str = "/eth/v1/builder/constraints"; +pub const SUBMIT_CONSTRAINTS_PATH: &str = "/constraints/v1/builder/constraints"; +/// The path to the constraints API delegate endpoint. +pub const DELEGATE_PATH: &str = "/constraints/v1/builder/delegate"; +/// The path to the constraints API revoke endpoint. +pub const REVOKE_PATH: &str = "/constraints/v1/builder/revoke"; +/// The path to the constraints API get header with proofs endpoint. +pub const GET_HEADER_WITH_PROOFS_PATH: &str = + "/eth/v1/builder/header_with_proofs/:slot/:parent_hash/:pubkey"; /// A response object for errors. #[derive(Debug, Clone, Serialize, Deserialize)] @@ -52,6 +62,10 @@ pub enum BuilderApiError { FailedGettingPayload(ErrorResponse), #[error("Failed submitting constraints: {0:?}")] FailedSubmittingConstraints(ErrorResponse), + #[error("Failed to delegate constraint submission rights: {0:?}")] + FailedDelegating(ErrorResponse), + #[error("Failed to revoke constraint submission rights: {0:?}")] + FailedRevoking(ErrorResponse), #[error("Failed to fetch local payload for slot {0}")] FailedToFetchLocalPayload(u64), #[error("Axum error: {0:?}")] @@ -85,6 +99,12 @@ impl IntoResponse for BuilderApiError { BuilderApiError::FailedSubmittingConstraints(error) => { (StatusCode::from_u16(error.code).unwrap(), Json(error)).into_response() } + BuilderApiError::FailedDelegating(error) => { + (StatusCode::from_u16(error.code).unwrap(), Json(error)).into_response() + } + BuilderApiError::FailedRevoking(error) => { + (StatusCode::from_u16(error.code).unwrap(), Json(error)).into_response() + } BuilderApiError::AxumError(err) => { (StatusCode::BAD_REQUEST, err.to_string()).into_response() } @@ -142,15 +162,21 @@ pub trait BuilderApi { #[async_trait::async_trait] /// Implements the constraints API as defines in pub trait ConstraintsApi: BuilderApi { - /// Implements: + /// Implements: async fn submit_constraints( &self, constraints: &BatchedSignedConstraints, ) -> Result<(), BuilderApiError>; - /// Implements: + /// Implements: async fn get_header_with_proofs( &self, params: GetHeaderParams, ) -> Result, BuilderApiError>; + + /// Implements: + async fn delegate(&self, signed_data: SignedDelegation) -> Result<(), BuilderApiError>; + + /// Implements: + async fn revoke(&self, signed_data: SignedRevocation) -> Result<(), BuilderApiError>; } diff --git a/bolt-sidecar/src/client/mevboost.rs b/bolt-sidecar/src/client/mevboost.rs index ae7ce070e..64bcc1ff2 100644 --- a/bolt-sidecar/src/client/mevboost.rs +++ b/bolt-sidecar/src/client/mevboost.rs @@ -14,21 +14,25 @@ use crate::{ api::{ builder::GetHeaderParams, spec::{ - BuilderApi, BuilderApiError, ConstraintsApi, ErrorResponse, CONSTRAINTS_PATH, - GET_PAYLOAD_PATH, REGISTER_VALIDATORS_PATH, STATUS_PATH, + BuilderApi, BuilderApiError, ConstraintsApi, ErrorResponse, DELEGATE_PATH, + GET_PAYLOAD_PATH, REGISTER_VALIDATORS_PATH, REVOKE_PATH, STATUS_PATH, + SUBMIT_CONSTRAINTS_PATH, }, }, - primitives::{BatchedSignedConstraints, GetPayloadResponse, SignedBuilderBid}, + primitives::{ + BatchedSignedConstraints, GetPayloadResponse, SignedBuilderBid, SignedDelegation, + SignedRevocation, + }, }; /// A client for interacting with the MEV-Boost API. #[derive(Debug, Clone)] -pub struct MevBoostClient { +pub struct ConstraintClient { url: Url, client: reqwest::Client, } -impl MevBoostClient { +impl ConstraintClient { /// Creates a new MEV-Boost client with the given URL. pub fn new>(url: U) -> Self { Self { @@ -46,7 +50,7 @@ impl MevBoostClient { } #[async_trait::async_trait] -impl BuilderApi for MevBoostClient { +impl BuilderApi for ConstraintClient { /// Implements: async fn status(&self) -> Result { Ok(self @@ -132,14 +136,14 @@ impl BuilderApi for MevBoostClient { } #[async_trait::async_trait] -impl ConstraintsApi for MevBoostClient { +impl ConstraintsApi for ConstraintClient { async fn submit_constraints( &self, constraints: &BatchedSignedConstraints, ) -> Result<(), BuilderApiError> { let response = self .client - .post(self.endpoint(CONSTRAINTS_PATH)) + .post(self.endpoint(SUBMIT_CONSTRAINTS_PATH)) .header("content-type", "application/json") .body(serde_json::to_vec(&constraints)?) .send() @@ -185,17 +189,51 @@ impl ConstraintsApi for MevBoostClient { Ok(header) } + + async fn delegate(&self, signed_data: SignedDelegation) -> Result<(), BuilderApiError> { + let response = self + .client + .post(self.endpoint(DELEGATE_PATH)) + .header("content-type", "application/json") + .body(serde_json::to_string(&signed_data)?) + .send() + .await?; + + if response.status() != StatusCode::OK { + let error = response.json::().await?; + return Err(BuilderApiError::FailedDelegating(error)); + } + + Ok(()) + } + + async fn revoke(&self, signed_data: SignedRevocation) -> Result<(), BuilderApiError> { + let response = self + .client + .post(self.endpoint(REVOKE_PATH)) + .header("content-type", "application/json") + .body(serde_json::to_string(&signed_data)?) + .send() + .await?; + + if response.status() != StatusCode::OK { + let error = response.json::().await?; + return Err(BuilderApiError::FailedRevoking(error)); + } + + Ok(()) + } } #[cfg(test)] mod tests { use reqwest::Url; - use crate::MevBoostClient; + use crate::ConstraintClient; #[test] fn test_join_endpoints() { - let client = MevBoostClient::new(Url::parse("http://localhost:8080/").unwrap()); + let client = ConstraintClient::new(Url::parse("http://localhost:8080/").unwrap()); assert_eq!( client.endpoint("/eth/v1/builder/header/1/0x123/0x456"), Url::parse("http://localhost:8080/eth/v1/builder/header/1/0x123/0x456").unwrap() diff --git a/bolt-sidecar/src/client/test_util/mod.rs b/bolt-sidecar/src/client/test_util/mod.rs index 00215de52..a8d6f4dca 100644 --- a/bolt-sidecar/src/client/test_util/mod.rs +++ b/bolt-sidecar/src/client/test_util/mod.rs @@ -15,7 +15,10 @@ use tokio::sync::watch; use crate::{ api::{builder::GetHeaderParams, spec::BuilderApiError}, - primitives::{BatchedSignedConstraints, GetPayloadResponse, PayloadAndBlobs, SignedBuilderBid}, + primitives::{ + BatchedSignedConstraints, GetPayloadResponse, PayloadAndBlobs, SignedBuilderBid, + SignedDelegation, SignedRevocation, + }, BuilderApi, ConstraintsApi, }; @@ -92,6 +95,14 @@ impl ConstraintsApi for MockMevBoost { let bid = serde_json::from_value(response)?; Ok(bid) } + + async fn delegate(&self, signed_data: SignedDelegation) -> Result<(), BuilderApiError> { + unimplemented!() + } + + async fn revoke(&self, signed_data: SignedRevocation) -> Result<(), BuilderApiError> { + unimplemented!() + } } #[test] diff --git a/bolt-sidecar/src/driver.rs b/bolt-sidecar/src/driver.rs index 152e4a85c..b76689d55 100644 --- a/bolt-sidecar/src/driver.rs +++ b/bolt-sidecar/src/driver.rs @@ -29,7 +29,7 @@ use crate::{ }, start_builder_proxy_server, state::{fetcher::StateFetcher, ConsensusState, ExecutionState, HeadTracker, StateClient}, - BuilderProxyConfig, CommitBoostClient, Config, ConstraintsApi, LocalBuilder, MevBoostClient, + BuilderProxyConfig, CommitBoostClient, Config, ConstraintClient, ConstraintsApi, LocalBuilder, }; /// The driver for the sidecar, responsible for managing the main event loop. @@ -40,7 +40,7 @@ pub struct SidecarDriver { constraint_signer: BlsSignerType, commitment_signer: ECDSA, local_builder: LocalBuilder, - mevboost_client: MevBoostClient, + mevboost_client: ConstraintClient, api_events_rx: mpsc::Receiver, payload_requests_rx: mpsc::Receiver, /// Stream of slots made from the consensus clock @@ -97,7 +97,7 @@ impl SidecarDriver { commitment_signer: ECDSA, fetcher: C, ) -> eyre::Result { - let mevboost_client = MevBoostClient::new(cfg.mevboost_url.clone()); + let mevboost_client = ConstraintClient::new(cfg.mevboost_url.clone()); let beacon_client = BeaconClient::new(cfg.beacon_api_url.clone()); let execution = ExecutionState::new(fetcher, cfg.limits).await?; diff --git a/bolt-sidecar/src/lib.rs b/bolt-sidecar/src/lib.rs index d29030c7a..d2225d625 100644 --- a/bolt-sidecar/src/lib.rs +++ b/bolt-sidecar/src/lib.rs @@ -13,7 +13,7 @@ pub use api::{ mod client; pub use client::{ - commit_boost::CommitBoostClient, mevboost::MevBoostClient, rpc::RpcClient, BeaconClient, + commit_boost::CommitBoostClient, mevboost::ConstraintClient, rpc::RpcClient, BeaconClient, }; /// Common types and compatibility utilities diff --git a/bolt-sidecar/src/primitives/constraint.rs b/bolt-sidecar/src/primitives/constraint.rs index 644d83dc8..3c32854a9 100644 --- a/bolt-sidecar/src/primitives/constraint.rs +++ b/bolt-sidecar/src/primitives/constraint.rs @@ -48,6 +48,9 @@ pub struct ConstraintsMessage { pub validator_index: u64, /// The consensus slot at which the constraints are valid pub slot: u64, + /// Indicates whether these constraints are only valid on the top of the block. + /// NOTE: Per slot, only 1 top-of-block bundle is valid. + pub top: bool, /// The constraints that need to be signed. pub constraints: Vec, } @@ -58,7 +61,7 @@ impl ConstraintsMessage { let constraints = request.txs.into_iter().map(|tx| Constraint::from_transaction(tx, None)).collect(); - Self { validator_index, slot: request.slot, constraints } + Self { validator_index, slot: request.slot, top: false, constraints } } } diff --git a/bolt-sidecar/src/primitives/mod.rs b/bolt-sidecar/src/primitives/mod.rs index 990f3936f..c03c54d7f 100644 --- a/bolt-sidecar/src/primitives/mod.rs +++ b/bolt-sidecar/src/primitives/mod.rs @@ -18,7 +18,7 @@ use ethereum_consensus::{ Fork, }; use reth_primitives::{BlobTransactionSidecar, Bytes, PooledTransactionsElement, TxKind, TxType}; -use serde::de; +use serde::{de, Serialize}; use tokio::sync::{mpsc, oneshot}; pub use ethereum_consensus::crypto::{PublicKey as BlsPublicKey, Signature as BlsSignature}; @@ -392,3 +392,27 @@ impl<'de> serde::Deserialize<'de> for FullTransaction { #[derive(Debug, thiserror::Error)] #[error("Invalid signature")] pub struct SignatureError; + +#[derive(Debug, Clone, Serialize)] +pub struct SignedDelegation { + pub message: DelegationMessage, + pub signature: BlsSignature, +} + +#[derive(Debug, Clone, Serialize)] +pub struct DelegationMessage { + pub validator_index: u64, + pub pubkey: BlsPublicKey, +} + +#[derive(Debug, Clone, Serialize)] +pub struct SignedRevocation { + pub message: RevocationMessage, + pub signature: BlsSignature, +} + +#[derive(Debug, Clone, Serialize)] +pub struct RevocationMessage { + pub validator_index: u64, + pub pubkey: BlsPublicKey, +} From 876f984874519319a22c5bd6ba556651305f1883 Mon Sep 17 00:00:00 2001 From: Naman Garg <0708ng@gmail.com> Date: Thu, 5 Sep 2024 12:15:37 +0530 Subject: [PATCH 02/30] chore(sidecar): rename mevboost > constraint_client --- bolt-sidecar/src/api/builder.rs | 2 +- bolt-sidecar/src/client/{mevboost.rs => constraint_client.rs} | 0 bolt-sidecar/src/client/mod.rs | 2 +- bolt-sidecar/src/lib.rs | 3 ++- 4 files changed, 4 insertions(+), 3 deletions(-) rename bolt-sidecar/src/client/{mevboost.rs => constraint_client.rs} (100%) diff --git a/bolt-sidecar/src/api/builder.rs b/bolt-sidecar/src/api/builder.rs index 9164e86ed..505e38495 100644 --- a/bolt-sidecar/src/api/builder.rs +++ b/bolt-sidecar/src/api/builder.rs @@ -26,7 +26,7 @@ use super::spec::{ STATUS_PATH, }; use crate::{ - client::mevboost::ConstraintClient, + client::constraint_client::ConstraintClient, primitives::{GetPayloadResponse, PayloadFetcher, SignedBuilderBid}, }; diff --git a/bolt-sidecar/src/client/mevboost.rs b/bolt-sidecar/src/client/constraint_client.rs similarity index 100% rename from bolt-sidecar/src/client/mevboost.rs rename to bolt-sidecar/src/client/constraint_client.rs diff --git a/bolt-sidecar/src/client/mod.rs b/bolt-sidecar/src/client/mod.rs index 314286660..d8f3ec4be 100644 --- a/bolt-sidecar/src/client/mod.rs +++ b/bolt-sidecar/src/client/mod.rs @@ -1,5 +1,5 @@ pub mod commit_boost; -pub mod mevboost; +pub mod constraint_client; pub mod pubsub; pub mod rpc; diff --git a/bolt-sidecar/src/lib.rs b/bolt-sidecar/src/lib.rs index d2225d625..1015ac160 100644 --- a/bolt-sidecar/src/lib.rs +++ b/bolt-sidecar/src/lib.rs @@ -13,7 +13,8 @@ pub use api::{ mod client; pub use client::{ - commit_boost::CommitBoostClient, mevboost::ConstraintClient, rpc::RpcClient, BeaconClient, + commit_boost::CommitBoostClient, constraint_client::ConstraintClient, rpc::RpcClient, + BeaconClient, }; /// Common types and compatibility utilities From 2f0be88050465b4b95faf6cbd16b547ac6e9482a Mon Sep 17 00:00:00 2001 From: Naman Garg <0708ng@gmail.com> Date: Fri, 6 Sep 2024 12:17:04 +0530 Subject: [PATCH 03/30] chore(sidecar): digest > tree hash root --- bolt-sidecar/Cargo.lock | 24 +++++++++--------- bolt-sidecar/Cargo.toml | 4 +-- bolt-sidecar/src/api/spec.rs | 3 --- bolt-sidecar/src/crypto/bls.rs | 3 +++ bolt-sidecar/src/driver.rs | 3 ++- bolt-sidecar/src/primitives/constraint.rs | 31 +++++++++++++++++++++++ bolt-sidecar/src/state/execution.rs | 8 +++--- bolt-sidecar/src/test_util.rs | 4 +++ 8 files changed, 58 insertions(+), 22 deletions(-) diff --git a/bolt-sidecar/Cargo.lock b/bolt-sidecar/Cargo.lock index 5d2308f27..d1cd4db45 100644 --- a/bolt-sidecar/Cargo.lock +++ b/bolt-sidecar/Cargo.lock @@ -1608,8 +1608,8 @@ dependencies = [ [[package]] name = "cb-cli" -version = "0.0.1" -source = "git+https://github.com/Commit-Boost/commit-boost-client#f1e6ff199f9f71b45cc3c138976716e1b9b17f7c" +version = "0.1.0" +source = "git+https://github.com/Commit-Boost/commit-boost-client?rev=45ce8f1#45ce8f1b8febd778c7a8a1fd7651b6e39afa8478" dependencies = [ "cb-common", "clap", @@ -1624,8 +1624,8 @@ dependencies = [ [[package]] name = "cb-common" -version = "0.0.1" -source = "git+https://github.com/Commit-Boost/commit-boost-client#f1e6ff199f9f71b45cc3c138976716e1b9b17f7c" +version = "0.1.0" +source = "git+https://github.com/Commit-Boost/commit-boost-client?rev=45ce8f1#45ce8f1b8febd778c7a8a1fd7651b6e39afa8478" dependencies = [ "alloy", "axum", @@ -1657,8 +1657,8 @@ dependencies = [ [[package]] name = "cb-metrics" -version = "0.0.1" -source = "git+https://github.com/Commit-Boost/commit-boost-client#f1e6ff199f9f71b45cc3c138976716e1b9b17f7c" +version = "0.1.0" +source = "git+https://github.com/Commit-Boost/commit-boost-client?rev=45ce8f1#45ce8f1b8febd778c7a8a1fd7651b6e39afa8478" dependencies = [ "axum", "cb-common", @@ -1671,8 +1671,8 @@ dependencies = [ [[package]] name = "cb-pbs" -version = "0.0.1" -source = "git+https://github.com/Commit-Boost/commit-boost-client#f1e6ff199f9f71b45cc3c138976716e1b9b17f7c" +version = "0.1.0" +source = "git+https://github.com/Commit-Boost/commit-boost-client?rev=45ce8f1#45ce8f1b8febd778c7a8a1fd7651b6e39afa8478" dependencies = [ "alloy", "async-trait", @@ -1696,8 +1696,8 @@ dependencies = [ [[package]] name = "cb-signer" -version = "0.0.1" -source = "git+https://github.com/Commit-Boost/commit-boost-client#f1e6ff199f9f71b45cc3c138976716e1b9b17f7c" +version = "0.1.0" +source = "git+https://github.com/Commit-Boost/commit-boost-client?rev=45ce8f1#45ce8f1b8febd778c7a8a1fd7651b6e39afa8478" dependencies = [ "alloy", "axum", @@ -1877,8 +1877,8 @@ dependencies = [ [[package]] name = "commit-boost" -version = "0.0.1" -source = "git+https://github.com/Commit-Boost/commit-boost-client#f1e6ff199f9f71b45cc3c138976716e1b9b17f7c" +version = "0.1.0" +source = "git+https://github.com/Commit-Boost/commit-boost-client?rev=45ce8f1#45ce8f1b8febd778c7a8a1fd7651b6e39afa8478" dependencies = [ "cb-cli", "cb-common", diff --git a/bolt-sidecar/Cargo.toml b/bolt-sidecar/Cargo.toml index 9eefb55ab..ea0162e0c 100644 --- a/bolt-sidecar/Cargo.toml +++ b/bolt-sidecar/Cargo.toml @@ -69,8 +69,8 @@ metrics-exporter-prometheus = { version = "0.15.3", features = [ ] } # commit-boost -commit-boost = { git = "https://github.com/Commit-Boost/commit-boost-client" } -cb-common = { git = "https://github.com/Commit-Boost/commit-boost-client" } +commit-boost = { git = "https://github.com/Commit-Boost/commit-boost-client", rev = "45ce8f1"} +cb-common = { git = "https://github.com/Commit-Boost/commit-boost-client", rev = "45ce8f1" } [dev-dependencies] alloy-node-bindings = "0.2.0" diff --git a/bolt-sidecar/src/api/spec.rs b/bolt-sidecar/src/api/spec.rs index ede8b0eca..64cd0a035 100644 --- a/bolt-sidecar/src/api/spec.rs +++ b/bolt-sidecar/src/api/spec.rs @@ -30,9 +30,6 @@ pub const SUBMIT_CONSTRAINTS_PATH: &str = "/constraints/v1/builder/constraints"; pub const DELEGATE_PATH: &str = "/constraints/v1/builder/delegate"; /// The path to the constraints API revoke endpoint. pub const REVOKE_PATH: &str = "/constraints/v1/builder/revoke"; -/// The path to the constraints API get header with proofs endpoint. -pub const GET_HEADER_WITH_PROOFS_PATH: &str = - "/eth/v1/builder/header_with_proofs/:slot/:parent_hash/:pubkey"; /// A response object for errors. #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/bolt-sidecar/src/crypto/bls.rs b/bolt-sidecar/src/crypto/bls.rs index 6c800defd..051459787 100644 --- a/bolt-sidecar/src/crypto/bls.rs +++ b/bolt-sidecar/src/crypto/bls.rs @@ -20,6 +20,9 @@ pub trait SignableBLS { /// This API doesn't enforce a specific hash or encoding method. fn digest(&self) -> [u8; 32]; + /// Creates SSZ tree hash root of the object. + fn tree_hash_root(&self) -> [u8; 32]; + /// Sign the object with the given key. Returns the signature. /// /// Note: The default implementation should be used where possible. diff --git a/bolt-sidecar/src/driver.rs b/bolt-sidecar/src/driver.rs index f3f1b9b38..ca4db897d 100644 --- a/bolt-sidecar/src/driver.rs +++ b/bolt-sidecar/src/driver.rs @@ -221,7 +221,8 @@ impl SidecarDriver SignedConstraints { message, signature }, Err(err) => { error!(?err, "Failed to sign constraints"); diff --git a/bolt-sidecar/src/primitives/constraint.rs b/bolt-sidecar/src/primitives/constraint.rs index 3cbeed4db..8ff1c8d3d 100644 --- a/bolt-sidecar/src/primitives/constraint.rs +++ b/bolt-sidecar/src/primitives/constraint.rs @@ -1,6 +1,8 @@ use alloy::primitives::{keccak256, Address}; +use cb_common::pbs::{DenebSpec, EthSpec, Transaction}; use secp256k1::Message; use serde::Serialize; +use tree_hash::{MerkleHasher, TreeHash}; use crate::crypto::{bls::BLSSig, ecdsa::SignableECDSA, SignableBLS}; @@ -63,6 +65,11 @@ impl ConstraintsMessage { Self { validator_index, slot: request.slot, top: false, constraints } } + + /// Returns the total number of leaves in the tree. + fn total_leaves(&self) -> usize { + 4 + self.constraints.len() + } } impl SignableBLS for ConstraintsMessage { @@ -80,6 +87,30 @@ impl SignableBLS for ConstraintsMessage { // Compute the Keccak-256 hash and return the 32-byte array directly keccak256(data).0 } + + fn tree_hash_root(&self) -> [u8; 32] { + let mut hasher = MerkleHasher::with_leaves(self.total_leaves()); + + hasher + .write(&self.validator_index.to_le_bytes()) + .expect("Should write validator index bytes"); + hasher.write(&self.slot.to_le_bytes()).expect("Should write slot bytes"); + hasher.write(&(self.top as u8).to_le_bytes()).expect("Should write top flag"); + + for constraint in &self.constraints { + hasher + .write( + Transaction::<::MaxBytesPerTransaction>::from( + constraint.transaction.envelope_encoded().to_vec(), + ) + .tree_hash_root() + .as_bytes(), + ) + .expect("Should write transaction root"); + } + + hasher.finish().unwrap().0 + } } /// A general constraint on block building. diff --git a/bolt-sidecar/src/state/execution.rs b/bolt-sidecar/src/state/execution.rs index 3a5cabe2f..8906f671a 100644 --- a/bolt-sidecar/src/state/execution.rs +++ b/bolt-sidecar/src/state/execution.rs @@ -724,7 +724,7 @@ mod tests { assert!(state.validate_request(&mut request).await.is_ok()); let message = ConstraintsMessage::build(0, request.as_inclusion_request().unwrap().clone()); - let signature = signer.sign(&message.digest()).await?; + let signature = signer.sign(&message.tree_hash_root()).await?; let signed_constraints = SignedConstraints { message, signature }; state.add_constraint(10, signed_constraints); @@ -839,7 +839,7 @@ mod tests { let bls_signer = Signer::random(); let message = ConstraintsMessage::build(0, inclusion_request); - let signature = bls_signer.sign(&message.digest()).await.unwrap(); + let signature = bls_signer.sign(&message.tree_hash_root()).await.unwrap(); let signed_constraints = SignedConstraints { message, signature }; state.add_constraint(target_slot, signed_constraints); @@ -887,7 +887,7 @@ mod tests { let bls_signer = Signer::random(); let message = ConstraintsMessage::build(0, inclusion_request); - let signature = bls_signer.sign(&message.digest()).await.unwrap(); + let signature = bls_signer.sign(&message.tree_hash_root()).await.unwrap(); let signed_constraints = SignedConstraints { message, signature }; state.add_constraint(target_slot, signed_constraints); @@ -933,7 +933,7 @@ mod tests { let bls_signer = Signer::random(); let message = ConstraintsMessage::build(0, inclusion_request); - let signature = bls_signer.sign(&message.digest()).await.unwrap(); + let signature = bls_signer.sign(&message.tree_hash_root()).await.unwrap(); let signed_constraints = SignedConstraints { message, signature }; state.add_constraint(target_slot, signed_constraints); diff --git a/bolt-sidecar/src/test_util.rs b/bolt-sidecar/src/test_util.rs index c03bad87e..f5b69ab94 100644 --- a/bolt-sidecar/src/test_util.rs +++ b/bolt-sidecar/src/test_util.rs @@ -125,6 +125,10 @@ impl SignableBLS for TestSignableData { fn digest(&self) -> [u8; 32] { self.data } + + fn tree_hash_root(&self) -> [u8; 32] { + self.data + } } impl SignableECDSA for TestSignableData { From b6306e683f15d0c8d1551dce4f5537d1404a4f13 Mon Sep 17 00:00:00 2001 From: Naman Garg <0708ng@gmail.com> Date: Fri, 6 Sep 2024 12:29:22 +0530 Subject: [PATCH 04/30] chore(sidecar): update mock mev-boost --- bolt-sidecar/src/client/constraint_client.rs | 2 +- bolt-sidecar/src/client/test_util/mod.rs | 22 ++++++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/bolt-sidecar/src/client/constraint_client.rs b/bolt-sidecar/src/client/constraint_client.rs index 64bcc1ff2..250d73297 100644 --- a/bolt-sidecar/src/client/constraint_client.rs +++ b/bolt-sidecar/src/client/constraint_client.rs @@ -33,7 +33,7 @@ pub struct ConstraintClient { } impl ConstraintClient { - /// Creates a new MEV-Boost client with the given URL. + /// Creates a new constraint client with the given URL. pub fn new>(url: U) -> Self { Self { url: url.into(), diff --git a/bolt-sidecar/src/client/test_util/mod.rs b/bolt-sidecar/src/client/test_util/mod.rs index a8d6f4dca..cb1014d2a 100644 --- a/bolt-sidecar/src/client/test_util/mod.rs +++ b/bolt-sidecar/src/client/test_util/mod.rs @@ -31,11 +31,11 @@ pub fn make_get_payload_response() -> GetPayloadResponse { GetPayloadResponse::Deneb(PayloadAndBlobs { execution_payload, blobs_bundle }) } -pub struct MockMevBoost { +pub struct MockConstraintClient { pub response_rx: watch::Receiver, } -impl MockMevBoost { +impl MockConstraintClient { pub fn new() -> (Self, watch::Sender) { let (response_tx, response_rx) = watch::channel(Value::Null); (Self { response_rx }, response_tx) @@ -43,9 +43,11 @@ impl MockMevBoost { } #[async_trait::async_trait] -impl BuilderApi for MockMevBoost { +impl BuilderApi for MockConstraintClient { async fn status(&self) -> Result { - Err(BuilderApiError::Generic("MockMevBoost does not support getting status".to_string())) + Err(BuilderApiError::Generic( + "MockConstraintClient does not support getting status".to_string(), + )) } async fn register_validators( @@ -53,7 +55,7 @@ impl BuilderApi for MockMevBoost { _registrations: Vec, ) -> Result<(), BuilderApiError> { Err(BuilderApiError::Generic( - "MockMevBoost does not support registering validators".to_string(), + "MockConstraintClient does not support registering validators".to_string(), )) } @@ -77,13 +79,13 @@ impl BuilderApi for MockMevBoost { } #[async_trait::async_trait] -impl ConstraintsApi for MockMevBoost { +impl ConstraintsApi for MockConstraintClient { async fn submit_constraints( &self, _constraints: &BatchedSignedConstraints, ) -> Result<(), BuilderApiError> { Err(BuilderApiError::Generic( - "MockMevBoost does not support submitting constraints".to_string(), + "MockConstraintClient does not support submitting constraints".to_string(), )) } @@ -97,11 +99,13 @@ impl ConstraintsApi for MockMevBoost { } async fn delegate(&self, signed_data: SignedDelegation) -> Result<(), BuilderApiError> { - unimplemented!() + Err(BuilderApiError::Generic( + "MockConstraintClient does not support delegating".to_string(), + )) } async fn revoke(&self, signed_data: SignedRevocation) -> Result<(), BuilderApiError> { - unimplemented!() + Err(BuilderApiError::Generic("MockConstraintClient does not support revoking".to_string())) } } From be11e3fb4c40368e10cf0a5061349bd2ff21a63a Mon Sep 17 00:00:00 2001 From: Naman Garg <0708ng@gmail.com> Date: Fri, 6 Sep 2024 13:57:25 +0530 Subject: [PATCH 05/30] chore(sidecar): rename to constraints client, remove digest --- bolt-sidecar/.env.example | 4 ++-- bolt-sidecar/src/api/builder.rs | 8 +++---- ...traint_client.rs => constraints_client.rs} | 12 +++++----- bolt-sidecar/src/client/mod.rs | 2 +- bolt-sidecar/src/client/test_util/mod.rs | 18 +++++++------- bolt-sidecar/src/config/mod.rs | 24 +++++++++---------- bolt-sidecar/src/crypto/bls.rs | 10 +++----- bolt-sidecar/src/driver.rs | 20 ++++++++-------- bolt-sidecar/src/lib.rs | 2 +- bolt-sidecar/src/primitives/constraint.rs | 15 ------------ bolt-sidecar/src/test_util.rs | 4 ---- 11 files changed, 48 insertions(+), 71 deletions(-) rename bolt-sidecar/src/client/{constraint_client.rs => constraints_client.rs} (96%) diff --git a/bolt-sidecar/.env.example b/bolt-sidecar/.env.example index 469134da5..a7ed8591c 100644 --- a/bolt-sidecar/.env.example +++ b/bolt-sidecar/.env.example @@ -3,12 +3,12 @@ BOLT_SIDECAR_EXECUTION_API_URL=http://localhost:4485 BOLT_SIDECAR_BEACON_API_URL=http://localhost:4400 BOLT_SIDECAR_ENGINE_API_URL=http://localhost:4451 -BOLT_SIDECAR_MEVBOOST_URL=http://localhost:19550 +BOLT_SIDECAR_CONSTRAINTS_URL=http://localhost:19550 BOLT_SIDECAR_CB_SIGNER_URL=http://localhost:19551 # server ports BOLT_SIDECAR_PORT=8000 -BOLT_SIDECAR_MEVBOOST_PROXY_PORT=18551 +BOLT_SIDECAR_CONSTRAINTS_PROXY_PORT=18551 # commitment limits BOLT_SIDECAR_MAX_COMMITMENTS=128 diff --git a/bolt-sidecar/src/api/builder.rs b/bolt-sidecar/src/api/builder.rs index 56c75b0f0..faf701e5c 100644 --- a/bolt-sidecar/src/api/builder.rs +++ b/bolt-sidecar/src/api/builder.rs @@ -26,7 +26,7 @@ use super::spec::{ STATUS_PATH, }; use crate::{ - client::constraint_client::ConstraintClient, + client::constraints_client::ConstraintsClient, primitives::{GetPayloadResponse, PayloadFetcher, SignedBuilderBid}, telemetry::ApiMetrics, }; @@ -218,7 +218,7 @@ where #[derive(Debug, Clone)] pub struct BuilderProxyConfig { /// The URL of the target mev-boost server. - pub mevboost_url: Url, + pub constraints_url: Url, /// The port on which the builder proxy should listen. pub server_port: u16, } @@ -233,11 +233,11 @@ where { info!( port = config.server_port, - target = config.mevboost_url.to_string(), + target = config.constraints_url.to_string(), "Starting builder proxy..." ); - let mev_boost = ConstraintClient::new(config.mevboost_url); + let mev_boost = ConstraintsClient::new(config.constraints_url); let server = Arc::new(BuilderProxyServer::new(mev_boost, payload_fetcher)); let router = Router::new() diff --git a/bolt-sidecar/src/client/constraint_client.rs b/bolt-sidecar/src/client/constraints_client.rs similarity index 96% rename from bolt-sidecar/src/client/constraint_client.rs rename to bolt-sidecar/src/client/constraints_client.rs index 250d73297..322bb8da4 100644 --- a/bolt-sidecar/src/client/constraint_client.rs +++ b/bolt-sidecar/src/client/constraints_client.rs @@ -27,12 +27,12 @@ use crate::{ /// A client for interacting with the MEV-Boost API. #[derive(Debug, Clone)] -pub struct ConstraintClient { +pub struct ConstraintsClient { url: Url, client: reqwest::Client, } -impl ConstraintClient { +impl ConstraintsClient { /// Creates a new constraint client with the given URL. pub fn new>(url: U) -> Self { Self { @@ -50,7 +50,7 @@ impl ConstraintClient { } #[async_trait::async_trait] -impl BuilderApi for ConstraintClient { +impl BuilderApi for ConstraintsClient { /// Implements: async fn status(&self) -> Result { Ok(self @@ -136,7 +136,7 @@ impl BuilderApi for ConstraintClient { } #[async_trait::async_trait] -impl ConstraintsApi for ConstraintClient { +impl ConstraintsApi for ConstraintsClient { async fn submit_constraints( &self, constraints: &BatchedSignedConstraints, @@ -229,11 +229,11 @@ impl ConstraintsApi for ConstraintClient { mod tests { use reqwest::Url; - use crate::ConstraintClient; + use crate::ConstraintsClient; #[test] fn test_join_endpoints() { - let client = ConstraintClient::new(Url::parse("http://localhost:8080/").unwrap()); + let client = ConstraintsClient::new(Url::parse("http://localhost:8080/").unwrap()); assert_eq!( client.endpoint("/eth/v1/builder/header/1/0x123/0x456"), Url::parse("http://localhost:8080/eth/v1/builder/header/1/0x123/0x456").unwrap() diff --git a/bolt-sidecar/src/client/mod.rs b/bolt-sidecar/src/client/mod.rs index d8f3ec4be..2235dbe09 100644 --- a/bolt-sidecar/src/client/mod.rs +++ b/bolt-sidecar/src/client/mod.rs @@ -1,5 +1,5 @@ pub mod commit_boost; -pub mod constraint_client; +pub mod constraints_client; pub mod pubsub; pub mod rpc; diff --git a/bolt-sidecar/src/client/test_util/mod.rs b/bolt-sidecar/src/client/test_util/mod.rs index cb1014d2a..0806e45ef 100644 --- a/bolt-sidecar/src/client/test_util/mod.rs +++ b/bolt-sidecar/src/client/test_util/mod.rs @@ -31,11 +31,11 @@ pub fn make_get_payload_response() -> GetPayloadResponse { GetPayloadResponse::Deneb(PayloadAndBlobs { execution_payload, blobs_bundle }) } -pub struct MockConstraintClient { +pub struct MockConstraintsClient { pub response_rx: watch::Receiver, } -impl MockConstraintClient { +impl MockConstraintsClient { pub fn new() -> (Self, watch::Sender) { let (response_tx, response_rx) = watch::channel(Value::Null); (Self { response_rx }, response_tx) @@ -43,10 +43,10 @@ impl MockConstraintClient { } #[async_trait::async_trait] -impl BuilderApi for MockConstraintClient { +impl BuilderApi for MockConstraintsClient { async fn status(&self) -> Result { Err(BuilderApiError::Generic( - "MockConstraintClient does not support getting status".to_string(), + "MockConstraintsClient does not support getting status".to_string(), )) } @@ -55,7 +55,7 @@ impl BuilderApi for MockConstraintClient { _registrations: Vec, ) -> Result<(), BuilderApiError> { Err(BuilderApiError::Generic( - "MockConstraintClient does not support registering validators".to_string(), + "MockConstraintsClient does not support registering validators".to_string(), )) } @@ -79,13 +79,13 @@ impl BuilderApi for MockConstraintClient { } #[async_trait::async_trait] -impl ConstraintsApi for MockConstraintClient { +impl ConstraintsApi for MockConstraintsClient { async fn submit_constraints( &self, _constraints: &BatchedSignedConstraints, ) -> Result<(), BuilderApiError> { Err(BuilderApiError::Generic( - "MockConstraintClient does not support submitting constraints".to_string(), + "MockConstraintsClient does not support submitting constraints".to_string(), )) } @@ -100,12 +100,12 @@ impl ConstraintsApi for MockConstraintClient { async fn delegate(&self, signed_data: SignedDelegation) -> Result<(), BuilderApiError> { Err(BuilderApiError::Generic( - "MockConstraintClient does not support delegating".to_string(), + "MockConstraintsClient does not support delegating".to_string(), )) } async fn revoke(&self, signed_data: SignedRevocation) -> Result<(), BuilderApiError> { - Err(BuilderApiError::Generic("MockConstraintClient does not support revoking".to_string())) + Err(BuilderApiError::Generic("MockConstraintsClient does not support revoking".to_string())) } } diff --git a/bolt-sidecar/src/config/mod.rs b/bolt-sidecar/src/config/mod.rs index 68953f4b2..33b0dcd54 100644 --- a/bolt-sidecar/src/config/mod.rs +++ b/bolt-sidecar/src/config/mod.rs @@ -38,8 +38,8 @@ pub struct Opts { #[clap(long, env = "BOLT_SIDECAR_BEACON_API_URL")] pub(super) beacon_api_url: String, /// URL for the MEV-Boost sidecar client to use - #[clap(long, env = "BOLT_SIDECAR_MEVBOOST_URL")] - pub(super) mevboost_url: String, + #[clap(long, env = "BOLT_SIDECAR_CONSTRAINTS_URL")] + pub(super) constraints_url: String, /// Execution client API URL #[clap(long, env = "BOLT_SIDECAR_EXECUTION_API_URL")] pub(super) execution_api_url: String, @@ -47,8 +47,8 @@ pub struct Opts { #[clap(long, env = "BOLT_SIDECAR_ENGINE_API_URL")] pub(super) engine_api_url: String, /// MEV-Boost proxy server port to use - #[clap(long, env = "BOLT_SIDECAR_MEVBOOST_PROXY_PORT")] - pub(super) mevboost_proxy_port: u16, + #[clap(long, env = "BOLT_SIDECAR_CONSTRAINTS_PROXY_PORT")] + pub(super) constraints_proxy_port: u16, /// Max number of commitments to accept per block #[clap(long, env = "BOLT_SIDECAR_MAX_COMMITMENTS")] pub(super) max_commitments: Option>, @@ -92,10 +92,10 @@ pub struct Opts { pub struct Config { /// Port to listen on for incoming JSON-RPC requests pub rpc_port: u16, - /// The MEV-Boost proxy server port to listen on - pub mevboost_proxy_port: u16, - /// URL for the MEV-Boost sidecar client to use - pub mevboost_url: Url, + /// The Constraints client proxy server port to listen on + pub constraints_proxy_port: u16, + /// URL for the Constraints sidecar client to use + pub constraints_url: Url, /// URL for the beacon client API URL pub beacon_api_url: Url, /// The execution API url @@ -132,10 +132,10 @@ impl Default for Config { fn default() -> Self { Self { rpc_port: DEFAULT_RPC_PORT, - mevboost_proxy_port: DEFAULT_MEV_BOOST_PROXY_PORT, + constraints_proxy_port: DEFAULT_MEV_BOOST_PROXY_PORT, commit_boost_address: None, commit_boost_jwt_hex: None, - mevboost_url: "http://localhost:3030".parse().expect("Valid URL"), + constraints_url: "http://localhost:3030".parse().expect("Valid URL"), beacon_api_url: "http://localhost:5052".parse().expect("Valid URL"), execution_api_url: "http://localhost:8545".parse().expect("Valid URL"), engine_api_url: "http://localhost:8551".parse().expect("Valid URL"), @@ -237,11 +237,11 @@ impl TryFrom for Config { info!("Engine JWT secret loaded successfully"); } - config.mevboost_proxy_port = opts.mevboost_proxy_port; + config.constraints_proxy_port = opts.constraints_proxy_port; config.engine_api_url = opts.engine_api_url.parse()?; config.execution_api_url = opts.execution_api_url.parse()?; config.beacon_api_url = opts.beacon_api_url.parse()?; - config.mevboost_url = opts.mevboost_url.parse()?; + config.constraints_url = opts.constraints_url.parse()?; config.fee_recipient = opts.fee_recipient; diff --git a/bolt-sidecar/src/crypto/bls.rs b/bolt-sidecar/src/crypto/bls.rs index 051459787..98b993310 100644 --- a/bolt-sidecar/src/crypto/bls.rs +++ b/bolt-sidecar/src/crypto/bls.rs @@ -16,10 +16,6 @@ pub type BLSSig = FixedBytes<96>; /// Trait for any types that can be signed and verified with BLS. /// This trait is used to abstract over the signing and verification of different types. pub trait SignableBLS { - /// Create a digest of the object that can be signed. - /// This API doesn't enforce a specific hash or encoding method. - fn digest(&self) -> [u8; 32]; - /// Creates SSZ tree hash root of the object. fn tree_hash_root(&self) -> [u8; 32]; @@ -28,14 +24,14 @@ pub trait SignableBLS { /// Note: The default implementation should be used where possible. #[allow(dead_code)] fn sign(&self, key: &BlsSecretKey) -> Signature { - sign_with_prefix(key, &self.digest()) + sign_with_prefix(key, &self.tree_hash_root()) } /// Verify the signature of the object with the given public key. /// /// Note: The default implementation should be used where possible. fn verify(&self, signature: &Signature, pubkey: &BlsPublicKey) -> bool { - signature.verify(false, &self.digest(), BLS_DST_PREFIX, &[], pubkey, true) == + signature.verify(false, &self.tree_hash_root(), BLS_DST_PREFIX, &[], pubkey, true) == BLST_ERROR::BLST_SUCCESS } } @@ -124,7 +120,7 @@ mod tests { rng.fill(&mut data); let msg = TestSignableData { data }; - let signature = SignerBLS::sign(&signer, &msg.digest()).await.unwrap(); + let signature = SignerBLS::sign(&signer, &msg.tree_hash_root()).await.unwrap(); let sig = blst::min_pk::Signature::from_bytes(signature.as_ref()).unwrap(); assert!(signer.verify(&msg, &sig, &pubkey)); } diff --git a/bolt-sidecar/src/driver.rs b/bolt-sidecar/src/driver.rs index ca4db897d..8db4a191c 100644 --- a/bolt-sidecar/src/driver.rs +++ b/bolt-sidecar/src/driver.rs @@ -24,7 +24,7 @@ use crate::{ start_builder_proxy_server, state::{fetcher::StateFetcher, ConsensusState, ExecutionState, HeadTracker, StateClient}, telemetry::ApiMetrics, - BuilderProxyConfig, CommitBoostSigner, Config, ConstraintClient, ConstraintsApi, LocalBuilder, + BuilderProxyConfig, CommitBoostSigner, Config, ConstraintsApi, ConstraintsClient, LocalBuilder, }; /// The driver for the sidecar, responsible for managing the main event loop. @@ -35,7 +35,7 @@ pub struct SidecarDriver { constraint_signer: BLS, commitment_signer: ECDSA, local_builder: LocalBuilder, - mevboost_client: ConstraintClient, + constraints_client: ConstraintsClient, api_events_rx: mpsc::Receiver, payload_requests_rx: mpsc::Receiver, /// Stream of slots made from the consensus clock @@ -51,7 +51,7 @@ impl fmt::Debug for SidecarDriver SidecarDriver eyre::Result { - let mevboost_client = ConstraintClient::new(cfg.mevboost_url.clone()); + let constraints_client = ConstraintsClient::new(cfg.constraints_url.clone()); let beacon_client = BeaconClient::new(cfg.beacon_api_url.clone()); let execution = ExecutionState::new(fetcher, cfg.limits).await?; @@ -125,8 +125,8 @@ impl SidecarDriver SidecarDriver SidecarDriver [u8; 32] { - let mut data = Vec::new(); - data.extend_from_slice(&self.validator_index.to_le_bytes()); - data.extend_from_slice(&self.slot.to_le_bytes()); - - let mut constraint_bytes = Vec::new(); - for constraint in &self.constraints { - constraint_bytes.extend_from_slice(&constraint.as_bytes()); - } - data.extend_from_slice(&constraint_bytes); - - // Compute the Keccak-256 hash and return the 32-byte array directly - keccak256(data).0 - } - fn tree_hash_root(&self) -> [u8; 32] { let mut hasher = MerkleHasher::with_leaves(self.total_leaves()); diff --git a/bolt-sidecar/src/test_util.rs b/bolt-sidecar/src/test_util.rs index f5b69ab94..d414b8a4c 100644 --- a/bolt-sidecar/src/test_util.rs +++ b/bolt-sidecar/src/test_util.rs @@ -122,10 +122,6 @@ pub(crate) struct TestSignableData { } impl SignableBLS for TestSignableData { - fn digest(&self) -> [u8; 32] { - self.data - } - fn tree_hash_root(&self) -> [u8; 32] { self.data } From a5765e8c3483fd8387bf9a3f580d8b9fb61a2b29 Mon Sep 17 00:00:00 2001 From: Naman Garg <0708ng@gmail.com> Date: Fri, 6 Sep 2024 16:59:55 +0530 Subject: [PATCH 06/30] test(sidecar): add hash tree root test --- bolt-sidecar/src/primitives/constraint.rs | 52 +++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/bolt-sidecar/src/primitives/constraint.rs b/bolt-sidecar/src/primitives/constraint.rs index 08516926f..3fc4a692d 100644 --- a/bolt-sidecar/src/primitives/constraint.rs +++ b/bolt-sidecar/src/primitives/constraint.rs @@ -129,3 +129,55 @@ impl Constraint { self.transaction.sender().expect("Recovered sender") } } + +#[cfg(test)] +mod tests { + use super::*; + use rand::{rngs::ThreadRng, Rng}; + + fn random_u64(rng: &mut ThreadRng) -> u64 { + rng.gen_range(0..u64::MAX) + } + + fn random_constraints(rng: &mut ThreadRng, count: usize) -> Vec { + // Random inclusion request + let json_req = r#"{ + "slot": 10, + "txs": ["0x02f86c870c72dd9d5e883e4d0183408f2382520894d2e2adf7177b7a8afddbc12d1634cf23ea1a71020180c001a08556dcfea479b34675db3fe08e29486fe719c2b22f6b0c1741ecbbdce4575cc6a01cd48009ccafd6b9f1290bbe2ceea268f94101d1d322c787018423ebcbc87ab4"] + }"#; + + let req: InclusionRequest = serde_json::from_str(json_req).unwrap(); + + (0..count) + .map(|_| { + Constraint::from_transaction( + req.txs.first().unwrap().clone(), + Some(random_u64(rng)), + ) + }) + .collect() + } + + #[test] + fn test_tree_hash_root() { + let mut rng = rand::thread_rng(); + + // Generate random values for the `ConstraintsMessage` fields + let validator_index = random_u64(&mut rng); + let slot = random_u64(&mut rng); + let top = false; + let constraints = random_constraints(&mut rng, 10); // Generate 10 random constraints + + // Create a random `ConstraintsMessage` + let message = ConstraintsMessage { validator_index, slot, top, constraints }; + + // Compute tree hash root + let tree_root = message.tree_hash_root(); + + // Verify that the tree hash root is a valid 32-byte array + assert_eq!(tree_root.len(), 32, "Tree hash root should be 32 bytes long"); + + // Additional checks can be added here, depending on your specific requirements + println!("Computed tree hash root: {:?}", tree_root); + } +} From 49aae9c4ae46770be43f29304612d9594f468fbb Mon Sep 17 00:00:00 2001 From: Naman Garg <0708ng@gmail.com> Date: Sat, 7 Sep 2024 00:13:27 +0530 Subject: [PATCH 07/30] chore(sidecar): change constraints type to fulltransaction --- bolt-sidecar/src/builder/template.rs | 44 +++++----------- bolt-sidecar/src/driver.rs | 2 +- bolt-sidecar/src/primitives/constraint.rs | 61 +++++------------------ bolt-sidecar/src/primitives/mod.rs | 4 +- bolt-sidecar/src/state/execution.rs | 2 +- 5 files changed, 29 insertions(+), 84 deletions(-) diff --git a/bolt-sidecar/src/builder/template.rs b/bolt-sidecar/src/builder/template.rs index 4b396081b..8dc69e627 100644 --- a/bolt-sidecar/src/builder/template.rs +++ b/bolt-sidecar/src/builder/template.rs @@ -16,9 +16,7 @@ use tracing::warn; use crate::{ common::max_transaction_cost, - primitives::{ - constraint::Constraint, AccountState, FullTransaction, SignedConstraints, TransactionExt, - }, + primitives::{AccountState, FullTransaction, SignedConstraints, TransactionExt}, }; /// A block template that serves as a fallback block, but is also used @@ -47,10 +45,7 @@ impl BlockTemplate { /// Returns the cloned list of transactions from the constraints. #[inline] pub fn transactions(&self) -> Vec { - self.signed_constraints_list - .iter() - .flat_map(|sc| sc.message.constraints.iter().map(|c| c.transaction.clone())) - .collect() + self.signed_constraints_list.iter().flat_map(|sc| sc.message.constraints.clone()).collect() } /// Converts the list of signed constraints into a list of signed transactions. Use this when @@ -60,10 +55,7 @@ impl BlockTemplate { self.signed_constraints_list .iter() .flat_map(|sc| { - sc.message - .constraints - .iter() - .map(|c| c.transaction.clone().into_inner().into_transaction()) + sc.message.constraints.iter().map(|c| c.clone().into_inner().into_transaction()) }) .collect() } @@ -76,7 +68,7 @@ impl BlockTemplate { self.signed_constraints_list .iter() .flat_map(|sc| sc.message.constraints.iter()) - .filter_map(|c| c.transaction.blob_sidecar()) + .filter_map(|c| c.blob_sidecar()) .fold( (Vec::new(), Vec::new(), Vec::new()), |(mut commitments, mut proofs, mut blobs), bs| { @@ -108,7 +100,7 @@ impl BlockTemplate { #[inline] pub fn committed_gas(&self) -> u64 { self.signed_constraints_list.iter().fold(0, |acc, sc| { - acc + sc.message.constraints.iter().fold(0, |acc, c| acc + c.transaction.gas_limit()) + acc + sc.message.constraints.iter().fold(0, |acc, c| acc + c.gas_limit()) }) } @@ -117,11 +109,7 @@ impl BlockTemplate { pub fn blob_count(&self) -> usize { self.signed_constraints_list.iter().fold(0, |mut acc, sc| { acc += sc.message.constraints.iter().fold(0, |acc, c| { - acc + c - .transaction - .as_eip4844() - .map(|tx| tx.blob_versioned_hashes.len()) - .unwrap_or(0) + acc + c.as_eip4844().map(|tx| tx.blob_versioned_hashes.len()).unwrap_or(0) }); acc @@ -131,7 +119,7 @@ impl BlockTemplate { /// Adds a list of constraints to the block template and updates the state diff. pub fn add_constraints(&mut self, constraints: SignedConstraints) { for constraint in constraints.message.constraints.iter() { - let max_cost = max_transaction_cost(&constraint.transaction); + let max_cost = max_transaction_cost(&constraint); self.state_diff .diffs .entry(constraint.sender()) @@ -150,13 +138,10 @@ impl BlockTemplate { let constraints = self.signed_constraints_list.remove(index); for constraint in constraints.message.constraints.iter() { - self.state_diff - .diffs - .entry(constraint.transaction.sender().expect("Recovered sender")) - .and_modify(|(nonce, balance)| { - *nonce = nonce.saturating_sub(1); - *balance -= max_transaction_cost(&constraint.transaction); - }); + self.state_diff.diffs.entry(constraint.sender()).and_modify(|(nonce, balance)| { + *nonce = nonce.saturating_sub(1); + *balance -= max_transaction_cost(&constraint); + }); } } @@ -166,7 +151,7 @@ impl BlockTemplate { // The preconfirmations made by such address, and the indexes of the signed constraints // in which they appear - let constraints_with_address: Vec<(usize, Vec<&Constraint>)> = self + let constraints_with_address: Vec<(usize, Vec<&FullTransaction>)> = self .signed_constraints_list .iter() .enumerate() @@ -181,10 +166,7 @@ impl BlockTemplate { .iter() .flat_map(|c| c.1.clone()) .fold((U256::ZERO, u64::MAX), |(total_cost, min_nonce), c| { - ( - total_cost + max_transaction_cost(&c.transaction), - min_nonce.min(c.transaction.nonce()), - ) + (total_cost + max_transaction_cost(&c), min_nonce.min(c.nonce())) }); if state.balance < max_total_cost || state.transaction_count > min_nonce { diff --git a/bolt-sidecar/src/driver.rs b/bolt-sidecar/src/driver.rs index 8db4a191c..0492cf6c4 100644 --- a/bolt-sidecar/src/driver.rs +++ b/bolt-sidecar/src/driver.rs @@ -232,7 +232,7 @@ impl SidecarDriver, + pub constraints: Vec, } impl ConstraintsMessage { /// Builds a constraints message from an inclusion request and metadata pub fn build(validator_index: u64, request: InclusionRequest) -> Self { - let constraints = - request.txs.into_iter().map(|tx| Constraint::from_transaction(tx, None)).collect(); + let constraints = request.txs; Self { validator_index, slot: request.slot, top: false, constraints } } @@ -86,7 +85,7 @@ impl SignableBLS for ConstraintsMessage { hasher .write( Transaction::<::MaxBytesPerTransaction>::from( - constraint.transaction.envelope_encoded().to_vec(), + constraint.envelope_encoded().to_vec(), ) .tree_hash_root() .as_bytes(), @@ -98,48 +97,17 @@ impl SignableBLS for ConstraintsMessage { } } -/// A general constraint on block building. -/// -/// Reference: https://chainbound.github.io/bolt-docs/api/builder-api#ethv1builderconstraints -#[derive(Serialize, Debug, Clone, PartialEq)] -pub struct Constraint { - /// The optional index at which the transaction needs to be included in the block - pub index: Option, - /// The transaction to be included in the block, in hex format - #[serde(rename(serialize = "tx"))] - pub(crate) transaction: FullTransaction, -} - -impl Constraint { - /// Builds a constraint from a transaction, with an optional index - pub fn from_transaction(transaction: FullTransaction, index: Option) -> Self { - Self { transaction, index } - } - - /// Converts the constraint to a byte representation useful for signing - /// TODO: remove if we go with SSZ - pub fn as_bytes(&self) -> Vec { - let mut data = Vec::new(); - self.transaction.encode_enveloped(&mut data); - data.extend_from_slice(&self.index.unwrap_or(0).to_le_bytes()); - data - } - - pub fn sender(&self) -> Address { - self.transaction.sender().expect("Recovered sender") - } -} - #[cfg(test)] mod tests { use super::*; + use alloy::hex::ToHexExt; use rand::{rngs::ThreadRng, Rng}; fn random_u64(rng: &mut ThreadRng) -> u64 { rng.gen_range(0..u64::MAX) } - fn random_constraints(rng: &mut ThreadRng, count: usize) -> Vec { + fn random_constraints(count: usize) -> Vec { // Random inclusion request let json_req = r#"{ "slot": 10, @@ -148,14 +116,7 @@ mod tests { let req: InclusionRequest = serde_json::from_str(json_req).unwrap(); - (0..count) - .map(|_| { - Constraint::from_transaction( - req.txs.first().unwrap().clone(), - Some(random_u64(rng)), - ) - }) - .collect() + (0..count).map(|_| req.txs.first().unwrap().clone()).collect() } #[test] @@ -166,11 +127,13 @@ mod tests { let validator_index = random_u64(&mut rng); let slot = random_u64(&mut rng); let top = false; - let constraints = random_constraints(&mut rng, 10); // Generate 10 random constraints + let constraints = random_constraints(1); // Generate 10 random constraints // Create a random `ConstraintsMessage` let message = ConstraintsMessage { validator_index, slot, top, constraints }; + println!("Generated random constraints message: {:?}", message); + // Compute tree hash root let tree_root = message.tree_hash_root(); @@ -178,6 +141,6 @@ mod tests { assert_eq!(tree_root.len(), 32, "Tree hash root should be 32 bytes long"); // Additional checks can be added here, depending on your specific requirements - println!("Computed tree hash root: {:?}", tree_root); + println!("Computed tree hash root: {:?}", tree_root.encode_hex()); } } diff --git a/bolt-sidecar/src/primitives/mod.rs b/bolt-sidecar/src/primitives/mod.rs index 258c10168..0f0a86703 100644 --- a/bolt-sidecar/src/primitives/mod.rs +++ b/bolt-sidecar/src/primitives/mod.rs @@ -376,8 +376,8 @@ impl FullTransaction { } /// Returns the sender of the transaction, if recovered. - pub fn sender(&self) -> Option
{ - self.sender + pub fn sender(&self) -> Address { + self.sender.expect("Recovered sender") } } diff --git a/bolt-sidecar/src/state/execution.rs b/bolt-sidecar/src/state/execution.rs index 8906f671a..dd374f5c8 100644 --- a/bolt-sidecar/src/state/execution.rs +++ b/bolt-sidecar/src/state/execution.rs @@ -312,7 +312,7 @@ impl ExecutionState { let mut bundle_nonce_diff_map = HashMap::new(); let mut bundle_balance_diff_map = HashMap::new(); for tx in req.txs.iter() { - let sender = tx.sender().expect("Recovered sender"); + let sender = tx.sender(); // From previous preconfirmations requests retrieve // - the nonce difference from the account state. From 9b5bfe81dd19717eedda068df4404af0a0ff809b Mon Sep 17 00:00:00 2001 From: Naman Garg <0708ng@gmail.com> Date: Sat, 7 Sep 2024 00:19:21 +0530 Subject: [PATCH 08/30] misc(sidecar): comment --- bolt-sidecar/src/primitives/constraint.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bolt-sidecar/src/primitives/constraint.rs b/bolt-sidecar/src/primitives/constraint.rs index ee2baf4cc..7b30ed968 100644 --- a/bolt-sidecar/src/primitives/constraint.rs +++ b/bolt-sidecar/src/primitives/constraint.rs @@ -127,13 +127,11 @@ mod tests { let validator_index = random_u64(&mut rng); let slot = random_u64(&mut rng); let top = false; - let constraints = random_constraints(1); // Generate 10 random constraints + let constraints = random_constraints(1); // Generate 'n' random constraints // Create a random `ConstraintsMessage` let message = ConstraintsMessage { validator_index, slot, top, constraints }; - println!("Generated random constraints message: {:?}", message); - // Compute tree hash root let tree_root = message.tree_hash_root(); From d03e31596ea725db7879c6c38470040e1ffb10e1 Mon Sep 17 00:00:00 2001 From: Naman Garg <0708ng@gmail.com> Date: Sat, 7 Sep 2024 14:20:54 +0530 Subject: [PATCH 09/30] misc(sidecar): update doc link --- bolt-sidecar/src/primitives/constraint.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bolt-sidecar/src/primitives/constraint.rs b/bolt-sidecar/src/primitives/constraint.rs index 7b30ed968..adedb9bab 100644 --- a/bolt-sidecar/src/primitives/constraint.rs +++ b/bolt-sidecar/src/primitives/constraint.rs @@ -32,7 +32,7 @@ pub type BatchedSignedConstraints = Vec; /// A container for a list of constraints and the signature of the proposer sidecar. /// -/// Reference: https://chainbound.github.io/bolt-docs/api/builder-api#ethv1builderconstraints +/// Reference: https://chainbound.github.io/bolt-docs/api/builder#constraints #[derive(Serialize, Default, Debug, Clone, PartialEq)] pub struct SignedConstraints { /// The constraints that need to be signed. @@ -43,7 +43,7 @@ pub struct SignedConstraints { /// A message that contains the constraints that need to be signed by the proposer sidecar. /// -/// Reference: https://chainbound.github.io/bolt-docs/api/builder-api#ethv1builderconstraints +/// Reference: https://chainbound.github.io/bolt-docs/api/builder#constraints #[derive(Serialize, Debug, Clone, PartialEq, Default)] pub struct ConstraintsMessage { /// The validator index of the proposer sidecar. From 849c04c2261d95be4674424128ad52c2a14107bf Mon Sep 17 00:00:00 2001 From: Naman Garg <0708ng@gmail.com> Date: Mon, 9 Sep 2024 11:14:20 +0530 Subject: [PATCH 10/30] misc(sidecar): update comments mevboost > constraints client --- bolt-sidecar/README.md | 4 ++-- bolt-sidecar/src/api/builder.rs | 14 +++++++------- bolt-sidecar/src/builder/mod.rs | 2 +- bolt-sidecar/src/client/constraints_client.rs | 6 +++--- bolt-sidecar/src/config/mod.rs | 10 +++++----- bolt-sidecar/src/driver.rs | 6 +++--- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/bolt-sidecar/README.md b/bolt-sidecar/README.md index 1fa54f3ab..206dcdb73 100644 --- a/bolt-sidecar/README.md +++ b/bolt-sidecar/README.md @@ -11,7 +11,7 @@ The sidecar is responsible for: 3. Implementing pricing strategies 4. Building a block template & simulation 5. Communicating constraints to the downstream PBS pipeline -6. Verifying any incoming builder bids from mev-boost +6. Verifying any incoming builder bids from constraints client 7. Dealing with PBS failures by falling back to the local template ### Local Block Template @@ -38,4 +38,4 @@ in case a fallback block is required. ## Running -- We require Anvil to be installed in the $PATH for running tests +- We require Anvil to be installed in the $PATH for running tests diff --git a/bolt-sidecar/src/api/builder.rs b/bolt-sidecar/src/api/builder.rs index faf701e5c..d32e679d8 100644 --- a/bolt-sidecar/src/api/builder.rs +++ b/bolt-sidecar/src/api/builder.rs @@ -63,7 +63,7 @@ where Self { proxy_target, local_payload: Mutex::new(None), payload_fetcher } } - /// Gets the status. Just forwards the request to mev-boost and returns the status. + /// Gets the status. Just forwards the request to constraints client and returns the status. pub async fn status(State(server): State>>) -> StatusCode { let start = std::time::Instant::now(); debug!("Received status request"); @@ -71,7 +71,7 @@ where let status = match server.proxy_target.status().await { Ok(status) => status, Err(error) => { - error!(%error, "Failed to get status from mev-boost"); + error!(%error, "Failed to get status from constraints client"); StatusCode::INTERNAL_SERVER_ERROR } }; @@ -82,7 +82,7 @@ where status } - /// Registers the validators. Just forwards the request to mev-boost + /// Registers the validators. Just forwards the request to constraints client /// and returns the status. /// /// TODO: intercept this to register Bolt validators on-chain as well. @@ -96,7 +96,7 @@ where } /// Gets the header. NOTE: converts this request to a get_header_with_proofs - /// request to the modified mev-boost. + /// request to the modified constraints client. /// /// In case of a builder or relay failure, we return the locally built block header /// and store the actual payload so we can return it later. @@ -203,11 +203,11 @@ where .await .map(Json) .map_err(|e| { - error!(elapsed = ?start.elapsed(), error = %e, "Failed to get payload from mev-boost"); + error!(elapsed = ?start.elapsed(), error = %e, "Failed to get payload from constraints client"); e })?; - info!(elapsed = ?start.elapsed(), "Returning payload from mev-boost"); + info!(elapsed = ?start.elapsed(), "Returning payload from constraints client"); ApiMetrics::increment_remote_blocks_proposed(); Ok(payload) @@ -217,7 +217,7 @@ where /// Configuration for the builder proxy. #[derive(Debug, Clone)] pub struct BuilderProxyConfig { - /// The URL of the target mev-boost server. + /// The URL of the target constraints client server. pub constraints_url: Url, /// The port on which the builder proxy should listen. pub server_port: u16, diff --git a/bolt-sidecar/src/builder/mod.rs b/bolt-sidecar/src/builder/mod.rs index 437a8ae54..7491ef803 100644 --- a/bolt-sidecar/src/builder/mod.rs +++ b/bolt-sidecar/src/builder/mod.rs @@ -102,7 +102,7 @@ impl LocalBuilder { // the current head of the chain let block = self.fallback_builder.build_fallback_payload(slot, &transactions).await?; - // NOTE: we use a big value for the bid to ensure it gets chosen by mev-boost. + // NOTE: we use a big value for the bid to ensure it gets chosen by constraints client. // the client has no way to actually verify this, and we don't need to trust // an external relay as this block is self-built, so the fake bid value is fine. // diff --git a/bolt-sidecar/src/client/constraints_client.rs b/bolt-sidecar/src/client/constraints_client.rs index 322bb8da4..67b49866d 100644 --- a/bolt-sidecar/src/client/constraints_client.rs +++ b/bolt-sidecar/src/client/constraints_client.rs @@ -1,5 +1,5 @@ -//! Module for interacting with the MEV-Boost API via its Builder API interface. -//! The Bolt sidecar's main purpose is to sit between the beacon node and MEV-Boost, +//! Module for interacting with the Constraints client API via its Builder API interface. +//! The Bolt sidecar's main purpose is to sit between the beacon node and Constraints client, //! so most requests are simply proxied to its API. use axum::http::StatusCode; @@ -25,7 +25,7 @@ use crate::{ }, }; -/// A client for interacting with the MEV-Boost API. +/// A client for interacting with the Constraints client API. #[derive(Debug, Clone)] pub struct ConstraintsClient { url: Url, diff --git a/bolt-sidecar/src/config/mod.rs b/bolt-sidecar/src/config/mod.rs index 33b0dcd54..6d222982f 100644 --- a/bolt-sidecar/src/config/mod.rs +++ b/bolt-sidecar/src/config/mod.rs @@ -25,8 +25,8 @@ use telemetry::TelemetryOpts; /// Default port for the JSON-RPC server exposed by the sidecar. pub const DEFAULT_RPC_PORT: u16 = 8000; -/// Default port for the MEV-Boost proxy server. -pub const DEFAULT_MEV_BOOST_PROXY_PORT: u16 = 18551; +/// Default port for the Constraints proxy server. +pub const DEFAULT_CONSTRAINTS_PROXY_PORT: u16 = 18551; /// Command-line options for the Bolt sidecar #[derive(Parser, Debug)] @@ -37,7 +37,7 @@ pub struct Opts { /// URL for the beacon client #[clap(long, env = "BOLT_SIDECAR_BEACON_API_URL")] pub(super) beacon_api_url: String, - /// URL for the MEV-Boost sidecar client to use + /// URL for the Constraint sidecar client to use #[clap(long, env = "BOLT_SIDECAR_CONSTRAINTS_URL")] pub(super) constraints_url: String, /// Execution client API URL @@ -46,7 +46,7 @@ pub struct Opts { /// Execution client Engine API URL #[clap(long, env = "BOLT_SIDECAR_ENGINE_API_URL")] pub(super) engine_api_url: String, - /// MEV-Boost proxy server port to use + /// Constraint proxy server port to use #[clap(long, env = "BOLT_SIDECAR_CONSTRAINTS_PROXY_PORT")] pub(super) constraints_proxy_port: u16, /// Max number of commitments to accept per block @@ -132,7 +132,7 @@ impl Default for Config { fn default() -> Self { Self { rpc_port: DEFAULT_RPC_PORT, - constraints_proxy_port: DEFAULT_MEV_BOOST_PROXY_PORT, + constraints_proxy_port: DEFAULT_CONSTRAINTS_PROXY_PORT, commit_boost_address: None, commit_boost_jwt_hex: None, constraints_url: "http://localhost:3030".parse().expect("Valid URL"), diff --git a/bolt-sidecar/src/driver.rs b/bolt-sidecar/src/driver.rs index 0492cf6c4..51ca7f304 100644 --- a/bolt-sidecar/src/driver.rs +++ b/bolt-sidecar/src/driver.rs @@ -260,7 +260,7 @@ impl SidecarDriver SidecarDriver= max_retries { - error!("Max retries reached while submitting to MEV-Boost"); + error!("Max retries reached while submitting to Constraints client"); break; } } From d9d2e0e75c329e3ca220a1d5ef080a7456092038 Mon Sep 17 00:00:00 2001 From: Naman Garg <0708ng@gmail.com> Date: Mon, 9 Sep 2024 12:34:25 +0530 Subject: [PATCH 11/30] test(sidecar): add ser/de test --- bolt-sidecar/src/primitives/constraint.rs | 27 +++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/bolt-sidecar/src/primitives/constraint.rs b/bolt-sidecar/src/primitives/constraint.rs index adedb9bab..ae9194228 100644 --- a/bolt-sidecar/src/primitives/constraint.rs +++ b/bolt-sidecar/src/primitives/constraint.rs @@ -1,7 +1,7 @@ use alloy::primitives::keccak256; use cb_common::pbs::{DenebSpec, EthSpec, Transaction}; use secp256k1::Message; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use tree_hash::{MerkleHasher, TreeHash}; use crate::crypto::{bls::BLSSig, ecdsa::SignableECDSA, SignableBLS}; @@ -44,7 +44,7 @@ pub struct SignedConstraints { /// A message that contains the constraints that need to be signed by the proposer sidecar. /// /// Reference: https://chainbound.github.io/bolt-docs/api/builder#constraints -#[derive(Serialize, Debug, Clone, PartialEq, Default)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)] pub struct ConstraintsMessage { /// The validator index of the proposer sidecar. pub validator_index: u64, @@ -141,4 +141,27 @@ mod tests { // Additional checks can be added here, depending on your specific requirements println!("Computed tree hash root: {:?}", tree_root.encode_hex()); } + + #[test] + fn test_serialize_deserialize_roundtrip() { + let mut rng = rand::thread_rng(); + + // Generate random values for the `ConstraintsMessage` fields + let validator_index = random_u64(&mut rng); + let slot = random_u64(&mut rng); + let top = false; + let constraints = random_constraints(2); // Generate 'n' random constraints + + // Create a random `ConstraintsMessage` + let message = ConstraintsMessage { validator_index, slot, top, constraints }; + + // Serialize the `ConstraintsMessage` to JSON + let json = serde_json::to_string(&message).unwrap(); + + // Deserialize the JSON back to a `ConstraintsMessage` + let deserialized_message: ConstraintsMessage = serde_json::from_str(&json).unwrap(); + + // Verify that the deserialized message is equal to the original message + assert_eq!(message, deserialized_message); + } } From 37356ccf177486274effd67bcfa9d2c06a431505 Mon Sep 17 00:00:00 2001 From: Naman Garg <0708ng@gmail.com> Date: Mon, 9 Sep 2024 14:14:01 +0530 Subject: [PATCH 12/30] chore(sidecar): specify ser/de impls --- bolt-sidecar/src/primitives/commitment.rs | 6 +++- bolt-sidecar/src/primitives/constraint.rs | 6 +++- bolt-sidecar/src/primitives/mod.rs | 34 +++++++++++++++-------- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/bolt-sidecar/src/primitives/commitment.rs b/bolt-sidecar/src/primitives/commitment.rs index 57e4531de..5364f02b1 100644 --- a/bolt-sidecar/src/primitives/commitment.rs +++ b/bolt-sidecar/src/primitives/commitment.rs @@ -3,7 +3,10 @@ use std::str::FromStr; use alloy::primitives::{keccak256, Address, Signature, B256}; -use crate::crypto::SignerECDSA; +use crate::{ + crypto::SignerECDSA, + primitives::{deserialize_txs, serialize_txs}, +}; use super::{FullTransaction, SignatureError, TransactionExt}; @@ -78,6 +81,7 @@ pub struct InclusionRequest { /// The consensus slot number at which the transaction should be included. pub slot: u64, /// The transaction to be included. + #[serde(deserialize_with = "deserialize_txs", serialize_with = "serialize_txs")] pub txs: Vec, /// The signature over the "slot" and "tx" fields by the user. /// A valid signature is the only proof that the user actually requested diff --git a/bolt-sidecar/src/primitives/constraint.rs b/bolt-sidecar/src/primitives/constraint.rs index ae9194228..5ceb02909 100644 --- a/bolt-sidecar/src/primitives/constraint.rs +++ b/bolt-sidecar/src/primitives/constraint.rs @@ -4,7 +4,10 @@ use secp256k1::Message; use serde::{Deserialize, Serialize}; use tree_hash::{MerkleHasher, TreeHash}; -use crate::crypto::{bls::BLSSig, ecdsa::SignableECDSA, SignableBLS}; +use crate::{ + crypto::{bls::BLSSig, ecdsa::SignableECDSA, SignableBLS}, + primitives::{deserialize_txs, serialize_txs}, +}; use super::{FullTransaction, InclusionRequest}; @@ -54,6 +57,7 @@ pub struct ConstraintsMessage { /// NOTE: Per slot, only 1 top-of-block bundle is valid. pub top: bool, /// The constraints that need to be signed. + #[serde(deserialize_with = "deserialize_txs", serialize_with = "serialize_txs")] pub constraints: Vec, } diff --git a/bolt-sidecar/src/primitives/mod.rs b/bolt-sidecar/src/primitives/mod.rs index 0f0a86703..f0b71ead1 100644 --- a/bolt-sidecar/src/primitives/mod.rs +++ b/bolt-sidecar/src/primitives/mod.rs @@ -18,7 +18,7 @@ use ethereum_consensus::{ Fork, }; use reth_primitives::{BlobTransactionSidecar, Bytes, PooledTransactionsElement, TxKind, TxType}; -use serde::{de, Serialize}; +use serde::{de, ser::SerializeSeq, Serialize}; use tokio::sync::{mpsc, oneshot}; pub use ethereum_consensus::crypto::{PublicKey as BlsPublicKey, Signature as BlsSignature}; @@ -381,22 +381,34 @@ impl FullTransaction { } } -impl serde::Serialize for FullTransaction { - fn serialize(&self, serializer: S) -> Result { - let mut data = Vec::new(); - self.tx.encode_enveloped(&mut data); - serializer.serialize_str(&format!("0x{}", hex::encode(&data))) +fn serialize_txs( + txs: &[FullTransaction], + serializer: S, +) -> Result { + let mut seq = serializer.serialize_seq(Some(txs.len()))?; + for tx in txs { + let encoded = tx.tx.envelope_encoded(); + seq.serialize_element(&format!("0x{}", hex::encode(encoded)))?; } + seq.end() } -impl<'de> serde::Deserialize<'de> for FullTransaction { - fn deserialize>(deserializer: D) -> Result { - let s = String::deserialize(deserializer)?; +fn deserialize_txs<'de, D>(deserializer: D) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + let hex_strings = as de::Deserialize>::deserialize(deserializer)?; + let mut txs = Vec::new(); + + for s in hex_strings { let data = hex::decode(s.trim_start_matches("0x")).map_err(de::Error::custom)?; - PooledTransactionsElement::decode_enveloped(&mut data.as_slice()) + let tx = PooledTransactionsElement::decode_enveloped(&mut data.as_slice()) .map_err(de::Error::custom) - .map(|tx| FullTransaction { tx, sender: None }) + .map(|tx| FullTransaction { tx, sender: None })?; + txs.push(tx); } + + Ok(txs) } #[derive(Debug, thiserror::Error)] From 56436767c7d2051fe2581231dbbab7775c2e1801 Mon Sep 17 00:00:00 2001 From: Jonas Bostoen Date: Mon, 9 Sep 2024 15:52:05 +0200 Subject: [PATCH 13/30] fix(sidecar): various fixes, fix tests --- bolt-sidecar/src/api/commitments/handlers.rs | 5 +- bolt-sidecar/src/builder/template.rs | 31 +++++++----- bolt-sidecar/src/crypto/bls.rs | 12 ++--- bolt-sidecar/src/driver.rs | 3 +- bolt-sidecar/src/primitives/constraint.rs | 52 +++++++------------- bolt-sidecar/src/primitives/mod.rs | 13 +++-- bolt-sidecar/src/state/execution.rs | 18 +++---- bolt-sidecar/src/test_util.rs | 2 +- 8 files changed, 66 insertions(+), 70 deletions(-) diff --git a/bolt-sidecar/src/api/commitments/handlers.rs b/bolt-sidecar/src/api/commitments/handlers.rs index 3b587a0f7..36626a514 100644 --- a/bolt-sidecar/src/api/commitments/handlers.rs +++ b/bolt-sidecar/src/api/commitments/handlers.rs @@ -52,7 +52,10 @@ pub async fn rpc_entrypoint( // Parse the inclusion request from the parameters let mut inclusion_request: InclusionRequest = serde_json::from_value(request_json) - .map_err(|e| RejectionError::ValidationFailed(e.to_string()))?; + .map_err(|e| RejectionError::ValidationFailed(e.to_string())) + .inspect_err(|e| error!("Failed to parse inclusion request: {:?}", e))?; + + debug!(?inclusion_request, "New inclusion request"); // Set the signature here for later processing inclusion_request.set_signature(signature); diff --git a/bolt-sidecar/src/builder/template.rs b/bolt-sidecar/src/builder/template.rs index 8dc69e627..b9d8df82e 100644 --- a/bolt-sidecar/src/builder/template.rs +++ b/bolt-sidecar/src/builder/template.rs @@ -1,9 +1,6 @@ //! Package `template` contains the functionality for building local block templates that can //! be used as a fallback. It's also used to keep any intermediary state that is needed to simulate //! new commitment requests. - -// Should this be a trait? - use std::collections::HashMap; use alloy::primitives::{Address, U256}; @@ -119,10 +116,10 @@ impl BlockTemplate { /// Adds a list of constraints to the block template and updates the state diff. pub fn add_constraints(&mut self, constraints: SignedConstraints) { for constraint in constraints.message.constraints.iter() { - let max_cost = max_transaction_cost(&constraint); + let max_cost = max_transaction_cost(constraint); self.state_diff .diffs - .entry(constraint.sender()) + .entry(*constraint.sender().expect("recovered sender")) .and_modify(|(nonce, balance)| { *nonce += 1; *balance += max_cost; @@ -138,10 +135,13 @@ impl BlockTemplate { let constraints = self.signed_constraints_list.remove(index); for constraint in constraints.message.constraints.iter() { - self.state_diff.diffs.entry(constraint.sender()).and_modify(|(nonce, balance)| { - *nonce = nonce.saturating_sub(1); - *balance -= max_transaction_cost(&constraint); - }); + self.state_diff + .diffs + .entry(*constraint.sender().expect("recovered sender")) + .and_modify(|(nonce, balance)| { + *nonce = nonce.saturating_sub(1); + *balance -= max_transaction_cost(constraint); + }); } } @@ -156,8 +156,15 @@ impl BlockTemplate { .iter() .enumerate() .map(|(idx, c)| (idx, &c.message.constraints)) - .filter(|(_idx, c)| c.iter().any(|c| c.sender() == address)) - .map(|(idx, c)| (idx, c.iter().filter(|c| c.sender() == address).collect())) + .filter(|(_idx, c)| c.iter().any(|c| c.sender().expect("recovered sender") == &address)) + .map(|(idx, c)| { + ( + idx, + c.iter() + .filter(|c| c.sender().expect("recovered sender") == &address) + .collect(), + ) + }) .collect(); // For every preconfirmation, gather the max total balance cost, @@ -166,7 +173,7 @@ impl BlockTemplate { .iter() .flat_map(|c| c.1.clone()) .fold((U256::ZERO, u64::MAX), |(total_cost, min_nonce), c| { - (total_cost + max_transaction_cost(&c), min_nonce.min(c.nonce())) + (total_cost + max_transaction_cost(c), min_nonce.min(c.nonce())) }); if state.balance < max_total_cost || state.transaction_count > min_nonce { diff --git a/bolt-sidecar/src/crypto/bls.rs b/bolt-sidecar/src/crypto/bls.rs index 98b993310..028362dfe 100644 --- a/bolt-sidecar/src/crypto/bls.rs +++ b/bolt-sidecar/src/crypto/bls.rs @@ -16,23 +16,23 @@ pub type BLSSig = FixedBytes<96>; /// Trait for any types that can be signed and verified with BLS. /// This trait is used to abstract over the signing and verification of different types. pub trait SignableBLS { - /// Creates SSZ tree hash root of the object. - fn tree_hash_root(&self) -> [u8; 32]; + /// Returns the digest of the object. + fn digest(&self) -> [u8; 32]; /// Sign the object with the given key. Returns the signature. /// /// Note: The default implementation should be used where possible. #[allow(dead_code)] fn sign(&self, key: &BlsSecretKey) -> Signature { - sign_with_prefix(key, &self.tree_hash_root()) + sign_with_prefix(key, &self.digest()) } /// Verify the signature of the object with the given public key. /// /// Note: The default implementation should be used where possible. fn verify(&self, signature: &Signature, pubkey: &BlsPublicKey) -> bool { - signature.verify(false, &self.tree_hash_root(), BLS_DST_PREFIX, &[], pubkey, true) == - BLST_ERROR::BLST_SUCCESS + signature.verify(false, &self.digest(), BLS_DST_PREFIX, &[], pubkey, true) + == BLST_ERROR::BLST_SUCCESS } } @@ -120,7 +120,7 @@ mod tests { rng.fill(&mut data); let msg = TestSignableData { data }; - let signature = SignerBLS::sign(&signer, &msg.tree_hash_root()).await.unwrap(); + let signature = SignerBLS::sign(&signer, &msg.digest()).await.unwrap(); let sig = blst::min_pk::Signature::from_bytes(signature.as_ref()).unwrap(); assert!(signer.verify(&msg, &sig, &pubkey)); } diff --git a/bolt-sidecar/src/driver.rs b/bolt-sidecar/src/driver.rs index 51ca7f304..740b77b2d 100644 --- a/bolt-sidecar/src/driver.rs +++ b/bolt-sidecar/src/driver.rs @@ -221,8 +221,7 @@ impl SidecarDriver SignedConstraints { message, signature }, Err(err) => { error!(?err, "Failed to sign constraints"); diff --git a/bolt-sidecar/src/primitives/constraint.rs b/bolt-sidecar/src/primitives/constraint.rs index 5ceb02909..c796b27f4 100644 --- a/bolt-sidecar/src/primitives/constraint.rs +++ b/bolt-sidecar/src/primitives/constraint.rs @@ -1,8 +1,9 @@ -use alloy::primitives::keccak256; -use cb_common::pbs::{DenebSpec, EthSpec, Transaction}; +use alloy::{ + primitives::keccak256, + signers::k256::sha2::{Digest, Sha256}, +}; use secp256k1::Message; use serde::{Deserialize, Serialize}; -use tree_hash::{MerkleHasher, TreeHash}; use crate::{ crypto::{bls::BLSSig, ecdsa::SignableECDSA, SignableBLS}, @@ -68,43 +69,26 @@ impl ConstraintsMessage { Self { validator_index, slot: request.slot, top: false, constraints } } - - /// Returns the total number of leaves in the tree. - fn total_leaves(&self) -> usize { - 4 + self.constraints.len() - } } impl SignableBLS for ConstraintsMessage { - fn tree_hash_root(&self) -> [u8; 32] { - let mut hasher = MerkleHasher::with_leaves(self.total_leaves()); - - hasher - .write(&self.validator_index.to_le_bytes()) - .expect("Should write validator index bytes"); - hasher.write(&self.slot.to_le_bytes()).expect("Should write slot bytes"); - hasher.write(&(self.top as u8).to_le_bytes()).expect("Should write top flag"); + fn digest(&self) -> [u8; 32] { + let mut hasher = Sha256::new(); + hasher.update(self.validator_index.to_le_bytes()); + hasher.update(self.slot.to_le_bytes()); + hasher.update((self.top as u8).to_le_bytes()); for constraint in &self.constraints { - hasher - .write( - Transaction::<::MaxBytesPerTransaction>::from( - constraint.envelope_encoded().to_vec(), - ) - .tree_hash_root() - .as_bytes(), - ) - .expect("Should write transaction root"); + hasher.update(constraint.hash()); } - hasher.finish().unwrap().0 + hasher.finalize().into() } } #[cfg(test)] mod tests { use super::*; - use alloy::hex::ToHexExt; use rand::{rngs::ThreadRng, Rng}; fn random_u64(rng: &mut ThreadRng) -> u64 { @@ -124,7 +108,7 @@ mod tests { } #[test] - fn test_tree_hash_root() { + fn test_bls_digest() { let mut rng = rand::thread_rng(); // Generate random values for the `ConstraintsMessage` fields @@ -134,16 +118,16 @@ mod tests { let constraints = random_constraints(1); // Generate 'n' random constraints // Create a random `ConstraintsMessage` - let message = ConstraintsMessage { validator_index, slot, top, constraints }; + let mut message = ConstraintsMessage { validator_index, slot, top, constraints }; + message.validator_index = 0; + message.slot = 0; + message.top = false; // Compute tree hash root - let tree_root = message.tree_hash_root(); + let digest = SignableBLS::digest(&message); // Verify that the tree hash root is a valid 32-byte array - assert_eq!(tree_root.len(), 32, "Tree hash root should be 32 bytes long"); - - // Additional checks can be added here, depending on your specific requirements - println!("Computed tree hash root: {:?}", tree_root.encode_hex()); + assert_eq!(digest.len(), 32, "Digest should be 32 bytes long"); } #[test] diff --git a/bolt-sidecar/src/primitives/mod.rs b/bolt-sidecar/src/primitives/mod.rs index f0b71ead1..8c8a6f734 100644 --- a/bolt-sidecar/src/primitives/mod.rs +++ b/bolt-sidecar/src/primitives/mod.rs @@ -1,7 +1,10 @@ // TODO: add docs #![allow(missing_docs)] -use std::sync::{atomic::AtomicU64, Arc}; +use std::{ + borrow::Cow, + sync::{atomic::AtomicU64, Arc}, +}; use alloy::primitives::{Address, U256}; use ethereum_consensus::{ @@ -376,8 +379,8 @@ impl FullTransaction { } /// Returns the sender of the transaction, if recovered. - pub fn sender(&self) -> Address { - self.sender.expect("Recovered sender") + pub fn sender(&self) -> Option<&Address> { + self.sender.as_ref() } } @@ -397,8 +400,8 @@ fn deserialize_txs<'de, D>(deserializer: D) -> Result, D::E where D: serde::Deserializer<'de>, { - let hex_strings = as de::Deserialize>::deserialize(deserializer)?; - let mut txs = Vec::new(); + let hex_strings = > as de::Deserialize>::deserialize(deserializer)?; + let mut txs = Vec::with_capacity(hex_strings.len()); for s in hex_strings { let data = hex::decode(s.trim_start_matches("0x")).map_err(de::Error::custom)?; diff --git a/bolt-sidecar/src/state/execution.rs b/bolt-sidecar/src/state/execution.rs index dd374f5c8..3d634a127 100644 --- a/bolt-sidecar/src/state/execution.rs +++ b/bolt-sidecar/src/state/execution.rs @@ -312,7 +312,7 @@ impl ExecutionState { let mut bundle_nonce_diff_map = HashMap::new(); let mut bundle_balance_diff_map = HashMap::new(); for tx in req.txs.iter() { - let sender = tx.sender(); + let sender = tx.sender().expect("Recovered sender"); // From previous preconfirmations requests retrieve // - the nonce difference from the account state. @@ -326,7 +326,7 @@ impl ExecutionState { (0, U256::ZERO, 0), |(nonce_diff_acc, balance_diff_acc, highest_slot), (slot, block_template)| { let (nonce_diff, balance_diff, slot) = block_template - .get_diff(&sender) + .get_diff(sender) .map(|(nonce, balance)| (nonce, balance, *slot)) .unwrap_or((0, U256::ZERO, 0)); @@ -345,11 +345,11 @@ impl ExecutionState { trace!(?signer, nonce_diff, %balance_diff, "Applying diffs to account state"); - let account_state = match self.account_state(&sender).copied() { + let account_state = match self.account_state(sender).copied() { Some(account) => account, None => { // Fetch the account state from the client if it does not exist - let account = match self.client.get_account_state(&sender, None).await { + let account = match self.client.get_account_state(sender, None).await { Ok(account) => account, Err(err) => { return Err(ValidationError::Internal(format!( @@ -359,7 +359,7 @@ impl ExecutionState { } }; - self.account_states.insert(sender, account); + self.account_states.insert(*sender, account); account } }; @@ -724,7 +724,7 @@ mod tests { assert!(state.validate_request(&mut request).await.is_ok()); let message = ConstraintsMessage::build(0, request.as_inclusion_request().unwrap().clone()); - let signature = signer.sign(&message.tree_hash_root()).await?; + let signature = signer.sign(&message.digest()).await?; let signed_constraints = SignedConstraints { message, signature }; state.add_constraint(10, signed_constraints); @@ -839,7 +839,7 @@ mod tests { let bls_signer = Signer::random(); let message = ConstraintsMessage::build(0, inclusion_request); - let signature = bls_signer.sign(&message.tree_hash_root()).await.unwrap(); + let signature = bls_signer.sign(&message.digest()).await.unwrap(); let signed_constraints = SignedConstraints { message, signature }; state.add_constraint(target_slot, signed_constraints); @@ -887,7 +887,7 @@ mod tests { let bls_signer = Signer::random(); let message = ConstraintsMessage::build(0, inclusion_request); - let signature = bls_signer.sign(&message.tree_hash_root()).await.unwrap(); + let signature = bls_signer.sign(&message.digest()).await.unwrap(); let signed_constraints = SignedConstraints { message, signature }; state.add_constraint(target_slot, signed_constraints); @@ -933,7 +933,7 @@ mod tests { let bls_signer = Signer::random(); let message = ConstraintsMessage::build(0, inclusion_request); - let signature = bls_signer.sign(&message.tree_hash_root()).await.unwrap(); + let signature = bls_signer.sign(&message.digest()).await.unwrap(); let signed_constraints = SignedConstraints { message, signature }; state.add_constraint(target_slot, signed_constraints); diff --git a/bolt-sidecar/src/test_util.rs b/bolt-sidecar/src/test_util.rs index d414b8a4c..c03bad87e 100644 --- a/bolt-sidecar/src/test_util.rs +++ b/bolt-sidecar/src/test_util.rs @@ -122,7 +122,7 @@ pub(crate) struct TestSignableData { } impl SignableBLS for TestSignableData { - fn tree_hash_root(&self) -> [u8; 32] { + fn digest(&self) -> [u8; 32] { self.data } } From a249122cd353c59736f58432fc71458b521607e3 Mon Sep 17 00:00:00 2001 From: Jonas Bostoen Date: Mon, 9 Sep 2024 15:58:25 +0200 Subject: [PATCH 14/30] feat(bolt-boost): update ConstraintsMessage digest --- bolt-boost/src/types.rs | 63 +++++++++++++---------------------------- 1 file changed, 19 insertions(+), 44 deletions(-) diff --git a/bolt-boost/src/types.rs b/bolt-boost/src/types.rs index b797fe820..6a9b81a27 100644 --- a/bolt-boost/src/types.rs +++ b/bolt-boost/src/types.rs @@ -1,11 +1,12 @@ use alloy::{ consensus::TxEnvelope, eips::eip2718::{Decodable2718, Eip2718Error}, - primitives::{Bytes, TxHash, B256}, + primitives::{keccak256, Bytes, TxHash, B256}, rpc::types::beacon::{BlsPublicKey, BlsSignature}, + signers::k256::sha2::{Digest, Sha256}, }; use axum::http::HeaderMap; -use commit_boost::prelude::tree_hash::{self, MerkleHasher, TreeHash, TreeHashType}; +use commit_boost::prelude::tree_hash; use reqwest::Url; use serde::{Deserialize, Serialize}; use ssz_derive::{Decode, Encode}; @@ -14,7 +15,8 @@ use std::ops::Deref; use cb_common::{ constants::COMMIT_BOOST_DOMAIN, pbs::{DenebSpec, EthSpec, SignedExecutionPayloadHeader, Transaction, VersionedResponse}, - signature::verify_signed_message, + signature::{compute_domain, compute_signing_root}, + signer::schemes::bls::verify_bls_signature, types::Chain, }; @@ -42,8 +44,10 @@ impl SignedConstraints { /// The `chain` and `COMMIT_BOOST_DOMAIN` are used to compute the signing root. #[allow(unused)] pub fn verify_signature(&self, chain: Chain, pubkey: &BlsPublicKey) -> bool { - verify_signed_message(chain, pubkey, &self.message, &self.signature, COMMIT_BOOST_DOMAIN) - .is_ok() + let domain = compute_domain(chain, COMMIT_BOOST_DOMAIN); + let signing_root = compute_signing_root(self.message.digest(), domain); + + verify_bls_signature(pubkey, &signing_root, &self.signature).is_ok() } } @@ -56,47 +60,18 @@ pub struct ConstraintsMessage { } impl ConstraintsMessage { - /// Returns the total number of leaves in the tree. - fn total_leaves(&self) -> usize { - 4 + self.transactions.len() - } -} - -impl TreeHash for ConstraintsMessage { - fn tree_hash_type() -> TreeHashType { - TreeHashType::Container - } - - fn tree_hash_packed_encoding(&self) -> tree_hash::PackedEncoding { - unreachable!("ConstraintsMessage should never be packed.") - } - - fn tree_hash_packing_factor() -> usize { - unreachable!("ConstraintsMessage should never be packed.") - } - - fn tree_hash_root(&self) -> HashTreeRoot { - let mut hasher = MerkleHasher::with_leaves(self.total_leaves()); - - hasher - .write(&self.validator_index.to_le_bytes()) - .expect("Should write validator index bytes"); - hasher.write(&self.slot.to_le_bytes()).expect("Should write slot bytes"); - hasher.write(&(self.top as u8).to_le_bytes()).expect("Should write top flag"); - - for transaction in &self.transactions { - hasher - .write( - Transaction::<::MaxBytesPerTransaction>::from( - transaction.to_vec(), - ) - .tree_hash_root() - .as_bytes(), - ) - .expect("Should write transaction root"); + /// Returns the digest of this message. + pub fn digest(&self) -> [u8; 32] { + let mut hasher = Sha256::new(); + hasher.update(self.validator_index.to_le_bytes()); + hasher.update(self.slot.to_le_bytes()); + hasher.update((self.top as u8).to_le_bytes()); + + for constraint in &self.transactions { + hasher.update(keccak256(constraint)); } - hasher.finish().unwrap() + hasher.finalize().into() } } From dbc985210ff197cbe9502b3543e7c59856ad6c8f Mon Sep 17 00:00:00 2001 From: Jonas Bostoen Date: Tue, 10 Sep 2024 11:28:44 +0200 Subject: [PATCH 15/30] chore(contracts): forge fmt --- bolt-contracts/script/ReadRegistry.s.sol | 16 +-- .../script/RegisterValidators.s.sol | 21 ++-- .../src/contracts/BoltChallenger.sol | 116 +++++------------- bolt-contracts/src/contracts/BoltRegistry.sol | 27 +--- .../src/interfaces/IBoltRegistry.sol | 20 +-- bolt-contracts/test/BoltRegistry.t.sol | 5 +- .../test/StringToUintArrayLib.t.sol | 3 +- 7 files changed, 51 insertions(+), 157 deletions(-) diff --git a/bolt-contracts/script/ReadRegistry.s.sol b/bolt-contracts/script/ReadRegistry.s.sol index 0e26d204e..9abfbb86a 100644 --- a/bolt-contracts/script/ReadRegistry.s.sol +++ b/bolt-contracts/script/ReadRegistry.s.sol @@ -12,21 +12,11 @@ contract ReadRegistry is Script { console.log("Bolt registry address:", registryAddress); BoltRegistry registry = BoltRegistry(registryAddress); - console.log( - "Bolt registry minimum collateral:", - registry.MINIMUM_COLLATERAL() - ); + console.log("Bolt registry minimum collateral:", registry.MINIMUM_COLLATERAL()); for (uint64 i = 0; i < 2000; i++) { - try registry.getOperatorForValidator(i) returns ( - IBoltRegistry.Registrant memory operator - ) { - console.log( - "Operator for validator found", - i, - ":", - operator.operator - ); + try registry.getOperatorForValidator(i) returns (IBoltRegistry.Registrant memory operator) { + console.log("Operator for validator found", i, ":", operator.operator); console.log("Operator RPC:", operator.metadata.rpc); } catch { // console.log("No operator for validator", i); diff --git a/bolt-contracts/script/RegisterValidators.s.sol b/bolt-contracts/script/RegisterValidators.s.sol index e4554fd88..04f9cd74f 100644 --- a/bolt-contracts/script/RegisterValidators.s.sol +++ b/bolt-contracts/script/RegisterValidators.s.sol @@ -24,10 +24,7 @@ contract RegisterValidators is Script { console.log("Bolt registry address:", registryAddress); BoltRegistry registry = BoltRegistry(registryAddress); - console.log( - "Bolt registry minimum collateral:", - registry.MINIMUM_COLLATERAL() - ); + console.log("Bolt registry minimum collateral:", registry.MINIMUM_COLLATERAL()); address sender = vm.addr(signerKey); @@ -39,11 +36,7 @@ contract RegisterValidators is Script { } // Register with minimal collateral - registry.register{value: registry.MINIMUM_COLLATERAL()}( - validatorIndexes, - rpc, - "" - ); + registry.register{value: registry.MINIMUM_COLLATERAL()}(validatorIndexes, rpc, ""); vm.stopBroadcast(); } @@ -62,7 +55,7 @@ library StringToUintArrayLib { uint256 rangeStart; for (uint256 i = 0; i < strBytes.length; i++) { - if (strBytes[i] == ',') { + if (strBytes[i] == ",") { if (parsingRange) { // Handle end of range for (uint256 j = rangeStart; j <= tempNum; j++) { @@ -76,15 +69,15 @@ library StringToUintArrayLib { vecIndex++; } tempNum = 0; - } else if (strBytes[i] == '.') { - if (i + 1 < strBytes.length && strBytes[i + 1] == '.') { + } else if (strBytes[i] == ".") { + if (i + 1 < strBytes.length && strBytes[i + 1] == ".") { // Handle start of range parsingRange = true; rangeStart = tempNum; tempNum = 0; i++; // Skip next dot } - } else if (strBytes[i] >= '0' && strBytes[i] <= '9') { + } else if (strBytes[i] >= "0" && strBytes[i] <= "9") { tempNum = tempNum * 10 + (uint8(strBytes[i]) - 48); // Convert ASCII to integer } } @@ -108,4 +101,4 @@ library StringToUintArrayLib { return result; } -} \ No newline at end of file +} diff --git a/bolt-contracts/src/contracts/BoltChallenger.sol b/bolt-contracts/src/contracts/BoltChallenger.sol index d66784cc9..7b120d915 100644 --- a/bolt-contracts/src/contracts/BoltChallenger.sol +++ b/bolt-contracts/src/contracts/BoltChallenger.sol @@ -78,12 +78,7 @@ contract BoltChallenger is IBoltChallenger { /// @param _boltRegistry The address of the BoltRegistry contract /// @param _reliquary The address of the Relic Reliquary contract /// @param _blockHeaderProver The address of the Relic block header prover contract - constructor( - address _boltRegistry, - address _reliquary, - address _blockHeaderProver, - address _accountInfoProver - ) { + constructor(address _boltRegistry, address _reliquary, address _blockHeaderProver, address _accountInfoProver) { boltRegistry = IBoltRegistry(_boltRegistry); reliquary = IReliquary(_reliquary); @@ -100,10 +95,7 @@ contract BoltChallenger is IBoltChallenger { /// @notice A challenge requires a bond to be transferred to this contract to avoid spamming. /// @param _basedProposer The address of the proposer to challenge /// @param _signedCommitment The signed commitment that the proposer is getting challenged for - function challengeProposer( - address _basedProposer, - SignedCommitment calldata _signedCommitment - ) public payable { + function challengeProposer(address _basedProposer, SignedCommitment calldata _signedCommitment) public payable { // First sanity checks if (_basedProposer == address(0) || _signedCommitment.slot == 0) { revert InvalidChallenge(); @@ -119,9 +111,8 @@ contract BoltChallenger is IBoltChallenger { // Check if the target slot is not too far in the past if ( - BeaconChainUtils._getSlotFromTimestamp(block.timestamp) - - _signedCommitment.slot > - CHALLENGE_RETROACTIVE_TARGET_SLOT_WINDOW + BeaconChainUtils._getSlotFromTimestamp(block.timestamp) - _signedCommitment.slot + > CHALLENGE_RETROACTIVE_TARGET_SLOT_WINDOW ) { // Challenges cannot be opened for slots that are too far in the past, because we rely // on the BEACON_ROOTS ring buffer to be available for the challenge to be resolved. @@ -142,12 +133,7 @@ contract BoltChallenger is IBoltChallenger { } // Check if the signed commitment was made by the challenged based proposer - if ( - _recoverCommitmentSigner( - commitmentID, - _signedCommitment.signature - ) != _basedProposer - ) { + if (_recoverCommitmentSigner(commitmentID, _signedCommitment.signature) != _basedProposer) { revert InvalidCommitmentSigner(); } @@ -157,9 +143,7 @@ contract BoltChallenger is IBoltChallenger { // Get the beacon block root for the target slot. We store it in the Challenge so that // it can be used even after 8192 slots have passed (the limit of the BEACON_ROOTS contract) - bytes32 beaconBlockRoot = BeaconChainUtils._getBeaconBlockRoot( - _signedCommitment.slot - ); + bytes32 beaconBlockRoot = BeaconChainUtils._getBeaconBlockRoot(_signedCommitment.slot); // ==== Create a new challenge ==== @@ -205,9 +189,7 @@ contract BoltChallenger is IBoltChallenger { // Check if the challenge has expired. // This means that the validator failed to honor the commitment and will get slashed. - if ( - block.timestamp - challenge.openTimestamp > MAX_CHALLENGE_DURATION - ) { + if (block.timestamp - challenge.openTimestamp > MAX_CHALLENGE_DURATION) { // Part of the slashed amount will also be returned to the challenger as a reward. // This is the reason we don't have access control in this function. // TODO: slash the based proposer. @@ -221,14 +203,10 @@ contract BoltChallenger is IBoltChallenger { } // Derive the block header data of the target block from the block header proof - CoreTypes.BlockHeaderData - memory verifiedHeader = _deriveBlockHeaderInfo(_blockHeaderProof); + CoreTypes.BlockHeaderData memory verifiedHeader = _deriveBlockHeaderInfo(_blockHeaderProof); // Derive the preconfirmed sender's account data from the account data proof - CoreTypes.AccountData memory verifiedAccount = _deriveAccountData( - _accountDataProof, - verifiedHeader.Number - ); + CoreTypes.AccountData memory verifiedAccount = _deriveAccountData(_accountDataProof, verifiedHeader.Number); // Check that the nonce of the preconfirmed sender is valid (not too low) // at the time of the based proposer's slot. @@ -241,10 +219,7 @@ contract BoltChallenger is IBoltChallenger { // Check that the balance of the preconfirmed sender is enough to cover the base fee // of the block. - if ( - verifiedAccount.Balance < - challenge.signedCommitment.gasUsed * verifiedHeader.BaseFee - ) { + if (verifiedAccount.Balance < challenge.signedCommitment.gasUsed * verifiedHeader.BaseFee) { // consider the challenge unsuccessful: the user doesn't have enough balance to cover the gas // thus invalidating the preconfirmation: the proposer is not at fault. _onChallengeFailure(_challengeID); @@ -257,12 +232,7 @@ contract BoltChallenger is IBoltChallenger { // Check if the block header timestamp is UP TO the challenge's target slot. // It can be earlier, in case the transaction was included before the based proposer's slot. - if ( - verifiedHeader.Time > - BeaconChainUtils._getTimestampFromSlot( - challenge.signedCommitment.slot - ) - ) { + if (verifiedHeader.Time > BeaconChainUtils._getTimestampFromSlot(challenge.signedCommitment.slot)) { // The block header timestamp is after the target slot, so the proposer didn't // honor the preconfirmation and the challenge is successful. // TODO: slash the based proposer @@ -271,10 +241,7 @@ contract BoltChallenger is IBoltChallenger { } bool isValid = _verifyInclusionProof( - verifiedHeader.TxHash, - _transactionIndex, - _inclusionProof, - challenge.signedCommitment.signedRawTransaction + verifiedHeader.TxHash, _transactionIndex, _inclusionProof, challenge.signedCommitment.signedRawTransaction ); if (!isValid) { @@ -308,18 +275,13 @@ contract BoltChallenger is IBoltChallenger { /// @notice Fetch trustlessly valid block header data /// @param _proof The ABI-encoded proof of the block header /// @return header The block header data - function _deriveBlockHeaderInfo( - bytes calldata _proof - ) internal returns (CoreTypes.BlockHeaderData memory header) { + function _deriveBlockHeaderInfo(bytes calldata _proof) internal returns (CoreTypes.BlockHeaderData memory header) { // TODO: handle fee for proving. make payable? Fact memory fact = blockHeaderProver.prove(_proof, false); header = abi.decode(fact.data, (CoreTypes.BlockHeaderData)); - if ( - FactSignature.unwrap(fact.sig) != - FactSignature.unwrap(FactSigs.blockHeaderSig(header.Number)) - ) { + if (FactSignature.unwrap(fact.sig) != FactSignature.unwrap(FactSigs.blockHeaderSig(header.Number))) { revert UnexpectedFactSignature(); } } @@ -328,20 +290,17 @@ contract BoltChallenger is IBoltChallenger { /// @param _proof The ABI-encoded proof of the account data /// @param _blockNumber The block number for which the account data is being proven /// @return account The account data - function _deriveAccountData( - bytes calldata _proof, - uint256 _blockNumber - ) internal returns (CoreTypes.AccountData memory account) { + function _deriveAccountData(bytes calldata _proof, uint256 _blockNumber) + internal + returns (CoreTypes.AccountData memory account) + { // TODO: handle fee for proving. make payable? Fact memory fact = accountInfoProver.prove(_proof, false); account = abi.decode(fact.data, (CoreTypes.AccountData)); // verify that the account data proof was provided for the correct block - if ( - FactSignature.unwrap(fact.sig) != - FactSignature.unwrap(FactSigs.accountFactSig(_blockNumber)) - ) { + if (FactSignature.unwrap(fact.sig) != FactSignature.unwrap(FactSigs.accountFactSig(_blockNumber))) { revert UnexpectedFactSignature(); } } @@ -367,29 +326,20 @@ contract BoltChallenger is IBoltChallenger { // To read more, check out https://github.com/ethereum/consensus-specs/blob/dev/ssz/simple-serialize.md#merkleization uint256 generalizedIndex = 2_097_152 + _transactionIndex; - bytes32 leaf = SSZContainers._transactionHashTreeRoot( - _signedRawTransaction - ); + bytes32 leaf = SSZContainers._transactionHashTreeRoot(_signedRawTransaction); - isValid = SSZ._verifyProof( - _inclusionProof, - _transactionsRoot, - leaf, - generalizedIndex - ); + isValid = SSZ._verifyProof(_inclusionProof, _transactionsRoot, leaf, generalizedIndex); } /// @notice Recover the signer of a commitment /// @param _commitmentSignature The signature of the commitment /// @param _commitmentHash The keccak hash of an unsigned message - function _recoverCommitmentSigner( - bytes32 _commitmentHash, - bytes calldata _commitmentSignature - ) internal pure returns (address) { - (address signer, ECDSA.RecoverError err, ) = ECDSA.tryRecover( - _commitmentHash, - _commitmentSignature - ); + function _recoverCommitmentSigner(bytes32 _commitmentHash, bytes calldata _commitmentSignature) + internal + pure + returns (address) + { + (address signer, ECDSA.RecoverError err,) = ECDSA.tryRecover(_commitmentHash, _commitmentSignature); if (err != ECDSA.RecoverError.NoError || signer == address(0)) { revert InvalidCommitmentSignature(); } @@ -398,16 +348,8 @@ contract BoltChallenger is IBoltChallenger { } /// @notice Hashes the inclusion commitment to a unique ID to index the challenge - function _getCommitmentID( - SignedCommitment memory _commitment - ) internal pure returns (bytes32) { + function _getCommitmentID(SignedCommitment memory _commitment) internal pure returns (bytes32) { return - keccak256( - abi.encodePacked( - _commitment.slot, - _commitment.transactionHash, - _commitment.signedRawTransaction - ) - ); + keccak256(abi.encodePacked(_commitment.slot, _commitment.transactionHash, _commitment.signedRawTransaction)); } } diff --git a/bolt-contracts/src/contracts/BoltRegistry.sol b/bolt-contracts/src/contracts/BoltRegistry.sol index c064eda8d..048d58e05 100644 --- a/bolt-contracts/src/contracts/BoltRegistry.sol +++ b/bolt-contracts/src/contracts/BoltRegistry.sol @@ -25,11 +25,7 @@ contract BoltRegistry is IBoltRegistry { } /// @notice Allows a based proposer to opt-in to the protocol - function register( - uint64[] calldata validatorIndexes, - string calldata rpc, - bytes calldata extra - ) external payable { + function register(uint64[] calldata validatorIndexes, string calldata rpc, bytes calldata extra) external payable { if (msg.value < MINIMUM_COLLATERAL) { revert InsufficientCollateral(); } @@ -40,15 +36,8 @@ contract BoltRegistry is IBoltRegistry { MetaData memory metadata = MetaData(rpc, extra); - registrants[msg.sender] = Registrant( - msg.sender, - validatorIndexes, - block.timestamp, - 0, - msg.value, - Status.ACTIVE, - metadata - ); + registrants[msg.sender] = + Registrant(msg.sender, validatorIndexes, block.timestamp, 0, msg.value, Status.ACTIVE, metadata); operators.push(msg.sender); @@ -105,7 +94,7 @@ contract BoltRegistry is IBoltRegistry { break; } } - + delete registrants[msg.sender]; for (uint256 i = 0; i < registrant.validatorIndexes.length; i++) { @@ -127,16 +116,12 @@ contract BoltRegistry is IBoltRegistry { /// @notice Get the status of a based proposer /// @param _operator The address of the operator /// @return The status of the based proposer - function getOperatorStatus( - address _operator - ) external view returns (Status) { + function getOperatorStatus(address _operator) external view returns (Status) { // Will return INACTIVE if the operator is not registered return registrants[_operator].status; } - function getOperatorForValidator( - uint64 _validatorIndex - ) external view returns (Registrant memory) { + function getOperatorForValidator(uint64 _validatorIndex) external view returns (Registrant memory) { if (delegations[_validatorIndex] != address(0)) { return registrants[delegations[_validatorIndex]]; } diff --git a/bolt-contracts/src/interfaces/IBoltRegistry.sol b/bolt-contracts/src/interfaces/IBoltRegistry.sol index 283f8f505..7810a65c2 100644 --- a/bolt-contracts/src/interfaces/IBoltRegistry.sol +++ b/bolt-contracts/src/interfaces/IBoltRegistry.sol @@ -41,27 +41,15 @@ interface IBoltRegistry { /// @notice Event to log the status change of a based proposer event StatusChange(address indexed operator, Status status); - event Registered( - address indexed operator, - uint64[] validatorIndexes, - MetaData metadata - ); + event Registered(address indexed operator, uint64[] validatorIndexes, MetaData metadata); - function register( - uint64[] calldata validatorIndexes, - string calldata rpc, - bytes calldata extra - ) external payable; + function register(uint64[] calldata validatorIndexes, string calldata rpc, bytes calldata extra) external payable; function isActiveOperator(address _operator) external view returns (bool); - function getOperatorStatus( - address _operator - ) external view returns (Status); + function getOperatorStatus(address _operator) external view returns (Status); - function getOperatorForValidator( - uint64 _validatorIndex - ) external view returns (Registrant memory); + function getOperatorForValidator(uint64 _validatorIndex) external view returns (Registrant memory); function startExit() external; diff --git a/bolt-contracts/test/BoltRegistry.t.sol b/bolt-contracts/test/BoltRegistry.t.sol index 9280a2c67..155b6f76b 100644 --- a/bolt-contracts/test/BoltRegistry.t.sol +++ b/bolt-contracts/test/BoltRegistry.t.sol @@ -27,10 +27,7 @@ contract BoltRegistryTest is Test { registry.register{value: 10 ether}(validatorIndexes, "rpc", ""); - assertEq( - uint8(registry.getOperatorStatus(alice)), - uint8(IBoltRegistry.Status.ACTIVE) - ); + assertEq(uint8(registry.getOperatorStatus(alice)), uint8(IBoltRegistry.Status.ACTIVE)); assertEq(registry.isActiveOperator(alice), true); diff --git a/bolt-contracts/test/StringToUintArrayLib.t.sol b/bolt-contracts/test/StringToUintArrayLib.t.sol index aaae88073..15bc7a5ff 100644 --- a/bolt-contracts/test/StringToUintArrayLib.t.sol +++ b/bolt-contracts/test/StringToUintArrayLib.t.sol @@ -5,7 +5,6 @@ import "forge-std/Test.sol"; import "../script/RegisterValidators.s.sol"; contract StringToUintArrayTest is Test { - function setUp() public {} function testParseValidatorIndexes1() public pure { @@ -79,4 +78,4 @@ contract StringToUintArrayTest is Test { assertEq(indexes[i], i + 1); } } -} \ No newline at end of file +} From 5fdccc1929b852f0c4b94c169d6b28ca46181bb4 Mon Sep 17 00:00:00 2001 From: Jonas Bostoen Date: Wed, 11 Sep 2024 16:13:42 +0200 Subject: [PATCH 16/30] doc(holesky): initial holesky launch instructions --- testnets/holesky/.cb.env | 2 + testnets/holesky/README.md | 55 ++++++ testnets/holesky/cb-bolt-config.toml | 159 ++++++++++++++++++ testnets/holesky/cb.docker-compose.yml | 104 ++++++++++++ testnets/holesky/keys.json | 4 + testnets/holesky/logs/pbs/pbs.2024-09-11 | 46 +++++ .../holesky/logs/signer/signer.2024-09-11 | 16 ++ testnets/holesky/prometheus.yml | 8 + testnets/holesky/targets.json | 26 +++ 9 files changed, 420 insertions(+) create mode 100644 testnets/holesky/.cb.env create mode 100644 testnets/holesky/README.md create mode 100644 testnets/holesky/cb-bolt-config.toml create mode 100644 testnets/holesky/cb.docker-compose.yml create mode 100644 testnets/holesky/keys.json create mode 100644 testnets/holesky/logs/pbs/pbs.2024-09-11 create mode 100644 testnets/holesky/logs/signer/signer.2024-09-11 create mode 100644 testnets/holesky/prometheus.yml create mode 100644 testnets/holesky/targets.json diff --git a/testnets/holesky/.cb.env b/testnets/holesky/.cb.env new file mode 100644 index 000000000..9faac7b8d --- /dev/null +++ b/testnets/holesky/.cb.env @@ -0,0 +1,2 @@ +CB_JWT_BOLT=jN7FpDQZSWS9r1XzrGL3dbW6fBd0uzEa +CB_JWTS="{\"BOLT\":\"jN7FpDQZSWS9r1XzrGL3dbW6fBd0uzEa\"}" diff --git a/testnets/holesky/README.md b/testnets/holesky/README.md new file mode 100644 index 000000000..50a4cabbd --- /dev/null +++ b/testnets/holesky/README.md @@ -0,0 +1,55 @@ +# Holesky Launch Instructions + +## Components +The components that need to run to test Bolt on Holesky are: +- A synced execution client +- A synced beacon node +- Active validators +- Commit-Boost with Bolt configuration + +## Setup + +### Commit-Boost +#### Installation +To install the `commit-boost` CLI with `cargo`: +```bash +# Use specific commit hash to ensure compatibility +cargo install --locked --git https://github.com/Commit-Boost/commit-boost-client --rev 45ce8f1 commit-boost + +# Test installation +commit-boost --version +``` +#### Configuration +A commit-boost configuration file with Bolt support is provided at [`cb-bolt-config.toml`](./cb-bolt-config.toml). This file has support +for the custom PBS module ([bolt-boost](../../bolt-boost)) that implements the [constraints-API](https://chainbound.github.io/bolt-docs/api/builder), as +well as the [bolt-sidecar](../../bolt-sidecar) module. This file can be used as a template for your own configuration. + +To initialize commit-boost, run the following command: +```bash +commit-boost init --config cb-bolt-config.toml +``` + +This will create 3 files: +- `cb.docker-compose.yml`: which contains the full setup of the Commit-Boost services +- `.cb.env`: with local env variables, including JWTs for modules +- `target.json`: which enables dynamic discovery of services for metrics scraping via Prometheus, only created if metrics are enabled + +#### Running +The final step is to run the Commit-Boost services. This can be done with the following command: +```bash +commit-boost start --docker cb.docker-compose.yml --env .cb.env +``` +This will run all modules in Docker containers. + +> [!IMPORTANT] +> bolt-boost will be exposed at `pbs.port` (18550 by default), and your beacon node MUST be configured +> to point the `builder-api` to this port for Bolt to work. + +### Bolt Sidecar +Your sidecar + +### Validators +Validators must be configured to always prefer builder proposals over their own. Refer to client documentation for the specific configuration flags. +**If this is not set, it could lead to commitment faults**. + +#### Registration diff --git a/testnets/holesky/cb-bolt-config.toml b/testnets/holesky/cb-bolt-config.toml new file mode 100644 index 000000000..179be6e1b --- /dev/null +++ b/testnets/holesky/cb-bolt-config.toml @@ -0,0 +1,159 @@ +# The main configuration file for the Commit-Boost sidecar. +# Some fields are optional and can be omitted, in which case the default value, if present, will be used. + +# Chain spec id. Supported values: Mainnet, Holesky, Helder +chain = "Holesky" + +# Configuration for the PBS module +[pbs] +# Docker image to use for the PBS module. +# BOLT: We use the bolt-boost PBS module here. +docker_image = "ghcr.io/chainbound/bolt-boost:v0.3.0-alpha-rc.1" +# Whether to enable the PBS module to request signatures from the Signer module (not used in the default PBS image) +# OPTIONAL, DEFAULT: false +with_signer = false +# Port to receive BuilderAPI calls from beacon node +port = 18550 +# Whether to forward `status` calls to relays or skip and return 200 +# OPTIONAL, DEFAULT: true +relay_check = true +# Timeout in milliseconds for the `get_header` call to relays. Note that the CL has also a timeout (e.g. 1 second) so +# this should be lower than that, leaving some margin for overhead +# OPTIONAL, DEFAULT: 950 +timeout_get_header_ms = 950 +# Timeout in milliseconds for the `submit_blinded_block` call to relays. +# OPTIONAL, DEFAULT: 4000 +timeout_get_payload_ms = 4000 +# Timeout in milliseconds for the `register_validator` call to relays. +# OPTIONAL, DEFAULT: 3000 +timeout_register_validator_ms = 3000 +# Whether to skip signature verification of headers against the relay pubkey +# OPTIONAL, DEFAULT: false +skip_sigverify = false +# Minimum bid in ETH that will be accepted from `get_header` +# OPTIONAL, DEFAULT: 0.0 +min_bid_eth = 0.0 +# List of URLs of relay monitors to send registrations to +# OPTIONAL +relay_monitors = [] +# How late in milliseconds in the slot is "late". This impacts the `get_header` requests, by shortening timeouts for `get_header` calls to +# relays and make sure a header is returned within this deadline. If the request from the CL comes later in the slot, then fetching headers is skipped +# to force local building and miniminzing the risk of missed slots. See also the timing games section below +# OPTIONAL, DEFAULT: 2000 +late_in_slot_time_ms = 1000 + +# The PBS module needs one or more [[relays]] as defined below. +[[relays]] +# Relay ID to use in telemetry +# OPTIONAL, DEFAULT: URL hostname +id = "example-relay" +# Relay URL in the format scheme://pubkey@host +url = "http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz" +# Headers to send with each request for this relay +# OPTIONAL +# headers = { X-MyCustomHeader = "MyCustomValue" } +# Whether to enable timing games, as tuned by `target_first_request_ms` and `frequency_get_header_ms`. +# These values should be carefully chosen for each relay, as each relay has different latency and timing games setups. +# They should only be used by advanced users, and if mis-configured can result in unforeseen effects, e.g. fetching a lower header value, +# or getting a temporary IP ban. +# +# EXAMPLES +# Assuming: timeout_get_header_ms = 950, frequency_get_header_ms = 300, target_first_request_ms = 200, late_in_slot_time_ms = 2000 +# +# 1) CL request comes at 100ms in the slot (max timeout 1050ms in the slot), then: +# - sleep for 100ms +# - send request at 200ms with 850ms timeout +# - send request at 500ms with 550ms timeout +# - send request at 800ms with 250ms timeout +# 2) CL request comes at 1500ms in the slot (max timeout 2000ms in the slot), then: +# - send request at 1500ms with 500ms timeout +# - send request at 1800ms with 200ms timeout +# 3) CL request comes 2500ms in the slot then: +# - return 204 and force local build +# +# OPTIONAL, DEFAULT: false +enable_timing_games = false +# Target time in slot when to send the first header request +# OPTIONAL +target_first_request_ms = 200 +# Frequency in ms to send get_header requests +# OPTIONAL +frequency_get_header_ms = 300 + +# Configuration for the Signer Module, only required if any `commit` module is present, or if `pbs.with_signer = true` +# OPTIONAL +[signer] +# Docker image to use for the Signer module. +# OPTIONAL, DEFAULT: ghcr.io/commit-boost/signer:latest +docker_image = "commitboost_signer" +# Configuration for how the Signer module should load validator keys. Currently two types of loaders are supported: +# - File: load keys from a plain text file (unsafe, use only for testing purposes) +# - ValidatorsDir: load keys from a `keys` and `secrets` folder (ERC-2335 style keystores as used in Lighthouse) +[signer.loader] +# File: path to the keys file +key_path = "./keys.json" +# ValidatorsDir: path to the keys directory +# keys_path = "" +# ValidatorsDir: path to the secrets directory +# secrets_path = "" + +# Commit-Boost can optionally run "modules" which extend the capabilities of the sidecar. +# Currently, two types of modules are supported: +# - "commit": modules which request commitment signatures from the validator keys +# - "events": modules which callback to BuilderAPI events as triggered from the PBS modules, used e.g. for monitoring +# If any "commit" module is present, then the [signer] section should also be configured +# OPTIONAL +[[modules]] +# Unique ID of the module +id = "BOLT" +# Type of the module. Supported values: commit, events +type = "commit" +# Docker image of the module +docker_image = "ghcr.io/chainbound/bolt-sidecar:v0.3.0-alpha-rc.1" + +env_file = ".cb.env" + +[modules.env] +BOLT_SIDECAR_CHAIN = "holesky" + +BOLT_SIDECAR_CONSTRAINTS_API = "http://cb_pbs:18550" # The address of the PBS module +BOLT_SIDECAR_BEACON_API = "http://remotebeast:4400" +BOLT_SIDECAR_EXECUTION_API = "http://remotebeast:4485" +BOLT_SIDECAR_ENGINE_API = "http://remotebeast:4451" +BOLT_SIDECAR_JWT_HEX = "89732cef77d7e9a20021ee8f419dbbb51bdf7f60586932c272ddef02e70cb755" +BOLT_SIDECAR_BUILDER_PROXY_PORT = "18551" +BOLT_SIDECAR_FEE_RECIPIENT = "0x0000000000000000000000000000000000000000" +BOLT_SIDECAR_VALIDATOR_INDEXES = "1..2" + + +# Configuration for how metrics should be collected and scraped +# OPTIONAL, skip metrics collection if missing +[metrics] +# Path to a `prometheus.yml` file to use in Prometheus. If using a custom config file, be sure to add a +# file discovery section as follows: +# ```yml +# file_sd_configs: +# - files: +# - /etc/prometheus/targets.json +# ``` +# and use the `targets.json` file generated by `commit-boost init` +prometheus_config = "./prometheus.yml" +# Whether to start Grafana with built-in dashboards +# OPTIONAL, DEFAULT: true +use_grafana = true +# Whether to start cadvisor for system monitoring +# OPTIONAL, DEFAULT: true +use_cadvisor = false + +# Configuration for how logs should be collected and stored +# OPTIONAL, info to stdout if missing +[logs] +# Path to the log directory +# OPTIONAL, DEFAULT: /var/logs/commit-boost +log_dir_path = "./logs" +# Log level. Supported values: trace, debug, info, warn, error +# OPTIONAL, DEFAULT: debug to file, info to stdout +log_level = "debug" +# Maximum number of log files to keep +# OPTIONAL +max_log_files = 30 diff --git a/testnets/holesky/cb.docker-compose.yml b/testnets/holesky/cb.docker-compose.yml new file mode 100644 index 000000000..57637433f --- /dev/null +++ b/testnets/holesky/cb.docker-compose.yml @@ -0,0 +1,104 @@ +services: + cb_bolt: + image: ghcr.io/chainbound/bolt-sidecar:v0.3.0-alpha-rc.1 + container_name: cb_bolt + environment: + CB_MODULE_ID: BOLT + CB_CONFIG: /cb-config.toml + CB_SIGNER_JWT: ${CB_JWT_BOLT} + SIGNER_SERVER: cb_signer:20000 + BOLT_SIDECAR_CONSTRAINTS_API: http://cb_pbs:18550 + BOLT_SIDECAR_CHAIN: holesky + BOLT_SIDECAR_EXECUTION_API: http://remotebeast:4485 + BOLT_SIDECAR_ENGINE_API: http://remotebeast:4451 + BOLT_SIDECAR_BEACON_API: http://remotebeast:4400 + BOLT_SIDECAR_FEE_RECIPIENT: '0x0000000000000000000000000000000000000000' + BOLT_SIDECAR_VALIDATOR_INDEXES: 1..2 + BOLT_SIDECAR_BUILDER_PROXY_PORT: '18551' + BOLT_SIDECAR_JWT_HEX: 89732cef77d7e9a20021ee8f419dbbb51bdf7f60586932c272ddef02e70cb755 + METRICS_SERVER: 10000 + USE_FILE_LOGS: true + RUST_LOG: debug + MAX_LOG_FILES: 30 + volumes: + - ./cb-bolt-config.toml:/cb-config.toml:ro + - ./logs/BOLT:/var/logs/commit-boost + networks: + - signer_network + - monitoring_network + depends_on: + - cb_signer + env_file: .cb.env + cb_pbs: + image: ghcr.io/chainbound/bolt-boost:v0.3.0-alpha-rc.1 + container_name: cb_pbs + ports: + - 18550:18550 + environment: + CB_CONFIG: /cb-config.toml + USE_FILE_LOGS: true + RUST_LOG: debug + MAX_LOG_FILES: 30 + METRICS_SERVER: 10000 + volumes: + - ./cb-bolt-config.toml:/cb-config.toml:ro + - ./logs/pbs:/var/logs/commit-boost + networks: + - monitoring_network + cb_signer: + image: commitboost_signer + container_name: cb_signer + environment: + CB_CONFIG: /cb-config.toml + CB_JWTS: ${CB_JWTS} + SIGNER_SERVER: 20000 + USE_FILE_LOGS: true + RUST_LOG: debug + MAX_LOG_FILES: 30 + METRICS_SERVER: 10000 + CB_SIGNER_FILE: /keys.json + volumes: + - ./cb-bolt-config.toml:/cb-config.toml:ro + - ././keys.json:/keys.json:ro + - ./logs/signer:/var/logs/commit-boost + networks: + - signer_network + - monitoring_network + cb_prometheus: + image: prom/prometheus:latest + container_name: cb_prometheus + ports: + - 9090:9090 + volumes: + - ./prometheus.yml:/etc/prometheus/prometheus.yml + - ./targets.json:/etc/prometheus/targets.json + - prometheus-data:/prometheus + networks: + - monitoring_network + cb_grafana: + image: grafana/grafana:latest + container_name: cb_grafana + ports: + - 3000:3000 + environment: + - GF_SECURITY_ADMIN_PASSWORD=admin + volumes: + - ./grafana/dashboards:/etc/grafana/provisioning/dashboards + - ./grafana/datasources:/etc/grafana/provisioning/datasources + - grafana-data:/var/lib/grafana + networks: + - monitoring_network + depends_on: + - cb_prometheus + logging: + driver: none +volumes: + prometheus-data: + driver: local + grafana-data: + driver: local +networks: + monitoring_network: + driver: bridge + signer_network: + driver: bridge diff --git a/testnets/holesky/keys.json b/testnets/holesky/keys.json new file mode 100644 index 000000000..4689c5d75 --- /dev/null +++ b/testnets/holesky/keys.json @@ -0,0 +1,4 @@ +[ + "0088e364a5396a81b50febbdc8784663fb9089b5e67cbdc173991a00c587673f", + "0x16f3bec1b7f4f1b87c5e1930f944a6dda76ad211a89bc98e8c8e88b5069f8a04" +] diff --git a/testnets/holesky/logs/pbs/pbs.2024-09-11 b/testnets/holesky/logs/pbs/pbs.2024-09-11 new file mode 100644 index 000000000..5a49cc8e3 --- /dev/null +++ b/testnets/holesky/logs/pbs/pbs.2024-09-11 @@ -0,0 +1,46 @@ +{"timestamp":"2024-09-11T12:36:34.518374Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T12:36:34.518388Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T12:44:09.499978Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T12:44:09.499990Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T12:44:09.500852Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} +{"timestamp":"2024-09-11T12:44:09.501500Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} +{"timestamp":"2024-09-11T12:58:05.935766Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T12:58:05.935775Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T12:58:05.936286Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} +{"timestamp":"2024-09-11T12:58:05.936371Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} +{"timestamp":"2024-09-11T13:29:40.402543Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:29:40.402859Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:29:40.403625Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} +{"timestamp":"2024-09-11T13:29:40.403807Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} +{"timestamp":"2024-09-11T13:33:47.575507Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:33:47.575515Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:33:47.576128Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} +{"timestamp":"2024-09-11T13:33:47.576135Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} +{"timestamp":"2024-09-11T13:38:26.286570Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:38:26.286579Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:38:26.287236Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} +{"timestamp":"2024-09-11T13:38:26.288260Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} +{"timestamp":"2024-09-11T13:39:32.787030Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:39:32.787110Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:39:32.787435Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} +{"timestamp":"2024-09-11T13:39:32.787456Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} +{"timestamp":"2024-09-11T13:48:03.820547Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:48:03.820629Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:48:03.820971Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} +{"timestamp":"2024-09-11T13:48:03.821076Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} +{"timestamp":"2024-09-11T13:49:46.905956Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:49:46.906113Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:49:46.906254Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} +{"timestamp":"2024-09-11T13:49:46.906373Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} +{"timestamp":"2024-09-11T13:59:13.961663Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:59:13.961717Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:59:13.962299Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} +{"timestamp":"2024-09-11T13:59:13.962488Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} +{"timestamp":"2024-09-11T14:04:43.274986Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T14:04:43.275020Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T14:04:43.276642Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} +{"timestamp":"2024-09-11T14:04:43.276947Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} +{"timestamp":"2024-09-11T14:12:27.560971Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T14:12:27.561262Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T14:12:27.561943Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} +{"timestamp":"2024-09-11T14:12:27.562565Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} diff --git a/testnets/holesky/logs/signer/signer.2024-09-11 b/testnets/holesky/logs/signer/signer.2024-09-11 new file mode 100644 index 000000000..8d6b42d04 --- /dev/null +++ b/testnets/holesky/logs/signer/signer.2024-09-11 @@ -0,0 +1,16 @@ +{"timestamp":"2024-09-11T09:10:23.547308Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T10:06:23.447915Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T11:42:34.467791Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T12:36:34.491189Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T12:44:09.550877Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T12:58:05.985880Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T13:29:40.397913Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T13:33:47.606426Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T13:38:26.295424Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T13:39:32.787635Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T13:48:03.812147Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T13:49:46.904054Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T13:59:13.944821Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T14:04:43.307941Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T14:12:27.532823Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T14:12:27.821186Z","level":"DEBUG","fields":{"message":"New request","event":"get_pubkeys","req_id":"8b01425e-2329-4771-989f-f922572ea06a"},"target":"cb_signer::service"} diff --git a/testnets/holesky/prometheus.yml b/testnets/holesky/prometheus.yml new file mode 100644 index 000000000..91b5d5905 --- /dev/null +++ b/testnets/holesky/prometheus.yml @@ -0,0 +1,8 @@ +global: + scrape_interval: 15s + +scrape_configs: + - job_name: "commit-boost" + file_sd_configs: + - files: + - /etc/prometheus/targets.json diff --git a/testnets/holesky/targets.json b/testnets/holesky/targets.json new file mode 100644 index 000000000..c2437c1e3 --- /dev/null +++ b/testnets/holesky/targets.json @@ -0,0 +1,26 @@ +[ + { + "targets": [ + "cb_bolt:10000" + ], + "labels": { + "job": "cb_bolt" + } + }, + { + "targets": [ + "cb_pbs:10000" + ], + "labels": { + "job": "pbs" + } + }, + { + "targets": [ + "cb_signer:10000" + ], + "labels": { + "job": "signer" + } + } +] \ No newline at end of file From 2f4daf48b8846524e469e59bca2a894da6d1be3f Mon Sep 17 00:00:00 2001 From: Jonas Bostoen Date: Wed, 11 Sep 2024 16:14:47 +0200 Subject: [PATCH 17/30] feat(all): various fixes & compat with commit-boost --- bolt-boost/Dockerfile | 5 ++--- bolt-boost/src/metrics.rs | 2 +- bolt-sidecar/Dockerfile | 4 ++-- bolt-sidecar/src/config/mod.rs | 26 +++++++++++++------------- bolt-sidecar/src/config/signing.rs | 11 ++++------- 5 files changed, 22 insertions(+), 26 deletions(-) diff --git a/bolt-boost/Dockerfile b/bolt-boost/Dockerfile index a14e95611..005f44863 100644 --- a/bolt-boost/Dockerfile +++ b/bolt-boost/Dockerfile @@ -14,11 +14,10 @@ COPY . . RUN cargo build --release -FROM ubuntu AS runtime +FROM debian:bookworm-slim AS runtime WORKDIR /app -RUN apt-get update -RUN apt-get install -y openssl ca-certificates libssl3 libssl-dev +RUN apt-get update && apt-get install -y libssl-dev libssl3 openssl ca-certificates && rm -rf /var/lib/apt/lists/* COPY --from=builder /app/target/release/bolt-boost /usr/local/bin ENTRYPOINT ["/usr/local/bin/bolt-boost"] diff --git a/bolt-boost/src/metrics.rs b/bolt-boost/src/metrics.rs index f913a6e15..3d86f8939 100644 --- a/bolt-boost/src/metrics.rs +++ b/bolt-boost/src/metrics.rs @@ -24,7 +24,7 @@ lazy_static! { /// The size of the constraints cache pub static ref CONSTRAINTS_CACHE_SIZE: IntGauge = register_int_gauge_with_registry!( - "bolt_boost.constraints_cache_size", + "constraints_cache_size", "size of the constraints cache", BOLT_BOOST_METRICS ) diff --git a/bolt-sidecar/Dockerfile b/bolt-sidecar/Dockerfile index 7eb73069e..c4e8b5c90 100644 --- a/bolt-sidecar/Dockerfile +++ b/bolt-sidecar/Dockerfile @@ -1,4 +1,4 @@ -FROM rust:slim-bullseye AS compiler +FROM rust:slim-bookworm AS compiler RUN cargo install cargo-chef @@ -15,7 +15,7 @@ RUN cargo chef cook --release --recipe-path recipe.json COPY . . RUN cargo build --release -FROM debian:bullseye-slim +FROM debian:bookworm-slim WORKDIR /usr/local/bin COPY --from=builder /app/target/release/bolt-sidecar / RUN apt-get update && apt-get install -y libssl-dev ca-certificates && rm -rf /var/lib/apt/lists/* diff --git a/bolt-sidecar/src/config/mod.rs b/bolt-sidecar/src/config/mod.rs index 68953f4b2..85e04ff44 100644 --- a/bolt-sidecar/src/config/mod.rs +++ b/bolt-sidecar/src/config/mod.rs @@ -35,19 +35,19 @@ pub struct Opts { #[clap(long, env = "BOLT_SIDECAR_PORT")] pub(super) port: Option, /// URL for the beacon client - #[clap(long, env = "BOLT_SIDECAR_BEACON_API_URL")] + #[clap(long, env = "BOLT_SIDECAR_BEACON_API")] pub(super) beacon_api_url: String, - /// URL for the MEV-Boost sidecar client to use - #[clap(long, env = "BOLT_SIDECAR_MEVBOOST_URL")] - pub(super) mevboost_url: String, + /// URL for the constraints API + #[clap(long, env = "BOLT_SIDECAR_CONSTRAINTS_API")] + pub(super) constraints_url: String, /// Execution client API URL - #[clap(long, env = "BOLT_SIDECAR_EXECUTION_API_URL")] + #[clap(long, env = "BOLT_SIDECAR_EXECUTION_API")] pub(super) execution_api_url: String, /// Execution client Engine API URL - #[clap(long, env = "BOLT_SIDECAR_ENGINE_API_URL")] + #[clap(long, env = "BOLT_SIDECAR_ENGINE_API")] pub(super) engine_api_url: String, /// MEV-Boost proxy server port to use - #[clap(long, env = "BOLT_SIDECAR_MEVBOOST_PROXY_PORT")] + #[clap(long, env = "BOLT_SIDECAR_BUILDER_PROXY_PORT")] pub(super) mevboost_proxy_port: u16, /// Max number of commitments to accept per block #[clap(long, env = "BOLT_SIDECAR_MAX_COMMITMENTS")] @@ -196,11 +196,11 @@ impl TryFrom for Config { } if let Some(commit_boost_url) = &opts.signing.commit_boost_url { - if let Ok(url) = Url::parse(commit_boost_url) { - if let Ok(socket_addrs) = url.socket_addrs(|| None) { - config.commit_boost_address = Some(socket_addrs[0].to_string()); - } - } + config.commit_boost_address = Some(commit_boost_url.clone()); + } + + if let Some(cb_jwt) = &opts.signing.commit_boost_jwt_hex { + config.commit_boost_jwt_hex = Some(cb_jwt.clone()); } config.private_key = if let Some(sk) = opts.signing.private_key { @@ -241,7 +241,7 @@ impl TryFrom for Config { config.engine_api_url = opts.engine_api_url.parse()?; config.execution_api_url = opts.execution_api_url.parse()?; config.beacon_api_url = opts.beacon_api_url.parse()?; - config.mevboost_url = opts.mevboost_url.parse()?; + config.mevboost_url = opts.constraints_url.parse()?; config.fee_recipient = opts.fee_recipient; diff --git a/bolt-sidecar/src/config/signing.rs b/bolt-sidecar/src/config/signing.rs index c592b1cf6..75e627d02 100644 --- a/bolt-sidecar/src/config/signing.rs +++ b/bolt-sidecar/src/config/signing.rs @@ -1,11 +1,8 @@ -use clap::{ArgGroup, Args}; +use clap::Args; /// Command-line options for signing #[derive(Debug, Clone, Args)] -#[clap( - group = ArgGroup::new("signing-opts").required(true) - .args(&["private_key", "commit_boost_url", "commit_boost_jwt_hex"]) -)] +#[group(required = true, multiple = true)] pub struct SigningOpts { /// Private key to use for signing preconfirmation requests #[clap(long, env = "BOLT_SIDECAR_PRIVATE_KEY", conflicts_with("commit_boost_url"))] @@ -13,7 +10,7 @@ pub struct SigningOpts { /// URL for the commit-boost sidecar #[clap( long, - env = "BOLT_SIDECAR_CB_SIGNER_URL", + env = "SIGNER_SERVER", conflicts_with("private_key"), requires("commit_boost_jwt_hex") )] @@ -21,7 +18,7 @@ pub struct SigningOpts { /// JWT in hexadecimal format for authenticating with the commit-boost service #[clap( long, - env = "BOLT_SIDECAR_CB_JWT_HEX", + env = "CB_SIGNER_JWT", conflicts_with("private_key"), requires("commit_boost_url") )] From 977cd5b7980b4b34e1f14e74646e0c7527f82a17 Mon Sep 17 00:00:00 2001 From: Jonas Bostoen Date: Thu, 12 Sep 2024 10:50:20 +0200 Subject: [PATCH 18/30] doc(holesky): update holesky launch instructions + config --- .gitignore | 3 +++ testnets/holesky/.cb.env | 4 ++-- testnets/holesky/README.md | 26 ++++++++++++++++++++++---- testnets/holesky/cb-bolt-config.toml | 17 +++++++---------- testnets/holesky/cb.docker-compose.yml | 13 ++++++------- 5 files changed, 40 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index be2b1a284..2b58236ad 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ *_dump.log target/ +logs/ +cb.docker-compose.yml +.cb.env diff --git a/testnets/holesky/.cb.env b/testnets/holesky/.cb.env index 9faac7b8d..b47ef4ccb 100644 --- a/testnets/holesky/.cb.env +++ b/testnets/holesky/.cb.env @@ -1,2 +1,2 @@ -CB_JWT_BOLT=jN7FpDQZSWS9r1XzrGL3dbW6fBd0uzEa -CB_JWTS="{\"BOLT\":\"jN7FpDQZSWS9r1XzrGL3dbW6fBd0uzEa\"}" +CB_JWT_BOLT=MmH34tKim3rwXna4EvsXv0I8gLNU6E4n +CB_JWTS="{\"BOLT\":\"MmH34tKim3rwXna4EvsXv0I8gLNU6E4n\"}" diff --git a/testnets/holesky/README.md b/testnets/holesky/README.md index 50a4cabbd..85a6d4fe7 100644 --- a/testnets/holesky/README.md +++ b/testnets/holesky/README.md @@ -14,7 +14,7 @@ The components that need to run to test Bolt on Holesky are: To install the `commit-boost` CLI with `cargo`: ```bash # Use specific commit hash to ensure compatibility -cargo install --locked --git https://github.com/Commit-Boost/commit-boost-client --rev 45ce8f1 commit-boost +cargo install --locked --git https://github.com/Commit-Boost/commit-boost-client --rev aed00e8 commit-boost # Test installation commit-boost --version @@ -24,6 +24,23 @@ A commit-boost configuration file with Bolt support is provided at [`cb-bolt-con for the custom PBS module ([bolt-boost](../../bolt-boost)) that implements the [constraints-API](https://chainbound.github.io/bolt-docs/api/builder), as well as the [bolt-sidecar](../../bolt-sidecar) module. This file can be used as a template for your own configuration. +The important fields to configure are under the `[modules.env]` section of the `BOLT` module, which contain the environment variables to configure +the bolt sidecar: +```toml +[modules.env] +BOLT_SIDECAR_CHAIN = "holesky" + +BOLT_SIDECAR_CONSTRAINTS_API = "http://cb_pbs:18550" # The address of the PBS module (static) +BOLT_SIDECAR_BEACON_API = "" +BOLT_SIDECAR_EXECUTION_API = "" +BOLT_SIDECAR_ENGINE_API = "" # The execution layer engine API endpoint +BOLT_SIDECAR_JWT_HEX = "" # The engine JWT used to authenticate with the engine API +BOLT_SIDECAR_BUILDER_PROXY_PORT = "18551" # The port on which the sidecar builder-API will listen on. This is what your beacon node should connect to. +BOLT_SIDECAR_FEE_RECIPIENT = "" # The fee recipient +BOLT_SIDECAR_VALIDATOR_INDEXES = "" # The active validator indexes (can be defined as a comma-separated list, or a range) + # e.g. "0,1,2,3,4" or "0..4", or a combination of both +``` + To initialize commit-boost, run the following command: ```bash commit-boost init --config cb-bolt-config.toml @@ -32,7 +49,7 @@ commit-boost init --config cb-bolt-config.toml This will create 3 files: - `cb.docker-compose.yml`: which contains the full setup of the Commit-Boost services - `.cb.env`: with local env variables, including JWTs for modules -- `target.json`: which enables dynamic discovery of services for metrics scraping via Prometheus, only created if metrics are enabled +- `target.json`: which enables dynamic discovery of services for metrics scraping via Prometheus #### Running The final step is to run the Commit-Boost services. This can be done with the following command: @@ -42,14 +59,15 @@ commit-boost start --docker cb.docker-compose.yml --env .cb.env This will run all modules in Docker containers. > [!IMPORTANT] -> bolt-boost will be exposed at `pbs.port` (18550 by default), and your beacon node MUST be configured +> bolt-boost will be exposed at `pbs.port` (18551 by default, set with `BOLT_SIDECAR_BUILDER_PROXY_PORT`), and your beacon node MUST be configured > to point the `builder-api` to this port for Bolt to work. ### Bolt Sidecar -Your sidecar +WIP ### Validators Validators must be configured to always prefer builder proposals over their own. Refer to client documentation for the specific configuration flags. **If this is not set, it could lead to commitment faults**. #### Registration +WIP diff --git a/testnets/holesky/cb-bolt-config.toml b/testnets/holesky/cb-bolt-config.toml index 179be6e1b..ccd110742 100644 --- a/testnets/holesky/cb-bolt-config.toml +++ b/testnets/holesky/cb-bolt-config.toml @@ -111,20 +111,17 @@ type = "commit" # Docker image of the module docker_image = "ghcr.io/chainbound/bolt-sidecar:v0.3.0-alpha-rc.1" -env_file = ".cb.env" - [modules.env] BOLT_SIDECAR_CHAIN = "holesky" BOLT_SIDECAR_CONSTRAINTS_API = "http://cb_pbs:18550" # The address of the PBS module -BOLT_SIDECAR_BEACON_API = "http://remotebeast:4400" -BOLT_SIDECAR_EXECUTION_API = "http://remotebeast:4485" -BOLT_SIDECAR_ENGINE_API = "http://remotebeast:4451" -BOLT_SIDECAR_JWT_HEX = "89732cef77d7e9a20021ee8f419dbbb51bdf7f60586932c272ddef02e70cb755" -BOLT_SIDECAR_BUILDER_PROXY_PORT = "18551" -BOLT_SIDECAR_FEE_RECIPIENT = "0x0000000000000000000000000000000000000000" -BOLT_SIDECAR_VALIDATOR_INDEXES = "1..2" - +BOLT_SIDECAR_BEACON_API = "http://100.85.200.41:4400" +BOLT_SIDECAR_EXECUTION_API = "http://100.85.200.41:4485" +BOLT_SIDECAR_ENGINE_API = "http://100.85.200.41:4451" # The execution layer engine API endpoint +BOLT_SIDECAR_JWT_HEX = "89732cef77d7e9a20021ee8f419dbbb51bdf7f60586932c272ddef02e70cb755" # The engine JWT +BOLT_SIDECAR_BUILDER_PROXY_PORT = "18551" # The port on which the sidecar builder-API will listen on. This is what your beacon node should connect to. +BOLT_SIDECAR_FEE_RECIPIENT = "0x0000000000000000000000000000000000000000" # The fee recipient +BOLT_SIDECAR_VALIDATOR_INDEXES = "1..2" # The active validator indexes # Configuration for how metrics should be collected and scraped # OPTIONAL, skip metrics collection if missing diff --git a/testnets/holesky/cb.docker-compose.yml b/testnets/holesky/cb.docker-compose.yml index 57637433f..2571fa71f 100644 --- a/testnets/holesky/cb.docker-compose.yml +++ b/testnets/holesky/cb.docker-compose.yml @@ -7,15 +7,15 @@ services: CB_CONFIG: /cb-config.toml CB_SIGNER_JWT: ${CB_JWT_BOLT} SIGNER_SERVER: cb_signer:20000 - BOLT_SIDECAR_CONSTRAINTS_API: http://cb_pbs:18550 - BOLT_SIDECAR_CHAIN: holesky - BOLT_SIDECAR_EXECUTION_API: http://remotebeast:4485 - BOLT_SIDECAR_ENGINE_API: http://remotebeast:4451 - BOLT_SIDECAR_BEACON_API: http://remotebeast:4400 + BOLT_SIDECAR_ENGINE_API: http://100.85.200.41:4451 BOLT_SIDECAR_FEE_RECIPIENT: '0x0000000000000000000000000000000000000000' - BOLT_SIDECAR_VALIDATOR_INDEXES: 1..2 BOLT_SIDECAR_BUILDER_PROXY_PORT: '18551' + BOLT_SIDECAR_CHAIN: holesky + BOLT_SIDECAR_VALIDATOR_INDEXES: 1..2 BOLT_SIDECAR_JWT_HEX: 89732cef77d7e9a20021ee8f419dbbb51bdf7f60586932c272ddef02e70cb755 + BOLT_SIDECAR_EXECUTION_API: http://100.85.200.41:4485 + BOLT_SIDECAR_CONSTRAINTS_API: http://cb_pbs:18550 + BOLT_SIDECAR_BEACON_API: http://100.85.200.41:4400 METRICS_SERVER: 10000 USE_FILE_LOGS: true RUST_LOG: debug @@ -28,7 +28,6 @@ services: - monitoring_network depends_on: - cb_signer - env_file: .cb.env cb_pbs: image: ghcr.io/chainbound/bolt-boost:v0.3.0-alpha-rc.1 container_name: cb_pbs From f18a6350b7916e0e753d71e571f893c9f3565685 Mon Sep 17 00:00:00 2001 From: Jonas Bostoen Date: Tue, 10 Sep 2024 11:28:44 +0200 Subject: [PATCH 19/30] chore(contracts): forge fmt --- bolt-contracts/script/ReadRegistry.s.sol | 16 +-- .../script/RegisterValidators.s.sol | 21 ++-- .../src/contracts/BoltChallenger.sol | 116 +++++------------- bolt-contracts/src/contracts/BoltRegistry.sol | 27 +--- .../src/interfaces/IBoltRegistry.sol | 20 +-- bolt-contracts/test/BoltRegistry.t.sol | 5 +- .../test/StringToUintArrayLib.t.sol | 3 +- 7 files changed, 51 insertions(+), 157 deletions(-) diff --git a/bolt-contracts/script/ReadRegistry.s.sol b/bolt-contracts/script/ReadRegistry.s.sol index 0e26d204e..9abfbb86a 100644 --- a/bolt-contracts/script/ReadRegistry.s.sol +++ b/bolt-contracts/script/ReadRegistry.s.sol @@ -12,21 +12,11 @@ contract ReadRegistry is Script { console.log("Bolt registry address:", registryAddress); BoltRegistry registry = BoltRegistry(registryAddress); - console.log( - "Bolt registry minimum collateral:", - registry.MINIMUM_COLLATERAL() - ); + console.log("Bolt registry minimum collateral:", registry.MINIMUM_COLLATERAL()); for (uint64 i = 0; i < 2000; i++) { - try registry.getOperatorForValidator(i) returns ( - IBoltRegistry.Registrant memory operator - ) { - console.log( - "Operator for validator found", - i, - ":", - operator.operator - ); + try registry.getOperatorForValidator(i) returns (IBoltRegistry.Registrant memory operator) { + console.log("Operator for validator found", i, ":", operator.operator); console.log("Operator RPC:", operator.metadata.rpc); } catch { // console.log("No operator for validator", i); diff --git a/bolt-contracts/script/RegisterValidators.s.sol b/bolt-contracts/script/RegisterValidators.s.sol index e4554fd88..04f9cd74f 100644 --- a/bolt-contracts/script/RegisterValidators.s.sol +++ b/bolt-contracts/script/RegisterValidators.s.sol @@ -24,10 +24,7 @@ contract RegisterValidators is Script { console.log("Bolt registry address:", registryAddress); BoltRegistry registry = BoltRegistry(registryAddress); - console.log( - "Bolt registry minimum collateral:", - registry.MINIMUM_COLLATERAL() - ); + console.log("Bolt registry minimum collateral:", registry.MINIMUM_COLLATERAL()); address sender = vm.addr(signerKey); @@ -39,11 +36,7 @@ contract RegisterValidators is Script { } // Register with minimal collateral - registry.register{value: registry.MINIMUM_COLLATERAL()}( - validatorIndexes, - rpc, - "" - ); + registry.register{value: registry.MINIMUM_COLLATERAL()}(validatorIndexes, rpc, ""); vm.stopBroadcast(); } @@ -62,7 +55,7 @@ library StringToUintArrayLib { uint256 rangeStart; for (uint256 i = 0; i < strBytes.length; i++) { - if (strBytes[i] == ',') { + if (strBytes[i] == ",") { if (parsingRange) { // Handle end of range for (uint256 j = rangeStart; j <= tempNum; j++) { @@ -76,15 +69,15 @@ library StringToUintArrayLib { vecIndex++; } tempNum = 0; - } else if (strBytes[i] == '.') { - if (i + 1 < strBytes.length && strBytes[i + 1] == '.') { + } else if (strBytes[i] == ".") { + if (i + 1 < strBytes.length && strBytes[i + 1] == ".") { // Handle start of range parsingRange = true; rangeStart = tempNum; tempNum = 0; i++; // Skip next dot } - } else if (strBytes[i] >= '0' && strBytes[i] <= '9') { + } else if (strBytes[i] >= "0" && strBytes[i] <= "9") { tempNum = tempNum * 10 + (uint8(strBytes[i]) - 48); // Convert ASCII to integer } } @@ -108,4 +101,4 @@ library StringToUintArrayLib { return result; } -} \ No newline at end of file +} diff --git a/bolt-contracts/src/contracts/BoltChallenger.sol b/bolt-contracts/src/contracts/BoltChallenger.sol index d66784cc9..7b120d915 100644 --- a/bolt-contracts/src/contracts/BoltChallenger.sol +++ b/bolt-contracts/src/contracts/BoltChallenger.sol @@ -78,12 +78,7 @@ contract BoltChallenger is IBoltChallenger { /// @param _boltRegistry The address of the BoltRegistry contract /// @param _reliquary The address of the Relic Reliquary contract /// @param _blockHeaderProver The address of the Relic block header prover contract - constructor( - address _boltRegistry, - address _reliquary, - address _blockHeaderProver, - address _accountInfoProver - ) { + constructor(address _boltRegistry, address _reliquary, address _blockHeaderProver, address _accountInfoProver) { boltRegistry = IBoltRegistry(_boltRegistry); reliquary = IReliquary(_reliquary); @@ -100,10 +95,7 @@ contract BoltChallenger is IBoltChallenger { /// @notice A challenge requires a bond to be transferred to this contract to avoid spamming. /// @param _basedProposer The address of the proposer to challenge /// @param _signedCommitment The signed commitment that the proposer is getting challenged for - function challengeProposer( - address _basedProposer, - SignedCommitment calldata _signedCommitment - ) public payable { + function challengeProposer(address _basedProposer, SignedCommitment calldata _signedCommitment) public payable { // First sanity checks if (_basedProposer == address(0) || _signedCommitment.slot == 0) { revert InvalidChallenge(); @@ -119,9 +111,8 @@ contract BoltChallenger is IBoltChallenger { // Check if the target slot is not too far in the past if ( - BeaconChainUtils._getSlotFromTimestamp(block.timestamp) - - _signedCommitment.slot > - CHALLENGE_RETROACTIVE_TARGET_SLOT_WINDOW + BeaconChainUtils._getSlotFromTimestamp(block.timestamp) - _signedCommitment.slot + > CHALLENGE_RETROACTIVE_TARGET_SLOT_WINDOW ) { // Challenges cannot be opened for slots that are too far in the past, because we rely // on the BEACON_ROOTS ring buffer to be available for the challenge to be resolved. @@ -142,12 +133,7 @@ contract BoltChallenger is IBoltChallenger { } // Check if the signed commitment was made by the challenged based proposer - if ( - _recoverCommitmentSigner( - commitmentID, - _signedCommitment.signature - ) != _basedProposer - ) { + if (_recoverCommitmentSigner(commitmentID, _signedCommitment.signature) != _basedProposer) { revert InvalidCommitmentSigner(); } @@ -157,9 +143,7 @@ contract BoltChallenger is IBoltChallenger { // Get the beacon block root for the target slot. We store it in the Challenge so that // it can be used even after 8192 slots have passed (the limit of the BEACON_ROOTS contract) - bytes32 beaconBlockRoot = BeaconChainUtils._getBeaconBlockRoot( - _signedCommitment.slot - ); + bytes32 beaconBlockRoot = BeaconChainUtils._getBeaconBlockRoot(_signedCommitment.slot); // ==== Create a new challenge ==== @@ -205,9 +189,7 @@ contract BoltChallenger is IBoltChallenger { // Check if the challenge has expired. // This means that the validator failed to honor the commitment and will get slashed. - if ( - block.timestamp - challenge.openTimestamp > MAX_CHALLENGE_DURATION - ) { + if (block.timestamp - challenge.openTimestamp > MAX_CHALLENGE_DURATION) { // Part of the slashed amount will also be returned to the challenger as a reward. // This is the reason we don't have access control in this function. // TODO: slash the based proposer. @@ -221,14 +203,10 @@ contract BoltChallenger is IBoltChallenger { } // Derive the block header data of the target block from the block header proof - CoreTypes.BlockHeaderData - memory verifiedHeader = _deriveBlockHeaderInfo(_blockHeaderProof); + CoreTypes.BlockHeaderData memory verifiedHeader = _deriveBlockHeaderInfo(_blockHeaderProof); // Derive the preconfirmed sender's account data from the account data proof - CoreTypes.AccountData memory verifiedAccount = _deriveAccountData( - _accountDataProof, - verifiedHeader.Number - ); + CoreTypes.AccountData memory verifiedAccount = _deriveAccountData(_accountDataProof, verifiedHeader.Number); // Check that the nonce of the preconfirmed sender is valid (not too low) // at the time of the based proposer's slot. @@ -241,10 +219,7 @@ contract BoltChallenger is IBoltChallenger { // Check that the balance of the preconfirmed sender is enough to cover the base fee // of the block. - if ( - verifiedAccount.Balance < - challenge.signedCommitment.gasUsed * verifiedHeader.BaseFee - ) { + if (verifiedAccount.Balance < challenge.signedCommitment.gasUsed * verifiedHeader.BaseFee) { // consider the challenge unsuccessful: the user doesn't have enough balance to cover the gas // thus invalidating the preconfirmation: the proposer is not at fault. _onChallengeFailure(_challengeID); @@ -257,12 +232,7 @@ contract BoltChallenger is IBoltChallenger { // Check if the block header timestamp is UP TO the challenge's target slot. // It can be earlier, in case the transaction was included before the based proposer's slot. - if ( - verifiedHeader.Time > - BeaconChainUtils._getTimestampFromSlot( - challenge.signedCommitment.slot - ) - ) { + if (verifiedHeader.Time > BeaconChainUtils._getTimestampFromSlot(challenge.signedCommitment.slot)) { // The block header timestamp is after the target slot, so the proposer didn't // honor the preconfirmation and the challenge is successful. // TODO: slash the based proposer @@ -271,10 +241,7 @@ contract BoltChallenger is IBoltChallenger { } bool isValid = _verifyInclusionProof( - verifiedHeader.TxHash, - _transactionIndex, - _inclusionProof, - challenge.signedCommitment.signedRawTransaction + verifiedHeader.TxHash, _transactionIndex, _inclusionProof, challenge.signedCommitment.signedRawTransaction ); if (!isValid) { @@ -308,18 +275,13 @@ contract BoltChallenger is IBoltChallenger { /// @notice Fetch trustlessly valid block header data /// @param _proof The ABI-encoded proof of the block header /// @return header The block header data - function _deriveBlockHeaderInfo( - bytes calldata _proof - ) internal returns (CoreTypes.BlockHeaderData memory header) { + function _deriveBlockHeaderInfo(bytes calldata _proof) internal returns (CoreTypes.BlockHeaderData memory header) { // TODO: handle fee for proving. make payable? Fact memory fact = blockHeaderProver.prove(_proof, false); header = abi.decode(fact.data, (CoreTypes.BlockHeaderData)); - if ( - FactSignature.unwrap(fact.sig) != - FactSignature.unwrap(FactSigs.blockHeaderSig(header.Number)) - ) { + if (FactSignature.unwrap(fact.sig) != FactSignature.unwrap(FactSigs.blockHeaderSig(header.Number))) { revert UnexpectedFactSignature(); } } @@ -328,20 +290,17 @@ contract BoltChallenger is IBoltChallenger { /// @param _proof The ABI-encoded proof of the account data /// @param _blockNumber The block number for which the account data is being proven /// @return account The account data - function _deriveAccountData( - bytes calldata _proof, - uint256 _blockNumber - ) internal returns (CoreTypes.AccountData memory account) { + function _deriveAccountData(bytes calldata _proof, uint256 _blockNumber) + internal + returns (CoreTypes.AccountData memory account) + { // TODO: handle fee for proving. make payable? Fact memory fact = accountInfoProver.prove(_proof, false); account = abi.decode(fact.data, (CoreTypes.AccountData)); // verify that the account data proof was provided for the correct block - if ( - FactSignature.unwrap(fact.sig) != - FactSignature.unwrap(FactSigs.accountFactSig(_blockNumber)) - ) { + if (FactSignature.unwrap(fact.sig) != FactSignature.unwrap(FactSigs.accountFactSig(_blockNumber))) { revert UnexpectedFactSignature(); } } @@ -367,29 +326,20 @@ contract BoltChallenger is IBoltChallenger { // To read more, check out https://github.com/ethereum/consensus-specs/blob/dev/ssz/simple-serialize.md#merkleization uint256 generalizedIndex = 2_097_152 + _transactionIndex; - bytes32 leaf = SSZContainers._transactionHashTreeRoot( - _signedRawTransaction - ); + bytes32 leaf = SSZContainers._transactionHashTreeRoot(_signedRawTransaction); - isValid = SSZ._verifyProof( - _inclusionProof, - _transactionsRoot, - leaf, - generalizedIndex - ); + isValid = SSZ._verifyProof(_inclusionProof, _transactionsRoot, leaf, generalizedIndex); } /// @notice Recover the signer of a commitment /// @param _commitmentSignature The signature of the commitment /// @param _commitmentHash The keccak hash of an unsigned message - function _recoverCommitmentSigner( - bytes32 _commitmentHash, - bytes calldata _commitmentSignature - ) internal pure returns (address) { - (address signer, ECDSA.RecoverError err, ) = ECDSA.tryRecover( - _commitmentHash, - _commitmentSignature - ); + function _recoverCommitmentSigner(bytes32 _commitmentHash, bytes calldata _commitmentSignature) + internal + pure + returns (address) + { + (address signer, ECDSA.RecoverError err,) = ECDSA.tryRecover(_commitmentHash, _commitmentSignature); if (err != ECDSA.RecoverError.NoError || signer == address(0)) { revert InvalidCommitmentSignature(); } @@ -398,16 +348,8 @@ contract BoltChallenger is IBoltChallenger { } /// @notice Hashes the inclusion commitment to a unique ID to index the challenge - function _getCommitmentID( - SignedCommitment memory _commitment - ) internal pure returns (bytes32) { + function _getCommitmentID(SignedCommitment memory _commitment) internal pure returns (bytes32) { return - keccak256( - abi.encodePacked( - _commitment.slot, - _commitment.transactionHash, - _commitment.signedRawTransaction - ) - ); + keccak256(abi.encodePacked(_commitment.slot, _commitment.transactionHash, _commitment.signedRawTransaction)); } } diff --git a/bolt-contracts/src/contracts/BoltRegistry.sol b/bolt-contracts/src/contracts/BoltRegistry.sol index c064eda8d..048d58e05 100644 --- a/bolt-contracts/src/contracts/BoltRegistry.sol +++ b/bolt-contracts/src/contracts/BoltRegistry.sol @@ -25,11 +25,7 @@ contract BoltRegistry is IBoltRegistry { } /// @notice Allows a based proposer to opt-in to the protocol - function register( - uint64[] calldata validatorIndexes, - string calldata rpc, - bytes calldata extra - ) external payable { + function register(uint64[] calldata validatorIndexes, string calldata rpc, bytes calldata extra) external payable { if (msg.value < MINIMUM_COLLATERAL) { revert InsufficientCollateral(); } @@ -40,15 +36,8 @@ contract BoltRegistry is IBoltRegistry { MetaData memory metadata = MetaData(rpc, extra); - registrants[msg.sender] = Registrant( - msg.sender, - validatorIndexes, - block.timestamp, - 0, - msg.value, - Status.ACTIVE, - metadata - ); + registrants[msg.sender] = + Registrant(msg.sender, validatorIndexes, block.timestamp, 0, msg.value, Status.ACTIVE, metadata); operators.push(msg.sender); @@ -105,7 +94,7 @@ contract BoltRegistry is IBoltRegistry { break; } } - + delete registrants[msg.sender]; for (uint256 i = 0; i < registrant.validatorIndexes.length; i++) { @@ -127,16 +116,12 @@ contract BoltRegistry is IBoltRegistry { /// @notice Get the status of a based proposer /// @param _operator The address of the operator /// @return The status of the based proposer - function getOperatorStatus( - address _operator - ) external view returns (Status) { + function getOperatorStatus(address _operator) external view returns (Status) { // Will return INACTIVE if the operator is not registered return registrants[_operator].status; } - function getOperatorForValidator( - uint64 _validatorIndex - ) external view returns (Registrant memory) { + function getOperatorForValidator(uint64 _validatorIndex) external view returns (Registrant memory) { if (delegations[_validatorIndex] != address(0)) { return registrants[delegations[_validatorIndex]]; } diff --git a/bolt-contracts/src/interfaces/IBoltRegistry.sol b/bolt-contracts/src/interfaces/IBoltRegistry.sol index 283f8f505..7810a65c2 100644 --- a/bolt-contracts/src/interfaces/IBoltRegistry.sol +++ b/bolt-contracts/src/interfaces/IBoltRegistry.sol @@ -41,27 +41,15 @@ interface IBoltRegistry { /// @notice Event to log the status change of a based proposer event StatusChange(address indexed operator, Status status); - event Registered( - address indexed operator, - uint64[] validatorIndexes, - MetaData metadata - ); + event Registered(address indexed operator, uint64[] validatorIndexes, MetaData metadata); - function register( - uint64[] calldata validatorIndexes, - string calldata rpc, - bytes calldata extra - ) external payable; + function register(uint64[] calldata validatorIndexes, string calldata rpc, bytes calldata extra) external payable; function isActiveOperator(address _operator) external view returns (bool); - function getOperatorStatus( - address _operator - ) external view returns (Status); + function getOperatorStatus(address _operator) external view returns (Status); - function getOperatorForValidator( - uint64 _validatorIndex - ) external view returns (Registrant memory); + function getOperatorForValidator(uint64 _validatorIndex) external view returns (Registrant memory); function startExit() external; diff --git a/bolt-contracts/test/BoltRegistry.t.sol b/bolt-contracts/test/BoltRegistry.t.sol index 9280a2c67..155b6f76b 100644 --- a/bolt-contracts/test/BoltRegistry.t.sol +++ b/bolt-contracts/test/BoltRegistry.t.sol @@ -27,10 +27,7 @@ contract BoltRegistryTest is Test { registry.register{value: 10 ether}(validatorIndexes, "rpc", ""); - assertEq( - uint8(registry.getOperatorStatus(alice)), - uint8(IBoltRegistry.Status.ACTIVE) - ); + assertEq(uint8(registry.getOperatorStatus(alice)), uint8(IBoltRegistry.Status.ACTIVE)); assertEq(registry.isActiveOperator(alice), true); diff --git a/bolt-contracts/test/StringToUintArrayLib.t.sol b/bolt-contracts/test/StringToUintArrayLib.t.sol index aaae88073..15bc7a5ff 100644 --- a/bolt-contracts/test/StringToUintArrayLib.t.sol +++ b/bolt-contracts/test/StringToUintArrayLib.t.sol @@ -5,7 +5,6 @@ import "forge-std/Test.sol"; import "../script/RegisterValidators.s.sol"; contract StringToUintArrayTest is Test { - function setUp() public {} function testParseValidatorIndexes1() public pure { @@ -79,4 +78,4 @@ contract StringToUintArrayTest is Test { assertEq(indexes[i], i + 1); } } -} \ No newline at end of file +} From 2bfa23861f4eb38bc9cea82e314aee7d7dabf23a Mon Sep 17 00:00:00 2001 From: Jonas Bostoen Date: Wed, 11 Sep 2024 16:13:42 +0200 Subject: [PATCH 20/30] doc(holesky): initial holesky launch instructions --- testnets/holesky/.cb.env | 2 + testnets/holesky/README.md | 55 ++++++ testnets/holesky/cb-bolt-config.toml | 159 ++++++++++++++++++ testnets/holesky/cb.docker-compose.yml | 104 ++++++++++++ testnets/holesky/keys.json | 4 + testnets/holesky/logs/pbs/pbs.2024-09-11 | 46 +++++ .../holesky/logs/signer/signer.2024-09-11 | 16 ++ testnets/holesky/prometheus.yml | 8 + testnets/holesky/targets.json | 26 +++ 9 files changed, 420 insertions(+) create mode 100644 testnets/holesky/.cb.env create mode 100644 testnets/holesky/README.md create mode 100644 testnets/holesky/cb-bolt-config.toml create mode 100644 testnets/holesky/cb.docker-compose.yml create mode 100644 testnets/holesky/keys.json create mode 100644 testnets/holesky/logs/pbs/pbs.2024-09-11 create mode 100644 testnets/holesky/logs/signer/signer.2024-09-11 create mode 100644 testnets/holesky/prometheus.yml create mode 100644 testnets/holesky/targets.json diff --git a/testnets/holesky/.cb.env b/testnets/holesky/.cb.env new file mode 100644 index 000000000..9faac7b8d --- /dev/null +++ b/testnets/holesky/.cb.env @@ -0,0 +1,2 @@ +CB_JWT_BOLT=jN7FpDQZSWS9r1XzrGL3dbW6fBd0uzEa +CB_JWTS="{\"BOLT\":\"jN7FpDQZSWS9r1XzrGL3dbW6fBd0uzEa\"}" diff --git a/testnets/holesky/README.md b/testnets/holesky/README.md new file mode 100644 index 000000000..50a4cabbd --- /dev/null +++ b/testnets/holesky/README.md @@ -0,0 +1,55 @@ +# Holesky Launch Instructions + +## Components +The components that need to run to test Bolt on Holesky are: +- A synced execution client +- A synced beacon node +- Active validators +- Commit-Boost with Bolt configuration + +## Setup + +### Commit-Boost +#### Installation +To install the `commit-boost` CLI with `cargo`: +```bash +# Use specific commit hash to ensure compatibility +cargo install --locked --git https://github.com/Commit-Boost/commit-boost-client --rev 45ce8f1 commit-boost + +# Test installation +commit-boost --version +``` +#### Configuration +A commit-boost configuration file with Bolt support is provided at [`cb-bolt-config.toml`](./cb-bolt-config.toml). This file has support +for the custom PBS module ([bolt-boost](../../bolt-boost)) that implements the [constraints-API](https://chainbound.github.io/bolt-docs/api/builder), as +well as the [bolt-sidecar](../../bolt-sidecar) module. This file can be used as a template for your own configuration. + +To initialize commit-boost, run the following command: +```bash +commit-boost init --config cb-bolt-config.toml +``` + +This will create 3 files: +- `cb.docker-compose.yml`: which contains the full setup of the Commit-Boost services +- `.cb.env`: with local env variables, including JWTs for modules +- `target.json`: which enables dynamic discovery of services for metrics scraping via Prometheus, only created if metrics are enabled + +#### Running +The final step is to run the Commit-Boost services. This can be done with the following command: +```bash +commit-boost start --docker cb.docker-compose.yml --env .cb.env +``` +This will run all modules in Docker containers. + +> [!IMPORTANT] +> bolt-boost will be exposed at `pbs.port` (18550 by default), and your beacon node MUST be configured +> to point the `builder-api` to this port for Bolt to work. + +### Bolt Sidecar +Your sidecar + +### Validators +Validators must be configured to always prefer builder proposals over their own. Refer to client documentation for the specific configuration flags. +**If this is not set, it could lead to commitment faults**. + +#### Registration diff --git a/testnets/holesky/cb-bolt-config.toml b/testnets/holesky/cb-bolt-config.toml new file mode 100644 index 000000000..179be6e1b --- /dev/null +++ b/testnets/holesky/cb-bolt-config.toml @@ -0,0 +1,159 @@ +# The main configuration file for the Commit-Boost sidecar. +# Some fields are optional and can be omitted, in which case the default value, if present, will be used. + +# Chain spec id. Supported values: Mainnet, Holesky, Helder +chain = "Holesky" + +# Configuration for the PBS module +[pbs] +# Docker image to use for the PBS module. +# BOLT: We use the bolt-boost PBS module here. +docker_image = "ghcr.io/chainbound/bolt-boost:v0.3.0-alpha-rc.1" +# Whether to enable the PBS module to request signatures from the Signer module (not used in the default PBS image) +# OPTIONAL, DEFAULT: false +with_signer = false +# Port to receive BuilderAPI calls from beacon node +port = 18550 +# Whether to forward `status` calls to relays or skip and return 200 +# OPTIONAL, DEFAULT: true +relay_check = true +# Timeout in milliseconds for the `get_header` call to relays. Note that the CL has also a timeout (e.g. 1 second) so +# this should be lower than that, leaving some margin for overhead +# OPTIONAL, DEFAULT: 950 +timeout_get_header_ms = 950 +# Timeout in milliseconds for the `submit_blinded_block` call to relays. +# OPTIONAL, DEFAULT: 4000 +timeout_get_payload_ms = 4000 +# Timeout in milliseconds for the `register_validator` call to relays. +# OPTIONAL, DEFAULT: 3000 +timeout_register_validator_ms = 3000 +# Whether to skip signature verification of headers against the relay pubkey +# OPTIONAL, DEFAULT: false +skip_sigverify = false +# Minimum bid in ETH that will be accepted from `get_header` +# OPTIONAL, DEFAULT: 0.0 +min_bid_eth = 0.0 +# List of URLs of relay monitors to send registrations to +# OPTIONAL +relay_monitors = [] +# How late in milliseconds in the slot is "late". This impacts the `get_header` requests, by shortening timeouts for `get_header` calls to +# relays and make sure a header is returned within this deadline. If the request from the CL comes later in the slot, then fetching headers is skipped +# to force local building and miniminzing the risk of missed slots. See also the timing games section below +# OPTIONAL, DEFAULT: 2000 +late_in_slot_time_ms = 1000 + +# The PBS module needs one or more [[relays]] as defined below. +[[relays]] +# Relay ID to use in telemetry +# OPTIONAL, DEFAULT: URL hostname +id = "example-relay" +# Relay URL in the format scheme://pubkey@host +url = "http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz" +# Headers to send with each request for this relay +# OPTIONAL +# headers = { X-MyCustomHeader = "MyCustomValue" } +# Whether to enable timing games, as tuned by `target_first_request_ms` and `frequency_get_header_ms`. +# These values should be carefully chosen for each relay, as each relay has different latency and timing games setups. +# They should only be used by advanced users, and if mis-configured can result in unforeseen effects, e.g. fetching a lower header value, +# or getting a temporary IP ban. +# +# EXAMPLES +# Assuming: timeout_get_header_ms = 950, frequency_get_header_ms = 300, target_first_request_ms = 200, late_in_slot_time_ms = 2000 +# +# 1) CL request comes at 100ms in the slot (max timeout 1050ms in the slot), then: +# - sleep for 100ms +# - send request at 200ms with 850ms timeout +# - send request at 500ms with 550ms timeout +# - send request at 800ms with 250ms timeout +# 2) CL request comes at 1500ms in the slot (max timeout 2000ms in the slot), then: +# - send request at 1500ms with 500ms timeout +# - send request at 1800ms with 200ms timeout +# 3) CL request comes 2500ms in the slot then: +# - return 204 and force local build +# +# OPTIONAL, DEFAULT: false +enable_timing_games = false +# Target time in slot when to send the first header request +# OPTIONAL +target_first_request_ms = 200 +# Frequency in ms to send get_header requests +# OPTIONAL +frequency_get_header_ms = 300 + +# Configuration for the Signer Module, only required if any `commit` module is present, or if `pbs.with_signer = true` +# OPTIONAL +[signer] +# Docker image to use for the Signer module. +# OPTIONAL, DEFAULT: ghcr.io/commit-boost/signer:latest +docker_image = "commitboost_signer" +# Configuration for how the Signer module should load validator keys. Currently two types of loaders are supported: +# - File: load keys from a plain text file (unsafe, use only for testing purposes) +# - ValidatorsDir: load keys from a `keys` and `secrets` folder (ERC-2335 style keystores as used in Lighthouse) +[signer.loader] +# File: path to the keys file +key_path = "./keys.json" +# ValidatorsDir: path to the keys directory +# keys_path = "" +# ValidatorsDir: path to the secrets directory +# secrets_path = "" + +# Commit-Boost can optionally run "modules" which extend the capabilities of the sidecar. +# Currently, two types of modules are supported: +# - "commit": modules which request commitment signatures from the validator keys +# - "events": modules which callback to BuilderAPI events as triggered from the PBS modules, used e.g. for monitoring +# If any "commit" module is present, then the [signer] section should also be configured +# OPTIONAL +[[modules]] +# Unique ID of the module +id = "BOLT" +# Type of the module. Supported values: commit, events +type = "commit" +# Docker image of the module +docker_image = "ghcr.io/chainbound/bolt-sidecar:v0.3.0-alpha-rc.1" + +env_file = ".cb.env" + +[modules.env] +BOLT_SIDECAR_CHAIN = "holesky" + +BOLT_SIDECAR_CONSTRAINTS_API = "http://cb_pbs:18550" # The address of the PBS module +BOLT_SIDECAR_BEACON_API = "http://remotebeast:4400" +BOLT_SIDECAR_EXECUTION_API = "http://remotebeast:4485" +BOLT_SIDECAR_ENGINE_API = "http://remotebeast:4451" +BOLT_SIDECAR_JWT_HEX = "89732cef77d7e9a20021ee8f419dbbb51bdf7f60586932c272ddef02e70cb755" +BOLT_SIDECAR_BUILDER_PROXY_PORT = "18551" +BOLT_SIDECAR_FEE_RECIPIENT = "0x0000000000000000000000000000000000000000" +BOLT_SIDECAR_VALIDATOR_INDEXES = "1..2" + + +# Configuration for how metrics should be collected and scraped +# OPTIONAL, skip metrics collection if missing +[metrics] +# Path to a `prometheus.yml` file to use in Prometheus. If using a custom config file, be sure to add a +# file discovery section as follows: +# ```yml +# file_sd_configs: +# - files: +# - /etc/prometheus/targets.json +# ``` +# and use the `targets.json` file generated by `commit-boost init` +prometheus_config = "./prometheus.yml" +# Whether to start Grafana with built-in dashboards +# OPTIONAL, DEFAULT: true +use_grafana = true +# Whether to start cadvisor for system monitoring +# OPTIONAL, DEFAULT: true +use_cadvisor = false + +# Configuration for how logs should be collected and stored +# OPTIONAL, info to stdout if missing +[logs] +# Path to the log directory +# OPTIONAL, DEFAULT: /var/logs/commit-boost +log_dir_path = "./logs" +# Log level. Supported values: trace, debug, info, warn, error +# OPTIONAL, DEFAULT: debug to file, info to stdout +log_level = "debug" +# Maximum number of log files to keep +# OPTIONAL +max_log_files = 30 diff --git a/testnets/holesky/cb.docker-compose.yml b/testnets/holesky/cb.docker-compose.yml new file mode 100644 index 000000000..57637433f --- /dev/null +++ b/testnets/holesky/cb.docker-compose.yml @@ -0,0 +1,104 @@ +services: + cb_bolt: + image: ghcr.io/chainbound/bolt-sidecar:v0.3.0-alpha-rc.1 + container_name: cb_bolt + environment: + CB_MODULE_ID: BOLT + CB_CONFIG: /cb-config.toml + CB_SIGNER_JWT: ${CB_JWT_BOLT} + SIGNER_SERVER: cb_signer:20000 + BOLT_SIDECAR_CONSTRAINTS_API: http://cb_pbs:18550 + BOLT_SIDECAR_CHAIN: holesky + BOLT_SIDECAR_EXECUTION_API: http://remotebeast:4485 + BOLT_SIDECAR_ENGINE_API: http://remotebeast:4451 + BOLT_SIDECAR_BEACON_API: http://remotebeast:4400 + BOLT_SIDECAR_FEE_RECIPIENT: '0x0000000000000000000000000000000000000000' + BOLT_SIDECAR_VALIDATOR_INDEXES: 1..2 + BOLT_SIDECAR_BUILDER_PROXY_PORT: '18551' + BOLT_SIDECAR_JWT_HEX: 89732cef77d7e9a20021ee8f419dbbb51bdf7f60586932c272ddef02e70cb755 + METRICS_SERVER: 10000 + USE_FILE_LOGS: true + RUST_LOG: debug + MAX_LOG_FILES: 30 + volumes: + - ./cb-bolt-config.toml:/cb-config.toml:ro + - ./logs/BOLT:/var/logs/commit-boost + networks: + - signer_network + - monitoring_network + depends_on: + - cb_signer + env_file: .cb.env + cb_pbs: + image: ghcr.io/chainbound/bolt-boost:v0.3.0-alpha-rc.1 + container_name: cb_pbs + ports: + - 18550:18550 + environment: + CB_CONFIG: /cb-config.toml + USE_FILE_LOGS: true + RUST_LOG: debug + MAX_LOG_FILES: 30 + METRICS_SERVER: 10000 + volumes: + - ./cb-bolt-config.toml:/cb-config.toml:ro + - ./logs/pbs:/var/logs/commit-boost + networks: + - monitoring_network + cb_signer: + image: commitboost_signer + container_name: cb_signer + environment: + CB_CONFIG: /cb-config.toml + CB_JWTS: ${CB_JWTS} + SIGNER_SERVER: 20000 + USE_FILE_LOGS: true + RUST_LOG: debug + MAX_LOG_FILES: 30 + METRICS_SERVER: 10000 + CB_SIGNER_FILE: /keys.json + volumes: + - ./cb-bolt-config.toml:/cb-config.toml:ro + - ././keys.json:/keys.json:ro + - ./logs/signer:/var/logs/commit-boost + networks: + - signer_network + - monitoring_network + cb_prometheus: + image: prom/prometheus:latest + container_name: cb_prometheus + ports: + - 9090:9090 + volumes: + - ./prometheus.yml:/etc/prometheus/prometheus.yml + - ./targets.json:/etc/prometheus/targets.json + - prometheus-data:/prometheus + networks: + - monitoring_network + cb_grafana: + image: grafana/grafana:latest + container_name: cb_grafana + ports: + - 3000:3000 + environment: + - GF_SECURITY_ADMIN_PASSWORD=admin + volumes: + - ./grafana/dashboards:/etc/grafana/provisioning/dashboards + - ./grafana/datasources:/etc/grafana/provisioning/datasources + - grafana-data:/var/lib/grafana + networks: + - monitoring_network + depends_on: + - cb_prometheus + logging: + driver: none +volumes: + prometheus-data: + driver: local + grafana-data: + driver: local +networks: + monitoring_network: + driver: bridge + signer_network: + driver: bridge diff --git a/testnets/holesky/keys.json b/testnets/holesky/keys.json new file mode 100644 index 000000000..4689c5d75 --- /dev/null +++ b/testnets/holesky/keys.json @@ -0,0 +1,4 @@ +[ + "0088e364a5396a81b50febbdc8784663fb9089b5e67cbdc173991a00c587673f", + "0x16f3bec1b7f4f1b87c5e1930f944a6dda76ad211a89bc98e8c8e88b5069f8a04" +] diff --git a/testnets/holesky/logs/pbs/pbs.2024-09-11 b/testnets/holesky/logs/pbs/pbs.2024-09-11 new file mode 100644 index 000000000..5a49cc8e3 --- /dev/null +++ b/testnets/holesky/logs/pbs/pbs.2024-09-11 @@ -0,0 +1,46 @@ +{"timestamp":"2024-09-11T12:36:34.518374Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T12:36:34.518388Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T12:44:09.499978Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T12:44:09.499990Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T12:44:09.500852Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} +{"timestamp":"2024-09-11T12:44:09.501500Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} +{"timestamp":"2024-09-11T12:58:05.935766Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T12:58:05.935775Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T12:58:05.936286Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} +{"timestamp":"2024-09-11T12:58:05.936371Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} +{"timestamp":"2024-09-11T13:29:40.402543Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:29:40.402859Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:29:40.403625Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} +{"timestamp":"2024-09-11T13:29:40.403807Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} +{"timestamp":"2024-09-11T13:33:47.575507Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:33:47.575515Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:33:47.576128Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} +{"timestamp":"2024-09-11T13:33:47.576135Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} +{"timestamp":"2024-09-11T13:38:26.286570Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:38:26.286579Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:38:26.287236Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} +{"timestamp":"2024-09-11T13:38:26.288260Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} +{"timestamp":"2024-09-11T13:39:32.787030Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:39:32.787110Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:39:32.787435Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} +{"timestamp":"2024-09-11T13:39:32.787456Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} +{"timestamp":"2024-09-11T13:48:03.820547Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:48:03.820629Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:48:03.820971Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} +{"timestamp":"2024-09-11T13:48:03.821076Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} +{"timestamp":"2024-09-11T13:49:46.905956Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:49:46.906113Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:49:46.906254Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} +{"timestamp":"2024-09-11T13:49:46.906373Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} +{"timestamp":"2024-09-11T13:59:13.961663Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:59:13.961717Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T13:59:13.962299Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} +{"timestamp":"2024-09-11T13:59:13.962488Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} +{"timestamp":"2024-09-11T14:04:43.274986Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T14:04:43.275020Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T14:04:43.276642Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} +{"timestamp":"2024-09-11T14:04:43.276947Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} +{"timestamp":"2024-09-11T14:12:27.560971Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T14:12:27.561262Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} +{"timestamp":"2024-09-11T14:12:27.561943Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} +{"timestamp":"2024-09-11T14:12:27.562565Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} diff --git a/testnets/holesky/logs/signer/signer.2024-09-11 b/testnets/holesky/logs/signer/signer.2024-09-11 new file mode 100644 index 000000000..8d6b42d04 --- /dev/null +++ b/testnets/holesky/logs/signer/signer.2024-09-11 @@ -0,0 +1,16 @@ +{"timestamp":"2024-09-11T09:10:23.547308Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T10:06:23.447915Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T11:42:34.467791Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T12:36:34.491189Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T12:44:09.550877Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T12:58:05.985880Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T13:29:40.397913Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T13:33:47.606426Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T13:38:26.295424Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T13:39:32.787635Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T13:48:03.812147Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T13:49:46.904054Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T13:59:13.944821Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T14:04:43.307941Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T14:12:27.532823Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} +{"timestamp":"2024-09-11T14:12:27.821186Z","level":"DEBUG","fields":{"message":"New request","event":"get_pubkeys","req_id":"8b01425e-2329-4771-989f-f922572ea06a"},"target":"cb_signer::service"} diff --git a/testnets/holesky/prometheus.yml b/testnets/holesky/prometheus.yml new file mode 100644 index 000000000..91b5d5905 --- /dev/null +++ b/testnets/holesky/prometheus.yml @@ -0,0 +1,8 @@ +global: + scrape_interval: 15s + +scrape_configs: + - job_name: "commit-boost" + file_sd_configs: + - files: + - /etc/prometheus/targets.json diff --git a/testnets/holesky/targets.json b/testnets/holesky/targets.json new file mode 100644 index 000000000..c2437c1e3 --- /dev/null +++ b/testnets/holesky/targets.json @@ -0,0 +1,26 @@ +[ + { + "targets": [ + "cb_bolt:10000" + ], + "labels": { + "job": "cb_bolt" + } + }, + { + "targets": [ + "cb_pbs:10000" + ], + "labels": { + "job": "pbs" + } + }, + { + "targets": [ + "cb_signer:10000" + ], + "labels": { + "job": "signer" + } + } +] \ No newline at end of file From 651aab30dfded8748c4794c5aa8f5a5317028907 Mon Sep 17 00:00:00 2001 From: Jonas Bostoen Date: Wed, 11 Sep 2024 16:14:47 +0200 Subject: [PATCH 21/30] feat(all): various fixes & compat with commit-boost --- bolt-boost/Dockerfile | 5 ++--- bolt-boost/src/metrics.rs | 2 +- bolt-sidecar/Dockerfile | 4 ++-- bolt-sidecar/src/config/mod.rs | 16 ++++++++-------- bolt-sidecar/src/config/signing.rs | 11 ++++------- 5 files changed, 17 insertions(+), 21 deletions(-) diff --git a/bolt-boost/Dockerfile b/bolt-boost/Dockerfile index a14e95611..005f44863 100644 --- a/bolt-boost/Dockerfile +++ b/bolt-boost/Dockerfile @@ -14,11 +14,10 @@ COPY . . RUN cargo build --release -FROM ubuntu AS runtime +FROM debian:bookworm-slim AS runtime WORKDIR /app -RUN apt-get update -RUN apt-get install -y openssl ca-certificates libssl3 libssl-dev +RUN apt-get update && apt-get install -y libssl-dev libssl3 openssl ca-certificates && rm -rf /var/lib/apt/lists/* COPY --from=builder /app/target/release/bolt-boost /usr/local/bin ENTRYPOINT ["/usr/local/bin/bolt-boost"] diff --git a/bolt-boost/src/metrics.rs b/bolt-boost/src/metrics.rs index f913a6e15..3d86f8939 100644 --- a/bolt-boost/src/metrics.rs +++ b/bolt-boost/src/metrics.rs @@ -24,7 +24,7 @@ lazy_static! { /// The size of the constraints cache pub static ref CONSTRAINTS_CACHE_SIZE: IntGauge = register_int_gauge_with_registry!( - "bolt_boost.constraints_cache_size", + "constraints_cache_size", "size of the constraints cache", BOLT_BOOST_METRICS ) diff --git a/bolt-sidecar/Dockerfile b/bolt-sidecar/Dockerfile index 7eb73069e..c4e8b5c90 100644 --- a/bolt-sidecar/Dockerfile +++ b/bolt-sidecar/Dockerfile @@ -1,4 +1,4 @@ -FROM rust:slim-bullseye AS compiler +FROM rust:slim-bookworm AS compiler RUN cargo install cargo-chef @@ -15,7 +15,7 @@ RUN cargo chef cook --release --recipe-path recipe.json COPY . . RUN cargo build --release -FROM debian:bullseye-slim +FROM debian:bookworm-slim WORKDIR /usr/local/bin COPY --from=builder /app/target/release/bolt-sidecar / RUN apt-get update && apt-get install -y libssl-dev ca-certificates && rm -rf /var/lib/apt/lists/* diff --git a/bolt-sidecar/src/config/mod.rs b/bolt-sidecar/src/config/mod.rs index 6d222982f..4adb6f0c6 100644 --- a/bolt-sidecar/src/config/mod.rs +++ b/bolt-sidecar/src/config/mod.rs @@ -35,16 +35,16 @@ pub struct Opts { #[clap(long, env = "BOLT_SIDECAR_PORT")] pub(super) port: Option, /// URL for the beacon client - #[clap(long, env = "BOLT_SIDECAR_BEACON_API_URL")] + #[clap(long, env = "BOLT_SIDECAR_BEACON_API")] pub(super) beacon_api_url: String, /// URL for the Constraint sidecar client to use #[clap(long, env = "BOLT_SIDECAR_CONSTRAINTS_URL")] pub(super) constraints_url: String, /// Execution client API URL - #[clap(long, env = "BOLT_SIDECAR_EXECUTION_API_URL")] + #[clap(long, env = "BOLT_SIDECAR_EXECUTION_API")] pub(super) execution_api_url: String, /// Execution client Engine API URL - #[clap(long, env = "BOLT_SIDECAR_ENGINE_API_URL")] + #[clap(long, env = "BOLT_SIDECAR_ENGINE_API")] pub(super) engine_api_url: String, /// Constraint proxy server port to use #[clap(long, env = "BOLT_SIDECAR_CONSTRAINTS_PROXY_PORT")] @@ -196,11 +196,11 @@ impl TryFrom for Config { } if let Some(commit_boost_url) = &opts.signing.commit_boost_url { - if let Ok(url) = Url::parse(commit_boost_url) { - if let Ok(socket_addrs) = url.socket_addrs(|| None) { - config.commit_boost_address = Some(socket_addrs[0].to_string()); - } - } + config.commit_boost_address = Some(commit_boost_url.clone()); + } + + if let Some(cb_jwt) = &opts.signing.commit_boost_jwt_hex { + config.commit_boost_jwt_hex = Some(cb_jwt.clone()); } config.private_key = if let Some(sk) = opts.signing.private_key { diff --git a/bolt-sidecar/src/config/signing.rs b/bolt-sidecar/src/config/signing.rs index c592b1cf6..75e627d02 100644 --- a/bolt-sidecar/src/config/signing.rs +++ b/bolt-sidecar/src/config/signing.rs @@ -1,11 +1,8 @@ -use clap::{ArgGroup, Args}; +use clap::Args; /// Command-line options for signing #[derive(Debug, Clone, Args)] -#[clap( - group = ArgGroup::new("signing-opts").required(true) - .args(&["private_key", "commit_boost_url", "commit_boost_jwt_hex"]) -)] +#[group(required = true, multiple = true)] pub struct SigningOpts { /// Private key to use for signing preconfirmation requests #[clap(long, env = "BOLT_SIDECAR_PRIVATE_KEY", conflicts_with("commit_boost_url"))] @@ -13,7 +10,7 @@ pub struct SigningOpts { /// URL for the commit-boost sidecar #[clap( long, - env = "BOLT_SIDECAR_CB_SIGNER_URL", + env = "SIGNER_SERVER", conflicts_with("private_key"), requires("commit_boost_jwt_hex") )] @@ -21,7 +18,7 @@ pub struct SigningOpts { /// JWT in hexadecimal format for authenticating with the commit-boost service #[clap( long, - env = "BOLT_SIDECAR_CB_JWT_HEX", + env = "CB_SIGNER_JWT", conflicts_with("private_key"), requires("commit_boost_url") )] From 78e24d4ed8b488adb89a57f11f0cf6f4bf3a264e Mon Sep 17 00:00:00 2001 From: Jonas Bostoen Date: Thu, 12 Sep 2024 10:50:20 +0200 Subject: [PATCH 22/30] doc(holesky): update holesky launch instructions + config --- .gitignore | 3 +++ testnets/holesky/.cb.env | 4 ++-- testnets/holesky/README.md | 26 ++++++++++++++++++++++---- testnets/holesky/cb-bolt-config.toml | 17 +++++++---------- testnets/holesky/cb.docker-compose.yml | 13 ++++++------- 5 files changed, 40 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index be2b1a284..2b58236ad 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ *_dump.log target/ +logs/ +cb.docker-compose.yml +.cb.env diff --git a/testnets/holesky/.cb.env b/testnets/holesky/.cb.env index 9faac7b8d..b47ef4ccb 100644 --- a/testnets/holesky/.cb.env +++ b/testnets/holesky/.cb.env @@ -1,2 +1,2 @@ -CB_JWT_BOLT=jN7FpDQZSWS9r1XzrGL3dbW6fBd0uzEa -CB_JWTS="{\"BOLT\":\"jN7FpDQZSWS9r1XzrGL3dbW6fBd0uzEa\"}" +CB_JWT_BOLT=MmH34tKim3rwXna4EvsXv0I8gLNU6E4n +CB_JWTS="{\"BOLT\":\"MmH34tKim3rwXna4EvsXv0I8gLNU6E4n\"}" diff --git a/testnets/holesky/README.md b/testnets/holesky/README.md index 50a4cabbd..85a6d4fe7 100644 --- a/testnets/holesky/README.md +++ b/testnets/holesky/README.md @@ -14,7 +14,7 @@ The components that need to run to test Bolt on Holesky are: To install the `commit-boost` CLI with `cargo`: ```bash # Use specific commit hash to ensure compatibility -cargo install --locked --git https://github.com/Commit-Boost/commit-boost-client --rev 45ce8f1 commit-boost +cargo install --locked --git https://github.com/Commit-Boost/commit-boost-client --rev aed00e8 commit-boost # Test installation commit-boost --version @@ -24,6 +24,23 @@ A commit-boost configuration file with Bolt support is provided at [`cb-bolt-con for the custom PBS module ([bolt-boost](../../bolt-boost)) that implements the [constraints-API](https://chainbound.github.io/bolt-docs/api/builder), as well as the [bolt-sidecar](../../bolt-sidecar) module. This file can be used as a template for your own configuration. +The important fields to configure are under the `[modules.env]` section of the `BOLT` module, which contain the environment variables to configure +the bolt sidecar: +```toml +[modules.env] +BOLT_SIDECAR_CHAIN = "holesky" + +BOLT_SIDECAR_CONSTRAINTS_API = "http://cb_pbs:18550" # The address of the PBS module (static) +BOLT_SIDECAR_BEACON_API = "" +BOLT_SIDECAR_EXECUTION_API = "" +BOLT_SIDECAR_ENGINE_API = "" # The execution layer engine API endpoint +BOLT_SIDECAR_JWT_HEX = "" # The engine JWT used to authenticate with the engine API +BOLT_SIDECAR_BUILDER_PROXY_PORT = "18551" # The port on which the sidecar builder-API will listen on. This is what your beacon node should connect to. +BOLT_SIDECAR_FEE_RECIPIENT = "" # The fee recipient +BOLT_SIDECAR_VALIDATOR_INDEXES = "" # The active validator indexes (can be defined as a comma-separated list, or a range) + # e.g. "0,1,2,3,4" or "0..4", or a combination of both +``` + To initialize commit-boost, run the following command: ```bash commit-boost init --config cb-bolt-config.toml @@ -32,7 +49,7 @@ commit-boost init --config cb-bolt-config.toml This will create 3 files: - `cb.docker-compose.yml`: which contains the full setup of the Commit-Boost services - `.cb.env`: with local env variables, including JWTs for modules -- `target.json`: which enables dynamic discovery of services for metrics scraping via Prometheus, only created if metrics are enabled +- `target.json`: which enables dynamic discovery of services for metrics scraping via Prometheus #### Running The final step is to run the Commit-Boost services. This can be done with the following command: @@ -42,14 +59,15 @@ commit-boost start --docker cb.docker-compose.yml --env .cb.env This will run all modules in Docker containers. > [!IMPORTANT] -> bolt-boost will be exposed at `pbs.port` (18550 by default), and your beacon node MUST be configured +> bolt-boost will be exposed at `pbs.port` (18551 by default, set with `BOLT_SIDECAR_BUILDER_PROXY_PORT`), and your beacon node MUST be configured > to point the `builder-api` to this port for Bolt to work. ### Bolt Sidecar -Your sidecar +WIP ### Validators Validators must be configured to always prefer builder proposals over their own. Refer to client documentation for the specific configuration flags. **If this is not set, it could lead to commitment faults**. #### Registration +WIP diff --git a/testnets/holesky/cb-bolt-config.toml b/testnets/holesky/cb-bolt-config.toml index 179be6e1b..ccd110742 100644 --- a/testnets/holesky/cb-bolt-config.toml +++ b/testnets/holesky/cb-bolt-config.toml @@ -111,20 +111,17 @@ type = "commit" # Docker image of the module docker_image = "ghcr.io/chainbound/bolt-sidecar:v0.3.0-alpha-rc.1" -env_file = ".cb.env" - [modules.env] BOLT_SIDECAR_CHAIN = "holesky" BOLT_SIDECAR_CONSTRAINTS_API = "http://cb_pbs:18550" # The address of the PBS module -BOLT_SIDECAR_BEACON_API = "http://remotebeast:4400" -BOLT_SIDECAR_EXECUTION_API = "http://remotebeast:4485" -BOLT_SIDECAR_ENGINE_API = "http://remotebeast:4451" -BOLT_SIDECAR_JWT_HEX = "89732cef77d7e9a20021ee8f419dbbb51bdf7f60586932c272ddef02e70cb755" -BOLT_SIDECAR_BUILDER_PROXY_PORT = "18551" -BOLT_SIDECAR_FEE_RECIPIENT = "0x0000000000000000000000000000000000000000" -BOLT_SIDECAR_VALIDATOR_INDEXES = "1..2" - +BOLT_SIDECAR_BEACON_API = "http://100.85.200.41:4400" +BOLT_SIDECAR_EXECUTION_API = "http://100.85.200.41:4485" +BOLT_SIDECAR_ENGINE_API = "http://100.85.200.41:4451" # The execution layer engine API endpoint +BOLT_SIDECAR_JWT_HEX = "89732cef77d7e9a20021ee8f419dbbb51bdf7f60586932c272ddef02e70cb755" # The engine JWT +BOLT_SIDECAR_BUILDER_PROXY_PORT = "18551" # The port on which the sidecar builder-API will listen on. This is what your beacon node should connect to. +BOLT_SIDECAR_FEE_RECIPIENT = "0x0000000000000000000000000000000000000000" # The fee recipient +BOLT_SIDECAR_VALIDATOR_INDEXES = "1..2" # The active validator indexes # Configuration for how metrics should be collected and scraped # OPTIONAL, skip metrics collection if missing diff --git a/testnets/holesky/cb.docker-compose.yml b/testnets/holesky/cb.docker-compose.yml index 57637433f..2571fa71f 100644 --- a/testnets/holesky/cb.docker-compose.yml +++ b/testnets/holesky/cb.docker-compose.yml @@ -7,15 +7,15 @@ services: CB_CONFIG: /cb-config.toml CB_SIGNER_JWT: ${CB_JWT_BOLT} SIGNER_SERVER: cb_signer:20000 - BOLT_SIDECAR_CONSTRAINTS_API: http://cb_pbs:18550 - BOLT_SIDECAR_CHAIN: holesky - BOLT_SIDECAR_EXECUTION_API: http://remotebeast:4485 - BOLT_SIDECAR_ENGINE_API: http://remotebeast:4451 - BOLT_SIDECAR_BEACON_API: http://remotebeast:4400 + BOLT_SIDECAR_ENGINE_API: http://100.85.200.41:4451 BOLT_SIDECAR_FEE_RECIPIENT: '0x0000000000000000000000000000000000000000' - BOLT_SIDECAR_VALIDATOR_INDEXES: 1..2 BOLT_SIDECAR_BUILDER_PROXY_PORT: '18551' + BOLT_SIDECAR_CHAIN: holesky + BOLT_SIDECAR_VALIDATOR_INDEXES: 1..2 BOLT_SIDECAR_JWT_HEX: 89732cef77d7e9a20021ee8f419dbbb51bdf7f60586932c272ddef02e70cb755 + BOLT_SIDECAR_EXECUTION_API: http://100.85.200.41:4485 + BOLT_SIDECAR_CONSTRAINTS_API: http://cb_pbs:18550 + BOLT_SIDECAR_BEACON_API: http://100.85.200.41:4400 METRICS_SERVER: 10000 USE_FILE_LOGS: true RUST_LOG: debug @@ -28,7 +28,6 @@ services: - monitoring_network depends_on: - cb_signer - env_file: .cb.env cb_pbs: image: ghcr.io/chainbound/bolt-boost:v0.3.0-alpha-rc.1 container_name: cb_pbs From 2aa8ecfd9e676c2728f6a4e37c9b33ca92de1be5 Mon Sep 17 00:00:00 2001 From: Jonas Bostoen Date: Thu, 12 Sep 2024 11:00:44 +0200 Subject: [PATCH 23/30] fix(config): config rebase --- bolt-sidecar/src/config/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bolt-sidecar/src/config/mod.rs b/bolt-sidecar/src/config/mod.rs index 4adb6f0c6..a8db7ff53 100644 --- a/bolt-sidecar/src/config/mod.rs +++ b/bolt-sidecar/src/config/mod.rs @@ -46,9 +46,9 @@ pub struct Opts { /// Execution client Engine API URL #[clap(long, env = "BOLT_SIDECAR_ENGINE_API")] pub(super) engine_api_url: String, - /// Constraint proxy server port to use - #[clap(long, env = "BOLT_SIDECAR_CONSTRAINTS_PROXY_PORT")] - pub(super) constraints_proxy_port: u16, + /// Builder proxy server port to use + #[clap(long, env = "BOLT_SIDECAR_BUILDER_PROXY_PORT")] + pub(super) builder_proxy_port: u16, /// Max number of commitments to accept per block #[clap(long, env = "BOLT_SIDECAR_MAX_COMMITMENTS")] pub(super) max_commitments: Option>, @@ -237,7 +237,7 @@ impl TryFrom for Config { info!("Engine JWT secret loaded successfully"); } - config.constraints_proxy_port = opts.constraints_proxy_port; + config.constraints_proxy_port = opts.builder_proxy_port; config.engine_api_url = opts.engine_api_url.parse()?; config.execution_api_url = opts.execution_api_url.parse()?; config.beacon_api_url = opts.beacon_api_url.parse()?; From 6375198bb92d47e94d4d9acfa88ccc7e9f7d06b5 Mon Sep 17 00:00:00 2001 From: Jonas Bostoen Date: Thu, 12 Sep 2024 11:05:54 +0200 Subject: [PATCH 24/30] chore(holesky): rm some configs --- testnets/holesky/.cb.env | 2 - testnets/holesky/cb.docker-compose.yml | 103 ------------------ testnets/holesky/logs/pbs/pbs.2024-09-11 | 46 -------- .../holesky/logs/signer/signer.2024-09-11 | 16 --- 4 files changed, 167 deletions(-) delete mode 100644 testnets/holesky/.cb.env delete mode 100644 testnets/holesky/cb.docker-compose.yml delete mode 100644 testnets/holesky/logs/pbs/pbs.2024-09-11 delete mode 100644 testnets/holesky/logs/signer/signer.2024-09-11 diff --git a/testnets/holesky/.cb.env b/testnets/holesky/.cb.env deleted file mode 100644 index b47ef4ccb..000000000 --- a/testnets/holesky/.cb.env +++ /dev/null @@ -1,2 +0,0 @@ -CB_JWT_BOLT=MmH34tKim3rwXna4EvsXv0I8gLNU6E4n -CB_JWTS="{\"BOLT\":\"MmH34tKim3rwXna4EvsXv0I8gLNU6E4n\"}" diff --git a/testnets/holesky/cb.docker-compose.yml b/testnets/holesky/cb.docker-compose.yml deleted file mode 100644 index 2571fa71f..000000000 --- a/testnets/holesky/cb.docker-compose.yml +++ /dev/null @@ -1,103 +0,0 @@ -services: - cb_bolt: - image: ghcr.io/chainbound/bolt-sidecar:v0.3.0-alpha-rc.1 - container_name: cb_bolt - environment: - CB_MODULE_ID: BOLT - CB_CONFIG: /cb-config.toml - CB_SIGNER_JWT: ${CB_JWT_BOLT} - SIGNER_SERVER: cb_signer:20000 - BOLT_SIDECAR_ENGINE_API: http://100.85.200.41:4451 - BOLT_SIDECAR_FEE_RECIPIENT: '0x0000000000000000000000000000000000000000' - BOLT_SIDECAR_BUILDER_PROXY_PORT: '18551' - BOLT_SIDECAR_CHAIN: holesky - BOLT_SIDECAR_VALIDATOR_INDEXES: 1..2 - BOLT_SIDECAR_JWT_HEX: 89732cef77d7e9a20021ee8f419dbbb51bdf7f60586932c272ddef02e70cb755 - BOLT_SIDECAR_EXECUTION_API: http://100.85.200.41:4485 - BOLT_SIDECAR_CONSTRAINTS_API: http://cb_pbs:18550 - BOLT_SIDECAR_BEACON_API: http://100.85.200.41:4400 - METRICS_SERVER: 10000 - USE_FILE_LOGS: true - RUST_LOG: debug - MAX_LOG_FILES: 30 - volumes: - - ./cb-bolt-config.toml:/cb-config.toml:ro - - ./logs/BOLT:/var/logs/commit-boost - networks: - - signer_network - - monitoring_network - depends_on: - - cb_signer - cb_pbs: - image: ghcr.io/chainbound/bolt-boost:v0.3.0-alpha-rc.1 - container_name: cb_pbs - ports: - - 18550:18550 - environment: - CB_CONFIG: /cb-config.toml - USE_FILE_LOGS: true - RUST_LOG: debug - MAX_LOG_FILES: 30 - METRICS_SERVER: 10000 - volumes: - - ./cb-bolt-config.toml:/cb-config.toml:ro - - ./logs/pbs:/var/logs/commit-boost - networks: - - monitoring_network - cb_signer: - image: commitboost_signer - container_name: cb_signer - environment: - CB_CONFIG: /cb-config.toml - CB_JWTS: ${CB_JWTS} - SIGNER_SERVER: 20000 - USE_FILE_LOGS: true - RUST_LOG: debug - MAX_LOG_FILES: 30 - METRICS_SERVER: 10000 - CB_SIGNER_FILE: /keys.json - volumes: - - ./cb-bolt-config.toml:/cb-config.toml:ro - - ././keys.json:/keys.json:ro - - ./logs/signer:/var/logs/commit-boost - networks: - - signer_network - - monitoring_network - cb_prometheus: - image: prom/prometheus:latest - container_name: cb_prometheus - ports: - - 9090:9090 - volumes: - - ./prometheus.yml:/etc/prometheus/prometheus.yml - - ./targets.json:/etc/prometheus/targets.json - - prometheus-data:/prometheus - networks: - - monitoring_network - cb_grafana: - image: grafana/grafana:latest - container_name: cb_grafana - ports: - - 3000:3000 - environment: - - GF_SECURITY_ADMIN_PASSWORD=admin - volumes: - - ./grafana/dashboards:/etc/grafana/provisioning/dashboards - - ./grafana/datasources:/etc/grafana/provisioning/datasources - - grafana-data:/var/lib/grafana - networks: - - monitoring_network - depends_on: - - cb_prometheus - logging: - driver: none -volumes: - prometheus-data: - driver: local - grafana-data: - driver: local -networks: - monitoring_network: - driver: bridge - signer_network: - driver: bridge diff --git a/testnets/holesky/logs/pbs/pbs.2024-09-11 b/testnets/holesky/logs/pbs/pbs.2024-09-11 deleted file mode 100644 index 5a49cc8e3..000000000 --- a/testnets/holesky/logs/pbs/pbs.2024-09-11 +++ /dev/null @@ -1,46 +0,0 @@ -{"timestamp":"2024-09-11T12:36:34.518374Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} -{"timestamp":"2024-09-11T12:36:34.518388Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} -{"timestamp":"2024-09-11T12:44:09.499978Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} -{"timestamp":"2024-09-11T12:44:09.499990Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} -{"timestamp":"2024-09-11T12:44:09.500852Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} -{"timestamp":"2024-09-11T12:44:09.501500Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} -{"timestamp":"2024-09-11T12:58:05.935766Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} -{"timestamp":"2024-09-11T12:58:05.935775Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} -{"timestamp":"2024-09-11T12:58:05.936286Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} -{"timestamp":"2024-09-11T12:58:05.936371Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} -{"timestamp":"2024-09-11T13:29:40.402543Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} -{"timestamp":"2024-09-11T13:29:40.402859Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} -{"timestamp":"2024-09-11T13:29:40.403625Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} -{"timestamp":"2024-09-11T13:29:40.403807Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} -{"timestamp":"2024-09-11T13:33:47.575507Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} -{"timestamp":"2024-09-11T13:33:47.575515Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} -{"timestamp":"2024-09-11T13:33:47.576128Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} -{"timestamp":"2024-09-11T13:33:47.576135Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} -{"timestamp":"2024-09-11T13:38:26.286570Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} -{"timestamp":"2024-09-11T13:38:26.286579Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} -{"timestamp":"2024-09-11T13:38:26.287236Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} -{"timestamp":"2024-09-11T13:38:26.288260Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} -{"timestamp":"2024-09-11T13:39:32.787030Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} -{"timestamp":"2024-09-11T13:39:32.787110Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} -{"timestamp":"2024-09-11T13:39:32.787435Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} -{"timestamp":"2024-09-11T13:39:32.787456Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} -{"timestamp":"2024-09-11T13:48:03.820547Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} -{"timestamp":"2024-09-11T13:48:03.820629Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} -{"timestamp":"2024-09-11T13:48:03.820971Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} -{"timestamp":"2024-09-11T13:48:03.821076Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} -{"timestamp":"2024-09-11T13:49:46.905956Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} -{"timestamp":"2024-09-11T13:49:46.906113Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} -{"timestamp":"2024-09-11T13:49:46.906254Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} -{"timestamp":"2024-09-11T13:49:46.906373Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} -{"timestamp":"2024-09-11T13:59:13.961663Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} -{"timestamp":"2024-09-11T13:59:13.961717Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} -{"timestamp":"2024-09-11T13:59:13.962299Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} -{"timestamp":"2024-09-11T13:59:13.962488Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} -{"timestamp":"2024-09-11T14:04:43.274986Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} -{"timestamp":"2024-09-11T14:04:43.275020Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} -{"timestamp":"2024-09-11T14:04:43.276642Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} -{"timestamp":"2024-09-11T14:04:43.276947Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} -{"timestamp":"2024-09-11T14:12:27.560971Z","level":"INFO","fields":{"message":"Starting bolt-boost with the following relays:","chain":"Holesky"},"target":"bolt_boost"} -{"timestamp":"2024-09-11T14:12:27.561262Z","level":"INFO","fields":{"message":"ID: example-relay - URI: http://0xa1cec75a3f0661e99299274182938151e8433c61a19222347ea1313d839229cb4ce4e3e5aa2bdeb71c8fcf1b084963c2@abc.xyz/"},"target":"bolt_boost"} -{"timestamp":"2024-09-11T14:12:27.561943Z","level":"INFO","fields":{"message":"Starting metrics server on port 10000"},"target":"cb_metrics::provider"} -{"timestamp":"2024-09-11T14:12:27.562565Z","level":"INFO","fields":{"message":"Starting PBS service","address":"0.0.0.0:18550","events_subs":0},"target":"cb_pbs::service"} diff --git a/testnets/holesky/logs/signer/signer.2024-09-11 b/testnets/holesky/logs/signer/signer.2024-09-11 deleted file mode 100644 index 8d6b42d04..000000000 --- a/testnets/holesky/logs/signer/signer.2024-09-11 +++ /dev/null @@ -1,16 +0,0 @@ -{"timestamp":"2024-09-11T09:10:23.547308Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} -{"timestamp":"2024-09-11T10:06:23.447915Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} -{"timestamp":"2024-09-11T11:42:34.467791Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} -{"timestamp":"2024-09-11T12:36:34.491189Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} -{"timestamp":"2024-09-11T12:44:09.550877Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} -{"timestamp":"2024-09-11T12:58:05.985880Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} -{"timestamp":"2024-09-11T13:29:40.397913Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} -{"timestamp":"2024-09-11T13:33:47.606426Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} -{"timestamp":"2024-09-11T13:38:26.295424Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} -{"timestamp":"2024-09-11T13:39:32.787635Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} -{"timestamp":"2024-09-11T13:48:03.812147Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} -{"timestamp":"2024-09-11T13:49:46.904054Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} -{"timestamp":"2024-09-11T13:59:13.944821Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} -{"timestamp":"2024-09-11T14:04:43.307941Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} -{"timestamp":"2024-09-11T14:12:27.532823Z","level":"INFO","fields":{"message":"Starting signing service","modules":"[\"BOLT\"]","port":"20000"},"target":"cb_signer::service"} -{"timestamp":"2024-09-11T14:12:27.821186Z","level":"DEBUG","fields":{"message":"New request","event":"get_pubkeys","req_id":"8b01425e-2329-4771-989f-f922572ea06a"},"target":"cb_signer::service"} From 3807669f0ebbf0b02d6583190917a07a53081d7d Mon Sep 17 00:00:00 2001 From: Jonas Bostoen Date: Thu, 12 Sep 2024 11:10:08 +0200 Subject: [PATCH 25/30] refactor(config): prefix envs --- bolt-sidecar/src/config/telemetry.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bolt-sidecar/src/config/telemetry.rs b/bolt-sidecar/src/config/telemetry.rs index 4e49cfaaf..98e83abeb 100644 --- a/bolt-sidecar/src/config/telemetry.rs +++ b/bolt-sidecar/src/config/telemetry.rs @@ -3,8 +3,8 @@ use clap::Parser; #[derive(Parser, Debug, Clone)] pub struct TelemetryOpts { /// The port on which to expose Prometheus metrics - #[clap(short, long, env = "METRICS_PORT", default_value_t = 3300)] + #[clap(short, long, env = "BOLT_SIDECAR_METRICS_PORT", default_value_t = 3300)] pub metrics_port: u16, - #[clap(short, long, env = "DISABLE_METRICS", default_value_t = false)] + #[clap(short, long, env = "BOLT_SIDECAR_DISABLE_METRICS", default_value_t = false)] pub disable_metrics: bool, } From f4e84620f4ba2b61a65d4df0a7426ea1ef512c7e Mon Sep 17 00:00:00 2001 From: Jonas Bostoen Date: Thu, 12 Sep 2024 11:11:09 +0200 Subject: [PATCH 26/30] fix(config): add correct metrics port --- testnets/holesky/cb-bolt-config.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/testnets/holesky/cb-bolt-config.toml b/testnets/holesky/cb-bolt-config.toml index ccd110742..3056e1472 100644 --- a/testnets/holesky/cb-bolt-config.toml +++ b/testnets/holesky/cb-bolt-config.toml @@ -123,6 +123,8 @@ BOLT_SIDECAR_BUILDER_PROXY_PORT = "18551" BOLT_SIDECAR_FEE_RECIPIENT = "0x0000000000000000000000000000000000000000" # The fee recipient BOLT_SIDECAR_VALIDATOR_INDEXES = "1..2" # The active validator indexes +BOLT_SIDECAR_METRICS_PORT = "10000" + # Configuration for how metrics should be collected and scraped # OPTIONAL, skip metrics collection if missing [metrics] From 22d8b17ec0bed6ea2c08c2ca44bf60513f45dc4f Mon Sep 17 00:00:00 2001 From: Jonas Bostoen Date: Thu, 12 Sep 2024 11:28:38 +0200 Subject: [PATCH 27/30] feat(holesky): add grafana support --- testnets/holesky/cb-bolt-config.toml | 2 +- .../holesky/grafana/dashboards/dashboard.json | 803 +++++++++++++++++ .../holesky/grafana/dashboards/dashboards.yml | 13 + .../grafana/dashboards/system_metrics.json | 853 ++++++++++++++++++ .../grafana/datasources/datasources.yml | 11 + testnets/holesky/targets.json | 8 + 6 files changed, 1689 insertions(+), 1 deletion(-) create mode 100644 testnets/holesky/grafana/dashboards/dashboard.json create mode 100644 testnets/holesky/grafana/dashboards/dashboards.yml create mode 100644 testnets/holesky/grafana/dashboards/system_metrics.json create mode 100644 testnets/holesky/grafana/datasources/datasources.yml diff --git a/testnets/holesky/cb-bolt-config.toml b/testnets/holesky/cb-bolt-config.toml index 3056e1472..be4e35002 100644 --- a/testnets/holesky/cb-bolt-config.toml +++ b/testnets/holesky/cb-bolt-config.toml @@ -142,7 +142,7 @@ prometheus_config = "./prometheus.yml" use_grafana = true # Whether to start cadvisor for system monitoring # OPTIONAL, DEFAULT: true -use_cadvisor = false +use_cadvisor = true # Configuration for how logs should be collected and stored # OPTIONAL, info to stdout if missing diff --git a/testnets/holesky/grafana/dashboards/dashboard.json b/testnets/holesky/grafana/dashboards/dashboard.json new file mode 100644 index 000000000..f903affb2 --- /dev/null +++ b/testnets/holesky/grafana/dashboards/dashboard.json @@ -0,0 +1,803 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "links": [], + "liveNow": true, + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 12, + "panels": [], + "repeat": "endpoint", + "repeatDirection": "h", + "title": "$endpoint calls", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 6, + "x": 0, + "y": 1 + }, + "id": 11, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "editorMode": "code", + "expr": "sum(increase(cb_pbs_relay_status_code_total{http_status_code=~\"2..\", endpoint=\"$endpoint\"}[1h])) by (relay_id)", + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "$endpoint Relay Success QPH", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 6, + "x": 6, + "y": 1 + }, + "id": 13, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "editorMode": "code", + "expr": "sum(increase(cb_pbs_relay_status_code_total{http_status_code=~\"4..|5..\", endpoint=\"$endpoint\"}[1h])) by (relay_id)", + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "$endpoint Relay Error QPH", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 6, + "x": 12, + "y": 1 + }, + "id": 43, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "editorMode": "code", + "expr": "sum(increase(cb_pbs_beacon_node_status_code_total{http_status_code=~\"2..\", endpoint=\"$endpoint\"}[1h]))", + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "$endpoint Beacon Node Success QPH", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 6, + "x": 18, + "y": 1 + }, + "id": 44, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "editorMode": "code", + "expr": "sum(increase(cb_pbs_beacon_node_status_code_total{http_status_code=~\"4..|5..\", endpoint=\"$endpoint\"}[1h]))", + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A" + } + ], + "title": "$endpoint Beacon Node Error QPH", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "always", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 6, + "x": 0, + "y": 12 + }, + "id": 20, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "histogram_quantile(0.50, sum(rate(cb_pbs_relay_latency_bucket{endpoint=\"$endpoint\"}[1m])) by (le, relay_id))", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "$endpoint Relay P50", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "always", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 6, + "x": 6, + "y": 12 + }, + "id": 29, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "histogram_quantile(0.90, sum(rate(cb_pbs_relay_latency_bucket{endpoint=\"$endpoint\"}[1m])) by (le, relay_id))", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "$endpoint Relay P90", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "always", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 6, + "x": 12, + "y": 12 + }, + "id": 30, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "histogram_quantile(0.99, sum(rate(cb_pbs_relay_latency_bucket{endpoint=\"$endpoint\"}[1m])) by (le, relay_id))", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "$endpoint Relay P99", + "type": "timeseries" + } + ], + "refresh": "5m", + "schemaVersion": 39, + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": true, + "text": "All", + "value": "$__all" + }, + "description": "BuilderAPI endpoint", + "hide": 0, + "includeAll": true, + "multi": false, + "name": "endpoint", + "options": [ + { + "selected": true, + "text": "All", + "value": "$__all" + }, + { + "selected": false, + "text": "get_header", + "value": "get_header" + }, + { + "selected": false, + "text": "submit_blinded_block", + "value": "submit_blinded_block" + }, + { + "selected": false, + "text": "register_validator", + "value": "register_validator" + } + ], + "query": "register_validator, get_header, submit_blinded_block", + "queryValue": "", + "skipUrlSync": false, + "type": "custom" + } + ] + }, + "time": { + "from": "now-2d", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "PBS Metrics", + "uid": "cb_prometheus", + "version": 1, + "weekStart": "" +} \ No newline at end of file diff --git a/testnets/holesky/grafana/dashboards/dashboards.yml b/testnets/holesky/grafana/dashboards/dashboards.yml new file mode 100644 index 000000000..db50699f9 --- /dev/null +++ b/testnets/holesky/grafana/dashboards/dashboards.yml @@ -0,0 +1,13 @@ +apiVersion: 1 + +providers: + - name: "default" + orgId: 1 + folder: "" + folderUid: "" + type: file + disableDeletion: false + editable: true + allowUiUpdates: true + options: + path: /etc/grafana/provisioning/dashboards diff --git a/testnets/holesky/grafana/dashboards/system_metrics.json b/testnets/holesky/grafana/dashboards/system_metrics.json new file mode 100644 index 000000000..93b649d80 --- /dev/null +++ b/testnets/holesky/grafana/dashboards/system_metrics.json @@ -0,0 +1,853 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "Prometheus", + "description": "Prometheus as the datasource is obligatory", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "7.4.5" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": 14282, + "graphTooltip": 0, + "id": null, + "iteration": 1617715580880, + "links": [], + "panels": [ + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 8, + "panels": [], + "title": "CPU", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 1 + }, + "hiddenSeries": false, + "id": 15, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_cpu_usage_seconds_total{instance=~\"$host\",name=~\"$container\",name=~\".+\"}[5m])) by (name) *100", + "hide": false, + "interval": "", + "legendFormat": "{{name}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU Usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:606", + "format": "percent", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:607", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 8 + }, + "id": 11, + "panels": [], + "title": "Memory", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 9 + }, + "hiddenSeries": false, + "id": 9, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(container_memory_rss{instance=~\"$host\",name=~\"$container\",name=~\".+\"}) by (name)", + "hide": false, + "interval": "", + "legendFormat": "{{name}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Usage", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:606", + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:607", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 9 + }, + "hiddenSeries": false, + "id": 14, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum(container_memory_cache{instance=~\"$host\",name=~\"$container\",name=~\".+\"}) by (name)", + "hide": false, + "interval": "", + "legendFormat": "{{name}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Memory Cached", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:606", + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:607", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 2, + "panels": [], + "title": "Network", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 18 + }, + "hiddenSeries": false, + "id": 4, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_network_receive_bytes_total[5m])) by (instance)", + "hide": false, + "interval": "", + "legendFormat": "{{name}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Received Network Traffic", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:674", + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:675", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 18 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "alignAsTable": true, + "avg": true, + "current": false, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "alertThreshold": true + }, + "percentage": false, + "pluginVersion": "7.4.5", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(rate(container_network_transmit_bytes_total[5m])) by (instance)", + "interval": "", + "legendFormat": "{{name}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Sent Network Traffic", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:832", + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:833", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 26 + }, + "id": 19, + "panels": [], + "title": "Misc", + "type": "row" + }, + { + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "fieldConfig": { + "defaults": { + "custom": { + "align": null, + "filterable": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "id" + }, + "properties": [ + { + "id": "custom.width", + "value": 260 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Running" + }, + "properties": [ + { + "id": "unit", + "value": "d" + }, + { + "id": "decimals", + "value": 1 + }, + { + "id": "custom.displayMode", + "value": "color-text" + }, + { + "id": "color", + "value": { + "fixedColor": "dark-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 17, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "7.4.5", + "targets": [ + { + "expr": "(time() - container_start_time_seconds{instance=~\"$host\",name=~\"$container\",name=~\".+\"})/86400", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "{{name}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Containers Info", + "transformations": [ + { + "id": "filterFieldsByName", + "options": { + "include": { + "names": [ + "container_label_com_docker_compose_project", + "container_label_com_docker_compose_project_working_dir", + "image", + "instance", + "name", + "Value", + "container_label_com_docker_compose_service" + ] + } + } + }, + { + "id": "organize", + "options": { + "excludeByName": {}, + "indexByName": {}, + "renameByName": { + "Value": "Running", + "container_label_com_docker_compose_project": "Label", + "container_label_com_docker_compose_project_working_dir": "Working dir", + "container_label_com_docker_compose_service": "Service", + "image": "Registry Image", + "instance": "Instance", + "name": "Name" + } + } + } + ], + "type": "table" + } + ], + "schemaVersion": 27, + "style": "dark", + "tags": [ + "cadvisor", + "docker" + ], + "templating": { + "list": [ + { + "allValue": ".*", + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "definition": "label_values({__name__=~\"container.*\"},instance)", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Host", + "multi": false, + "name": "host", + "options": [], + "query": { + "query": "label_values({__name__=~\"container.*\"},instance)", + "refId": "Prometheus-host-Variable-Query" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "current": {}, + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "definition": "label_values({__name__=~\"container.*\", instance=~\"$host\"},name)", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Container", + "multi": false, + "name": "container", + "options": [], + "query": { + "query": "label_values({__name__=~\"container.*\", instance=~\"$host\"},name)", + "refId": "Prometheus-container-Variable-Query" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Commit-Boost System Metrics", + "uid": "pMEd7m0Mz", + "version": 1, + "description": "Simple exporter for cadvisor only" +} \ No newline at end of file diff --git a/testnets/holesky/grafana/datasources/datasources.yml b/testnets/holesky/grafana/datasources/datasources.yml new file mode 100644 index 000000000..6d29d617b --- /dev/null +++ b/testnets/holesky/grafana/datasources/datasources.yml @@ -0,0 +1,11 @@ +apiVersion: 1 + +datasources: + - name: cb-prometheus + type: prometheus + uid: cb_prometheus + access: proxy + orgId: 1 + url: http://cb_prometheus:9090 + isDefault: true + editable: true diff --git a/testnets/holesky/targets.json b/testnets/holesky/targets.json index c2437c1e3..6eb23eea1 100644 --- a/testnets/holesky/targets.json +++ b/testnets/holesky/targets.json @@ -22,5 +22,13 @@ "labels": { "job": "signer" } + }, + { + "targets": [ + "cb_cadvisor:8080" + ], + "labels": { + "job": "cadvisor" + } } ] \ No newline at end of file From 2ff9bf6d4d8091ace64b2417d294aa8622ec9fcf Mon Sep 17 00:00:00 2001 From: Jonas Bostoen Date: Thu, 12 Sep 2024 11:41:15 +0200 Subject: [PATCH 28/30] feat(holesky): add initial bolt dashboard --- .../grafana/dashboards/bolt_dashboard.json | 238 ++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100644 testnets/holesky/grafana/dashboards/bolt_dashboard.json diff --git a/testnets/holesky/grafana/dashboards/bolt_dashboard.json b/testnets/holesky/grafana/dashboards/bolt_dashboard.json new file mode 100644 index 000000000..886ddfe02 --- /dev/null +++ b/testnets/holesky/grafana/dashboards/bolt_dashboard.json @@ -0,0 +1,238 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "Metrics related to the bolt-sidecar and bolt-boost.", + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 3, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 2, + "panels": [], + "title": "Bolt sidecar", + "type": "row" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "cb_prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 1 + }, + "id": 1, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "11.2.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "bolt_sidecar_latest_head", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Latest head", + "type": "stat" + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 9 + }, + "id": 4, + "panels": [], + "title": "Bolt boost", + "type": "row" + }, + { + "datasource": { + "default": true, + "type": "prometheus", + "uid": "cb_prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 10 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "cb_prometheus" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "cb_pbs_constraints_cache_size", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "{{__name__}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Constraints cache size", + "type": "timeseries" + } + ], + "schemaVersion": 39, + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": {}, + "timezone": "browser", + "title": "Bolt Metrics", + "uid": "edxnwlpgaw934c", + "version": 3, + "weekStart": "" +} From 8efc22f61a906e26b2fd00b6555264f6a16339ad Mon Sep 17 00:00:00 2001 From: Jonas Bostoen Date: Thu, 12 Sep 2024 12:13:24 +0200 Subject: [PATCH 29/30] feat(holesky): add update dashboard scripts + doc --- testnets/holesky/README.md | 11 +++++++++++ testnets/holesky/update-grafana.sh | 7 +++++++ 2 files changed, 18 insertions(+) create mode 100755 testnets/holesky/update-grafana.sh diff --git a/testnets/holesky/README.md b/testnets/holesky/README.md index 85a6d4fe7..6e0cdbd95 100644 --- a/testnets/holesky/README.md +++ b/testnets/holesky/README.md @@ -65,6 +65,17 @@ This will run all modules in Docker containers. ### Bolt Sidecar WIP +### Observability +commit-boost comes with various observability tools, such as Prometheus, cadvisor, and Grafana. It also comes with some pre-built dashboards, +which can be found in the `grafana` directory. + +To update these dashboards, run the following command: +```bash +./update-grafana.sh +``` + +In this directory, you can also find a Bolt dashboard, which will be launched alongside the other dashboards. + ### Validators Validators must be configured to always prefer builder proposals over their own. Refer to client documentation for the specific configuration flags. **If this is not set, it could lead to commitment faults**. diff --git a/testnets/holesky/update-grafana.sh b/testnets/holesky/update-grafana.sh new file mode 100755 index 000000000..ef91d97ed --- /dev/null +++ b/testnets/holesky/update-grafana.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +# Get the commit-hash from first argument +commit_hash=$1 + +curl https://raw.githubusercontent.com/Commit-Boost/commit-boost-client/main/grafana/dashboards/dashboard.json -o ./grafana/dashboards/dashboard.json +curl https://raw.githubusercontent.com/Commit-Boost/commit-boost-client/main/grafana/dashboards/system_metrics.json -o ./grafana/dashboards/system_metrics.json From 2f8f4cb63f218b90db3448789f6e1d515177d177 Mon Sep 17 00:00:00 2001 From: Jonas Bostoen Date: Thu, 12 Sep 2024 12:14:18 +0200 Subject: [PATCH 30/30] feat(holesky): update script --- testnets/holesky/update-grafana.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/testnets/holesky/update-grafana.sh b/testnets/holesky/update-grafana.sh index ef91d97ed..4e5a16695 100755 --- a/testnets/holesky/update-grafana.sh +++ b/testnets/holesky/update-grafana.sh @@ -1,7 +1,5 @@ #!/bin/bash -# Get the commit-hash from first argument -commit_hash=$1 - +# Fetches the latest dashboards from commit-boost main curl https://raw.githubusercontent.com/Commit-Boost/commit-boost-client/main/grafana/dashboards/dashboard.json -o ./grafana/dashboards/dashboard.json curl https://raw.githubusercontent.com/Commit-Boost/commit-boost-client/main/grafana/dashboards/system_metrics.json -o ./grafana/dashboards/system_metrics.json