From 42ead6252d6536956c7193ca6e2a8e69b5a55a2a Mon Sep 17 00:00:00 2001 From: Meet Mangukiya Date: Thu, 17 Mar 2022 16:14:28 +0530 Subject: [PATCH] =?UTF-8?q?feat(ethers-core/block):=20add=20gas=5Ftarget?= =?UTF-8?q?=20and=20next=5Fblock=5Fbase=5Ffee=20fns=20a=E2=80=A6=20(#1047)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(ethers-core/block): add gas_target and next_block_base_fee fns according to EIP-1559 * fix: feature flag gas_target, and next_block_base_fee to !celo, address review comments * fix: in decreasing base fee case max(delta, 1) is not used Refer https://github.com/ethereum/EIPs/blob/599ea45b9e70f8075e7f867af1c274e316ece583/EIPS/eip-1559.md?plain=1#L193 --- ethers-core/src/types/block.rs | 75 ++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/ethers-core/src/types/block.rs b/ethers-core/src/types/block.rs index 61c266fc..a0ef2b5a 100644 --- a/ethers-core/src/types/block.rs +++ b/ethers-core/src/types/block.rs @@ -1,5 +1,7 @@ // Taken from https://github.com/tomusdrw/rust-web3/blob/master/src/types/block.rs use crate::types::{Address, Bloom, Bytes, H256, U256, U64}; +#[cfg(not(feature = "celo"))] +use core::cmp::Ordering; use serde::{ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer}; use std::str::FromStr; @@ -89,6 +91,52 @@ pub struct Block { pub epoch_snark_data: Option, } +// ref https://eips.ethereum.org/EIPS/eip-1559 +#[cfg(not(feature = "celo"))] +pub const ELASTICITY_MULTIPLIER: U256 = U256([2u64, 0, 0, 0]); +// max base fee delta is 12.5% +#[cfg(not(feature = "celo"))] +pub const BASE_FEE_MAX_CHANGE_DENOMINATOR: U256 = U256([8u64, 0, 0, 0]); + +impl Block { + /// The target gas usage as per EIP-1559 + #[cfg(not(feature = "celo"))] + pub fn gas_target(&self) -> U256 { + self.gas_limit / ELASTICITY_MULTIPLIER + } + + /// The next block's base fee, it is a function of parent block's base fee and gas usage. + /// Reference: https://eips.ethereum.org/EIPS/eip-1559 + #[cfg(not(feature = "celo"))] + pub fn next_block_base_fee(&self) -> Option { + let target_usage = self.gas_target(); + let base_fee_per_gas = self.base_fee_per_gas?; + + match self.gas_used.cmp(&target_usage) { + Ordering::Greater => { + let gas_used_delta = self.gas_used - self.gas_target(); + let base_fee_per_gas_delta = U256::max( + base_fee_per_gas * gas_used_delta / + target_usage / + BASE_FEE_MAX_CHANGE_DENOMINATOR, + U256::from(1u32), + ); + let expected_base_fee_per_gas = base_fee_per_gas + base_fee_per_gas_delta; + Some(expected_base_fee_per_gas) + } + Ordering::Less => { + let gas_used_delta = self.gas_target() - self.gas_used; + let base_fee_per_gas_delta = base_fee_per_gas * gas_used_delta / + target_usage / + BASE_FEE_MAX_CHANGE_DENOMINATOR; + let expected_base_fee_per_gas = base_fee_per_gas - base_fee_per_gas_delta; + Some(expected_base_fee_per_gas) + } + Ordering::Equal => self.base_fee_per_gas, + } + } +} + #[derive(Debug, Default, Clone, PartialEq, Deserialize, Serialize)] #[cfg(feature = "celo")] /// Commit-reveal data for generating randomness in the @@ -279,6 +327,33 @@ mod tests { let block: Block<()> = serde_json::from_value(json).unwrap(); assert_eq!(block.base_fee_per_gas, Some(U256::from(7))); } + + #[test] + fn test_next_block_base_fee() { + // https://etherscan.io/block/14402566 + let mut block_14402566 = Block::::default(); + block_14402566.number = Some(U64::from(14402566u64)); + block_14402566.base_fee_per_gas = Some(U256::from(36_803_013_756u128)); + block_14402566.gas_limit = U256::from(30_087_887u128); + block_14402566.gas_used = U256::from(2_023_848u128); + + assert_eq!(block_14402566.base_fee_per_gas, Some(U256::from(36_803_013_756u128))); + assert_eq!(block_14402566.gas_target(), U256::from(15_043_943u128)); + // next block decreasing base fee https://etherscan.io/block/14402567 + assert_eq!(block_14402566.next_block_base_fee(), Some(U256::from(32_821_521_542u128))); + + // https://etherscan.io/block/14402712 + let mut block_14402712 = Block::::default(); + block_14402712.number = Some(U64::from(14402712u64)); + block_14402712.base_fee_per_gas = Some(U256::from(24_870_031_149u128)); + block_14402712.gas_limit = U256::from(30_000_000u128); + block_14402712.gas_used = U256::from(29_999_374u128); + + assert_eq!(block_14402712.base_fee_per_gas, Some(U256::from(24_870_031_149u128))); + assert_eq!(block_14402712.gas_target(), U256::from(15_000_000u128)); + // next block increasing base fee https://etherscan.io/block/14402713 + assert_eq!(block_14402712.next_block_base_fee(), Some(U256::from(27_978_655_303u128))); + } } #[cfg(test)]