Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
719efe0
Intoduce XCM v2
gavofyork Aug 10, 2021
b2dae98
Minor version cleanup
gavofyork Aug 10, 2021
5ab1b8b
Minor version cleanup
gavofyork Aug 10, 2021
c854e94
Introduce SendError for XcmSend trait to avoid cycles with having Out…
gavofyork Aug 10, 2021
1e287f3
comment
gavofyork Aug 10, 2021
c279e44
Corrent type
gavofyork Aug 10, 2021
632a992
Docs
gavofyork Aug 10, 2021
18ef569
Fix build
gavofyork Aug 10, 2021
ef3bc2e
Fixes
gavofyork Aug 10, 2021
eaea484
Build
gavofyork Aug 10, 2021
9820197
Introduce the basic impl
gavofyork Aug 10, 2021
82a67f7
Docs
gavofyork Aug 12, 2021
ace53dc
Add function
gavofyork Aug 12, 2021
49f1895
Merge remote-tracking branch 'origin/master' into gav-xcm-v2
gavofyork Aug 12, 2021
c6835ae
Basic implementation
gavofyork Aug 12, 2021
19617eb
Weighed responses and on_report
gavofyork Aug 12, 2021
0831192
Make XCM more script-like
gavofyork Aug 14, 2021
62d76b4
Remove BuyExecution::orders
gavofyork Aug 14, 2021
2bf963c
Fixes
gavofyork Aug 15, 2021
d58848f
Fixes
gavofyork Aug 15, 2021
e97f993
Fixes
gavofyork Aug 15, 2021
1a0e0ce
Formatting
gavofyork Aug 15, 2021
89debf5
Merge branch 'gav-rm-buy-orders' into gav-xcm-v2
gavofyork Aug 15, 2021
4516074
Initial draft and make pallet-xcm build
gavofyork Aug 16, 2021
329360f
fix XCM tests
gavofyork Aug 16, 2021
0ca87bd
Formatting
gavofyork Aug 16, 2021
15b9371
Merge remote-tracking branch 'origin/master' into gav-xcm-v2
gavofyork Aug 16, 2021
40efb2e
Fixes
gavofyork Aug 16, 2021
36f7a4e
Formatting
gavofyork Aug 16, 2021
33594b3
spelling
gavofyork Aug 16, 2021
8fd21f2
Fixes
gavofyork Aug 16, 2021
30c225d
Fixes
gavofyork Aug 17, 2021
b0f884e
spelling
gavofyork Aug 17, 2021
732ec50
tests for translation
gavofyork Aug 17, 2021
fbd84e4
extra fields to XCM pallet
gavofyork Aug 17, 2021
236f275
Formatting
gavofyork Aug 17, 2021
0188a9d
Fixes
gavofyork Aug 17, 2021
dcdf01d
spelling
gavofyork Aug 17, 2021
3d20770
first integration test
gavofyork Aug 17, 2021
0b27f43
Another integration test
gavofyork Aug 18, 2021
11b8a80
Formatting
gavofyork Aug 20, 2021
df76b24
Merge remote-tracking branch 'origin/master' into gav-xcm-v2
gavofyork Aug 20, 2021
170a20d
fix tests
gavofyork Aug 20, 2021
26330fa
all tests
gavofyork Aug 21, 2021
5d03978
Fixes
gavofyork Aug 21, 2021
7e7528d
Fixes
gavofyork Aug 22, 2021
b462eae
Formatting
gavofyork Aug 22, 2021
e1f36c4
Fixes
gavofyork Aug 22, 2021
a0db17a
Fixes
gavofyork Aug 22, 2021
653a2a2
Formatting
gavofyork Aug 22, 2021
f1ce4eb
Bump
gavofyork Aug 22, 2021
07ba2d0
Remove unneeded structuring
gavofyork Aug 22, 2021
48baab6
add instruction
gavofyork Aug 22, 2021
f317a64
Fixes
gavofyork Aug 22, 2021
dd80ebc
spelling
gavofyork Aug 22, 2021
de5e76c
Fixes
gavofyork Aug 22, 2021
e798658
Fixes
gavofyork Aug 22, 2021
df8f941
Formatting
gavofyork Aug 22, 2021
e39b1e6
Fixes
gavofyork Aug 22, 2021
bea12fb
Fixes
gavofyork Aug 23, 2021
2b47c3c
Formatting
gavofyork Aug 23, 2021
ca21160
Introduce and use VersionedResponse
gavofyork Aug 23, 2021
a062919
Introduce versioning to dispatchables' params
gavofyork Aug 23, 2021
26ca165
Fixes
gavofyork Aug 23, 2021
aeba4a8
Formatting
gavofyork Aug 23, 2021
1862f69
Merge branch 'gav-versioned-params' into gav-xcm-v2
gavofyork Aug 23, 2021
d92b7a7
Rest of merge
gavofyork Aug 23, 2021
c4c45d5
Merge branch 'gav-xcm-v2' into gav-xcm-trycatch
gavofyork Aug 23, 2021
7d7f2ac
more work
gavofyork Aug 23, 2021
604414c
Formatting
gavofyork Aug 23, 2021
8130a36
Basic logic
gavofyork Aug 23, 2021
fc58298
Fixes
gavofyork Aug 24, 2021
93dc645
Fixes
gavofyork Aug 24, 2021
6b5045f
Merge branch 'gav-xcm-v2' into gav-xcm-trycatch
gavofyork Aug 24, 2021
22fcbf2
Fixes
gavofyork Aug 24, 2021
7f5add7
Add test
gavofyork Aug 24, 2021
8c231a0
Fixes
gavofyork Aug 24, 2021
745835f
Formatting
gavofyork Aug 24, 2021
bb046cc
Fixes
gavofyork Aug 24, 2021
34dae85
Fixes
gavofyork Aug 24, 2021
ffe8513
Fixes
gavofyork Aug 24, 2021
c0f1875
Nits
gavofyork Aug 25, 2021
7b243cc
Simplify
gavofyork Aug 25, 2021
9f7e88c
Spelling
gavofyork Aug 25, 2021
8f07df6
Formatting
gavofyork Aug 25, 2021
41d8435
Return weight of unexecuted instructions in case of error as surplus
gavofyork Aug 25, 2021
53fc8dd
Formatting
gavofyork Aug 25, 2021
944b597
Fixes
gavofyork Aug 25, 2021
bcbacce
Test for instruction count limiting
gavofyork Aug 25, 2021
8c8d434
Formatting
gavofyork Aug 25, 2021
feb79ce
Docs
gavofyork Aug 25, 2021
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
Prev Previous commit
Next Next commit
Another integration test
  • Loading branch information
gavofyork committed Aug 18, 2021
commit 0b27f437378e0caf054375dfb9ace54dfb219de5
43 changes: 31 additions & 12 deletions runtime/test-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -546,15 +546,17 @@ pub mod pallet_test_notifier {

#[pallet::config]
pub trait Config: frame_system::Config + pallet_xcm::Config {
type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
type Origin: From<<Self as frame_system::Config>::Origin>
type Event: IsType<<Self as frame_system::Config>::Event> + From<Event<Self>>;
type Origin: IsType<<Self as frame_system::Config>::Origin>
+ Into<Result<pallet_xcm::Origin, <Self as Config>::Origin>>;
type Call: From<Call<Self>> + Into<<Self as pallet_xcm::Config>::Call>;
type Call: IsType<<Self as pallet_xcm::Config>::Call> + From<Call<Self>>;
}

#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
QueryPrepared(QueryId),
NotifyQueryPrepared(QueryId),
ResponseReceived(MultiLocation, QueryId, Response),
}

Expand All @@ -566,30 +568,47 @@ pub mod pallet_test_notifier {

#[pallet::call]
impl<T: Config> Pallet<T> {

#[pallet::weight(1_000_000)]
pub fn notification_received(
pub fn prepare_new_query(
origin: OriginFor<T>,
query_id: QueryId,
response: Response,
) -> DispatchResult {
let responder = ensure_response(<T as Config>::Origin::from(origin))?;
Self::deposit_event(Event::<T>::ResponseReceived(responder, query_id, response));
let who = ensure_signed(origin)?;
let id = who.using_encoded(|mut d| <[u8; 32]>::decode(&mut d))
.map_err(|_| Error::<T>::BadAccountFormat)?;
let qid = pallet_xcm::Pallet::<T>::new_query(
Junction::AccountId32 { network: Any, id }.into(),
100u32.into(),
);
Self::deposit_event(Event::<T>::QueryPrepared(qid));
Ok(())
}

#[pallet::weight(1_000_000)]
pub fn prepare_for_notification(
pub fn prepare_new_notify_query(
origin: OriginFor<T>,
) -> DispatchResult {
let who = ensure_signed(origin)?;
let id = who.using_encoded(|mut d| <[u8; 32]>::decode(&mut d))
.map_err(|_| Error::<T>::BadAccountFormat)?;
let call = Call::<T>::notification_received(0, Default::default());
let qid = pallet_xcm::Pallet::<T>::new_notify_query(
Junction::AccountId32 { network: Any, id }.into(),
<T as Config>::Call::from(Call::<T>::notification_received(0, Response::Assets(sp_std::vec::Vec::new().into()))).into(),
0u32.into(),
<T as Config>::Call::from(call),
100u32.into(),
);
ensure!(qid == 0, Error::<T>::UnexpectedId);
Self::deposit_event(Event::<T>::NotifyQueryPrepared(qid));
Ok(())
}

#[pallet::weight(1_000_000)]
pub fn notification_received(
origin: OriginFor<T>,
query_id: QueryId,
response: Response,
) -> DispatchResult {
let responder = ensure_response(<T as Config>::Origin::from(origin))?;
Self::deposit_event(Event::<T>::ResponseReceived(responder, query_id, response));
Ok(())
}
}
Expand Down
41 changes: 26 additions & 15 deletions xcm/pallet-xcm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,11 @@ pub mod pallet {
Attempted(xcm::latest::Outcome),
Sent(MultiLocation, MultiLocation, Xcm<()>),
UnexpectedResponse(MultiLocation, QueryId),
OnResponse(MultiLocation, QueryId, Response, Weight),
Notifying(QueryId, u8, u8),
NotifyOverweight(QueryId, Weight, Weight),
NotifyDispatchError(QueryId),
NotifyDecodeFailed(QueryId),
ResponseReceived(MultiLocation, QueryId, Response, Weight),
Notified(QueryId, u8, u8),
NotifyOverweight(QueryId, u8, u8, Weight, Weight),
NotifyDispatchError(QueryId, u8, u8),
NotifyDecodeFailed(QueryId, u8, u8),
InvalidResponder(MultiLocation, QueryId, MultiLocation),
InvalidResponderVersion(MultiLocation, QueryId),
}
Expand Down Expand Up @@ -151,7 +151,7 @@ pub mod pallet {
}

/// The status of a query.
#[derive(Clone, Eq, PartialEq, Encode, Decode)]
#[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug)]
pub enum QueryStatus<BlockNumber> {
/// The query was sent but no response has yet been received.
Pending {
Expand All @@ -172,6 +172,7 @@ pub mod pallet {

/// The ongoing queries.
#[pallet::storage]
#[pallet::getter(fn query)]
pub(super) type Queries<T: Config> =
StorageMap<_, Blake2_128Concat, QueryId, QueryStatus<T::BlockNumber>, OptionQuery>;

Expand Down Expand Up @@ -429,11 +430,8 @@ pub mod pallet {
impl<T: Config> OnResponse for Pallet<T> {
/// Returns `true` if we are expecting a response from `origin` for query `query_id`.
fn expecting_response(origin: &MultiLocation, query_id: QueryId) -> bool {

if let Some(QueryStatus::Pending { responder, .. }) = Queries::<T>::get(query_id) {
return MultiLocation::try_from(responder).map_or(false, |r| origin == &r)
} else {
Self::deposit_event(Event::UnexpectedResponse(origin.clone(), query_id));
}
false
}
Expand All @@ -445,15 +443,15 @@ pub mod pallet {
response: Response,
max_weight: Weight,
) -> Weight {
Self::deposit_event(Event::OnResponse(origin.clone(), query_id, response.clone(), max_weight));
let e = Event::ResponseReceived(origin.clone(), query_id, response.clone(), max_weight);
Self::deposit_event(e);
if let Some(QueryStatus::Pending { responder, maybe_notify, .. }) =
Queries::<T>::get(query_id)
{
if let Ok(responder) = MultiLocation::try_from(responder) {
if origin == &responder {
return match maybe_notify {
Some((pallet_index, call_index)) => {
Self::deposit_event(Event::Notifying(query_id, pallet_index, call_index));
// This is a bit horrible, but we happen to know that the `Call` will
// be built by `(pallet_index: u8, call_index: u8, QueryId, Response)`.
// So we just encode that and then re-encode to a real Call.
Expand All @@ -463,22 +461,35 @@ pub mod pallet {
{
let weight = call.get_dispatch_info().weight;
if weight > max_weight {
Self::deposit_event(Event::NotifyOverweight(query_id, weight, max_weight));
let e = Event::NotifyOverweight(
query_id,
pallet_index,
call_index,
weight,
max_weight,
);
Self::deposit_event(e);
return 0
}
let dispatch_origin = Origin::Response(origin.clone()).into();
match call.dispatch(dispatch_origin) {
Ok(post_info) => post_info.actual_weight,
Ok(post_info) => {
let e = Event::Notified(query_id, pallet_index, call_index);
Self::deposit_event(e);
post_info.actual_weight
},
Err(error_and_info) => {
Self::deposit_event(Event::NotifyDispatchError(query_id));
let e = Event::NotifyDispatchError(query_id, pallet_index, call_index);
Self::deposit_event(e);
// Not much to do with the result as it is. It's up to the parachain to ensure that the
// message makes sense.
error_and_info.post_info.actual_weight
},
}
.unwrap_or(weight)
} else {
Self::deposit_event(Event::NotifyDecodeFailed(query_id));
let e = Event::NotifyDecodeFailed(query_id, pallet_index, call_index);
Self::deposit_event(e);
0
}
},
Expand Down
8 changes: 8 additions & 0 deletions xcm/src/v2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,20 @@ pub mod prelude {
/// Response data to a query.
#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)]
pub enum Response {
/// No response. Serves as a neutral default.
Null,
/// Some assets.
Assets(MultiAssets),
/// The outcome of an XCM instruction.
ExecutionResult(result::Result<(), (u32, Error)>),
}

impl Default for Response {
fn default() -> Self {
Self::Null
}
}

/// An optional weight limit.
#[derive(Clone, Eq, PartialEq, Encode, Decode, Debug)]
pub enum WeightLimit {
Expand Down
135 changes: 121 additions & 14 deletions xcm/xcm-executor/integration-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,30 +70,140 @@ fn basic_buy_fees_message_executes() {
});
}


#[test]
fn query_response_elicits_handler() {
fn query_response_fires() {
use polkadot_test_runtime::Event::TestNotifier;
use pallet_test_notifier::Event::*;
use pallet_xcm::QueryStatus;

sp_tracing::try_init_simple();
let mut client = TestClientBuilder::new()
.set_execution_strategy(ExecutionStrategy::AlwaysWasm)
.build();

let mut block_builder = client.init_polkadot_block_builder();

let execute = construct_extrinsic(
&client,
polkadot_test_runtime::Call::TestNotifier(pallet_test_notifier::Call::prepare_new_query()),
sp_keyring::Sr25519Keyring::Alice,
0,
);

block_builder.push_polkadot_extrinsic(execute).expect("pushes extrinsic");

let block = block_builder.build().expect("Finalizes the block").block;
let block_hash = block.hash();

futures::executor::block_on(client.import(sp_consensus::BlockOrigin::Own, block))
.expect("imports the block");

let mut query_id = None;
client
.state_at(&BlockId::Hash(block_hash))
.expect("state should exist")
.inspect_state(|| {
for r in polkadot_test_runtime::System::events().iter() {
match r.event {
TestNotifier(QueryPrepared(q)) => query_id = Some(q),
_ => (),
}
}
});
let query_id = query_id.unwrap();

let mut block_builder = client.init_polkadot_block_builder();

let response = Response::ExecutionResult(Ok(()));
let msg = Xcm(vec![
QueryResponse { query_id: 0, response, max_weight: 1_000_000 },
]);
let max_weight = 1_000_000;
let msg = Xcm(vec![QueryResponse { query_id, response, max_weight }]);

let execute = construct_extrinsic(
&client,
polkadot_test_runtime::Call::Xcm(pallet_xcm::Call::execute(msg, 1_000_000_000)),
sp_keyring::Sr25519Keyring::Alice,
1,
);

block_builder.push_polkadot_extrinsic(execute).expect("pushes extrinsic");

let block = block_builder.build().expect("Finalizes the block").block;
let block_hash = block.hash();

futures::executor::block_on(client.import(sp_consensus::BlockOrigin::Own, block))
.expect("imports the block");

client
.state_at(&BlockId::Hash(block_hash))
.expect("state should exist")
.inspect_state(|| {
assert!(polkadot_test_runtime::System::events().iter().any(|r| matches!(
r.event,
polkadot_test_runtime::Event::Xcm(pallet_xcm::Event::ResponseReceived(
MultiLocation { parents: 0, interior: X1(Junction::AccountId32 { .. }) },
q,
Response::ExecutionResult(Ok(())),
1_000_000,
)) if q == query_id,
)));
assert_eq!(
polkadot_test_runtime::Xcm::query(query_id),
Some(QueryStatus::Ready {
response: Response::ExecutionResult(Ok(())),
at: 2u32.into()
}),
)
});
}

#[test]
fn query_response_elicits_handler() {
use polkadot_test_runtime::Event::TestNotifier;
use pallet_test_notifier::Event::*;

sp_tracing::try_init_simple();
let mut client = TestClientBuilder::new()
.set_execution_strategy(ExecutionStrategy::AlwaysWasm)
.build();

let mut block_builder = client.init_polkadot_block_builder();

let execute = construct_extrinsic(
&client,
polkadot_test_runtime::Call::TestNotifier(pallet_test_notifier::Call::prepare_for_notification()),
polkadot_test_runtime::Call::TestNotifier(pallet_test_notifier::Call::prepare_new_notify_query()),
sp_keyring::Sr25519Keyring::Alice,
0,
);

block_builder.push_polkadot_extrinsic(execute).expect("pushes extrinsic");

let block = block_builder.build().expect("Finalizes the block").block;
let block_hash = block.hash();

futures::executor::block_on(client.import(sp_consensus::BlockOrigin::Own, block))
.expect("imports the block");

let mut query_id = None;
client
.state_at(&BlockId::Hash(block_hash))
.expect("state should exist")
.inspect_state(|| {
dbg!(polkadot_test_runtime::System::events());
for r in polkadot_test_runtime::System::events().iter() {
match r.event {
TestNotifier(NotifyQueryPrepared(q)) => query_id = Some(q),
_ => (),
}
}
});
let query_id = query_id.unwrap();

let mut block_builder = client.init_polkadot_block_builder();

let response = Response::ExecutionResult(Ok(()));
let max_weight = 1_000_000;
let msg = Xcm(vec![QueryResponse { query_id, response, max_weight }]);

let execute = construct_extrinsic(
&client,
polkadot_test_runtime::Call::Xcm(pallet_xcm::Call::execute(msg, 1_000_000_000)),
Expand All @@ -113,16 +223,13 @@ fn query_response_elicits_handler() {
.state_at(&BlockId::Hash(block_hash))
.expect("state should exist")
.inspect_state(|| {
dbg!(polkadot_test_runtime::System::events());
assert!(polkadot_test_runtime::System::events().iter().any(|r| matches!(
r.event,
polkadot_test_runtime::Event::TestNotifier(
pallet_test_notifier::Event::ResponseReceived(
MultiLocation { parents: 0, interior: X1(Junction::AccountId32 { .. }) },
0,
Response::ExecutionResult(Ok(())),
),
)
TestNotifier(ResponseReceived(
MultiLocation { parents: 0, interior: X1(Junction::AccountId32 { .. }) },
q,
Response::ExecutionResult(Ok(())),
)) if q == query_id,
)));
});
}
Expand Down