diff --git a/bolt-sidecar/src/builder/template.rs b/bolt-sidecar/src/builder/template.rs index b9d8df82e..6d3b5735c 100644 --- a/bolt-sidecar/src/builder/template.rs +++ b/bolt-sidecar/src/builder/template.rs @@ -42,7 +42,7 @@ impl BlockTemplate { /// Returns the cloned list of transactions from the constraints. #[inline] pub fn transactions(&self) -> Vec { - self.signed_constraints_list.iter().flat_map(|sc| sc.message.constraints.clone()).collect() + self.signed_constraints_list.iter().flat_map(|sc| sc.message.transactions.clone()).collect() } /// Converts the list of signed constraints into a list of signed transactions. Use this when @@ -52,7 +52,7 @@ impl BlockTemplate { self.signed_constraints_list .iter() .flat_map(|sc| { - sc.message.constraints.iter().map(|c| c.clone().into_inner().into_transaction()) + sc.message.transactions.iter().map(|c| c.clone().into_inner().into_transaction()) }) .collect() } @@ -64,7 +64,7 @@ impl BlockTemplate { let (commitments, proofs, blobs) = self.signed_constraints_list .iter() - .flat_map(|sc| sc.message.constraints.iter()) + .flat_map(|sc| sc.message.transactions.iter()) .filter_map(|c| c.blob_sidecar()) .fold( (Vec::new(), Vec::new(), Vec::new()), @@ -90,14 +90,14 @@ impl BlockTemplate { /// Returns the length of the transactions in the block template. #[inline] pub fn transactions_len(&self) -> usize { - self.signed_constraints_list.iter().fold(0, |acc, sc| acc + sc.message.constraints.len()) + self.signed_constraints_list.iter().fold(0, |acc, sc| acc + sc.message.transactions.len()) } /// Returns the committed gas in the block template. #[inline] pub fn committed_gas(&self) -> u64 { self.signed_constraints_list.iter().fold(0, |acc, sc| { - acc + sc.message.constraints.iter().fold(0, |acc, c| acc + c.gas_limit()) + acc + sc.message.transactions.iter().fold(0, |acc, c| acc + c.gas_limit()) }) } @@ -105,7 +105,7 @@ impl BlockTemplate { #[inline] pub fn blob_count(&self) -> usize { self.signed_constraints_list.iter().fold(0, |mut acc, sc| { - acc += sc.message.constraints.iter().fold(0, |acc, c| { + acc += sc.message.transactions.iter().fold(0, |acc, c| { acc + c.as_eip4844().map(|tx| tx.blob_versioned_hashes.len()).unwrap_or(0) }); @@ -115,7 +115,7 @@ impl BlockTemplate { /// Adds a list of constraints to the block template and updates the state diff. pub fn add_constraints(&mut self, constraints: SignedConstraints) { - for constraint in constraints.message.constraints.iter() { + for constraint in constraints.message.transactions.iter() { let max_cost = max_transaction_cost(constraint); self.state_diff .diffs @@ -134,7 +134,7 @@ impl BlockTemplate { fn remove_constraints_at_index(&mut self, index: usize) { let constraints = self.signed_constraints_list.remove(index); - for constraint in constraints.message.constraints.iter() { + for constraint in constraints.message.transactions.iter() { self.state_diff .diffs .entry(*constraint.sender().expect("recovered sender")) @@ -155,7 +155,7 @@ impl BlockTemplate { .signed_constraints_list .iter() .enumerate() - .map(|(idx, c)| (idx, &c.message.constraints)) + .map(|(idx, c)| (idx, &c.message.transactions)) .filter(|(_idx, c)| c.iter().any(|c| c.sender().expect("recovered sender") == &address)) .map(|(idx, c)| { ( diff --git a/bolt-sidecar/src/driver.rs b/bolt-sidecar/src/driver.rs index 6cd3520ab..99a37912d 100644 --- a/bolt-sidecar/src/driver.rs +++ b/bolt-sidecar/src/driver.rs @@ -231,7 +231,7 @@ impl SidecarDriver, + pub transactions: Vec, } impl ConstraintsMessage { /// Builds a constraints message from an inclusion request and metadata pub fn build(pubkey: BlsPublicKey, request: InclusionRequest) -> Self { - let constraints = request.txs; + let transactions = request.txs; - Self { pubkey, slot: request.slot, top: false, constraints } + Self { pubkey, slot: request.slot, top: false, transactions } } } @@ -79,8 +79,8 @@ impl SignableBLS for ConstraintsMessage { hasher.update(self.slot.to_le_bytes()); hasher.update((self.top as u8).to_le_bytes()); - for constraint in &self.constraints { - hasher.update(constraint.hash()); + for tx in &self.transactions { + hasher.update(tx.hash()); } hasher.finalize().into() @@ -114,10 +114,10 @@ mod tests { let pubkey = BlsPublicKey::default(); let slot = 0; let top = false; - let constraints = random_constraints(1); // Generate 'n' random constraints + let transactions = random_constraints(1); // Generate 'n' random constraints // Create a random `ConstraintsMessage` - let message = ConstraintsMessage { pubkey, slot, top, constraints }; + let message = ConstraintsMessage { pubkey, slot, top, transactions }; // Compute tree hash root let digest = SignableBLS::digest(&message); @@ -134,10 +134,10 @@ mod tests { let pubkey = BlsPublicKey::default(); let slot = random_u64(&mut rng); let top = false; - let constraints = random_constraints(2); // Generate 'n' random constraints + let transactions = random_constraints(2); // Generate 'n' random constraints // Create a random `ConstraintsMessage` - let message = ConstraintsMessage { pubkey, slot, top, constraints }; + let message = ConstraintsMessage { pubkey, slot, top, transactions }; // Serialize the `ConstraintsMessage` to JSON let json = serde_json::to_string(&message).unwrap(); diff --git a/bolt-sidecar/src/primitives/mod.rs b/bolt-sidecar/src/primitives/mod.rs index e705e698b..d9cfbec70 100644 --- a/bolt-sidecar/src/primitives/mod.rs +++ b/bolt-sidecar/src/primitives/mod.rs @@ -6,7 +6,10 @@ use std::{ sync::{atomic::AtomicU64, Arc}, }; -use alloy::primitives::{Address, U256}; +use alloy::{ + primitives::{Address, U256}, + signers::k256::sha2::{Digest, Sha256}, +}; use ethereum_consensus::{ crypto::KzgCommitment, deneb::{ @@ -36,6 +39,8 @@ pub mod constraint; pub use constraint::{BatchedSignedConstraints, ConstraintsMessage, SignedConstraints}; use tracing::{error, info}; +use crate::crypto::SignableBLS; + /// An alias for a Beacon Chain slot number pub type Slot = u64; @@ -430,6 +435,16 @@ pub struct DelegationMessage { pub delegatee_pubkey: BlsPublicKey, } +impl SignableBLS for DelegationMessage { + fn digest(&self) -> [u8; 32] { + let mut hasher = Sha256::new(); + hasher.update(&self.validator_pubkey.to_vec()); + hasher.update(&self.delegatee_pubkey.to_vec()); + + hasher.finalize().into() + } +} + #[derive(Debug, Clone, Serialize)] pub struct SignedRevocation { pub message: RevocationMessage, @@ -441,3 +456,13 @@ pub struct RevocationMessage { pub validator_pubkey: BlsPublicKey, pub delegatee_pubkey: BlsPublicKey, } + +impl SignableBLS for RevocationMessage { + fn digest(&self) -> [u8; 32] { + let mut hasher = Sha256::new(); + hasher.update(&self.validator_pubkey.to_vec()); + hasher.update(&self.delegatee_pubkey.to_vec()); + + hasher.finalize().into() + } +} diff --git a/bolt-sidecar/src/test_util.rs b/bolt-sidecar/src/test_util.rs index c03bad87e..ad599b124 100644 --- a/bolt-sidecar/src/test_util.rs +++ b/bolt-sidecar/src/test_util.rs @@ -11,13 +11,18 @@ use alloy::{ }; 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; use crate::{ - crypto::{ecdsa::SignableECDSA, SignableBLS}, - primitives::{CommitmentRequest, FullTransaction, InclusionRequest}, + crypto::{bls::Signer as BlsSigner, ecdsa::SignableECDSA, SignableBLS, SignerBLS}, + primitives::{ + CommitmentRequest, ConstraintsMessage, DelegationMessage, FullTransaction, + InclusionRequest, RevocationMessage, SignedConstraints, SignedDelegation, SignedRevocation, + }, Config, }; @@ -170,3 +175,103 @@ pub(crate) async fn create_signed_commitment_request( Ok(CommitmentRequest::Inclusion(request)) } + +fn random_constraints(count: usize) -> Vec { + // Random inclusion request + let json_req = r#"{ + "slot": 10, + "txs": [ + "0x02f86c870c72dd9d5e883e4d0183408f2382520894d2e2adf7177b7a8afddbc12d1634cf23ea1a71020180c001a08556dcfea479b34675db3fe08e29486fe719c2b22f6b0c1741ecbbdce4575cc6a01cd48009ccafd6b9f1290bbe2ceea268f94101d1d322c787018423ebcbc87ab4", + "0x02f9017b8501a2140cff8303dec685012a05f2008512a05f2000830249f094843669e5220036eddbaca89d8c8b5b82268a0fc580b901040cc7326300000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000022006292538e66f0000000000000000000000005ba38f2c245618e39f6fa067bf1dec304e73ff3c00000000000000000000000092f0ee29e6e1bf0f7c668317ada78f5774a6cb7f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000003fac6482aee49bf58515be2d3fb58378a8497cc9000000000000000000000000c6cc140787b02ae479a10e41169607000c0d44f6c080a00cf74c45dbe9ee1fb923118ec5ce9db8f88cd651196ed3f9d4f8f2a65827e611a04a6bc1d49a7e18b7c92e8f3614cae116b1832ceb311c81d54b2c87de1545f68f", + "0x02f8708501a2140cff82012f800782520894b6c402298fcb88039bbfde70f5ace791f18cfac88707131d70870dc880c080a03aab1b17ecf28f85de43c7733611759b87d25ba885babacb6b4c625d715415eea03fb52cb7744ccb885906e42f6b9cf82e74b47a4b4b4072af2aa52a8dc472236e" + ] + }"#; + + let req: InclusionRequest = serde_json::from_str(json_req).unwrap(); + + req.txs.iter().cloned().take(count).collect() +} + +#[tokio::test] +async fn generate_test_data() { + let sk = test_bls_secret_key(); + let pk = sk.sk_to_pk(); + let signer = BlsSigner::new(sk); + + println!("Validator Public Key: {}", hex::encode(pk.to_bytes())); + + // Generate a delegatee's BLS secret key and public key + let delegatee_ikm: [u8; 32] = rand::thread_rng().gen(); + let delegatee_sk = + SecretKey::key_gen(&delegatee_ikm, &[]).expect("Failed to generate delegatee secret key"); + let delegatee_pk = delegatee_sk.sk_to_pk(); + + // 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"), + delegatee_pubkey: 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 = SignerBLS::sign(&signer, &digest).await.unwrap(); + + // Create SignedDelegation + let signed_delegation = SignedDelegation { + message: delegation_msg, + signature: Signature::try_from(delegation_signature.as_ref()) + .expect("Failed to convert delegation signature"), + }; + + // Output SignedDelegation + println!("{}", serde_json::to_string_pretty(&signed_delegation).unwrap()); + + // 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"), + delegatee_pubkey: PublicKey::try_from(delegatee_pk.to_bytes().as_slice()) + .expect("Failed to convert delegatee public key"), + }; + + let digest = SignableBLS::digest(&revocation_msg); + + // Sign the Revocation message + let revocation_signature = SignerBLS::sign(&signer, &digest).await.unwrap(); + + // Create SignedRevocation + let signed_revocation = SignedRevocation { + message: revocation_msg, + signature: Signature::try_from(revocation_signature.as_ref()) + .expect("Failed to convert revocation signature"), + }; + + // Output SignedRevocation + println!("{}", serde_json::to_string_pretty(&signed_revocation).unwrap()); + + 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 digest = SignableBLS::digest(&constraints_msg); + + // Sign the ConstraintsMessage + let constraints_signature = SignerBLS::sign(&signer, &digest).await.unwrap(); + + // Create SignedConstraints + let signed_constraints = + SignedConstraints { message: constraints_msg, signature: constraints_signature }; + + // Output SignedConstraints + println!("{}", serde_json::to_string_pretty(&signed_constraints).unwrap()); +}