mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-18 13:28:33 +00:00
Initial merge changes
Added Execution Payload from Rayonism Fork Updated new Containers to match Merge Spec Updated BeaconBlockBody for Merge Spec Completed updating BeaconState and BeaconBlockBody Modified ExecutionPayload<T> to use Transaction<T> Mostly Finished Changes for beacon-chain.md Added some things for fork-choice.md Update to match new fork-choice.md/fork.md changes ran cargo fmt Added Missing Pieces in eth2_libp2p for Merge fix ef test Various Changes to Conform Closer to Merge Spec
This commit is contained in:
@@ -2838,6 +2838,11 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
SyncAggregate::new()
|
||||
}))
|
||||
};
|
||||
// Closure to fetch a sync aggregate in cases where it is required.
|
||||
let get_execution_payload = || -> Result<ExecutionPayload<_>, BlockProductionError> {
|
||||
// TODO: actually get the payload from eth1 node..
|
||||
Ok(ExecutionPayload::default())
|
||||
};
|
||||
|
||||
let inner_block = match state {
|
||||
BeaconState::Base(_) => BeaconBlock::Base(BeaconBlockBase {
|
||||
@@ -2876,6 +2881,28 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
},
|
||||
})
|
||||
}
|
||||
BeaconState::Merge(_) => {
|
||||
let sync_aggregate = get_sync_aggregate()?;
|
||||
let execution_payload = get_execution_payload()?;
|
||||
BeaconBlock::Merge(BeaconBlockMerge {
|
||||
slot,
|
||||
proposer_index,
|
||||
parent_root,
|
||||
state_root: Hash256::zero(),
|
||||
body: BeaconBlockBodyMerge {
|
||||
randao_reveal,
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings: proposer_slashings.into(),
|
||||
attester_slashings: attester_slashings.into(),
|
||||
attestations,
|
||||
deposits,
|
||||
voluntary_exits: voluntary_exits.into(),
|
||||
sync_aggregate,
|
||||
execution_payload,
|
||||
},
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let block = SignedBeaconBlock::from_block(
|
||||
|
||||
@@ -48,7 +48,7 @@ use crate::{
|
||||
BLOCK_PROCESSING_CACHE_LOCK_TIMEOUT, MAXIMUM_GOSSIP_CLOCK_DISPARITY,
|
||||
VALIDATOR_PUBKEY_CACHE_LOCK_TIMEOUT,
|
||||
},
|
||||
metrics, BeaconChain, BeaconChainError, BeaconChainTypes,
|
||||
eth1_chain, metrics, BeaconChain, BeaconChainError, BeaconChainTypes,
|
||||
};
|
||||
use fork_choice::{ForkChoice, ForkChoiceStore};
|
||||
use parking_lot::RwLockReadGuard;
|
||||
@@ -56,6 +56,7 @@ use proto_array::Block as ProtoBlock;
|
||||
use slog::{debug, error, Logger};
|
||||
use slot_clock::SlotClock;
|
||||
use ssz::Encode;
|
||||
use state_processing::per_block_processing::{is_execution_enabled, is_merge_complete};
|
||||
use state_processing::{
|
||||
block_signature_verifier::{BlockSignatureVerifier, Error as BlockSignatureVerifierError},
|
||||
per_block_processing, per_slot_processing,
|
||||
@@ -68,9 +69,9 @@ use std::io::Write;
|
||||
use store::{Error as DBError, HotColdDB, HotStateSummary, KeyValueStore, StoreOp};
|
||||
use tree_hash::TreeHash;
|
||||
use types::{
|
||||
BeaconBlockRef, BeaconState, BeaconStateError, ChainSpec, CloneConfig, Epoch, EthSpec, Hash256,
|
||||
InconsistentFork, PublicKey, PublicKeyBytes, RelativeEpoch, SignedBeaconBlock,
|
||||
SignedBeaconBlockHeader, Slot,
|
||||
BeaconBlockRef, BeaconState, BeaconStateError, ChainSpec, CloneConfig, Epoch, EthSpec,
|
||||
ExecutionPayload, Hash256, InconsistentFork, PublicKey, PublicKeyBytes, RelativeEpoch,
|
||||
SignedBeaconBlock, SignedBeaconBlockHeader, Slot,
|
||||
};
|
||||
|
||||
/// Maximum block slot number. Block with slots bigger than this constant will NOT be processed.
|
||||
@@ -223,6 +224,66 @@ pub enum BlockError<T: EthSpec> {
|
||||
///
|
||||
/// The block is invalid and the peer is faulty.
|
||||
InconsistentFork(InconsistentFork),
|
||||
/// There was an error while validating the ExecutionPayload
|
||||
///
|
||||
/// ## Peer scoring
|
||||
///
|
||||
/// See `ExecutionPayloadError` for scoring information
|
||||
ExecutionPayloadError(ExecutionPayloadError),
|
||||
}
|
||||
|
||||
/// Returned when block validation failed due to some issue verifying
|
||||
/// the execution payload.
|
||||
#[derive(Debug)]
|
||||
pub enum ExecutionPayloadError {
|
||||
/// There's no eth1 connection (mandatory after merge)
|
||||
///
|
||||
/// ## Peer scoring
|
||||
///
|
||||
/// As this is our fault, do not penalize the peer
|
||||
NoEth1Connection,
|
||||
/// Error occurred during engine_executePayload
|
||||
///
|
||||
/// ## Peer scoring
|
||||
///
|
||||
/// Some issue with our configuration, do not penalize peer
|
||||
Eth1VerificationError(eth1_chain::Error),
|
||||
/// The execution engine returned INVALID for the payload
|
||||
///
|
||||
/// ## Peer scoring
|
||||
///
|
||||
/// The block is invalid and the peer is faulty
|
||||
RejectedByExecutionEngine,
|
||||
/// The execution payload is empty when is shouldn't be
|
||||
///
|
||||
/// ## Peer scoring
|
||||
///
|
||||
/// The block is invalid and the peer is faulty
|
||||
PayloadEmpty,
|
||||
/// The execution payload timestamp does not match the slot
|
||||
///
|
||||
/// ## Peer scoring
|
||||
///
|
||||
/// The block is invalid and the peer is faulty
|
||||
InvalidPayloadTimestamp,
|
||||
/// The gas used in the block exceeds the gas limit
|
||||
///
|
||||
/// ## Peer scoring
|
||||
///
|
||||
/// The block is invalid and the peer is faulty
|
||||
GasUsedExceedsLimit,
|
||||
/// The payload block hash equals the parent hash
|
||||
///
|
||||
/// ## Peer scoring
|
||||
///
|
||||
/// The block is invalid and the peer is faulty
|
||||
BlockHashEqualsParentHash,
|
||||
/// The execution payload transaction list data exceeds size limits
|
||||
///
|
||||
/// ## Peer scoring
|
||||
///
|
||||
/// The block is invalid and the peer is faulty
|
||||
TransactionDataExceedsSizeLimit,
|
||||
}
|
||||
|
||||
impl<T: EthSpec> std::fmt::Display for BlockError<T> {
|
||||
@@ -668,6 +729,18 @@ impl<T: BeaconChainTypes> GossipVerifiedBlock<T> {
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: avoid this by adding field to fork-choice to determine if merge-block has been imported
|
||||
let (parent, block) = if let Some(snapshot) = parent {
|
||||
(Some(snapshot), block)
|
||||
} else {
|
||||
let (snapshot, block) = load_parent(block, chain)?;
|
||||
(Some(snapshot), block)
|
||||
};
|
||||
let state = &parent.as_ref().unwrap().pre_state;
|
||||
|
||||
// validate the block's execution_payload
|
||||
validate_execution_payload(block.message(), state)?;
|
||||
|
||||
Ok(Self {
|
||||
block,
|
||||
block_root,
|
||||
@@ -989,6 +1062,34 @@ impl<'a, T: BeaconChainTypes> FullyVerifiedBlock<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
// This is the soonest we can run these checks as they must be called AFTER per_slot_processing
|
||||
if is_execution_enabled(&state, block.message().body()) {
|
||||
let eth1_chain = chain
|
||||
.eth1_chain
|
||||
.as_ref()
|
||||
.ok_or(BlockError::ExecutionPayloadError(
|
||||
ExecutionPayloadError::NoEth1Connection,
|
||||
))?;
|
||||
|
||||
if !eth1_chain
|
||||
.on_payload(block.message().body().execution_payload().ok_or(
|
||||
BlockError::InconsistentFork(InconsistentFork {
|
||||
fork_at_slot: eth2::types::ForkName::Merge,
|
||||
object_fork: block.message().body().fork_name(),
|
||||
}),
|
||||
)?)
|
||||
.map_err(|e| {
|
||||
BlockError::ExecutionPayloadError(ExecutionPayloadError::Eth1VerificationError(
|
||||
e,
|
||||
))
|
||||
})?
|
||||
{
|
||||
return Err(BlockError::ExecutionPayloadError(
|
||||
ExecutionPayloadError::RejectedByExecutionEngine,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// If the block is sufficiently recent, notify the validator monitor.
|
||||
if let Some(slot) = chain.slot_clock.now() {
|
||||
let epoch = slot.epoch(T::EthSpec::slots_per_epoch());
|
||||
@@ -1097,6 +1198,38 @@ impl<'a, T: BeaconChainTypes> FullyVerifiedBlock<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Validate the gossip block's execution_payload according to the checks described here:
|
||||
/// https://github.com/ethereum/consensus-specs/blob/dev/specs/merge/p2p-interface.md#beacon_block
|
||||
fn validate_execution_payload<E: EthSpec>(
|
||||
block: BeaconBlockRef<'_, E>,
|
||||
state: &BeaconState<E>,
|
||||
) -> Result<(), BlockError<E>> {
|
||||
if !is_execution_enabled(state, block.body()) {
|
||||
return Ok(());
|
||||
}
|
||||
let execution_payload = block
|
||||
.body()
|
||||
.execution_payload()
|
||||
// TODO: this really should never error so maybe
|
||||
// we should make this simpler..
|
||||
.ok_or(BlockError::InconsistentFork(InconsistentFork {
|
||||
fork_at_slot: eth2::types::ForkName::Merge,
|
||||
object_fork: block.body().fork_name(),
|
||||
}))?;
|
||||
|
||||
if is_merge_complete(state) {
|
||||
if *execution_payload == <ExecutionPayload<E>>::default() {
|
||||
return Err(BlockError::ExecutionPayloadError(
|
||||
ExecutionPayloadError::PayloadEmpty,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: finish these
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Check that the count of skip slots between the block and its parent does not exceed our maximum
|
||||
/// value.
|
||||
///
|
||||
|
||||
@@ -15,8 +15,8 @@ use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use store::{DBColumn, Error as StoreError, StoreItem};
|
||||
use task_executor::TaskExecutor;
|
||||
use types::{
|
||||
BeaconState, BeaconStateError, ChainSpec, Deposit, Eth1Data, EthSpec, Hash256, Slot, Unsigned,
|
||||
DEPOSIT_TREE_DEPTH,
|
||||
BeaconState, BeaconStateError, ChainSpec, Deposit, Eth1Data, EthSpec, ExecutionPayload,
|
||||
Hash256, Slot, Unsigned, DEPOSIT_TREE_DEPTH,
|
||||
};
|
||||
|
||||
type BlockNumber = u64;
|
||||
@@ -53,6 +53,8 @@ pub enum Error {
|
||||
UnknownPreviousEth1BlockHash,
|
||||
/// An arithmetic error occurred.
|
||||
ArithError(safe_arith::ArithError),
|
||||
/// Unable to execute payload
|
||||
UnableToExecutePayload(String),
|
||||
}
|
||||
|
||||
impl From<safe_arith::ArithError> for Error {
|
||||
@@ -274,6 +276,15 @@ where
|
||||
)
|
||||
}
|
||||
|
||||
pub fn on_payload(&self, execution_payload: &ExecutionPayload<E>) -> Result<bool, Error> {
|
||||
if self.use_dummy_backend {
|
||||
let dummy_backend: DummyEth1ChainBackend<E> = DummyEth1ChainBackend::default();
|
||||
dummy_backend.on_payload(execution_payload)
|
||||
} else {
|
||||
self.backend.on_payload(execution_payload)
|
||||
}
|
||||
}
|
||||
|
||||
/// Instantiate `Eth1Chain` from a persisted `SszEth1`.
|
||||
///
|
||||
/// The `Eth1Chain` will have the same caches as the persisted `SszEth1`.
|
||||
@@ -334,6 +345,9 @@ pub trait Eth1ChainBackend<T: EthSpec>: Sized + Send + Sync {
|
||||
/// an idea of how up-to-date the remote eth1 node is.
|
||||
fn head_block(&self) -> Option<Eth1Block>;
|
||||
|
||||
/// Verifies the execution payload
|
||||
fn on_payload(&self, execution_payload: &ExecutionPayload<T>) -> Result<bool, Error>;
|
||||
|
||||
/// Encode the `Eth1ChainBackend` instance to bytes.
|
||||
fn as_bytes(&self) -> Vec<u8>;
|
||||
|
||||
@@ -388,6 +402,10 @@ impl<T: EthSpec> Eth1ChainBackend<T> for DummyEth1ChainBackend<T> {
|
||||
None
|
||||
}
|
||||
|
||||
fn on_payload(&self, _execution_payload: &ExecutionPayload<T>) -> Result<bool, Error> {
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
/// Return empty Vec<u8> for dummy backend.
|
||||
fn as_bytes(&self) -> Vec<u8> {
|
||||
Vec::new()
|
||||
@@ -556,6 +574,15 @@ impl<T: EthSpec> Eth1ChainBackend<T> for CachingEth1Backend<T> {
|
||||
self.core.head_block()
|
||||
}
|
||||
|
||||
fn on_payload(&self, execution_payload: &ExecutionPayload<T>) -> Result<bool, Error> {
|
||||
futures::executor::block_on(async move {
|
||||
self.core
|
||||
.on_payload(execution_payload.clone())
|
||||
.await
|
||||
.map_err(|e| Error::UnableToExecutePayload(format!("{:?}", e)))
|
||||
})
|
||||
}
|
||||
|
||||
/// Return encoded byte representation of the block and deposit caches.
|
||||
fn as_bytes(&self) -> Vec<u8> {
|
||||
self.core.as_bytes()
|
||||
|
||||
@@ -44,7 +44,7 @@ pub use self::errors::{BeaconChainError, BlockProductionError};
|
||||
pub use self::historical_blocks::HistoricalBlockError;
|
||||
pub use attestation_verification::Error as AttestationError;
|
||||
pub use beacon_fork_choice_store::{BeaconForkChoiceStore, Error as ForkChoiceStoreError};
|
||||
pub use block_verification::{BlockError, GossipVerifiedBlock};
|
||||
pub use block_verification::{BlockError, ExecutionPayloadError, GossipVerifiedBlock};
|
||||
pub use eth1_chain::{Eth1Chain, Eth1ChainBackend};
|
||||
pub use events::ServerSentEventHandler;
|
||||
pub use metrics::scrape_for_metrics;
|
||||
|
||||
Reference in New Issue
Block a user