feat(ethers-core/block): add gas_target and next_block_base_fee fns a… (#1047)
* 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 599ea45b9e/EIPS/eip-1559.md
?plain=1#L193
This commit is contained in:
parent
745d14ea7b
commit
42ead6252d
|
@ -1,5 +1,7 @@
|
||||||
// Taken from https://github.com/tomusdrw/rust-web3/blob/master/src/types/block.rs
|
// Taken from https://github.com/tomusdrw/rust-web3/blob/master/src/types/block.rs
|
||||||
use crate::types::{Address, Bloom, Bytes, H256, U256, U64};
|
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 serde::{ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
@ -89,6 +91,52 @@ pub struct Block<TX> {
|
||||||
pub epoch_snark_data: Option<EpochSnarkData>,
|
pub epoch_snark_data: Option<EpochSnarkData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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<TX> Block<TX> {
|
||||||
|
/// 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<U256> {
|
||||||
|
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)]
|
#[derive(Debug, Default, Clone, PartialEq, Deserialize, Serialize)]
|
||||||
#[cfg(feature = "celo")]
|
#[cfg(feature = "celo")]
|
||||||
/// Commit-reveal data for generating randomness in the
|
/// Commit-reveal data for generating randomness in the
|
||||||
|
@ -279,6 +327,33 @@ mod tests {
|
||||||
let block: Block<()> = serde_json::from_value(json).unwrap();
|
let block: Block<()> = serde_json::from_value(json).unwrap();
|
||||||
assert_eq!(block.base_fee_per_gas, Some(U256::from(7)));
|
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::<TxHash>::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::<TxHash>::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)]
|
#[cfg(test)]
|
||||||
|
|
Loading…
Reference in New Issue