Skip to content

Commit de96e49

Browse files
committed
Documentation & benchmarking code
1 parent 2984b23 commit de96e49

File tree

4 files changed

+152
-17
lines changed

4 files changed

+152
-17
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pallets/dynamic-evm-base-fee/Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ parity-scale-codec = { workspace = true }
1313
scale-info = { workspace = true }
1414

1515
# Substrate
16+
frame-benchmarking = { workspace = true, optional = true }
1617
frame-support = { workspace = true }
1718
frame-system = { workspace = true }
1819
pallet-transaction-payment = { workspace = true }
@@ -41,9 +42,16 @@ std = [
4142
"pallet-transaction-payment/std",
4243
"pallet-balances/std",
4344
"pallet-timestamp/std",
45+
"frame-benchmarking/std",
4446
# Frontier
4547
"fp-evm/std",
4648
]
49+
runtime-benchmarks = [
50+
"frame-benchmarking",
51+
"frame-support/runtime-benchmarks",
52+
"frame-system/runtime-benchmarks",
53+
"sp-runtime/runtime-benchmarks",
54+
]
4755
try-runtime = [
4856
"frame-support/try-runtime",
4957
"frame-system/try-runtime",
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// This file is part of Astar.
2+
3+
// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd.
4+
// SPDX-License-Identifier: GPL-3.0-or-later
5+
6+
// Astar is free software: you can redistribute it and/or modify
7+
// it under the terms of the GNU General Public License as published by
8+
// the Free Software Foundation, either version 3 of the License, or
9+
// (at your option) any later version.
10+
11+
// Astar is distributed in the hope that it will be useful,
12+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
// GNU General Public License for more details.
15+
16+
// You should have received a copy of the GNU General Public License
17+
// along with Astar. If not, see <http://www.gnu.org/licenses/>.
18+
19+
use super::*;
20+
21+
use frame_benchmarking::v2::*;
22+
use frame_support::traits::Hooks;
23+
use frame_system::RawOrigin;
24+
25+
#[benchmarks]
26+
mod benchmarks {
27+
use super::*;
28+
29+
#[benchmark]
30+
fn base_fee_per_gas_adjustment() {
31+
let (first_block, second_block) = (T::BlockNumber::from(1u32), T::BlockNumber::from(2u32));
32+
let init_bfpg = BaseFeePerGas::<T>::get();
33+
34+
// Setup actions, should ensure default value is written to storage.
35+
Pallet::<T>::on_initialize(first_block);
36+
Pallet::<T>::on_finalize(first_block);
37+
Pallet::<T>::on_initialize(second_block);
38+
39+
#[block]
40+
{
41+
Pallet::<T>::on_finalize(second_block);
42+
}
43+
44+
// Ensure that the value has changed.
45+
assert!(BaseFeePerGas::<T>::get() != init_bfpg);
46+
}
47+
48+
#[benchmark]
49+
fn set_base_fee_per_gas() {
50+
let old_bfpg = BaseFeePerGas::<T>::get();
51+
let new_bfpg = old_bfpg + 1;
52+
53+
#[extrinsic_call]
54+
_(RawOrigin::Root, new_bfpg);
55+
56+
// Ensure that the value has changed.
57+
assert_eq!(BaseFeePerGas::<T>::get(), new_bfpg);
58+
}
59+
60+
impl_benchmark_test_suite!(
61+
Pallet,
62+
crate::benchmarking::tests::new_test_ext(),
63+
crate::mock::TestRuntime,
64+
);
65+
}
66+
67+
#[cfg(test)]
68+
mod tests {
69+
use crate::mock;
70+
use sp_io::TestExternalities;
71+
72+
pub fn new_test_ext() -> TestExternalities {
73+
mock::ExtBuilder::default().build()
74+
}
75+
}

pallets/dynamic-evm-base-fee/src/lib.rs

Lines changed: 68 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,59 @@
1616
// You should have received a copy of the GNU General Public License
1717
// along with Astar. If not, see <http://www.gnu.org/licenses/>.
1818

19-
//! TODO: Rustdoc!!!
20-
21-
// TODO: remove this comment later
22-
// Max amount that adjustment factor will be able to change on live networks using the new tokenomics will be:
23-
//
24-
// c_n = c_n-1 * (1 + adjustment + adjustment^2/2)
25-
//
26-
// adjustment = v * (s - s*)
27-
//
28-
// Biggest possible adjustment between 2 blocks is: 0.000015 * (1 - 0.25) = 0.000_011_25
29-
// Expressed as ratio: 11_250 / 1_000_000_000.
30-
// This is a much smaller change compared to the max step limit ratio we'll use to limit bfpg adaptation.
31-
// This means that once equilibrium is reached, the `StepLimitRatio` will be larger than the max possible adjustment, essentially eliminating it's effect.
19+
//! Dynamic Evm Base Fee Pallet
20+
//!
21+
//! ## Overview
22+
//!
23+
//! The pallet is responsible for calculating `Base Fee Per Gas` value, according to the current system parameters.
24+
//! This is not like `EIP-1559`, instead it's intended for `Astar` and `Astar-like` networks, which allow both
25+
//! **Substrate native transactions** (which in `Astar` case reuse Polkadot transaction fee approach)
26+
//! and **EVM transactions** (which use `Base Fee Per Gas`).
27+
//!
28+
//! For a more detailed description, reader is advised to refer to Astar Network forum post about [Tokenomics 2.0](https://forum.astar.network/t/astar-tokenomics-2-0-a-dynamically-adjusted-inflation/4924).
29+
//!
30+
//! ## Approach
31+
//!
32+
//! The core formula this pallet tries to satisfy is:
33+
//!
34+
//! base_fee_per_gas = adjustment_factor * weight_factor * 25 / 98974
35+
//!
36+
//! Where:
37+
//! * **adjustment_factor** - is a value that changes in-between the blocks, related to the block fill ratio.
38+
//! * **weight_factor** - fixed constant, used to convert consumed _weight_ to _fee_.
39+
//!
40+
//! The implementation doesn't make any hard requirements on these values, and only requires that a type implementing `Get<_>` provides them.
41+
//!
42+
//! ## Implementation
43+
//!
44+
//! The core logic is implemented in `on_finalize` hook, which is called at the end of each block.
45+
//! This pallet's hook should be called AFTER whicever pallet's hook is responsible for updating **adjustment factor**.
46+
//!
47+
//! The hook will calculate the ideal new `base_fee_per_gas` value, and then clamp it in between the allowed limits.
48+
//!
49+
//! ## Interface
50+
//!
51+
//! Pallet provides an implementation of `FeeCalculator` trait. This makes it usable directly in `pallet-evm`.
52+
//!
53+
//! A _root-only_ extrinsic is provided to allow setting the `base_fee_per_gas` value manually.
54+
//!
55+
//! ## Practical Remarks
56+
//!
57+
//! According to the proposed **Tokenomics 2.0**, max amount that adjustment factor will be able to change on live networks in-between blocks is:
58+
//!
59+
//! adjustment_new = adjustment_old * (1 + adj + adj^2/2)
60+
//!
61+
//! adj = v * (s - s*)
62+
//! --> recommended _v_ value: 0.000_015
63+
//! --> larges 's' delta: (1 - 0.25) = **0.75**
64+
//!
65+
//! adj = 0.000015 * (1 - 0.25) = **0.000_011_25**
66+
//! (1 + 0.000_011_25 + 0.000_011_25^2/2) = (1 + 0.000_011_25 + 0.000_000_000_063_281) = **1,000_011_250_063_281**
67+
//!
68+
//! Discarding the **1**, and only considering the decimals, this can be expressed as ratio:
69+
//! Expressed as ratio: 11_250_063_281 / 1_000_000_000_000_000.
70+
//! This is a much smaller change compared to the max step limit ratio we'll use to limit bfpg alignment.
71+
//! This means that once equilibrium is reached (fees are aligned), the `StepLimitRatio` will be larger than the max possible adjustment, essentially eliminating it's effect.
3272
3373
#![cfg_attr(not(feature = "std"), no_std)]
3474

@@ -43,6 +83,15 @@ mod mock;
4383
#[cfg(test)]
4484
mod tests;
4585

86+
#[cfg(feature = "runtime-benchmarks")]
87+
mod benchmarking;
88+
89+
// TODO: remove this after proper benchmarking!
90+
pub trait WeightInfo {
91+
fn base_fee_per_gas_adjustment() -> Weight;
92+
fn set_base_fee_per_gas() -> Weight;
93+
}
94+
4695
#[frame_support::pallet]
4796
pub mod pallet {
4897
use frame_support::pallet_prelude::*;
@@ -71,6 +120,8 @@ pub mod pallet {
71120
/// It's expressed as percentage, and used to calculate the delta between the old and new value.
72121
/// E.g. if the current 'base fee per gas' is 100, and the limit is 10%, then the new base fee per gas can be between 90 and 110.
73122
type StepLimitRatio: Get<Perquintill>;
123+
/// Weight information for extrinsics & functions of this pallet.
124+
type WeightInfo: WeightInfo;
74125
}
75126

76127
#[pallet::type_value]
@@ -97,9 +148,7 @@ pub mod pallet {
97148
#[pallet::hooks]
98149
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
99150
fn on_initialize(_: T::BlockNumber) -> Weight {
100-
// TODO: benchmark this!
101-
let db_weight = <T as frame_system::Config>::DbWeight::get();
102-
db_weight.reads_writes(2, 1)
151+
T::WeightInfo::base_fee_per_gas_adjustment()
103152
}
104153

105154
fn on_finalize(_n: <T as frame_system::Config>::BlockNumber) {
@@ -160,8 +209,10 @@ pub mod pallet {
160209

161210
#[pallet::call]
162211
impl<T: Config> Pallet<T> {
212+
/// `root-only` extrinsic to set the `base_fee_per_gas` value manually.
213+
/// The specified value has to respect min & max limits configured in the runtime.
163214
#[pallet::call_index(0)]
164-
#[pallet::weight(10_000 + T::DbWeight::get().writes(1).ref_time())] // TODO: weight!
215+
#[pallet::weight(T::WeightInfo::set_base_fee_per_gas())]
165216
pub fn set_base_fee_per_gas(origin: OriginFor<T>, fee: U256) -> DispatchResult {
166217
ensure_root(origin)?;
167218
ensure!(

0 commit comments

Comments
 (0)