diff --git a/runtime/moonbase/src/lib.rs b/runtime/moonbase/src/lib.rs index c75b624fde5..aff65920f5a 100644 --- a/runtime/moonbase/src/lib.rs +++ b/runtime/moonbase/src/lib.rs @@ -56,7 +56,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, @@ -191,13 +191,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); @@ -227,7 +247,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. @@ -442,7 +462,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 4570b3e8da6..ea36bc1ae79 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 precompile_utils::testing::MockHandle; @@ -1999,9 +1999,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(); @@ -2021,11 +2023,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() @@ -2602,6 +2606,27 @@ 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, + ); + }); +} + #[test] fn evm_revert_substrate_events() { ExtBuilder::default() diff --git a/tests/tests/test-author/test-author-mapping.ts b/tests/tests/test-author/test-author-mapping.ts index c02129ba446..35d628a95c4 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(1208925819590952822705800n); + ).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 43e242f403c..20d6c3b739d 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 = Math.floor((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(808971); // 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); diff --git a/tests/tests/test-fees/test-length-fees.ts b/tests/tests/test-fees/test-length-fees.ts index a99e6ac171c..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(12772901520875n); + expect(fee).to.equal(20958001520875n); }); }, "Legacy", @@ -22,7 +22,7 @@ describeDevMoonbeam( (context) => { it("should have expensive runtime-upgrade fees", async () => { const fee = await testRuntimeUpgrade(context); - expect(fee).to.equal(9226793130623667008n); + expect(fee).to.equal(9226801315723667008n); }); }, "Legacy", diff --git a/tests/tests/test-staking/test-staking-locks.ts b/tests/tests/test-staking/test-staking-locks.ts index e062985adfb..4ac5e4520b4 100644 --- a/tests/tests/test-staking/test-staking-locks.ts +++ b/tests/tests/test-staking/test-staking-locks.ts @@ -447,13 +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() - ) - .fill(0) - .map(() => generateKeyringPair()); + context.polkadotApi.consts.parachainStaking.maxBottomDelegationsPerCandidate.toNumber(); + + // Create the delegators to fill the lists + additionalDelegators = new Array(maxDelegations).fill(0).map(() => generateKeyringPair()); await expectOk( context.createBlock( @@ -482,20 +481,29 @@ 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 < txns.length; i += batchSize) { + await expectOk(context.createBlock(txns.slice(i, i + batchSize))); + } + + const alithCandidateInfo = ( + (await context.polkadotApi.query.parachainStaking.candidateInfo(alith.address)) as any + ).unwrap(); + expect(alithCandidateInfo.delegationCount.toNumber()).to.equal(additionalDelegators.length); + const newLocks = await context.polkadotApi.query.balances.locks(randomAccount.address); expect(newLocks.length).to.be.equal( 0, - "Lock should have been removed after getting removed from bottom delegations" + `Unexpected number of locks: ${newLocks + .map((l) => `${l.id.toHuman().toString()}: ${l.amount.toHuman().toString()}`) + .join(` - `)}` ); }); }); diff --git a/tests/util/constants.ts b/tests/util/constants.ts index 7ccca0c304a..a51aa90ad3e 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; -// 86_298_000 Weight per extrinsics -export const EXTRINSIC_BASE_COST = Math.ceil(86_298_000 / GAS_PER_WEIGHT); +// 400_000_000 Weight per extrinsics +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.