From 0ff8c2437c43c0719a3f5cfb75e853e2179db5b5 Mon Sep 17 00:00:00 2001 From: Hernando Castano Date: Wed, 9 Dec 2020 07:30:52 -0500 Subject: [PATCH] Cross-Chain Transfer Generator (#535) * Attempt at adding Cross-Chain Transfer Generator * Add Transfer subcommand for sending messages to Rialto * Add temp helper script for sending messages * Remove Message and Lane Ids from Dispatch Event * Increase transfer amount used by script * Endow derived Dave account on Rialto with funds * Update Message generator to send more types of messages This commit first of all updates the script to use the new CLI commands for sending messages. Second, it adds messages which are sent from both Target and Source origins. * Generate messages from Root origin * Remove dbg! logs from relayer * Log AccountId as well as HexId * Remove Balances logs * Add InstanceId and MessageId back to Dispatch Event * Add InstanceId and MessageId types for Apps * Add missing comment * Document derived accounts as tests * Move shared commands to variables * Add example usage for send_message script * Add docs to message variants * Fix Clippy complaint --- bridges/bin/rialto/node/Cargo.toml | 1 + bridges/bin/rialto/node/src/chain_spec.rs | 24 +++++++++++++ bridges/modules/call-dispatch/src/lib.rs | 16 ++++++--- bridges/primitives/rialto/src/lib.rs | 17 +++++++-- bridges/relays/substrate/src/cli.rs | 37 ++++++++++++++----- bridges/relays/substrate/src/main.rs | 44 ++++++++++++++++------- 6 files changed, 112 insertions(+), 27 deletions(-) diff --git a/bridges/bin/rialto/node/Cargo.toml b/bridges/bin/rialto/node/Cargo.toml index 08b152b682..c5453468f7 100644 --- a/bridges/bin/rialto/node/Cargo.toml +++ b/bridges/bin/rialto/node/Cargo.toml @@ -17,6 +17,7 @@ structopt = "0.3.21" bp-message-lane = { path = "../../../primitives/message-lane" } bp-runtime = { path = "../../../primitives/runtime" } +bp-rialto = { path = "../../../primitives/rialto" } pallet-message-lane-rpc = { path = "../../../modules/message-lane/rpc" } rialto-runtime = { path = "../runtime" } diff --git a/bridges/bin/rialto/node/src/chain_spec.rs b/bridges/bin/rialto/node/src/chain_spec.rs index 939dcc5e3f..229fbd1cc9 100644 --- a/bridges/bin/rialto/node/src/chain_spec.rs +++ b/bridges/bin/rialto/node/src/chain_spec.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . +use bp_rialto::derive_account_from_millau_id; use rialto_runtime::{ AccountId, AuraConfig, BalancesConfig, BridgeKovanConfig, BridgeMillauConfig, BridgeRialtoPoAConfig, GenesisConfig, GrandpaConfig, SessionConfig, SessionKeys, Signature, SudoConfig, SystemConfig, WASM_BINARY, @@ -121,6 +122,10 @@ impl Alternative { get_account_id_from_seed::("Ferdie//stash"), get_account_id_from_seed::("George//stash"), get_account_id_from_seed::("Harry//stash"), + derive_account_from_millau_id(bp_runtime::SourceAccount::Root), + derive_account_from_millau_id(bp_runtime::SourceAccount::Account( + get_account_id_from_seed::("Dave"), + )), ], true, ) @@ -191,3 +196,22 @@ fn load_kovan_bridge_config() -> BridgeKovanConfig { initial_validators: rialto_runtime::kovan::genesis_validators(), } } + +#[test] +fn derived_dave_account_is_as_expected() { + let dave = get_account_id_from_seed::("Dave"); + let derived: AccountId = derive_account_from_millau_id(bp_runtime::SourceAccount::Account(dave)); + assert_eq!( + derived.to_string(), + "5Hg7WQyk8C1FmPzxY3xSjR7S6zZZC5sAL35vMr6NpW17jBhQ".to_string() + ); +} + +#[test] +fn derived_root_account_is_as_expected() { + let root: AccountId = derive_account_from_millau_id(bp_runtime::SourceAccount::Root); + assert_eq!( + root.to_string(), + "5HYYwXQvxhgdcBYs6kzqfK1HW6M3UF3Kh4YM7j288yiqbhnt".to_string() + ); +} diff --git a/bridges/modules/call-dispatch/src/lib.rs b/bridges/modules/call-dispatch/src/lib.rs index 6e7d26f545..19c728162e 100644 --- a/bridges/modules/call-dispatch/src/lib.rs +++ b/bridges/modules/call-dispatch/src/lib.rs @@ -211,8 +211,10 @@ impl, I: Instance> MessageDispatch for Module { // prepare dispatch origin let origin_account = match message.origin { CallOrigin::SourceRoot => { - let encoded_id = derive_account_id::(bridge, SourceAccount::Root); - T::AccountIdConverter::convert(encoded_id) + let hex_id = derive_account_id::(bridge, SourceAccount::Root); + let target_id = T::AccountIdConverter::convert(hex_id); + frame_support::debug::trace!("Root Account: {:?}", &target_id); + target_id } CallOrigin::TargetAccount(source_account_id, target_public, target_signature) => { let mut signed_message = Vec::new(); @@ -232,18 +234,24 @@ impl, I: Instance> MessageDispatch for Module { return; } + frame_support::debug::trace!("Target Account: {:?}", &target_account); target_account } CallOrigin::SourceAccount(source_account_id) => { - let encoded_id = derive_account_id(bridge, SourceAccount::Account(source_account_id)); - T::AccountIdConverter::convert(encoded_id) + let hex_id = derive_account_id(bridge, SourceAccount::Account(source_account_id)); + let target_id = T::AccountIdConverter::convert(hex_id); + frame_support::debug::trace!("Source Account: {:?}", &target_id); + target_id } }; // finally dispatch message let origin = RawOrigin::Signed(origin_account).into(); + + frame_support::debug::trace!("Message being dispatched is: {:?}", &message.call); let dispatch_result = message.call.dispatch(origin); let actual_call_weight = extract_actual_weight(&dispatch_result, &dispatch_info); + frame_support::debug::trace!( "Message {:?}/{:?} has been dispatched. Weight: {} of {}. Result: {:?}", bridge, diff --git a/bridges/primitives/rialto/src/lib.rs b/bridges/primitives/rialto/src/lib.rs index 30b1f0ae79..458a3abc0a 100644 --- a/bridges/primitives/rialto/src/lib.rs +++ b/bridges/primitives/rialto/src/lib.rs @@ -25,7 +25,7 @@ use bp_runtime::Chain; use frame_support::{weights::Weight, RuntimeDebug}; use sp_core::Hasher as HasherT; use sp_runtime::{ - traits::{BlakeTwo256, IdentifyAccount, Verify}, + traits::{BlakeTwo256, Convert, IdentifyAccount, Verify}, MultiSignature, MultiSigner, }; use sp_std::prelude::*; @@ -112,12 +112,25 @@ pub type Balance = u128; /// Convert a 256-bit hash into an AccountId. pub struct AccountIdConverter; -impl sp_runtime::traits::Convert for AccountIdConverter { +impl Convert for AccountIdConverter { fn convert(hash: sp_core::H256) -> AccountId { hash.to_fixed_bytes().into() } } +// We use this to get the account on Rialto (target) which is derived from Millau's (source) +// account. We do this so we can fund the derived account on Rialto at Genesis to it can pay +// transaction fees. +// +// The reason we can use the same `AccountId` type for both chains is because they share the same +// development seed phrase. +// +// Note that this should only be used for testing. +pub fn derive_account_from_millau_id(id: bp_runtime::SourceAccount) -> AccountId { + let encoded_id = bp_runtime::derive_account_id(*b"mlau", id); + AccountIdConverter::convert(encoded_id) +} + sp_api::decl_runtime_apis! { /// API for querying information about Rialto headers from the Bridge Pallet instance. /// diff --git a/bridges/relays/substrate/src/cli.rs b/bridges/relays/substrate/src/cli.rs index 0119359cde..d3662ba268 100644 --- a/bridges/relays/substrate/src/cli.rs +++ b/bridges/relays/substrate/src/cli.rs @@ -101,12 +101,15 @@ pub enum Command { /// Hex-encoded lane id. #[structopt(long)] lane: HexLaneId, - /// Message type. - #[structopt(long, possible_values = &ToRialtoMessage::variants())] - message: ToRialtoMessage, /// Delivery and dispatch fee. #[structopt(long)] fee: bp_millau::Balance, + /// Message type. + #[structopt(subcommand)] + message: ToRialtoMessage, + /// The origin to use when dispatching the message on the target chain. + #[structopt(long, possible_values = &Origins::variants())] + origin: Origins, }, /// Serve given lane of Rialto -> Millau messages. RialtoMessagesToMillau { @@ -144,12 +147,18 @@ pub enum Command { }, } -arg_enum! { - #[derive(Debug)] - /// All possible messages that may be delivered to the Rialto chain. - pub enum ToRialtoMessage { - Remark, - } +/// All possible messages that may be delivered to the Rialto chain. +#[derive(StructOpt, Debug)] +pub enum ToRialtoMessage { + /// Make an on-chain remark (comment). + Remark, + /// Transfer the specified `amount` of native tokens to a particular `recipient`. + Transfer { + #[structopt(long)] + recipient: bp_rialto::AccountId, + #[structopt(long)] + amount: bp_rialto::Balance, + }, } arg_enum! { @@ -160,6 +169,16 @@ arg_enum! { } } +arg_enum! { + #[derive(Debug)] + /// The origin to use when dispatching the message on the target chain. + pub enum Origins { + Root, + Target, + Source, + } +} + /// Lane id. #[derive(Debug)] pub struct HexLaneId(LaneId); diff --git a/bridges/relays/substrate/src/main.rs b/bridges/relays/substrate/src/main.rs index 8258f985a7..789105a27b 100644 --- a/bridges/relays/substrate/src/main.rs +++ b/bridges/relays/substrate/src/main.rs @@ -248,6 +248,8 @@ async fn run_command(command: cli::Command) -> Result<(), String> { lane, message, fee, + origin, + .. } => { let millau_client = MillauClient::new(ConnectionParams { host: millau.millau_host, @@ -277,33 +279,51 @@ async fn run_command(command: cli::Command) -> Result<(), String> { .as_bytes() .to_vec(), )), + cli::ToRialtoMessage::Transfer { recipient, amount } => { + rialto_runtime::Call::Balances(rialto_runtime::BalancesCall::transfer(recipient, amount)) + } }; - let rialto_call_weight = rialto_call.get_dispatch_info().weight; + let rialto_call_weight = rialto_call.get_dispatch_info().weight; let millau_sender_public: bp_millau::AccountSigner = millau_sign.signer.public().clone().into(); let millau_account_id: bp_millau::AccountId = millau_sender_public.into_account(); let rialto_origin_public = rialto_sign.signer.public(); - let mut rialto_origin_signature_message = Vec::new(); - rialto_call.encode_to(&mut rialto_origin_signature_message); - millau_account_id.encode_to(&mut rialto_origin_signature_message); - let rialto_origin_signature = rialto_sign.signer.sign(&rialto_origin_signature_message); + let payload = match origin { + cli::Origins::Root => MessagePayload { + spec_version: rialto_runtime::VERSION.spec_version, + weight: rialto_call_weight, + origin: CallOrigin::SourceRoot, + call: rialto_call.encode(), + }, + cli::Origins::Source => MessagePayload { + spec_version: rialto_runtime::VERSION.spec_version, + weight: rialto_call_weight, + origin: CallOrigin::SourceAccount(millau_account_id), + call: rialto_call.encode(), + }, + cli::Origins::Target => { + let mut rialto_origin_signature_message = Vec::new(); + rialto_call.encode_to(&mut rialto_origin_signature_message); + millau_account_id.encode_to(&mut rialto_origin_signature_message); + let rialto_origin_signature = rialto_sign.signer.sign(&rialto_origin_signature_message); - let millau_call = - millau_runtime::Call::BridgeRialtoMessageLane(millau_runtime::MessageLaneCall::send_message( - lane.into(), MessagePayload { spec_version: rialto_runtime::VERSION.spec_version, weight: rialto_call_weight, origin: CallOrigin::TargetAccount( - millau_account_id, + millau_account_id.clone(), rialto_origin_public.into(), rialto_origin_signature.into(), ), call: rialto_call.encode(), - }, - fee, - )); + } + } + }; + + let millau_call = millau_runtime::Call::BridgeRialtoMessageLane( + millau_runtime::MessageLaneCall::send_message(lane.into(), payload, fee), + ); let signed_millau_call = Millau::sign_transaction( &millau_client,