mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-01-28 08:37:59 -05:00
fix: chainspec ttd check (#1285)
Co-authored-by: Georgios Konstantopoulos <me@gakonst.com>
This commit is contained in:
@@ -50,7 +50,8 @@ impl Consensus for BeaconConsensus {
|
||||
}
|
||||
|
||||
fn validate_header(&self, header: &SealedHeader, total_difficulty: U256) -> Result<(), Error> {
|
||||
if self.chain_spec.fork(Hardfork::Paris).active_at_ttd(total_difficulty) {
|
||||
if self.chain_spec.fork(Hardfork::Paris).active_at_ttd(total_difficulty, header.difficulty)
|
||||
{
|
||||
// EIP-3675: Upgrade consensus to Proof-of-Stake:
|
||||
// https://eips.ethereum.org/EIPS/eip-3675#replacing-difficulty-with-0
|
||||
if header.difficulty != U256::ZERO {
|
||||
@@ -80,8 +81,8 @@ impl Consensus for BeaconConsensus {
|
||||
validation::validate_block_standalone(block)
|
||||
}
|
||||
|
||||
fn has_block_reward(&self, total_difficulty: U256) -> bool {
|
||||
!self.chain_spec.fork(Hardfork::Paris).active_at_ttd(total_difficulty)
|
||||
fn has_block_reward(&self, total_difficulty: U256, difficulty: U256) -> bool {
|
||||
!self.chain_spec.fork(Hardfork::Paris).active_at_ttd(total_difficulty, difficulty)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,6 +97,6 @@ mod test {
|
||||
fn test_has_block_reward_before_paris() {
|
||||
let chain_spec = ChainSpecBuilder::mainnet().build();
|
||||
let (consensus, _) = BeaconConsensus::builder().build(chain_spec);
|
||||
assert!(consensus.has_block_reward(U256::ZERO));
|
||||
assert!(consensus.has_block_reward(U256::ZERO, U256::ZERO));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,8 @@ mod tests {
|
||||
revm_spec(
|
||||
&MAINNET,
|
||||
Head {
|
||||
total_difficulty: U256::from(58_750_000_000_000_000_000_000u128),
|
||||
total_difficulty: U256::from(58_750_000_000_000_000_000_010_u128),
|
||||
difficulty: U256::from(10_u128),
|
||||
..Default::default()
|
||||
}
|
||||
),
|
||||
@@ -110,7 +111,8 @@ mod tests {
|
||||
&MAINNET,
|
||||
Head {
|
||||
number: 15537394 - 10,
|
||||
total_difficulty: U256::from(58_750_000_000_000_000_000_000u128),
|
||||
total_difficulty: U256::from(58_750_000_000_000_000_000_010_u128),
|
||||
difficulty: U256::from(10_u128),
|
||||
..Default::default()
|
||||
}
|
||||
),
|
||||
|
||||
@@ -69,8 +69,9 @@ where
|
||||
Head {
|
||||
number: header.number,
|
||||
timestamp: header.timestamp,
|
||||
difficulty: header.difficulty,
|
||||
total_difficulty,
|
||||
..Default::default()
|
||||
hash: Default::default(),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -220,7 +221,8 @@ where
|
||||
// ommer, we raise the block’s beneficiary by an additional 1/32 of the block reward
|
||||
// and the beneficiary of the ommer gets rewarded depending on the blocknumber.
|
||||
// Formally we define the function Ω:
|
||||
if self.chain_spec.fork(Hardfork::Paris).active_at_ttd(total_difficulty) {
|
||||
if self.chain_spec.fork(Hardfork::Paris).active_at_ttd(total_difficulty, header.difficulty)
|
||||
{
|
||||
None
|
||||
} else if self.chain_spec.fork(Hardfork::Petersburg).active_at_block(header.number) {
|
||||
Some(WEI_2ETH)
|
||||
|
||||
@@ -45,7 +45,7 @@ pub trait Consensus: Debug + Send + Sync {
|
||||
/// This flag is needed as reth's changeset is indexed on transaction level granularity.
|
||||
///
|
||||
/// More info [here](https://github.com/paradigmxyz/reth/issues/237)
|
||||
fn has_block_reward(&self, total_difficulty: U256) -> bool;
|
||||
fn has_block_reward(&self, total_difficulty: U256, difficulty: U256) -> bool;
|
||||
}
|
||||
|
||||
/// Consensus Errors
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use reth_primitives::{BlockNumber, SealedBlock, SealedHeader};
|
||||
use reth_primitives::{BlockNumber, SealedBlock, SealedHeader, U256};
|
||||
|
||||
/// The block response
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
@@ -22,4 +22,12 @@ impl BlockResponse {
|
||||
pub fn block_number(&self) -> BlockNumber {
|
||||
self.header().number
|
||||
}
|
||||
|
||||
/// Return the reference to the response header
|
||||
pub fn difficulty(&self) -> U256 {
|
||||
match self {
|
||||
BlockResponse::Full(block) => block.difficulty,
|
||||
BlockResponse::Empty(header) => header.difficulty,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,7 +340,7 @@ impl Consensus for TestConsensus {
|
||||
}
|
||||
}
|
||||
|
||||
fn has_block_reward(&self, _: U256) -> bool {
|
||||
fn has_block_reward(&self, _: U256, _: U256) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,8 +307,9 @@ impl NetworkConfigBuilder {
|
||||
let head = head.unwrap_or(Head {
|
||||
hash: chain_spec.genesis_hash(),
|
||||
number: 0,
|
||||
total_difficulty: U256::ZERO,
|
||||
timestamp: 0,
|
||||
difficulty: chain_spec.genesis.difficulty,
|
||||
total_difficulty: U256::ZERO,
|
||||
});
|
||||
|
||||
// set the status
|
||||
|
||||
@@ -32,7 +32,7 @@ pub static MAINNET: Lazy<ChainSpec> = Lazy::new(|| ChainSpec {
|
||||
Hardfork::Paris,
|
||||
ForkCondition::TTD {
|
||||
fork_block: None,
|
||||
total_difficulty: U256::from(58_750_000_000_000_000_000_000u128),
|
||||
total_difficulty: U256::from(58_750_000_000_000_000_000_000_u128),
|
||||
},
|
||||
),
|
||||
]),
|
||||
@@ -472,12 +472,17 @@ impl ForkCondition {
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether the fork condition is satisfied at the given total difficulty.
|
||||
/// Checks whether the fork condition is satisfied at the given total difficulty and difficulty
|
||||
/// of a current block.
|
||||
///
|
||||
/// The fork is considered active if the _previous_ total difficulty is above the threshold.
|
||||
/// To achieve that, we subtract the passed `difficulty` from the current block's total difficulty,
|
||||
/// and check if it's above the Fork Condition's total difficulty (here: 58_750_000_000_000_000_000_000)
|
||||
///
|
||||
/// This will return false for any condition that is not TTD-based.
|
||||
pub fn active_at_ttd(&self, ttd: U256) -> bool {
|
||||
pub fn active_at_ttd(&self, ttd: U256, difficulty: U256) -> bool {
|
||||
if let ForkCondition::TTD { total_difficulty, .. } = self {
|
||||
ttd >= *total_difficulty
|
||||
ttd.saturating_sub(difficulty) >= *total_difficulty
|
||||
} else {
|
||||
false
|
||||
}
|
||||
@@ -504,7 +509,7 @@ impl ForkCondition {
|
||||
pub fn active_at_head(&self, head: &Head) -> bool {
|
||||
self.active_at_block(head.number) ||
|
||||
self.active_at_timestamp(head.timestamp) ||
|
||||
self.active_at_ttd(head.total_difficulty)
|
||||
self.active_at_ttd(head.total_difficulty, head.difficulty)
|
||||
}
|
||||
|
||||
/// Get the total terminal difficulty for this fork condition.
|
||||
@@ -532,6 +537,8 @@ impl ForkCondition {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use revm_primitives::U256;
|
||||
|
||||
use crate::{
|
||||
Chain, ChainSpec, ChainSpecBuilder, ForkCondition, ForkHash, ForkId, Genesis, Hardfork,
|
||||
Head, GOERLI, MAINNET, SEPOLIA,
|
||||
@@ -834,4 +841,24 @@ mod tests {
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// Checks that the fork is not active at a terminal ttd block.
|
||||
#[test]
|
||||
fn check_terminal_ttd() {
|
||||
let chainspec = ChainSpecBuilder::mainnet().build();
|
||||
|
||||
// Check that Paris is not active on terminal PoW block #15537393.
|
||||
let terminal_block_ttd = U256::from(58750003716598352816469_u128);
|
||||
let terminal_block_difficulty = U256::from(11055787484078698_u128);
|
||||
assert!(!chainspec
|
||||
.fork(Hardfork::Paris)
|
||||
.active_at_ttd(terminal_block_ttd, terminal_block_difficulty));
|
||||
|
||||
// Check that Paris is active on first PoS block #15537394.
|
||||
let first_pos_block_ttd = U256::from(58750003716598352816469_u128);
|
||||
let first_pos_difficulty = U256::ZERO;
|
||||
assert!(chainspec
|
||||
.fork(Hardfork::Paris)
|
||||
.active_at_ttd(first_pos_block_ttd, first_pos_difficulty));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,9 @@ pub struct Head {
|
||||
pub number: BlockNumber,
|
||||
/// The hash of the head block.
|
||||
pub hash: H256,
|
||||
/// The total difficulty of the head block.
|
||||
/// The difficulty of the head block.
|
||||
pub difficulty: U256,
|
||||
/// The total difficulty at the head block.
|
||||
pub total_difficulty: U256,
|
||||
/// The timestamp of the head block.
|
||||
pub timestamp: u64,
|
||||
|
||||
@@ -161,7 +161,8 @@ impl<Client: HeaderProvider + BlockProvider + StateProvider> EngineApi<Client> {
|
||||
}))
|
||||
};
|
||||
|
||||
if !self.chain_spec.fork(Hardfork::Paris).active_at_ttd(parent_td) {
|
||||
// Short circuit the check by passing parent total difficulty.
|
||||
if !self.chain_spec.fork(Hardfork::Paris).active_at_ttd(parent_td, U256::ZERO) {
|
||||
return Ok(PayloadStatus::from_status(PayloadStatusEnum::Invalid {
|
||||
validation_error: EngineApiError::PayloadPreMerge.to_string(),
|
||||
}))
|
||||
|
||||
@@ -113,6 +113,7 @@ impl<DB: Database, D: BodyDownloader> Stage<DB> for BodyStage<D> {
|
||||
for response in downloaded_bodies {
|
||||
// Write block
|
||||
let block_number = response.block_number();
|
||||
let difficulty = response.difficulty();
|
||||
|
||||
match response {
|
||||
BlockResponse::Full(block) => {
|
||||
@@ -161,7 +162,7 @@ impl<DB: Database, D: BodyDownloader> Stage<DB> for BodyStage<D> {
|
||||
.seek(block_number)?
|
||||
.ok_or(ProviderError::TotalDifficulty { number: block_number })?
|
||||
.1;
|
||||
let has_reward = self.consensus.has_block_reward(td.into());
|
||||
let has_reward = self.consensus.has_block_reward(td.into(), difficulty);
|
||||
if has_reward {
|
||||
transition_id += 1;
|
||||
}
|
||||
@@ -664,7 +665,7 @@ mod tests {
|
||||
.seek(number)?
|
||||
.expect("Missing TD for header")
|
||||
.1;
|
||||
if self.consensus.has_block_reward(td.into()) {
|
||||
if self.consensus.has_block_reward(td.into(), header.difficulty) {
|
||||
expected_transition_id += 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ impl<DB: Database> Stage<DB> for TotalDifficultyStage {
|
||||
let (key, header) = entry?;
|
||||
td += header.difficulty;
|
||||
|
||||
if self.chain_spec.fork(Hardfork::Paris).active_at_ttd(td) {
|
||||
if self.chain_spec.fork(Hardfork::Paris).active_at_ttd(td, header.difficulty) {
|
||||
if header.difficulty != U256::ZERO {
|
||||
return Err(StageError::Validation {
|
||||
block: header.number,
|
||||
|
||||
@@ -25,8 +25,12 @@ pub fn insert_block<'a, TX: DbTxMut<'a> + DbTx<'a>>(
|
||||
tx.put::<tables::HeaderNumbers>(block.hash(), block.number)?;
|
||||
tx.put::<tables::HeaderTD>(
|
||||
block.number,
|
||||
if has_block_reward { U256::ZERO } else { U256::from(58_750_000_000_000_000_000_000u128) }
|
||||
.into(),
|
||||
if has_block_reward {
|
||||
U256::ZERO
|
||||
} else {
|
||||
U256::from(58_750_000_000_000_000_000_000_u128) + block.difficulty
|
||||
}
|
||||
.into(),
|
||||
)?;
|
||||
|
||||
// insert body ommers data
|
||||
|
||||
Reference in New Issue
Block a user