(
+pub fn claim_slot_inner(
slot: Slot,
authorities: &Vec>,
keystore: &KeystorePtr,
diff --git a/client/consensus/src/collators/lookahead.rs b/client/consensus/src/collators/lookahead.rs
index 8d9f6e11d..611ff3bfd 100644
--- a/client/consensus/src/collators/lookahead.rs
+++ b/client/consensus/src/collators/lookahead.rs
@@ -464,10 +464,10 @@ where
// Here we lean on the property that building on an empty unincluded segment must always
// be legal. Skipping the runtime API query here allows us to seamlessly run this
// collator against chains which have not yet upgraded their runtime.
- if parent_header.hash() != included_block {
- if !runtime_api.can_build_upon(parent_header.hash(), included_block, slot)? {
- return Ok(None);
- }
+ if parent_header.hash() != included_block
+ && !runtime_api.can_build_upon(parent_header.hash(), included_block, slot)?
+ {
+ return Ok(None);
}
slot_claim
diff --git a/client/consensus/src/consensus_orchestrator.rs b/client/consensus/src/consensus_orchestrator.rs
index f941b8c98..04d938829 100644
--- a/client/consensus/src/consensus_orchestrator.rs
+++ b/client/consensus/src/consensus_orchestrator.rs
@@ -22,8 +22,6 @@
//! it implements the TanssiWorker to TanssiOnSlot trait. This trait is
use {
crate::{AuthorityId, Pair, Slot},
- sc_consensus_slots::{SimpleSlotWorker, SlotInfo, SlotResult},
- sp_consensus::Proposer,
sp_runtime::traits::Block as BlockT,
};
@@ -63,17 +61,3 @@ where
pub authorities: Vec>,
pub min_slot_freq: Option,
}
-
-#[async_trait::async_trait]
-pub trait TanssiSlotWorker: SimpleSlotWorker {
- /// Called when a new slot is triggered.
- ///
- /// Returns a future that resolves to a [`SlotResult`] iff a block was successfully built in
- /// the slot. Otherwise `None` is returned.
- /// Accepts the orchestrator header as an input
- async fn tanssi_on_slot(
- &mut self,
- slot_info: SlotInfo,
- aux_data: Self::AuxData,
- ) -> Option>::Proof>>;
-}
diff --git a/client/consensus/src/tests.rs b/client/consensus/src/tests.rs
index 614364478..025ecac0b 100644
--- a/client/consensus/src/tests.rs
+++ b/client/consensus/src/tests.rs
@@ -133,7 +133,7 @@ sp_api::mock_impl_runtime_apis! {
}
#[derive(Clone)]
-struct RelayChain(Arc);
+struct RelayChain;
#[async_trait]
impl RelayChainInterface for RelayChain {
@@ -252,7 +252,7 @@ impl RelayChainInterface for RelayChain {
}
#[derive(Clone)]
-struct DummySpawner(Arc);
+struct DummySpawner;
impl SpawnNamed for DummySpawner {
fn spawn_blocking(
&self,
@@ -271,7 +271,7 @@ impl SpawnNamed for DummySpawner {
}
}
-struct DummyProposer(u64, Arc);
+struct DummyProposer(Arc);
// This is going to be our block verifier
// It will mimic what the Nimbus verifier does, but again, Nimbus verifier is non-public
@@ -354,8 +354,8 @@ impl Environment for DummyFactory {
type CreateProposer = future::Ready>;
type Error = Error;
- fn init(&mut self, parent_header: &::Header) -> Self::CreateProposer {
- future::ready(Ok(DummyProposer(parent_header.number + 1, self.0.clone())))
+ fn init(&mut self, _parent_header: &::Header) -> Self::CreateProposer {
+ future::ready(Ok(DummyProposer(self.0.clone())))
}
}
@@ -373,9 +373,9 @@ impl Proposer for DummyProposer {
_: Duration,
_: Option,
) -> Self::Proposal {
- let r = BlockBuilderBuilder::new(&*self.1)
- .on_parent_block(self.1.chain_info().best_hash)
- .fetch_parent_block_number(&*self.1)
+ let r = BlockBuilderBuilder::new(&*self.0)
+ .on_parent_block(self.0.chain_info().best_hash)
+ .fetch_parent_block_number(&*self.0)
.unwrap()
.with_inherent_digests(digests)
.build()
@@ -562,8 +562,8 @@ async fn collate_returns_correct_block() {
let peer = net.peer(3);
let client = peer.client().as_client();
let environ = DummyFactory(client.clone());
- let spawner = DummySpawner(client.clone());
- let relay_client = RelayChain(client.clone());
+ let spawner = DummySpawner;
+ let relay_client = RelayChain;
// Build the collator
let mut collator = {
diff --git a/container-chains/nodes/frontier/src/client.rs b/container-chains/nodes/frontier/src/client.rs
deleted file mode 100644
index 49b3c41f9..000000000
--- a/container-chains/nodes/frontier/src/client.rs
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (C) Moondance Labs Ltd.
-// This file is part of Tanssi.
-
-// Tanssi 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.
-
-// Tanssi 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 Tanssi. If not, see .
-
-// Substrate
-use sp_consensus_aura::sr25519::AuthorityId as AuraId;
-// Local
-use container_chain_template_frontier_runtime::{opaque::Block, AccountId, Index};
-
-use crate::eth::EthCompatRuntimeApiCollection;
-
-/// A set of APIs that every runtimes must implement.
-pub trait BaseRuntimeApiCollection:
- sp_api::ApiExt
- + sp_api::Metadata
- + sp_block_builder::BlockBuilder
- + sp_offchain::OffchainWorkerApi
- + sp_session::SessionKeys
- + sp_transaction_pool::runtime_api::TaggedTransactionQueue
-{
-}
-
-impl BaseRuntimeApiCollection for Api where
- Api: sp_api::ApiExt
- + sp_api::Metadata
- + sp_block_builder::BlockBuilder
- + sp_offchain::OffchainWorkerApi
- + sp_session::SessionKeys
- + sp_transaction_pool::runtime_api::TaggedTransactionQueue
-{
-}
-
-/// A set of APIs that template runtime must implement.
-pub trait RuntimeApiCollection:
- BaseRuntimeApiCollection
- + EthCompatRuntimeApiCollection
- + sp_consensus_aura::AuraApi
- + frame_system_rpc_runtime_api::AccountNonceApi
-{
-}
-
-impl RuntimeApiCollection for Api where
- Api: BaseRuntimeApiCollection
- + EthCompatRuntimeApiCollection
- + sp_consensus_aura::AuraApi
- + frame_system_rpc_runtime_api::AccountNonceApi
-{
-}
diff --git a/container-chains/nodes/frontier/src/eth.rs b/container-chains/nodes/frontier/src/eth.rs
deleted file mode 100644
index 2ddf51e76..000000000
--- a/container-chains/nodes/frontier/src/eth.rs
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (C) Moondance Labs Ltd.
-// This file is part of Tanssi.
-
-// Tanssi 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.
-
-// Tanssi 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 Tanssi. If not, see .
-
-// Local
-use container_chain_template_frontier_runtime::opaque::Block;
-
-/// A set of APIs that ethereum-compatible runtimes must implement.
-pub trait EthCompatRuntimeApiCollection:
- sp_api::ApiExt
- + fp_rpc::EthereumRuntimeRPCApi
- + fp_rpc::ConvertTransactionRuntimeApi
-{
-}
-
-impl EthCompatRuntimeApiCollection for Api where
- Api: sp_api::ApiExt
- + fp_rpc::EthereumRuntimeRPCApi
- + fp_rpc::ConvertTransactionRuntimeApi
-{
-}
diff --git a/container-chains/nodes/frontier/src/main.rs b/container-chains/nodes/frontier/src/main.rs
index b5163b5df..984f332e0 100644
--- a/container-chains/nodes/frontier/src/main.rs
+++ b/container-chains/nodes/frontier/src/main.rs
@@ -20,9 +20,7 @@
mod chain_spec;
mod cli;
-mod client;
mod command;
-mod eth;
mod rpc;
mod service;
diff --git a/container-chains/runtime-templates/frontier/src/lib.rs b/container-chains/runtime-templates/frontier/src/lib.rs
index e55d56bb2..b369b3a0c 100644
--- a/container-chains/runtime-templates/frontier/src/lib.rs
+++ b/container-chains/runtime-templates/frontier/src/lib.rs
@@ -1524,6 +1524,7 @@ impl_runtime_apis! {
}
}
+#[allow(dead_code)]
struct CheckInherents;
// TODO: this should be removed but currently if we remove it the relay does not check anything
diff --git a/container-chains/runtime-templates/simple/src/lib.rs b/container-chains/runtime-templates/simple/src/lib.rs
index 702981e5f..03a450db3 100644
--- a/container-chains/runtime-templates/simple/src/lib.rs
+++ b/container-chains/runtime-templates/simple/src/lib.rs
@@ -1099,6 +1099,7 @@ impl_runtime_apis! {
}
}
+#[allow(dead_code)]
struct CheckInherents;
#[allow(deprecated)]
diff --git a/node/src/chain_spec/dancebox.rs b/node/src/chain_spec/dancebox.rs
index 29fbaacef..1d1c92671 100644
--- a/node/src/chain_spec/dancebox.rs
+++ b/node/src/chain_spec/dancebox.rs
@@ -288,22 +288,3 @@ fn mock_container_chain_genesis_data>(
properties: Default::default(),
}
}
-
-/// Can be called for a `Configuration` to check if it is a configuration for
-/// the `Tanssi` network.
-pub trait IdentifyVariant {
- /// Returns `true` if this is a configuration for the `Dancebox` network.
- fn is_dancebox(&self) -> bool;
- /// Returns `true` if this is a configuration for a dev network.
- fn is_dev(&self) -> bool;
-}
-
-impl IdentifyVariant for Box {
- fn is_dancebox(&self) -> bool {
- self.id().starts_with("dancebox")
- }
-
- fn is_dev(&self) -> bool {
- self.chain_type() == sc_chain_spec::ChainType::Development
- }
-}
diff --git a/node/src/chain_spec/flashbox.rs b/node/src/chain_spec/flashbox.rs
index ab45835cb..48593555c 100644
--- a/node/src/chain_spec/flashbox.rs
+++ b/node/src/chain_spec/flashbox.rs
@@ -286,22 +286,3 @@ fn mock_container_chain_genesis_data>(
properties: Default::default(),
}
}
-
-/// Can be called for a `Configuration` to check if it is a configuration for
-/// the `Tanssi` network.
-pub trait IdentifyVariant {
- /// Returns `true` if this is a configuration for the `Flashbox` network.
- fn is_flashbox(&self) -> bool;
- /// Returns `true` if this is a configuration for a dev network.
- fn is_dev(&self) -> bool;
-}
-
-impl IdentifyVariant for Box {
- fn is_flashbox(&self) -> bool {
- self.id().starts_with("flashbox")
- }
-
- fn is_dev(&self) -> bool {
- self.chain_type() == sc_chain_spec::ChainType::Development
- }
-}
diff --git a/pallets/authority-assignment/src/mock.rs b/pallets/authority-assignment/src/mock.rs
index 4e0d47b45..44bf6eac7 100644
--- a/pallets/authority-assignment/src/mock.rs
+++ b/pallets/authority-assignment/src/mock.rs
@@ -126,10 +126,6 @@ pub fn new_test_ext() -> sp_io::TestExternalities {
.into()
}
-pub trait GetCollators {
- fn collators(session_index: SessionIndex) -> Vec;
-}
-
pub const SESSION_LEN: u64 = 5;
pub fn run_to_session(n: u32) {
diff --git a/pallets/initializer/src/lib.rs b/pallets/initializer/src/lib.rs
index 951a00205..60f622f04 100644
--- a/pallets/initializer/src/lib.rs
+++ b/pallets/initializer/src/lib.rs
@@ -73,13 +73,13 @@ pub mod pallet {
impl Pallet {
/// Should be called when a new session occurs. If `queued` is `None`,
/// the `validators` are considered queued.
- fn on_new_session<'a, I: 'a>(
+ fn on_new_session<'a, I>(
changed: bool,
session_index: T::SessionIndex,
validators: I,
queued: Option,
) where
- I: Iterator- ,
+ I: Iterator
- + 'a,
{
let validators: Vec<_> = validators.map(|(k, v)| (k.clone(), v)).collect();
let queued: Vec<_> = if let Some(queued) = queued {
@@ -93,9 +93,9 @@ impl Pallet {
/// Should be called when a new session occurs. Buffers the session notification to be applied
/// at the end of the block. If `queued` is `None`, the `validators` are considered queued.
- fn on_genesis_session<'a, I: 'a>(validators: I)
+ fn on_genesis_session<'a, I>(validators: I)
where
- I: Iterator
- ,
+ I: Iterator
- + 'a,
{
>::on_new_session(false, 0u32.into(), validators, None);
}
@@ -103,13 +103,13 @@ impl Pallet {
// Allow to trigger `on_new_session` in tests, this is needed as long as `pallet_session` is not
// implemented in mock.
#[cfg(any(test, feature = "runtime-benchmarks"))]
- pub(crate) fn test_trigger_on_new_session<'a, I: 'a>(
+ pub(crate) fn test_trigger_on_new_session<'a, I>(
changed: bool,
session_index: T::SessionIndex,
validators: I,
queued: Option,
) where
- I: Iterator
- ,
+ I: Iterator
- + 'a,
{
Self::on_new_session(changed, session_index, validators, queued)
}
@@ -122,16 +122,16 @@ impl sp_runtime::BoundToRuntimeAppPublic for Pallet {
impl OneSessionHandler for Pallet {
type Key = T::AuthorityId;
- fn on_genesis_session<'a, I: 'a>(validators: I)
+ fn on_genesis_session<'a, I>(validators: I)
where
- I: Iterator
- ,
+ I: Iterator
- + 'a,
{
>::on_genesis_session(validators);
}
- fn on_new_session<'a, I: 'a>(changed: bool, validators: I, queued: I)
+ fn on_new_session<'a, I>(changed: bool, validators: I, queued: I)
where
- I: Iterator
- ,
+ I: Iterator
- + 'a,
{
let session_index = >::current_index();
>::on_new_session(changed, session_index.into(), validators, Some(queued));
diff --git a/pallets/invulnerables/src/benchmarking.rs b/pallets/invulnerables/src/benchmarking.rs
index 1e92d253e..a80683a32 100644
--- a/pallets/invulnerables/src/benchmarking.rs
+++ b/pallets/invulnerables/src/benchmarking.rs
@@ -112,6 +112,7 @@ pub(crate) fn currency_issue(
<::Currency as Balanced>::issue(amount)
}
+#[allow(clippy::multiple_bound_locations)]
#[benchmarks(where T: session::Config + pallet_balances::Config, BalanceOf: AtLeast32BitUnsigned)]
mod benchmarks {
use super::*;
diff --git a/pallets/pooled-staking/src/pools.rs b/pallets/pooled-staking/src/pools.rs
index 081a46676..d230919de 100644
--- a/pallets/pooled-staking/src/pools.rs
+++ b/pallets/pooled-staking/src/pools.rs
@@ -30,6 +30,7 @@ use {
tp_maths::{ErrAdd, ErrMul, ErrSub, MulDiv},
};
+#[allow(dead_code)]
pub trait Pool {
/// Get the amount of shares a delegator have for given candidate.
fn shares(candidate: &Candidate, delegator: &Delegator) -> Shares;
diff --git a/pallets/registrar/src/benchmarks.rs b/pallets/registrar/src/benchmarks.rs
index 8b89541bb..8298d41ee 100644
--- a/pallets/registrar/src/benchmarks.rs
+++ b/pallets/registrar/src/benchmarks.rs
@@ -40,7 +40,7 @@ fn create_funded_user(
let min_reserve_amount = T::DepositAmount::get();
let total = min_reserve_amount + extra;
T::Currency::make_free_balance_be(&user, total);
- T::Currency::issue(total);
+ let _ = T::Currency::issue(total);
(user, total)
}
diff --git a/pallets/registrar/src/lib.rs b/pallets/registrar/src/lib.rs
index de981de26..4a0b6dfda 100644
--- a/pallets/registrar/src/lib.rs
+++ b/pallets/registrar/src/lib.rs
@@ -625,7 +625,7 @@ pub mod pallet {
const SEED: u32 = 0;
let user = account(string, n, SEED);
T::Currency::make_free_balance_be(&user, total);
- T::Currency::issue(total);
+ let _ = T::Currency::issue(total);
(user, total)
}
let new_balance =
@@ -641,7 +641,7 @@ pub mod pallet {
let new_balance =
(T::Currency::minimum_balance() + T::DepositAmount::get()) * 2u32.into();
T::Currency::make_free_balance_be(&deposit_info.creator, new_balance);
- T::Currency::issue(new_balance);
+ let _ = T::Currency::issue(new_balance);
deposit_info.creator
}
diff --git a/pallets/xcm-core-buyer/src/mock.rs b/pallets/xcm-core-buyer/src/mock.rs
index 418b453bb..4ea806213 100644
--- a/pallets/xcm-core-buyer/src/mock.rs
+++ b/pallets/xcm-core-buyer/src/mock.rs
@@ -29,7 +29,7 @@ use {
sp_core::H256,
sp_io::TestExternalities,
sp_runtime::{
- traits::{BlakeTwo256, Convert, IdentityLookup},
+ traits::{BlakeTwo256, IdentityLookup},
BuildStorage,
},
sp_std::collections::btree_map::BTreeMap,
@@ -228,26 +228,6 @@ impl GetParathreadCollators for GetAssignedCollatorsImpl {
}
}
-pub struct GetBlockNumber;
-
-impl Get for GetBlockNumber {
- fn get() -> u32 {
- System::block_number() as u32
- }
-}
-
-pub struct ParaIdToAccount32;
-
-impl Convert for ParaIdToAccount32 {
- fn convert(para_id: ParaId) -> [u8; 32] {
- let mut res = [0; 32];
-
- res[..4].copy_from_slice(&u32::from(para_id).to_le_bytes());
-
- res
- }
-}
-
pub struct EncodedCallToBuyCore;
impl GetPurchaseCoreCall<()> for EncodedCallToBuyCore {
diff --git a/runtime/dancebox/src/lib.rs b/runtime/dancebox/src/lib.rs
index 4d4185f2f..72f2cdc6a 100644
--- a/runtime/dancebox/src/lib.rs
+++ b/runtime/dancebox/src/lib.rs
@@ -2356,6 +2356,7 @@ impl_runtime_apis! {
}
}
+#[allow(dead_code)]
struct CheckInherents;
// TODO: this should be removed but currently if we remove it the relay does not check anything
diff --git a/runtime/flashbox/src/lib.rs b/runtime/flashbox/src/lib.rs
index 6bca44669..5d75deea7 100644
--- a/runtime/flashbox/src/lib.rs
+++ b/runtime/flashbox/src/lib.rs
@@ -1921,6 +1921,7 @@ impl_runtime_apis! {
}
}
+#[allow(dead_code)]
struct CheckInherents;
// TODO: this should be removed but currently if we remove it the relay does not check anything
diff --git a/rust-toolchain b/rust-toolchain
index fa4029d55..6d7617d1a 100644
--- a/rust-toolchain
+++ b/rust-toolchain
@@ -1,5 +1,5 @@
[toolchain]
-channel = "1.75.0"
+channel = "1.78.0"
components = [ "rustfmt", "clippy", "rust-src" ]
targets = [ "wasm32-unknown-unknown" ]
profile = "minimal"
From d6f2905dc4c4f4827c5efbb9f5f5f088a2782e68 Mon Sep 17 00:00:00 2001
From: Parth
Date: Mon, 13 May 2024 16:25:26 +0400
Subject: [PATCH 5/7] Modifying xcm-core-buyer to add reporting of the core
purchase (#516)
* modifying xcm-core-buyer to add reporting of the core purchase
* add query id in BuyCoreXCMSent + add more tests for storage mutations
* fix assert_expected_events macro + add xcm notification check
* fix tests for delivery fees
* use transaction status + add tests
* add more unit tests + fix a bug regarding pending block production check
* add proper constant for pending block map size
* add accurate benchmarks
* fix typescript test + api interfaces
---------
Co-authored-by: girazoki
---
Cargo.lock | 1 +
pallets/xcm-core-buyer/Cargo.toml | 5 +
pallets/xcm-core-buyer/src/benchmarks.rs | 130 ++++++-
pallets/xcm-core-buyer/src/lib.rs | 314 ++++++++++++++--
pallets/xcm-core-buyer/src/mock.rs | 32 +-
pallets/xcm-core-buyer/src/tests.rs | 347 +++++++++++++++++-
pallets/xcm-core-buyer/src/weights.rs | 198 ++++++++--
runtime/dancebox/src/lib.rs | 4 +-
.../src/weights/pallet_xcm_core_buyer.rs | 91 ++++-
runtime/dancebox/src/xcm_config.rs | 42 ++-
.../dancebox/tests/common/xcm/core_buyer.rs | 248 ++++++++++++-
.../tests/common/xcm/delivery_fees.rs | 14 +-
.../common/xcm/expected_event_checker.rs | 103 ++++++
.../xcm/foreign_signed_based_sovereign.rs | 1 +
.../tests/common/xcm/foreign_sovereigns.rs | 1 +
runtime/dancebox/tests/common/xcm/mod.rs | 5 +-
.../xcm/reserver_transfers_polkadot_xcm.rs | 1 +
...derivative_reception_container_dancebox.rs | 1 +
...e_reception_dancebox_frontier_container.rs | 1 +
...ive_reception_dancebox_simple_container.rs | 1 +
...ken_derivative_reception_relay_dancebox.rs | 1 +
...tive_reception_relay_frontier_container.rs | 1 +
...vative_reception_relay_simple_container.rs | 1 +
runtime/dancebox/tests/common/xcm/transact.rs | 1 +
runtime/dancebox/tests/common/xcm/trap.rs | 1 +
.../test_set_latest_author_data_weight.ts | 2 +-
.../dancebox/interfaces/augment-api-consts.ts | 13 +-
.../dancebox/interfaces/augment-api-errors.ts | 8 +
.../dancebox/interfaces/augment-api-events.ts | 16 +-
.../dancebox/interfaces/augment-api-query.ts | 23 +-
.../src/dancebox/interfaces/augment-api-tx.ts | 30 ++
.../src/dancebox/interfaces/lookup.ts | 291 ++++++++-------
.../src/dancebox/interfaces/registry.ts | 2 +
.../src/dancebox/interfaces/types-lookup.ts | 319 +++++++++-------
34 files changed, 1841 insertions(+), 408 deletions(-)
create mode 100644 runtime/dancebox/tests/common/xcm/expected_event_checker.rs
diff --git a/Cargo.lock b/Cargo.lock
index 2c9a3c7fd..a44d1c25d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -9561,6 +9561,7 @@ dependencies = [
"nimbus-primitives",
"num-traits",
"pallet-balances",
+ "pallet-xcm",
"parity-scale-codec",
"scale-info",
"serde",
diff --git a/pallets/xcm-core-buyer/Cargo.toml b/pallets/xcm-core-buyer/Cargo.toml
index fe4a69424..8e842dd17 100644
--- a/pallets/xcm-core-buyer/Cargo.toml
+++ b/pallets/xcm-core-buyer/Cargo.toml
@@ -17,6 +17,7 @@ serde = { workspace = true, optional = true }
tp-traits = { workspace = true }
# Polkadot
+pallet-xcm = { workspace = true }
staging-xcm = { workspace = true }
# Substrate
@@ -51,6 +52,7 @@ std = [
"log/std",
"nimbus-primitives/std",
"pallet-balances/std",
+ "pallet-xcm/std",
"parity-scale-codec/std",
"scale-info/std",
"serde",
@@ -60,6 +62,7 @@ std = [
"sp-runtime/std",
"sp-std/std",
"staging-xcm/std",
+ "staging-xcm/std",
"tp-traits/std",
]
runtime-benchmarks = [
@@ -69,6 +72,7 @@ runtime-benchmarks = [
"frame-system/runtime-benchmarks",
"nimbus-primitives/runtime-benchmarks",
"pallet-balances/runtime-benchmarks",
+ "pallet-xcm/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
"tp-traits/runtime-benchmarks",
]
@@ -77,5 +81,6 @@ try-runtime = [
"frame-system/try-runtime",
"nimbus-primitives/try-runtime",
"pallet-balances/try-runtime",
+ "pallet-xcm/try-runtime",
"sp-runtime/try-runtime",
]
diff --git a/pallets/xcm-core-buyer/src/benchmarks.rs b/pallets/xcm-core-buyer/src/benchmarks.rs
index c8e9d62d2..70a6d55a0 100644
--- a/pallets/xcm-core-buyer/src/benchmarks.rs
+++ b/pallets/xcm-core-buyer/src/benchmarks.rs
@@ -24,21 +24,25 @@ use {
},
core::marker::PhantomData,
frame_benchmarking::{account, v2::*},
- frame_support::{assert_ok, pallet_prelude::Weight, BoundedBTreeSet},
+ frame_support::{assert_ok, pallet_prelude::Weight, BoundedVec},
frame_system::RawOrigin,
- sp_std::{collections::btree_set::BTreeSet, vec},
+ sp_std::vec,
tp_traits::{ParaId, ParathreadParams, SlotFrequency},
};
pub const BUY_EXECUTION_COST: u128 = 50_000_000;
pub const PLACE_ORDER_WEIGHT_AT_MOST: Weight = Weight::from_parts(1_000_000_000, 100_000);
-#[benchmarks]
+#[benchmarks(where ::RuntimeOrigin: From)]
mod benchmarks {
use super::*;
+ use crate::{InFlightCoreBuyingOrder, PendingBlocks, QueryIdToParaId};
+ use frame_system::pallet_prelude::BlockNumberFor;
+ use staging_xcm::latest::{MaybeErrorCode, QueryId};
+ use staging_xcm::v3::{MultiLocation, Response};
#[benchmark]
- fn force_buy_core(x: Linear<1, 99>) {
+ fn force_buy_core() {
assert_ok!(Pallet::::set_relay_xcm_weight_config(
RawOrigin::Root.into(),
Some(RelayXcmWeightConfigInner {
@@ -48,15 +52,24 @@ mod benchmarks {
}),
));
- let para_id = ParaId::from(x + 1);
- assert_eq!(InFlightOrders::::get(), BTreeSet::new());
+ let x = 1000u32;
- // Mock `x` xcm messages already sent in this block
- let bbs: BoundedBTreeSet = BTreeSet::from_iter((0..x).map(ParaId::from))
- .try_into()
- .expect("x is greater than MaxParathreads");
- InFlightOrders::::put(bbs);
- assert!(!InFlightOrders::::get().contains(¶_id));
+ let para_id = ParaId::from(x + 1);
+ for i in 0..=x {
+ InFlightOrders::::set(
+ ParaId::from(i),
+ Some(InFlightCoreBuyingOrder {
+ para_id: ParaId::from(i),
+ query_id: QueryId::from(i),
+ ttl: >::block_number()
+ + BlockNumberFor::::from(100u32),
+ }),
+ );
+
+ QueryIdToParaId::::set(QueryId::from(i), Some(ParaId::from(i)));
+ }
+
+ assert!(InFlightOrders::::get(para_id).is_none());
// For the extrinsic to succeed, we need to ensure that:
// * the para_id is a parathread
@@ -73,7 +86,98 @@ mod benchmarks {
#[extrinsic_call]
Pallet::::force_buy_core(RawOrigin::Root, para_id);
- assert!(InFlightOrders::::get().contains(¶_id));
+ assert!(InFlightOrders::::get(para_id).is_some());
+ }
+
+ #[benchmark]
+ fn query_response() {
+ let x = 1000u32;
+
+ let para_id = ParaId::from(x);
+ for i in 0..=x {
+ InFlightOrders::::set(
+ ParaId::from(i),
+ Some(InFlightCoreBuyingOrder {
+ para_id: ParaId::from(i),
+ query_id: QueryId::from(i),
+ ttl: >::block_number()
+ + BlockNumberFor::::from(100u32),
+ }),
+ );
+
+ QueryIdToParaId::::set(QueryId::from(i), Some(ParaId::from(i)));
+ }
+
+ assert!(InFlightOrders::::get(para_id).is_some());
+
+ let response = if x % 2 == 0 {
+ Response::DispatchResult(MaybeErrorCode::Success)
+ } else {
+ Response::DispatchResult(MaybeErrorCode::Error(BoundedVec::default()))
+ };
+ let xcm_origin = pallet_xcm::Origin::Response(MultiLocation::here());
+
+ #[extrinsic_call]
+ Pallet::::query_response(xcm_origin, QueryId::from(x), response);
+
+ assert!(InFlightOrders::::get(para_id).is_none());
+ assert!(QueryIdToParaId::::get(QueryId::from(x)).is_none());
+
+ if x % 2 == 0 {
+ assert!(PendingBlocks::::get(para_id).is_some());
+ } else {
+ assert!(PendingBlocks::::get(para_id).is_none());
+ }
+ }
+
+ #[benchmark]
+ fn clean_up_expired_in_flight_orders(x: Linear<1, 1000>) {
+ let caller: T::AccountId = whitelisted_caller();
+ for i in 0..=x {
+ InFlightOrders::::set(
+ ParaId::from(i),
+ Some(InFlightCoreBuyingOrder {
+ para_id: ParaId::from(i),
+ query_id: QueryId::from(i),
+ ttl: BlockNumberFor::::from(0u32),
+ }),
+ );
+
+ QueryIdToParaId::::set(QueryId::from(i), Some(ParaId::from(i)));
+ }
+
+ let para_ids_to_clean_up = (0..=x).map(ParaId::from).collect();
+
+ #[extrinsic_call]
+ Pallet::::clean_up_expired_in_flight_orders(
+ RawOrigin::Signed(caller),
+ para_ids_to_clean_up,
+ );
+
+ for i in 0..=x {
+ assert!(InFlightOrders::::get(ParaId::from(i)).is_none());
+ assert!(QueryIdToParaId::::get(QueryId::from(i)).is_none());
+ }
+ }
+
+ #[benchmark]
+ fn clean_up_expired_pending_blocks(x: Linear<1, 1000>) {
+ let caller: T::AccountId = whitelisted_caller();
+ for i in 0..=x {
+ PendingBlocks::::set(ParaId::from(i), Some(BlockNumberFor::::from(0u32)));
+ }
+
+ let para_ids_to_clean_up = (0..=x).map(ParaId::from).collect();
+
+ #[extrinsic_call]
+ Pallet::::clean_up_expired_pending_blocks(
+ RawOrigin::Signed(caller),
+ para_ids_to_clean_up,
+ );
+
+ for i in 0..=x {
+ assert!(PendingBlocks::::get(ParaId::from(i)).is_none());
+ }
}
#[benchmark]
diff --git a/pallets/xcm-core-buyer/src/lib.rs b/pallets/xcm-core-buyer/src/lib.rs
index 4cb44ee11..05acf15c9 100644
--- a/pallets/xcm-core-buyer/src/lib.rs
+++ b/pallets/xcm-core-buyer/src/lib.rs
@@ -20,6 +20,7 @@
#![cfg_attr(not(feature = "std"), no_std)]
+use frame_support::{Deserialize, Serialize};
pub use pallet::*;
#[cfg(test)]
@@ -33,9 +34,11 @@ mod benchmarks;
pub mod weights;
pub use weights::WeightInfo;
+use tp_traits::{AuthorNotingHook, BlockNumber};
use {
dp_core::ParaId,
frame_support::{
+ dispatch::GetDispatchInfo,
pallet_prelude::*,
traits::fungible::{Balanced, Inspect},
},
@@ -43,6 +46,7 @@ use {
parity_scale_codec::EncodeLike,
sp_runtime::traits::{AccountIdConversion, Convert, Get},
sp_std::{vec, vec::Vec},
+ staging_xcm::v3::Response,
staging_xcm::{
prelude::*,
v3::{InteriorMultiLocation, MultiAsset, MultiAssets, Xcm},
@@ -50,9 +54,51 @@ use {
tp_traits::ParathreadParams,
};
+pub trait XCMNotifier {
+ fn new_notify_query(
+ responder: impl Into,
+ notify: impl Into<::RuntimeCall>,
+ timeout: BlockNumberFor,
+ match_querier: impl Into,
+ ) -> u64;
+}
+
+/// Dummy implementation. Should only be used for testing.
+impl XCMNotifier for () {
+ fn new_notify_query(
+ _responder: impl Into,
+ _notify: impl Into<::RuntimeCall>,
+ _timeout: BlockNumberFor,
+ _match_querier: impl Into,
+ ) -> u64 {
+ 0
+ }
+}
+
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
+#[derive(RuntimeDebug, PartialEq, Eq, Encode, Decode, Clone, TypeInfo)]
+pub struct InFlightCoreBuyingOrder {
+ para_id: ParaId,
+ query_id: QueryId,
+ ttl: BN,
+}
+
+impl AuthorNotingHook for Pallet {
+ fn on_container_author_noted(
+ _author: &T::AccountId,
+ _block_number: BlockNumber,
+ para_id: ParaId,
+ ) -> Weight {
+ PendingBlocks::::remove(para_id);
+
+ T::DbWeight::get().writes(1)
+ }
+}
+
#[frame_support::pallet]
pub mod pallet {
use super::*;
+ use pallet_xcm::ensure_response;
#[pallet::pallet]
#[pallet::without_storage_info]
pub struct Pallet(PhantomData);
@@ -87,9 +133,7 @@ pub mod pallet {
+ Clone
+ PartialEq
+ sp_std::fmt::Debug;
- /// Limit how many in-flight XCM requests can be sent to the relay chain in one block.
- #[pallet::constant]
- type MaxParathreads: Get;
+
/// Get the parathread params. Used to verify that the para id is a parathread.
// TODO: and in the future to restrict the ability to buy a core depending on slot frequency
type GetParathreadParams: GetParathreadParams;
@@ -102,6 +146,31 @@ pub mod pallet {
#[pallet::constant]
type UnsignedPriority: Get;
+ /// TTL for pending blocks entry, which prevents anyone to submit another core buying xcm.
+ #[pallet::constant]
+ type PendingBlocksTtl: Get>;
+
+ /// TTL to be used in xcm's notify query
+ #[pallet::constant]
+ type CoreBuyingXCMQueryTtl: Get>;
+
+ /// Additional ttl for in flight orders (total would be CoreBuyingXCMQueryTtl + AdditionalTtlForInflightOrders)
+ /// after which the in flight orders can be cleaned up by anyone.
+ #[pallet::constant]
+ type AdditionalTtlForInflightOrders: Get>;
+
+ #[pallet::constant]
+ type UniversalLocation: Get;
+
+ type RuntimeOrigin: Into::RuntimeOrigin>>
+ + From<::RuntimeOrigin>;
+
+ /// The overarching call type
+ type RuntimeCall: From> + Encode + GetDispatchInfo;
+
+ /// Outcome notifier implements functionality to enable reporting back the outcome
+ type XCMNotifier: XCMNotifier;
+
type WeightInfo: WeightInfo;
}
@@ -109,7 +178,18 @@ pub mod pallet {
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event {
/// An XCM message to buy a core for this parathread has been sent to the relay chain.
- BuyCoreXcmSent { para_id: ParaId },
+ BuyCoreXcmSent {
+ para_id: ParaId,
+ transaction_status_query_id: QueryId,
+ },
+ /// We received response for xcm
+ ReceivedBuyCoreXCMResult { para_id: ParaId, response: Response },
+
+ /// We cleaned up expired pending blocks entries.
+ CleanedUpExpiredPendingBlocksEntries { para_ids: Vec },
+
+ /// We cleaned up expired in flight orders entries.
+ CleanedUpExpiredInFlightOrderEntries { para_ids: Vec },
}
#[pallet::error]
@@ -133,6 +213,14 @@ pub mod pallet {
XcmWeightStorageNotSet,
/// Converting a multilocation into a relay relative multilocation failed
ReanchorFailed,
+ /// Inverting location from destination point of view failed
+ LocationInversionFailed,
+ /// Modifying XCM to report the result of XCM failed
+ ReportNotifyingSetupFailed,
+ /// Unexpected XCM response
+ UnexpectedXCMResponse,
+ /// Block production is pending for para id with successfully placed order
+ BlockProductionPending,
}
/// Proof that I am a collator, assigned to a para_id, and I can buy a core for that para_id
@@ -149,7 +237,16 @@ pub mod pallet {
/// 1 core in 1 relay block for the same parathread.
#[pallet::storage]
pub type InFlightOrders =
- StorageValue<_, BoundedBTreeSet, ValueQuery>;
+ StorageMap<_, Twox128, ParaId, InFlightCoreBuyingOrder>, OptionQuery>;
+
+ /// Number of pending blocks
+ #[pallet::storage]
+ pub type PendingBlocks =
+ StorageMap<_, Twox128, ParaId, BlockNumberFor, OptionQuery>;
+
+ /// Mapping of QueryId to ParaId
+ #[pallet::storage]
+ pub type QueryIdToParaId = StorageMap<_, Twox128, QueryId, ParaId, OptionQuery>;
/// This must be set by root with the value of the relay chain xcm call weight and extrinsic
/// weight limit. This is a storage item because relay chain weights can change, so we need to
@@ -183,7 +280,7 @@ pub mod pallet {
// state.
#[pallet::call_index(0)]
// TODO: weight
- #[pallet::weight(T::WeightInfo::force_buy_core(T::MaxParathreads::get()))]
+ #[pallet::weight(T::WeightInfo::force_buy_core())]
pub fn buy_core(
origin: OriginFor,
para_id: ParaId,
@@ -213,7 +310,7 @@ pub mod pallet {
/// Buy core for para id as root. Does not require any proof, useful in tests.
#[pallet::call_index(1)]
- #[pallet::weight(T::WeightInfo::force_buy_core(T::MaxParathreads::get()))]
+ #[pallet::weight(T::WeightInfo::force_buy_core())]
pub fn force_buy_core(origin: OriginFor, para_id: ParaId) -> DispatchResult {
ensure_root(origin)?;
@@ -261,6 +358,107 @@ pub mod pallet {
Ok(())
}
+
+ #[pallet::call_index(4)]
+ #[pallet::weight(T::WeightInfo::query_response())]
+ pub fn query_response(
+ origin: OriginFor,
+ query_id: QueryId,
+ response: Response,
+ ) -> DispatchResult {
+ let _responder = ensure_response(::RuntimeOrigin::from(origin))?;
+
+ let maybe_para_id = QueryIdToParaId::::get(query_id);
+
+ let para_id = if let Some(para_id) = maybe_para_id {
+ para_id
+ } else {
+ // Most probably entry was expired or removed in some other way. Let's return early.
+ return Ok(());
+ };
+
+ QueryIdToParaId::::remove(query_id);
+ InFlightOrders::::remove(para_id);
+
+ match response {
+ Response::DispatchResult(MaybeErrorCode::Success) => {
+ // Success. Add para id to pending block
+ let now = >::block_number();
+ let ttl = T::PendingBlocksTtl::get();
+ PendingBlocks::::insert(para_id, now + ttl);
+ }
+ Response::DispatchResult(_) => {
+ // We do not add paraid to pending block on failure
+ }
+ _ => {
+ // Unexpected.
+ return Err(Error::::UnexpectedXCMResponse.into());
+ }
+ }
+
+ Self::deposit_event(Event::ReceivedBuyCoreXCMResult { para_id, response });
+
+ Ok(())
+ }
+
+ #[pallet::call_index(5)]
+ #[pallet::weight(T::WeightInfo::clean_up_expired_in_flight_orders(expired_pending_blocks_para_id.len() as u32))]
+ pub fn clean_up_expired_pending_blocks(
+ origin: OriginFor,
+ expired_pending_blocks_para_id: Vec,
+ ) -> DispatchResult {
+ let _ = ensure_signed(origin)?;
+ let now = frame_system::Pallet::::block_number();
+ let mut cleaned_up_para_ids = vec![];
+
+ for para_id in expired_pending_blocks_para_id {
+ let maybe_pending_block_ttl = PendingBlocks::::get(para_id);
+ if let Some(pending_block_ttl) = maybe_pending_block_ttl {
+ if pending_block_ttl < now {
+ PendingBlocks::::remove(para_id);
+ cleaned_up_para_ids.push(para_id);
+ } else {
+ // Ignore if not expired
+ }
+ }
+ }
+
+ Self::deposit_event(Event::CleanedUpExpiredPendingBlocksEntries {
+ para_ids: cleaned_up_para_ids,
+ });
+
+ Ok(())
+ }
+
+ #[pallet::call_index(6)]
+ #[pallet::weight(T::WeightInfo::clean_up_expired_in_flight_orders(expired_in_flight_orders.len() as u32))]
+ pub fn clean_up_expired_in_flight_orders(
+ origin: OriginFor,
+ expired_in_flight_orders: Vec,
+ ) -> DispatchResult {
+ let _ = ensure_signed(origin)?;
+ let now = frame_system::Pallet::::block_number();
+ let mut cleaned_up_para_ids = vec![];
+
+ for para_id in expired_in_flight_orders {
+ let maybe_in_flight_order = InFlightOrders::::get(para_id);
+ if let Some(in_flight_order) = maybe_in_flight_order {
+ if in_flight_order.ttl < now {
+ InFlightOrders::::remove(para_id);
+ QueryIdToParaId::::remove(in_flight_order.query_id);
+ cleaned_up_para_ids.push(para_id);
+ } else {
+ // Ignore if not expired
+ }
+ }
+ }
+
+ Self::deposit_event(Event::CleanedUpExpiredInFlightOrderEntries {
+ para_ids: cleaned_up_para_ids,
+ });
+
+ Ok(())
+ }
}
impl Pallet {
@@ -293,13 +491,27 @@ pub mod pallet {
/// Send an XCM message to the relay chain to try to buy a core for this para_id.
fn on_collator_instantaneous_core_requested(para_id: ParaId) -> DispatchResult {
- let mut in_flight_orders = InFlightOrders::::get();
- if in_flight_orders.contains(¶_id) {
- return Err(Error::::OrderAlreadyExists.into());
+ // If an in flight order is pending (i.e we did not receive the notification yet) and our
+ // record is not expired yet, we should not allow the collator to buy another core.
+ let maybe_in_flight_order = InFlightOrders::::get(para_id);
+ if let Some(in_flight_order) = maybe_in_flight_order {
+ if in_flight_order.ttl < >::block_number() {
+ InFlightOrders::::remove(para_id);
+ } else {
+ return Err(Error::::OrderAlreadyExists.into());
+ }
+ }
+
+ // If a block production is pending and our record is not expired yet, we should not allow
+ // the collator to buy another core yet.
+ let maybe_pending_blocks_ttl = PendingBlocks::::get(para_id);
+ if let Some(pending_blocks_ttl) = maybe_pending_blocks_ttl {
+ if pending_blocks_ttl < >::block_number() {
+ PendingBlocks::::remove(para_id);
+ } else {
+ return Err(Error::::BlockProductionPending.into());
+ }
}
- in_flight_orders
- .try_insert(para_id)
- .map_err(|_| Error::::InFlightLimitReached)?;
// Check that the para id is a parathread
let parathread_params = T::GetParathreadParams::get_parathread_params(para_id);
@@ -349,6 +561,25 @@ pub mod pallet {
// We use `descend_origin` instead of wrapping the transact call in `utility.as_derivative`
// because with `descend_origin` the parathread tank account will pay for fees, while
// `utility.as_derivative` will make the tanssi sovereign account pay for fees.
+
+ let notify_call = ::RuntimeCall::from(Call::::query_response {
+ query_id: 0,
+ response: Default::default(),
+ });
+ let notify_call_weight = notify_call.get_dispatch_info().weight;
+
+ let notify_query_ttl =
+ >::block_number() + T::CoreBuyingXCMQueryTtl::get();
+
+ // Send XCM to relay chain
+ let relay_chain = MultiLocation::parent();
+ let query_id = T::XCMNotifier::new_notify_query(
+ relay_chain,
+ notify_call,
+ notify_query_ttl,
+ interior_multilocation,
+ );
+
let message: Xcm<()> = Xcm::builder_unsafe()
.descend_origin(interior_multilocation)
.withdraw_asset(MultiAssets::from(vec![relay_asset_total.clone()]))
@@ -356,6 +587,13 @@ pub mod pallet {
// Both in case of error and in case of success, we want to refund the unused weight
.set_appendix(
Xcm::builder_unsafe()
+ .report_transact_status(QueryResponseInfo {
+ destination: T::UniversalLocation::get()
+ .invert_target(&relay_chain)
+ .map_err(|_| Error::::LocationInversionFailed)?, // This location from the point of view of destination
+ query_id,
+ max_weight: notify_call_weight,
+ })
.refund_surplus()
.deposit_asset(refund_asset_filter, derived_account)
.build(),
@@ -363,42 +601,40 @@ pub mod pallet {
.transact(origin, weight_at_most, call.into())
.build();
- // Send XCM to relay chain
- let relay_chain = MultiLocation::parent();
// We intentionally do not charge any fees
let (ticket, _price) =
T::XcmSender::validate(&mut Some(relay_chain), &mut Some(message))
.map_err(|_| Error::::ErrorValidatingXCM)?;
T::XcmSender::deliver(ticket).map_err(|_| Error::::ErrorDeliveringXCM)?;
- Self::deposit_event(Event::BuyCoreXcmSent { para_id });
- InFlightOrders::::put(in_flight_orders);
+ Self::deposit_event(Event::BuyCoreXcmSent {
+ para_id,
+ transaction_status_query_id: query_id,
+ });
+
+ let in_flight_order_ttl = notify_query_ttl + T::AdditionalTtlForInflightOrders::get();
+ InFlightOrders::::insert(
+ para_id,
+ InFlightCoreBuyingOrder {
+ para_id,
+ query_id,
+ ttl: in_flight_order_ttl,
+ },
+ );
+
+ QueryIdToParaId::::insert(query_id, para_id);
Ok(())
}
- }
-
- #[pallet::hooks]
- impl Hooks> for Pallet {
- fn on_initialize(_n: BlockNumberFor) -> Weight {
- let mut weight = Weight::zero();
-
- // 1 write in on_finalize
- weight += T::DbWeight::get().writes(1);
- weight
- }
+ pub fn para_deregistered(para_id: ParaId) {
+ // If para is deregistered we need to clean up in flight order, query id mapping
+ if let Some(in_flight_order) = InFlightOrders::::take(para_id) {
+ InFlightOrders::::remove(para_id);
+ QueryIdToParaId::::remove(in_flight_order.query_id);
+ }
- fn on_finalize(_: BlockNumberFor) {
- // We clear this storage item because we only need it to prevent collators from buying
- // more than one core for the same parathread in the same relay block
- // TODO: with async backing, it is possible that two tanssi blocks are included in the
- // same relay block, so this kill is not correct, should only kill the storage if the
- // relay block number has changed
- // TODO: this allows collators to send N consecutive messages to buy 1 core for the same
- // parathread, as long as the parathread block is not included in pallet_author_noting.
- // So a malicious collator could drain the parathread tank account by buying cores on
- // every tanssi block but not actually producing any block.
- InFlightOrders::::kill();
+ // We need to clean the pending block entry if any
+ PendingBlocks::::remove(para_id);
}
}
diff --git a/pallets/xcm-core-buyer/src/mock.rs b/pallets/xcm-core-buyer/src/mock.rs
index 4ea806213..10ea2e020 100644
--- a/pallets/xcm-core-buyer/src/mock.rs
+++ b/pallets/xcm-core-buyer/src/mock.rs
@@ -14,6 +14,9 @@
// You should have received a copy of the GNU General Public License
// along with Tanssi. If not, see
+use pallet_xcm::Origin;
+use staging_xcm::prelude::{GlobalConsensus, Parachain, X2};
+use staging_xcm::prelude::{InteriorMultiLocation, NetworkId};
use {
crate::{
self as pallet_xcm_core_buyer, GetParathreadCollators, GetPurchaseCoreCall,
@@ -54,6 +57,20 @@ frame_support::construct_runtime!(
}
);
+/// Only needed for benchmark test suite
+impl From for RuntimeOrigin {
+ fn from(_value: Origin) -> Self {
+ RuntimeOrigin::root()
+ }
+}
+
+/// Only needed for benchmark test suite
+impl From for Result {
+ fn from(_value: RuntimeOrigin) -> Self {
+ Ok(Origin::Response(MultiLocation::parent()))
+ }
+}
+
impl frame_system::Config for Test {
type BaseCallFilter = Everything;
type Block = Block;
@@ -161,6 +178,13 @@ parameter_types! {
pub const ParachainId: ParaId = ParaId::new(1000);
}
+parameter_types! {
+ pub const PendingBlocksTtl: u32 = 5;
+ pub const CoreBuyingXCMQueryTtl: u32 = 100;
+ pub const AdditionalTtlForInflightOrders: u32 = 5;
+ pub UniversalLocation: InteriorMultiLocation = X2(GlobalConsensus(NetworkId::Westend), Parachain(1000));
+}
+
impl pallet_xcm_core_buyer::Config for Test {
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
@@ -171,10 +195,16 @@ impl pallet_xcm_core_buyer::Config for Test {
type GetParathreadMaxCorePrice = ();
type SelfParaId = ParachainId;
type RelayChain = ();
- type MaxParathreads = ConstU32<100>;
type GetParathreadParams = GetParathreadParamsImpl;
type GetAssignedCollators = GetAssignedCollatorsImpl;
type UnsignedPriority = ();
+ type PendingBlocksTtl = PendingBlocksTtl;
+ type CoreBuyingXCMQueryTtl = CoreBuyingXCMQueryTtl;
+ type AdditionalTtlForInflightOrders = AdditionalTtlForInflightOrders;
+ type UniversalLocation = UniversalLocation;
+ type RuntimeOrigin = RuntimeOrigin;
+ type RuntimeCall = RuntimeCall;
+ type XCMNotifier = ();
type WeightInfo = ();
}
diff --git a/pallets/xcm-core-buyer/src/tests.rs b/pallets/xcm-core-buyer/src/tests.rs
index d64688aea..2d51ca3b1 100644
--- a/pallets/xcm-core-buyer/src/tests.rs
+++ b/pallets/xcm-core-buyer/src/tests.rs
@@ -14,6 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Tanssi. If not, see
+use frame_support::assert_storage_noop;
use {
crate::{mock::*, *},
frame_support::{assert_noop, assert_ok},
@@ -31,7 +32,9 @@ fn root_origin_can_force_buy_xcm() {
assert_ok!(XcmCoreBuyer::force_buy_core(RuntimeOrigin::root(), para_id,));
- assert_eq!(events(), vec![Event::BuyCoreXcmSent { para_id }]);
+ let events = events();
+ assert_eq!(events.len(), 1);
+ matches!(events[0], Event::BuyCoreXcmSent { para_id: event_para_id, .. } if event_para_id == para_id);
});
}
@@ -62,7 +65,9 @@ fn force_buy_two_messages_in_one_block_fails() {
assert_ok!(XcmCoreBuyer::force_buy_core(RuntimeOrigin::root(), para_id,));
- assert_eq!(events(), vec![Event::BuyCoreXcmSent { para_id }]);
+ let events = events();
+ assert_eq!(events.len(), 1);
+ matches!(events[0], Event::BuyCoreXcmSent { para_id: event_para_id, .. } if event_para_id == para_id);
assert_noop!(
XcmCoreBuyer::force_buy_core(RuntimeOrigin::root(), para_id),
@@ -72,7 +77,7 @@ fn force_buy_two_messages_in_one_block_fails() {
}
#[test]
-fn force_buy_two_messages_in_two_consecutive_blocks_works() {
+fn force_buy_two_messages_in_two_consecutive_blocks_failes() {
ExtBuilder::default()
.with_balances([(ALICE, 1_000)].into())
.build()
@@ -82,13 +87,345 @@ fn force_buy_two_messages_in_two_consecutive_blocks_works() {
assert_ok!(XcmCoreBuyer::force_buy_core(RuntimeOrigin::root(), para_id,));
- assert_eq!(events(), vec![Event::BuyCoreXcmSent { para_id }]);
+ let events = events();
+ assert_eq!(events.len(), 1);
+ matches!(events[0], Event::BuyCoreXcmSent { para_id: event_para_id, .. } if event_para_id == para_id);
run_to_block(2);
+ assert_noop!(
+ XcmCoreBuyer::force_buy_core(RuntimeOrigin::root(), para_id),
+ Error::::OrderAlreadyExists
+ );
+ });
+}
+
+#[test]
+fn force_buy_two_messages_succeds_after_receiving_order_failure_response() {
+ ExtBuilder::default()
+ .with_balances([(ALICE, 1_000)].into())
+ .build()
+ .execute_with(|| {
+ run_to_block(1);
+ let para_id = 3333.into();
+
+ assert_ok!(XcmCoreBuyer::force_buy_core(RuntimeOrigin::root(), para_id,));
+
+ let system_events = events();
+ assert_eq!(system_events.len(), 1);
+ matches!(system_events[0], Event::BuyCoreXcmSent { para_id: event_para_id, .. } if event_para_id == para_id);
+ let query_id = match system_events[0] {
+ Event::BuyCoreXcmSent { transaction_status_query_id, .. } => transaction_status_query_id,
+ _ => panic!("We checked for the event variant above; qed")
+ };
+
+ // QueryId -> ParaId mapping should exists
+ assert_eq!(QueryIdToParaId::