Skip to content

Commit

Permalink
Documentation & benchmarking code
Browse files Browse the repository at this point in the history
  • Loading branch information
Dinonard committed Sep 25, 2023
1 parent 2984b23 commit de96e49
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 17 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions pallets/dynamic-evm-base-fee/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ parity-scale-codec = { workspace = true }
scale-info = { workspace = true }

# Substrate
frame-benchmarking = { workspace = true, optional = true }
frame-support = { workspace = true }
frame-system = { workspace = true }
pallet-transaction-payment = { workspace = true }
Expand Down Expand Up @@ -41,9 +42,16 @@ std = [
"pallet-transaction-payment/std",
"pallet-balances/std",
"pallet-timestamp/std",
"frame-benchmarking/std",
# Frontier
"fp-evm/std",
]
runtime-benchmarks = [
"frame-benchmarking",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
]
try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
Expand Down
75 changes: 75 additions & 0 deletions pallets/dynamic-evm-base-fee/src/benchmarking.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// This file is part of Astar.

// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later

// Astar is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Astar is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Astar. If not, see <http://www.gnu.org/licenses/>.

use super::*;

use frame_benchmarking::v2::*;
use frame_support::traits::Hooks;
use frame_system::RawOrigin;

#[benchmarks]
mod benchmarks {
use super::*;

#[benchmark]
fn base_fee_per_gas_adjustment() {
let (first_block, second_block) = (T::BlockNumber::from(1u32), T::BlockNumber::from(2u32));
let init_bfpg = BaseFeePerGas::<T>::get();

// Setup actions, should ensure default value is written to storage.
Pallet::<T>::on_initialize(first_block);
Pallet::<T>::on_finalize(first_block);
Pallet::<T>::on_initialize(second_block);

#[block]
{
Pallet::<T>::on_finalize(second_block);
}

// Ensure that the value has changed.
assert!(BaseFeePerGas::<T>::get() != init_bfpg);
}

#[benchmark]
fn set_base_fee_per_gas() {
let old_bfpg = BaseFeePerGas::<T>::get();
let new_bfpg = old_bfpg + 1;

#[extrinsic_call]
_(RawOrigin::Root, new_bfpg);

// Ensure that the value has changed.
assert_eq!(BaseFeePerGas::<T>::get(), new_bfpg);
}

impl_benchmark_test_suite!(
Pallet,
crate::benchmarking::tests::new_test_ext(),
crate::mock::TestRuntime,
);
}

#[cfg(test)]
mod tests {
use crate::mock;
use sp_io::TestExternalities;

pub fn new_test_ext() -> TestExternalities {
mock::ExtBuilder::default().build()
}
}
85 changes: 68 additions & 17 deletions pallets/dynamic-evm-base-fee/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,59 @@
// You should have received a copy of the GNU General Public License
// along with Astar. If not, see <http://www.gnu.org/licenses/>.

//! TODO: Rustdoc!!!
// TODO: remove this comment later
// Max amount that adjustment factor will be able to change on live networks using the new tokenomics will be:
//
// c_n = c_n-1 * (1 + adjustment + adjustment^2/2)
//
// adjustment = v * (s - s*)
//
// Biggest possible adjustment between 2 blocks is: 0.000015 * (1 - 0.25) = 0.000_011_25
// Expressed as ratio: 11_250 / 1_000_000_000.
// This is a much smaller change compared to the max step limit ratio we'll use to limit bfpg adaptation.
// This means that once equilibrium is reached, the `StepLimitRatio` will be larger than the max possible adjustment, essentially eliminating it's effect.
//! Dynamic Evm Base Fee Pallet
//!
//! ## Overview
//!
//! The pallet is responsible for calculating `Base Fee Per Gas` value, according to the current system parameters.
//! This is not like `EIP-1559`, instead it's intended for `Astar` and `Astar-like` networks, which allow both
//! **Substrate native transactions** (which in `Astar` case reuse Polkadot transaction fee approach)
//! and **EVM transactions** (which use `Base Fee Per Gas`).
//!
//! 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).
//!
//! ## Approach
//!
//! The core formula this pallet tries to satisfy is:
//!
//! base_fee_per_gas = adjustment_factor * weight_factor * 25 / 98974
//!
//! Where:
//! * **adjustment_factor** - is a value that changes in-between the blocks, related to the block fill ratio.
//! * **weight_factor** - fixed constant, used to convert consumed _weight_ to _fee_.
//!
//! The implementation doesn't make any hard requirements on these values, and only requires that a type implementing `Get<_>` provides them.
//!
//! ## Implementation
//!
//! The core logic is implemented in `on_finalize` hook, which is called at the end of each block.
//! This pallet's hook should be called AFTER whicever pallet's hook is responsible for updating **adjustment factor**.
//!
//! The hook will calculate the ideal new `base_fee_per_gas` value, and then clamp it in between the allowed limits.
//!
//! ## Interface
//!
//! Pallet provides an implementation of `FeeCalculator` trait. This makes it usable directly in `pallet-evm`.
//!
//! A _root-only_ extrinsic is provided to allow setting the `base_fee_per_gas` value manually.
//!
//! ## Practical Remarks
//!
//! According to the proposed **Tokenomics 2.0**, max amount that adjustment factor will be able to change on live networks in-between blocks is:
//!
//! adjustment_new = adjustment_old * (1 + adj + adj^2/2)
//!
//! adj = v * (s - s*)
//! --> recommended _v_ value: 0.000_015
//! --> larges 's' delta: (1 - 0.25) = **0.75**
//!
//! adj = 0.000015 * (1 - 0.25) = **0.000_011_25**
//! (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**
//!
//! Discarding the **1**, and only considering the decimals, this can be expressed as ratio:
//! Expressed as ratio: 11_250_063_281 / 1_000_000_000_000_000.
//! This is a much smaller change compared to the max step limit ratio we'll use to limit bfpg alignment.
//! 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.
#![cfg_attr(not(feature = "std"), no_std)]

Expand All @@ -43,6 +83,15 @@ mod mock;
#[cfg(test)]
mod tests;

#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;

// TODO: remove this after proper benchmarking!
pub trait WeightInfo {
fn base_fee_per_gas_adjustment() -> Weight;
fn set_base_fee_per_gas() -> Weight;
}

#[frame_support::pallet]
pub mod pallet {
use frame_support::pallet_prelude::*;
Expand Down Expand Up @@ -71,6 +120,8 @@ pub mod pallet {
/// It's expressed as percentage, and used to calculate the delta between the old and new value.
/// 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.
type StepLimitRatio: Get<Perquintill>;
/// Weight information for extrinsics & functions of this pallet.
type WeightInfo: WeightInfo;
}

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

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

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

0 comments on commit de96e49

Please sign in to comment.