Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change XcmDryRunApi::dry_run_extrinsic to take a call instead #4621

Merged
merged 19 commits into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,15 @@

use crate::imports::*;

use sp_keyring::AccountKeyring::Alice;
use sp_runtime::{generic, MultiSignature};
use frame_system::RawOrigin;
use xcm_fee_payment_runtime_api::{
dry_run::runtime_decl_for_xcm_dry_run_api::XcmDryRunApiV1,
dry_run::runtime_decl_for_dry_run_api::DryRunApiV1,
fees::runtime_decl_for_xcm_payment_api::XcmPaymentApiV1,
};

/// We are able to dry-run and estimate the fees for a teleport between relay and system para.
/// Scenario: Alice on Westend relay chain wants to teleport WND to Asset Hub.
/// We want to know the fees using the `XcmDryRunApi` and `XcmPaymentApi`.
/// We want to know the fees using the `DryRunApi` and `XcmPaymentApi`.
#[test]
fn teleport_relay_system_para_works() {
let destination: Location = Parachain(1000).into(); // Asset Hub.
Expand All @@ -42,6 +41,7 @@ fn teleport_relay_system_para_works() {
<Westend as TestExt>::new_ext().execute_with(|| {
type Runtime = <Westend as Chain>::Runtime;
type RuntimeCall = <Westend as Chain>::RuntimeCall;
type OriginCaller = <Westend as Chain>::OriginCaller;

let call = RuntimeCall::XcmPallet(pallet_xcm::Call::transfer_assets {
dest: Box::new(VersionedLocation::V4(destination.clone())),
Expand All @@ -50,9 +50,8 @@ fn teleport_relay_system_para_works() {
fee_asset_item: 0,
weight_limit: Unlimited,
});
let sender = Alice; // Is the same as `WestendSender`.
let extrinsic = construct_extrinsic_westend(sender, call);
let result = Runtime::dry_run_extrinsic(extrinsic).unwrap();
let origin = OriginCaller::system(RawOrigin::Signed(WestendSender::get()));
let result = Runtime::dry_run_call(origin, call).unwrap();
assert_eq!(result.forwarded_xcms.len(), 1);
let (destination_to_query, messages_to_query) = &result.forwarded_xcms[0];
assert_eq!(messages_to_query.len(), 1);
Expand Down Expand Up @@ -105,7 +104,7 @@ fn teleport_relay_system_para_works() {

/// We are able to dry-run and estimate the fees for a multi-hop XCM journey.
/// Scenario: Alice on PenpalA has some WND and wants to send them to PenpalB.
/// We want to know the fees using the `XcmDryRunApi` and `XcmPaymentApi`.
/// We want to know the fees using the `DryRunApi` and `XcmPaymentApi`.
#[test]
fn multi_hop_works() {
let destination = PenpalA::sibling_location_of(PenpalB::para_id());
Expand Down Expand Up @@ -142,6 +141,7 @@ fn multi_hop_works() {
<PenpalA as TestExt>::execute_with(|| {
type Runtime = <PenpalA as Chain>::Runtime;
type RuntimeCall = <PenpalA as Chain>::RuntimeCall;
type OriginCaller = <PenpalA as Chain>::OriginCaller;

let call = RuntimeCall::PolkadotXcm(pallet_xcm::Call::transfer_assets {
dest: Box::new(VersionedLocation::V4(destination.clone())),
Expand All @@ -150,9 +150,8 @@ fn multi_hop_works() {
fee_asset_item: 0,
weight_limit: Unlimited,
});
let sender = Alice; // Same as `PenpalASender`.
let extrinsic = construct_extrinsic_penpal(sender, call);
let result = Runtime::dry_run_extrinsic(extrinsic).unwrap();
let origin = OriginCaller::system(RawOrigin::Signed(PenpalASender::get()));
let result = Runtime::dry_run_call(origin, call).unwrap();
assert_eq!(result.forwarded_xcms.len(), 1);
let (destination_to_query, messages_to_query) = &result.forwarded_xcms[0];
assert_eq!(messages_to_query.len(), 1);
Expand Down Expand Up @@ -304,68 +303,3 @@ fn transfer_assets_para_to_para(test: ParaToParaThroughRelayTest) -> DispatchRes
test.args.weight_limit,
)
}

// Constructs the SignedExtra component of an extrinsic for the Westend runtime.
fn construct_extrinsic_westend(
sender: sp_keyring::AccountKeyring,
call: westend_runtime::RuntimeCall,
) -> westend_runtime::UncheckedExtrinsic {
type Runtime = <Westend as Chain>::Runtime;
let account_id = <Runtime as frame_system::Config>::AccountId::from(sender.public());
let tip = 0;
let extra: westend_runtime::SignedExtra = (
frame_system::CheckNonZeroSender::<Runtime>::new(),
frame_system::CheckSpecVersion::<Runtime>::new(),
frame_system::CheckTxVersion::<Runtime>::new(),
frame_system::CheckGenesis::<Runtime>::new(),
frame_system::CheckMortality::<Runtime>::from(sp_runtime::generic::Era::immortal()),
frame_system::CheckNonce::<Runtime>::from(
frame_system::Pallet::<Runtime>::account(&account_id).nonce,
),
frame_system::CheckWeight::<Runtime>::new(),
pallet_transaction_payment::ChargeTransactionPayment::<Runtime>::from(tip),
frame_metadata_hash_extension::CheckMetadataHash::<Runtime>::new(false),
);
let raw_payload = westend_runtime::SignedPayload::new(call, extra).unwrap();
let signature = raw_payload.using_encoded(|payload| sender.sign(payload));
let (call, extra, _) = raw_payload.deconstruct();
westend_runtime::UncheckedExtrinsic::new_signed(
call,
account_id.into(),
MultiSignature::Sr25519(signature),
extra,
)
}

// Constructs the SignedExtra component of an extrinsic for the Westend runtime.
fn construct_extrinsic_penpal(
sender: sp_keyring::AccountKeyring,
call: penpal_runtime::RuntimeCall,
) -> penpal_runtime::UncheckedExtrinsic {
type Runtime = <PenpalA as Chain>::Runtime;
let account_id = <Runtime as frame_system::Config>::AccountId::from(sender.public());
let tip = 0;
let extra: penpal_runtime::SignedExtra = (
frame_system::CheckNonZeroSender::<Runtime>::new(),
frame_system::CheckSpecVersion::<Runtime>::new(),
frame_system::CheckTxVersion::<Runtime>::new(),
frame_system::CheckGenesis::<Runtime>::new(),
frame_system::CheckEra::<Runtime>::from(generic::Era::immortal()),
frame_system::CheckNonce::<Runtime>::from(
frame_system::Pallet::<Runtime>::account(&account_id).nonce,
),
frame_system::CheckWeight::<Runtime>::new(),
pallet_asset_tx_payment::ChargeAssetTxPayment::<Runtime>::from(tip, None),
);
type SignedPayload =
generic::SignedPayload<penpal_runtime::RuntimeCall, penpal_runtime::SignedExtra>;
let raw_payload = SignedPayload::new(call, extra).unwrap();
let signature = raw_payload.using_encoded(|payload| sender.sign(payload));
let (call, extra, _) = raw_payload.deconstruct();
penpal_runtime::UncheckedExtrinsic::new_signed(
call,
account_id.into(),
MultiSignature::Sr25519(signature),
extra,
)
}
66 changes: 6 additions & 60 deletions cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ use xcm::{
IntoVersion, VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm,
};
use xcm_fee_payment_runtime_api::{
dry_run::{Error as XcmDryRunApiError, ExtrinsicDryRunEffects, XcmDryRunEffects},
dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects},
fees::Error as XcmPaymentApiError,
};

Expand Down Expand Up @@ -1332,67 +1332,13 @@ impl_runtime_apis! {
}
}

impl xcm_fee_payment_runtime_api::dry_run::XcmDryRunApi<Block, RuntimeCall, RuntimeEvent> for Runtime {
fn dry_run_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> Result<ExtrinsicDryRunEffects<RuntimeEvent>, XcmDryRunApiError> {
use xcm_builder::InspectMessageQueues;
use xcm_executor::RecordXcm;
use xcm::prelude::*;

pallet_xcm::Pallet::<Runtime>::set_record_xcm(true);
let result = Executive::apply_extrinsic(extrinsic).map_err(|error| {
log::error!(
target: "xcm::XcmDryRunApi::dry_run_extrinsic",
"Applying extrinsic failed with error {:?}",
error,
);
XcmDryRunApiError::InvalidExtrinsic
})?;
let local_xcm = pallet_xcm::Pallet::<Runtime>::recorded_xcm();
let forwarded_xcms = xcm_config::XcmRouter::get_messages();
let events: Vec<RuntimeEvent> = System::read_events_no_consensus().map(|record| record.event.clone()).collect();
Ok(ExtrinsicDryRunEffects {
local_xcm: local_xcm.map(VersionedXcm::<()>::from),
forwarded_xcms,
emitted_events: events,
execution_result: result,
})
impl xcm_fee_payment_runtime_api::dry_run::DryRunApi<Block, RuntimeCall, RuntimeEvent, OriginCaller> for Runtime {
fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result<CallDryRunEffects<RuntimeEvent>, XcmDryRunApiError> {
PolkadotXcm::dry_run_call::<Runtime, xcm_config::XcmRouter, OriginCaller, RuntimeCall>(origin, call)
}

fn dry_run_xcm(origin_location: VersionedLocation, program: VersionedXcm<RuntimeCall>) -> Result<XcmDryRunEffects<RuntimeEvent>, XcmDryRunApiError> {
use xcm_builder::InspectMessageQueues;
use xcm::prelude::*;

let origin_location: Location = origin_location.try_into().map_err(|error| {
log::error!(
target: "xcm::XcmDryRunApi::dry_run_xcm",
"Location version conversion failed with error: {:?}",
error,
);
XcmDryRunApiError::VersionedConversionFailed
})?;
let program: Xcm<RuntimeCall> = program.try_into().map_err(|error| {
log::error!(
target: "xcm::XcmDryRunApi::dry_run_xcm",
"Xcm version conversion failed with error {:?}",
error,
);
XcmDryRunApiError::VersionedConversionFailed
})?;
let mut hash = program.using_encoded(sp_core::hashing::blake2_256);
let result = xcm_executor::XcmExecutor::<xcm_config::XcmConfig>::prepare_and_execute(
origin_location,
program,
&mut hash,
Weight::MAX, // Max limit available for execution.
Weight::zero(),
);
let forwarded_xcms = xcm_config::XcmRouter::get_messages();
let events: Vec<RuntimeEvent> = System::read_events_no_consensus().map(|record| record.event.clone()).collect();
Ok(XcmDryRunEffects {
forwarded_xcms,
emitted_events: events,
execution_result: result,
})
fn dry_run_xcm(origin_location: VersionedLocation, xcm: VersionedXcm<RuntimeCall>) -> Result<XcmDryRunEffects<RuntimeEvent>, XcmDryRunApiError> {
PolkadotXcm::dry_run_xcm::<Runtime, xcm_config::XcmRouter, RuntimeCall, xcm_config::XcmConfig>(origin_location, xcm)
}
}

Expand Down
66 changes: 6 additions & 60 deletions cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ use xcm::latest::prelude::{
};

use xcm_fee_payment_runtime_api::{
dry_run::{Error as XcmDryRunApiError, ExtrinsicDryRunEffects, XcmDryRunEffects},
dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects},
fees::Error as XcmPaymentApiError,
};

Expand Down Expand Up @@ -1368,67 +1368,13 @@ impl_runtime_apis! {
}
}

impl xcm_fee_payment_runtime_api::dry_run::XcmDryRunApi<Block, RuntimeCall, RuntimeEvent> for Runtime {
fn dry_run_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> Result<ExtrinsicDryRunEffects<RuntimeEvent>, XcmDryRunApiError> {
use xcm_builder::InspectMessageQueues;
use xcm_executor::RecordXcm;
use xcm::prelude::*;

pallet_xcm::Pallet::<Runtime>::set_record_xcm(true);
let result = Executive::apply_extrinsic(extrinsic).map_err(|error| {
log::error!(
target: "xcm::XcmDryRunApi::dry_run_extrinsic",
"Applying extrinsic failed with error {:?}",
error,
);
XcmDryRunApiError::InvalidExtrinsic
})?;
let local_xcm = pallet_xcm::Pallet::<Runtime>::recorded_xcm();
let forwarded_xcms = xcm_config::XcmRouter::get_messages();
let events: Vec<RuntimeEvent> = System::read_events_no_consensus().map(|record| record.event.clone()).collect();
Ok(ExtrinsicDryRunEffects {
local_xcm: local_xcm.map(VersionedXcm::<()>::from),
forwarded_xcms,
emitted_events: events,
execution_result: result,
})
impl xcm_fee_payment_runtime_api::dry_run::DryRunApi<Block, RuntimeCall, RuntimeEvent, OriginCaller> for Runtime {
fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result<CallDryRunEffects<RuntimeEvent>, XcmDryRunApiError> {
PolkadotXcm::dry_run_call::<Runtime, xcm_config::XcmRouter, OriginCaller, RuntimeCall>(origin, call)
}

fn dry_run_xcm(origin_location: VersionedLocation, program: VersionedXcm<RuntimeCall>) -> Result<XcmDryRunEffects<RuntimeEvent>, XcmDryRunApiError> {
use xcm_builder::InspectMessageQueues;
use xcm::prelude::*;

let origin_location: Location = origin_location.try_into().map_err(|error| {
log::error!(
target: "xcm::XcmDryRunApi::dry_run_xcm",
"Location version conversion failed with error: {:?}",
error,
);
XcmDryRunApiError::VersionedConversionFailed
})?;
let program: Xcm<RuntimeCall> = program.try_into().map_err(|error| {
log::error!(
target: "xcm::XcmDryRunApi::dry_run_xcm",
"Xcm version conversion failed with error {:?}",
error,
);
XcmDryRunApiError::VersionedConversionFailed
})?;
let mut hash = program.using_encoded(sp_core::hashing::blake2_256);
let result = xcm_executor::XcmExecutor::<xcm_config::XcmConfig>::prepare_and_execute(
origin_location,
program,
&mut hash,
Weight::MAX, // Max limit available for execution.
Weight::zero(),
);
let forwarded_xcms = xcm_config::XcmRouter::get_messages();
let events: Vec<RuntimeEvent> = System::read_events_no_consensus().map(|record| record.event.clone()).collect();
Ok(XcmDryRunEffects {
forwarded_xcms,
emitted_events: events,
execution_result: result,
})
fn dry_run_xcm(origin_location: VersionedLocation, xcm: VersionedXcm<RuntimeCall>) -> Result<XcmDryRunEffects<RuntimeEvent>, XcmDryRunApiError> {
PolkadotXcm::dry_run_xcm::<Runtime, xcm_config::XcmRouter, RuntimeCall, xcm_config::XcmConfig>(origin_location, xcm)
}
}

Expand Down
27 changes: 11 additions & 16 deletions cumulus/parachains/runtimes/testing/penpal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ pub use sp_consensus_aura::sr25519::AuthorityId as AuraId;
use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
use sp_runtime::{
create_runtime_str, generic, impl_opaque_keys,
traits::{AccountIdLookup, BlakeTwo256, Block as BlockT},
traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, Dispatchable},
transaction_validity::{TransactionSource, TransactionValidity},
ApplyExtrinsicResult,
};
Expand All @@ -86,7 +86,7 @@ use xcm::{
IntoVersion, VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm,
};
use xcm_fee_payment_runtime_api::{
dry_run::{Error as XcmDryRunApiError, ExtrinsicDryRunEffects, XcmDryRunEffects},
dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects},
fees::Error as XcmPaymentApiError,
};

Expand Down Expand Up @@ -886,25 +886,19 @@ impl_runtime_apis! {
}
}

impl xcm_fee_payment_runtime_api::dry_run::XcmDryRunApi<Block, RuntimeCall, RuntimeEvent> for Runtime {
fn dry_run_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> Result<ExtrinsicDryRunEffects<RuntimeEvent>, XcmDryRunApiError> {
impl xcm_fee_payment_runtime_api::dry_run::DryRunApi<Block, RuntimeCall, RuntimeEvent, OriginCaller> for Runtime {
fn dry_run_call(origin: OriginCaller, call: RuntimeCall) -> Result<CallDryRunEffects<RuntimeEvent>, XcmDryRunApiError> {
use xcm_builder::InspectMessageQueues;
use xcm_executor::RecordXcm;
use xcm::prelude::*;

pallet_xcm::Pallet::<Runtime>::set_record_xcm(true);
let result = Executive::apply_extrinsic(extrinsic).map_err(|error| {
log::error!(
target: "xcm::XcmDryRunApi::dry_run_extrinsic",
"Applying extrinsic failed with error {:?}",
error,
);
XcmDryRunApiError::InvalidExtrinsic
})?;
frame_system::Pallet::<Runtime>::reset_events(); // To make sure we only record events from current call.
let result = call.dispatch(origin.into());
pallet_xcm::Pallet::<Runtime>::set_record_xcm(false);
let local_xcm = pallet_xcm::Pallet::<Runtime>::recorded_xcm();
let forwarded_xcms = xcm_config::XcmRouter::get_messages();
let events: Vec<RuntimeEvent> = System::read_events_no_consensus().map(|record| record.event.clone()).collect();
Ok(ExtrinsicDryRunEffects {
Ok(CallDryRunEffects {
local_xcm: local_xcm.map(VersionedXcm::<()>::from),
forwarded_xcms,
emitted_events: events,
Expand All @@ -918,21 +912,22 @@ impl_runtime_apis! {

let origin_location: Location = origin_location.try_into().map_err(|error| {
log::error!(
target: "xcm::XcmDryRunApi::dry_run_xcm",
target: "xcm::DryRunApi::dry_run_xcm",
"Location version conversion failed with error: {:?}",
error,
);
XcmDryRunApiError::VersionedConversionFailed
})?;
let program: Xcm<RuntimeCall> = program.try_into().map_err(|error| {
log::error!(
target: "xcm::XcmDryRunApi::dry_run_xcm",
target: "xcm::DryRunApi::dry_run_xcm",
"Xcm version conversion failed with error {:?}",
error,
);
XcmDryRunApiError::VersionedConversionFailed
})?;
let mut hash = program.using_encoded(sp_core::hashing::blake2_256);
frame_system::Pallet::<Runtime>::reset_events(); // To make sure we only record events from current call.
let result = xcm_executor::XcmExecutor::<xcm_config::XcmConfig>::prepare_and_execute(
origin_location,
program,
Expand Down
Loading
Loading