Skip to content

Commit 6d0926e

Browse files
muharemggwpez
andauthored
Make on_unbalanceds work with fungibles imbalances (#4564)
Make `on_unbalanceds` work with `fungibles` `imbalances`. The `fungibles` `imbalances` cannot be handled by the default implementation of `on_unbalanceds` from the `OnUnbalanced` trait. This is because the `fungibles` `imbalances` types do not implement the `Imbalance` trait (and cannot with its current semantics). The `on_unbalanceds` function requires only the `merge` function for the imbalance type. In this PR, we provide the `TryMerge` trait, which can be implemented by all imbalance types and make `OnUnbalanced` require it instead `Imbalance`. ### Migration for `OnUnbalanced` trait implementations: In case if you have a custom implementation of `on_unbalanceds` trait function, remove it's `<B>` type argument. ### Migration for custom imbalance types: If you have your own imbalance types implementations, implement the `TryMerge` trait for it introduced with this update. The applicability of the `on_unbalanceds` function to fungibles imbalances is useful in cases like - [link](https://github.com/paritytech/polkadot-sdk/blob/3a8e675e9f6f283514c00c14d3d1d90ed5bf59c0/substrate/frame/transaction-payment/asset-conversion-tx-payment/src/payment.rs#L267) from #4488. --------- Co-authored-by: Oliver Tale-Yazdi <[email protected]>
1 parent 2bd187f commit 6d0926e

11 files changed

Lines changed: 108 additions & 12 deletions

File tree

cumulus/parachains/common/src/impls.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ where
6767
AccountIdOf<R>: From<polkadot_primitives::AccountId> + Into<polkadot_primitives::AccountId>,
6868
<R as frame_system::Config>::RuntimeEvent: From<pallet_balances::Event<R>>,
6969
{
70-
fn on_unbalanceds<B>(
70+
fn on_unbalanceds(
7171
mut fees_then_tips: impl Iterator<
7272
Item = fungible::Credit<R::AccountId, pallet_balances::Pallet<R>>,
7373
>,

polkadot/runtime/common/src/impls.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ where
5151
<R as frame_system::Config>::AccountId: From<polkadot_primitives::AccountId>,
5252
<R as frame_system::Config>::AccountId: Into<polkadot_primitives::AccountId>,
5353
{
54-
fn on_unbalanceds<B>(
54+
fn on_unbalanceds(
5555
mut fees_then_tips: impl Iterator<Item = Credit<R::AccountId, pallet_balances::Pallet<R>>>,
5656
) {
5757
if let Some(fees) = fees_then_tips.next() {

prdoc/pr_4564.prdoc

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
title: "Make `OnUnbalanced::on_unbalanceds` work with `fungibles` `imbalances`"
2+
3+
doc:
4+
- audience: Runtime Dev
5+
description: |
6+
The `on_unbalanceds` function of `OnUnbalanced` trait accepts the `fungibles` `imbalances`
7+
imbalances. This is done by replacing the `Imbalance` trait bound on imbalance type with
8+
the `TryMerge` trait bound. The `TryMerge` trait is implemented for all imbalance types.
9+
10+
### Migration for `OnUnbalanced` trait implementations:
11+
In case if you have a custom implementation of `on_unbalanceds` trait function, remove
12+
it's `<B>` type argument.
13+
14+
### Migration for custom imbalance types:
15+
If you have your own imbalance types implementations, implement the `TryMerge` trait for it
16+
introduced with this update.
17+
18+
crates:
19+
- name: frame-support
20+
bump: major
21+
- name: pallet-balances
22+
bump: minor
23+
- name: pallet-asset-conversion-tx-payment
24+
bump: patch
25+
- name: pallet-transaction-payment
26+
bump: patch
27+
- name: kitchensink-runtime
28+
bump: patch
29+
- name: polkadot-runtime-common
30+
bump: patch
31+
- name: parachains-common
32+
bump: minor

substrate/bin/node/runtime/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ type NegativeImbalance = <Balances as Currency<AccountId>>::NegativeImbalance;
189189

190190
pub struct DealWithFees;
191191
impl OnUnbalanced<NegativeImbalance> for DealWithFees {
192-
fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item = NegativeImbalance>) {
192+
fn on_unbalanceds(mut fees_then_tips: impl Iterator<Item = NegativeImbalance>) {
193193
if let Some(fees) = fees_then_tips.next() {
194194
// for fees, 80% to treasury, 20% to author
195195
let mut split = fees.ration(80, 20);

substrate/frame/balances/src/impl_currency.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ use sp_runtime::traits::Bounded;
4141
mod imbalances {
4242
use super::*;
4343
use core::mem;
44-
use frame_support::traits::SameOrOther;
44+
use frame_support::traits::{tokens::imbalance::TryMerge, SameOrOther};
4545

4646
/// Opaque, move-only struct with private fields that serves as a token denoting that
4747
/// funds have been created without any equal and opposite accounting.
@@ -133,6 +133,12 @@ mod imbalances {
133133
}
134134
}
135135

136+
impl<T: Config<I>, I: 'static> TryMerge for PositiveImbalance<T, I> {
137+
fn try_merge(self, other: Self) -> Result<Self, (Self, Self)> {
138+
Ok(self.merge(other))
139+
}
140+
}
141+
136142
impl<T: Config<I>, I: 'static> TryDrop for NegativeImbalance<T, I> {
137143
fn try_drop(self) -> result::Result<(), Self> {
138144
self.drop_zero()
@@ -197,6 +203,12 @@ mod imbalances {
197203
}
198204
}
199205

206+
impl<T: Config<I>, I: 'static> TryMerge for NegativeImbalance<T, I> {
207+
fn try_merge(self, other: Self) -> Result<Self, (Self, Self)> {
208+
Ok(self.merge(other))
209+
}
210+
}
211+
200212
impl<T: Config<I>, I: 'static> Drop for PositiveImbalance<T, I> {
201213
/// Basic drop handler will just square up the total issuance.
202214
fn drop(&mut self) {

substrate/frame/support/src/traits/tokens/fungible/imbalance.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use super::{super::Imbalance as ImbalanceT, Balanced, *};
2424
use crate::traits::{
2525
fungibles,
2626
misc::{SameOrOther, TryDrop},
27-
tokens::{AssetId, Balance},
27+
tokens::{imbalance::TryMerge, AssetId, Balance},
2828
};
2929
use core::marker::PhantomData;
3030
use frame_support_procedural::{EqNoBound, PartialEqNoBound, RuntimeDebugNoBound};
@@ -157,6 +157,14 @@ impl<B: Balance, OnDrop: HandleImbalanceDrop<B>, OppositeOnDrop: HandleImbalance
157157
}
158158
}
159159

160+
impl<B: Balance, OnDrop: HandleImbalanceDrop<B>, OppositeOnDrop: HandleImbalanceDrop<B>> TryMerge
161+
for Imbalance<B, OnDrop, OppositeOnDrop>
162+
{
163+
fn try_merge(self, other: Self) -> Result<Self, (Self, Self)> {
164+
Ok(self.merge(other))
165+
}
166+
}
167+
160168
/// Converts a `fungibles` `imbalance` instance to an instance of a `fungible` imbalance type.
161169
///
162170
/// This function facilitates imbalance conversions within the implementations of

substrate/frame/support/src/traits/tokens/fungibles/imbalance.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ use super::*;
2424
use crate::traits::{
2525
fungible,
2626
misc::{SameOrOther, TryDrop},
27-
tokens::{imbalance::Imbalance as ImbalanceT, AssetId, Balance},
27+
tokens::{
28+
imbalance::{Imbalance as ImbalanceT, TryMerge},
29+
AssetId, Balance,
30+
},
2831
};
2932
use core::marker::PhantomData;
3033
use frame_support_procedural::{EqNoBound, PartialEqNoBound, RuntimeDebugNoBound};
@@ -176,6 +179,18 @@ impl<
176179
}
177180
}
178181

182+
impl<
183+
A: AssetId,
184+
B: Balance,
185+
OnDrop: HandleImbalanceDrop<A, B>,
186+
OppositeOnDrop: HandleImbalanceDrop<A, B>,
187+
> TryMerge for Imbalance<A, B, OnDrop, OppositeOnDrop>
188+
{
189+
fn try_merge(self, other: Self) -> Result<Self, (Self, Self)> {
190+
self.merge(other)
191+
}
192+
}
193+
179194
/// Converts a `fungible` `imbalance` instance to an instance of a `fungibles` imbalance type using
180195
/// a specified `asset`.
181196
///

substrate/frame/support/src/traits/tokens/imbalance.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ pub use split_two_ways::SplitTwoWays;
5858
///
5959
/// You can always retrieve the raw balance value using `peek`.
6060
#[must_use]
61-
pub trait Imbalance<Balance>: Sized + TryDrop + Default {
61+
pub trait Imbalance<Balance>: Sized + TryDrop + Default + TryMerge {
6262
/// The oppositely imbalanced type. They come in pairs.
6363
type Opposite: Imbalance<Balance>;
6464

@@ -182,6 +182,13 @@ pub trait Imbalance<Balance>: Sized + TryDrop + Default {
182182
fn peek(&self) -> Balance;
183183
}
184184

185+
/// Try to merge two imbalances.
186+
pub trait TryMerge: Sized {
187+
/// Consume `self` and an `other` to return a new instance that combines both. Errors with
188+
/// Err(self, other) if the imbalances cannot be merged (e.g. imbalances of different assets).
189+
fn try_merge(self, other: Self) -> Result<Self, (Self, Self)>;
190+
}
191+
185192
#[cfg(feature = "std")]
186193
impl<Balance: Default> Imbalance<Balance> for () {
187194
type Opposite = ();
@@ -236,3 +243,10 @@ impl<Balance: Default> Imbalance<Balance> for () {
236243
Default::default()
237244
}
238245
}
246+
247+
#[cfg(feature = "std")]
248+
impl TryMerge for () {
249+
fn try_merge(self, _: Self) -> Result<Self, (Self, Self)> {
250+
Ok(())
251+
}
252+
}

substrate/frame/support/src/traits/tokens/imbalance/on_unbalanced.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,26 @@ pub trait OnUnbalanced<Imbalance: TryDrop> {
3535
/// Handler for some imbalances. The different imbalances might have different origins or
3636
/// meanings, dependent on the context. Will default to simply calling on_unbalanced for all
3737
/// of them. Infallible.
38-
fn on_unbalanceds<B>(amounts: impl Iterator<Item = Imbalance>)
38+
fn on_unbalanceds(mut amounts: impl Iterator<Item = Imbalance>)
3939
where
40-
Imbalance: crate::traits::Imbalance<B>,
40+
Imbalance: crate::traits::tokens::imbalance::TryMerge,
4141
{
42-
Self::on_unbalanced(amounts.fold(Imbalance::zero(), |i, x| x.merge(i)))
42+
let mut sum: Option<Imbalance> = None;
43+
while let Some(next) = amounts.next() {
44+
sum = match sum {
45+
Some(sum) => match sum.try_merge(next) {
46+
Ok(sum) => Some(sum),
47+
Err((sum, next)) => {
48+
Self::on_unbalanced(next);
49+
Some(sum)
50+
},
51+
},
52+
None => Some(next),
53+
}
54+
}
55+
if let Some(sum) = sum {
56+
Self::on_unbalanced(sum)
57+
}
4358
}
4459

4560
/// Handler for some imbalance. Infallible.

substrate/frame/transaction-payment/asset-conversion-tx-payment/src/mock.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ pub struct DealWithFees;
131131
impl OnUnbalanced<fungible::Credit<<Runtime as frame_system::Config>::AccountId, Balances>>
132132
for DealWithFees
133133
{
134-
fn on_unbalanceds<B>(
134+
fn on_unbalanceds(
135135
mut fees_then_tips: impl Iterator<
136136
Item = fungible::Credit<<Runtime as frame_system::Config>::AccountId, Balances>,
137137
>,

0 commit comments

Comments
 (0)