Skip to content

Commit

Permalink
Add xcm upm mock endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
dimartiro committed Dec 23, 2024
1 parent db79f6f commit 7369f6b
Show file tree
Hide file tree
Showing 11 changed files with 203 additions and 15 deletions.
49 changes: 48 additions & 1 deletion client/manual-xcm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,17 @@ const DEFAULT_PROOF_SIZE: u64 = 64 * 1024;
#[jsonrpsee::core::async_trait]
pub trait ManualXcmApi {
/// Inject a downward xcm message - A message that comes from the relay chain.
/// You may provide an arbitrary message, or if you provide an emtpy byte array,
/// You may provide an arbitrary message, or if you provide an empty byte array,
/// Then a default message (DOT transfer down to ALITH) will be injected
#[method(name = "xcm_injectDownwardMessage")]
async fn inject_downward_message(&self, message: Vec<u8>) -> RpcResult<()>;

/// Inject a upward xcm message - A message that comes from the a parachain.
/// You may provide an arbitrary message, or if you provide an empty byte array,
/// Then a default message (DOT transfer up to ALITH) will be injected
#[method(name = "xcm_injectUpwardMessage")]
async fn inject_upward_message(&self, message: Vec<u8>) -> RpcResult<()>;

/// Inject an HRMP message - A message that comes from a dedicated channel to a sibling
/// parachain.
///
Expand All @@ -51,6 +57,7 @@ pub trait ManualXcmApi {

pub struct ManualXcm {
pub downward_message_channel: flume::Sender<Vec<u8>>,
pub upward_message_channel: flume::Sender<Vec<u8>>,
pub hrmp_message_channel: flume::Sender<(ParaId, Vec<u8>)>,
}

Expand Down Expand Up @@ -96,6 +103,46 @@ impl ManualXcmApiServer for ManualXcm {
Ok(())
}

async fn inject_upward_message(&self, msg: Vec<u8>) -> RpcResult<()> {
let upward_message_channel = self.upward_message_channel.clone();
// If no message is supplied, inject a default one.
let msg = if msg.is_empty() {
staging_xcm::VersionedXcm::<()>::V4(Xcm(vec![
ReserveAssetDeposited((Here, 10000000000000u128).into()),
ClearOrigin,
BuyExecution {
fees: (Here, 10000000000000u128).into(),
weight_limit: Limited(Weight::from_parts(
4_000_000_000u64,
DEFAULT_PROOF_SIZE * 2,
)),
},
DepositAsset {
assets: AllCounted(1).into(),
beneficiary: Location::new(
0,
[AccountKey20 {
network: None,
key: hex_literal::hex!("f24FF3a9CF04c71Dbc94D0b566f7A27B94566cac"),
}],
),
},
]))
.encode()
} else {
msg
};

// Push the message to the shared channel where it will be queued up
// to be injected in to an upcoming block.
upward_message_channel
.send_async(msg)
.await
.map_err(|err| internal_err(err.to_string()))?;

Ok(())
}

async fn inject_hrmp_message(&self, sender: ParaId, msg: Vec<u8>) -> RpcResult<()> {
let hrmp_message_channel = self.hrmp_message_channel.clone();

Expand Down
17 changes: 14 additions & 3 deletions client/service-container-chain/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,11 @@ pub struct FullDeps<C, P> {
/// Manual seal command sink
pub command_sink: Option<futures::channel::mpsc::Sender<EngineCommand<Hash>>>,
/// Channels for manual xcm messages (downward, hrmp)
pub xcm_senders: Option<(flume::Sender<Vec<u8>>, flume::Sender<(ParaId, Vec<u8>)>)>,
pub xcm_senders: Option<(
flume::Sender<Vec<u8>>,
flume::Sender<Vec<u8>>,
flume::Sender<(ParaId, Vec<u8>)>,
)>,
}

tp_traits::alias!(
Expand Down Expand Up @@ -103,10 +107,13 @@ where
)?;
};

if let Some((downward_message_channel, hrmp_message_channel)) = xcm_senders {
if let Some((downward_message_channel, upward_message_channel, hrmp_message_channel)) =
xcm_senders
{
module.merge(
ManualXcm {
downward_message_channel,
upward_message_channel,
hrmp_message_channel,
}
.into_rpc(),
Expand Down Expand Up @@ -137,7 +144,11 @@ pub mod generate_rpc_builder {
sc_transaction_pool::TransactionPoolHandle<Block, ContainerChainClient<RuntimeApi>>;
pub type CommandSink =
futures::channel::mpsc::Sender<sc_consensus_manual_seal::EngineCommand<Hash>>;
pub type XcmSenders = (flume::Sender<Vec<u8>>, flume::Sender<(ParaId, Vec<u8>)>);
pub type XcmSenders = (
flume::Sender<Vec<u8>>,
flume::Sender<Vec<u8>>,
flume::Sender<(ParaId, Vec<u8>)>,
);
pub type Network = dyn sc_network::service::traits::NetworkService;
pub type CompleteRpcBuilder = Box<
dyn Fn(sc_rpc::SubscriptionTaskExecutor) -> Result<jsonrpsee::RpcModule<()>, ServiceError>,
Expand Down
11 changes: 9 additions & 2 deletions container-chains/nodes/frontier/src/rpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,11 @@ pub struct FullDeps<C, P, A: ChainApi, BE> {
/// Manual seal command sink
pub command_sink: Option<futures::channel::mpsc::Sender<EngineCommand<Hash>>>,
/// Channels for manual xcm messages (downward, hrmp)
pub xcm_senders: Option<(flume::Sender<Vec<u8>>, flume::Sender<(ParaId, Vec<u8>)>)>,
pub xcm_senders: Option<(
flume::Sender<Vec<u8>>,
flume::Sender<Vec<u8>>,
flume::Sender<(ParaId, Vec<u8>)>,
)>,
}

/// Instantiate all Full RPC extensions.
Expand Down Expand Up @@ -320,10 +324,13 @@ where
)?;
io.merge(tx_pool.into_rpc())?;

if let Some((downward_message_channel, hrmp_message_channel)) = xcm_senders {
if let Some((downward_message_channel, upward_message_channel, hrmp_message_channel)) =
xcm_senders
{
io.merge(
ManualXcm {
downward_message_channel,
upward_message_channel,
hrmp_message_channel,
}
.into_rpc(),
Expand Down
3 changes: 2 additions & 1 deletion container-chains/nodes/frontier/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,8 +369,9 @@ pub async fn start_dev_node(
if parachain_config.role.is_authority() {
let client = node_builder.client.clone();
let (downward_xcm_sender, downward_xcm_receiver) = flume::bounded::<Vec<u8>>(100);
let (upward_xcm_sender, _) = flume::bounded::<Vec<u8>>(100);
let (hrmp_xcm_sender, hrmp_xcm_receiver) = flume::bounded::<(ParaId, Vec<u8>)>(100);
xcm_senders = Some((downward_xcm_sender, hrmp_xcm_sender));
xcm_senders = Some((downward_xcm_sender, upward_xcm_sender, hrmp_xcm_sender));

let authorities = vec![get_aura_id_from_seed("alice")];

Expand Down
11 changes: 9 additions & 2 deletions container-chains/nodes/simple/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,11 @@ pub struct FullDeps<C, P> {
/// Manual seal command sink
pub command_sink: Option<futures::channel::mpsc::Sender<EngineCommand<Hash>>>,
/// Channels for manual xcm messages (downward, hrmp)
pub xcm_senders: Option<(flume::Sender<Vec<u8>>, flume::Sender<(ParaId, Vec<u8>)>)>,
pub xcm_senders: Option<(
flume::Sender<Vec<u8>>,
flume::Sender<Vec<u8>>,
flume::Sender<(ParaId, Vec<u8>)>,
)>,
}

/// Instantiate all RPC extensions.
Expand Down Expand Up @@ -89,10 +93,13 @@ where
)?;
};

if let Some((downward_message_channel, hrmp_message_channel)) = xcm_senders {
if let Some((downward_message_channel, upward_message_channel, hrmp_message_channel)) =
xcm_senders
{
module.merge(
ManualXcm {
downward_message_channel,
upward_message_channel,
hrmp_message_channel,
}
.into_rpc(),
Expand Down
3 changes: 2 additions & 1 deletion container-chains/nodes/simple/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,9 @@ pub async fn start_dev_node(
if parachain_config.role.is_authority() {
let client = node_builder.client.clone();
let (downward_xcm_sender, downward_xcm_receiver) = flume::bounded::<Vec<u8>>(100);
let (upward_xcm_sender, _) = flume::bounded::<Vec<u8>>(100);
let (hrmp_xcm_sender, hrmp_xcm_receiver) = flume::bounded::<(ParaId, Vec<u8>)>(100);
xcm_senders = Some((downward_xcm_sender, hrmp_xcm_sender));
xcm_senders = Some((downward_xcm_sender, upward_xcm_sender, hrmp_xcm_sender));

let authorities = vec![get_aura_id_from_seed("alice")];

Expand Down
11 changes: 9 additions & 2 deletions node/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,11 @@ pub struct FullDeps<C, P> {
/// Manual seal command sink
pub command_sink: Option<futures::channel::mpsc::Sender<EngineCommand<Hash>>>,
/// Channels for manual xcm messages (downward, hrmp)
pub xcm_senders: Option<(flume::Sender<Vec<u8>>, flume::Sender<(ParaId, Vec<u8>)>)>,
pub xcm_senders: Option<(
flume::Sender<Vec<u8>>,
flume::Sender<Vec<u8>>,
flume::Sender<(ParaId, Vec<u8>)>,
)>,
}

/// Instantiate all RPC extensions.
Expand Down Expand Up @@ -98,10 +102,13 @@ where
)?;
};

if let Some((downward_message_channel, hrmp_message_channel)) = xcm_senders {
if let Some((downward_message_channel, upward_message_channel, hrmp_message_channel)) =
xcm_senders
{
module.merge(
ManualXcm {
downward_message_channel,
upward_message_channel,
hrmp_message_channel,
}
.into_rpc(),
Expand Down
3 changes: 2 additions & 1 deletion node/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -896,8 +896,9 @@ pub fn start_dev_node(
if parachain_config.role.is_authority() {
let client = node_builder.client.clone();
let (downward_xcm_sender, downward_xcm_receiver) = flume::bounded::<Vec<u8>>(100);
let (upward_xcm_sender, _) = flume::bounded::<Vec<u8>>(100);
let (hrmp_xcm_sender, hrmp_xcm_receiver) = flume::bounded::<(ParaId, Vec<u8>)>(100);
xcm_senders = Some((downward_xcm_sender, hrmp_xcm_sender));
xcm_senders = Some((downward_xcm_sender, upward_xcm_sender, hrmp_xcm_sender));

command_sink = node_builder.install_manual_seal(ManualSealConfiguration {
block_import,
Expand Down
28 changes: 27 additions & 1 deletion solo-chains/node/tanssi-relay-service/src/dev_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ use {
polkadot_core_primitives::{AccountId, Balance, Block, Hash, Nonce},
polkadot_node_core_parachains_inherent::Error as InherentError,
polkadot_overseer::Handle,
polkadot_parachain_primitives::primitives::UpwardMessages,
polkadot_primitives::{
runtime_api::ParachainHost, BackedCandidate, CandidateCommitments, CandidateDescriptor,
CollatorPair, CommittedCandidateReceipt, CompactStatement, EncodeAs,
Expand Down Expand Up @@ -77,6 +78,7 @@ use {

// We use this key to store whether we want the para inherent mocker to be active
const PARA_INHERENT_SELECTOR_AUX_KEY: &[u8] = b"__DEV_PARA_INHERENT_SELECTOR";
const XMC_UPM_SELECTOR_AUX_KEY: &[u8] = b"__DEV_XMC_UMP_SELECTOR";

pub type FullBackend = service::TFullBackend<Block>;

Expand Down Expand Up @@ -231,6 +233,7 @@ struct MockParachainsInherentDataProvider<C: HeaderBackend<Block> + ProvideRunti
impl<C: HeaderBackend<Block> + ProvideRuntimeApi<Block>> MockParachainsInherentDataProvider<C>
where
C::Api: ParachainHost<Block>,
C: AuxStore,
{
pub fn new(client: Arc<C>, parent: Hash, keystore: KeystorePtr) -> Self {
MockParachainsInherentDataProvider {
Expand Down Expand Up @@ -388,6 +391,14 @@ where
&validation_code_hash,
);
let collator_signature = collator_pair.sign(&payload);

let mut upm_messages = UpwardMessages::new();

client
.get_aux(XMC_UPM_SELECTOR_AUX_KEY)
.expect("Should be able to query aux storage; qed")
.map(|upm_message| upm_messages.force_push(upm_message));

// generate a candidate with most of the values mocked
let candidate = CommittedCandidateReceipt::<H256> {
descriptor: CandidateDescriptor::<H256> {
Expand All @@ -402,7 +413,7 @@ where
validation_code_hash,
},
commitments: CandidateCommitments::<u32> {
upward_messages: Default::default(),
upward_messages: upm_messages,
horizontal_messages: Default::default(),
new_validation_code: None,
head_data: parachain_mocked_header.clone().encode().into(),
Expand Down Expand Up @@ -594,6 +605,9 @@ fn new_full<
let (downward_mock_para_inherent_sender, downward_mock_para_inherent_receiver) =
flume::bounded::<Vec<u8>>(100);

let (_, upward_mock_para_inherent_receiver) =
flume::bounded::<Vec<u8>>(100);

let (network, system_rpc_tx, tx_handler_controller, network_starter, sync_service) =
service::build_network(service::BuildNetworkParams {
config: &config,
Expand Down Expand Up @@ -705,12 +719,16 @@ fn new_full<
let client_clone = client_clone.clone();
let keystore = keystore_clone.clone();
let downward_mock_para_inherent_receiver = downward_mock_para_inherent_receiver.clone();
let upward_mock_para_inherent_receiver = upward_mock_para_inherent_receiver.clone();
async move {

let downward_mock_para_inherent_receiver = downward_mock_para_inherent_receiver.clone();
// here we only take the last one
let para_inherent_decider_messages: Vec<Vec<u8>> = downward_mock_para_inherent_receiver.drain().collect();

let upward_mock_para_inherent_receiver = upward_mock_para_inherent_receiver.clone();
let para_inherent_upward_messages: Vec<Vec<u8>> = upward_mock_para_inherent_receiver.drain().collect();

// If there is a value to be updated, we update it
if let Some(value) = para_inherent_decider_messages.last() {
client_clone
Expand All @@ -719,7 +737,15 @@ fn new_full<
&[],
)
.expect("Should be able to write to aux storage; qed");
}

if let Some(value) = para_inherent_upward_messages.last() {
client_clone
.insert_aux(
&[(XMC_UPM_SELECTOR_AUX_KEY, value.as_slice())],
&[],
)
.expect("Should be able to write to aux storage; qed");
}

let parachain = MockParachainsInherentDataProvider::new(
Expand Down
68 changes: 68 additions & 0 deletions test/suites/dev-tanssi-relay/xcm/test-xcm-send-upward.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { beforeAll, describeSuite, expect } from "@moonwall/cli";
import { KeyringPair } from "@moonwall/util";
import { ApiPromise, Keyring } from "@polkadot/api";
import { u8aToHex } from "@polkadot/util";
import { RawXcmMessage, XcmFragment, injectUmpMessageAndSeal } from "../../../util/xcm";


describeSuite({
id: "DTR1003",
title: "XCM - Succeeds sending XCM",
foundationMethods: "dev",
testCases: ({ context, it }) => {
let polkadotJs: ApiPromise;
let alice: KeyringPair;
let transferredBalance;

beforeAll(async function () {
polkadotJs = context.polkadotJs();
alice = new Keyring({ type: "sr25519" }).addFromUri("//Alice", {
name: "Alice default",
});

transferredBalance = 10_000_000_000_000n;
});

it({
id: "T01",
title: "Should succeed receiving tokens",
test: async function () {
// XCM message sending reserved assets to alice
const xcmMessage = new XcmFragment({
assets: [
{
multilocation: {
parents: 1,
interior: { Here: null },
},
fungible: transferredBalance,
},
],
beneficiary: u8aToHex(alice.addressRaw),
})
.reserve_asset_deposited()
.clear_origin()
.buy_execution()
.deposit_asset()
.as_v3();

// Send an XCM and create block to execute it
await injectUmpMessageAndSeal(context, {
type: "XcmVersionedXcm",
payload: xcmMessage,
} as RawXcmMessage);

// Create a block in which the XCM will be executed
await context.createBlock();

// Make sure the state has alice's to DOT tokens
const alice_dot_balance = (await context.polkadotJs().query.foreignAssets.account(1, alice.address))
.unwrap()
.balance.toBigInt();
expect(alice_dot_balance > 0n).to.be.true;
// we should expect to have received less than the amount transferred
expect(alice_dot_balance < transferredBalance).to.be.true;
},
});
},
});
Loading

0 comments on commit 7369f6b

Please sign in to comment.