Transactional processing for XCM (#1222)

Moved from: https://github.com/paritytech/polkadot/pull/6951

closes https://github.com/paritytech/polkadot-sdk/issues/490

- [x] update cumulus

--- 
This PR introduces transactional processing of certain xcm instructions.
For the list of instructions checkout
https://github.com/paritytech/polkadot-sdk/issues/490. The transactional
processing is implemented as an xcm-executor config item. The two
implementations in this PR are `FrameTransactionalProcessor` and `()`.
The `()` implementation does no transactional processing. Each
implementation of the `ProcessTransaction` trait has an
`IS_TRANSACTIONAL` const that tells the XCVM if transactional processing
is actually implemented. If Transactional processing is implemented,
changes to touched registers should also be rolled back to prevent
inconsistencies.


Note for reviewers:
Check out the following safety assumption:
https://github.com/paritytech/polkadot-sdk/pull/1222/files#diff-4effad7d8c1c9de19fd27e18661cbf2128c8718f3b2420a27d2f816e0749ea53R30

---------

Co-authored-by: Keith Yeung <kungfukeith11@gmail.com>
Co-authored-by: Francisco Aguirre <franciscoaguirreperez@gmail.com>
Co-authored-by: command-bot <>
This commit is contained in:
Just van Stam
2024-01-24 17:30:27 +01:00
committed by GitHub
parent a78ff7d770
commit 50eb12cf2f
54 changed files with 675 additions and 295 deletions
+4 -1
View File
@@ -32,7 +32,9 @@ use sp_runtime::{
use xcm::prelude::*;
#[allow(deprecated)]
use xcm_builder::CurrencyAdapter;
use xcm_builder::{FixedWeightBounds, IsConcrete, NativeAsset, ParentIsPreset};
use xcm_builder::{
FixedWeightBounds, FrameTransactionalProcessor, IsConcrete, NativeAsset, ParentIsPreset,
};
use xcm_executor::traits::ConvertOrigin;
type Block = frame_system::mocking::MockBlock<Test>;
@@ -175,6 +177,7 @@ impl xcm_executor::Config for XcmConfig {
type CallDispatcher = RuntimeCall;
type SafeCallFilter = Everything;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
}
pub type XcmRouter = (
@@ -16,11 +16,11 @@ use xcm::latest::prelude::*;
use xcm_builder::CurrencyAdapter;
use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom,
DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, IsConcrete,
NativeAsset, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
WithComputedOrigin, WithUniqueTopic,
DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FixedWeightBounds,
FrameTransactionalProcessor, IsConcrete, NativeAsset, ParentIsPreset, RelayChainAsNative,
SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative,
SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId,
UsingComponents, WithComputedOrigin, WithUniqueTopic,
};
use xcm_executor::XcmExecutor;
@@ -139,6 +139,7 @@ impl xcm_executor::Config for XcmConfig {
type CallDispatcher = RuntimeCall;
type SafeCallFilter = Everything;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
}
/// No local origins on this chain are allowed to dispatch XCM sends/executions.
@@ -1601,6 +1601,13 @@ impl_runtime_apis! {
Ok((origin, ticket, assets))
}
fn fee_asset() -> Result<Asset, BenchmarkError> {
Ok(Asset {
id: AssetId(TokenLocation::get()),
fun: Fungible(1_000_000 * UNITS),
})
}
fn unlockable_asset() -> Result<(Location, Location, Asset), BenchmarkError> {
Err(BenchmarkError::Skip)
}
@@ -53,10 +53,10 @@ use xcm_builder::CurrencyAdapter;
use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain,
DenyThenTry, DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin, FungiblesAdapter,
GlobalConsensusParachainConvertsFor, HashedDescription, IsConcrete, LocalMint,
NetworkExportTableItem, NoChecking, NonFungiblesAdapter, ParentAsSuperuser, ParentIsPreset,
RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
DenyThenTry, DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin, FrameTransactionalProcessor,
FungiblesAdapter, GlobalConsensusParachainConvertsFor, HashedDescription, IsConcrete,
LocalMint, NetworkExportTableItem, NoChecking, NonFungiblesAdapter, ParentAsSuperuser,
ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
SignedAccountId32AsNative, SignedToAccountId32, SovereignPaidRemoteExporter,
SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit,
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
@@ -652,6 +652,7 @@ impl xcm_executor::Config for XcmConfig {
type CallDispatcher = WithOriginFilter<SafeCallFilter>;
type SafeCallFilter = SafeCallFilter;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
}
/// Converts a local signed origin into an XCM location.
@@ -1643,6 +1643,13 @@ impl_runtime_apis! {
Ok((origin, ticket, assets))
}
fn fee_asset() -> Result<Asset, BenchmarkError> {
Ok(Asset {
id: AssetId(WestendLocation::get()),
fun: Fungible(1_000_000 * UNITS),
})
}
fn unlockable_asset() -> Result<(Location, Location, Asset), BenchmarkError> {
Err(BenchmarkError::Skip)
}
@@ -51,14 +51,14 @@ use xcm_builder::CurrencyAdapter;
use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain,
DenyThenTry, DescribeFamily, DescribePalletTerminal, EnsureXcmOrigin, FungiblesAdapter,
GlobalConsensusParachainConvertsFor, HashedDescription, IsConcrete, LocalMint,
NetworkExportTableItem, NoChecking, NonFungiblesAdapter, ParentAsSuperuser, ParentIsPreset,
RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, StartsWith,
StartsWithExplicitGlobalConsensus, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents,
XcmFeeToAccount,
DenyThenTry, DescribeFamily, DescribePalletTerminal, EnsureXcmOrigin,
FrameTransactionalProcessor, FungiblesAdapter, GlobalConsensusParachainConvertsFor,
HashedDescription, IsConcrete, LocalMint, NetworkExportTableItem, NoChecking,
NonFungiblesAdapter, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative,
SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative,
SignedToAccountId32, SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus,
TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin,
WithUniqueTopic, XcmFeeManagerFromComponents, XcmFeeToAccount,
};
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
@@ -676,6 +676,7 @@ impl xcm_executor::Config for XcmConfig {
type CallDispatcher = WithOriginFilter<SafeCallFilter>;
type SafeCallFilter = SafeCallFilter;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
}
/// Local origins on this chain are allowed to dispatch XCM sends/executions.
@@ -1216,6 +1216,13 @@ impl_runtime_apis! {
Ok((origin, ticket, assets))
}
fn fee_asset() -> Result<Asset, BenchmarkError> {
Ok(Asset {
id: AssetId(TokenLocation::get()),
fun: Fungible(1_000_000 * UNITS),
})
}
fn unlockable_asset() -> Result<(Location, Location, Asset), BenchmarkError> {
Err(BenchmarkError::Skip)
}
@@ -57,11 +57,12 @@ use xcm::latest::prelude::*;
use xcm_builder::{
deposit_or_burn_fee, AccountId32Aliases, AllowExplicitUnpaidExecutionFrom,
AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom,
CurrencyAdapter, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, HandleFee,
IsConcrete, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeToAccount,
CurrencyAdapter, DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin,
FrameTransactionalProcessor, HandleFee, IsConcrete, ParentAsSuperuser, ParentIsPreset,
RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
XcmFeeToAccount,
};
use xcm_executor::{
traits::{FeeManager, FeeReason, FeeReason::Export, TransactAsset, WithOriginFilter},
@@ -326,6 +327,7 @@ impl xcm_executor::Config for XcmConfig {
type CallDispatcher = WithOriginFilter<SafeCallFilter>;
type SafeCallFilter = SafeCallFilter;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
}
pub type PriceForParentDelivery =
@@ -914,6 +914,13 @@ impl_runtime_apis! {
Ok((origin, ticket, assets))
}
fn fee_asset() -> Result<Asset, BenchmarkError> {
Ok(Asset {
id: AssetId(WestendLocation::get()),
fun: Fungible(1_000_000 * UNITS),
})
}
fn unlockable_asset() -> Result<(Location, Location, Asset), BenchmarkError> {
Err(BenchmarkError::Skip)
}
@@ -43,8 +43,8 @@ use xcm_builder::CurrencyAdapter;
use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain,
DenyThenTry, EnsureXcmOrigin, IsConcrete, ParentAsSuperuser, ParentIsPreset,
RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
DenyThenTry, EnsureXcmOrigin, FrameTransactionalProcessor, IsConcrete, ParentAsSuperuser,
ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
XcmFeeManagerFromComponents, XcmFeeToAccount,
@@ -265,6 +265,7 @@ impl xcm_executor::Config for XcmConfig {
type CallDispatcher = WithOriginFilter<SafeCallFilter>;
type SafeCallFilter = SafeCallFilter;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
}
pub type PriceForParentDelivery =
@@ -41,12 +41,12 @@ use xcm_builder::CurrencyAdapter;
use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain,
DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, IsConcrete, LocatableAssetId,
OriginToPluralityVoice, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative,
SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative,
SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId,
UsingComponents, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents,
XcmFeeToAccount,
DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, FrameTransactionalProcessor, IsConcrete,
LocatableAssetId, OriginToPluralityVoice, ParentAsSuperuser, ParentIsPreset,
RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic,
XcmFeeManagerFromComponents, XcmFeeToAccount,
};
use xcm_executor::{traits::WithOriginFilter, XcmExecutor};
@@ -290,6 +290,7 @@ impl xcm_executor::Config for XcmConfig {
type CallDispatcher = WithOriginFilter<SafeCallFilter>;
type SafeCallFilter = SafeCallFilter;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
}
/// Converts a local signed origin into an XCM location.
@@ -42,11 +42,11 @@ use xcm_builder::CurrencyAdapter;
use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain,
DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, IsConcrete, NativeAsset, ParentAsSuperuser,
ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic,
XcmFeeManagerFromComponents, XcmFeeToAccount,
DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, FrameTransactionalProcessor, IsConcrete,
NativeAsset, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, XcmFeeToAccount,
};
use xcm_executor::XcmExecutor;
@@ -198,6 +198,7 @@ impl xcm_executor::Config for XcmConfig {
type CallDispatcher = RuntimeCall;
type SafeCallFilter = Everything;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
}
/// Converts a local signed origin into an XCM location.
@@ -804,6 +804,13 @@ impl_runtime_apis! {
Ok((origin, ticket, assets))
}
fn fee_asset() -> Result<Asset, BenchmarkError> {
Ok(Asset {
id: AssetId(RocRelayLocation::get()),
fun: Fungible(1_000_000 * UNITS),
})
}
fn unlockable_asset() -> Result<(Location, Location, Asset), BenchmarkError> {
Err(BenchmarkError::Skip)
}
@@ -42,8 +42,8 @@ use xcm_builder::CurrencyAdapter;
use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain,
DenyThenTry, EnsureXcmOrigin, IsConcrete, ParentAsSuperuser, ParentIsPreset,
RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
DenyThenTry, EnsureXcmOrigin, FrameTransactionalProcessor, IsConcrete, ParentAsSuperuser,
ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
XcmFeeManagerFromComponents, XcmFeeToAccount,
@@ -238,6 +238,7 @@ impl xcm_executor::Config for XcmConfig {
type CallDispatcher = WithOriginFilter<SafeCallFilter>;
type SafeCallFilter = SafeCallFilter;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
}
/// Converts a local signed origin into an XCM location. Forms the basis for local origins
@@ -791,6 +791,13 @@ impl_runtime_apis! {
Ok((origin, ticket, assets))
}
fn fee_asset() -> Result<Asset, BenchmarkError> {
Ok(Asset {
id: AssetId(WndRelayLocation::get()),
fun: Fungible(1_000_000 * UNITS),
})
}
fn unlockable_asset() -> Result<(Location, Location, Asset), BenchmarkError> {
Err(BenchmarkError::Skip)
}
@@ -42,8 +42,8 @@ use xcm_builder::CurrencyAdapter;
use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain,
DenyThenTry, EnsureXcmOrigin, IsConcrete, ParentAsSuperuser, ParentIsPreset,
RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
DenyThenTry, EnsureXcmOrigin, FrameTransactionalProcessor, IsConcrete, ParentAsSuperuser,
ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia,
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
XcmFeeManagerFromComponents, XcmFeeToAccount,
@@ -243,6 +243,7 @@ impl xcm_executor::Config for XcmConfig {
type CallDispatcher = WithOriginFilter<SafeCallFilter>;
type SafeCallFilter = SafeCallFilter;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
}
/// Converts a local signed origin into an XCM location. Forms the basis for local origins
@@ -24,8 +24,8 @@ use frame_support::{
};
use xcm::latest::prelude::*;
use xcm_builder::{
AllowExplicitUnpaidExecutionFrom, FixedWeightBounds, ParentAsSuperuser, ParentIsPreset,
SovereignSignedViaLocation,
AllowExplicitUnpaidExecutionFrom, FixedWeightBounds, FrameTransactionalProcessor,
ParentAsSuperuser, ParentIsPreset, SovereignSignedViaLocation,
};
parameter_types! {
@@ -87,6 +87,7 @@ impl xcm_executor::Config for XcmConfig {
type CallDispatcher = RuntimeCall;
type SafeCallFilter = Everything;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
}
impl cumulus_pallet_xcm::Config for Runtime {
@@ -776,6 +776,13 @@ impl_runtime_apis! {
Ok((origin, ticket, assets))
}
fn fee_asset() -> Result<Asset, BenchmarkError> {
Ok(Asset {
id: AssetId(RelayLocation::get()),
fun: Fungible(1_000_000 * UNITS),
})
}
fn unlockable_asset() -> Result<(Location, Location, Asset), BenchmarkError> {
Err(BenchmarkError::Skip)
}
@@ -39,8 +39,8 @@ use xcm_builder::CurrencyAdapter;
use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain,
DenyThenTry, DescribeTerminus, EnsureXcmOrigin, HashedDescription, IsConcrete,
ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
DenyThenTry, DescribeTerminus, EnsureXcmOrigin, FrameTransactionalProcessor, HashedDescription,
IsConcrete, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents,
@@ -277,6 +277,7 @@ impl xcm_executor::Config for XcmConfig {
type CallDispatcher = WithOriginFilter<SafeCallFilter>;
type SafeCallFilter = SafeCallFilter;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
}
/// Converts a local signed origin into an XCM location. Forms the basis for local origins
@@ -776,6 +776,13 @@ impl_runtime_apis! {
Ok((origin, ticket, assets))
}
fn fee_asset() -> Result<Asset, BenchmarkError> {
Ok(Asset {
id: AssetId(RelayLocation::get()),
fun: Fungible(1_000_000 * UNITS),
})
}
fn unlockable_asset() -> Result<(Location, Location, Asset), BenchmarkError> {
Err(BenchmarkError::Skip)
}
@@ -39,8 +39,8 @@ use xcm_builder::CurrencyAdapter;
use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, DenyReserveTransferToRelayChain,
DenyThenTry, DescribeTerminus, EnsureXcmOrigin, HashedDescription, IsConcrete,
ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
DenyThenTry, DescribeTerminus, EnsureXcmOrigin, FrameTransactionalProcessor, HashedDescription,
IsConcrete, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents,
@@ -285,6 +285,7 @@ impl xcm_executor::Config for XcmConfig {
type CallDispatcher = WithOriginFilter<SafeCallFilter>;
type SafeCallFilter = SafeCallFilter;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
}
/// Converts a local signed origin into an XCM location. Forms the basis for local origins
@@ -87,6 +87,7 @@ impl xcm_executor::Config for XcmConfig {
type CallDispatcher = RuntimeCall;
type SafeCallFilter = Everything;
type Aliasers = Nothing;
type TransactionalProcessor = ();
}
impl cumulus_pallet_xcm::Config for Runtime {
@@ -50,11 +50,11 @@ use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, AsPrefixedGeneralIndex,
ConvertedConcreteId, CurrencyAdapter, DenyReserveTransferToRelayChain, DenyThenTry,
EnsureXcmOrigin, FixedWeightBounds, FungiblesAdapter, IsConcrete, LocalMint, NativeAsset,
NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative,
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, StartsWith, TakeWeightCredit, TrailingSetTopicAsId,
UsingComponents, WithComputedOrigin, WithUniqueTopic,
EnsureXcmOrigin, FixedWeightBounds, FrameTransactionalProcessor, FungiblesAdapter, IsConcrete,
LocalMint, NativeAsset, NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative,
SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative,
SignedToAccountId32, SovereignSignedViaLocation, StartsWith, TakeWeightCredit,
TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic,
};
use xcm_executor::{traits::JustTry, XcmExecutor};
@@ -355,6 +355,7 @@ impl xcm_executor::Config for XcmConfig {
type CallDispatcher = RuntimeCall;
type SafeCallFilter = Everything;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
}
/// No local origins on this chain are allowed to dispatch XCM sends/executions.
@@ -75,7 +75,8 @@ use parachains_common::{
};
use xcm_builder::{
AllowKnownQueryResponses, AllowSubscriptionsFrom, AsPrefixedGeneralIndex, ConvertedConcreteId,
FungiblesAdapter, LocalMint, TrailingSetTopicAsId, WithUniqueTopic,
FrameTransactionalProcessor, FungiblesAdapter, LocalMint, TrailingSetTopicAsId,
WithUniqueTopic,
};
use xcm_executor::traits::JustTry;
@@ -489,6 +490,7 @@ impl xcm_executor::Config for XcmConfig {
type CallDispatcher = RuntimeCall;
type SafeCallFilter = Everything;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
}
/// Local origins on this chain are allowed to dispatch XCM sends/executions.
+2
View File
@@ -25,6 +25,7 @@ use frame_support::{
defensive,
traits::{tokens::fungibles, Get, OnUnbalanced as OnUnbalancedT},
weights::{Weight, WeightToFee as WeightToFeeT},
CloneNoBound,
};
use pallet_asset_conversion::SwapCredit as SwapCreditT;
use polkadot_runtime_common::xcm_sender::PriceForMessageDelivery;
@@ -106,6 +107,7 @@ struct AssetTraderRefunder {
/// later refund purposes
/// Important: Errors if the Trader is being called twice by 2 BuyExecution instructions
/// Alternatively we could just return payment in the aforementioned case
#[derive(CloneNoBound)]
pub struct TakeFirstAssetTrader<
AccountId: Eq,
FeeCharger: ChargeWeightInFungibles<AccountId, ConcreteAssets>,
+7
View File
@@ -2393,6 +2393,13 @@ sp_api::impl_runtime_apis! {
Ok((origin, ticket, assets))
}
fn fee_asset() -> Result<Asset, BenchmarkError> {
Ok(Asset {
id: AssetId(TokenLocation::get()),
fun: Fungible(1_000_000 * UNITS),
})
}
fn unlockable_asset() -> Result<(Location, Location, Asset), BenchmarkError> {
// Rococo doesn't support asset locking
Err(BenchmarkError::Skip)
+6 -4
View File
@@ -42,10 +42,11 @@ use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative,
ChildParachainConvertsVia, DescribeBodyTerminal, DescribeFamily, FixedWeightBounds,
HashedDescription, IsChildSystemParachain, IsConcrete, MintLocation, OriginToPluralityVoice,
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
XcmFeeManagerFromComponents, XcmFeeToAccount,
FrameTransactionalProcessor, HashedDescription, IsChildSystemParachain, IsConcrete,
MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents,
XcmFeeToAccount,
};
use xcm_executor::XcmExecutor;
@@ -222,6 +223,7 @@ impl xcm_executor::Config for XcmConfig {
type CallDispatcher = RuntimeCall;
type SafeCallFilter = Everything;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
}
parameter_types! {
@@ -22,8 +22,8 @@ use frame_support::{
use frame_system::EnsureRoot;
use xcm::latest::prelude::*;
use xcm_builder::{
AllowUnpaidExecutionFrom, EnsureXcmOrigin, FixedWeightBounds, SignedAccountId32AsNative,
SignedToAccountId32,
AllowUnpaidExecutionFrom, EnsureXcmOrigin, FixedWeightBounds, FrameTransactionalProcessor,
SignedAccountId32AsNative, SignedToAccountId32,
};
use xcm_executor::{
traits::{TransactAsset, WeightTrader},
@@ -74,6 +74,7 @@ impl TransactAsset for DummyAssetTransactor {
}
}
#[derive(Clone)]
pub struct DummyWeightTrader;
impl WeightTrader for DummyWeightTrader {
fn new() -> Self {
@@ -121,6 +122,7 @@ impl xcm_executor::Config for XcmConfig {
type CallDispatcher = super::RuntimeCall;
type SafeCallFilter = Everything;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
}
impl pallet_xcm::Config for crate::Runtime {
+7
View File
@@ -2421,6 +2421,13 @@ sp_api::impl_runtime_apis! {
Ok((origin, ticket, assets))
}
fn fee_asset() -> Result<Asset, BenchmarkError> {
Ok(Asset {
id: AssetId(TokenLocation::get()),
fun: Fungible(1_000_000 * UNITS),
})
}
fn unlockable_asset() -> Result<(Location, Location, Asset), BenchmarkError> {
// Westend doesn't support asset locking
Err(BenchmarkError::Skip)
+6 -5
View File
@@ -44,11 +44,11 @@ use xcm_builder::CurrencyAdapter as XcmCurrencyAdapter;
use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowKnownQueryResponses,
AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative,
ChildParachainConvertsVia, DescribeBodyTerminal, DescribeFamily, HashedDescription, IsConcrete,
MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents,
WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents,
XcmFeeToAccount,
ChildParachainConvertsVia, DescribeBodyTerminal, DescribeFamily, FrameTransactionalProcessor,
HashedDescription, IsConcrete, MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative,
SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId,
UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic,
XcmFeeManagerFromComponents, XcmFeeToAccount,
};
use xcm_executor::XcmExecutor;
@@ -217,6 +217,7 @@ impl xcm_executor::Config for XcmConfig {
type CallDispatcher = RuntimeCall;
type SafeCallFilter = Everything;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
}
parameter_types! {
@@ -26,7 +26,7 @@ use frame_support::{
use sp_core::H256;
use sp_runtime::traits::{BlakeTwo256, IdentityLookup};
use xcm::latest::prelude::*;
use xcm_builder::{AllowUnpaidExecutionFrom, MintLocation};
use xcm_builder::{AllowUnpaidExecutionFrom, FrameTransactionalProcessor, MintLocation};
type Block = frame_system::mocking::MockBlock<Test>;
@@ -145,6 +145,7 @@ impl xcm_executor::Config for XcmConfig {
type CallDispatcher = RuntimeCall;
type SafeCallFilter = Everything;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
}
impl crate::Config for Test {
@@ -125,11 +125,15 @@ benchmarks! {
}
refund_surplus {
let holding = T::worst_case_holding(0).into();
let mut executor = new_executor::<T>(Default::default());
executor.set_holding(holding);
let holding_assets = T::worst_case_holding(1);
// We can already buy execution since we'll load the holding register manually
let asset_for_fees = T::fee_asset().unwrap();
let previous_xcm = Xcm(vec![BuyExecution { fees: asset_for_fees, weight_limit: Limited(Weight::from_parts(1337, 1337)) }]);
executor.set_holding(holding_assets.into());
executor.set_total_surplus(Weight::from_parts(1337, 1337));
executor.set_total_refunded(Weight::zero());
executor.bench_process(previous_xcm).expect("Holding has been loaded, so we can buy execution here");
let instruction = Instruction::<XcmCallOf<T>>::RefundSurplus;
let xcm = Xcm(vec![instruction]);
@@ -30,7 +30,7 @@ use xcm_builder::{
AssetsInHolding, TestAssetExchanger, TestAssetLocker, TestAssetTrap,
TestSubscriptionService, TestUniversalAliases,
},
AliasForeignAccountId32, AllowUnpaidExecutionFrom,
AliasForeignAccountId32, AllowUnpaidExecutionFrom, FrameTransactionalProcessor,
};
use xcm_executor::traits::ConvertOrigin;
@@ -134,6 +134,7 @@ impl xcm_executor::Config for XcmConfig {
type CallDispatcher = RuntimeCall;
type SafeCallFilter = Everything;
type Aliasers = Aliasers;
type TransactionalProcessor = FrameTransactionalProcessor;
}
parameter_types! {
@@ -196,6 +197,10 @@ impl generic::Config for Test {
Ok((Default::default(), ticket, assets))
}
fn fee_asset() -> Result<Asset, BenchmarkError> {
Ok(Asset { id: AssetId(Here.into()), fun: Fungible(1_000_000) })
}
fn unlockable_asset() -> Result<(Location, Location, Asset), BenchmarkError> {
let assets: Asset = (AssetId(Here.into()), 100).into();
Ok((Default::default(), account_id_junction::<Test>(1).into(), assets))
@@ -73,6 +73,10 @@ pub mod pallet {
/// Return an origin, ticket, and assets that can be trapped and claimed.
fn claimable_asset() -> Result<(Location, Location, Assets), BenchmarkError>;
/// Asset used to pay for fees. Used to buy weight in benchmarks, for example in
/// `refund_surplus`.
fn fee_asset() -> Result<Asset, BenchmarkError>;
/// Return an unlocker, owner and assets that can be locked and unlocked.
fn unlockable_asset() -> Result<(Location, Location, Asset), BenchmarkError>;
+4 -3
View File
@@ -36,9 +36,9 @@ use xcm_builder::{
AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom,
AllowTopLevelPaidExecutionFrom, Case, ChildParachainAsNative, ChildParachainConvertsVia,
ChildSystemParachainAsSuperuser, DescribeAllTerminal, FixedRateOfFungible, FixedWeightBounds,
FungiblesAdapter, HashedDescription, IsConcrete, MatchedConvertedConcreteId, NoChecking,
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
XcmFeeManagerFromComponents, XcmFeeToAccount,
FrameTransactionalProcessor, FungiblesAdapter, HashedDescription, IsConcrete,
MatchedConvertedConcreteId, NoChecking, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, TakeWeightCredit, XcmFeeManagerFromComponents, XcmFeeToAccount,
};
use xcm_executor::{
traits::{Identity, JustTry},
@@ -516,6 +516,7 @@ impl xcm_executor::Config for XcmConfig {
type CallDispatcher = RuntimeCall;
type SafeCallFilter = Everything;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
}
pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, AnyNetwork>;
+1 -1
View File
@@ -567,7 +567,7 @@ impl TryFrom<NewMultiAsset> for MultiAsset {
/// A `Vec` of `MultiAsset`s.
///
/// There are a number of invariants which the construction and mutation functions must ensure are
/// maintained:
/// maintained in order to maintain polynomial time complexity during iteration:
/// - It may contain no items of duplicate asset class;
/// - All items must be ordered;
/// - The number of items should grow no larger than `MAX_ITEMS_IN_MULTIASSETS`.
+1 -1
View File
@@ -470,7 +470,7 @@ pub trait SendXcm {
/// Intermediate value which connects the two phases of the send operation.
type Ticket;
/// Check whether the given `_message` is deliverable to the given `_destination` and if so
/// Check whether the given `message` is deliverable to the given `destination` and if so
/// determine the cost which will be paid by this chain to do so, returning a `Validated` token
/// which can be used to enact delivery.
///
+45 -42
View File
@@ -26,26 +26,6 @@ mod tests;
#[cfg(feature = "std")]
pub mod test_utils;
mod location_conversion;
#[allow(deprecated)]
pub use location_conversion::ForeignChainAliasAccount;
pub use location_conversion::{
Account32Hash, AccountId32Aliases, AccountKey20Aliases, AliasesIntoAccountId32,
ChildParachainConvertsVia, DescribeAccountId32Terminal, DescribeAccountIdTerminal,
DescribeAccountKey20Terminal, DescribeAllTerminal, DescribeBodyTerminal, DescribeFamily,
DescribeLocation, DescribePalletTerminal, DescribeTerminus, DescribeTreasuryVoiceTerminal,
GlobalConsensusConvertsFor, GlobalConsensusParachainConvertsFor, HashedDescription,
LocalTreasuryVoiceConvertsVia, ParentIsPreset, SiblingParachainConvertsVia,
};
mod origin_conversion;
pub use origin_conversion::{
BackingToPlurality, ChildParachainAsNative, ChildSystemParachainAsSuperuser, EnsureXcmOrigin,
OriginToPluralityVoice, ParentAsSuperuser, RelayChainAsNative, SiblingParachainAsNative,
SiblingSystemParachainAsSuperuser, SignedAccountId32AsNative, SignedAccountKey20AsNative,
SignedToAccountId32, SovereignSignedViaLocation,
};
mod asset_conversion;
#[allow(deprecated)]
pub use asset_conversion::ConvertedConcreteAssetId;
@@ -61,8 +41,11 @@ pub use barriers::{
WithComputedOrigin,
};
mod process_xcm_message;
pub use process_xcm_message::ProcessXcmMessage;
mod controller;
pub use controller::{
Controller, ExecuteController, ExecuteControllerWeightInfo, QueryController,
QueryControllerWeightInfo, QueryHandler, SendController, SendControllerWeightInfo,
};
mod currency_adapter;
#[allow(deprecated)]
@@ -73,6 +56,9 @@ pub use fee_handling::{
deposit_or_burn_fee, HandleFee, XcmFeeManagerFromComponents, XcmFeeToAccount,
};
mod filter_asset_location;
pub use filter_asset_location::{AllAssets, Case, LocationWithAssetFilters, NativeAsset};
mod fungible_adapter;
pub use fungible_adapter::{FungibleAdapter, FungibleMutateAdapter, FungibleTransferAdapter};
@@ -82,14 +68,16 @@ pub use fungibles_adapter::{
LocalMint, MintLocation, NoChecking, NonLocalMint,
};
mod nonfungibles_adapter;
pub use nonfungibles_adapter::{
NonFungiblesAdapter, NonFungiblesMutateAdapter, NonFungiblesTransferAdapter,
};
mod weight;
pub use weight::{
FixedRateOfFungible, FixedWeightBounds, TakeRevenue, UsingComponents, WeightInfoBounds,
mod location_conversion;
#[allow(deprecated)]
pub use location_conversion::ForeignChainAliasAccount;
pub use location_conversion::{
Account32Hash, AccountId32Aliases, AccountKey20Aliases, AliasesIntoAccountId32,
ChildParachainConvertsVia, DescribeAccountId32Terminal, DescribeAccountIdTerminal,
DescribeAccountKey20Terminal, DescribeAllTerminal, DescribeBodyTerminal, DescribeFamily,
DescribeLocation, DescribePalletTerminal, DescribeTerminus, DescribeTreasuryVoiceTerminal,
GlobalConsensusConvertsFor, GlobalConsensusParachainConvertsFor, HashedDescription,
LocalTreasuryVoiceConvertsVia, ParentIsPreset, SiblingParachainConvertsVia,
};
mod matches_location;
@@ -101,12 +89,34 @@ pub use matches_token::IsConcrete;
mod matcher;
pub use matcher::{CreateMatcher, MatchXcm, Matcher};
mod filter_asset_location;
pub use filter_asset_location::{AllAssets, Case, LocationWithAssetFilters, NativeAsset};
mod nonfungibles_adapter;
pub use nonfungibles_adapter::{
NonFungiblesAdapter, NonFungiblesMutateAdapter, NonFungiblesTransferAdapter,
};
mod origin_aliases;
pub use origin_aliases::AliasForeignAccountId32;
mod origin_conversion;
pub use origin_conversion::{
BackingToPlurality, ChildParachainAsNative, ChildSystemParachainAsSuperuser, EnsureXcmOrigin,
OriginToPluralityVoice, ParentAsSuperuser, RelayChainAsNative, SiblingParachainAsNative,
SiblingSystemParachainAsSuperuser, SignedAccountId32AsNative, SignedAccountKey20AsNative,
SignedToAccountId32, SovereignSignedViaLocation,
};
mod pay;
pub use pay::{FixedLocation, LocatableAssetId, PayAccountId32OnChainOverXcm, PayOverXcm};
mod process_xcm_message;
pub use process_xcm_message::ProcessXcmMessage;
mod routing;
pub use routing::{WithTopicSource, WithUniqueTopic};
mod transactional;
pub use transactional::FrameTransactionalProcessor;
mod universal_exports;
pub use universal_exports::{
ensure_is_remote, BridgeBlobDispatcher, BridgeMessage, DispatchBlob, DispatchBlobError,
@@ -114,14 +124,7 @@ pub use universal_exports::{
NetworkExportTableItem, SovereignPaidRemoteExporter, UnpaidLocalExporter, UnpaidRemoteExporter,
};
mod origin_aliases;
pub use origin_aliases::AliasForeignAccountId32;
mod pay;
pub use pay::{FixedLocation, LocatableAssetId, PayAccountId32OnChainOverXcm, PayOverXcm};
mod controller;
pub use controller::{
Controller, ExecuteController, ExecuteControllerWeightInfo, QueryController,
QueryControllerWeightInfo, QueryHandler, SendController, SendControllerWeightInfo,
mod weight;
pub use weight::{
FixedRateOfFungible, FixedWeightBounds, TakeRevenue, UsingComponents, WeightInfoBounds,
};
@@ -742,6 +742,7 @@ impl Config for TestConfig {
type CallDispatcher = TestCall;
type SafeCallFilter = Everything;
type Aliasers = AliasForeignAccountId32<SiblingPrefix>;
type TransactionalProcessor = ();
}
pub fn fungible_multi_asset(location: Location, amount: u128) -> Asset {
@@ -175,6 +175,7 @@ type OriginConverter = (
);
type Barrier = AllowUnpaidExecutionFrom<Everything>;
#[derive(Clone)]
pub struct DummyWeightTrader;
impl WeightTrader for DummyWeightTrader {
fn new() -> Self {
@@ -217,6 +218,7 @@ impl xcm_executor::Config for XcmConfig {
type CallDispatcher = RuntimeCall;
type SafeCallFilter = Everything;
type Aliasers = Nothing;
type TransactionalProcessor = ();
}
parameter_types! {
@@ -0,0 +1,40 @@
// Copyright 2021 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot 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.
// Polkadot 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 Polkadot. If not, see <http://www.gnu.org/licenses/>.
use frame_support::storage::{with_transaction, TransactionOutcome};
use sp_runtime::DispatchError;
use xcm::latest::prelude::*;
use xcm_executor::traits::ProcessTransaction;
/// Transactional processor implementation using frame transactional layers.
pub struct FrameTransactionalProcessor;
impl ProcessTransaction for FrameTransactionalProcessor {
const IS_TRANSACTIONAL: bool = true;
fn process<F>(f: F) -> Result<(), XcmError>
where
F: FnOnce() -> Result<(), XcmError>,
{
with_transaction(|| -> TransactionOutcome<Result<_, DispatchError>> {
let output = f();
match &output {
Ok(()) => TransactionOutcome::Commit(Ok(output)),
_ => TransactionOutcome::Rollback(Ok(output)),
}
})
.map_err(|_| XcmError::ExceedsStackLimit)?
}
}
+2 -1
View File
@@ -232,12 +232,13 @@ impl<
}
fn refund_weight(&mut self, weight: Weight, context: &XcmContext) -> Option<Asset> {
log::trace!(target: "xcm::weight", "UsingComponents::refund_weight weight: {:?}, context: {:?}", weight, context);
log::trace!(target: "xcm::weight", "UsingComponents::refund_weight weight: {:?}, context: {:?}, available weight: {:?}, available amount: {:?}", weight, context, self.0, self.1);
let weight = weight.min(self.0);
let amount = WeightToFee::weight_to_fee(&weight);
self.0 -= weight;
self.1 = self.1.saturating_sub(amount);
let amount: u128 = amount.saturated_into();
log::trace!(target: "xcm::weight", "UsingComponents::refund_weight amount to refund: {:?}", amount);
if amount > 0 {
Some((AssetIdValue::get(), amount).into())
} else {
@@ -212,6 +212,7 @@ impl xcm_executor::Config for XcmConfig {
type CallDispatcher = RuntimeCall;
type SafeCallFilter = Everything;
type Aliasers = Nothing;
type TransactionalProcessor = ();
}
pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, KusamaNetwork>;
+5 -2
View File
@@ -16,8 +16,8 @@
use crate::traits::{
AssetExchange, AssetLock, CallDispatcher, ClaimAssets, ConvertOrigin, DropAssets, ExportXcm,
FeeManager, OnResponse, ShouldExecute, TransactAsset, VersionChangeNotifier, WeightBounds,
WeightTrader,
FeeManager, OnResponse, ProcessTransaction, ShouldExecute, TransactAsset,
VersionChangeNotifier, WeightBounds, WeightTrader,
};
use frame_support::{
dispatch::{GetDispatchInfo, Parameter, PostDispatchInfo},
@@ -111,4 +111,7 @@ pub trait Config {
/// Use this type to explicitly whitelist calls that cannot undergo recursion. This is a
/// temporary measure until we properly account for proof size weights for XCM instructions.
type SafeCallFilter: Contains<Self::RuntimeCall>;
/// Transactional processor for XCM instructions.
type TransactionalProcessor: ProcessTransaction;
}
+276 -161
View File
@@ -19,7 +19,7 @@
use frame_support::{
dispatch::GetDispatchInfo,
ensure,
traits::{Contains, ContainsPair, Get, PalletsInfoAccess},
traits::{Contains, ContainsPair, Defensive, Get, PalletsInfoAccess},
};
use parity_scale_codec::{Decode, Encode};
use sp_core::defer;
@@ -31,8 +31,9 @@ use xcm::latest::prelude::*;
pub mod traits;
use traits::{
validate_export, AssetExchange, AssetLock, CallDispatcher, ClaimAssets, ConvertOrigin,
DropAssets, Enact, ExportXcm, FeeManager, FeeReason, OnResponse, Properties, ShouldExecute,
TransactAsset, VersionChangeNotifier, WeightBounds, WeightTrader, XcmAssetTransfers,
DropAssets, Enact, ExportXcm, FeeManager, FeeReason, OnResponse, ProcessTransaction,
Properties, ShouldExecute, TransactAsset, VersionChangeNotifier, WeightBounds, WeightTrader,
XcmAssetTransfers,
};
mod assets;
@@ -373,33 +374,53 @@ impl<Config: config::Config> XcmExecutor<Config> {
r
}
fn subsume_asset(&mut self, asset: Asset) -> Result<(), XcmError> {
fn ensure_can_subsume_assets(&self, assets_length: usize) -> Result<(), XcmError> {
// worst-case, holding.len becomes 2 * holding_limit.
ensure!(self.holding.len() < self.holding_limit * 2, XcmError::HoldingWouldOverflow);
self.holding.subsume(asset);
Ok(())
}
fn subsume_assets(&mut self, assets: AssetsInHolding) -> Result<(), XcmError> {
// worst-case, holding.len becomes 2 * holding_limit.
// this guarantees that if holding.len() == holding_limit and you have holding_limit more
// items (which has a best case outcome of holding.len() == holding_limit), then you'll
// be guaranteed of making the operation.
let worst_case_holding_len = self.holding.len() + assets.len();
// this guarantees that if holding.len() == holding_limit and you have more than
// `holding_limit` items (which has a best case outcome of holding.len() == holding_limit),
// then the operation is guaranteed to succeed.
let worst_case_holding_len = self.holding.len() + assets_length;
log::trace!(target: "xcm::ensure_can_subsume_assets", "worst_case_holding_len: {:?}, holding_limit: {:?}", worst_case_holding_len, self.holding_limit);
ensure!(worst_case_holding_len <= self.holding_limit * 2, XcmError::HoldingWouldOverflow);
self.holding.subsume_assets(assets);
Ok(())
}
/// Refund any unused weight.
fn refund_surplus(&mut self) -> Result<(), XcmError> {
let current_surplus = self.total_surplus.saturating_sub(self.total_refunded);
log::trace!(
target: "xcm::refund_surplus",
"total_surplus: {:?}, total_refunded: {:?}, current_surplus: {:?}",
self.total_surplus,
self.total_refunded,
current_surplus,
);
if current_surplus.any_gt(Weight::zero()) {
self.total_refunded.saturating_accrue(current_surplus);
if let Some(w) = self.trader.refund_weight(current_surplus, &self.context) {
self.subsume_asset(w)?;
if !self.holding.contains_asset(&(w.id.clone(), 1).into()) &&
self.ensure_can_subsume_assets(1).is_err()
{
let _ = self
.trader
.buy_weight(current_surplus, w.into(), &self.context)
.defensive_proof(
"refund_weight returned an asset capable of buying weight; qed",
);
log::error!(
target: "xcm::refund_surplus",
"error: HoldingWouldOverflow",
);
return Err(XcmError::HoldingWouldOverflow)
}
self.total_refunded.saturating_accrue(current_surplus);
self.holding.subsume_assets(w.into());
}
}
log::trace!(
target: "xcm::refund_surplus",
"total_refunded: {:?}",
self.total_refunded,
);
Ok(())
}
@@ -554,75 +575,101 @@ impl<Config: config::Config> XcmExecutor<Config> {
);
match instr {
WithdrawAsset(assets) => {
let origin = self.cloned_origin().ok_or(XcmError::BadOrigin)?;
// Take `assets` from the origin account (on-chain) and place in holding.
for asset in assets.into_inner().into_iter() {
Config::AssetTransactor::withdraw_asset(&asset, &origin, Some(&self.context))?;
self.subsume_asset(asset)?;
}
Ok(())
let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
self.ensure_can_subsume_assets(assets.len())?;
Config::TransactionalProcessor::process(|| {
// Take `assets` from the origin account (on-chain)...
for asset in assets.inner() {
Config::AssetTransactor::withdraw_asset(
asset,
origin,
Some(&self.context),
)?;
}
Ok(())
})
.and_then(|_| {
// ...and place into holding.
self.holding.subsume_assets(assets.into());
Ok(())
})
},
ReserveAssetDeposited(assets) => {
// check whether we trust origin to be our reserve location for this asset.
for asset in assets.into_inner().into_iter() {
let origin = self.cloned_origin().ok_or(XcmError::BadOrigin)?;
let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
self.ensure_can_subsume_assets(assets.len())?;
for asset in assets.inner() {
// Must ensure that we recognise the asset as being managed by the origin.
ensure!(
Config::IsReserve::contains(&asset, &origin),
Config::IsReserve::contains(asset, origin),
XcmError::UntrustedReserveLocation
);
self.subsume_asset(asset)?;
}
self.holding.subsume_assets(assets.into());
Ok(())
},
TransferAsset { assets, beneficiary } => {
// Take `assets` from the origin account (on-chain) and place into dest account.
let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
for asset in assets.inner() {
Config::AssetTransactor::transfer_asset(
&asset,
origin,
&beneficiary,
&self.context,
)?;
}
Ok(())
Config::TransactionalProcessor::process(|| {
// Take `assets` from the origin account (on-chain) and place into dest account.
let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
for asset in assets.inner() {
Config::AssetTransactor::transfer_asset(
&asset,
origin,
&beneficiary,
&self.context,
)?;
}
Ok(())
})
},
TransferReserveAsset { mut assets, dest, xcm } => {
let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
// Take `assets` from the origin account (on-chain) and place into dest account.
for asset in assets.inner() {
Config::AssetTransactor::transfer_asset(asset, origin, &dest, &self.context)?;
}
let reanchor_context = Config::UniversalLocation::get();
assets.reanchor(&dest, &reanchor_context).map_err(|()| XcmError::LocationFull)?;
let mut message = vec![ReserveAssetDeposited(assets), ClearOrigin];
message.extend(xcm.0.into_iter());
self.send(dest, Xcm(message), FeeReason::TransferReserveAsset)?;
Ok(())
Config::TransactionalProcessor::process(|| {
let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
// Take `assets` from the origin account (on-chain) and place into dest account.
for asset in assets.inner() {
Config::AssetTransactor::transfer_asset(
asset,
origin,
&dest,
&self.context,
)?;
}
let reanchor_context = Config::UniversalLocation::get();
assets
.reanchor(&dest, &reanchor_context)
.map_err(|()| XcmError::LocationFull)?;
let mut message = vec![ReserveAssetDeposited(assets), ClearOrigin];
message.extend(xcm.0.into_iter());
self.send(dest, Xcm(message), FeeReason::TransferReserveAsset)?;
Ok(())
})
},
ReceiveTeleportedAsset(assets) => {
let origin = self.cloned_origin().ok_or(XcmError::BadOrigin)?;
// check whether we trust origin to teleport this asset to us via config trait.
for asset in assets.inner() {
// We only trust the origin to send us assets that they identify as their
// sovereign assets.
ensure!(
Config::IsTeleporter::contains(asset, &origin),
XcmError::UntrustedTeleportLocation
);
// We should check that the asset can actually be teleported in (for this to be
// in error, there would need to be an accounting violation by one of the
// trusted chains, so it's unlikely, but we don't want to punish a possibly
// innocent chain/user).
Config::AssetTransactor::can_check_in(&origin, asset, &self.context)?;
}
for asset in assets.into_inner().into_iter() {
let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
Config::AssetTransactor::check_in(&origin, &asset, &self.context);
self.subsume_asset(asset)?;
}
Ok(())
let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
self.ensure_can_subsume_assets(assets.len())?;
Config::TransactionalProcessor::process(|| {
// check whether we trust origin to teleport this asset to us via config trait.
for asset in assets.inner() {
// We only trust the origin to send us assets that they identify as their
// sovereign assets.
ensure!(
Config::IsTeleporter::contains(asset, origin),
XcmError::UntrustedTeleportLocation
);
// We should check that the asset can actually be teleported in (for this to
// be in error, there would need to be an accounting violation by one of the
// trusted chains, so it's unlikely, but we don't want to punish a possibly
// innocent chain/user).
Config::AssetTransactor::can_check_in(origin, asset, &self.context)?;
Config::AssetTransactor::check_in(origin, asset, &self.context);
}
Ok(())
})
.and_then(|_| {
self.holding.subsume_assets(assets.into());
Ok(())
})
},
Transact { origin_kind, require_weight_at_most, mut call } => {
// We assume that the Relay-chain is allowed to use transact on this parachain.
@@ -755,62 +802,92 @@ impl<Config: config::Config> XcmExecutor<Config> {
Ok(())
},
DepositAsset { assets, beneficiary } => {
let deposited = self.holding.saturating_take(assets);
for asset in deposited.into_assets_iter() {
Config::AssetTransactor::deposit_asset(
&asset,
&beneficiary,
Some(&self.context),
)?;
let old_holding = self.holding.clone();
let result = Config::TransactionalProcessor::process(|| {
let deposited = self.holding.saturating_take(assets);
for asset in deposited.into_assets_iter() {
Config::AssetTransactor::deposit_asset(
&asset,
&beneficiary,
Some(&self.context),
)?;
}
Ok(())
});
if Config::TransactionalProcessor::IS_TRANSACTIONAL && result.is_err() {
self.holding = old_holding;
}
Ok(())
result
},
DepositReserveAsset { assets, dest, xcm } => {
let deposited = self.holding.saturating_take(assets);
for asset in deposited.assets_iter() {
Config::AssetTransactor::deposit_asset(&asset, &dest, Some(&self.context))?;
let old_holding = self.holding.clone();
let result = Config::TransactionalProcessor::process(|| {
let deposited = self.holding.saturating_take(assets);
for asset in deposited.assets_iter() {
Config::AssetTransactor::deposit_asset(&asset, &dest, Some(&self.context))?;
}
// Note that we pass `None` as `maybe_failed_bin` and drop any assets which
// cannot be reanchored because we have already called `deposit_asset` on all
// assets.
let assets = Self::reanchored(deposited, &dest, None);
let mut message = vec![ReserveAssetDeposited(assets), ClearOrigin];
message.extend(xcm.0.into_iter());
self.send(dest, Xcm(message), FeeReason::DepositReserveAsset)?;
Ok(())
});
if Config::TransactionalProcessor::IS_TRANSACTIONAL && result.is_err() {
self.holding = old_holding;
}
// Note that we pass `None` as `maybe_failed_bin` and drop any assets which cannot
// be reanchored because we have already called `deposit_asset` on all assets.
let assets = Self::reanchored(deposited, &dest, None);
let mut message = vec![ReserveAssetDeposited(assets), ClearOrigin];
message.extend(xcm.0.into_iter());
self.send(dest, Xcm(message), FeeReason::DepositReserveAsset)?;
Ok(())
result
},
InitiateReserveWithdraw { assets, reserve, xcm } => {
// Note that here we are able to place any assets which could not be reanchored
// back into Holding.
let assets = Self::reanchored(
self.holding.saturating_take(assets),
&reserve,
Some(&mut self.holding),
);
let mut message = vec![WithdrawAsset(assets), ClearOrigin];
message.extend(xcm.0.into_iter());
self.send(reserve, Xcm(message), FeeReason::InitiateReserveWithdraw)?;
Ok(())
let old_holding = self.holding.clone();
let result = Config::TransactionalProcessor::process(|| {
// Note that here we are able to place any assets which could not be reanchored
// back into Holding.
let assets = Self::reanchored(
self.holding.saturating_take(assets),
&reserve,
Some(&mut self.holding),
);
let mut message = vec![WithdrawAsset(assets), ClearOrigin];
message.extend(xcm.0.into_iter());
self.send(reserve, Xcm(message), FeeReason::InitiateReserveWithdraw)?;
Ok(())
});
if Config::TransactionalProcessor::IS_TRANSACTIONAL && result.is_err() {
self.holding = old_holding;
}
result
},
InitiateTeleport { assets, dest, xcm } => {
// We must do this first in order to resolve wildcards.
let assets = self.holding.saturating_take(assets);
for asset in assets.assets_iter() {
// We should check that the asset can actually be teleported out (for this to
// be in error, there would need to be an accounting violation by ourselves,
// so it's unlikely, but we don't want to allow that kind of bug to leak into
// a trusted chain.
Config::AssetTransactor::can_check_out(&dest, &asset, &self.context)?;
let old_holding = self.holding.clone();
let result = (|| -> Result<(), XcmError> {
// We must do this first in order to resolve wildcards.
let assets = self.holding.saturating_take(assets);
for asset in assets.assets_iter() {
// We should check that the asset can actually be teleported out (for this
// to be in error, there would need to be an accounting violation by
// ourselves, so it's unlikely, but we don't want to allow that kind of bug
// to leak into a trusted chain.
Config::AssetTransactor::can_check_out(&dest, &asset, &self.context)?;
}
// Note that we pass `None` as `maybe_failed_bin` and drop any assets which
// cannot be reanchored because we have already checked all assets out.
let reanchored_assets = Self::reanchored(assets.clone(), &dest, None);
let mut message = vec![ReceiveTeleportedAsset(reanchored_assets), ClearOrigin];
message.extend(xcm.0.into_iter());
self.send(dest.clone(), Xcm(message), FeeReason::InitiateTeleport)?;
for asset in assets.assets_iter() {
Config::AssetTransactor::check_out(&dest, &asset, &self.context);
}
Ok(())
})();
if result.is_err() {
self.holding = old_holding;
}
for asset in assets.assets_iter() {
Config::AssetTransactor::check_out(&dest, &asset, &self.context);
}
// Note that we pass `None` as `maybe_failed_bin` and drop any assets which cannot
// be reanchored because we have already checked all assets out.
let assets = Self::reanchored(assets, &dest, None);
let mut message = vec![ReceiveTeleportedAsset(assets), ClearOrigin];
message.extend(xcm.0.into_iter());
self.send(dest, Xcm(message), FeeReason::InitiateTeleport)?;
Ok(())
result
},
ReportHolding { response_info, assets } => {
// Note that we pass `None` as `maybe_failed_bin` since no assets were ever removed
@@ -826,18 +903,24 @@ impl<Config: config::Config> XcmExecutor<Config> {
Ok(())
},
BuyExecution { fees, weight_limit } => {
// There is no need to buy any weight is `weight_limit` is `Unlimited` since it
// There is no need to buy any weight if `weight_limit` is `Unlimited` since it
// would indicate that `AllowTopLevelPaidExecutionFrom` was unused for execution
// and thus there is some other reason why it has been determined that this XCM
// should be executed.
if let Some(weight) = Option::<Weight>::from(weight_limit) {
// pay for `weight` using up to `fees` of the holding register.
let max_fee =
self.holding.try_take(fees.into()).map_err(|_| XcmError::NotHoldingFees)?;
let Some(weight) = Option::<Weight>::from(weight_limit) else { return Ok(()) };
let old_holding = self.holding.clone();
// pay for `weight` using up to `fees` of the holding register.
let max_fee =
self.holding.try_take(fees.into()).map_err(|_| XcmError::NotHoldingFees)?;
let result = || -> Result<(), XcmError> {
let unspent = self.trader.buy_weight(weight, max_fee, &self.context)?;
self.subsume_assets(unspent)?;
self.holding.subsume_assets(unspent);
Ok(())
}();
if result.is_err() {
self.holding = old_holding;
}
Ok(())
result
},
RefundSurplus => self.refund_surplus(),
SetErrorHandler(mut handler) => {
@@ -862,11 +945,10 @@ impl<Config: config::Config> XcmExecutor<Config> {
},
ClaimAsset { assets, ticket } => {
let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?;
self.ensure_can_subsume_assets(assets.len())?;
let ok = Config::AssetClaims::claim_assets(origin, &ticket, &assets, &self.context);
ensure!(ok, XcmError::UnknownClaim);
for asset in assets.into_inner().into_iter() {
self.subsume_asset(asset)?;
}
self.holding.subsume_assets(assets.into());
Ok(())
},
Trap(code) => Err(XcmError::Trap(code)),
@@ -984,8 +1066,8 @@ impl<Config: config::Config> XcmExecutor<Config> {
let hash = (self.origin_ref(), &destination).using_encoded(blake2_128);
let channel = u32::decode(&mut hash.as_ref()).unwrap_or(0);
// Hash identifies the lane on the exporter which we use. We use the pairwise
// combination of the origin and destination to ensure origin/destination pairs will
// generally have their own lanes.
// combination of the origin and destination to ensure origin/destination pairs
// will generally have their own lanes.
let (ticket, fee) = validate_export::<Config::MessageExporter>(
network,
channel,
@@ -993,23 +1075,41 @@ impl<Config: config::Config> XcmExecutor<Config> {
destination.clone(),
xcm,
)?;
self.take_fee(fee, FeeReason::Export { network, destination })?;
Config::MessageExporter::deliver(ticket)?;
Ok(())
let old_holding = self.holding.clone();
let result = Config::TransactionalProcessor::process(|| {
self.take_fee(fee, FeeReason::Export { network, destination })?;
let _ = Config::MessageExporter::deliver(ticket).defensive_proof(
"`deliver` called immediately after `validate_export`; \
`take_fee` does not affect the validity of the ticket; qed",
);
Ok(())
});
if Config::TransactionalProcessor::IS_TRANSACTIONAL && result.is_err() {
self.holding = old_holding;
}
result
},
LockAsset { asset, unlocker } => {
let origin = self.cloned_origin().ok_or(XcmError::BadOrigin)?;
let (remote_asset, context) = Self::try_reanchor(asset.clone(), &unlocker)?;
let lock_ticket =
Config::AssetLocker::prepare_lock(unlocker.clone(), asset, origin.clone())?;
let owner =
origin.reanchored(&unlocker, &context).map_err(|_| XcmError::ReanchorFailed)?;
let msg = Xcm::<()>(vec![NoteUnlockable { asset: remote_asset, owner }]);
let (ticket, price) = validate_send::<Config::XcmSender>(unlocker, msg)?;
self.take_fee(price, FeeReason::LockAsset)?;
lock_ticket.enact()?;
Config::XcmSender::deliver(ticket)?;
Ok(())
let old_holding = self.holding.clone();
let result = Config::TransactionalProcessor::process(|| {
let origin = self.cloned_origin().ok_or(XcmError::BadOrigin)?;
let (remote_asset, context) = Self::try_reanchor(asset.clone(), &unlocker)?;
let lock_ticket =
Config::AssetLocker::prepare_lock(unlocker.clone(), asset, origin.clone())?;
let owner = origin
.reanchored(&unlocker, &context)
.map_err(|_| XcmError::ReanchorFailed)?;
let msg = Xcm::<()>(vec![NoteUnlockable { asset: remote_asset, owner }]);
let (ticket, price) = validate_send::<Config::XcmSender>(unlocker, msg)?;
self.take_fee(price, FeeReason::LockAsset)?;
lock_ticket.enact()?;
Config::XcmSender::deliver(ticket)?;
Ok(())
});
if Config::TransactionalProcessor::IS_TRANSACTIONAL && result.is_err() {
self.holding = old_holding;
}
result
},
UnlockAsset { asset, target } => {
let origin = self.cloned_origin().ok_or(XcmError::BadOrigin)?;
@@ -1033,25 +1133,40 @@ impl<Config: config::Config> XcmExecutor<Config> {
let msg =
Xcm::<()>(vec![UnlockAsset { asset: remote_asset, target: remote_target }]);
let (ticket, price) = validate_send::<Config::XcmSender>(locker, msg)?;
self.take_fee(price, FeeReason::RequestUnlock)?;
reduce_ticket.enact()?;
Config::XcmSender::deliver(ticket)?;
Ok(())
let old_holding = self.holding.clone();
let result = Config::TransactionalProcessor::process(|| {
self.take_fee(price, FeeReason::RequestUnlock)?;
reduce_ticket.enact()?;
Config::XcmSender::deliver(ticket)?;
Ok(())
});
if Config::TransactionalProcessor::IS_TRANSACTIONAL && result.is_err() {
self.holding = old_holding;
}
result
},
ExchangeAsset { give, want, maximal } => {
let old_holding = self.holding.clone();
let give = self.holding.saturating_take(give);
let r =
Config::AssetExchanger::exchange_asset(self.origin_ref(), give, &want, maximal);
let completed = r.is_ok();
let received = r.unwrap_or_else(|a| a);
for asset in received.into_assets_iter() {
self.holding.subsume(asset);
}
if completed {
Ok(())
} else {
Err(XcmError::NoDeal)
let result = (|| -> Result<(), XcmError> {
self.ensure_can_subsume_assets(want.len())?;
let exchange_result = Config::AssetExchanger::exchange_asset(
self.origin_ref(),
give,
&want,
maximal,
);
if let Ok(received) = exchange_result {
self.holding.subsume_assets(received.into());
Ok(())
} else {
Err(XcmError::NoDeal)
}
})();
if result.is_err() {
self.holding = old_holding;
}
result
},
SetFeesMode { jit_withdraw } => {
self.fees_mode = FeesMode { jit_withdraw };
+5 -2
View File
@@ -39,6 +39,8 @@ pub use token_matching::{
};
mod on_response;
pub use on_response::{OnResponse, QueryHandler, QueryResponseStatus, VersionChangeNotifier};
mod process_transaction;
pub use process_transaction::ProcessTransaction;
mod should_execute;
pub use should_execute::{CheckSuspension, Properties, ShouldExecute};
mod transact_asset;
@@ -52,8 +54,9 @@ pub mod prelude {
pub use super::{
export_xcm, validate_export, AssetExchange, AssetLock, ClaimAssets, ConvertOrigin,
DropAssets, Enact, Error, ExportXcm, FeeManager, FeeReason, LockError, MatchesFungible,
MatchesFungibles, MatchesNonFungible, MatchesNonFungibles, OnResponse, ShouldExecute,
TransactAsset, VersionChangeNotifier, WeightBounds, WeightTrader, WithOriginFilter,
MatchesFungibles, MatchesNonFungible, MatchesNonFungibles, OnResponse, ProcessTransaction,
ShouldExecute, TransactAsset, VersionChangeNotifier, WeightBounds, WeightTrader,
WithOriginFilter,
};
#[allow(deprecated)]
pub use super::{Identity, JustTry};
@@ -0,0 +1,57 @@
// Copyright Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot 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.
// Polkadot 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 Polkadot. If not, see <http://www.gnu.org/licenses/>.
use xcm::latest::prelude::*;
/// Provides mechanisms for transactional processing of XCM instructions.
///
/// This trait defines the behavior required to process XCM instructions in a transactional
/// manner. Implementers of this trait can ensure that XCM instructions are executed
/// atomically, meaning they either fully succeed or fully fail without any partial effects.
///
/// Implementers of this trait can also choose to not process XCM instructions transactionally.
/// This is useful for cases where the implementer is not able to provide transactional guarantees.
/// In this case the `IS_TRANSACTIONAL` constant should be set to `false`.
/// The `()` type implements this trait in a non-transactional manner.
pub trait ProcessTransaction {
/// Whether or not the implementor of the this trait is actually transactional.
const IS_TRANSACTIONAL: bool;
/// Processes an XCM instruction encapsulated within the provided closure. Responsible for
/// processing an XCM instruction transactionally. If the closure returns an error, any
/// changes made during its execution should be rolled back. In the case where the
/// implementer is not able to provide transactional guarantees, the closure should be
/// executed as is.
/// # Parameters
/// - `f`: A closure that encapsulates the XCM instruction being processed. It will return a
/// `Result` indicating the success or failure of the instruction.
///
/// # Returns
/// - A `Result` indicating the overall success or failure of the transactional process.
fn process<F>(f: F) -> Result<(), XcmError>
where
F: FnOnce() -> Result<(), XcmError>;
}
impl ProcessTransaction for () {
const IS_TRANSACTIONAL: bool = false;
fn process<F>(f: F) -> Result<(), XcmError>
where
F: FnOnce() -> Result<(), XcmError>,
{
f()
}
}
@@ -40,9 +40,10 @@ use polkadot_parachain_primitives::primitives::{
use xcm::{latest::prelude::*, VersionedXcm};
use xcm_builder::{
Account32Hash, AccountId32Aliases, AllowUnpaidExecutionFrom, ConvertedConcreteId,
EnsureXcmOrigin, FixedRateOfFungible, FixedWeightBounds, FungibleAdapter, IsConcrete,
NativeAsset, NoChecking, NonFungiblesAdapter, ParentIsPreset, SiblingParachainConvertsVia,
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation,
EnsureXcmOrigin, FixedRateOfFungible, FixedWeightBounds, FrameTransactionalProcessor,
FungibleAdapter, IsConcrete, NativeAsset, NoChecking, NonFungiblesAdapter, ParentIsPreset,
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation,
};
use xcm_executor::{
traits::{ConvertLocation, JustTry},
@@ -250,6 +251,7 @@ impl Config for XcmConfig {
type CallDispatcher = RuntimeCall;
type SafeCallFilter = Everything;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
}
#[frame_support::pallet]
@@ -36,9 +36,9 @@ use xcm::latest::prelude::*;
use xcm_builder::{
Account32Hash, AccountId32Aliases, AllowUnpaidExecutionFrom, AsPrefixedGeneralIndex,
ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser,
ConvertedConcreteId, FixedRateOfFungible, FixedWeightBounds, FungibleAdapter, IsConcrete,
NoChecking, NonFungiblesAdapter, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation,
ConvertedConcreteId, FixedRateOfFungible, FixedWeightBounds, FrameTransactionalProcessor,
FungibleAdapter, IsConcrete, NoChecking, NonFungiblesAdapter, SignedAccountId32AsNative,
SignedToAccountId32, SovereignSignedViaLocation,
};
use xcm_executor::{traits::JustTry, Config, XcmExecutor};
@@ -198,6 +198,7 @@ impl Config for XcmConfig {
type CallDispatcher = RuntimeCall;
type SafeCallFilter = Everything;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
}
pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>;
@@ -41,8 +41,9 @@ use xcm::{latest::prelude::*, VersionedXcm};
use xcm_builder::CurrencyAdapter as XcmCurrencyAdapter;
use xcm_builder::{
AccountId32Aliases, AllowUnpaidExecutionFrom, EnsureXcmOrigin, FixedRateOfFungible,
FixedWeightBounds, IsConcrete, NativeAsset, ParentIsPreset, SiblingParachainConvertsVia,
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation,
FixedWeightBounds, FrameTransactionalProcessor, IsConcrete, NativeAsset, ParentIsPreset,
SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation,
};
use xcm_executor::{Config, XcmExecutor};
@@ -166,6 +167,7 @@ impl Config for XcmConfig {
type CallDispatcher = RuntimeCall;
type SafeCallFilter = Everything;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
}
#[frame_support::pallet]
@@ -38,8 +38,8 @@ use xcm_builder::CurrencyAdapter as XcmCurrencyAdapter;
use xcm_builder::{
AccountId32Aliases, AllowUnpaidExecutionFrom, ChildParachainAsNative,
ChildParachainConvertsVia, ChildSystemParachainAsSuperuser, FixedRateOfFungible,
FixedWeightBounds, IsConcrete, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation,
FixedWeightBounds, FrameTransactionalProcessor, IsConcrete, SignedAccountId32AsNative,
SignedToAccountId32, SovereignSignedViaLocation,
};
use xcm_executor::{Config, XcmExecutor};
@@ -165,6 +165,7 @@ impl Config for XcmConfig {
type CallDispatcher = RuntimeCall;
type SafeCallFilter = Everything;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
}
pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, ThisNetwork>;
+33
View File
@@ -0,0 +1,33 @@
title: Transactional processing for XCM
doc:
- audience: Runtime Dev
description: |
Transactional processing was introduced for certain XCM instructions. They are:
- WithdrawAsset
- ReserveAssetDeposited
- TransferAsset
- TransferReserveAsset
- ReceiveTeleportedAsset
- DepositAsset
- DepositReserveAsset
- InitiateReserveWithdraw
- InitiateTeleport
- BuyExecution
- ClaimAsset
- ExportMessage
- LockAsset
- UnlockAsset
- RequestUnlock
Developers must specify a `TransactionalProcessor` when configuring their XCM executor.
FRAME-based runtimes would simply need to configure it with `FrameTransactionalProcessor` to
enable transactional processing. To disable transactional processing of XCMs, `()` may also be
specified as the type for `TransactionalProcessor`.
For runtimes that are not FRAME-based but would like to still harness transactional processing
of XCMs, a type implementing the `ProcessTransaction` trait must be specified as the type for
`TransactionalProcessor`. This trait is for the purpose of connecting the chain's runtime
transactional processor with the XCM executor -- any implementation of `ProcessTransaction` is
possible to be assigned as the `TransactionalProcessor` for the XCM executor.
crates:
- name: staging-xcm-executor
@@ -41,9 +41,10 @@ use xcm::latest::prelude::*;
use xcm_builder::CurrencyAdapter as XcmCurrencyAdapter;
use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom,
ConvertedConcreteId, EnsureXcmOrigin, FixedRateOfFungible, FixedWeightBounds, FungiblesAdapter,
IsConcrete, NativeAsset, NoChecking, ParentAsSuperuser, ParentIsPreset,
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, WithComputedOrigin,
ConvertedConcreteId, EnsureXcmOrigin, FixedRateOfFungible, FixedWeightBounds,
FrameTransactionalProcessor, FungiblesAdapter, IsConcrete, NativeAsset, NoChecking,
ParentAsSuperuser, ParentIsPreset, SignedAccountId32AsNative, SignedToAccountId32,
SovereignSignedViaLocation, WithComputedOrigin,
};
use xcm_executor::{traits::JustTry, Config, XcmExecutor};
@@ -284,6 +285,7 @@ impl Config for XcmConfig {
type CallDispatcher = RuntimeCall;
type SafeCallFilter = Everything;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
}
impl mock_msg_queue::Config for Runtime {
@@ -35,8 +35,8 @@ use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowSubscriptionsFrom,
AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia,
ChildSystemParachainAsSuperuser, DescribeAllTerminal, DescribeFamily, FixedRateOfFungible,
FixedWeightBounds, HashedDescription, IsConcrete, SignedAccountId32AsNative,
SignedToAccountId32, SovereignSignedViaLocation, WithComputedOrigin,
FixedWeightBounds, FrameTransactionalProcessor, HashedDescription, IsConcrete,
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, WithComputedOrigin,
};
use xcm_executor::{Config, XcmExecutor};
@@ -185,6 +185,7 @@ impl Config for XcmConfig {
type CallDispatcher = RuntimeCall;
type SafeCallFilter = Everything;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
}
pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>;