mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-31 21:27:12 +00:00
Resolve merge conflicts
This commit is contained in:
@@ -1,50 +1,57 @@
|
||||
use crate::blob_verification::GossipVerifiedBlob;
|
||||
use crate::block_verification_types::{AsBlock, RpcBlock};
|
||||
use crate::custody_context::NodeCustodyType;
|
||||
use crate::data_column_verification::CustodyDataColumn;
|
||||
use crate::graffiti_calculator::GraffitiSettings;
|
||||
use crate::kzg_utils::build_data_column_sidecars;
|
||||
use crate::observed_operations::ObservationOutcome;
|
||||
pub use crate::persisted_beacon_chain::PersistedBeaconChain;
|
||||
use crate::{BeaconBlockResponseWrapper, get_block_root};
|
||||
use crate::{
|
||||
BeaconChain, BeaconChainTypes, BlockError, ChainConfig, ServerSentEventHandler,
|
||||
StateSkipConfig,
|
||||
builder::{BeaconChainBuilder, Witness},
|
||||
};
|
||||
pub use crate::{
|
||||
beacon_chain::{BEACON_CHAIN_DB_KEY, ETH1_CACHE_DB_KEY, FORK_CHOICE_DB_KEY, OP_POOL_DB_KEY},
|
||||
BeaconChainError, NotifyExecutionLayer, ProduceBlockVerification,
|
||||
beacon_chain::{BEACON_CHAIN_DB_KEY, FORK_CHOICE_DB_KEY, OP_POOL_DB_KEY},
|
||||
migrate::MigratorConfig,
|
||||
single_attestation::single_attestation_to_attestation,
|
||||
sync_committee_verification::Error as SyncCommitteeError,
|
||||
validator_monitor::{ValidatorMonitor, ValidatorMonitorConfig},
|
||||
BeaconChainError, NotifyExecutionLayer, ProduceBlockVerification,
|
||||
};
|
||||
use crate::{
|
||||
builder::{BeaconChainBuilder, Witness},
|
||||
eth1_chain::CachingEth1Backend,
|
||||
BeaconChain, BeaconChainTypes, BlockError, ChainConfig, ServerSentEventHandler,
|
||||
StateSkipConfig,
|
||||
};
|
||||
use crate::{get_block_root, BeaconBlockResponseWrapper};
|
||||
use bls::get_withdrawal_credentials;
|
||||
use eth2::types::SignedBlockContentsTuple;
|
||||
use bls::{
|
||||
AggregateSignature, Keypair, PublicKey, PublicKeyBytes, SecretKey, Signature, SignatureBytes,
|
||||
};
|
||||
use eth2::types::{GraffitiPolicy, SignedBlockContentsTuple};
|
||||
use execution_layer::test_utils::generate_genesis_header;
|
||||
use execution_layer::{
|
||||
ExecutionLayer,
|
||||
auth::JwtKey,
|
||||
test_utils::{
|
||||
ExecutionBlockGenerator, MockBuilder, MockExecutionLayer, DEFAULT_JWT_SECRET,
|
||||
DEFAULT_TERMINAL_BLOCK,
|
||||
DEFAULT_JWT_SECRET, DEFAULT_TERMINAL_BLOCK, ExecutionBlockGenerator, MockBuilder,
|
||||
MockExecutionLayer,
|
||||
},
|
||||
ExecutionLayer,
|
||||
};
|
||||
use fixed_bytes::FixedBytesExtended;
|
||||
use futures::channel::mpsc::Receiver;
|
||||
pub use genesis::{InteropGenesisBuilder, DEFAULT_ETH1_BLOCK_HASH};
|
||||
pub use genesis::{DEFAULT_ETH1_BLOCK_HASH, InteropGenesisBuilder};
|
||||
use int_to_bytes::int_to_bytes32;
|
||||
use kzg::Kzg;
|
||||
use kzg::trusted_setup::get_trusted_setup;
|
||||
use kzg::{Kzg, TrustedSetup};
|
||||
use logging::create_test_tracing_subscriber;
|
||||
use merkle_proof::MerkleTree;
|
||||
use operation_pool::ReceivedPreCapella;
|
||||
use parking_lot::{Mutex, RwLockWriteGuard};
|
||||
use rand::rngs::StdRng;
|
||||
use rand::Rng;
|
||||
use rand::SeedableRng;
|
||||
use rand::rngs::StdRng;
|
||||
use rand::seq::SliceRandom;
|
||||
use rayon::prelude::*;
|
||||
use sensitive_url::SensitiveUrl;
|
||||
use slot_clock::{SlotClock, TestingSlotClock};
|
||||
use ssz_types::{RuntimeVariableList, VariableList};
|
||||
use state_processing::per_block_processing::compute_timestamp_at_slot;
|
||||
use state_processing::state_advance::complete_state_advance;
|
||||
use std::borrow::Cow;
|
||||
@@ -55,26 +62,26 @@ use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::{Arc, LazyLock};
|
||||
use std::time::Duration;
|
||||
use store::database::interface::BeaconNodeBackend;
|
||||
use store::{config::StoreConfig, HotColdDB, ItemStore, MemoryStore};
|
||||
use store::{HotColdDB, ItemStore, MemoryStore, config::StoreConfig};
|
||||
use task_executor::TaskExecutor;
|
||||
use task_executor::{test_utils::TestRuntime, ShutdownReason};
|
||||
use task_executor::{ShutdownReason, test_utils::TestRuntime};
|
||||
use tree_hash::TreeHash;
|
||||
use typenum::U4294967296;
|
||||
use types::data_column_custody_group::CustodyIndex;
|
||||
use types::indexed_attestation::IndexedAttestationBase;
|
||||
use types::payload::BlockProductionVersion;
|
||||
pub use types::test_utils::generate_deterministic_keypairs;
|
||||
use types::test_utils::TestRandom;
|
||||
use types::{typenum::U4294967296, *};
|
||||
pub use types::test_utils::generate_deterministic_keypairs;
|
||||
use types::*;
|
||||
|
||||
// 4th September 2019
|
||||
pub const HARNESS_GENESIS_TIME: u64 = 1_567_552_690;
|
||||
// Environment variable to read if `fork_from_env` feature is enabled.
|
||||
pub const FORK_NAME_ENV_VAR: &str = "FORK_NAME";
|
||||
// Environment variable to read if `ci_logger` feature is enabled.
|
||||
pub const CI_LOGGER_DIR_ENV_VAR: &str = "CI_LOGGER_DIR";
|
||||
|
||||
// Pre-computed data column sidecar using a single static blob from:
|
||||
// `beacon_node/execution_layer/src/test_utils/fixtures/mainnet/test_blobs_bundle.ssz`
|
||||
const TEST_DATA_COLUMN_SIDECARS_SSZ: &[u8] =
|
||||
pub const TEST_DATA_COLUMN_SIDECARS_SSZ: &[u8] =
|
||||
include_bytes!("test_utils/fixtures/test_data_column_sidecars.ssz");
|
||||
|
||||
// Default target aggregators to set during testing, this ensures an aggregator at each slot.
|
||||
@@ -83,34 +90,23 @@ const TEST_DATA_COLUMN_SIDECARS_SSZ: &[u8] =
|
||||
// a different value.
|
||||
pub const DEFAULT_TARGET_AGGREGATORS: u64 = u64::MAX;
|
||||
|
||||
static KZG: LazyLock<Arc<Kzg>> = LazyLock::new(|| {
|
||||
let trusted_setup: TrustedSetup = serde_json::from_reader(get_trusted_setup().as_slice())
|
||||
.map_err(|e| format!("Unable to read trusted setup file: {}", e))
|
||||
.expect("should have trusted setup");
|
||||
let kzg = Kzg::new_from_trusted_setup(trusted_setup).expect("should create kzg");
|
||||
Arc::new(kzg)
|
||||
});
|
||||
// Minimum and maximum number of blobs to generate in each slot when using the `NumBlobs::Random` option (default).
|
||||
const DEFAULT_MIN_BLOBS: usize = 1;
|
||||
const DEFAULT_MAX_BLOBS: usize = 2;
|
||||
|
||||
static KZG_PEERDAS: LazyLock<Arc<Kzg>> = LazyLock::new(|| {
|
||||
let trusted_setup: TrustedSetup = serde_json::from_reader(get_trusted_setup().as_slice())
|
||||
.map_err(|e| format!("Unable to read trusted setup file: {}", e))
|
||||
.expect("should have trusted setup");
|
||||
let kzg = Kzg::new_from_trusted_setup_das_enabled(trusted_setup).expect("should create kzg");
|
||||
static KZG: LazyLock<Arc<Kzg>> = LazyLock::new(|| {
|
||||
let kzg = Kzg::new_from_trusted_setup(&get_trusted_setup()).expect("should create kzg");
|
||||
Arc::new(kzg)
|
||||
});
|
||||
|
||||
static KZG_NO_PRECOMP: LazyLock<Arc<Kzg>> = LazyLock::new(|| {
|
||||
let trusted_setup: TrustedSetup = serde_json::from_reader(get_trusted_setup().as_slice())
|
||||
.map_err(|e| format!("Unable to read trusted setup file: {}", e))
|
||||
.expect("should have trusted setup");
|
||||
let kzg = Kzg::new_from_trusted_setup_no_precomp(trusted_setup).expect("should create kzg");
|
||||
let kzg =
|
||||
Kzg::new_from_trusted_setup_no_precomp(&get_trusted_setup()).expect("should create kzg");
|
||||
Arc::new(kzg)
|
||||
});
|
||||
|
||||
pub fn get_kzg(spec: &ChainSpec) -> Arc<Kzg> {
|
||||
if spec.fulu_fork_epoch.is_some() {
|
||||
KZG_PEERDAS.clone()
|
||||
} else if spec.deneb_fork_epoch.is_some() {
|
||||
KZG.clone()
|
||||
} else {
|
||||
KZG_NO_PRECOMP.clone()
|
||||
@@ -118,7 +114,7 @@ pub fn get_kzg(spec: &ChainSpec) -> Arc<Kzg> {
|
||||
}
|
||||
|
||||
pub type BaseHarnessType<E, THotStore, TColdStore> =
|
||||
Witness<TestingSlotClock, CachingEth1Backend<E>, E, THotStore, TColdStore>;
|
||||
Witness<TestingSlotClock, E, THotStore, TColdStore>;
|
||||
|
||||
pub type DiskHarnessType<E> = BaseHarnessType<E, BeaconNodeBackend<E>, BeaconNodeBackend<E>>;
|
||||
pub type EphemeralHarnessType<E> = BaseHarnessType<E, MemoryStore<E>, MemoryStore<E>>;
|
||||
@@ -189,23 +185,28 @@ fn make_rng() -> Mutex<StdRng> {
|
||||
Mutex::new(StdRng::seed_from_u64(0x0DDB1A5E5BAD5EEDu64))
|
||||
}
|
||||
|
||||
/// Return a `ChainSpec` suitable for test usage.
|
||||
///
|
||||
/// If the `fork_from_env` feature is enabled, read the fork to use from the FORK_NAME environment
|
||||
/// variable. Otherwise use the default spec.
|
||||
pub fn test_spec<E: EthSpec>() -> ChainSpec {
|
||||
let mut spec = if cfg!(feature = "fork_from_env") {
|
||||
pub fn fork_name_from_env() -> Option<ForkName> {
|
||||
if cfg!(feature = "fork_from_env") {
|
||||
let fork_name = std::env::var(FORK_NAME_ENV_VAR).unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"{} env var must be defined when using fork_from_env: {:?}",
|
||||
FORK_NAME_ENV_VAR, e
|
||||
)
|
||||
});
|
||||
let fork = ForkName::from_str(fork_name.as_str()).unwrap();
|
||||
fork.make_genesis_spec(E::default_spec())
|
||||
Some(ForkName::from_str(fork_name.as_str()).unwrap())
|
||||
} else {
|
||||
E::default_spec()
|
||||
};
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a `ChainSpec` suitable for test usage.
|
||||
///
|
||||
/// If the `fork_from_env` feature is enabled, read the fork to use from the FORK_NAME environment
|
||||
/// variable. Otherwise use the default spec.
|
||||
pub fn test_spec<E: EthSpec>() -> ChainSpec {
|
||||
let mut spec = fork_name_from_env()
|
||||
.map(|fork| fork.make_genesis_spec(E::default_spec()))
|
||||
.unwrap_or_else(|| E::default_spec());
|
||||
|
||||
// Set target aggregators to a high value by default.
|
||||
spec.target_aggregators_per_committee = DEFAULT_TARGET_AGGREGATORS;
|
||||
@@ -228,7 +229,7 @@ pub struct Builder<T: BeaconChainTypes> {
|
||||
testing_slot_clock: Option<TestingSlotClock>,
|
||||
validator_monitor_config: Option<ValidatorMonitorConfig>,
|
||||
genesis_state_builder: Option<InteropGenesisBuilder<T::EthSpec>>,
|
||||
import_all_data_columns: bool,
|
||||
node_custody_type: NodeCustodyType,
|
||||
runtime: TestRuntime,
|
||||
}
|
||||
|
||||
@@ -374,7 +375,7 @@ where
|
||||
testing_slot_clock: None,
|
||||
validator_monitor_config: None,
|
||||
genesis_state_builder: None,
|
||||
import_all_data_columns: false,
|
||||
node_custody_type: NodeCustodyType::Fullnode,
|
||||
runtime,
|
||||
}
|
||||
}
|
||||
@@ -460,8 +461,8 @@ where
|
||||
self
|
||||
}
|
||||
|
||||
pub fn import_all_data_columns(mut self, import_all_data_columns: bool) -> Self {
|
||||
self.import_all_data_columns = import_all_data_columns;
|
||||
pub fn node_custody_type(mut self, node_custody_type: NodeCustodyType) -> Self {
|
||||
self.node_custody_type = node_custody_type;
|
||||
self
|
||||
}
|
||||
|
||||
@@ -518,15 +519,15 @@ where
|
||||
mock.server.execution_block_generator().osaka_time = spec.fulu_fork_epoch.map(|epoch| {
|
||||
genesis_time + spec.seconds_per_slot * E::slots_per_epoch() * epoch.as_u64()
|
||||
});
|
||||
mock.server.execution_block_generator().amsterdam_time =
|
||||
spec.gloas_fork_epoch.map(|epoch| {
|
||||
genesis_time + spec.seconds_per_slot * E::slots_per_epoch() * epoch.as_u64()
|
||||
});
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn mock_execution_layer(self) -> Self {
|
||||
self.mock_execution_layer_with_config()
|
||||
}
|
||||
|
||||
pub fn mock_execution_layer_with_config(mut self) -> Self {
|
||||
pub fn mock_execution_layer(mut self) -> Self {
|
||||
let mock = mock_execution_layer_from_parts::<E>(
|
||||
self.spec.clone().expect("cannot build without spec"),
|
||||
self.runtime.task_executor.clone(),
|
||||
@@ -585,11 +586,10 @@ where
|
||||
)
|
||||
.task_executor(self.runtime.task_executor.clone())
|
||||
.execution_layer(self.execution_layer)
|
||||
.dummy_eth1_backend()
|
||||
.expect("should build dummy backend")
|
||||
.shutdown_sender(shutdown_tx)
|
||||
.chain_config(chain_config)
|
||||
.import_all_data_columns(self.import_all_data_columns)
|
||||
.node_custody_type(self.node_custody_type)
|
||||
.ordered_custody_column_indices(generate_data_column_indices_rand_order::<E>())
|
||||
.event_handler(Some(ServerSentEventHandler::new_with_capacity(5)))
|
||||
.validator_monitor_config(validator_monitor_config)
|
||||
.rng(Box::new(StdRng::seed_from_u64(42)));
|
||||
@@ -619,12 +619,6 @@ where
|
||||
|
||||
let chain = builder.build().expect("should build");
|
||||
|
||||
let sampling_column_count = if self.import_all_data_columns {
|
||||
chain.spec.number_of_custody_groups as usize
|
||||
} else {
|
||||
chain.spec.custody_requirement as usize
|
||||
};
|
||||
|
||||
BeaconChainHarness {
|
||||
spec: chain.spec.clone(),
|
||||
chain: Arc::new(chain),
|
||||
@@ -635,7 +629,6 @@ where
|
||||
mock_execution_layer: self.mock_execution_layer,
|
||||
mock_builder: None,
|
||||
rng: make_rng(),
|
||||
sampling_column_count,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -659,6 +652,9 @@ pub fn mock_execution_layer_from_parts<E: EthSpec>(
|
||||
let osaka_time = spec.fulu_fork_epoch.map(|epoch| {
|
||||
HARNESS_GENESIS_TIME + spec.seconds_per_slot * E::slots_per_epoch() * epoch.as_u64()
|
||||
});
|
||||
let amsterdam_time = spec.gloas_fork_epoch.map(|epoch| {
|
||||
HARNESS_GENESIS_TIME + spec.seconds_per_slot * E::slots_per_epoch() * epoch.as_u64()
|
||||
});
|
||||
|
||||
let kzg = get_kzg(&spec);
|
||||
|
||||
@@ -670,6 +666,7 @@ pub fn mock_execution_layer_from_parts<E: EthSpec>(
|
||||
prague_time,
|
||||
eip7805_time,
|
||||
osaka_time,
|
||||
amsterdam_time,
|
||||
Some(JwtKey::from_slice(&DEFAULT_JWT_SECRET).unwrap()),
|
||||
spec,
|
||||
Some(kzg),
|
||||
@@ -696,7 +693,6 @@ pub struct BeaconChainHarness<T: BeaconChainTypes> {
|
||||
|
||||
pub mock_execution_layer: Option<MockExecutionLayer<T::EthSpec>>,
|
||||
pub mock_builder: Option<Arc<MockBuilder<T::EthSpec>>>,
|
||||
pub sampling_column_count: usize,
|
||||
|
||||
pub rng: Mutex<StdRng>,
|
||||
}
|
||||
@@ -738,7 +734,10 @@ where
|
||||
pub fn set_mock_builder(
|
||||
&mut self,
|
||||
beacon_url: SensitiveUrl,
|
||||
) -> impl futures::Future<Output = ()> {
|
||||
strict_registrations: bool,
|
||||
apply_operations: bool,
|
||||
broadcast_to_bn: bool,
|
||||
) -> impl futures::Future<Output = ()> + use<E, Hot, Cold> {
|
||||
let mock_el = self
|
||||
.mock_execution_layer
|
||||
.as_ref()
|
||||
@@ -750,6 +749,9 @@ where
|
||||
let (mock_builder, (addr, mock_builder_server)) = MockBuilder::new_for_testing(
|
||||
mock_el_url,
|
||||
beacon_url,
|
||||
strict_registrations,
|
||||
apply_operations,
|
||||
broadcast_to_bn,
|
||||
self.spec.clone(),
|
||||
self.runtime.task_executor.clone(),
|
||||
);
|
||||
@@ -798,10 +800,6 @@ where
|
||||
(0..self.validator_keypairs.len()).collect()
|
||||
}
|
||||
|
||||
pub fn get_sampling_column_count(&self) -> usize {
|
||||
self.sampling_column_count
|
||||
}
|
||||
|
||||
pub fn slots_per_epoch(&self) -> u64 {
|
||||
E::slots_per_epoch()
|
||||
}
|
||||
@@ -914,7 +912,9 @@ where
|
||||
let fork_choice = self.chain.canonical_head.fork_choice_read_lock();
|
||||
if heads.is_empty() {
|
||||
let nodes = &fork_choice.proto_array().core_proto_array().nodes;
|
||||
panic!("Expected to know head block root {head_block_root:?}, but heads is empty. Nodes: {nodes:#?}");
|
||||
panic!(
|
||||
"Expected to know head block root {head_block_root:?}, but heads is empty. Nodes: {nodes:#?}"
|
||||
);
|
||||
} else {
|
||||
panic!(
|
||||
"Expected to know head block root {head_block_root:?}, known heads {heads:#?}"
|
||||
@@ -928,8 +928,67 @@ where
|
||||
state: BeaconState<E>,
|
||||
slot: Slot,
|
||||
) -> (SignedBlindedBeaconBlock<E>, BeaconState<E>) {
|
||||
let (unblinded, new_state) = self.make_block(state, slot).await;
|
||||
((*unblinded.0).clone().into(), new_state)
|
||||
self.make_blinded_block_with_modifier(state, slot, |_| {})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn make_blinded_block_with_modifier(
|
||||
&self,
|
||||
mut state: BeaconState<E>,
|
||||
slot: Slot,
|
||||
block_modifier: impl FnOnce(&mut BlindedBeaconBlock<E>),
|
||||
) -> (SignedBlindedBeaconBlock<E>, BeaconState<E>) {
|
||||
assert_ne!(slot, 0, "can't produce a block at slot 0");
|
||||
assert!(slot >= state.slot());
|
||||
|
||||
complete_state_advance(&mut state, None, slot, &self.spec)
|
||||
.expect("should be able to advance state to slot");
|
||||
|
||||
state.build_caches(&self.spec).expect("should build caches");
|
||||
|
||||
let proposer_index = state.get_beacon_proposer_index(slot, &self.spec).unwrap();
|
||||
|
||||
// If we produce two blocks for the same slot, they hash up to the same value and
|
||||
// BeaconChain errors out with `DuplicateFullyImported`. Vary the graffiti so that we produce
|
||||
// different blocks each time.
|
||||
let graffiti = Graffiti::from(self.rng.lock().random::<[u8; 32]>());
|
||||
let graffiti_settings =
|
||||
GraffitiSettings::new(Some(graffiti), Some(GraffitiPolicy::PreserveUserGraffiti));
|
||||
|
||||
let randao_reveal = self.sign_randao_reveal(&state, proposer_index, slot);
|
||||
|
||||
// Always use the builder, so that we produce a "real" blinded payload.
|
||||
let builder_boost_factor = Some(u64::MAX);
|
||||
|
||||
let BeaconBlockResponseWrapper::Blinded(block_response) = self
|
||||
.chain
|
||||
.produce_block_on_state(
|
||||
state,
|
||||
None,
|
||||
slot,
|
||||
randao_reveal,
|
||||
graffiti_settings,
|
||||
ProduceBlockVerification::VerifyRandao,
|
||||
builder_boost_factor,
|
||||
BlockProductionVersion::V3,
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
else {
|
||||
panic!("Should always be a blinded payload response");
|
||||
};
|
||||
|
||||
let mut block = block_response.block;
|
||||
block_modifier(&mut block);
|
||||
|
||||
let signed_block = block.sign(
|
||||
&self.validator_keypairs[proposer_index].sk,
|
||||
&block_response.state.fork(),
|
||||
block_response.state.genesis_validators_root(),
|
||||
&self.spec,
|
||||
);
|
||||
|
||||
(signed_block, block_response.state)
|
||||
}
|
||||
|
||||
/// Returns a newly created block, signed by the proposer for the given slot.
|
||||
@@ -951,7 +1010,9 @@ where
|
||||
// If we produce two blocks for the same slot, they hash up to the same value and
|
||||
// BeaconChain errors out with `DuplicateFullyImported`. Vary the graffiti so that we produce
|
||||
// different blocks each time.
|
||||
let graffiti = Graffiti::from(self.rng.lock().gen::<[u8; 32]>());
|
||||
let graffiti = Graffiti::from(self.rng.lock().random::<[u8; 32]>());
|
||||
let graffiti_settings =
|
||||
GraffitiSettings::new(Some(graffiti), Some(GraffitiPolicy::PreserveUserGraffiti));
|
||||
|
||||
let randao_reveal = self.sign_randao_reveal(&state, proposer_index, slot);
|
||||
|
||||
@@ -962,7 +1023,7 @@ where
|
||||
None,
|
||||
slot,
|
||||
randao_reveal,
|
||||
Some(graffiti),
|
||||
graffiti_settings,
|
||||
ProduceBlockVerification::VerifyRandao,
|
||||
None,
|
||||
BlockProductionVersion::FullV2,
|
||||
@@ -1010,7 +1071,9 @@ where
|
||||
// If we produce two blocks for the same slot, they hash up to the same value and
|
||||
// BeaconChain errors out with `DuplicateFullyImported`. Vary the graffiti so that we produce
|
||||
// different blocks each time.
|
||||
let graffiti = Graffiti::from(self.rng.lock().gen::<[u8; 32]>());
|
||||
let graffiti = Graffiti::from(self.rng.lock().random::<[u8; 32]>());
|
||||
let graffiti_settings =
|
||||
GraffitiSettings::new(Some(graffiti), Some(GraffitiPolicy::PreserveUserGraffiti));
|
||||
|
||||
let randao_reveal = self.sign_randao_reveal(&state, proposer_index, slot);
|
||||
|
||||
@@ -1023,7 +1086,7 @@ where
|
||||
None,
|
||||
slot,
|
||||
randao_reveal,
|
||||
Some(graffiti),
|
||||
graffiti_settings,
|
||||
ProduceBlockVerification::VerifyRandao,
|
||||
None,
|
||||
BlockProductionVersion::FullV2,
|
||||
@@ -1137,9 +1200,14 @@ where
|
||||
attn.aggregation_bits
|
||||
.set(aggregation_bit_index, true)
|
||||
.unwrap();
|
||||
attn
|
||||
Attestation::Electra(attn)
|
||||
}
|
||||
Attestation::Base(mut attn) => {
|
||||
attn.aggregation_bits
|
||||
.set(aggregation_bit_index, true)
|
||||
.unwrap();
|
||||
Attestation::Base(attn)
|
||||
}
|
||||
Attestation::Base(_) => panic!("Must be an Electra attestation"),
|
||||
};
|
||||
|
||||
let aggregation_bits = attestation.get_aggregation_bits();
|
||||
@@ -1167,8 +1235,10 @@ where
|
||||
let single_attestation =
|
||||
attestation.to_single_attestation_with_attester_index(attester_index as u64)?;
|
||||
|
||||
let fork_name = self.spec.fork_name_at_slot::<E>(attestation.data().slot);
|
||||
let attestation: Attestation<E> =
|
||||
single_attestation_to_attestation(&single_attestation, committee.committee).unwrap();
|
||||
single_attestation_to_attestation(&single_attestation, committee.committee, fork_name)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
single_attestation.committee_index,
|
||||
@@ -2344,7 +2414,7 @@ where
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Building a VarList from leaves
|
||||
let deposit_data_list = VariableList::<_, U4294967296>::from(leaves.clone());
|
||||
let deposit_data_list = VariableList::<_, U4294967296>::try_from(leaves.clone()).unwrap();
|
||||
|
||||
// Setting the deposit_root to be the tree_hash_root of the VarList
|
||||
state.eth1_data_mut().deposit_root = deposit_data_list.tree_hash_root();
|
||||
@@ -2368,7 +2438,7 @@ where
|
||||
let deposits = datas
|
||||
.into_par_iter()
|
||||
.zip(proofs.into_par_iter())
|
||||
.map(|(data, proof)| (data, proof.into()))
|
||||
.map(|(data, proof)| (data, proof.try_into().unwrap()))
|
||||
.map(|(data, proof)| Deposit { proof, data })
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@@ -2440,7 +2510,7 @@ where
|
||||
.blob_kzg_commitments()
|
||||
.is_ok_and(|c| !c.is_empty());
|
||||
if !has_blobs {
|
||||
return RpcBlock::new_without_blobs(Some(block_root), block, 0);
|
||||
return RpcBlock::new_without_blobs(Some(block_root), block);
|
||||
}
|
||||
|
||||
// Blobs are stored as data columns from Fulu (PeerDAS)
|
||||
@@ -2450,14 +2520,7 @@ where
|
||||
.into_iter()
|
||||
.map(CustodyDataColumn::from_asserted_custody)
|
||||
.collect::<Vec<_>>();
|
||||
RpcBlock::new_with_custody_columns(
|
||||
Some(block_root),
|
||||
block,
|
||||
custody_columns,
|
||||
self.get_sampling_column_count(),
|
||||
&self.spec,
|
||||
)
|
||||
.unwrap()
|
||||
RpcBlock::new_with_custody_columns(Some(block_root), block, custody_columns).unwrap()
|
||||
} else {
|
||||
let blobs = self.chain.get_blobs(&block_root).unwrap().blobs();
|
||||
RpcBlock::new(Some(block_root), block, blobs).unwrap()
|
||||
@@ -2465,14 +2528,15 @@ where
|
||||
}
|
||||
|
||||
/// Builds an `RpcBlock` from a `SignedBeaconBlock` and `BlobsList`.
|
||||
fn build_rpc_block_from_blobs(
|
||||
pub fn build_rpc_block_from_blobs(
|
||||
&self,
|
||||
block_root: Hash256,
|
||||
block: Arc<SignedBeaconBlock<E, FullPayload<E>>>,
|
||||
blob_items: Option<(KzgProofs<E>, BlobsList<E>)>,
|
||||
) -> Result<RpcBlock<E>, BlockError> {
|
||||
Ok(if self.spec.is_peer_das_enabled_for_epoch(block.epoch()) {
|
||||
let sampling_column_count = self.get_sampling_column_count();
|
||||
let epoch = block.slot().epoch(E::slots_per_epoch());
|
||||
let sampling_columns = self.chain.sampling_columns_for_epoch(epoch);
|
||||
|
||||
if blob_items.is_some_and(|(_, blobs)| !blobs.is_empty()) {
|
||||
// Note: this method ignores the actual custody columns and just take the first
|
||||
@@ -2480,18 +2544,12 @@ where
|
||||
// currently have any knowledge of the columns being custodied.
|
||||
let columns = generate_data_column_sidecars_from_block(&block, &self.spec)
|
||||
.into_iter()
|
||||
.take(sampling_column_count)
|
||||
.filter(|d| sampling_columns.contains(&d.index))
|
||||
.map(CustodyDataColumn::from_asserted_custody)
|
||||
.collect::<Vec<_>>();
|
||||
RpcBlock::new_with_custody_columns(
|
||||
Some(block_root),
|
||||
block,
|
||||
columns,
|
||||
sampling_column_count,
|
||||
&self.spec,
|
||||
)?
|
||||
RpcBlock::new_with_custody_columns(Some(block_root), block, columns)?
|
||||
} else {
|
||||
RpcBlock::new_without_blobs(Some(block_root), block, 0)
|
||||
RpcBlock::new_without_blobs(Some(block_root), block)
|
||||
}
|
||||
} else {
|
||||
let blobs = blob_items
|
||||
@@ -2504,7 +2562,11 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
pub fn process_attestations(&self, attestations: HarnessAttestations<E>) {
|
||||
pub fn process_attestations(
|
||||
&self,
|
||||
attestations: HarnessAttestations<E>,
|
||||
state: &BeaconState<E>,
|
||||
) {
|
||||
let num_validators = self.validator_keypairs.len();
|
||||
let mut unaggregated = Vec::with_capacity(num_validators);
|
||||
// This is an over-allocation, but it should be fine. It won't be *that* memory hungry and
|
||||
@@ -2513,7 +2575,35 @@ where
|
||||
|
||||
for (unaggregated_attestations, maybe_signed_aggregate) in attestations.iter() {
|
||||
for (attn, subnet) in unaggregated_attestations {
|
||||
unaggregated.push((attn, Some(*subnet)));
|
||||
let aggregation_bits = attn.get_aggregation_bits();
|
||||
|
||||
if aggregation_bits.len() != 1 {
|
||||
panic!("Must be an unaggregated attestation")
|
||||
}
|
||||
|
||||
let aggregation_bit = *aggregation_bits.first().unwrap();
|
||||
|
||||
let committee = state
|
||||
.get_beacon_committee(attn.data().slot, attn.committee_index().unwrap())
|
||||
.unwrap();
|
||||
|
||||
let attester_index = committee
|
||||
.committee
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find_map(|(i, &index)| {
|
||||
if aggregation_bit as usize == i {
|
||||
return Some(index);
|
||||
}
|
||||
None
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let single_attestation = attn
|
||||
.to_single_attestation_with_attester_index(attester_index as u64)
|
||||
.unwrap();
|
||||
|
||||
unaggregated.push((single_attestation, Some(*subnet)));
|
||||
}
|
||||
|
||||
if let Some(a) = maybe_signed_aggregate {
|
||||
@@ -2523,7 +2613,9 @@ where
|
||||
|
||||
for result in self
|
||||
.chain
|
||||
.batch_verify_unaggregated_attestations_for_gossip(unaggregated.into_iter())
|
||||
.batch_verify_unaggregated_attestations_for_gossip(
|
||||
unaggregated.iter().map(|(attn, subnet)| (attn, *subnet)),
|
||||
)
|
||||
.unwrap()
|
||||
{
|
||||
let verified = result.unwrap();
|
||||
@@ -2590,7 +2682,7 @@ where
|
||||
) {
|
||||
let attestations =
|
||||
self.make_attestations(validators, state, state_root, block_hash, block.slot());
|
||||
self.process_attestations(attestations);
|
||||
self.process_attestations(attestations, state);
|
||||
}
|
||||
|
||||
pub fn sync_committee_sign_block(
|
||||
@@ -2745,10 +2837,7 @@ where
|
||||
mut latest_block_hash: Option<SignedBeaconBlockHash>,
|
||||
sync_committee_strategy: SyncCommitteeStrategy,
|
||||
) -> AddBlocksResult<E> {
|
||||
assert!(
|
||||
slots.windows(2).all(|w| w[0] <= w[1]),
|
||||
"Slots have to be sorted"
|
||||
); // slice.is_sorted() isn't stabilized at the moment of writing this
|
||||
assert!(slots.is_sorted(), "Slots have to be in ascending order");
|
||||
let mut block_hash_from_slot: HashMap<Slot, SignedBeaconBlockHash> = HashMap::new();
|
||||
let mut state_hash_from_slot: HashMap<Slot, BeaconStateHash> = HashMap::new();
|
||||
for slot in slots {
|
||||
@@ -2788,10 +2877,7 @@ where
|
||||
mut latest_block_hash: Option<SignedBeaconBlockHash>,
|
||||
sync_committee_strategy: SyncCommitteeStrategy,
|
||||
) -> AddBlocksResult<E> {
|
||||
assert!(
|
||||
slots.windows(2).all(|w| w[0] <= w[1]),
|
||||
"Slots have to be sorted"
|
||||
); // slice.is_sorted() isn't stabilized at the moment of writing this
|
||||
assert!(slots.is_sorted(), "Slots have to be in ascending order");
|
||||
let mut block_hash_from_slot: HashMap<Slot, SignedBeaconBlockHash> = HashMap::new();
|
||||
let mut state_hash_from_slot: HashMap<Slot, BeaconStateHash> = HashMap::new();
|
||||
for slot in slots {
|
||||
@@ -2918,7 +3004,6 @@ where
|
||||
let chain_dump = self.chain.chain_dump().unwrap();
|
||||
chain_dump
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|checkpoint| checkpoint.beacon_state.finalized_checkpoint().root)
|
||||
.filter(|block_hash| *block_hash != Hash256::zero())
|
||||
.map(|hash| hash.into())
|
||||
@@ -3190,17 +3275,22 @@ where
|
||||
let is_peerdas_enabled = self.chain.spec.is_peer_das_enabled_for_epoch(block.epoch());
|
||||
if is_peerdas_enabled {
|
||||
let custody_columns = custody_columns_opt.unwrap_or_else(|| {
|
||||
let sampling_column_count = self.get_sampling_column_count() as u64;
|
||||
(0..sampling_column_count).collect()
|
||||
let epoch = block.slot().epoch(E::slots_per_epoch());
|
||||
self.chain
|
||||
.sampling_columns_for_epoch(epoch)
|
||||
.iter()
|
||||
.copied()
|
||||
.collect()
|
||||
});
|
||||
|
||||
let verified_columns = generate_data_column_sidecars_from_block(block, &self.spec)
|
||||
.into_iter()
|
||||
.filter(|c| custody_columns.contains(&c.index))
|
||||
.map(|sidecar| {
|
||||
let column_index = sidecar.index;
|
||||
let subnet_id =
|
||||
DataColumnSubnetId::from_column_index(sidecar.index, &self.spec);
|
||||
self.chain
|
||||
.verify_data_column_sidecar_for_gossip(sidecar, column_index)
|
||||
.verify_data_column_sidecar_for_gossip(sidecar, subnet_id)
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.unwrap();
|
||||
@@ -3246,96 +3336,50 @@ pub enum NumBlobs {
|
||||
None,
|
||||
}
|
||||
|
||||
macro_rules! add_blob_transactions {
|
||||
($message:expr, $payload_type:ty, $num_blobs:expr, $rng:expr, $fork_name:expr) => {{
|
||||
let num_blobs = match $num_blobs {
|
||||
NumBlobs::Random => $rng.random_range(DEFAULT_MIN_BLOBS..=DEFAULT_MAX_BLOBS),
|
||||
NumBlobs::Number(n) => n,
|
||||
NumBlobs::None => 0,
|
||||
};
|
||||
let (bundle, transactions) =
|
||||
execution_layer::test_utils::generate_blobs::<E>(num_blobs, $fork_name).unwrap();
|
||||
|
||||
let payload: &mut $payload_type = &mut $message.body.execution_payload;
|
||||
payload.execution_payload.transactions = <_>::default();
|
||||
for tx in Vec::from(transactions) {
|
||||
payload.execution_payload.transactions.push(tx).unwrap();
|
||||
}
|
||||
$message.body.blob_kzg_commitments = bundle.commitments.clone();
|
||||
bundle
|
||||
}};
|
||||
}
|
||||
|
||||
pub fn generate_rand_block_and_blobs<E: EthSpec>(
|
||||
fork_name: ForkName,
|
||||
num_blobs: NumBlobs,
|
||||
rng: &mut impl Rng,
|
||||
spec: &ChainSpec,
|
||||
) -> (SignedBeaconBlock<E, FullPayload<E>>, Vec<BlobSidecar<E>>) {
|
||||
let inner = map_fork_name!(fork_name, BeaconBlock, <_>::random_for_test(rng));
|
||||
|
||||
let mut block = SignedBeaconBlock::from_block(inner, types::Signature::random_for_test(rng));
|
||||
let max_blobs = spec.max_blobs_per_block(block.epoch()) as usize;
|
||||
let mut block = SignedBeaconBlock::from_block(inner, Signature::random_for_test(rng));
|
||||
let mut blob_sidecars = vec![];
|
||||
|
||||
let bundle = match block {
|
||||
SignedBeaconBlock::Deneb(SignedBeaconBlockDeneb {
|
||||
ref mut message, ..
|
||||
}) => {
|
||||
// Get either zero blobs or a random number of blobs between 1 and Max Blobs.
|
||||
let payload: &mut FullPayloadDeneb<E> = &mut message.body.execution_payload;
|
||||
let num_blobs = match num_blobs {
|
||||
NumBlobs::Random => rng.gen_range(1..=max_blobs),
|
||||
NumBlobs::Number(n) => n,
|
||||
NumBlobs::None => 0,
|
||||
};
|
||||
let (bundle, transactions) =
|
||||
execution_layer::test_utils::generate_blobs::<E>(num_blobs, fork_name).unwrap();
|
||||
|
||||
payload.execution_payload.transactions = <_>::default();
|
||||
for tx in Vec::from(transactions) {
|
||||
payload.execution_payload.transactions.push(tx).unwrap();
|
||||
}
|
||||
message.body.blob_kzg_commitments = bundle.commitments.clone();
|
||||
bundle
|
||||
}
|
||||
}) => add_blob_transactions!(message, FullPayloadDeneb<E>, num_blobs, rng, fork_name),
|
||||
SignedBeaconBlock::Electra(SignedBeaconBlockElectra {
|
||||
ref mut message, ..
|
||||
}) => {
|
||||
// Get either zero blobs or a random number of blobs between 1 and Max Blobs.
|
||||
let payload: &mut FullPayloadElectra<E> = &mut message.body.execution_payload;
|
||||
let num_blobs = match num_blobs {
|
||||
NumBlobs::Random => rng.gen_range(1..=max_blobs),
|
||||
NumBlobs::Number(n) => n,
|
||||
NumBlobs::None => 0,
|
||||
};
|
||||
let (bundle, transactions) =
|
||||
execution_layer::test_utils::generate_blobs::<E>(num_blobs, fork_name).unwrap();
|
||||
payload.execution_payload.transactions = <_>::default();
|
||||
for tx in Vec::from(transactions) {
|
||||
payload.execution_payload.transactions.push(tx).unwrap();
|
||||
}
|
||||
message.body.blob_kzg_commitments = bundle.commitments.clone();
|
||||
bundle
|
||||
}
|
||||
SignedBeaconBlock::Eip7805(SignedBeaconBlockEip7805 {
|
||||
ref mut message, ..
|
||||
}) => {
|
||||
// Get either zero blobs or a random number of blobs between 1 and Max Blobs.
|
||||
let payload: &mut FullPayloadEip7805<E> = &mut message.body.execution_payload;
|
||||
let num_blobs = match num_blobs {
|
||||
NumBlobs::Random => rng.gen_range(1..=max_blobs),
|
||||
NumBlobs::Number(n) => n,
|
||||
NumBlobs::None => 0,
|
||||
};
|
||||
let (bundle, transactions) =
|
||||
execution_layer::test_utils::generate_blobs::<E>(num_blobs, fork_name).unwrap();
|
||||
payload.execution_payload.transactions = <_>::default();
|
||||
for tx in Vec::from(transactions) {
|
||||
payload.execution_payload.transactions.push(tx).unwrap();
|
||||
}
|
||||
message.body.blob_kzg_commitments = bundle.commitments.clone();
|
||||
bundle
|
||||
}
|
||||
}) => add_blob_transactions!(message, FullPayloadElectra<E>, num_blobs, rng, fork_name),
|
||||
SignedBeaconBlock::Fulu(SignedBeaconBlockFulu {
|
||||
ref mut message, ..
|
||||
}) => {
|
||||
// Get either zero blobs or a random number of blobs between 1 and Max Blobs.
|
||||
let payload: &mut FullPayloadFulu<E> = &mut message.body.execution_payload;
|
||||
let num_blobs = match num_blobs {
|
||||
NumBlobs::Random => rng.gen_range(1..=max_blobs),
|
||||
NumBlobs::Number(n) => n,
|
||||
NumBlobs::None => 0,
|
||||
};
|
||||
let (bundle, transactions) =
|
||||
execution_layer::test_utils::generate_blobs::<E>(num_blobs, fork_name).unwrap();
|
||||
payload.execution_payload.transactions = <_>::default();
|
||||
for tx in Vec::from(transactions) {
|
||||
payload.execution_payload.transactions.push(tx).unwrap();
|
||||
}
|
||||
message.body.blob_kzg_commitments = bundle.commitments.clone();
|
||||
bundle
|
||||
}
|
||||
}) => add_blob_transactions!(message, FullPayloadFulu<E>, num_blobs, rng, fork_name),
|
||||
SignedBeaconBlock::Eip7805(SignedBeaconBlockEip7805 {
|
||||
ref mut message, ..
|
||||
}) => add_blob_transactions!(message, FullPayloadEip7805<E>, num_blobs, rng, fork_name),
|
||||
// TODO(EIP-7732) Add `SignedBeaconBlock::Gloas` variant
|
||||
_ => return (block, blob_sidecars),
|
||||
};
|
||||
|
||||
@@ -3376,13 +3420,13 @@ pub fn generate_rand_block_and_data_columns<E: EthSpec>(
|
||||
SignedBeaconBlock<E, FullPayload<E>>,
|
||||
DataColumnSidecarList<E>,
|
||||
) {
|
||||
let (block, _blobs) = generate_rand_block_and_blobs(fork_name, num_blobs, rng, spec);
|
||||
let (block, _blobs) = generate_rand_block_and_blobs(fork_name, num_blobs, rng);
|
||||
let data_columns = generate_data_column_sidecars_from_block(&block, spec);
|
||||
(block, data_columns)
|
||||
}
|
||||
|
||||
/// Generate data column sidecars from pre-computed cells and proofs.
|
||||
fn generate_data_column_sidecars_from_block<E: EthSpec>(
|
||||
pub fn generate_data_column_sidecars_from_block<E: EthSpec>(
|
||||
block: &SignedBeaconBlock<E>,
|
||||
spec: &ChainSpec,
|
||||
) -> DataColumnSidecarList<E> {
|
||||
@@ -3401,7 +3445,7 @@ fn generate_data_column_sidecars_from_block<E: EthSpec>(
|
||||
// load the precomputed column sidecar to avoid computing them for every block in the tests.
|
||||
let template_data_columns = RuntimeVariableList::<DataColumnSidecar<E>>::from_ssz_bytes(
|
||||
TEST_DATA_COLUMN_SIDECARS_SSZ,
|
||||
spec.number_of_columns as usize,
|
||||
E::number_of_columns(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -3432,3 +3476,9 @@ fn generate_data_column_sidecars_from_block<E: EthSpec>(
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn generate_data_column_indices_rand_order<E: EthSpec>() -> Vec<CustodyIndex> {
|
||||
let mut indices = (0..E::number_of_columns() as u64).collect::<Vec<_>>();
|
||||
indices.shuffle(&mut StdRng::seed_from_u64(42));
|
||||
indices
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user