diff --git a/Cargo.lock b/Cargo.lock index f2cb150a5a9..7db5f6387a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -292,6 +292,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "anstyle" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" + [[package]] name = "anyhow" version = "1.0.80" @@ -2024,6 +2030,12 @@ dependencies = [ "syn 2.0.52", ] +[[package]] +name = "downcast" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" + [[package]] name = "dtoa" version = "1.0.9" @@ -3009,6 +3021,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fragile" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" + [[package]] name = "fs2" version = "0.4.3" @@ -4234,6 +4252,7 @@ dependencies = [ "ethereum_ssz", "ethereum_ssz_derive", "hex", + "mockall", "serde", "tree_hash", ] @@ -4353,7 +4372,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2caa5afb8bf9f3a2652760ce7d4f62d21c4d5a423e68466fca30df82f2330164" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.4", ] [[package]] @@ -5266,6 +5285,45 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9366861eb2a2c436c20b12c8dbec5f798cea6b47ad99216be0282942e2c81ea0" +[[package]] +name = "mockall" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43766c2b5203b10de348ffe19f7e54564b64f3d6018ff7648d1e2d6d3a0f0a48" +dependencies = [ + "cfg-if", + "downcast", + "fragile", + "lazy_static", + "mockall_derive", + "predicates", + "predicates-tree", +] + +[[package]] +name = "mockall_derive" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af7cbce79ec385a1d4f54baa90a76401eb15d9cab93685f62e7e9f942aa00ae2" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "mockall_double" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1ca96e5ac35256ae3e13536edd39b172b88f41615e1d7b653c8ad24524113e8" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn 2.0.52", +] + [[package]] name = "monitoring_api" version = "0.1.0" @@ -6211,6 +6269,32 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "predicates" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8" +dependencies = [ + "anstyle", + "predicates-core", +] + +[[package]] +name = "predicates-core" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" + +[[package]] +name = "predicates-tree" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +dependencies = [ + "predicates-core", + "termtree", +] + [[package]] name = "pretty_reqwest_error" version = "0.1.0" @@ -8086,6 +8170,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "termtree" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" + [[package]] name = "test-test_logger" version = "0.1.0" @@ -8647,6 +8737,7 @@ dependencies = [ "maplit", "merkle_proof", "metastruct", + "mockall_double", "parking_lot 0.12.1", "paste", "rand", diff --git a/Cargo.toml b/Cargo.toml index bc306f736c1..8bf34fad421 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -119,6 +119,8 @@ libsecp256k1 = "0.7" log = "0.4" lru = "0.12" maplit = "1" +mockall = "0.12" +mockall_double = "0.3" num_cpus = "1" parking_lot = "0.12" paste = "1" diff --git a/beacon_node/beacon_chain/src/block_verification.rs b/beacon_node/beacon_chain/src/block_verification.rs index 1e1ac6ddff5..88ab1c1612b 100644 --- a/beacon_node/beacon_chain/src/block_verification.rs +++ b/beacon_node/beacon_chain/src/block_verification.rs @@ -773,6 +773,8 @@ fn build_gossip_verified_data_columns( gossip_verified_blobs: Option<&GossipVerifiedBlobList>, ) -> Result>, BlockContentsError> { gossip_verified_blobs + // Only attempt to build data columns if blobs is non empty to avoid skewing the metrics. + .filter(|b| !b.is_empty()) .map(|blobs| { // NOTE: we expect KZG to be initialized if the blobs are present let kzg = chain @@ -786,7 +788,7 @@ fn build_gossip_verified_data_columns( let blob_sidecar_list = BlobSidecarList::new(blob_sidecar_list) .map_err(DataColumnSidecarError::SszError)?; let timer = metrics::start_timer(&metrics::DATA_COLUMN_SIDECAR_COMPUTATION); - let sidecars = DataColumnSidecar::build_sidecars(&blob_sidecar_list, &block, kzg)?; + let sidecars = DataColumnSidecar::build_sidecars(&blob_sidecar_list, block, kzg)?; drop(timer); let mut gossip_verified_data_columns = vec![]; for sidecar in sidecars { diff --git a/consensus/types/Cargo.toml b/consensus/types/Cargo.toml index e77cd67ed15..a0abae8a7b3 100644 --- a/consensus/types/Cargo.toml +++ b/consensus/types/Cargo.toml @@ -60,6 +60,7 @@ eth2_network_config = { workspace = true } state_processing = { workspace = true } tokio = { workspace = true } paste = { workspace = true } +mockall_double = { workspace = true } [features] default = ["sqlite", "legacy-arith"] diff --git a/consensus/types/src/data_column_sidecar.rs b/consensus/types/src/data_column_sidecar.rs index 885dc243cfd..6b1925f3c4c 100644 --- a/consensus/types/src/data_column_sidecar.rs +++ b/consensus/types/src/data_column_sidecar.rs @@ -7,8 +7,12 @@ use crate::{ }; use bls::Signature; use derivative::Derivative; -use kzg::{Blob as KzgBlob, Error as KzgError, Kzg}; +#[cfg_attr(test, double)] +use kzg::Kzg; +use kzg::{Blob as KzgBlob, Error as KzgError}; use kzg::{KzgCommitment, KzgProof}; +#[cfg(test)] +use mockall_double::double; use safe_arith::ArithError; use serde::{Deserialize, Serialize}; use ssz::Encode; @@ -76,6 +80,9 @@ impl DataColumnSidecar { block: &SignedBeaconBlock, kzg: &Kzg, ) -> Result, DataColumnSidecarError> { + if blobs.is_empty() { + return Ok(DataColumnSidecarList::empty()); + } let kzg_commitments = block .message() .body() @@ -239,6 +246,7 @@ pub type FixedDataColumnSidecarList = #[cfg(test)] mod test { + use super::*; use crate::beacon_block::EmptyBlock; use crate::beacon_block_body::KzgCommitments; use crate::eth_spec::EthSpec; @@ -247,10 +255,24 @@ mod test { DataColumnSidecar, MainnetEthSpec, SignedBeaconBlock, }; use bls::Signature; - use eth2_network_config::TRUSTED_SETUP_BYTES; - use kzg::{Kzg, KzgCommitment, KzgProof, TrustedSetup}; + use kzg::{KzgCommitment, KzgProof}; use std::sync::Arc; + #[test] + fn test_build_sidecars_empty() { + type E = MainnetEthSpec; + let num_of_blobs = 0; + let spec = E::default_spec(); + let (signed_block, blob_sidecars) = + create_test_block_and_blob_sidecars::(num_of_blobs, &spec); + + let mock_kzg = Arc::new(Kzg::default()); + let column_sidecars = + DataColumnSidecar::build_sidecars(&blob_sidecars, &signed_block, &mock_kzg).unwrap(); + + assert!(column_sidecars.is_empty()); + } + #[test] fn test_build_sidecars() { type E = MainnetEthSpec; @@ -259,11 +281,13 @@ mod test { let (signed_block, blob_sidecars) = create_test_block_and_blob_sidecars::(num_of_blobs, &spec); - let trusted_setup: TrustedSetup = serde_json::from_reader(TRUSTED_SETUP_BYTES).unwrap(); - let kzg = Arc::new(Kzg::new_from_trusted_setup(trusted_setup).unwrap()); + let mut mock_kzg = Kzg::default(); + mock_kzg + .expect_compute_cells_and_proofs() + .returning(kzg::mock::compute_cells_and_proofs); let column_sidecars = - DataColumnSidecar::build_sidecars(&blob_sidecars, &signed_block, &kzg).unwrap(); + DataColumnSidecar::build_sidecars(&blob_sidecars, &signed_block, &mock_kzg).unwrap(); let block_kzg_commitments = signed_block .message() diff --git a/crypto/kzg/Cargo.toml b/crypto/kzg/Cargo.toml index d26dfe4992a..2c3c894b49c 100644 --- a/crypto/kzg/Cargo.toml +++ b/crypto/kzg/Cargo.toml @@ -17,3 +17,4 @@ ethereum_serde_utils = { workspace = true } hex = { workspace = true } ethereum_hashing = { workspace = true } c-kzg = { workspace = true } +mockall = { workspace = true } diff --git a/crypto/kzg/src/lib.rs b/crypto/kzg/src/lib.rs index 60eb0dfe0e7..3a015d3c048 100644 --- a/crypto/kzg/src/lib.rs +++ b/crypto/kzg/src/lib.rs @@ -14,6 +14,8 @@ pub use c_kzg::{ BYTES_PER_FIELD_ELEMENT, BYTES_PER_PROOF, FIELD_ELEMENTS_PER_BLOB, }; use c_kzg::{Cell, CELLS_PER_BLOB}; +use mockall::automock; + #[derive(Debug)] pub enum Error { /// An error from the underlying kzg library. @@ -34,6 +36,7 @@ pub struct Kzg { trusted_setup: KzgSettings, } +#[automock] impl Kzg { /// Load the kzg trusted setup parameters from a vec of G1 and G2 points. pub fn new_from_trusted_setup(trusted_setup: TrustedSetup) -> Result { @@ -191,6 +194,22 @@ impl Kzg { } } +pub mod mock { + use crate::{Error, KzgProof}; + use c_kzg::{Blob, Cell, CELLS_PER_BLOB}; + + pub const MOCK_KZG_BYTES_PER_CELL: usize = 2048; + pub fn compute_cells_and_proofs( + _blob: &Blob, + ) -> Result<(Box<[Cell; CELLS_PER_BLOB]>, Box<[KzgProof; CELLS_PER_BLOB]>), Error> { + let empty_cell = Cell::new([0; MOCK_KZG_BYTES_PER_CELL]); + Ok(( + Box::new([empty_cell; CELLS_PER_BLOB]), + Box::new([KzgProof::empty(); CELLS_PER_BLOB]), + )) + } +} + impl TryFrom for Kzg { type Error = Error;