From fc839a0b337fe9ca50db43a4331d537706fa3831 Mon Sep 17 00:00:00 2001 From: Hernando Castano Date: Wed, 27 May 2020 12:41:25 -0400 Subject: [PATCH] Add tests for Polkadot runtime weights and fees (#1090) * Add tests for Balance module weights * Add tests for some of the Staking functions * Add tests for system Pallet weights * Add weight tests for Session pallet * Add tests for Democracy Pallet weights * Add tests for Phragment weights * Add tests for Treasury weights * Use consistent naming for tests * Split tests into separate weight and fee suites * Move weight constant checks into one test * Use formulas instead of hardcoded weights * Slim down number of tests Mainly removing ones that are either root calls that aren't "important", or others which will likely change if another test (which we kept) also changes. * Update timestamp set() weight * Update Staking Pallet weights * Update Democracy Pallet weights * Update copyright year Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com> --- runtime/polkadot/src/constants.rs | 6 +- runtime/polkadot/tests/weights.rs | 275 ++++++++++++++++++++++++++++++ 2 files changed, 278 insertions(+), 3 deletions(-) create mode 100644 runtime/polkadot/tests/weights.rs diff --git a/runtime/polkadot/src/constants.rs b/runtime/polkadot/src/constants.rs index 27affd820e64..9b6ea0426559 100644 --- a/runtime/polkadot/src/constants.rs +++ b/runtime/polkadot/src/constants.rs @@ -19,9 +19,9 @@ pub mod currency { use primitives::Balance; pub const DOTS: Balance = 1_000_000_000_000; - pub const DOLLARS: Balance = DOTS / 100; - pub const CENTS: Balance = DOLLARS / 100; - pub const MILLICENTS: Balance = CENTS / 1_000; + pub const DOLLARS: Balance = DOTS / 100; // 10_000_000_000 + pub const CENTS: Balance = DOLLARS / 100; // 100_000_000 + pub const MILLICENTS: Balance = CENTS / 1_000; // 100_000 } /// Time and blocks. diff --git a/runtime/polkadot/tests/weights.rs b/runtime/polkadot/tests/weights.rs new file mode 100644 index 000000000000..6bfe1dced4e7 --- /dev/null +++ b/runtime/polkadot/tests/weights.rs @@ -0,0 +1,275 @@ +// Copyright 2020 Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Tests to make sure that Polkadot's weights and fees match what we +//! expect from Substrate. +//! +//! These test are not meant to be exhaustive, as it is inevitable that +//! weights in Substrate will change. Instead they are supposed to provide +//! some sort of indicator that calls we consider important (e.g Balances::transfer) +//! have not suddenly changed from under us. + +use frame_support::{ + traits::ContainsLengthBound, + weights::{constants::*, GetDispatchInfo, Weight}, +}; +use keyring::AccountKeyring; +use polkadot_runtime::constants::currency::*; +use polkadot_runtime::{self, Runtime}; +use primitives::AccountId; +use runtime_common::MaximumBlockWeight; + +use democracy::Call as DemocracyCall; +use elections_phragmen::Call as PhragmenCall; +use session::Call as SessionCall; +use staking::Call as StakingCall; +use system::Call as SystemCall; +use treasury::Call as TreasuryCall; + +type DbWeight = ::DbWeight; + +#[test] +fn sanity_check_weight_per_time_constants_are_as_expected() { + // These values comes from Substrate, we want to make sure that if it + // ever changes we don't accidently break Polkadot + assert_eq!(WEIGHT_PER_SECOND, 1_000_000_000_000); + assert_eq!(WEIGHT_PER_MILLIS, WEIGHT_PER_SECOND / 1000); + assert_eq!(WEIGHT_PER_MICROS, WEIGHT_PER_MILLIS / 1000); + assert_eq!(WEIGHT_PER_NANOS, WEIGHT_PER_MICROS / 1000); +} + +#[test] +fn weight_of_balances_transfer_is_correct() { + // #[weight = T::DbWeight::get().reads_writes(1, 1) + 70_000_000] + let expected_weight = DbWeight::get().read + DbWeight::get().write + 70_000_000; + + let weight = polkadot_runtime::BalancesCall::transfer::(Default::default(), Default::default()) + .get_dispatch_info() + .weight; + assert_eq!(weight, expected_weight); +} + +#[test] +fn weight_of_balances_transfer_keep_alive_is_correct() { + // #[weight = T::DbWeight::get().reads_writes(1, 1) + 50_000_000] + let expected_weight = DbWeight::get().read + DbWeight::get().write + 50_000_000; + + let weight = polkadot_runtime::BalancesCall::transfer_keep_alive::(Default::default(), Default::default()) + .get_dispatch_info() + .weight; + + assert_eq!(weight, expected_weight); +} + +#[test] +fn weight_of_timestamp_set_is_correct() { + // #[weight = T::DbWeight::get().reads_writes(2, 1) + 8_000_000] + let expected_weight = (2 * DbWeight::get().read) + DbWeight::get().write + 8_000_000; + let weight = polkadot_runtime::TimestampCall::set::(Default::default()).get_dispatch_info().weight; + + assert_eq!(weight, expected_weight); +} + +#[test] +fn weight_of_staking_bond_is_correct() { + let controller: AccountId = AccountKeyring::Alice.into(); + + // #[weight = 67 * WEIGHT_PER_MICROS + T::DbWeight::get().reads_writes(5, 4)] + let expected_weight = 67 * WEIGHT_PER_MICROS + (DbWeight::get().read * 5) + (DbWeight::get().write * 4); + let weight = StakingCall::bond::(controller, 1 * DOLLARS, Default::default()).get_dispatch_info().weight; + + assert_eq!(weight, expected_weight); +} + +#[test] +fn weight_of_staking_validate_is_correct() { + // #[weight = 17 * WEIGHT_PER_MICROS + T::DbWeight::get().reads_writes(2, 2)] + let expected_weight = 17 * WEIGHT_PER_MICROS + (DbWeight::get().read * 2) + (DbWeight::get().write * 2); + let weight = StakingCall::validate::(Default::default()).get_dispatch_info().weight; + + assert_eq!(weight, expected_weight); +} + +#[test] +fn weight_of_staking_nominate_is_correct() { + let targets: Vec = vec![Default::default(), Default::default(), Default::default()]; + + // #[weight = T::DbWeight::get().reads_writes(3, 2) + // .saturating_add(22 * WEIGHT_PER_MICROS) + // .saturating_add((360 * WEIGHT_PER_NANOS).saturating_mul(targets.len() as Weight)) + // ] + let db_weight = (DbWeight::get().read * 3) + (DbWeight::get().write * 2); + let targets_weight = (360 * WEIGHT_PER_NANOS).saturating_mul(targets.len() as Weight); + + let expected_weight = db_weight.saturating_add(22 * WEIGHT_PER_MICROS).saturating_add(targets_weight); + let weight = StakingCall::nominate::(targets).get_dispatch_info().weight; + + assert_eq!(weight, expected_weight); +} + +#[test] +fn weight_of_system_set_code_is_correct() { + // #[weight = (T::MaximumBlockWeight::get(), DispatchClass::Operational)] + let expected_weight = MaximumBlockWeight::get(); + let weight = SystemCall::set_code::(vec![]).get_dispatch_info().weight; + + assert_eq!(weight, expected_weight); +} + +#[test] +fn weight_of_system_set_storage_is_correct() { + let storage_items = vec![(vec![12], vec![34]), (vec![45], vec![83])]; + let len = storage_items.len() as Weight; + + // #[weight = FunctionOf( + // |(items,): (&Vec,)| { + // T::DbWeight::get().writes(items.len() as Weight) + // .saturating_add((items.len() as Weight).saturating_mul(600_000)) + // }, + // DispatchClass::Operational, + // Pays::Yes, + // )] + let expected_weight = (DbWeight::get().write * len).saturating_add(len.saturating_mul(600_000)); + let weight = SystemCall::set_storage::(storage_items).get_dispatch_info().weight; + + assert_eq!(weight, expected_weight); +} + +#[test] +fn weight_of_system_remark_is_correct() { + // #[weight = 700_000] + let expected_weight = 700_000; + let weight = SystemCall::remark::(vec![]).get_dispatch_info().weight; + + assert_eq!(weight, expected_weight); +} + +#[test] +fn weight_of_session_set_keys_is_correct() { + // #[weight = 200_000_000 + // + T::DbWeight::get().reads(2 + T::Keys::key_ids().len() as Weight) + // + T::DbWeight::get().writes(1 + T::Keys::key_ids().len() as Weight)] + // + // Polkadot has five possible session keys, so we default to key_ids.len() = 5 + let expected_weight = 200_000_000 + (DbWeight::get().read * (2 + 5)) + (DbWeight::get().write * (1 + 5)); + let weight = SessionCall::set_keys::(Default::default(), Default::default()).get_dispatch_info().weight; + + assert_eq!(weight, expected_weight); +} + +#[test] +fn weight_of_session_purge_keys_is_correct() { + // #[weight = 120_000_000 + // + T::DbWeight::get().reads_writes(2, 1 + T::Keys::key_ids().len() as Weight)] + // + // Polkadot has five possible session keys, so we default to key_ids.len() = 5 + let expected_weight = 120_000_000 + (DbWeight::get().read * 2) + (DbWeight::get().write * (1 + 5)); + let weight = SessionCall::purge_keys::().get_dispatch_info().weight; + + assert_eq!(weight, expected_weight); +} + +#[test] +fn weight_of_democracy_propose_is_correct() { + // #[weight = 50_000_000 + T::DbWeight::get().reads_writes(2, 3)] + let expected_weight = 50_000_000 + (DbWeight::get().read * 2) + (DbWeight::get().write * 3); + let weight = DemocracyCall::propose::(Default::default(), Default::default()).get_dispatch_info().weight; + + assert_eq!(weight, expected_weight); +} + +#[test] +fn weight_of_democracy_vote_is_correct() { + use democracy::AccountVote; + let vote = AccountVote::Standard { vote: Default::default(), balance: Default::default() }; + + // #[weight = 50_000_000 + 350_000 * Weight::from(T::MaxVotes::get()) + T::DbWeight::get().reads_writes(3, 3)] + let expected_weight = 50_000_000 + + 350_000 * (Weight::from(polkadot_runtime::MaxVotes::get())) + + (DbWeight::get().read * 3) + + (DbWeight::get().write * 3); + let weight = DemocracyCall::vote::(Default::default(), vote).get_dispatch_info().weight; + + assert_eq!(weight, expected_weight); +} + +#[test] +fn weight_of_democracy_enact_proposal_is_correct() { + // #[weight = T::MaximumBlockWeight::get()] + let expected_weight = MaximumBlockWeight::get(); + let weight = + DemocracyCall::enact_proposal::(Default::default(), Default::default()).get_dispatch_info().weight; + + assert_eq!(weight, expected_weight); +} + +#[test] +fn weight_of_phragmen_vote_is_correct() { + // #[weight = 100_000_000] + let expected_weight = 100_000_000; + let weight = PhragmenCall::vote::(Default::default(), Default::default()).get_dispatch_info().weight; + + assert_eq!(weight, expected_weight); +} + +#[test] +fn weight_of_phragmen_submit_candidacy_is_correct() { + // #[weight = 500_000_000] + let expected_weight = 500_000_000; + let weight = PhragmenCall::submit_candidacy::().get_dispatch_info().weight; + + assert_eq!(weight, expected_weight); +} + +#[test] +fn weight_of_phragmen_renounce_candidacy_is_correct() { + // #[weight = (2_000_000_000, DispatchClass::Operational)] + let expected_weight = 2_000_000_000; + let weight = PhragmenCall::renounce_candidacy::().get_dispatch_info().weight; + + assert_eq!(weight, expected_weight); +} + +#[test] +fn weight_of_treasury_propose_spend_is_correct() { + // #[weight = 120_000_000 + T::DbWeight::get().reads_writes(1, 2)] + let expected_weight = 120_000_000 + DbWeight::get().read + 2 * DbWeight::get().write; + let weight = + TreasuryCall::propose_spend::(Default::default(), Default::default()).get_dispatch_info().weight; + + assert_eq!(weight, expected_weight); +} + +#[test] +fn weight_of_treasury_approve_proposal_is_correct() { + // #[weight = (34_000_000 + T::DbWeight::get().reads_writes(2, 1), DispatchClass::Operational)] + let expected_weight = 34_000_000 + 2 * DbWeight::get().read + DbWeight::get().write; + let weight = TreasuryCall::approve_proposal::(Default::default()).get_dispatch_info().weight; + + assert_eq!(weight, expected_weight); +} + +#[test] +fn weight_of_treasury_tip_is_correct() { + let max_len: Weight = ::Tippers::max_len() as Weight; + + // #[weight = 68_000_000 + 2_000_000 * T::Tippers::max_len() as Weight + // + T::DbWeight::get().reads_writes(2, 1)] + let expected_weight = 68_000_000 + 2_000_000 * max_len + 2 * DbWeight::get().read + DbWeight::get().write; + let weight = TreasuryCall::tip::(Default::default(), Default::default()).get_dispatch_info().weight; + + assert_eq!(weight, expected_weight); +}