diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs index 8d57e6fbf8c27b286a9c76fa02e9c84c20fcec9a..ed10357e5983f3e0e04426d76ea7bddf35c5a11a 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -24,7 +24,7 @@ use sp_std::prelude::*; use frame_support::{ construct_runtime, parameter_types, debug, weights::Weight, - traits::{SplitTwoWays, Currency, Randomness}, + traits::{Currency, Randomness, OnUnbalanced, Imbalance}, }; use sp_core::u32_trait::{_1, _2, _3, _4}; pub use node_primitives::{AccountId, Signature}; @@ -98,12 +98,21 @@ pub fn native_version() -> NativeVersion { type NegativeImbalance = <Balances as Currency<AccountId>>::NegativeImbalance; -pub type DealWithFees = SplitTwoWays< - Balance, - NegativeImbalance, - _4, Treasury, // 4 parts (80%) goes to the treasury. - _1, Author, // 1 part (20%) goes to the block author. ->; +pub struct DealWithFees; +impl OnUnbalanced<NegativeImbalance> for DealWithFees { + fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item=NegativeImbalance>) { + if let Some(fees) = fees_then_tips.next() { + // for fees, 80% to treasury, 20% to author + let mut split = fees.ration(80, 20); + if let Some(tips) = fees_then_tips.next() { + // for tips, if any, 80% to treasury, 20% to author (though this can be anything) + tips.ration_merge_into(80, 20, &mut split); + } + Treasury::on_unbalanced(split.0); + Author::on_unbalanced(split.1); + } + } +} parameter_types! { pub const BlockHashCount: BlockNumber = 250; diff --git a/substrate/frame/support/src/traits.rs b/substrate/frame/support/src/traits.rs index c1e9e7c317159b2b4eaeee51ade9762a7c311389..2e87629a9f02e86671c5fc7d726703e15401bf83 100644 --- a/substrate/frame/support/src/traits.rs +++ b/substrate/frame/support/src/traits.rs @@ -256,6 +256,13 @@ pub trait KeyOwnerProofSystem<Key> { /// - Someone got slashed. /// - Someone paid for a transaction to be included. pub trait OnUnbalanced<Imbalance: TryDrop> { + /// Handler for some imbalances. The different imbalances might have different origins or + /// meanings, dependent on the context. Will default to simply calling on_unbalanced for all + /// of them. Infallible. + fn on_unbalanceds<B>(amounts: impl Iterator<Item=Imbalance>) where Imbalance: crate::traits::Imbalance<B> { + Self::on_unbalanced(amounts.fold(Imbalance::zero(), |i, x| x.merge(i))) + } + /// Handler for some imbalance. Infallible. fn on_unbalanced(amount: Imbalance) { amount.try_drop().unwrap_or_else(Self::on_nonzero_unbalanced) @@ -263,13 +270,11 @@ pub trait OnUnbalanced<Imbalance: TryDrop> { /// Actually handle a non-zero imbalance. You probably want to implement this rather than /// `on_unbalanced`. - fn on_nonzero_unbalanced(amount: Imbalance); -} - -impl<Imbalance: TryDrop> OnUnbalanced<Imbalance> for () { fn on_nonzero_unbalanced(amount: Imbalance) { drop(amount); } } +impl<Imbalance: TryDrop> OnUnbalanced<Imbalance> for () {} + /// Simple boolean for whether an account needs to be kept in existence. #[derive(Copy, Clone, Eq, PartialEq)] pub enum ExistenceRequirement { @@ -331,10 +336,71 @@ pub trait Imbalance<Balance>: Sized + TryDrop { /// is guaranteed to be at most `amount` and the second will be the remainder. fn split(self, amount: Balance) -> (Self, Self); + /// Consume `self` and return two independent instances; the amounts returned will be in + /// approximately the same ratio as `first`:`second`. + /// + /// NOTE: This requires up to `first + second` room for a multiply, and `first + second` should + /// fit into a `u32`. Overflow will safely saturate in both cases. + fn ration(self, first: u32, second: u32) -> (Self, Self) + where Balance: From<u32> + Saturating + Div<Output=Balance> + { + let total: u32 = first.saturating_add(second); + let amount1 = self.peek().saturating_mul(first.into()) / total.into(); + self.split(amount1) + } + + /// Consume self and add its two components, defined by the first component's balance, + /// element-wise to two pre-existing Imbalances. + /// + /// A convenient replacement for `split` and `merge`. + fn split_merge(self, amount: Balance, others: (Self, Self)) -> (Self, Self) { + let (a, b) = self.split(amount); + (a.merge(others.0), b.merge(others.1)) + } + + /// Consume self and add its two components, defined by the ratio `first`:`second`, + /// element-wise to two pre-existing Imbalances. + /// + /// A convenient replacement for `split` and `merge`. + fn ration_merge(self, first: u32, second: u32, others: (Self, Self)) -> (Self, Self) + where Balance: From<u32> + Saturating + Div<Output=Balance> + { + let (a, b) = self.ration(first, second); + (a.merge(others.0), b.merge(others.1)) + } + + /// Consume self and add its two components, defined by the first component's balance, + /// element-wise into two pre-existing Imbalance refs. + /// + /// A convenient replacement for `split` and `subsume`. + fn split_merge_into(self, amount: Balance, others: &mut (Self, Self)) { + let (a, b) = self.split(amount); + others.0.subsume(a); + others.1.subsume(b); + } + + /// Consume self and add its two components, defined by the ratio `first`:`second`, + /// element-wise to two pre-existing Imbalances. + /// + /// A convenient replacement for `split` and `merge`. + fn ration_merge_into(self, first: u32, second: u32, others: &mut (Self, Self)) + where Balance: From<u32> + Saturating + Div<Output=Balance> + { + let (a, b) = self.ration(first, second); + others.0.subsume(a); + others.1.subsume(b); + } + /// Consume `self` and an `other` to return a new instance that combines /// both. fn merge(self, other: Self) -> Self; + /// Consume self to mutate `other` so that it combines both. Just like `subsume`, only with + /// reversed arguments. + fn merge_into(self, other: &mut Self) { + other.subsume(self) + } + /// Consume `self` and maybe an `other` to return a new instance that combines /// both. fn maybe_merge(self, other: Option<Self>) -> Self { diff --git a/substrate/frame/transaction-payment/src/lib.rs b/substrate/frame/transaction-payment/src/lib.rs index fe15bdf79465c8256f94e5f9e90a6731e2a9aff1..2367d5ee5abe30b1b1b8e661d446c1ae9202330a 100644 --- a/substrate/frame/transaction-payment/src/lib.rs +++ b/substrate/frame/transaction-payment/src/lib.rs @@ -35,7 +35,7 @@ use sp_std::prelude::*; use codec::{Encode, Decode}; use frame_support::{ decl_storage, decl_module, - traits::{Currency, Get, OnUnbalanced, ExistenceRequirement, WithdrawReason}, + traits::{Currency, Get, OnUnbalanced, ExistenceRequirement, WithdrawReason, Imbalance}, weights::{Weight, DispatchInfo, GetDispatchInfo}, }; use sp_runtime::{ @@ -58,7 +58,9 @@ pub trait Trait: frame_system::Trait { /// The currency type in which fees will be paid. type Currency: Currency<Self::AccountId> + Send + Sync; - /// Handler for the unbalanced reduction when taking transaction fees. + /// Handler for the unbalanced reduction when taking transaction fees. This is either one or + /// two separate imbalances, the first is the transaction fee paid, the second is the tip paid, + /// if any. type OnTransactionPayment: OnUnbalanced<NegativeImbalanceOf<Self>>; /// The fee to be paid for making a transaction; the base. @@ -234,7 +236,9 @@ impl<T: Trait + Send + Sync> SignedExtension for ChargeTransactionPayment<T> Ok(imbalance) => imbalance, Err(_) => return InvalidTransaction::Payment.into(), }; - T::OnTransactionPayment::on_unbalanced(imbalance); + let imbalances = imbalance.split(tip); + T::OnTransactionPayment::on_unbalanceds(Some(imbalances.0).into_iter() + .chain(Some(imbalances.1))); } let mut r = ValidTransaction::default();