reth_consensus_common/calc.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
use alloy_consensus::constants::ETH_TO_WEI;
use alloy_primitives::{BlockNumber, U256};
use reth_chainspec::{EthereumHardfork, Hardforks};
/// 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: impl Hardforks,
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: impl Hardforks, 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 alloy_consensus::constants::ETH_TO_WEI;
/// # use alloy_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);
}
}
}