diff --git a/runtime/moonbase/src/lib.rs b/runtime/moonbase/src/lib.rs index 2f4b0d49db8..bcc606c1063 100644 --- a/runtime/moonbase/src/lib.rs +++ b/runtime/moonbase/src/lib.rs @@ -47,8 +47,8 @@ use frame_support::{ }, weights::{ constants::{RocksDbWeight, WEIGHT_PER_SECOND}, - ConstantMultiplier, DispatchClass, GetDispatchInfo, IdentityFee, Weight, - WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial, + DispatchClass, GetDispatchInfo, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, + WeightToFeePolynomial, }, PalletId, }; @@ -129,7 +129,7 @@ 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; + pub const TRANSACTION_BYTE_FEE: Balance = 1 * GIGAWEI * SUPPLY_FACTOR; pub const STORAGE_BYTE_FEE: Balance = 100 * MICROUNIT * SUPPLY_FACTOR; pub const WEIGHT_FEE: Balance = 50 * KILOWEI * SUPPLY_FACTOR; @@ -322,15 +322,33 @@ impl WeightToFeePolynomial for WeightToFee { } } -parameter_types! { - pub const TransactionByteFee: Balance = currency::TRANSACTION_BYTE_FEE; +pub struct LengthToFee; +impl WeightToFeePolynomial for LengthToFee { + type Balance = Balance; + + fn polynomial() -> WeightToFeeCoefficients { + smallvec![ + WeightToFeeCoefficient { + degree: 1, + coeff_frac: Perbill::zero(), + coeff_integer: currency::TRANSACTION_BYTE_FEE, + negative: false, + }, + WeightToFeeCoefficient { + degree: 3, + coeff_frac: Perbill::zero(), + coeff_integer: 1, + negative: false, + }, + ] + } } impl pallet_transaction_payment::Config for Runtime { type OnChargeTransaction = CurrencyAdapter>; type OperationalFeeMultiplier = ConstU8<5>; - type WeightToFee = IdentityFee; - type LengthToFee = ConstantMultiplier; + type WeightToFee = WeightToFee; + type LengthToFee = LengthToFee; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; } @@ -1373,7 +1391,7 @@ mod tests { assert_eq!(SUPPLY_FACTOR, 1); // txn fees - assert_eq!(TRANSACTION_BYTE_FEE, Balance::from(10 * MICROUNIT)); + assert_eq!(TRANSACTION_BYTE_FEE, Balance::from(1 * GIGAWEI)); assert_eq!( get!(pallet_transaction_payment, OperationalFeeMultiplier, u8), 5_u8 diff --git a/runtime/moonbase/tests/integration_test.rs b/runtime/moonbase/tests/integration_test.rs index f29b048accf..27e23780417 100644 --- a/runtime/moonbase/tests/integration_test.rs +++ b/runtime/moonbase/tests/integration_test.rs @@ -33,7 +33,7 @@ use frame_support::{ StorageHasher, Twox128, }; use moonbase_runtime::{ - asset_config::AssetRegistrarMetadata, asset_config::LocalAssetInstance, currency::UNIT, get, + asset_config::AssetRegistrarMetadata, asset_config::LocalAssetInstance, get, xcm_config::AssetType, AccountId, AssetId, AssetManager, Assets, Balances, BaseFee, BlockWeights, Call, CrowdloanRewards, Event, LocalAssets, ParachainStaking, PolkadotXcm, Precompiles, Runtime, System, XTokens, XcmTransactor, FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, @@ -2299,6 +2299,58 @@ where }); } +#[test] +#[rustfmt::skip] +fn length_fee_is_sensible() { + use sp_runtime::testing::TestXt; + + ExtBuilder::default() + .with_balances(vec![ + (AccountId::from(ALICE), (1 * UNIT) + (1 * WEI)), + (AccountId::from(BOB), 0), + ]) + .build() + .execute_with(|| { + // Substrate transfer + assert_ok!(Balances::transfer( + origin_of(AccountId::from(ALICE)), + AccountId::from(BOB), + 1 * UNIT, + )); + // 1 WEI is left in the account + assert_eq!(Balances::free_balance(AccountId::from(ALICE)), 1 * WEI); + }); + + // tests that length fee is sensible for a few hypothetical transactions + ExtBuilder::default().build().execute_with(|| { + let call = frame_system::Call::remark:: { remark: vec![] }; + let uxt: TestXt<_, ()> = TestXt::new(call, Some((1u64, ()))); + + let calc_fee = |len: u32| -> Balance { + moonbase_runtime::TransactionPayment::query_fee_details(uxt.clone(), len) + .inclusion_fee + .expect("fee should be calculated") + .len_fee + }; + + // editorconfig-checker-disable + // left: cost of length fee, right: size in bytes + // /------------- proportional component: O(N * 1B) + // | /- exponential component: O(N ** 3) + // | | + assert_eq!( 1_000_000_001, calc_fee(1)); + assert_eq!( 10_000_001_000, calc_fee(10)); + assert_eq!( 100_001_000_000, calc_fee(100)); + assert_eq!( 1_001_000_000_000, calc_fee(1_000)); + assert_eq!( 11_000_000_000_000, calc_fee(10_000)); // inflection point + assert_eq!( 1_100_000_000_000_000, calc_fee(100_000)); + assert_eq!( 1_001_000_000_000_000_000, calc_fee(1_000_000)); // one UNIT, ~ 1MB + assert_eq!( 1_000_010_000_000_000_000_000, calc_fee(10_000_000)); + assert_eq!(1_000_000_100_000_000_000_000_000, calc_fee(100_000_000)); + // editorconfig-checker-enable + }); +} + #[test] fn multiplier_can_grow_from_zero() { let minimum_multiplier = moonbase_runtime::MinimumMultiplier::get(); diff --git a/tests/tests/test-author-mapping.ts b/tests/tests/test-author-mapping.ts index b9bc9b01008..fb2d0f74696 100644 --- a/tests/tests/test-author-mapping.ts +++ b/tests/tests/test-author-mapping.ts @@ -68,7 +68,7 @@ describeDevMoonbeam("Author Mapping - simple association", (context) => { expect((await getMappingInfo(context, bobAuthorId)).account).to.eq(ALITH); expect( ((await context.polkadotApi.query.system.account(ALITH)) as any).data.free.toBigInt() - ).to.eq(1207725818354628664997176n); + ).to.eq(1207725819589017722705800n); expect( ((await context.polkadotApi.query.system.account(ALITH)) as any).data.reserved.toBigInt() ).to.eq(2n * DEFAULT_GENESIS_MAPPING + DEFAULT_GENESIS_STAKING); @@ -95,7 +95,7 @@ describeDevMoonbeam("Author Mapping - Fail to reassociate alice", (context) => { //check state expect( ((await context.polkadotApi.query.system.account(BALTATHAR)) as any).data.free.toBigInt() - ).to.eq(1208925818354628664997176n); + ).to.eq(1208925819589017722705800n); expect( ((await context.polkadotApi.query.system.account(BALTATHAR)) as any).data.reserved.toBigInt() ).to.eq(0n);