From e0671a8a5cddb4cb1e9ceaf84719595466258b24 Mon Sep 17 00:00:00 2001 From: Stephen Shelton Date: Tue, 7 Jun 2022 17:04:05 +0000 Subject: [PATCH 01/10] Implement custom BlockWeights to tune extrinsic base fee --- runtime/moonbase/src/lib.rs | 34 ++++++++++++++++---- runtime/moonbase/tests/integration_test.rs | 37 ++++++++++++++++++---- 2 files changed, 58 insertions(+), 13 deletions(-) diff --git a/runtime/moonbase/src/lib.rs b/runtime/moonbase/src/lib.rs index 7c9d5a2cb48..5a7bc6457b0 100644 --- a/runtime/moonbase/src/lib.rs +++ b/runtime/moonbase/src/lib.rs @@ -55,7 +55,7 @@ use frame_support::{ #[cfg(feature = "std")] pub use fp_evm::GenesisAccount; -use frame_system::{EnsureRoot, EnsureSigned}; +use frame_system::{limits::BlockWeights, EnsureRoot, EnsureSigned}; pub use moonbeam_core_primitives::{ AccountId, AccountIndex, Address, AssetId, Balance, BlockNumber, DigestItem, Hash, Header, Index, Signature, @@ -190,13 +190,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. +// TODO: we should use benchmarking's overhead feature to measure this +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("Provided BlockWeight definitions are valid, qed") + } +} parameter_types! { 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 +246,7 @@ impl frame_system::Config for Runtime { /// Maximum number of block number to block hash mappings to keep (oldest pruned first). type BlockHashCount = ConstU32<256>; /// 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. @@ -463,7 +483,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; } impl pallet_scheduler::Config for Runtime { diff --git a/runtime/moonbase/tests/integration_test.rs b/runtime/moonbase/tests/integration_test.rs index 68cf3991fb0..513c66aceb0 100644 --- a/runtime/moonbase/tests/integration_test.rs +++ b/runtime/moonbase/tests/integration_test.rs @@ -34,10 +34,10 @@ use frame_support::{ }; use moonbase_runtime::{ 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, - LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX, + xcm_config::AssetType, AccountId, AssetId, AssetManager, Assets, Balances, BaseFee, Call, + CrowdloanRewards, Event, LocalAssets, ParachainStaking, PolkadotXcm, Precompiles, Runtime, + RuntimeBlockWeights, System, TransactionPayment, XTokens, XcmTransactor, + FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, LOCAL_ASSET_PRECOMPILE_ADDRESS_PREFIX, }; use crowdloan_rewards_precompiles::Action as CrowdloanAction; @@ -1968,9 +1968,11 @@ fn length_fee_is_sensible() { #[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(); @@ -1990,11 +1992,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() @@ -2570,3 +2574,24 @@ fn base_fee_should_default_to_associate_type_value() { ); }); } + +#[test] +fn substrate_based_fees_zero_txn_costs_only_base_extrinsic() { + use frame_support::weights::{DispatchInfo, Pays}; + use moonbase_runtime::{currency, 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 * currency::WEIGHT_FEE, + ); + }); +} From 77c8c6964e22848a074dab1b19212519ff77ef56 Mon Sep 17 00:00:00 2001 From: Stephen Shelton Date: Thu, 21 Jul 2022 16:28:25 -0600 Subject: [PATCH 02/10] Fix some tests --- tests/tests/test-author/test-author-mapping.ts | 2 +- tests/tests/test-eth-tx/test-eth-tx-size.ts | 4 ++-- tests/tests/test-fees/test-length-fees.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/tests/test-author/test-author-mapping.ts b/tests/tests/test-author/test-author-mapping.ts index 941a4ad6089..8ae917f680d 100644 --- a/tests/tests/test-author/test-author-mapping.ts +++ b/tests/tests/test-author/test-author-mapping.ts @@ -88,7 +88,7 @@ describeDevMoonbeam("Author Mapping - Fail to reassociate alice", (context) => { //check state expect( (await context.polkadotApi.query.system.account(baltathar.address)).data.free.toBigInt() - ).to.eq(1208925819590977972705800n); + ).to.eq(1208925819582767722705800n); expect( (await context.polkadotApi.query.system.account(baltathar.address)).data.reserved.toBigInt() ).to.eq(0n); diff --git a/tests/tests/test-eth-tx/test-eth-tx-size.ts b/tests/tests/test-eth-tx/test-eth-tx-size.ts index 76e839a0fed..a3c04a2c2fe 100644 --- a/tests/tests/test-eth-tx/test-eth-tx-size.ts +++ b/tests/tests/test-eth-tx/test-eth-tx-size.ts @@ -27,10 +27,10 @@ describeDevMoonbeam("Ethereum Transaction - Large Transaction", (context) => { }; // TODO: I'm not sure where this 2000 came from... - const max_size = (EXTRINSIC_GAS_LIMIT - 21000) / 16 - 2000; + const max_size = Math.floor((EXTRINSIC_GAS_LIMIT - 21000) / 16) - 2000; it("should accept txns up to known size", async function () { - expect(max_size).to.equal(808973); // our max Ethereum TXN size in bytes + expect(max_size).to.equal(808187); // our max Ethereum TXN size in bytes const tx = await generateLargeTxn(max_size); const { result } = await context.createBlock(tx); diff --git a/tests/tests/test-fees/test-length-fees.ts b/tests/tests/test-fees/test-length-fees.ts index c74d07123a6..1c238d3e3ea 100644 --- a/tests/tests/test-fees/test-length-fees.ts +++ b/tests/tests/test-fees/test-length-fees.ts @@ -10,7 +10,7 @@ describeDevMoonbeam( (context) => { it("should have low balance transfer fees", async () => { const fee = await testBalanceTransfer(context); - expect(fee).to.equal(12418651520875n); + expect(fee).to.equal(20628901520875n); }); }, "Legacy", @@ -22,7 +22,7 @@ describeDevMoonbeam( (context) => { it("should have expensive runtime-upgrade fees", async () => { const fee = await testRuntimeUpgrade(context); - expect(fee).to.equal(9226793105473667008n); + expect(fee).to.equal(9226801315723667008n); }); }, "Legacy", From 05b09fd733f4e26506830f6f2f8276e80e99e3a3 Mon Sep 17 00:00:00 2001 From: Stephen Shelton Date: Thu, 21 Jul 2022 16:29:19 -0600 Subject: [PATCH 03/10] Adjust EXTRINSIC_BASE_COST --- tests/util/constants.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/util/constants.ts b/tests/util/constants.ts index 76ec3574c70..f0eb74927d4 100644 --- a/tests/util/constants.ts +++ b/tests/util/constants.ts @@ -40,8 +40,8 @@ export const BLOCK_TX_LIMIT = GAS_PER_SECOND * 0.5; // Current implementation is limiting block transactions to 75% of the block gas limit export const BLOCK_TX_GAS_LIMIT = BLOCK_TX_LIMIT * 0.75; -// 85_800_000 Weight per extrinsics -export const EXTRINSIC_BASE_COST = 85_800_000 / GAS_PER_WEIGHT; +// 400_000_000 Weight per extrinsics +export const EXTRINSIC_BASE_COST = 400_000_000 / GAS_PER_WEIGHT; // Maximum extrinsic weight is taken from the max allowed transaction weight per block, // minus the block initialization (10%) and minus the extrinsic base cost. From dfe4b5134b5cc5d9c980e595b432bcbe724c5b4f Mon Sep 17 00:00:00 2001 From: Stephen Shelton Date: Thu, 21 Jul 2022 16:39:20 -0600 Subject: [PATCH 04/10] Rework staking test that can't fit in one block now --- .../tests/test-staking/test-staking-locks.ts | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/tests/tests/test-staking/test-staking-locks.ts b/tests/tests/test-staking/test-staking-locks.ts index e062985adfb..b8f2c470ea6 100644 --- a/tests/tests/test-staking/test-staking-locks.ts +++ b/tests/tests/test-staking/test-staking-locks.ts @@ -447,11 +447,12 @@ describeDevMoonbeam("Staking - Locks - bottom delegator removed", (context) => { before("setup candidate & delegations", async function () { this.timeout(20000); - // Create the delegators to fill the lists - additionalDelegators = new Array( + const maxDelegations = context.polkadotApi.consts.parachainStaking.maxTopDelegationsPerCandidate.toNumber() + - context.polkadotApi.consts.parachainStaking.maxBottomDelegationsPerCandidate.toNumber() - ) + context.polkadotApi.consts.parachainStaking.maxBottomDelegationsPerCandidate.toNumber(); + + // Create the delegators to fill the lists + additionalDelegators = new Array(maxDelegations) .fill(0) .map(() => generateKeyringPair()); @@ -482,20 +483,28 @@ describeDevMoonbeam("Staking - Locks - bottom delegator removed", (context) => { `Unexpected number of locks: ${locks.map((l) => l.id.toHuman().toString()).join(` - `)}` ); - await expectOk( - context.createBlock( - [...additionalDelegators].map((account, i) => - context.polkadotApi.tx.parachainStaking - .delegate(alith.address, MIN_GLMR_DELEGATOR + GLMR, i + 1, 1) - .signAsync(account) - ) - ) - ); + const txns = + await [...additionalDelegators].map((account, i) => + context.polkadotApi.tx.parachainStaking + .delegate(alith.address, MIN_GLMR_DELEGATOR + GLMR, i + 1, 1) + .signAsync(account) + ); + + // this can no longer fit in one block + const batchSize = 100; + for (let i=0; i `${l.id.toHuman().toString()}: ${l.amount.toHuman().toString()}`).join(` - `)}` ); }); }); From 474daa691b31b315fb48dbaad7289f3e28df802d Mon Sep 17 00:00:00 2001 From: Stephen Shelton Date: Thu, 21 Jul 2022 16:39:53 -0600 Subject: [PATCH 05/10] prettier --- .../tests/test-staking/test-staking-locks.ts | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/tests/tests/test-staking/test-staking-locks.ts b/tests/tests/test-staking/test-staking-locks.ts index b8f2c470ea6..4ac5e4520b4 100644 --- a/tests/tests/test-staking/test-staking-locks.ts +++ b/tests/tests/test-staking/test-staking-locks.ts @@ -447,14 +447,12 @@ describeDevMoonbeam("Staking - Locks - bottom delegator removed", (context) => { before("setup candidate & delegations", async function () { this.timeout(20000); - const maxDelegations = + const maxDelegations = context.polkadotApi.consts.parachainStaking.maxTopDelegationsPerCandidate.toNumber() + - context.polkadotApi.consts.parachainStaking.maxBottomDelegationsPerCandidate.toNumber(); + context.polkadotApi.consts.parachainStaking.maxBottomDelegationsPerCandidate.toNumber(); // Create the delegators to fill the lists - additionalDelegators = new Array(maxDelegations) - .fill(0) - .map(() => generateKeyringPair()); + additionalDelegators = new Array(maxDelegations).fill(0).map(() => generateKeyringPair()); await expectOk( context.createBlock( @@ -483,17 +481,16 @@ describeDevMoonbeam("Staking - Locks - bottom delegator removed", (context) => { `Unexpected number of locks: ${locks.map((l) => l.id.toHuman().toString()).join(` - `)}` ); - const txns = - await [...additionalDelegators].map((account, i) => - context.polkadotApi.tx.parachainStaking - .delegate(alith.address, MIN_GLMR_DELEGATOR + GLMR, i + 1, 1) - .signAsync(account) - ); + const txns = await [...additionalDelegators].map((account, i) => + context.polkadotApi.tx.parachainStaking + .delegate(alith.address, MIN_GLMR_DELEGATOR + GLMR, i + 1, 1) + .signAsync(account) + ); // this can no longer fit in one block const batchSize = 100; - for (let i=0; i { const newLocks = await context.polkadotApi.query.balances.locks(randomAccount.address); expect(newLocks.length).to.be.equal( 0, - `Unexpected number of locks: ${newLocks.map((l) => `${l.id.toHuman().toString()}: ${l.amount.toHuman().toString()}`).join(` - `)}` + `Unexpected number of locks: ${newLocks + .map((l) => `${l.id.toHuman().toString()}: ${l.amount.toHuman().toString()}`) + .join(` - `)}` ); }); }); From 859986c5f545a8ac11d137a14562d4b6383370c7 Mon Sep 17 00:00:00 2001 From: Stephen Shelton Date: Thu, 21 Jul 2022 17:07:28 -0600 Subject: [PATCH 06/10] Correct EXTRINSIC_BASE_COST in constant --- tests/util/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/util/constants.ts b/tests/util/constants.ts index f0eb74927d4..a51aa90ad3e 100644 --- a/tests/util/constants.ts +++ b/tests/util/constants.ts @@ -41,7 +41,7 @@ export const BLOCK_TX_LIMIT = GAS_PER_SECOND * 0.5; // Current implementation is limiting block transactions to 75% of the block gas limit export const BLOCK_TX_GAS_LIMIT = BLOCK_TX_LIMIT * 0.75; // 400_000_000 Weight per extrinsics -export const EXTRINSIC_BASE_COST = 400_000_000 / GAS_PER_WEIGHT; +export const EXTRINSIC_BASE_COST = 250_000_000 / GAS_PER_WEIGHT; // Maximum extrinsic weight is taken from the max allowed transaction weight per block, // minus the block initialization (10%) and minus the extrinsic base cost. From df981289b624bbeb230cd522e648ad036079d0a9 Mon Sep 17 00:00:00 2001 From: Stephen Shelton Date: Thu, 21 Jul 2022 17:13:07 -0600 Subject: [PATCH 07/10] Reflect latest change to EXTRINSIC_GAS_LIMIT --- tests/tests/test-eth-tx/test-eth-tx-size.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tests/test-eth-tx/test-eth-tx-size.ts b/tests/tests/test-eth-tx/test-eth-tx-size.ts index a3c04a2c2fe..20d6c3b739d 100644 --- a/tests/tests/test-eth-tx/test-eth-tx-size.ts +++ b/tests/tests/test-eth-tx/test-eth-tx-size.ts @@ -30,7 +30,7 @@ describeDevMoonbeam("Ethereum Transaction - Large Transaction", (context) => { const max_size = Math.floor((EXTRINSIC_GAS_LIMIT - 21000) / 16) - 2000; it("should accept txns up to known size", async function () { - expect(max_size).to.equal(808187); // our max Ethereum TXN size in bytes + expect(max_size).to.equal(808562); // our max Ethereum TXN size in bytes const tx = await generateLargeTxn(max_size); const { result } = await context.createBlock(tx); From d9daf78013e4ebf449ba4624cce4984e63260c29 Mon Sep 17 00:00:00 2001 From: Stephen Shelton Date: Thu, 21 Jul 2022 17:14:02 -0600 Subject: [PATCH 08/10] Reflect change to Delegator Leaving (right?) --- tests/tests/test-staking/test-delegator-join.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/tests/test-staking/test-delegator-join.ts b/tests/tests/test-staking/test-delegator-join.ts index a11790d9b11..326f750591f 100644 --- a/tests/tests/test-staking/test-delegator-join.ts +++ b/tests/tests/test-staking/test-delegator-join.ts @@ -165,8 +165,7 @@ describeDevMoonbeam("Staking - Delegator Join - valid request", (context) => { ], id: ethan.address, lessTotal: 0, - status: { active: null }, - total: numberToHex(MIN_GLMR_DELEGATOR), + status: "Active" }); }); }); From fa0e271f640d5ae9f0b0110f1302eef172fae5fd Mon Sep 17 00:00:00 2001 From: Stephen Shelton Date: Thu, 21 Jul 2022 17:18:05 -0600 Subject: [PATCH 09/10] Revert "Reflect change to Delegator Leaving (right?)" This reverts commit d9daf78013e4ebf449ba4624cce4984e63260c29. --- tests/tests/test-staking/test-delegator-join.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/tests/test-staking/test-delegator-join.ts b/tests/tests/test-staking/test-delegator-join.ts index 326f750591f..a11790d9b11 100644 --- a/tests/tests/test-staking/test-delegator-join.ts +++ b/tests/tests/test-staking/test-delegator-join.ts @@ -165,7 +165,8 @@ describeDevMoonbeam("Staking - Delegator Join - valid request", (context) => { ], id: ethan.address, lessTotal: 0, - status: "Active" + status: { active: null }, + total: numberToHex(MIN_GLMR_DELEGATOR), }); }); }); From 095fb27ca3249e005feca95ffa05e561510fbc07 Mon Sep 17 00:00:00 2001 From: Stephen Shelton Date: Mon, 1 Aug 2022 18:50:53 -0600 Subject: [PATCH 10/10] Fix test --- tests/tests/test-fees/test-length-fees.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tests/test-fees/test-length-fees.ts b/tests/tests/test-fees/test-length-fees.ts index fd800b49855..cc9021a0578 100644 --- a/tests/tests/test-fees/test-length-fees.ts +++ b/tests/tests/test-fees/test-length-fees.ts @@ -10,7 +10,7 @@ describeDevMoonbeam( (context) => { it("should have low balance transfer fees", async () => { const fee = await testBalanceTransfer(context); - expect(fee).to.equal(20628901520875n); + expect(fee).to.equal(20958001520875n); }); }, "Legacy",