diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 82e3a9f7e0..621de954c7 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -573,6 +573,7 @@ impl pallet_election_provider_multi_phase::BenchmarkingConfig for BenchmarkConfi impl pallet_election_provider_multi_phase::Config for Runtime { type Event = Event; type Currency = Balances; + type EstimateCallFee = TransactionPayment; type SignedPhase = SignedPhase; type UnsignedPhase = UnsignedPhase; type SolutionImprovementThreshold = SolutionImprovementThreshold; diff --git a/substrate/client/network/src/request_responses.rs b/substrate/client/network/src/request_responses.rs index 226e1c546d..f51055af55 100644 --- a/substrate/client/network/src/request_responses.rs +++ b/substrate/client/network/src/request_responses.rs @@ -788,7 +788,7 @@ pub enum ResponseFailure { /// Implements the libp2p [`RequestResponseCodec`] trait. Defines how streams of bytes are turned /// into requests and responses and vice-versa. #[derive(Debug, Clone)] -#[doc(hidden)] // Needs to be public in order to satisfy the Rust compiler. +#[doc(hidden)]// Needs to be public in order to satisfy the Rust compiler. pub struct GenericCodec { max_request_size: u64, max_response_size: u64, diff --git a/substrate/frame/election-provider-multi-phase/src/lib.rs b/substrate/frame/election-provider-multi-phase/src/lib.rs index 905492d6ca..48504b6073 100644 --- a/substrate/frame/election-provider-multi-phase/src/lib.rs +++ b/substrate/frame/election-provider-multi-phase/src/lib.rs @@ -237,7 +237,7 @@ use frame_support::{ }; use frame_system::{ensure_none, offchain::SendTransactionTypes}; use sp_arithmetic::{ - traits::{CheckedAdd, Zero}, + traits::{CheckedAdd, Saturating, Zero}, UpperOf, }; use sp_npos_elections::{ @@ -554,7 +554,7 @@ pub use pallet::*; #[frame_support::pallet] pub mod pallet { use super::*; - use frame_support::pallet_prelude::*; + use frame_support::{pallet_prelude::*, traits::EstimateCallFee}; use frame_system::pallet_prelude::*; #[pallet::config] @@ -566,6 +566,9 @@ pub mod pallet { /// Currency type. type Currency: ReservableCurrency + Currency; + /// Something that can predict the fee of a call. Used to sensibly distribute rewards. + type EstimateCallFee: EstimateCallFee, BalanceOf>; + /// Duration of the unsigned phase. #[pallet::constant] type UnsignedPhase: Get; @@ -973,7 +976,13 @@ pub mod pallet { // create the submission let deposit = Self::deposit_for(&solution, size); - let submission = SignedSubmission { who: who.clone(), deposit, solution }; + let reward = { + let call = Call::submit(solution.clone(), num_signed_submissions); + let call_fee = T::EstimateCallFee::estimate_call_fee(&call, None.into()); + T::SignedRewardBase::get().saturating_add(call_fee) + }; + + let submission = SignedSubmission { who: who.clone(), deposit, solution, reward }; // insert the submission if the queue has space or it's better than the weakest // eject the weakest if the queue was full diff --git a/substrate/frame/election-provider-multi-phase/src/mock.rs b/substrate/frame/election-provider-multi-phase/src/mock.rs index c5007733c1..56007f15f8 100644 --- a/substrate/frame/election-provider-multi-phase/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/src/mock.rs @@ -261,7 +261,6 @@ parameter_types! { pub static SignedDepositByte: Balance = 0; pub static SignedDepositWeight: Balance = 0; pub static SignedRewardBase: Balance = 7; - pub static SignedRewardMax: Balance = 10; pub static SignedMaxWeight: Weight = BlockWeights::get().max_block; pub static MinerMaxIterations: u32 = 5; pub static MinerTxPriority: u64 = 100; @@ -356,6 +355,7 @@ impl multi_phase::weights::WeightInfo for DualMockWeightInfo { impl crate::Config for Runtime { type Event = Event; type Currency = Balances; + type EstimateCallFee = frame_support::traits::ConstU32<8>; type SignedPhase = SignedPhase; type UnsignedPhase = UnsignedPhase; type SolutionImprovementThreshold = SolutionImprovementThreshold; diff --git a/substrate/frame/election-provider-multi-phase/src/signed.rs b/substrate/frame/election-provider-multi-phase/src/signed.rs index c91c923d93..40dee8bb78 100644 --- a/substrate/frame/election-provider-multi-phase/src/signed.rs +++ b/substrate/frame/election-provider-multi-phase/src/signed.rs @@ -51,6 +51,8 @@ pub struct SignedSubmission { pub deposit: Balance, /// The raw solution itself. pub solution: RawSolution, + /// The reward that should potentially be paid for this solution, if accepted. + pub reward: Balance, } impl Ord @@ -351,10 +353,8 @@ impl Pallet { let SolutionOrSnapshotSize { voters, targets } = Self::snapshot_metadata().unwrap_or_default(); - let reward = T::SignedRewardBase::get(); - while let Some(best) = all_submissions.pop_last() { - let SignedSubmission { solution, who, deposit } = best; + let SignedSubmission { solution, who, deposit, reward } = best; let active_voters = solution.compact.voter_count() as u32; let feasibility_weight = { // defensive only: at the end of signed phase, snapshot will exits. @@ -567,7 +567,7 @@ mod tests { assert_eq!(balances(&99), (95, 5)); assert!(MultiPhase::finalize_signed_phase().0); - assert_eq!(balances(&99), (100 + 7, 0)); + assert_eq!(balances(&99), (100 + 7 + 8, 0)); }) } @@ -616,7 +616,7 @@ mod tests { assert!(MultiPhase::finalize_signed_phase().0); // 99 is rewarded. - assert_eq!(balances(&99), (100 + 7, 0)); + assert_eq!(balances(&99), (100 + 7 + 8, 0)); // 999 gets everything back. assert_eq!(balances(&999), (100, 0)); }) @@ -807,7 +807,7 @@ mod tests { assert!(MultiPhase::finalize_signed_phase().0); // 99 is rewarded. - assert_eq!(balances(&99), (100 + 7, 0)); + assert_eq!(balances(&99), (100 + 7 + 8, 0)); // 999 is slashed. assert_eq!(balances(&999), (95, 0)); // 9999 gets everything back. diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index fcc3305c40..4c674e1f96 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -51,9 +51,9 @@ pub use filter::{ mod misc; pub use misc::{ - Backing, ConstU32, EnsureInherentsAreFirst, ExecuteBlock, ExtrinsicCall, Get, GetBacking, - GetDefault, HandleLifetime, IsSubType, IsType, Len, OffchainWorker, OnKilledAccount, - OnNewAccount, SameOrOther, Time, TryDrop, UnixTime, + Backing, ConstU32, EnsureInherentsAreFirst, EstimateCallFee, ExecuteBlock, ExtrinsicCall, Get, + GetBacking, GetDefault, HandleLifetime, IsSubType, IsType, Len, OffchainWorker, + OnKilledAccount, OnNewAccount, SameOrOther, Time, TryDrop, UnixTime, }; mod stored_map; diff --git a/substrate/frame/support/src/traits/misc.rs b/substrate/frame/support/src/traits/misc.rs index d6eb8331cd..382c5ebf57 100644 --- a/substrate/frame/support/src/traits/misc.rs +++ b/substrate/frame/support/src/traits/misc.rs @@ -18,7 +18,6 @@ //! Smaller traits used in FRAME which don't need their own file. use crate::dispatch::Parameter; -use sp_arithmetic::traits::AtLeast32Bit; use sp_runtime::{traits::Block as BlockT, DispatchError}; /// Anything that can have a `::len()` method. @@ -181,7 +180,7 @@ pub trait HandleLifetime { impl HandleLifetime for () {} pub trait Time { - type Moment: AtLeast32Bit + Parameter + Default + Copy; + type Moment: sp_arithmetic::traits::AtLeast32Bit + Parameter + Default + Copy; fn now() -> Self::Moment; } @@ -307,7 +306,7 @@ pub trait OffchainWorker { fn offchain_worker(_n: BlockNumber) {} } -/// Some amount of backing from a group. The precise defintion of what it means to "back" something +/// Some amount of backing from a group. The precise definition of what it means to "back" something /// is left flexible. pub struct Backing { /// The number of members of the group that back some motion. @@ -358,3 +357,22 @@ where &self.function } } + +/// Something that can estimate the fee of a (frame-based) call. +/// +/// Typically, the same pallet that will charge transaction fees will implement this. +pub trait EstimateCallFee { + /// Estimate the fee of this call. + /// + /// The dispatch info and the length is deduced from the call. The post info can optionally be + /// provided. + fn estimate_call_fee(call: &Call, post_info: crate::weights::PostDispatchInfo) -> Balance; +} + +// Useful for building mocks. +#[cfg(feature = "std")] +impl, const T: u32> EstimateCallFee for ConstU32 { + fn estimate_call_fee(_: &Call, _: crate::weights::PostDispatchInfo) -> Balance { + T.into() + } +} diff --git a/substrate/frame/transaction-payment/src/lib.rs b/substrate/frame/transaction-payment/src/lib.rs index 882f37dcee..61de183dac 100644 --- a/substrate/frame/transaction-payment/src/lib.rs +++ b/substrate/frame/transaction-payment/src/lib.rs @@ -52,7 +52,7 @@ use codec::{Decode, Encode}; use sp_runtime::{ traits::{ Convert, DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SaturatedConversion, Saturating, - SignedExtension, + SignedExtension, Zero, }, transaction_validity::{ TransactionPriority, TransactionValidity, TransactionValidityError, ValidTransaction, @@ -63,7 +63,7 @@ use sp_std::prelude::*; use frame_support::{ dispatch::DispatchResult, - traits::Get, + traits::{EstimateCallFee, Get}, weights::{ DispatchClass, DispatchInfo, GetDispatchInfo, Pays, PostDispatchInfo, Weight, WeightToFeeCoefficient, WeightToFeePolynomial, @@ -656,6 +656,19 @@ where } } +impl EstimateCallFee> + for Pallet +where + BalanceOf: FixedPointOperand, + T::Call: Dispatchable, +{ + fn estimate_call_fee(call: &AnyCall, post_info: PostDispatchInfo) -> BalanceOf { + let len = call.encoded_size() as u32; + let info = call.get_dispatch_info(); + Self::compute_actual_fee(len, &info, &post_info, Zero::zero()) + } +} + #[cfg(test)] mod tests { use super::*;