mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-01-29 09:08:05 -05:00
refactor: reward calc cleanup (#2075)
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -4727,6 +4727,7 @@ dependencies = [
|
||||
"hash-db",
|
||||
"parking_lot 0.12.1",
|
||||
"plain_hasher",
|
||||
"reth-consensus-common",
|
||||
"reth-db",
|
||||
"reth-interfaces",
|
||||
"reth-primitives",
|
||||
|
||||
143
crates/consensus/common/src/calc.rs
Normal file
143
crates/consensus/common/src/calc.rs
Normal file
@@ -0,0 +1,143 @@
|
||||
use reth_primitives::{constants::ETH_TO_WEI, BlockNumber, ChainSpec, Hardfork, U256};
|
||||
|
||||
/// Calculates the base block reward.
|
||||
///
|
||||
/// The base block reward is defined as:
|
||||
///
|
||||
/// - For Paris and later: `None`
|
||||
/// - For Petersburg and later: `Some(2 ETH)`
|
||||
/// - For Byzantium and later: `Some(3 ETH)`
|
||||
/// - Otherwise: `Some(5 ETH)`
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// This does not include the reward for including ommers. To calculate the full block reward, see
|
||||
/// [`block_reward`].
|
||||
///
|
||||
/// # References
|
||||
///
|
||||
/// - Definition: [Yellow Paper][yp] (page 15, 11.3)
|
||||
///
|
||||
/// [yp]: https://ethereum.github.io/yellowpaper/paper.pdf
|
||||
pub fn base_block_reward(
|
||||
chain_spec: &ChainSpec,
|
||||
block_number: BlockNumber,
|
||||
block_difficulty: U256,
|
||||
total_difficulty: U256,
|
||||
) -> Option<u128> {
|
||||
if chain_spec.fork(Hardfork::Paris).active_at_ttd(total_difficulty, block_difficulty) {
|
||||
None
|
||||
} else if chain_spec.fork(Hardfork::Petersburg).active_at_block(block_number) {
|
||||
Some(ETH_TO_WEI * 2)
|
||||
} else if chain_spec.fork(Hardfork::Byzantium).active_at_block(block_number) {
|
||||
Some(ETH_TO_WEI * 3)
|
||||
} else {
|
||||
Some(ETH_TO_WEI * 5)
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates the reward for a block, including the reward for ommer inclusion.
|
||||
///
|
||||
/// The base reward should be calculated using [`base_block_reward`]. `ommers` represents the number
|
||||
/// of ommers included in the block.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use reth_consensus_common::calc::{base_block_reward, block_reward};
|
||||
/// # use reth_primitives::constants::ETH_TO_WEI;
|
||||
/// # use reth_primitives::{MAINNET, U256};
|
||||
/// #
|
||||
/// // This is block 126 on mainnet.
|
||||
/// let block_number = 126;
|
||||
/// let block_difficulty = U256::from(18_145_285_642usize);
|
||||
/// let total_difficulty = U256::from(2_235_668_675_900usize);
|
||||
/// let number_of_ommers = 1;
|
||||
///
|
||||
/// let reward = base_block_reward(&MAINNET, block_number, block_difficulty, total_difficulty).map(|reward| block_reward(reward, 1));
|
||||
///
|
||||
/// // The base block reward is 5 ETH, and the ommer inclusion reward is 1/32th of 5 ETH.
|
||||
/// assert_eq!(
|
||||
/// reward.unwrap(),
|
||||
/// U256::from(ETH_TO_WEI * 5 + ((ETH_TO_WEI * 5) >> 5))
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// # References
|
||||
///
|
||||
/// - Definition: [Yellow Paper][yp] (page 15, 11.3)
|
||||
///
|
||||
/// [yp]: https://ethereum.github.io/yellowpaper/paper.pdf
|
||||
pub fn block_reward(base_block_reward: u128, ommers: usize) -> U256 {
|
||||
U256::from(base_block_reward + (base_block_reward >> 5) * ommers as u128)
|
||||
}
|
||||
|
||||
/// Calculate the reward for an ommer.
|
||||
///
|
||||
/// # Application
|
||||
///
|
||||
/// Rewards are accumulative, so they should be added to the beneficiary addresses in addition to
|
||||
/// any other rewards from the same block.
|
||||
///
|
||||
/// From the yellow paper (page 15):
|
||||
///
|
||||
/// > If there are collissions of the beneficiary addresses between ommers and the block (i.e. two
|
||||
/// > ommers with the same beneficiary address or an ommer with the same beneficiary address as the
|
||||
/// > present block), additions are applied cumulatively.
|
||||
///
|
||||
/// # References
|
||||
///
|
||||
/// - Implementation: [OpenEthereum][oe]
|
||||
/// - Definition: [Yellow Paper][yp] (page 15, 11.3)
|
||||
///
|
||||
/// [oe]: https://github.com/openethereum/openethereum/blob/6c2d392d867b058ff867c4373e40850ca3f96969/crates/ethcore/src/ethereum/ethash.rs#L319-L333
|
||||
/// [yp]: https://ethereum.github.io/yellowpaper/paper.pdf
|
||||
pub fn ommer_reward(
|
||||
base_block_reward: u128,
|
||||
block_number: BlockNumber,
|
||||
ommer_block_number: BlockNumber,
|
||||
) -> U256 {
|
||||
U256::from(((8 + ommer_block_number - block_number) as u128 * base_block_reward) >> 3)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use reth_primitives::{MAINNET, U256};
|
||||
|
||||
#[test]
|
||||
fn calc_base_block_reward() {
|
||||
// ((block number, td), reward)
|
||||
let cases = [
|
||||
// Pre-byzantium
|
||||
((0, U256::ZERO), Some(ETH_TO_WEI * 5)),
|
||||
// Byzantium
|
||||
((4370000, U256::ZERO), Some(ETH_TO_WEI * 3)),
|
||||
// Petersburg
|
||||
((7280000, U256::ZERO), Some(ETH_TO_WEI * 2)),
|
||||
// Merge
|
||||
((10000000, U256::from(58_750_000_000_000_000_000_000_u128)), None),
|
||||
];
|
||||
|
||||
for ((block_number, td), expected_reward) in cases {
|
||||
assert_eq!(base_block_reward(&MAINNET, block_number, U256::ZERO, td), expected_reward);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn calc_full_block_reward() {
|
||||
let base_reward = ETH_TO_WEI * 1;
|
||||
let one_thirty_twoth_reward = base_reward >> 5;
|
||||
|
||||
// (num_ommers, reward)
|
||||
let cases = [
|
||||
(0, base_reward),
|
||||
(1, base_reward + one_thirty_twoth_reward),
|
||||
(2, base_reward + one_thirty_twoth_reward * 2),
|
||||
];
|
||||
|
||||
for (num_ommers, expected_reward) in cases {
|
||||
assert_eq!(block_reward(base_reward, num_ommers), U256::from(expected_reward));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,3 +9,6 @@
|
||||
|
||||
/// Collection of consensus validation methods.
|
||||
pub mod validation;
|
||||
|
||||
/// Various calculation methods (e.g. block rewards)
|
||||
pub mod calc;
|
||||
|
||||
@@ -21,6 +21,7 @@ reth-revm-inspectors = { path = "../revm/revm-inspectors" }
|
||||
reth-rlp = { path = "../rlp" }
|
||||
reth-db = { path = "../storage/db" }
|
||||
reth-provider = { path = "../storage/provider" }
|
||||
reth-consensus-common = { path = "../consensus/common" }
|
||||
|
||||
# revm
|
||||
revm = { version = "3.0.0" }
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::post_state::PostState;
|
||||
use reth_consensus_common::calc;
|
||||
use reth_interfaces::executor::Error;
|
||||
use reth_primitives::{
|
||||
Account, Address, Block, Bloom, Bytecode, ChainSpec, Hardfork, Header, Log, Receipt,
|
||||
@@ -6,7 +7,6 @@ use reth_primitives::{
|
||||
};
|
||||
use reth_provider::{BlockExecutor, StateProvider};
|
||||
use reth_revm::{
|
||||
config::{WEI_2ETH, WEI_3ETH, WEI_5ETH},
|
||||
database::SubState,
|
||||
env::{fill_cfg_and_block_env, fill_tx_env},
|
||||
into_reth_log, to_reth_acc,
|
||||
@@ -216,26 +216,22 @@ where
|
||||
) -> Result<HashMap<Address, U256>, Error> {
|
||||
let mut balance_increments = HashMap::<Address, U256>::default();
|
||||
|
||||
// Collect balance increments for block and uncle rewards.
|
||||
if let Some(reward) = self.get_block_reward(block, td) {
|
||||
// Calculate Uncle reward
|
||||
// OpenEthereum code: https://github.com/openethereum/openethereum/blob/6c2d392d867b058ff867c4373e40850ca3f96969/crates/ethcore/src/ethereum/ethash.rs#L319-L333
|
||||
// Add block rewards if they are enabled.
|
||||
if let Some(base_block_reward) =
|
||||
calc::base_block_reward(&self.chain_spec, block.number, block.difficulty, td)
|
||||
{
|
||||
// Ommer rewards
|
||||
for ommer in block.ommers.iter() {
|
||||
let ommer_reward =
|
||||
U256::from(((8 + ommer.number - block.number) as u128 * reward) >> 3);
|
||||
// From yellowpaper Page 15:
|
||||
// If there are collisions of the beneficiary addresses between ommers and the
|
||||
// block (i.e. two ommers with the same beneficiary address
|
||||
// or an ommer with the same beneficiary address as the
|
||||
// present block), additions are applied cumulatively
|
||||
*balance_increments.entry(ommer.beneficiary).or_default() += ommer_reward;
|
||||
*balance_increments.entry(ommer.beneficiary).or_default() +=
|
||||
calc::ommer_reward(base_block_reward, block.number, ommer.number);
|
||||
}
|
||||
|
||||
// Increment balance for main block reward.
|
||||
let block_reward = U256::from(reward + (reward >> 5) * block.ommers.len() as u128);
|
||||
*balance_increments.entry(block.beneficiary).or_default() += block_reward;
|
||||
// Full block reward
|
||||
*balance_increments.entry(block.beneficiary).or_default() +=
|
||||
calc::block_reward(base_block_reward, block.ommers.len());
|
||||
}
|
||||
|
||||
// Process withdrawals
|
||||
if self.chain_spec.fork(Hardfork::Shanghai).active_at_timestamp(block.timestamp) {
|
||||
if let Some(withdrawals) = block.withdrawals.as_ref() {
|
||||
for withdrawal in withdrawals {
|
||||
@@ -248,29 +244,6 @@ where
|
||||
Ok(balance_increments)
|
||||
}
|
||||
|
||||
/// From yellowpapper Page 15:
|
||||
/// 11.3. Reward Application. The application of rewards to a block involves raising the
|
||||
/// balance of the accounts of the beneficiary address of the block and each ommer by
|
||||
/// a certain amount. We raise the block’s beneficiary account by Rblock; for each
|
||||
/// 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 Ω.
|
||||
///
|
||||
/// NOTE: Related to Ethereum reward change, for other network this is probably going to be
|
||||
/// moved to config.
|
||||
fn get_block_reward(&self, header: &Header, total_difficulty: U256) -> Option<u128> {
|
||||
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)
|
||||
} else if self.chain_spec.fork(Hardfork::Byzantium).active_at_block(header.number) {
|
||||
Some(WEI_3ETH)
|
||||
} else {
|
||||
Some(WEI_5ETH)
|
||||
}
|
||||
}
|
||||
|
||||
/// Irregular state change at Ethereum DAO hardfork
|
||||
fn apply_dao_fork_changes(&mut self, post_state: &mut PostState) -> Result<(), Error> {
|
||||
let db = self.db();
|
||||
@@ -521,9 +494,10 @@ pub fn verify_receipt<'a>(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use reth_consensus_common::calc;
|
||||
use reth_primitives::{
|
||||
hex_literal::hex, keccak256, Account, Address, BlockNumber, Bytecode, Bytes,
|
||||
ChainSpecBuilder, ForkCondition, StorageKey, H256, MAINNET, U256,
|
||||
constants::ETH_TO_WEI, hex_literal::hex, keccak256, Account, Address, BlockNumber,
|
||||
Bytecode, Bytes, ChainSpecBuilder, ForkCondition, StorageKey, H256, MAINNET, U256,
|
||||
};
|
||||
use reth_provider::{
|
||||
post_state::{Change, Storage},
|
||||
@@ -669,7 +643,8 @@ mod tests {
|
||||
"Should executed two transitions (1 tx and 1 block reward)"
|
||||
);
|
||||
|
||||
let block_reward = U256::from(WEI_2ETH + (WEI_2ETH >> 5));
|
||||
let base_block_reward = ETH_TO_WEI * 2;
|
||||
let block_reward = calc::block_reward(base_block_reward, 1);
|
||||
|
||||
let account1_info = Account { balance: U256::ZERO, nonce: 0x00, bytecode_hash: None };
|
||||
let account2_info = Account {
|
||||
@@ -688,8 +663,11 @@ mod tests {
|
||||
nonce: 0x01,
|
||||
bytecode_hash: None,
|
||||
};
|
||||
let ommer_beneficiary_info =
|
||||
Account { nonce: 0, balance: U256::from((8 * WEI_2ETH) >> 3), bytecode_hash: None };
|
||||
let ommer_beneficiary_info = Account {
|
||||
nonce: 0,
|
||||
balance: calc::ommer_reward(base_block_reward, block.number, block.ommers[0].number),
|
||||
bytecode_hash: None,
|
||||
};
|
||||
|
||||
// Check if cache is set
|
||||
// account1
|
||||
|
||||
@@ -18,6 +18,12 @@ pub const EIP1559_ELASTICITY_MULTIPLIER: u64 = 2;
|
||||
/// Multiplier for converting gwei to wei.
|
||||
pub const GWEI_TO_WEI: u64 = 1_000_000_000;
|
||||
|
||||
/// Multiplier for converting finney (milliether) to wei.
|
||||
pub const FINNEY_TO_WEI: u128 = (GWEI_TO_WEI as u128) * 1_000_000;
|
||||
|
||||
/// Multiplier for converting ether to wei.
|
||||
pub const ETH_TO_WEI: u128 = FINNEY_TO_WEI * 1000;
|
||||
|
||||
/// The Ethereum mainnet genesis hash.
|
||||
pub const MAINNET_GENESIS: H256 =
|
||||
H256(hex!("d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"));
|
||||
|
||||
@@ -2,13 +2,6 @@
|
||||
|
||||
use reth_primitives::{ChainSpec, Hardfork, Head};
|
||||
|
||||
/// Two ethereum worth of wei
|
||||
pub const WEI_2ETH: u128 = 2000000000000000000u128;
|
||||
/// Three ethereum worth of wei
|
||||
pub const WEI_3ETH: u128 = 3000000000000000000u128;
|
||||
/// Five ethereum worth of wei
|
||||
pub const WEI_5ETH: u128 = 5000000000000000000u128;
|
||||
|
||||
/// return revm_spec from spec configuration.
|
||||
pub fn revm_spec(chain_spec: &ChainSpec, block: Head) -> revm::primitives::SpecId {
|
||||
if chain_spec.fork(Hardfork::Shanghai).active_at_head(&block) {
|
||||
|
||||
Reference in New Issue
Block a user