diff --git a/bridges/bin/millau/runtime/Cargo.toml b/bridges/bin/millau/runtime/Cargo.toml index 65ea06963c37..59a28d19413f 100644 --- a/bridges/bin/millau/runtime/Cargo.toml +++ b/bridges/bin/millau/runtime/Cargo.toml @@ -17,6 +17,8 @@ serde = { version = "1.0.117", optional = true, features = ["derive"] } bp-message-lane = { path = "../../../primitives/message-lane", default-features = false } bp-millau = { path = "../../../primitives/millau", default-features = false } bp-rialto = { path = "../../../primitives/rialto", default-features = false } +bp-runtime = { path = "../../../primitives/runtime", default-features = false } +bridge-runtime-common = { path = "../../runtime-common", default-features = false } pallet-bridge-call-dispatch = { path = "../../../modules/call-dispatch", default-features = false } pallet-message-lane = { path = "../../../modules/message-lane", default-features = false } pallet-shift-session-manager = { path = "../../../modules/shift-session-manager", default-features = false } @@ -47,6 +49,7 @@ sp-runtime = { version = "2.0", default-features = false } sp-session = { version = "2.0", default-features = false } sp-std = { version = "2.0", default-features = false } sp-transaction-pool = { version = "2.0", default-features = false } +sp-trie = { version = "2.0", default-features = false } sp-version = { version = "2.0", default-features = false } [build-dependencies] @@ -58,6 +61,8 @@ std = [ "bp-message-lane/std", "bp-millau/std", "bp-rialto/std", + "bp-runtime/std", + "bridge-runtime-common/std", "codec/std", "frame-executive/std", "frame-support/std", @@ -87,5 +92,6 @@ std = [ "sp-session/std", "sp-std/std", "sp-transaction-pool/std", + "sp-trie/std", "sp-version/std", ] diff --git a/bridges/bin/millau/runtime/src/lib.rs b/bridges/bin/millau/runtime/src/lib.rs index 340639e36733..dd8b0aa79528 100644 --- a/bridges/bin/millau/runtime/src/lib.rs +++ b/bridges/bin/millau/runtime/src/lib.rs @@ -29,12 +29,13 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); pub mod rialto; +pub mod rialto_messages; use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList}; use sp_api::impl_runtime_apis; use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; -use sp_runtime::traits::{Block as BlockT, IdentifyAccount, IdentityLookup, NumberFor, OpaqueKeys, Saturating, Verify}; +use sp_runtime::traits::{Block as BlockT, IdentityLookup, NumberFor, OpaqueKeys}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, transaction_validity::{TransactionSource, TransactionValidity}, @@ -65,18 +66,18 @@ pub use sp_runtime::{Perbill, Permill}; pub type BlockNumber = bp_millau::BlockNumber; /// Alias to 512-bit hash when used in the context of a transaction signature on the chain. -pub type Signature = MultiSignature; +pub type Signature = bp_millau::Signature; /// Some way of identifying an account on the chain. We intentionally make it equivalent /// to the public key of our transaction signing scheme. -pub type AccountId = <::Signer as IdentifyAccount>::AccountId; +pub type AccountId = bp_millau::AccountId; /// The type for looking up accounts. We don't expect more than 4 billion of them, but you /// never know... pub type AccountIndex = u32; /// Balance of an account. -pub type Balance = u128; +pub type Balance = bp_millau::Balance; /// Index of a transaction in the chain. pub type Index = u32; @@ -145,12 +146,10 @@ pub fn native_version() -> NativeVersion { parameter_types! { pub const BlockHashCount: BlockNumber = 250; - pub const MaximumBlockWeight: Weight = 2_000_000_000_000; + pub const MaximumBlockWeight: Weight = bp_millau::MAXIMUM_BLOCK_WEIGHT; pub const ExtrinsicBaseWeight: Weight = 10_000_000; - pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); - /// Assume 10% of weight for average on_initialize calls. - pub MaximumExtrinsicWeight: Weight = AvailableBlockRatio::get() - .saturating_sub(Perbill::from_percent(10)) * MaximumBlockWeight::get(); + pub const AvailableBlockRatio: Perbill = Perbill::from_percent(bp_millau::AVAILABLE_BLOCK_RATIO); + pub MaximumExtrinsicWeight: Weight = bp_millau::MAXIMUM_EXTRINSIC_WEIGHT; pub const MaximumBlockLength: u32 = 5 * 1024 * 1024; pub const Version: RuntimeVersion = VERSION; pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { @@ -317,6 +316,32 @@ impl pallet_substrate_bridge::Trait for Runtime { impl pallet_shift_session_manager::Trait for Runtime {} +parameter_types! { + pub const MaxMessagesToPruneAtOnce: bp_message_lane::MessageNonce = 8; + pub const MaxUnconfirmedMessagesAtInboundLane: bp_message_lane::MessageNonce = 128; +} + +impl pallet_message_lane::Trait for Runtime { + type Event = Event; + type MaxMessagesToPruneAtOnce = MaxMessagesToPruneAtOnce; + type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; + + type OutboundPayload = crate::rialto_messages::ToRialtoMessagePayload; + type OutboundMessageFee = Balance; + + type InboundPayload = crate::rialto_messages::FromRialtoMessagePayload; + type InboundMessageFee = bp_rialto::Balance; + type InboundRelayer = bp_rialto::AccountId; + + type TargetHeaderChain = crate::rialto_messages::Rialto; + type LaneMessageVerifier = crate::rialto_messages::ToRialtoMessageVerifier; + type MessageDeliveryAndDispatchPayment = + pallet_message_lane::instant_payments::InstantCurrencyPayments>; + + type SourceHeaderChain = crate::rialto_messages::Rialto; + type MessageDispatch = crate::rialto_messages::FromRialtoMessageDispatch; +} + construct_runtime!( pub enum Runtime where Block = Block, @@ -324,6 +349,7 @@ construct_runtime!( UncheckedExtrinsic = UncheckedExtrinsic { BridgeRialto: pallet_substrate_bridge::{Module, Call, Storage, Config}, + BridgeRialtoMessageLane: pallet_message_lane::{Module, Call, Event}, BridgeCallDispatch: pallet_bridge_call_dispatch::{Module, Event}, System: frame_system::{Module, Call, Config, Storage, Event}, RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Module, Call, Storage}, diff --git a/bridges/bin/millau/runtime/src/rialto_messages.rs b/bridges/bin/millau/runtime/src/rialto_messages.rs new file mode 100644 index 000000000000..e2a41e88f9cd --- /dev/null +++ b/bridges/bin/millau/runtime/src/rialto_messages.rs @@ -0,0 +1,157 @@ +// Copyright 2019-2020 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 . + +//! Everything required to serve Millau <-> Rialto message lanes. + +use bridge_runtime_common::messages; + +use bp_message_lane::{ + source_chain::TargetHeaderChain, + target_chain::{ProvedMessages, SourceHeaderChain}, + InboundLaneData, LaneId, Message, MessageNonce, +}; +use bp_runtime::InstanceId; +use bridge_runtime_common::messages::MessageBridge; +use frame_support::{ + weights::{Weight, WeightToFeePolynomial}, + RuntimeDebug, +}; +use sp_trie::StorageProof; + +/// Message payload for Millau -> Rialto messages. +pub type ToRialtoMessagePayload = messages::source::FromThisChainMessagePayload; + +/// Message verifier for Millau -> Rialto messages. +pub type ToRialtoMessageVerifier = messages::source::FromThisChainMessageVerifier; + +/// Message payload for Rialto -> Millau messages. +pub type FromRialtoMessagePayload = messages::target::FromBridgedChainMessagePayload; + +/// Call-dispatch based message dispatch for Rialto -> Millau messages. +pub type FromRialtoMessageDispatch = messages::target::FromBridgedChainMessageDispatch< + WithRialtoMessageBridge, + crate::Runtime, + pallet_bridge_call_dispatch::DefaultInstance, +>; + +/// Millau <-> Rialto message bridge. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct WithRialtoMessageBridge; + +impl MessageBridge for WithRialtoMessageBridge { + const INSTANCE: InstanceId = *b"rlto"; + + const RELAYER_FEE_PERCENT: u32 = 10; + + type ThisChain = Millau; + type BridgedChain = Rialto; + + fn maximal_dispatch_weight_of_message_on_bridged_chain() -> Weight { + // we don't want to relay too large messages + keep reserve for future upgrades + bp_rialto::MAXIMUM_EXTRINSIC_WEIGHT / 2 + } + + fn weight_of_delivery_transaction() -> Weight { + 0 // TODO: https://github.com/paritytech/parity-bridges-common/issues/391 + } + + fn weight_of_delivery_confirmation_transaction_on_this_chain() -> Weight { + 0 // TODO: https://github.com/paritytech/parity-bridges-common/issues/391 + } + + fn weight_of_reward_confirmation_transaction_on_target_chain() -> Weight { + 0 // TODO: https://github.com/paritytech/parity-bridges-common/issues/391 + } + + fn this_weight_to_balance(weight: Weight) -> bp_rialto::Balance { + ::WeightToFee::calc(&weight) + } + + fn bridged_weight_to_balance(weight: Weight) -> bp_millau::Balance { + // we're using the same weights in both chains now + ::WeightToFee::calc(&weight) + } + + fn this_chain_balance_to_bridged_chain_balance(this_balance: bp_rialto::Balance) -> bp_millau::Balance { + // 1:1 conversion that will probably change in the future + this_balance + } +} + +/// Millau chain from message lane point of view. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct Millau; + +impl messages::ChainWithMessageLanes for Millau { + type AccountId = bp_millau::AccountId; + type Signer = bp_millau::AccountSigner; + type Signature = bp_millau::Signature; + type Call = crate::Call; + type Weight = Weight; + type Balance = bp_millau::Balance; +} + +/// Rialto chain from message lane point of view. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct Rialto; + +impl messages::ChainWithMessageLanes for Rialto { + type AccountId = bp_rialto::AccountId; + type Signer = bp_rialto::AccountSigner; + type Signature = bp_rialto::Signature; + type Call = (); // unknown to us + type Weight = Weight; + type Balance = bp_rialto::Balance; +} + +impl TargetHeaderChain for Rialto { + type Error = &'static str; + // The proof is: + // - hash of the header this proof has been created with; + // - the storage proof or one or several keys; + // - id of the lane we prove state of. + type MessagesDeliveryProof = (bp_rialto::Hash, StorageProof, LaneId); + + fn verify_message(payload: &ToRialtoMessagePayload) -> Result<(), Self::Error> { + if payload.weight > WithRialtoMessageBridge::maximal_dispatch_weight_of_message_on_bridged_chain() { + return Err("Too large weight declared"); + } + + Ok(()) + } + + fn verify_messages_delivery_proof( + _proof: Self::MessagesDeliveryProof, + ) -> Result<(LaneId, InboundLaneData), Self::Error> { + unimplemented!("https://github.com/paritytech/parity-bridges-common/issues/397") + } +} + +impl SourceHeaderChain for Rialto { + type Error = &'static str; + // The proof is: + // - hash of the header this proof has been created with; + // - the storage proof or one or several keys; + // - id of the lane we prove messages for; + // - inclusive range of messages nonces that are proved. + type MessagesProof = (bp_rialto::Hash, StorageProof, LaneId, MessageNonce, MessageNonce); + + fn verify_messages_proof( + _proof: Self::MessagesProof, + ) -> Result>, Self::Error> { + unimplemented!("https://github.com/paritytech/parity-bridges-common/issues/397") + } +} diff --git a/bridges/bin/rialto/runtime/Cargo.toml b/bridges/bin/rialto/runtime/Cargo.toml index 1cda71cf9ef8..67e8ab8eee55 100644 --- a/bridges/bin/rialto/runtime/Cargo.toml +++ b/bridges/bin/rialto/runtime/Cargo.toml @@ -18,9 +18,12 @@ serde = { version = "1.0.117", optional = true, features = ["derive"] } bp-currency-exchange = { path = "../../../primitives/currency-exchange", default-features = false } bp-eth-poa = { path = "../../../primitives/ethereum-poa", default-features = false } bp-header-chain = { path = "../../../primitives/header-chain", default-features = false } +bp-message-dispatch = { path = "../../../primitives/message-dispatch", default-features = false } bp-message-lane = { path = "../../../primitives/message-lane", default-features = false } bp-millau = { path = "../../../primitives/millau", default-features = false } bp-rialto = { path = "../../../primitives/rialto", default-features = false } +bp-runtime = { path = "../../../primitives/runtime", default-features = false } +bridge-runtime-common = { path = "../../runtime-common", default-features = false } pallet-bridge-eth-poa = { path = "../../../modules/ethereum", default-features = false } pallet-bridge-call-dispatch = { path = "../../../modules/call-dispatch", default-features = false } pallet-bridge-currency-exchange = { path = "../../../modules/currency-exchange", default-features = false } @@ -55,6 +58,7 @@ sp-runtime = { version = "2.0", default-features = false } sp-session = { version = "2.0", default-features = false } sp-std = { version = "2.0", default-features = false } sp-transaction-pool = { version = "2.0", default-features = false } +sp-trie = { version = "2.0", default-features = false } sp-version = { version = "2.0", default-features = false } [dev-dependencies] @@ -69,9 +73,12 @@ std = [ "bp-currency-exchange/std", "bp-eth-poa/std", "bp-header-chain/std", + "bp-message-dispatch/std", "bp-message-lane/std", - "bp-rialto/std", "bp-millau/std", + "bp-rialto/std", + "bp-runtime/std", + "bridge-runtime-common/std", "codec/std", "frame-benchmarking/std", "frame-executive/std", @@ -104,6 +111,7 @@ std = [ "sp-session/std", "sp-std/std", "sp-transaction-pool/std", + "sp-trie/std", "sp-version/std", ] runtime-benchmarks = [ diff --git a/bridges/bin/rialto/runtime/src/lib.rs b/bridges/bin/rialto/runtime/src/lib.rs index cdb09c6cb009..c4815ea9bc7b 100644 --- a/bridges/bin/rialto/runtime/src/lib.rs +++ b/bridges/bin/rialto/runtime/src/lib.rs @@ -34,13 +34,14 @@ pub mod exchange; pub mod benches; pub mod kovan; pub mod millau; +pub mod millau_messages; pub mod rialto_poa; use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList}; use sp_api::impl_runtime_apis; use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; -use sp_runtime::traits::{Block as BlockT, IdentifyAccount, IdentityLookup, NumberFor, OpaqueKeys, Saturating, Verify}; +use sp_runtime::traits::{Block as BlockT, IdentityLookup, NumberFor, OpaqueKeys}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, transaction_validity::{TransactionSource, TransactionValidity}, @@ -73,18 +74,18 @@ pub use sp_runtime::{Perbill, Permill}; pub type BlockNumber = bp_rialto::BlockNumber; /// Alias to 512-bit hash when used in the context of a transaction signature on the chain. -pub type Signature = MultiSignature; +pub type Signature = bp_rialto::Signature; /// Some way of identifying an account on the chain. We intentionally make it equivalent /// to the public key of our transaction signing scheme. -pub type AccountId = <::Signer as IdentifyAccount>::AccountId; +pub type AccountId = bp_rialto::AccountId; /// The type for looking up accounts. We don't expect more than 4 billion of them, but you /// never know... pub type AccountIndex = u32; /// Balance of an account. -pub type Balance = u128; +pub type Balance = bp_rialto::Balance; /// Index of a transaction in the chain. pub type Index = u32; @@ -153,12 +154,10 @@ pub fn native_version() -> NativeVersion { parameter_types! { pub const BlockHashCount: BlockNumber = 250; - pub const MaximumBlockWeight: Weight = 2_000_000_000_000; + pub const MaximumBlockWeight: Weight = bp_rialto::MAXIMUM_BLOCK_WEIGHT; pub const ExtrinsicBaseWeight: Weight = 10_000_000; - pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75); - /// Assume 10% of weight for average on_initialize calls. - pub MaximumExtrinsicWeight: Weight = AvailableBlockRatio::get() - .saturating_sub(Perbill::from_percent(10)) * MaximumBlockWeight::get(); + pub const AvailableBlockRatio: Perbill = Perbill::from_percent(bp_rialto::AVAILABLE_BLOCK_RATIO); + pub MaximumExtrinsicWeight: Weight = bp_rialto::MAXIMUM_EXTRINSIC_WEIGHT; pub const MaximumBlockLength: u32 = 5 * 1024 * 1024; pub const Version: RuntimeVersion = VERSION; pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { @@ -425,6 +424,32 @@ impl pallet_substrate_bridge::Trait for Runtime { impl pallet_shift_session_manager::Trait for Runtime {} +parameter_types! { + pub const MaxMessagesToPruneAtOnce: bp_message_lane::MessageNonce = 8; + pub const MaxUnconfirmedMessagesAtInboundLane: bp_message_lane::MessageNonce = 128; +} + +impl pallet_message_lane::Trait for Runtime { + type Event = Event; + type MaxMessagesToPruneAtOnce = MaxMessagesToPruneAtOnce; + type MaxUnconfirmedMessagesAtInboundLane = MaxUnconfirmedMessagesAtInboundLane; + + type OutboundPayload = crate::millau_messages::ToMillauMessagePayload; + type OutboundMessageFee = Balance; + + type InboundPayload = crate::millau_messages::FromMillauMessagePayload; + type InboundMessageFee = bp_millau::Balance; + type InboundRelayer = bp_millau::AccountId; + + type TargetHeaderChain = crate::millau_messages::Millau; + type LaneMessageVerifier = crate::millau_messages::ToMillauMessageVerifier; + type MessageDeliveryAndDispatchPayment = + pallet_message_lane::instant_payments::InstantCurrencyPayments>; + + type SourceHeaderChain = crate::millau_messages::Millau; + type MessageDispatch = crate::millau_messages::FromMillauMessageDispatch; +} + construct_runtime!( pub enum Runtime where Block = Block, @@ -437,6 +462,7 @@ construct_runtime!( BridgeKovanCurrencyExchange: pallet_bridge_currency_exchange::::{Module, Call}, BridgeMillau: pallet_substrate_bridge::{Module, Call, Storage, Config}, BridgeCallDispatch: pallet_bridge_call_dispatch::{Module, Event}, + BridgeMillauMessageLane: pallet_message_lane::{Module, Call, Event}, System: frame_system::{Module, Call, Config, Storage, Event}, RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Module, Call, Storage}, Timestamp: pallet_timestamp::{Module, Call, Storage, Inherent}, diff --git a/bridges/bin/rialto/runtime/src/millau_messages.rs b/bridges/bin/rialto/runtime/src/millau_messages.rs new file mode 100644 index 000000000000..920c3b39eb48 --- /dev/null +++ b/bridges/bin/rialto/runtime/src/millau_messages.rs @@ -0,0 +1,157 @@ +// Copyright 2019-2020 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 . + +//! Everything required to serve Millau <-> Rialto message lanes. + +use bridge_runtime_common::messages; + +use bp_message_lane::{ + source_chain::TargetHeaderChain, + target_chain::{ProvedMessages, SourceHeaderChain}, + InboundLaneData, LaneId, Message, MessageNonce, +}; +use bp_runtime::InstanceId; +use bridge_runtime_common::messages::MessageBridge; +use frame_support::{ + weights::{Weight, WeightToFeePolynomial}, + RuntimeDebug, +}; +use sp_trie::StorageProof; + +/// Message payload for Rialto -> Millau messages. +pub type ToMillauMessagePayload = messages::source::FromThisChainMessagePayload; + +/// Message verifier for Rialto -> Millau messages. +pub type ToMillauMessageVerifier = messages::source::FromThisChainMessageVerifier; + +/// Message payload for Millau -> Rialto messages. +pub type FromMillauMessagePayload = messages::target::FromBridgedChainMessagePayload; + +/// Call-dispatch based message dispatch for Millau -> Rialto messages. +pub type FromMillauMessageDispatch = messages::target::FromBridgedChainMessageDispatch< + WithMillauMessageBridge, + crate::Runtime, + pallet_bridge_call_dispatch::DefaultInstance, +>; + +/// Millau <-> Rialto message bridge. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct WithMillauMessageBridge; + +impl MessageBridge for WithMillauMessageBridge { + const INSTANCE: InstanceId = *b"mlau"; + + const RELAYER_FEE_PERCENT: u32 = 10; + + type ThisChain = Rialto; + type BridgedChain = Millau; + + fn maximal_dispatch_weight_of_message_on_bridged_chain() -> Weight { + // we don't want to relay too large messages + keep reserve for future upgrades + bp_millau::MAXIMUM_EXTRINSIC_WEIGHT / 2 + } + + fn weight_of_delivery_transaction() -> Weight { + 0 // TODO: https://github.com/paritytech/parity-bridges-common/issues/391 + } + + fn weight_of_delivery_confirmation_transaction_on_this_chain() -> Weight { + 0 // TODO: https://github.com/paritytech/parity-bridges-common/issues/391 + } + + fn weight_of_reward_confirmation_transaction_on_target_chain() -> Weight { + 0 // TODO: https://github.com/paritytech/parity-bridges-common/issues/391 + } + + fn this_weight_to_balance(weight: Weight) -> bp_rialto::Balance { + ::WeightToFee::calc(&weight) + } + + fn bridged_weight_to_balance(weight: Weight) -> bp_millau::Balance { + // we're using the same weights in both chains now + ::WeightToFee::calc(&weight) + } + + fn this_chain_balance_to_bridged_chain_balance(this_balance: bp_rialto::Balance) -> bp_millau::Balance { + // 1:1 conversion that will probably change in the future + this_balance + } +} + +/// Rialto chain from message lane point of view. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct Rialto; + +impl messages::ChainWithMessageLanes for Rialto { + type AccountId = bp_rialto::AccountId; + type Signer = bp_rialto::AccountSigner; + type Signature = bp_rialto::Signature; + type Call = crate::Call; + type Weight = Weight; + type Balance = bp_rialto::Balance; +} + +/// Millau chain from message lane point of view. +#[derive(RuntimeDebug, Clone, Copy)] +pub struct Millau; + +impl messages::ChainWithMessageLanes for Millau { + type AccountId = bp_millau::AccountId; + type Signer = bp_millau::AccountSigner; + type Signature = bp_millau::Signature; + type Call = (); // unknown to us + type Weight = Weight; + type Balance = bp_millau::Balance; +} + +impl TargetHeaderChain for Millau { + type Error = &'static str; + // The proof is: + // - hash of the header this proof has been created with; + // - the storage proof of one or several keys; + // - id of the lane we prove state of. + type MessagesDeliveryProof = (bp_millau::Hash, StorageProof, LaneId); + + fn verify_message(payload: &ToMillauMessagePayload) -> Result<(), Self::Error> { + if payload.weight > WithMillauMessageBridge::maximal_dispatch_weight_of_message_on_bridged_chain() { + return Err("Payload has weight larger than maximum allowed weight"); + } + + Ok(()) + } + + fn verify_messages_delivery_proof( + _proof: Self::MessagesDeliveryProof, + ) -> Result<(LaneId, InboundLaneData), Self::Error> { + unimplemented!("https://github.com/paritytech/parity-bridges-common/issues/397") + } +} + +impl SourceHeaderChain for Millau { + type Error = &'static str; + // The proof is: + // - hash of the header this proof has been created with; + // - the storage proof of one or several keys; + // - id of the lane we prove messages for; + // - inclusive range of messages nonces that are proved. + type MessagesProof = (bp_millau::Hash, StorageProof, LaneId, MessageNonce, MessageNonce); + + fn verify_messages_proof( + _proof: Self::MessagesProof, + ) -> Result>, Self::Error> { + unimplemented!("https://github.com/paritytech/parity-bridges-common/issues/397") + } +} diff --git a/bridges/bin/runtime-common/Cargo.toml b/bridges/bin/runtime-common/Cargo.toml new file mode 100644 index 000000000000..960fbc580caf --- /dev/null +++ b/bridges/bin/runtime-common/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "bridge-runtime-common" +version = "0.1.0" +authors = ["Parity Technologies "] +edition = "2018" +homepage = "https://substrate.dev" +repository = "https://github.com/paritytech/parity-bridges-common/" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" + +[dependencies] +codec = { package = "parity-scale-codec", version = "1.3.1", default-features = false, features = ["derive"] } + +# Bridge dependencies + +bp-message-dispatch = { path = "../../primitives/message-dispatch", default-features = false } +bp-message-lane = { path = "../../primitives/message-lane", default-features = false } +bp-runtime = { path = "../../primitives/runtime", default-features = false } +pallet-bridge-call-dispatch = { path = "../../modules/call-dispatch", default-features = false } + +# Substrate dependencies + +frame-support = { version = "2.0", default-features = false } +sp-runtime = { version = "2.0", default-features = false } +sp-std = { version = "2.0", default-features = false } +sp-trie = { version = "2.0", default-features = false } + +[features] +default = ["std"] +std = [ + "bp-message-dispatch/std", + "bp-message-lane/std", + "bp-runtime/std", + "codec/std", + "frame-support/std", + "pallet-bridge-call-dispatch/std", + "sp-runtime/std", + "sp-std/std", + "sp-trie/std", +] diff --git a/bridges/bin/runtime-common/src/lib.rs b/bridges/bin/runtime-common/src/lib.rs new file mode 100644 index 000000000000..3168383f5eb8 --- /dev/null +++ b/bridges/bin/runtime-common/src/lib.rs @@ -0,0 +1,21 @@ +// Copyright 2019-2020 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 . + +//! Common types/functions that may be used by runtimes of all bridged chains. + +#![cfg_attr(not(feature = "std"), no_std)] + +pub mod messages; diff --git a/bridges/bin/runtime-common/src/messages.rs b/bridges/bin/runtime-common/src/messages.rs new file mode 100644 index 000000000000..9e534c6d782a --- /dev/null +++ b/bridges/bin/runtime-common/src/messages.rs @@ -0,0 +1,539 @@ +// Copyright 2019-2020 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 . + +//! Types that allow runtime to act as a source/target endpoint of message lanes. +//! +//! Messages are assumed to be encoded `Call`s of the target chain. Call-dispatch +//! pallet is used to dispatch incoming messages. Message identified by a tuple +//! of to elements - message lane id and message nonce. + +use bp_message_dispatch::MessageDispatch as _; +use bp_message_lane::{ + source_chain::LaneMessageVerifier, + target_chain::{DispatchMessage, MessageDispatch}, + LaneId, MessageNonce, +}; +use bp_runtime::InstanceId; +use codec::{Compact, Decode, Input}; +use frame_support::RuntimeDebug; +use sp_runtime::traits::{CheckedAdd, CheckedDiv, CheckedMul}; +use sp_std::{cmp::PartialOrd, marker::PhantomData, vec::Vec}; + +/// Bidirectional message bridge. +pub trait MessageBridge { + /// Instance id of this bridge. + const INSTANCE: InstanceId; + + /// Relayer interest (in percents). + const RELAYER_FEE_PERCENT: u32; + + /// This chain in context of message bridge. + type ThisChain: ChainWithMessageLanes; + /// Bridged chain in context of message bridge. + type BridgedChain: ChainWithMessageLanes; + + /// Maximal (dispatch) weight of the message that we are able to send to Bridged chain. + fn maximal_dispatch_weight_of_message_on_bridged_chain() -> WeightOf>; + + /// Maximal weight of single message delivery transaction on Bridged chain. + fn weight_of_delivery_transaction() -> WeightOf>; + + /// Maximal weight of single message delivery confirmation transaction on This chain. + fn weight_of_delivery_confirmation_transaction_on_this_chain() -> WeightOf>; + + /// Weight of single message reward confirmation on the Bridged chain. This confirmation + /// is a part of delivery transaction, so this weight is added to the delivery + /// transaction weight. + fn weight_of_reward_confirmation_transaction_on_target_chain() -> WeightOf>; + + /// Convert weight of This chain to the fee (paid in Balance) of This chain. + fn this_weight_to_balance(weight: WeightOf>) -> BalanceOf>; + + /// Convert weight of the Bridged chain to the fee (paid in Balance) of the Bridged chain. + fn bridged_weight_to_balance(weight: WeightOf>) -> BalanceOf>; + + /// Convert This chain Balance into Bridged chain Balance. + fn this_chain_balance_to_bridged_chain_balance( + this_balance: BalanceOf>, + ) -> BalanceOf>; +} + +/// Chain that has `message-lane` and `call-dispatch` modules. +pub trait ChainWithMessageLanes { + /// Accound id on the chain. + type AccountId; + /// Public key of the chain account that may be used to verify signatures. + type Signer: Decode; + /// Signature type used on the chain. + type Signature: Decode; + /// Call type on the chain. + type Call: Decode; + /// Type of weight that is used on the chain. This would almost always be a regular + /// `frame_support::weight::Weight`. But since the meaning of weight on different chains + /// may be different, the `WeightOf<>` construct is used to avoid confusion between + /// different weights. + type Weight: From; + /// Type of balances that is used on the chain. + type Balance: CheckedAdd + CheckedDiv + CheckedMul + PartialOrd + From + Copy; +} + +pub(crate) type ThisChain = ::ThisChain; +pub(crate) type BridgedChain = ::BridgedChain; +pub(crate) type AccountIdOf = ::AccountId; +pub(crate) type SignerOf = ::Signer; +pub(crate) type SignatureOf = ::Signature; +pub(crate) type WeightOf = ::Weight; +pub(crate) type BalanceOf = ::Balance; +pub(crate) type CallOf = ::Call; + +/// Sub-module that is declaring types required for processing This -> Bridged chain messages. +pub mod source { + use super::*; + + /// Encoded Call of the Bridged chain. We never try to decode it on This chain. + pub type BridgedChainOpaqueCall = Vec; + + /// Message payload for This -> Bridged chain messages. + pub type FromThisChainMessagePayload = pallet_bridge_call_dispatch::MessagePayload< + SignerOf>, + SignerOf>, + SignatureOf>, + BridgedChainOpaqueCall, + >; + + /// Message verifier that requires submitter to pay minimal delivery and dispatch fee. + #[derive(RuntimeDebug)] + pub struct FromThisChainMessageVerifier(PhantomData); + + impl + LaneMessageVerifier>, FromThisChainMessagePayload, BalanceOf>> + for FromThisChainMessageVerifier + { + type Error = &'static str; + + fn verify_message( + _submitter: &AccountIdOf>, + delivery_and_dispatch_fee: &BalanceOf>, + _lane: &LaneId, + payload: &FromThisChainMessagePayload, + ) -> Result<(), Self::Error> { + let minimal_fee_in_bridged_tokens = + estimate_message_dispatch_and_delivery_fee::(payload, B::RELAYER_FEE_PERCENT)?; + + // compare with actual fee paid + let actual_fee_in_bridged_tokens = + B::this_chain_balance_to_bridged_chain_balance(*delivery_and_dispatch_fee); + if actual_fee_in_bridged_tokens < minimal_fee_in_bridged_tokens { + return Err("Too low fee paid"); + } + + Ok(()) + } + } + + /// Estimate delivery and dispatch fee that must be paid for delivering a message to the Bridged chain. + /// + /// The fee is paid in This chain Balance, but we use Bridged chain balance to avoid additional conversions. + /// Returns `None` if overflow has happened. + pub fn estimate_message_dispatch_and_delivery_fee( + payload: &FromThisChainMessagePayload, + relayer_fee_percent: u32, + ) -> Result>, &'static str> { + // the fee (in Bridged tokens) of all transactions that are made on the Bridged chain + let delivery_fee = B::bridged_weight_to_balance(B::weight_of_delivery_transaction()); + let dispatch_fee = B::bridged_weight_to_balance(payload.weight.into()); + let reward_confirmation_fee = + B::bridged_weight_to_balance(B::weight_of_reward_confirmation_transaction_on_target_chain()); + + // the fee (in Bridged tokens) of all transactions that are made on This chain + let delivery_confirmation_fee = B::this_chain_balance_to_bridged_chain_balance(B::this_weight_to_balance( + B::weight_of_delivery_confirmation_transaction_on_this_chain(), + )); + + // minimal fee (in Bridged tokens) is a sum of all required fees + let minimal_fee = delivery_fee + .checked_add(&dispatch_fee) + .and_then(|fee| fee.checked_add(&reward_confirmation_fee)) + .and_then(|fee| fee.checked_add(&delivery_confirmation_fee)); + + // before returning, add extra fee that is paid to the relayer (relayer interest) + minimal_fee + .and_then(|fee| + // having message with fee that is near the `Balance::MAX_VALUE` of the chain is + // unlikely and should be treated as an error + // => let's do multiplication first + fee + .checked_mul(&relayer_fee_percent.into()) + .and_then(|interest| interest.checked_div(&100u32.into())) + .and_then(|interest| fee.checked_add(&interest))) + .ok_or("Overflow when computing minimal required message delivery and dispatch fee") + } +} + +/// Sub-module that is declaring types required for processing Bridged -> This chain messages. +pub mod target { + use super::*; + + /// Call origin for Bridged -> This chain messages. + pub type FromBridgedChainMessageCallOrigin = pallet_bridge_call_dispatch::CallOrigin< + SignerOf>, + SignerOf>, + SignatureOf>, + >; + + /// Decoded Bridged -> This message payload. + pub type FromBridgedChainDecodedMessagePayload = pallet_bridge_call_dispatch::MessagePayload< + SignerOf>, + SignerOf>, + SignatureOf>, + CallOf>, + >; + + /// Message payload for Bridged -> This messages. + pub struct FromBridgedChainMessagePayload(pub(crate) FromBridgedChainDecodedMessagePayload); + + impl Decode for FromBridgedChainMessagePayload { + fn decode(input: &mut I) -> Result { + // for bridged chain our Calls are opaque - they're encoded to Vec by submitter + // => skip encoded vec length here before decoding Call + let spec_version = pallet_bridge_call_dispatch::SpecVersion::decode(input)?; + let weight = frame_support::weights::Weight::decode(input)?; + let origin = FromBridgedChainMessageCallOrigin::::decode(input)?; + let _skipped_length = Compact::::decode(input)?; + let call = CallOf::>::decode(input)?; + + Ok(FromBridgedChainMessagePayload( + pallet_bridge_call_dispatch::MessagePayload { + spec_version, + weight, + origin, + call, + }, + )) + } + } + + /// Dispatching Bridged -> This chain messages. + #[derive(RuntimeDebug, Clone, Copy)] + pub struct FromBridgedChainMessageDispatch { + _marker: PhantomData<(B, ThisRuntime, ThisCallDispatchInstance)>, + } + + impl + MessageDispatch< as ChainWithMessageLanes>::Balance> + for FromBridgedChainMessageDispatch + where + ThisCallDispatchInstance: frame_support::traits::Instance, + ThisRuntime: pallet_bridge_call_dispatch::Trait, + pallet_bridge_call_dispatch::Module: + bp_message_dispatch::MessageDispatch< + (LaneId, MessageNonce), + Message = FromBridgedChainDecodedMessagePayload, + >, + { + type DispatchPayload = FromBridgedChainMessagePayload; + + fn dispatch_weight( + message: &DispatchMessage>>, + ) -> frame_support::weights::Weight { + message + .data + .payload + .as_ref() + .map(|payload| payload.0.weight) + .unwrap_or(0) + } + + fn dispatch(message: DispatchMessage>>) { + if let Ok(payload) = message.data.payload { + pallet_bridge_call_dispatch::Module::::dispatch( + B::INSTANCE, + (message.key.lane_id, message.key.nonce), + payload.0, + ); + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use codec::{Decode, Encode}; + use frame_support::weights::Weight; + + const DELIVERY_TRANSACTION_WEIGHT: Weight = 100; + const DELIVERY_CONFIRMATION_TRANSACTION_WEIGHT: Weight = 100; + const REWARD_CONFIRMATION_TRANSACTION_WEIGHT: Weight = 100; + const THIS_CHAIN_WEIGHT_TO_BALANCE_RATE: Weight = 2; + const BRIDGED_CHAIN_WEIGHT_TO_BALANCE_RATE: Weight = 4; + const THIS_CHAIN_TO_BRIDGED_CHAIN_BALANCE_RATE: u32 = 6; + + /// Bridge that is deployed on ThisChain and allows sending/receiving messages to/from BridgedChain; + struct OnThisChainBridge; + + impl MessageBridge for OnThisChainBridge { + const INSTANCE: InstanceId = *b"this"; + const RELAYER_FEE_PERCENT: u32 = 10; + + type ThisChain = ThisChain; + type BridgedChain = BridgedChain; + + fn maximal_dispatch_weight_of_message_on_bridged_chain() -> Weight { + unreachable!() + } + + fn weight_of_delivery_transaction() -> Weight { + DELIVERY_TRANSACTION_WEIGHT + } + + fn weight_of_delivery_confirmation_transaction_on_this_chain() -> Weight { + DELIVERY_CONFIRMATION_TRANSACTION_WEIGHT + } + + fn weight_of_reward_confirmation_transaction_on_target_chain() -> Weight { + REWARD_CONFIRMATION_TRANSACTION_WEIGHT + } + + fn this_weight_to_balance(weight: Weight) -> ThisChainBalance { + ThisChainBalance(weight as u32 * THIS_CHAIN_WEIGHT_TO_BALANCE_RATE as u32) + } + + fn bridged_weight_to_balance(weight: Weight) -> BridgedChainBalance { + BridgedChainBalance(weight as u32 * BRIDGED_CHAIN_WEIGHT_TO_BALANCE_RATE as u32) + } + + fn this_chain_balance_to_bridged_chain_balance(this_balance: ThisChainBalance) -> BridgedChainBalance { + BridgedChainBalance(this_balance.0 * THIS_CHAIN_TO_BRIDGED_CHAIN_BALANCE_RATE as u32) + } + } + + /// Bridge that is deployed on BridgedChain and allows sending/receiving messages to/from ThisChain; + struct OnBridgedChainBridge; + + impl MessageBridge for OnBridgedChainBridge { + const INSTANCE: InstanceId = *b"brdg"; + const RELAYER_FEE_PERCENT: u32 = 20; + + type ThisChain = BridgedChain; + type BridgedChain = ThisChain; + + fn maximal_dispatch_weight_of_message_on_bridged_chain() -> Weight { + unreachable!() + } + + fn weight_of_delivery_transaction() -> Weight { + unreachable!() + } + + fn weight_of_delivery_confirmation_transaction_on_this_chain() -> Weight { + unreachable!() + } + + fn weight_of_reward_confirmation_transaction_on_target_chain() -> Weight { + unreachable!() + } + + fn this_weight_to_balance(_weight: Weight) -> BridgedChainBalance { + unreachable!() + } + + fn bridged_weight_to_balance(_weight: Weight) -> ThisChainBalance { + unreachable!() + } + + fn this_chain_balance_to_bridged_chain_balance(_this_balance: BridgedChainBalance) -> ThisChainBalance { + unreachable!() + } + } + + #[derive(Debug, PartialEq, Decode, Encode)] + struct ThisChainAccountId(u32); + #[derive(Debug, PartialEq, Decode, Encode)] + struct ThisChainSigner(u32); + #[derive(Debug, PartialEq, Decode, Encode)] + struct ThisChainSignature(u32); + #[derive(Debug, PartialEq, Decode, Encode)] + enum ThisChainCall { + #[codec(index = 42)] + Transfer, + #[codec(index = 84)] + Mint, + } + + #[derive(Debug, PartialEq, Decode, Encode)] + struct BridgedChainAccountId(u32); + #[derive(Debug, PartialEq, Decode, Encode)] + struct BridgedChainSigner(u32); + #[derive(Debug, PartialEq, Decode, Encode)] + struct BridgedChainSignature(u32); + #[derive(Debug, PartialEq, Decode, Encode)] + enum BridgedChainCall {} + + macro_rules! impl_wrapped_balance { + ($name:ident) => { + #[derive(Debug, PartialEq, Decode, Encode, Clone, Copy)] + struct $name(u32); + + impl From for $name { + fn from(balance: u32) -> Self { + Self(balance) + } + } + + impl sp_std::ops::Add for $name { + type Output = $name; + + fn add(self, other: Self) -> Self { + Self(self.0 + other.0) + } + } + + impl sp_std::ops::Div for $name { + type Output = $name; + + fn div(self, other: Self) -> Self { + Self(self.0 / other.0) + } + } + + impl sp_std::ops::Mul for $name { + type Output = $name; + + fn mul(self, other: Self) -> Self { + Self(self.0 * other.0) + } + } + + impl sp_std::cmp::PartialOrd for $name { + fn partial_cmp(&self, other: &Self) -> Option { + self.0.partial_cmp(&other.0) + } + } + + impl CheckedAdd for $name { + fn checked_add(&self, other: &Self) -> Option { + self.0.checked_add(other.0).map(Self) + } + } + + impl CheckedDiv for $name { + fn checked_div(&self, other: &Self) -> Option { + self.0.checked_div(other.0).map(Self) + } + } + + impl CheckedMul for $name { + fn checked_mul(&self, other: &Self) -> Option { + self.0.checked_mul(other.0).map(Self) + } + } + }; + } + + impl_wrapped_balance!(ThisChainBalance); + impl_wrapped_balance!(BridgedChainBalance); + + struct ThisChain; + + impl ChainWithMessageLanes for ThisChain { + type AccountId = ThisChainAccountId; + type Signer = ThisChainSigner; + type Signature = ThisChainSignature; + type Call = ThisChainCall; + type Weight = frame_support::weights::Weight; + type Balance = ThisChainBalance; + } + + struct BridgedChain; + + impl ChainWithMessageLanes for BridgedChain { + type AccountId = BridgedChainAccountId; + type Signer = BridgedChainSigner; + type Signature = BridgedChainSignature; + type Call = BridgedChainCall; + type Weight = frame_support::weights::Weight; + type Balance = BridgedChainBalance; + } + + #[test] + fn message_from_bridged_chain_is_decoded() { + // the message is encoded on the bridged chain + let message_on_bridged_chain = source::FromThisChainMessagePayload:: { + spec_version: 1, + weight: 100, + origin: pallet_bridge_call_dispatch::CallOrigin::BridgeAccount, + call: ThisChainCall::Transfer.encode(), + } + .encode(); + + // and sent to this chain where it is decoded + let message_on_this_chain = + target::FromBridgedChainMessagePayload::::decode(&mut &message_on_bridged_chain[..]) + .unwrap(); + assert_eq!( + message_on_this_chain.0, + target::FromBridgedChainDecodedMessagePayload:: { + spec_version: 1, + weight: 100, + origin: pallet_bridge_call_dispatch::CallOrigin::BridgeAccount, + call: ThisChainCall::Transfer, + } + ); + } + + #[test] + fn message_fee_is_checked_by_verifier() { + const EXPECTED_MINIMAL_FEE: u32 = 2640; + + // payload of the This -> Bridged chain message + let payload = source::FromThisChainMessagePayload:: { + spec_version: 1, + weight: 100, + origin: pallet_bridge_call_dispatch::CallOrigin::BridgeAccount, + call: vec![42], + }; + + // let's check if estimation matching hardcoded value + assert_eq!( + source::estimate_message_dispatch_and_delivery_fee::( + &payload, + OnThisChainBridge::RELAYER_FEE_PERCENT, + ), + Ok(BridgedChainBalance(EXPECTED_MINIMAL_FEE)), + ); + + // and now check that the verifier checks the fee + assert!( + source::FromThisChainMessageVerifier::::verify_message( + &ThisChainAccountId(0), + &ThisChainBalance(1), + &*b"test", + &payload, + ) + .is_err(), + ); + assert!( + source::FromThisChainMessageVerifier::::verify_message( + &ThisChainAccountId(0), + &ThisChainBalance(1_000_000), + &*b"test", + &payload, + ) + .is_ok(), + ); + } +} diff --git a/bridges/modules/call-dispatch/src/lib.rs b/bridges/modules/call-dispatch/src/lib.rs index 6adac937e5cd..f6fda67fbae4 100644 --- a/bridges/modules/call-dispatch/src/lib.rs +++ b/bridges/modules/call-dispatch/src/lib.rs @@ -47,7 +47,7 @@ use sp_std::{marker::PhantomData, prelude::*}; pub type SpecVersion = u32; /// Origin of the call on the target chain. -#[derive(RuntimeDebug, Encode, Decode, Clone)] +#[derive(RuntimeDebug, Encode, Decode, Clone, PartialEq, Eq)] pub enum CallOrigin { /// Call is originated from bridge account, which is (designed to be) specific to /// the single deployed instance of the messages bridge (message-lane, ...) module. @@ -67,7 +67,7 @@ pub enum CallOrigin { /// Runtime specification version. We only dispatch messages that have the same /// runtime version. Otherwise we risk to misinterpret encoded calls. diff --git a/bridges/modules/message-lane/Cargo.toml b/bridges/modules/message-lane/Cargo.toml index 0240d2225059..e9313a4d70d5 100644 --- a/bridges/modules/message-lane/Cargo.toml +++ b/bridges/modules/message-lane/Cargo.toml @@ -12,6 +12,7 @@ codec = { package = "parity-scale-codec", version = "1.3.1", default-features = # Bridge dependencies bp-message-lane = { path = "../../primitives/message-lane", default-features = false } +bp-runtime = { path = "../../primitives/runtime", default-features = false } # Substrate Dependencies @@ -28,6 +29,7 @@ sp-io = "2.0" default = ["std"] std = [ "bp-message-lane/std", + "bp-runtime/std", "codec/std", "frame-support/std", "frame-system/std", diff --git a/bridges/modules/message-lane/src/instant_payments.rs b/bridges/modules/message-lane/src/instant_payments.rs new file mode 100644 index 000000000000..3c11d263cebb --- /dev/null +++ b/bridges/modules/message-lane/src/instant_payments.rs @@ -0,0 +1,75 @@ +// Copyright 2019-2020 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 . + +//! Implementation of `MessageDeliveryAndDispatchPayment` trait on top of `Currency` trait. +//! All payments are instant. + +use bp_message_lane::source_chain::MessageDeliveryAndDispatchPayment; +use bp_runtime::{bridge_account_id, MESSAGE_LANE_MODULE_PREFIX, NO_INSTANCE_ID}; +use codec::Decode; +use frame_support::traits::{Currency as CurrencyT, ExistenceRequirement}; +use sp_std::fmt::Debug; + +/// Instant message payments made in given currency. Until claimed, fee is stored in special +/// 'relayers-fund' account. +pub struct InstantCurrencyPayments { + _phantom: sp_std::marker::PhantomData<(AccountId, Currency)>, +} + +impl MessageDeliveryAndDispatchPayment + for InstantCurrencyPayments +where + Currency: CurrencyT, + AccountId: Debug + Default + Decode, +{ + type Error = &'static str; + + fn pay_delivery_and_dispatch_fee(submitter: &AccountId, fee: &Currency::Balance) -> Result<(), Self::Error> { + Currency::transfer( + submitter, + &relayers_fund_account(), + *fee, + ExistenceRequirement::AllowDeath, + ) + .map_err(Into::into) + } + + fn pay_relayer_reward(_confirmation_relayer: &AccountId, relayer: &AccountId, reward: &Currency::Balance) { + let pay_result = Currency::transfer( + &relayers_fund_account(), + relayer, + *reward, + ExistenceRequirement::AllowDeath, + ); + + // we can't actually do anything here, because rewards are paid as a part of unrelated transaction + if let Err(error) = pay_result { + frame_support::debug::trace!( + target: "runtime", + "Failed to pay relayer {:?} reward {:?}: {:?}", + relayer, + reward, + error, + ); + } + } +} + +/// Return account id of shared relayers-fund account that is storing all fees +/// paid by submitters, until they're claimed by relayers. +fn relayers_fund_account() -> AccountId { + bridge_account_id(NO_INSTANCE_ID, MESSAGE_LANE_MODULE_PREFIX) +} diff --git a/bridges/modules/message-lane/src/lib.rs b/bridges/modules/message-lane/src/lib.rs index 0404fecd5cfa..6e7a6add2fcc 100644 --- a/bridges/modules/message-lane/src/lib.rs +++ b/bridges/modules/message-lane/src/lib.rs @@ -48,6 +48,8 @@ use sp_std::{cell::RefCell, marker::PhantomData, prelude::*}; mod inbound_lane; mod outbound_lane; +pub mod instant_payments; + #[cfg(test)] mod mock; diff --git a/bridges/primitives/millau/src/lib.rs b/bridges/primitives/millau/src/lib.rs index 844e4667c603..8571ba9499f9 100644 --- a/bridges/primitives/millau/src/lib.rs +++ b/bridges/primitives/millau/src/lib.rs @@ -21,11 +21,22 @@ #![allow(clippy::unnecessary_mut_passed)] use bp_runtime::Chain; -use frame_support::RuntimeDebug; +use frame_support::{weights::Weight, RuntimeDebug}; use sp_core::Hasher as HasherT; -use sp_runtime::traits::BlakeTwo256; +use sp_runtime::{ + traits::{BlakeTwo256, IdentifyAccount, Verify}, + MultiSignature, MultiSigner, +}; use sp_std::prelude::*; +/// Maximal weight of single Millau block. +pub const MAXIMUM_BLOCK_WEIGHT: Weight = 2_000_000_000_000; +/// Portion of block reserved for regular transactions. +pub const AVAILABLE_BLOCK_RATIO: u32 = 75; +/// Maximal weight of single Millau extrinsic (65% of maximum block weight = 75% for regular +/// transactions minus 10% for initialization). +pub const MAXIMUM_EXTRINSIC_WEIGHT: Weight = MAXIMUM_BLOCK_WEIGHT / 100 * (AVAILABLE_BLOCK_RATIO as Weight - 10); + /// Block number type used in Millau. pub type BlockNumber = u32; @@ -56,6 +67,19 @@ pub const IS_KNOWN_MILLAU_BLOCK_METHOD: &str = "MillauHeaderApi_is_known_block"; /// Name of the `MillauHeaderApi::incomplete_headers` runtime method. pub const INCOMPLETE_MILLAU_HEADERS_METHOD: &str = "MillauHeaderApi_incomplete_headers"; +/// Alias to 512-bit hash when used in the context of a transaction signature on the chain. +pub type Signature = MultiSignature; + +/// Some way of identifying an account on the chain. We intentionally make it equivalent +/// to the public key of our transaction signing scheme. +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; + +/// Public key of the chain account that may be used to verify signatures. +pub type AccountSigner = MultiSigner; + +/// Balance of an account. +pub type Balance = u128; + sp_api::decl_runtime_apis! { /// API for querying information about Millau headers from the Bridge Pallet instance. /// diff --git a/bridges/primitives/rialto/Cargo.toml b/bridges/primitives/rialto/Cargo.toml index 9c9cb4bc8160..b03806905167 100644 --- a/bridges/primitives/rialto/Cargo.toml +++ b/bridges/primitives/rialto/Cargo.toml @@ -13,6 +13,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" bp-runtime = { path = "../runtime", default-features = false } # Substrate Based Dependencies + frame-support = { version = "2.0", default-features = false } sp-api = { version = "2.0", default-features = false } sp-core = { version = "2.0", default-features = false } diff --git a/bridges/primitives/rialto/src/lib.rs b/bridges/primitives/rialto/src/lib.rs index ea20d72ab022..7e761a72031d 100644 --- a/bridges/primitives/rialto/src/lib.rs +++ b/bridges/primitives/rialto/src/lib.rs @@ -21,11 +21,22 @@ #![allow(clippy::unnecessary_mut_passed)] use bp_runtime::Chain; -use frame_support::RuntimeDebug; +use frame_support::{weights::Weight, RuntimeDebug}; use sp_core::Hasher as HasherT; -use sp_runtime::traits::BlakeTwo256; +use sp_runtime::{ + traits::{BlakeTwo256, IdentifyAccount, Verify}, + MultiSignature, MultiSigner, +}; use sp_std::prelude::*; +/// Maximal weight of single Millau block. +pub const MAXIMUM_BLOCK_WEIGHT: Weight = 2_000_000_000_000; +/// Portion of block reserved for regular transactions. +pub const AVAILABLE_BLOCK_RATIO: u32 = 75; +/// Maximal weight of single Millau extrinsic (65% of maximum block weight = 75% for regular +/// transactions minus 10% for initialization). +pub const MAXIMUM_EXTRINSIC_WEIGHT: Weight = MAXIMUM_BLOCK_WEIGHT / 100 * (AVAILABLE_BLOCK_RATIO as Weight - 10); + /// Block number type used in Rialto. pub type BlockNumber = u32; @@ -49,6 +60,19 @@ impl Chain for Rialto { type Header = Header; } +/// Alias to 512-bit hash when used in the context of a transaction signature on the chain. +pub type Signature = MultiSignature; + +/// Some way of identifying an account on the chain. We intentionally make it equivalent +/// to the public key of our transaction signing scheme. +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; + +/// Public key of the chain account that may be used to verify signatures. +pub type AccountSigner = MultiSigner; + +/// Balance of an account. +pub type Balance = u128; + sp_api::decl_runtime_apis! { /// API for querying information about Rialto headers from the Bridge Pallet instance. /// diff --git a/bridges/primitives/runtime/src/lib.rs b/bridges/primitives/runtime/src/lib.rs index 6a826da3af74..a7894554c359 100644 --- a/bridges/primitives/runtime/src/lib.rs +++ b/bridges/primitives/runtime/src/lib.rs @@ -25,9 +25,15 @@ pub use chain::{BlockNumberOf, Chain, HashOf, HasherOf, HeaderOf}; mod chain; +/// Use this when something must be shared among all instances. +pub const NO_INSTANCE_ID: InstanceId = [0, 0, 0, 0]; + /// Call-dispatch module prefix. pub const CALL_DISPATCH_MODULE_PREFIX: &[u8] = b"pallet-bridge/call-dispatch"; +/// Message-lane module prefix. +pub const MESSAGE_LANE_MODULE_PREFIX: &[u8] = b"pallet-bridge/message-lane"; + /// Id of deployed module instance. We have a bunch of pallets that may be used in /// different bridges. E.g. message-lane pallet may be deployed twice in the same /// runtime to bridge ThisChain with Chain1 and Chain2. Sometimes we need to be able