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_primitives::{BlockNumber, U256};
use reth_chainspec::{EthereumHardfork, Hardforks};
use reth_primitives::constants::ETH_TO_WEI;

/// 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 reth_primitives::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);
        }
    }
}