Pre-generate test blobs bundle to improve test time. (#4829)
## Issue Addressed Addresses #4778, and potentially fixes the flaky deneb builder test `builder_works_post_deneb`. The [deneb builder test](c5c84f1213/beacon_node/http_api/tests/tests.rs (L5371)
) has been quite flaky on our CI (`release-tests`) since it was introduced. I'm guessing that it might be timing out on the builder `get_header` call (1 second), and therefore the local payload is used, while the test expects builder payload to be used. On my machine the [`get_header` ](c5c84f1213/beacon_node/execution_layer/src/test_utils/mock_builder.rs (L367)
) call takes about 550ms, which could easily go over 1s on slower environments (our windows CI runner is much slower than the ubuntu one). I did a profile on the test and it showed that `blob_to_kzg_commiment` and `compute_kzg_proof` was taking a large chunk of time, so perhaps pre-generating the blobs could help stablise this test. ## Proposed Changes Pre-generate blobs bundle for Mainnet and Minimal presets. Before the change `get_header` took about **550ms**, and it's now reduced to **50-55ms** after the change. If timeout was indeed the cause of the flaky test, this fix should stablise it. This also brings the flaky `builder_works_post_deneb` test time from 50s to 10s. (8s if we only use a single blob)
This commit is contained in:
parent
369b624b19
commit
64c156c0c1
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2531,6 +2531,7 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"environment",
|
"environment",
|
||||||
"eth2",
|
"eth2",
|
||||||
|
"eth2_network_config",
|
||||||
"ethereum_serde_utils",
|
"ethereum_serde_utils",
|
||||||
"ethereum_ssz",
|
"ethereum_ssz",
|
||||||
"ethers-core",
|
"ethers-core",
|
||||||
|
@ -267,9 +267,7 @@ pub mod tests {
|
|||||||
use crate::test_utils::{generate_rand_block_and_blobs, NumBlobs};
|
use crate::test_utils::{generate_rand_block_and_blobs, NumBlobs};
|
||||||
use crate::AvailabilityPendingExecutedBlock;
|
use crate::AvailabilityPendingExecutedBlock;
|
||||||
use crate::PayloadVerificationOutcome;
|
use crate::PayloadVerificationOutcome;
|
||||||
use eth2_network_config::get_trusted_setup;
|
|
||||||
use fork_choice::PayloadVerificationStatus;
|
use fork_choice::PayloadVerificationStatus;
|
||||||
use kzg::{Kzg, TrustedSetup};
|
|
||||||
use rand::rngs::StdRng;
|
use rand::rngs::StdRng;
|
||||||
use rand::SeedableRng;
|
use rand::SeedableRng;
|
||||||
use state_processing::ConsensusContext;
|
use state_processing::ConsensusContext;
|
||||||
@ -285,13 +283,9 @@ pub mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
pub fn pre_setup() -> Setup<E> {
|
pub fn pre_setup() -> Setup<E> {
|
||||||
let trusted_setup: TrustedSetup =
|
|
||||||
serde_json::from_reader(get_trusted_setup::<<E as EthSpec>::Kzg>()).unwrap();
|
|
||||||
let kzg = Kzg::new_from_trusted_setup(trusted_setup).unwrap();
|
|
||||||
|
|
||||||
let mut rng = StdRng::seed_from_u64(0xDEADBEEF0BAD5EEDu64);
|
let mut rng = StdRng::seed_from_u64(0xDEADBEEF0BAD5EEDu64);
|
||||||
let (block, blobs_vec) =
|
let (block, blobs_vec) =
|
||||||
generate_rand_block_and_blobs::<E>(ForkName::Deneb, NumBlobs::Random, &kzg, &mut rng);
|
generate_rand_block_and_blobs::<E>(ForkName::Deneb, NumBlobs::Random, &mut rng);
|
||||||
let mut blobs: FixedVector<_, <E as EthSpec>::MaxBlobsPerBlock> = FixedVector::default();
|
let mut blobs: FixedVector<_, <E as EthSpec>::MaxBlobsPerBlock> = FixedVector::default();
|
||||||
|
|
||||||
for blob in blobs_vec {
|
for blob in blobs_vec {
|
||||||
|
@ -2526,7 +2526,6 @@ pub enum NumBlobs {
|
|||||||
pub fn generate_rand_block_and_blobs<E: EthSpec>(
|
pub fn generate_rand_block_and_blobs<E: EthSpec>(
|
||||||
fork_name: ForkName,
|
fork_name: ForkName,
|
||||||
num_blobs: NumBlobs,
|
num_blobs: NumBlobs,
|
||||||
kzg: &Kzg<E::Kzg>,
|
|
||||||
rng: &mut impl Rng,
|
rng: &mut impl Rng,
|
||||||
) -> (SignedBeaconBlock<E, FullPayload<E>>, Vec<BlobSidecar<E>>) {
|
) -> (SignedBeaconBlock<E, FullPayload<E>>, Vec<BlobSidecar<E>>) {
|
||||||
let inner = map_fork_name!(fork_name, BeaconBlock, <_>::random_for_test(rng));
|
let inner = map_fork_name!(fork_name, BeaconBlock, <_>::random_for_test(rng));
|
||||||
@ -2540,8 +2539,7 @@ pub fn generate_rand_block_and_blobs<E: EthSpec>(
|
|||||||
NumBlobs::None => 0,
|
NumBlobs::None => 0,
|
||||||
};
|
};
|
||||||
let (bundle, transactions) =
|
let (bundle, transactions) =
|
||||||
execution_layer::test_utils::generate_random_blobs::<E, _>(num_blobs, kzg, rng)
|
execution_layer::test_utils::generate_blobs::<E>(num_blobs).unwrap();
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
payload.execution_payload.transactions = <_>::default();
|
payload.execution_payload.transactions = <_>::default();
|
||||||
for tx in Vec::from(transactions) {
|
for tx in Vec::from(transactions) {
|
||||||
|
@ -50,3 +50,4 @@ triehash = "0.8.4"
|
|||||||
hash-db = "0.15.2"
|
hash-db = "0.15.2"
|
||||||
pretty_reqwest_error = { workspace = true }
|
pretty_reqwest_error = { workspace = true }
|
||||||
arc-swap = "1.6.0"
|
arc-swap = "1.6.0"
|
||||||
|
eth2_network_config = { workspace = true }
|
||||||
|
@ -10,7 +10,7 @@ use crate::{
|
|||||||
ExecutionBlockWithTransactions,
|
ExecutionBlockWithTransactions,
|
||||||
};
|
};
|
||||||
use eth2::types::BlobsBundle;
|
use eth2::types::BlobsBundle;
|
||||||
use kzg::Kzg;
|
use kzg::{Kzg, KzgCommitment, KzgProof};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use rand::{rngs::StdRng, Rng, SeedableRng};
|
use rand::{rngs::StdRng, Rng, SeedableRng};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -20,12 +20,16 @@ use std::sync::Arc;
|
|||||||
use tree_hash::TreeHash;
|
use tree_hash::TreeHash;
|
||||||
use tree_hash_derive::TreeHash;
|
use tree_hash_derive::TreeHash;
|
||||||
use types::{
|
use types::{
|
||||||
BlobSidecar, ChainSpec, EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadCapella,
|
Blob, ChainSpec, EthSpec, EthSpecId, ExecutionBlockHash, ExecutionPayload,
|
||||||
ExecutionPayloadDeneb, ExecutionPayloadHeader, ExecutionPayloadMerge, ForkName, Hash256,
|
ExecutionPayloadCapella, ExecutionPayloadDeneb, ExecutionPayloadHeader, ExecutionPayloadMerge,
|
||||||
Transaction, Transactions, Uint256,
|
ForkName, Hash256, Transaction, Transactions, Uint256,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::DEFAULT_TERMINAL_BLOCK;
|
use super::DEFAULT_TERMINAL_BLOCK;
|
||||||
|
use ssz::Decode;
|
||||||
|
|
||||||
|
const TEST_BLOB_BUNDLE_MAINNET: &[u8] = include_bytes!("fixtures/mainnet/test_blobs_bundle.ssz");
|
||||||
|
const TEST_BLOB_BUNDLE_MINIMAL: &[u8] = include_bytes!("fixtures/minimal/test_blobs_bundle.ssz");
|
||||||
|
|
||||||
const GAS_LIMIT: u64 = 16384;
|
const GAS_LIMIT: u64 = 16384;
|
||||||
const GAS_USED: u64 = GAS_LIMIT - 1;
|
const GAS_USED: u64 = GAS_LIMIT - 1;
|
||||||
@ -627,8 +631,7 @@ impl<T: EthSpec> ExecutionBlockGenerator<T> {
|
|||||||
// get random number between 0 and Max Blobs
|
// get random number between 0 and Max Blobs
|
||||||
let mut rng = self.rng.lock();
|
let mut rng = self.rng.lock();
|
||||||
let num_blobs = rng.gen::<usize>() % (T::max_blobs_per_block() + 1);
|
let num_blobs = rng.gen::<usize>() % (T::max_blobs_per_block() + 1);
|
||||||
let kzg = self.kzg.as_ref().ok_or("kzg not initialized")?;
|
let (bundle, transactions) = generate_blobs(num_blobs)?;
|
||||||
let (bundle, transactions) = generate_random_blobs(num_blobs, kzg, &mut *rng)?;
|
|
||||||
for tx in Vec::from(transactions) {
|
for tx in Vec::from(transactions) {
|
||||||
execution_payload
|
execution_payload
|
||||||
.transactions_mut()
|
.transactions_mut()
|
||||||
@ -645,30 +648,51 @@ impl<T: EthSpec> ExecutionBlockGenerator<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_random_blobs<T: EthSpec, R: Rng>(
|
pub fn load_test_blobs_bundle<E: EthSpec>() -> Result<(KzgCommitment, KzgProof, Blob<E>), String> {
|
||||||
|
let blob_bundle_bytes = match E::spec_name() {
|
||||||
|
EthSpecId::Mainnet => TEST_BLOB_BUNDLE_MAINNET,
|
||||||
|
EthSpecId::Minimal => TEST_BLOB_BUNDLE_MINIMAL,
|
||||||
|
EthSpecId::Gnosis => {
|
||||||
|
return Err("Test blobs bundle not available for Gnosis preset".to_string())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let BlobsBundle {
|
||||||
|
commitments,
|
||||||
|
proofs,
|
||||||
|
blobs,
|
||||||
|
} = BlobsBundle::<E>::from_ssz_bytes(blob_bundle_bytes)
|
||||||
|
.map_err(|e| format!("Unable to decode SSZ: {:?}", e))?;
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
commitments
|
||||||
|
.get(0)
|
||||||
|
.cloned()
|
||||||
|
.ok_or("commitment missing in test bundle")?,
|
||||||
|
proofs
|
||||||
|
.get(0)
|
||||||
|
.cloned()
|
||||||
|
.ok_or("proof missing in test bundle")?,
|
||||||
|
blobs.get(0).cloned().ok_or("blob missing in test bundle")?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_blobs<E: EthSpec>(
|
||||||
n_blobs: usize,
|
n_blobs: usize,
|
||||||
kzg: &Kzg<T::Kzg>,
|
) -> Result<(BlobsBundle<E>, Transactions<E>), String> {
|
||||||
rng: &mut R,
|
let (kzg_commitment, kzg_proof, blob) = load_test_blobs_bundle::<E>()?;
|
||||||
) -> Result<(BlobsBundle<T>, Transactions<T>), String> {
|
|
||||||
let mut bundle = BlobsBundle::<T>::default();
|
let mut bundle = BlobsBundle::<E>::default();
|
||||||
let mut transactions = vec![];
|
let mut transactions = vec![];
|
||||||
|
|
||||||
for blob_index in 0..n_blobs {
|
for blob_index in 0..n_blobs {
|
||||||
let random_valid_sidecar = BlobSidecar::<T>::random_valid(rng, kzg)?;
|
let tx = static_valid_tx::<E>()
|
||||||
|
|
||||||
let BlobSidecar {
|
|
||||||
blob,
|
|
||||||
kzg_commitment,
|
|
||||||
kzg_proof,
|
|
||||||
..
|
|
||||||
} = random_valid_sidecar;
|
|
||||||
|
|
||||||
let tx = static_valid_tx::<T>()
|
|
||||||
.map_err(|e| format!("error creating valid tx SSZ bytes: {:?}", e))?;
|
.map_err(|e| format!("error creating valid tx SSZ bytes: {:?}", e))?;
|
||||||
|
|
||||||
transactions.push(tx);
|
transactions.push(tx);
|
||||||
bundle
|
bundle
|
||||||
.blobs
|
.blobs
|
||||||
.push(blob)
|
.push(blob.clone())
|
||||||
.map_err(|_| format!("blobs are full, blob index: {:?}", blob_index))?;
|
.map_err(|_| format!("blobs are full, blob index: {:?}", blob_index))?;
|
||||||
bundle
|
bundle
|
||||||
.commitments
|
.commitments
|
||||||
@ -797,7 +821,8 @@ pub fn generate_pow_block(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use types::MainnetEthSpec;
|
use kzg::TrustedSetup;
|
||||||
|
use types::{MainnetEthSpec, MinimalEthSpec};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn pow_chain_only() {
|
fn pow_chain_only() {
|
||||||
@ -859,4 +884,33 @@ mod test {
|
|||||||
assert!(generator.block_by_number(next_i).is_none());
|
assert!(generator.block_by_number(next_i).is_none());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn valid_test_blobs() {
|
||||||
|
assert!(
|
||||||
|
validate_blob::<MainnetEthSpec>().unwrap(),
|
||||||
|
"Mainnet preset test blobs bundle should contain valid proofs"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
validate_blob::<MinimalEthSpec>().unwrap(),
|
||||||
|
"Minimal preset test blobs bundle should contain valid proofs"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_blob<E: EthSpec>() -> Result<bool, String> {
|
||||||
|
let kzg = load_kzg::<E>()?;
|
||||||
|
let (kzg_commitment, kzg_proof, blob) = load_test_blobs_bundle::<E>()?;
|
||||||
|
let kzg_blob = E::blob_from_bytes(blob.as_ref())
|
||||||
|
.map_err(|e| format!("Error converting blob to kzg blob: {e:?}"))?;
|
||||||
|
kzg.verify_blob_kzg_proof(&kzg_blob, kzg_commitment, kzg_proof)
|
||||||
|
.map_err(|e| format!("Invalid blobs bundle: {e:?}"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_kzg<E: EthSpec>() -> Result<Kzg<E::Kzg>, String> {
|
||||||
|
let trusted_setup: TrustedSetup =
|
||||||
|
serde_json::from_reader(eth2_network_config::get_trusted_setup::<E::Kzg>())
|
||||||
|
.map_err(|e| format!("Unable to read trusted setup file: {e:?}"))?;
|
||||||
|
Kzg::new_from_trusted_setup(trusted_setup)
|
||||||
|
.map_err(|e| format!("Failed to load trusted setup: {e:?}"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Binary file not shown.
@ -25,8 +25,8 @@ use warp::{http::StatusCode, Filter, Rejection};
|
|||||||
|
|
||||||
use crate::EngineCapabilities;
|
use crate::EngineCapabilities;
|
||||||
pub use execution_block_generator::{
|
pub use execution_block_generator::{
|
||||||
generate_genesis_block, generate_genesis_header, generate_pow_block, generate_random_blobs,
|
generate_blobs, generate_genesis_block, generate_genesis_header, generate_pow_block, Block,
|
||||||
Block, ExecutionBlockGenerator,
|
ExecutionBlockGenerator,
|
||||||
};
|
};
|
||||||
pub use hook::Hook;
|
pub use hook::Hook;
|
||||||
pub use mock_builder::{MockBuilder, Operation};
|
pub use mock_builder::{MockBuilder, Operation};
|
||||||
|
@ -91,10 +91,8 @@ impl TestRig {
|
|||||||
fork_name: ForkName,
|
fork_name: ForkName,
|
||||||
num_blobs: NumBlobs,
|
num_blobs: NumBlobs,
|
||||||
) -> (SignedBeaconBlock<E>, Vec<BlobSidecar<E>>) {
|
) -> (SignedBeaconBlock<E>, Vec<BlobSidecar<E>>) {
|
||||||
let kzg = self.harness.chain.kzg.as_ref().unwrap();
|
|
||||||
let rng = &mut self.rng;
|
let rng = &mut self.rng;
|
||||||
|
generate_rand_block_and_blobs::<E>(fork_name, num_blobs, rng)
|
||||||
generate_rand_block_and_blobs::<E>(fork_name, num_blobs, kzg.as_ref(), rng)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
|
@ -7,7 +7,7 @@ use mediatype::{names, MediaType, MediaTypeList};
|
|||||||
use serde::{Deserialize, Deserializer, Serialize};
|
use serde::{Deserialize, Deserializer, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use ssz::{Decode, DecodeError};
|
use ssz::{Decode, DecodeError};
|
||||||
use ssz_derive::Encode;
|
use ssz_derive::{Decode, Encode};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt::{self, Display};
|
use std::fmt::{self, Display};
|
||||||
use std::str::{from_utf8, FromStr};
|
use std::str::{from_utf8, FromStr};
|
||||||
@ -2012,7 +2012,7 @@ pub struct ExecutionPayloadAndBlobs<E: EthSpec> {
|
|||||||
pub blobs_bundle: BlobsBundle<E>,
|
pub blobs_bundle: BlobsBundle<E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, Encode)]
|
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, Encode, Decode)]
|
||||||
#[serde(bound = "E: EthSpec")]
|
#[serde(bound = "E: EthSpec")]
|
||||||
pub struct BlobsBundle<E: EthSpec> {
|
pub struct BlobsBundle<E: EthSpec> {
|
||||||
pub commitments: KzgCommitments<E>,
|
pub commitments: KzgCommitments<E>,
|
||||||
|
Loading…
Reference in New Issue
Block a user