mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 23:21:02 +00:00
Integrate Rialto <-> Millau message lanes into Millau/Rialto runtimes (#386)
* millau -> rialto lanes integration * extrace common message-lane integration types into bridge-runtime-common * rialto_messages.rs in Millau runtime * tests * Update bin/rialto/runtime/src/millau_messages.rs Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com> * RELAYER_INTEREST_PERCENT -> RELAYER_FEE_PERCENT * Update bin/runtime-common/src/messages.rs Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com> * estimate_message_dispatch_and_delivery_fee returns Result * Update bin/rialto/runtime/src/millau_messages.rs Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com> * Update bin/rialto/runtime/src/millau_messages.rs Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com> * Update bin/rialto/runtime/src/millau_messages.rs Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com> * fmt * mowed weight formula to primitives Co-authored-by: Hernando Castano <HCastano@users.noreply.github.com>
This commit is contained in:
committed by
Bastian Köcher
parent
3738bc4277
commit
e2d9b6393d
@@ -17,6 +17,8 @@ serde = { version = "1.0.117", optional = true, features = ["derive"] }
|
|||||||
bp-message-lane = { path = "../../../primitives/message-lane", default-features = false }
|
bp-message-lane = { path = "../../../primitives/message-lane", default-features = false }
|
||||||
bp-millau = { path = "../../../primitives/millau", default-features = false }
|
bp-millau = { path = "../../../primitives/millau", default-features = false }
|
||||||
bp-rialto = { path = "../../../primitives/rialto", 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-bridge-call-dispatch = { path = "../../../modules/call-dispatch", default-features = false }
|
||||||
pallet-message-lane = { path = "../../../modules/message-lane", 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 }
|
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-session = { version = "2.0", default-features = false }
|
||||||
sp-std = { version = "2.0", default-features = false }
|
sp-std = { version = "2.0", default-features = false }
|
||||||
sp-transaction-pool = { 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 }
|
sp-version = { version = "2.0", default-features = false }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
@@ -58,6 +61,8 @@ std = [
|
|||||||
"bp-message-lane/std",
|
"bp-message-lane/std",
|
||||||
"bp-millau/std",
|
"bp-millau/std",
|
||||||
"bp-rialto/std",
|
"bp-rialto/std",
|
||||||
|
"bp-runtime/std",
|
||||||
|
"bridge-runtime-common/std",
|
||||||
"codec/std",
|
"codec/std",
|
||||||
"frame-executive/std",
|
"frame-executive/std",
|
||||||
"frame-support/std",
|
"frame-support/std",
|
||||||
@@ -87,5 +92,6 @@ std = [
|
|||||||
"sp-session/std",
|
"sp-session/std",
|
||||||
"sp-std/std",
|
"sp-std/std",
|
||||||
"sp-transaction-pool/std",
|
"sp-transaction-pool/std",
|
||||||
|
"sp-trie/std",
|
||||||
"sp-version/std",
|
"sp-version/std",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -29,12 +29,13 @@
|
|||||||
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
|
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
|
||||||
|
|
||||||
pub mod rialto;
|
pub mod rialto;
|
||||||
|
pub mod rialto_messages;
|
||||||
|
|
||||||
use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList};
|
use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList};
|
||||||
use sp_api::impl_runtime_apis;
|
use sp_api::impl_runtime_apis;
|
||||||
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
|
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
|
||||||
use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
|
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::{
|
use sp_runtime::{
|
||||||
create_runtime_str, generic, impl_opaque_keys,
|
create_runtime_str, generic, impl_opaque_keys,
|
||||||
transaction_validity::{TransactionSource, TransactionValidity},
|
transaction_validity::{TransactionSource, TransactionValidity},
|
||||||
@@ -65,18 +66,18 @@ pub use sp_runtime::{Perbill, Permill};
|
|||||||
pub type BlockNumber = bp_millau::BlockNumber;
|
pub type BlockNumber = bp_millau::BlockNumber;
|
||||||
|
|
||||||
/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
|
/// 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
|
/// Some way of identifying an account on the chain. We intentionally make it equivalent
|
||||||
/// to the public key of our transaction signing scheme.
|
/// to the public key of our transaction signing scheme.
|
||||||
pub type AccountId = <<Signature as Verify>::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
|
/// The type for looking up accounts. We don't expect more than 4 billion of them, but you
|
||||||
/// never know...
|
/// never know...
|
||||||
pub type AccountIndex = u32;
|
pub type AccountIndex = u32;
|
||||||
|
|
||||||
/// Balance of an account.
|
/// Balance of an account.
|
||||||
pub type Balance = u128;
|
pub type Balance = bp_millau::Balance;
|
||||||
|
|
||||||
/// Index of a transaction in the chain.
|
/// Index of a transaction in the chain.
|
||||||
pub type Index = u32;
|
pub type Index = u32;
|
||||||
@@ -145,12 +146,10 @@ pub fn native_version() -> NativeVersion {
|
|||||||
|
|
||||||
parameter_types! {
|
parameter_types! {
|
||||||
pub const BlockHashCount: BlockNumber = 250;
|
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 ExtrinsicBaseWeight: Weight = 10_000_000;
|
||||||
pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);
|
pub const AvailableBlockRatio: Perbill = Perbill::from_percent(bp_millau::AVAILABLE_BLOCK_RATIO);
|
||||||
/// Assume 10% of weight for average on_initialize calls.
|
pub MaximumExtrinsicWeight: Weight = bp_millau::MAXIMUM_EXTRINSIC_WEIGHT;
|
||||||
pub MaximumExtrinsicWeight: Weight = AvailableBlockRatio::get()
|
|
||||||
.saturating_sub(Perbill::from_percent(10)) * MaximumBlockWeight::get();
|
|
||||||
pub const MaximumBlockLength: u32 = 5 * 1024 * 1024;
|
pub const MaximumBlockLength: u32 = 5 * 1024 * 1024;
|
||||||
pub const Version: RuntimeVersion = VERSION;
|
pub const Version: RuntimeVersion = VERSION;
|
||||||
pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight {
|
pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight {
|
||||||
@@ -317,6 +316,32 @@ impl pallet_substrate_bridge::Trait for Runtime {
|
|||||||
|
|
||||||
impl pallet_shift_session_manager::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<AccountId, pallet_balances::Module<Runtime>>;
|
||||||
|
|
||||||
|
type SourceHeaderChain = crate::rialto_messages::Rialto;
|
||||||
|
type MessageDispatch = crate::rialto_messages::FromRialtoMessageDispatch;
|
||||||
|
}
|
||||||
|
|
||||||
construct_runtime!(
|
construct_runtime!(
|
||||||
pub enum Runtime where
|
pub enum Runtime where
|
||||||
Block = Block,
|
Block = Block,
|
||||||
@@ -324,6 +349,7 @@ construct_runtime!(
|
|||||||
UncheckedExtrinsic = UncheckedExtrinsic
|
UncheckedExtrinsic = UncheckedExtrinsic
|
||||||
{
|
{
|
||||||
BridgeRialto: pallet_substrate_bridge::{Module, Call, Storage, Config<T>},
|
BridgeRialto: pallet_substrate_bridge::{Module, Call, Storage, Config<T>},
|
||||||
|
BridgeRialtoMessageLane: pallet_message_lane::{Module, Call, Event<T>},
|
||||||
BridgeCallDispatch: pallet_bridge_call_dispatch::{Module, Event<T>},
|
BridgeCallDispatch: pallet_bridge_call_dispatch::{Module, Event<T>},
|
||||||
System: frame_system::{Module, Call, Config, Storage, Event<T>},
|
System: frame_system::{Module, Call, Config, Storage, Event<T>},
|
||||||
RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Module, Call, Storage},
|
RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Module, Call, Storage},
|
||||||
|
|||||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! 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<WithRialtoMessageBridge>;
|
||||||
|
|
||||||
|
/// Message verifier for Millau -> Rialto messages.
|
||||||
|
pub type ToRialtoMessageVerifier = messages::source::FromThisChainMessageVerifier<WithRialtoMessageBridge>;
|
||||||
|
|
||||||
|
/// Message payload for Rialto -> Millau messages.
|
||||||
|
pub type FromRialtoMessagePayload = messages::target::FromBridgedChainMessagePayload<WithRialtoMessageBridge>;
|
||||||
|
|
||||||
|
/// 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 {
|
||||||
|
<crate::Runtime as pallet_transaction_payment::Trait>::WeightToFee::calc(&weight)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bridged_weight_to_balance(weight: Weight) -> bp_millau::Balance {
|
||||||
|
// we're using the same weights in both chains now
|
||||||
|
<crate::Runtime as pallet_transaction_payment::Trait>::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<ToRialtoMessagePayload, bp_rialto::AccountId> 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<bp_rialto::AccountId>), Self::Error> {
|
||||||
|
unimplemented!("https://github.com/paritytech/parity-bridges-common/issues/397")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SourceHeaderChain<bp_rialto::Balance> 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<ProvedMessages<Message<bp_rialto::Balance>>, Self::Error> {
|
||||||
|
unimplemented!("https://github.com/paritytech/parity-bridges-common/issues/397")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,9 +18,12 @@ serde = { version = "1.0.117", optional = true, features = ["derive"] }
|
|||||||
bp-currency-exchange = { path = "../../../primitives/currency-exchange", default-features = false }
|
bp-currency-exchange = { path = "../../../primitives/currency-exchange", default-features = false }
|
||||||
bp-eth-poa = { path = "../../../primitives/ethereum-poa", default-features = false }
|
bp-eth-poa = { path = "../../../primitives/ethereum-poa", default-features = false }
|
||||||
bp-header-chain = { path = "../../../primitives/header-chain", 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-message-lane = { path = "../../../primitives/message-lane", default-features = false }
|
||||||
bp-millau = { path = "../../../primitives/millau", default-features = false }
|
bp-millau = { path = "../../../primitives/millau", default-features = false }
|
||||||
bp-rialto = { path = "../../../primitives/rialto", 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-eth-poa = { path = "../../../modules/ethereum", default-features = false }
|
||||||
pallet-bridge-call-dispatch = { path = "../../../modules/call-dispatch", 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 }
|
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-session = { version = "2.0", default-features = false }
|
||||||
sp-std = { version = "2.0", default-features = false }
|
sp-std = { version = "2.0", default-features = false }
|
||||||
sp-transaction-pool = { 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 }
|
sp-version = { version = "2.0", default-features = false }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
@@ -69,9 +73,12 @@ std = [
|
|||||||
"bp-currency-exchange/std",
|
"bp-currency-exchange/std",
|
||||||
"bp-eth-poa/std",
|
"bp-eth-poa/std",
|
||||||
"bp-header-chain/std",
|
"bp-header-chain/std",
|
||||||
|
"bp-message-dispatch/std",
|
||||||
"bp-message-lane/std",
|
"bp-message-lane/std",
|
||||||
"bp-rialto/std",
|
|
||||||
"bp-millau/std",
|
"bp-millau/std",
|
||||||
|
"bp-rialto/std",
|
||||||
|
"bp-runtime/std",
|
||||||
|
"bridge-runtime-common/std",
|
||||||
"codec/std",
|
"codec/std",
|
||||||
"frame-benchmarking/std",
|
"frame-benchmarking/std",
|
||||||
"frame-executive/std",
|
"frame-executive/std",
|
||||||
@@ -104,6 +111,7 @@ std = [
|
|||||||
"sp-session/std",
|
"sp-session/std",
|
||||||
"sp-std/std",
|
"sp-std/std",
|
||||||
"sp-transaction-pool/std",
|
"sp-transaction-pool/std",
|
||||||
|
"sp-trie/std",
|
||||||
"sp-version/std",
|
"sp-version/std",
|
||||||
]
|
]
|
||||||
runtime-benchmarks = [
|
runtime-benchmarks = [
|
||||||
|
|||||||
@@ -34,13 +34,14 @@ pub mod exchange;
|
|||||||
pub mod benches;
|
pub mod benches;
|
||||||
pub mod kovan;
|
pub mod kovan;
|
||||||
pub mod millau;
|
pub mod millau;
|
||||||
|
pub mod millau_messages;
|
||||||
pub mod rialto_poa;
|
pub mod rialto_poa;
|
||||||
|
|
||||||
use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList};
|
use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList};
|
||||||
use sp_api::impl_runtime_apis;
|
use sp_api::impl_runtime_apis;
|
||||||
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
|
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
|
||||||
use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
|
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::{
|
use sp_runtime::{
|
||||||
create_runtime_str, generic, impl_opaque_keys,
|
create_runtime_str, generic, impl_opaque_keys,
|
||||||
transaction_validity::{TransactionSource, TransactionValidity},
|
transaction_validity::{TransactionSource, TransactionValidity},
|
||||||
@@ -73,18 +74,18 @@ pub use sp_runtime::{Perbill, Permill};
|
|||||||
pub type BlockNumber = bp_rialto::BlockNumber;
|
pub type BlockNumber = bp_rialto::BlockNumber;
|
||||||
|
|
||||||
/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
|
/// 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
|
/// Some way of identifying an account on the chain. We intentionally make it equivalent
|
||||||
/// to the public key of our transaction signing scheme.
|
/// to the public key of our transaction signing scheme.
|
||||||
pub type AccountId = <<Signature as Verify>::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
|
/// The type for looking up accounts. We don't expect more than 4 billion of them, but you
|
||||||
/// never know...
|
/// never know...
|
||||||
pub type AccountIndex = u32;
|
pub type AccountIndex = u32;
|
||||||
|
|
||||||
/// Balance of an account.
|
/// Balance of an account.
|
||||||
pub type Balance = u128;
|
pub type Balance = bp_rialto::Balance;
|
||||||
|
|
||||||
/// Index of a transaction in the chain.
|
/// Index of a transaction in the chain.
|
||||||
pub type Index = u32;
|
pub type Index = u32;
|
||||||
@@ -153,12 +154,10 @@ pub fn native_version() -> NativeVersion {
|
|||||||
|
|
||||||
parameter_types! {
|
parameter_types! {
|
||||||
pub const BlockHashCount: BlockNumber = 250;
|
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 ExtrinsicBaseWeight: Weight = 10_000_000;
|
||||||
pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);
|
pub const AvailableBlockRatio: Perbill = Perbill::from_percent(bp_rialto::AVAILABLE_BLOCK_RATIO);
|
||||||
/// Assume 10% of weight for average on_initialize calls.
|
pub MaximumExtrinsicWeight: Weight = bp_rialto::MAXIMUM_EXTRINSIC_WEIGHT;
|
||||||
pub MaximumExtrinsicWeight: Weight = AvailableBlockRatio::get()
|
|
||||||
.saturating_sub(Perbill::from_percent(10)) * MaximumBlockWeight::get();
|
|
||||||
pub const MaximumBlockLength: u32 = 5 * 1024 * 1024;
|
pub const MaximumBlockLength: u32 = 5 * 1024 * 1024;
|
||||||
pub const Version: RuntimeVersion = VERSION;
|
pub const Version: RuntimeVersion = VERSION;
|
||||||
pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight {
|
pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight {
|
||||||
@@ -425,6 +424,32 @@ impl pallet_substrate_bridge::Trait for Runtime {
|
|||||||
|
|
||||||
impl pallet_shift_session_manager::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<AccountId, pallet_balances::Module<Runtime>>;
|
||||||
|
|
||||||
|
type SourceHeaderChain = crate::millau_messages::Millau;
|
||||||
|
type MessageDispatch = crate::millau_messages::FromMillauMessageDispatch;
|
||||||
|
}
|
||||||
|
|
||||||
construct_runtime!(
|
construct_runtime!(
|
||||||
pub enum Runtime where
|
pub enum Runtime where
|
||||||
Block = Block,
|
Block = Block,
|
||||||
@@ -437,6 +462,7 @@ construct_runtime!(
|
|||||||
BridgeKovanCurrencyExchange: pallet_bridge_currency_exchange::<Instance2>::{Module, Call},
|
BridgeKovanCurrencyExchange: pallet_bridge_currency_exchange::<Instance2>::{Module, Call},
|
||||||
BridgeMillau: pallet_substrate_bridge::{Module, Call, Storage, Config<T>},
|
BridgeMillau: pallet_substrate_bridge::{Module, Call, Storage, Config<T>},
|
||||||
BridgeCallDispatch: pallet_bridge_call_dispatch::{Module, Event<T>},
|
BridgeCallDispatch: pallet_bridge_call_dispatch::{Module, Event<T>},
|
||||||
|
BridgeMillauMessageLane: pallet_message_lane::{Module, Call, Event<T>},
|
||||||
System: frame_system::{Module, Call, Config, Storage, Event<T>},
|
System: frame_system::{Module, Call, Config, Storage, Event<T>},
|
||||||
RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Module, Call, Storage},
|
RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Module, Call, Storage},
|
||||||
Timestamp: pallet_timestamp::{Module, Call, Storage, Inherent},
|
Timestamp: pallet_timestamp::{Module, Call, Storage, Inherent},
|
||||||
|
|||||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! 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<WithMillauMessageBridge>;
|
||||||
|
|
||||||
|
/// Message verifier for Rialto -> Millau messages.
|
||||||
|
pub type ToMillauMessageVerifier = messages::source::FromThisChainMessageVerifier<WithMillauMessageBridge>;
|
||||||
|
|
||||||
|
/// Message payload for Millau -> Rialto messages.
|
||||||
|
pub type FromMillauMessagePayload = messages::target::FromBridgedChainMessagePayload<WithMillauMessageBridge>;
|
||||||
|
|
||||||
|
/// 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 {
|
||||||
|
<crate::Runtime as pallet_transaction_payment::Trait>::WeightToFee::calc(&weight)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bridged_weight_to_balance(weight: Weight) -> bp_millau::Balance {
|
||||||
|
// we're using the same weights in both chains now
|
||||||
|
<crate::Runtime as pallet_transaction_payment::Trait>::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<ToMillauMessagePayload, bp_millau::AccountId> 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<bp_millau::AccountId>), Self::Error> {
|
||||||
|
unimplemented!("https://github.com/paritytech/parity-bridges-common/issues/397")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SourceHeaderChain<bp_millau::Balance> 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<ProvedMessages<Message<bp_millau::Balance>>, Self::Error> {
|
||||||
|
unimplemented!("https://github.com/paritytech/parity-bridges-common/issues/397")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
[package]
|
||||||
|
name = "bridge-runtime-common"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
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",
|
||||||
|
]
|
||||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Common types/functions that may be used by runtimes of all bridged chains.
|
||||||
|
|
||||||
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
|
pub mod messages;
|
||||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! 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<BridgedChain<Self>>;
|
||||||
|
|
||||||
|
/// Maximal weight of single message delivery transaction on Bridged chain.
|
||||||
|
fn weight_of_delivery_transaction() -> WeightOf<BridgedChain<Self>>;
|
||||||
|
|
||||||
|
/// Maximal weight of single message delivery confirmation transaction on This chain.
|
||||||
|
fn weight_of_delivery_confirmation_transaction_on_this_chain() -> WeightOf<ThisChain<Self>>;
|
||||||
|
|
||||||
|
/// 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<BridgedChain<Self>>;
|
||||||
|
|
||||||
|
/// Convert weight of This chain to the fee (paid in Balance) of This chain.
|
||||||
|
fn this_weight_to_balance(weight: WeightOf<ThisChain<Self>>) -> BalanceOf<ThisChain<Self>>;
|
||||||
|
|
||||||
|
/// Convert weight of the Bridged chain to the fee (paid in Balance) of the Bridged chain.
|
||||||
|
fn bridged_weight_to_balance(weight: WeightOf<BridgedChain<Self>>) -> BalanceOf<BridgedChain<Self>>;
|
||||||
|
|
||||||
|
/// Convert This chain Balance into Bridged chain Balance.
|
||||||
|
fn this_chain_balance_to_bridged_chain_balance(
|
||||||
|
this_balance: BalanceOf<ThisChain<Self>>,
|
||||||
|
) -> BalanceOf<BridgedChain<Self>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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<frame_support::weights::Weight>;
|
||||||
|
/// Type of balances that is used on the chain.
|
||||||
|
type Balance: CheckedAdd + CheckedDiv + CheckedMul + PartialOrd + From<u32> + Copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) type ThisChain<B> = <B as MessageBridge>::ThisChain;
|
||||||
|
pub(crate) type BridgedChain<B> = <B as MessageBridge>::BridgedChain;
|
||||||
|
pub(crate) type AccountIdOf<C> = <C as ChainWithMessageLanes>::AccountId;
|
||||||
|
pub(crate) type SignerOf<C> = <C as ChainWithMessageLanes>::Signer;
|
||||||
|
pub(crate) type SignatureOf<C> = <C as ChainWithMessageLanes>::Signature;
|
||||||
|
pub(crate) type WeightOf<C> = <C as ChainWithMessageLanes>::Weight;
|
||||||
|
pub(crate) type BalanceOf<C> = <C as ChainWithMessageLanes>::Balance;
|
||||||
|
pub(crate) type CallOf<C> = <C as ChainWithMessageLanes>::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<u8>;
|
||||||
|
|
||||||
|
/// Message payload for This -> Bridged chain messages.
|
||||||
|
pub type FromThisChainMessagePayload<B> = pallet_bridge_call_dispatch::MessagePayload<
|
||||||
|
SignerOf<ThisChain<B>>,
|
||||||
|
SignerOf<BridgedChain<B>>,
|
||||||
|
SignatureOf<BridgedChain<B>>,
|
||||||
|
BridgedChainOpaqueCall,
|
||||||
|
>;
|
||||||
|
|
||||||
|
/// Message verifier that requires submitter to pay minimal delivery and dispatch fee.
|
||||||
|
#[derive(RuntimeDebug)]
|
||||||
|
pub struct FromThisChainMessageVerifier<B>(PhantomData<B>);
|
||||||
|
|
||||||
|
impl<B: MessageBridge>
|
||||||
|
LaneMessageVerifier<AccountIdOf<ThisChain<B>>, FromThisChainMessagePayload<B>, BalanceOf<ThisChain<B>>>
|
||||||
|
for FromThisChainMessageVerifier<B>
|
||||||
|
{
|
||||||
|
type Error = &'static str;
|
||||||
|
|
||||||
|
fn verify_message(
|
||||||
|
_submitter: &AccountIdOf<ThisChain<B>>,
|
||||||
|
delivery_and_dispatch_fee: &BalanceOf<ThisChain<B>>,
|
||||||
|
_lane: &LaneId,
|
||||||
|
payload: &FromThisChainMessagePayload<B>,
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
let minimal_fee_in_bridged_tokens =
|
||||||
|
estimate_message_dispatch_and_delivery_fee::<B>(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<B: MessageBridge>(
|
||||||
|
payload: &FromThisChainMessagePayload<B>,
|
||||||
|
relayer_fee_percent: u32,
|
||||||
|
) -> Result<BalanceOf<BridgedChain<B>>, &'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<B> = pallet_bridge_call_dispatch::CallOrigin<
|
||||||
|
SignerOf<BridgedChain<B>>,
|
||||||
|
SignerOf<ThisChain<B>>,
|
||||||
|
SignatureOf<ThisChain<B>>,
|
||||||
|
>;
|
||||||
|
|
||||||
|
/// Decoded Bridged -> This message payload.
|
||||||
|
pub type FromBridgedChainDecodedMessagePayload<B> = pallet_bridge_call_dispatch::MessagePayload<
|
||||||
|
SignerOf<BridgedChain<B>>,
|
||||||
|
SignerOf<ThisChain<B>>,
|
||||||
|
SignatureOf<ThisChain<B>>,
|
||||||
|
CallOf<ThisChain<B>>,
|
||||||
|
>;
|
||||||
|
|
||||||
|
/// Message payload for Bridged -> This messages.
|
||||||
|
pub struct FromBridgedChainMessagePayload<B: MessageBridge>(pub(crate) FromBridgedChainDecodedMessagePayload<B>);
|
||||||
|
|
||||||
|
impl<B: MessageBridge> Decode for FromBridgedChainMessagePayload<B> {
|
||||||
|
fn decode<I: Input>(input: &mut I) -> Result<Self, codec::Error> {
|
||||||
|
// for bridged chain our Calls are opaque - they're encoded to Vec<u8> 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::<B>::decode(input)?;
|
||||||
|
let _skipped_length = Compact::<u32>::decode(input)?;
|
||||||
|
let call = CallOf::<ThisChain<B>>::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<B, ThisRuntime, ThisCallDispatchInstance> {
|
||||||
|
_marker: PhantomData<(B, ThisRuntime, ThisCallDispatchInstance)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: MessageBridge, ThisRuntime, ThisCallDispatchInstance>
|
||||||
|
MessageDispatch<<BridgedChain<B> as ChainWithMessageLanes>::Balance>
|
||||||
|
for FromBridgedChainMessageDispatch<B, ThisRuntime, ThisCallDispatchInstance>
|
||||||
|
where
|
||||||
|
ThisCallDispatchInstance: frame_support::traits::Instance,
|
||||||
|
ThisRuntime: pallet_bridge_call_dispatch::Trait<ThisCallDispatchInstance>,
|
||||||
|
pallet_bridge_call_dispatch::Module<ThisRuntime, ThisCallDispatchInstance>:
|
||||||
|
bp_message_dispatch::MessageDispatch<
|
||||||
|
(LaneId, MessageNonce),
|
||||||
|
Message = FromBridgedChainDecodedMessagePayload<B>,
|
||||||
|
>,
|
||||||
|
{
|
||||||
|
type DispatchPayload = FromBridgedChainMessagePayload<B>;
|
||||||
|
|
||||||
|
fn dispatch_weight(
|
||||||
|
message: &DispatchMessage<Self::DispatchPayload, BalanceOf<BridgedChain<B>>>,
|
||||||
|
) -> frame_support::weights::Weight {
|
||||||
|
message
|
||||||
|
.data
|
||||||
|
.payload
|
||||||
|
.as_ref()
|
||||||
|
.map(|payload| payload.0.weight)
|
||||||
|
.unwrap_or(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dispatch(message: DispatchMessage<Self::DispatchPayload, BalanceOf<BridgedChain<B>>>) {
|
||||||
|
if let Ok(payload) = message.data.payload {
|
||||||
|
pallet_bridge_call_dispatch::Module::<ThisRuntime, ThisCallDispatchInstance>::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<u32> 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<sp_std::cmp::Ordering> {
|
||||||
|
self.0.partial_cmp(&other.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CheckedAdd for $name {
|
||||||
|
fn checked_add(&self, other: &Self) -> Option<Self> {
|
||||||
|
self.0.checked_add(other.0).map(Self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CheckedDiv for $name {
|
||||||
|
fn checked_div(&self, other: &Self) -> Option<Self> {
|
||||||
|
self.0.checked_div(other.0).map(Self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CheckedMul for $name {
|
||||||
|
fn checked_mul(&self, other: &Self) -> Option<Self> {
|
||||||
|
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::<OnBridgedChainBridge> {
|
||||||
|
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::<OnThisChainBridge>::decode(&mut &message_on_bridged_chain[..])
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
message_on_this_chain.0,
|
||||||
|
target::FromBridgedChainDecodedMessagePayload::<OnThisChainBridge> {
|
||||||
|
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::<OnThisChainBridge> {
|
||||||
|
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::<OnThisChainBridge>(
|
||||||
|
&payload,
|
||||||
|
OnThisChainBridge::RELAYER_FEE_PERCENT,
|
||||||
|
),
|
||||||
|
Ok(BridgedChainBalance(EXPECTED_MINIMAL_FEE)),
|
||||||
|
);
|
||||||
|
|
||||||
|
// and now check that the verifier checks the fee
|
||||||
|
assert!(
|
||||||
|
source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
|
||||||
|
&ThisChainAccountId(0),
|
||||||
|
&ThisChainBalance(1),
|
||||||
|
&*b"test",
|
||||||
|
&payload,
|
||||||
|
)
|
||||||
|
.is_err(),
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
source::FromThisChainMessageVerifier::<OnThisChainBridge>::verify_message(
|
||||||
|
&ThisChainAccountId(0),
|
||||||
|
&ThisChainBalance(1_000_000),
|
||||||
|
&*b"test",
|
||||||
|
&payload,
|
||||||
|
)
|
||||||
|
.is_ok(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -47,7 +47,7 @@ use sp_std::{marker::PhantomData, prelude::*};
|
|||||||
pub type SpecVersion = u32;
|
pub type SpecVersion = u32;
|
||||||
|
|
||||||
/// Origin of the call on the target chain.
|
/// Origin of the call on the target chain.
|
||||||
#[derive(RuntimeDebug, Encode, Decode, Clone)]
|
#[derive(RuntimeDebug, Encode, Decode, Clone, PartialEq, Eq)]
|
||||||
pub enum CallOrigin<SourceChainAccountPublic, TargetChainAccountPublic, TargetChainSignature> {
|
pub enum CallOrigin<SourceChainAccountPublic, TargetChainAccountPublic, TargetChainSignature> {
|
||||||
/// Call is originated from bridge account, which is (designed to be) specific to
|
/// Call is originated from bridge account, which is (designed to be) specific to
|
||||||
/// the single deployed instance of the messages bridge (message-lane, ...) module.
|
/// the single deployed instance of the messages bridge (message-lane, ...) module.
|
||||||
@@ -67,7 +67,7 @@ pub enum CallOrigin<SourceChainAccountPublic, TargetChainAccountPublic, TargetCh
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Message payload type used by call-dispatch module.
|
/// Message payload type used by call-dispatch module.
|
||||||
#[derive(RuntimeDebug, Encode, Decode, Clone)]
|
#[derive(RuntimeDebug, Encode, Decode, Clone, PartialEq, Eq)]
|
||||||
pub struct MessagePayload<SourceChainAccountPublic, TargetChainAccountPublic, TargetChainSignature, Call> {
|
pub struct MessagePayload<SourceChainAccountPublic, TargetChainAccountPublic, TargetChainSignature, Call> {
|
||||||
/// Runtime specification version. We only dispatch messages that have the same
|
/// Runtime specification version. We only dispatch messages that have the same
|
||||||
/// runtime version. Otherwise we risk to misinterpret encoded calls.
|
/// runtime version. Otherwise we risk to misinterpret encoded calls.
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ codec = { package = "parity-scale-codec", version = "1.3.1", default-features =
|
|||||||
# Bridge dependencies
|
# Bridge dependencies
|
||||||
|
|
||||||
bp-message-lane = { path = "../../primitives/message-lane", default-features = false }
|
bp-message-lane = { path = "../../primitives/message-lane", default-features = false }
|
||||||
|
bp-runtime = { path = "../../primitives/runtime", default-features = false }
|
||||||
|
|
||||||
# Substrate Dependencies
|
# Substrate Dependencies
|
||||||
|
|
||||||
@@ -28,6 +29,7 @@ sp-io = "2.0"
|
|||||||
default = ["std"]
|
default = ["std"]
|
||||||
std = [
|
std = [
|
||||||
"bp-message-lane/std",
|
"bp-message-lane/std",
|
||||||
|
"bp-runtime/std",
|
||||||
"codec/std",
|
"codec/std",
|
||||||
"frame-support/std",
|
"frame-support/std",
|
||||||
"frame-system/std",
|
"frame-system/std",
|
||||||
|
|||||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! 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<AccountId, Currency> {
|
||||||
|
_phantom: sp_std::marker::PhantomData<(AccountId, Currency)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<AccountId, Currency> MessageDeliveryAndDispatchPayment<AccountId, Currency::Balance>
|
||||||
|
for InstantCurrencyPayments<AccountId, Currency>
|
||||||
|
where
|
||||||
|
Currency: CurrencyT<AccountId>,
|
||||||
|
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: Default + Decode>() -> AccountId {
|
||||||
|
bridge_account_id(NO_INSTANCE_ID, MESSAGE_LANE_MODULE_PREFIX)
|
||||||
|
}
|
||||||
@@ -48,6 +48,8 @@ use sp_std::{cell::RefCell, marker::PhantomData, prelude::*};
|
|||||||
mod inbound_lane;
|
mod inbound_lane;
|
||||||
mod outbound_lane;
|
mod outbound_lane;
|
||||||
|
|
||||||
|
pub mod instant_payments;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod mock;
|
mod mock;
|
||||||
|
|
||||||
|
|||||||
@@ -21,11 +21,22 @@
|
|||||||
#![allow(clippy::unnecessary_mut_passed)]
|
#![allow(clippy::unnecessary_mut_passed)]
|
||||||
|
|
||||||
use bp_runtime::Chain;
|
use bp_runtime::Chain;
|
||||||
use frame_support::RuntimeDebug;
|
use frame_support::{weights::Weight, RuntimeDebug};
|
||||||
use sp_core::Hasher as HasherT;
|
use sp_core::Hasher as HasherT;
|
||||||
use sp_runtime::traits::BlakeTwo256;
|
use sp_runtime::{
|
||||||
|
traits::{BlakeTwo256, IdentifyAccount, Verify},
|
||||||
|
MultiSignature, MultiSigner,
|
||||||
|
};
|
||||||
use sp_std::prelude::*;
|
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.
|
/// Block number type used in Millau.
|
||||||
pub type BlockNumber = u32;
|
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.
|
/// Name of the `MillauHeaderApi::incomplete_headers` runtime method.
|
||||||
pub const INCOMPLETE_MILLAU_HEADERS_METHOD: &str = "MillauHeaderApi_incomplete_headers";
|
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 = <<Signature as Verify>::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! {
|
sp_api::decl_runtime_apis! {
|
||||||
/// API for querying information about Millau headers from the Bridge Pallet instance.
|
/// API for querying information about Millau headers from the Bridge Pallet instance.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
|
|||||||
bp-runtime = { path = "../runtime", default-features = false }
|
bp-runtime = { path = "../runtime", default-features = false }
|
||||||
|
|
||||||
# Substrate Based Dependencies
|
# Substrate Based Dependencies
|
||||||
|
|
||||||
frame-support = { version = "2.0", default-features = false }
|
frame-support = { version = "2.0", default-features = false }
|
||||||
sp-api = { version = "2.0", default-features = false }
|
sp-api = { version = "2.0", default-features = false }
|
||||||
sp-core = { version = "2.0", default-features = false }
|
sp-core = { version = "2.0", default-features = false }
|
||||||
|
|||||||
@@ -21,11 +21,22 @@
|
|||||||
#![allow(clippy::unnecessary_mut_passed)]
|
#![allow(clippy::unnecessary_mut_passed)]
|
||||||
|
|
||||||
use bp_runtime::Chain;
|
use bp_runtime::Chain;
|
||||||
use frame_support::RuntimeDebug;
|
use frame_support::{weights::Weight, RuntimeDebug};
|
||||||
use sp_core::Hasher as HasherT;
|
use sp_core::Hasher as HasherT;
|
||||||
use sp_runtime::traits::BlakeTwo256;
|
use sp_runtime::{
|
||||||
|
traits::{BlakeTwo256, IdentifyAccount, Verify},
|
||||||
|
MultiSignature, MultiSigner,
|
||||||
|
};
|
||||||
use sp_std::prelude::*;
|
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.
|
/// Block number type used in Rialto.
|
||||||
pub type BlockNumber = u32;
|
pub type BlockNumber = u32;
|
||||||
|
|
||||||
@@ -49,6 +60,19 @@ impl Chain for Rialto {
|
|||||||
type Header = Header;
|
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 = <<Signature as Verify>::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! {
|
sp_api::decl_runtime_apis! {
|
||||||
/// API for querying information about Rialto headers from the Bridge Pallet instance.
|
/// API for querying information about Rialto headers from the Bridge Pallet instance.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -25,9 +25,15 @@ pub use chain::{BlockNumberOf, Chain, HashOf, HasherOf, HeaderOf};
|
|||||||
|
|
||||||
mod chain;
|
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.
|
/// Call-dispatch module prefix.
|
||||||
pub const CALL_DISPATCH_MODULE_PREFIX: &[u8] = b"pallet-bridge/call-dispatch";
|
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
|
/// 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
|
/// 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
|
/// runtime to bridge ThisChain with Chain1 and Chain2. Sometimes we need to be able
|
||||||
|
|||||||
Reference in New Issue
Block a user