Files
reth/crates/consensus/common/src/calc.rs
2024-07-05 10:38:58 +00:00

153 lines
5.0 KiB
Rust

use reth_chainspec::{ChainSpec, EthereumHardfork};
use reth_primitives::{constants::ETH_TO_WEI, BlockNumber, 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(EthereumHardfork::Paris).active_at_ttd(total_difficulty, block_difficulty) {
None
} else {
Some(base_block_reward_pre_merge(chain_spec, block_number))
}
}
/// Calculates the base block reward __before__ the merge (Paris hardfork).
///
/// Caution: The caller must ensure that the block number is before the merge.
pub fn base_block_reward_pre_merge(chain_spec: &ChainSpec, block_number: BlockNumber) -> u128 {
if chain_spec.fork(EthereumHardfork::Constantinople).active_at_block(block_number) {
ETH_TO_WEI * 2
} else if chain_spec.fork(EthereumHardfork::Byzantium).active_at_block(block_number) {
ETH_TO_WEI * 3
} else {
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_chainspec::MAINNET;
/// # use reth_consensus_common::calc::{base_block_reward, block_reward};
/// # use reth_primitives::constants::ETH_TO_WEI;
/// # use reth_primitives::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(), 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 const fn block_reward(base_block_reward: u128, ommers: usize) -> u128 {
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 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.
///
/// # 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 const fn ommer_reward(
base_block_reward: u128,
block_number: BlockNumber,
ommer_block_number: BlockNumber,
) -> u128 {
((8 + ommer_block_number - block_number) as u128 * base_block_reward) >> 3
}
#[cfg(test)]
mod tests {
use super::*;
use reth_chainspec::MAINNET;
#[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;
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), expected_reward);
}
}
}