diff --git a/Cargo.lock b/Cargo.lock index 2733a0754fb..df68abadce6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -847,7 +847,7 @@ dependencies = [ "bp-runtime", "frame-support", "parity-scale-codec", - "smallvec 1.7.0", + "smallvec 1.8.0", "sp-api", "sp-runtime", "sp-std", @@ -1289,7 +1289,7 @@ dependencies = [ "gimli", "log", "regalloc", - "smallvec 1.7.0", + "smallvec 1.8.0", "target-lexicon", ] @@ -1326,7 +1326,7 @@ checksum = "e07339bd461766deb7605169de039e01954768ff730fa1254e149001884a8525" dependencies = [ "cranelift-codegen", "log", - "smallvec 1.7.0", + "smallvec 1.8.0", "target-lexicon", ] @@ -1352,7 +1352,7 @@ dependencies = [ "cranelift-frontend", "itertools", "log", - "smallvec 1.7.0", + "smallvec 1.8.0", "wasmparser", "wasmtime-types", ] @@ -2791,7 +2791,7 @@ dependencies = [ "paste", "scale-info", "serde", - "smallvec 1.7.0", + "smallvec 1.8.0", "sp-arithmetic", "sp-core", "sp-core-hashing-proc-macro", @@ -4024,7 +4024,7 @@ dependencies = [ "scale-info", "serde", "serde_derive", - "smallvec 1.7.0", + "smallvec 1.8.0", "sp-api", "sp-arithmetic", "sp-authority-discovery", @@ -4064,7 +4064,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45a3f58dc069ec0e205a27f5b45920722a46faed802a0541538241af6228f512" dependencies = [ "parity-util-mem", - "smallvec 1.7.0", + "smallvec 1.8.0", ] [[package]] @@ -4093,7 +4093,7 @@ dependencies = [ "parking_lot 0.11.1", "regex", "rocksdb", - "smallvec 1.7.0", + "smallvec 1.8.0", ] [[package]] @@ -4180,7 +4180,7 @@ dependencies = [ "multiaddr", "parking_lot 0.11.1", "pin-project 1.0.8", - "smallvec 1.7.0", + "smallvec 1.8.0", "wasm-timer", ] @@ -4211,7 +4211,7 @@ dependencies = [ "ring", "rw-stream-sink", "sha2 0.9.8", - "smallvec 1.7.0", + "smallvec 1.8.0", "thiserror", "unsigned-varint 0.7.0", "void", @@ -4239,7 +4239,7 @@ dependencies = [ "futures 0.3.17", "libp2p-core", "log", - "smallvec 1.7.0", + "smallvec 1.8.0", "trust-dns-resolver", ] @@ -4258,7 +4258,7 @@ dependencies = [ "prost", "prost-build", "rand 0.7.3", - "smallvec 1.7.0", + "smallvec 1.8.0", ] [[package]] @@ -4282,7 +4282,7 @@ dependencies = [ "rand 0.7.3", "regex", "sha2 0.9.8", - "smallvec 1.7.0", + "smallvec 1.8.0", "unsigned-varint 0.7.0", "wasm-timer", ] @@ -4300,7 +4300,7 @@ dependencies = [ "lru 0.6.6", "prost", "prost-build", - "smallvec 1.7.0", + "smallvec 1.8.0", "wasm-timer", ] @@ -4323,7 +4323,7 @@ dependencies = [ "prost-build", "rand 0.7.3", "sha2 0.9.8", - "smallvec 1.7.0", + "smallvec 1.8.0", "uint", "unsigned-varint 0.7.0", "void", @@ -4346,7 +4346,7 @@ dependencies = [ "libp2p-swarm", "log", "rand 0.8.4", - "smallvec 1.7.0", + "smallvec 1.8.0", "socket2 0.4.0", "void", ] @@ -4379,7 +4379,7 @@ dependencies = [ "nohash-hasher", "parking_lot 0.11.1", "rand 0.7.3", - "smallvec 1.7.0", + "smallvec 1.8.0", "unsigned-varint 0.7.0", ] @@ -4468,7 +4468,7 @@ dependencies = [ "prost", "prost-build", "rand 0.7.3", - "smallvec 1.7.0", + "smallvec 1.8.0", "unsigned-varint 0.7.0", "void", "wasm-timer", @@ -4510,7 +4510,7 @@ dependencies = [ "log", "lru 0.7.0", "rand 0.7.3", - "smallvec 1.7.0", + "smallvec 1.8.0", "unsigned-varint 0.7.0", "wasm-timer", ] @@ -4526,7 +4526,7 @@ dependencies = [ "libp2p-core", "log", "rand 0.7.3", - "smallvec 1.7.0", + "smallvec 1.8.0", "void", "wasm-timer", ] @@ -5214,6 +5214,7 @@ dependencies = [ "serde", "sha3 0.8.2", "sha3 0.9.1", + "smallvec 1.8.0", "sp-api", "sp-block-builder", "sp-core", @@ -5985,7 +5986,7 @@ dependencies = [ "futures 0.3.17", "log", "pin-project 1.0.8", - "smallvec 1.7.0", + "smallvec 1.8.0", "unsigned-varint 0.7.0", ] @@ -7536,7 +7537,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "smallvec 1.7.0", + "smallvec 1.8.0", "sp-core", "sp-io", "sp-runtime", @@ -7773,7 +7774,7 @@ dependencies = [ "parity-util-mem-derive", "parking_lot 0.11.1", "primitive-types", - "smallvec 1.7.0", + "smallvec 1.8.0", "winapi 0.3.9", ] @@ -7907,7 +7908,7 @@ dependencies = [ "cloudabi", "libc", "redox_syscall 0.1.57", - "smallvec 1.7.0", + "smallvec 1.8.0", "winapi 0.3.9", ] @@ -7921,7 +7922,7 @@ dependencies = [ "instant", "libc", "redox_syscall 0.2.9", - "smallvec 1.7.0", + "smallvec 1.8.0", "winapi 0.3.9", ] @@ -8732,7 +8733,7 @@ dependencies = [ "polkadot-primitives", "polkadot-statement-table", "sc-network", - "smallvec 1.7.0", + "smallvec 1.8.0", "substrate-prometheus-endpoint", "thiserror", ] @@ -8944,7 +8945,7 @@ dependencies = [ "scale-info", "serde", "serde_derive", - "smallvec 1.7.0", + "smallvec 1.8.0", "sp-api", "sp-authority-discovery", "sp-block-builder", @@ -9845,7 +9846,7 @@ checksum = "a6304468554ed921da3d32c355ea107b8d13d7b8996c3adfb7aab48d3bc321f4" dependencies = [ "log", "rustc-hash", - "smallvec 1.7.0", + "smallvec 1.8.0", ] [[package]] @@ -10065,7 +10066,7 @@ dependencies = [ "scale-info", "serde", "serde_derive", - "smallvec 1.7.0", + "smallvec 1.8.0", "sp-api", "sp-authority-discovery", "sp-block-builder", @@ -10828,7 +10829,7 @@ dependencies = [ "sc-utils", "serde", "serde_json", - "smallvec 1.7.0", + "smallvec 1.8.0", "sp-arithmetic", "sp-blockchain", "sp-consensus", @@ -11586,9 +11587,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" [[package]] name = "smol" @@ -12211,7 +12212,7 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.11.1", "rand 0.7.3", - "smallvec 1.7.0", + "smallvec 1.8.0", "sp-core", "sp-externalities", "sp-panic-handler", @@ -13049,7 +13050,7 @@ dependencies = [ "serde", "serde_json", "sharded-slab", - "smallvec 1.7.0", + "smallvec 1.8.0", "thread_local", "tracing", "tracing-core", @@ -13073,7 +13074,7 @@ dependencies = [ "hashbrown", "log", "rustc-hex", - "smallvec 1.7.0", + "smallvec 1.8.0", ] [[package]] @@ -13122,7 +13123,7 @@ dependencies = [ "lazy_static", "log", "rand 0.8.4", - "smallvec 1.7.0", + "smallvec 1.8.0", "thiserror", "tinyvec", "url 2.2.2", @@ -13142,7 +13143,7 @@ dependencies = [ "lru-cache", "parking_lot 0.11.1", "resolv-conf", - "smallvec 1.7.0", + "smallvec 1.8.0", "thiserror", "trust-dns-proto", ] @@ -13819,7 +13820,7 @@ dependencies = [ "scale-info", "serde", "serde_derive", - "smallvec 1.7.0", + "smallvec 1.8.0", "sp-api", "sp-authority-discovery", "sp-block-builder", diff --git a/runtime/moonbase/Cargo.toml b/runtime/moonbase/Cargo.toml index aa0c3b8d4a0..b61db6d1ef6 100644 --- a/runtime/moonbase/Cargo.toml +++ b/runtime/moonbase/Cargo.toml @@ -13,6 +13,7 @@ log = "0.4" rlp = { version = "0.5", optional = true, default-features = false } serde = { version = "1.0.101", optional = true, default-features = false, features = [ "derive" ] } sha3 = { version = "0.8", optional = true, default-features = false } +smallvec = "1.8.0" # Moonbeam account = { path = "../../primitives/account/", default-features = false } diff --git a/runtime/moonbase/src/lib.rs b/runtime/moonbase/src/lib.rs index a03480feffb..ac21609dc4a 100644 --- a/runtime/moonbase/src/lib.rs +++ b/runtime/moonbase/src/lib.rs @@ -44,7 +44,8 @@ use frame_support::{ }, weights::{ constants::{RocksDbWeight, WEIGHT_PER_SECOND}, - DispatchClass, GetDispatchInfo, IdentityFee, Weight, + DispatchClass, GetDispatchInfo, IdentityFee, Weight, WeightToFeeCoefficient, + WeightToFeeCoefficients, WeightToFeePolynomial, }, PalletId, }; @@ -60,7 +61,7 @@ use xcm_builder::{ use xcm_executor::traits::JustTry; -use frame_system::{EnsureOneOf, EnsureRoot, EnsureSigned}; +use frame_system::{limits::BlockWeights, EnsureOneOf, EnsureRoot, EnsureSigned}; pub use moonbeam_core_primitives::{ AccountId, AccountIndex, Address, AssetId, Balance, BlockNumber, DigestItem, Hash, Header, Index, Signature, @@ -101,6 +102,8 @@ use xcm::latest::prelude::*; use nimbus_primitives::{CanAuthor, NimbusId}; +use smallvec::smallvec; + mod precompiles; use precompiles::{MoonbasePrecompiles, ASSET_PRECOMPILE_ADDRESS_PREFIX}; @@ -130,8 +133,12 @@ pub mod currency { pub const UNIT: Balance = 1_000_000_000_000_000_000; pub const KILOUNIT: Balance = 1_000_000_000_000_000_000_000; - pub const TRANSACTION_BYTE_FEE: Balance = 10 * MICROUNIT * SUPPLY_FACTOR; + // NOTE: Kusama sets this to 40000 (their supply is 10^10*12 though) + // Ethereum charges 4 or 16 (right?) gas per byte (0 byte or non-zero byte) + // An avg of this is 10. + pub const TRANSACTION_BYTE_FEE: Balance = 10 * GIGAWEI * SUPPLY_FACTOR; pub const STORAGE_BYTE_FEE: Balance = 100 * MICROUNIT * SUPPLY_FACTOR; + pub const WEIGHT_FEE: Balance = 50 * KILOWEI * SUPPLY_FACTOR; pub const fn deposit(items: u32, bytes: u32) -> Balance { items as Balance * 1 * UNIT * SUPPLY_FACTOR + (bytes as Balance) * STORAGE_BYTE_FEE @@ -188,14 +195,33 @@ pub fn native_version() -> NativeVersion { } const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); +const NORMAL_WEIGHT: Weight = MAXIMUM_BLOCK_WEIGHT * 3 / 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. +pub const EXTRINSIC_BASE_WEIGHT: Weight = 10000 * WEIGHT_PER_GAS; + +pub struct RuntimeBlockWeights; +impl Get for RuntimeBlockWeights { + fn get() -> BlockWeights { + BlockWeights::builder() + .for_class(DispatchClass::Normal, |weights| { + weights.base_extrinsic = EXTRINSIC_BASE_WEIGHT; + weights.max_total = NORMAL_WEIGHT.into(); + }) + .for_class(DispatchClass::Operational, |weights| { + weights.max_total = MAXIMUM_BLOCK_WEIGHT.into(); + weights.reserved = (MAXIMUM_BLOCK_WEIGHT - NORMAL_WEIGHT).into(); + }) + .avg_block_initialization(Perbill::from_percent(10)) + .build() + .expect("Should work") + } +} parameter_types! { pub const BlockHashCount: BlockNumber = 256; pub const Version: RuntimeVersion = VERSION; - /// We allow for one half second of compute with a 6 second average block time. - /// These values are dictated by Polkadot for the parachain. - pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights - ::with_sensible_defaults(MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO); /// We allow for 5 MB blocks. pub BlockLength: frame_system::limits::BlockLength = frame_system::limits::BlockLength ::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); @@ -226,7 +252,7 @@ impl frame_system::Config for Runtime { /// Maximum number of block number to block hash mappings to keep (oldest pruned first). type BlockHashCount = BlockHashCount; /// Maximum weight of each block. With a default weight system of 1byte == 1weight, 4mb is ok. - type BlockWeights = BlockWeights; + type BlockWeights = RuntimeBlockWeights; /// Maximum size of all encoded transactions (in bytes) that are allowed in one block. type BlockLength = BlockLength; /// Runtime version. @@ -314,11 +340,33 @@ parameter_types! { pub OperationalFeeMultiplier: u8 = 5; } +pub struct WeightToFee; +impl WeightToFeePolynomial for WeightToFee { + type Balance = Balance; + + /// Return a vec of coefficients. Here we just use one coefficient and reduce it to a constant + /// modifier in order to closely match Ethereum-based fees. + /// + /// Calculation, per the documentation in `frame_support`: + /// + /// ```ignore + /// coeff_integer * x^(degree) + coeff_frac * x^(degree) + /// ``` + fn polynomial() -> WeightToFeeCoefficients { + smallvec![WeightToFeeCoefficient { + degree: 1, + coeff_frac: Perbill::zero(), + coeff_integer: currency::WEIGHT_FEE, + negative: false, + }] + } +} + impl pallet_transaction_payment::Config for Runtime { type OnChargeTransaction = CurrencyAdapter>; type TransactionByteFee = TransactionByteFee; type OperationalFeeMultiplier = OperationalFeeMultiplier; - type WeightToFee = IdentityFee; + type WeightToFee = WeightToFee; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; } @@ -492,7 +540,7 @@ impl pallet_evm::Config for Runtime { } parameter_types! { - pub MaximumSchedulerWeight: Weight = NORMAL_DISPATCH_RATIO * BlockWeights::get().max_block; + pub MaximumSchedulerWeight: Weight = NORMAL_DISPATCH_RATIO * RuntimeBlockWeights::get().max_block; pub const MaxScheduledPerBlock: u32 = 50; } @@ -1144,7 +1192,7 @@ impl xcm_executor::Config for XcmExecutorConfig { // units per second we should charge type Trader = ( UsingComponents< - IdentityFee, + WeightToFee, SelfReserve, AccountId, Balances, @@ -1950,6 +1998,13 @@ mod tests { ); } + #[test] + fn weight_to_fee_is_constant() { + assert_eq!(WeightToFee::calc(&1u64), MEGAWEI); + assert_eq!(WeightToFee::calc(&10u64), 10u128 * MEGAWEI); + assert_eq!(WeightToFee::calc(&1_000u64), 1_000u128 * MEGAWEI); + } + #[test] // Required migration is parachain_staking::migrations::IncreaseMaxDelegatorsPerCandidate // Purpose of this test is to remind of required migration if constant is ever changed diff --git a/runtime/moonbase/tests/integration_test.rs b/runtime/moonbase/tests/integration_test.rs index 578f26b1df8..39b65da2670 100644 --- a/runtime/moonbase/tests/integration_test.rs +++ b/runtime/moonbase/tests/integration_test.rs @@ -31,8 +31,8 @@ use frame_support::{ }; use moonbase_runtime::{ currency::UNIT, AccountId, AssetId, AssetManager, AssetRegistrarMetadata, AssetType, Assets, - Balances, BlockWeights, Call, CrowdloanRewards, Event, ParachainStaking, PolkadotXcm, - Precompiles, Runtime, System, XTokens, XcmTransactor, + Balances, Call, CrowdloanRewards, Event, ParachainStaking, PolkadotXcm, Precompiles, Runtime, + RuntimeBlockWeights, System, TransactionPayment, XTokens, XcmTransactor, }; use nimbus_primitives::NimbusId; use pallet_author_mapping_precompiles::Action as AuthorMappingAction; @@ -1458,9 +1458,11 @@ where #[test] fn multiplier_can_grow_from_zero() { + use frame_support::traits::Get; + let minimum_multiplier = moonbase_runtime::MinimumMultiplier::get(); let target = moonbase_runtime::TargetBlockFullness::get() - * BlockWeights::get() + * RuntimeBlockWeights::get() .get(DispatchClass::Normal) .max_total .unwrap(); @@ -1480,11 +1482,13 @@ fn multiplier_can_grow_from_zero() { #[test] #[ignore] // test runs for a very long time fn multiplier_growth_simulator() { + use frame_support::traits::Get; + // assume the multiplier is initially set to its minimum. We update it with values twice the //target (target is 25%, thus 50%) and we see at which point it reaches 1. let mut multiplier = moonbase_runtime::MinimumMultiplier::get(); let block_weight = moonbase_runtime::TargetBlockFullness::get() - * BlockWeights::get() + * RuntimeBlockWeights::get() .get(DispatchClass::Normal) .max_total .unwrap() @@ -1908,3 +1912,24 @@ fn precompile_existance() { } }); } + +#[test] +fn substrate_based_fees_zero_txn_costs_only_base_extrinsic() { + use frame_support::weights::{DispatchInfo, Pays}; + use moonbase_runtime::{currency::MEGAWEI, EXTRINSIC_BASE_WEIGHT}; + + ExtBuilder::default().build().execute_with(|| { + let size_bytes = 0; + let tip = 0; + let dispatch_info = DispatchInfo { + weight: 0, + class: DispatchClass::Normal, + pays_fee: Pays::Yes, + }; + + assert_eq!( + TransactionPayment::compute_fee(size_bytes, &dispatch_info, tip), + EXTRINSIC_BASE_WEIGHT as u128 * MEGAWEI, + ); + }); +}