From 51d9b81d5e6788f34c544a510e304aee53b19cc8 Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Tue, 8 Oct 2024 17:02:39 +0200 Subject: [PATCH 01/64] fix: updated devnet --- bolt-sidecar/src/builder/signature.rs | 21 ++++-- bolt-sidecar/src/client/commit_boost.rs | 26 +++++-- bolt-sidecar/src/config/chain.rs | 10 +-- bolt-sidecar/src/crypto/bls.rs | 29 ++++---- bolt-sidecar/src/driver.rs | 7 +- bolt-sidecar/src/primitives/constraint.rs | 22 ++++++ bolt-sidecar/src/primitives/mod.rs | 6 ++ bolt-sidecar/src/test_util.rs | 21 ++---- builder/builder/builder.go | 91 +++++++++++------------ builder/builder/builder_test.go | 35 +++++++++ 10 files changed, 174 insertions(+), 94 deletions(-) diff --git a/bolt-sidecar/src/builder/signature.rs b/bolt-sidecar/src/builder/signature.rs index 107326fa0..ee1d0e57c 100644 --- a/bolt-sidecar/src/builder/signature.rs +++ b/bolt-sidecar/src/builder/signature.rs @@ -23,7 +23,7 @@ pub fn sign_builder_message( sk: &SecretKey, msg: &T, ) -> Result { - let domain = chain.builder_domain(); + let domain = chain.application_builder_domain(); let object_root = msg.hash_tree_root()?.0; let signing_root = compute_signing_root(object_root, domain); @@ -42,7 +42,7 @@ pub fn verify_signed_builder_message( msg: &T, signature: &BlsSignature, ) -> Result<(), ethereum_consensus::Error> { - let domain = chain.builder_domain(); + let domain = chain.application_builder_domain(); let object_root = msg.hash_tree_root()?.0; let signing_root = compute_signing_root(object_root, domain); @@ -121,18 +121,27 @@ mod tests { #[test] fn test_compute_builder_domain() { let mainnet = ChainConfig::mainnet(); - assert_eq!(compute_builder_domain(mainnet.fork_version(), None), mainnet.builder_domain()); + assert_eq!( + compute_builder_domain(mainnet.fork_version(), None), + mainnet.application_builder_domain() + ); let holesky = ChainConfig::holesky(); - assert_eq!(compute_builder_domain(holesky.fork_version(), None), holesky.builder_domain()); + assert_eq!( + compute_builder_domain(holesky.fork_version(), None), + holesky.application_builder_domain() + ); let kurtosis = ChainConfig::kurtosis(0, 0); assert_eq!( compute_builder_domain(kurtosis.fork_version(), None), - kurtosis.builder_domain() + kurtosis.application_builder_domain() ); let helder = ChainConfig::helder(); - assert_eq!(compute_builder_domain(helder.fork_version(), None), helder.builder_domain()); + assert_eq!( + compute_builder_domain(helder.fork_version(), None), + helder.application_builder_domain() + ); } } diff --git a/bolt-sidecar/src/client/commit_boost.rs b/bolt-sidecar/src/client/commit_boost.rs index ad5931727..6082e5bd4 100644 --- a/bolt-sidecar/src/client/commit_boost.rs +++ b/bolt-sidecar/src/client/commit_boost.rs @@ -3,9 +3,10 @@ use std::{str::FromStr, sync::Arc}; use alloy::{rpc::types::beacon::BlsSignature, signers::Signature}; use cb_common::{ commit::{client::SignerClient, request::SignConsensusRequest}, - signer::{BlsPublicKey, EcdsaPublicKey}, + signer::EcdsaPublicKey, }; use commit_boost::prelude::SignProxyRequest; +use ethereum_consensus::crypto::bls::PublicKey as BlsPublicKey; use eyre::ErrReport; use parking_lot::RwLock; use thiserror::Error; @@ -60,7 +61,11 @@ impl CommitBoostSigner { ); let mut pubkeys_lock = this.pubkeys.write(); let mut proxy_ecdsa_lock = this.proxy_ecdsa.write(); - *pubkeys_lock = pubkeys.consensus; + *pubkeys_lock = pubkeys + .consensus + .into_iter() + .map(|k| BlsPublicKey::try_from(k.as_ref()).unwrap()) + .collect(); *proxy_ecdsa_lock = pubkeys.proxy_ecdsa; } Err(e) => { @@ -74,7 +79,8 @@ impl CommitBoostSigner { /// Get the consensus public key from the Commit-Boost signer. pub fn get_consensus_pubkey(&self) -> BlsPublicKey { - *self.pubkeys.read().first().expect("consensus pubkey loaded") + let pk = self.pubkeys.read().first().expect("consensus pubkey loaded").clone(); + BlsPublicKey::try_from(pk.as_ref()).expect("consensus pubkey is valid") } /// Get the proxy ECDSA public key from the Commit-Boost signer. @@ -109,11 +115,17 @@ impl CommitBoostSigner { #[async_trait::async_trait] impl SignerBLS for CommitBoostSigner { + fn pubkey(&self) -> BlsPublicKey { + self.get_consensus_pubkey() + } + async fn sign_commit_boost_root(&self, data: &[u8; 32]) -> eyre::Result { - let request = SignConsensusRequest { - pubkey: *self.pubkeys.read().first().expect("consensus pubkey loaded"), - object_root: *data, - }; + // convert the pubkey from ethereum_consensus to commit-boost format + let pubkey = cb_common::signer::BlsPublicKey::from( + alloy::rpc::types::beacon::BlsPublicKey::from_slice(self.pubkey().as_ref()), + ); + + let request = SignConsensusRequest { pubkey, object_root: *data }; debug!(?request, "Requesting signature from commit_boost"); diff --git a/bolt-sidecar/src/config/chain.rs b/bolt-sidecar/src/config/chain.rs index 0c5dda74e..f5c4769b5 100644 --- a/bolt-sidecar/src/config/chain.rs +++ b/bolt-sidecar/src/config/chain.rs @@ -92,7 +92,7 @@ impl ChainConfig { } /// Get the domain for signing application-builder messages on the given chain. - pub fn builder_domain(&self) -> [u8; 32] { + pub fn application_builder_domain(&self) -> [u8; 32] { self.compute_domain_from_mask(APPLICATION_BUILDER_DOMAIN_MASK) } @@ -174,15 +174,15 @@ mod tests { use super::ChainConfig; let mainnet = ChainConfig::mainnet(); - assert_eq!(mainnet.builder_domain(), BUILDER_DOMAIN_MAINNET); + assert_eq!(mainnet.application_builder_domain(), BUILDER_DOMAIN_MAINNET); let holesky = ChainConfig::holesky(); - assert_eq!(holesky.builder_domain(), BUILDER_DOMAIN_HOLESKY); + assert_eq!(holesky.application_builder_domain(), BUILDER_DOMAIN_HOLESKY); let helder = ChainConfig::helder(); - assert_eq!(helder.builder_domain(), BUILDER_DOMAIN_HELDER); + assert_eq!(helder.application_builder_domain(), BUILDER_DOMAIN_HELDER); let kurtosis = ChainConfig::kurtosis(0, 0); - assert_eq!(kurtosis.builder_domain(), BUILDER_DOMAIN_KURTOSIS); + assert_eq!(kurtosis.application_builder_domain(), BUILDER_DOMAIN_KURTOSIS); } } diff --git a/bolt-sidecar/src/crypto/bls.rs b/bolt-sidecar/src/crypto/bls.rs index 56179aba5..ece368515 100644 --- a/bolt-sidecar/src/crypto/bls.rs +++ b/bolt-sidecar/src/crypto/bls.rs @@ -2,10 +2,10 @@ use std::fmt::Debug; use alloy::primitives::FixedBytes; use blst::{min_pk::Signature, BLST_ERROR}; -use ethereum_consensus::deneb::compute_signing_root; +use ethereum_consensus::{crypto::PublicKey as BlsPublicKey, deneb::compute_signing_root}; use rand::RngCore; -pub use blst::min_pk::{PublicKey as BlsPublicKey, SecretKey as BlsSecretKey}; +pub use blst::min_pk::{PublicKey, SecretKey as BlsSecretKey}; pub use ethereum_consensus::deneb::BlsSignature; use crate::ChainConfig; @@ -28,6 +28,9 @@ pub trait SignableBLS { /// Note: we keep this async to allow remote signer implementations. #[async_trait::async_trait] pub trait SignerBLS: Send + Debug { + /// Get the public key of the signer. + fn pubkey(&self) -> BlsPublicKey; + /// Sign the given data and return the signature. async fn sign_commit_boost_root(&self, data: &[u8; 32]) -> eyre::Result; } @@ -62,12 +65,13 @@ impl Signer { /// Get the public key of the signer. pub fn pubkey(&self) -> BlsPublicKey { - self.key.sk_to_pk() + let pk = self.key.sk_to_pk(); + BlsPublicKey::try_from(pk.to_bytes().as_ref()).unwrap() } /// Sign an SSZ object root with the Application Builder domain. pub fn sign_application_builder_root(&self, root: [u8; 32]) -> eyre::Result { - self.sign_root(root, self.chain.builder_domain()) + self.sign_root(root, self.chain.application_builder_domain()) } /// Sign an SSZ object root with the Commit Boost domain. @@ -88,7 +92,7 @@ impl Signer { root: [u8; 32], signature: &Signature, ) -> eyre::Result<()> { - self.verify_root(root, signature, &self.pubkey(), self.chain.builder_domain()) + self.verify_root(root, signature, self.chain.application_builder_domain()) } /// Verify the signature with the public key of the signer using the Commit Boost domain. @@ -97,7 +101,7 @@ impl Signer { root: [u8; 32], signature: &Signature, ) -> eyre::Result<()> { - self.verify_root(root, signature, &self.pubkey(), self.chain.commit_boost_domain()) + self.verify_root(root, signature, self.chain.commit_boost_domain()) } /// Verify the signature of the object with the given public key. @@ -105,12 +109,12 @@ impl Signer { &self, root: [u8; 32], signature: &Signature, - pubkey: &BlsPublicKey, domain: [u8; 32], ) -> eyre::Result<()> { let signing_root = compute_signing_root(&root, domain)?; + let pk = blst::min_pk::PublicKey::from_bytes(self.pubkey().as_ref()).unwrap(); - let res = signature.verify(true, signing_root.as_ref(), BLS_DST_PREFIX, &[], pubkey, true); + let res = signature.verify(true, signing_root.as_ref(), BLS_DST_PREFIX, &[], &pk, true); if res == BLST_ERROR::BLST_SUCCESS { Ok(()) } else { @@ -121,16 +125,15 @@ impl Signer { #[async_trait::async_trait] impl SignerBLS for Signer { + fn pubkey(&self) -> BlsPublicKey { + self.pubkey() + } + async fn sign_commit_boost_root(&self, data: &[u8; 32]) -> eyre::Result { self.sign_commit_boost_root(*data) } } -/// Compatibility between ethereum_consensus and blst -pub fn from_bls_signature_to_consensus_signature(sig_bytes: impl AsRef<[u8]>) -> BlsSignature { - BlsSignature::try_from(sig_bytes.as_ref()).unwrap() -} - /// Generate a random BLS secret key. pub fn random_bls_secret() -> BlsSecretKey { let mut rng = rand::thread_rng(); diff --git a/bolt-sidecar/src/driver.rs b/bolt-sidecar/src/driver.rs index bee3969ed..740f617eb 100644 --- a/bolt-sidecar/src/driver.rs +++ b/bolt-sidecar/src/driver.rs @@ -193,7 +193,9 @@ impl SidecarDriver index, Err(err) => { error!(?err, "Consensus: failed to validate request"); @@ -228,7 +230,8 @@ impl SidecarDriver u64 { @@ -131,4 +135,22 @@ mod tests { // Verify that the deserialized message is equal to the original message assert_eq!(message, deserialized_message); } + + #[test] + fn test_constraints_signature_roundtrip() { + let signer = Signer::random(); + + let tx_bytes = bytes!("f8678085019dc6838082520894deaddeaddeaddeaddeaddeaddeaddeaddeaddead38808360306ca06664c078fa60bd3ece050903dd295949908dd9686ec8871fa558f868e031cd39a00ed4f0b122b32b73f19230fabe6a726e2d07f84eda5beaa42a1ae1271bdee39f").to_vec(); + let tx = FullTransaction::decode_enveloped(tx_bytes.as_slice()).unwrap(); + + let constraint = ConstraintsMessage::from_transaction(signer.pubkey(), 165, tx); + + let digest = constraint.digest(); + let signature = signer.sign_commit_boost_root(digest).unwrap(); + let signed_constraints = SignedConstraints { message: constraint, signature }; + + // verify the signature + let blst_sig = BlsSignature::from_bytes(signed_constraints.signature.as_ref()).unwrap(); + assert!(signer.verify_commit_boost_root(digest, &blst_sig).is_ok()); + } } diff --git a/bolt-sidecar/src/primitives/mod.rs b/bolt-sidecar/src/primitives/mod.rs index c4cbc5dee..ce7f9b3fd 100644 --- a/bolt-sidecar/src/primitives/mod.rs +++ b/bolt-sidecar/src/primitives/mod.rs @@ -379,6 +379,12 @@ impl std::ops::DerefMut for FullTransaction { } impl FullTransaction { + /// Convenience method to parse a raw transaction into a `FullTransaction`. + pub fn decode_enveloped(data: impl AsRef<[u8]>) -> eyre::Result { + let tx = PooledTransactionsElement::decode_enveloped(&mut data.as_ref())?; + Ok(Self { tx, sender: None }) + } + pub fn into_inner(self) -> PooledTransactionsElement { self.tx } diff --git a/bolt-sidecar/src/test_util.rs b/bolt-sidecar/src/test_util.rs index d62429434..a32c6cc3b 100644 --- a/bolt-sidecar/src/test_util.rs +++ b/bolt-sidecar/src/test_util.rs @@ -13,7 +13,6 @@ use alloy_node_bindings::{Anvil, AnvilInstance}; use blst::min_pk::SecretKey; use ethereum_consensus::crypto::{PublicKey, Signature}; use rand::Rng; -use reth_primitives::PooledTransactionsElement; use secp256k1::Message; use tracing::warn; @@ -157,8 +156,8 @@ pub(crate) async fn create_signed_commitment_request( for tx in txs { let tx_signed = tx.clone().build(&wallet).await?; let raw_encoded = tx_signed.encoded_2718(); - let tx_pooled = PooledTransactionsElement::decode_enveloped(&mut raw_encoded.as_slice())?; - full_txs.push(FullTransaction::from(tx_pooled)); + let full_tx = FullTransaction::decode_enveloped(raw_encoded.as_slice())?; + full_txs.push(full_tx); } let mut request = InclusionRequest { txs: full_txs, slot, signature: None, signer: None }; @@ -192,7 +191,7 @@ async fn generate_test_data() { let signer = BlsSigner::random(); let pk = signer.pubkey(); - println!("Validator Public Key: {}", hex::encode(pk.to_bytes())); + println!("Validator Public Key: {}", hex::encode(pk.as_ref())); // Generate a delegatee's BLS secret key and public key let delegatee_ikm: [u8; 32] = rand::thread_rng().gen(); @@ -202,8 +201,7 @@ async fn generate_test_data() { // Prepare a Delegation message let delegation_msg = DelegationMessage { - validator_pubkey: PublicKey::try_from(pk.to_bytes().as_slice()) - .expect("Failed to convert validator public key"), + validator_pubkey: pk.clone(), delegatee_pubkey: PublicKey::try_from(delegatee_pk.to_bytes().as_slice()) .expect("Failed to convert delegatee public key"), }; @@ -225,8 +223,7 @@ async fn generate_test_data() { // Prepare a revocation message let revocation_msg = RevocationMessage { - validator_pubkey: PublicKey::try_from(pk.to_bytes().as_slice()) - .expect("Failed to convert validator public key"), + validator_pubkey: pk.clone(), delegatee_pubkey: PublicKey::try_from(delegatee_pk.to_bytes().as_slice()) .expect("Failed to convert delegatee public key"), }; @@ -249,13 +246,7 @@ async fn generate_test_data() { let transactions = random_constraints(1); // Prepare a ConstraintsMessage - let constraints_msg = ConstraintsMessage { - pubkey: PublicKey::try_from(pk.to_bytes().as_slice()) - .expect("Failed to convert validator public key"), - slot: 32, - top: true, - transactions, - }; + let constraints_msg = ConstraintsMessage { pubkey: pk, slot: 32, top: true, transactions }; let digest = SignableBLS::digest(&constraints_msg); diff --git a/builder/builder/builder.go b/builder/builder/builder.go index 65c65f144..02714f36f 100644 --- a/builder/builder/builder.go +++ b/builder/builder/builder.go @@ -350,66 +350,65 @@ func (b *Builder) subscribeToRelayForConstraints(relayBaseEndpoint string) error // We assume the data is the JSON representation of the constraints log.Info(fmt.Sprintf("Received new constraint: %s", data)) - constraintsSigned := make(types.SignedConstraintsList, 0, 8) + constraintsSigned := new(types.SignedConstraints) if err := json.Unmarshal([]byte(data), &constraintsSigned); err != nil { log.Warn(fmt.Sprintf("Failed to unmarshal constraints: %v", err)) continue } - if len(constraintsSigned) == 0 { + if len(constraintsSigned.Message.Transactions) == 0 { log.Warn("Received 0 length list of constraints") continue } - for _, constraint := range constraintsSigned { - // TODO: re-enable this once testing the devnet has ended - // oneValidSignature := false - // Check if the signature is valid against any of the authorized pubkeys - // for _, pubkey := range b.slotConstraintsPubkeys { - // valid, err := constraint.VerifySignature(pubkey, b.GetConstraintsDomain()) - // if err != nil || !valid { - // log.Error("Failed to verify constraint signature", "err", err) - // continue - // } - // - // oneValidSignature = true - // } - - // TODO: remove this once testing the devnet has ended, we should check for authorized keys - valid, err := constraint.VerifySignature(constraint.Message.Pubkey, b.GetConstraintsDomain()) - if err != nil || !valid { - log.Error("Failed to verify constraint signature", "err", err) - continue - } - - // TODO: re-enable this once testing the devnet has ended - // If there is no valid signature, continue with the next constraint - // if !oneValidSignature { - // continue - // } + // TODO: re-enable this once testing the devnet has ended + // oneValidSignature := false + // Check if the signature is valid against any of the authorized pubkeys + // for _, pubkey := range b.slotConstraintsPubkeys { + // valid, err := constraint.VerifySignature(pubkey, b.GetConstraintsDomain()) + // if err != nil || !valid { + // log.Error("Failed to verify constraint signature", "err", err) + // continue + // } + // + // oneValidSignature = true + // } + + // TODO: remove this once testing the devnet has ended, we should check for authorized keys + valid, err := constraintsSigned.VerifySignature(constraintsSigned.Message.Pubkey, b.GetConstraintsDomain()) + if err != nil || !valid { + log.Error("Failed to verify constraint signature", "err", err) + continue + } - decodedConstraints, err := DecodeConstraints(constraint) - if err != nil { - log.Error("Failed to decode constraint: ", err) - continue - } + // TODO: re-enable this once testing the devnet has ended + // If there is no valid signature, continue with the next constraint + // if !oneValidSignature { + // continue + // } - // For every constraint, we need to check if it has already been seen for the associated slot - slotConstraints, _ := b.constraintsCache.Get(constraint.Message.Slot) - if len(slotConstraints) == 0 { - // New constraint for this slot, add it in the map and continue with the next constraint - b.constraintsCache.Put(constraint.Message.Slot, decodedConstraints) - continue - } + decodedConstraints, err := DecodeConstraints(constraintsSigned) + if err != nil { + log.Error("Failed to decode constraint: ", err) + continue + } - for hash := range decodedConstraints { - // Update the slot constraints - slotConstraints[hash] = decodedConstraints[hash] - } + // For every constraint, we need to check if it has already been seen for the associated slot + slotConstraints, _ := b.constraintsCache.Get(constraintsSigned.Message.Slot) + if len(slotConstraints) == 0 { + // New constraint for this slot, add it in the map and continue with the next constraint + b.constraintsCache.Put(constraintsSigned.Message.Slot, decodedConstraints) + continue + } - // Update the slot constraints in the cache - b.constraintsCache.Put(constraint.Message.Slot, slotConstraints) + for hash := range decodedConstraints { + // Update the slot constraints + slotConstraints[hash] = decodedConstraints[hash] } + + // Update the slot constraints in the cache + b.constraintsCache.Put(constraintsSigned.Message.Slot, slotConstraints) + } return nil diff --git a/builder/builder/builder_test.go b/builder/builder/builder_test.go index c4aa35868..07d7d1fc4 100644 --- a/builder/builder/builder_test.go +++ b/builder/builder/builder_test.go @@ -465,6 +465,41 @@ func TestSubscribeProposerConstraints(t *testing.T) { } } +func TestDeserializeConstraints(t *testing.T) { + jsonStr := `[ + { + "message": { + "pubkey": "0xa695ad325dfc7e1191fbc9f186f58eff42a634029731b18380ff89bf42c464a42cb8ca55b200f051f57f1e1893c68759", + "slot": 32, + "top": true, + "transactions": [ + "0x02f86c870c72dd9d5e883e4d0183408f2382520894d2e2adf7177b7a8afddbc12d1634cf23ea1a71020180c001a08556dcfea479b34675db3fe08e29486fe719c2b22f6b0c1741ecbbdce4575cc6a01cd48009ccafd6b9f1290bbe2ceea268f94101d1d322c787018423ebcbc87ab4" + ] + }, + "signature": "0xb8d50ee0d4b269db3d4658c1dac784d273a4160d769e16dce723a9684c390afe5865348416b3bf0f1a4f47098bec9024135d0d95f08bed18eb577a3d8a67f5dc78b13cc62515e280786a73fb267d35dfb7ab46a25ac29bf5bc2fa5b07b3e07a6" + } + ]` + + var constraints types.SignedConstraintsList + err := json.Unmarshal([]byte(jsonStr), &constraints) + require.NoError(t, err) + + jsonStr = `{ + "message": { + "pubkey":"0xb3cd9c9e59730c210bf9b76959bf11e20bb05cf47cfefdcaab74bc17c369d6daefe1219c2b94d743ffd27988edf24b90", + "slot":183, + "top":false, + "transactions": [ + "0xf8678085019dc6838082520894deaddeaddeaddeaddeaddeaddeaddeaddeaddead04808360306ca0fde9bdf8f1a9fefef7538490242afb21a0160cf19f1686c7b9bddb45de973b62a0318411f2c959d3e6a25434f99850a0eaa6beb617f7a2dbc9683dccded7bd4b10" + ] + }, + "signature": "0xaa8a47c6398d5862b56d1bbb308352c65e57e62b0bfdda39a36db7fff3a256c3c7066b219a15a013aae5303f42b6f07b025f34ed6d899e6172fec20d40c4ffebeb50f5d0b75a303c1cc916574c3e0f29d53b2211d28234f430fffce62b4ee554" + }` + + err = json.Unmarshal([]byte(jsonStr), &constraints) + require.NoError(t, err) +} + func sseConstraintsHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/event-stream") w.Header().Set("Cache-Control", "no-cache") From fa0bd302081bcd9187ca3994c302e14d42b07009 Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Tue, 8 Oct 2024 17:25:48 +0200 Subject: [PATCH 02/64] fix(builder): runtime err in commit-transaction --- builder/miner/worker.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builder/miner/worker.go b/builder/miner/worker.go index 98f02a9e8..2a69317c4 100644 --- a/builder/miner/worker.go +++ b/builder/miner/worker.go @@ -1176,7 +1176,7 @@ func (w *worker) commitTransactions(env *environment, plainTxs, blobTxs *transac } } else { // No more pool tx left, we can add the unindexed ones if available - if len(constraintsOrderedByNonceAndHashDesc) == 0 { + if len(constraintsRecoveredOrderedByNonceAndHashDesc) == 0 { // To recap, this means: // 1. there are no more pool tx left // 2. there are no more constraints From cf90e1609cbf5b9e30d4094d8ab04848e4b81e88 Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Tue, 8 Oct 2024 17:37:30 +0200 Subject: [PATCH 03/64] fix(builder): golang strikes again --- builder/core/types/constraints.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/builder/core/types/constraints.go b/builder/core/types/constraints.go index 39c7caeca..ea16c6128 100644 --- a/builder/core/types/constraints.go +++ b/builder/core/types/constraints.go @@ -13,6 +13,7 @@ import ( capellaSpec "github.com/attestantio/go-eth2-client/spec/capella" denebSpec "github.com/attestantio/go-eth2-client/spec/deneb" + "github.com/attestantio/go-builder-client/api/deneb" v1 "github.com/attestantio/go-builder-client/api/v1" "github.com/attestantio/go-eth2-client/spec/phase0" "github.com/ethereum/go-ethereum/common" @@ -147,10 +148,12 @@ func (v *VersionedSubmitBlockRequestWithProofs) MarshalJSON() ([]byte, error) { ExecutionPayload *denebSpec.ExecutionPayload `json:"execution_payload"` Signature phase0.BLSSignature `json:"signature"` Proofs *InclusionProof `json:"proofs"` + BlobsBundle *deneb.BlobsBundle `json:"blobs_bundle"` }{ Message: v.Deneb.Message, ExecutionPayload: v.Deneb.ExecutionPayload, Signature: v.Deneb.Signature, + BlobsBundle: v.Deneb.BlobsBundle, Proofs: v.Proofs, }) } From 11cd07783b886df2a5797545e8eec996741034ba Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Wed, 9 Oct 2024 17:10:57 +0200 Subject: [PATCH 04/64] chore(stash): bolt-boost fixes --- bolt-boost/Cargo.lock | 1 + bolt-boost/Cargo.toml | 1 + bolt-boost/src/server.rs | 8 +-- bolt-boost/src/types.rs | 112 +++++++++++++++++++++++++++--- bolt-kurtosis-client/src/main.rs | 9 ++- bolt-kurtosis-client/src/utils.rs | 2 +- builder/builder/builder.go | 91 ++++++++++++------------ 7 files changed, 159 insertions(+), 65 deletions(-) diff --git a/bolt-boost/Cargo.lock b/bolt-boost/Cargo.lock index 26a114203..4ea87e87c 100644 --- a/bolt-boost/Cargo.lock +++ b/bolt-boost/Cargo.lock @@ -1060,6 +1060,7 @@ name = "bolt-boost" version = "0.1.0" dependencies = [ "alloy", + "alloy-rlp", "async-trait", "axum", "axum-extra", diff --git a/bolt-boost/Cargo.toml b/bolt-boost/Cargo.toml index fd02c0d07..36987f0e2 100644 --- a/bolt-boost/Cargo.toml +++ b/bolt-boost/Cargo.toml @@ -38,6 +38,7 @@ alloy = { version = "0.3.6", features = [ "rpc-types-beacon", "rpc-types-engine", ] } +alloy-rlp = "0.3.8" # commit-boost cb-common = { git = "https://github.com/commit-boost/commit-boost-client", tag = "v0.3.0" } diff --git a/bolt-boost/src/server.rs b/bolt-boost/src/server.rs index a0022b551..332e24efd 100644 --- a/bolt-boost/src/server.rs +++ b/bolt-boost/src/server.rs @@ -543,13 +543,9 @@ where Ok(response) => { let url = response.url().clone(); let status = response.status(); - let body = response.text().await.ok(); if status != StatusCode::OK { - error!( - %status, - %url, - "Failed to POST to relay: {body:?}" - ) + let body = response.text().await.ok(); + error!(%status, %url, "Failed to POST to relay: {body:?}"); } else { debug!(%url, "Successfully sent POST request to relay"); success = true; diff --git a/bolt-boost/src/types.rs b/bolt-boost/src/types.rs index 4bd62ccd3..d9ab762f6 100644 --- a/bolt-boost/src/types.rs +++ b/bolt-boost/src/types.rs @@ -1,15 +1,17 @@ use alloy::{ - consensus::TxEnvelope, - eips::eip2718::{Decodable2718, Eip2718Error}, + consensus::{TxEip4844Variant, TxEnvelope}, + eips::eip2718::{Decodable2718, Eip2718Error, Eip2718Result}, primitives::{Bytes, TxHash, B256}, rpc::types::beacon::{BlsPublicKey, BlsSignature}, signers::k256::sha2::{Digest, Sha256}, }; +use alloy_rlp::{BufMut, Encodable}; use axum::http::HeaderMap; use reqwest::Url; use serde::{Deserialize, Serialize}; use ssz_derive::{Decode, Encode}; use std::ops::Deref; +use tracing::error; use cb_common::{ constants::COMMIT_BOOST_DOMAIN, @@ -44,8 +46,15 @@ impl SignedConstraints { #[allow(unused)] pub fn verify_signature(&self, chain: Chain, pubkey: &BlsPublicKey) -> bool { let domain = compute_domain(chain, COMMIT_BOOST_DOMAIN); - let signing_root = compute_signing_root(self.message.digest(), domain); + let digest = match self.message.digest() { + Ok(digest) => digest, + Err(e) => { + error!(err = ?e, "Failed to compute digest"); + return false; + } + }; + let signing_root = compute_signing_root(digest, domain); verify_bls_signature(pubkey, &signing_root, &self.signature).is_ok() } } @@ -60,19 +69,19 @@ pub struct ConstraintsMessage { impl ConstraintsMessage { /// Returns the digest of this message. - pub fn digest(&self) -> [u8; 32] { + pub fn digest(&self) -> Eip2718Result<[u8; 32]> { let mut hasher = Sha256::new(); hasher.update(self.pubkey); hasher.update(self.slot.to_le_bytes()); hasher.update((self.top as u8).to_le_bytes()); for bytes in &self.transactions { - let tx = TxEnvelope::decode_2718(&mut bytes.as_ref()).expect("valid transaction"); + let tx = TxEnvelope::decode_2718(&mut bytes.as_ref())?; hasher.update(tx.tx_hash()); } - hasher.finalize().into() + Ok(hasher.finalize().into()) } } @@ -92,14 +101,45 @@ impl TryFrom for ConstraintsWithProofData { .transactions .iter() .map(|tx| { - let tx_hash = *TxEnvelope::decode_2718(&mut tx.as_ref())?.tx_hash(); + let envelope = TxEnvelope::decode_2718(&mut tx.as_ref())?; + let tx_hash = *envelope.tx_hash(); - let tx_root = - tree_hash::TreeHash::tree_hash_root(&Transaction::< + let root = match envelope { + // For type 3 txs, take the hash tree root of the inner tx (EIP-4844) + TxEnvelope::Eip4844(tx) => match tx.tx() { + TxEip4844Variant::TxEip4844(tx) => { + let mut out = Vec::new(); + out.put_u8(0x03); + tx.encode(&mut out); + + tree_hash::TreeHash::tree_hash_root(&Transaction::< + ::MaxBytesPerTransaction, + >::from( + out + )) + } + TxEip4844Variant::TxEip4844WithSidecar(tx) => { + use alloy_rlp::Encodable; + let mut out = Vec::new(); + out.put_u8(0x03); + tx.tx.encode(&mut out); + + tree_hash::TreeHash::tree_hash_root(&Transaction::< + ::MaxBytesPerTransaction, + >::from( + out + )) + } + }, + // For other transaction types, take the hash tree root of the whole tx + _ => tree_hash::TreeHash::tree_hash_root(&Transaction::< ::MaxBytesPerTransaction, - >::from(tx.to_vec())); + >::from( + tx.to_vec() + )), + }; - Ok((tx_hash, tx_root)) + Ok((tx_hash, root)) }) .collect::, Eip2718Error>>()?; @@ -173,3 +213,53 @@ pub struct RequestConfig { pub timeout_ms: u64, pub headers: HeaderMap, } + +#[cfg(test)] +mod tests { + use alloy::{hex::FromHex, primitives::Bytes}; + + use super::ConstraintsWithProofData; + use crate::types::SignedConstraints; + + #[test] + fn decode_constraints_test() { + let raw = r#"{ + "message": { + "pubkey": "0xa695ad325dfc7e1191fbc9f186f58eff42a634029731b18380ff89bf42c464a42cb8ca55b200f051f57f1e1893c68759", + "slot": 32, + "top": true, + "transactions": [ + "0x02f86c870c72dd9d5e883e4d0183408f2382520894d2e2adf7177b7a8afddbc12d1634cf23ea1a71020180c001a08556dcfea479b34675db3fe08e29486fe719c2b22f6b0c1741ecbbdce4575cc6a01cd48009ccafd6b9f1290bbe2ceea268f94101d1d322c787018423ebcbc87ab4" + ] + }, + "signature": "0xb8d50ee0d4b269db3d4658c1dac784d273a4160d769e16dce723a9684c390afe5865348416b3bf0f1a4f47098bec9024135d0d95f08bed18eb577a3d8a67f5dc78b13cc62515e280786a73fb267d35dfb7ab46a25ac29bf5bc2fa5b07b3e07a6" + }"#; + + let mut c = serde_json::from_str::(raw).unwrap(); + let pd = ConstraintsWithProofData::try_from(c.message.clone()).unwrap().proof_data[0]; + + assert_eq!( + pd.0.to_string(), + "0x385b9f1ba5dbbe419dcbbbbf0840b76b941f3c216d383ec9deb9b1a323ee0cea".to_string() + ); + + assert_eq!( + pd.1.to_string(), + "0x02e383af0c34516ef38e13391d917d5b61b6f69e17d5234f77cb8cc3a1ae932e".to_string() + ); + + c.message.transactions[0] = Bytes::from_hex("0x03f9029c01830299f184b2d05e008507aef40a00832dc6c09468d30f47f19c07bccef4ac7fae2dc12fca3e0dc980b90204ef16e845000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000633b68f5d8d3a86593ebb815b4663bcbe0302e31382e302d64657600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004109de8da2a97e37f2e6dc9f7d50a408f9344d7aa1a925ae53daf7fbef43491a571960d76c0cb926190a9da10df7209fb1ba93cd98b1565a3a2368749d505f90c81c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0843b9aca00e1a00141e3a338e30c49ed0501e315bcc45e4edefebed43ab1368a1505461d9cf64901a01e8511e06b17683d89eb57b9869b96b8b611f969f7f56cbc0adc2df7c88a2a07a00910deacf91bba0d74e368d285d311dc5884e7cfe219d85aea5741b2b6e3a2fe").unwrap(); + + let pd = ConstraintsWithProofData::try_from(c.message).unwrap().proof_data[0]; + + assert_eq!( + pd.0.to_string(), + "0x15bd881daa1408b33f67fa4bdeb8acfb0a2289d9b4c6f81eef9bb2bb2e52e780".to_string() + ); + + assert_eq!( + pd.1.to_string(), + "0x0a637924b9f9b28a413b01cb543bcd688850b8964f77576fc71219448f7b4ab9".to_string() + ); + } +} diff --git a/bolt-kurtosis-client/src/main.rs b/bolt-kurtosis-client/src/main.rs index 5c2c925fd..dae9b84b6 100644 --- a/bolt-kurtosis-client/src/main.rs +++ b/bolt-kurtosis-client/src/main.rs @@ -84,7 +84,7 @@ async fn main() -> Result<()> { ); info!("Transaction hash: {}", tx_hash); - info!("body: {}", serde_json::to_string(&request)?); + info!("body: {}", trim_zeroes(serde_json::to_string(&request)?)); let client = reqwest::Client::new(); let response = client @@ -95,8 +95,13 @@ async fn main() -> Result<()> { .send() .await?; - info!("Response: {:?}", response.text().await?); + let res = trim_zeroes(response.text().await?); + info!("Response: {:?}", res); } Ok(()) } + +fn trim_zeroes(s: impl Into) -> String { + s.into().replace(&"0".repeat(32), ".").replace(&".".repeat(4), "") +} diff --git a/bolt-kurtosis-client/src/utils.rs b/bolt-kurtosis-client/src/utils.rs index 89edf80bc..1d9f2a7a1 100644 --- a/bolt-kurtosis-client/src/utils.rs +++ b/bolt-kurtosis-client/src/utils.rs @@ -37,7 +37,7 @@ pub fn generate_random_blob_tx() -> TransactionRequest { .with_value(U256::from(100)) .with_max_fee_per_blob_gas(100u128) .max_fee_per_gas(NOICE_GAS_PRICE) - .max_priority_fee_per_gas(NOICE_GAS_PRICE / 10) + .max_priority_fee_per_gas(NOICE_GAS_PRICE) .with_gas_limit(42_000u128) .with_blob_sidecar(sidecar) .with_input(random_bytes) diff --git a/builder/builder/builder.go b/builder/builder/builder.go index 02714f36f..65c65f144 100644 --- a/builder/builder/builder.go +++ b/builder/builder/builder.go @@ -350,65 +350,66 @@ func (b *Builder) subscribeToRelayForConstraints(relayBaseEndpoint string) error // We assume the data is the JSON representation of the constraints log.Info(fmt.Sprintf("Received new constraint: %s", data)) - constraintsSigned := new(types.SignedConstraints) + constraintsSigned := make(types.SignedConstraintsList, 0, 8) if err := json.Unmarshal([]byte(data), &constraintsSigned); err != nil { log.Warn(fmt.Sprintf("Failed to unmarshal constraints: %v", err)) continue } - if len(constraintsSigned.Message.Transactions) == 0 { + if len(constraintsSigned) == 0 { log.Warn("Received 0 length list of constraints") continue } - // TODO: re-enable this once testing the devnet has ended - // oneValidSignature := false - // Check if the signature is valid against any of the authorized pubkeys - // for _, pubkey := range b.slotConstraintsPubkeys { - // valid, err := constraint.VerifySignature(pubkey, b.GetConstraintsDomain()) - // if err != nil || !valid { - // log.Error("Failed to verify constraint signature", "err", err) - // continue - // } - // - // oneValidSignature = true - // } - - // TODO: remove this once testing the devnet has ended, we should check for authorized keys - valid, err := constraintsSigned.VerifySignature(constraintsSigned.Message.Pubkey, b.GetConstraintsDomain()) - if err != nil || !valid { - log.Error("Failed to verify constraint signature", "err", err) - continue - } - - // TODO: re-enable this once testing the devnet has ended - // If there is no valid signature, continue with the next constraint - // if !oneValidSignature { - // continue - // } + for _, constraint := range constraintsSigned { + // TODO: re-enable this once testing the devnet has ended + // oneValidSignature := false + // Check if the signature is valid against any of the authorized pubkeys + // for _, pubkey := range b.slotConstraintsPubkeys { + // valid, err := constraint.VerifySignature(pubkey, b.GetConstraintsDomain()) + // if err != nil || !valid { + // log.Error("Failed to verify constraint signature", "err", err) + // continue + // } + // + // oneValidSignature = true + // } + + // TODO: remove this once testing the devnet has ended, we should check for authorized keys + valid, err := constraint.VerifySignature(constraint.Message.Pubkey, b.GetConstraintsDomain()) + if err != nil || !valid { + log.Error("Failed to verify constraint signature", "err", err) + continue + } - decodedConstraints, err := DecodeConstraints(constraintsSigned) - if err != nil { - log.Error("Failed to decode constraint: ", err) - continue - } + // TODO: re-enable this once testing the devnet has ended + // If there is no valid signature, continue with the next constraint + // if !oneValidSignature { + // continue + // } - // For every constraint, we need to check if it has already been seen for the associated slot - slotConstraints, _ := b.constraintsCache.Get(constraintsSigned.Message.Slot) - if len(slotConstraints) == 0 { - // New constraint for this slot, add it in the map and continue with the next constraint - b.constraintsCache.Put(constraintsSigned.Message.Slot, decodedConstraints) - continue - } + decodedConstraints, err := DecodeConstraints(constraint) + if err != nil { + log.Error("Failed to decode constraint: ", err) + continue + } - for hash := range decodedConstraints { - // Update the slot constraints - slotConstraints[hash] = decodedConstraints[hash] - } + // For every constraint, we need to check if it has already been seen for the associated slot + slotConstraints, _ := b.constraintsCache.Get(constraint.Message.Slot) + if len(slotConstraints) == 0 { + // New constraint for this slot, add it in the map and continue with the next constraint + b.constraintsCache.Put(constraint.Message.Slot, decodedConstraints) + continue + } - // Update the slot constraints in the cache - b.constraintsCache.Put(constraintsSigned.Message.Slot, slotConstraints) + for hash := range decodedConstraints { + // Update the slot constraints + slotConstraints[hash] = decodedConstraints[hash] + } + // Update the slot constraints in the cache + b.constraintsCache.Put(constraint.Message.Slot, slotConstraints) + } } return nil From cb72c20b2da8c0deb175da63b864ced535a7170e Mon Sep 17 00:00:00 2001 From: Naman Garg <0708ng@gmail.com> Date: Mon, 7 Oct 2024 17:08:14 +0530 Subject: [PATCH 05/64] feat(mev-boost): update ConstraintMessage --- mev-boost/server/constraints.go | 76 ++++++++++++++------------------ mev-boost/server/service.go | 43 ++++++++---------- mev-boost/server/service_test.go | 39 ++++++++-------- 3 files changed, 70 insertions(+), 88 deletions(-) diff --git a/mev-boost/server/constraints.go b/mev-boost/server/constraints.go index 4f5914aa1..0697a2938 100644 --- a/mev-boost/server/constraints.go +++ b/mev-boost/server/constraints.go @@ -7,22 +7,25 @@ import ( lru "github.com/hashicorp/golang-lru/v2" ) -type BatchedSignedConstraints = []*SignedConstraints +type ( + BatchedSignedConstraints = []*SignedConstraints + HashToTransactionDecoded = map[gethCommon.Hash]*types.Transaction +) +// SignedConstraints represents the signed constraints. +// Reference: https://docs.boltprotocol.xyz/api/builder type SignedConstraints struct { Message ConstraintsMessage `json:"message"` Signature phase0.BLSSignature `json:"signature"` } +// ConstraintsMessage represents the constraints message. +// Reference: https://docs.boltprotocol.xyz/api/builder type ConstraintsMessage struct { - ValidatorIndex uint64 `json:"validator_index"` - Slot uint64 `json:"slot"` - Constraints []*Constraint `json:"constraints"` -} - -type Constraint struct { - Tx Transaction `json:"tx"` - Index *uint64 `json:"index"` + Pubkey phase0.BLSPubKey `json:"pubkey"` + Slot uint64 `json:"slot"` + Top bool `json:"top"` + Transactions []Transaction // Custom marshal and unmarshal implemented below } func (s *SignedConstraints) String() string { @@ -33,29 +36,25 @@ func (m *ConstraintsMessage) String() string { return JSONStringify(m) } -func (c *Constraint) String() string { - return JSONStringify(c) -} - -// ConstraintCache is a cache for constraints. -type ConstraintCache struct { +// ConstraintsCache is a cache for constraints. +type ConstraintsCache struct { // map of slots to all constraints for that slot - constraints *lru.Cache[uint64, map[gethCommon.Hash]*Constraint] + constraints *lru.Cache[uint64, map[gethCommon.Hash]*Transaction] } -// NewConstraintCache creates a new constraint cache. +// NewConstraintsCache creates a new constraint cache. // cap is the maximum number of slots to store constraints for. -func NewConstraintCache(cap int) *ConstraintCache { - constraints, _ := lru.New[uint64, map[gethCommon.Hash]*Constraint](cap) - return &ConstraintCache{ +func NewConstraintsCache(cap int) *ConstraintsCache { + constraints, _ := lru.New[uint64, map[gethCommon.Hash]*Transaction](cap) + return &ConstraintsCache{ constraints: constraints, } } // AddInclusionConstraint adds an inclusion constraint to the cache at the given slot for the given transaction. -func (c *ConstraintCache) AddInclusionConstraint(slot uint64, tx Transaction, index *uint64) error { +func (c *ConstraintsCache) AddInclusionConstraint(slot uint64, tx Transaction, index *uint64) error { if _, exists := c.constraints.Get(slot); !exists { - c.constraints.Add(slot, make(map[gethCommon.Hash]*Constraint)) + c.constraints.Add(slot, make(map[gethCommon.Hash]*Transaction)) } // parse transaction to get its hash and store it in the cache @@ -67,52 +66,41 @@ func (c *ConstraintCache) AddInclusionConstraint(slot uint64, tx Transaction, in } m, _ := c.constraints.Get(slot) - m[parsedTx.Hash()] = &Constraint{ - Tx: tx, - Index: index, - } + m[parsedTx.Hash()] = &tx return nil } // AddInclusionConstraints adds multiple inclusion constraints to the cache at the given slot -func (c *ConstraintCache) AddInclusionConstraints(slot uint64, constraints []*Constraint) error { +func (c *ConstraintsCache) AddInclusionConstraints(slot uint64, transactions []Transaction) error { if _, exists := c.constraints.Get(slot); !exists { - c.constraints.Add(slot, make(map[gethCommon.Hash]*Constraint)) + c.constraints.Add(slot, make(map[gethCommon.Hash]*Transaction)) } m, _ := c.constraints.Get(slot) - for _, constraint := range constraints { + for _, tx := range transactions { parsedTx := new(types.Transaction) - err := parsedTx.UnmarshalBinary(constraint.Tx) + err := parsedTx.UnmarshalBinary(tx) if err != nil { return err } - m[parsedTx.Hash()] = constraint + m[parsedTx.Hash()] = &tx } return nil } // Get gets the constraints at the given slot. -func (c *ConstraintCache) Get(slot uint64) (map[gethCommon.Hash]*Constraint, bool) { +func (c *ConstraintsCache) Get(slot uint64) (map[gethCommon.Hash]*Transaction, bool) { return c.constraints.Get(slot) } // FindTransactionByHash finds the constraint for the given transaction hash and returns it. -func (c *ConstraintCache) FindTransactionByHash(txHash gethCommon.Hash) (*Constraint, bool) { - for _, hashToConstraint := range c.constraints.Values() { - if constraint, exists := hashToConstraint[txHash]; exists { - return constraint, true +func (c *ConstraintsCache) FindTransactionByHash(txHash gethCommon.Hash) (*Transaction, bool) { + for _, hashToTx := range c.constraints.Values() { + if tx, exists := hashToTx[txHash]; exists { + return tx, true } } return nil, false } - -type ( - HashToConstraintDecoded = map[gethCommon.Hash]*ConstraintDecoded - ConstraintDecoded struct { - Index *uint64 - Tx *types.Transaction - } -) diff --git a/mev-boost/server/service.go b/mev-boost/server/service.go index 36a501792..84c19ace2 100644 --- a/mev-boost/server/service.go +++ b/mev-boost/server/service.go @@ -121,7 +121,7 @@ type BoostService struct { slotUIDLock sync.Mutex // BOLT: constraint cache - constraints *ConstraintCache + constraints *ConstraintsCache } // NewBoostService created a new BoostService @@ -166,7 +166,7 @@ func NewBoostService(opts BoostServiceOpts) (*BoostService, error) { requestMaxRetries: opts.RequestMaxRetries, // BOLT: Initialize the constraint cache - constraints: NewConstraintCache(64), + constraints: NewConstraintsCache(64), }, nil } @@ -196,10 +196,8 @@ func (m *BoostService) getRouter() http.Handler { r.HandleFunc(pathStatus, m.handleStatus).Methods(http.MethodGet) r.HandleFunc(pathRegisterValidator, m.handleRegisterValidator).Methods(http.MethodPost) r.HandleFunc(pathSubmitConstraint, m.handleSubmitConstraint).Methods(http.MethodPost) - // TODO: manage the switch between the endpoint with and without proofs - // with the bolt sidecar proxy instead of using the same response here. - // TODO: revert this to m.handleGetHeader - r.HandleFunc(pathGetHeader, m.handleGetHeaderWithProofs).Methods(http.MethodGet) + + r.HandleFunc(pathGetHeader, m.handleGetHeader).Methods(http.MethodGet) r.HandleFunc(pathGetHeaderWithProofs, m.handleGetHeaderWithProofs).Methods(http.MethodGet) r.HandleFunc(pathGetPayload, m.handleGetPayload).Methods(http.MethodPost) @@ -364,42 +362,39 @@ func (m *BoostService) verifyInclusionProof(transactionsRoot phase0.Root, proof return errHashesIndexesMismatch } - log.Infof("[BOLT]: Verifying merkle multiproofs for %d transactions", len(proof.TransactionHashes)) + log.Infof("[BOLT]: Verifying merkel multiproofs for %d transactions", len(proof.TransactionHashes)) // Decode the constraints, and sort them according to the utility function used // TODO: this should be done before verification ideally - hashToConstraint := make(HashToConstraintDecoded) - for hash, constraint := range inclusionConstraints { + hashToTransaction := make(HashToTransactionDecoded) + for hash, tx := range inclusionConstraints { transaction := new(gethTypes.Transaction) - err := transaction.UnmarshalBinary(constraint.Tx) + err := transaction.UnmarshalBinary(*tx) if err != nil { log.WithError(err).Error("error unmarshalling transaction while verifying proofs") return err } - hashToConstraint[hash] = &ConstraintDecoded{ - Tx: transaction.WithoutBlobTxSidecar(), - Index: constraint.Index, - } + hashToTransaction[hash] = transaction.WithoutBlobTxSidecar() } leaves := make([][]byte, len(inclusionConstraints)) indexes := make([]int, len(proof.GeneralizedIndexes)) for i, hash := range proof.TransactionHashes { - constraint, ok := hashToConstraint[gethCommon.Hash(hash)] - if constraint == nil || !ok { + tx, ok := hashToTransaction[gethCommon.Hash(hash)] + if tx == nil || !ok { return errNilConstraint } // Compute the hash tree root for the raw preconfirmed transaction // and use it as "Leaf" in the proof to be verified against - encoded, err := constraint.Tx.MarshalBinary() + encoded, err := tx.MarshalBinary() if err != nil { log.WithError(err).Error("error marshalling transaction without blob tx sidecar") return err } - tx := Transaction(encoded) - txHashTreeRoot, err := tx.HashTreeRoot() + txBytes := Transaction(encoded) + txHashTreeRoot, err := txBytes.HashTreeRoot() if err != nil { return errInvalidRoot } @@ -464,19 +459,19 @@ func (m *BoostService) handleSubmitConstraint(w http.ResponseWriter, req *http.R // Add all constraints to the cache for _, signedConstraints := range payload { - constraintMessage := signedConstraints.Message + constraintsMessage := signedConstraints.Message - log.Infof("[BOLT]: adding inclusion constraints to cache. slot = %d, validatorIndex = %d, number of relays = %d", constraintMessage.Slot, constraintMessage.ValidatorIndex, len(m.relays)) + log.Infof("[BOLT]: adding inclusion constraints to cache. slot = %d, validatorPubkey = %d, number of relays = %d", constraintsMessage.Slot, constraintsMessage.Pubkey, len(m.relays)) // Add the constraints to the cache. // They will be cleared when we receive a payload for the slot in `handleGetPayload` - err := m.constraints.AddInclusionConstraints(constraintMessage.Slot, constraintMessage.Constraints) + err := m.constraints.AddInclusionConstraints(constraintsMessage.Slot, constraintsMessage.Transactions) if err != nil { log.WithError(err).Errorf("error adding inclusion constraints to cache") continue } - log.Infof("[BOLT]: added inclusion constraints to cache. slot = %d, validatorIndex = %d, number of relays = %d", constraintMessage.Slot, constraintMessage.ValidatorIndex, len(m.relays)) + log.Infof("[BOLT]: added inclusion constraints to cache. slot = %d, validatorPubkey = %d, number of relays = %d", constraintsMessage.Slot, constraintsMessage.Pubkey, len(m.relays)) } relayRespCh := make(chan error, len(m.relays)) @@ -877,7 +872,7 @@ func (m *BoostService) handleGetHeaderWithProofs(w http.ResponseWriter, req *htt return } - // BOLT: verify preconfirmation inclusion proofs. If they don't match, we don't consider the bid to be valid. + // BOLT: verify inclusion proofs. If they don't match, we don't consider the bid to be valid. if responsePayload.Proofs != nil { // BOLT: verify the proofs against the constraints. If they don't match, we don't consider the bid to be valid. transactionsRoot, err := responsePayload.Bid.TransactionsRoot() diff --git a/mev-boost/server/service_test.go b/mev-boost/server/service_test.go index 4446f23e8..0199bcb58 100644 --- a/mev-boost/server/service_test.go +++ b/mev-boost/server/service_test.go @@ -312,27 +312,27 @@ func TestRegisterValidator(t *testing.T) { } func TestParseConstraints(t *testing.T) { - jsonStr := `[{ + jsonStr := `[ + { "message": { - "validator_index": 12345, - "slot": 8978583, - "constraints": [{ - "tx": "0x02f871018304a5758085025ff11caf82565f94388c818ca8b9251b393131c08a736a67ccb1929787a41bb7ee22b41380c001a0c8630f734aba7acb4275a8f3b0ce831cf0c7c487fd49ee7bcca26ac622a28939a04c3745096fa0130a188fa249289fd9e60f9d6360854820dba22ae779ea6f573f", - "index": null - }] + "pubkey": "0xa695ad325dfc7e1191fbc9f186f58eff42a634029731b18380ff89bf42c464a42cb8ca55b200f051f57f1e1893c68759", + "slot": 32, + "top": true, + "transactions": [ + "0x02f86c870c72dd9d5e883e4d0183408f2382520894d2e2adf7177b7a8afddbc12d1634cf23ea1a71020180c001a08556dcfea479b34675db3fe08e29486fe719c2b22f6b0c1741ecbbdce4575cc6a01cd48009ccafd6b9f1290bbe2ceea268f94101d1d322c787018423ebcbc87ab4" + ] }, - "signature": "0x81510b571e22f89d1697545aac01c9ad0c1e7a3e778b3078bef524efae14990e58a6e960a152abd49de2e18d7fd3081c15d5c25867ccfad3d47beef6b39ac24b6b9fbf2cfa91c88f67aff750438a6841ec9e4a06a94ae41410c4f97b75ab284c" - }]` + "signature": "0xb8d50ee0d4b269db3d4658c1dac784d273a4160d769e16dce723a9684c390afe5865348416b3bf0f1a4f47098bec9024135d0d95f08bed18eb577a3d8a67f5dc78b13cc62515e280786a73fb267d35dfb7ab46a25ac29bf5bc2fa5b07b3e07a6" + } + ]` constraints := BatchedSignedConstraints{} err := json.Unmarshal([]byte(jsonStr), &constraints) require.NoError(t, err) require.Len(t, constraints, 1) - require.Equal(t, uint64(12345), constraints[0].Message.ValidatorIndex) - require.Equal(t, uint64(8978583), constraints[0].Message.Slot) - require.Len(t, constraints[0].Message.Constraints, 1) - require.Equal(t, constraints[0].Message.Constraints[0].Tx, Transaction(_HexToBytes("0x02f871018304a5758085025ff11caf82565f94388c818ca8b9251b393131c08a736a67ccb1929787a41bb7ee22b41380c001a0c8630f734aba7acb4275a8f3b0ce831cf0c7c487fd49ee7bcca26ac622a28939a04c3745096fa0130a188fa249289fd9e60f9d6360854820dba22ae779ea6f573f"))) - require.Nil(t, constraints[0].Message.Constraints[0].Index) + require.Equal(t, phase0.BLSPubKey(_HexToBytes("0xa695ad325dfc7e1191fbc9f186f58eff42a634029731b18380ff89bf42c464a42cb8ca55b200f051f57f1e1893c68759")), constraints[0].Message.Pubkey) + require.Equal(t, uint64(32), constraints[0].Message.Slot) + require.Equal(t, constraints[0].Message.Transactions[0], Transaction(_HexToBytes("0x02f86c870c72dd9d5e883e4d0183408f2382520894d2e2adf7177b7a8afddbc12d1634cf23ea1a71020180c001a08556dcfea479b34675db3fe08e29486fe719c2b22f6b0c1741ecbbdce4575cc6a01cd48009ccafd6b9f1290bbe2ceea268f94101d1d322c787018423ebcbc87ab4"))) } func TestConstraintsAndProofs(t *testing.T) { @@ -344,9 +344,9 @@ func TestConstraintsAndProofs(t *testing.T) { payload := BatchedSignedConstraints{&SignedConstraints{ Message: ConstraintsMessage{ - ValidatorIndex: 12345, - Slot: slot, - Constraints: []*Constraint{{Transaction(rawTx), nil}}, + Pubkey: phase0.BLSPubKey(_HexToBytes("0xa695ad325dfc7e1191fbc9f186f58eff42a634029731b18380ff89bf42c464a42cb8ca55b200f051f57f1e1893c68759")), + Slot: slot, + Transactions: []Transaction{rawTx}, }, Signature: phase0.BLSSignature(_HexToBytes( "0x81510b571e22f89d1697545aac01c9ad0c1e7a3e778b3078bef524efae14990e58a6e960a152abd49de2e18d7fd3081c15d5c25867ccfad3d47beef6b39ac24b6b9fbf2cfa91c88f67aff750438a6841ec9e4a06a94ae41410c4f97b75ab284c")), @@ -364,10 +364,9 @@ func TestConstraintsAndProofs(t *testing.T) { require.Equal(t, http.StatusOK, rr.Code) require.Equal(t, 1, backend.relays[0].GetRequestCount(path)) - got, ok := backend.boost.constraints.FindTransactionByHash(common.HexToHash(txHash.String())) + tx, ok := backend.boost.constraints.FindTransactionByHash(common.HexToHash(txHash.String())) require.True(t, ok) - require.Equal(t, Transaction(rawTx), got.Tx) - require.Nil(t, got.Index) + require.Equal(t, Transaction(rawTx), *tx) }) t.Run("Normal function with constraints", func(t *testing.T) { From 7c77455ab42b9248dec677f898ebd5f5d22e3034 Mon Sep 17 00:00:00 2001 From: Naman Garg <0708ng@gmail.com> Date: Mon, 7 Oct 2024 17:54:55 +0530 Subject: [PATCH 06/64] feat(mev-boost): add delegate, revoke --- mev-boost/server/backend.go | 6 +- mev-boost/server/constraints.go | 20 +++++++ mev-boost/server/service.go | 101 ++++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 1 deletion(-) diff --git a/mev-boost/server/backend.go b/mev-boost/server/backend.go index 631a587a4..d3b5cf0e5 100644 --- a/mev-boost/server/backend.go +++ b/mev-boost/server/backend.go @@ -4,11 +4,15 @@ const ( // Router paths pathStatus = "/eth/v1/builder/status" pathRegisterValidator = "/eth/v1/builder/validators" - pathSubmitConstraint = "/eth/v1/builder/constraints" pathGetHeader = "/eth/v1/builder/header/{slot:[0-9]+}/{parent_hash:0x[a-fA-F0-9]+}/{pubkey:0x[a-fA-F0-9]+}" pathGetHeaderWithProofs = "/eth/v1/builder/header_with_proofs/{slot:[0-9]+}/{parent_hash:0x[a-fA-F0-9]+}/{pubkey:0x[a-fA-F0-9]+}" pathGetPayload = "/eth/v1/builder/blinded_blocks" + // Constraints namespace paths + pathSubmitConstraint = "/constraints/v1/builder/constraints" + pathDelegate = "/constraints/v1/builder/delegate" + pathRevoke = "/constraints/v1/builder/revoke" + // // Relay Monitor paths // pathAuctionTranscript = "/monitor/v1/transcript" ) diff --git a/mev-boost/server/constraints.go b/mev-boost/server/constraints.go index 0697a2938..28dc736bf 100644 --- a/mev-boost/server/constraints.go +++ b/mev-boost/server/constraints.go @@ -104,3 +104,23 @@ func (c *ConstraintsCache) FindTransactionByHash(txHash gethCommon.Hash) (*Trans } return nil, false } + +type SignedDelegation struct { + Message Delegation `json:"message"` + Signature phase0.BLSSignature `json:"signature"` +} + +type Delegation struct { + ValidatorPubkey phase0.BLSPubKey `json:"validator_pubkey"` + DelegateePubkey phase0.BLSPubKey `json:"delegatee_pubkey"` +} + +type SignedRevocation struct { + Message Delegation `json:"message"` + Signature phase0.BLSSignature `json:"signature"` +} + +type Revocation struct { + ValidatorPubkey phase0.BLSPubKey `json:"validator_pubkey"` + DelegateePubkey phase0.BLSPubKey `json:"delegatee_pubkey"` +} diff --git a/mev-boost/server/service.go b/mev-boost/server/service.go index 84c19ace2..c978dfc29 100644 --- a/mev-boost/server/service.go +++ b/mev-boost/server/service.go @@ -112,6 +112,8 @@ type BoostService struct { httpClientGetPayload http.Client httpClientRegVal http.Client httpClientSubmitConstraint http.Client + httpClientDelegate http.Client + httpClientRevoke http.Client requestMaxRetries int bids map[bidRespKey]bidResp // keeping track of bids, to log the originating relay on withholding @@ -163,6 +165,16 @@ func NewBoostService(opts BoostServiceOpts) (*BoostService, error) { Timeout: opts.RequestTimeoutSubmitConstraint, CheckRedirect: httpClientDisallowRedirects, }, + httpClientDelegate: http.Client{ + // NOTE: using the same timeout as registerValidator + Timeout: opts.RequestTimeoutRegVal, + CheckRedirect: httpClientDisallowRedirects, + }, + httpClientRevoke: http.Client{ + // NOTE: using the same timeout as registerValidator + Timeout: opts.RequestTimeoutRegVal, + CheckRedirect: httpClientDisallowRedirects, + }, requestMaxRetries: opts.RequestMaxRetries, // BOLT: Initialize the constraint cache @@ -201,6 +213,9 @@ func (m *BoostService) getRouter() http.Handler { r.HandleFunc(pathGetHeaderWithProofs, m.handleGetHeaderWithProofs).Methods(http.MethodGet) r.HandleFunc(pathGetPayload, m.handleGetPayload).Methods(http.MethodPost) + r.HandleFunc(pathDelegate, m.handleDelegate).Methods(http.MethodPost) + r.HandleFunc(pathRevoke, m.handleRevoke).Methods(http.MethodPost) + r.Use(mux.CORSMethodMiddleware(r)) loggedRouter := httplogger.LoggingMiddlewareLogrus(m.log, r) return loggedRouter @@ -339,6 +354,92 @@ func (m *BoostService) handleRegisterValidator(w http.ResponseWriter, req *http. m.respondError(w, http.StatusBadGateway, errNoSuccessfulRelayResponse.Error()) } +func (m *BoostService) handleDelegate(w http.ResponseWriter, req *http.Request) { + log := m.log.WithField("method", "delegate") + log.Debug("delegate") + + payload := SignedDelegation{} + if err := DecodeJSON(req.Body, &payload); err != nil { + m.respondError(w, http.StatusBadRequest, err.Error()) + return + } + + ua := UserAgent(req.Header.Get("User-Agent")) + log = log.WithFields(logrus.Fields{ + "delegateePubkey": payload.Message.DelegateePubkey.String(), + "ua": ua, + }) + + relayRespCh := make(chan error, len(m.relays)) + + for _, relay := range m.relays { + go func(relay RelayEntry) { + url := relay.GetURI(pathDelegate) + log := log.WithField("url", url) + + _, err := SendHTTPRequest(context.Background(), m.httpClientDelegate, http.MethodPost, url, ua, nil, payload, nil) + relayRespCh <- err + if err != nil { + log.WithError(err).Warn("error calling delegate on relay") + return + } + }(relay) + } + + for i := 0; i < len(m.relays); i++ { + respErr := <-relayRespCh + if respErr == nil { + m.respondOK(w, nilResponse) + return + } + } + + m.respondError(w, http.StatusBadGateway, errNoSuccessfulRelayResponse.Error()) +} + +func (m *BoostService) handleRevoke(w http.ResponseWriter, req *http.Request) { + log := m.log.WithField("method", "revoke") + log.Debug("revoke") + + payload := SignedRevocation{} + if err := DecodeJSON(req.Body, &payload); err != nil { + m.respondError(w, http.StatusBadRequest, err.Error()) + return + } + + ua := UserAgent(req.Header.Get("User-Agent")) + log = log.WithFields(logrus.Fields{ + "delegateePubkey": payload.Message.DelegateePubkey.String(), + "ua": ua, + }) + + relayRespCh := make(chan error, len(m.relays)) + + for _, relay := range m.relays { + go func(relay RelayEntry) { + url := relay.GetURI(pathRevoke) + log := log.WithField("url", url) + + _, err := SendHTTPRequest(context.Background(), m.httpClientRevoke, http.MethodPost, url, ua, nil, payload, nil) + relayRespCh <- err + if err != nil { + log.WithError(err).Warn("error calling revoke on relay") + return + } + }(relay) + } + + for i := 0; i < len(m.relays); i++ { + respErr := <-relayRespCh + if respErr == nil { + m.respondOK(w, nilResponse) + return + } + } + + m.respondError(w, http.StatusBadGateway, errNoSuccessfulRelayResponse.Error()) +} + // verifyInclusionProof verifies the proofs against the constraints, and returns an error if the proofs are invalid. func (m *BoostService) verifyInclusionProof(transactionsRoot phase0.Root, proof *InclusionProof, slot uint64) error { log := m.log.WithFields(logrus.Fields{}) From d678b3fd28569878f8561ad6c93b3ac1600925cc Mon Sep 17 00:00:00 2001 From: Naman Garg <0708ng@gmail.com> Date: Mon, 7 Oct 2024 19:01:09 +0530 Subject: [PATCH 07/64] feat(mev-boost): versioned signed builder bid --- mev-boost/server/proofs.go | 64 +++++++++++++++++++++++++++++++------ mev-boost/server/service.go | 14 ++++---- 2 files changed, 61 insertions(+), 17 deletions(-) diff --git a/mev-boost/server/proofs.go b/mev-boost/server/proofs.go index 72ccd626e..d6e9fc2db 100644 --- a/mev-boost/server/proofs.go +++ b/mev-boost/server/proofs.go @@ -10,23 +10,67 @@ import ( fastSsz "github.com/ferranbt/fastssz" + builderApiBellatrix "github.com/attestantio/go-builder-client/api/bellatrix" + builderApiCapella "github.com/attestantio/go-builder-client/api/capella" + builderApiDeneb "github.com/attestantio/go-builder-client/api/deneb" builderSpec "github.com/attestantio/go-builder-client/spec" + consensusSpec "github.com/attestantio/go-eth2-client/spec" + "github.com/attestantio/go-eth2-client/spec/phase0" ) -type BidWithInclusionProofs struct { - // The block bid - Bid *builderSpec.VersionedSignedBuilderBid `json:"bid"` - // The inclusion proofs - Proofs *InclusionProof `json:"proofs"` +// A wrapper struct over `builderSpec.VersionedSignedBuilderBid` +// to include constraint inclusion proofs +type VersionedSignedBuilderBidWithProofs struct { + Proofs *InclusionProof + *builderSpec.VersionedSignedBuilderBid } -func (b *BidWithInclusionProofs) String() string { - out, err := json.Marshal(b) - if err != nil { - return err.Error() +// this is necessary, because the mev-boost-relay deserialization doesn't expect a "Version" and "Data" wrapper object +// for deserialization. Instead, it tries to decode the object into the "Deneb" version first and if that fails, it tries +// the "Capella" version. This is a workaround to make the deserialization work. +// +// NOTE(bolt): struct embedding of the VersionedSubmitBlockRequest is not possible for some reason because it causes the json +// encoding to omit the `proofs` field. Embedding all of the fields directly does the job. +func (v *VersionedSignedBuilderBidWithProofs) MarshalJSON() ([]byte, error) { + switch v.Version { + case consensusSpec.DataVersionBellatrix: + return json.Marshal(struct { + Message *builderApiBellatrix.BuilderBid `json:"message"` + Signature phase0.BLSSignature `json:"signature"` + Proofs *InclusionProof `json:"proofs"` + }{ + Message: v.Bellatrix.Message, + Signature: v.Bellatrix.Signature, + Proofs: v.Proofs, + }) + case consensusSpec.DataVersionCapella: + return json.Marshal(struct { + Message *builderApiCapella.BuilderBid `json:"message"` + Signature phase0.BLSSignature `json:"signature"` + Proofs *InclusionProof `json:"proofs"` + }{ + Message: v.Capella.Message, + Signature: v.Capella.Signature, + Proofs: v.Proofs, + }) + case consensusSpec.DataVersionDeneb: + return json.Marshal(struct { + Message *builderApiDeneb.BuilderBid `json:"message"` + Signature phase0.BLSSignature `json:"signature"` + Proofs *InclusionProof `json:"proofs"` + }{ + Message: v.Deneb.Message, + Signature: v.Deneb.Signature, + Proofs: v.Proofs, + }) } - return string(out) + + return nil, fmt.Errorf("unknown data version %d", v.Version) +} + +func (v *VersionedSignedBuilderBidWithProofs) String() string { + return JSONStringify(v) } func (p *InclusionProof) String() string { diff --git a/mev-boost/server/service.go b/mev-boost/server/service.go index c978dfc29..4b84ab6d5 100644 --- a/mev-boost/server/service.go +++ b/mev-boost/server/service.go @@ -885,7 +885,7 @@ func (m *BoostService) handleGetHeaderWithProofs(w http.ResponseWriter, req *htt path := fmt.Sprintf("/eth/v1/builder/header_with_proofs/%s/%s/%s", slot, parentHashHex, pubkey) url := relay.GetURI(path) log := log.WithField("url", url) - responsePayload := new(BidWithInclusionProofs) + responsePayload := new(VersionedSignedBuilderBidWithProofs) code, err := SendHTTPRequest(context.Background(), m.httpClientGetHeader, http.MethodGet, url, ua, headers, nil, responsePayload) if err != nil { log.WithError(err).Warn("error making request to relay") @@ -901,19 +901,19 @@ func (m *BoostService) handleGetHeaderWithProofs(w http.ResponseWriter, req *htt return } - if responsePayload.Bid == nil { + if responsePayload == nil { log.Warn("Bid in response is nil") return } // Skip if payload is empty - if responsePayload.Bid.IsEmpty() { + if responsePayload.IsEmpty() { log.Warn("Bid is empty") return } // Getting the bid info will check if there are missing fields in the response - bidInfo, err := parseBidInfo(responsePayload.Bid) + bidInfo, err := parseBidInfo(responsePayload.VersionedSignedBuilderBid) if err != nil { log.WithError(err).Warn("error parsing bid info") return @@ -939,7 +939,7 @@ func (m *BoostService) handleGetHeaderWithProofs(w http.ResponseWriter, req *htt // Verify the relay signature in the relay response if !config.SkipRelaySignatureCheck { - ok, err := checkRelaySignature(responsePayload.Bid, m.builderSigningDomain, relay.PublicKey) + ok, err := checkRelaySignature(responsePayload.VersionedSignedBuilderBid, m.builderSigningDomain, relay.PublicKey) if err != nil { log.WithError(err).Error("error verifying relay signature") return @@ -976,7 +976,7 @@ func (m *BoostService) handleGetHeaderWithProofs(w http.ResponseWriter, req *htt // BOLT: verify inclusion proofs. If they don't match, we don't consider the bid to be valid. if responsePayload.Proofs != nil { // BOLT: verify the proofs against the constraints. If they don't match, we don't consider the bid to be valid. - transactionsRoot, err := responsePayload.Bid.TransactionsRoot() + transactionsRoot, err := responsePayload.TransactionsRoot() if err != nil { log.WithError(err).Error("[BOLT]: error getting transaction root") return @@ -1008,7 +1008,7 @@ func (m *BoostService) handleGetHeaderWithProofs(w http.ResponseWriter, req *htt // Use this relay's response as mev-boost response because it's most profitable log.Infof("new best bid. Has proofs: %v", responsePayload.Proofs != nil) - result.response = *responsePayload.Bid + result.response = *responsePayload.VersionedSignedBuilderBid result.bidInfo = bidInfo result.t = time.Now() }(relay) From 65783377fef3afb07348d3621cf8634c69bbdaa3 Mon Sep 17 00:00:00 2001 From: Naman Garg <0708ng@gmail.com> Date: Mon, 7 Oct 2024 19:34:42 +0530 Subject: [PATCH 08/64] fix(mev-boost): mock relay - rm bid with inclusion proof --- mev-boost/server/mock_relay.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mev-boost/server/mock_relay.go b/mev-boost/server/mock_relay.go index fc0695f60..cdde64fad 100644 --- a/mev-boost/server/mock_relay.go +++ b/mev-boost/server/mock_relay.go @@ -65,7 +65,7 @@ type mockRelay struct { // Default responses placeholders, used if overrider does not exist GetHeaderResponse *builderSpec.VersionedSignedBuilderBid - GetHeaderWithProofsResponse *BidWithInclusionProofs + GetHeaderWithProofsResponse *VersionedSignedBuilderBidWithProofs GetPayloadResponse *builderApi.VersionedSubmitBlindedBlockResponse // Server section @@ -197,7 +197,7 @@ func (m *mockRelay) MakeGetHeaderWithConstraintsResponse(value uint64, blockHash tx Transaction hash phase0.Hash32 }, -) *BidWithInclusionProofs { +) *VersionedSignedBuilderBidWithProofs { transactions := new(utilbellatrix.ExecutionPayloadTransactions) for _, con := range constraints { @@ -288,7 +288,7 @@ func (m *mockRelay) MakeGetHeaderResponse(value uint64, blockHash, parentHash, p // MakeGetHeaderWithProofsResponseWithTxsRoot is used to create the default or can be used to create a custom response to the getHeaderWithProofs // method -func (m *mockRelay) MakeGetHeaderWithProofsResponseWithTxsRoot(value uint64, blockHash, parentHash, publicKey string, version spec.DataVersion, txsRoot phase0.Root) *BidWithInclusionProofs { +func (m *mockRelay) MakeGetHeaderWithProofsResponseWithTxsRoot(value uint64, blockHash, parentHash, publicKey string, version spec.DataVersion, txsRoot phase0.Root) *VersionedSignedBuilderBidWithProofs { switch version { case spec.DataVersionCapella: // Fill the payload with custom values. @@ -307,8 +307,8 @@ func (m *mockRelay) MakeGetHeaderWithProofsResponseWithTxsRoot(value uint64, blo signature, err := ssz.SignMessage(message, ssz.DomainBuilder, m.secretKey) require.NoError(m.t, err) - return &BidWithInclusionProofs{ - Bid: &builderSpec.VersionedSignedBuilderBid{ + return &VersionedSignedBuilderBidWithProofs{ + VersionedSignedBuilderBid: &builderSpec.VersionedSignedBuilderBid{ Version: spec.DataVersionCapella, Capella: &builderApiCapella.SignedBuilderBid{ Message: message, @@ -335,8 +335,8 @@ func (m *mockRelay) MakeGetHeaderWithProofsResponseWithTxsRoot(value uint64, blo signature, err := ssz.SignMessage(message, ssz.DomainBuilder, m.secretKey) require.NoError(m.t, err) - return &BidWithInclusionProofs{ - Bid: &builderSpec.VersionedSignedBuilderBid{ + return &VersionedSignedBuilderBidWithProofs{ + VersionedSignedBuilderBid: &builderSpec.VersionedSignedBuilderBid{ Version: spec.DataVersionDeneb, Deneb: &builderApiDeneb.SignedBuilderBid{ Message: message, From 8074c7da21c7a534a02ed4d0bcda4464ece8dd44 Mon Sep 17 00:00:00 2001 From: Naman Garg <0708ng@gmail.com> Date: Tue, 8 Oct 2024 10:41:09 +0530 Subject: [PATCH 09/64] misc(mev-boost): address review --- mev-boost/server/backend.go | 7 +++++-- mev-boost/server/constraints.go | 6 +++++- mev-boost/server/service.go | 8 +++++--- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/mev-boost/server/backend.go b/mev-boost/server/backend.go index d3b5cf0e5..8e4979dee 100644 --- a/mev-boost/server/backend.go +++ b/mev-boost/server/backend.go @@ -9,9 +9,12 @@ const ( pathGetPayload = "/eth/v1/builder/blinded_blocks" // Constraints namespace paths + // Ref: https://docs.boltprotocol.xyz/api/builder#constraints pathSubmitConstraint = "/constraints/v1/builder/constraints" - pathDelegate = "/constraints/v1/builder/delegate" - pathRevoke = "/constraints/v1/builder/revoke" + // Ref: https://docs.boltprotocol.xyz/api/builder#delegate + pathDelegate = "/constraints/v1/builder/delegate" + // Ref: https://docs.boltprotocol.xyz/api/builder#revoke + pathRevoke = "/constraints/v1/builder/revoke" // // Relay Monitor paths // pathAuctionTranscript = "/monitor/v1/transcript" diff --git a/mev-boost/server/constraints.go b/mev-boost/server/constraints.go index 28dc736bf..df1e396a9 100644 --- a/mev-boost/server/constraints.go +++ b/mev-boost/server/constraints.go @@ -25,7 +25,7 @@ type ConstraintsMessage struct { Pubkey phase0.BLSPubKey `json:"pubkey"` Slot uint64 `json:"slot"` Top bool `json:"top"` - Transactions []Transaction // Custom marshal and unmarshal implemented below + Transactions []Transaction `json:"transactions"` } func (s *SignedConstraints) String() string { @@ -105,21 +105,25 @@ func (c *ConstraintsCache) FindTransactionByHash(txHash gethCommon.Hash) (*Trans return nil, false } +// Ref: https://docs.boltprotocol.xyz/api/builder#delegate type SignedDelegation struct { Message Delegation `json:"message"` Signature phase0.BLSSignature `json:"signature"` } +// Ref: https://docs.boltprotocol.xyz/api/builder#delegate type Delegation struct { ValidatorPubkey phase0.BLSPubKey `json:"validator_pubkey"` DelegateePubkey phase0.BLSPubKey `json:"delegatee_pubkey"` } +// Ref: https://docs.boltprotocol.xyz/api/builder#revoke type SignedRevocation struct { Message Delegation `json:"message"` Signature phase0.BLSSignature `json:"signature"` } +// Ref: https://docs.boltprotocol.xyz/api/builder#revoke type Revocation struct { ValidatorPubkey phase0.BLSPubKey `json:"validator_pubkey"` DelegateePubkey phase0.BLSPubKey `json:"delegatee_pubkey"` diff --git a/mev-boost/server/service.go b/mev-boost/server/service.go index 4b84ab6d5..5e8eefdff 100644 --- a/mev-boost/server/service.go +++ b/mev-boost/server/service.go @@ -356,7 +356,7 @@ func (m *BoostService) handleRegisterValidator(w http.ResponseWriter, req *http. func (m *BoostService) handleDelegate(w http.ResponseWriter, req *http.Request) { log := m.log.WithField("method", "delegate") - log.Debug("delegate") + log.Debug("delegate:", req.Body) payload := SignedDelegation{} if err := DecodeJSON(req.Body, &payload); err != nil { @@ -366,6 +366,7 @@ func (m *BoostService) handleDelegate(w http.ResponseWriter, req *http.Request) ua := UserAgent(req.Header.Get("User-Agent")) log = log.WithFields(logrus.Fields{ + "validatorPubkey": payload.Message.ValidatorPubkey.String(), "delegateePubkey": payload.Message.DelegateePubkey.String(), "ua": ua, }) @@ -399,7 +400,7 @@ func (m *BoostService) handleDelegate(w http.ResponseWriter, req *http.Request) func (m *BoostService) handleRevoke(w http.ResponseWriter, req *http.Request) { log := m.log.WithField("method", "revoke") - log.Debug("revoke") + log.Debug("revoke:", req.Body) payload := SignedRevocation{} if err := DecodeJSON(req.Body, &payload); err != nil { @@ -409,6 +410,7 @@ func (m *BoostService) handleRevoke(w http.ResponseWriter, req *http.Request) { ua := UserAgent(req.Header.Get("User-Agent")) log = log.WithFields(logrus.Fields{ + "validatorPubkey": payload.Message.ValidatorPubkey.String(), "delegateePubkey": payload.Message.DelegateePubkey.String(), "ua": ua, }) @@ -901,7 +903,7 @@ func (m *BoostService) handleGetHeaderWithProofs(w http.ResponseWriter, req *htt return } - if responsePayload == nil { + if responsePayload.VersionedSignedBuilderBid == nil { log.Warn("Bid in response is nil") return } From 53579f68cd73b500c4f364292a7bed0b1e2ac196 Mon Sep 17 00:00:00 2001 From: Naman Garg <0708ng@gmail.com> Date: Tue, 8 Oct 2024 11:48:48 +0530 Subject: [PATCH 10/64] chore(mev-boost): rm bolt demo events --- mev-boost/server/service.go | 14 -------------- mev-boost/server/utils.go | 13 ------------- 2 files changed, 27 deletions(-) diff --git a/mev-boost/server/service.go b/mev-boost/server/service.go index 5e8eefdff..a8573afb4 100644 --- a/mev-boost/server/service.go +++ b/mev-boost/server/service.go @@ -522,19 +522,9 @@ func (m *BoostService) verifyInclusionProof(transactionsRoot phase0.Root, proof if !ok { log.Error("[BOLT]: proof verification failed") - - // BOLT: send event to web demo - message := fmt.Sprintf("failed to verify merkle proof for slot %d", slot) - EmitBoltDemoEvent(message) - return errInvalidProofs } else { log.Info(fmt.Sprintf("[BOLT]: merkle proof verified in %s", elapsed)) - - // BOLT: send event to web demo - // verified merkle proof for tx: %s in %v", proof.TxHash.String(), elapsed) - message := fmt.Sprintf("verified merkle proof for slot %d in %v", slot, elapsed) - EmitBoltDemoEvent(message) } return nil @@ -549,8 +539,6 @@ func (m *BoostService) handleSubmitConstraint(w http.ResponseWriter, req *http.R "ua": ua, }) - path := req.URL.Path - log.Info("submitConstraint") payload := BatchedSignedConstraints{} @@ -579,8 +567,6 @@ func (m *BoostService) handleSubmitConstraint(w http.ResponseWriter, req *http.R relayRespCh := make(chan error, len(m.relays)) - EmitBoltDemoEvent(fmt.Sprintf("received %d constraints, forwarding to Bolt relays... (path: %s)", len(payload), path)) - for _, relay := range m.relays { go func(relay RelayEntry) { url := relay.GetURI(pathSubmitConstraint) diff --git a/mev-boost/server/utils.go b/mev-boost/server/utils.go index a7ec11cef..9e51b0e47 100644 --- a/mev-boost/server/utils.go +++ b/mev-boost/server/utils.go @@ -273,19 +273,6 @@ func getPayloadResponseIsEmpty(payload *builderApi.VersionedSubmitBlindedBlockRe return false } -// EmitBoltDemoEvent sends a message to the web demo backend to log an event. -// This is only used for demo purposes and should be removed in production. -func EmitBoltDemoEvent(message string) { - event := strings.NewReader(fmt.Sprintf("{ \"message\": \"BOLT-MEV-BOOST: %s\"}", message)) - eventRes, err := http.Post("http://host.docker.internal:3001/events", "application/json", event) - if err != nil { - fmt.Printf("Failed to send web demo event: %v", err) - } - if eventRes != nil { - defer eventRes.Body.Close() - } -} - func Map[T any, U any](slice []*T, mapper func(el *T) *U) []*U { result := make([]*U, len(slice)) for i, el := range slice { From 4a675c9e587a32bf6a9aab75757406fea293ff58 Mon Sep 17 00:00:00 2001 From: Naman Garg <0708ng@gmail.com> Date: Tue, 8 Oct 2024 12:19:23 +0530 Subject: [PATCH 11/64] fix(mev-boost): pubkey log display --- mev-boost/server/service.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mev-boost/server/service.go b/mev-boost/server/service.go index a8573afb4..4f038f94e 100644 --- a/mev-boost/server/service.go +++ b/mev-boost/server/service.go @@ -552,7 +552,7 @@ func (m *BoostService) handleSubmitConstraint(w http.ResponseWriter, req *http.R for _, signedConstraints := range payload { constraintsMessage := signedConstraints.Message - log.Infof("[BOLT]: adding inclusion constraints to cache. slot = %d, validatorPubkey = %d, number of relays = %d", constraintsMessage.Slot, constraintsMessage.Pubkey, len(m.relays)) + log.Infof("[BOLT]: adding inclusion constraints to cache. slot = %d, validatorPubkey = %s, number of relays = %d", constraintsMessage.Slot, constraintsMessage.Pubkey.String(), len(m.relays)) // Add the constraints to the cache. // They will be cleared when we receive a payload for the slot in `handleGetPayload` @@ -562,7 +562,7 @@ func (m *BoostService) handleSubmitConstraint(w http.ResponseWriter, req *http.R continue } - log.Infof("[BOLT]: added inclusion constraints to cache. slot = %d, validatorPubkey = %d, number of relays = %d", constraintsMessage.Slot, constraintsMessage.Pubkey, len(m.relays)) + log.Infof("[BOLT]: added inclusion constraints to cache. slot = %d, validatorPubkey = %s, number of relays = %d", constraintsMessage.Slot, constraintsMessage.Pubkey.String(), len(m.relays)) } relayRespCh := make(chan error, len(m.relays)) From ea2f6b154aab4486ed9787a7fef7b377ab3c9ef3 Mon Sep 17 00:00:00 2001 From: Naman Garg <0708ng@gmail.com> Date: Tue, 8 Oct 2024 15:24:11 +0530 Subject: [PATCH 12/64] test(mev-boost): add logs, nits --- mev-boost/server/proofs.go | 2 +- mev-boost/server/service.go | 2 +- mev-boost/server/service_test.go | 13 +++++++------ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/mev-boost/server/proofs.go b/mev-boost/server/proofs.go index d6e9fc2db..dd6315932 100644 --- a/mev-boost/server/proofs.go +++ b/mev-boost/server/proofs.go @@ -30,7 +30,7 @@ type VersionedSignedBuilderBidWithProofs struct { // for deserialization. Instead, it tries to decode the object into the "Deneb" version first and if that fails, it tries // the "Capella" version. This is a workaround to make the deserialization work. // -// NOTE(bolt): struct embedding of the VersionedSubmitBlockRequest is not possible for some reason because it causes the json +// NOTE(bolt): struct embedding of the VersionedSignedBuilderBid is not possible for some reason because it causes the json // encoding to omit the `proofs` field. Embedding all of the fields directly does the job. func (v *VersionedSignedBuilderBidWithProofs) MarshalJSON() ([]byte, error) { switch v.Version { diff --git a/mev-boost/server/service.go b/mev-boost/server/service.go index 4f038f94e..971697304 100644 --- a/mev-boost/server/service.go +++ b/mev-boost/server/service.go @@ -852,7 +852,7 @@ func (m *BoostService) handleGetHeaderWithProofs(w http.ResponseWriter, req *htt "genesisTime": m.genesisTime, "slotTimeSec": config.SlotTimeSec, "msIntoSlot": msIntoSlot, - }).Infof("getHeader request start - %d milliseconds into slot %d", msIntoSlot, slotUint) + }).Infof("getHeaderWithProof request start - %d milliseconds into slot %d", msIntoSlot, slotUint) // Add request headers headers := map[string]string{ diff --git a/mev-boost/server/service_test.go b/mev-boost/server/service_test.go index 0199bcb58..9a1865b0d 100644 --- a/mev-boost/server/service_test.go +++ b/mev-boost/server/service_test.go @@ -344,8 +344,9 @@ func TestConstraintsAndProofs(t *testing.T) { payload := BatchedSignedConstraints{&SignedConstraints{ Message: ConstraintsMessage{ - Pubkey: phase0.BLSPubKey(_HexToBytes("0xa695ad325dfc7e1191fbc9f186f58eff42a634029731b18380ff89bf42c464a42cb8ca55b200f051f57f1e1893c68759")), + Pubkey: phase0.BLSPubKey(_HexToBytes("0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249")), Slot: slot, + Top: false, Transactions: []Transaction{rawTx}, }, Signature: phase0.BLSSignature(_HexToBytes( @@ -356,7 +357,7 @@ func TestConstraintsAndProofs(t *testing.T) { hash := _HexToHash("0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7") pubkey := _HexToPubkey( "0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249") - getHeaderPath := getHeaderWithProofsPath(slot, hash, pubkey) + getHeaderWithProofsPath := getHeaderWithProofsPath(slot, hash, pubkey) t.Run("Normal function", func(t *testing.T) { backend := newTestBackend(t, 1, time.Second) @@ -388,9 +389,9 @@ func TestConstraintsAndProofs(t *testing.T) { ) backend.relays[0].GetHeaderWithProofsResponse = resp - rr := backend.request(t, http.MethodGet, getHeaderPath, nil) + rr := backend.request(t, http.MethodGet, getHeaderWithProofsPath, nil) require.Equal(t, http.StatusOK, rr.Code, rr.Body.String()) - require.Equal(t, 1, backend.relays[0].GetRequestCount(getHeaderPath)) + require.Equal(t, 1, backend.relays[0].GetRequestCount(getHeaderWithProofsPath)) }) t.Run("No proofs given", func(t *testing.T) { @@ -408,11 +409,11 @@ func TestConstraintsAndProofs(t *testing.T) { ) backend.relays[0].GetHeaderResponse = resp - rr := backend.request(t, http.MethodGet, getHeaderPath, nil) + rr := backend.request(t, http.MethodGet, getHeaderWithProofsPath, nil) // When we have constraints registered, but the relay does not return any proofs, we should return no content. // This will force a locally built block. require.Equal(t, http.StatusNoContent, rr.Code, rr.Body.String()) - require.Equal(t, 1, backend.relays[0].GetRequestCount(getHeaderPath)) + require.Equal(t, 1, backend.relays[0].GetRequestCount(getHeaderWithProofsPath)) }) } From ed3af9988e867abfe47a02d08e8059803eb6f032 Mon Sep 17 00:00:00 2001 From: Naman Garg <0708ng@gmail.com> Date: Tue, 8 Oct 2024 18:52:40 +0530 Subject: [PATCH 13/64] chore(mev-boost): unmarshal json builder bid with proof --- mev-boost/server/mock_relay.go | 2 +- mev-boost/server/proofs.go | 63 ++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/mev-boost/server/mock_relay.go b/mev-boost/server/mock_relay.go index cdde64fad..f286b1107 100644 --- a/mev-boost/server/mock_relay.go +++ b/mev-boost/server/mock_relay.go @@ -411,7 +411,7 @@ func (m *mockRelay) defaultHandleGetHeaderWithProofs(w http.ResponseWriter) { "0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", "0xe28385e7bd68df656cd0042b74b69c3104b5356ed1f20eb69f1f925df47a3ab7", "0x8a1d7b8dd64e0aafe7ea7b6c95065c9364cf99d38470c12ee807d55f7de1529ad29ce2c422e0b65e3d5a05c02caca249", - spec.DataVersionCapella, + spec.DataVersionDeneb, nil, ) diff --git a/mev-boost/server/proofs.go b/mev-boost/server/proofs.go index dd6315932..5ba5f40ba 100644 --- a/mev-boost/server/proofs.go +++ b/mev-boost/server/proofs.go @@ -69,6 +69,69 @@ func (v *VersionedSignedBuilderBidWithProofs) MarshalJSON() ([]byte, error) { return nil, fmt.Errorf("unknown data version %d", v.Version) } +func (v *VersionedSignedBuilderBidWithProofs) UnmarshalJSON(data []byte) error { + var err error + + // Try Deneb + var deneb struct { + Message *builderApiDeneb.BuilderBid `json:"message"` + Signature phase0.BLSSignature `json:"signature"` + Proofs *InclusionProof `json:"proofs"` + } + err = json.Unmarshal(data, &deneb) + if err == nil && deneb.Message != nil { + v.Proofs = deneb.Proofs + + v.VersionedSignedBuilderBid = &builderSpec.VersionedSignedBuilderBid{} + v.Deneb = &builderApiDeneb.SignedBuilderBid{ + Message: deneb.Message, + Signature: deneb.Signature, + } + v.Version = consensusSpec.DataVersionDeneb + return nil + } + + // Try Capella + var capella struct { + Message *builderApiCapella.BuilderBid `json:"message"` + Signature phase0.BLSSignature `json:"signature"` + Proofs *InclusionProof `json:"proofs"` + } + err = json.Unmarshal(data, &capella) + if err == nil && capella.Message != nil { + v.Proofs = capella.Proofs + + v.VersionedSignedBuilderBid = &builderSpec.VersionedSignedBuilderBid{} + v.Capella = &builderApiCapella.SignedBuilderBid{ + Message: capella.Message, + Signature: capella.Signature, + } + v.Version = consensusSpec.DataVersionCapella + return nil + } + + // Try Bellatrix + var bellatrix struct { + Message *builderApiBellatrix.BuilderBid `json:"message"` + Signature phase0.BLSSignature `json:"signature"` + Proofs *InclusionProof `json:"proofs"` + } + err = json.Unmarshal(data, &bellatrix) + if err == nil && bellatrix.Message != nil { + v.Proofs = bellatrix.Proofs + + v.VersionedSignedBuilderBid = &builderSpec.VersionedSignedBuilderBid{} + v.Bellatrix = &builderApiBellatrix.SignedBuilderBid{ + Message: bellatrix.Message, + Signature: bellatrix.Signature, + } + v.Version = consensusSpec.DataVersionBellatrix + return nil + } + + return fmt.Errorf("failed to unmarshal VersionedSignedBuilderBidWithProofs: %v", err) +} + func (v *VersionedSignedBuilderBidWithProofs) String() string { return JSONStringify(v) } From b09363b75344c1c8ba19f3c7a7ee3792f9be1351 Mon Sep 17 00:00:00 2001 From: Naman Garg <0708ng@gmail.com> Date: Tue, 8 Oct 2024 19:49:07 +0530 Subject: [PATCH 14/64] test(mev-boost): delegation revocation --- mev-boost/server/constraints.go | 2 +- mev-boost/server/mock_relay.go | 24 ++++++++++++++ mev-boost/server/service_test.go | 55 ++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) diff --git a/mev-boost/server/constraints.go b/mev-boost/server/constraints.go index df1e396a9..d6c2f6597 100644 --- a/mev-boost/server/constraints.go +++ b/mev-boost/server/constraints.go @@ -119,7 +119,7 @@ type Delegation struct { // Ref: https://docs.boltprotocol.xyz/api/builder#revoke type SignedRevocation struct { - Message Delegation `json:"message"` + Message Revocation `json:"message"` Signature phase0.BLSSignature `json:"signature"` } diff --git a/mev-boost/server/mock_relay.go b/mev-boost/server/mock_relay.go index f286b1107..07fee42aa 100644 --- a/mev-boost/server/mock_relay.go +++ b/mev-boost/server/mock_relay.go @@ -123,6 +123,8 @@ func (m *mockRelay) getRouter() http.Handler { r.HandleFunc(pathGetHeader, m.handleGetHeader).Methods(http.MethodGet) r.HandleFunc(pathGetHeaderWithProofs, m.handleGetHeaderWithProofs).Methods(http.MethodGet) r.HandleFunc(pathSubmitConstraint, m.handleSubmitConstraint).Methods(http.MethodPost) + r.HandleFunc(pathDelegate, m.handleDelegate).Methods(http.MethodPost) + r.HandleFunc(pathRevoke, m.handleRevoke).Methods(http.MethodPost) r.HandleFunc(pathGetPayload, m.handleGetPayload).Methods(http.MethodPost) return m.newTestMiddleware(r) @@ -172,6 +174,28 @@ func (m *mockRelay) defaultHandleRegisterValidator(w http.ResponseWriter, req *h w.WriteHeader(http.StatusOK) } +func (m *mockRelay) handleDelegate(w http.ResponseWriter, req *http.Request) { + payload := SignedDelegation{} + if err := DecodeJSON(req.Body, &payload); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) +} + +func (m *mockRelay) handleRevoke(w http.ResponseWriter, req *http.Request) { + payload := SignedRevocation{} + if err := DecodeJSON(req.Body, &payload); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) +} + func (m *mockRelay) handleSubmitConstraint(w http.ResponseWriter, req *http.Request) { m.mu.Lock() defer m.mu.Unlock() diff --git a/mev-boost/server/service_test.go b/mev-boost/server/service_test.go index 9a1865b0d..6efb23972 100644 --- a/mev-boost/server/service_test.go +++ b/mev-boost/server/service_test.go @@ -311,6 +311,61 @@ func TestRegisterValidator(t *testing.T) { }) } +func TestDelegate(t *testing.T) { + path := pathDelegate + delegate := SignedDelegation{ + Message: Delegation{ + ValidatorPubkey: _HexToPubkey("0xa695ad325dfc7e1191fbc9f186f58eff42a634029731b18380ff89bf42c464a42cb8ca55b200f051f57f1e1893c68759"), + DelegateePubkey: _HexToPubkey("0xb8ba260170b9cda2ad54c321d9a8d77e4ca34517106f587eb5ec184bf78f8a0ce4fb55658301b0dc6b129d10adf62391"), + }, + Signature: _HexToSignature("0x8790321eacadd5b869838bc01db2338b0bd88a802d768bff8ddbe12aeff67ebc003af8ecc3bafedfef98d2946e869974075006f22367f77c58ca1f1ba20f0d90bf323d243063db16c631ce4ff89bc4f3f239e0879cc4eb492b9906a16fab6f16"), + } + payload := delegate + + t.Run("Normal function", func(t *testing.T) { + backend := newTestBackend(t, 1, time.Second) + rr := backend.request(t, http.MethodPost, path, payload) + require.Equal(t, http.StatusOK, rr.Code) + require.Equal(t, 1, backend.relays[0].GetRequestCount(path)) + }) +} + +func TestRevoke(t *testing.T) { + path := pathRevoke + revoke := SignedRevocation{ + Message: Revocation{ + ValidatorPubkey: _HexToPubkey("0xa695ad325dfc7e1191fbc9f186f58eff42a634029731b18380ff89bf42c464a42cb8ca55b200f051f57f1e1893c68759"), + DelegateePubkey: _HexToPubkey("0xb8ba260170b9cda2ad54c321d9a8d77e4ca34517106f587eb5ec184bf78f8a0ce4fb55658301b0dc6b129d10adf62391"), + }, + Signature: _HexToSignature("0x8790321eacadd5b869838bc01db2338b0bd88a802d768bff8ddbe12aeff67ebc003af8ecc3bafedfef98d2946e869974075006f22367f77c58ca1f1ba20f0d90bf323d243063db16c631ce4ff89bc4f3f239e0879cc4eb492b9906a16fab6f16"), + } + payload := revoke + + t.Run("Normal function", func(t *testing.T) { + backend := newTestBackend(t, 1, time.Second) + rr := backend.request(t, http.MethodPost, path, payload) + require.Equal(t, http.StatusOK, rr.Code) + require.Equal(t, 1, backend.relays[0].GetRequestCount(path)) + }) +} + +func TestParseSignedDelegation(t *testing.T) { + jsonStr := `{ + "message": { + "validator_pubkey": "0xa695ad325dfc7e1191fbc9f186f58eff42a634029731b18380ff89bf42c464a42cb8ca55b200f051f57f1e1893c68759", + "delegatee_pubkey": "0xb8ba260170b9cda2ad54c321d9a8d77e4ca34517106f587eb5ec184bf78f8a0ce4fb55658301b0dc6b129d10adf62391" + }, + "signature": "0x8790321eacadd5b869838bc01db2338b0bd88a802d768bff8ddbe12aeff67ebc003af8ecc3bafedfef98d2946e869974075006f22367f77c58ca1f1ba20f0d90bf323d243063db16c631ce4ff89bc4f3f239e0879cc4eb492b9906a16fab6f16" + }` + + delegation := SignedDelegation{} + err := json.Unmarshal([]byte(jsonStr), &delegation) + require.NoError(t, err) + require.Equal(t, phase0.BLSPubKey(_HexToBytes("0xa695ad325dfc7e1191fbc9f186f58eff42a634029731b18380ff89bf42c464a42cb8ca55b200f051f57f1e1893c68759")), delegation.Message.ValidatorPubkey) + require.Equal(t, phase0.BLSPubKey(_HexToBytes("0xb8ba260170b9cda2ad54c321d9a8d77e4ca34517106f587eb5ec184bf78f8a0ce4fb55658301b0dc6b129d10adf62391")), delegation.Message.DelegateePubkey) + require.Equal(t, phase0.BLSSignature(_HexToBytes("0x8790321eacadd5b869838bc01db2338b0bd88a802d768bff8ddbe12aeff67ebc003af8ecc3bafedfef98d2946e869974075006f22367f77c58ca1f1ba20f0d90bf323d243063db16c631ce4ff89bc4f3f239e0879cc4eb492b9906a16fab6f16")), delegation.Signature) +} + func TestParseConstraints(t *testing.T) { jsonStr := `[ { From eb47e268ed9d2a7e9978ce70dc488559ed874ac3 Mon Sep 17 00:00:00 2001 From: Lorenzo Date: Tue, 8 Oct 2024 17:26:59 +0200 Subject: [PATCH 15/64] Update mev-boost/server/service.go --- mev-boost/server/service.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mev-boost/server/service.go b/mev-boost/server/service.go index 971697304..d0d88b6d1 100644 --- a/mev-boost/server/service.go +++ b/mev-boost/server/service.go @@ -465,7 +465,7 @@ func (m *BoostService) verifyInclusionProof(transactionsRoot phase0.Root, proof return errHashesIndexesMismatch } - log.Infof("[BOLT]: Verifying merkel multiproofs for %d transactions", len(proof.TransactionHashes)) + log.Infof("[BOLT]: Verifying merkle multiproofs for %d transactions", len(proof.TransactionHashes)) // Decode the constraints, and sort them according to the utility function used // TODO: this should be done before verification ideally From d48011b67b5c4f6d153caaa5565ed0ce0b1187d9 Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Thu, 10 Oct 2024 11:14:26 +0200 Subject: [PATCH 16/64] chore: addressed review --- bolt-boost/src/types.rs | 78 ++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/bolt-boost/src/types.rs b/bolt-boost/src/types.rs index d9ab762f6..edb44dbe7 100644 --- a/bolt-boost/src/types.rs +++ b/bolt-boost/src/types.rs @@ -77,7 +77,6 @@ impl ConstraintsMessage { for bytes in &self.transactions { let tx = TxEnvelope::decode_2718(&mut bytes.as_ref())?; - hasher.update(tx.tx_hash()); } @@ -102,44 +101,9 @@ impl TryFrom for ConstraintsWithProofData { .iter() .map(|tx| { let envelope = TxEnvelope::decode_2718(&mut tx.as_ref())?; - let tx_hash = *envelope.tx_hash(); - - let root = match envelope { - // For type 3 txs, take the hash tree root of the inner tx (EIP-4844) - TxEnvelope::Eip4844(tx) => match tx.tx() { - TxEip4844Variant::TxEip4844(tx) => { - let mut out = Vec::new(); - out.put_u8(0x03); - tx.encode(&mut out); - - tree_hash::TreeHash::tree_hash_root(&Transaction::< - ::MaxBytesPerTransaction, - >::from( - out - )) - } - TxEip4844Variant::TxEip4844WithSidecar(tx) => { - use alloy_rlp::Encodable; - let mut out = Vec::new(); - out.put_u8(0x03); - tx.tx.encode(&mut out); - - tree_hash::TreeHash::tree_hash_root(&Transaction::< - ::MaxBytesPerTransaction, - >::from( - out - )) - } - }, - // For other transaction types, take the hash tree root of the whole tx - _ => tree_hash::TreeHash::tree_hash_root(&Transaction::< - ::MaxBytesPerTransaction, - >::from( - tx.to_vec() - )), - }; - - Ok((tx_hash, root)) + let tx_hash_tree_root = calculate_tx_hash_tree_root(&envelope, tx)?; + + Ok((*envelope.tx_hash(), tx_hash_tree_root)) }) .collect::, Eip2718Error>>()?; @@ -147,6 +111,42 @@ impl TryFrom for ConstraintsWithProofData { } } +/// Calculate the SSZ hash tree root of a transaction, starting from its enveloped form. +/// For type 3 transactions, the hash tree root of the inner transaction is taken (without blobs). +fn calculate_tx_hash_tree_root( + envelope: &TxEnvelope, + raw_tx: &Bytes, +) -> Result { + match envelope { + // For type 3 txs, take the hash tree root of the inner tx (EIP-4844) + TxEnvelope::Eip4844(tx) => match tx.tx() { + TxEip4844Variant::TxEip4844(tx) => { + let mut out = Vec::new(); + out.put_u8(0x03); + tx.encode(&mut out); + + Ok(tree_hash::TreeHash::tree_hash_root(&Transaction::< + ::MaxBytesPerTransaction, + >::from(out))) + } + TxEip4844Variant::TxEip4844WithSidecar(tx) => { + use alloy_rlp::Encodable; + let mut out = Vec::new(); + out.put_u8(0x03); + tx.tx.encode(&mut out); + + Ok(tree_hash::TreeHash::tree_hash_root(&Transaction::< + ::MaxBytesPerTransaction, + >::from(out))) + } + }, + // For other transaction types, take the hash tree root of the whole tx + _ => Ok(tree_hash::TreeHash::tree_hash_root(&Transaction::< + ::MaxBytesPerTransaction, + >::from(raw_tx.to_vec()))), + } +} + #[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)] pub struct SignedDelegation { pub message: DelegationMessage, From 601f8d6637f2a640e9cc3b31451f18ccda01a4bb Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Thu, 10 Oct 2024 14:41:02 +0200 Subject: [PATCH 17/64] feat: signed message actions (with runtime check) --- bolt-sidecar/src/primitives/constraint.rs | 4 +-- bolt-sidecar/src/primitives/mod.rs | 37 +++++++++++++++++--- bolt-sidecar/src/test_util.rs | 41 +++++++++++++---------- 3 files changed, 59 insertions(+), 23 deletions(-) diff --git a/bolt-sidecar/src/primitives/constraint.rs b/bolt-sidecar/src/primitives/constraint.rs index a762952d1..230627ebe 100644 --- a/bolt-sidecar/src/primitives/constraint.rs +++ b/bolt-sidecar/src/primitives/constraint.rs @@ -16,7 +16,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#constraints -#[derive(Serialize, Default, Debug, Clone, PartialEq)] +#[derive(Serialize, Default, Debug, Clone, PartialEq, Eq)] pub struct SignedConstraints { /// The constraints that need to be signed. pub message: ConstraintsMessage, @@ -27,7 +27,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, Deserialize, Debug, Clone, PartialEq, Default)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, Eq)] pub struct ConstraintsMessage { /// The validator pubkey of the proposer sidecar. pub pubkey: BlsPublicKey, diff --git a/bolt-sidecar/src/primitives/mod.rs b/bolt-sidecar/src/primitives/mod.rs index ce7f9b3fd..5a9b04f6b 100644 --- a/bolt-sidecar/src/primitives/mod.rs +++ b/bolt-sidecar/src/primitives/mod.rs @@ -452,21 +452,41 @@ where #[error("Invalid signature")] pub struct SignatureError; -#[derive(Debug, Clone, Serialize)] +/// Event types that can be emitted by the validator pubkey to +/// signal some action on the Bolt protocol. +#[derive(Debug, Clone, Copy)] +#[repr(u8)] +enum SignedMessageAction { + /// Signal delegation of a validator pubkey to a delegatee pubkey. + Delegation, + /// Signal revocation of a previously delegated pubkey. + Revocation, +} + +#[derive(Debug, Clone, Serialize, PartialEq, Eq)] pub struct SignedDelegation { pub message: DelegationMessage, pub signature: BlsSignature, } -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, Serialize, PartialEq, Eq)] pub struct DelegationMessage { + action: u8, pub validator_pubkey: BlsPublicKey, pub delegatee_pubkey: BlsPublicKey, } +impl DelegationMessage { + /// Create a new delegation message. + pub fn new(validator_pubkey: BlsPublicKey, delegatee_pubkey: BlsPublicKey) -> Self { + Self { action: SignedMessageAction::Delegation as u8, validator_pubkey, delegatee_pubkey } + } +} + impl SignableBLS for DelegationMessage { fn digest(&self) -> [u8; 32] { let mut hasher = Sha256::new(); + hasher.update([self.action]); hasher.update(self.validator_pubkey.to_vec()); hasher.update(self.delegatee_pubkey.to_vec()); @@ -474,21 +494,30 @@ impl SignableBLS for DelegationMessage { } } -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, Serialize, PartialEq, Eq)] pub struct SignedRevocation { pub message: RevocationMessage, pub signature: BlsSignature, } -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, Serialize, PartialEq, Eq)] pub struct RevocationMessage { + action: u8, pub validator_pubkey: BlsPublicKey, pub delegatee_pubkey: BlsPublicKey, } +impl RevocationMessage { + /// Create a new revocation message. + pub fn new(validator_pubkey: BlsPublicKey, delegatee_pubkey: BlsPublicKey) -> Self { + Self { action: SignedMessageAction::Revocation as u8, validator_pubkey, delegatee_pubkey } + } +} + impl SignableBLS for RevocationMessage { fn digest(&self) -> [u8; 32] { let mut hasher = Sha256::new(); + hasher.update([self.action]); hasher.update(self.validator_pubkey.to_vec()); hasher.update(self.delegatee_pubkey.to_vec()); diff --git a/bolt-sidecar/src/test_util.rs b/bolt-sidecar/src/test_util.rs index a32c6cc3b..2b1c6643b 100644 --- a/bolt-sidecar/src/test_util.rs +++ b/bolt-sidecar/src/test_util.rs @@ -17,12 +17,16 @@ use secp256k1::Message; use tracing::warn; use crate::{ - crypto::{bls::Signer as BlsSigner, ecdsa::SignableECDSA, SignableBLS}, + crypto::{ + bls::{random_bls_secret, Signer as BlsSigner}, + ecdsa::SignableECDSA, + SignableBLS, + }, primitives::{ CommitmentRequest, ConstraintsMessage, DelegationMessage, FullTransaction, InclusionRequest, RevocationMessage, SignedConstraints, SignedDelegation, SignedRevocation, }, - Config, + ChainConfig, Config, }; /// The URL of the test execution client HTTP API. @@ -187,8 +191,8 @@ fn random_constraints(count: usize) -> Vec { } #[tokio::test] -async fn generate_test_data() { - let signer = BlsSigner::random(); +async fn generate_test_data_kurtosis() { + let signer = BlsSigner::new(random_bls_secret(), ChainConfig::kurtosis(0, 0)); let pk = signer.pubkey(); println!("Validator Public Key: {}", hex::encode(pk.as_ref())); @@ -200,33 +204,36 @@ async fn generate_test_data() { let delegatee_pk = delegatee_sk.sk_to_pk(); // Prepare a Delegation message - let delegation_msg = DelegationMessage { - validator_pubkey: pk.clone(), - delegatee_pubkey: PublicKey::try_from(delegatee_pk.to_bytes().as_slice()) + let delegation_msg = DelegationMessage::new( + pk.clone(), + PublicKey::try_from(delegatee_pk.to_bytes().as_slice()) .expect("Failed to convert delegatee public key"), - }; + ); let digest = SignableBLS::digest(&delegation_msg); // Sign the Delegation message let delegation_signature = signer.sign_commit_boost_root(digest).unwrap(); + let blst_sig = blst::min_pk::Signature::from_bytes(delegation_signature.as_ref()) + .expect("Failed to convert delegation signature"); + let consensus_sig = Signature::try_from(delegation_signature.as_ref()) + .expect("Failed to convert delegation signature"); + + // Sanity check: verify the signature + assert!(signer.verify_commit_boost_root(digest, &blst_sig).is_ok()); // Create SignedDelegation - let signed_delegation = SignedDelegation { - message: delegation_msg, - signature: Signature::try_from(delegation_signature.as_ref()) - .expect("Failed to convert delegation signature"), - }; + let signed_delegation = SignedDelegation { message: delegation_msg, signature: consensus_sig }; // Output SignedDelegation println!("{}", serde_json::to_string_pretty(&signed_delegation).unwrap()); // Prepare a revocation message - let revocation_msg = RevocationMessage { - validator_pubkey: pk.clone(), - delegatee_pubkey: PublicKey::try_from(delegatee_pk.to_bytes().as_slice()) + let revocation_msg = RevocationMessage::new( + pk.clone(), + PublicKey::try_from(delegatee_pk.to_bytes().as_slice()) .expect("Failed to convert delegatee public key"), - }; + ); let digest = SignableBLS::digest(&revocation_msg); From 482b8501f369216dd46702744d0dc3e3da5afa18 Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:52:26 +0200 Subject: [PATCH 18/64] feat(mev-boost): add delegation action to api --- mev-boost/server/constraints.go | 16 ++++++++++++---- mev-boost/server/service.go | 7 +++++++ mev-boost/server/service_test.go | 2 ++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/mev-boost/server/constraints.go b/mev-boost/server/constraints.go index d6c2f6597..817ab1692 100644 --- a/mev-boost/server/constraints.go +++ b/mev-boost/server/constraints.go @@ -105,26 +105,34 @@ func (c *ConstraintsCache) FindTransactionByHash(txHash gethCommon.Hash) (*Trans return nil, false } -// Ref: https://docs.boltprotocol.xyz/api/builder#delegate +// SignedDelegation represents the delegation signed by the proposer pubkey to +// authorize the delegatee pubkey to submit constraints on their behalf. +// +// Specs: https://docs.boltprotocol.xyz/api/builder#delegate type SignedDelegation struct { Message Delegation `json:"message"` Signature phase0.BLSSignature `json:"signature"` } -// Ref: https://docs.boltprotocol.xyz/api/builder#delegate +// Delegation as from Specs: https://docs.boltprotocol.xyz/api/builder#delegate type Delegation struct { + Action uint8 `json:"action"` ValidatorPubkey phase0.BLSPubKey `json:"validator_pubkey"` DelegateePubkey phase0.BLSPubKey `json:"delegatee_pubkey"` } -// Ref: https://docs.boltprotocol.xyz/api/builder#revoke +// SignedRevocation represents the revocation signed by the proposer pubkey to +// revoke the delegatee pubkey's ability to submit constraints on their behalf. +// +// Specs: https://docs.boltprotocol.xyz/api/builder#revoke type SignedRevocation struct { Message Revocation `json:"message"` Signature phase0.BLSSignature `json:"signature"` } -// Ref: https://docs.boltprotocol.xyz/api/builder#revoke +// Revocation as from Specs: https://docs.boltprotocol.xyz/api/builder#revoke type Revocation struct { + Action uint8 `json:"action"` ValidatorPubkey phase0.BLSPubKey `json:"validator_pubkey"` DelegateePubkey phase0.BLSPubKey `json:"delegatee_pubkey"` } diff --git a/mev-boost/server/service.go b/mev-boost/server/service.go index d0d88b6d1..746566c54 100644 --- a/mev-boost/server/service.go +++ b/mev-boost/server/service.go @@ -363,6 +363,10 @@ func (m *BoostService) handleDelegate(w http.ResponseWriter, req *http.Request) m.respondError(w, http.StatusBadRequest, err.Error()) return } + if payload.Message.Action != 0 { + m.respondError(w, http.StatusBadRequest, "invalid action, expected 0 for delegate") + return + } ua := UserAgent(req.Header.Get("User-Agent")) log = log.WithFields(logrus.Fields{ @@ -407,6 +411,9 @@ func (m *BoostService) handleRevoke(w http.ResponseWriter, req *http.Request) { m.respondError(w, http.StatusBadRequest, err.Error()) return } + if payload.Message.Action != 1 { + m.respondError(w, http.StatusBadRequest, "invalid action, expected 1 for revoke") + } ua := UserAgent(req.Header.Get("User-Agent")) log = log.WithFields(logrus.Fields{ diff --git a/mev-boost/server/service_test.go b/mev-boost/server/service_test.go index 6efb23972..c4212951d 100644 --- a/mev-boost/server/service_test.go +++ b/mev-boost/server/service_test.go @@ -315,6 +315,7 @@ func TestDelegate(t *testing.T) { path := pathDelegate delegate := SignedDelegation{ Message: Delegation{ + Action: 0, ValidatorPubkey: _HexToPubkey("0xa695ad325dfc7e1191fbc9f186f58eff42a634029731b18380ff89bf42c464a42cb8ca55b200f051f57f1e1893c68759"), DelegateePubkey: _HexToPubkey("0xb8ba260170b9cda2ad54c321d9a8d77e4ca34517106f587eb5ec184bf78f8a0ce4fb55658301b0dc6b129d10adf62391"), }, @@ -334,6 +335,7 @@ func TestRevoke(t *testing.T) { path := pathRevoke revoke := SignedRevocation{ Message: Revocation{ + Action: 1, ValidatorPubkey: _HexToPubkey("0xa695ad325dfc7e1191fbc9f186f58eff42a634029731b18380ff89bf42c464a42cb8ca55b200f051f57f1e1893c68759"), DelegateePubkey: _HexToPubkey("0xb8ba260170b9cda2ad54c321d9a8d77e4ca34517106f587eb5ec184bf78f8a0ce4fb55658301b0dc6b129d10adf62391"), }, From 345c10904f0570e060088e344ea9ced22b94c915 Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:52:43 +0200 Subject: [PATCH 19/64] feat(bolt-boost): added action to delegation api --- bolt-boost/src/types.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bolt-boost/src/types.rs b/bolt-boost/src/types.rs index edb44dbe7..8a5b355d6 100644 --- a/bolt-boost/src/types.rs +++ b/bolt-boost/src/types.rs @@ -155,6 +155,7 @@ pub struct SignedDelegation { #[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)] pub struct DelegationMessage { + action: u8, pub validator_pubkey: BlsPublicKey, pub delegatee_pubkey: BlsPublicKey, } @@ -167,6 +168,7 @@ pub struct SignedRevocation { #[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)] pub struct RevocationMessage { + action: u8, pub validator_pubkey: BlsPublicKey, pub delegatee_pubkey: BlsPublicKey, } From bc77deea1850af5f4aa78604e21e52611d12a981 Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Fri, 11 Oct 2024 11:53:53 +0200 Subject: [PATCH 20/64] fix(builder): re-add constraint pubkey validation --- builder/builder/builder.go | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/builder/builder/builder.go b/builder/builder/builder.go index 65c65f144..e765b4bad 100644 --- a/builder/builder/builder.go +++ b/builder/builder/builder.go @@ -11,6 +11,7 @@ import ( "math/big" "net/http" _ "os" + "slices" "strings" "sync" "time" @@ -362,32 +363,19 @@ func (b *Builder) subscribeToRelayForConstraints(relayBaseEndpoint string) error } for _, constraint := range constraintsSigned { - // TODO: re-enable this once testing the devnet has ended - // oneValidSignature := false - // Check if the signature is valid against any of the authorized pubkeys - // for _, pubkey := range b.slotConstraintsPubkeys { - // valid, err := constraint.VerifySignature(pubkey, b.GetConstraintsDomain()) - // if err != nil || !valid { - // log.Error("Failed to verify constraint signature", "err", err) - // continue - // } - // - // oneValidSignature = true - // } - - // TODO: remove this once testing the devnet has ended, we should check for authorized keys + // Check that the constraints pubkey is authorized to sign constraints + if !slices.Contains(b.slotConstraintsPubkeys, constraint.Message.Pubkey) { + log.Warn("Received constraint from unauthorized pubkey", "pubkey", constraint.Message.Pubkey) + continue + } + + // Verify the signature of the constraints message valid, err := constraint.VerifySignature(constraint.Message.Pubkey, b.GetConstraintsDomain()) if err != nil || !valid { log.Error("Failed to verify constraint signature", "err", err) continue } - // TODO: re-enable this once testing the devnet has ended - // If there is no valid signature, continue with the next constraint - // if !oneValidSignature { - // continue - // } - decodedConstraints, err := DecodeConstraints(constraint) if err != nil { log.Error("Failed to decode constraint: ", err) From 83f2deec00fabcff1af8d5c3113be06e2ca805e1 Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Tue, 8 Oct 2024 15:56:21 +0200 Subject: [PATCH 21/64] feat(sidecar): keys dir for ERC-2335 keystore --- bolt-sidecar/keys/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 bolt-sidecar/keys/.gitignore diff --git a/bolt-sidecar/keys/.gitignore b/bolt-sidecar/keys/.gitignore new file mode 100644 index 000000000..d6b7ef32c --- /dev/null +++ b/bolt-sidecar/keys/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore From dffe0fade3d7180f5e67bdc80bfe6c16b6f1319f Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Tue, 8 Oct 2024 17:22:57 +0200 Subject: [PATCH 22/64] chore(sidecar): lighthouse dependencies for keystore --- bolt-sidecar/Cargo.lock | 2364 ++++++++++++++++++++++++++++++++++++--- bolt-sidecar/Cargo.toml | 4 + 2 files changed, 2200 insertions(+), 168 deletions(-) diff --git a/bolt-sidecar/Cargo.lock b/bolt-sidecar/Cargo.lock index d1cd4db45..62a9ec52b 100644 --- a/bolt-sidecar/Cargo.lock +++ b/bolt-sidecar/Cargo.lock @@ -2,6 +2,26 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "account_utils" +version = "0.1.0" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +dependencies = [ + "directory", + "eth2_keystore 0.1.0 (git+https://github.com/sigp/lighthouse?rev=32f2e05)", + "eth2_wallet", + "filesystem", + "rand 0.8.5", + "regex", + "rpassword", + "serde", + "serde_yaml 0.9.33", + "slog", + "types", + "validator_dir", + "zeroize", +] + [[package]] name = "addr2line" version = "0.21.0" @@ -17,6 +37,27 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" + +[[package]] +name = "aead" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" +dependencies = [ + "generic-array", +] + [[package]] name = "aes" version = "0.7.5" @@ -24,12 +65,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ "cfg-if", - "cipher", + "cipher 0.3.0", "cpufeatures", - "ctr", + "ctr 0.8.0", "opaque-debug", ] +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher 0.4.4", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc3be92e19a7ef47457b8e6f90707e12b6ac5d20c6f3866584fa3be0787d839f" +dependencies = [ + "aead", + "aes 0.7.5", + "cipher 0.3.0", + "ctr 0.7.0", + "ghash", + "subtle", +] + [[package]] name = "ahash" version = "0.8.11" @@ -851,7 +917,7 @@ dependencies = [ "alloy-transport 0.2.1", "futures", "http 1.1.0", - "rustls", + "rustls 0.23.12", "serde_json", "tokio", "tokio-tungstenite 0.23.1", @@ -954,6 +1020,21 @@ dependencies = [ "derive_arbitrary", ] +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + +[[package]] +name = "archery" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a8da9bc4c4053ee067669762bcaeea6e241841295a2b6c948312dad6ef4cc02" +dependencies = [ + "static_assertions", +] + [[package]] name = "ark-ff" version = "0.3.0" @@ -1090,6 +1171,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "asn1_der" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "155a5a185e42c6b77ac7b88a15143d930a9e9727a5b7b77eed417404ab15c247" + [[package]] name = "async-channel" version = "1.9.0" @@ -1310,11 +1397,17 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.7.4", "object", "rustc-demangle", ] +[[package]] +name = "base-x" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" + [[package]] name = "base16ct" version = "0.1.1" @@ -1432,17 +1525,29 @@ dependencies = [ "serde", ] +[[package]] +name = "bitvec" +version = "0.20.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7774144344a4faa177370406a7ff5f1da24303817368584c6206c8303eb07848" +dependencies = [ + "funty 1.1.0", + "radium 0.6.2", + "tap", + "wyz 0.2.0", +] + [[package]] name = "bitvec" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ - "funty", - "radium", + "funty 2.0.0", + "radium 0.7.0", "serde", "tap", - "wyz", + "wyz 0.5.1", ] [[package]] @@ -1451,6 +1556,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ + "block-padding", "generic-array", ] @@ -1463,6 +1569,30 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + +[[package]] +name = "bls" +version = "0.2.0" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +dependencies = [ + "arbitrary", + "blst", + "ethereum-types 0.14.1", + "ethereum_hashing 0.6.0", + "ethereum_serde_utils", + "ethereum_ssz", + "hex", + "rand 0.8.5", + "serde", + "tree_hash 0.6.0", + "zeroize", +] + [[package]] name = "bls" version = "0.2.0" @@ -1470,7 +1600,25 @@ source = "git+https://github.com/sigp/lighthouse?rev=9e12c21f268c80a3f002ae0ca27 dependencies = [ "arbitrary", "blst", - "ethereum-types", + "ethereum-types 0.14.1", + "ethereum_hashing 0.6.0", + "ethereum_serde_utils", + "ethereum_ssz", + "hex", + "rand 0.8.5", + "serde", + "tree_hash 0.6.0", + "zeroize", +] + +[[package]] +name = "bls" +version = "0.2.0" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" +dependencies = [ + "arbitrary", + "blst", + "ethereum-types 0.14.1", "ethereum_hashing 0.6.0", "ethereum_serde_utils", "ethereum_ssz", @@ -1506,10 +1654,27 @@ dependencies = [ "zeroize", ] +[[package]] +name = "blstrs" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a8a8ed6fefbeef4a8c7b460e4110e12c5e22a5b7cf32621aae6ad650c4dcf29" +dependencies = [ + "blst", + "byte-slice-cast", + "ff 0.13.0", + "group 0.13.0", + "pairing", + "rand_core 0.6.4", + "serde", + "subtle", +] + [[package]] name = "bolt-sidecar" version = "0.2.1-alpha" dependencies = [ + "account_utils", "alloy", "alloy-node-bindings", "async-trait", @@ -1522,6 +1687,7 @@ dependencies = [ "clap", "commit-boost", "dotenvy", + "eth2_keystore 0.1.0 (git+https://github.com/sigp/lighthouse?rev=a87f19d)", "ethereum-consensus", "ethereum_ssz", "ethereum_ssz_derive", @@ -1531,7 +1697,7 @@ dependencies = [ "lru", "metrics", "metrics-exporter-prometheus", - "parking_lot", + "parking_lot 0.12.3", "partial-mpt", "rand 0.8.5", "regex", @@ -1548,7 +1714,7 @@ dependencies = [ "tracing", "tracing-subscriber", "tree_hash 0.5.2", - "tree_hash_derive", + "tree_hash_derive 0.5.2", "warp", ] @@ -1558,6 +1724,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + [[package]] name = "bumpalo" version = "3.16.0" @@ -1591,6 +1766,27 @@ dependencies = [ "serde", ] +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "c-kzg" version = "1.0.3" @@ -1632,8 +1828,8 @@ dependencies = [ "bimap", "blst", "derive_more 1.0.0", - "eth2_keystore", - "ethereum-types", + "eth2_keystore 0.1.0 (git+https://github.com/sigp/lighthouse?rev=9e12c21f268c80a3f002ae0ca27477f9f512eb6f)", + "ethereum-types 0.14.1", "ethereum_serde_utils", "ethereum_ssz", "ethereum_ssz_derive", @@ -1643,7 +1839,7 @@ dependencies = [ "reqwest 0.12.7", "serde", "serde_json", - "ssz_types", + "ssz_types 0.5.4", "thiserror", "tokio", "toml 0.8.19", @@ -1651,7 +1847,7 @@ dependencies = [ "tracing-appender", "tracing-subscriber", "tree_hash 0.5.2", - "tree_hash_derive", + "tree_hash_derive 0.5.2", "url", ] @@ -1714,7 +1910,7 @@ dependencies = [ "tokio", "tracing", "tree_hash 0.5.2", - "tree_hash_derive", + "tree_hash_derive 0.5.2", "uuid 1.10.0", ] @@ -1772,6 +1968,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clang-sys" version = "1.8.1" @@ -1803,6 +2009,7 @@ dependencies = [ "anstyle", "clap_lex", "strsim 0.11.1", + "terminal_size", ] [[package]] @@ -1823,6 +2030,23 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" +[[package]] +name = "clap_utils" +version = "0.1.0" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +dependencies = [ + "clap", + "dirs", + "eth2_network_config", + "ethereum-types 0.14.1", + "ethereum_ssz", + "hex", + "serde", + "serde_json", + "serde_yaml 0.9.33", + "types", +] + [[package]] name = "cmake" version = "0.1.51" @@ -1890,7 +2114,24 @@ dependencies = [ "eyre", "tokio", "tree_hash 0.5.2", - "tree_hash_derive", + "tree_hash_derive 0.5.2", +] + +[[package]] +name = "compare_fields" +version = "0.2.0" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +dependencies = [ + "itertools 0.10.5", +] + +[[package]] +name = "compare_fields_derive" +version = "0.2.0" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +dependencies = [ + "quote", + "syn 1.0.109", ] [[package]] @@ -1921,6 +2162,12 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + [[package]] name = "convert_case" version = "0.4.0" @@ -1970,6 +2217,52 @@ dependencies = [ "libc", ] +[[package]] +name = "crate_crypto_internal_eth_kzg_bls12_381" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8761b04feb6031ffaf93933c955a0c91a2f3ce15dcac6b9586d2487fe55abf0b" +dependencies = [ + "blst", + "blstrs", + "ff 0.13.0", + "group 0.13.0", + "pairing", + "rayon", +] + +[[package]] +name = "crate_crypto_internal_eth_kzg_erasure_codes" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca410dff79524a2babe8a0d9ab5fdce21b16808f8189eb8b6da6159681f8de2" +dependencies = [ + "crate_crypto_internal_eth_kzg_bls12_381", + "crate_crypto_internal_eth_kzg_polynomial", +] + +[[package]] +name = "crate_crypto_internal_eth_kzg_polynomial" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68be1a5f16bc1c09254dec5209e22278d7d395284443576886a5890e7131234f" +dependencies = [ + "crate_crypto_internal_eth_kzg_bls12_381", +] + +[[package]] +name = "crate_crypto_kzg_multi_open_fk20" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702fe5b687fe8c5a46851b8bc624ad49603a339dc93c920d4f7e61592c201ee8" +dependencies = [ + "crate_crypto_internal_eth_kzg_bls12_381", + "crate_crypto_internal_eth_kzg_polynomial", + "hex", + "rayon", + "sha2 0.10.8", +] + [[package]] name = "crc" version = "3.2.1" @@ -1985,6 +2278,15 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + [[package]] name = "crossbeam-channel" version = "0.5.13" @@ -2059,6 +2361,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + [[package]] name = "crypto-mac" version = "0.11.0" @@ -2069,13 +2381,49 @@ dependencies = [ "subtle", ] +[[package]] +name = "ctr" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a232f92a03f37dd7d7dd2adc67166c77e9cd88de5b019b9a9eecfaeaf7bfd481" +dependencies = [ + "cipher 0.3.0", +] + [[package]] name = "ctr" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" dependencies = [ - "cipher", + "cipher 0.3.0", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "rustc_version 0.4.1", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.76", ] [[package]] @@ -2148,6 +2496,12 @@ dependencies = [ "syn 2.0.76", ] +[[package]] +name = "dary_heap" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7762d17f1241643615821a8455a0b2c3e803784b058693d990b11f2dce25a0ca" + [[package]] name = "dashmap" version = "5.5.3" @@ -2158,7 +2512,7 @@ dependencies = [ "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core", + "parking_lot_core 0.9.10", ] [[package]] @@ -2168,12 +2522,57 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] -name = "der" -version = "0.6.1" +name = "data-encoding-macro" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +checksum = "f1559b6cba622276d6d63706db152618eeb15b89b3e4041446b05876e352e639" dependencies = [ - "const-oid", + "data-encoding", + "data-encoding-macro-internal", +] + +[[package]] +name = "data-encoding-macro-internal" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "332d754c0af53bc87c108fed664d121ecf59207ec4196041f04d6ab9002ad33f" +dependencies = [ + "data-encoding", + "syn 1.0.109", +] + +[[package]] +name = "delay_map" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4355c25cbf99edcb6b4a0e906f6bdc6956eda149e84455bea49696429b2f8e8" +dependencies = [ + "futures", + "tokio-util", +] + +[[package]] +name = "deposit_contract" +version = "0.2.0" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +dependencies = [ + "ethabi 16.0.0", + "ethereum_ssz", + "hex", + "reqwest 0.11.27", + "serde_json", + "sha2 0.9.9", + "tree_hash 0.6.0", + "types", +] + +[[package]] +name = "der" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +dependencies = [ + "const-oid", "zeroize", ] @@ -2306,6 +2705,88 @@ dependencies = [ "subtle", ] +[[package]] +name = "directory" +version = "0.1.0" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +dependencies = [ + "clap", + "clap_utils", + "eth2_network_config", +] + +[[package]] +name = "dirs" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "discv5" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bac33cb3f99889a57e56a8c6ccb77aaf0cfc7787602b7af09783f736d77314e1" +dependencies = [ + "aes 0.7.5", + "aes-gcm", + "arrayvec", + "delay_map", + "enr 0.10.0", + "fnv", + "futures", + "hashlink", + "hex", + "hkdf", + "lazy_static", + "libp2p", + "lru", + "more-asserts", + "parking_lot 0.11.2", + "rand 0.8.5", + "rlp", + "smallvec", + "socket2 0.4.10", + "tokio", + "tracing", + "uint", + "zeroize", +] + [[package]] name = "docker-compose-types" version = "0.12.0" @@ -2368,6 +2849,31 @@ dependencies = [ "spki 0.7.3", ] +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8 0.10.2", + "signature 2.2.0", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand_core 0.6.4", + "serde", + "sha2 0.10.8", + "subtle", + "zeroize", +] + [[package]] name = "either" version = "1.13.0" @@ -2429,7 +2935,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26fa0a0be8915790626d5759eb51fe47435a8eac92c2f212bd2da9aa7f30ea56" dependencies = [ "base64 0.13.1", - "bs58", + "bs58 0.4.0", "bytes", "hex", "k256 0.11.6", @@ -2437,7 +2943,26 @@ dependencies = [ "rand 0.8.5", "rlp", "serde", - "sha3", + "sha3 0.10.8", + "zeroize", +] + +[[package]] +name = "enr" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a3d8dc56e02f954cac8eb489772c552c473346fc34f67412bb6244fd647f7e4" +dependencies = [ + "base64 0.21.7", + "bytes", + "ed25519-dalek", + "hex", + "k256 0.13.3", + "log", + "rand 0.8.5", + "rlp", + "serde", + "sha3 0.10.8", "zeroize", ] @@ -2458,6 +2983,15 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "erased-serde" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c138974f9d5e7fe373eb04df7cae98833802ae4b11c24ac7039a21d5af4b26c" +dependencies = [ + "serde", +] + [[package]] name = "errno" version = "0.3.9" @@ -2468,29 +3002,97 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "eth2_config" +version = "0.2.0" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +dependencies = [ + "paste", + "types", +] + +[[package]] +name = "eth2_interop_keypairs" +version = "0.2.0" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +dependencies = [ + "bls 0.2.0 (git+https://github.com/sigp/lighthouse?rev=32f2e05)", + "ethereum_hashing 0.6.0", + "hex", + "num-bigint", + "serde", + "serde_yaml 0.9.33", +] + +[[package]] +name = "eth2_key_derivation" +version = "0.1.0" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +dependencies = [ + "bls 0.2.0 (git+https://github.com/sigp/lighthouse?rev=32f2e05)", + "num-bigint-dig", + "ring 0.16.20", + "sha2 0.9.9", + "zeroize", +] + [[package]] name = "eth2_key_derivation" version = "0.1.0" source = "git+https://github.com/sigp/lighthouse?rev=9e12c21f268c80a3f002ae0ca27477f9f512eb6f#9e12c21f268c80a3f002ae0ca27477f9f512eb6f" dependencies = [ - "bls", + "bls 0.2.0 (git+https://github.com/sigp/lighthouse?rev=9e12c21f268c80a3f002ae0ca27477f9f512eb6f)", + "num-bigint-dig", + "ring 0.16.20", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "eth2_key_derivation" +version = "0.1.0" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" +dependencies = [ + "bls 0.2.0 (git+https://github.com/sigp/lighthouse?rev=a87f19d)", "num-bigint-dig", "ring 0.16.20", "sha2 0.9.9", "zeroize", ] +[[package]] +name = "eth2_keystore" +version = "0.1.0" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +dependencies = [ + "aes 0.7.5", + "bls 0.2.0 (git+https://github.com/sigp/lighthouse?rev=32f2e05)", + "eth2_key_derivation 0.1.0 (git+https://github.com/sigp/lighthouse?rev=32f2e05)", + "hex", + "hmac 0.11.0", + "pbkdf2 0.8.0", + "rand 0.8.5", + "scrypt", + "serde", + "serde_json", + "serde_repr", + "sha2 0.9.9", + "unicode-normalization", + "uuid 0.8.2", + "zeroize", +] + [[package]] name = "eth2_keystore" version = "0.1.0" source = "git+https://github.com/sigp/lighthouse?rev=9e12c21f268c80a3f002ae0ca27477f9f512eb6f#9e12c21f268c80a3f002ae0ca27477f9f512eb6f" dependencies = [ - "aes", - "bls", - "eth2_key_derivation", + "aes 0.7.5", + "bls 0.2.0 (git+https://github.com/sigp/lighthouse?rev=9e12c21f268c80a3f002ae0ca27477f9f512eb6f)", + "eth2_key_derivation 0.1.0 (git+https://github.com/sigp/lighthouse?rev=9e12c21f268c80a3f002ae0ca27477f9f512eb6f)", "hex", "hmac 0.11.0", - "pbkdf2", + "pbkdf2 0.8.0", "rand 0.8.5", "scrypt", "serde", @@ -2502,23 +3104,108 @@ dependencies = [ "zeroize", ] +[[package]] +name = "eth2_keystore" +version = "0.1.0" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" +dependencies = [ + "aes 0.7.5", + "bls 0.2.0 (git+https://github.com/sigp/lighthouse?rev=a87f19d)", + "eth2_key_derivation 0.1.0 (git+https://github.com/sigp/lighthouse?rev=a87f19d)", + "hex", + "hmac 0.11.0", + "pbkdf2 0.8.0", + "rand 0.8.5", + "scrypt", + "serde", + "serde_json", + "serde_repr", + "sha2 0.9.9", + "unicode-normalization", + "uuid 0.8.2", + "zeroize", +] + +[[package]] +name = "eth2_network_config" +version = "0.2.0" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +dependencies = [ + "bytes", + "discv5", + "eth2_config", + "logging", + "pretty_reqwest_error", + "reqwest 0.11.27", + "sensitive_url", + "serde_yaml 0.9.33", + "sha2 0.9.9", + "slog", + "types", + "url", + "zip", +] + +[[package]] +name = "eth2_wallet" +version = "0.1.0" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +dependencies = [ + "eth2_key_derivation 0.1.0 (git+https://github.com/sigp/lighthouse?rev=32f2e05)", + "eth2_keystore 0.1.0 (git+https://github.com/sigp/lighthouse?rev=32f2e05)", + "rand 0.8.5", + "serde", + "serde_json", + "serde_repr", + "tiny-bip39", + "uuid 0.8.2", +] + +[[package]] +name = "ethabi" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c98847055d934070b90e806e12d3936b787d0a115068981c1d8dfd5dfef5a5" +dependencies = [ + "ethereum-types 0.12.1", + "hex", + "serde", + "serde_json", + "sha3 0.9.1", + "thiserror", + "uint", +] + [[package]] name = "ethabi" version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" dependencies = [ - "ethereum-types", + "ethereum-types 0.14.1", "hex", "once_cell", "regex", "serde", "serde_json", - "sha3", + "sha3 0.10.8", "thiserror", "uint", ] +[[package]] +name = "ethbloom" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb684ac8fa8f6c5759f788862bb22ec6fe3cb392f6bfd08e3c64b603661e3f8" +dependencies = [ + "crunchy", + "fixed-hash 0.7.0", + "impl-rlp", + "impl-serde 0.3.2", + "tiny-keccak", +] + [[package]] name = "ethbloom" version = "0.13.0" @@ -2526,10 +3213,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" dependencies = [ "crunchy", - "fixed-hash", - "impl-codec", + "fixed-hash 0.8.0", + "impl-codec 0.6.0", "impl-rlp", - "impl-serde", + "impl-serde 0.4.0", "scale-info", "tiny-keccak", ] @@ -2540,13 +3227,13 @@ version = "0.1.1" source = "git+https://github.com/ralexstokes/ethereum-consensus?rev=cf3c404#cf3c404043230559660810bc0c9d6d5a8498d819" dependencies = [ "blst", - "bs58", + "bs58 0.4.0", "c-kzg", - "enr", + "enr 0.6.2", "hex", "integer-sqrt", - "multiaddr", - "multihash", + "multiaddr 0.14.0", + "multihash 0.16.3", "rand 0.8.5", "serde", "serde_json", @@ -2558,18 +3245,32 @@ dependencies = [ "tokio-stream", ] +[[package]] +name = "ethereum-types" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05136f7057fe789f06e6d41d07b34e6f70d8c86e5693b60f97aaa6553553bdaf" +dependencies = [ + "ethbloom 0.11.1", + "fixed-hash 0.7.0", + "impl-rlp", + "impl-serde 0.3.2", + "primitive-types 0.10.1", + "uint", +] + [[package]] name = "ethereum-types" version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" dependencies = [ - "ethbloom", - "fixed-hash", - "impl-codec", + "ethbloom 0.13.0", + "fixed-hash 0.8.0", + "impl-codec 0.6.0", "impl-rlp", - "impl-serde", - "primitive-types", + "impl-serde 0.4.0", + "primitive-types 0.12.2", "scale-info", "uint", ] @@ -2604,7 +3305,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de4d5951468846963c24e8744c133d44f39dff2cd3a233f6be22b370d08a524f" dependencies = [ - "ethereum-types", + "ethereum-types 0.14.1", "hex", "serde", "serde_derive", @@ -2617,7 +3318,7 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d3627f83d8b87b432a5fad9934b4565260722a141a2c40f371f8080adec9425" dependencies = [ - "ethereum-types", + "ethereum-types 0.14.1", "itertools 0.10.5", "smallvec", ] @@ -2645,7 +3346,7 @@ dependencies = [ "chrono", "const-hex", "elliptic-curve 0.13.8", - "ethabi", + "ethabi 18.0.0", "generic-array", "k256 0.13.3", "num_enum", @@ -2677,6 +3378,18 @@ dependencies = [ "once_cell", ] +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + [[package]] name = "fastrand" version = "1.9.0" @@ -2719,23 +3432,71 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "bitvec", + "bitvec 1.0.1", "rand_core 0.6.4", "subtle", ] +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "field-offset" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" +dependencies = [ + "memoffset", + "rustc_version 0.4.1", +] + +[[package]] +name = "filesystem" +version = "0.1.0" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +dependencies = [ + "winapi", + "windows-acl", +] + +[[package]] +name = "fixed-hash" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" +dependencies = [ + "byteorder", + "rand 0.8.5", + "rustc-hex", + "static_assertions", +] + [[package]] name = "fixed-hash" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ + "arbitrary", "byteorder", "rand 0.8.5", "rustc-hex", "static_assertions", ] +[[package]] +name = "flate2" +version = "1.0.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +dependencies = [ + "crc32fast", + "miniz_oxide 0.8.0", +] + [[package]] name = "fnv" version = "1.0.7" @@ -2766,12 +3527,28 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "fs_extra" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +[[package]] +name = "funty" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" + [[package]] name = "funty" version = "2.0.0" @@ -2818,6 +3595,7 @@ dependencies = [ "futures-core", "futures-task", "futures-util", + "num_cpus", ] [[package]] @@ -2864,6 +3642,12 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + [[package]] name = "futures-util" version = "0.3.30" @@ -2923,6 +3707,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "ghash" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" +dependencies = [ + "opaque-debug", + "polyval", +] + [[package]] name = "gimli" version = "0.28.1" @@ -2953,7 +3747,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff 0.13.0", + "rand 0.8.5", "rand_core 0.6.4", + "rand_xorshift", "subtle", ] @@ -3012,6 +3808,15 @@ dependencies = [ "serde", ] +[[package]] +name = "hashlink" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +dependencies = [ + "hashbrown 0.14.5", +] + [[package]] name = "headers" version = "0.3.9" @@ -3078,6 +3883,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "hex" version = "0.4.3" @@ -3093,13 +3904,32 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac 0.12.1", +] + +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac 0.8.0", + "digest 0.9.0", +] + [[package]] name = "hmac" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" dependencies = [ - "crypto-mac", + "crypto-mac 0.11.0", "digest 0.9.0", ] @@ -3112,6 +3942,17 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array", + "hmac 0.8.1", +] + [[package]] name = "home" version = "0.5.9" @@ -3226,7 +4067,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.5.7", "tokio", "tower-service", "tracing", @@ -3254,6 +4095,20 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http 0.2.12", + "hyper 0.14.30", + "rustls 0.21.12", + "tokio", + "tokio-rustls 0.24.1", +] + [[package]] name = "hyper-rustls" version = "0.27.2" @@ -3265,11 +4120,11 @@ dependencies = [ "hyper 1.4.1", "hyper-util", "log", - "rustls", + "rustls 0.23.12", "rustls-native-certs", "rustls-pki-types", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.0", "tower-service", ] @@ -3315,7 +4170,7 @@ dependencies = [ "http-body 1.0.1", "hyper 1.4.1", "pin-project-lite", - "socket2", + "socket2 0.5.7", "tokio", "tower", "tower-service", @@ -3361,13 +4216,22 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "impl-codec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "161ebdfec3c8e3b52bf61c4f3550a1eea4f9579d10dc1b936f3171ebdcd6c443" +dependencies = [ + "parity-scale-codec 2.3.1", +] + [[package]] name = "impl-codec" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" dependencies = [ - "parity-scale-codec", + "parity-scale-codec 3.6.12", ] [[package]] @@ -3379,6 +4243,15 @@ dependencies = [ "rlp", ] +[[package]] +name = "impl-serde" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c" +dependencies = [ + "serde", +] + [[package]] name = "impl-serde" version = "0.4.0" @@ -3433,6 +4306,15 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac" +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "instant" version = "0.1.13" @@ -3442,6 +4324,14 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "int_to_bytes" +version = "0.2.0" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +dependencies = [ + "bytes", +] + [[package]] name = "integer-sqrt" version = "0.1.5" @@ -3462,7 +4352,7 @@ dependencies = [ "libc", "recvmsg", "tokio", - "widestring", + "widestring 1.1.0", "windows-sys 0.52.0", ] @@ -3472,6 +4362,17 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +[[package]] +name = "is-terminal" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +dependencies = [ + "hermit-abi 0.4.0", + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -3570,11 +4471,11 @@ dependencies = [ "base64 0.22.1", "http-body 1.0.1", "hyper 1.4.1", - "hyper-rustls", + "hyper-rustls 0.27.2", "hyper-util", "jsonrpsee-core", "jsonrpsee-types", - "rustls", + "rustls 0.23.12", "rustls-platform-verifier", "serde", "serde_json", @@ -3586,128 +4487,364 @@ dependencies = [ ] [[package]] -name = "jsonrpsee-types" -version = "0.24.3" +name = "jsonrpsee-types" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b67d6e008164f027afbc2e7bb79662650158d26df200040282d2aa1cbb093b" +dependencies = [ + "http 1.1.0", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "jsonwebtoken" +version = "9.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f" +dependencies = [ + "base64 0.21.7", + "js-sys", + "pem", + "ring 0.17.8", + "serde", + "serde_json", + "simple_asn1", +] + +[[package]] +name = "k256" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" +dependencies = [ + "cfg-if", + "ecdsa 0.14.8", + "elliptic-curve 0.12.3", + "sha2 0.10.8", +] + +[[package]] +name = "k256" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +dependencies = [ + "cfg-if", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "once_cell", + "sha2 0.10.8", + "signature 2.2.0", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "keccak-asm" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "422fbc7ff2f2f5bdffeb07718e5a5324dca72b0c9293d50df4026652385e3314" +dependencies = [ + "digest 0.10.7", + "sha3-asm", +] + +[[package]] +name = "kzg" +version = "0.1.0" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +dependencies = [ + "arbitrary", + "c-kzg", + "derivative", + "ethereum_hashing 0.6.0", + "ethereum_serde_utils", + "ethereum_ssz", + "ethereum_ssz_derive", + "hex", + "rust_eth_kzg", + "serde", + "tree_hash 0.6.0", +] + +[[package]] +name = "kzg-rs" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd9920cd4460ce3cbca19c62f3bb9a9611562478a4dc9d2c556f4a7d049c5b6b" +dependencies = [ + "bls12_381", + "glob", + "hex", + "once_cell", + "serde", + "serde_derive", + "serde_yaml 0.9.33", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin 0.9.8", +] + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" + +[[package]] +name = "libflate" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45d9dfdc14ea4ef0900c1cddbc8dcd553fbaacd8a4a282cf4018ae9dd04fb21e" +dependencies = [ + "adler32", + "core2", + "crc32fast", + "dary_heap", + "libflate_lz77", +] + +[[package]] +name = "libflate_lz77" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e0d73b369f386f1c44abd9c570d5318f55ccde816ff4b562fa452e5182863d" +dependencies = [ + "core2", + "hashbrown 0.14.5", + "rle-decode-fast", +] + +[[package]] +name = "libloading" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +dependencies = [ + "cfg-if", + "windows-targets 0.48.5", +] + +[[package]] +name = "libm" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b67d6e008164f027afbc2e7bb79662650158d26df200040282d2aa1cbb093b" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libp2p" +version = "0.53.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "681fb3f183edfbedd7a57d32ebe5dcdc0b9f94061185acf3c30249349cc6fc99" dependencies = [ - "http 1.1.0", - "serde", - "serde_json", + "bytes", + "either", + "futures", + "futures-timer", + "getrandom 0.2.15", + "instant", + "libp2p-allow-block-list", + "libp2p-connection-limits", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "multiaddr 0.18.2", + "pin-project", + "rw-stream-sink", "thiserror", ] [[package]] -name = "jsonwebtoken" -version = "9.3.0" +name = "libp2p-allow-block-list" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f" +checksum = "107b238b794cb83ab53b74ad5dcf7cca3200899b72fe662840cfb52f5b0a32e6" dependencies = [ - "base64 0.21.7", - "js-sys", - "pem", - "ring 0.17.8", - "serde", - "serde_json", - "simple_asn1", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "void", ] [[package]] -name = "k256" -version = "0.11.6" +name = "libp2p-connection-limits" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" +checksum = "c7cd50a78ccfada14de94cbacd3ce4b0138157f376870f13d3a8422cd075b4fd" dependencies = [ - "cfg-if", - "ecdsa 0.14.8", - "elliptic-curve 0.12.3", - "sha2 0.10.8", + "libp2p-core", + "libp2p-identity", + "libp2p-swarm", + "void", ] [[package]] -name = "k256" -version = "0.13.3" +name = "libp2p-core" +version = "0.41.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +checksum = "a5a8920cbd8540059a01950c1e5c96ea8d89eb50c51cd366fc18bdf540a6e48f" dependencies = [ - "cfg-if", - "ecdsa 0.16.9", - "elliptic-curve 0.13.8", + "either", + "fnv", + "futures", + "futures-timer", + "libp2p-identity", + "multiaddr 0.18.2", + "multihash 0.19.1", + "multistream-select", "once_cell", + "parking_lot 0.12.3", + "pin-project", + "quick-protobuf", + "rand 0.8.5", + "rw-stream-sink", + "smallvec", + "thiserror", + "tracing", + "unsigned-varint 0.8.0", + "void", + "web-time", +] + +[[package]] +name = "libp2p-identity" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cca1eb2bc1fd29f099f3daaab7effd01e1a54b7c577d0ed082521034d912e8" +dependencies = [ + "asn1_der", + "bs58 0.5.1", + "ed25519-dalek", + "hkdf", + "libsecp256k1", + "multihash 0.19.1", + "quick-protobuf", + "rand 0.8.5", "sha2 0.10.8", - "signature 2.2.0", + "thiserror", + "tracing", + "zeroize", ] [[package]] -name = "keccak" -version = "0.1.5" +name = "libp2p-swarm" +version = "0.44.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +checksum = "80cae6cb75f89dbca53862f9ebe0b9f463aa7b302762fcfaafb9e51dcc9b0f7e" dependencies = [ - "cpufeatures", + "either", + "fnv", + "futures", + "futures-timer", + "instant", + "libp2p-core", + "libp2p-identity", + "lru", + "multistream-select", + "once_cell", + "rand 0.8.5", + "smallvec", + "tracing", + "void", ] [[package]] -name = "keccak-asm" +name = "libredox" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "422fbc7ff2f2f5bdffeb07718e5a5324dca72b0c9293d50df4026652385e3314" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "digest 0.10.7", - "sha3-asm", + "bitflags 2.6.0", + "libc", ] [[package]] -name = "kzg-rs" -version = "0.1.0" +name = "libsecp256k1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd9920cd4460ce3cbca19c62f3bb9a9611562478a4dc9d2c556f4a7d049c5b6b" +checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" dependencies = [ - "bls12_381", - "glob", - "hex", - "once_cell", + "arrayref", + "base64 0.13.1", + "digest 0.9.0", + "hmac-drbg", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.8.5", "serde", - "serde_derive", - "serde_yaml 0.9.33", + "sha2 0.9.9", + "typenum", ] [[package]] -name = "lazy_static" -version = "1.5.0" +name = "libsecp256k1-core" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" dependencies = [ - "spin 0.9.8", + "crunchy", + "digest 0.9.0", + "subtle", ] [[package]] -name = "lazycell" -version = "1.3.0" +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] [[package]] -name = "libc" -version = "0.2.158" +name = "libsecp256k1-gen-genmult" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] [[package]] -name = "libloading" -version = "0.8.5" +name = "libsqlite3-sys" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +checksum = "29f835d03d717946d28b1d1ed632eb6f0e24a299388ee623d0c23118d3e8a7fa" dependencies = [ - "cfg-if", - "windows-targets 0.48.5", + "cc", + "pkg-config", + "vcpkg", ] [[package]] -name = "libm" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +name = "lighthouse_metrics" +version = "0.2.0" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +dependencies = [ + "prometheus", +] [[package]] name = "linked-hash-map" @@ -3731,12 +4868,42 @@ dependencies = [ "scopeguard", ] +[[package]] +name = "lockfile" +version = "0.1.0" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +dependencies = [ + "fs2", +] + [[package]] name = "log" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +[[package]] +name = "logging" +version = "0.2.0" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +dependencies = [ + "chrono", + "lighthouse_metrics", + "parking_lot 0.12.3", + "serde", + "serde_json", + "slog", + "slog-term", + "sloggers", + "take_mut", + "tokio", + "tracing", + "tracing-appender", + "tracing-core", + "tracing-log", + "tracing-subscriber", +] + [[package]] name = "lru" version = "0.12.4" @@ -3746,6 +4913,12 @@ dependencies = [ "hashbrown 0.14.5", ] +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + [[package]] name = "matchers" version = "0.1.0" @@ -3767,6 +4940,48 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "merkle_proof" +version = "0.2.0" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +dependencies = [ + "ethereum-types 0.14.1", + "ethereum_hashing 0.6.0", + "safe_arith", +] + +[[package]] +name = "metastruct" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f00a5ba4a0f3453c31c397b214e1675d95b697c33763aa58add57ea833424384" +dependencies = [ + "metastruct_macro", +] + +[[package]] +name = "metastruct_macro" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c3a991d4536c933306e52f0e8ab303757185ec13a09d1f3e1cbde5a0d8410bf" +dependencies = [ + "darling 0.13.4", + "itertools 0.10.5", + "proc-macro2", + "quote", + "smallvec", + "syn 1.0.109", +] + [[package]] name = "metrics" version = "0.23.0" @@ -3786,7 +5001,7 @@ dependencies = [ "base64 0.22.1", "http-body-util", "hyper 1.4.1", - "hyper-rustls", + "hyper-rustls 0.27.2", "hyper-util", "indexmap 2.4.0", "ipnet", @@ -3832,6 +5047,29 @@ dependencies = [ "tracing", ] +[[package]] +name = "milhouse" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3826d3602a3674b07e080ce1982350e454ec253d73f156bd927ac1b652293f4d" +dependencies = [ + "arbitrary", + "derivative", + "ethereum-types 0.14.1", + "ethereum_hashing 0.6.0", + "ethereum_ssz", + "ethereum_ssz_derive", + "itertools 0.10.5", + "parking_lot 0.12.3", + "rayon", + "serde", + "smallvec", + "tree_hash 0.6.0", + "triomphe", + "typenum", + "vec_map", +] + [[package]] name = "mime" version = "0.3.17" @@ -3863,13 +5101,22 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + [[package]] name = "mio" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", @@ -3902,6 +5149,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "more-asserts" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e" + [[package]] name = "multer" version = "2.1.0" @@ -3927,17 +5180,47 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c580bfdd8803cce319b047d239559a22f809094aaea4ac13902a1fdcfcd4261" dependencies = [ "arrayref", - "bs58", + "bs58 0.4.0", + "byteorder", + "data-encoding", + "multihash 0.16.3", + "percent-encoding", + "serde", + "static_assertions", + "unsigned-varint 0.7.2", + "url", +] + +[[package]] +name = "multiaddr" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe6351f60b488e04c1d21bc69e56b89cb3f5e8f5d22557d6e8031bdfd79b6961" +dependencies = [ + "arrayref", "byteorder", "data-encoding", - "multihash", + "libp2p-identity", + "multibase", + "multihash 0.19.1", "percent-encoding", "serde", "static_assertions", - "unsigned-varint", + "unsigned-varint 0.8.0", "url", ] +[[package]] +name = "multibase" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b3539ec3c1f04ac9748a260728e855f261b4977f5c3406612c884564f329404" +dependencies = [ + "base-x", + "data-encoding", + "data-encoding-macro", +] + [[package]] name = "multihash" version = "0.16.3" @@ -3948,7 +5231,17 @@ dependencies = [ "digest 0.10.7", "multihash-derive", "sha2 0.10.8", - "unsigned-varint", + "unsigned-varint 0.7.2", +] + +[[package]] +name = "multihash" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "076d548d76a0e2a0d4ab471d0b1c36c577786dfc4471242035d97a12a735c492" +dependencies = [ + "core2", + "unsigned-varint 0.7.2", ] [[package]] @@ -3965,6 +5258,20 @@ dependencies = [ "synstructure", ] +[[package]] +name = "multistream-select" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea0df8e5eec2298a62b326ee4f0d7fe1a6b90a09dfcf9df37b38f947a8c42f19" +dependencies = [ + "bytes", + "futures", + "log", + "pin-project", + "smallvec", + "unsigned-varint 0.7.2", +] + [[package]] name = "native-tls" version = "0.2.12" @@ -4072,7 +5379,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi", + "hermit-abi 0.3.9", "libc", ] @@ -4140,7 +5447,7 @@ dependencies = [ "arrayvec", "auto_impl", "bytes", - "ethereum-types", + "ethereum-types 0.14.1", "open-fastrlp-derive", ] @@ -4186,7 +5493,16 @@ dependencies = [ name = "openssl-probe" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-src" +version = "300.3.2+3.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a211a18d945ef7e648cc6e0058f4c548ee46aab922ea203e0d30e966ea23647b" +dependencies = [ + "cc", +] [[package]] name = "openssl-sys" @@ -4196,6 +5512,7 @@ checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" dependencies = [ "cc", "libc", + "openssl-src", "pkg-config", "vcpkg", ] @@ -4221,6 +5538,20 @@ dependencies = [ "group 0.13.0", ] +[[package]] +name = "parity-scale-codec" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373b1a4c1338d9cd3d1fa53b3a11bdab5ab6bd80a20f7f7becd76953ae2be909" +dependencies = [ + "arrayvec", + "bitvec 0.20.4", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive 2.3.1", + "serde", +] + [[package]] name = "parity-scale-codec" version = "3.6.12" @@ -4228,13 +5559,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" dependencies = [ "arrayvec", - "bitvec", + "bitvec 1.0.1", "byte-slice-cast", "impl-trait-for-tuples", - "parity-scale-codec-derive", + "parity-scale-codec-derive 3.6.12", "serde", ] +[[package]] +name = "parity-scale-codec-derive" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1557010476e0595c9b568d16dcfb81b93cdeb157612726f5170d31aa707bed27" +dependencies = [ + "proc-macro-crate 1.1.3", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "parity-scale-codec-derive" version = "3.6.12" @@ -4253,6 +5596,17 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -4260,7 +5614,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core", + "parking_lot_core 0.9.10", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", ] [[package]] @@ -4271,7 +5639,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.3", "smallvec", "windows-targets 0.52.6", ] @@ -4292,6 +5660,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "paste" version = "1.0.15" @@ -4304,7 +5683,19 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa" dependencies = [ - "crypto-mac", + "crypto-mac 0.11.0", +] + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", + "hmac 0.12.1", + "password-hash", + "sha2 0.10.8", ] [[package]] @@ -4402,6 +5793,18 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +[[package]] +name = "polyval" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "portable-atomic" version = "1.7.0" @@ -4423,6 +5826,15 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "pretty_reqwest_error" +version = "0.1.0" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +dependencies = [ + "reqwest 0.11.27", + "sensitive_url", +] + [[package]] name = "prettyplease" version = "0.2.20" @@ -4433,16 +5845,29 @@ dependencies = [ "syn 2.0.76", ] +[[package]] +name = "primitive-types" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373" +dependencies = [ + "fixed-hash 0.7.0", + "impl-codec 0.5.1", + "impl-rlp", + "impl-serde 0.3.2", + "uint", +] + [[package]] name = "primitive-types" version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ - "fixed-hash", - "impl-codec", + "fixed-hash 0.8.0", + "impl-codec 0.6.0", "impl-rlp", - "impl-serde", + "impl-serde 0.4.0", "scale-info", "uint", ] @@ -4509,7 +5934,7 @@ dependencies = [ "fnv", "lazy_static", "memchr", - "parking_lot", + "parking_lot 0.12.3", "protobuf", "thiserror", ] @@ -4561,6 +5986,15 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +[[package]] +name = "quick-protobuf" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d6da84cc204722a989e01ba2f6e1e276e190f22263d0cb6ce8526fcdb0d2e1f" +dependencies = [ + "byteorder", +] + [[package]] name = "quote" version = "1.0.37" @@ -4570,6 +6004,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" + [[package]] name = "radium" version = "0.7.0" @@ -4691,6 +6131,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3edd4d5d42c92f0a659926464d4cce56b562761267ecf0f469d85b7de384175" +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.5.3" @@ -4700,6 +6149,17 @@ dependencies = [ "bitflags 2.6.0", ] +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom 0.2.15", + "libredox", + "thiserror", +] + [[package]] name = "regex" version = "1.10.6" @@ -4759,6 +6219,7 @@ dependencies = [ "http 0.2.12", "http-body 0.4.6", "hyper 0.14.30", + "hyper-rustls 0.24.2", "hyper-tls 0.5.0", "ipnet", "js-sys", @@ -4768,6 +6229,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "rustls 0.21.12", "rustls-pemfile 1.0.4", "serde", "serde_json", @@ -4776,6 +6238,7 @@ dependencies = [ "system-configuration 0.5.1", "tokio", "tokio-native-tls", + "tokio-rustls 0.24.1", "tokio-util", "tower-service", "url", @@ -4783,6 +6246,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", + "webpki-roots 0.25.4", "winreg", ] @@ -4802,7 +6266,7 @@ dependencies = [ "http-body 1.0.1", "http-body-util", "hyper 1.4.1", - "hyper-rustls", + "hyper-rustls 0.27.2", "hyper-tls 0.6.0", "hyper-util", "ipnet", @@ -4901,7 +6365,7 @@ dependencies = [ "serde", "tempfile", "thiserror", - "zstd", + "zstd 0.13.2", ] [[package]] @@ -4979,7 +6443,7 @@ dependencies = [ "alloy-primitives", "auto_impl", "bitflags 2.6.0", - "bitvec", + "bitvec 1.0.1", "c-kzg", "cfg-if", "derive_more 0.99.18", @@ -5043,6 +6507,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rle-decode-fast" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422" + [[package]] name = "rlp" version = "0.5.2" @@ -5075,6 +6545,25 @@ dependencies = [ "byteorder", ] +[[package]] +name = "rpassword" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc936cf8a7ea60c58f030fd36a612a48f440610214dc54bc36431f9ea0c3efb" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "rpds" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ef5140bcb576bfd6d56cd2de709a7d17851ac1f3805e67fe9d99e42a11821f" +dependencies = [ + "archery", +] + [[package]] name = "ruint" version = "1.12.3" @@ -5089,8 +6578,8 @@ dependencies = [ "fastrlp", "num-bigint", "num-traits", - "parity-scale-codec", - "primitive-types", + "parity-scale-codec 3.6.12", + "primitive-types 0.12.2", "proptest", "rand 0.8.5", "rlp", @@ -5106,6 +6595,35 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" +[[package]] +name = "rusqlite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01e213bc3ecb39ac32e81e51ebe31fd888a940515173e3a18a35f8c6e896422a" +dependencies = [ + "bitflags 1.3.2", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] + +[[package]] +name = "rust_eth_kzg" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "013a850c7e131a8f9651ffbb151dc33240234f21dd357b692bd5ff4cdc84bf9a" +dependencies = [ + "crate_crypto_internal_eth_kzg_bls12_381", + "crate_crypto_internal_eth_kzg_erasure_codes", + "crate_crypto_kzg_multi_open_fk20", + "hex", + "rayon", + "serde", + "serde_json", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -5161,6 +6679,18 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring 0.17.8", + "rustls-webpki 0.101.7", + "sct", +] + [[package]] name = "rustls" version = "0.23.12" @@ -5172,7 +6702,7 @@ dependencies = [ "once_cell", "ring 0.17.8", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.102.7", "subtle", "zeroize", ] @@ -5226,13 +6756,13 @@ dependencies = [ "jni", "log", "once_cell", - "rustls", + "rustls 0.23.12", "rustls-native-certs", "rustls-platform-verifier-android", - "rustls-webpki", + "rustls-webpki 0.102.7", "security-framework", "security-framework-sys", - "webpki-roots", + "webpki-roots 0.26.3", "winapi", ] @@ -5242,6 +6772,16 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring 0.17.8", + "untrusted 0.9.0", +] + [[package]] name = "rustls-webpki" version = "0.102.7" @@ -5272,19 +6812,35 @@ dependencies = [ "wait-timeout", ] +[[package]] +name = "rw-stream-sink" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8c9026ff5d2f23da5e45bbc283f156383001bfb09c4e44256d02c1a685fe9a1" +dependencies = [ + "futures", + "pin-project", + "static_assertions", +] + [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "safe_arith" +version = "0.1.0" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" + [[package]] name = "salsa20" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ecbd2eb639fd7cab5804a0837fe373cc2172d15437e804c054a9fb885cb923b0" dependencies = [ - "cipher", + "cipher 0.3.0", ] [[package]] @@ -5304,7 +6860,7 @@ checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" dependencies = [ "cfg-if", "derive_more 0.99.18", - "parity-scale-codec", + "parity-scale-codec 3.6.12", "scale-info-derive", ] @@ -5348,11 +6904,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879588d8f90906e73302547e20fffefdd240eb3e0e744e142321f5d49dea0518" dependencies = [ "hmac 0.11.0", - "pbkdf2", + "pbkdf2 0.8.0", "salsa20", "sha2 0.9.9", ] +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring 0.17.8", + "untrusted 0.9.0", +] + [[package]] name = "sec1" version = "0.3.0" @@ -5454,6 +7020,15 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" +[[package]] +name = "sensitive_url" +version = "0.1.0" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +dependencies = [ + "serde", + "url", +] + [[package]] name = "serde" version = "1.0.209" @@ -5629,6 +7204,18 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha3" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "keccak", + "opaque-debug", +] + [[package]] name = "sha3" version = "0.10.8" @@ -5712,12 +7299,114 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85636c14b73d81f541e525f585c0a2109e6744e1565b5c1668e31c70c10ed65c" [[package]] -name = "slab" -version = "0.4.9" +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "slog" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8347046d4ebd943127157b94d63abb990fcf729dc4e9978927fdf4ac3c998d06" +dependencies = [ + "erased-serde", +] + +[[package]] +name = "slog-async" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c8038f898a2c79507940990f05386455b3a317d8f18d4caea7cbc3d5096b84" +dependencies = [ + "crossbeam-channel", + "slog", + "take_mut", + "thread_local", +] + +[[package]] +name = "slog-json" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e1e53f61af1e3c8b852eef0a9dee29008f55d6dd63794f3f12cef786cf0f219" +dependencies = [ + "serde", + "serde_json", + "slog", + "time", +] + +[[package]] +name = "slog-kvfilter" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae939ed7d169eed9699f4f5cd440f046f5dc5dfc27c19e3cd311619594c175e0" +dependencies = [ + "regex", + "slog", +] + +[[package]] +name = "slog-scope" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f95a4b4c3274cd2869549da82b57ccc930859bdbf5bcea0424bc5f140b3c786" +dependencies = [ + "arc-swap", + "lazy_static", + "slog", +] + +[[package]] +name = "slog-stdlog" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6706b2ace5bbae7291d3f8d2473e2bfab073ccd7d03670946197aec98471fa3e" +dependencies = [ + "log", + "slog", + "slog-scope", +] + +[[package]] +name = "slog-term" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6e022d0b998abfe5c3782c1f03551a596269450ccd677ea51c56f8b214610e8" +dependencies = [ + "is-terminal", + "slog", + "term", + "thread_local", + "time", +] + +[[package]] +name = "sloggers" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +checksum = "75062c2738b82cd45ae633623caae3393f43eb00aada1dc2d3ebe88db6b0db9b" dependencies = [ - "autocfg", + "chrono", + "libc", + "libflate", + "once_cell", + "regex", + "serde", + "slog", + "slog-async", + "slog-json", + "slog-kvfilter", + "slog-scope", + "slog-stdlog", + "slog-term", + "trackable", + "winapi", + "windows-acl", ] [[package]] @@ -5726,9 +7415,20 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" dependencies = [ + "arbitrary", "serde", ] +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "socket2" version = "0.5.7" @@ -5777,7 +7477,7 @@ version = "0.9.0" source = "git+https://github.com/ralexstokes/ssz-rs?rev=84ef2b71aa004f6767420badb42c902ad56b8b72#84ef2b71aa004f6767420badb42c902ad56b8b72" dependencies = [ "alloy-primitives", - "bitvec", + "bitvec 1.0.1", "serde", "sha2 0.9.9", "ssz_rs_derive 0.9.0 (git+https://github.com/ralexstokes/ssz-rs?rev=84ef2b71aa004f6767420badb42c902ad56b8b72)", @@ -5789,7 +7489,7 @@ version = "0.9.0" source = "git+https://github.com/ralexstokes/ssz-rs#84ef2b71aa004f6767420badb42c902ad56b8b72" dependencies = [ "alloy-primitives", - "bitvec", + "bitvec 1.0.1", "serde", "sha2 0.9.9", "ssz_rs_derive 0.9.0 (git+https://github.com/ralexstokes/ssz-rs)", @@ -5832,6 +7532,30 @@ dependencies = [ "typenum", ] +[[package]] +name = "ssz_types" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625b20de2d4b3891e6972f4ce5061cb11bd52b3479270c4b177c134b571194a9" +dependencies = [ + "arbitrary", + "derivative", + "ethereum_serde_utils", + "ethereum_ssz", + "itertools 0.10.5", + "serde", + "serde_derive", + "smallvec", + "tree_hash 0.6.0", + "typenum", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "static_assertions" version = "1.1.0" @@ -5878,6 +7602,29 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "superstruct" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf0f31f730ad9e579364950e10d6172b4a9bd04b447edf5988b066a860cc340e" +dependencies = [ + "darling 0.13.4", + "itertools 0.10.5", + "proc-macro2", + "quote", + "smallvec", + "syn 1.0.109", +] + +[[package]] +name = "swap_or_not_shuffle" +version = "0.2.0" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +dependencies = [ + "ethereum-types 0.14.1", + "ethereum_hashing 0.6.0", +] + [[package]] name = "syn" version = "1.0.109" @@ -5981,6 +7728,12 @@ dependencies = [ "libc", ] +[[package]] +name = "take_mut" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" + [[package]] name = "tap" version = "1.0.1" @@ -6000,6 +7753,36 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + +[[package]] +name = "terminal_size" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +dependencies = [ + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "test_random_derive" +version = "0.2.0" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +dependencies = [ + "quote", + "syn 1.0.109", +] + [[package]] name = "thiserror" version = "1.0.63" @@ -6090,6 +7873,25 @@ dependencies = [ "time-core", ] +[[package]] +name = "tiny-bip39" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62cc94d358b5a1e84a5cb9109f559aa3c4d634d2b1b4de3d0fa4adc7c78e2861" +dependencies = [ + "anyhow", + "hmac 0.12.1", + "once_cell", + "pbkdf2 0.11.0", + "rand 0.8.5", + "rustc-hash 1.1.0", + "sha2 0.10.8", + "thiserror", + "unicode-normalization", + "wasm-bindgen", + "zeroize", +] + [[package]] name = "tiny-keccak" version = "2.0.2" @@ -6124,10 +7926,10 @@ dependencies = [ "bytes", "libc", "mio", - "parking_lot", + "parking_lot 0.12.3", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.5.7", "tokio-macros", "windows-sys 0.52.0", ] @@ -6153,13 +7955,23 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.12", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls", + "rustls 0.23.12", "rustls-pki-types", "tokio", ] @@ -6196,12 +8008,12 @@ checksum = "c6989540ced10490aaf14e6bad2e3d33728a2813310a0c71d1574304c49631cd" dependencies = [ "futures-util", "log", - "rustls", + "rustls 0.23.12", "rustls-pki-types", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.0", "tungstenite 0.23.0", - "webpki-roots", + "webpki-roots 0.26.3", ] [[package]] @@ -6214,6 +8026,7 @@ dependencies = [ "futures-core", "futures-sink", "pin-project-lite", + "slab", "tokio", ] @@ -6402,13 +8215,32 @@ dependencies = [ "tracing-serde", ] +[[package]] +name = "trackable" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15bd114abb99ef8cee977e517c8f37aee63f184f2d08e3e6ceca092373369ae" +dependencies = [ + "trackable_derive", +] + +[[package]] +name = "trackable_derive" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebeb235c5847e2f82cfe0f07eb971d1e5f6804b18dac2ae16349cc604380f82f" +dependencies = [ + "quote", + "syn 1.0.109", +] + [[package]] name = "tree_hash" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c998ac5fe2b07c025444bdd522e6258110b63861c6698eedc610c071980238d" dependencies = [ - "ethereum-types", + "ethereum-types 0.14.1", "ethereum_hashing 1.0.0-beta.2", "smallvec", ] @@ -6419,7 +8251,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "134d6b24a5b829f30b5ee7de05ba7384557f5f6b00e29409cdf2392f93201bfa" dependencies = [ - "ethereum-types", + "ethereum-types 0.14.1", "ethereum_hashing 0.6.0", "smallvec", ] @@ -6435,6 +8267,27 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "tree_hash_derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce7bccc538359a213436af7bc95804bdbf1c2a21d80e22953cbe9e096837ff1" +dependencies = [ + "darling 0.13.4", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "triomphe" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef8f7726da4807b58ea5c96fdc122f80702030edc33b35aff9190a51148ccc85" +dependencies = [ + "serde", + "stable_deref_trait", +] + [[package]] name = "try-lock" version = "0.2.5" @@ -6473,7 +8326,7 @@ dependencies = [ "httparse", "log", "rand 0.8.5", - "rustls", + "rustls 0.23.12", "rustls-pki-types", "sha1", "thiserror", @@ -6486,6 +8339,55 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "types" +version = "0.2.1" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "arbitrary", + "bls 0.2.0 (git+https://github.com/sigp/lighthouse?rev=32f2e05)", + "compare_fields", + "compare_fields_derive", + "derivative", + "eth2_interop_keypairs", + "ethereum-types 0.14.1", + "ethereum_hashing 0.6.0", + "ethereum_serde_utils", + "ethereum_ssz", + "ethereum_ssz_derive", + "hex", + "int_to_bytes", + "itertools 0.10.5", + "kzg", + "log", + "maplit", + "merkle_proof", + "metastruct", + "milhouse", + "parking_lot 0.12.3", + "rand 0.8.5", + "rand_xorshift", + "rayon", + "regex", + "rpds", + "rusqlite", + "safe_arith", + "serde", + "serde_json", + "serde_yaml 0.9.33", + "slog", + "smallvec", + "ssz_types 0.6.0", + "superstruct", + "swap_or_not_shuffle", + "tempfile", + "test_random_derive", + "tree_hash 0.6.0", + "tree_hash_derive 0.6.0", +] + [[package]] name = "ucd-trie" version = "0.1.6" @@ -6498,6 +8400,7 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" dependencies = [ + "arbitrary", "byteorder", "crunchy", "hex", @@ -6552,6 +8455,16 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" +[[package]] +name = "universal-hash" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402" +dependencies = [ + "generic-array", + "subtle", +] + [[package]] name = "unsafe-libyaml" version = "0.2.11" @@ -6564,6 +8477,12 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6889a77d49f1f013504cec6bf97a2c730394adedaeb1deb5ea08949a50541105" +[[package]] +name = "unsigned-varint" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb066959b24b5196ae73cb057f45598450d2c5f71460e98c49b738086eff9c06" + [[package]] name = "untrusted" version = "0.7.1" @@ -6621,6 +8540,24 @@ dependencies = [ "serde", ] +[[package]] +name = "validator_dir" +version = "0.1.0" +source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +dependencies = [ + "bls 0.2.0 (git+https://github.com/sigp/lighthouse?rev=32f2e05)", + "deposit_contract", + "derivative", + "directory", + "eth2_keystore 0.1.0 (git+https://github.com/sigp/lighthouse?rev=32f2e05)", + "filesystem", + "hex", + "lockfile", + "rand 0.8.5", + "tree_hash 0.6.0", + "types", +] + [[package]] name = "valuable" version = "0.1.0" @@ -6633,12 +8570,24 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + [[package]] name = "wait-timeout" version = "0.2.0" @@ -6804,6 +8753,22 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + [[package]] name = "webpki-roots" version = "0.26.3" @@ -6825,6 +8790,12 @@ dependencies = [ "rustix", ] +[[package]] +name = "widestring" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c" + [[package]] name = "widestring" version = "1.1.0" @@ -6862,6 +8833,18 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-acl" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "177b1723986bcb4c606058e77f6e8614b51c7f9ad2face6f6fd63dd5c8b3cec3" +dependencies = [ + "field-offset", + "libc", + "widestring 0.4.3", + "winapi", +] + [[package]] name = "windows-core" version = "0.52.0" @@ -7087,6 +9070,12 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wyz" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" + [[package]] name = "wyz" version = "0.5.1" @@ -7146,13 +9135,52 @@ dependencies = [ "syn 2.0.76", ] +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "aes 0.8.4", + "byteorder", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "flate2", + "hmac 0.12.1", + "pbkdf2 0.11.0", + "sha1", + "time", + "zstd 0.11.2+zstd.1.5.2", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe 5.0.2+zstd.1.5.2", +] + [[package]] name = "zstd" version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" dependencies = [ - "zstd-safe", + "zstd-safe 7.2.1", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", ] [[package]] diff --git a/bolt-sidecar/Cargo.toml b/bolt-sidecar/Cargo.toml index ea0162e0c..3fc083bc7 100644 --- a/bolt-sidecar/Cargo.toml +++ b/bolt-sidecar/Cargo.toml @@ -40,6 +40,10 @@ reqwest = "0.12" ethereum-consensus = { git = "https://github.com/ralexstokes/ethereum-consensus", rev = "cf3c404" } beacon-api-client = { git = "https://github.com/ralexstokes/ethereum-consensus", rev = "cf3c404" } +# lighthouse +lighthouse_account_utils = { package = "account_utils", git = "https://github.com/sigp/lighthouse", rev = "32f2e05" } +lighthouse_eth2_keystore = { package = "eth2_keystore", git = "https://github.com/sigp/lighthouse", rev = "a87f19d" } + # types partial-mpt = { git = "https://github.com/chainbound/partial-mpt", branch = "feat/alloy" } serde = { version = "1.0.197", features = ["derive"] } From 7fcfa882e2fee582e4c638ee0457b66420dbb218 Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Tue, 8 Oct 2024 17:50:30 +0200 Subject: [PATCH 23/64] chore(sidecar): custom Debug for SigningOpts with the keystore_password field --- bolt-sidecar/src/config/mod.rs | 2 +- bolt-sidecar/src/config/signing.rs | 27 +++++++++++++++++++++++---- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/bolt-sidecar/src/config/mod.rs b/bolt-sidecar/src/config/mod.rs index 6a3012185..99e6cb187 100644 --- a/bolt-sidecar/src/config/mod.rs +++ b/bolt-sidecar/src/config/mod.rs @@ -34,7 +34,7 @@ pub const DEFAULT_MAX_COMMITTED_GAS: u64 = 10_000_000; pub const DEFAULT_MIN_PRIORITY_FEE: u128 = 1_000_000_000; // 1 Gwei /// Command-line options for the Bolt sidecar -#[derive(Parser, Debug)] +#[derive(Debug, Parser)] pub struct Opts { /// Port to listen on for incoming JSON-RPC requests #[clap(long, env = "BOLT_SIDECAR_PORT")] diff --git a/bolt-sidecar/src/config/signing.rs b/bolt-sidecar/src/config/signing.rs index c592b1cf6..81c402a41 100644 --- a/bolt-sidecar/src/config/signing.rs +++ b/bolt-sidecar/src/config/signing.rs @@ -1,20 +1,23 @@ +use std::fmt; + use clap::{ArgGroup, Args}; +use lighthouse_account_utils::ZeroizeString; /// Command-line options for signing -#[derive(Debug, Clone, Args)] +#[derive(Clone, Args)] #[clap( group = ArgGroup::new("signing-opts").required(true) .args(&["private_key", "commit_boost_url", "commit_boost_jwt_hex"]) )] pub struct SigningOpts { /// Private key to use for signing preconfirmation requests - #[clap(long, env = "BOLT_SIDECAR_PRIVATE_KEY", conflicts_with("commit_boost_url"))] + #[clap(long, env = "BOLT_SIDECAR_PRIVATE_KEY", group = "signing-opts")] pub(super) private_key: Option, /// URL for the commit-boost sidecar #[clap( long, env = "BOLT_SIDECAR_CB_SIGNER_URL", - conflicts_with("private_key"), + group = "signing-opts", requires("commit_boost_jwt_hex") )] pub(super) commit_boost_url: Option, @@ -22,8 +25,24 @@ pub struct SigningOpts { #[clap( long, env = "BOLT_SIDECAR_CB_JWT_HEX", - conflicts_with("private_key"), + group = "signing-opts", requires("commit_boost_url") )] pub(super) commit_boost_jwt_hex: Option, + /// The password for the ERC-2335 keystore. + /// Reference: https://eips.ethereum.org/EIPS/eip-2335 + #[clap(long, env = "BOLT_SIDECAR_KEYSTORE_PASSWORD", group = "signing-opts")] + pub(super) keystore_password: Option, +} + +// Implement Debug manually to hide the keystore_password field +impl fmt::Debug for SigningOpts { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SigningOpts") + .field("private_key", &self.private_key) + .field("commit_boost_url", &self.commit_boost_url) + .field("commit_boost_jwt_hex", &self.commit_boost_jwt_hex) + .field("keystore_password", &"********") // Hides the actual password + .finish() + } } From c6f4535248105190f55327281d7f1c4600052efe Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Wed, 9 Oct 2024 10:08:59 +0200 Subject: [PATCH 24/64] chore(sidecar): readme in keys folder --- bolt-sidecar/keys/.gitignore | 1 + bolt-sidecar/keys/README.md | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 bolt-sidecar/keys/README.md diff --git a/bolt-sidecar/keys/.gitignore b/bolt-sidecar/keys/.gitignore index d6b7ef32c..7c9d611b5 100644 --- a/bolt-sidecar/keys/.gitignore +++ b/bolt-sidecar/keys/.gitignore @@ -1,2 +1,3 @@ * !.gitignore +!README.md diff --git a/bolt-sidecar/keys/README.md b/bolt-sidecar/keys/README.md new file mode 100644 index 000000000..86e131a4f --- /dev/null +++ b/bolt-sidecar/keys/README.md @@ -0,0 +1,6 @@ +### About + +This directory is intended to be used as the folder to place ERC-2335 keystores. + +It is assumed that the keystore files are placed in a directory named after the +public key, and such file is called `voting_keystore.json`. From 5421b48eaae53ea3e3f9de3b2084bfe718c02e5d Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Thu, 10 Oct 2024 11:50:07 +0200 Subject: [PATCH 25/64] chore(sidecar): keys folder readme --- bolt-sidecar/keys/README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bolt-sidecar/keys/README.md b/bolt-sidecar/keys/README.md index 86e131a4f..1a539d703 100644 --- a/bolt-sidecar/keys/README.md +++ b/bolt-sidecar/keys/README.md @@ -1,6 +1,7 @@ ### About -This directory is intended to be used as the folder to place ERC-2335 keystores. +This directory is intended to be used as the folder to place ERC-2335 keystores +files. -It is assumed that the keystore files are placed in a directory named after the -public key, and such file is called `voting_keystore.json`. +It is assumed that each keystore file has a `.json` extension and is is placed +in a directory named after the public key it corresponds to. From b84280080a035904df17508e529b9f1093ad4b70 Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Wed, 9 Oct 2024 16:22:40 +0200 Subject: [PATCH 26/64] feat(sidecar): keystore signer stub --- bolt-sidecar/src/signer/keystore.rs | 77 +++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 bolt-sidecar/src/signer/keystore.rs diff --git a/bolt-sidecar/src/signer/keystore.rs b/bolt-sidecar/src/signer/keystore.rs new file mode 100644 index 000000000..456133bd9 --- /dev/null +++ b/bolt-sidecar/src/signer/keystore.rs @@ -0,0 +1,77 @@ +//! An ERC-2335 keystore signer. + +use std::{ + ffi::OsString, + fs, + path::{Path, PathBuf}, +}; + +use ethereum_consensus::crypto::PublicKey as CLPublicKey; + +use blst::min_pk::{PublicKey, SecretKey}; +use eyre::eyre; + +use lighthouse_bls::Keypair; +use lighthouse_eth2_keystore::Keystore; + +use crate::{config::signing::BlsSecretKey, crypto::SignerBLS}; + +pub struct KeystoreSigner { + keypairs: Vec, +} + +impl KeystoreSigner { + fn new(keys_path: Option<&str>, password: &[u8]) -> eyre::Result { + let keystores_paths = keystore_paths(keys_path)?; + let mut keypairs = Vec::with_capacity(keystores_paths.len()); + + for path in keystores_paths { + let keypair = Keystore::from_json_file(path.clone()) + .map_err(|e| { + eyre!(format!("err while reading keystore json file {:?}: {:?}", path, e)) + })? + .decrypt_keypair(password) + .map_err(|e| { + eyre!(format!( + "err while decrypting keypair from json file {:?}: {:?}", + path, e + )) + })?; + keypairs.push(keypair); + } + + Ok(Self { keypairs }) + } +} + +/// Returns the paths of all the keystore files provided an optional `keys_path`, which defaults to `keys`. +/// `keys_path` is a relative path from the root of this cargo project +/// We're expecting a directory structure like: +/// ${keys_path}/ +/// -- 0x1234.../validator.json +/// -- 0x5678.../validator.json +/// -- ... +/// +fn keystore_paths(keys_path: Option<&str>) -> Result, eyre::Error> { + // Create the path to the keystore directory, starting from the root of the project + let project_root = env!("CARGO_MANIFEST_DIR"); + let keys_path = Path::new(project_root).join(keys_path.unwrap_or("keys")); + + let json_extension = OsString::from("json"); + + let mut keystores_paths = vec![]; + // Iter over the `keys` directory + for entry in fs::read_dir(keys_path)? { + let path = entry?.path(); + if path.is_dir() { + for entry in fs::read_dir(path)? { + let path = entry?.path(); + if path.is_file() && path.extension() == Some(&json_extension) { + keystores_paths.push(path); + } + } + } + } + + Ok(keystores_paths) +} From d71dfe177c57c1e24a3c6672f8519baa15d9e082 Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Wed, 9 Oct 2024 13:26:04 +0200 Subject: [PATCH 27/64] refactor(sidecar): config struct --- bolt-sidecar/bin/sidecar.rs | 19 +- bolt-sidecar/src/builder/mod.rs | 14 +- bolt-sidecar/src/builder/payload_builder.rs | 10 +- bolt-sidecar/src/config/limits.rs | 36 ++ bolt-sidecar/src/config/mod.rs | 419 +++++++++---------- bolt-sidecar/src/config/signing.rs | 64 ++- bolt-sidecar/src/config/validator_indexes.rs | 6 + bolt-sidecar/src/driver.rs | 47 ++- bolt-sidecar/src/lib.rs | 2 +- bolt-sidecar/src/state/execution.rs | 2 +- bolt-sidecar/src/test_util.rs | 32 +- 11 files changed, 361 insertions(+), 290 deletions(-) create mode 100644 bolt-sidecar/src/config/limits.rs diff --git a/bolt-sidecar/bin/sidecar.rs b/bolt-sidecar/bin/sidecar.rs index 3082f3a6c..ab63b2ee5 100644 --- a/bolt-sidecar/bin/sidecar.rs +++ b/bolt-sidecar/bin/sidecar.rs @@ -1,28 +1,27 @@ -use bolt_sidecar::{telemetry::init_telemetry_stack, Config, SidecarDriver}; +use bolt_sidecar::{telemetry::init_telemetry_stack, Opts, SidecarDriver}; +use clap::Parser; use eyre::{bail, Result}; use tracing::info; #[tokio::main] async fn main() -> Result<()> { - let config = match Config::parse_from_cli() { - Ok(config) => config, - Err(err) => bail!("Failed to parse CLI arguments: {:?}", err), - }; + let opts = Opts::parse(); - let metrics_port = if !config.disable_metrics { Some(config.metrics_port) } else { None }; + let metrics_port = + if !opts.telemetry.disable_metrics { Some(opts.telemetry.metrics_port) } else { None }; if let Err(err) = init_telemetry_stack(metrics_port) { bail!("Failed to initialize telemetry stack: {:?}", err) } - info!(chain = config.chain.name(), "Starting Bolt sidecar"); + info!(chain = opts.chain.name(), "Starting Bolt sidecar"); - if config.private_key.is_some() { - match SidecarDriver::with_local_signer(config).await { + if opts.signing.private_key.is_some() { + match SidecarDriver::with_local_signer(&opts).await { Ok(driver) => driver.run_forever().await, Err(err) => bail!("Failed to initialize the sidecar driver: {:?}", err), } } else { - match SidecarDriver::with_commit_boost_signer(config).await { + match SidecarDriver::with_commit_boost_signer(&opts).await { Ok(driver) => driver.run_forever().await, Err(err) => { bail!("Failed to initialize the sidecar driver with commit boost: {:?}", err) diff --git a/bolt-sidecar/src/builder/mod.rs b/bolt-sidecar/src/builder/mod.rs index 88f59b3d3..7c75f22a0 100644 --- a/bolt-sidecar/src/builder/mod.rs +++ b/bolt-sidecar/src/builder/mod.rs @@ -1,6 +1,5 @@ use alloy::primitives::U256; use beacon_api_client::mainnet::Client as BeaconClient; -use blst::min_pk::SecretKey; use ethereum_consensus::{ crypto::{KzgCommitment, PublicKey}, deneb::mainnet::ExecutionPayloadHeader, @@ -10,10 +9,11 @@ use payload_builder::FallbackPayloadBuilder; use signature::sign_builder_message; use crate::{ + config::signing::BlsSecretKey, primitives::{ BuilderBid, GetPayloadResponse, PayloadAndBid, PayloadAndBlobs, SignedBuilderBid, }, - ChainConfig, Config, + ChainConfig, Opts, }; /// Basic block template handler that can keep track of @@ -65,7 +65,7 @@ pub enum BuilderError { pub struct LocalBuilder { /// BLS credentials for the local builder. We use this to sign the /// payload bid submissions built by the sidecar. - secret_key: SecretKey, + secret_key: BlsSecretKey, /// Chain configuration /// (necessary for signing messages with the correct domain) chain: ChainConfig, @@ -78,12 +78,12 @@ pub struct LocalBuilder { impl LocalBuilder { /// Create a new local builder with the given secret key. - pub fn new(config: &Config, beacon_api_client: BeaconClient, genesis_time: u64) -> Self { + pub fn new(opts: &Opts, beacon_api_client: BeaconClient, genesis_time: u64) -> Self { Self { payload_and_bid: None, - fallback_builder: FallbackPayloadBuilder::new(config, beacon_api_client, genesis_time), - secret_key: config.builder_private_key.clone(), - chain: config.chain, + fallback_builder: FallbackPayloadBuilder::new(opts, beacon_api_client, genesis_time), + secret_key: opts.builder_private_key.clone(), + chain: opts.chain, } } diff --git a/bolt-sidecar/src/builder/payload_builder.rs b/bolt-sidecar/src/builder/payload_builder.rs index 72dede40f..fbfb5d2d7 100644 --- a/bolt-sidecar/src/builder/payload_builder.rs +++ b/bolt-sidecar/src/builder/payload_builder.rs @@ -21,7 +21,7 @@ use super::{ compat::{to_alloy_execution_payload, to_reth_withdrawal}, BuilderError, }; -use crate::{BeaconClient, Config, RpcClient}; +use crate::{BeaconClient, Opts, RpcClient}; /// Extra-data payload field used for locally built blocks, decoded in UTF-8. /// @@ -54,7 +54,7 @@ pub struct FallbackPayloadBuilder { impl FallbackPayloadBuilder { /// Create a new fallback payload builder - pub fn new(config: &Config, beacon_api_client: BeaconClient, genesis_time: u64) -> Self { + pub fn new(config: &Opts, beacon_api_client: BeaconClient, genesis_time: u64) -> Self { let engine_hinter = EngineHinter { client: reqwest::Client::new(), jwt_hex: config.jwt_hex.to_string(), @@ -454,9 +454,9 @@ mod tests { let raw_encoded = tx_signed.encoded_2718(); let tx_signed_reth = TransactionSigned::decode_enveloped(&mut raw_encoded.as_slice())?; - let slot = genesis_time + - (SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs() / cfg.chain.slot_time()) + - 1; + let slot = genesis_time + + (SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs() / cfg.chain.slot_time()) + + 1; let block = builder.build_fallback_payload(slot, &[tx_signed_reth]).await?; assert_eq!(block.body.len(), 1); diff --git a/bolt-sidecar/src/config/limits.rs b/bolt-sidecar/src/config/limits.rs new file mode 100644 index 000000000..7424672eb --- /dev/null +++ b/bolt-sidecar/src/config/limits.rs @@ -0,0 +1,36 @@ +use clap::Parser; +use std::num::NonZero; + +// Default limit values +pub const DEFAULT_MAX_COMMITMENTS: usize = 128; +pub const DEFAULT_MAX_COMMITTED_GAS: u64 = 10_000_000; +pub const DEFAULT_MIN_PRIORITY_FEE: u128 = 1_000_000_000; // 1 Gwei + +/// Limits for the sidecar. +#[derive(Debug, Parser, Clone)] +pub struct LimitsOpts { + /// Max number of commitments to accept per block + #[clap(long, env = "BOLT_SIDECAR_MAX_COMMITMENTS", + default_value_t = LimitsOpts::default().max_commitments_per_slot)] + pub max_commitments_per_slot: NonZero, + /// Max committed gas per slot + #[clap(long, env = "BOLT_SIDECAR_MAX_COMMITTED_GAS", + default_value_t = LimitsOpts::default().max_committed_gas_per_slot)] + pub max_committed_gas_per_slot: NonZero, + /// Min priority fee to accept for a commitment + #[clap(long, env = "BOLT_SIDECAR_MIN_PRIORITY_FEE", + default_value_t = LimitsOpts::default().min_priority_fee)] + pub min_priority_fee: NonZero, +} + +impl Default for LimitsOpts { + fn default() -> Self { + Self { + max_commitments_per_slot: NonZero::new(DEFAULT_MAX_COMMITMENTS) + .expect("Valid non-zero"), + max_committed_gas_per_slot: NonZero::new(DEFAULT_MAX_COMMITTED_GAS) + .expect("Valid non-zero"), + min_priority_fee: NonZero::new(DEFAULT_MIN_PRIORITY_FEE).expect("Valid non-zero"), + } + } +} diff --git a/bolt-sidecar/src/config/mod.rs b/bolt-sidecar/src/config/mod.rs index 99e6cb187..3dac1c5e4 100644 --- a/bolt-sidecar/src/config/mod.rs +++ b/bolt-sidecar/src/config/mod.rs @@ -1,14 +1,9 @@ -use std::{fs::read_to_string, path::Path, str::FromStr}; +use std::str::FromStr; use alloy::primitives::Address; -use blst::min_pk::SecretKey; use clap::Parser; -use eyre::{bail, eyre, Report, Result}; use reqwest::Url; -use std::num::NonZero; -use tracing::info; - -use crate::crypto::bls::random_bls_secret; +use signing::BlsSecretKey; pub mod validator_indexes; pub use validator_indexes::ValidatorIndexes; @@ -22,256 +17,236 @@ pub use signing::SigningOpts; pub mod telemetry; use telemetry::TelemetryOpts; +pub mod limits; +use limits::LimitsOpts; + /// Default port for the JSON-RPC server exposed by the sidecar. pub const DEFAULT_RPC_PORT: u16 = 8000; /// Default port for the Constraints proxy server. pub const DEFAULT_CONSTRAINTS_PROXY_PORT: u16 = 18551; -// Default limit values -pub const DEFAULT_MAX_COMMITMENTS: usize = 128; -pub const DEFAULT_MAX_COMMITTED_GAS: u64 = 10_000_000; -pub const DEFAULT_MIN_PRIORITY_FEE: u128 = 1_000_000_000; // 1 Gwei - /// Command-line options for the Bolt sidecar #[derive(Debug, Parser)] pub struct Opts { /// Port to listen on for incoming JSON-RPC requests - #[clap(long, env = "BOLT_SIDECAR_PORT")] - pub(super) port: Option, + #[clap(long, env = "BOLT_SIDECAR_PORT", + default_value_t = DEFAULT_RPC_PORT)] + pub port: u16, /// URL for the beacon client - #[clap(long, env = "BOLT_SIDECAR_BEACON_API_URL")] - pub(super) beacon_api_url: String, + #[clap(long, env = "BOLT_SIDECAR_BEACON_API_URL", + default_value_t = Url::parse("http://localhost:5052").expect("Valid Beacon API URL"))] + pub beacon_api_url: Url, /// URL for the Constraint sidecar client to use - #[clap(long, env = "BOLT_SIDECAR_CONSTRAINTS_URL")] - pub(super) constraints_url: String, + #[clap(long, env = "BOLT_SIDECAR_CONSTRAINTS_URL", + default_value_t = Url::parse("http://localhost:3030").expect("Valid URL"))] + pub constraints_url: Url, /// Execution client API URL - #[clap(long, env = "BOLT_SIDECAR_EXECUTION_API_URL")] - pub(super) execution_api_url: String, + #[clap(long, env = "BOLT_SIDECAR_EXECUTION_API_URL", + default_value_t = Url::parse("http://localhost:8545").expect("Valid Execution API URL"))] + pub execution_api_url: Url, /// Execution client Engine API URL - #[clap(long, env = "BOLT_SIDECAR_ENGINE_API_URL")] - pub(super) engine_api_url: String, + #[clap(long, env = "BOLT_SIDECAR_ENGINE_API_URL", + default_value_t = Url::parse("http://localhost:8551").expect("Valid Engine API URL"))] + pub engine_api_url: Url, /// 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 - #[clap(long, env = "BOLT_SIDECAR_MAX_COMMITMENTS")] - pub(super) max_commitments: Option>, - /// Max committed gas per slot - #[clap(long, env = "BOLT_SIDECAR_MAX_COMMITTED_GAS")] - pub(super) max_committed_gas: Option>, - /// Min priority fee to accept for a commitment - #[clap(long, env = "BOLT_SIDECAR_MIN_PRIORITY_FEE")] - pub(super) min_priority_fee: Option>, + #[clap(long, env = "BOLT_SIDECAR_CONSTRAINTS_PROXY_PORT", + default_value_t = DEFAULT_CONSTRAINTS_PROXY_PORT)] + pub constraints_proxy_port: u16, /// Validator indexes of connected validators that the sidecar /// should accept commitments on behalf of. Accepted values: /// - a comma-separated list of indexes (e.g. "1,2,3,4") /// - a contiguous range of indexes (e.g. "1..4") /// - a mix of the above (e.g. "1,2..4,6..8") - #[clap(long, value_parser = ValidatorIndexes::from_str, env = "BOLT_SIDECAR_VALIDATOR_INDEXES")] - pub(super) validator_indexes: ValidatorIndexes, + #[clap(long, value_parser = ValidatorIndexes::from_str, env = "BOLT_SIDECAR_VALIDATOR_INDEXES", + default_value_t = ValidatorIndexes::default())] + pub validator_indexes: ValidatorIndexes, /// The JWT secret token to authenticate calls to the engine API. /// /// It can either be a hex-encoded string or a file path to a file /// containing the hex-encoded secret. - #[clap(long, env = "BOLT_SIDECAR_JWT_HEX")] - pub(super) jwt_hex: String, + /// TODO: validate this by using a Jwt struct + #[clap(long, env = "BOLT_SIDECAR_JWT_HEX", + default_value_t = String::new())] + pub jwt_hex: String, /// The fee recipient address for fallback blocks - #[clap(long, env = "BOLT_SIDECAR_FEE_RECIPIENT")] - pub(super) fee_recipient: Address, + #[clap(long, env = "BOLT_SIDECAR_FEE_RECIPIENT", + default_value_t = Address::ZERO)] + pub fee_recipient: Address, /// Secret BLS key to sign fallback payloads with /// (If not provided, a random key will be used) - #[clap(long, env = "BOLT_SIDECAR_BUILDER_PRIVATE_KEY")] - pub(super) builder_private_key: Option, + #[clap(long, env = "BOLT_SIDECAR_BUILDER_PRIVATE_KEY", + default_value_t = BlsSecretKey::random_bls_secret())] + pub builder_private_key: BlsSecretKey, + /// Operating limits for the sidecar + #[clap(flatten)] + pub limits: LimitsOpts, /// Chain config for the chain on which the sidecar is running #[clap(flatten)] - pub(super) chain: ChainConfig, + pub chain: ChainConfig, /// Commitment signing options. #[clap(flatten)] - pub(super) signing: SigningOpts, + pub signing: SigningOpts, /// Telemetry options #[clap(flatten)] - pub(super) telemetry: TelemetryOpts, + pub telemetry: TelemetryOpts, } -/// Configuration options for the sidecar. These are parsed from -/// command-line options in the form of [`Opts`]. -#[derive(Debug, Clone)] -pub struct Config { - /// Port to listen on for incoming JSON-RPC requests - pub rpc_port: u16, - /// 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 - pub execution_api_url: Url, - /// The engine API url - pub engine_api_url: Url, - /// URL for the commit-boost sidecar - pub commit_boost_url: Option, - /// The JWT secret token to authenticate calls to the commit-boost - pub commit_boost_jwt_hex: Option, - /// Private key to use for signing preconfirmation requests - pub private_key: Option, - /// The jwt.hex secret to authenticate calls to the engine API - pub jwt_hex: String, - /// The fee recipient address for fallback blocks - pub fee_recipient: Address, - /// Operating limits for the sidecar - pub limits: Limits, - /// Validator indexes of connected validators that the - /// sidecar should accept commitments on behalf of - pub validator_indexes: ValidatorIndexes, - /// Local bulider private key for signing fallback payloads. - /// If not provided, a random key will be used. - pub builder_private_key: SecretKey, - /// The chain on which the sidecar is running - pub chain: ChainConfig, - /// Metrics port - pub metrics_port: u16, - /// Toggle for metrics - pub disable_metrics: bool, -} - -impl Default for Config { - fn default() -> Self { - Self { - rpc_port: DEFAULT_RPC_PORT, - constraints_proxy_port: DEFAULT_CONSTRAINTS_PROXY_PORT, - commit_boost_url: None, - commit_boost_jwt_hex: None, - 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"), - private_key: Some(random_bls_secret()), - jwt_hex: String::new(), - fee_recipient: Address::ZERO, - builder_private_key: random_bls_secret(), - limits: Limits::default(), - validator_indexes: ValidatorIndexes::default(), - chain: ChainConfig::default(), - metrics_port: 0, - disable_metrics: false, - } - } -} - -/// Limits for the sidecar. -#[derive(Debug, Clone, Copy)] -pub struct Limits { - /// Maximum number of commitments to accept per block - pub max_commitments_per_slot: NonZero, - pub max_committed_gas_per_slot: NonZero, - - /// Minimum priority fee to accept for a commitment in wei - pub min_priority_fee: NonZero, -} - -impl Default for Limits { - fn default() -> Self { - Self { - max_commitments_per_slot: NonZero::new(DEFAULT_MAX_COMMITMENTS) - .expect("Valid non-zero"), - max_committed_gas_per_slot: NonZero::new(DEFAULT_MAX_COMMITTED_GAS) - .expect("Valid non-zero"), - min_priority_fee: NonZero::new(DEFAULT_MIN_PRIORITY_FEE).expect("Valid non-zero"), - } - } -} - -impl Config { - /// Parse the command-line options and return a new [`Config`] instance - pub fn parse_from_cli() -> Result { - let opts = Opts::parse(); - Self::try_from(opts) - } -} - -impl TryFrom for Config { - type Error = Report; - - fn try_from(opts: Opts) -> Result { - let mut config = Config::default(); - - if let Some(port) = opts.port { - config.rpc_port = port; - } - - if let Some(max_commitments) = opts.max_commitments { - config.limits.max_commitments_per_slot = max_commitments; - } - - if let Some(max_committed_gas) = opts.max_committed_gas { - config.limits.max_committed_gas_per_slot = max_committed_gas; - } - - if let Some(min_priority_fee) = opts.min_priority_fee { - config.limits.min_priority_fee = min_priority_fee; - } - - 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_url = Some(socket_addrs[0].to_string()); - } - } - } - - config.private_key = if let Some(sk) = opts.signing.private_key { - let hex_sk = sk.strip_prefix("0x").unwrap_or(&sk); - let sk = SecretKey::from_bytes(&hex::decode(hex_sk)?) - .map_err(|e| eyre!("Failed decoding BLS signer secret key: {:?}", e))?; - Some(sk) - } else { - None - }; - - if let Some(builder_sk) = opts.builder_private_key { - let hex_sk = builder_sk.strip_prefix("0x").unwrap_or(&builder_sk); - let sk = SecretKey::from_bytes(&hex::decode(hex_sk)?) - .map_err(|e| eyre!("Failed decoding BLS builder secret key: {:?}", e))?; - config.builder_private_key = sk; - } - - config.jwt_hex = if opts.jwt_hex.starts_with("0x") { - opts.jwt_hex.trim_start_matches("0x").to_string() - } else if Path::new(&opts.jwt_hex).exists() { - read_to_string(opts.jwt_hex) - .map_err(|e| eyre!("Failed reading JWT secret file: {:?}", e))? - .trim_start_matches("0x") - .to_string() - } else { - opts.jwt_hex - }; - - // Validate the JWT secret - if config.jwt_hex.len() != 64 { - bail!("Engine JWT secret must be a 32 byte hex string"); - } else { - info!("Engine JWT secret loaded successfully"); - } - - 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.constraints_url = opts.constraints_url.parse()?; - - config.fee_recipient = opts.fee_recipient; - - config.validator_indexes = opts.validator_indexes; - - config.chain = opts.chain; - config.metrics_port = opts.telemetry.metrics_port; - config.disable_metrics = opts.telemetry.disable_metrics; - - Ok(config) - } -} +/// /// Configuration options for the sidecar. These are parsed from +/// /// command-line options in the form of [`Opts`]. +/// #[derive(Debug, Clone)] +/// pub struct Config { +/// /// Port to listen on for incoming JSON-RPC requests +/// pub rpc_port: u16, +/// /// 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 +/// pub execution_api_url: Url, +/// /// The engine API url +/// pub engine_api_url: Url, +/// /// URL for the commit-boost sidecar +/// pub commit_boost_url: Option, +/// /// The JWT secret token to authenticate calls to the commit-boost +/// pub commit_boost_jwt_hex: Option, +/// /// Private key to use for signing preconfirmation requests +/// pub private_key: Option, +/// /// The jwt.hex secret to authenticate calls to the engine API +/// pub jwt_hex: String, +/// /// The fee recipient address for fallback blocks +/// pub fee_recipient: Address, +/// /// Operating limits for the sidecar +/// pub limits: Limits, +/// /// Validator indexes of connected validators that the +/// /// sidecar should accept commitments on behalf of +/// pub validator_indexes: ValidatorIndexes, +/// /// Local bulider private key for signing fallback payloads. +/// /// If not provided, a random key will be used. +/// pub builder_private_key: SecretKey, +/// /// The chain on which the sidecar is running +/// pub chain: ChainConfig, +/// /// Metrics port +/// pub metrics_port: u16, +/// /// Toggle for metrics +/// pub disable_metrics: bool, +/// } +/// +/// impl Default for Config { +/// fn default() -> Self { +/// Self { +/// rpc_port: DEFAULT_RPC_PORT, +/// constraints_proxy_port: DEFAULT_CONSTRAINTS_PROXY_PORT, +/// commit_boost_url: None, +/// commit_boost_jwt_hex: None, +/// 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"), +/// private_key: Some(random_bls_secret()), +/// jwt_hex: String::new(), +/// fee_recipient: Address::ZERO, +/// builder_private_key: random_bls_secret(), +/// limits: Limits::default(), +/// validator_indexes: ValidatorIndexes::default(), +/// chain: ChainConfig::default(), +/// metrics_port: 0, +/// disable_metrics: false, +/// } +/// } +/// } + +// impl Config { +// /// Parse the command-line options and return a new [`Config`] instance +// pub fn parse_from_cli() -> Result { +// let opts = Opts::parse(); +// Self::try_from(opts) +// } +// } +// +// impl Opts { +// type Error = Report; +// +// fn validate(&self) -> Result { +// let mut config = Config::default(); +// +// if let Some(port) = opts.port { +// config.rpc_port = port; +// } +// +// if let Some(max_commitments) = opts.max_commitments { +// config.limits.max_commitments_per_slot = max_commitments; +// } +// +// if let Some(max_committed_gas) = opts.max_committed_gas { +// config.limits.max_committed_gas_per_slot = max_committed_gas; +// } +// +// if let Some(min_priority_fee) = opts.min_priority_fee { +// config.limits.min_priority_fee = min_priority_fee; +// } +// +// 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_url = Some(socket_addrs[0].to_string()); +// } +// } +// } +// +// if let Some(sk) = self.signing.private_key { +// let hex_sk = sk.strip_prefix("0x").unwrap_or(&sk); +// let sk = SecretKey::from_bytes(&hex::decode(hex_sk)?) +// .map_err(|e| eyre!("Failed decoding BLS signer secret key: {:?}", e))?; +// Some(sk) +// } else { +// None +// }; +// +// if let Some(builder_sk) = opts.builder_private_key { +// let hex_sk = builder_sk.strip_prefix("0x").unwrap_or(&builder_sk); +// let sk = SecretKey::from_bytes(&hex::decode(hex_sk)?) +// .map_err(|e| eyre!("Failed decoding BLS builder secret key: {:?}", e))?; +// config.builder_private_key = sk; +// } +// +// config.jwt_hex = if opts.jwt_hex.starts_with("0x") { +// opts.jwt_hex.trim_start_matches("0x").to_string() +// } else if Path::new(&opts.jwt_hex).exists() { +// read_to_string(opts.jwt_hex) +// .map_err(|e| eyre!("Failed reading JWT secret file: {:?}", e))? +// .trim_start_matches("0x") +// .to_string() +// } else { +// opts.jwt_hex +// }; +// +// // Validate the JWT secret +// if config.jwt_hex.len() != 64 { +// bail!("Engine JWT secret must be a 32 byte hex string"); +// } else { +// info!("Engine JWT secret loaded successfully"); +// } +// +// 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.constraints_url = opts.constraints_url.parse()?; +// +// config.fee_recipient = opts.fee_recipient; +// +// config.validator_indexes = opts.validator_indexes; +// +// config.chain = opts.chain; +// config.metrics_port = opts.telemetry.metrics_port; +// config.disable_metrics = opts.telemetry.disable_metrics; +// +// Ok(config) +// } +// } #[cfg(test)] mod tests { diff --git a/bolt-sidecar/src/config/signing.rs b/bolt-sidecar/src/config/signing.rs index 81c402a41..810dc9fa7 100644 --- a/bolt-sidecar/src/config/signing.rs +++ b/bolt-sidecar/src/config/signing.rs @@ -1,26 +1,28 @@ -use std::fmt; +use std::{fmt, net::SocketAddr, ops::Deref}; +use blst::min_pk::SecretKey; use clap::{ArgGroup, Args}; use lighthouse_account_utils::ZeroizeString; +use rand::RngCore; /// Command-line options for signing -#[derive(Clone, Args)] +#[derive(Args)] #[clap( group = ArgGroup::new("signing-opts").required(true) - .args(&["private_key", "commit_boost_url", "commit_boost_jwt_hex"]) + .args(&["private_key", "commit_boost_url", "commit_boost_jwt_hex", "keystore_password"]) )] pub struct SigningOpts { /// Private key to use for signing preconfirmation requests #[clap(long, env = "BOLT_SIDECAR_PRIVATE_KEY", group = "signing-opts")] - pub(super) private_key: Option, - /// URL for the commit-boost sidecar + pub private_key: Option, + /// Socket address for the commit-boost sidecar #[clap( long, env = "BOLT_SIDECAR_CB_SIGNER_URL", group = "signing-opts", requires("commit_boost_jwt_hex") )] - pub(super) commit_boost_url: Option, + pub commit_boost_address: Option, /// JWT in hexadecimal format for authenticating with the commit-boost service #[clap( long, @@ -28,11 +30,11 @@ pub struct SigningOpts { group = "signing-opts", requires("commit_boost_url") )] - pub(super) commit_boost_jwt_hex: Option, + pub commit_boost_jwt_hex: Option, /// The password for the ERC-2335 keystore. /// Reference: https://eips.ethereum.org/EIPS/eip-2335 #[clap(long, env = "BOLT_SIDECAR_KEYSTORE_PASSWORD", group = "signing-opts")] - pub(super) keystore_password: Option, + pub keystore_password: Option, } // Implement Debug manually to hide the keystore_password field @@ -40,9 +42,53 @@ impl fmt::Debug for SigningOpts { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SigningOpts") .field("private_key", &self.private_key) - .field("commit_boost_url", &self.commit_boost_url) + .field("commit_boost_url", &self.commit_boost_address) .field("commit_boost_jwt_hex", &self.commit_boost_jwt_hex) .field("keystore_password", &"********") // Hides the actual password .finish() } } + +impl Default for SigningOpts { + fn default() -> Self { + Self { + private_key: Some(BlsSecretKey::random_bls_secret()), + commit_boost_address: None, + commit_boost_jwt_hex: None, + keystore_password: None, + } + } +} + +#[derive(Clone, Debug)] +pub struct BlsSecretKey(pub SecretKey); + +impl BlsSecretKey { + pub fn random_bls_secret() -> Self { + let mut rng = rand::thread_rng(); + let mut ikm = [0u8; 32]; + rng.fill_bytes(&mut ikm); + Self(SecretKey::key_gen(&ikm, &[]).unwrap()) + } +} + +impl From<&str> for BlsSecretKey { + fn from(sk: &str) -> Self { + let hex_sk = sk.strip_prefix("0x").unwrap_or(sk); + let sk = SecretKey::from_bytes(&hex::decode(hex_sk).expect("valid hex")).expect("valid sk"); + BlsSecretKey(sk) + } +} + +impl Deref for BlsSecretKey { + type Target = SecretKey; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl fmt::Display for BlsSecretKey { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "0x{}", hex::encode(self.0.to_bytes())) + } +} diff --git a/bolt-sidecar/src/config/validator_indexes.rs b/bolt-sidecar/src/config/validator_indexes.rs index 54321f907..2cfa72ac6 100644 --- a/bolt-sidecar/src/config/validator_indexes.rs +++ b/bolt-sidecar/src/config/validator_indexes.rs @@ -51,6 +51,12 @@ impl From> for ValidatorIndexes { } } +impl ToString for ValidatorIndexes { + fn to_string(&self) -> String { + self.0.iter().map(|index| index.to_string()).collect::>().join(",") + } +} + #[cfg(test)] mod tests { #[test] diff --git a/bolt-sidecar/src/driver.rs b/bolt-sidecar/src/driver.rs index 740f617eb..68ad8568d 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, ConstraintsApi, ConstraintsClient, LocalBuilder, + BuilderProxyConfig, CommitBoostSigner, ConstraintsApi, ConstraintsClient, LocalBuilder, Opts, }; /// The driver for the sidecar, responsible for managing the main event loop. @@ -60,31 +60,34 @@ impl fmt::Debug for SidecarDriver { /// Create a new sidecar driver with the given [Config] and private key signer. - pub async fn with_local_signer(cfg: Config) -> eyre::Result { + pub async fn with_local_signer(opts: &Opts) -> eyre::Result { // The default state client simply uses the execution API URL to fetch state updates. - let state_client = StateClient::new(cfg.execution_api_url.clone()); + let state_client = StateClient::new(opts.execution_api_url.clone()); // Constraints are signed with a BLS private key - let constraint_signing_key = cfg.private_key.clone().expect("Private key must be provided"); - let constraint_signer = BlsSigner::new(constraint_signing_key, cfg.chain); + let constraint_signer = + BlsSigner::new(opts.signing.private_key.clone().expect("local signer").0, opts.chain); // Commitment responses are signed with a regular Ethereum wallet private key. // This is now generated randomly because slashing is not yet implemented. let commitment_signer = PrivateKeySigner::random(); - Self::from_components(cfg, constraint_signer, commitment_signer, state_client).await + Self::from_components(opts, constraint_signer, commitment_signer, state_client).await } } impl SidecarDriver { /// Create a new sidecar driver with the given [Config] and commit-boost signer. - pub async fn with_commit_boost_signer(cfg: Config) -> eyre::Result { + pub async fn with_commit_boost_signer(opts: &Opts) -> eyre::Result { // The default state client simply uses the execution API URL to fetch state updates. - let state_client = StateClient::new(cfg.execution_api_url.clone()); + let state_client = StateClient::new(opts.execution_api_url.clone()); let commit_boost_signer = CommitBoostSigner::new( - cfg.commit_boost_url.clone().expect("CommitBoost URL must be provided"), - &cfg.commit_boost_jwt_hex.clone().expect("CommitBoost JWT must be provided"), + opts.signing + .commit_boost_address + .expect("CommitBoost URL must be provided") + .to_string(), + &opts.signing.commit_boost_jwt_hex.clone().expect("CommitBoost JWT must be provided"), ) .await?; @@ -94,40 +97,40 @@ impl SidecarDriver { // Commitment responses are signed with commit-boost signer let commitment_signer = commit_boost_signer.clone(); - Self::from_components(cfg, constraint_signer, commitment_signer, state_client).await + Self::from_components(opts, constraint_signer, commitment_signer, state_client).await } } impl SidecarDriver { /// Create a new sidecar driver with the given components pub async fn from_components( - cfg: Config, + opts: &Opts, constraint_signer: BLS, commitment_signer: ECDSA, fetcher: C, ) -> eyre::Result { - 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?; + let constraints_client = ConstraintsClient::new(opts.constraints_url.clone()); + let beacon_client = BeaconClient::new(opts.beacon_api_url.clone()); + let execution = ExecutionState::new(fetcher, opts.limits.clone()).await?; let genesis_time = beacon_client.get_genesis_details().await?.genesis_time; let slot_stream = - clock::from_system_time(genesis_time, cfg.chain.slot_time(), SLOTS_PER_EPOCH) + clock::from_system_time(genesis_time, opts.chain.slot_time(), SLOTS_PER_EPOCH) .into_stream(); - let local_builder = LocalBuilder::new(&cfg, beacon_client.clone(), genesis_time); + let local_builder = LocalBuilder::new(opts, beacon_client.clone(), genesis_time); let head_tracker = HeadTracker::start(beacon_client.clone()); let consensus = ConsensusState::new( beacon_client, - cfg.validator_indexes.clone(), - cfg.chain.commitment_deadline(), + opts.validator_indexes.clone(), + opts.chain.commitment_deadline(), ); let (payload_requests_tx, payload_requests_rx) = mpsc::channel(16); let builder_proxy_cfg = BuilderProxyConfig { - constraints_url: cfg.constraints_url.clone(), - server_port: cfg.constraints_proxy_port, + constraints_url: opts.constraints_url.clone(), + server_port: opts.constraints_proxy_port, }; // start the builder api proxy server @@ -139,7 +142,7 @@ impl SidecarDriver Option<&'static str> { /// - The default values for the remaining configuration fields. /// /// If any of the above values can't be found, the function will return `None`. -pub(crate) async fn get_test_config() -> Option { +pub(crate) async fn get_test_config() -> Option { let _ = dotenvy::dotenv(); + std::env::set_var("BOLT_SIDECAR_PRIVATE_KEY", BlsSecretKey::random_bls_secret().to_string()); + let mut opts = Opts::parse(); + let Some(jwt) = std::env::var("ENGINE_JWT").ok() else { warn!("ENGINE_JWT not found in environment variables"); return None; }; - let execution = try_get_execution_api_url().await?; - let beacon = try_get_beacon_api_url().await?; - let engine = try_get_engine_api_url().await?; - - Some(Config { - execution_api_url: execution.parse().ok()?, - engine_api_url: engine.parse().ok()?, - beacon_api_url: beacon.parse().ok()?, - jwt_hex: jwt, - ..Default::default() - }) + if let Some(url) = try_get_execution_api_url().await { + opts.execution_api_url = url.parse().expect("valid URL"); + } + if let Some(url) = try_get_beacon_api_url().await { + opts.beacon_api_url = url.parse().expect("valid URL"); + } + if let Some(url) = try_get_engine_api_url().await { + opts.engine_api_url = url.parse().expect("valid URL"); + } + opts.jwt_hex = jwt; + + Some(opts) } /// Launch a local instance of the Anvil test chain. From 44624aee59c2c2fc0a88952a1ac0633047f3780c Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Wed, 9 Oct 2024 16:23:13 +0200 Subject: [PATCH 28/64] chore(sidecar): lighthouse deps revision --- bolt-sidecar/Cargo.lock | 221 ++++++++++------------------------------ bolt-sidecar/Cargo.toml | 15 +-- 2 files changed, 61 insertions(+), 175 deletions(-) diff --git a/bolt-sidecar/Cargo.lock b/bolt-sidecar/Cargo.lock index 62a9ec52b..64b0123ce 100644 --- a/bolt-sidecar/Cargo.lock +++ b/bolt-sidecar/Cargo.lock @@ -5,10 +5,10 @@ version = 3 [[package]] name = "account_utils" version = "0.1.0" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" dependencies = [ "directory", - "eth2_keystore 0.1.0 (git+https://github.com/sigp/lighthouse?rev=32f2e05)", + "eth2_keystore 0.1.0 (git+https://github.com/sigp/lighthouse?rev=a87f19d)", "eth2_wallet", "filesystem", "rand 0.8.5", @@ -1575,24 +1575,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" -[[package]] -name = "bls" -version = "0.2.0" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" -dependencies = [ - "arbitrary", - "blst", - "ethereum-types 0.14.1", - "ethereum_hashing 0.6.0", - "ethereum_serde_utils", - "ethereum_ssz", - "hex", - "rand 0.8.5", - "serde", - "tree_hash 0.6.0", - "zeroize", -] - [[package]] name = "bls" version = "0.2.0" @@ -1654,22 +1636,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "blstrs" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a8a8ed6fefbeef4a8c7b460e4110e12c5e22a5b7cf32621aae6ad650c4dcf29" -dependencies = [ - "blst", - "byte-slice-cast", - "ff 0.13.0", - "group 0.13.0", - "pairing", - "rand_core 0.6.4", - "serde", - "subtle", -] - [[package]] name = "bolt-sidecar" version = "0.2.1-alpha" @@ -1681,6 +1647,7 @@ dependencies = [ "axum", "axum-extra", "beacon-api-client", + "bls 0.2.0 (git+https://github.com/sigp/lighthouse?rev=a87f19d)", "blst", "bytes", "cb-common", @@ -1802,6 +1769,20 @@ dependencies = [ "serde", ] +[[package]] +name = "cached_tree_hash" +version = "0.1.0" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" +dependencies = [ + "ethereum-types 0.14.1", + "ethereum_hashing 0.6.0", + "ethereum_ssz", + "ethereum_ssz_derive", + "smallvec", + "ssz_types 0.6.0", + "tree_hash 0.6.0", +] + [[package]] name = "cb-cli" version = "0.1.0" @@ -2033,7 +2014,7 @@ checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" [[package]] name = "clap_utils" version = "0.1.0" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" dependencies = [ "clap", "dirs", @@ -2120,7 +2101,7 @@ dependencies = [ [[package]] name = "compare_fields" version = "0.2.0" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" dependencies = [ "itertools 0.10.5", ] @@ -2128,7 +2109,7 @@ dependencies = [ [[package]] name = "compare_fields_derive" version = "0.2.0" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" dependencies = [ "quote", "syn 1.0.109", @@ -2217,52 +2198,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crate_crypto_internal_eth_kzg_bls12_381" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8761b04feb6031ffaf93933c955a0c91a2f3ce15dcac6b9586d2487fe55abf0b" -dependencies = [ - "blst", - "blstrs", - "ff 0.13.0", - "group 0.13.0", - "pairing", - "rayon", -] - -[[package]] -name = "crate_crypto_internal_eth_kzg_erasure_codes" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca410dff79524a2babe8a0d9ab5fdce21b16808f8189eb8b6da6159681f8de2" -dependencies = [ - "crate_crypto_internal_eth_kzg_bls12_381", - "crate_crypto_internal_eth_kzg_polynomial", -] - -[[package]] -name = "crate_crypto_internal_eth_kzg_polynomial" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68be1a5f16bc1c09254dec5209e22278d7d395284443576886a5890e7131234f" -dependencies = [ - "crate_crypto_internal_eth_kzg_bls12_381", -] - -[[package]] -name = "crate_crypto_kzg_multi_open_fk20" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fe5b687fe8c5a46851b8bc624ad49603a339dc93c920d4f7e61592c201ee8" -dependencies = [ - "crate_crypto_internal_eth_kzg_bls12_381", - "crate_crypto_internal_eth_kzg_polynomial", - "hex", - "rayon", - "sha2 0.10.8", -] - [[package]] name = "crc" version = "3.2.1" @@ -2554,7 +2489,7 @@ dependencies = [ [[package]] name = "deposit_contract" version = "0.2.0" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" dependencies = [ "ethabi 16.0.0", "ethereum_ssz", @@ -2708,7 +2643,7 @@ dependencies = [ [[package]] name = "directory" version = "0.1.0" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" dependencies = [ "clap", "clap_utils", @@ -3005,7 +2940,7 @@ dependencies = [ [[package]] name = "eth2_config" version = "0.2.0" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" dependencies = [ "paste", "types", @@ -3014,28 +2949,17 @@ dependencies = [ [[package]] name = "eth2_interop_keypairs" version = "0.2.0" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" dependencies = [ - "bls 0.2.0 (git+https://github.com/sigp/lighthouse?rev=32f2e05)", + "bls 0.2.0 (git+https://github.com/sigp/lighthouse?rev=a87f19d)", "ethereum_hashing 0.6.0", "hex", + "lazy_static", "num-bigint", "serde", "serde_yaml 0.9.33", ] -[[package]] -name = "eth2_key_derivation" -version = "0.1.0" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" -dependencies = [ - "bls 0.2.0 (git+https://github.com/sigp/lighthouse?rev=32f2e05)", - "num-bigint-dig", - "ring 0.16.20", - "sha2 0.9.9", - "zeroize", -] - [[package]] name = "eth2_key_derivation" version = "0.1.0" @@ -3060,28 +2984,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "eth2_keystore" -version = "0.1.0" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" -dependencies = [ - "aes 0.7.5", - "bls 0.2.0 (git+https://github.com/sigp/lighthouse?rev=32f2e05)", - "eth2_key_derivation 0.1.0 (git+https://github.com/sigp/lighthouse?rev=32f2e05)", - "hex", - "hmac 0.11.0", - "pbkdf2 0.8.0", - "rand 0.8.5", - "scrypt", - "serde", - "serde_json", - "serde_repr", - "sha2 0.9.9", - "unicode-normalization", - "uuid 0.8.2", - "zeroize", -] - [[package]] name = "eth2_keystore" version = "0.1.0" @@ -3129,7 +3031,7 @@ dependencies = [ [[package]] name = "eth2_network_config" version = "0.2.0" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" dependencies = [ "bytes", "discv5", @@ -3149,10 +3051,10 @@ dependencies = [ [[package]] name = "eth2_wallet" version = "0.1.0" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" dependencies = [ - "eth2_key_derivation 0.1.0 (git+https://github.com/sigp/lighthouse?rev=32f2e05)", - "eth2_keystore 0.1.0 (git+https://github.com/sigp/lighthouse?rev=32f2e05)", + "eth2_key_derivation 0.1.0 (git+https://github.com/sigp/lighthouse?rev=a87f19d)", + "eth2_keystore 0.1.0 (git+https://github.com/sigp/lighthouse?rev=a87f19d)", "rand 0.8.5", "serde", "serde_json", @@ -3456,7 +3358,7 @@ dependencies = [ [[package]] name = "filesystem" version = "0.1.0" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" dependencies = [ "winapi", "windows-acl", @@ -3747,9 +3649,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff 0.13.0", - "rand 0.8.5", "rand_core 0.6.4", - "rand_xorshift", "subtle", ] @@ -4327,7 +4227,7 @@ dependencies = [ [[package]] name = "int_to_bytes" version = "0.2.0" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" dependencies = [ "bytes", ] @@ -4561,7 +4461,7 @@ dependencies = [ [[package]] name = "kzg" version = "0.1.0" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" dependencies = [ "arbitrary", "c-kzg", @@ -4571,7 +4471,6 @@ dependencies = [ "ethereum_ssz", "ethereum_ssz_derive", "hex", - "rust_eth_kzg", "serde", "tree_hash 0.6.0", ] @@ -4841,7 +4740,7 @@ dependencies = [ [[package]] name = "lighthouse_metrics" version = "0.2.0" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" dependencies = [ "prometheus", ] @@ -4871,7 +4770,7 @@ dependencies = [ [[package]] name = "lockfile" version = "0.1.0" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" dependencies = [ "fs2", ] @@ -4885,9 +4784,10 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "logging" version = "0.2.0" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" dependencies = [ "chrono", + "lazy_static", "lighthouse_metrics", "parking_lot 0.12.3", "serde", @@ -4952,10 +4852,11 @@ dependencies = [ [[package]] name = "merkle_proof" version = "0.2.0" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" dependencies = [ "ethereum-types 0.14.1", "ethereum_hashing 0.6.0", + "lazy_static", "safe_arith", ] @@ -5829,7 +5730,7 @@ dependencies = [ [[package]] name = "pretty_reqwest_error" version = "0.1.0" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" dependencies = [ "reqwest 0.11.27", "sensitive_url", @@ -6609,21 +6510,6 @@ dependencies = [ "smallvec", ] -[[package]] -name = "rust_eth_kzg" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "013a850c7e131a8f9651ffbb151dc33240234f21dd357b692bd5ff4cdc84bf9a" -dependencies = [ - "crate_crypto_internal_eth_kzg_bls12_381", - "crate_crypto_internal_eth_kzg_erasure_codes", - "crate_crypto_kzg_multi_open_fk20", - "hex", - "rayon", - "serde", - "serde_json", -] - [[package]] name = "rustc-demangle" version = "0.1.24" @@ -6832,7 +6718,7 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "safe_arith" version = "0.1.0" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" [[package]] name = "salsa20" @@ -7023,7 +6909,7 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "sensitive_url" version = "0.1.0" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" dependencies = [ "serde", "url", @@ -7415,7 +7301,6 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" dependencies = [ - "arbitrary", "serde", ] @@ -7604,9 +7489,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "superstruct" -version = "0.8.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf0f31f730ad9e579364950e10d6172b4a9bd04b447edf5988b066a860cc340e" +checksum = "6f4e1f478a7728f8855d7e620e9a152cf8932c6614f86564c886f9b8141f3201" dependencies = [ "darling 0.13.4", "itertools 0.10.5", @@ -7619,7 +7504,7 @@ dependencies = [ [[package]] name = "swap_or_not_shuffle" version = "0.2.0" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" dependencies = [ "ethereum-types 0.14.1", "ethereum_hashing 0.6.0", @@ -7777,7 +7662,7 @@ dependencies = [ [[package]] name = "test_random_derive" version = "0.2.0" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" dependencies = [ "quote", "syn 1.0.109", @@ -8342,12 +8227,11 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "types" version = "0.2.1" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" dependencies = [ - "alloy-primitives", - "alloy-rlp", "arbitrary", - "bls 0.2.0 (git+https://github.com/sigp/lighthouse?rev=32f2e05)", + "bls 0.2.0 (git+https://github.com/sigp/lighthouse?rev=a87f19d)", + "cached_tree_hash", "compare_fields", "compare_fields_derive", "derivative", @@ -8361,6 +8245,7 @@ dependencies = [ "int_to_bytes", "itertools 0.10.5", "kzg", + "lazy_static", "log", "maplit", "merkle_proof", @@ -8543,13 +8428,13 @@ dependencies = [ [[package]] name = "validator_dir" version = "0.1.0" -source = "git+https://github.com/sigp/lighthouse?rev=32f2e05#32f2e059c5027366ef529bdceb0e3e23ded931f2" +source = "git+https://github.com/sigp/lighthouse?rev=a87f19d#a87f19d801a57b1d6ff101750840294c210ff956" dependencies = [ - "bls 0.2.0 (git+https://github.com/sigp/lighthouse?rev=32f2e05)", + "bls 0.2.0 (git+https://github.com/sigp/lighthouse?rev=a87f19d)", "deposit_contract", "derivative", "directory", - "eth2_keystore 0.1.0 (git+https://github.com/sigp/lighthouse?rev=32f2e05)", + "eth2_keystore 0.1.0 (git+https://github.com/sigp/lighthouse?rev=a87f19d)", "filesystem", "hex", "lockfile", diff --git a/bolt-sidecar/Cargo.toml b/bolt-sidecar/Cargo.toml index 3fc083bc7..6501a3d7f 100644 --- a/bolt-sidecar/Cargo.toml +++ b/bolt-sidecar/Cargo.toml @@ -25,10 +25,10 @@ ethereum_ssz_derive = "0.5" # alloy alloy = { version = "0.2.0", features = [ - "full", - "provider-trace-api", - "rpc-types-beacon", - "rpc-types-engine", + "full", + "provider-trace-api", + "rpc-types-beacon", + "rpc-types-engine", ] } # reth @@ -41,8 +41,9 @@ ethereum-consensus = { git = "https://github.com/ralexstokes/ethereum-consensus" beacon-api-client = { git = "https://github.com/ralexstokes/ethereum-consensus", rev = "cf3c404" } # lighthouse -lighthouse_account_utils = { package = "account_utils", git = "https://github.com/sigp/lighthouse", rev = "32f2e05" } +lighthouse_account_utils = { package = "account_utils", git = "https://github.com/sigp/lighthouse", rev = "a87f19d" } lighthouse_eth2_keystore = { package = "eth2_keystore", git = "https://github.com/sigp/lighthouse", rev = "a87f19d" } +lighthouse_bls = { package = "bls", git = "https://github.com/sigp/lighthouse", rev = "a87f19d" } # types partial-mpt = { git = "https://github.com/chainbound/partial-mpt", branch = "feat/alloy" } @@ -69,11 +70,11 @@ tracing-subscriber = { version = "0.3.18", features = ["env-filter", "fmt"] } # telemetry metrics = "0.23" metrics-exporter-prometheus = { version = "0.15.3", features = [ - "http-listener", + "http-listener", ] } # commit-boost -commit-boost = { git = "https://github.com/Commit-Boost/commit-boost-client", rev = "45ce8f1"} +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] From 53ee181974863d282cfff9e5c40da6756eb8490b Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Wed, 9 Oct 2024 16:23:59 +0200 Subject: [PATCH 29/64] refactor(sidecar): move commit boost signer to signer folder --- bolt-sidecar/src/client/mod.rs | 1 - bolt-sidecar/src/lib.rs | 9 +++++---- bolt-sidecar/src/{client => signer}/commit_boost.rs | 0 bolt-sidecar/src/signer/mod.rs | 8 ++++++++ 4 files changed, 13 insertions(+), 5 deletions(-) rename bolt-sidecar/src/{client => signer}/commit_boost.rs (100%) create mode 100644 bolt-sidecar/src/signer/mod.rs diff --git a/bolt-sidecar/src/client/mod.rs b/bolt-sidecar/src/client/mod.rs index 2235dbe09..c09795fc5 100644 --- a/bolt-sidecar/src/client/mod.rs +++ b/bolt-sidecar/src/client/mod.rs @@ -1,4 +1,3 @@ -pub mod commit_boost; pub mod constraints_client; pub mod pubsub; pub mod rpc; diff --git a/bolt-sidecar/src/lib.rs b/bolt-sidecar/src/lib.rs index 6fe59cffa..1a7f7d17f 100644 --- a/bolt-sidecar/src/lib.rs +++ b/bolt-sidecar/src/lib.rs @@ -12,10 +12,7 @@ pub use api::{ }; mod client; -pub use client::{ - commit_boost::CommitBoostSigner, constraints_client::ConstraintsClient, rpc::RpcClient, - BeaconClient, -}; +pub use client::{constraints_client::ConstraintsClient, rpc::RpcClient, BeaconClient}; /// Telemetry and metrics utilities pub mod telemetry; @@ -47,6 +44,10 @@ pub mod primitives; /// State management and fetching for EVM simulation pub mod state; +/// The signers available to the sidecar +mod signer; +pub use signer::commit_boost::CommitBoostSigner; + /// Utilities for testing #[cfg(test)] mod test_util; diff --git a/bolt-sidecar/src/client/commit_boost.rs b/bolt-sidecar/src/signer/commit_boost.rs similarity index 100% rename from bolt-sidecar/src/client/commit_boost.rs rename to bolt-sidecar/src/signer/commit_boost.rs diff --git a/bolt-sidecar/src/signer/mod.rs b/bolt-sidecar/src/signer/mod.rs new file mode 100644 index 000000000..acff32098 --- /dev/null +++ b/bolt-sidecar/src/signer/mod.rs @@ -0,0 +1,8 @@ +pub mod commit_boost; +pub mod keystore; +pub mod local; + +// pub enum SignerBLSEnum { +// Local(Signer), +// CommitBoost(CommitBoostSigner), +// } From f93425fc5ec1a85300c010f9e51c759b72c2b4d8 Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Wed, 9 Oct 2024 17:53:44 +0200 Subject: [PATCH 30/64] refactor,feat(sidecar): SignerBLS is now Enum, sign with keystore wip keystore update --- bolt-sidecar/src/crypto/bls.rs | 136 +----------------------- bolt-sidecar/src/driver.rs | 71 ++++++++----- bolt-sidecar/src/lib.rs | 2 +- bolt-sidecar/src/signer/commit_boost.rs | 9 +- bolt-sidecar/src/signer/keystore.rs | 28 ++++- bolt-sidecar/src/signer/local.rs | 132 +++++++++++++++++++++++ bolt-sidecar/src/signer/mod.rs | 15 ++- 7 files changed, 221 insertions(+), 172 deletions(-) create mode 100644 bolt-sidecar/src/signer/local.rs diff --git a/bolt-sidecar/src/crypto/bls.rs b/bolt-sidecar/src/crypto/bls.rs index ece368515..90d03fede 100644 --- a/bolt-sidecar/src/crypto/bls.rs +++ b/bolt-sidecar/src/crypto/bls.rs @@ -1,6 +1,6 @@ use std::fmt::Debug; -use alloy::primitives::FixedBytes; +use alloy::{primitives::FixedBytes, rpc::types::beacon::constants::BLS_PUBLIC_KEY_BYTES_LEN}; use blst::{min_pk::Signature, BLST_ERROR}; use ethereum_consensus::{crypto::PublicKey as BlsPublicKey, deneb::compute_signing_root}; use rand::RngCore; @@ -8,7 +8,7 @@ use rand::RngCore; pub use blst::min_pk::{PublicKey, SecretKey as BlsSecretKey}; pub use ethereum_consensus::deneb::BlsSignature; -use crate::ChainConfig; +use crate::{ChainConfig, CommitBoostSigner}; /// The BLS Domain Separator used in Ethereum 2.0. pub const BLS_DST_PREFIX: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"; @@ -35,134 +35,6 @@ pub trait SignerBLS: Send + Debug { async fn sign_commit_boost_root(&self, data: &[u8; 32]) -> eyre::Result; } -/// A BLS signer that can sign any type that implements the [`SignableBLS`] trait. -#[derive(Clone)] -pub struct Signer { - chain: ChainConfig, - key: BlsSecretKey, -} - -impl Debug for Signer { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Signer") - .field("pubkey", &self.pubkey()) - .field("chain", &self.chain.name()) - .finish() - } -} - -impl Signer { - /// Create a new signer with the given BLS secret key. - pub fn new(key: BlsSecretKey, chain: ChainConfig) -> Self { - Self { key, chain } - } - - /// Create a signer with a random BLS key configured for Mainnet for testing. - #[cfg(test)] - pub fn random() -> Self { - Self { key: random_bls_secret(), chain: ChainConfig::mainnet() } - } - - /// Get the public key of the signer. - pub fn pubkey(&self) -> BlsPublicKey { - let pk = self.key.sk_to_pk(); - BlsPublicKey::try_from(pk.to_bytes().as_ref()).unwrap() - } - - /// Sign an SSZ object root with the Application Builder domain. - pub fn sign_application_builder_root(&self, root: [u8; 32]) -> eyre::Result { - self.sign_root(root, self.chain.application_builder_domain()) - } - - /// Sign an SSZ object root with the Commit Boost domain. - pub fn sign_commit_boost_root(&self, root: [u8; 32]) -> eyre::Result { - self.sign_root(root, self.chain.commit_boost_domain()) - } - - /// Sign an SSZ object root with the given domain. - pub fn sign_root(&self, root: [u8; 32], domain: [u8; 32]) -> eyre::Result { - let signing_root = compute_signing_root(&root, domain)?; - let sig = self.key.sign(signing_root.as_slice(), BLS_DST_PREFIX, &[]); - Ok(BLSSig::from_slice(&sig.to_bytes())) - } - - /// Verify the signature with the public key of the signer using the Application Builder domain. - pub fn verify_application_builder_root( - &self, - root: [u8; 32], - signature: &Signature, - ) -> eyre::Result<()> { - self.verify_root(root, signature, self.chain.application_builder_domain()) - } - - /// Verify the signature with the public key of the signer using the Commit Boost domain. - pub fn verify_commit_boost_root( - &self, - root: [u8; 32], - signature: &Signature, - ) -> eyre::Result<()> { - self.verify_root(root, signature, self.chain.commit_boost_domain()) - } - - /// Verify the signature of the object with the given public key. - pub fn verify_root( - &self, - root: [u8; 32], - signature: &Signature, - domain: [u8; 32], - ) -> eyre::Result<()> { - let signing_root = compute_signing_root(&root, domain)?; - let pk = blst::min_pk::PublicKey::from_bytes(self.pubkey().as_ref()).unwrap(); - - let res = signature.verify(true, signing_root.as_ref(), BLS_DST_PREFIX, &[], &pk, true); - if res == BLST_ERROR::BLST_SUCCESS { - Ok(()) - } else { - eyre::bail!(format!("Invalid signature: {:?}", res)) - } - } -} - -#[async_trait::async_trait] -impl SignerBLS for Signer { - fn pubkey(&self) -> BlsPublicKey { - self.pubkey() - } - - async fn sign_commit_boost_root(&self, data: &[u8; 32]) -> eyre::Result { - self.sign_commit_boost_root(*data) - } -} - -/// Generate a random BLS secret key. -pub fn random_bls_secret() -> BlsSecretKey { - let mut rng = rand::thread_rng(); - let mut ikm = [0u8; 32]; - rng.fill_bytes(&mut ikm); - BlsSecretKey::key_gen(&ikm, &[]).unwrap() -} - -#[cfg(test)] -mod tests { - use crate::{ - crypto::bls::{SignableBLS, Signer}, - test_util::TestSignableData, - }; - - use rand::Rng; - - #[tokio::test] - async fn test_bls_signer() { - let signer = Signer::random(); - - // Generate random data for the test - let mut rng = rand::thread_rng(); - let mut data = [0u8; 32]; - rng.fill(&mut data); - let msg = TestSignableData { data }; - - let signature = signer.sign_commit_boost_root(msg.digest()).unwrap(); - let sig = blst::min_pk::Signature::from_bytes(signature.as_ref()).unwrap(); - assert!(signer.verify_commit_boost_root(msg.digest(), &sig).is_ok()); - } +pub fn cl_public_key_to_arr(pubkey: BlsPublicKey) -> [u8; BLS_PUBLIC_KEY_BYTES_LEN] { + pubkey.as_ref().try_into().expect("BLS keys are 48 bytes") } diff --git a/bolt-sidecar/src/driver.rs b/bolt-sidecar/src/driver.rs index 68ad8568d..9fb212520 100644 --- a/bolt-sidecar/src/driver.rs +++ b/bolt-sidecar/src/driver.rs @@ -3,6 +3,7 @@ use std::time::{Duration, Instant}; use alloy::{rpc::types::beacon::events::HeadEvent, signers::local::PrivateKeySigner}; use beacon_api_client::mainnet::Client as BeaconClient; +use cb_common::signer::BlsSigner; use ethereum_consensus::{ clock::{self, SlotStream, SystemTimeProvider}, phase0::mainnet::SLOTS_PER_EPOCH, @@ -16,23 +17,28 @@ use crate::{ server::{CommitmentsApiServer, Event as CommitmentEvent}, spec::Error as CommitmentError, }, - crypto::{bls::Signer as BlsSigner, SignableBLS, SignerBLS, SignerECDSA}, + crypto::{ + bls::{cl_public_key_to_arr, Signer as BlsSigner}, + SignableBLS, SignerBLS, SignerECDSA, + }, primitives::{ CommitmentRequest, ConstraintsMessage, FetchPayloadRequest, LocalPayloadFetcher, SignedConstraints, TransactionExt, }, + signer::local::Signer, start_builder_proxy_server, state::{fetcher::StateFetcher, ConsensusState, ExecutionState, HeadTracker, StateClient}, telemetry::ApiMetrics, BuilderProxyConfig, CommitBoostSigner, ConstraintsApi, ConstraintsClient, LocalBuilder, Opts, + SignerBLSEnum, }; /// The driver for the sidecar, responsible for managing the main event loop. -pub struct SidecarDriver { +pub struct SidecarDriver { head_tracker: HeadTracker, execution: ExecutionState, consensus: ConsensusState, - constraint_signer: BLS, + constraint_signer: SignerBLSEnum, commitment_signer: ECDSA, local_builder: LocalBuilder, constraints_client: ConstraintsClient, @@ -58,15 +64,17 @@ impl fmt::Debug for SidecarDriver { +impl SidecarDriver { /// Create a new sidecar driver with the given [Config] and private key signer. pub async fn with_local_signer(opts: &Opts) -> eyre::Result { // The default state client simply uses the execution API URL to fetch state updates. let state_client = StateClient::new(opts.execution_api_url.clone()); // Constraints are signed with a BLS private key - let constraint_signer = - BlsSigner::new(opts.signing.private_key.clone().expect("local signer").0, opts.chain); + let constraint_signer = SignerBLSEnum::Local(Signer::new( + opts.signing.private_key.clone().expect("local signer").0, + opts.chain, + )); // Commitment responses are signed with a regular Ethereum wallet private key. // This is now generated randomly because slashing is not yet implemented. @@ -76,7 +84,7 @@ impl SidecarDriver { } } -impl SidecarDriver { +impl SidecarDriver { /// Create a new sidecar driver with the given [Config] and commit-boost signer. pub async fn with_commit_boost_signer(opts: &Opts) -> eyre::Result { // The default state client simply uses the execution API URL to fetch state updates. @@ -91,21 +99,20 @@ impl SidecarDriver { ) .await?; - // Constraints are signed with commit-boost signer - let constraint_signer = commit_boost_signer.clone(); + let cb_bls_signer = SignerBLSEnum::CommitBoost(commit_boost_signer.clone()); // Commitment responses are signed with commit-boost signer let commitment_signer = commit_boost_signer.clone(); - Self::from_components(opts, constraint_signer, commitment_signer, state_client).await + Self::from_components(opts, cb_bls_signer, commitment_signer, state_client).await } } -impl SidecarDriver { +impl SidecarDriver { /// Create a new sidecar driver with the given components pub async fn from_components( opts: &Opts, - constraint_signer: BLS, + constraint_signer: SignerBLSEnum, commitment_signer: ECDSA, fetcher: C, ) -> eyre::Result { @@ -198,7 +205,7 @@ impl SidecarDriver index, Err(err) => { error!(?err, "Consensus: failed to validate request"); @@ -227,24 +234,38 @@ impl SidecarDriver signer.pubkey(), + SignerBLSEnum::CommitBoost(ref signer) => signer.pubkey(), + SignerBLSEnum::Keystore(_) => validator_pubkey.clone(), + }; + // NOTE: we iterate over the transactions in the request and generate a signed constraint // for each one. This is because the transactions in the commitment request are not // supposed to be treated as a relative-ordering bundle, but a batch // with no ordering guarantees. for tx in inclusion_request.txs { let tx_type = tx.tx_type(); - let pubkey = self.constraint_signer.pubkey(); - let message = ConstraintsMessage::from_transaction(pubkey, slot, tx); - - let signed_constraints = - match self.constraint_signer.sign_commit_boost_root(&message.digest()).await { - Ok(signature) => SignedConstraints { message, signature }, - Err(err) => { - error!(?err, "Failed to sign constraints"); - let _ = response.send(Err(CommitmentError::Internal)); - return; - } - }; + let message = ConstraintsMessage::from_transaction(pubkey.clone(), slot, tx); + let digest = message.digest(); + + let signature = match self.constraint_signer { + SignerBLSEnum::Local(ref signer) => signer.sign_commit_boost_root(digest), + SignerBLSEnum::CommitBoost(ref signer) => { + signer.sign_commit_boost_root(digest).await + } + SignerBLSEnum::Keystore(ref signer) => { + signer.sign_commit_boost_root(digest, cl_public_key_to_arr(pubkey)) + } + }; + let signed_constraints = match signature { + Ok(signature) => SignedConstraints { message, signature }, + Err(e) => { + error!(?e, "Failed to sign constraints"); + let _ = response.send(Err(CommitmentError::Internal)); + return; + } + }; ApiMetrics::increment_transactions_preconfirmed(tx_type); self.execution.add_constraint(slot, signed_constraints); diff --git a/bolt-sidecar/src/lib.rs b/bolt-sidecar/src/lib.rs index 1a7f7d17f..2ef4a30ed 100644 --- a/bolt-sidecar/src/lib.rs +++ b/bolt-sidecar/src/lib.rs @@ -46,7 +46,7 @@ pub mod state; /// The signers available to the sidecar mod signer; -pub use signer::commit_boost::CommitBoostSigner; +pub use signer::{commit_boost::CommitBoostSigner, SignerBLSEnum}; /// Utilities for testing #[cfg(test)] diff --git a/bolt-sidecar/src/signer/commit_boost.rs b/bolt-sidecar/src/signer/commit_boost.rs index 6082e5bd4..6196e7011 100644 --- a/bolt-sidecar/src/signer/commit_boost.rs +++ b/bolt-sidecar/src/signer/commit_boost.rs @@ -113,19 +113,18 @@ impl CommitBoostSigner { } } -#[async_trait::async_trait] -impl SignerBLS for CommitBoostSigner { - fn pubkey(&self) -> BlsPublicKey { +impl CommitBoostSigner { + pub fn pubkey(&self) -> BlsPublicKey { self.get_consensus_pubkey() } - async fn sign_commit_boost_root(&self, data: &[u8; 32]) -> eyre::Result { + pub async fn sign_commit_boost_root(&self, data: [u8; 32]) -> eyre::Result { // convert the pubkey from ethereum_consensus to commit-boost format let pubkey = cb_common::signer::BlsPublicKey::from( alloy::rpc::types::beacon::BlsPublicKey::from_slice(self.pubkey().as_ref()), ); - let request = SignConsensusRequest { pubkey, object_root: *data }; + let request = SignConsensusRequest { pubkey, object_root: data }; debug!(?request, "Requesting signature from commit_boost"); diff --git a/bolt-sidecar/src/signer/keystore.rs b/bolt-sidecar/src/signer/keystore.rs index 456133bd9..c9bba413b 100644 --- a/bolt-sidecar/src/signer/keystore.rs +++ b/bolt-sidecar/src/signer/keystore.rs @@ -6,22 +6,21 @@ use std::{ path::{Path, PathBuf}, }; -use ethereum_consensus::crypto::PublicKey as CLPublicKey; - -use blst::min_pk::{PublicKey, SecretKey}; +use alloy::rpc::types::beacon::constants::BLS_PUBLIC_KEY_BYTES_LEN; use eyre::eyre; use lighthouse_bls::Keypair; use lighthouse_eth2_keystore::Keystore; -use crate::{config::signing::BlsSecretKey, crypto::SignerBLS}; +use crate::crypto::bls::BLSSig; +#[derive(Clone)] pub struct KeystoreSigner { keypairs: Vec, } impl KeystoreSigner { - fn new(keys_path: Option<&str>, password: &[u8]) -> eyre::Result { + pub fn new(keys_path: Option<&str>, password: &[u8]) -> eyre::Result { let keystores_paths = keystore_paths(keys_path)?; let mut keypairs = Vec::with_capacity(keystores_paths.len()); @@ -42,6 +41,25 @@ impl KeystoreSigner { Ok(Self { keypairs }) } + + pub fn sign_commit_boost_root( + &self, + root: [u8; 32], + public_key: [u8; BLS_PUBLIC_KEY_BYTES_LEN], + ) -> eyre::Result { + // NOTE: is this a good comparison? + let sk = self + .keypairs + .iter() + .find(|kp| kp.pk.as_hex_string() == hex::encode(public_key)) + .ok_or(eyre!("could not find private key associated to public key"))?; + + let sig = hex::decode(sk.sk.sign(root.into()).to_string())?; + let sig = + BLSSig::try_from(sig.as_slice()).map_err(|_| eyre!("invalid signature length"))?; + + Ok(sig) + } } /// Returns the paths of all the keystore files provided an optional `keys_path`, which defaults to `keys`. diff --git a/bolt-sidecar/src/signer/local.rs b/bolt-sidecar/src/signer/local.rs new file mode 100644 index 000000000..d431679d7 --- /dev/null +++ b/bolt-sidecar/src/signer/local.rs @@ -0,0 +1,132 @@ +use std::fmt::Debug; + +use blst::{min_pk::Signature, BLST_ERROR}; +use ethereum_consensus::{crypto::PublicKey as BlsPublicKey, deneb::compute_signing_root}; +use rand::RngCore; + +use crate::{crypto::bls::BLSSig, ChainConfig}; +pub use blst::min_pk::SecretKey as BlsSecretKey; + +/// The BLS Domain Separator used in Ethereum 2.0. +pub const BLS_DST_PREFIX: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"; + +/// A BLS signer that can sign any type that implements the [`SignableBLS`] trait. +#[derive(Clone)] +pub struct Signer { + chain: ChainConfig, + key: BlsSecretKey, +} + +impl Debug for Signer { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Signer") + .field("pubkey", &self.pubkey()) + .field("chain", &self.chain.name()) + .finish() + } +} + +impl Signer { + /// Create a new signer with the given BLS secret key. + pub fn new(key: BlsSecretKey, chain: ChainConfig) -> Self { + Self { key, chain } + } + + /// Create a signer with a random BLS key configured for Mainnet for testing. + #[cfg(test)] + pub fn random() -> Self { + Self { key: random_bls_secret(), chain: ChainConfig::mainnet() } + } + + /// Get the public key of the signer. + pub fn pubkey(&self) -> BlsPublicKey { + let pk = self.key.sk_to_pk(); + BlsPublicKey::try_from(pk.to_bytes().as_ref()).unwrap() + } + + /// Sign an SSZ object root with the Application Builder domain. + pub fn sign_application_builder_root(&self, root: [u8; 32]) -> eyre::Result { + self.sign_root(root, self.chain.application_builder_domain()) + } + + /// Sign an SSZ object root with the Commit Boost domain. + pub fn sign_commit_boost_root(&self, root: [u8; 32]) -> eyre::Result { + self.sign_root(root, self.chain.commit_boost_domain()) + } + + /// Sign an SSZ object root with the given domain. + pub fn sign_root(&self, root: [u8; 32], domain: [u8; 32]) -> eyre::Result { + let signing_root = compute_signing_root(&root, domain)?; + let sig = self.key.sign(signing_root.as_slice(), BLS_DST_PREFIX, &[]); + Ok(BLSSig::from_slice(&sig.to_bytes())) + } + + /// Verify the signature with the public key of the signer using the Application Builder domain. + pub fn verify_application_builder_root( + &self, + root: [u8; 32], + signature: &Signature, + ) -> eyre::Result<()> { + self.verify_root(root, signature, self.chain.application_builder_domain()) + } + + /// Verify the signature with the public key of the signer using the Commit Boost domain. + pub fn verify_commit_boost_root( + &self, + root: [u8; 32], + signature: &Signature, + ) -> eyre::Result<()> { + self.verify_root(root, signature, self.chain.commit_boost_domain()) + } + + /// Verify the signature of the object with the given public key. + pub fn verify_root( + &self, + root: [u8; 32], + signature: &Signature, + domain: [u8; 32], + ) -> eyre::Result<()> { + let signing_root = compute_signing_root(&root, domain)?; + let pk = blst::min_pk::PublicKey::from_bytes(self.pubkey().as_ref()).unwrap(); + + let res = signature.verify(true, signing_root.as_ref(), BLS_DST_PREFIX, &[], &pk, true); + if res == BLST_ERROR::BLST_SUCCESS { + Ok(()) + } else { + eyre::bail!(format!("Invalid signature: {:?}", res)) + } + } +} + +/// Generate a random BLS secret key. +pub fn random_bls_secret() -> BlsSecretKey { + let mut rng = rand::thread_rng(); + let mut ikm = [0u8; 32]; + rng.fill_bytes(&mut ikm); + BlsSecretKey::key_gen(&ikm, &[]).unwrap() +} + +#[cfg(test)] +mod tests { + use crate::{ + crypto::bls::{SignableBLS, Signer}, + test_util::TestSignableData, + }; + + use rand::Rng; + + #[tokio::test] + async fn test_bls_signer() { + let signer = Signer::random(); + + // Generate random data for the test + let mut rng = rand::thread_rng(); + let mut data = [0u8; 32]; + rng.fill(&mut data); + let msg = TestSignableData { data }; + + let signature = signer.sign_commit_boost_root(msg.digest()).unwrap(); + let sig = blst::min_pk::Signature::from_bytes(signature.as_ref()).unwrap(); + assert!(signer.verify_commit_boost_root(msg.digest(), &sig).is_ok()); + } +} diff --git a/bolt-sidecar/src/signer/mod.rs b/bolt-sidecar/src/signer/mod.rs index acff32098..907d17fa6 100644 --- a/bolt-sidecar/src/signer/mod.rs +++ b/bolt-sidecar/src/signer/mod.rs @@ -1,8 +1,15 @@ +use keystore::KeystoreSigner; +use local::Signer; + +use crate::CommitBoostSigner; + pub mod commit_boost; pub mod keystore; pub mod local; -// pub enum SignerBLSEnum { -// Local(Signer), -// CommitBoost(CommitBoostSigner), -// } +#[derive(Clone)] +pub enum SignerBLSEnum { + Local(Signer), + CommitBoost(CommitBoostSigner), + Keystore(KeystoreSigner), +} From 4b7144780898c899392d844d8ae2f7bcfcb8f76b Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Thu, 10 Oct 2024 11:18:40 +0200 Subject: [PATCH 31/64] fix(sidecar): imports, errors --- bolt-sidecar/src/crypto/bls.rs | 6 +----- bolt-sidecar/src/driver.rs | 10 +++------- bolt-sidecar/src/primitives/constraint.rs | 2 +- bolt-sidecar/src/signer/commit_boost.rs | 7 ++----- bolt-sidecar/src/signer/local.rs | 5 +---- bolt-sidecar/src/state/execution.rs | 4 ++-- bolt-sidecar/src/test_util.rs | 7 ++----- 7 files changed, 12 insertions(+), 29 deletions(-) diff --git a/bolt-sidecar/src/crypto/bls.rs b/bolt-sidecar/src/crypto/bls.rs index 90d03fede..b6c94339a 100644 --- a/bolt-sidecar/src/crypto/bls.rs +++ b/bolt-sidecar/src/crypto/bls.rs @@ -1,15 +1,11 @@ use std::fmt::Debug; use alloy::{primitives::FixedBytes, rpc::types::beacon::constants::BLS_PUBLIC_KEY_BYTES_LEN}; -use blst::{min_pk::Signature, BLST_ERROR}; -use ethereum_consensus::{crypto::PublicKey as BlsPublicKey, deneb::compute_signing_root}; -use rand::RngCore; +use ethereum_consensus::crypto::PublicKey as BlsPublicKey; pub use blst::min_pk::{PublicKey, SecretKey as BlsSecretKey}; pub use ethereum_consensus::deneb::BlsSignature; -use crate::{ChainConfig, CommitBoostSigner}; - /// The BLS Domain Separator used in Ethereum 2.0. pub const BLS_DST_PREFIX: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"; diff --git a/bolt-sidecar/src/driver.rs b/bolt-sidecar/src/driver.rs index 9fb212520..481071e39 100644 --- a/bolt-sidecar/src/driver.rs +++ b/bolt-sidecar/src/driver.rs @@ -3,7 +3,6 @@ use std::time::{Duration, Instant}; use alloy::{rpc::types::beacon::events::HeadEvent, signers::local::PrivateKeySigner}; use beacon_api_client::mainnet::Client as BeaconClient; -use cb_common::signer::BlsSigner; use ethereum_consensus::{ clock::{self, SlotStream, SystemTimeProvider}, phase0::mainnet::SLOTS_PER_EPOCH, @@ -17,10 +16,7 @@ use crate::{ server::{CommitmentsApiServer, Event as CommitmentEvent}, spec::Error as CommitmentError, }, - crypto::{ - bls::{cl_public_key_to_arr, Signer as BlsSigner}, - SignableBLS, SignerBLS, SignerECDSA, - }, + crypto::{bls::cl_public_key_to_arr, SignableBLS, SignerBLS, SignerECDSA}, primitives::{ CommitmentRequest, ConstraintsMessage, FetchPayloadRequest, LocalPayloadFetcher, SignedConstraints, TransactionExt, @@ -48,7 +44,7 @@ pub struct SidecarDriver { slot_stream: SlotStream, } -impl fmt::Debug for SidecarDriver { +impl fmt::Debug for SidecarDriver { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SidecarDriver") .field("head_tracker", &self.head_tracker) @@ -255,7 +251,7 @@ impl SidecarDriver { signer.sign_commit_boost_root(digest).await } SignerBLSEnum::Keystore(ref signer) => { - signer.sign_commit_boost_root(digest, cl_public_key_to_arr(pubkey)) + signer.sign_commit_boost_root(digest, cl_public_key_to_arr(pubkey.clone())) } }; let signed_constraints = match signature { diff --git a/bolt-sidecar/src/primitives/constraint.rs b/bolt-sidecar/src/primitives/constraint.rs index 230627ebe..acbab4aaa 100644 --- a/bolt-sidecar/src/primitives/constraint.rs +++ b/bolt-sidecar/src/primitives/constraint.rs @@ -72,7 +72,7 @@ impl SignableBLS for ConstraintsMessage { #[cfg(test)] mod tests { - use crate::crypto::bls::Signer; + use crate::signer::local::Signer; use super::*; use alloy::primitives::bytes; diff --git a/bolt-sidecar/src/signer/commit_boost.rs b/bolt-sidecar/src/signer/commit_boost.rs index 6196e7011..ab928ada0 100644 --- a/bolt-sidecar/src/signer/commit_boost.rs +++ b/bolt-sidecar/src/signer/commit_boost.rs @@ -13,10 +13,7 @@ use thiserror::Error; use tracing::{debug, error, info}; use crate::{ - crypto::{ - bls::{SignerBLS, BLS_DST_PREFIX}, - ecdsa::SignerECDSA, - }, + crypto::{bls::BLS_DST_PREFIX, ecdsa::SignerECDSA}, primitives::commitment::ECDSASignatureExt, }; @@ -178,7 +175,7 @@ mod test { let mut data = [0u8; 32]; rng.fill(&mut data); - let signature = signer.sign_commit_boost_root(&data).await.unwrap(); + let signature = signer.sign_commit_boost_root(data).await.unwrap(); let sig = blst::min_pk::Signature::from_bytes(signature.as_ref()).unwrap(); let pubkey = signer.get_consensus_pubkey(); let bls_pubkey = blst::min_pk::PublicKey::from_bytes(pubkey.as_ref()).unwrap(); diff --git a/bolt-sidecar/src/signer/local.rs b/bolt-sidecar/src/signer/local.rs index d431679d7..4c46463b5 100644 --- a/bolt-sidecar/src/signer/local.rs +++ b/bolt-sidecar/src/signer/local.rs @@ -108,10 +108,7 @@ pub fn random_bls_secret() -> BlsSecretKey { #[cfg(test)] mod tests { - use crate::{ - crypto::bls::{SignableBLS, Signer}, - test_util::TestSignableData, - }; + use crate::{crypto::bls::SignableBLS, signer::local::Signer, test_util::TestSignableData}; use rand::Rng; diff --git a/bolt-sidecar/src/state/execution.rs b/bolt-sidecar/src/state/execution.rs index d2ec5f363..c349c28be 100644 --- a/bolt-sidecar/src/state/execution.rs +++ b/bolt-sidecar/src/state/execution.rs @@ -527,7 +527,7 @@ pub struct StateUpdate { #[cfg(test)] mod tests { - use crate::builder::template::StateDiff; + use crate::{builder::template::StateDiff, signer::local::Signer}; use std::{num::NonZero, str::FromStr, time::Duration}; use alloy::{ @@ -542,7 +542,7 @@ mod tests { use reth_primitives::constants::GWEI_TO_WEI; use crate::{ - crypto::{bls::Signer, SignableBLS}, + crypto::SignableBLS, primitives::{ConstraintsMessage, SignedConstraints}, state::fetcher, test_util::{create_signed_commitment_request, default_test_transaction, launch_anvil}, diff --git a/bolt-sidecar/src/test_util.rs b/bolt-sidecar/src/test_util.rs index c1f1f3215..6e0f85e0b 100644 --- a/bolt-sidecar/src/test_util.rs +++ b/bolt-sidecar/src/test_util.rs @@ -19,15 +19,12 @@ use tracing::warn; use crate::{ config::signing::BlsSecretKey, - crypto::{ - bls::{random_bls_secret, Signer as BlsSigner}, - ecdsa::SignableECDSA, - SignableBLS, - }, + crypto::{ecdsa::SignableECDSA, SignableBLS}, primitives::{ CommitmentRequest, ConstraintsMessage, DelegationMessage, FullTransaction, InclusionRequest, RevocationMessage, SignedConstraints, SignedDelegation, SignedRevocation, }, + signer::local::{random_bls_secret, Signer as BlsSigner}, ChainConfig, Opts, }; From 22b7a47e08e1b346fb55bf2f24ee18c1fa7a43f8 Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Thu, 10 Oct 2024 11:20:19 +0200 Subject: [PATCH 32/64] chore(sidecar): Signer -> LocalSigner --- bolt-sidecar/src/driver.rs | 4 ++-- bolt-sidecar/src/primitives/constraint.rs | 4 ++-- bolt-sidecar/src/signer/local.rs | 12 +++++++----- bolt-sidecar/src/signer/mod.rs | 4 ++-- bolt-sidecar/src/state/execution.rs | 10 +++++----- bolt-sidecar/src/test_util.rs | 7 ++++--- 6 files changed, 22 insertions(+), 19 deletions(-) diff --git a/bolt-sidecar/src/driver.rs b/bolt-sidecar/src/driver.rs index 481071e39..e39737f9b 100644 --- a/bolt-sidecar/src/driver.rs +++ b/bolt-sidecar/src/driver.rs @@ -21,7 +21,7 @@ use crate::{ CommitmentRequest, ConstraintsMessage, FetchPayloadRequest, LocalPayloadFetcher, SignedConstraints, TransactionExt, }, - signer::local::Signer, + signer::local::LocalSigner, start_builder_proxy_server, state::{fetcher::StateFetcher, ConsensusState, ExecutionState, HeadTracker, StateClient}, telemetry::ApiMetrics, @@ -67,7 +67,7 @@ impl SidecarDriver { let state_client = StateClient::new(opts.execution_api_url.clone()); // Constraints are signed with a BLS private key - let constraint_signer = SignerBLSEnum::Local(Signer::new( + let constraint_signer = SignerBLSEnum::Local(LocalSigner::new( opts.signing.private_key.clone().expect("local signer").0, opts.chain, )); diff --git a/bolt-sidecar/src/primitives/constraint.rs b/bolt-sidecar/src/primitives/constraint.rs index acbab4aaa..344bf7807 100644 --- a/bolt-sidecar/src/primitives/constraint.rs +++ b/bolt-sidecar/src/primitives/constraint.rs @@ -72,7 +72,7 @@ impl SignableBLS for ConstraintsMessage { #[cfg(test)] mod tests { - use crate::signer::local::Signer; + use crate::signer::local::LocalSigner; use super::*; use alloy::primitives::bytes; @@ -138,7 +138,7 @@ mod tests { #[test] fn test_constraints_signature_roundtrip() { - let signer = Signer::random(); + let signer = LocalSigner::random(); let tx_bytes = bytes!("f8678085019dc6838082520894deaddeaddeaddeaddeaddeaddeaddeaddeaddead38808360306ca06664c078fa60bd3ece050903dd295949908dd9686ec8871fa558f868e031cd39a00ed4f0b122b32b73f19230fabe6a726e2d07f84eda5beaa42a1ae1271bdee39f").to_vec(); let tx = FullTransaction::decode_enveloped(tx_bytes.as_slice()).unwrap(); diff --git a/bolt-sidecar/src/signer/local.rs b/bolt-sidecar/src/signer/local.rs index 4c46463b5..264232580 100644 --- a/bolt-sidecar/src/signer/local.rs +++ b/bolt-sidecar/src/signer/local.rs @@ -12,12 +12,12 @@ pub const BLS_DST_PREFIX: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_" /// A BLS signer that can sign any type that implements the [`SignableBLS`] trait. #[derive(Clone)] -pub struct Signer { +pub struct LocalSigner { chain: ChainConfig, key: BlsSecretKey, } -impl Debug for Signer { +impl Debug for LocalSigner { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Signer") .field("pubkey", &self.pubkey()) @@ -26,7 +26,7 @@ impl Debug for Signer { } } -impl Signer { +impl LocalSigner { /// Create a new signer with the given BLS secret key. pub fn new(key: BlsSecretKey, chain: ChainConfig) -> Self { Self { key, chain } @@ -108,13 +108,15 @@ pub fn random_bls_secret() -> BlsSecretKey { #[cfg(test)] mod tests { - use crate::{crypto::bls::SignableBLS, signer::local::Signer, test_util::TestSignableData}; + use crate::{ + crypto::bls::SignableBLS, signer::local::LocalSigner, test_util::TestSignableData, + }; use rand::Rng; #[tokio::test] async fn test_bls_signer() { - let signer = Signer::random(); + let signer = LocalSigner::random(); // Generate random data for the test let mut rng = rand::thread_rng(); diff --git a/bolt-sidecar/src/signer/mod.rs b/bolt-sidecar/src/signer/mod.rs index 907d17fa6..48f78fdec 100644 --- a/bolt-sidecar/src/signer/mod.rs +++ b/bolt-sidecar/src/signer/mod.rs @@ -1,5 +1,5 @@ use keystore::KeystoreSigner; -use local::Signer; +use local::LocalSigner; use crate::CommitBoostSigner; @@ -9,7 +9,7 @@ pub mod local; #[derive(Clone)] pub enum SignerBLSEnum { - Local(Signer), + Local(LocalSigner), CommitBoost(CommitBoostSigner), Keystore(KeystoreSigner), } diff --git a/bolt-sidecar/src/state/execution.rs b/bolt-sidecar/src/state/execution.rs index c349c28be..249a5f7a9 100644 --- a/bolt-sidecar/src/state/execution.rs +++ b/bolt-sidecar/src/state/execution.rs @@ -527,7 +527,7 @@ pub struct StateUpdate { #[cfg(test)] mod tests { - use crate::{builder::template::StateDiff, signer::local::Signer}; + use crate::{builder::template::StateDiff, signer::local::LocalSigner}; use std::{num::NonZero, str::FromStr, time::Duration}; use alloy::{ @@ -703,7 +703,7 @@ mod tests { let sender = anvil.addresses().first().unwrap(); let sender_pk = anvil.keys().first().unwrap(); - let signer = Signer::random(); + let signer = LocalSigner::random(); // initialize the state by updating the head once let slot = client.get_head().await?; @@ -985,7 +985,7 @@ mod tests { assert!(state.validate_request(&mut request).await.is_ok()); - let bls_signer = Signer::random(); + let bls_signer = LocalSigner::random(); let message = ConstraintsMessage::build(Default::default(), inclusion_request); let signature = bls_signer.sign_commit_boost_root(message.digest()).unwrap(); let signed_constraints = SignedConstraints { message, signature }; @@ -1033,7 +1033,7 @@ mod tests { assert!(state.validate_request(&mut request).await.is_ok()); - let bls_signer = Signer::random(); + let bls_signer = LocalSigner::random(); let message = ConstraintsMessage::build(Default::default(), inclusion_request); let signature = bls_signer.sign_commit_boost_root(message.digest()).unwrap(); let signed_constraints = SignedConstraints { message, signature }; @@ -1080,7 +1080,7 @@ mod tests { assert!(state.validate_request(&mut request).await.is_ok()); - let bls_signer = Signer::random(); + let bls_signer = LocalSigner::random(); let message = ConstraintsMessage::build(Default::default(), inclusion_request); let signature = bls_signer.sign_commit_boost_root(message.digest()).unwrap(); let signed_constraints = SignedConstraints { message, signature }; diff --git a/bolt-sidecar/src/test_util.rs b/bolt-sidecar/src/test_util.rs index 6e0f85e0b..ef22276be 100644 --- a/bolt-sidecar/src/test_util.rs +++ b/bolt-sidecar/src/test_util.rs @@ -1,3 +1,4 @@ +use crate::{signer::local::random_bls_secret, ChainConfig}; use alloy::{ eips::eip2718::Encodable2718, network::{EthereumWallet, TransactionBuilder}, @@ -24,8 +25,8 @@ use crate::{ CommitmentRequest, ConstraintsMessage, DelegationMessage, FullTransaction, InclusionRequest, RevocationMessage, SignedConstraints, SignedDelegation, SignedRevocation, }, - signer::local::{random_bls_secret, Signer as BlsSigner}, - ChainConfig, Opts, + signer::local::LocalSigner, + Opts, }; /// The URL of the test execution client HTTP API. @@ -195,7 +196,7 @@ fn random_constraints(count: usize) -> Vec { #[tokio::test] async fn generate_test_data_kurtosis() { - let signer = BlsSigner::new(random_bls_secret(), ChainConfig::kurtosis(0, 0)); + let signer = LocalSigner::new(random_bls_secret(), ChainConfig::kurtosis(0, 0)); let pk = signer.pubkey(); println!("Validator Public Key: {}", hex::encode(pk.as_ref())); From c6d2f6f07eb62e0bd38bac3875da9dee7d9c0145 Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Thu, 10 Oct 2024 11:20:39 +0200 Subject: [PATCH 33/64] chore(sidecar): just fmt --- bolt-sidecar/src/builder/payload_builder.rs | 6 +++--- bolt-sidecar/src/signer/keystore.rs | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/bolt-sidecar/src/builder/payload_builder.rs b/bolt-sidecar/src/builder/payload_builder.rs index fbfb5d2d7..1eba21b9d 100644 --- a/bolt-sidecar/src/builder/payload_builder.rs +++ b/bolt-sidecar/src/builder/payload_builder.rs @@ -454,9 +454,9 @@ mod tests { let raw_encoded = tx_signed.encoded_2718(); let tx_signed_reth = TransactionSigned::decode_enveloped(&mut raw_encoded.as_slice())?; - let slot = genesis_time - + (SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs() / cfg.chain.slot_time()) - + 1; + let slot = genesis_time + + (SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs() / cfg.chain.slot_time()) + + 1; let block = builder.build_fallback_payload(slot, &[tx_signed_reth]).await?; assert_eq!(block.body.len(), 1); diff --git a/bolt-sidecar/src/signer/keystore.rs b/bolt-sidecar/src/signer/keystore.rs index c9bba413b..ad2b68fc0 100644 --- a/bolt-sidecar/src/signer/keystore.rs +++ b/bolt-sidecar/src/signer/keystore.rs @@ -62,14 +62,13 @@ impl KeystoreSigner { } } -/// Returns the paths of all the keystore files provided an optional `keys_path`, which defaults to `keys`. -/// `keys_path` is a relative path from the root of this cargo project +/// Returns the paths of all the keystore files provided an optional `keys_path`, which defaults to +/// `keys`. `keys_path` is a relative path from the root of this cargo project /// We're expecting a directory structure like: /// ${keys_path}/ /// -- 0x1234.../validator.json /// -- 0x5678.../validator.json /// -- ... -/// fn keystore_paths(keys_path: Option<&str>) -> Result, eyre::Error> { // Create the path to the keystore directory, starting from the root of the project let project_root = env!("CARGO_MANIFEST_DIR"); From aad480f7735eccace043bdaa0ba0ac4e82deadff Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Thu, 10 Oct 2024 11:27:26 +0200 Subject: [PATCH 34/64] chore(sidecar): Debug for SignerBLSEnum --- bolt-sidecar/src/driver.rs | 4 ++-- bolt-sidecar/src/signer/keystore.rs | 12 ++++++++++++ bolt-sidecar/src/signer/mod.rs | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/bolt-sidecar/src/driver.rs b/bolt-sidecar/src/driver.rs index e39737f9b..2e0d82a07 100644 --- a/bolt-sidecar/src/driver.rs +++ b/bolt-sidecar/src/driver.rs @@ -16,7 +16,7 @@ use crate::{ server::{CommitmentsApiServer, Event as CommitmentEvent}, spec::Error as CommitmentError, }, - crypto::{bls::cl_public_key_to_arr, SignableBLS, SignerBLS, SignerECDSA}, + crypto::{bls::cl_public_key_to_arr, SignableBLS, SignerECDSA}, primitives::{ CommitmentRequest, ConstraintsMessage, FetchPayloadRequest, LocalPayloadFetcher, SignedConstraints, TransactionExt, @@ -44,7 +44,7 @@ pub struct SidecarDriver { slot_stream: SlotStream, } -impl fmt::Debug for SidecarDriver { +impl fmt::Debug for SidecarDriver { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SidecarDriver") .field("head_tracker", &self.head_tracker) diff --git a/bolt-sidecar/src/signer/keystore.rs b/bolt-sidecar/src/signer/keystore.rs index ad2b68fc0..6a17fed39 100644 --- a/bolt-sidecar/src/signer/keystore.rs +++ b/bolt-sidecar/src/signer/keystore.rs @@ -1,5 +1,6 @@ //! An ERC-2335 keystore signer. +use std::fmt::Debug; use std::{ ffi::OsString, fs, @@ -62,6 +63,17 @@ impl KeystoreSigner { } } +impl Debug for KeystoreSigner { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Signer") + .field( + "pubkeys", + &self.keypairs.iter().map(|kp| kp.pk.as_hex_string()).collect::>(), + ) + .finish() + } +} + /// Returns the paths of all the keystore files provided an optional `keys_path`, which defaults to /// `keys`. `keys_path` is a relative path from the root of this cargo project /// We're expecting a directory structure like: diff --git a/bolt-sidecar/src/signer/mod.rs b/bolt-sidecar/src/signer/mod.rs index 48f78fdec..60fec54d3 100644 --- a/bolt-sidecar/src/signer/mod.rs +++ b/bolt-sidecar/src/signer/mod.rs @@ -7,7 +7,7 @@ pub mod commit_boost; pub mod keystore; pub mod local; -#[derive(Clone)] +#[derive(Debug, Clone)] pub enum SignerBLSEnum { Local(LocalSigner), CommitBoost(CommitBoostSigner), From fa286d9dec29c43aa8beaa909a25e3ca23e6913f Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Thu, 10 Oct 2024 11:30:07 +0200 Subject: [PATCH 35/64] chore(sidecar): SignerBLSEnum -> SignerBLS --- bolt-sidecar/src/crypto/bls.rs | 15 +-------------- bolt-sidecar/src/crypto/mod.rs | 2 +- bolt-sidecar/src/driver.rs | 24 +++++++++++------------- bolt-sidecar/src/lib.rs | 2 +- bolt-sidecar/src/signer/mod.rs | 6 +++++- 5 files changed, 19 insertions(+), 30 deletions(-) diff --git a/bolt-sidecar/src/crypto/bls.rs b/bolt-sidecar/src/crypto/bls.rs index b6c94339a..2f5687b14 100644 --- a/bolt-sidecar/src/crypto/bls.rs +++ b/bolt-sidecar/src/crypto/bls.rs @@ -1,5 +1,3 @@ -use std::fmt::Debug; - use alloy::{primitives::FixedBytes, rpc::types::beacon::constants::BLS_PUBLIC_KEY_BYTES_LEN}; use ethereum_consensus::crypto::PublicKey as BlsPublicKey; @@ -19,18 +17,7 @@ pub trait SignableBLS { fn digest(&self) -> [u8; 32]; } -/// A generic signing trait to generate BLS signatures. -/// -/// Note: we keep this async to allow remote signer implementations. -#[async_trait::async_trait] -pub trait SignerBLS: Send + Debug { - /// Get the public key of the signer. - fn pubkey(&self) -> BlsPublicKey; - - /// Sign the given data and return the signature. - async fn sign_commit_boost_root(&self, data: &[u8; 32]) -> eyre::Result; -} - +/// Convert a BLS public key from Consensus Types to a byte array. pub fn cl_public_key_to_arr(pubkey: BlsPublicKey) -> [u8; BLS_PUBLIC_KEY_BYTES_LEN] { pubkey.as_ref().try_into().expect("BLS keys are 48 bytes") } diff --git a/bolt-sidecar/src/crypto/mod.rs b/bolt-sidecar/src/crypto/mod.rs index 2cabada59..330d3fdde 100644 --- a/bolt-sidecar/src/crypto/mod.rs +++ b/bolt-sidecar/src/crypto/mod.rs @@ -1,6 +1,6 @@ /// BLS12_381 signatures and verification functions. pub mod bls; -pub use bls::{SignableBLS, SignerBLS}; +pub use bls::SignableBLS; /// ECDSA signatures and verification functions. pub mod ecdsa; diff --git a/bolt-sidecar/src/driver.rs b/bolt-sidecar/src/driver.rs index 2e0d82a07..4ce5c43db 100644 --- a/bolt-sidecar/src/driver.rs +++ b/bolt-sidecar/src/driver.rs @@ -26,7 +26,7 @@ use crate::{ state::{fetcher::StateFetcher, ConsensusState, ExecutionState, HeadTracker, StateClient}, telemetry::ApiMetrics, BuilderProxyConfig, CommitBoostSigner, ConstraintsApi, ConstraintsClient, LocalBuilder, Opts, - SignerBLSEnum, + SignerBLS, }; /// The driver for the sidecar, responsible for managing the main event loop. @@ -34,7 +34,7 @@ pub struct SidecarDriver { head_tracker: HeadTracker, execution: ExecutionState, consensus: ConsensusState, - constraint_signer: SignerBLSEnum, + constraint_signer: SignerBLS, commitment_signer: ECDSA, local_builder: LocalBuilder, constraints_client: ConstraintsClient, @@ -67,7 +67,7 @@ impl SidecarDriver { let state_client = StateClient::new(opts.execution_api_url.clone()); // Constraints are signed with a BLS private key - let constraint_signer = SignerBLSEnum::Local(LocalSigner::new( + let constraint_signer = SignerBLS::Local(LocalSigner::new( opts.signing.private_key.clone().expect("local signer").0, opts.chain, )); @@ -95,7 +95,7 @@ impl SidecarDriver { ) .await?; - let cb_bls_signer = SignerBLSEnum::CommitBoost(commit_boost_signer.clone()); + let cb_bls_signer = SignerBLS::CommitBoost(commit_boost_signer.clone()); // Commitment responses are signed with commit-boost signer let commitment_signer = commit_boost_signer.clone(); @@ -108,7 +108,7 @@ impl SidecarDriver { /// Create a new sidecar driver with the given components pub async fn from_components( opts: &Opts, - constraint_signer: SignerBLSEnum, + constraint_signer: SignerBLS, commitment_signer: ECDSA, fetcher: C, ) -> eyre::Result { @@ -231,9 +231,9 @@ impl SidecarDriver { let slot = inclusion_request.slot; let pubkey = match self.constraint_signer { - SignerBLSEnum::Local(ref signer) => signer.pubkey(), - SignerBLSEnum::CommitBoost(ref signer) => signer.pubkey(), - SignerBLSEnum::Keystore(_) => validator_pubkey.clone(), + SignerBLS::Local(ref signer) => signer.pubkey(), + SignerBLS::CommitBoost(ref signer) => signer.pubkey(), + SignerBLS::Keystore(_) => validator_pubkey.clone(), }; // NOTE: we iterate over the transactions in the request and generate a signed constraint @@ -246,11 +246,9 @@ impl SidecarDriver { let digest = message.digest(); let signature = match self.constraint_signer { - SignerBLSEnum::Local(ref signer) => signer.sign_commit_boost_root(digest), - SignerBLSEnum::CommitBoost(ref signer) => { - signer.sign_commit_boost_root(digest).await - } - SignerBLSEnum::Keystore(ref signer) => { + SignerBLS::Local(ref signer) => signer.sign_commit_boost_root(digest), + SignerBLS::CommitBoost(ref signer) => signer.sign_commit_boost_root(digest).await, + SignerBLS::Keystore(ref signer) => { signer.sign_commit_boost_root(digest, cl_public_key_to_arr(pubkey.clone())) } }; diff --git a/bolt-sidecar/src/lib.rs b/bolt-sidecar/src/lib.rs index 2ef4a30ed..53180f6c5 100644 --- a/bolt-sidecar/src/lib.rs +++ b/bolt-sidecar/src/lib.rs @@ -46,7 +46,7 @@ pub mod state; /// The signers available to the sidecar mod signer; -pub use signer::{commit_boost::CommitBoostSigner, SignerBLSEnum}; +pub use signer::{commit_boost::CommitBoostSigner, SignerBLS}; /// Utilities for testing #[cfg(test)] diff --git a/bolt-sidecar/src/signer/mod.rs b/bolt-sidecar/src/signer/mod.rs index 60fec54d3..f52e34909 100644 --- a/bolt-sidecar/src/signer/mod.rs +++ b/bolt-sidecar/src/signer/mod.rs @@ -8,8 +8,12 @@ pub mod keystore; pub mod local; #[derive(Debug, Clone)] -pub enum SignerBLSEnum { +/// Signer for BLS signatures. +pub enum SignerBLS { + /// Local signer with a BLS secret key. Local(LocalSigner), + /// Signer from Commit-Boost. CommitBoost(CommitBoostSigner), + /// Signer consisting of multiple keypairs loaded from ERC-2335 keystores files. Keystore(KeystoreSigner), } From 94d7a1589e6e96dbdf40dd7da00ec2e8c7e7270a Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Thu, 10 Oct 2024 11:32:03 +0200 Subject: [PATCH 36/64] fix(sidecar): warnings --- bolt-sidecar/src/signer/commit_boost.rs | 2 ++ bolt-sidecar/src/signer/keystore.rs | 2 +- bolt-sidecar/src/signer/local.rs | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/bolt-sidecar/src/signer/commit_boost.rs b/bolt-sidecar/src/signer/commit_boost.rs index ab928ada0..01af5357f 100644 --- a/bolt-sidecar/src/signer/commit_boost.rs +++ b/bolt-sidecar/src/signer/commit_boost.rs @@ -111,10 +111,12 @@ impl CommitBoostSigner { } impl CommitBoostSigner { + /// Get the public key of the signer. pub fn pubkey(&self) -> BlsPublicKey { self.get_consensus_pubkey() } + /// Sign an object root with the Commit Boost domain. pub async fn sign_commit_boost_root(&self, data: [u8; 32]) -> eyre::Result { // convert the pubkey from ethereum_consensus to commit-boost format let pubkey = cb_common::signer::BlsPublicKey::from( diff --git a/bolt-sidecar/src/signer/keystore.rs b/bolt-sidecar/src/signer/keystore.rs index 6a17fed39..9652a603a 100644 --- a/bolt-sidecar/src/signer/keystore.rs +++ b/bolt-sidecar/src/signer/keystore.rs @@ -1,8 +1,8 @@ //! An ERC-2335 keystore signer. -use std::fmt::Debug; use std::{ ffi::OsString, + fmt::Debug, fs, path::{Path, PathBuf}, }; diff --git a/bolt-sidecar/src/signer/local.rs b/bolt-sidecar/src/signer/local.rs index 264232580..f9cd38f00 100644 --- a/bolt-sidecar/src/signer/local.rs +++ b/bolt-sidecar/src/signer/local.rs @@ -2,7 +2,6 @@ use std::fmt::Debug; use blst::{min_pk::Signature, BLST_ERROR}; use ethereum_consensus::{crypto::PublicKey as BlsPublicKey, deneb::compute_signing_root}; -use rand::RngCore; use crate::{crypto::bls::BLSSig, ChainConfig}; pub use blst::min_pk::SecretKey as BlsSecretKey; @@ -99,7 +98,9 @@ impl LocalSigner { } /// Generate a random BLS secret key. +#[cfg(test)] pub fn random_bls_secret() -> BlsSecretKey { + use rand::RngCore; let mut rng = rand::thread_rng(); let mut ikm = [0u8; 32]; rng.fill_bytes(&mut ikm); From c6d3dacb0614ba147f08e5c7beb0de71d532ebe8 Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Thu, 10 Oct 2024 11:41:44 +0200 Subject: [PATCH 37/64] feat(sidecar): add keystore signer to driver --- bolt-sidecar/bin/sidecar.rs | 11 ++++++++++- bolt-sidecar/src/driver.rs | 25 ++++++++++++++++++++++--- bolt-sidecar/src/signer/keystore.rs | 4 +++- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/bolt-sidecar/bin/sidecar.rs b/bolt-sidecar/bin/sidecar.rs index ab63b2ee5..909d4e402 100644 --- a/bolt-sidecar/bin/sidecar.rs +++ b/bolt-sidecar/bin/sidecar.rs @@ -18,7 +18,16 @@ async fn main() -> Result<()> { if opts.signing.private_key.is_some() { match SidecarDriver::with_local_signer(&opts).await { Ok(driver) => driver.run_forever().await, - Err(err) => bail!("Failed to initialize the sidecar driver: {:?}", err), + Err(err) => { + bail!("Failed to initialize the sidecar driver with local signer: {:?}", err) + } + } + } else if opts.signing.keystore_password.is_some() { + match SidecarDriver::with_keystore_signer(&opts).await { + Ok(driver) => driver.run_forever().await, + Err(err) => { + bail!("Failed to initialize the sidecar driver with keystore signer: {:?}", err) + } } } else { match SidecarDriver::with_commit_boost_signer(&opts).await { diff --git a/bolt-sidecar/src/driver.rs b/bolt-sidecar/src/driver.rs index 4ce5c43db..060120671 100644 --- a/bolt-sidecar/src/driver.rs +++ b/bolt-sidecar/src/driver.rs @@ -21,7 +21,7 @@ use crate::{ CommitmentRequest, ConstraintsMessage, FetchPayloadRequest, LocalPayloadFetcher, SignedConstraints, TransactionExt, }, - signer::local::LocalSigner, + signer::{keystore::KeystoreSigner, local::LocalSigner}, start_builder_proxy_server, state::{fetcher::StateFetcher, ConsensusState, ExecutionState, HeadTracker, StateClient}, telemetry::ApiMetrics, @@ -61,7 +61,7 @@ impl fmt::Debug for SidecarDriver { } impl SidecarDriver { - /// Create a new sidecar driver with the given [Config] and private key signer. + /// Create a new sidecar driver with the given [Opts] and private key signer. pub async fn with_local_signer(opts: &Opts) -> eyre::Result { // The default state client simply uses the execution API URL to fetch state updates. let state_client = StateClient::new(opts.execution_api_url.clone()); @@ -80,8 +80,27 @@ impl SidecarDriver { } } +impl SidecarDriver { + /// Create a new sidecar driver with the given [Opts] and keystore signer. + pub async fn with_keystore_signer(opts: &Opts) -> eyre::Result { + // The default state client simply uses the execution API URL to fetch state updates. + let state_client = StateClient::new(opts.execution_api_url.clone()); + + let keystore_signer = SignerBLS::Keystore(KeystoreSigner::new( + None, + opts.signing.keystore_password.as_ref().expect("keystore password").as_ref(), + )?); + + // Commitment responses are signed with a regular Ethereum wallet private key. + // This is now generated randomly because slashing is not yet implemented. + let commitment_signer = PrivateKeySigner::random(); + + Self::from_components(opts, keystore_signer, commitment_signer, state_client).await + } +} + impl SidecarDriver { - /// Create a new sidecar driver with the given [Config] and commit-boost signer. + /// Create a new sidecar driver with the given [Opts] and commit-boost signer. pub async fn with_commit_boost_signer(opts: &Opts) -> eyre::Result { // The default state client simply uses the execution API URL to fetch state updates. let state_client = StateClient::new(opts.execution_api_url.clone()); diff --git a/bolt-sidecar/src/signer/keystore.rs b/bolt-sidecar/src/signer/keystore.rs index 9652a603a..e05373503 100644 --- a/bolt-sidecar/src/signer/keystore.rs +++ b/bolt-sidecar/src/signer/keystore.rs @@ -15,6 +15,8 @@ use lighthouse_eth2_keystore::Keystore; use crate::crypto::bls::BLSSig; +pub const KEYSTORES_DEFAULT_PATH: &str = "keys"; + #[derive(Clone)] pub struct KeystoreSigner { keypairs: Vec, @@ -84,7 +86,7 @@ impl Debug for KeystoreSigner { fn keystore_paths(keys_path: Option<&str>) -> Result, eyre::Error> { // Create the path to the keystore directory, starting from the root of the project let project_root = env!("CARGO_MANIFEST_DIR"); - let keys_path = Path::new(project_root).join(keys_path.unwrap_or("keys")); + let keys_path = Path::new(project_root).join(keys_path.unwrap_or(KEYSTORES_DEFAULT_PATH)); let json_extension = OsString::from("json"); From fdeec0bebc32ef149d7491abe1c9e3aba9ae5714 Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Thu, 10 Oct 2024 12:28:35 +0200 Subject: [PATCH 38/64] chore(sidecar): jwt validation in opts --- bolt-sidecar/src/config/mod.rs | 163 +---------------------------- bolt-sidecar/src/config/signing.rs | 55 +++++++++- 2 files changed, 55 insertions(+), 163 deletions(-) diff --git a/bolt-sidecar/src/config/mod.rs b/bolt-sidecar/src/config/mod.rs index 3dac1c5e4..a7fc12b9b 100644 --- a/bolt-sidecar/src/config/mod.rs +++ b/bolt-sidecar/src/config/mod.rs @@ -3,7 +3,7 @@ use std::str::FromStr; use alloy::primitives::Address; use clap::Parser; use reqwest::Url; -use signing::BlsSecretKey; +use signing::{BlsSecretKey, JwtSecretConfig}; pub mod validator_indexes; pub use validator_indexes::ValidatorIndexes; @@ -65,10 +65,9 @@ pub struct Opts { /// /// It can either be a hex-encoded string or a file path to a file /// containing the hex-encoded secret. - /// TODO: validate this by using a Jwt struct #[clap(long, env = "BOLT_SIDECAR_JWT_HEX", - default_value_t = String::new())] - pub jwt_hex: String, + default_value_t = JwtSecretConfig::default())] + pub jwt_hex: JwtSecretConfig, /// The fee recipient address for fallback blocks #[clap(long, env = "BOLT_SIDECAR_FEE_RECIPIENT", default_value_t = Address::ZERO)] @@ -92,162 +91,6 @@ pub struct Opts { pub telemetry: TelemetryOpts, } -/// /// Configuration options for the sidecar. These are parsed from -/// /// command-line options in the form of [`Opts`]. -/// #[derive(Debug, Clone)] -/// pub struct Config { -/// /// Port to listen on for incoming JSON-RPC requests -/// pub rpc_port: u16, -/// /// 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 -/// pub execution_api_url: Url, -/// /// The engine API url -/// pub engine_api_url: Url, -/// /// URL for the commit-boost sidecar -/// pub commit_boost_url: Option, -/// /// The JWT secret token to authenticate calls to the commit-boost -/// pub commit_boost_jwt_hex: Option, -/// /// Private key to use for signing preconfirmation requests -/// pub private_key: Option, -/// /// The jwt.hex secret to authenticate calls to the engine API -/// pub jwt_hex: String, -/// /// The fee recipient address for fallback blocks -/// pub fee_recipient: Address, -/// /// Operating limits for the sidecar -/// pub limits: Limits, -/// /// Validator indexes of connected validators that the -/// /// sidecar should accept commitments on behalf of -/// pub validator_indexes: ValidatorIndexes, -/// /// Local bulider private key for signing fallback payloads. -/// /// If not provided, a random key will be used. -/// pub builder_private_key: SecretKey, -/// /// The chain on which the sidecar is running -/// pub chain: ChainConfig, -/// /// Metrics port -/// pub metrics_port: u16, -/// /// Toggle for metrics -/// pub disable_metrics: bool, -/// } -/// -/// impl Default for Config { -/// fn default() -> Self { -/// Self { -/// rpc_port: DEFAULT_RPC_PORT, -/// constraints_proxy_port: DEFAULT_CONSTRAINTS_PROXY_PORT, -/// commit_boost_url: None, -/// commit_boost_jwt_hex: None, -/// 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"), -/// private_key: Some(random_bls_secret()), -/// jwt_hex: String::new(), -/// fee_recipient: Address::ZERO, -/// builder_private_key: random_bls_secret(), -/// limits: Limits::default(), -/// validator_indexes: ValidatorIndexes::default(), -/// chain: ChainConfig::default(), -/// metrics_port: 0, -/// disable_metrics: false, -/// } -/// } -/// } - -// impl Config { -// /// Parse the command-line options and return a new [`Config`] instance -// pub fn parse_from_cli() -> Result { -// let opts = Opts::parse(); -// Self::try_from(opts) -// } -// } -// -// impl Opts { -// type Error = Report; -// -// fn validate(&self) -> Result { -// let mut config = Config::default(); -// -// if let Some(port) = opts.port { -// config.rpc_port = port; -// } -// -// if let Some(max_commitments) = opts.max_commitments { -// config.limits.max_commitments_per_slot = max_commitments; -// } -// -// if let Some(max_committed_gas) = opts.max_committed_gas { -// config.limits.max_committed_gas_per_slot = max_committed_gas; -// } -// -// if let Some(min_priority_fee) = opts.min_priority_fee { -// config.limits.min_priority_fee = min_priority_fee; -// } -// -// 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_url = Some(socket_addrs[0].to_string()); -// } -// } -// } -// -// if let Some(sk) = self.signing.private_key { -// let hex_sk = sk.strip_prefix("0x").unwrap_or(&sk); -// let sk = SecretKey::from_bytes(&hex::decode(hex_sk)?) -// .map_err(|e| eyre!("Failed decoding BLS signer secret key: {:?}", e))?; -// Some(sk) -// } else { -// None -// }; -// -// if let Some(builder_sk) = opts.builder_private_key { -// let hex_sk = builder_sk.strip_prefix("0x").unwrap_or(&builder_sk); -// let sk = SecretKey::from_bytes(&hex::decode(hex_sk)?) -// .map_err(|e| eyre!("Failed decoding BLS builder secret key: {:?}", e))?; -// config.builder_private_key = sk; -// } -// -// config.jwt_hex = if opts.jwt_hex.starts_with("0x") { -// opts.jwt_hex.trim_start_matches("0x").to_string() -// } else if Path::new(&opts.jwt_hex).exists() { -// read_to_string(opts.jwt_hex) -// .map_err(|e| eyre!("Failed reading JWT secret file: {:?}", e))? -// .trim_start_matches("0x") -// .to_string() -// } else { -// opts.jwt_hex -// }; -// -// // Validate the JWT secret -// if config.jwt_hex.len() != 64 { -// bail!("Engine JWT secret must be a 32 byte hex string"); -// } else { -// info!("Engine JWT secret loaded successfully"); -// } -// -// 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.constraints_url = opts.constraints_url.parse()?; -// -// config.fee_recipient = opts.fee_recipient; -// -// config.validator_indexes = opts.validator_indexes; -// -// config.chain = opts.chain; -// config.metrics_port = opts.telemetry.metrics_port; -// config.disable_metrics = opts.telemetry.disable_metrics; -// -// Ok(config) -// } -// } - #[cfg(test)] mod tests { use super::*; diff --git a/bolt-sidecar/src/config/signing.rs b/bolt-sidecar/src/config/signing.rs index 810dc9fa7..a6a641062 100644 --- a/bolt-sidecar/src/config/signing.rs +++ b/bolt-sidecar/src/config/signing.rs @@ -1,9 +1,15 @@ -use std::{fmt, net::SocketAddr, ops::Deref}; +use std::{ + fmt::{self, Display}, + fs::read_to_string, + net::SocketAddr, + ops::Deref, + path::Path, +}; use blst::min_pk::SecretKey; use clap::{ArgGroup, Args}; use lighthouse_account_utils::ZeroizeString; -use rand::RngCore; +use rand::{Rng, RngCore}; /// Command-line options for signing #[derive(Args)] @@ -30,7 +36,7 @@ pub struct SigningOpts { group = "signing-opts", requires("commit_boost_url") )] - pub commit_boost_jwt_hex: Option, + pub commit_boost_jwt_hex: Option, /// The password for the ERC-2335 keystore. /// Reference: https://eips.ethereum.org/EIPS/eip-2335 #[clap(long, env = "BOLT_SIDECAR_KEYSTORE_PASSWORD", group = "signing-opts")] @@ -92,3 +98,46 @@ impl fmt::Display for BlsSecretKey { write!(f, "0x{}", hex::encode(self.0.to_bytes())) } } + +#[derive(Debug, Clone)] +pub struct JwtSecretConfig(pub String); + +impl Default for JwtSecretConfig { + fn default() -> Self { + let random_bytes: [u8; 32] = rand::thread_rng().gen(); + let secret = hex::encode(random_bytes); + Self(secret) + } +} + +impl From<&str> for JwtSecretConfig { + fn from(jwt: &str) -> Self { + let jwt = if jwt.starts_with("0x") { + jwt.trim_start_matches("0x").to_string() + } else if Path::new(&jwt).exists() { + read_to_string(jwt) + .unwrap_or_else(|_| panic!("Failed reading JWT secret file: {:?}", jwt)) + .trim_start_matches("0x") + .to_string() + } else { + jwt.to_string() + }; + + assert!(jwt.len() == 64, "Engine JWT secret must be a 32 byte hex string"); + + Self(jwt) + } +} + +impl Deref for JwtSecretConfig { + type Target = str; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Display for JwtSecretConfig { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "0x{}", self.0) + } +} From 094dee356225a93a1e0408d2deb22843cd7ff807 Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Thu, 10 Oct 2024 12:57:27 +0200 Subject: [PATCH 39/64] fix(sidecar): tests --- bolt-sidecar/src/config/signing.rs | 20 +++++--------------- bolt-sidecar/src/config/validator_indexes.rs | 15 +++++++++++---- bolt-sidecar/src/test_util.rs | 9 ++++++--- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/bolt-sidecar/src/config/signing.rs b/bolt-sidecar/src/config/signing.rs index a6a641062..ba068e92f 100644 --- a/bolt-sidecar/src/config/signing.rs +++ b/bolt-sidecar/src/config/signing.rs @@ -15,31 +15,21 @@ use rand::{Rng, RngCore}; #[derive(Args)] #[clap( group = ArgGroup::new("signing-opts").required(true) - .args(&["private_key", "commit_boost_url", "commit_boost_jwt_hex", "keystore_password"]) + .args(&["private_key", "commit_boost_address", "commit_boost_jwt_hex", "keystore_password"]) )] pub struct SigningOpts { /// Private key to use for signing preconfirmation requests - #[clap(long, env = "BOLT_SIDECAR_PRIVATE_KEY", group = "signing-opts")] + #[clap(long, env = "BOLT_SIDECAR_PRIVATE_KEY")] pub private_key: Option, /// Socket address for the commit-boost sidecar - #[clap( - long, - env = "BOLT_SIDECAR_CB_SIGNER_URL", - group = "signing-opts", - requires("commit_boost_jwt_hex") - )] + #[clap(long, env = "BOLT_SIDECAR_CB_SIGNER_URL", requires("commit_boost_jwt_hex"))] pub commit_boost_address: Option, /// JWT in hexadecimal format for authenticating with the commit-boost service - #[clap( - long, - env = "BOLT_SIDECAR_CB_JWT_HEX", - group = "signing-opts", - requires("commit_boost_url") - )] + #[clap(long, env = "BOLT_SIDECAR_CB_JWT_HEX", requires("commit_boost_address"))] pub commit_boost_jwt_hex: Option, /// The password for the ERC-2335 keystore. /// Reference: https://eips.ethereum.org/EIPS/eip-2335 - #[clap(long, env = "BOLT_SIDECAR_KEYSTORE_PASSWORD", group = "signing-opts")] + #[clap(long, env = "BOLT_SIDECAR_KEYSTORE_PASSWORD")] pub keystore_password: Option, } diff --git a/bolt-sidecar/src/config/validator_indexes.rs b/bolt-sidecar/src/config/validator_indexes.rs index 2cfa72ac6..48e8cca0a 100644 --- a/bolt-sidecar/src/config/validator_indexes.rs +++ b/bolt-sidecar/src/config/validator_indexes.rs @@ -1,4 +1,7 @@ -use std::str::FromStr; +use std::{ + fmt::{self, Display}, + str::FromStr, +}; #[derive(Debug, Clone, Default)] pub struct ValidatorIndexes(Vec); @@ -24,6 +27,10 @@ impl FromStr for ValidatorIndexes { let s = s.trim(); let mut vec = Vec::new(); + if s.is_empty() { + return Ok(Self(vec)); + } + for comma_separated_part in s.split(',') { if comma_separated_part.contains("..") { let mut parts = comma_separated_part.split(".."); @@ -51,9 +58,9 @@ impl From> for ValidatorIndexes { } } -impl ToString for ValidatorIndexes { - fn to_string(&self) -> String { - self.0.iter().map(|index| index.to_string()).collect::>().join(",") +impl Display for ValidatorIndexes { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0.iter().map(|index| index.to_string()).collect::>().join(",")) } } diff --git a/bolt-sidecar/src/test_util.rs b/bolt-sidecar/src/test_util.rs index ef22276be..f7128fedb 100644 --- a/bolt-sidecar/src/test_util.rs +++ b/bolt-sidecar/src/test_util.rs @@ -19,7 +19,7 @@ use secp256k1::Message; use tracing::warn; use crate::{ - config::signing::BlsSecretKey, + config::signing::{BlsSecretKey, JwtSecretConfig}, crypto::{ecdsa::SignableECDSA, SignableBLS}, primitives::{ CommitmentRequest, ConstraintsMessage, DelegationMessage, FullTransaction, @@ -80,9 +80,12 @@ pub(crate) async fn try_get_beacon_api_url() -> Option<&'static str> { /// /// If any of the above values can't be found, the function will return `None`. pub(crate) async fn get_test_config() -> Option { + let sk = BlsSecretKey::random_bls_secret().to_string(); + println!("sk: {}", sk); + std::env::set_var("BOLT_SIDECAR_PRIVATE_KEY", BlsSecretKey::random_bls_secret().to_string()); + let _ = dotenvy::dotenv(); - std::env::set_var("BOLT_SIDECAR_PRIVATE_KEY", BlsSecretKey::random_bls_secret().to_string()); let mut opts = Opts::parse(); let Some(jwt) = std::env::var("ENGINE_JWT").ok() else { @@ -99,7 +102,7 @@ pub(crate) async fn get_test_config() -> Option { if let Some(url) = try_get_engine_api_url().await { opts.engine_api_url = url.parse().expect("valid URL"); } - opts.jwt_hex = jwt; + opts.jwt_hex = JwtSecretConfig(jwt); Some(opts) } From 552733699aa54c972b25733f9cc77a887325c38e Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Thu, 10 Oct 2024 14:16:05 +0200 Subject: [PATCH 40/64] chore(sidecar): less verbose opts --- bolt-sidecar/src/config/mod.rs | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/bolt-sidecar/src/config/mod.rs b/bolt-sidecar/src/config/mod.rs index a7fc12b9b..217725330 100644 --- a/bolt-sidecar/src/config/mod.rs +++ b/bolt-sidecar/src/config/mod.rs @@ -1,5 +1,3 @@ -use std::str::FromStr; - use alloy::primitives::Address; use clap::Parser; use reqwest::Url; @@ -34,20 +32,16 @@ pub struct Opts { default_value_t = DEFAULT_RPC_PORT)] pub port: u16, /// URL for the beacon client - #[clap(long, env = "BOLT_SIDECAR_BEACON_API_URL", - default_value_t = Url::parse("http://localhost:5052").expect("Valid Beacon API URL"))] + #[clap(long, env = "BOLT_SIDECAR_BEACON_API_URL", default_value = "http://localhost:5052")] pub beacon_api_url: Url, /// URL for the Constraint sidecar client to use - #[clap(long, env = "BOLT_SIDECAR_CONSTRAINTS_URL", - default_value_t = Url::parse("http://localhost:3030").expect("Valid URL"))] + #[clap(long, env = "BOLT_SIDECAR_CONSTRAINTS_URL", default_value = "http://localhost:3030")] pub constraints_url: Url, /// Execution client API URL - #[clap(long, env = "BOLT_SIDECAR_EXECUTION_API_URL", - default_value_t = Url::parse("http://localhost:8545").expect("Valid Execution API URL"))] + #[clap(long, env = "BOLT_SIDECAR_EXECUTION_API_URL", default_value = "http://localhost:8545")] pub execution_api_url: Url, /// Execution client Engine API URL - #[clap(long, env = "BOLT_SIDECAR_ENGINE_API_URL", - default_value_t = Url::parse("http://localhost:8551").expect("Valid Engine API URL"))] + #[clap(long, env = "BOLT_SIDECAR_ENGINE_API_URL", default_value = "http://localhost:8551")] pub engine_api_url: Url, /// Constraint proxy server port to use #[clap(long, env = "BOLT_SIDECAR_CONSTRAINTS_PROXY_PORT", @@ -58,15 +52,13 @@ pub struct Opts { /// - a comma-separated list of indexes (e.g. "1,2,3,4") /// - a contiguous range of indexes (e.g. "1..4") /// - a mix of the above (e.g. "1,2..4,6..8") - #[clap(long, value_parser = ValidatorIndexes::from_str, env = "BOLT_SIDECAR_VALIDATOR_INDEXES", - default_value_t = ValidatorIndexes::default())] + #[clap(long, env = "BOLT_SIDECAR_VALIDATOR_INDEXES", default_value_t)] pub validator_indexes: ValidatorIndexes, /// The JWT secret token to authenticate calls to the engine API. /// /// It can either be a hex-encoded string or a file path to a file /// containing the hex-encoded secret. - #[clap(long, env = "BOLT_SIDECAR_JWT_HEX", - default_value_t = JwtSecretConfig::default())] + #[clap(long, env = "BOLT_SIDECAR_JWT_HEX", default_value_t)] pub jwt_hex: JwtSecretConfig, /// The fee recipient address for fallback blocks #[clap(long, env = "BOLT_SIDECAR_FEE_RECIPIENT", From 06dc1a08d11263be18c19d85ed9676101e7dee6a Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Thu, 10 Oct 2024 14:30:47 +0200 Subject: [PATCH 41/64] refactor(sidecar): cleanup between different bls signers --- bolt-sidecar/src/builder/mod.rs | 4 +- bolt-sidecar/src/common.rs | 85 +++++++++++++++++++++++++++++ bolt-sidecar/src/config/mod.rs | 7 ++- bolt-sidecar/src/config/signing.rs | 88 ++---------------------------- bolt-sidecar/src/signer/local.rs | 32 +++++------ bolt-sidecar/src/signer/mod.rs | 10 ++-- bolt-sidecar/src/test_util.rs | 6 +- 7 files changed, 116 insertions(+), 116 deletions(-) diff --git a/bolt-sidecar/src/builder/mod.rs b/bolt-sidecar/src/builder/mod.rs index 7c75f22a0..1ea89bb76 100644 --- a/bolt-sidecar/src/builder/mod.rs +++ b/bolt-sidecar/src/builder/mod.rs @@ -9,7 +9,7 @@ use payload_builder::FallbackPayloadBuilder; use signature::sign_builder_message; use crate::{ - config::signing::BlsSecretKey, + common::BlsSecretKeyWrapper, primitives::{ BuilderBid, GetPayloadResponse, PayloadAndBid, PayloadAndBlobs, SignedBuilderBid, }, @@ -65,7 +65,7 @@ pub enum BuilderError { pub struct LocalBuilder { /// BLS credentials for the local builder. We use this to sign the /// payload bid submissions built by the sidecar. - secret_key: BlsSecretKey, + secret_key: BlsSecretKeyWrapper, /// Chain configuration /// (necessary for signing messages with the correct domain) chain: ChainConfig, diff --git a/bolt-sidecar/src/common.rs b/bolt-sidecar/src/common.rs index 0563a0296..b6366792c 100644 --- a/bolt-sidecar/src/common.rs +++ b/bolt-sidecar/src/common.rs @@ -1,4 +1,13 @@ +use std::{ + fmt::{self, Display}, + fs::read_to_string, + ops::Deref, + path::Path, +}; + use alloy::primitives::U256; +use blst::min_pk::SecretKey; +use rand::{Rng, RngCore}; use reth_primitives::PooledTransactionsElement; use crate::{ @@ -86,6 +95,82 @@ pub fn validate_transaction( Ok(()) } +#[derive(Clone, Debug)] +pub struct BlsSecretKeyWrapper(pub SecretKey); + +impl BlsSecretKeyWrapper { + pub fn random() -> Self { + let mut rng = rand::thread_rng(); + let mut ikm = [0u8; 32]; + rng.fill_bytes(&mut ikm); + Self(SecretKey::key_gen(&ikm, &[]).unwrap()) + } +} + +impl From<&str> for BlsSecretKeyWrapper { + fn from(sk: &str) -> Self { + let hex_sk = sk.strip_prefix("0x").unwrap_or(sk); + let sk = SecretKey::from_bytes(&hex::decode(hex_sk).expect("valid hex")).expect("valid sk"); + BlsSecretKeyWrapper(sk) + } +} + +impl Deref for BlsSecretKeyWrapper { + type Target = SecretKey; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl fmt::Display for BlsSecretKeyWrapper { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "0x{}", hex::encode(self.0.to_bytes())) + } +} + +#[derive(Debug, Clone)] +pub struct JwtSecretConfig(pub String); + +impl Default for JwtSecretConfig { + fn default() -> Self { + let random_bytes: [u8; 32] = rand::thread_rng().gen(); + let secret = hex::encode(random_bytes); + Self(secret) + } +} + +impl From<&str> for JwtSecretConfig { + fn from(jwt: &str) -> Self { + let jwt = if jwt.starts_with("0x") { + jwt.trim_start_matches("0x").to_string() + } else if Path::new(&jwt).exists() { + read_to_string(jwt) + .unwrap_or_else(|_| panic!("Failed reading JWT secret file: {:?}", jwt)) + .trim_start_matches("0x") + .to_string() + } else { + jwt.to_string() + }; + + assert!(jwt.len() == 64, "Engine JWT secret must be a 32 byte hex string"); + + Self(jwt) + } +} + +impl Deref for JwtSecretConfig { + type Target = str; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Display for JwtSecretConfig { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "0x{}", self.0) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/bolt-sidecar/src/config/mod.rs b/bolt-sidecar/src/config/mod.rs index 217725330..2e6362090 100644 --- a/bolt-sidecar/src/config/mod.rs +++ b/bolt-sidecar/src/config/mod.rs @@ -1,7 +1,6 @@ use alloy::primitives::Address; use clap::Parser; use reqwest::Url; -use signing::{BlsSecretKey, JwtSecretConfig}; pub mod validator_indexes; pub use validator_indexes::ValidatorIndexes; @@ -18,6 +17,8 @@ use telemetry::TelemetryOpts; pub mod limits; use limits::LimitsOpts; +use crate::common::{BlsSecretKeyWrapper, JwtSecretConfig}; + /// Default port for the JSON-RPC server exposed by the sidecar. pub const DEFAULT_RPC_PORT: u16 = 8000; @@ -67,8 +68,8 @@ pub struct Opts { /// Secret BLS key to sign fallback payloads with /// (If not provided, a random key will be used) #[clap(long, env = "BOLT_SIDECAR_BUILDER_PRIVATE_KEY", - default_value_t = BlsSecretKey::random_bls_secret())] - pub builder_private_key: BlsSecretKey, + default_value_t = BlsSecretKeyWrapper::random())] + pub builder_private_key: BlsSecretKeyWrapper, /// Operating limits for the sidecar #[clap(flatten)] pub limits: LimitsOpts, diff --git a/bolt-sidecar/src/config/signing.rs b/bolt-sidecar/src/config/signing.rs index ba068e92f..c204edfac 100644 --- a/bolt-sidecar/src/config/signing.rs +++ b/bolt-sidecar/src/config/signing.rs @@ -1,15 +1,11 @@ +use crate::common::{BlsSecretKeyWrapper, JwtSecretConfig}; use std::{ - fmt::{self, Display}, - fs::read_to_string, + fmt::{self}, net::SocketAddr, - ops::Deref, - path::Path, }; -use blst::min_pk::SecretKey; use clap::{ArgGroup, Args}; use lighthouse_account_utils::ZeroizeString; -use rand::{Rng, RngCore}; /// Command-line options for signing #[derive(Args)] @@ -20,7 +16,7 @@ use rand::{Rng, RngCore}; pub struct SigningOpts { /// Private key to use for signing preconfirmation requests #[clap(long, env = "BOLT_SIDECAR_PRIVATE_KEY")] - pub private_key: Option, + pub private_key: Option, /// Socket address for the commit-boost sidecar #[clap(long, env = "BOLT_SIDECAR_CB_SIGNER_URL", requires("commit_boost_jwt_hex"))] pub commit_boost_address: Option, @@ -48,86 +44,10 @@ impl fmt::Debug for SigningOpts { impl Default for SigningOpts { fn default() -> Self { Self { - private_key: Some(BlsSecretKey::random_bls_secret()), + private_key: Some(BlsSecretKeyWrapper::random()), commit_boost_address: None, commit_boost_jwt_hex: None, keystore_password: None, } } } - -#[derive(Clone, Debug)] -pub struct BlsSecretKey(pub SecretKey); - -impl BlsSecretKey { - pub fn random_bls_secret() -> Self { - let mut rng = rand::thread_rng(); - let mut ikm = [0u8; 32]; - rng.fill_bytes(&mut ikm); - Self(SecretKey::key_gen(&ikm, &[]).unwrap()) - } -} - -impl From<&str> for BlsSecretKey { - fn from(sk: &str) -> Self { - let hex_sk = sk.strip_prefix("0x").unwrap_or(sk); - let sk = SecretKey::from_bytes(&hex::decode(hex_sk).expect("valid hex")).expect("valid sk"); - BlsSecretKey(sk) - } -} - -impl Deref for BlsSecretKey { - type Target = SecretKey; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl fmt::Display for BlsSecretKey { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "0x{}", hex::encode(self.0.to_bytes())) - } -} - -#[derive(Debug, Clone)] -pub struct JwtSecretConfig(pub String); - -impl Default for JwtSecretConfig { - fn default() -> Self { - let random_bytes: [u8; 32] = rand::thread_rng().gen(); - let secret = hex::encode(random_bytes); - Self(secret) - } -} - -impl From<&str> for JwtSecretConfig { - fn from(jwt: &str) -> Self { - let jwt = if jwt.starts_with("0x") { - jwt.trim_start_matches("0x").to_string() - } else if Path::new(&jwt).exists() { - read_to_string(jwt) - .unwrap_or_else(|_| panic!("Failed reading JWT secret file: {:?}", jwt)) - .trim_start_matches("0x") - .to_string() - } else { - jwt.to_string() - }; - - assert!(jwt.len() == 64, "Engine JWT secret must be a 32 byte hex string"); - - Self(jwt) - } -} - -impl Deref for JwtSecretConfig { - type Target = str; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl Display for JwtSecretConfig { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "0x{}", self.0) - } -} diff --git a/bolt-sidecar/src/signer/local.rs b/bolt-sidecar/src/signer/local.rs index f9cd38f00..3ca839978 100644 --- a/bolt-sidecar/src/signer/local.rs +++ b/bolt-sidecar/src/signer/local.rs @@ -1,10 +1,10 @@ use std::fmt::Debug; use blst::{min_pk::Signature, BLST_ERROR}; -use ethereum_consensus::{crypto::PublicKey as BlsPublicKey, deneb::compute_signing_root}; +use ethereum_consensus::{crypto::PublicKey as ClPublicKey, deneb::compute_signing_root}; use crate::{crypto::bls::BLSSig, ChainConfig}; -pub use blst::min_pk::SecretKey as BlsSecretKey; +pub use blst::min_pk::SecretKey; /// The BLS Domain Separator used in Ethereum 2.0. pub const BLS_DST_PREFIX: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"; @@ -13,7 +13,7 @@ pub const BLS_DST_PREFIX: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_" #[derive(Clone)] pub struct LocalSigner { chain: ChainConfig, - key: BlsSecretKey, + key: SecretKey, } impl Debug for LocalSigner { @@ -27,20 +27,14 @@ impl Debug for LocalSigner { impl LocalSigner { /// Create a new signer with the given BLS secret key. - pub fn new(key: BlsSecretKey, chain: ChainConfig) -> Self { + pub fn new(key: SecretKey, chain: ChainConfig) -> Self { Self { key, chain } } - /// Create a signer with a random BLS key configured for Mainnet for testing. - #[cfg(test)] - pub fn random() -> Self { - Self { key: random_bls_secret(), chain: ChainConfig::mainnet() } - } - /// Get the public key of the signer. - pub fn pubkey(&self) -> BlsPublicKey { + pub fn pubkey(&self) -> ClPublicKey { let pk = self.key.sk_to_pk(); - BlsPublicKey::try_from(pk.to_bytes().as_ref()).unwrap() + ClPublicKey::try_from(pk.to_bytes().as_ref()).unwrap() } /// Sign an SSZ object root with the Application Builder domain. @@ -97,14 +91,14 @@ impl LocalSigner { } } -/// Generate a random BLS secret key. #[cfg(test)] -pub fn random_bls_secret() -> BlsSecretKey { - use rand::RngCore; - let mut rng = rand::thread_rng(); - let mut ikm = [0u8; 32]; - rng.fill_bytes(&mut ikm); - BlsSecretKey::key_gen(&ikm, &[]).unwrap() +impl LocalSigner { + /// Create a signer with a random BLS key configured for Mainnet for testing. + pub fn random() -> Self { + use crate::common::BlsSecretKeyWrapper; + + Self { key: BlsSecretKeyWrapper::random().0, chain: ChainConfig::mainnet() } + } } #[cfg(test)] diff --git a/bolt-sidecar/src/signer/mod.rs b/bolt-sidecar/src/signer/mod.rs index f52e34909..bbed32f7b 100644 --- a/bolt-sidecar/src/signer/mod.rs +++ b/bolt-sidecar/src/signer/mod.rs @@ -1,11 +1,11 @@ -use keystore::KeystoreSigner; -use local::LocalSigner; - -use crate::CommitBoostSigner; - pub mod commit_boost; +use commit_boost::CommitBoostSigner; + pub mod keystore; +use keystore::KeystoreSigner; + pub mod local; +use local::LocalSigner; #[derive(Debug, Clone)] /// Signer for BLS signatures. diff --git a/bolt-sidecar/src/test_util.rs b/bolt-sidecar/src/test_util.rs index f7128fedb..0fef94c72 100644 --- a/bolt-sidecar/src/test_util.rs +++ b/bolt-sidecar/src/test_util.rs @@ -19,7 +19,7 @@ use secp256k1::Message; use tracing::warn; use crate::{ - config::signing::{BlsSecretKey, JwtSecretConfig}, + common::{BlsSecretKeyWrapper, JwtSecretConfig}, crypto::{ecdsa::SignableECDSA, SignableBLS}, primitives::{ CommitmentRequest, ConstraintsMessage, DelegationMessage, FullTransaction, @@ -80,9 +80,9 @@ pub(crate) async fn try_get_beacon_api_url() -> Option<&'static str> { /// /// If any of the above values can't be found, the function will return `None`. pub(crate) async fn get_test_config() -> Option { - let sk = BlsSecretKey::random_bls_secret().to_string(); + let sk = BlsSecretKeyWrapper::random().to_string(); println!("sk: {}", sk); - std::env::set_var("BOLT_SIDECAR_PRIVATE_KEY", BlsSecretKey::random_bls_secret().to_string()); + std::env::set_var("BOLT_SIDECAR_PRIVATE_KEY", BlsSecretKeyWrapper::random().to_string()); let _ = dotenvy::dotenv(); From d3d7a80ecab5acc6e7e2af8b7029eb23309c65da Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Thu, 10 Oct 2024 14:32:32 +0200 Subject: [PATCH 42/64] fix(sidecar): revert LimitOpts alias --- bolt-sidecar/src/state/execution.rs | 38 ++++++++++++++--------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/bolt-sidecar/src/state/execution.rs b/bolt-sidecar/src/state/execution.rs index 249a5f7a9..29073c299 100644 --- a/bolt-sidecar/src/state/execution.rs +++ b/bolt-sidecar/src/state/execution.rs @@ -13,7 +13,7 @@ use tracing::{debug, trace}; use crate::{ builder::BlockTemplate, common::{calculate_max_basefee, max_transaction_cost, validate_transaction}, - config::limits::LimitsOpts as Limits, + config::limits::LimitsOpts, primitives::{AccountState, CommitmentRequest, SignedConstraints, Slot}, }; @@ -154,7 +154,7 @@ pub struct ExecutionState { /// The chain ID of the chain (constant). chain_id: u64, /// The limits set for the sidecar. - limits: Limits, + limits: LimitsOpts, /// The KZG settings for validating blobs. kzg_settings: EnvKzgSettings, /// The state fetcher client. @@ -184,7 +184,7 @@ impl Default for ValidationParams { impl ExecutionState { /// Creates a new state with the given client, initializing the /// basefee and head block number. - pub async fn new(client: C, limits: Limits) -> Result { + pub async fn new(client: C, limits: LimitsOpts) -> Result { let (basefee, blob_basefee, block_number, chain_id) = tokio::try_join!( client.get_basefee(None), client.get_blob_basefee(None), @@ -557,7 +557,7 @@ mod tests { let anvil = launch_anvil(); let client = StateClient::new(anvil.endpoint_url()); - let mut state = ExecutionState::new(client.clone(), Limits::default()).await?; + let mut state = ExecutionState::new(client.clone(), LimitsOpts::default()).await?; let sender = anvil.addresses().first().unwrap(); let sender_pk = anvil.keys().first().unwrap(); @@ -582,7 +582,7 @@ mod tests { let anvil = launch_anvil(); let client = StateClient::new(anvil.endpoint_url()); - let mut state = ExecutionState::new(client.clone(), Limits::default()).await?; + let mut state = ExecutionState::new(client.clone(), LimitsOpts::default()).await?; let sender = anvil.addresses().first().unwrap(); let sender_pk = anvil.keys().first().unwrap(); @@ -620,7 +620,7 @@ mod tests { let anvil = launch_anvil(); let client = StateClient::new(anvil.endpoint_url()); - let mut state = ExecutionState::new(client.clone(), Limits::default()).await?; + let mut state = ExecutionState::new(client.clone(), LimitsOpts::default()).await?; let sender = anvil.addresses().first().unwrap(); let sender_pk = anvil.keys().first().unwrap(); @@ -669,7 +669,7 @@ mod tests { let anvil = launch_anvil(); let client = StateClient::new(anvil.endpoint_url()); - let mut state = ExecutionState::new(client.clone(), Limits::default()).await?; + let mut state = ExecutionState::new(client.clone(), LimitsOpts::default()).await?; let sender = anvil.addresses().first().unwrap(); let sender_pk = anvil.keys().first().unwrap(); @@ -699,7 +699,7 @@ mod tests { let anvil = launch_anvil(); let client = StateClient::new(anvil.endpoint_url()); - let mut state = ExecutionState::new(client.clone(), Limits::default()).await?; + let mut state = ExecutionState::new(client.clone(), LimitsOpts::default()).await?; let sender = anvil.addresses().first().unwrap(); let sender_pk = anvil.keys().first().unwrap(); @@ -761,7 +761,7 @@ mod tests { let anvil = launch_anvil(); let client = StateClient::new(anvil.endpoint_url()); - let limits = Limits { + let limits = LimitsOpts { max_commitments_per_slot: NonZero::new(10).unwrap(), max_committed_gas_per_slot: NonZero::new(5_000_000).unwrap(), min_priority_fee: NonZero::new(200000000).unwrap(), // 0.2 gwei @@ -800,7 +800,7 @@ mod tests { let anvil = launch_anvil(); let client = StateClient::new(anvil.endpoint_url()); - let limits = Limits { + let limits = LimitsOpts { max_commitments_per_slot: NonZero::new(10).unwrap(), max_committed_gas_per_slot: NonZero::new(5_000_000).unwrap(), min_priority_fee: NonZero::new(2000000000).unwrap(), @@ -831,7 +831,7 @@ mod tests { let anvil = launch_anvil(); let client = StateClient::new(anvil.endpoint_url()); - let limits = Limits { + let limits = LimitsOpts { max_commitments_per_slot: NonZero::new(10).unwrap(), max_committed_gas_per_slot: NonZero::new(5_000_000).unwrap(), min_priority_fee: NonZero::new(2 * GWEI_TO_WEI as u128).unwrap(), @@ -873,7 +873,7 @@ mod tests { let anvil = launch_anvil(); let client = StateClient::new(anvil.endpoint_url()); - let limits = Limits { + let limits = LimitsOpts { max_commitments_per_slot: NonZero::new(10).unwrap(), max_committed_gas_per_slot: NonZero::new(5_000_000).unwrap(), min_priority_fee: NonZero::new(2 * GWEI_TO_WEI as u128).unwrap(), @@ -920,7 +920,7 @@ mod tests { let anvil = launch_anvil(); let client = StateClient::new(anvil.endpoint_url()); - let limits = Limits { + let limits = LimitsOpts { max_commitments_per_slot: NonZero::new(10).unwrap(), max_committed_gas_per_slot: NonZero::new(5_000_000).unwrap(), min_priority_fee: NonZero::new(2 * GWEI_TO_WEI as u128).unwrap(), @@ -963,7 +963,7 @@ mod tests { let client = StateClient::new(anvil.endpoint_url()); let provider = ProviderBuilder::new().on_http(anvil.endpoint_url()); - let mut state = ExecutionState::new(client.clone(), Limits::default()).await?; + let mut state = ExecutionState::new(client.clone(), LimitsOpts::default()).await?; let sender = anvil.addresses().first().unwrap(); let sender_pk = anvil.keys().first().unwrap(); @@ -1016,7 +1016,7 @@ mod tests { let anvil = launch_anvil(); let client = StateClient::new(anvil.endpoint_url()); - let mut state = ExecutionState::new(client.clone(), Limits::default()).await?; + let mut state = ExecutionState::new(client.clone(), LimitsOpts::default()).await?; let sender = anvil.addresses().first().unwrap(); let sender_pk = anvil.keys().first().unwrap(); @@ -1058,7 +1058,7 @@ mod tests { let anvil = launch_anvil(); let client = StateClient::new(anvil.endpoint_url()); - let limits: Limits = Limits { + let limits: LimitsOpts = LimitsOpts { max_commitments_per_slot: NonZero::new(10).unwrap(), max_committed_gas_per_slot: NonZero::new(5_000_000).unwrap(), min_priority_fee: NonZero::new(1000000000).unwrap(), @@ -1109,7 +1109,7 @@ mod tests { let anvil = launch_anvil(); let client = StateClient::new(anvil.endpoint_url()); - let mut state = ExecutionState::new(client.clone(), Limits::default()).await?; + let mut state = ExecutionState::new(client.clone(), LimitsOpts::default()).await?; let sender = anvil.addresses().first().unwrap(); let sender_pk = anvil.keys().first().unwrap(); @@ -1136,7 +1136,7 @@ mod tests { let anvil = launch_anvil(); let client = StateClient::new(anvil.endpoint_url()); - let mut state = ExecutionState::new(client.clone(), Limits::default()).await?; + let mut state = ExecutionState::new(client.clone(), LimitsOpts::default()).await?; let sender = anvil.addresses().first().unwrap(); let sender_pk = anvil.keys().first().unwrap(); @@ -1166,7 +1166,7 @@ mod tests { let anvil = launch_anvil(); let client = StateClient::new(anvil.endpoint_url()); - let mut state = ExecutionState::new(client.clone(), Limits::default()).await?; + let mut state = ExecutionState::new(client.clone(), LimitsOpts::default()).await?; let sender = anvil.addresses().first().unwrap(); let sender_pk = anvil.keys().first().unwrap(); From 6bade57d4501542291c285fb9372d83af057f143 Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Thu, 10 Oct 2024 14:38:28 +0200 Subject: [PATCH 43/64] fix(sidecar): keystore validation logic --- bolt-sidecar/src/signer/keystore.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bolt-sidecar/src/signer/keystore.rs b/bolt-sidecar/src/signer/keystore.rs index e05373503..931cd1f53 100644 --- a/bolt-sidecar/src/signer/keystore.rs +++ b/bolt-sidecar/src/signer/keystore.rs @@ -12,6 +12,7 @@ use eyre::eyre; use lighthouse_bls::Keypair; use lighthouse_eth2_keystore::Keystore; +use ssz::Encode; use crate::crypto::bls::BLSSig; @@ -50,11 +51,11 @@ impl KeystoreSigner { root: [u8; 32], public_key: [u8; BLS_PUBLIC_KEY_BYTES_LEN], ) -> eyre::Result { - // NOTE: is this a good comparison? let sk = self .keypairs .iter() - .find(|kp| kp.pk.as_hex_string() == hex::encode(public_key)) + // NOTE: need to check if this method returns just the raw bytes + .find(|kp| kp.pk.as_ssz_bytes() == public_key.as_ref()) .ok_or(eyre!("could not find private key associated to public key"))?; let sig = hex::decode(sk.sk.sign(root.into()).to_string())?; From 9db5347b1409fe877156f3d50c9b95798124ad1a Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Thu, 10 Oct 2024 14:39:09 +0200 Subject: [PATCH 44/64] fix(sidecar): restore Copy to Limits --- bolt-sidecar/src/config/limits.rs | 2 +- bolt-sidecar/src/driver.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bolt-sidecar/src/config/limits.rs b/bolt-sidecar/src/config/limits.rs index 7424672eb..6bf02c47a 100644 --- a/bolt-sidecar/src/config/limits.rs +++ b/bolt-sidecar/src/config/limits.rs @@ -7,7 +7,7 @@ pub const DEFAULT_MAX_COMMITTED_GAS: u64 = 10_000_000; pub const DEFAULT_MIN_PRIORITY_FEE: u128 = 1_000_000_000; // 1 Gwei /// Limits for the sidecar. -#[derive(Debug, Parser, Clone)] +#[derive(Debug, Parser, Clone, Copy)] pub struct LimitsOpts { /// Max number of commitments to accept per block #[clap(long, env = "BOLT_SIDECAR_MAX_COMMITMENTS", diff --git a/bolt-sidecar/src/driver.rs b/bolt-sidecar/src/driver.rs index 060120671..df50322be 100644 --- a/bolt-sidecar/src/driver.rs +++ b/bolt-sidecar/src/driver.rs @@ -133,7 +133,7 @@ impl SidecarDriver { ) -> eyre::Result { let constraints_client = ConstraintsClient::new(opts.constraints_url.clone()); let beacon_client = BeaconClient::new(opts.beacon_api_url.clone()); - let execution = ExecutionState::new(fetcher, opts.limits.clone()).await?; + let execution = ExecutionState::new(fetcher, opts.limits).await?; let genesis_time = beacon_client.get_genesis_details().await?.genesis_time; let slot_stream = From 59a0836742d4d986ba0e79e824e78ca6420d773b Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Thu, 10 Oct 2024 15:22:44 +0200 Subject: [PATCH 45/64] test(sidecar): fix some of the test after rebase remove log as well --- bolt-sidecar/src/builder/payload_builder.rs | 8 ++++---- bolt-sidecar/src/test_util.rs | 6 ++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/bolt-sidecar/src/builder/payload_builder.rs b/bolt-sidecar/src/builder/payload_builder.rs index 1eba21b9d..3a69dcc86 100644 --- a/bolt-sidecar/src/builder/payload_builder.rs +++ b/bolt-sidecar/src/builder/payload_builder.rs @@ -449,14 +449,14 @@ mod tests { let wallet = EthereumWallet::from(signer); let addy = Address::from_private_key(&sk); - let tx = default_test_transaction(addy, Some(1)).with_chain_id(1); + let tx = default_test_transaction(addy, Some(3)).with_chain_id(1); let tx_signed = tx.build(&wallet).await?; let raw_encoded = tx_signed.encoded_2718(); let tx_signed_reth = TransactionSigned::decode_enveloped(&mut raw_encoded.as_slice())?; - let slot = genesis_time + - (SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs() / cfg.chain.slot_time()) + - 1; + let slot = genesis_time + + (SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs() / cfg.chain.slot_time()) + + 1; let block = builder.build_fallback_payload(slot, &[tx_signed_reth]).await?; assert_eq!(block.body.len(), 1); diff --git a/bolt-sidecar/src/test_util.rs b/bolt-sidecar/src/test_util.rs index 0fef94c72..cbf7d67a4 100644 --- a/bolt-sidecar/src/test_util.rs +++ b/bolt-sidecar/src/test_util.rs @@ -1,4 +1,4 @@ -use crate::{signer::local::random_bls_secret, ChainConfig}; +use crate::ChainConfig; use alloy::{ eips::eip2718::Encodable2718, network::{EthereumWallet, TransactionBuilder}, @@ -80,8 +80,6 @@ pub(crate) async fn try_get_beacon_api_url() -> Option<&'static str> { /// /// If any of the above values can't be found, the function will return `None`. pub(crate) async fn get_test_config() -> Option { - let sk = BlsSecretKeyWrapper::random().to_string(); - println!("sk: {}", sk); std::env::set_var("BOLT_SIDECAR_PRIVATE_KEY", BlsSecretKeyWrapper::random().to_string()); let _ = dotenvy::dotenv(); @@ -199,7 +197,7 @@ fn random_constraints(count: usize) -> Vec { #[tokio::test] async fn generate_test_data_kurtosis() { - let signer = LocalSigner::new(random_bls_secret(), ChainConfig::kurtosis(0, 0)); + let signer = LocalSigner::new(BlsSecretKeyWrapper::random().0, ChainConfig::kurtosis(0, 0)); let pk = signer.pubkey(); println!("Validator Public Key: {}", hex::encode(pk.as_ref())); From 7c82e692c561fad19cfd66c710c0c2498ac8e5bb Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Thu, 10 Oct 2024 17:36:22 +0200 Subject: [PATCH 46/64] dep(sidecar): add tempfile --- bolt-sidecar/Cargo.lock | 11 ++++++----- bolt-sidecar/Cargo.toml | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/bolt-sidecar/Cargo.lock b/bolt-sidecar/Cargo.lock index 64b0123ce..e3b816772 100644 --- a/bolt-sidecar/Cargo.lock +++ b/bolt-sidecar/Cargo.lock @@ -1675,6 +1675,7 @@ dependencies = [ "serde", "serde_json", "ssz_rs 0.9.0 (git+https://github.com/ralexstokes/ssz-rs)", + "tempfile", "thiserror", "tokio", "tower-http", @@ -4542,7 +4543,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -6554,9 +6555,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.35" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a85d50532239da68e9addb745ba38ff4612a242c1c7ceea689c4bc7c2f43c36f" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags 2.6.0", "errno", @@ -7627,9 +7628,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ "cfg-if", "fastrand 2.1.1", diff --git a/bolt-sidecar/Cargo.toml b/bolt-sidecar/Cargo.toml index 6501a3d7f..0aa4535c7 100644 --- a/bolt-sidecar/Cargo.toml +++ b/bolt-sidecar/Cargo.toml @@ -79,6 +79,7 @@ cb-common = { git = "https://github.com/Commit-Boost/commit-boost-client", rev = [dev-dependencies] alloy-node-bindings = "0.2.0" +tempfile = "3.13.0" [[bin]] From d558754e6421c4b8f28511c900bc05eaaa4dec44 Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Thu, 10 Oct 2024 17:37:28 +0200 Subject: [PATCH 47/64] feat(sidecar): add sign with domain method to keystore signer --- bolt-sidecar/src/driver.rs | 1 + bolt-sidecar/src/signer/keystore.rs | 22 +++++++++++++++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/bolt-sidecar/src/driver.rs b/bolt-sidecar/src/driver.rs index df50322be..812fc82c7 100644 --- a/bolt-sidecar/src/driver.rs +++ b/bolt-sidecar/src/driver.rs @@ -89,6 +89,7 @@ impl SidecarDriver { let keystore_signer = SignerBLS::Keystore(KeystoreSigner::new( None, opts.signing.keystore_password.as_ref().expect("keystore password").as_ref(), + opts.chain, )?); // Commitment responses are signed with a regular Ethereum wallet private key. diff --git a/bolt-sidecar/src/signer/keystore.rs b/bolt-sidecar/src/signer/keystore.rs index 931cd1f53..00c0dcc16 100644 --- a/bolt-sidecar/src/signer/keystore.rs +++ b/bolt-sidecar/src/signer/keystore.rs @@ -14,17 +14,18 @@ use lighthouse_bls::Keypair; use lighthouse_eth2_keystore::Keystore; use ssz::Encode; -use crate::crypto::bls::BLSSig; +use crate::{builder::signature::compute_signing_root, crypto::bls::BLSSig, ChainConfig}; pub const KEYSTORES_DEFAULT_PATH: &str = "keys"; #[derive(Clone)] pub struct KeystoreSigner { keypairs: Vec, + chain: ChainConfig, } impl KeystoreSigner { - pub fn new(keys_path: Option<&str>, password: &[u8]) -> eyre::Result { + pub fn new(keys_path: Option<&str>, password: &[u8], chain: ChainConfig) -> eyre::Result { let keystores_paths = keystore_paths(keys_path)?; let mut keypairs = Vec::with_capacity(keystores_paths.len()); @@ -43,22 +44,33 @@ impl KeystoreSigner { keypairs.push(keypair); } - Ok(Self { keypairs }) + Ok(Self { keypairs, chain }) } pub fn sign_commit_boost_root( &self, root: [u8; 32], public_key: [u8; BLS_PUBLIC_KEY_BYTES_LEN], + ) -> eyre::Result { + self.sign_root(root, public_key, self.chain.commit_boost_domain()) + } + + fn sign_root( + &self, + root: [u8; 32], + public_key: [u8; BLS_PUBLIC_KEY_BYTES_LEN], + domain: [u8; 32], ) -> eyre::Result { let sk = self .keypairs .iter() - // NOTE: need to check if this method returns just the raw bytes + // `as_ssz_bytes` returns the raw bytes we need .find(|kp| kp.pk.as_ssz_bytes() == public_key.as_ref()) .ok_or(eyre!("could not find private key associated to public key"))?; - let sig = hex::decode(sk.sk.sign(root.into()).to_string())?; + let signing_root = compute_signing_root(root, domain); + + let sig = sk.sk.sign(signing_root.into()).as_ssz_bytes(); let sig = BLSSig::try_from(sig.as_slice()).map_err(|_| eyre!("invalid signature length"))?; From 5356c8f19dfee99d4627bc1b350b9ffcffcc532f Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Thu, 10 Oct 2024 17:37:54 +0200 Subject: [PATCH 48/64] test(sidecar): add e2e test for keystore signer --- bolt-sidecar/src/signer/keystore.rs | 117 ++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/bolt-sidecar/src/signer/keystore.rs b/bolt-sidecar/src/signer/keystore.rs index 00c0dcc16..6513fcba9 100644 --- a/bolt-sidecar/src/signer/keystore.rs +++ b/bolt-sidecar/src/signer/keystore.rs @@ -119,3 +119,120 @@ fn keystore_paths(keys_path: Option<&str>) -> Result, eyre::Error> Ok(keystores_paths) } + +#[cfg(test)] +mod tests { + use std::{fs::File, io::Write}; + + use blst::min_pk::SecretKey; + + use crate::{signer::local::LocalSigner, ChainConfig}; + + use super::{KeystoreSigner, KEYSTORES_DEFAULT_PATH}; + /// The str path of the root of the project + pub const CARGO_MANIFEST_DIR: &str = env!("CARGO_MANIFEST_DIR"); + + #[test] + fn test_keystore_signer() { + // 0. Test data setup + + // Reference: https://eips.ethereum.org/EIPS/eip-2335#test-cases + let test_keystore_json = r#" + { + "crypto": { + "kdf": { + "function": "scrypt", + "params": { + "dklen": 32, + "n": 262144, + "p": 1, + "r": 8, + "salt": "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" + }, + "message": "" + }, + "checksum": { + "function": "sha256", + "params": {}, + "message": "d2217fe5f3e9a1e34581ef8a78f7c9928e436d36dacc5e846690a5581e8ea484" + }, + "cipher": { + "function": "aes-128-ctr", + "params": { + "iv": "264daa3f303d7259501c93d997d84fe6" + }, + "message": "06ae90d55fe0a6e9c5c3bc5b170827b2e5cce3929ed3f116c2811e6366dfe20f" + } + }, + "description": "This is a test keystore that uses scrypt to secure the secret.", + "pubkey": "9612d7a727c9d0a22e185a1c768478dfe919cada9266988cb32359c11f2b7b27f4ae4040902382ae2910c15e2b420d07", + "path": "m/12381/60/3141592653/589793238", + "uuid": "1d85ae20-35c5-4611-98e8-aa14a633906f", + "version": 4 + } + "#; + // Reference: https://eips.ethereum.org/EIPS/eip-2335#test-cases + let keystore_password = r#"𝔱𝔢𝔰𝔱𝔭𝔞𝔰𝔰𝔴𝔬𝔯𝔡🔑"#; + let keystore_public_key = "0x9612d7a727c9d0a22e185a1c768478dfe919cada9266988cb32359c11f2b7b27f4ae4040902382ae2910c15e2b420d07"; + let keystore_publlc_key_bytes: [u8; 48] = [ + 0x96, 0x12, 0xd7, 0xa7, 0x27, 0xc9, 0xd0, 0xa2, 0x2e, 0x18, 0x5a, 0x1c, 0x76, 0x84, + 0x78, 0xdf, 0xe9, 0x19, 0xca, 0xda, 0x92, 0x66, 0x98, 0x8c, 0xb3, 0x23, 0x59, 0xc1, + 0x1f, 0x2b, 0x7b, 0x27, 0xf4, 0xae, 0x40, 0x40, 0x90, 0x23, 0x82, 0xae, 0x29, 0x10, + 0xc1, 0x5e, 0x2b, 0x42, 0x0d, 0x07, + ]; + let keystore_secret_key = + "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"; + let chain_config = ChainConfig::mainnet(); + + // 1. Create a temp directory with the keystore and create a signer from it + + let path_str = format!("{}/{}", CARGO_MANIFEST_DIR, KEYSTORES_DEFAULT_PATH); + let tmp_dir = + tempfile::TempDir::with_prefix_in("0xdeadbeefdeadbeefdeadbeefdeadbeef", path_str) + .expect("to create temp dir"); + + // NOTE: it is sufficient to create a temp dir, then we can create a file as usual and it + // will be dropped correctly + let mut tmp_file = File::create_new(tmp_dir.path().join("voting-keystore.json")) + .expect("to create new file"); + + tmp_file.write_all(test_keystore_json.as_bytes()).expect("to write to temp file"); + + for entry in tmp_dir.path().read_dir().expect("to read tmp dir") { + let mut path = entry.expect("to read entry").path(); + println!("inside loop: {:?}", path); + let extenstion = + path.extension().expect("to get extension").to_str().expect("to convert to str"); + + if extenstion.contains("tmp") { + path.set_extension("json"); + println!("path: {:?}", path); + break; + } + } + + let keystore_signer = KeystoreSigner::new(None, keystore_password.as_bytes(), chain_config) + .expect("to create keystore signer"); + + assert_eq!(keystore_signer.keypairs.len(), 1); + assert_eq!( + keystore_signer.keypairs.first().expect("to get keypair").pk.to_string(), + keystore_public_key + ); + + // 2. Sign a message with the signer and check the signature + + let keystore_sk_bls = SecretKey::from_bytes( + hex::decode(keystore_secret_key).expect("to decode secret key").as_slice(), + ) + .expect("to create secret key"); + + let local_signer = LocalSigner::new(keystore_sk_bls, chain_config); + + let sig_local = local_signer.sign_commit_boost_root([0; 32]).expect("to sign message"); + let sig_keystore = keystore_signer + .sign_commit_boost_root([0; 32], keystore_publlc_key_bytes) + .expect("to sign message"); + assert_eq!(sig_local, sig_keystore); + } +} From 1de7d0978b827e7e6f654074ff6f1f68539ca26d Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Fri, 11 Oct 2024 11:30:45 +0200 Subject: [PATCH 49/64] chore(sidecar): KeystoreError --- bolt-sidecar/src/signer/keystore.rs | 42 +++++++++++++++++------------ 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/bolt-sidecar/src/signer/keystore.rs b/bolt-sidecar/src/signer/keystore.rs index 6513fcba9..5eedd4ec2 100644 --- a/bolt-sidecar/src/signer/keystore.rs +++ b/bolt-sidecar/src/signer/keystore.rs @@ -8,7 +8,6 @@ use std::{ }; use alloy::rpc::types::beacon::constants::BLS_PUBLIC_KEY_BYTES_LEN; -use eyre::eyre; use lighthouse_bls::Keypair; use lighthouse_eth2_keystore::Keystore; @@ -18,6 +17,22 @@ use crate::{builder::signature::compute_signing_root, crypto::bls::BLSSig, Chain pub const KEYSTORES_DEFAULT_PATH: &str = "keys"; +#[derive(Debug, thiserror::Error)] +pub enum KeystoreError { + #[error("Failed to read keystore directory: {0}")] + ReadFromDirectory(#[from] std::io::Error), + #[error("Failed to read keystore from JSON file {0}: {1}")] + ReadFromJSON(PathBuf, String), + #[error("Failed to decrypt keypair from JSON file {0} with the provided password: {1}")] + KeypairDecryption(PathBuf, String), + #[error("Could not find private key associated to public key {0}")] + UnknownPublicKey(String), + #[error("Invalid signature key length. Signature: {0}. Message: {1}")] + SignatureLength(String, String), +} + +type Result = std::result::Result; + #[derive(Clone)] pub struct KeystoreSigner { keypairs: Vec, @@ -25,22 +40,15 @@ pub struct KeystoreSigner { } impl KeystoreSigner { - pub fn new(keys_path: Option<&str>, password: &[u8], chain: ChainConfig) -> eyre::Result { + pub fn new(keys_path: Option<&str>, password: &[u8], chain: ChainConfig) -> Result { let keystores_paths = keystore_paths(keys_path)?; let mut keypairs = Vec::with_capacity(keystores_paths.len()); for path in keystores_paths { let keypair = Keystore::from_json_file(path.clone()) - .map_err(|e| { - eyre!(format!("err while reading keystore json file {:?}: {:?}", path, e)) - })? + .map_err(|e| KeystoreError::ReadFromJSON(path.clone(), format!("{e:?}")))? .decrypt_keypair(password) - .map_err(|e| { - eyre!(format!( - "err while decrypting keypair from json file {:?}: {:?}", - path, e - )) - })?; + .map_err(|e| KeystoreError::KeypairDecryption(path.clone(), format!("{e:?}")))?; keypairs.push(keypair); } @@ -51,7 +59,7 @@ impl KeystoreSigner { &self, root: [u8; 32], public_key: [u8; BLS_PUBLIC_KEY_BYTES_LEN], - ) -> eyre::Result { + ) -> Result { self.sign_root(root, public_key, self.chain.commit_boost_domain()) } @@ -60,19 +68,19 @@ impl KeystoreSigner { root: [u8; 32], public_key: [u8; BLS_PUBLIC_KEY_BYTES_LEN], domain: [u8; 32], - ) -> eyre::Result { + ) -> Result { let sk = self .keypairs .iter() // `as_ssz_bytes` returns the raw bytes we need .find(|kp| kp.pk.as_ssz_bytes() == public_key.as_ref()) - .ok_or(eyre!("could not find private key associated to public key"))?; + .ok_or(KeystoreError::UnknownPublicKey(hex::encode(public_key)))?; let signing_root = compute_signing_root(root, domain); let sig = sk.sk.sign(signing_root.into()).as_ssz_bytes(); - let sig = - BLSSig::try_from(sig.as_slice()).map_err(|_| eyre!("invalid signature length"))?; + let sig = BLSSig::try_from(sig.as_slice()) + .map_err(|e| KeystoreError::SignatureLength(hex::encode(sig), format!("{e:?}")))?; Ok(sig) } @@ -96,7 +104,7 @@ impl Debug for KeystoreSigner { /// -- 0x1234.../validator.json /// -- 0x5678.../validator.json /// -- ... -fn keystore_paths(keys_path: Option<&str>) -> Result, eyre::Error> { +fn keystore_paths(keys_path: Option<&str>) -> Result> { // Create the path to the keystore directory, starting from the root of the project let project_root = env!("CARGO_MANIFEST_DIR"); let keys_path = Path::new(project_root).join(keys_path.unwrap_or(KEYSTORES_DEFAULT_PATH)); From b60efa959c3ad2f190ecbab861be51111620ae96 Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Fri, 11 Oct 2024 12:17:50 +0200 Subject: [PATCH 50/64] refactor(sidecar): error handling --- bolt-sidecar/src/driver.rs | 15 ++++++++----- bolt-sidecar/src/signer/commit_boost.rs | 16 ++++++++------ bolt-sidecar/src/signer/keystore.rs | 4 ++-- bolt-sidecar/src/signer/local.rs | 28 +++++++++++++++---------- bolt-sidecar/src/signer/mod.rs | 13 +++++++++++- 5 files changed, 51 insertions(+), 25 deletions(-) diff --git a/bolt-sidecar/src/driver.rs b/bolt-sidecar/src/driver.rs index 812fc82c7..be9ed5ae9 100644 --- a/bolt-sidecar/src/driver.rs +++ b/bolt-sidecar/src/driver.rs @@ -21,7 +21,7 @@ use crate::{ CommitmentRequest, ConstraintsMessage, FetchPayloadRequest, LocalPayloadFetcher, SignedConstraints, TransactionExt, }, - signer::{keystore::KeystoreSigner, local::LocalSigner}, + signer::{keystore::KeystoreSigner, local::LocalSigner, SignerError}, start_builder_proxy_server, state::{fetcher::StateFetcher, ConsensusState, ExecutionState, HeadTracker, StateClient}, telemetry::ApiMetrics, @@ -266,12 +266,17 @@ impl SidecarDriver { let digest = message.digest(); let signature = match self.constraint_signer { - SignerBLS::Local(ref signer) => signer.sign_commit_boost_root(digest), - SignerBLS::CommitBoost(ref signer) => signer.sign_commit_boost_root(digest).await, - SignerBLS::Keystore(ref signer) => { - signer.sign_commit_boost_root(digest, cl_public_key_to_arr(pubkey.clone())) + SignerBLS::Local(ref signer) => { + signer.sign_commit_boost_root(digest).map_err(SignerError::LocalSigner) } + SignerBLS::CommitBoost(ref signer) => { + signer.sign_commit_boost_root(digest).await.map_err(SignerError::CommitBoost) + } + SignerBLS::Keystore(ref signer) => signer + .sign_commit_boost_root(digest, cl_public_key_to_arr(pubkey.clone())) + .map_err(SignerError::Keystore), }; + let signed_constraints = match signature { Ok(signature) => SignedConstraints { message, signature }, Err(e) => { diff --git a/bolt-sidecar/src/signer/commit_boost.rs b/bolt-sidecar/src/signer/commit_boost.rs index 01af5357f..a3f8033d6 100644 --- a/bolt-sidecar/src/signer/commit_boost.rs +++ b/bolt-sidecar/src/signer/commit_boost.rs @@ -2,12 +2,11 @@ use std::{str::FromStr, sync::Arc}; use alloy::{rpc::types::beacon::BlsSignature, signers::Signature}; use cb_common::{ - commit::{client::SignerClient, request::SignConsensusRequest}, + commit::{client::SignerClient, error::SignerClientError, request::SignConsensusRequest}, signer::EcdsaPublicKey, }; use commit_boost::prelude::SignProxyRequest; use ethereum_consensus::crypto::bls::PublicKey as BlsPublicKey; -use eyre::ErrReport; use parking_lot::RwLock; use thiserror::Error; use tracing::{debug, error, info}; @@ -31,14 +30,19 @@ pub enum CommitBoostError { #[error("failed to sign constraint: {0}")] NoSignature(String), #[error("failed to create signer client: {0}")] - SignerClientError(#[from] ErrReport), + SignerClientError(#[from] SignerClientError), + #[error("error in commit boost signer: {0}")] + Other(#[from] eyre::Report), } +type Result = std::result::Result; + #[allow(unused)] impl CommitBoostSigner { /// Create a new [CommitBoostSigner] instance - pub async fn new(signer_server_address: String, jwt: &str) -> Result { - let signer_client = SignerClient::new(signer_server_address, jwt)?; + pub async fn new(signer_server_address: String, jwt: &str) -> Result { + let signer_client = + SignerClient::new(signer_server_address, jwt).map_err(CommitBoostError::Other)?; let client = Self { signer_client, @@ -117,7 +121,7 @@ impl CommitBoostSigner { } /// Sign an object root with the Commit Boost domain. - pub async fn sign_commit_boost_root(&self, data: [u8; 32]) -> eyre::Result { + pub async fn sign_commit_boost_root(&self, data: [u8; 32]) -> Result { // convert the pubkey from ethereum_consensus to commit-boost format let pubkey = cb_common::signer::BlsPublicKey::from( alloy::rpc::types::beacon::BlsPublicKey::from_slice(self.pubkey().as_ref()), diff --git a/bolt-sidecar/src/signer/keystore.rs b/bolt-sidecar/src/signer/keystore.rs index 5eedd4ec2..17d3cb8b7 100644 --- a/bolt-sidecar/src/signer/keystore.rs +++ b/bolt-sidecar/src/signer/keystore.rs @@ -113,8 +113,8 @@ fn keystore_paths(keys_path: Option<&str>) -> Result> { let mut keystores_paths = vec![]; // Iter over the `keys` directory - for entry in fs::read_dir(keys_path)? { - let path = entry?.path(); + for entry in fs::read_dir(keys_path).map_err(KeystoreError::ReadFromDirectory)? { + let path = entry.map_err(KeystoreError::ReadFromDirectory)?.path(); if path.is_dir() { for entry in fs::read_dir(path)? { let path = entry?.path(); diff --git a/bolt-sidecar/src/signer/local.rs b/bolt-sidecar/src/signer/local.rs index 3ca839978..792175536 100644 --- a/bolt-sidecar/src/signer/local.rs +++ b/bolt-sidecar/src/signer/local.rs @@ -9,6 +9,16 @@ pub use blst::min_pk::SecretKey; /// The BLS Domain Separator used in Ethereum 2.0. pub const BLS_DST_PREFIX: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"; +#[derive(Debug, thiserror::Error)] +pub enum LocalSignerError { + #[error("Failed to compute signing root: {0}")] + SigningRootComputation(#[from] ethereum_consensus::error::Error), + #[error("Invalid signature: {0}")] + InvalidSignature(String), +} + +type Result = std::result::Result; + /// A BLS signer that can sign any type that implements the [`SignableBLS`] trait. #[derive(Clone)] pub struct LocalSigner { @@ -38,17 +48,17 @@ impl LocalSigner { } /// Sign an SSZ object root with the Application Builder domain. - pub fn sign_application_builder_root(&self, root: [u8; 32]) -> eyre::Result { + pub fn sign_application_builder_root(&self, root: [u8; 32]) -> Result { self.sign_root(root, self.chain.application_builder_domain()) } /// Sign an SSZ object root with the Commit Boost domain. - pub fn sign_commit_boost_root(&self, root: [u8; 32]) -> eyre::Result { + pub fn sign_commit_boost_root(&self, root: [u8; 32]) -> Result { self.sign_root(root, self.chain.commit_boost_domain()) } /// Sign an SSZ object root with the given domain. - pub fn sign_root(&self, root: [u8; 32], domain: [u8; 32]) -> eyre::Result { + pub fn sign_root(&self, root: [u8; 32], domain: [u8; 32]) -> Result { let signing_root = compute_signing_root(&root, domain)?; let sig = self.key.sign(signing_root.as_slice(), BLS_DST_PREFIX, &[]); Ok(BLSSig::from_slice(&sig.to_bytes())) @@ -59,16 +69,12 @@ impl LocalSigner { &self, root: [u8; 32], signature: &Signature, - ) -> eyre::Result<()> { + ) -> Result<()> { self.verify_root(root, signature, self.chain.application_builder_domain()) } /// Verify the signature with the public key of the signer using the Commit Boost domain. - pub fn verify_commit_boost_root( - &self, - root: [u8; 32], - signature: &Signature, - ) -> eyre::Result<()> { + pub fn verify_commit_boost_root(&self, root: [u8; 32], signature: &Signature) -> Result<()> { self.verify_root(root, signature, self.chain.commit_boost_domain()) } @@ -78,7 +84,7 @@ impl LocalSigner { root: [u8; 32], signature: &Signature, domain: [u8; 32], - ) -> eyre::Result<()> { + ) -> Result<()> { let signing_root = compute_signing_root(&root, domain)?; let pk = blst::min_pk::PublicKey::from_bytes(self.pubkey().as_ref()).unwrap(); @@ -86,7 +92,7 @@ impl LocalSigner { if res == BLST_ERROR::BLST_SUCCESS { Ok(()) } else { - eyre::bail!(format!("Invalid signature: {:?}", res)) + Err(LocalSignerError::InvalidSignature(format!("{res:?}"))) } } } diff --git a/bolt-sidecar/src/signer/mod.rs b/bolt-sidecar/src/signer/mod.rs index bbed32f7b..f71ded19f 100644 --- a/bolt-sidecar/src/signer/mod.rs +++ b/bolt-sidecar/src/signer/mod.rs @@ -7,8 +7,8 @@ use keystore::KeystoreSigner; pub mod local; use local::LocalSigner; -#[derive(Debug, Clone)] /// Signer for BLS signatures. +#[derive(Debug, Clone)] pub enum SignerBLS { /// Local signer with a BLS secret key. Local(LocalSigner), @@ -17,3 +17,14 @@ pub enum SignerBLS { /// Signer consisting of multiple keypairs loaded from ERC-2335 keystores files. Keystore(KeystoreSigner), } + +/// Error in the signer. +#[derive(Debug, thiserror::Error)] +pub enum SignerError { + #[error("local signer error: {0}")] + LocalSigner(#[from] local::LocalSignerError), + #[error("commit boost signer error: {0}")] + CommitBoost(commit_boost::CommitBoostError), + #[error("keystore signer error: {0}")] + Keystore(keystore::KeystoreError), +} From 80a0d3565369a455c8d2343f4479d7480ba796af Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Fri, 11 Oct 2024 12:50:06 +0200 Subject: [PATCH 51/64] config(sidecar): add keystores path --- bolt-sidecar/src/config/signing.rs | 4 ++++ bolt-sidecar/src/driver.rs | 2 +- bolt-sidecar/src/signer/keystore.rs | 8 ++++++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/bolt-sidecar/src/config/signing.rs b/bolt-sidecar/src/config/signing.rs index c204edfac..d4d91494d 100644 --- a/bolt-sidecar/src/config/signing.rs +++ b/bolt-sidecar/src/config/signing.rs @@ -27,6 +27,9 @@ pub struct SigningOpts { /// Reference: https://eips.ethereum.org/EIPS/eip-2335 #[clap(long, env = "BOLT_SIDECAR_KEYSTORE_PASSWORD")] pub keystore_password: Option, + /// Path to the keystores folder. If not provided, the default path is used. + #[clap(long, env = "BOLT_SIDECAR_KEYSTORE_PATH", requires("keystore_password"))] + pub keystore_path: Option, } // Implement Debug manually to hide the keystore_password field @@ -48,6 +51,7 @@ impl Default for SigningOpts { commit_boost_address: None, commit_boost_jwt_hex: None, keystore_password: None, + keystore_path: None, } } } diff --git a/bolt-sidecar/src/driver.rs b/bolt-sidecar/src/driver.rs index be9ed5ae9..ca7a18f02 100644 --- a/bolt-sidecar/src/driver.rs +++ b/bolt-sidecar/src/driver.rs @@ -87,7 +87,7 @@ impl SidecarDriver { let state_client = StateClient::new(opts.execution_api_url.clone()); let keystore_signer = SignerBLS::Keystore(KeystoreSigner::new( - None, + opts.signing.keystore_path.as_deref(), opts.signing.keystore_password.as_ref().expect("keystore password").as_ref(), opts.chain, )?); diff --git a/bolt-sidecar/src/signer/keystore.rs b/bolt-sidecar/src/signer/keystore.rs index 17d3cb8b7..6223ec209 100644 --- a/bolt-sidecar/src/signer/keystore.rs +++ b/bolt-sidecar/src/signer/keystore.rs @@ -106,8 +106,12 @@ impl Debug for KeystoreSigner { /// -- ... fn keystore_paths(keys_path: Option<&str>) -> Result> { // Create the path to the keystore directory, starting from the root of the project - let project_root = env!("CARGO_MANIFEST_DIR"); - let keys_path = Path::new(project_root).join(keys_path.unwrap_or(KEYSTORES_DEFAULT_PATH)); + let keys_path = if let Some(keys_path) = keys_path { + Path::new(&keys_path).to_path_buf() + } else { + let project_root = env!("CARGO_MANIFEST_DIR"); + Path::new(project_root).join(keys_path.unwrap_or(KEYSTORES_DEFAULT_PATH)) + }; let json_extension = OsString::from("json"); From 2ceb70468a17d8663bd4dd3a53c545a2086520e6 Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Fri, 11 Oct 2024 16:54:53 +0200 Subject: [PATCH 52/64] fix(sidecar): dockerfile --- bolt-sidecar/Dockerfile | 52 ++++++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/bolt-sidecar/Dockerfile b/bolt-sidecar/Dockerfile index 5b2075b99..99c0f839c 100644 --- a/bolt-sidecar/Dockerfile +++ b/bolt-sidecar/Dockerfile @@ -1,23 +1,57 @@ -FROM rust:1.81.0-slim-bullseye AS compiler +# Stage 1: Base compiler image with necessary dependencies +FROM rust:1.81.0-slim-bullseye AS base +# Install cargo-chef for dependency caching RUN cargo install cargo-chef +# Set the working directory to /app WORKDIR /app -FROM compiler AS planner -COPY . . +# Stage 2: Planner (generating the recipe) +FROM base AS planner + +# Copy only Cargo files to cache dependencies +COPY Cargo.toml Cargo.lock ./ + +# Prepare the recipe for caching dependencies (Cargo.toml/Cargo.lock) RUN cargo chef prepare --recipe-path recipe.json -FROM compiler AS builder +# Stage 3: Builder with necessary dependencies for OpenSSL +FROM base AS builder + +# Install required dependencies for building Rust projects (OpenSSL, pkg-config) +RUN apt-get update && apt-get install -y \ + pkg-config \ + libssl-dev \ + build-essential \ + perl \ + gcc \ + make + +# Copy the generated recipe from the planner stage COPY --from=planner /app/recipe.json recipe.json -RUN apt-get update && apt-get install pkg-config libssl-dev -y + +# Cache the dependencies using the cargo-chef recipe RUN cargo chef cook --release --recipe-path recipe.json + +# Copy the source code and build the project COPY . . RUN cargo build --release -FROM debian:bullseye-slim +# Stage 4: Final runtime image (lean image) +FROM debian:bullseye-slim AS runtime + +# Set the working directory for the final container 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/* -ENTRYPOINT ["/bolt-sidecar"] +# Install necessary runtime dependencies (OpenSSL and CA certificates) +RUN apt-get update && apt-get install -y \ + libssl-dev \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# Copy the compiled binary from the builder stage +COPY --from=builder /app/target/release/bolt-sidecar /usr/local/bin/bolt-sidecar + +# Define the entrypoint for the container +ENTRYPOINT ["/usr/local/bin/bolt-sidecar"] From a3f971ebbe1159b47a59e2c61eb9ce9092473c30 Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Fri, 11 Oct 2024 16:55:23 +0200 Subject: [PATCH 53/64] chore(sidecar): .dockerignore --- .dockerignore | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..2d2c3db58 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +target +.git +Dockerfile +.dockerignore From d3883fb6e7b3b6d2850d577d53b6cd4abd859c3c Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Fri, 11 Oct 2024 16:55:44 +0200 Subject: [PATCH 54/64] feat(justfile): just bash and small refactor of commands --- justfile | 56 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/justfile b/justfile index bd18c1b75..ce6f30fc2 100644 --- a/justfile +++ b/justfile @@ -43,61 +43,61 @@ _restart-sidecar: inspect: kurtosis enclave inspect bolt-devnet -# show the logs for the bolt devnet relay -relay-logs: +bash service: @id=$(docker ps -n 100 | grep helix-relay | awk -F' ' '{print $1}') && \ + docker exec -it $id bash + +log service: + @id=$(docker ps -n 100 | grep {{ service }} | awk -F' ' '{print $1}') && \ docker logs -f $id +dump service: + @id=$(docker ps -n 100 | grep {{ service }} | awk -F' ' '{print $1}') && \ + docker logs $id 2>&1 | tee {{ service }}_dump.log + +# show the logs for the bolt devnet relay +relay-logs: + @just log helix-relay + # show the logs for the bolt devnet builder builder-logs: - @id=$(docker ps -n 100 | grep bolt-builder | awk -F' ' '{print $1}') && \ - docker logs -f $id + @just log bolt-builder # show the logs for the bolt devnet bolt-boost sidecar boost-logs: - @id=$(docker ps -n 100 | grep bolt-boost | awk -F' ' '{print $1}') && \ - docker logs -f $id + @just log bolt-boost # show the logs for the bolt devnet mev-boost sidecar mev-boost-logs: - @id=$(docker ps -n 100 | grep bolt-mev-boost | awk -F' ' '{print $1}') && \ - docker logs -f $id + @just log bolt-mev-boost # show the logs for the bolt devnet bolt-sidecar sidecar-logs: - @id=$(docker ps -n 100 | grep sidecar | awk -F' ' '{print $1}') && \ - docker logs -f $id + @just log sidecar # show the logs for the bolt devnet for beacon node beacon-logs: - @id=$(docker ps -n 100 | grep 'cl-1-lighthouse-geth' | awk -F' ' '{print $1}') && \ - docker logs -f $id + @just log 'cl-1-lighthouse-geth' # show the logs for the bolt devnet for beacon node beacon-dump: - @id=$(docker ps -n 100 | grep 'cl-1-lighthouse-geth' | awk -F' ' '{print $1}') && \ - docker logs $id 2>&1 | tee beacon_dump.log + @just dump 'cl-1-lighthouse-geth' # show the logs for the bolt devnet relay relay-dump: - @id=$(docker ps -n 100 | grep mev-relay-api | awk -F' ' '{print $1}') && \ - docker logs $id 2>&1 | tee relay_dump.log + @just dump mev-relay-api # show the logs for the bolt devnet builder builder-dump: - @id=$(docker ps -n 100 | grep bolt-builder | awk -F' ' '{print $1}') && \ - docker logs $id 2>&1 | tee builder_dump.log + @just dump bolt-builder # show the logs for the bolt devnet mev-boost sidecar boost-dump: - @id=$(docker ps -n 100 | grep bolt-mev-boost | awk -F' ' '{print $1}') && \ - docker logs $id 2>&1 | tee boost_dump.log + @just dump bolt-mev-boost # show the logs for the bolt devnet bolt-sidecar sidecar-dump: - @id=$(docker ps -n 100 | grep sidecar | awk -F' ' '{print $1}') && \ - docker logs $id 2>&1 | tee sidecar_dump.log - + @just dump sidecar # show the logs for the bolt devnet builder kill-builder: @@ -153,23 +153,23 @@ build-images: # build the docker image for the bolt builder _build-builder: - cd builder && docker buildx build -t ghcr.io/chainbound/bolt-builder:0.1.0 . --load + cd builder && docker build -t ghcr.io/chainbound/bolt-builder:0.1.0 . --load # build the docker image for the bolt relay _build-relay: - cd mev-boost-relay && docker buildx build -t ghcr.io/chainbound/bolt-relay:0.1.0 . --load + cd mev-boost-relay && docker build -t ghcr.io/chainbound/bolt-relay:0.1.0 . --load # build the docker image for the bolt sidecar _build-sidecar: - cd bolt-sidecar && docker buildx build -t ghcr.io/chainbound/bolt-sidecar:0.1.0 . --load + cd bolt-sidecar && docker build -t ghcr.io/chainbound/bolt-sidecar:0.1.0 . --load # build the docker image for the bolt mev-boost sidecar _build-mevboost: - cd mev-boost && docker buildx build -t ghcr.io/chainbound/bolt-mev-boost:0.1.0 . --load + cd mev-boost && docker build -t ghcr.io/chainbound/bolt-mev-boost:0.1.0 . --load # build the docker image for bolt-boost _build-bolt-boost: - cd bolt-boost && docker buildx build -t ghcr.io/chainbound/bolt-boost:0.1.0 . --load + cd bolt-boost && docker build -t ghcr.io/chainbound/bolt-boost:0.1.0 . --load # deploy the bolt sidecar to the dev server deploy-sidecar-dev: From 7a4fd66ae59f4bdacdb104a67acf696d423e714c Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Fri, 11 Oct 2024 19:52:10 +0200 Subject: [PATCH 55/64] test(sidecar): updated keystore test wip; devnet keystore is failing --- bolt-sidecar/src/signer/keystore.rs | 123 +++++++++++++++++++++++++++- 1 file changed, 120 insertions(+), 3 deletions(-) diff --git a/bolt-sidecar/src/signer/keystore.rs b/bolt-sidecar/src/signer/keystore.rs index 6223ec209..658f6dfdf 100644 --- a/bolt-sidecar/src/signer/keystore.rs +++ b/bolt-sidecar/src/signer/keystore.rs @@ -145,11 +145,12 @@ mod tests { pub const CARGO_MANIFEST_DIR: &str = env!("CARGO_MANIFEST_DIR"); #[test] - fn test_keystore_signer() { + fn test_keystore_signer_1() { // 0. Test data setup // Reference: https://eips.ethereum.org/EIPS/eip-2335#test-cases - let test_keystore_json = r#" + let tests_keystore_json = [ + r#" { "crypto": { "kdf": { @@ -182,7 +183,42 @@ mod tests { "uuid": "1d85ae20-35c5-4611-98e8-aa14a633906f", "version": 4 } - "#; + "#, + r#" + { + "crypto": { + "kdf": { + "function": "pbkdf2", + "params": { + "dklen": 32, + "c": 262144, + "prf": "hmac-sha256", + "salt": "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" + }, + "message": "" + }, + "checksum": { + "function": "sha256", + "params": {}, + "message": "8a9f5d9912ed7e75ea794bc5a89bca5f193721d30868ade6f73043c6ea6febf1" + }, + "cipher": { + "function": "aes-128-ctr", + "params": { + "iv": "264daa3f303d7259501c93d997d84fe6" + }, + "message": "cee03fde2af33149775b7223e7845e4fb2c8ae1792e5f99fe9ecf474cc8c16ad" + } + }, + "description": "This is a test keystore that uses PBKDF2 to secure the secret.", + "pubkey": "9612d7a727c9d0a22e185a1c768478dfe919cada9266988cb32359c11f2b7b27f4ae4040902382ae2910c15e2b420d07", + "path": "m/12381/60/0/0", + "uuid": "64625def-3331-4eea-ab6f-782f3ed16a83", + "version": 4 + } + "#, + ]; + // Reference: https://eips.ethereum.org/EIPS/eip-2335#test-cases let keystore_password = r#"𝔱𝔢𝔰𝔱𝔭𝔞𝔰𝔰𝔴𝔬𝔯𝔡🔑"#; let keystore_public_key = "0x9612d7a727c9d0a22e185a1c768478dfe919cada9266988cb32359c11f2b7b27f4ae4040902382ae2910c15e2b420d07"; @@ -198,6 +234,87 @@ mod tests { // 1. Create a temp directory with the keystore and create a signer from it + let path_str = format!("{}/{}", CARGO_MANIFEST_DIR, KEYSTORES_DEFAULT_PATH); + + for test_keystore_json in tests_keystore_json { + let tmp_dir = tempfile::TempDir::with_prefix_in( + "0xdeadbeefdeadbeefdeadbeefdeadbeef", + path_str.clone(), + ) + .expect("to create temp dir"); + + // NOTE: it is sufficient to create a temp dir, then we can create a file as usual and it + // will be dropped correctly + let mut tmp_file = File::create_new(tmp_dir.path().join("voting-keystore.json")) + .expect("to create new file"); + + tmp_file.write_all(test_keystore_json.as_bytes()).expect("to write to temp file"); + + for entry in tmp_dir.path().read_dir().expect("to read tmp dir") { + let mut path = entry.expect("to read entry").path(); + println!("inside loop: {:?}", path); + let extenstion = path + .extension() + .expect("to get extension") + .to_str() + .expect("to convert to str"); + + if extenstion.contains("tmp") { + path.set_extension("json"); + println!("path: {:?}", path); + break; + } + } + + let keystore_signer = + KeystoreSigner::new(None, keystore_password.as_bytes(), chain_config) + .expect("to create keystore signer"); + + assert_eq!(keystore_signer.keypairs.len(), 1); + assert_eq!( + keystore_signer.keypairs.first().expect("to get keypair").pk.to_string(), + keystore_public_key + ); + + // 2. Sign a message with the signer and check the signature + + let keystore_sk_bls = SecretKey::from_bytes( + hex::decode(keystore_secret_key).expect("to decode secret key").as_slice(), + ) + .expect("to create secret key"); + + let local_signer = LocalSigner::new(keystore_sk_bls, chain_config); + + let sig_local = local_signer.sign_commit_boost_root([0; 32]).expect("to sign message"); + let sig_keystore = keystore_signer + .sign_commit_boost_root([0; 32], keystore_publlc_key_bytes) + .expect("to sign message"); + assert_eq!(sig_local, sig_keystore); + } + } + + #[test] + fn test_keystore_signer_2() { + // 0. Test data setup + + // Taken from the Kurtosis devnet + let test_keystore_json = r#"{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":2,"prf":"hmac-sha256","salt":"1411b589ab43558f1d29053f6e96e6268f4b8491ba48d0c164273575dd80c1b6"},"message":""},"checksum":{"function":"sha256","params":{},"message":"f669c41a996d60d094053504ccb1a7fa180376dd2474a9659dd86104f790d59c"},"cipher":{"function":"aes-128-ctr","params":{"iv":"2f0927f8ff08e9d4faee279a98fe8377"},"message":"2c34bed346f5520291239f067a912a34ee5f7680be06b0f7c4a930111b5c1b57"}},"description":"0x81b676591b823270a3284ace7d81cbce2d6cdce55bb0e053874d7e3a08f729453009d3e662ec3130379f43c0f3210b6d","pubkey":"81b676591b823270a3284ace7d81cbce2d6cdce55bb0e053874d7e3a08f729453009d3e662ec3130379f43c0f3210b6d","path":"","uuid":"a4f153d8-9ebf-49ac-b447-8aab996f7778","version":4}"#; + // Reference: https://eips.ethereum.org/EIPS/eip-2335#test-cases + let keystore_password = r#"password"#; + println!("{:?}", keystore_password.as_bytes()); + let keystore_public_key = "0x9612d7a727c9d0a22e185a1c768478dfe919cada9266988cb32359c11f2b7b27f4ae4040902382ae2910c15e2b420d07"; + let keystore_publlc_key_bytes: [u8; 48] = [ + 0x96, 0x12, 0xd7, 0xa7, 0x27, 0xc9, 0xd0, 0xa2, 0x2e, 0x18, 0x5a, 0x1c, 0x76, 0x84, + 0x78, 0xdf, 0xe9, 0x19, 0xca, 0xda, 0x92, 0x66, 0x98, 0x8c, 0xb3, 0x23, 0x59, 0xc1, + 0x1f, 0x2b, 0x7b, 0x27, 0xf4, 0xae, 0x40, 0x40, 0x90, 0x23, 0x82, 0xae, 0x29, 0x10, + 0xc1, 0x5e, 0x2b, 0x42, 0x0d, 0x07, + ]; + let keystore_secret_key = + "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"; + let chain_config = ChainConfig::mainnet(); + + // 1. Create a temp directory with the keystore and create a signer from it + let path_str = format!("{}/{}", CARGO_MANIFEST_DIR, KEYSTORES_DEFAULT_PATH); let tmp_dir = tempfile::TempDir::with_prefix_in("0xdeadbeefdeadbeefdeadbeefdeadbeef", path_str) From 34ae469052838c891d29e603030053d7bac689a3 Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Sun, 13 Oct 2024 20:32:11 +0200 Subject: [PATCH 56/64] fix(justfile): just bash {{ service }} had hardcoded helix --- justfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/justfile b/justfile index ce6f30fc2..54827ebcb 100644 --- a/justfile +++ b/justfile @@ -44,7 +44,7 @@ inspect: kurtosis enclave inspect bolt-devnet bash service: - @id=$(docker ps -n 100 | grep helix-relay | awk -F' ' '{print $1}') && \ + @id=$(docker ps -n 100 | grep {{ service }} | awk -F' ' '{print $1}') && \ docker exec -it $id bash log service: From c5ac649e0e54b2c6be01120a691f707d508ac014 Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Sun, 13 Oct 2024 20:33:17 +0200 Subject: [PATCH 57/64] test(sidecar): another keystore test, but temporary --- bolt-sidecar/src/signer/keystore.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/bolt-sidecar/src/signer/keystore.rs b/bolt-sidecar/src/signer/keystore.rs index 658f6dfdf..b2fbe99d7 100644 --- a/bolt-sidecar/src/signer/keystore.rs +++ b/bolt-sidecar/src/signer/keystore.rs @@ -45,7 +45,8 @@ impl KeystoreSigner { let mut keypairs = Vec::with_capacity(keystores_paths.len()); for path in keystores_paths { - let keypair = Keystore::from_json_file(path.clone()) + let keypair = Keystore::from_json_file(path.clone()); + let keypair = keypair .map_err(|e| KeystoreError::ReadFromJSON(path.clone(), format!("{e:?}")))? .decrypt_keypair(password) .map_err(|e| KeystoreError::KeypairDecryption(path.clone(), format!("{e:?}")))?; @@ -296,21 +297,21 @@ mod tests { #[test] fn test_keystore_signer_2() { // 0. Test data setup + // // Taken from the Kurtosis devnet - let test_keystore_json = r#"{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":2,"prf":"hmac-sha256","salt":"1411b589ab43558f1d29053f6e96e6268f4b8491ba48d0c164273575dd80c1b6"},"message":""},"checksum":{"function":"sha256","params":{},"message":"f669c41a996d60d094053504ccb1a7fa180376dd2474a9659dd86104f790d59c"},"cipher":{"function":"aes-128-ctr","params":{"iv":"2f0927f8ff08e9d4faee279a98fe8377"},"message":"2c34bed346f5520291239f067a912a34ee5f7680be06b0f7c4a930111b5c1b57"}},"description":"0x81b676591b823270a3284ace7d81cbce2d6cdce55bb0e053874d7e3a08f729453009d3e662ec3130379f43c0f3210b6d","pubkey":"81b676591b823270a3284ace7d81cbce2d6cdce55bb0e053874d7e3a08f729453009d3e662ec3130379f43c0f3210b6d","path":"","uuid":"a4f153d8-9ebf-49ac-b447-8aab996f7778","version":4}"#; + let test_keystore_json = r#"{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"be4382b8194846b21d15a46df9d0e8062a48dfb46d2826880af554f12979a743"},"message":""},"checksum":{"function":"sha256","params":{},"message":"9e7c6c8b9040fbe0cb4bd06119b90d5b72bac9cd2dfb36cd5997099f7f2eb338"},"cipher":{"function":"aes-128-ctr","params":{"iv":"e01ca31de1e01e3d29dc3f755ec02866"},"message":"8a9a40bfa7464c313b85787541bb2d4694095a19bc9235bc55e425ff0c12b1b8"}},"description":"0x81b676591b823270a3284ace7d81cbce2d6cdce55bb0e053874d7e3a08f729453009d3e662ec3130379f43c0f3210b6d","pubkey":"81b676591b823270a3284ace7d81cbce2d6cdce55bb0e053874d7e3a08f729453009d3e662ec3130379f43c0f3210b6d","path":"","uuid":"78a76023-9753-47b5-a989-3bd94aac4872","version":4}"#; // Reference: https://eips.ethereum.org/EIPS/eip-2335#test-cases - let keystore_password = r#"password"#; - println!("{:?}", keystore_password.as_bytes()); - let keystore_public_key = "0x9612d7a727c9d0a22e185a1c768478dfe919cada9266988cb32359c11f2b7b27f4ae4040902382ae2910c15e2b420d07"; + let keystore_password = r#"My5Sv2UAENRAppJ3w7ZvyO6ez1TyvKZ4NfJ25hgBRrw="#; + let keystore_public_key = "0x81b676591b823270a3284ace7d81cbce2d6cdce55bb0e053874d7e3a08f729453009d3e662ec3130379f43c0f3210b6d"; let keystore_publlc_key_bytes: [u8; 48] = [ - 0x96, 0x12, 0xd7, 0xa7, 0x27, 0xc9, 0xd0, 0xa2, 0x2e, 0x18, 0x5a, 0x1c, 0x76, 0x84, - 0x78, 0xdf, 0xe9, 0x19, 0xca, 0xda, 0x92, 0x66, 0x98, 0x8c, 0xb3, 0x23, 0x59, 0xc1, - 0x1f, 0x2b, 0x7b, 0x27, 0xf4, 0xae, 0x40, 0x40, 0x90, 0x23, 0x82, 0xae, 0x29, 0x10, - 0xc1, 0x5e, 0x2b, 0x42, 0x0d, 0x07, + 0x81, 0xb6, 0x76, 0x59, 0x1b, 0x82, 0x32, 0x70, 0xa3, 0x28, 0x4a, 0xce, 0x7d, 0x81, + 0xcb, 0xce, 0x2d, 0x6c, 0xdc, 0xe5, 0x5b, 0xb0, 0xe0, 0x53, 0x87, 0x4d, 0x7e, 0x3a, + 0x08, 0xf7, 0x29, 0x45, 0x30, 0x09, 0xd3, 0xe6, 0x62, 0xec, 0x31, 0x30, 0x37, 0x9f, + 0x43, 0xc0, 0xf3, 0x21, 0x0b, 0x6d, ]; let keystore_secret_key = - "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"; + "64fc5f1ae34cc39e9040eb82aca3ab48dc417103f1ec58de2465a61210ce1829"; let chain_config = ChainConfig::mainnet(); // 1. Create a temp directory with the keystore and create a signer from it From 60a9e47dd7015b41997b1f28a9f317dae1e4ea19 Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Sun, 13 Oct 2024 21:27:46 +0200 Subject: [PATCH 58/64] test(sidecar): keep only erc-2335 canonical tests --- bolt-sidecar/src/signer/keystore.rs | 74 +---------------------------- 1 file changed, 1 insertion(+), 73 deletions(-) diff --git a/bolt-sidecar/src/signer/keystore.rs b/bolt-sidecar/src/signer/keystore.rs index b2fbe99d7..83736c2dc 100644 --- a/bolt-sidecar/src/signer/keystore.rs +++ b/bolt-sidecar/src/signer/keystore.rs @@ -146,7 +146,7 @@ mod tests { pub const CARGO_MANIFEST_DIR: &str = env!("CARGO_MANIFEST_DIR"); #[test] - fn test_keystore_signer_1() { + fn test_keystore_signer() { // 0. Test data setup // Reference: https://eips.ethereum.org/EIPS/eip-2335#test-cases @@ -293,76 +293,4 @@ mod tests { assert_eq!(sig_local, sig_keystore); } } - - #[test] - fn test_keystore_signer_2() { - // 0. Test data setup - // - - // Taken from the Kurtosis devnet - let test_keystore_json = r#"{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"be4382b8194846b21d15a46df9d0e8062a48dfb46d2826880af554f12979a743"},"message":""},"checksum":{"function":"sha256","params":{},"message":"9e7c6c8b9040fbe0cb4bd06119b90d5b72bac9cd2dfb36cd5997099f7f2eb338"},"cipher":{"function":"aes-128-ctr","params":{"iv":"e01ca31de1e01e3d29dc3f755ec02866"},"message":"8a9a40bfa7464c313b85787541bb2d4694095a19bc9235bc55e425ff0c12b1b8"}},"description":"0x81b676591b823270a3284ace7d81cbce2d6cdce55bb0e053874d7e3a08f729453009d3e662ec3130379f43c0f3210b6d","pubkey":"81b676591b823270a3284ace7d81cbce2d6cdce55bb0e053874d7e3a08f729453009d3e662ec3130379f43c0f3210b6d","path":"","uuid":"78a76023-9753-47b5-a989-3bd94aac4872","version":4}"#; - // Reference: https://eips.ethereum.org/EIPS/eip-2335#test-cases - let keystore_password = r#"My5Sv2UAENRAppJ3w7ZvyO6ez1TyvKZ4NfJ25hgBRrw="#; - let keystore_public_key = "0x81b676591b823270a3284ace7d81cbce2d6cdce55bb0e053874d7e3a08f729453009d3e662ec3130379f43c0f3210b6d"; - let keystore_publlc_key_bytes: [u8; 48] = [ - 0x81, 0xb6, 0x76, 0x59, 0x1b, 0x82, 0x32, 0x70, 0xa3, 0x28, 0x4a, 0xce, 0x7d, 0x81, - 0xcb, 0xce, 0x2d, 0x6c, 0xdc, 0xe5, 0x5b, 0xb0, 0xe0, 0x53, 0x87, 0x4d, 0x7e, 0x3a, - 0x08, 0xf7, 0x29, 0x45, 0x30, 0x09, 0xd3, 0xe6, 0x62, 0xec, 0x31, 0x30, 0x37, 0x9f, - 0x43, 0xc0, 0xf3, 0x21, 0x0b, 0x6d, - ]; - let keystore_secret_key = - "64fc5f1ae34cc39e9040eb82aca3ab48dc417103f1ec58de2465a61210ce1829"; - let chain_config = ChainConfig::mainnet(); - - // 1. Create a temp directory with the keystore and create a signer from it - - let path_str = format!("{}/{}", CARGO_MANIFEST_DIR, KEYSTORES_DEFAULT_PATH); - let tmp_dir = - tempfile::TempDir::with_prefix_in("0xdeadbeefdeadbeefdeadbeefdeadbeef", path_str) - .expect("to create temp dir"); - - // NOTE: it is sufficient to create a temp dir, then we can create a file as usual and it - // will be dropped correctly - let mut tmp_file = File::create_new(tmp_dir.path().join("voting-keystore.json")) - .expect("to create new file"); - - tmp_file.write_all(test_keystore_json.as_bytes()).expect("to write to temp file"); - - for entry in tmp_dir.path().read_dir().expect("to read tmp dir") { - let mut path = entry.expect("to read entry").path(); - println!("inside loop: {:?}", path); - let extenstion = - path.extension().expect("to get extension").to_str().expect("to convert to str"); - - if extenstion.contains("tmp") { - path.set_extension("json"); - println!("path: {:?}", path); - break; - } - } - - let keystore_signer = KeystoreSigner::new(None, keystore_password.as_bytes(), chain_config) - .expect("to create keystore signer"); - - assert_eq!(keystore_signer.keypairs.len(), 1); - assert_eq!( - keystore_signer.keypairs.first().expect("to get keypair").pk.to_string(), - keystore_public_key - ); - - // 2. Sign a message with the signer and check the signature - - let keystore_sk_bls = SecretKey::from_bytes( - hex::decode(keystore_secret_key).expect("to decode secret key").as_slice(), - ) - .expect("to create secret key"); - - let local_signer = LocalSigner::new(keystore_sk_bls, chain_config); - - let sig_local = local_signer.sign_commit_boost_root([0; 32]).expect("to sign message"); - let sig_keystore = keystore_signer - .sign_commit_boost_root([0; 32], keystore_publlc_key_bytes) - .expect("to sign message"); - assert_eq!(sig_local, sig_keystore); - } } From ba91b23c9e67bf4048a748efb6b2f57fc326d610 Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Mon, 14 Oct 2024 10:51:33 +0200 Subject: [PATCH 59/64] chore(sidecar): remove TODO comment --- bolt-sidecar/src/driver.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/bolt-sidecar/src/driver.rs b/bolt-sidecar/src/driver.rs index ca7a18f02..d6c75125d 100644 --- a/bolt-sidecar/src/driver.rs +++ b/bolt-sidecar/src/driver.rs @@ -219,8 +219,6 @@ impl SidecarDriver { let start = Instant::now(); - // TODO(nico): currently we don't use the validator pubkey to sign. this will be re-added - // later to support different signing setups. let validator_pubkey = match self.consensus.validate_request(&request) { Ok(index) => index, Err(err) => { From a07452db9fac431dc0cf9de4506d4e7e52f405c9 Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Mon, 14 Oct 2024 10:54:17 +0200 Subject: [PATCH 60/64] chore(sidecar): imports --- bolt-sidecar/src/test_util.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bolt-sidecar/src/test_util.rs b/bolt-sidecar/src/test_util.rs index cbf7d67a4..b4dbf40c3 100644 --- a/bolt-sidecar/src/test_util.rs +++ b/bolt-sidecar/src/test_util.rs @@ -1,4 +1,3 @@ -use crate::ChainConfig; use alloy::{ eips::eip2718::Encodable2718, network::{EthereumWallet, TransactionBuilder}, @@ -26,7 +25,7 @@ use crate::{ InclusionRequest, RevocationMessage, SignedConstraints, SignedDelegation, SignedRevocation, }, signer::local::LocalSigner, - Opts, + ChainConfig, Opts, }; /// The URL of the test execution client HTTP API. From 5ced625a588170e5fd8d6ba9402b65cd78c1e561 Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Mon, 14 Oct 2024 11:40:41 +0200 Subject: [PATCH 61/64] fix,test(sidecar): fix tests not working with cargo nextest. Now extra args are captured in testing environment --- bolt-sidecar/src/config/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bolt-sidecar/src/config/mod.rs b/bolt-sidecar/src/config/mod.rs index 2e6362090..7110d7aca 100644 --- a/bolt-sidecar/src/config/mod.rs +++ b/bolt-sidecar/src/config/mod.rs @@ -27,6 +27,7 @@ pub const DEFAULT_CONSTRAINTS_PROXY_PORT: u16 = 18551; /// Command-line options for the Bolt sidecar #[derive(Debug, Parser)] +#[clap(trailing_var_arg = true)] pub struct Opts { /// Port to listen on for incoming JSON-RPC requests #[clap(long, env = "BOLT_SIDECAR_PORT", @@ -82,6 +83,11 @@ pub struct Opts { /// Telemetry options #[clap(flatten)] pub telemetry: TelemetryOpts, + /// Additional unrecognized arguments. Useful for CI and testing + /// to avoid issues on potential extra flags provided (e.g. "--exact" from cargo nextest). + #[cfg(test)] + #[clap(allow_hyphen_values = true)] + pub extra_args: Vec, } #[cfg(test)] From ddaedb52c89dce8604a0d36570dc9ac21d85c9ea Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Mon, 14 Oct 2024 12:44:19 +0200 Subject: [PATCH 62/64] refactor(sidecar): signer errors --- bolt-sidecar/src/driver.rs | 14 +++------ bolt-sidecar/src/signer/commit_boost.rs | 14 ++++++--- bolt-sidecar/src/signer/keystore.rs | 41 +++++++++++++++---------- bolt-sidecar/src/signer/local.rs | 32 +++++++++++-------- bolt-sidecar/src/signer/mod.rs | 6 ++-- 5 files changed, 62 insertions(+), 45 deletions(-) diff --git a/bolt-sidecar/src/driver.rs b/bolt-sidecar/src/driver.rs index d6c75125d..ed365244f 100644 --- a/bolt-sidecar/src/driver.rs +++ b/bolt-sidecar/src/driver.rs @@ -21,7 +21,7 @@ use crate::{ CommitmentRequest, ConstraintsMessage, FetchPayloadRequest, LocalPayloadFetcher, SignedConstraints, TransactionExt, }, - signer::{keystore::KeystoreSigner, local::LocalSigner, SignerError}, + signer::{keystore::KeystoreSigner, local::LocalSigner}, start_builder_proxy_server, state::{fetcher::StateFetcher, ConsensusState, ExecutionState, HeadTracker, StateClient}, telemetry::ApiMetrics, @@ -264,15 +264,11 @@ impl SidecarDriver { let digest = message.digest(); let signature = match self.constraint_signer { - SignerBLS::Local(ref signer) => { - signer.sign_commit_boost_root(digest).map_err(SignerError::LocalSigner) + SignerBLS::Local(ref signer) => signer.sign_commit_boost_root(digest), + SignerBLS::CommitBoost(ref signer) => signer.sign_commit_boost_root(digest).await, + SignerBLS::Keystore(ref signer) => { + signer.sign_commit_boost_root(digest, cl_public_key_to_arr(pubkey.clone())) } - SignerBLS::CommitBoost(ref signer) => { - signer.sign_commit_boost_root(digest).await.map_err(SignerError::CommitBoost) - } - SignerBLS::Keystore(ref signer) => signer - .sign_commit_boost_root(digest, cl_public_key_to_arr(pubkey.clone())) - .map_err(SignerError::Keystore), }; let signed_constraints = match signature { diff --git a/bolt-sidecar/src/signer/commit_boost.rs b/bolt-sidecar/src/signer/commit_boost.rs index a3f8033d6..1757e8071 100644 --- a/bolt-sidecar/src/signer/commit_boost.rs +++ b/bolt-sidecar/src/signer/commit_boost.rs @@ -16,6 +16,8 @@ use crate::{ primitives::commitment::ECDSASignatureExt, }; +use super::SignerResult; + /// A client for interacting with CommitBoost. #[derive(Debug, Clone)] pub struct CommitBoostSigner { @@ -35,12 +37,10 @@ pub enum CommitBoostError { Other(#[from] eyre::Report), } -type Result = std::result::Result; - #[allow(unused)] impl CommitBoostSigner { /// Create a new [CommitBoostSigner] instance - pub async fn new(signer_server_address: String, jwt: &str) -> Result { + pub async fn new(signer_server_address: String, jwt: &str) -> SignerResult { let signer_client = SignerClient::new(signer_server_address, jwt).map_err(CommitBoostError::Other)?; @@ -121,7 +121,7 @@ impl CommitBoostSigner { } /// Sign an object root with the Commit Boost domain. - pub async fn sign_commit_boost_root(&self, data: [u8; 32]) -> Result { + pub async fn sign_commit_boost_root(&self, data: [u8; 32]) -> SignerResult { // convert the pubkey from ethereum_consensus to commit-boost format let pubkey = cb_common::signer::BlsPublicKey::from( alloy::rpc::types::beacon::BlsPublicKey::from_slice(self.pubkey().as_ref()), @@ -131,7 +131,11 @@ impl CommitBoostSigner { debug!(?request, "Requesting signature from commit_boost"); - Ok(self.signer_client.request_consensus_signature(request).await?) + Ok(self + .signer_client + .request_consensus_signature(request) + .await + .map_err(CommitBoostError::SignerClientError)?) } } diff --git a/bolt-sidecar/src/signer/keystore.rs b/bolt-sidecar/src/signer/keystore.rs index 83736c2dc..e6391e1fc 100644 --- a/bolt-sidecar/src/signer/keystore.rs +++ b/bolt-sidecar/src/signer/keystore.rs @@ -3,7 +3,8 @@ use std::{ ffi::OsString, fmt::Debug, - fs, + fs::{self, DirEntry, ReadDir}, + io, path::{Path, PathBuf}, }; @@ -15,24 +16,24 @@ use ssz::Encode; use crate::{builder::signature::compute_signing_root, crypto::bls::BLSSig, ChainConfig}; +use super::SignerResult; + pub const KEYSTORES_DEFAULT_PATH: &str = "keys"; #[derive(Debug, thiserror::Error)] pub enum KeystoreError { - #[error("Failed to read keystore directory: {0}")] + #[error("failed to read keystore directory: {0}")] ReadFromDirectory(#[from] std::io::Error), - #[error("Failed to read keystore from JSON file {0}: {1}")] + #[error("failed to read keystore from JSON file {0}: {1}")] ReadFromJSON(PathBuf, String), - #[error("Failed to decrypt keypair from JSON file {0} with the provided password: {1}")] + #[error("failed to decrypt keypair from JSON file {0} with the provided password: {1}")] KeypairDecryption(PathBuf, String), - #[error("Could not find private key associated to public key {0}")] + #[error("could not find private key associated to public key {0}")] UnknownPublicKey(String), - #[error("Invalid signature key length. Signature: {0}. Message: {1}")] + #[error("invalid signature key length -- signature: {0} -- message: {1}")] SignatureLength(String, String), } -type Result = std::result::Result; - #[derive(Clone)] pub struct KeystoreSigner { keypairs: Vec, @@ -40,7 +41,7 @@ pub struct KeystoreSigner { } impl KeystoreSigner { - pub fn new(keys_path: Option<&str>, password: &[u8], chain: ChainConfig) -> Result { + pub fn new(keys_path: Option<&str>, password: &[u8], chain: ChainConfig) -> SignerResult { let keystores_paths = keystore_paths(keys_path)?; let mut keypairs = Vec::with_capacity(keystores_paths.len()); @@ -60,7 +61,7 @@ impl KeystoreSigner { &self, root: [u8; 32], public_key: [u8; BLS_PUBLIC_KEY_BYTES_LEN], - ) -> Result { + ) -> SignerResult { self.sign_root(root, public_key, self.chain.commit_boost_domain()) } @@ -69,7 +70,7 @@ impl KeystoreSigner { root: [u8; 32], public_key: [u8; BLS_PUBLIC_KEY_BYTES_LEN], domain: [u8; 32], - ) -> Result { + ) -> SignerResult { let sk = self .keypairs .iter() @@ -105,7 +106,7 @@ impl Debug for KeystoreSigner { /// -- 0x1234.../validator.json /// -- 0x5678.../validator.json /// -- ... -fn keystore_paths(keys_path: Option<&str>) -> Result> { +fn keystore_paths(keys_path: Option<&str>) -> SignerResult> { // Create the path to the keystore directory, starting from the root of the project let keys_path = if let Some(keys_path) = keys_path { Path::new(&keys_path).to_path_buf() @@ -118,11 +119,11 @@ fn keystore_paths(keys_path: Option<&str>) -> Result> { let mut keystores_paths = vec![]; // Iter over the `keys` directory - for entry in fs::read_dir(keys_path).map_err(KeystoreError::ReadFromDirectory)? { - let path = entry.map_err(KeystoreError::ReadFromDirectory)?.path(); + for entry in read_dir(keys_path)? { + let path = read_path(entry)?; if path.is_dir() { - for entry in fs::read_dir(path)? { - let path = entry?.path(); + for entry in read_dir(path)? { + let path = read_path(entry)?; if path.is_file() && path.extension() == Some(&json_extension) { keystores_paths.push(path); } @@ -133,6 +134,14 @@ fn keystore_paths(keys_path: Option<&str>) -> Result> { Ok(keystores_paths) } +fn read_dir(path: PathBuf) -> SignerResult { + Ok(fs::read_dir(path).map_err(KeystoreError::ReadFromDirectory)?) +} + +fn read_path(entry: std::result::Result) -> SignerResult { + Ok(entry.map_err(KeystoreError::ReadFromDirectory)?.path()) +} + #[cfg(test)] mod tests { use std::{fs::File, io::Write}; diff --git a/bolt-sidecar/src/signer/local.rs b/bolt-sidecar/src/signer/local.rs index 792175536..2ce970594 100644 --- a/bolt-sidecar/src/signer/local.rs +++ b/bolt-sidecar/src/signer/local.rs @@ -6,19 +6,19 @@ use ethereum_consensus::{crypto::PublicKey as ClPublicKey, deneb::compute_signin use crate::{crypto::bls::BLSSig, ChainConfig}; pub use blst::min_pk::SecretKey; +use super::SignerResult; + /// The BLS Domain Separator used in Ethereum 2.0. pub const BLS_DST_PREFIX: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"; #[derive(Debug, thiserror::Error)] pub enum LocalSignerError { - #[error("Failed to compute signing root: {0}")] + #[error("failed to compute signing root: {0}")] SigningRootComputation(#[from] ethereum_consensus::error::Error), - #[error("Invalid signature: {0}")] + #[error("invalid signature: {0}")] InvalidSignature(String), } -type Result = std::result::Result; - /// A BLS signer that can sign any type that implements the [`SignableBLS`] trait. #[derive(Clone)] pub struct LocalSigner { @@ -48,18 +48,19 @@ impl LocalSigner { } /// Sign an SSZ object root with the Application Builder domain. - pub fn sign_application_builder_root(&self, root: [u8; 32]) -> Result { + pub fn sign_application_builder_root(&self, root: [u8; 32]) -> SignerResult { self.sign_root(root, self.chain.application_builder_domain()) } /// Sign an SSZ object root with the Commit Boost domain. - pub fn sign_commit_boost_root(&self, root: [u8; 32]) -> Result { + pub fn sign_commit_boost_root(&self, root: [u8; 32]) -> SignerResult { self.sign_root(root, self.chain.commit_boost_domain()) } /// Sign an SSZ object root with the given domain. - pub fn sign_root(&self, root: [u8; 32], domain: [u8; 32]) -> Result { - let signing_root = compute_signing_root(&root, domain)?; + pub fn sign_root(&self, root: [u8; 32], domain: [u8; 32]) -> SignerResult { + let signing_root = compute_signing_root(&root, domain) + .map_err(LocalSignerError::SigningRootComputation)?; let sig = self.key.sign(signing_root.as_slice(), BLS_DST_PREFIX, &[]); Ok(BLSSig::from_slice(&sig.to_bytes())) } @@ -69,12 +70,16 @@ impl LocalSigner { &self, root: [u8; 32], signature: &Signature, - ) -> Result<()> { + ) -> SignerResult<()> { self.verify_root(root, signature, self.chain.application_builder_domain()) } /// Verify the signature with the public key of the signer using the Commit Boost domain. - pub fn verify_commit_boost_root(&self, root: [u8; 32], signature: &Signature) -> Result<()> { + pub fn verify_commit_boost_root( + &self, + root: [u8; 32], + signature: &Signature, + ) -> SignerResult<()> { self.verify_root(root, signature, self.chain.commit_boost_domain()) } @@ -84,15 +89,16 @@ impl LocalSigner { root: [u8; 32], signature: &Signature, domain: [u8; 32], - ) -> Result<()> { - let signing_root = compute_signing_root(&root, domain)?; + ) -> SignerResult<()> { + let signing_root = compute_signing_root(&root, domain) + .map_err(LocalSignerError::SigningRootComputation)?; let pk = blst::min_pk::PublicKey::from_bytes(self.pubkey().as_ref()).unwrap(); let res = signature.verify(true, signing_root.as_ref(), BLS_DST_PREFIX, &[], &pk, true); if res == BLST_ERROR::BLST_SUCCESS { Ok(()) } else { - Err(LocalSignerError::InvalidSignature(format!("{res:?}"))) + Err(LocalSignerError::InvalidSignature(format!("{res:?}")))? } } } diff --git a/bolt-sidecar/src/signer/mod.rs b/bolt-sidecar/src/signer/mod.rs index f71ded19f..3d74c2629 100644 --- a/bolt-sidecar/src/signer/mod.rs +++ b/bolt-sidecar/src/signer/mod.rs @@ -24,7 +24,9 @@ pub enum SignerError { #[error("local signer error: {0}")] LocalSigner(#[from] local::LocalSignerError), #[error("commit boost signer error: {0}")] - CommitBoost(commit_boost::CommitBoostError), + CommitBoost(#[from] commit_boost::CommitBoostError), #[error("keystore signer error: {0}")] - Keystore(keystore::KeystoreError), + Keystore(#[from] keystore::KeystoreError), } + +pub type SignerResult = std::result::Result; From bc7e6292cfbc30411b122d52fa386ddeb46ae069 Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Mon, 14 Oct 2024 13:47:16 +0200 Subject: [PATCH 63/64] fmt: sidecar --- bolt-sidecar/src/builder/payload_builder.rs | 6 +++--- bolt-sidecar/src/signer/keystore.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bolt-sidecar/src/builder/payload_builder.rs b/bolt-sidecar/src/builder/payload_builder.rs index 3a69dcc86..1dfe2e9ff 100644 --- a/bolt-sidecar/src/builder/payload_builder.rs +++ b/bolt-sidecar/src/builder/payload_builder.rs @@ -454,9 +454,9 @@ mod tests { let raw_encoded = tx_signed.encoded_2718(); let tx_signed_reth = TransactionSigned::decode_enveloped(&mut raw_encoded.as_slice())?; - let slot = genesis_time - + (SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs() / cfg.chain.slot_time()) - + 1; + let slot = genesis_time + + (SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs() / cfg.chain.slot_time()) + + 1; let block = builder.build_fallback_payload(slot, &[tx_signed_reth]).await?; assert_eq!(block.body.len(), 1); diff --git a/bolt-sidecar/src/signer/keystore.rs b/bolt-sidecar/src/signer/keystore.rs index e6391e1fc..f0dda8a6d 100644 --- a/bolt-sidecar/src/signer/keystore.rs +++ b/bolt-sidecar/src/signer/keystore.rs @@ -253,8 +253,8 @@ mod tests { ) .expect("to create temp dir"); - // NOTE: it is sufficient to create a temp dir, then we can create a file as usual and it - // will be dropped correctly + // NOTE: it is sufficient to create a temp dir, then we can create a file as usual and + // it will be dropped correctly let mut tmp_file = File::create_new(tmp_dir.path().join("voting-keystore.json")) .expect("to create new file"); From 7c7d6772518d9c8e4ec8226d702f7fb45766c4fd Mon Sep 17 00:00:00 2001 From: thedevbirb Date: Mon, 14 Oct 2024 13:47:24 +0200 Subject: [PATCH 64/64] fmt: bolt-boost --- bolt-boost/src/proofs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bolt-boost/src/proofs.rs b/bolt-boost/src/proofs.rs index 432b4d527..d28284232 100644 --- a/bolt-boost/src/proofs.rs +++ b/bolt-boost/src/proofs.rs @@ -41,8 +41,8 @@ pub fn verify_multiproofs( // Get all the leaves from the saved constraints let mut leaves = Vec::with_capacity(proofs.total_leaves()); - // NOTE: Get the leaves from the constraints cache by matching the saved hashes. We need the leaves - // in order to verify the multiproof. + // NOTE: Get the leaves from the constraints cache by matching the saved hashes. We need the + // leaves in order to verify the multiproof. for hash in &proofs.transaction_hashes { let mut found = false; for constraint in constraints {