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,