Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve readability in weight per gas calculation #2075

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion runtime/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@

#![cfg_attr(not(feature = "std"), no_std)]

use frame_support::weights::{constants::WEIGHT_REF_TIME_PER_MILLIS, Weight};
use sp_core::H160;
use sp_runtime::Perbill;

mod apis;
mod impl_moonbeam_xcm_call;
Expand All @@ -25,9 +27,41 @@ mod impl_on_charge_evm_transaction;
mod impl_self_contained_call;
pub mod migrations;

// Here we assume Ethereum's base fee of 21000 gas and convert to weight, but we
// subtract roughly the cost of a balance transfer from it (about 1/3 the cost)
// and some cost to account for per-byte-fee.
// TODO: we should use benchmarking's overhead feature to measure this
pub fn extrinsic_base_weight(weight_per_gas: Weight) -> Weight {
weight_per_gas * 10000
}

/// `WeightPerGas` is an approximate ratio of the amount of Weight per Gas.
/// u64 works for approximations because Weight is a very small unit compared to gas.
///
/// `GAS_PER_MILLIS * WEIGHT_MILLIS_PER_BLOCK * TXN_RATIO ~= BLOCK_GAS_LIMIT`
/// `WEIGHT_PER_GAS = WEIGHT_REF_TIME_PER_MILLIS / GAS_PER_MILLIS
/// = WEIGHT_REF_TIME_PER_MILLIS / (BLOCK_GAS_LIMIT / TXN_RATIO / WEIGHT_MILLIS_PER_BLOCK)
/// = TXN_RATIO * (WEIGHT_REF_TIME_PER_MILLIS * WEIGHT_MILLIS_PER_BLOCK) / BLOCK_GAS_LIMIT`
///
/// For example, given the 500ms Weight, from which 75% only are used for transactions,
/// the total EVM execution gas limit is `GAS_PER_MILLIS * 500 * 75% = BLOCK_GAS_LIMIT`.
pub fn weight_per_gas(
block_gas_limit: u64,
txn_ratio: Perbill,
weight_millis_per_block: u64,
) -> u64 {
let weight_per_block = WEIGHT_REF_TIME_PER_MILLIS.saturating_mul(weight_millis_per_block);
let weight_per_gas = (txn_ratio * weight_per_block).saturating_div(block_gas_limit);
assert!(
weight_per_gas >= 1,
"WeightPerGas must greater than or equal with 1"
);
weight_per_gas
}

//TODO maybe this should be upstreamed into Frontier.

/// And ipmlementation of Frontier's AddressMapping trait for Moonbeam Accounts.
/// And implementation of Frontier's AddressMapping trait for Moonbeam Accounts.
/// This is basically identical to Frontier's own IdentityAddressMapping, but it works for any type
/// that is Into<H160> like AccountId20 for example.
pub struct IntoAddressMapping;
Expand Down
2 changes: 0 additions & 2 deletions runtime/moonbase/src/governance/origins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

#![cfg_attr(not(feature = "std"), no_std)]

//! Custom origins for governance interventions.
pub use custom_origins::*;

Expand Down
42 changes: 18 additions & 24 deletions runtime/moonbase/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ use frame_support::{
OnUnbalanced,
},
weights::{
constants::{RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND},
constants::{RocksDbWeight, WEIGHT_REF_TIME_PER_MILLIS},
ConstantMultiplier, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients,
WeightToFeePolynomial,
},
Expand Down Expand Up @@ -143,9 +143,11 @@ pub mod currency {
}

/// Maximum weight per block
pub const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_ref_time(WEIGHT_REF_TIME_PER_SECOND)
.saturating_div(2)
.set_proof_size(cumulus_primitives_core::relay_chain::v2::MAX_POV_SIZE as u64);
pub const WEIGHT_MILLISECS_PER_BLOCK: u64 = 500;
pub const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts(
WEIGHT_MILLISECS_PER_BLOCK * WEIGHT_REF_TIME_PER_MILLIS,
cumulus_primitives_core::relay_chain::v2::MAX_POV_SIZE as u64,
);

pub const MILLISECS_PER_BLOCK: u64 = 12000;
pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
Expand Down Expand Up @@ -197,18 +199,14 @@ pub fn native_version() -> NativeVersion {

const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
pub const NORMAL_WEIGHT: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_mul(3).saturating_div(4);
// Here we assume Ethereum's base fee of 21000 gas and convert to weight, but we
// subtract roughly the cost of a balance transfer from it (about 1/3 the cost)
// and some cost to account for per-byte-fee.
// TODO: we should use benchmarking's overhead feature to measure this
pub const EXTRINSIC_BASE_WEIGHT: Weight = Weight::from_ref_time(10000 * WEIGHT_PER_GAS);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing this constant means we have to use the 10_000 magic number elsewhere (e.g. in tests below). In addition, extracting this value out of BlockWeights isn't straightforward. I think we should leave it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added the extrinsic_base_weight function and moved it into moonbeam_runtime_common crate.


pub struct RuntimeBlockWeights;
impl Get<frame_system::limits::BlockWeights> for RuntimeBlockWeights {
fn get() -> frame_system::limits::BlockWeights {
frame_system::limits::BlockWeights::builder()
.for_class(DispatchClass::Normal, |weights| {
weights.base_extrinsic = EXTRINSIC_BASE_WEIGHT;
weights.base_extrinsic =
moonbeam_runtime_common::extrinsic_base_weight(WeightPerGas::get());
weights.max_total = NORMAL_WEIGHT.into();
})
.for_class(DispatchClass::Operational, |weights| {
Expand Down Expand Up @@ -370,19 +368,10 @@ impl pallet_ethereum_chain_id::Config for Runtime {}

impl pallet_randomness_collective_flip::Config for Runtime {}

/// Current approximation of the gas/s consumption considering
/// EVM execution over compiled WASM (on 4.4Ghz CPU).
/// Given the 500ms Weight, from which 75% only are used for transactions,
/// the total EVM execution gas limit is: GAS_PER_SECOND * 0.500 * 0.75 ~= 15_000_000.
pub const GAS_PER_SECOND: u64 = 40_000_000;

/// Approximate ratio of the amount of Weight per Gas.
/// u64 works for approximations because Weight is a very small unit compared to gas.
pub const WEIGHT_PER_GAS: u64 = WEIGHT_REF_TIME_PER_SECOND / GAS_PER_SECOND;
Comment on lines -373 to -381
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly, I think these constants are valuable for readability.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pub const BLOCK_GAS_LIMIT: u64 = 15_000_000;

parameter_types! {
pub BlockGasLimit: U256
= U256::from(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT.ref_time() / WEIGHT_PER_GAS);
pub BlockGasLimit: U256 = U256::from(BLOCK_GAS_LIMIT);
/// The portion of the `NORMAL_DISPATCH_RATIO` that we adjust the fees with. Blocks filled less
/// than this will decrease the weight and more will increase.
pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(25);
Expand All @@ -398,7 +387,11 @@ parameter_types! {
/// as a safety net.
pub MaximumMultiplier: Multiplier = Multiplier::from(100_000u128);
pub PrecompilesValue: MoonbasePrecompiles<Runtime> = MoonbasePrecompiles::<_>::new();
pub WeightPerGas: Weight = Weight::from_ref_time(WEIGHT_PER_GAS);
pub WeightPerGas: Weight = Weight::from_ref_time(
moonbeam_runtime_common::weight_per_gas(
BLOCK_GAS_LIMIT, NORMAL_DISPATCH_RATIO, WEIGHT_MILLISECS_PER_BLOCK
)
);
}

pub struct TransactionPaymentAsGasPrice;
Expand All @@ -417,8 +410,9 @@ impl FeeCalculator for TransactionPaymentAsGasPrice {
// This can lead to min_gas_price being same across blocks even if the multiplier changes.
// There's still some precision loss when the final `gas_price` (used_gas * min_gas_price)
// is computed in frontier, but that's currently unavoidable.
let min_gas_price = TransactionPayment::next_fee_multiplier()
.saturating_mul_int(currency::WEIGHT_FEE.saturating_mul(WEIGHT_PER_GAS as u128));
let min_gas_price = TransactionPayment::next_fee_multiplier().saturating_mul_int(
currency::WEIGHT_FEE.saturating_mul(WeightPerGas::get().ref_time() as u128),
);
(
min_gas_price.into(),
<Runtime as frame_system::Config>::DbWeight::get().reads(1),
Expand Down
14 changes: 9 additions & 5 deletions runtime/moonbase/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3008,7 +3008,7 @@ fn precompile_existence() {
#[test]
fn substrate_based_fees_zero_txn_costs_only_base_extrinsic() {
use frame_support::dispatch::{DispatchInfo, Pays};
use moonbase_runtime::{currency, EXTRINSIC_BASE_WEIGHT};
use moonbase_runtime::{currency, WeightPerGas};

ExtBuilder::default().build().execute_with(|| {
let size_bytes = 0;
Expand All @@ -3021,7 +3021,8 @@ fn substrate_based_fees_zero_txn_costs_only_base_extrinsic() {

assert_eq!(
TransactionPayment::compute_fee(size_bytes, &dispatch_info, tip),
EXTRINSIC_BASE_WEIGHT.ref_time() as u128 * currency::WEIGHT_FEE,
moonbeam_runtime_common::extrinsic_base_weight(WeightPerGas::get()).ref_time() as u128
* currency::WEIGHT_FEE,
);
});
}
Expand Down Expand Up @@ -3146,7 +3147,7 @@ mod fee_tests {
};
use moonbase_runtime::{
currency, BlockWeights, FastAdjustingFeeUpdate, LengthToFee, MinimumMultiplier,
TargetBlockFullness, NORMAL_WEIGHT, WEIGHT_PER_GAS,
TargetBlockFullness, WeightPerGas, NORMAL_WEIGHT,
};
use sp_runtime::{FixedPointNumber, Perbill};

Expand Down Expand Up @@ -3242,7 +3243,9 @@ mod fee_tests {
pallet_transaction_payment::NextFeeMultiplier::<Runtime>::set(multiplier);
let actual = TransactionPaymentAsGasPrice::min_gas_price().0;
let expected: U256 = multiplier
.saturating_mul_int(currency::WEIGHT_FEE.saturating_mul(WEIGHT_PER_GAS as u128))
.saturating_mul_int(
currency::WEIGHT_FEE.saturating_mul(WeightPerGas::get().ref_time() as u128),
)
.into();

assert_eq!(expected, actual);
Expand Down Expand Up @@ -3279,7 +3282,8 @@ mod fee_tests {
.unwrap()
.into();
t.execute_with(|| {
let weight_fee_per_gas = currency::WEIGHT_FEE.saturating_mul(WEIGHT_PER_GAS as u128);
let weight_fee_per_gas =
currency::WEIGHT_FEE.saturating_mul(WeightPerGas::get().ref_time() as u128);
let sim = |start_gas_price: u128, fullness: Perbill, num_blocks: u64| -> U256 {
let start_multiplier =
FixedU128::from_rational(start_gas_price, weight_fee_per_gas);
Expand Down
36 changes: 15 additions & 21 deletions runtime/moonbeam/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ use frame_support::{
OffchainWorker, OnFinalize, OnIdle, OnInitialize, OnRuntimeUpgrade, OnUnbalanced,
},
weights::{
constants::{RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND},
constants::{RocksDbWeight, WEIGHT_REF_TIME_PER_MILLIS},
ConstantMultiplier, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients,
WeightToFeePolynomial,
},
Expand Down Expand Up @@ -134,9 +134,11 @@ pub mod currency {
}

/// Maximum weight per block
pub const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_ref_time(WEIGHT_REF_TIME_PER_SECOND)
.saturating_div(2)
.set_proof_size(cumulus_primitives_core::relay_chain::v2::MAX_POV_SIZE as u64);
pub const WEIGHT_MILLISECS_PER_BLOCK: u64 = 500;
pub const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts(
WEIGHT_MILLISECS_PER_BLOCK * WEIGHT_REF_TIME_PER_MILLIS,
cumulus_primitives_core::relay_chain::v2::MAX_POV_SIZE as u64,
);

pub const MILLISECS_PER_BLOCK: u64 = 12000;
pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
Expand Down Expand Up @@ -189,18 +191,14 @@ pub fn native_version() -> NativeVersion {

const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
const NORMAL_WEIGHT: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_mul(3).saturating_div(4);
// Here we assume Ethereum's base fee of 21000 gas and convert to weight, but we
// subtract roughly the cost of a balance transfer from it (about 1/3 the cost)
// and some cost to account for per-byte-fee.
// TODO: we should use benchmarking's overhead feature to measure this
pub const EXTRINSIC_BASE_WEIGHT: Weight = Weight::from_ref_time(10000 * WEIGHT_PER_GAS);

pub struct RuntimeBlockWeights;
impl Get<frame_system::limits::BlockWeights> for RuntimeBlockWeights {
fn get() -> frame_system::limits::BlockWeights {
frame_system::limits::BlockWeights::builder()
.for_class(DispatchClass::Normal, |weights| {
weights.base_extrinsic = EXTRINSIC_BASE_WEIGHT;
weights.base_extrinsic =
moonbeam_runtime_common::extrinsic_base_weight(WeightPerGas::get());
weights.max_total = NORMAL_WEIGHT.into();
})
.for_class(DispatchClass::Operational, |weights| {
Expand Down Expand Up @@ -353,19 +351,11 @@ impl pallet_ethereum_chain_id::Config for Runtime {}

impl pallet_randomness_collective_flip::Config for Runtime {}

/// Current approximation of the gas/s consumption considering
/// EVM execution over compiled WASM (on 4.4Ghz CPU).
/// Given the 500ms Weight, from which 75% only are used for transactions,
/// the total EVM execution gas limit is: GAS_PER_SECOND * 0.500 * 0.75 ~= 15_000_000.
pub const GAS_PER_SECOND: u64 = 40_000_000;

/// Approximate ratio of the amount of Weight per Gas.
/// u64 works for approximations because Weight is a very small unit compared to gas.
pub const WEIGHT_PER_GAS: u64 = WEIGHT_REF_TIME_PER_SECOND / GAS_PER_SECOND;
pub const BLOCK_GAS_LIMIT: u64 = 15_000_000;

parameter_types! {
pub BlockGasLimit: U256
= U256::from(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT.ref_time() / WEIGHT_PER_GAS);
= U256::from(BLOCK_GAS_LIMIT);
/// The portion of the `NORMAL_DISPATCH_RATIO` that we adjust the fees with. Blocks filled less
/// than this will decrease the weight and more will increase.
pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(25);
Expand All @@ -382,7 +372,11 @@ parameter_types! {
/// as a safety net.
pub MaximumMultiplier: Multiplier = Multiplier::from(100_000u128);
pub PrecompilesValue: MoonbeamPrecompiles<Runtime> = MoonbeamPrecompiles::<_>::new();
pub WeightPerGas: Weight = Weight::from_ref_time(WEIGHT_PER_GAS);
pub WeightPerGas: Weight = Weight::from_ref_time(
moonbeam_runtime_common::weight_per_gas(
BLOCK_GAS_LIMIT, NORMAL_DISPATCH_RATIO, WEIGHT_MILLISECS_PER_BLOCK
)
);
}

pub struct FixedGasPrice;
Expand Down
1 change: 0 additions & 1 deletion runtime/moonriver/src/governance/origins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
// GNU General Public License for more details.

//! Custom origins for governance interventions.
#![cfg_attr(not(feature = "std"), no_std)]

pub use custom_origins::*;

Expand Down
43 changes: 19 additions & 24 deletions runtime/moonriver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ use frame_support::{
OffchainWorker, OnFinalize, OnIdle, OnInitialize, OnRuntimeUpgrade, OnUnbalanced,
},
weights::{
constants::{RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND},
constants::{RocksDbWeight, WEIGHT_REF_TIME_PER_MILLIS},
ConstantMultiplier, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients,
WeightToFeePolynomial,
},
Expand Down Expand Up @@ -138,9 +138,12 @@ pub mod currency {
}

/// Maximum weight per block
pub const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_ref_time(WEIGHT_REF_TIME_PER_SECOND)
.saturating_div(2)
.set_proof_size(cumulus_primitives_core::relay_chain::v2::MAX_POV_SIZE as u64);
/// Maximum weight per block
pub const WEIGHT_MILLISECS_PER_BLOCK: u64 = 500;
pub const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts(
WEIGHT_MILLISECS_PER_BLOCK * WEIGHT_REF_TIME_PER_MILLIS,
cumulus_primitives_core::relay_chain::v2::MAX_POV_SIZE as u64,
);

pub const MILLISECS_PER_BLOCK: u64 = 12000;
pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
Expand Down Expand Up @@ -192,18 +195,14 @@ pub fn native_version() -> NativeVersion {

const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
pub const NORMAL_WEIGHT: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_mul(3).saturating_div(4);
// Here we assume Ethereum's base fee of 21000 gas and convert to weight, but we
// subtract roughly the cost of a balance transfer from it (about 1/3 the cost)
// and some cost to account for per-byte-fee.
// TODO: we should use benchmarking's overhead feature to measure this
pub const EXTRINSIC_BASE_WEIGHT: Weight = Weight::from_ref_time(10000 * WEIGHT_PER_GAS);

pub struct RuntimeBlockWeights;
impl Get<frame_system::limits::BlockWeights> for RuntimeBlockWeights {
fn get() -> frame_system::limits::BlockWeights {
frame_system::limits::BlockWeights::builder()
.for_class(DispatchClass::Normal, |weights| {
weights.base_extrinsic = EXTRINSIC_BASE_WEIGHT;
weights.base_extrinsic =
moonbeam_runtime_common::extrinsic_base_weight(WeightPerGas::get());
weights.max_total = NORMAL_WEIGHT.into();
})
.for_class(DispatchClass::Operational, |weights| {
Expand Down Expand Up @@ -356,19 +355,10 @@ impl pallet_ethereum_chain_id::Config for Runtime {}

impl pallet_randomness_collective_flip::Config for Runtime {}

/// Current approximation of the gas/s consumption considering
/// EVM execution over compiled WASM (on 4.4Ghz CPU).
/// Given the 500ms Weight, from which 75% only are used for transactions,
/// the total EVM execution gas limit is: GAS_PER_SECOND * 0.500 * 0.75 ~= 15_000_000.
pub const GAS_PER_SECOND: u64 = 40_000_000;

/// Approximate ratio of the amount of Weight per Gas.
/// u64 works for approximations because Weight is a very small unit compared to gas.
pub const WEIGHT_PER_GAS: u64 = WEIGHT_REF_TIME_PER_SECOND / GAS_PER_SECOND;
pub const BLOCK_GAS_LIMIT: u64 = 15_000_000;

parameter_types! {
pub BlockGasLimit: U256
= U256::from(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT.ref_time() / WEIGHT_PER_GAS);
pub BlockGasLimit: U256 = U256::from(BLOCK_GAS_LIMIT);
/// The portion of the `NORMAL_DISPATCH_RATIO` that we adjust the fees with. Blocks filled less
/// than this will decrease the weight and more will increase.
pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(25);
Expand All @@ -385,7 +375,11 @@ parameter_types! {
/// as a safety net.
pub MaximumMultiplier: Multiplier = Multiplier::from(100_000u128);
pub PrecompilesValue: MoonriverPrecompiles<Runtime> = MoonriverPrecompiles::<_>::new();
pub WeightPerGas: Weight = Weight::from_ref_time(WEIGHT_PER_GAS);
pub WeightPerGas: Weight = Weight::from_ref_time(
moonbeam_runtime_common::weight_per_gas(
BLOCK_GAS_LIMIT, NORMAL_DISPATCH_RATIO, WEIGHT_MILLISECS_PER_BLOCK
)
);
}

pub struct TransactionPaymentAsGasPrice;
Expand All @@ -404,8 +398,9 @@ impl FeeCalculator for TransactionPaymentAsGasPrice {
// This can lead to min_gas_price being same across blocks even if the multiplier changes.
// There's still some precision loss when the final `gas_price` (used_gas * min_gas_price)
// is computed in frontier, but that's currently unavoidable.
let min_gas_price = TransactionPayment::next_fee_multiplier()
.saturating_mul_int(currency::WEIGHT_FEE.saturating_mul(WEIGHT_PER_GAS as u128));
let min_gas_price = TransactionPayment::next_fee_multiplier().saturating_mul_int(
currency::WEIGHT_FEE.saturating_mul(WeightPerGas::get().ref_time() as u128),
);
(
min_gas_price.into(),
<Runtime as frame_system::Config>::DbWeight::get().reads(1),
Expand Down