From 077e2cc11bb6166ac9f58a0b827d2f11c92a4dbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= <tomusdrw@users.noreply.github.com> Date: Tue, 2 Mar 2021 01:26:03 +0100 Subject: [PATCH] Derive bridged accounts (#781) * Add derivation support. * Add custom decoder for Accounts. * cargo fmt --all * Fix warn. * Fix articles. Co-authored-by: Hernando Castano <castano.ha@gmail.com> --- bridges/relays/substrate/src/cli.rs | 70 ++++++++++++++++++++++++++-- bridges/relays/substrate/src/main.rs | 32 ++++++++++++- 2 files changed, 96 insertions(+), 6 deletions(-) diff --git a/bridges/relays/substrate/src/cli.rs b/bridges/relays/substrate/src/cli.rs index 090ff3f92a9..9914cd2e3a5 100644 --- a/bridges/relays/substrate/src/cli.rs +++ b/bridges/relays/substrate/src/cli.rs @@ -20,6 +20,7 @@ use bp_message_lane::LaneId; use frame_support::weights::Weight; use sp_core::Bytes; use sp_finality_grandpa::SetId as GrandpaAuthoritiesSetId; +use sp_runtime::app_crypto::Ss58Codec; use structopt::{clap::arg_enum, StructOpt}; /// Parse relay CLI args. @@ -63,6 +64,8 @@ pub enum Command { EncodeMessagePayload(EncodeMessagePayload), /// Estimate Delivery and Dispatch Fee required for message submission to message lane. EstimateFee(EstimateFee), + /// Given a source chain `AccountId`, derive the corresponding `AccountId` for the target chain. + DeriveAccount(DeriveAccount), } /// Start headers relayer process. @@ -268,6 +271,20 @@ pub enum EstimateFee { }, } +/// Given a source chain `AccountId`, derive the corresponding `AccountId` for the target chain. +/// +/// The (derived) target chain `AccountId` is going to be used as dispatch origin of the call +/// that has been sent over the bridge. +/// This account can also be used to receive target-chain funds (or other form of ownership), +/// since messages sent over the bridge will be able to spend these. +#[derive(StructOpt)] +pub enum DeriveAccount { + /// Given Rialto AccountId, display corresponding Millau AccountId. + RialtoToMillau { account: AccountId }, + /// Given Millau AccountId, display corresponding Rialto AccountId. + MillauToRialto { account: AccountId }, +} + /// MessagePayload that can be delivered to message lane pallet on Millau. #[derive(StructOpt, Debug)] pub enum MillauToRialtoMessagePayload { @@ -284,7 +301,7 @@ pub enum MillauToRialtoMessagePayload { message: ToRialtoMessage, /// SS58 encoded account that will send the payload (must have SS58Prefix = 42) #[structopt(long)] - sender: bp_rialto::AccountId, + sender: AccountId, }, } @@ -305,7 +322,7 @@ pub enum RialtoToMillauMessagePayload { /// SS58 encoded account that will send the payload (must have SS58Prefix = 42) #[structopt(long)] - sender: bp_rialto::AccountId, + sender: AccountId, }, } @@ -327,7 +344,7 @@ pub enum ToRialtoMessage { Transfer { /// SS58 encoded account that will receive the transfer (must have SS58Prefix = 42) #[structopt(long)] - recipient: bp_rialto::AccountId, + recipient: AccountId, /// Amount of target tokens to send. #[structopt(long)] amount: bp_rialto::Balance, @@ -352,7 +369,7 @@ pub enum ToMillauMessage { Transfer { /// SS58 encoded account that will receive the transfer (must have SS58Prefix = 42) #[structopt(long)] - recipient: bp_millau::AccountId, + recipient: AccountId, /// Amount of target tokens to send. #[structopt(long)] amount: bp_millau::Balance, @@ -371,6 +388,51 @@ arg_enum! { } } +/// Generic account id with custom parser. +#[derive(Debug)] +pub struct AccountId { + account: sp_runtime::AccountId32, + version: sp_core::crypto::Ss58AddressFormat, +} + +impl std::str::FromStr for AccountId { + type Err = String; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + let (account, version) = sp_runtime::AccountId32::from_ss58check_with_version(s) + .map_err(|err| format!("Unable to decode SS58 address: {:?}", err))?; + Ok(Self { account, version }) + } +} + +impl AccountId { + /// Perform runtime checks of SS58 version and get Rialto's AccountId. + pub fn into_rialto(self) -> bp_rialto::AccountId { + self.check_and_get("Rialto", rialto_runtime::SS58Prefix::get()) + } + + /// Perform runtime checks of SS58 version and get Millau's AccountId. + pub fn into_millau(self) -> bp_millau::AccountId { + self.check_and_get("Millau", millau_runtime::SS58Prefix::get()) + } + + /// Check SS58Prefix and return the account id. + fn check_and_get(self, net: &str, expected_prefix: u8) -> sp_runtime::AccountId32 { + let version: u16 = self.version.into(); + println!("Version: {} vs {}", version, expected_prefix); + if version != expected_prefix as u16 { + log::warn!( + target: "bridge", + "Following address: {} does not seem to match {}'s format, got: {}", + self.account, + net, + self.version, + ) + } + self.account + } +} + /// 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 ed17e309670..f5c8c6a1e43 100644 --- a/bridges/relays/substrate/src/main.rs +++ b/bridges/relays/substrate/src/main.rs @@ -68,6 +68,7 @@ async fn run_command(command: cli::Command) -> Result<(), String> { cli::Command::EncodeCall(arg) => run_encode_call(arg).await, cli::Command::EncodeMessagePayload(arg) => run_encode_message_payload(arg).await, cli::Command::EstimateFee(arg) => run_estimate_fee(arg).await, + cli::Command::DeriveAccount(arg) => run_derive_account(arg).await, } } @@ -412,6 +413,31 @@ async fn run_estimate_fee(cmd: cli::EstimateFee) -> Result<(), String> { Ok(()) } +async fn run_derive_account(cmd: cli::DeriveAccount) -> Result<(), String> { + match cmd { + cli::DeriveAccount::RialtoToMillau { account } => { + let account = account.into_rialto(); + let acc = bp_runtime::SourceAccount::Account(account.clone()); + let id = bp_millau::derive_account_from_rialto_id(acc); + println!( + "{} (Rialto)\n\nCorresponding (derived) account id:\n-> {} (Millau)", + account, id + ) + } + cli::DeriveAccount::MillauToRialto { account } => { + let account = account.into_millau(); + let acc = bp_runtime::SourceAccount::Account(account.clone()); + let id = bp_rialto::derive_account_from_millau_id(acc); + println!( + "{} (Millau)\n\nCorresponding (derived) account id:\n-> {} (Rialto)", + account, id + ) + } + } + + Ok(()) +} + async fn estimate_message_delivery_and_dispatch_fee<Fee: Decode, C: Chain, P: Encode>( client: &relay_substrate_client::Client<C>, estimate_fee_method: &str, @@ -615,7 +641,7 @@ impl crate::cli::MillauToRialtoMessagePayload { .map_err(|e| format!("Failed to decode Millau's MessagePayload: {:?}", e)), Self::Message { message, sender } => { let spec_version = rialto_runtime::VERSION.spec_version; - let origin = CallOrigin::SourceAccount(sender); + let origin = CallOrigin::SourceAccount(sender.into_millau()); let call = message.into_call()?; let weight = call.get_dispatch_info().weight; @@ -635,7 +661,7 @@ impl crate::cli::RialtoToMillauMessagePayload { .map_err(|e| format!("Failed to decode Rialto's MessagePayload: {:?}", e)), Self::Message { message, sender } => { let spec_version = millau_runtime::VERSION.spec_version; - let origin = CallOrigin::SourceAccount(sender); + let origin = CallOrigin::SourceAccount(sender.into_rialto()); let call = message.into_call()?; let weight = call.get_dispatch_info().weight; @@ -699,6 +725,7 @@ impl crate::cli::ToRialtoMessage { ))) } cli::ToRialtoMessage::Transfer { recipient, amount } => { + let recipient = recipient.into_rialto(); rialto_runtime::Call::Balances(rialto_runtime::BalancesCall::transfer(recipient, amount)) } }; @@ -728,6 +755,7 @@ impl crate::cli::ToMillauMessage { ))) } cli::ToMillauMessage::Transfer { recipient, amount } => { + let recipient = recipient.into_millau(); millau_runtime::Call::Balances(millau_runtime::BalancesCall::transfer(recipient, amount)) } }; -- GitLab