diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 3b3814f6c..5d88c5ca4 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -100,6 +100,7 @@ use types::*; pub use crate::canonical_head::{CanonicalHead, CanonicalHeadRwLock}; pub use fork_choice::CountUnrealized; use types::kzg_commitment::KzgCommitment; +use types::signed_blobs_sidecar::SignedBlobsSidecar; pub type ForkChoiceError = fork_choice::Error; @@ -374,6 +375,8 @@ pub struct BeaconChain { /// Sender given to tasks, so that if they encounter a state in which execution cannot /// continue they can request that everything shuts down. pub shutdown_sender: Sender, + pub block_waiting_for_sidecar: Mutex>>, + pub sidecar_waiting_for_block: Mutex>>, /// Logging to CLI, etc. pub(crate) log: Logger, /// Arbitrary bytes included in the blocks. @@ -2342,7 +2345,7 @@ impl BeaconChain { // Import the blocks into the chain. for signature_verified_block in signature_verified_blocks { match self - .process_block(signature_verified_block, count_unrealized) + .process_block(signature_verified_block, None, count_unrealized) .await { Ok(_) => imported_blocks += 1, @@ -2428,6 +2431,7 @@ impl BeaconChain { pub async fn process_block>( self: &Arc, unverified_block: B, + sidecar: Option>, count_unrealized: CountUnrealized, ) -> Result> { // Start the Prometheus timer. @@ -2444,7 +2448,7 @@ impl BeaconChain { let import_block = async move { let execution_pending = unverified_block.into_execution_pending_block(&chain)?; chain - .import_execution_pending_block(execution_pending, count_unrealized) + .import_execution_pending_block(execution_pending, sidecar, count_unrealized) .await }; @@ -2502,6 +2506,7 @@ impl BeaconChain { async fn import_execution_pending_block( self: Arc, execution_pending_block: ExecutionPendingBlock, + sidecar: Option>, count_unrealized: CountUnrealized, ) -> Result> { let ExecutionPendingBlock { @@ -2557,6 +2562,7 @@ impl BeaconChain { move || { chain.import_block( block, + sidecar, block_root, state, confirmed_state_roots, @@ -2579,6 +2585,7 @@ impl BeaconChain { fn import_block( &self, signed_block: Arc>, + sidecar: Option>, block_root: Hash256, mut state: BeaconState, confirmed_state_roots: Vec, @@ -2917,6 +2924,9 @@ impl BeaconChain { .collect(); ops.push(StoreOp::PutBlock(block_root, signed_block.clone())); ops.push(StoreOp::PutState(block.state_root(), &state)); + if let Some(sidecar) = sidecar { + ops.push(StoreOp::PutBlobs(block_root, sidecar)); + } let txn_lock = self.store.hot_db.begin_rw_transaction(); if let Err(e) = self.store.do_atomically(ops) { diff --git a/beacon_node/beacon_chain/src/block_verification.rs b/beacon_node/beacon_chain/src/block_verification.rs index cdcbf3f68..8eae5f256 100644 --- a/beacon_node/beacon_chain/src/block_verification.rs +++ b/beacon_node/beacon_chain/src/block_verification.rs @@ -144,6 +144,7 @@ pub enum BlockError { present_slot: Slot, block_slot: Slot, }, + MissingSidecar, /// The block state_root does not match the generated state. /// /// ## Peer scoring @@ -277,6 +278,7 @@ pub enum BlockError { /// The peer sent us an invalid block, but I'm not really sure how to score this in an /// "optimistic" sync world. ParentExecutionPayloadInvalid { parent_root: Hash256 }, + } /// Returned when block validation failed due to some issue verifying diff --git a/beacon_node/beacon_chain/src/builder.rs b/beacon_node/beacon_chain/src/builder.rs index 270469044..8bed973e5 100644 --- a/beacon_node/beacon_chain/src/builder.rs +++ b/beacon_node/beacon_chain/src/builder.rs @@ -797,6 +797,8 @@ where validator_pubkey_cache: TimeoutRwLock::new(validator_pubkey_cache), attester_cache: <_>::default(), early_attester_cache: <_>::default(), + block_waiting_for_sidecar: <_>::default(), + sidecar_waiting_for_block: <_>::default(), shutdown_sender: self .shutdown_sender .ok_or("Cannot build without a shutdown sender.")?, diff --git a/beacon_node/beacon_chain/src/test_utils.rs b/beacon_node/beacon_chain/src/test_utils.rs index a62608202..128a33760 100644 --- a/beacon_node/beacon_chain/src/test_utils.rs +++ b/beacon_node/beacon_chain/src/test_utils.rs @@ -1458,7 +1458,7 @@ where self.set_current_slot(slot); let block_hash: SignedBeaconBlockHash = self .chain - .process_block(Arc::new(block), CountUnrealized::True) + .process_block(Arc::new(block), todo!(), CountUnrealized::True) .await? .into(); self.chain.recompute_head_at_current_slot().await; @@ -1471,7 +1471,7 @@ where ) -> Result> { let block_hash: SignedBeaconBlockHash = self .chain - .process_block(Arc::new(block), CountUnrealized::True) + .process_block(Arc::new(block), todo!(),CountUnrealized::True) .await? .into(); self.chain.recompute_head_at_current_slot().await; diff --git a/beacon_node/http_api/src/publish_blocks.rs b/beacon_node/http_api/src/publish_blocks.rs index 60ca8f232..511205814 100644 --- a/beacon_node/http_api/src/publish_blocks.rs +++ b/beacon_node/http_api/src/publish_blocks.rs @@ -32,7 +32,7 @@ pub async fn publish_block( metrics::observe_duration(&metrics::HTTP_API_BLOCK_BROADCAST_DELAY_TIMES, delay); match chain - .process_block(block.clone(), CountUnrealized::True) + .process_block(block.clone(), None, CountUnrealized::True) .await { Ok(root) => { diff --git a/beacon_node/network/src/beacon_processor/worker/gossip_methods.rs b/beacon_node/network/src/beacon_processor/worker/gossip_methods.rs index 0e1ab697e..63b252099 100644 --- a/beacon_node/network/src/beacon_processor/worker/gossip_methods.rs +++ b/beacon_node/network/src/beacon_processor/worker/gossip_methods.rs @@ -673,6 +673,7 @@ impl Worker { .await { let block_root = gossip_verified_block.block_root; + if let Some(handle) = duplicate_cache.check_and_insert(block_root) { self.process_gossip_verified_block( peer_id, @@ -759,6 +760,9 @@ impl Worker { verified_block } + Err(BlockError::MissingSidecar) => { + todo!(); //is relevant? + } Err(BlockError::ParentUnknown(block)) => { debug!( self.log, @@ -920,9 +924,24 @@ impl Worker { ) { let block: Arc<_> = verified_block.block.clone(); + let sidecar = if verified_block.block.message() + .body().blob_kzg_commitments().map(|committments| committments.is_empty()).unwrap_or(true) { + None + } else if let Some(sidecar) = self.chain.sidecar_waiting_for_block.lock().as_ref() { + if sidecar.message.beacon_block_root == verified_block.block_root() { + Some(sidecar.clone()) + } else { + *self.chain.block_waiting_for_sidecar.lock() = Some(verified_block); + return + } + } else { + // we need the sidecar but dont have it yet + return + }; + match self .chain - .process_block(verified_block, CountUnrealized::True) + .process_block(verified_block, sidecar, CountUnrealized::True) .await { Ok(block_root) => { diff --git a/beacon_node/network/src/beacon_processor/worker/sync_methods.rs b/beacon_node/network/src/beacon_processor/worker/sync_methods.rs index 760896e0e..b2d46f411 100644 --- a/beacon_node/network/src/beacon_processor/worker/sync_methods.rs +++ b/beacon_node/network/src/beacon_processor/worker/sync_methods.rs @@ -80,7 +80,7 @@ impl Worker { } }; let slot = block.slot(); - let result = self.chain.process_block(block, CountUnrealized::True).await; + let result = self.chain.process_block(block, None, CountUnrealized::True).await; metrics::inc_counter(&metrics::BEACON_PROCESSOR_RPC_BLOCK_IMPORTED_TOTAL); diff --git a/beacon_node/store/src/hot_cold_store.rs b/beacon_node/store/src/hot_cold_store.rs index 8240007b6..3c07b4073 100644 --- a/beacon_node/store/src/hot_cold_store.rs +++ b/beacon_node/store/src/hot_cold_store.rs @@ -483,6 +483,19 @@ impl, Cold: ItemStore> HotColdDB } } + pub fn blobs_as_kv_store_ops( + &self, + key: &Hash256, + blobs: &SignedBlobsSidecar, + ops: &mut Vec, + ) { + let db_key = get_key_for_col(DBColumn::BeaconBlob.into(), key.as_bytes()); + ops.push(KeyValueStoreOp::PutKeyValue( + db_key, + blobs.as_ssz_bytes(), + )); + } + pub fn put_state_summary( &self, state_root: &Hash256, @@ -710,6 +723,14 @@ impl, Cold: ItemStore> HotColdDB self.store_hot_state(&state_root, state, &mut key_value_batch)?; } + StoreOp::PutBlobs(block_root, blobs) => { + self.blobs_as_kv_store_ops( + &block_root, + &blobs, + &mut key_value_batch, + ); + } + StoreOp::PutStateSummary(state_root, summary) => { key_value_batch.push(summary.as_kv_store_op(state_root)); } @@ -754,6 +775,7 @@ impl, Cold: ItemStore> HotColdDB // Update the block cache whilst holding a lock, to ensure that the cache updates atomically // with the database. let mut guard = self.block_cache.lock(); + let mut guard_blob = self.blob_cache.lock(); for op in &batch { match op { @@ -761,6 +783,10 @@ impl, Cold: ItemStore> HotColdDB guard.put(*block_root, (**block).clone()); } + StoreOp::PutBlobs(block_root, blobs) => { + guard_blob.put(*block_root, blobs.clone()); + } + StoreOp::PutState(_, _) => (), StoreOp::PutStateSummary(_, _) => (), diff --git a/beacon_node/store/src/lib.rs b/beacon_node/store/src/lib.rs index f7af172f5..5e74827c9 100644 --- a/beacon_node/store/src/lib.rs +++ b/beacon_node/store/src/lib.rs @@ -42,6 +42,7 @@ use parking_lot::MutexGuard; use std::sync::Arc; use strum::{EnumString, IntoStaticStr}; pub use types::*; +use types::signed_blobs_sidecar::SignedBlobsSidecar; pub type ColumnIter<'a> = Box), Error>> + 'a>; pub type ColumnKeyIter<'a> = Box> + 'a>; @@ -155,6 +156,7 @@ pub trait ItemStore: KeyValueStore + Sync + Send + Sized + 'stati pub enum StoreOp<'a, E: EthSpec> { PutBlock(Hash256, Arc>), PutState(Hash256, &'a BeaconState), + PutBlobs(Hash256, SignedBlobsSidecar), PutStateSummary(Hash256, HotStateSummary), PutStateTemporaryFlag(Hash256), DeleteStateTemporaryFlag(Hash256), diff --git a/common/eth2_config/src/lib.rs b/common/eth2_config/src/lib.rs index 7e3c025a8..d18808825 100644 --- a/common/eth2_config/src/lib.rs +++ b/common/eth2_config/src/lib.rs @@ -307,5 +307,10 @@ define_hardcoded_nets!( // Set to `true` if the genesis state can be found in the `built_in_network_configs` // directory. GENESIS_STATE_IS_KNOWN + ), + ( + eip4844, + "eip4844", + GENESIS_STATE_IS_KNOWN ) ); diff --git a/common/eth2_network_config/built_in_network_configs/eip4844/boot_enr.yaml b/common/eth2_network_config/built_in_network_configs/eip4844/boot_enr.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/common/eth2_network_config/built_in_network_configs/eip4844/config.yaml b/common/eth2_network_config/built_in_network_configs/eip4844/config.yaml new file mode 100644 index 000000000..8e779eac3 --- /dev/null +++ b/common/eth2_network_config/built_in_network_configs/eip4844/config.yaml @@ -0,0 +1,85 @@ +# Prater config + +# Extends the mainnet preset +CONFIG_NAME: 'eip4844' +PRESET_BASE: 'mainnet' + +# Transition +# --------------------------------------------------------------- +TERMINAL_TOTAL_DIFFICULTY: 40 +# By default, don't use these params +TERMINAL_BLOCK_HASH: 0x0000000000000000000000000000000000000000000000000000000000000000 +TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH: 18446744073709551615 + +# Genesis +# --------------------------------------------------------------- +# `2**14` (= 16,384) +MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 2 +# Mar-01-2021 08:53:32 AM +UTC +MIN_GENESIS_TIME: 1653318000 +# Prater area code (Vienna) +GENESIS_FORK_VERSION: 0x00000ffd +# Customized for Prater: 1919188 seconds (Mar-23-2021 02:00:00 PM +UTC) +GENESIS_DELAY: 0 + + +# Forking +# --------------------------------------------------------------- +# Some forks are disabled for now: +# - These may be re-assigned to another fork-version later +# - Temporarily set to max uint64 value: 2**64 - 1 + +# Altair +ALTAIR_FORK_VERSION: 0x01000ffd +ALTAIR_FORK_EPOCH: 1 +# Merge +BELLATRIX_FORK_VERSION: 0x02000ffd +BELLATRIX_FORK_EPOCH: 2 +# Sharding +EIP4844_FORK_VERSION: 0x03000ffd +EIP4844_FORK_EPOCH: 3 + +# TBD, 2**32 is a placeholder. Merge transition approach is in active R&D. +TRANSITION_TOTAL_DIFFICULTY: 40 + + +# Time parameters +# --------------------------------------------------------------- +# 12 seconds +SECONDS_PER_SLOT: 12 +# 14 (estimate from Eth1 mainnet) +SECONDS_PER_ETH1_BLOCK: 14 +# 2**8 (= 256) epochs ~27 hours +MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 256 +# 2**8 (= 256) epochs ~27 hours +SHARD_COMMITTEE_PERIOD: 256 +# 2**11 (= 2,048) Eth1 blocks ~8 hours +ETH1_FOLLOW_DISTANCE: 15 + + +# Validator cycle +# --------------------------------------------------------------- +# 2**2 (= 4) +INACTIVITY_SCORE_BIAS: 4 +# 2**4 (= 16) +INACTIVITY_SCORE_RECOVERY_RATE: 16 +# 2**4 * 10**9 (= 16,000,000,000) Gwei +EJECTION_BALANCE: 16000000000 +# 2**2 (= 4) +MIN_PER_EPOCH_CHURN_LIMIT: 4 +# 2**16 (= 65,536) +CHURN_LIMIT_QUOTIENT: 65536 + + +# Fork choice +# --------------------------------------------------------------- +# 40% +PROPOSER_SCORE_BOOST: 40 + +# Deposit contract +# --------------------------------------------------------------- +# Ethereum Goerli testnet +DEPOSIT_CHAIN_ID: 1331 +DEPOSIT_NETWORK_ID: 69 +# Prater test deposit contract on Goerli Testnet +DEPOSIT_CONTRACT_ADDRESS: 0x8A04d14125D0FDCDc742F4A05C051De07232EDa4 diff --git a/common/eth2_network_config/built_in_network_configs/eip4844/deploy_block.txt b/common/eth2_network_config/built_in_network_configs/eip4844/deploy_block.txt new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/common/eth2_network_config/built_in_network_configs/eip4844/deploy_block.txt @@ -0,0 +1 @@ +0 diff --git a/common/eth2_network_config/built_in_network_configs/eip4844/genesis.ssz.zip b/common/eth2_network_config/built_in_network_configs/eip4844/genesis.ssz.zip new file mode 100644 index 000000000..9a1c014f6 Binary files /dev/null and b/common/eth2_network_config/built_in_network_configs/eip4844/genesis.ssz.zip differ