Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
Impl WeightTrader for tuple (#3601)
Browse files Browse the repository at this point in the history
* Impl WeightTrader for tuple.

* fmt

* Renaming.

* add tracing for buy_weight

* Add comment clarifying the default behavior of a WeightTrader tuple

Co-authored-by: Alexander Popiak <alexander.popiak@parity.io>
Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>
  • Loading branch information
3 people authored and chevdor committed Sep 13, 2021
1 parent 24c155a commit 38e52c3
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 4 deletions.
50 changes: 50 additions & 0 deletions xcm/xcm-builder/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.

use super::{mock::*, *};
use frame_support::{assert_err, weights::constants::WEIGHT_PER_SECOND};
use xcm::latest::prelude::*;
use xcm_executor::{traits::*, Config, XcmExecutor};

Expand Down Expand Up @@ -383,3 +384,52 @@ fn prepaid_result_of_query_should_get_free_execution() {
let r = XcmExecutor::<TestConfig>::execute_xcm(origin.clone(), message.clone(), weight_limit);
assert_eq!(r, Outcome::Incomplete(10, XcmError::Barrier));
}

fn fungible_multi_asset(location: MultiLocation, amount: u128) -> MultiAsset {
(AssetId::from(location), Fungibility::Fungible(amount)).into()
}

#[test]
fn weight_trader_tuple_should_work() {
pub const PARA_1: MultiLocation = X1(Parachain(1));
pub const PARA_2: MultiLocation = X1(Parachain(2));

parameter_types! {
pub static HereWeightPrice: (AssetId, u128) = (Here.into(), WEIGHT_PER_SECOND.into());
pub static PARA1WeightPrice: (AssetId, u128) = (PARA_1.into(), WEIGHT_PER_SECOND.into());
}

type Traders = (
// trader one
FixedRateOfFungible<HereWeightPrice, ()>,
// trader two
FixedRateOfFungible<PARA1WeightPrice, ()>,
);

let mut traders = Traders::new();
// trader one buys weight
assert_eq!(
traders.buy_weight(5, fungible_multi_asset(Here, 10).into()),
Ok(fungible_multi_asset(Here, 5).into()),
);
// trader one refunds
assert_eq!(traders.refund_weight(2), Some(fungible_multi_asset(Here, 2)));

let mut traders = Traders::new();
// trader one failed; trader two buys weight
assert_eq!(
traders.buy_weight(5, fungible_multi_asset(PARA_1, 10).into()),
Ok(fungible_multi_asset(PARA_1, 5).into()),
);
// trader two refunds
assert_eq!(traders.refund_weight(2), Some(fungible_multi_asset(PARA_1, 2)));

let mut traders = Traders::new();
// all traders fails
assert_err!(
traders.buy_weight(5, fungible_multi_asset(PARA_2, 10).into()),
XcmError::TooExpensive,
);
// and no refund
assert_eq!(traders.refund_weight(2), None);
}
33 changes: 29 additions & 4 deletions xcm/xcm-executor/src/traits/weight.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ pub trait UniversalWeigher {
}

/// Charge for weight in order to execute XCM.
///
/// A `WeightTrader` may also be put into a tuple, in which case the default behavior of
/// `buy_weight` and `refund_weight` would be to attempt to call each tuple element's own
/// implementation of these two functions, in the order of which they appear in the tuple,
/// returning early when a successful result is returned.
pub trait WeightTrader: Sized {
/// Create a new trader instance.
fn new() -> Self;
Expand All @@ -76,11 +81,31 @@ pub trait WeightTrader: Sized {
}
}

impl WeightTrader for () {
#[impl_trait_for_tuples::impl_for_tuples(30)]
impl WeightTrader for Tuple {
fn new() -> Self {
()
for_tuples!( ( #( Tuple::new() ),* ) )
}
fn buy_weight(&mut self, _: Weight, _: Assets) -> Result<Assets, Error> {
Err(Error::Unimplemented)

fn buy_weight(&mut self, weight: Weight, payment: Assets) -> Result<Assets, Error> {
let mut last_error = None;
for_tuples!( #(
match Tuple.buy_weight(weight, payment.clone()) {
Ok(assets) => return Ok(assets),
Err(e) => { last_error = Some(e) }
}
)* );
let last_error = last_error.unwrap_or(Error::TooExpensive);
log::trace!(target: "xcm::buy_weight", "last_error: {:?}", last_error);
Err(last_error)
}

fn refund_weight(&mut self, weight: Weight) -> Option<MultiAsset> {
for_tuples!( #(
if let Some(asset) = Tuple.refund_weight(weight) {
return Some(asset);
}
)* );
None
}
}

0 comments on commit 38e52c3

Please sign in to comment.