mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-06 10:11:44 +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:
@@ -33,7 +33,7 @@ pub fn slash_validator<T: EthSpec>(
|
||||
|
||||
let min_slashing_penalty_quotient = match state {
|
||||
BeaconState::Base(_) => spec.min_slashing_penalty_quotient,
|
||||
BeaconState::Altair(_) => spec.min_slashing_penalty_quotient_altair,
|
||||
BeaconState::Altair(_) | BeaconState::Merge(_) => spec.min_slashing_penalty_quotient_altair,
|
||||
};
|
||||
decrease_balance(
|
||||
state,
|
||||
@@ -48,7 +48,7 @@ pub fn slash_validator<T: EthSpec>(
|
||||
validator_effective_balance.safe_div(spec.whistleblower_reward_quotient)?;
|
||||
let proposer_reward = match state {
|
||||
BeaconState::Base(_) => whistleblower_reward.safe_div(spec.proposer_reward_quotient)?,
|
||||
BeaconState::Altair(_) => whistleblower_reward
|
||||
BeaconState::Altair(_) | BeaconState::Merge(_) => whistleblower_reward
|
||||
.safe_mul(PROPOSER_WEIGHT)?
|
||||
.safe_div(WEIGHT_DENOMINATOR)?,
|
||||
};
|
||||
|
||||
@@ -52,6 +52,8 @@ pub fn initialize_beacon_state_from_eth1<T: EthSpec>(
|
||||
state.fork_mut().previous_version = spec.altair_fork_version;
|
||||
}
|
||||
|
||||
// TODO: handle upgrade_to_merge() here
|
||||
|
||||
// Now that we have our validators, initialize the caches (including the committees)
|
||||
state.build_all_caches(spec)?;
|
||||
|
||||
|
||||
@@ -149,6 +149,10 @@ pub fn per_block_processing<T: EthSpec>(
|
||||
)?;
|
||||
}
|
||||
|
||||
if is_execution_enabled(state, block.body()) {
|
||||
process_execution_payload(state, block.body().execution_payload().unwrap(), spec)?
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -283,3 +287,135 @@ pub fn get_new_eth1_data<T: EthSpec>(
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
/// https://github.com/ethereum/consensus-specs/blob/dev/specs/merge/beacon-chain.md#is_valid_gas_limit
|
||||
pub fn is_valid_gas_limit<T: EthSpec>(
|
||||
payload: &ExecutionPayload<T>,
|
||||
parent: &ExecutionPayloadHeader<T>,
|
||||
) -> bool {
|
||||
// check if payload used too much gas
|
||||
if payload.gas_used > payload.gas_limit {
|
||||
return false;
|
||||
}
|
||||
// check if payload changed the gas limit too much
|
||||
if payload.gas_limit >= parent.gas_limit + parent.gas_limit / T::gas_limit_denominator() {
|
||||
return false;
|
||||
}
|
||||
if payload.gas_limit <= parent.gas_limit - parent.gas_limit / T::gas_limit_denominator() {
|
||||
return false;
|
||||
}
|
||||
// check if the gas limit is at least the minimum gas limit
|
||||
if payload.gas_limit < T::min_gas_limit() {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// https://github.com/ethereum/consensus-specs/blob/dev/specs/merge/beacon-chain.md#process_execution_payload
|
||||
pub fn process_execution_payload<T: EthSpec>(
|
||||
state: &mut BeaconState<T>,
|
||||
payload: &ExecutionPayload<T>,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), BlockProcessingError> {
|
||||
if is_merge_complete(state) {
|
||||
block_verify!(
|
||||
payload.parent_hash == state.latest_execution_payload_header()?.block_hash,
|
||||
BlockProcessingError::ExecutionHashChainIncontiguous {
|
||||
expected: state.latest_execution_payload_header()?.block_hash,
|
||||
found: payload.parent_hash,
|
||||
}
|
||||
);
|
||||
block_verify!(
|
||||
payload.block_number
|
||||
== state
|
||||
.latest_execution_payload_header()?
|
||||
.block_number
|
||||
.safe_add(1)?,
|
||||
BlockProcessingError::ExecutionBlockNumberIncontiguous {
|
||||
expected: state
|
||||
.latest_execution_payload_header()?
|
||||
.block_number
|
||||
.safe_add(1)?,
|
||||
found: payload.block_number,
|
||||
}
|
||||
);
|
||||
block_verify!(
|
||||
payload.random == *state.get_randao_mix(state.current_epoch())?,
|
||||
BlockProcessingError::ExecutionRandaoMismatch {
|
||||
expected: *state.get_randao_mix(state.current_epoch())?,
|
||||
found: payload.random,
|
||||
}
|
||||
);
|
||||
block_verify!(
|
||||
is_valid_gas_limit(payload, state.latest_execution_payload_header()?),
|
||||
BlockProcessingError::ExecutionInvalidGasLimit {
|
||||
used: payload.gas_used,
|
||||
limit: payload.gas_limit,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
let timestamp = compute_timestamp_at_slot(state, spec)?;
|
||||
block_verify!(
|
||||
payload.timestamp == timestamp,
|
||||
BlockProcessingError::ExecutionInvalidTimestamp {
|
||||
expected: timestamp,
|
||||
found: payload.timestamp,
|
||||
}
|
||||
);
|
||||
|
||||
*state.latest_execution_payload_header_mut()? = ExecutionPayloadHeader {
|
||||
parent_hash: payload.parent_hash,
|
||||
coinbase: payload.coinbase,
|
||||
state_root: payload.state_root,
|
||||
receipt_root: payload.receipt_root,
|
||||
logs_bloom: payload.logs_bloom.clone(),
|
||||
random: payload.random,
|
||||
block_number: payload.block_number,
|
||||
gas_limit: payload.gas_limit,
|
||||
gas_used: payload.gas_used,
|
||||
timestamp: payload.timestamp,
|
||||
base_fee_per_gas: payload.base_fee_per_gas,
|
||||
block_hash: payload.block_hash,
|
||||
transactions_root: payload.transactions.tree_hash_root(),
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// These functions will definitely be called before the merge. Their entire purpose is to check if
|
||||
/// the merge has happened or if we're on the transition block. Thus we don't want to propagate
|
||||
/// errors from the `BeaconState` being an earlier variant than `BeaconStateMerge` as we'd have to
|
||||
/// repeaetedly write code to treat these errors as false.
|
||||
/// https://github.com/ethereum/consensus-specs/blob/dev/specs/merge/beacon-chain.md#is_merge_complete
|
||||
pub fn is_merge_complete<T: EthSpec>(state: &BeaconState<T>) -> bool {
|
||||
state
|
||||
.latest_execution_payload_header()
|
||||
.map(|header| *header != <ExecutionPayloadHeader<T>>::default())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
/// https://github.com/ethereum/consensus-specs/blob/dev/specs/merge/beacon-chain.md#is_merge_block
|
||||
pub fn is_merge_block<T: EthSpec>(state: &BeaconState<T>, body: BeaconBlockBodyRef<T>) -> bool {
|
||||
body.execution_payload()
|
||||
.map(|payload| !is_merge_complete(state) && *payload != <ExecutionPayload<T>>::default())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
/// https://github.com/ethereum/consensus-specs/blob/dev/specs/merge/beacon-chain.md#is_execution_enabled
|
||||
pub fn is_execution_enabled<T: EthSpec>(
|
||||
state: &BeaconState<T>,
|
||||
body: BeaconBlockBodyRef<T>,
|
||||
) -> bool {
|
||||
is_merge_block(state, body) || is_merge_complete(state)
|
||||
}
|
||||
|
||||
/// https://github.com/ethereum/consensus-specs/blob/dev/specs/merge/beacon-chain.md#compute_timestamp_at_slot
|
||||
pub fn compute_timestamp_at_slot<T: EthSpec>(
|
||||
state: &BeaconState<T>,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<u64, ArithError> {
|
||||
let slots_since_genesis = state.slot().as_u64().safe_sub(spec.genesis_slot.as_u64())?;
|
||||
slots_since_genesis
|
||||
.safe_mul(spec.seconds_per_slot)
|
||||
.and_then(|since_genesis| state.genesis_time().safe_add(since_genesis))
|
||||
}
|
||||
|
||||
@@ -57,6 +57,26 @@ pub enum BlockProcessingError {
|
||||
ArithError(ArithError),
|
||||
InconsistentBlockFork(InconsistentFork),
|
||||
InconsistentStateFork(InconsistentFork),
|
||||
ExecutionHashChainIncontiguous {
|
||||
expected: Hash256,
|
||||
found: Hash256,
|
||||
},
|
||||
ExecutionBlockNumberIncontiguous {
|
||||
expected: u64,
|
||||
found: u64,
|
||||
},
|
||||
ExecutionRandaoMismatch {
|
||||
expected: Hash256,
|
||||
found: Hash256,
|
||||
},
|
||||
ExecutionInvalidGasLimit {
|
||||
used: u64,
|
||||
limit: u64,
|
||||
},
|
||||
ExecutionInvalidTimestamp {
|
||||
expected: u64,
|
||||
found: u64,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<BeaconStateError> for BlockProcessingError {
|
||||
|
||||
@@ -228,7 +228,7 @@ pub fn process_attestations<'a, T: EthSpec>(
|
||||
BeaconBlockBodyRef::Base(_) => {
|
||||
base::process_attestations(state, block_body.attestations(), verify_signatures, spec)?;
|
||||
}
|
||||
BeaconBlockBodyRef::Altair(_) => {
|
||||
BeaconBlockBodyRef::Altair(_) | BeaconBlockBodyRef::Merge(_) => {
|
||||
altair::process_attestations(
|
||||
state,
|
||||
block_body.attestations(),
|
||||
|
||||
@@ -35,7 +35,7 @@ pub fn process_epoch<T: EthSpec>(
|
||||
|
||||
match state {
|
||||
BeaconState::Base(_) => base::process_epoch(state, spec),
|
||||
BeaconState::Altair(_) => altair::process_epoch(state, spec),
|
||||
BeaconState::Altair(_) | BeaconState::Merge(_) => altair::process_epoch(state, spec),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::upgrade::upgrade_to_altair;
|
||||
use crate::upgrade::{upgrade_to_altair, upgrade_to_merge};
|
||||
use crate::{per_epoch_processing::EpochProcessingSummary, *};
|
||||
use safe_arith::{ArithError, SafeArith};
|
||||
use types::*;
|
||||
@@ -44,11 +44,17 @@ pub fn per_slot_processing<T: EthSpec>(
|
||||
|
||||
state.slot_mut().safe_add_assign(1)?;
|
||||
|
||||
// If the Altair fork epoch is reached, perform an irregular state upgrade.
|
||||
if state.slot().safe_rem(T::slots_per_epoch())? == 0
|
||||
&& spec.altair_fork_epoch == Some(state.current_epoch())
|
||||
{
|
||||
upgrade_to_altair(state, spec)?;
|
||||
// Process fork upgrades here. Note that multiple upgrades can potentially run
|
||||
// in sequence if they are scheduled in the same Epoch (common in testnets)
|
||||
if state.slot().safe_rem(T::slots_per_epoch())? == 0 {
|
||||
// If the Altair fork epoch is reached, perform an irregular state upgrade.
|
||||
if spec.altair_fork_epoch == Some(state.current_epoch()) {
|
||||
upgrade_to_altair(state, spec)?;
|
||||
}
|
||||
// If the Merge fork epoch is reached, perform an irregular state upgrade.
|
||||
if spec.merge_fork_epoch == Some(state.current_epoch()) {
|
||||
upgrade_to_merge(state, spec)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(summary)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
pub mod altair;
|
||||
pub mod merge;
|
||||
|
||||
pub use altair::upgrade_to_altair;
|
||||
pub use merge::upgrade_to_merge;
|
||||
|
||||
72
consensus/state_processing/src/upgrade/merge.rs
Normal file
72
consensus/state_processing/src/upgrade/merge.rs
Normal file
@@ -0,0 +1,72 @@
|
||||
use std::mem;
|
||||
use types::{
|
||||
BeaconState, BeaconStateError as Error, BeaconStateMerge, ChainSpec, EthSpec,
|
||||
ExecutionPayloadHeader, Fork,
|
||||
};
|
||||
|
||||
/// Transform a `Altair` state into an `Merge` state.
|
||||
pub fn upgrade_to_merge<E: EthSpec>(
|
||||
pre_state: &mut BeaconState<E>,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), Error> {
|
||||
let epoch = pre_state.current_epoch();
|
||||
let pre = pre_state.as_altair_mut()?;
|
||||
|
||||
// Where possible, use something like `mem::take` to move fields from behind the &mut
|
||||
// reference. For other fields that don't have a good default value, use `clone`.
|
||||
//
|
||||
// Fixed size vectors get cloned because replacing them would require the same size
|
||||
// allocation as cloning.
|
||||
let post = BeaconState::Merge(BeaconStateMerge {
|
||||
// Versioning
|
||||
genesis_time: pre.genesis_time,
|
||||
genesis_validators_root: pre.genesis_validators_root,
|
||||
slot: pre.slot,
|
||||
fork: Fork {
|
||||
previous_version: pre.fork.current_version,
|
||||
current_version: spec.merge_fork_version,
|
||||
epoch,
|
||||
},
|
||||
// History
|
||||
latest_block_header: pre.latest_block_header.clone(),
|
||||
block_roots: pre.block_roots.clone(),
|
||||
state_roots: pre.state_roots.clone(),
|
||||
historical_roots: mem::take(&mut pre.historical_roots),
|
||||
// Eth1
|
||||
eth1_data: pre.eth1_data.clone(),
|
||||
eth1_data_votes: mem::take(&mut pre.eth1_data_votes),
|
||||
eth1_deposit_index: pre.eth1_deposit_index,
|
||||
// Registry
|
||||
validators: mem::take(&mut pre.validators),
|
||||
balances: mem::take(&mut pre.balances),
|
||||
// Randomness
|
||||
randao_mixes: pre.randao_mixes.clone(),
|
||||
// Slashings
|
||||
slashings: pre.slashings.clone(),
|
||||
// `Participation
|
||||
previous_epoch_participation: mem::take(&mut pre.previous_epoch_participation),
|
||||
current_epoch_participation: mem::take(&mut pre.current_epoch_participation),
|
||||
// Finality
|
||||
justification_bits: pre.justification_bits.clone(),
|
||||
previous_justified_checkpoint: pre.previous_justified_checkpoint,
|
||||
current_justified_checkpoint: pre.current_justified_checkpoint,
|
||||
finalized_checkpoint: pre.finalized_checkpoint,
|
||||
// Inactivity
|
||||
inactivity_scores: mem::take(&mut pre.inactivity_scores),
|
||||
// Sync committees
|
||||
current_sync_committee: pre.current_sync_committee.clone(),
|
||||
next_sync_committee: pre.next_sync_committee.clone(),
|
||||
// Execution
|
||||
latest_execution_payload_header: <ExecutionPayloadHeader<E>>::default(),
|
||||
// Caches
|
||||
total_active_balance: pre.total_active_balance,
|
||||
committee_caches: mem::take(&mut pre.committee_caches),
|
||||
pubkey_cache: mem::take(&mut pre.pubkey_cache),
|
||||
exit_cache: mem::take(&mut pre.exit_cache),
|
||||
tree_hash_cache: mem::take(&mut pre.tree_hash_cache),
|
||||
});
|
||||
|
||||
*pre_state = post;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user