Remove support for encoded-call messaging from relay and runtime integration code (#1376)

* remove support for encoded-call messaging

* continue cleanup

* continue cleanup

* continue cleanup

* more cleanpup

* more cleanup

* fmt

* continue cleanup

* spellcheck

* rename

* fix benchmarks

* mention encoded-calls-messaging tag

* fixing deployments

* fix messages generation

* fmt
This commit is contained in:
Svyatoslav Nikolsky
2022-05-04 15:05:14 +03:00
committed by Bastian Köcher
parent dc96aeea35
commit d582061dff
58 changed files with 408 additions and 7062 deletions
-4
View File
@@ -25,24 +25,20 @@ strum = { version = "0.21.0", features = ["derive"] }
bp-header-chain = { path = "../../primitives/header-chain" }
bp-kusama = { path = "../../primitives/chain-kusama" }
bp-messages = { path = "../../primitives/messages" }
bp-message-dispatch = { path = "../../primitives/message-dispatch" }
bp-millau = { path = "../../primitives/chain-millau" }
bp-polkadot = { path = "../../primitives/chain-polkadot" }
bp-rialto = { path = "../../primitives/chain-rialto" }
bp-rialto-parachain = { path = "../../primitives/chain-rialto-parachain" }
bp-rococo = { path = "../../primitives/chain-rococo" }
bp-runtime = { path = "../../primitives/runtime" }
bp-token-swap = { path = "../../primitives/token-swap" }
bp-westend = { path = "../../primitives/chain-westend" }
bp-wococo = { path = "../../primitives/chain-wococo" }
bridge-runtime-common = { path = "../../bin/runtime-common" }
finality-relay = { path = "../finality" }
messages-relay = { path = "../messages" }
millau-runtime = { path = "../../bin/millau/runtime" }
pallet-bridge-dispatch = { path = "../../modules/dispatch" }
pallet-bridge-grandpa = { path = "../../modules/grandpa" }
pallet-bridge-messages = { path = "../../modules/messages" }
pallet-bridge-token-swap = { path = "../../modules/token-swap" }
relay-kusama-client = { path = "../client-kusama" }
relay-millau-client = { path = "../client-millau" }
relay-polkadot-client = { path = "../client-polkadot" }
@@ -14,82 +14,46 @@
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use anyhow::anyhow;
use bp_message_dispatch::{CallOrigin, MessagePayload};
use bp_messages::LaneId;
use bp_runtime::EncodedOrDecodedCall;
use codec::Decode;
use frame_support::weights::{DispatchClass, DispatchInfo, Pays, Weight};
use relay_kusama_client::Kusama;
use relay_substrate_client::BalanceOf;
use sp_version::RuntimeVersion;
use crate::cli::{
bridge,
encode_call::{self, Call, CliEncodeCall},
encode_message,
send_message::{self, DispatchFeePayment},
encode_message::{CliEncodeMessage, RawMessage},
CliChain,
};
/// Weight of the `system::remark` call at Kusama.
///
/// This weight is larger (x2) than actual weight at current Kusama runtime to avoid unsuccessful
/// calls in the future. But since it is used only in tests (and on test chains), this is ok.
pub(crate) const SYSTEM_REMARK_CALL_WEIGHT: Weight = 2 * 1_345_000;
impl CliEncodeCall for Kusama {
fn encode_call(call: &Call) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
Ok(match call {
Call::Raw { data } => EncodedOrDecodedCall::Encoded(data.0.clone()),
Call::Remark { remark_payload, .. } => relay_kusama_client::runtime::Call::System(
relay_kusama_client::runtime::SystemCall::remark(
remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
),
)
.into(),
Call::BridgeSendMessage { lane, payload, fee, bridge_instance_index } =>
match *bridge_instance_index {
bridge::KUSAMA_TO_POLKADOT_INDEX => {
let payload = Decode::decode(&mut &*payload.0)?;
relay_kusama_client::runtime::Call::BridgePolkadotMessages(
relay_kusama_client::runtime::BridgePolkadotMessagesCall::send_message(
lane.0, payload, fee.0,
),
)
.into()
},
_ => anyhow::bail!(
"Unsupported target bridge pallet with instance index: {}",
bridge_instance_index
impl CliEncodeMessage for Kusama {
fn encode_send_message_call(
lane: LaneId,
payload: RawMessage,
fee: BalanceOf<Self>,
bridge_instance_index: u8,
) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
Ok(match bridge_instance_index {
bridge::KUSAMA_TO_POLKADOT_INDEX =>
relay_kusama_client::runtime::Call::BridgePolkadotMessages(
relay_kusama_client::runtime::BridgePolkadotMessagesCall::send_message(
lane, payload, fee,
),
},
_ => anyhow::bail!("Unsupported Kusama call: {:?}", call),
)
.into(),
_ => anyhow::bail!(
"Unsupported target bridge pallet with instance index: {}",
bridge_instance_index
),
})
}
fn get_dispatch_info(call: &EncodedOrDecodedCall<Self::Call>) -> anyhow::Result<DispatchInfo> {
match *call {
EncodedOrDecodedCall::Decoded(relay_kusama_client::runtime::Call::System(
relay_kusama_client::runtime::SystemCall::remark(_),
)) => Ok(DispatchInfo {
weight: crate::chains::kusama::SYSTEM_REMARK_CALL_WEIGHT,
class: DispatchClass::Normal,
pays_fee: Pays::Yes,
}),
_ => anyhow::bail!("Unsupported Kusama call: {:?}", call),
}
}
}
impl CliChain for Kusama {
const RUNTIME_VERSION: RuntimeVersion = bp_kusama::VERSION;
type KeyPair = sp_core::sr25519::Pair;
type MessagePayload = MessagePayload<
bp_kusama::AccountId,
bp_polkadot::AccountPublic,
bp_polkadot::Signature,
Vec<u8>,
>;
type MessagePayload = Vec<u8>;
fn ss58_format() -> u16 {
sp_core::crypto::Ss58AddressFormat::from(
@@ -97,39 +61,4 @@ impl CliChain for Kusama {
)
.into()
}
fn encode_message(
message: encode_message::MessagePayload,
) -> anyhow::Result<Self::MessagePayload> {
match message {
encode_message::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0)
.map_err(|e| anyhow!("Failed to decode Kusama's MessagePayload: {:?}", e)),
encode_message::MessagePayload::Call { mut call, mut sender, dispatch_weight } => {
type Source = Kusama;
type Target = relay_polkadot_client::Polkadot;
sender.enforce_chain::<Source>();
let spec_version = Target::RUNTIME_VERSION.spec_version;
let origin = CallOrigin::SourceAccount(sender.raw_id());
encode_call::preprocess_call::<Source, Target>(
&mut call,
bridge::KUSAMA_TO_POLKADOT_INDEX,
);
let call = Target::encode_call(&call)?;
let dispatch_weight = dispatch_weight.map(Ok).unwrap_or_else(|| {
Err(anyhow::format_err!(
"Please specify dispatch weight of the encoded Polkadot call"
))
})?;
Ok(send_message::message_payload(
spec_version,
dispatch_weight,
origin,
&call,
DispatchFeePayment::AtSourceChain,
))
},
}
}
}
@@ -18,106 +18,46 @@
use crate::cli::{
bridge,
encode_call::{self, Call, CliEncodeCall},
encode_message,
send_message::{self, DispatchFeePayment},
encode_message::{CliEncodeMessage, RawMessage},
CliChain,
};
use anyhow::anyhow;
use bp_message_dispatch::{CallOrigin, MessagePayload};
use bp_messages::LaneId;
use bp_runtime::EncodedOrDecodedCall;
use codec::Decode;
use frame_support::weights::{DispatchInfo, GetDispatchInfo};
use relay_millau_client::Millau;
use relay_substrate_client::BalanceOf;
use sp_version::RuntimeVersion;
impl CliEncodeCall for Millau {
fn encode_call(call: &Call) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
Ok(match call {
Call::Raw { data } => Self::Call::decode(&mut &*data.0)?.into(),
Call::Remark { remark_payload, .. } =>
millau_runtime::Call::System(millau_runtime::SystemCall::remark {
remark: remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
})
.into(),
Call::Transfer { recipient, amount } =>
millau_runtime::Call::Balances(millau_runtime::BalancesCall::transfer {
dest: recipient.raw_id(),
value: amount.cast(),
})
.into(),
Call::BridgeSendMessage { lane, payload, fee, bridge_instance_index } =>
match *bridge_instance_index {
bridge::MILLAU_TO_RIALTO_INDEX => {
let payload = Decode::decode(&mut &*payload.0)?;
millau_runtime::Call::BridgeRialtoMessages(
millau_runtime::MessagesCall::send_message {
lane_id: lane.0,
payload,
delivery_and_dispatch_fee: fee.cast(),
},
)
.into()
},
_ => anyhow::bail!(
"Unsupported target bridge pallet with instance index: {}",
bridge_instance_index
),
impl CliEncodeMessage for Millau {
fn encode_send_message_call(
lane: LaneId,
payload: RawMessage,
fee: BalanceOf<Self>,
bridge_instance_index: u8,
) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
Ok(match bridge_instance_index {
bridge::MILLAU_TO_RIALTO_INDEX => millau_runtime::Call::BridgeRialtoMessages(
millau_runtime::MessagesCall::send_message {
lane_id: lane,
payload,
delivery_and_dispatch_fee: fee,
},
)
.into(),
_ => anyhow::bail!(
"Unsupported target bridge pallet with instance index: {}",
bridge_instance_index
),
})
}
fn get_dispatch_info(call: &EncodedOrDecodedCall<Self::Call>) -> anyhow::Result<DispatchInfo> {
Ok(call.to_decoded()?.get_dispatch_info())
}
}
impl CliChain for Millau {
const RUNTIME_VERSION: RuntimeVersion = millau_runtime::VERSION;
type KeyPair = sp_core::sr25519::Pair;
type MessagePayload = MessagePayload<
bp_millau::AccountId,
bp_rialto::AccountSigner,
bp_rialto::Signature,
Vec<u8>,
>;
type MessagePayload = Vec<u8>;
fn ss58_format() -> u16 {
millau_runtime::SS58Prefix::get() as u16
}
// TODO [#854|#843] support multiple bridges?
fn encode_message(
message: encode_message::MessagePayload,
) -> anyhow::Result<Self::MessagePayload> {
match message {
encode_message::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0)
.map_err(|e| anyhow!("Failed to decode Millau's MessagePayload: {:?}", e)),
encode_message::MessagePayload::Call { mut call, mut sender, dispatch_weight } => {
type Source = Millau;
type Target = relay_rialto_client::Rialto;
sender.enforce_chain::<Source>();
let spec_version = Target::RUNTIME_VERSION.spec_version;
let origin = CallOrigin::SourceAccount(sender.raw_id());
encode_call::preprocess_call::<Source, Target>(
&mut call,
bridge::MILLAU_TO_RIALTO_INDEX,
);
let call = Target::encode_call(&call)?;
let dispatch_weight = dispatch_weight.map(Ok).unwrap_or_else(|| {
call.to_decoded().map(|call| call.get_dispatch_info().weight)
})?;
Ok(send_message::message_payload(
spec_version,
dispatch_weight,
origin,
&call,
DispatchFeePayment::AtSourceChain,
))
},
}
}
}
+7 -133
View File
@@ -41,95 +41,28 @@ mod wococo;
#[cfg(test)]
mod tests {
use crate::cli::{encode_call, send_message};
use crate::cli::encode_message;
use bp_messages::source_chain::TargetHeaderChain;
use bp_runtime::Chain as _;
use codec::Encode;
use frame_support::dispatch::GetDispatchInfo;
use relay_millau_client::Millau;
use relay_rialto_client::Rialto;
use relay_substrate_client::{SignParam, TransactionSignScheme, UnsignedTransaction};
use sp_core::Pair;
use sp_runtime::traits::{IdentifyAccount, Verify};
#[test]
fn millau_signature_is_valid_on_rialto() {
let millau_sign = relay_millau_client::SigningParams::from_string("//Dave", None).unwrap();
let call =
rialto_runtime::Call::System(rialto_runtime::SystemCall::remark { remark: vec![] });
let millau_public: bp_millau::AccountSigner = millau_sign.public().into();
let millau_account_id: bp_millau::AccountId = millau_public.into_account();
let digest = millau_runtime::millau_to_rialto_account_ownership_digest(
&call,
millau_account_id,
rialto_runtime::VERSION.spec_version,
);
let rialto_signer =
relay_rialto_client::SigningParams::from_string("//Dave", None).unwrap();
let signature = rialto_signer.sign(&digest);
assert!(signature.verify(&digest[..], &rialto_signer.public()));
}
#[test]
fn rialto_signature_is_valid_on_millau() {
let rialto_sign = relay_rialto_client::SigningParams::from_string("//Dave", None).unwrap();
let call =
millau_runtime::Call::System(millau_runtime::SystemCall::remark { remark: vec![] });
let rialto_public: bp_rialto::AccountSigner = rialto_sign.public().into();
let rialto_account_id: bp_rialto::AccountId = rialto_public.into_account();
let digest = rialto_runtime::rialto_to_millau_account_ownership_digest(
&call,
rialto_account_id,
millau_runtime::VERSION.spec_version,
);
let millau_signer =
relay_millau_client::SigningParams::from_string("//Dave", None).unwrap();
let signature = millau_signer.sign(&digest);
assert!(signature.verify(&digest[..], &millau_signer.public()));
}
#[test]
fn maximal_rialto_to_millau_message_arguments_size_is_computed_correctly() {
fn maximal_rialto_to_millau_message_size_is_computed_correctly() {
use rialto_runtime::millau_messages::Millau;
let maximal_remark_size = encode_call::compute_maximal_message_arguments_size(
let maximal_message_size = encode_message::compute_maximal_message_size(
bp_rialto::Rialto::max_extrinsic_size(),
bp_millau::Millau::max_extrinsic_size(),
);
let call: millau_runtime::Call =
millau_runtime::SystemCall::remark { remark: vec![42; maximal_remark_size as _] }
.into();
let payload = send_message::message_payload(
Default::default(),
call.get_dispatch_info().weight,
bp_message_dispatch::CallOrigin::SourceRoot,
&call,
send_message::DispatchFeePayment::AtSourceChain,
);
assert_eq!(Millau::verify_message(&payload), Ok(()));
let message = vec![42; maximal_message_size as _];
assert_eq!(Millau::verify_message(&message), Ok(()));
let call: millau_runtime::Call =
millau_runtime::SystemCall::remark { remark: vec![42; (maximal_remark_size + 1) as _] }
.into();
let payload = send_message::message_payload(
Default::default(),
call.get_dispatch_info().weight,
bp_message_dispatch::CallOrigin::SourceRoot,
&call,
send_message::DispatchFeePayment::AtSourceChain,
);
assert!(Millau::verify_message(&payload).is_err());
let message = vec![42; (maximal_message_size + 1) as _];
assert!(Millau::verify_message(&message).is_err());
}
#[test]
@@ -141,65 +74,6 @@ mod tests {
"We can't actually send maximal messages to Rialto from Millau, because Millau extrinsics can't be that large",
)
}
#[test]
fn maximal_rialto_to_millau_message_dispatch_weight_is_computed_correctly() {
use rialto_runtime::millau_messages::Millau;
let maximal_dispatch_weight = send_message::compute_maximal_message_dispatch_weight(
bp_millau::Millau::max_extrinsic_weight(),
);
let call: millau_runtime::Call =
rialto_runtime::SystemCall::remark { remark: vec![] }.into();
let payload = send_message::message_payload(
Default::default(),
maximal_dispatch_weight,
bp_message_dispatch::CallOrigin::SourceRoot,
&call,
send_message::DispatchFeePayment::AtSourceChain,
);
assert_eq!(Millau::verify_message(&payload), Ok(()));
let payload = send_message::message_payload(
Default::default(),
maximal_dispatch_weight + 1,
bp_message_dispatch::CallOrigin::SourceRoot,
&call,
send_message::DispatchFeePayment::AtSourceChain,
);
assert!(Millau::verify_message(&payload).is_err());
}
#[test]
fn maximal_weight_fill_block_to_rialto_is_generated_correctly() {
use millau_runtime::rialto_messages::Rialto;
let maximal_dispatch_weight = send_message::compute_maximal_message_dispatch_weight(
bp_rialto::Rialto::max_extrinsic_weight(),
);
let call: rialto_runtime::Call =
millau_runtime::SystemCall::remark { remark: vec![] }.into();
let payload = send_message::message_payload(
Default::default(),
maximal_dispatch_weight,
bp_message_dispatch::CallOrigin::SourceRoot,
&call,
send_message::DispatchFeePayment::AtSourceChain,
);
assert_eq!(Rialto::verify_message(&payload), Ok(()));
let payload = send_message::message_payload(
Default::default(),
maximal_dispatch_weight + 1,
bp_message_dispatch::CallOrigin::SourceRoot,
&call,
send_message::DispatchFeePayment::AtSourceChain,
);
assert!(Rialto::verify_message(&payload).is_err());
}
#[test]
fn rialto_tx_extra_bytes_constant_is_correct() {
let rialto_call =
@@ -14,82 +14,46 @@
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use anyhow::anyhow;
use bp_message_dispatch::{CallOrigin, MessagePayload};
use bp_messages::LaneId;
use bp_runtime::EncodedOrDecodedCall;
use codec::Decode;
use frame_support::weights::{DispatchClass, DispatchInfo, Pays, Weight};
use relay_polkadot_client::Polkadot;
use relay_substrate_client::BalanceOf;
use sp_version::RuntimeVersion;
use crate::cli::{
bridge,
encode_call::{self, Call, CliEncodeCall},
encode_message,
send_message::{self, DispatchFeePayment},
encode_message::{CliEncodeMessage, RawMessage},
CliChain,
};
/// Weight of the `system::remark` call at Polkadot.
///
/// This weight is larger (x2) than actual weight at current Polkadot runtime to avoid unsuccessful
/// calls in the future. But since it is used only in tests (and on test chains), this is ok.
pub(crate) const SYSTEM_REMARK_CALL_WEIGHT: Weight = 2 * 1_345_000;
impl CliEncodeCall for Polkadot {
fn encode_call(call: &Call) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
Ok(match call {
Call::Raw { data } => EncodedOrDecodedCall::Encoded(data.0.clone()),
Call::Remark { remark_payload, .. } => relay_polkadot_client::runtime::Call::System(
relay_polkadot_client::runtime::SystemCall::remark(
remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
),
)
.into(),
Call::BridgeSendMessage { lane, payload, fee, bridge_instance_index } =>
match *bridge_instance_index {
bridge::POLKADOT_TO_KUSAMA_INDEX => {
let payload = Decode::decode(&mut &*payload.0)?;
relay_polkadot_client::runtime::Call::BridgeKusamaMessages(
relay_polkadot_client::runtime::BridgeKusamaMessagesCall::send_message(
lane.0, payload, fee.0,
),
)
.into()
},
_ => anyhow::bail!(
"Unsupported target bridge pallet with instance index: {}",
bridge_instance_index
impl CliEncodeMessage for Polkadot {
fn encode_send_message_call(
lane: LaneId,
payload: RawMessage,
fee: BalanceOf<Self>,
bridge_instance_index: u8,
) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
Ok(match bridge_instance_index {
bridge::POLKADOT_TO_KUSAMA_INDEX =>
relay_polkadot_client::runtime::Call::BridgeKusamaMessages(
relay_polkadot_client::runtime::BridgeKusamaMessagesCall::send_message(
lane, payload, fee,
),
},
_ => anyhow::bail!("Unsupported Polkadot call: {:?}", call),
)
.into(),
_ => anyhow::bail!(
"Unsupported target bridge pallet with instance index: {}",
bridge_instance_index
),
})
}
fn get_dispatch_info(call: &EncodedOrDecodedCall<Self::Call>) -> anyhow::Result<DispatchInfo> {
match *call {
EncodedOrDecodedCall::Decoded(relay_polkadot_client::runtime::Call::System(
relay_polkadot_client::runtime::SystemCall::remark(_),
)) => Ok(DispatchInfo {
weight: crate::chains::polkadot::SYSTEM_REMARK_CALL_WEIGHT,
class: DispatchClass::Normal,
pays_fee: Pays::Yes,
}),
_ => anyhow::bail!("Unsupported Polkadot call: {:?}", call),
}
}
}
impl CliChain for Polkadot {
const RUNTIME_VERSION: RuntimeVersion = bp_polkadot::VERSION;
type KeyPair = sp_core::sr25519::Pair;
type MessagePayload = MessagePayload<
bp_polkadot::AccountId,
bp_kusama::AccountPublic,
bp_kusama::Signature,
Vec<u8>,
>;
type MessagePayload = Vec<u8>;
fn ss58_format() -> u16 {
sp_core::crypto::Ss58AddressFormat::from(
@@ -97,39 +61,4 @@ impl CliChain for Polkadot {
)
.into()
}
fn encode_message(
message: encode_message::MessagePayload,
) -> anyhow::Result<Self::MessagePayload> {
match message {
encode_message::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0)
.map_err(|e| anyhow!("Failed to decode Polkadot's MessagePayload: {:?}", e)),
encode_message::MessagePayload::Call { mut call, mut sender, dispatch_weight } => {
type Source = Polkadot;
type Target = relay_kusama_client::Kusama;
sender.enforce_chain::<Source>();
let spec_version = Target::RUNTIME_VERSION.spec_version;
let origin = CallOrigin::SourceAccount(sender.raw_id());
encode_call::preprocess_call::<Source, Target>(
&mut call,
bridge::POLKADOT_TO_KUSAMA_INDEX,
);
let call = Target::encode_call(&call)?;
let dispatch_weight = dispatch_weight.map(Ok).unwrap_or_else(|| {
Err(anyhow::format_err!(
"Please specify dispatch weight of the encoded Kusama call"
))
})?;
Ok(send_message::message_payload(
spec_version,
dispatch_weight,
origin,
&call,
DispatchFeePayment::AtSourceChain,
))
},
}
}
}
@@ -18,105 +18,46 @@
use crate::cli::{
bridge,
encode_call::{self, Call, CliEncodeCall},
encode_message,
send_message::{self, DispatchFeePayment},
encode_message::{CliEncodeMessage, RawMessage},
CliChain,
};
use anyhow::anyhow;
use bp_message_dispatch::{CallOrigin, MessagePayload};
use bp_messages::LaneId;
use bp_runtime::EncodedOrDecodedCall;
use codec::Decode;
use frame_support::weights::{DispatchInfo, GetDispatchInfo};
use relay_rialto_client::Rialto;
use relay_substrate_client::BalanceOf;
use sp_version::RuntimeVersion;
impl CliEncodeCall for Rialto {
fn encode_call(call: &Call) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
Ok(match call {
Call::Raw { data } => Self::Call::decode(&mut &*data.0)?.into(),
Call::Remark { remark_payload, .. } =>
rialto_runtime::Call::System(rialto_runtime::SystemCall::remark {
remark: remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
})
.into(),
Call::Transfer { recipient, amount } =>
rialto_runtime::Call::Balances(rialto_runtime::BalancesCall::transfer {
dest: recipient.raw_id().into(),
value: amount.0,
})
.into(),
Call::BridgeSendMessage { lane, payload, fee, bridge_instance_index } =>
match *bridge_instance_index {
bridge::RIALTO_TO_MILLAU_INDEX => {
let payload = Decode::decode(&mut &*payload.0)?;
rialto_runtime::Call::BridgeMillauMessages(
rialto_runtime::MessagesCall::send_message {
lane_id: lane.0,
payload,
delivery_and_dispatch_fee: fee.0,
},
)
.into()
},
_ => anyhow::bail!(
"Unsupported target bridge pallet with instance index: {}",
bridge_instance_index
),
impl CliEncodeMessage for Rialto {
fn encode_send_message_call(
lane: LaneId,
payload: RawMessage,
fee: BalanceOf<Self>,
bridge_instance_index: u8,
) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
Ok(match bridge_instance_index {
bridge::RIALTO_TO_MILLAU_INDEX => rialto_runtime::Call::BridgeMillauMessages(
rialto_runtime::MessagesCall::send_message {
lane_id: lane,
payload,
delivery_and_dispatch_fee: fee,
},
)
.into(),
_ => anyhow::bail!(
"Unsupported target bridge pallet with instance index: {}",
bridge_instance_index
),
})
}
fn get_dispatch_info(call: &EncodedOrDecodedCall<Self::Call>) -> anyhow::Result<DispatchInfo> {
Ok(call.to_decoded()?.get_dispatch_info())
}
}
impl CliChain for Rialto {
const RUNTIME_VERSION: RuntimeVersion = rialto_runtime::VERSION;
type KeyPair = sp_core::sr25519::Pair;
type MessagePayload = MessagePayload<
bp_rialto::AccountId,
bp_millau::AccountSigner,
bp_millau::Signature,
Vec<u8>,
>;
type MessagePayload = Vec<u8>;
fn ss58_format() -> u16 {
rialto_runtime::SS58Prefix::get() as u16
}
fn encode_message(
message: encode_message::MessagePayload,
) -> anyhow::Result<Self::MessagePayload> {
match message {
encode_message::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0)
.map_err(|e| anyhow!("Failed to decode Rialto's MessagePayload: {:?}", e)),
encode_message::MessagePayload::Call { mut call, mut sender, dispatch_weight } => {
type Source = Rialto;
type Target = relay_millau_client::Millau;
sender.enforce_chain::<Source>();
let spec_version = Target::RUNTIME_VERSION.spec_version;
let origin = CallOrigin::SourceAccount(sender.raw_id());
encode_call::preprocess_call::<Source, Target>(
&mut call,
bridge::RIALTO_TO_MILLAU_INDEX,
);
let call = Target::encode_call(&call)?;
let dispatch_weight = dispatch_weight.map(Ok).unwrap_or_else(|| {
call.to_decoded().map(|call| call.get_dispatch_info().weight)
})?;
Ok(send_message::message_payload(
spec_version,
dispatch_weight,
origin,
&call,
DispatchFeePayment::AtSourceChain,
))
},
}
}
}
@@ -16,63 +16,17 @@
//! Rialto parachain specification for CLI.
use crate::cli::{
encode_call::{Call, CliEncodeCall},
encode_message, CliChain,
};
use bp_message_dispatch::MessagePayload;
use bp_runtime::EncodedOrDecodedCall;
use codec::Decode;
use frame_support::weights::{DispatchInfo, GetDispatchInfo};
use crate::cli::CliChain;
use relay_rialto_parachain_client::RialtoParachain;
use sp_version::RuntimeVersion;
impl CliEncodeCall for RialtoParachain {
fn encode_call(call: &Call) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
Ok(match call {
Call::Raw { data } => Self::Call::decode(&mut &*data.0)?.into(),
Call::Remark { remark_payload, .. } => rialto_parachain_runtime::Call::System(
rialto_parachain_runtime::SystemCall::remark {
remark: remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
},
)
.into(),
Call::Transfer { recipient, amount } => rialto_parachain_runtime::Call::Balances(
rialto_parachain_runtime::BalancesCall::transfer {
dest: recipient.raw_id().into(),
value: amount.0,
},
)
.into(),
Call::BridgeSendMessage { .. } => {
anyhow::bail!("Bridge messages are not (yet) supported here",)
},
})
}
fn get_dispatch_info(call: &EncodedOrDecodedCall<Self::Call>) -> anyhow::Result<DispatchInfo> {
Ok(call.to_decoded()?.get_dispatch_info())
}
}
impl CliChain for RialtoParachain {
const RUNTIME_VERSION: RuntimeVersion = rialto_parachain_runtime::VERSION;
type KeyPair = sp_core::sr25519::Pair;
type MessagePayload = MessagePayload<
bp_rialto_parachain::AccountId,
bp_millau::AccountSigner,
bp_millau::Signature,
Vec<u8>,
>;
type MessagePayload = Vec<u8>;
fn ss58_format() -> u16 {
rialto_parachain_runtime::SS58Prefix::get() as u16
}
fn encode_message(
_message: encode_message::MessagePayload,
) -> anyhow::Result<Self::MessagePayload> {
anyhow::bail!("Not supported")
}
}
@@ -14,119 +14,47 @@
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use anyhow::anyhow;
use bp_message_dispatch::{CallOrigin, MessagePayload};
use bp_messages::LaneId;
use bp_runtime::EncodedOrDecodedCall;
use codec::Decode;
use frame_support::weights::{DispatchClass, DispatchInfo, Pays, Weight};
use relay_rococo_client::Rococo;
use relay_substrate_client::BalanceOf;
use sp_version::RuntimeVersion;
use crate::cli::{
bridge,
encode_call::{self, Call, CliEncodeCall},
encode_message,
send_message::{self, DispatchFeePayment},
encode_message::{CliEncodeMessage, RawMessage},
CliChain,
};
/// Weight of the `system::remark` call at Rococo.
///
/// This weight is larger (x2) than actual weight at current Rococo runtime to avoid unsuccessful
/// calls in the future. But since it is used only in tests (and on test chains), this is ok.
pub(crate) const SYSTEM_REMARK_CALL_WEIGHT: Weight = 2 * 1_345_000;
impl CliEncodeCall for Rococo {
fn encode_call(call: &Call) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
Ok(match call {
Call::Raw { data } => EncodedOrDecodedCall::Encoded(data.0.clone()),
Call::Remark { remark_payload, .. } => relay_rococo_client::runtime::Call::System(
relay_rococo_client::runtime::SystemCall::remark(
remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
),
)
.into(),
Call::BridgeSendMessage { lane, payload, fee, bridge_instance_index } =>
match *bridge_instance_index {
bridge::ROCOCO_TO_WOCOCO_INDEX => {
let payload = Decode::decode(&mut &*payload.0)?;
relay_rococo_client::runtime::Call::BridgeWococoMessages(
relay_rococo_client::runtime::BridgeWococoMessagesCall::send_message(
lane.0, payload, fee.0,
),
)
.into()
},
_ => anyhow::bail!(
"Unsupported target bridge pallet with instance index: {}",
bridge_instance_index
impl CliEncodeMessage for Rococo {
fn encode_send_message_call(
lane: LaneId,
payload: RawMessage,
fee: BalanceOf<Self>,
bridge_instance_index: u8,
) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
Ok(match bridge_instance_index {
bridge::ROCOCO_TO_WOCOCO_INDEX =>
relay_rococo_client::runtime::Call::BridgeWococoMessages(
relay_rococo_client::runtime::BridgeWococoMessagesCall::send_message(
lane, payload, fee,
),
},
_ => anyhow::bail!("The call is not supported"),
)
.into(),
_ => anyhow::bail!(
"Unsupported target bridge pallet with instance index: {}",
bridge_instance_index
),
})
}
fn get_dispatch_info(call: &EncodedOrDecodedCall<Self::Call>) -> anyhow::Result<DispatchInfo> {
match *call {
EncodedOrDecodedCall::Decoded(relay_rococo_client::runtime::Call::System(
relay_rococo_client::runtime::SystemCall::remark(_),
)) => Ok(DispatchInfo {
weight: SYSTEM_REMARK_CALL_WEIGHT,
class: DispatchClass::Normal,
pays_fee: Pays::Yes,
}),
_ => anyhow::bail!("Unsupported Rococo call: {:?}", call),
}
}
}
impl CliChain for Rococo {
const RUNTIME_VERSION: RuntimeVersion = bp_rococo::VERSION;
type KeyPair = sp_core::sr25519::Pair;
type MessagePayload = MessagePayload<
bp_rococo::AccountId,
bp_wococo::AccountPublic,
bp_wococo::Signature,
Vec<u8>,
>;
type MessagePayload = Vec<u8>;
fn ss58_format() -> u16 {
42
}
fn encode_message(
message: encode_message::MessagePayload,
) -> anyhow::Result<Self::MessagePayload> {
match message {
encode_message::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0)
.map_err(|e| anyhow!("Failed to decode Rococo's MessagePayload: {:?}", e)),
encode_message::MessagePayload::Call { mut call, mut sender, dispatch_weight } => {
type Source = Rococo;
type Target = relay_wococo_client::Wococo;
sender.enforce_chain::<Source>();
let spec_version = Target::RUNTIME_VERSION.spec_version;
let origin = CallOrigin::SourceAccount(sender.raw_id());
encode_call::preprocess_call::<Source, Target>(
&mut call,
bridge::ROCOCO_TO_WOCOCO_INDEX,
);
let call = Target::encode_call(&call)?;
let dispatch_weight = dispatch_weight.map(Ok).unwrap_or_else(|| {
Err(anyhow::format_err!(
"Please specify dispatch weight of the encoded Wococo call"
))
})?;
Ok(send_message::message_payload(
spec_version,
dispatch_weight,
origin,
&call,
DispatchFeePayment::AtSourceChain,
))
},
}
}
}
@@ -16,8 +16,7 @@
//! Westend chain specification for CLI.
use crate::cli::{encode_message, CliChain};
use anyhow::anyhow;
use crate::cli::CliChain;
use relay_westend_client::Westend;
use sp_version::RuntimeVersion;
@@ -25,7 +24,7 @@ impl CliChain for Westend {
const RUNTIME_VERSION: RuntimeVersion = bp_westend::VERSION;
type KeyPair = sp_core::sr25519::Pair;
type MessagePayload = ();
type MessagePayload = Vec<u8>;
fn ss58_format() -> u16 {
sp_core::crypto::Ss58AddressFormat::from(
@@ -33,10 +32,4 @@ impl CliChain for Westend {
)
.into()
}
fn encode_message(
_message: encode_message::MessagePayload,
) -> anyhow::Result<Self::MessagePayload> {
Err(anyhow!("Sending messages from Westend is not yet supported."))
}
}
@@ -14,113 +14,48 @@
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use anyhow::anyhow;
use bp_message_dispatch::{CallOrigin, MessagePayload};
use bp_messages::LaneId;
use bp_runtime::EncodedOrDecodedCall;
use codec::Decode;
use frame_support::weights::{DispatchClass, DispatchInfo, Pays};
use relay_substrate_client::BalanceOf;
use relay_wococo_client::Wococo;
use sp_version::RuntimeVersion;
use crate::cli::{
bridge,
encode_call::{self, Call, CliEncodeCall},
encode_message,
send_message::{self, DispatchFeePayment},
encode_message::{CliEncodeMessage, RawMessage},
CliChain,
};
impl CliEncodeCall for Wococo {
fn encode_call(call: &Call) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
Ok(match call {
Call::Raw { data } => EncodedOrDecodedCall::Encoded(data.0.clone()),
Call::Remark { remark_payload, .. } => relay_wococo_client::runtime::Call::System(
relay_wococo_client::runtime::SystemCall::remark(
remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
),
)
.into(),
Call::BridgeSendMessage { lane, payload, fee, bridge_instance_index } =>
match *bridge_instance_index {
bridge::WOCOCO_TO_ROCOCO_INDEX => {
let payload = Decode::decode(&mut &*payload.0)?;
relay_wococo_client::runtime::Call::BridgeRococoMessages(
relay_wococo_client::runtime::BridgeRococoMessagesCall::send_message(
lane.0, payload, fee.0,
),
)
.into()
},
_ => anyhow::bail!(
"Unsupported target bridge pallet with instance index: {}",
bridge_instance_index
impl CliEncodeMessage for Wococo {
fn encode_send_message_call(
lane: LaneId,
payload: RawMessage,
fee: BalanceOf<Self>,
bridge_instance_index: u8,
) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>> {
Ok(match bridge_instance_index {
bridge::WOCOCO_TO_ROCOCO_INDEX =>
relay_wococo_client::runtime::Call::BridgeRococoMessages(
relay_wococo_client::runtime::BridgeRococoMessagesCall::send_message(
lane, payload, fee,
),
},
_ => anyhow::bail!("The call is not supported"),
)
.into(),
_ => anyhow::bail!(
"Unsupported target bridge pallet with instance index: {}",
bridge_instance_index
),
})
}
fn get_dispatch_info(call: &EncodedOrDecodedCall<Self::Call>) -> anyhow::Result<DispatchInfo> {
match *call {
EncodedOrDecodedCall::Decoded(relay_wococo_client::runtime::Call::System(
relay_wococo_client::runtime::SystemCall::remark(_),
)) => Ok(DispatchInfo {
weight: crate::chains::rococo::SYSTEM_REMARK_CALL_WEIGHT,
class: DispatchClass::Normal,
pays_fee: Pays::Yes,
}),
_ => anyhow::bail!("Unsupported Wococo call: {:?}", call),
}
}
}
impl CliChain for Wococo {
const RUNTIME_VERSION: RuntimeVersion = bp_wococo::VERSION;
type KeyPair = sp_core::sr25519::Pair;
type MessagePayload = MessagePayload<
bp_wococo::AccountId,
bp_rococo::AccountPublic,
bp_rococo::Signature,
Vec<u8>,
>;
type MessagePayload = Vec<u8>;
fn ss58_format() -> u16 {
42
}
fn encode_message(
message: encode_message::MessagePayload,
) -> anyhow::Result<Self::MessagePayload> {
match message {
encode_message::MessagePayload::Raw { data } => MessagePayload::decode(&mut &*data.0)
.map_err(|e| anyhow!("Failed to decode Wococo's MessagePayload: {:?}", e)),
encode_message::MessagePayload::Call { mut call, mut sender, dispatch_weight } => {
type Source = Wococo;
type Target = relay_rococo_client::Rococo;
sender.enforce_chain::<Source>();
let spec_version = Target::RUNTIME_VERSION.spec_version;
let origin = CallOrigin::SourceAccount(sender.raw_id());
encode_call::preprocess_call::<Source, Target>(
&mut call,
bridge::WOCOCO_TO_ROCOCO_INDEX,
);
let call = Target::encode_call(&call)?;
let dispatch_weight = dispatch_weight.map(Ok).unwrap_or_else(|| {
Err(anyhow::format_err!(
"Please specify dispatch weight of the encoded Rococo call"
))
})?;
Ok(send_message::message_payload(
spec_version,
dispatch_weight,
origin,
&call,
DispatchFeePayment::AtSourceChain,
))
},
}
}
}
+6 -25
View File
@@ -73,12 +73,9 @@ macro_rules! select_full_bridge {
// Send-message / Estimate-fee
#[allow(unused_imports)]
use bp_rialto::TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD;
// Send-message
#[allow(unused_imports)]
use millau_runtime::millau_to_rialto_account_ownership_digest as account_ownership_digest;
$generic
}
},
FullBridge::RialtoToMillau => {
type Source = relay_rialto_client::Rialto;
#[allow(dead_code)]
@@ -96,12 +93,8 @@ macro_rules! select_full_bridge {
#[allow(unused_imports)]
use bp_millau::TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD;
// Send-message
#[allow(unused_imports)]
use rialto_runtime::rialto_to_millau_account_ownership_digest as account_ownership_digest;
$generic
}
},
FullBridge::RococoToWococo => {
type Source = relay_rococo_client::Rococo;
#[allow(dead_code)]
@@ -118,12 +111,9 @@ macro_rules! select_full_bridge {
// Send-message / Estimate-fee
#[allow(unused_imports)]
use bp_wococo::TO_WOCOCO_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD;
// Send-message
#[allow(unused_imports)]
use relay_rococo_client::runtime::rococo_to_wococo_account_ownership_digest as account_ownership_digest;
$generic
}
},
FullBridge::WococoToRococo => {
type Source = relay_wococo_client::Wococo;
#[allow(dead_code)]
@@ -140,12 +130,9 @@ macro_rules! select_full_bridge {
// Send-message / Estimate-fee
#[allow(unused_imports)]
use bp_rococo::TO_ROCOCO_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD;
// Send-message
#[allow(unused_imports)]
use relay_wococo_client::runtime::wococo_to_rococo_account_ownership_digest as account_ownership_digest;
$generic
}
},
FullBridge::KusamaToPolkadot => {
type Source = relay_kusama_client::Kusama;
#[allow(dead_code)]
@@ -162,12 +149,9 @@ macro_rules! select_full_bridge {
// Send-message / Estimate-fee
#[allow(unused_imports)]
use bp_polkadot::TO_POLKADOT_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD;
// Send-message
#[allow(unused_imports)]
use relay_kusama_client::runtime::kusama_to_polkadot_account_ownership_digest as account_ownership_digest;
$generic
}
},
FullBridge::PolkadotToKusama => {
type Source = relay_polkadot_client::Polkadot;
#[allow(dead_code)]
@@ -184,12 +168,9 @@ macro_rules! select_full_bridge {
// Send-message / Estimate-fee
#[allow(unused_imports)]
use bp_kusama::TO_KUSAMA_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD;
// Send-message
#[allow(unused_imports)]
use relay_polkadot_client::runtime::polkadot_to_kusama_account_ownership_digest as account_ownership_digest;
$generic
}
},
}
};
}
@@ -1,101 +0,0 @@
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use crate::{
cli::{bridge::FullBridge, AccountId},
select_full_bridge,
};
use relay_substrate_client::Chain;
use structopt::StructOpt;
use strum::VariantNames;
/// 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 struct DeriveAccount {
/// A bridge instance to initialize.
#[structopt(possible_values = FullBridge::VARIANTS, case_insensitive = true)]
bridge: FullBridge,
/// Source-chain address to derive Target-chain address from.
account: AccountId,
}
impl DeriveAccount {
/// Parse CLI arguments and derive account.
///
/// Returns both the Source account in correct SS58 format and the derived account.
fn derive_account(&self) -> (AccountId, AccountId) {
select_full_bridge!(self.bridge, {
let mut account = self.account.clone();
account.enforce_chain::<Source>();
let acc = bp_runtime::SourceAccount::Account(account.raw_id());
let id = derive_account(acc);
let derived_account = AccountId::from_raw::<Target>(id);
(account, derived_account)
})
}
/// Run the command.
pub async fn run(self) -> anyhow::Result<()> {
select_full_bridge!(self.bridge, {
let (account, derived_account) = self.derive_account();
println!("Source address:\n{} ({})", account, Source::NAME);
println!("->Corresponding (derived) address:\n{} ({})", derived_account, Target::NAME,);
Ok(())
})
}
}
#[cfg(test)]
mod tests {
use super::*;
fn derive_account_cli(bridge: &str, account: &str) -> (AccountId, AccountId) {
DeriveAccount::from_iter(vec!["derive-account", bridge, account]).derive_account()
}
#[test]
fn should_derive_accounts_correctly() {
// given
let rialto = "5sauUXUfPjmwxSgmb3tZ5d6yx24eZX4wWJ2JtVUBaQqFbvEU";
let millau = "752paRyW1EGfq9YLTSSqcSJ5hqnBDidBmaftGhBo8fy6ypW9";
// when
let (rialto_parsed, rialto_derived) = derive_account_cli("rialto-to-millau", rialto);
let (millau_parsed, millau_derived) = derive_account_cli("millau-to-rialto", millau);
let (millau2_parsed, millau2_derived) = derive_account_cli("millau-to-rialto", rialto);
// then
assert_eq!(format!("{}", rialto_parsed), rialto);
assert_eq!(format!("{}", millau_parsed), millau);
assert_eq!(format!("{}", millau2_parsed), millau);
assert_eq!(
format!("{}", rialto_derived),
"74GNQjmkcfstRftSQPJgMREchqHM56EvAUXRc266cZ1NYVW5"
);
assert_eq!(
format!("{}", millau_derived),
"5rERgaT1Z8nM3et2epA5i1VtEBfp5wkhwHtVE8HK7BRbjAH2"
);
assert_eq!(millau_derived, millau2_derived);
}
}
@@ -1,354 +0,0 @@
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use crate::{
cli::{
bridge::FullBridge, AccountId, Balance, CliChain, ExplicitOrMaximal, HexBytes, HexLaneId,
},
select_full_bridge,
};
use bp_runtime::EncodedOrDecodedCall;
use frame_support::weights::DispatchInfo;
use relay_substrate_client::Chain;
use structopt::StructOpt;
use strum::VariantNames;
/// Encode source chain runtime call.
#[derive(StructOpt, Debug)]
pub struct EncodeCall {
/// A bridge instance to encode call for.
#[structopt(possible_values = FullBridge::VARIANTS, case_insensitive = true)]
bridge: FullBridge,
#[structopt(flatten)]
call: Call,
}
/// All possible messages that may be delivered to generic Substrate chain.
///
/// Note this enum may be used in the context of both Source (as part of `encode-call`)
/// and Target chain (as part of `encode-message/send-message`).
#[derive(StructOpt, Debug, PartialEq, Eq)]
pub enum Call {
/// Raw bytes for the message
Raw {
/// Raw, SCALE-encoded message
data: HexBytes,
},
/// Make an on-chain remark (comment).
Remark {
/// Explicit remark payload.
#[structopt(long, conflicts_with("remark-size"))]
remark_payload: Option<HexBytes>,
/// Remark size. If not passed, small UTF8-encoded string is generated by relay as remark.
#[structopt(long, conflicts_with("remark-payload"))]
remark_size: Option<ExplicitOrMaximal<usize>>,
},
/// Transfer the specified `amount` of native tokens to a particular `recipient`.
Transfer {
/// Address of an account to receive the transfer.
#[structopt(long)]
recipient: AccountId,
/// Amount of target tokens to send in target chain base currency units.
#[structopt(long)]
amount: Balance,
},
/// A call to the specific Bridge Messages pallet to queue message to be sent over a bridge.
BridgeSendMessage {
/// An index of the bridge instance which represents the expected target chain.
#[structopt(skip = 255)]
bridge_instance_index: u8,
/// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`.
#[structopt(long, default_value = "00000000")]
lane: HexLaneId,
/// Raw SCALE-encoded Message Payload to submit to the messages pallet.
///
/// This can be obtained by encoding call for the target chain.
#[structopt(long)]
payload: HexBytes,
/// Declared delivery and dispatch fee in base source-chain currency units.
#[structopt(long)]
fee: Balance,
},
}
pub trait CliEncodeCall: Chain {
/// Encode a CLI call.
fn encode_call(call: &Call) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>>;
/// Get dispatch info for the call.
fn get_dispatch_info(call: &EncodedOrDecodedCall<Self::Call>) -> anyhow::Result<DispatchInfo>;
}
impl EncodeCall {
fn encode(&mut self) -> anyhow::Result<HexBytes> {
select_full_bridge!(self.bridge, {
preprocess_call::<Source, Target>(&mut self.call, self.bridge.bridge_instance_index());
let call = Source::encode_call(&self.call)?;
let encoded = HexBytes::encode(&call);
log::info!(target: "bridge", "Generated {} call: {:#?}", Source::NAME, call);
log::info!(target: "bridge", "Weight of {} call: {}", Source::NAME, Source::get_dispatch_info(&call)
.map(|dispatch_info| format!("{}", dispatch_info.weight))
.unwrap_or_else(|_| "<unknown>".to_string())
);
log::info!(target: "bridge", "Encoded {} call: {:?}", Source::NAME, encoded);
Ok(encoded)
})
}
/// Run the command.
pub async fn run(mut self) -> anyhow::Result<()> {
println!("{:?}", self.encode()?);
Ok(())
}
}
/// Prepare the call to be passed to [`CliEncodeCall::encode_call`].
///
/// This function will fill in all optional and missing pieces and will make sure that
/// values are converted to bridge-specific ones.
///
/// Most importantly, the method will fill-in [`bridge_instance_index`] parameter for
/// target-chain specific calls.
pub(crate) fn preprocess_call<Source: CliEncodeCall + CliChain, Target: CliEncodeCall>(
call: &mut Call,
bridge_instance: u8,
) {
match *call {
Call::Raw { .. } => {},
Call::Remark { ref remark_size, ref mut remark_payload } =>
if remark_payload.is_none() {
*remark_payload = Some(HexBytes(generate_remark_payload(
remark_size,
compute_maximal_message_arguments_size(
Source::max_extrinsic_size(),
Target::max_extrinsic_size(),
),
)));
},
Call::Transfer { ref mut recipient, .. } => {
recipient.enforce_chain::<Source>();
},
Call::BridgeSendMessage { ref mut bridge_instance_index, .. } => {
*bridge_instance_index = bridge_instance;
},
};
}
fn generate_remark_payload(
remark_size: &Option<ExplicitOrMaximal<usize>>,
maximal_allowed_size: u32,
) -> Vec<u8> {
match remark_size {
Some(ExplicitOrMaximal::Explicit(remark_size)) => vec![0; *remark_size],
Some(ExplicitOrMaximal::Maximal) => vec![0; maximal_allowed_size as _],
None => format!(
"Unix time: {}",
std::time::SystemTime::now()
.duration_since(std::time::SystemTime::UNIX_EPOCH)
.unwrap_or_default()
.as_secs(),
)
.as_bytes()
.to_vec(),
}
}
pub(crate) fn compute_maximal_message_arguments_size(
maximal_source_extrinsic_size: u32,
maximal_target_extrinsic_size: u32,
) -> u32 {
// assume that both signed extensions and other arguments fit 1KB
let service_tx_bytes_on_source_chain = 1024;
let maximal_source_extrinsic_size =
maximal_source_extrinsic_size - service_tx_bytes_on_source_chain;
let maximal_call_size = bridge_runtime_common::messages::target::maximal_incoming_message_size(
maximal_target_extrinsic_size,
);
let maximal_call_size = if maximal_call_size > maximal_source_extrinsic_size {
maximal_source_extrinsic_size
} else {
maximal_call_size
};
// bytes in Call encoding that are used to encode everything except arguments
let service_bytes = 1 + 1 + 4;
maximal_call_size - service_bytes
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cli::send_message::SendMessage;
#[test]
fn should_encode_transfer_call() {
// given
let mut encode_call = EncodeCall::from_iter(vec![
"encode-call",
"rialto-to-millau",
"transfer",
"--amount",
"12345",
"--recipient",
"5sauUXUfPjmwxSgmb3tZ5d6yx24eZX4wWJ2JtVUBaQqFbvEU",
]);
// when
let hex = encode_call.encode().unwrap();
// then
assert_eq!(
format!("{:?}", hex),
"0x040000d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27de5c0"
);
}
#[test]
fn should_encode_remark_with_default_payload() {
// given
let mut encode_call =
EncodeCall::from_iter(vec!["encode-call", "rialto-to-millau", "remark"]);
// when
let hex = encode_call.encode().unwrap();
// then
assert!(format!("{:?}", hex).starts_with("0x000154556e69782074696d653a"));
}
#[test]
fn should_encode_remark_with_explicit_payload() {
// given
let mut encode_call = EncodeCall::from_iter(vec![
"encode-call",
"rialto-to-millau",
"remark",
"--remark-payload",
"1234",
]);
// when
let hex = encode_call.encode().unwrap();
// then
assert_eq!(format!("{:?}", hex), "0x0001081234");
}
#[test]
fn should_encode_remark_with_size() {
// given
let mut encode_call = EncodeCall::from_iter(vec![
"encode-call",
"rialto-to-millau",
"remark",
"--remark-size",
"12",
]);
// when
let hex = encode_call.encode().unwrap();
// then
assert_eq!(format!("{:?}", hex), "0x000130000000000000000000000000");
}
#[test]
fn should_disallow_both_payload_and_size() {
// when
let err = EncodeCall::from_iter_safe(vec![
"encode-call",
"rialto-to-millau",
"remark",
"--remark-payload",
"1234",
"--remark-size",
"12",
])
.unwrap_err();
// then
assert_eq!(err.kind, structopt::clap::ErrorKind::ArgumentConflict);
let info = err.info.unwrap();
assert!(
info.contains(&"remark-payload".to_string()) |
info.contains(&"remark-size".to_string())
)
}
#[test]
fn should_encode_raw_call() {
// given
let mut encode_call = EncodeCall::from_iter(vec![
"encode-call",
"rialto-to-millau",
"raw",
"040000d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27de5c0",
]);
// when
let hex = encode_call.encode().unwrap();
// then
assert_eq!(
format!("{:?}", hex),
"0x040000d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27de5c0"
);
}
#[async_std::test]
async fn should_encode_bridge_send_message_call() {
// given
let encode_message = SendMessage::from_iter(vec![
"send-message",
"millau-to-rialto",
"--source-port",
"10946",
"--source-signer",
"//Alice",
"--target-signer",
"//Alice",
"--origin",
"Target",
"remark",
])
.encode_payload()
.await
.unwrap();
let mut encode_call = EncodeCall::from_iter(vec![
"encode-call",
"rialto-to-millau",
"bridge-send-message",
"--fee",
"12345",
"--payload",
format!("{:}", &HexBytes::encode(&encode_message)).as_str(),
]);
// when
let call_hex = encode_call.encode().unwrap();
// then
assert!(format!("{:?}", call_hex).starts_with(
"0x0f030000000001000000000000000000000001d43593c715fdd31c61141abd04a99fd6822c8558854cc\
de39a5684e7a56da27d01d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01"
))
}
}
@@ -14,107 +14,80 @@
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use crate::{
cli::{bridge::FullBridge, AccountId, CliChain, HexBytes},
select_full_bridge,
};
use frame_support::weights::Weight;
use crate::cli::{ExplicitOrMaximal, HexBytes};
use bp_messages::LaneId;
use bp_runtime::EncodedOrDecodedCall;
use relay_substrate_client::Chain;
use structopt::StructOpt;
use strum::VariantNames;
/// Generic message payload.
/// All possible messages that may be delivered to generic Substrate chain.
///
/// Note this enum may be used in the context of both Source (as part of `encode-call`)
/// and Target chain (as part of `encode-message/send-message`).
#[derive(StructOpt, Debug, PartialEq, Eq)]
pub enum MessagePayload {
/// Raw, SCALE-encoded `MessagePayload`.
pub enum Message {
/// Raw bytes for the message.
Raw {
/// Hex-encoded SCALE data.
/// Raw message bytes.
data: HexBytes,
},
/// Construct message to send over the bridge.
Call {
/// Message details.
#[structopt(flatten)]
call: crate::cli::encode_call::Call,
/// SS58 encoded Source account that will send the payload.
#[structopt(long)]
sender: AccountId,
/// Weight of the call.
///
/// It must be specified if the chain runtime is not bundled with the relay, or if
/// you want to override bundled weight.
#[structopt(long)]
dispatch_weight: Option<Weight>,
/// Message with given size.
Sized {
/// Sized of the message.
size: ExplicitOrMaximal<u32>,
},
}
/// A `MessagePayload` to encode.
#[derive(StructOpt)]
pub struct EncodeMessage {
/// A bridge instance to initialize.
#[structopt(possible_values = FullBridge::VARIANTS, case_insensitive = true)]
bridge: FullBridge,
#[structopt(flatten)]
payload: MessagePayload,
/// Raw, SCALE-encoded message payload used in expected deployment.
pub type RawMessage = Vec<u8>;
pub trait CliEncodeMessage: Chain {
/// Encode a send message call.
fn encode_send_message_call(
lane: LaneId,
message: RawMessage,
fee: Self::Balance,
bridge_instance_index: u8,
) -> anyhow::Result<EncodedOrDecodedCall<Self::Call>>;
}
impl EncodeMessage {
/// Run the command.
pub fn encode(self) -> anyhow::Result<HexBytes> {
select_full_bridge!(self.bridge, {
let payload =
Source::encode_message(self.payload).map_err(|e| anyhow::format_err!("{}", e))?;
Ok(HexBytes::encode(&payload))
})
}
/// Run the command.
pub async fn run(self) -> anyhow::Result<()> {
let payload = self.encode()?;
println!("{:?}", payload);
Ok(())
}
/// Encode message payload passed through CLI flags.
pub(crate) fn encode_message<Source: Chain, Target: Chain>(
message: &Message,
) -> anyhow::Result<RawMessage> {
Ok(match message {
Message::Raw { ref data } => data.0.clone(),
Message::Sized { ref size } => match *size {
ExplicitOrMaximal::Explicit(size) => vec![42; size as usize],
ExplicitOrMaximal::Maximal => {
let maximal_size = compute_maximal_message_size(
Source::max_extrinsic_size(),
Target::max_extrinsic_size(),
);
vec![42; maximal_size as usize]
},
},
})
}
#[cfg(test)]
mod tests {
use super::*;
use sp_core::crypto::Ss58Codec;
/// Compute maximal message size, given max extrinsic size at source and target chains.
pub(crate) fn compute_maximal_message_size(
maximal_source_extrinsic_size: u32,
maximal_target_extrinsic_size: u32,
) -> u32 {
// assume that both signed extensions and other arguments fit 1KB
let service_tx_bytes_on_source_chain = 1024;
let maximal_source_extrinsic_size =
maximal_source_extrinsic_size - service_tx_bytes_on_source_chain;
let maximal_message_size =
bridge_runtime_common::messages::target::maximal_incoming_message_size(
maximal_target_extrinsic_size,
);
let maximal_message_size = if maximal_message_size > maximal_source_extrinsic_size {
maximal_source_extrinsic_size
} else {
maximal_message_size
};
#[test]
fn should_encode_raw_message() {
// given
let msg = "01000000e88514000000000002d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d003c040130000000000000000000000000";
let encode_message =
EncodeMessage::from_iter(vec!["encode-message", "rialto-to-millau", "raw", msg]);
// when
let hex = encode_message.encode().unwrap();
// then
assert_eq!(format!("{:?}", hex), format!("0x{}", msg));
}
#[test]
fn should_encode_remark_with_size() {
// given
let sender = sp_keyring::AccountKeyring::Alice.to_account_id().to_ss58check();
let encode_message = EncodeMessage::from_iter(vec![
"encode-message",
"rialto-to-millau",
"call",
"--sender",
&sender,
"--dispatch-weight",
"42",
"remark",
"--remark-size",
"12",
]);
// when
let hex = encode_message.encode().unwrap();
// then
assert_eq!(format!("{:?}", hex), "0x010000002a0000000000000002d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d003c000130000000000000000000000000");
}
maximal_message_size
}
@@ -17,7 +17,7 @@
use crate::{
cli::{
bridge::FullBridge, relay_headers_and_messages::CONVERSION_RATE_ALLOWED_DIFFERENCE_RATIO,
Balance, CliChain, HexBytes, HexLaneId, SourceConnectionParams,
Balance, HexBytes, HexLaneId, SourceConnectionParams,
},
select_full_bridge,
};
@@ -48,7 +48,7 @@ pub struct EstimateFee {
conversion_rate_override: Option<ConversionRateOverride>,
/// Payload to send over the bridge.
#[structopt(flatten)]
payload: crate::cli::encode_message::MessagePayload,
payload: crate::cli::encode_message::Message,
}
/// A way to override conversion rate between bridge tokens.
@@ -82,8 +82,8 @@ impl EstimateFee {
select_full_bridge!(bridge, {
let source_client = source.to_client::<Source>().await?;
let lane = lane.into();
let payload =
Source::encode_message(payload).map_err(|e| anyhow::format_err!("{:?}", e))?;
let payload = crate::cli::encode_message::encode_message::<Source, Target>(&payload)
.map_err(|e| anyhow::format_err!("{:?}", e))?;
let fee = estimate_message_delivery_and_dispatch_fee::<Source, Target, _>(
&source_client,
@@ -219,14 +219,10 @@ async fn do_estimate_message_delivery_and_dispatch_fee<Source: Chain, P: Encode>
#[cfg(test)]
mod tests {
use super::*;
use crate::cli::{encode_call, RuntimeVersionType, SourceRuntimeVersionParams};
use sp_core::crypto::Ss58Codec;
use crate::cli::{RuntimeVersionType, SourceRuntimeVersionParams};
#[test]
fn should_parse_cli_options() {
// given
let alice = sp_keyring::AccountKeyring::Alice.to_account_id().to_ss58check();
// when
let res = EstimateFee::from_iter(vec![
"estimate_fee",
@@ -235,13 +231,7 @@ mod tests {
"1234",
"--conversion-rate-override",
"42.5",
"call",
"--sender",
&alice,
"--dispatch-weight",
"42",
"remark",
"--remark-payload",
"raw",
"1234",
]);
@@ -262,13 +252,8 @@ mod tests {
source_transaction_version: None,
}
},
payload: crate::cli::encode_message::MessagePayload::Call {
sender: alice.parse().unwrap(),
call: encode_call::Call::Remark {
remark_payload: Some(HexBytes(vec![0x12, 0x34])),
remark_size: None,
},
dispatch_weight: Some(42),
payload: crate::cli::encode_message::Message::Raw {
data: HexBytes(vec![0x12, 0x34])
}
}
);
+2 -110
View File
@@ -20,19 +20,16 @@ use std::convert::TryInto;
use codec::{Decode, Encode};
use relay_substrate_client::ChainRuntimeVersion;
use sp_runtime::app_crypto::Ss58Codec;
use structopt::{clap::arg_enum, StructOpt};
use strum::{EnumString, EnumVariantNames};
use bp_messages::LaneId;
pub(crate) mod bridge;
pub(crate) mod encode_call;
pub(crate) mod encode_message;
pub(crate) mod estimate_fee;
pub(crate) mod send_message;
mod derive_account;
mod init_bridge;
mod register_parachain;
mod reinit_bridge;
@@ -40,7 +37,6 @@ mod relay_headers;
mod relay_headers_and_messages;
mod relay_messages;
mod resubmit_transactions;
mod swap_tokens;
/// Parse relay CLI args.
pub fn parse_args() -> Command {
@@ -83,25 +79,10 @@ pub enum Command {
/// The message is being sent to the source chain, delivered to the target chain and dispatched
/// there.
SendMessage(send_message::SendMessage),
/// Generate SCALE-encoded `Call` for choosen network.
///
/// The call can be used either as message payload or can be wrapped into a transaction
/// and executed on the chain directly.
EncodeCall(encode_call::EncodeCall),
/// Generate SCALE-encoded `MessagePayload` object that can be sent over selected bridge.
///
/// The `MessagePayload` can be then fed to `Messages::send_message` function and sent over
/// the bridge.
EncodeMessage(encode_message::EncodeMessage),
/// Estimate Delivery and Dispatch Fee required for message submission to messages pallet.
EstimateFee(estimate_fee::EstimateFee),
/// Given a source chain `AccountId`, derive the corresponding `AccountId` for the target
/// chain.
DeriveAccount(derive_account::DeriveAccount),
/// Resubmit transactions with increased tip if they are stalled.
ResubmitTransactions(resubmit_transactions::ResubmitTransactions),
/// Swap tokens using token-swap bridge.
SwapTokens(swap_tokens::SwapTokens),
/// Register parachain.
RegisterParachain(register_parachain::RegisterParachain),
}
@@ -134,12 +115,8 @@ impl Command {
Self::InitBridge(arg) => arg.run().await?,
Self::ReinitBridge(arg) => arg.run().await?,
Self::SendMessage(arg) => arg.run().await?,
Self::EncodeCall(arg) => arg.run().await?,
Self::EncodeMessage(arg) => arg.run().await?,
Self::EstimateFee(arg) => arg.run().await?,
Self::DeriveAccount(arg) => arg.run().await?,
Self::ResubmitTransactions(arg) => arg.run().await?,
Self::SwapTokens(arg) => arg.run().await?,
Self::RegisterParachain(arg) => arg.run().await?,
}
Ok(())
@@ -184,66 +161,7 @@ impl Balance {
}
}
/// Generic account id with custom parser.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AccountId {
account: sp_runtime::AccountId32,
ss58_format: sp_core::crypto::Ss58AddressFormat,
}
impl std::fmt::Display for AccountId {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(fmt, "{}", self.account.to_ss58check_with_version(self.ss58_format))
}
}
impl std::str::FromStr for AccountId {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let (account, ss58_format) = sp_runtime::AccountId32::from_ss58check_with_version(s)
.map_err(|err| format!("Unable to decode SS58 address: {:?}", err))?;
Ok(Self { account, ss58_format })
}
}
const SS58_FORMAT_PROOF: &str = "u16 -> Ss58Format is infallible; qed";
impl AccountId {
/// Create new SS58-formatted address from raw account id.
pub fn from_raw<T: CliChain>(account: sp_runtime::AccountId32) -> Self {
Self { account, ss58_format: T::ss58_format().try_into().expect(SS58_FORMAT_PROOF) }
}
/// Enforces formatting account to be for given [`CliChain`] type.
///
/// This will change the `ss58format` of the account to match the requested one.
/// Note that a warning will be produced in case the current format does not match
/// the requested one, but the conversion always succeeds.
pub fn enforce_chain<T: CliChain>(&mut self) {
let original = self.clone();
self.ss58_format = T::ss58_format().try_into().expect(SS58_FORMAT_PROOF);
log::debug!("{} SS58 format: {} (RAW: {})", self, self.ss58_format, self.account);
if original.ss58_format != self.ss58_format {
log::warn!(
target: "bridge",
"Address {} does not seem to match {}'s SS58 format (got: {}, expected: {}).\nConverted to: {}",
original,
T::NAME,
original.ss58_format,
self.ss58_format,
self,
)
}
}
/// Returns the raw (no SS58-prefixed) account id.
pub fn raw_id(&self) -> sp_runtime::AccountId32 {
self.account.clone()
}
}
/// Bridge-supported network definition.
// Bridge-supported network definition.
///
/// Used to abstract away CLI commands.
pub trait CliChain: relay_substrate_client::Chain {
@@ -262,11 +180,6 @@ pub trait CliChain: relay_substrate_client::Chain {
/// Numeric value of SS58 format.
fn ss58_format() -> u16;
/// Construct message payload to be sent over the bridge.
fn encode_message(
message: crate::cli::encode_message::MessagePayload,
) -> anyhow::Result<Self::MessagePayload>;
}
/// Lane id.
@@ -623,29 +536,8 @@ declare_chain_options!(Parachain, parachain);
#[cfg(test)]
mod tests {
use std::str::FromStr;
use sp_core::Pair;
use super::*;
#[test]
fn should_format_addresses_with_ss58_format() {
// given
let rialto1 = "5sauUXUfPjmwxSgmb3tZ5d6yx24eZX4wWJ2JtVUBaQqFbvEU";
let rialto2 = "5rERgaT1Z8nM3et2epA5i1VtEBfp5wkhwHtVE8HK7BRbjAH2";
let millau1 = "752paRyW1EGfq9YLTSSqcSJ5hqnBDidBmaftGhBo8fy6ypW9";
let millau2 = "74GNQjmkcfstRftSQPJgMREchqHM56EvAUXRc266cZ1NYVW5";
let expected = vec![rialto1, rialto2, millau1, millau2];
// when
let parsed = expected.iter().map(|s| AccountId::from_str(s).unwrap()).collect::<Vec<_>>();
let actual = parsed.iter().map(|a| format!("{}", a)).collect::<Vec<_>>();
assert_eq!(actual, expected)
}
use sp_core::Pair;
#[test]
fn hex_bytes_display_matches_from_str_for_clap() {
@@ -15,8 +15,7 @@
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use crate::cli::{
swap_tokens::wait_until_transaction_is_finalized, Balance, ParachainConnectionParams,
RelaychainConnectionParams, RelaychainSigningParams,
Balance, ParachainConnectionParams, RelaychainConnectionParams, RelaychainSigningParams,
};
use codec::Encode;
@@ -30,7 +29,8 @@ use polkadot_runtime_common::{
};
use polkadot_runtime_parachains::paras::ParaLifecycle;
use relay_substrate_client::{
AccountIdOf, CallOf, Chain, Client, SignParam, TransactionSignScheme, UnsignedTransaction,
AccountIdOf, CallOf, Chain, Client, HashOf, SignParam, Subscription, TransactionSignScheme,
TransactionStatusOf, UnsignedTransaction,
};
use rialto_runtime::SudoCall;
use sp_core::{
@@ -270,6 +270,46 @@ impl RegisterParachain {
}
}
/// Wait until transaction is included into finalized block.
///
/// Returns the hash of the finalized block with transaction.
pub(crate) async fn wait_until_transaction_is_finalized<C: Chain>(
subscription: Subscription<TransactionStatusOf<C>>,
) -> anyhow::Result<HashOf<C>> {
loop {
let transaction_status = subscription.next().await?;
match transaction_status {
Some(TransactionStatusOf::<C>::FinalityTimeout(_)) |
Some(TransactionStatusOf::<C>::Usurped(_)) |
Some(TransactionStatusOf::<C>::Dropped) |
Some(TransactionStatusOf::<C>::Invalid) |
None =>
return Err(anyhow::format_err!(
"We've been waiting for finalization of {} transaction, but it now has the {:?} status",
C::NAME,
transaction_status,
)),
Some(TransactionStatusOf::<C>::Finalized(block_hash)) => {
log::trace!(
target: "bridge",
"{} transaction has been finalized at block {}",
C::NAME,
block_hash,
);
return Ok(block_hash)
},
_ => {
log::trace!(
target: "bridge",
"Received intermediate status of {} transaction: {:?}",
C::NAME,
transaction_status,
);
},
}
}
}
/// Wait until parachain state is changed.
async fn wait_para_state<Relaychain: Chain>(
relay_client: &Client<Relaychain>,
@@ -20,7 +20,7 @@ use crate::{
polkadot_headers_to_kusama::PolkadotFinalityToKusama,
},
cli::{
swap_tokens::wait_until_transaction_is_finalized, SourceConnectionParams,
register_parachain::wait_until_transaction_is_finalized, SourceConnectionParams,
TargetConnectionParams, TargetSigningParams,
},
};
@@ -16,18 +16,14 @@
use crate::cli::{
bridge::FullBridge,
encode_call::{self, CliEncodeCall},
encode_message::{self, CliEncodeMessage},
estimate_fee::{estimate_message_delivery_and_dispatch_fee, ConversionRateOverride},
Balance, ExplicitOrMaximal, HexBytes, HexLaneId, Origins, SourceConnectionParams,
SourceSigningParams, TargetConnectionParams, TargetSigningParams,
Balance, HexBytes, HexLaneId, SourceConnectionParams, SourceSigningParams,
};
use bp_message_dispatch::{CallOrigin, MessagePayload};
use bp_runtime::Chain as _;
use codec::Encode;
use frame_support::weights::Weight;
use relay_substrate_client::{Chain, SignParam, TransactionSignScheme, UnsignedTransaction};
use sp_core::{Bytes, Pair};
use sp_runtime::{traits::IdentifyAccount, AccountId32, MultiSignature, MultiSigner};
use sp_runtime::AccountId32;
use std::fmt::Debug;
use structopt::StructOpt;
use strum::{EnumString, EnumVariantNames, VariantNames};
@@ -61,8 +57,6 @@ pub struct SendMessage {
source: SourceConnectionParams,
#[structopt(flatten)]
source_sign: SourceSigningParams,
#[structopt(flatten)]
target_sign: TargetSigningParams,
/// Hex-encoded lane id. Defaults to `00000000`.
#[structopt(long, default_value = "00000000")]
lane: HexLaneId,
@@ -72,104 +66,20 @@ pub struct SendMessage {
/// your message won't be relayed.
#[structopt(long)]
conversion_rate_override: Option<ConversionRateOverride>,
/// Where dispatch fee is paid?
#[structopt(
long,
possible_values = DispatchFeePayment::VARIANTS,
case_insensitive = true,
default_value = "at-source-chain",
)]
dispatch_fee_payment: DispatchFeePayment,
/// Dispatch weight of the message. If not passed, determined automatically.
#[structopt(long)]
dispatch_weight: Option<ExplicitOrMaximal<Weight>>,
/// Delivery and dispatch fee in source chain base currency units. If not passed, determined
/// automatically.
#[structopt(long)]
fee: Option<Balance>,
/// Message type.
#[structopt(subcommand)]
message: crate::cli::encode_call::Call,
/// The origin to use when dispatching the message on the target chain. Defaults to
/// `SourceAccount`.
#[structopt(long, possible_values = &Origins::variants(), default_value = "Source")]
origin: Origins,
// Normally we don't need to connect to the target chain to send message. But for testing
// we may want to use **actual** `spec_version` of the target chain when composing a message.
// Then we'll need to read version from the target chain node.
#[structopt(flatten)]
target: TargetConnectionParams,
message: crate::cli::encode_message::Message,
}
impl SendMessage {
pub async fn encode_payload(
&mut self,
) -> anyhow::Result<MessagePayload<AccountId32, MultiSigner, MultiSignature, Vec<u8>>> {
crate::select_full_bridge!(self.bridge, {
let SendMessage {
source_sign,
target_sign,
ref mut message,
dispatch_fee_payment,
dispatch_weight,
origin,
bridge,
..
} = self;
let source_sign = source_sign.to_keypair::<Source>()?;
encode_call::preprocess_call::<Source, Target>(message, bridge.bridge_instance_index());
let target_call = Target::encode_call(message)?;
let target_spec_version = self.target.selected_chain_spec_version::<Target>().await?;
let payload = {
let target_call_weight = prepare_call_dispatch_weight(
dispatch_weight,
|| {
Ok(ExplicitOrMaximal::Explicit(
Target::get_dispatch_info(&target_call)?.weight,
))
},
compute_maximal_message_dispatch_weight(Target::max_extrinsic_weight()),
)?;
let source_sender_public: MultiSigner = source_sign.public().into();
let source_account_id = source_sender_public.into_account();
message_payload(
target_spec_version,
target_call_weight,
match origin {
Origins::Source => CallOrigin::SourceAccount(source_account_id),
Origins::Target => {
let target_sign = target_sign.to_keypair::<Target>()?;
let digest = account_ownership_digest(
&target_call,
source_account_id.clone(),
target_spec_version,
);
let target_origin_public = target_sign.public();
let digest_signature = target_sign.sign(&digest);
CallOrigin::TargetAccount(
source_account_id,
target_origin_public.into(),
digest_signature.into(),
)
},
},
&target_call,
*dispatch_fee_payment,
)
};
Ok(payload)
})
}
/// Run the command.
pub async fn run(mut self) -> anyhow::Result<()> {
pub async fn run(self) -> anyhow::Result<()> {
crate::select_full_bridge!(self.bridge, {
let payload = self.encode_payload().await?;
let payload = encode_message::encode_message::<Source, Target>(&self.message)?;
let source_client = self.source.to_client::<Source>().await?;
let source_sign = self.source_sign.to_keypair::<Source>()?;
@@ -189,14 +99,13 @@ impl SendMessage {
.await? as _,
),
};
let dispatch_weight = payload.weight;
let payload_len = payload.encode().len();
let send_message_call = Source::encode_call(&encode_call::Call::BridgeSendMessage {
bridge_instance_index: self.bridge.bridge_instance_index(),
lane: self.lane,
payload: HexBytes::encode(&payload),
fee,
})?;
let send_message_call = Source::encode_send_message_call(
self.lane.0,
payload,
fee.cast().into(),
self.bridge.bridge_instance_index(),
)?;
let source_genesis_hash = *source_client.genesis_hash();
let (spec_version, transaction_version) =
@@ -228,11 +137,10 @@ impl SendMessage {
log::info!(
target: "bridge",
"Sending message to {}. Lane: {:?}. Size: {}. Dispatch weight: {}. Fee: {}",
"Sending message to {}. Lane: {:?}. Size: {}. Fee: {}",
Target::NAME,
lane,
payload_len,
dispatch_weight,
fee,
);
log::info!(
@@ -260,66 +168,15 @@ impl SendMessage {
}
}
fn prepare_call_dispatch_weight(
user_specified_dispatch_weight: &Option<ExplicitOrMaximal<Weight>>,
weight_from_pre_dispatch_call: impl Fn() -> anyhow::Result<ExplicitOrMaximal<Weight>>,
maximal_allowed_weight: Weight,
) -> anyhow::Result<Weight> {
match user_specified_dispatch_weight
.clone()
.map(Ok)
.unwrap_or_else(weight_from_pre_dispatch_call)?
{
ExplicitOrMaximal::Explicit(weight) => Ok(weight),
ExplicitOrMaximal::Maximal => Ok(maximal_allowed_weight),
}
}
pub(crate) fn message_payload<SAccountId, TPublic, TSignature>(
spec_version: u32,
weight: Weight,
origin: CallOrigin<SAccountId, TPublic, TSignature>,
call: &impl Encode,
dispatch_fee_payment: DispatchFeePayment,
) -> MessagePayload<SAccountId, TPublic, TSignature, Vec<u8>>
where
SAccountId: Encode + Debug,
TPublic: Encode + Debug,
TSignature: Encode + Debug,
{
// Display nicely formatted call.
let payload = MessagePayload {
spec_version,
weight,
origin,
dispatch_fee_payment: dispatch_fee_payment.into(),
call: HexBytes::encode(call),
};
log::info!(target: "bridge", "Created Message Payload: {:#?}", payload);
log::info!(target: "bridge", "Encoded Message Payload: {:?}", HexBytes::encode(&payload));
// re-pack to return `Vec<u8>`
let MessagePayload { spec_version, weight, origin, dispatch_fee_payment, call } = payload;
MessagePayload { spec_version, weight, origin, dispatch_fee_payment, call: call.0 }
}
pub(crate) fn compute_maximal_message_dispatch_weight(maximal_extrinsic_weight: Weight) -> Weight {
bridge_runtime_common::messages::target::maximal_incoming_message_dispatch_weight(
maximal_extrinsic_weight,
)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cli::CliChain;
use hex_literal::hex;
use crate::cli::ExplicitOrMaximal;
#[async_std::test]
async fn send_remark_rialto_to_millau() {
#[test]
fn send_raw_rialto_to_millau() {
// given
let mut send_message = SendMessage::from_iter(vec![
let send_message = SendMessage::from_iter(vec![
"send-message",
"rialto-to-millau",
"--source-port",
@@ -328,117 +185,48 @@ mod tests {
"//Alice",
"--conversion-rate-override",
"0.75",
"remark",
"--remark-payload",
"1234",
"raw",
"dead",
]);
// when
let payload = send_message.encode_payload().await.unwrap();
// then
assert_eq!(send_message.bridge, FullBridge::RialtoToMillau);
assert_eq!(send_message.source.source_port, 1234);
assert_eq!(send_message.source_sign.source_signer, Some("//Alice".into()));
assert_eq!(
payload,
MessagePayload {
spec_version: relay_millau_client::Millau::RUNTIME_VERSION.spec_version,
weight: 0,
origin: CallOrigin::SourceAccount(
sp_keyring::AccountKeyring::Alice.to_account_id()
),
dispatch_fee_payment: bp_runtime::messages::DispatchFeePayment::AtSourceChain,
call: hex!("0001081234").to_vec(),
}
send_message.conversion_rate_override,
Some(ConversionRateOverride::Explicit(0.75))
);
}
#[async_std::test]
async fn send_remark_millau_to_rialto() {
// given
let mut send_message = SendMessage::from_iter(vec![
"send-message",
"millau-to-rialto",
"--source-port",
"1234",
"--source-signer",
"//Alice",
"--origin",
"Target",
"--target-signer",
"//Bob",
"--conversion-rate-override",
"metric",
"remark",
"--remark-payload",
"1234",
]);
// when
let payload = send_message.encode_payload().await.unwrap();
// then
// Since signatures are randomized we extract it from here and only check the rest.
let signature = match payload.origin {
CallOrigin::TargetAccount(_, _, ref sig) => sig.clone(),
_ => panic!("Unexpected `CallOrigin`: {:?}", payload),
};
assert_eq!(
payload,
MessagePayload {
spec_version: relay_millau_client::Millau::RUNTIME_VERSION.spec_version,
weight: 0,
origin: CallOrigin::TargetAccount(
sp_keyring::AccountKeyring::Alice.to_account_id(),
sp_keyring::AccountKeyring::Bob.into(),
signature,
),
dispatch_fee_payment: bp_runtime::messages::DispatchFeePayment::AtSourceChain,
call: hex!("0001081234").to_vec(),
}
send_message.message,
crate::cli::encode_message::Message::Raw { data: HexBytes(vec![0xDE, 0xAD]) }
);
}
#[test]
fn accepts_send_message_command_without_target_sign_options() {
fn send_sized_rialto_to_millau() {
// given
let send_message = SendMessage::from_iter_safe(vec![
let send_message = SendMessage::from_iter(vec![
"send-message",
"rialto-to-millau",
"--source-port",
"1234",
"--source-signer",
"//Alice",
"--origin",
"Target",
"remark",
"--remark-payload",
"1234",
"--conversion-rate-override",
"metric",
"sized",
"max",
]);
assert!(send_message.is_ok());
}
#[async_std::test]
async fn accepts_non_default_dispatch_fee_payment() {
// given
let mut send_message = SendMessage::from_iter(vec![
"send-message",
"rialto-to-millau",
"--source-port",
"1234",
"--source-signer",
"//Alice",
"--dispatch-fee-payment",
"at-target-chain",
"remark",
]);
// when
let payload = send_message.encode_payload().await.unwrap();
// then
assert_eq!(send_message.bridge, FullBridge::RialtoToMillau);
assert_eq!(send_message.source.source_port, 1234);
assert_eq!(send_message.source_sign.source_signer, Some("//Alice".into()));
assert_eq!(send_message.conversion_rate_override, Some(ConversionRateOverride::Metric));
assert_eq!(
payload.dispatch_fee_payment,
bp_runtime::messages::DispatchFeePayment::AtTargetChain
send_message.message,
crate::cli::encode_message::Message::Sized { size: ExplicitOrMaximal::Maximal }
);
}
}
@@ -1,869 +0,0 @@
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
//! Tokens swap using token-swap bridge pallet.
// TokenSwapBalances fields are never directly accessed, but the whole struct is printed
// to show token swap progress
#![allow(dead_code)]
use codec::Encode;
use num_traits::One;
use rand::random;
use structopt::StructOpt;
use strum::{EnumString, EnumVariantNames, VariantNames};
use frame_support::dispatch::GetDispatchInfo;
use relay_substrate_client::{
AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, CallOf, Chain, ChainWithBalances,
Client, Error as SubstrateError, HashOf, SignParam, SignatureOf, Subscription,
TransactionSignScheme, TransactionStatusOf, UnsignedTransaction,
};
use sp_core::{blake2_256, storage::StorageKey, Bytes, Pair, U256};
use sp_runtime::traits::{Convert, Header as HeaderT};
use crate::cli::{
estimate_fee::ConversionRateOverride, Balance, CliChain, SourceConnectionParams,
SourceSigningParams, TargetConnectionParams, TargetSigningParams,
};
/// Swap tokens.
#[derive(StructOpt, Debug, PartialEq)]
pub struct SwapTokens {
/// A bridge instance to use in token swap.
#[structopt(possible_values = SwapTokensBridge::VARIANTS, case_insensitive = true)]
bridge: SwapTokensBridge,
#[structopt(flatten)]
source: SourceConnectionParams,
#[structopt(flatten)]
source_sign: SourceSigningParams,
#[structopt(flatten)]
target: TargetConnectionParams,
#[structopt(flatten)]
target_sign: TargetSigningParams,
#[structopt(subcommand)]
swap_type: TokenSwapType,
/// Source chain balance that source signer wants to swap.
#[structopt(long)]
source_balance: Balance,
/// Target chain balance that target signer wants to swap.
#[structopt(long)]
target_balance: Balance,
/// A way to override conversion rate from target to source tokens.
///
/// If not specified, conversion rate from runtime storage is used. It may be obsolete and
/// your message won't be relayed.
#[structopt(long)]
target_to_source_conversion_rate_override: Option<ConversionRateOverride>,
/// A way to override conversion rate from source to target tokens.
///
/// If not specified, conversion rate from runtime storage is used. It may be obsolete and
/// your message won't be relayed.
#[structopt(long)]
source_to_target_conversion_rate_override: Option<ConversionRateOverride>,
}
/// Token swap type.
#[derive(StructOpt, Debug, PartialEq, Eq, Clone)]
pub enum TokenSwapType {
/// The `target_sign` is temporary and only have funds for single swap.
NoLock,
/// This swap type prevents `source_signer` from restarting the swap after it has been
/// completed.
LockUntilBlock {
/// Number of blocks before the swap expires.
#[structopt(long)]
blocks_before_expire: u32,
/// Unique swap nonce.
#[structopt(long)]
swap_nonce: Option<U256>,
},
}
/// Swap tokens bridge.
#[derive(Debug, EnumString, EnumVariantNames, PartialEq)]
#[strum(serialize_all = "kebab_case")]
pub enum SwapTokensBridge {
/// Use token-swap pallet deployed at Millau to swap tokens with Rialto.
MillauToRialto,
}
macro_rules! select_bridge {
($bridge: expr, $generic: tt) => {
match $bridge {
SwapTokensBridge::MillauToRialto => {
type Source = relay_millau_client::Millau;
type Target = relay_rialto_client::Rialto;
const SOURCE_SPEC_VERSION: u32 = millau_runtime::VERSION.spec_version;
const TARGET_SPEC_VERSION: u32 = rialto_runtime::VERSION.spec_version;
type FromSwapToThisAccountIdConverter = bp_rialto::AccountIdConverter;
use bp_millau::{
derive_account_from_rialto_id as derive_source_account_from_target_account,
TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_TARGET_TO_SOURCE_MESSAGE_FEE_METHOD,
WITH_RIALTO_TOKEN_SWAP_PALLET_NAME as TOKEN_SWAP_PALLET_NAME,
};
use bp_rialto::{
derive_account_from_millau_id as derive_target_account_from_source_account,
TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_SOURCE_TO_TARGET_MESSAGE_FEE_METHOD,
};
const SOURCE_CHAIN_ID: bp_runtime::ChainId = bp_runtime::MILLAU_CHAIN_ID;
const TARGET_CHAIN_ID: bp_runtime::ChainId = bp_runtime::RIALTO_CHAIN_ID;
const SOURCE_TO_TARGET_LANE_ID: bp_messages::LaneId = *b"swap";
const TARGET_TO_SOURCE_LANE_ID: bp_messages::LaneId = [0, 0, 0, 0];
$generic
},
}
};
}
impl SwapTokens {
/// Run the command.
pub async fn run(self) -> anyhow::Result<()> {
select_bridge!(self.bridge, {
let source_client = self.source.to_client::<Source>().await?;
let source_sign = self.source_sign.to_keypair::<Target>()?;
let target_client = self.target.to_client::<Target>().await?;
let target_sign = self.target_sign.to_keypair::<Target>()?;
let target_to_source_conversion_rate_override =
self.target_to_source_conversion_rate_override;
let source_to_target_conversion_rate_override =
self.source_to_target_conversion_rate_override;
// names of variables in this function are matching names used by the
// `pallet-bridge-token-swap`
// prepare token swap intention
let token_swap = self
.prepare_token_swap::<Source, Target>(&source_client, &source_sign, &target_sign)
.await?;
// group all accounts that will be used later
let accounts = TokenSwapAccounts {
source_account_at_bridged_chain: derive_target_account_from_source_account(
bp_runtime::SourceAccount::Account(
token_swap.source_account_at_this_chain.clone(),
),
),
target_account_at_this_chain: derive_source_account_from_target_account(
bp_runtime::SourceAccount::Account(
token_swap.target_account_at_bridged_chain.clone(),
),
),
source_account_at_this_chain: token_swap.source_account_at_this_chain.clone(),
target_account_at_bridged_chain: token_swap.target_account_at_bridged_chain.clone(),
swap_account: FromSwapToThisAccountIdConverter::convert(
token_swap.using_encoded(blake2_256).into(),
),
};
// account balances are used to demonstrate what's happening :)
let initial_balances =
read_account_balances(&accounts, &source_client, &target_client).await?;
// before calling something that may fail, log what we're trying to do
log::info!(target: "bridge", "Starting swap: {:?}", token_swap);
log::info!(target: "bridge", "Swap accounts: {:?}", accounts);
log::info!(target: "bridge", "Initial account balances: {:?}", initial_balances);
//
// Step 1: swap is created
//
// prepare `Currency::transfer` call that will happen at the target chain
let bridged_currency_transfer: CallOf<Target> = pallet_balances::Call::transfer {
dest: accounts.source_account_at_bridged_chain.clone().into(),
value: token_swap.target_balance_at_bridged_chain,
}
.into();
let bridged_currency_transfer_weight =
bridged_currency_transfer.get_dispatch_info().weight;
// sign message
let bridged_chain_spec_version = TARGET_SPEC_VERSION;
let signature_payload = pallet_bridge_dispatch::account_ownership_digest(
&bridged_currency_transfer,
&accounts.swap_account,
&bridged_chain_spec_version,
SOURCE_CHAIN_ID,
TARGET_CHAIN_ID,
);
let bridged_currency_transfer_signature: SignatureOf<Target> =
target_sign.sign(&signature_payload).into();
// prepare `create_swap` call
let target_public_at_bridged_chain: AccountPublicOf<Target> =
target_sign.public().into();
let swap_delivery_and_dispatch_fee =
crate::cli::estimate_fee::estimate_message_delivery_and_dispatch_fee::<
Source,
Target,
_,
>(
&source_client,
target_to_source_conversion_rate_override,
ESTIMATE_SOURCE_TO_TARGET_MESSAGE_FEE_METHOD,
SOURCE_TO_TARGET_LANE_ID,
bp_message_dispatch::MessagePayload {
spec_version: TARGET_SPEC_VERSION,
weight: bridged_currency_transfer_weight,
origin: bp_message_dispatch::CallOrigin::TargetAccount(
accounts.swap_account.clone(),
target_public_at_bridged_chain.clone(),
bridged_currency_transfer_signature.clone(),
),
dispatch_fee_payment:
bp_runtime::messages::DispatchFeePayment::AtTargetChain,
call: bridged_currency_transfer.encode(),
},
)
.await?;
let create_swap_call: CallOf<Source> = pallet_bridge_token_swap::Call::create_swap {
swap: token_swap.clone(),
swap_creation_params: Box::new(bp_token_swap::TokenSwapCreation {
target_public_at_bridged_chain,
swap_delivery_and_dispatch_fee,
bridged_chain_spec_version,
bridged_currency_transfer: bridged_currency_transfer.encode(),
bridged_currency_transfer_weight,
bridged_currency_transfer_signature,
}),
}
.into();
// start tokens swap
let source_genesis_hash = *source_client.genesis_hash();
let create_swap_signer = source_sign.clone();
let (spec_version, transaction_version) =
source_client.simple_runtime_version().await?;
let swap_created_at = wait_until_transaction_is_finalized::<Source>(
source_client
.submit_and_watch_signed_extrinsic(
accounts.source_account_at_this_chain.clone(),
move |_, transaction_nonce| {
Ok(Bytes(
Source::sign_transaction(SignParam {
spec_version,
transaction_version,
genesis_hash: source_genesis_hash,
signer: create_swap_signer,
era: relay_substrate_client::TransactionEra::immortal(),
unsigned: UnsignedTransaction::new(
create_swap_call.into(),
transaction_nonce,
),
})?
.encode(),
))
},
)
.await?,
)
.await?;
// read state of swap after it has been created
let token_swap_hash = token_swap.hash();
let token_swap_storage_key = bp_token_swap::storage_keys::pending_swaps_key(
TOKEN_SWAP_PALLET_NAME,
token_swap_hash,
);
match read_token_swap_state(&source_client, swap_created_at, &token_swap_storage_key)
.await?
{
Some(bp_token_swap::TokenSwapState::Started) => {
log::info!(target: "bridge", "Swap has been successfully started");
let intermediate_balances =
read_account_balances(&accounts, &source_client, &target_client).await?;
log::info!(target: "bridge", "Intermediate balances: {:?}", intermediate_balances);
},
Some(token_swap_state) =>
return Err(anyhow::format_err!(
"Fresh token swap has unexpected state: {:?}",
token_swap_state,
)),
None => return Err(anyhow::format_err!("Failed to start token swap")),
};
//
// Step 2: message is being relayed to the target chain and dispathed there
//
// wait until message is dispatched at the target chain and dispatch result delivered
// back to source chain
let token_swap_state = wait_until_token_swap_state_is_changed(
&source_client,
&token_swap_storage_key,
bp_token_swap::TokenSwapState::Started,
)
.await?;
let is_transfer_succeeded = match token_swap_state {
Some(bp_token_swap::TokenSwapState::Started) => {
unreachable!("wait_until_token_swap_state_is_changed only returns if state is not Started; qed",)
},
None =>
return Err(anyhow::format_err!("Fresh token swap has disappeared unexpectedly")),
Some(bp_token_swap::TokenSwapState::Confirmed) => {
log::info!(
target: "bridge",
"Transfer has been successfully dispatched at the target chain. Swap can be claimed",
);
true
},
Some(bp_token_swap::TokenSwapState::Failed) => {
log::info!(
target: "bridge",
"Transfer has been dispatched with an error at the target chain. Swap can be canceled",
);
false
},
};
// by this time: (1) token swap account has been created and (2) if transfer has been
// successfully dispatched, both target chain balances have changed
let intermediate_balances =
read_account_balances(&accounts, &source_client, &target_client).await?;
log::info!(target: "bridge", "Intermediate balances: {:?}", intermediate_balances);
// transfer has been dispatched, but we may need to wait until block where swap can be
// claimed/canceled
if let bp_token_swap::TokenSwapType::LockClaimUntilBlock(
ref last_available_block_number,
_,
) = token_swap.swap_type
{
wait_until_swap_unlocked(
&source_client,
last_available_block_number + BlockNumberOf::<Source>::one(),
)
.await?;
}
//
// Step 3: we may now claim or cancel the swap
//
if is_transfer_succeeded {
log::info!(target: "bridge", "Claiming the swap");
// prepare `claim_swap` message that will be sent over the bridge
let claim_swap_call: CallOf<Source> =
pallet_bridge_token_swap::Call::claim_swap { swap: token_swap }.into();
let claim_swap_message = bp_message_dispatch::MessagePayload {
spec_version: SOURCE_SPEC_VERSION,
weight: claim_swap_call.get_dispatch_info().weight,
origin: bp_message_dispatch::CallOrigin::SourceAccount(
accounts.target_account_at_bridged_chain.clone(),
),
dispatch_fee_payment: bp_runtime::messages::DispatchFeePayment::AtSourceChain,
call: claim_swap_call.encode(),
};
let claim_swap_delivery_and_dispatch_fee =
crate::cli::estimate_fee::estimate_message_delivery_and_dispatch_fee::<
Target,
Source,
_,
>(
&target_client,
source_to_target_conversion_rate_override,
ESTIMATE_TARGET_TO_SOURCE_MESSAGE_FEE_METHOD,
TARGET_TO_SOURCE_LANE_ID,
claim_swap_message.clone(),
)
.await?;
let send_message_call: CallOf<Target> =
pallet_bridge_messages::Call::send_message {
lane_id: TARGET_TO_SOURCE_LANE_ID,
payload: claim_swap_message,
delivery_and_dispatch_fee: claim_swap_delivery_and_dispatch_fee,
}
.into();
// send `claim_swap` message
let target_genesis_hash = *target_client.genesis_hash();
let (spec_version, transaction_version) =
target_client.simple_runtime_version().await?;
let _ = wait_until_transaction_is_finalized::<Target>(
target_client
.submit_and_watch_signed_extrinsic(
accounts.target_account_at_bridged_chain.clone(),
move |_, transaction_nonce| {
Ok(Bytes(
Target::sign_transaction(SignParam {
spec_version,
transaction_version,
genesis_hash: target_genesis_hash,
signer: target_sign,
era: relay_substrate_client::TransactionEra::immortal(),
unsigned: UnsignedTransaction::new(
send_message_call.into(),
transaction_nonce,
),
})?
.encode(),
))
},
)
.await?,
)
.await?;
// wait until swap state is updated
let token_swap_state = wait_until_token_swap_state_is_changed(
&source_client,
&token_swap_storage_key,
bp_token_swap::TokenSwapState::Confirmed,
)
.await?;
if token_swap_state != None {
return Err(anyhow::format_err!(
"Confirmed token swap state has been changed to {:?} unexpectedly",
token_swap_state
))
}
} else {
log::info!(target: "bridge", "Cancelling the swap");
let cancel_swap_call: CallOf<Source> =
pallet_bridge_token_swap::Call::cancel_swap { swap: token_swap.clone() }.into();
let (spec_version, transaction_version) =
source_client.simple_runtime_version().await?;
let _ = wait_until_transaction_is_finalized::<Source>(
source_client
.submit_and_watch_signed_extrinsic(
accounts.source_account_at_this_chain.clone(),
move |_, transaction_nonce| {
Ok(Bytes(
Source::sign_transaction(SignParam {
spec_version,
transaction_version,
genesis_hash: source_genesis_hash,
signer: source_sign,
era: relay_substrate_client::TransactionEra::immortal(),
unsigned: UnsignedTransaction::new(
cancel_swap_call.into(),
transaction_nonce,
),
})?
.encode(),
))
},
)
.await?,
)
.await?;
}
// print final balances
let final_balances =
read_account_balances(&accounts, &source_client, &target_client).await?;
log::info!(target: "bridge", "Final account balances: {:?}", final_balances);
Ok(())
})
}
/// Prepare token swap intention.
async fn prepare_token_swap<Source: CliChain, Target: CliChain>(
&self,
source_client: &Client<Source>,
source_sign: &Source::KeyPair,
target_sign: &Target::KeyPair,
) -> anyhow::Result<
bp_token_swap::TokenSwap<
BlockNumberOf<Source>,
BalanceOf<Source>,
AccountIdOf<Source>,
BalanceOf<Target>,
AccountIdOf<Target>,
>,
>
where
AccountIdOf<Source>: From<<Source::KeyPair as Pair>::Public>,
AccountIdOf<Target>: From<<Target::KeyPair as Pair>::Public>,
BalanceOf<Source>: From<u64>,
BalanceOf<Target>: From<u64>,
{
// accounts that are directly controlled by participants
let source_account_at_this_chain: AccountIdOf<Source> = source_sign.public().into();
let target_account_at_bridged_chain: AccountIdOf<Target> = target_sign.public().into();
// balances that we're going to swap
let source_balance_at_this_chain: BalanceOf<Source> = self.source_balance.cast().into();
let target_balance_at_bridged_chain: BalanceOf<Target> = self.target_balance.cast().into();
// prepare token swap intention
Ok(bp_token_swap::TokenSwap {
swap_type: self.prepare_token_swap_type(source_client).await?,
source_balance_at_this_chain,
source_account_at_this_chain: source_account_at_this_chain.clone(),
target_balance_at_bridged_chain,
target_account_at_bridged_chain: target_account_at_bridged_chain.clone(),
})
}
/// Prepare token swap type.
async fn prepare_token_swap_type<Source: Chain>(
&self,
source_client: &Client<Source>,
) -> anyhow::Result<bp_token_swap::TokenSwapType<BlockNumberOf<Source>>> {
match self.swap_type {
TokenSwapType::NoLock =>
Ok(bp_token_swap::TokenSwapType::TemporaryTargetAccountAtBridgedChain),
TokenSwapType::LockUntilBlock { blocks_before_expire, ref swap_nonce } => {
let blocks_before_expire: BlockNumberOf<Source> = blocks_before_expire.into();
let current_source_block_number = *source_client.best_header().await?.number();
Ok(bp_token_swap::TokenSwapType::LockClaimUntilBlock(
current_source_block_number + blocks_before_expire,
swap_nonce.unwrap_or_else(|| {
U256::from(random::<u128>()).overflowing_mul(U256::from(random::<u128>())).0
}),
))
},
}
}
}
/// Accounts that are participating in the swap.
#[derive(Debug)]
struct TokenSwapAccounts<ThisAccountId, BridgedAccountId> {
source_account_at_this_chain: ThisAccountId,
source_account_at_bridged_chain: BridgedAccountId,
target_account_at_bridged_chain: BridgedAccountId,
target_account_at_this_chain: ThisAccountId,
swap_account: ThisAccountId,
}
/// Swap accounts balances.
#[derive(Debug)]
struct TokenSwapBalances<ThisBalance, BridgedBalance> {
source_account_at_this_chain_balance: Option<ThisBalance>,
source_account_at_bridged_chain_balance: Option<BridgedBalance>,
target_account_at_bridged_chain_balance: Option<BridgedBalance>,
target_account_at_this_chain_balance: Option<ThisBalance>,
swap_account_balance: Option<ThisBalance>,
}
/// Read swap accounts balances.
async fn read_account_balances<Source: ChainWithBalances, Target: ChainWithBalances>(
accounts: &TokenSwapAccounts<AccountIdOf<Source>, AccountIdOf<Target>>,
source_client: &Client<Source>,
target_client: &Client<Target>,
) -> anyhow::Result<TokenSwapBalances<BalanceOf<Source>, BalanceOf<Target>>> {
Ok(TokenSwapBalances {
source_account_at_this_chain_balance: read_account_balance(
source_client,
&accounts.source_account_at_this_chain,
)
.await?,
source_account_at_bridged_chain_balance: read_account_balance(
target_client,
&accounts.source_account_at_bridged_chain,
)
.await?,
target_account_at_bridged_chain_balance: read_account_balance(
target_client,
&accounts.target_account_at_bridged_chain,
)
.await?,
target_account_at_this_chain_balance: read_account_balance(
source_client,
&accounts.target_account_at_this_chain,
)
.await?,
swap_account_balance: read_account_balance(source_client, &accounts.swap_account).await?,
})
}
/// Read account balance.
async fn read_account_balance<C: ChainWithBalances>(
client: &Client<C>,
account: &AccountIdOf<C>,
) -> anyhow::Result<Option<BalanceOf<C>>> {
match client.free_native_balance(account.clone()).await {
Ok(balance) => Ok(Some(balance)),
Err(SubstrateError::AccountDoesNotExist) => Ok(None),
Err(error) => Err(anyhow::format_err!(
"Failed to read balance of {} account {:?}: {:?}",
C::NAME,
account,
error,
)),
}
}
/// Wait until transaction is included into finalized block.
///
/// Returns the hash of the finalized block with transaction.
pub(crate) async fn wait_until_transaction_is_finalized<C: Chain>(
subscription: Subscription<TransactionStatusOf<C>>,
) -> anyhow::Result<HashOf<C>> {
loop {
let transaction_status = subscription.next().await?;
match transaction_status {
Some(TransactionStatusOf::<C>::FinalityTimeout(_)) |
Some(TransactionStatusOf::<C>::Usurped(_)) |
Some(TransactionStatusOf::<C>::Dropped) |
Some(TransactionStatusOf::<C>::Invalid) |
None =>
return Err(anyhow::format_err!(
"We've been waiting for finalization of {} transaction, but it now has the {:?} status",
C::NAME,
transaction_status,
)),
Some(TransactionStatusOf::<C>::Finalized(block_hash)) => {
log::trace!(
target: "bridge",
"{} transaction has been finalized at block {}",
C::NAME,
block_hash,
);
return Ok(block_hash)
},
_ => {
log::trace!(
target: "bridge",
"Received intermediate status of {} transaction: {:?}",
C::NAME,
transaction_status,
);
},
}
}
}
/// Waits until token swap state is changed from `Started` to something else.
async fn wait_until_token_swap_state_is_changed<C: Chain>(
client: &Client<C>,
swap_state_storage_key: &StorageKey,
previous_token_swap_state: bp_token_swap::TokenSwapState,
) -> anyhow::Result<Option<bp_token_swap::TokenSwapState>> {
log::trace!(target: "bridge", "Waiting for token swap state change");
loop {
async_std::task::sleep(C::AVERAGE_BLOCK_INTERVAL).await;
let best_block = client.best_finalized_header_number().await?;
let best_block_hash = client.block_hash_by_number(best_block).await?;
log::trace!(target: "bridge", "Inspecting {} block {}/{}", C::NAME, best_block, best_block_hash);
let token_swap_state =
read_token_swap_state(client, best_block_hash, swap_state_storage_key).await?;
match token_swap_state {
Some(new_token_swap_state) if new_token_swap_state == previous_token_swap_state => {},
_ => {
log::trace!(
target: "bridge",
"Token swap state has been changed from {:?} to {:?}",
previous_token_swap_state,
token_swap_state,
);
return Ok(token_swap_state)
},
}
}
}
/// Waits until swap can be claimed or canceled.
async fn wait_until_swap_unlocked<C: Chain>(
client: &Client<C>,
required_block_number: BlockNumberOf<C>,
) -> anyhow::Result<()> {
log::trace!(target: "bridge", "Waiting for token swap unlock");
loop {
async_std::task::sleep(C::AVERAGE_BLOCK_INTERVAL).await;
let best_block = client.best_finalized_header_number().await?;
let best_block_hash = client.block_hash_by_number(best_block).await?;
if best_block >= required_block_number {
return Ok(())
}
log::trace!(target: "bridge", "Skipping {} block {}/{}", C::NAME, best_block, best_block_hash);
}
}
/// Read state of the active token swap.
async fn read_token_swap_state<C: Chain>(
client: &Client<C>,
at_block: C::Hash,
swap_state_storage_key: &StorageKey,
) -> anyhow::Result<Option<bp_token_swap::TokenSwapState>> {
Ok(client.storage_value(swap_state_storage_key.clone(), Some(at_block)).await?)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cli::{RuntimeVersionType, SourceRuntimeVersionParams, TargetRuntimeVersionParams};
#[test]
fn swap_tokens_millau_to_rialto_no_lock() {
let swap_tokens = SwapTokens::from_iter(vec![
"swap-tokens",
"millau-to-rialto",
"--source-host",
"127.0.0.1",
"--source-port",
"9000",
"--source-signer",
"//Alice",
"--source-balance",
"8000000000",
"--target-host",
"127.0.0.1",
"--target-port",
"9001",
"--target-signer",
"//Bob",
"--target-balance",
"9000000000",
"no-lock",
]);
assert_eq!(
swap_tokens,
SwapTokens {
bridge: SwapTokensBridge::MillauToRialto,
source: SourceConnectionParams {
source_host: "127.0.0.1".into(),
source_port: 9000,
source_secure: false,
source_runtime_version: SourceRuntimeVersionParams {
source_version_mode: RuntimeVersionType::Bundle,
source_spec_version: None,
source_transaction_version: None,
}
},
source_sign: SourceSigningParams {
source_signer: Some("//Alice".into()),
source_signer_password: None,
source_signer_file: None,
source_signer_password_file: None,
source_transactions_mortality: None,
},
target: TargetConnectionParams {
target_host: "127.0.0.1".into(),
target_port: 9001,
target_secure: false,
target_runtime_version: TargetRuntimeVersionParams {
target_version_mode: RuntimeVersionType::Bundle,
target_spec_version: None,
target_transaction_version: None,
}
},
target_sign: TargetSigningParams {
target_signer: Some("//Bob".into()),
target_signer_password: None,
target_signer_file: None,
target_signer_password_file: None,
target_transactions_mortality: None,
},
swap_type: TokenSwapType::NoLock,
source_balance: Balance(8000000000),
target_balance: Balance(9000000000),
target_to_source_conversion_rate_override: None,
source_to_target_conversion_rate_override: None,
}
);
}
#[test]
fn swap_tokens_millau_to_rialto_lock_until() {
let swap_tokens = SwapTokens::from_iter(vec![
"swap-tokens",
"millau-to-rialto",
"--source-host",
"127.0.0.1",
"--source-port",
"9000",
"--source-signer",
"//Alice",
"--source-balance",
"8000000000",
"--target-host",
"127.0.0.1",
"--target-port",
"9001",
"--target-signer",
"//Bob",
"--target-balance",
"9000000000",
"--target-to-source-conversion-rate-override",
"metric",
"--source-to-target-conversion-rate-override",
"84.56",
"lock-until-block",
"--blocks-before-expire",
"1",
]);
assert_eq!(
swap_tokens,
SwapTokens {
bridge: SwapTokensBridge::MillauToRialto,
source: SourceConnectionParams {
source_host: "127.0.0.1".into(),
source_port: 9000,
source_secure: false,
source_runtime_version: SourceRuntimeVersionParams {
source_version_mode: RuntimeVersionType::Bundle,
source_spec_version: None,
source_transaction_version: None,
}
},
source_sign: SourceSigningParams {
source_signer: Some("//Alice".into()),
source_signer_password: None,
source_signer_file: None,
source_signer_password_file: None,
source_transactions_mortality: None,
},
target: TargetConnectionParams {
target_host: "127.0.0.1".into(),
target_port: 9001,
target_secure: false,
target_runtime_version: TargetRuntimeVersionParams {
target_version_mode: RuntimeVersionType::Bundle,
target_spec_version: None,
target_transaction_version: None,
}
},
target_sign: TargetSigningParams {
target_signer: Some("//Bob".into()),
target_signer_password: None,
target_signer_file: None,
target_signer_password_file: None,
target_transactions_mortality: None,
},
swap_type: TokenSwapType::LockUntilBlock {
blocks_before_expire: 1,
swap_nonce: None,
},
source_balance: Balance(8000000000),
target_balance: Balance(9000000000),
target_to_source_conversion_rate_override: Some(ConversionRateOverride::Metric),
source_to_target_conversion_rate_override: Some(ConversionRateOverride::Explicit(
84.56
)),
}
);
}
}
-2
View File
@@ -15,13 +15,11 @@ scale-info = { version = "2.1.1", features = ["derive"] }
bp-header-chain = { path = "../../primitives/header-chain" }
bp-kusama = { path = "../../primitives/chain-kusama" }
bp-message-dispatch = { path = "../../primitives/message-dispatch" }
bp-messages = { path = "../../primitives/messages" }
bp-polkadot = { path = "../../primitives/chain-polkadot" }
bp-polkadot-core = { path = "../../primitives/polkadot-core" }
bp-runtime = { path = "../../primitives/runtime" }
bridge-runtime-common = { path = "../../bin/runtime-common" }
pallet-bridge-dispatch = { path = "../../modules/dispatch" }
# Substrate Dependencies
+1 -34
View File
@@ -27,30 +27,6 @@ use sp_runtime::FixedU128;
/// Unchecked Kusama extrinsic.
pub type UncheckedExtrinsic = bp_polkadot_core::UncheckedExtrinsic<Call>;
/// Polkadot account ownership digest from Kusama.
///
/// The byte vector returned by this function should be signed with a Polkadot account private key.
/// This way, the owner of `kusama_account_id` on Kusama proves that the Polkadot account private
/// key is also under his control.
pub fn kusama_to_polkadot_account_ownership_digest<Call, AccountId, SpecVersion>(
polkadot_call: &Call,
kusama_account_id: AccountId,
polkadot_spec_version: SpecVersion,
) -> Vec<u8>
where
Call: codec::Encode,
AccountId: codec::Encode,
SpecVersion: codec::Encode,
{
pallet_bridge_dispatch::account_ownership_digest(
polkadot_call,
kusama_account_id,
polkadot_spec_version,
bp_runtime::KUSAMA_CHAIN_ID,
bp_runtime::POLKADOT_CHAIN_ID,
)
}
/// Kusama Runtime `Call` enum.
///
/// The enum represents a subset of possible `Call`s we can send to Kusama chain.
@@ -115,16 +91,7 @@ pub enum BridgePolkadotMessagesCall {
#[codec(index = 2)]
update_pallet_parameter(BridgePolkadotMessagesParameter),
#[codec(index = 3)]
send_message(
LaneId,
bp_message_dispatch::MessagePayload<
bp_kusama::AccountId,
bp_polkadot::AccountId,
bp_polkadot::AccountPublic,
Vec<u8>,
>,
bp_kusama::Balance,
),
send_message(LaneId, Vec<u8>, bp_kusama::Balance),
#[codec(index = 5)]
receive_messages_proof(
bp_polkadot::AccountId,
@@ -15,13 +15,11 @@ scale-info = { version = "2.1.1", features = ["derive"] }
bp-header-chain = { path = "../../primitives/header-chain" }
bp-kusama = { path = "../../primitives/chain-kusama" }
bp-message-dispatch = { path = "../../primitives/message-dispatch" }
bp-messages = { path = "../../primitives/messages" }
bp-polkadot = { path = "../../primitives/chain-polkadot" }
bp-polkadot-core = { path = "../../primitives/polkadot-core" }
bp-runtime = { path = "../../primitives/runtime" }
bridge-runtime-common = { path = "../../bin/runtime-common" }
pallet-bridge-dispatch = { path = "../../modules/dispatch" }
# Substrate Dependencies
+1 -34
View File
@@ -27,30 +27,6 @@ use sp_runtime::FixedU128;
/// Unchecked Polkadot extrinsic.
pub type UncheckedExtrinsic = bp_polkadot_core::UncheckedExtrinsic<Call>;
/// Kusama account ownership digest from Polkadot.
///
/// The byte vector returned by this function should be signed with a Kusama account private key.
/// This way, the owner of `kusam_account_id` on Polkadot proves that the Kusama account private key
/// is also under his control.
pub fn polkadot_to_kusama_account_ownership_digest<Call, AccountId, SpecVersion>(
kusama_call: &Call,
kusam_account_id: AccountId,
kusama_spec_version: SpecVersion,
) -> Vec<u8>
where
Call: codec::Encode,
AccountId: codec::Encode,
SpecVersion: codec::Encode,
{
pallet_bridge_dispatch::account_ownership_digest(
kusama_call,
kusam_account_id,
kusama_spec_version,
bp_runtime::POLKADOT_CHAIN_ID,
bp_runtime::KUSAMA_CHAIN_ID,
)
}
/// Polkadot Runtime `Call` enum.
///
/// The enum represents a subset of possible `Call`s we can send to Polkadot chain.
@@ -115,16 +91,7 @@ pub enum BridgeKusamaMessagesCall {
#[codec(index = 2)]
update_pallet_parameter(BridgeKusamaMessagesParameter),
#[codec(index = 3)]
send_message(
LaneId,
bp_message_dispatch::MessagePayload<
bp_polkadot::AccountId,
bp_kusama::AccountId,
bp_kusama::AccountPublic,
Vec<u8>,
>,
bp_polkadot::Balance,
),
send_message(LaneId, Vec<u8>, bp_polkadot::Balance),
#[codec(index = 5)]
receive_messages_proof(
bp_kusama::AccountId,
-2
View File
@@ -15,13 +15,11 @@ scale-info = { version = "2.1.1", features = ["derive"] }
bridge-runtime-common = { path = "../../bin/runtime-common" }
bp-header-chain = { path = "../../primitives/header-chain" }
bp-message-dispatch = { path = "../../primitives/message-dispatch" }
bp-messages = { path = "../../primitives/messages" }
bp-polkadot-core = { path = "../../primitives/polkadot-core" }
bp-rococo = { path = "../../primitives/chain-rococo" }
bp-runtime = { path = "../../primitives/runtime" }
bp-wococo = { path = "../../primitives/chain-wococo" }
pallet-bridge-dispatch = { path = "../../modules/dispatch" }
pallet-bridge-messages = { path = "../../modules/messages" }
# Substrate Dependencies
+1 -34
View File
@@ -26,30 +26,6 @@ use scale_info::TypeInfo;
/// Unchecked Rococo extrinsic.
pub type UncheckedExtrinsic = bp_polkadot_core::UncheckedExtrinsic<Call>;
/// Wococo account ownership digest from Rococo.
///
/// The byte vector returned by this function should be signed with a Wococo account private key.
/// This way, the owner of `rococo_account_id` on Rococo proves that the Wococo account private key
/// is also under his control.
pub fn rococo_to_wococo_account_ownership_digest<Call, AccountId, SpecVersion>(
wococo_call: &Call,
rococo_account_id: AccountId,
wococo_spec_version: SpecVersion,
) -> Vec<u8>
where
Call: codec::Encode,
AccountId: codec::Encode,
SpecVersion: codec::Encode,
{
pallet_bridge_dispatch::account_ownership_digest(
wococo_call,
rococo_account_id,
wococo_spec_version,
bp_runtime::ROCOCO_CHAIN_ID,
bp_runtime::WOCOCO_CHAIN_ID,
)
}
/// Rococo Runtime `Call` enum.
///
/// The enum represents a subset of possible `Call`s we can send to Rococo chain.
@@ -107,16 +83,7 @@ pub enum BridgeGrandpaWococoCall {
#[allow(non_camel_case_types)]
pub enum BridgeWococoMessagesCall {
#[codec(index = 3)]
send_message(
LaneId,
bp_message_dispatch::MessagePayload<
bp_rococo::AccountId,
bp_wococo::AccountId,
bp_wococo::AccountPublic,
Vec<u8>,
>,
bp_rococo::Balance,
),
send_message(LaneId, Vec<u8>, bp_rococo::Balance),
#[codec(index = 5)]
receive_messages_proof(
bp_wococo::AccountId,
-2
View File
@@ -14,13 +14,11 @@ scale-info = { version = "2.1.1", default-features = false, features = ["derive"
# Bridge dependencies
bridge-runtime-common = { path = "../../bin/runtime-common" }
bp-header-chain = { path = "../../primitives/header-chain" }
bp-message-dispatch = { path = "../../primitives/message-dispatch" }
bp-messages = { path = "../../primitives/messages" }
bp-polkadot-core = { path = "../../primitives/polkadot-core" }
bp-rococo = { path = "../../primitives/chain-rococo" }
bp-runtime = { path = "../../primitives/runtime" }
bp-wococo = { path = "../../primitives/chain-wococo" }
pallet-bridge-dispatch = { path = "../../modules/dispatch" }
pallet-bridge-messages = { path = "../../modules/messages" }
# Substrate Dependencies
+1 -34
View File
@@ -26,30 +26,6 @@ use scale_info::TypeInfo;
/// Unchecked Wococo extrinsic.
pub type UncheckedExtrinsic = bp_polkadot_core::UncheckedExtrinsic<Call>;
/// Rococo account ownership digest from Wococo.
///
/// The byte vector returned by this function should be signed with a Rococo account private key.
/// This way, the owner of `wococo_account_id` on Rococo proves that the Rococo account private key
/// is also under his control.
pub fn wococo_to_rococo_account_ownership_digest<Call, AccountId, SpecVersion>(
rococo_call: &Call,
wococo_account_id: AccountId,
rococo_spec_version: SpecVersion,
) -> Vec<u8>
where
Call: codec::Encode,
AccountId: codec::Encode,
SpecVersion: codec::Encode,
{
pallet_bridge_dispatch::account_ownership_digest(
rococo_call,
wococo_account_id,
rococo_spec_version,
bp_runtime::WOCOCO_CHAIN_ID,
bp_runtime::ROCOCO_CHAIN_ID,
)
}
/// Wococo Runtime `Call` enum.
///
/// The enum represents a subset of possible `Call`s we can send to Rococo chain.
@@ -107,16 +83,7 @@ pub enum BridgeGrandpaRococoCall {
#[allow(non_camel_case_types)]
pub enum BridgeRococoMessagesCall {
#[codec(index = 3)]
send_message(
LaneId,
bp_message_dispatch::MessagePayload<
bp_rococo::AccountId,
bp_wococo::AccountId,
bp_wococo::AccountPublic,
Vec<u8>,
>,
bp_rococo::Balance,
),
send_message(LaneId, Vec<u8>, bp_rococo::Balance),
#[codec(index = 5)]
receive_messages_proof(
bp_rococo::AccountId,