diff --git a/bridges/bin/millau/node/Cargo.toml b/bridges/bin/millau/node/Cargo.toml
index b650bd478a62..c4438d0cef3e 100644
--- a/bridges/bin/millau/node/Cargo.toml
+++ b/bridges/bin/millau/node/Cargo.toml
@@ -23,9 +23,13 @@ pallet-bridge-messages = { path = "../../../modules/messages" }
# Substrate Dependencies
+beefy-gadget = { git = "https://github.com/paritytech/substrate", branch = "master" }
+beefy-gadget-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" }
+beefy-primitives = { git = "https://github.com/paritytech/substrate", branch = "master" }
frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master" }
frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "master" }
node-inspect = { git = "https://github.com/paritytech/substrate", branch = "master" }
+pallet-mmr-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-transaction-payment-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-basic-authorship = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-cli = { git = "https://github.com/paritytech/substrate", branch = "master", features = ["wasmtime"] }
diff --git a/bridges/bin/millau/node/src/chain_spec.rs b/bridges/bin/millau/node/src/chain_spec.rs
index 05496bb64f63..fbfca8692fcb 100644
--- a/bridges/bin/millau/node/src/chain_spec.rs
+++ b/bridges/bin/millau/node/src/chain_spec.rs
@@ -14,11 +14,12 @@
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see .
+use beefy_primitives::crypto::AuthorityId as BeefyId;
use bp_millau::derive_account_from_rialto_id;
use millau_runtime::{
- AccountId, AuraConfig, BalancesConfig, BridgeRialtoMessagesConfig, BridgeWestendGrandpaConfig,
- GenesisConfig, GrandpaConfig, SessionConfig, SessionKeys, Signature, SudoConfig, SystemConfig,
- WASM_BINARY,
+ AccountId, AuraConfig, BalancesConfig, BeefyConfig, BridgeRialtoMessagesConfig,
+ BridgeWestendGrandpaConfig, GenesisConfig, GrandpaConfig, SessionConfig, SessionKeys,
+ Signature, SudoConfig, SystemConfig, WASM_BINARY,
};
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
use sp_core::{sr25519, Pair, Public};
@@ -57,10 +58,11 @@ where
}
/// Helper function to generate an authority key for Aura
-pub fn get_authority_keys_from_seed(s: &str) -> (AccountId, AuraId, GrandpaId) {
+pub fn get_authority_keys_from_seed(s: &str) -> (AccountId, AuraId, BeefyId, GrandpaId) {
(
get_account_id_from_seed::(s),
get_from_seed::(s),
+ get_from_seed::(s),
get_from_seed::(s),
)
}
@@ -173,12 +175,12 @@ impl Alternative {
}
}
-fn session_keys(aura: AuraId, grandpa: GrandpaId) -> SessionKeys {
- SessionKeys { aura, grandpa }
+fn session_keys(aura: AuraId, beefy: BeefyId, grandpa: GrandpaId) -> SessionKeys {
+ SessionKeys { aura, beefy, grandpa }
}
fn testnet_genesis(
- initial_authorities: Vec<(AccountId, AuraId, GrandpaId)>,
+ initial_authorities: Vec<(AccountId, AuraId, BeefyId, GrandpaId)>,
root_key: AccountId,
endowed_accounts: Vec,
_enable_println: bool,
@@ -191,12 +193,15 @@ fn testnet_genesis(
balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 50)).collect(),
},
aura: AuraConfig { authorities: Vec::new() },
+ beefy: BeefyConfig { authorities: Vec::new() },
grandpa: GrandpaConfig { authorities: Vec::new() },
sudo: SudoConfig { key: root_key },
session: SessionConfig {
keys: initial_authorities
.iter()
- .map(|x| (x.0.clone(), x.0.clone(), session_keys(x.1.clone(), x.2.clone())))
+ .map(|x| {
+ (x.0.clone(), x.0.clone(), session_keys(x.1.clone(), x.2.clone(), x.3.clone()))
+ })
.collect::>(),
},
bridge_westend_grandpa: BridgeWestendGrandpaConfig {
diff --git a/bridges/bin/millau/node/src/service.rs b/bridges/bin/millau/node/src/service.rs
index 4085982494b8..b01c0bfca906 100644
--- a/bridges/bin/millau/node/src/service.rs
+++ b/bridges/bin/millau/node/src/service.rs
@@ -21,9 +21,10 @@
// =====================================================================================
// UPDATE GUIDE:
// 1) replace everything with node-template/src/service.rs contents (found in main Substrate repo);
-// 2) the only thing to keep from old code, is `rpc_extensions_builder` - we use our own custom
-// RPCs; 3) fix compilation errors;
-// 4) test :)
+// 2) from old code keep `rpc_extensions_builder` - we use our own custom RPCs;
+// 3) from old code keep the Beefy gadget;
+// 4) fix compilation errors;
+// 5) test :)
// =====================================================================================
// =====================================================================================
// =====================================================================================
@@ -209,6 +210,7 @@ pub fn new_full(mut config: Configuration) -> Result
}
config.network.extra_sets.push(sc_finality_grandpa::grandpa_peers_set_config());
+ config.network.extra_sets.push(beefy_gadget::beefy_peers_set_config());
let warp_sync = Arc::new(sc_finality_grandpa::warp_proof::NetworkProvider::new(
backend.clone(),
grandpa_link.shared_authority_set().clone(),
@@ -242,6 +244,8 @@ pub fn new_full(mut config: Configuration) -> Result
let enable_grandpa = !config.disable_grandpa;
let prometheus_registry = config.prometheus_registry().cloned();
let shared_voter_state = SharedVoterState::empty();
+ let (signed_commitment_sender, signed_commitment_stream) =
+ beefy_gadget::notification::BeefySignedCommitmentStream::channel();
let rpc_extensions_builder = {
use sc_finality_grandpa::FinalityProofProvider as GrandpaFinalityProofProvider;
@@ -264,7 +268,7 @@ pub fn new_full(mut config: Configuration) -> Result
Some(shared_authority_set.clone()),
);
- Box::new(move |_, subscription_executor| {
+ Box::new(move |_, subscription_executor: sc_rpc::SubscriptionTaskExecutor| {
let mut io = jsonrpc_core::IoHandler::default();
io.extend_with(SystemApi::to_delegate(FullSystem::new(
client.clone(),
@@ -278,9 +282,18 @@ pub fn new_full(mut config: Configuration) -> Result
shared_authority_set.clone(),
shared_voter_state.clone(),
justification_stream.clone(),
- subscription_executor,
+ subscription_executor.clone(),
finality_proof_provider.clone(),
)));
+ io.extend_with(beefy_gadget_rpc::BeefyApi::to_delegate(
+ beefy_gadget_rpc::BeefyRpcHandler::new(
+ signed_commitment_stream.clone(),
+ subscription_executor,
+ ),
+ ));
+ io.extend_with(pallet_mmr_rpc::MmrApi::to_delegate(pallet_mmr_rpc::Mmr::new(
+ client.clone(),
+ )));
Ok(io)
})
};
@@ -292,7 +305,7 @@ pub fn new_full(mut config: Configuration) -> Result
task_manager: &mut task_manager,
transaction_pool: transaction_pool.clone(),
rpc_extensions_builder,
- backend,
+ backend: backend.clone(),
system_rpc_tx,
config,
telemetry: telemetry.as_mut(),
@@ -355,6 +368,23 @@ pub fn new_full(mut config: Configuration) -> Result
let keystore =
if role.is_authority() { Some(keystore_container.sync_keystore()) } else { None };
+ let beefy_params = beefy_gadget::BeefyParams {
+ client,
+ backend,
+ key_store: keystore.clone(),
+ network: network.clone(),
+ signed_commitment_sender,
+ min_block_delta: 4,
+ prometheus_registry: prometheus_registry.clone(),
+ };
+
+ // Start the BEEFY bridge gadget.
+ task_manager.spawn_essential_handle().spawn_blocking(
+ "beefy-gadget",
+ None,
+ beefy_gadget::start_beefy_gadget::<_, _, _, _>(beefy_params),
+ );
+
let grandpa_config = sc_finality_grandpa::Config {
// FIXME #1578 make this available through chainspec
gossip_duration: Duration::from_millis(333),
diff --git a/bridges/bin/millau/runtime/Cargo.toml b/bridges/bin/millau/runtime/Cargo.toml
index c8d7f0a15958..13195b95194b 100644
--- a/bridges/bin/millau/runtime/Cargo.toml
+++ b/bridges/bin/millau/runtime/Cargo.toml
@@ -30,6 +30,7 @@ pallet-shift-session-manager = { path = "../../../modules/shift-session-manager"
# Substrate Dependencies
+beefy-primitives = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true }
frame-executive = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
@@ -37,7 +38,11 @@ frame-system = { git = "https://github.com/paritytech/substrate", branch = "mast
frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-aura = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
+pallet-beefy = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
+pallet-beefy-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
+pallet-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
+pallet-mmr-primitives = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-randomness-collective-flip = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-session = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-sudo = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
@@ -64,6 +69,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran
[features]
default = ["std"]
std = [
+ "beefy-primitives/std",
"bp-header-chain/std",
"bp-messages/std",
"bp-millau/std",
@@ -78,11 +84,14 @@ std = [
"frame-system/std",
"pallet-aura/std",
"pallet-balances/std",
+ "pallet-beefy/std",
+ "pallet-beefy-mmr/std",
"pallet-bridge-dispatch/std",
"pallet-bridge-grandpa/std",
"pallet-bridge-messages/std",
"pallet-bridge-token-swap/std",
"pallet-grandpa/std",
+ "pallet-mmr/std",
"pallet-randomness-collective-flip/std",
"pallet-session/std",
"pallet-shift-session-manager/std",
diff --git a/bridges/bin/millau/runtime/src/lib.rs b/bridges/bin/millau/runtime/src/lib.rs
index b713211b1e48..288ff9a47d60 100644
--- a/bridges/bin/millau/runtime/src/lib.rs
+++ b/bridges/bin/millau/runtime/src/lib.rs
@@ -34,19 +34,23 @@ pub mod rialto_messages;
use crate::rialto_messages::{ToRialtoMessagePayload, WithRialtoMessageBridge};
+use beefy_primitives::{crypto::AuthorityId as BeefyId, mmr::MmrLeafVersion, ValidatorSet};
use bridge_runtime_common::messages::{
source::estimate_message_dispatch_and_delivery_fee, MessageBridge,
};
use pallet_grandpa::{
fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList,
};
+use pallet_mmr_primitives::{
+ DataOrHash, EncodableOpaqueLeaf, Error as MmrError, LeafDataProvider, Proof as MmrProof,
+};
use pallet_transaction_payment::{FeeDetails, Multiplier, RuntimeDispatchInfo};
use sp_api::impl_runtime_apis;
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
use sp_runtime::{
create_runtime_str, generic, impl_opaque_keys,
- traits::{Block as BlockT, IdentityLookup, NumberFor, OpaqueKeys},
+ traits::{Block as BlockT, IdentityLookup, Keccak256, NumberFor, OpaqueKeys},
transaction_validity::{TransactionSource, TransactionValidity},
ApplyExtrinsicResult, FixedPointNumber, MultiSignature, MultiSigner, Perquintill,
};
@@ -120,6 +124,7 @@ pub mod opaque {
impl_opaque_keys! {
pub struct SessionKeys {
pub aura: Aura,
+ pub beefy: Beefy,
pub grandpa: Grandpa,
}
}
@@ -212,6 +217,11 @@ impl pallet_aura::Config for Runtime {
type MaxAuthorities = MaxAuthorities;
type DisabledValidators = ();
}
+
+impl pallet_beefy::Config for Runtime {
+ type BeefyId = BeefyId;
+}
+
impl pallet_bridge_dispatch::Config for Runtime {
type Event = Event;
type BridgeMessageId = (bp_messages::LaneId, bp_messages::MessageNonce);
@@ -240,6 +250,40 @@ impl pallet_grandpa::Config for Runtime {
type MaxAuthorities = MaxAuthorities;
}
+type MmrHash = ::Output;
+
+impl pallet_mmr::Config for Runtime {
+ const INDEXING_PREFIX: &'static [u8] = b"mmr";
+ type Hashing = Keccak256;
+ type Hash = MmrHash;
+ type OnNewRoot = pallet_beefy_mmr::DepositBeefyDigest;
+ type WeightInfo = ();
+ type LeafData = pallet_beefy_mmr::Pallet;
+}
+
+parameter_types! {
+ /// Version of the produced MMR leaf.
+ ///
+ /// The version consists of two parts;
+ /// - `major` (3 bits)
+ /// - `minor` (5 bits)
+ ///
+ /// `major` should be updated only if decoding the previous MMR Leaf format from the payload
+ /// is not possible (i.e. backward incompatible change).
+ /// `minor` should be updated if fields are added to the previous MMR Leaf, which given SCALE
+ /// encoding does not prevent old leafs from being decoded.
+ ///
+ /// Hence we expect `major` to be changed really rarely (think never).
+ /// See [`MmrLeafVersion`] type documentation for more details.
+ pub LeafVersion: MmrLeafVersion = MmrLeafVersion::new(0, 0);
+}
+
+impl pallet_beefy_mmr::Config for Runtime {
+ type LeafVersion = LeafVersion;
+ type BeefyAuthorityToMerkleLeaf = pallet_beefy_mmr::BeefyEcdsaToEthereum;
+ type ParachainHeads = ();
+}
+
parameter_types! {
pub const MinimumPeriod: u64 = bp_millau::SLOT_DURATION / 2;
}
@@ -459,6 +503,11 @@ construct_runtime!(
ShiftSessionManager: pallet_shift_session_manager::{Pallet},
RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage},
+ // BEEFY Bridges support.
+ Beefy: pallet_beefy::{Pallet, Storage, Config},
+ Mmr: pallet_mmr::{Pallet, Storage},
+ MmrLeaf: pallet_beefy_mmr::{Pallet, Storage},
+
// Rialto bridge modules.
BridgeRialtoGrandpa: pallet_bridge_grandpa::{Pallet, Call, Storage},
BridgeDispatch: pallet_bridge_dispatch::{Pallet, Event},
@@ -603,6 +652,45 @@ impl_runtime_apis! {
}
}
+ impl beefy_primitives::BeefyApi for Runtime {
+ fn validator_set() -> ValidatorSet {
+ Beefy::validator_set()
+ }
+ }
+
+ impl pallet_mmr_primitives::MmrApi for Runtime {
+ fn generate_proof(leaf_index: u64)
+ -> Result<(EncodableOpaqueLeaf, MmrProof), MmrError>
+ {
+ Mmr::generate_proof(leaf_index)
+ .map(|(leaf, proof)| (EncodableOpaqueLeaf::from_leaf(&leaf), proof))
+ }
+
+ fn verify_proof(leaf: EncodableOpaqueLeaf, proof: MmrProof)
+ -> Result<(), MmrError>
+ {
+ pub type Leaf = <
+ ::LeafData as LeafDataProvider
+ >::LeafData;
+
+ let leaf: Leaf = leaf
+ .into_opaque_leaf()
+ .try_decode()
+ .ok_or(MmrError::Verify)?;
+ Mmr::verify_leaf(leaf, proof)
+ }
+
+ fn verify_proof_stateless(
+ root: MmrHash,
+ leaf: EncodableOpaqueLeaf,
+ proof: MmrProof
+ ) -> Result<(), MmrError> {
+ type MmrHashing = ::Hashing;
+ let node = DataOrHash::Data(leaf.into_opaque_leaf());
+ pallet_mmr::verify_leaf_proof::(root, node, proof)
+ }
+ }
+
impl fg_primitives::GrandpaApi for Runtime {
fn current_set_id() -> fg_primitives::SetId {
Grandpa::current_set_id()
diff --git a/bridges/bin/rialto/node/Cargo.toml b/bridges/bin/rialto/node/Cargo.toml
index fd76fbf9a617..2795f2eecaec 100644
--- a/bridges/bin/rialto/node/Cargo.toml
+++ b/bridges/bin/rialto/node/Cargo.toml
@@ -28,10 +28,15 @@ rialto-runtime = { path = "../runtime" }
# Substrate Dependencies
+beefy-gadget = { git = "https://github.com/paritytech/substrate", branch = "master" }
+beefy-gadget-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" }
+beefy-primitives = { git = "https://github.com/paritytech/substrate", branch = "master" }
frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master" }
frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "master" }
frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
node-inspect = { git = "https://github.com/paritytech/substrate", branch = "master" }
+pallet-mmr-primitives = { git = "https://github.com/paritytech/substrate", branch = "master" }
+pallet-mmr-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-transaction-payment-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" }
pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master" }
@@ -70,6 +75,10 @@ sp-timestamp = { git = "https://github.com/paritytech/substrate", branch = "mast
substrate-frame-rpc-system = { git = "https://github.com/paritytech/substrate", branch = "master" }
substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate", branch = "master" }
+# Polkadot Dependencies
+
+polkadot-client = { git = "https://github.com/paritytech/polkadot", branch = "master" }
+
# Polkadot (parachain) Dependencies
polkadot-approval-distribution = { git = "https://github.com/paritytech/polkadot", branch = "master" }
diff --git a/bridges/bin/rialto/node/src/chain_spec.rs b/bridges/bin/rialto/node/src/chain_spec.rs
index cadacad72da9..fb18a35a6af0 100644
--- a/bridges/bin/rialto/node/src/chain_spec.rs
+++ b/bridges/bin/rialto/node/src/chain_spec.rs
@@ -14,12 +14,13 @@
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see .
+use beefy_primitives::crypto::AuthorityId as BeefyId;
use bp_rialto::derive_account_from_millau_id;
use polkadot_primitives::v1::{AssignmentId, ValidatorId};
use rialto_runtime::{
- AccountId, BabeConfig, BalancesConfig, BridgeMillauMessagesConfig, ConfigurationConfig,
- GenesisConfig, GrandpaConfig, SessionConfig, SessionKeys, Signature, SudoConfig, SystemConfig,
- WASM_BINARY,
+ AccountId, BabeConfig, BalancesConfig, BeefyConfig, BridgeMillauMessagesConfig,
+ ConfigurationConfig, GenesisConfig, GrandpaConfig, SessionConfig, SessionKeys, Signature,
+ SudoConfig, SystemConfig, WASM_BINARY,
};
use serde_json::json;
use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
@@ -62,10 +63,11 @@ where
/// Helper function to generate authority keys.
pub fn get_authority_keys_from_seed(
s: &str,
-) -> (AccountId, BabeId, GrandpaId, ValidatorId, AssignmentId, AuthorityDiscoveryId) {
+) -> (AccountId, BabeId, BeefyId, GrandpaId, ValidatorId, AssignmentId, AuthorityDiscoveryId) {
(
get_account_id_from_seed::(s),
get_from_seed::(s),
+ get_from_seed::(s),
get_from_seed::(s),
get_from_seed::(s),
get_from_seed::(s),
@@ -183,18 +185,20 @@ impl Alternative {
fn session_keys(
babe: BabeId,
+ beefy: BeefyId,
grandpa: GrandpaId,
para_validator: ValidatorId,
para_assignment: AssignmentId,
authority_discovery: AuthorityDiscoveryId,
) -> SessionKeys {
- SessionKeys { babe, grandpa, para_validator, para_assignment, authority_discovery }
+ SessionKeys { babe, beefy, grandpa, para_validator, para_assignment, authority_discovery }
}
fn testnet_genesis(
initial_authorities: Vec<(
AccountId,
BabeId,
+ BeefyId,
GrandpaId,
ValidatorId,
AssignmentId,
@@ -215,6 +219,7 @@ fn testnet_genesis(
authorities: Vec::new(),
epoch_config: Some(rialto_runtime::BABE_GENESIS_EPOCH_CONFIG),
},
+ beefy: BeefyConfig { authorities: Vec::new() },
grandpa: GrandpaConfig { authorities: Vec::new() },
sudo: SudoConfig { key: root_key },
session: SessionConfig {
@@ -230,6 +235,7 @@ fn testnet_genesis(
x.3.clone(),
x.4.clone(),
x.5.clone(),
+ x.6.clone(),
),
)
})
diff --git a/bridges/bin/rialto/node/src/service.rs b/bridges/bin/rialto/node/src/service.rs
index fb774d86cca9..3349b09edb9f 100644
--- a/bridges/bin/rialto/node/src/service.rs
+++ b/bridges/bin/rialto/node/src/service.rs
@@ -17,16 +17,11 @@
//! Rialto chain node service.
//!
//! The code is mostly copy of `service/src/lib.rs` file from Polkadot repository
-//! without optional functions.
-
-// this warning comes from Error enum (sc_cli::Error in particular) && it isn't easy to use box
-// there
-#![allow(clippy::large_enum_variant)]
-// this warning comes from `sc_service::PartialComponents` type
-#![allow(clippy::type_complexity)]
+//! without optional functions, and with BEEFY added on top.
use crate::overseer::{OverseerGen, OverseerGenArgs};
+use polkadot_client::RuntimeApiCollection;
use polkadot_node_core_approval_voting::Config as ApprovalVotingConfig;
use polkadot_node_core_av_store::Config as AvailabilityConfig;
use polkadot_node_core_candidate_validation::Config as CandidateValidationConfig;
@@ -43,7 +38,7 @@ use sc_service::{config::PrometheusConfig, Configuration, TaskManager};
use sc_telemetry::{Telemetry, TelemetryWorker};
use sp_api::{ConstructRuntimeApi, HeaderT};
use sp_consensus::SelectChain;
-use sp_runtime::traits::{BlakeTwo256, Block as BlockT};
+use sp_runtime::traits::Block as BlockT;
use std::{sync::Arc, time::Duration};
use substrate_prometheus_endpoint::Registry;
@@ -115,52 +110,6 @@ type FullBabeBlockImport =
type FullBabeLink = sc_consensus_babe::BabeLink;
type FullGrandpaLink = sc_finality_grandpa::LinkHalf;
-/// A set of APIs that polkadot-like runtimes must implement.
-///
-/// This is the copy of `polkadot_service::RuntimeApiCollection` with some APIs removed
-/// (right now - MMR and BEEFY).
-pub trait RequiredApiCollection:
- sp_transaction_pool::runtime_api::TaggedTransactionQueue
- + sp_api::ApiExt
- + sp_consensus_babe::BabeApi
- + sp_finality_grandpa::GrandpaApi
- + polkadot_primitives::v1::ParachainHost
- + sp_block_builder::BlockBuilder
- + frame_system_rpc_runtime_api::AccountNonceApi<
- Block,
- bp_rialto::AccountId,
- rialto_runtime::Index,
- > + pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi
- + sp_api::Metadata
- + sp_offchain::OffchainWorkerApi
- + sp_session::SessionKeys
- + sp_authority_discovery::AuthorityDiscoveryApi
-where
- >::StateBackend: sp_api::StateBackend,
-{
-}
-
-impl RequiredApiCollection for Api
-where
- Api: sp_transaction_pool::runtime_api::TaggedTransactionQueue
- + sp_api::ApiExt
- + sp_consensus_babe::BabeApi
- + sp_finality_grandpa::GrandpaApi
- + polkadot_primitives::v1::ParachainHost
- + sp_block_builder::BlockBuilder
- + frame_system_rpc_runtime_api::AccountNonceApi<
- Block,
- bp_rialto::AccountId,
- rialto_runtime::Index,
- > + pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi
- + sp_api::Metadata
- + sp_offchain::OffchainWorkerApi
- + sp_session::SessionKeys
- + sp_authority_discovery::AuthorityDiscoveryApi,
- >::StateBackend: sp_api::StateBackend,
-{
-}
-
// If we're using prometheus, use a registry with a prefix of `polkadot`.
fn set_prometheus_registry(config: &mut Configuration) -> Result<(), Error> {
if let Some(PrometheusConfig { registry, .. }) = config.prometheus_config.as_mut() {
@@ -170,6 +119,8 @@ fn set_prometheus_registry(config: &mut Configuration) -> Result<(), Error> {
Ok(())
}
+// Needed here for complex return type while `impl Trait` in type aliases is unstable.
+#[allow(clippy::type_complexity)]
pub fn new_partial(
config: &mut Configuration,
) -> Result<
@@ -184,7 +135,12 @@ pub fn new_partial(
sc_rpc::DenyUnsafe,
sc_rpc::SubscriptionTaskExecutor,
) -> Result, sc_service::Error>,
- (FullBabeBlockImport, FullGrandpaLink, FullBabeLink),
+ (
+ FullBabeBlockImport,
+ FullGrandpaLink,
+ FullBabeLink,
+ beefy_gadget::notification::BeefySignedCommitmentSender,
+ ),
sc_finality_grandpa::SharedVoterState,
std::time::Duration,
Option,
@@ -195,7 +151,7 @@ pub fn new_partial(
where
RuntimeApi: ConstructRuntimeApi + Send + Sync + 'static,
>::RuntimeApi:
- RequiredApiCollection>,
+ RuntimeApiCollection>,
ExecutorDispatch: NativeExecutionDispatch + 'static,
{
set_prometheus_registry(config)?;
@@ -282,7 +238,10 @@ where
let shared_authority_set = grandpa_link.shared_authority_set().clone();
let shared_voter_state = sc_finality_grandpa::SharedVoterState::empty();
- let import_setup = (block_import, grandpa_link, babe_link);
+ let (signed_commitment_sender, signed_commitment_stream) =
+ beefy_gadget::notification::BeefySignedCommitmentStream::channel();
+
+ let import_setup = (block_import, grandpa_link, babe_link, signed_commitment_sender);
let rpc_setup = shared_voter_state.clone();
let slot_duration = babe_config.slot_duration();
@@ -316,14 +275,23 @@ where
pool,
deny_unsafe,
)));
- io.extend_with(TransactionPaymentApi::to_delegate(TransactionPayment::new(client)));
+ io.extend_with(TransactionPaymentApi::to_delegate(TransactionPayment::new(
+ client.clone(),
+ )));
io.extend_with(GrandpaApi::to_delegate(GrandpaRpcHandler::new(
shared_authority_set.clone(),
shared_voter_state,
justification_stream.clone(),
- subscription_executor,
+ subscription_executor.clone(),
finality_proof_provider,
)));
+ io.extend_with(beefy_gadget_rpc::BeefyApi::to_delegate(
+ beefy_gadget_rpc::BeefyRpcHandler::new(
+ signed_commitment_stream.clone(),
+ subscription_executor,
+ ),
+ ));
+ io.extend_with(pallet_mmr_rpc::MmrApi::to_delegate(pallet_mmr_rpc::Mmr::new(client)));
Ok(io)
}
@@ -361,7 +329,7 @@ async fn active_leaves(
where
RuntimeApi: ConstructRuntimeApi + Send + Sync + 'static,
>::RuntimeApi:
- RequiredApiCollection>,
+ RuntimeApiCollection>,
ExecutorDispatch: NativeExecutionDispatch + 'static,
{
let best_block = select_chain.best_chain().await?;
@@ -406,7 +374,7 @@ pub fn new_full(
where
RuntimeApi: ConstructRuntimeApi + Send + Sync + 'static,
>::RuntimeApi:
- RequiredApiCollection>,
+ RuntimeApiCollection>,
ExecutorDispatch: NativeExecutionDispatch + 'static,
{
let is_collator = false;
@@ -442,6 +410,8 @@ where
// Substrate nodes.
config.network.extra_sets.push(sc_finality_grandpa::grandpa_peers_set_config());
+ config.network.extra_sets.push(beefy_gadget::beefy_peers_set_config());
+
{
use polkadot_network_bridge::{peer_sets_info, IsAuthority};
let is_authority = if role.is_authority() { IsAuthority::Yes } else { IsAuthority::No };
@@ -536,7 +506,7 @@ where
telemetry: telemetry.as_mut(),
})?;
- let (block_import, link_half, babe_link) = import_setup;
+ let (block_import, link_half, babe_link, signed_commitment_sender) = import_setup;
let overseer_client = client.clone();
let spawner = task_manager.spawn_handle();
@@ -713,6 +683,23 @@ where
let keystore_opt =
if role.is_authority() { Some(keystore_container.sync_keystore()) } else { None };
+ let beefy_params = beefy_gadget::BeefyParams {
+ client: client.clone(),
+ backend: backend.clone(),
+ key_store: keystore_opt.clone(),
+ network: network.clone(),
+ signed_commitment_sender,
+ min_block_delta: 2,
+ prometheus_registry: prometheus_registry.clone(),
+ };
+
+ // Start the BEEFY bridge gadget.
+ task_manager.spawn_essential_handle().spawn_blocking(
+ "beefy-gadget",
+ None,
+ beefy_gadget::start_beefy_gadget::<_, _, _, _>(beefy_params),
+ );
+
let config = sc_finality_grandpa::Config {
// FIXME substrate#1578 make this available through chainspec
gossip_duration: Duration::from_millis(1000),
diff --git a/bridges/bin/rialto/runtime/Cargo.toml b/bridges/bin/rialto/runtime/Cargo.toml
index 36dc436ddca6..3c4ec1ebce1c 100644
--- a/bridges/bin/rialto/runtime/Cargo.toml
+++ b/bridges/bin/rialto/runtime/Cargo.toml
@@ -31,6 +31,7 @@ pallet-shift-session-manager = { path = "../../../modules/shift-session-manager"
# Substrate Dependencies
+beefy-primitives = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true }
frame-executive = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
@@ -39,7 +40,11 @@ frame-system-rpc-runtime-api = { git = "https://github.com/paritytech/substrate"
pallet-authority-discovery = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-babe = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
+pallet-beefy = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
+pallet-beefy-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
+pallet-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
+pallet-mmr-primitives = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-session = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-sudo = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-timestamp = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
@@ -76,6 +81,7 @@ substrate-wasm-builder = { git = "https://github.com/paritytech/substrate", bran
[features]
default = ["std"]
std = [
+ "beefy-primitives/std",
"bp-header-chain/std",
"bp-message-dispatch/std",
"bp-messages/std",
@@ -93,10 +99,14 @@ std = [
"pallet-authority-discovery/std",
"pallet-babe/std",
"pallet-balances/std",
+ "pallet-beefy/std",
+ "pallet-beefy-mmr/std",
"pallet-bridge-dispatch/std",
"pallet-bridge-grandpa/std",
"pallet-bridge-messages/std",
"pallet-grandpa/std",
+ "pallet-mmr/std",
+ "pallet-mmr-primitives/std",
"pallet-shift-session-manager/std",
"pallet-sudo/std",
"pallet-timestamp/std",
diff --git a/bridges/bin/rialto/runtime/src/lib.rs b/bridges/bin/rialto/runtime/src/lib.rs
index 5e7e47490d58..0987184c73aa 100644
--- a/bridges/bin/rialto/runtime/src/lib.rs
+++ b/bridges/bin/rialto/runtime/src/lib.rs
@@ -35,19 +35,23 @@ pub mod parachains;
use crate::millau_messages::{ToMillauMessagePayload, WithMillauMessageBridge};
+use beefy_primitives::{crypto::AuthorityId as BeefyId, mmr::MmrLeafVersion, ValidatorSet};
use bridge_runtime_common::messages::{
source::estimate_message_dispatch_and_delivery_fee, MessageBridge,
};
use pallet_grandpa::{
fg_primitives, AuthorityId as GrandpaId, AuthorityList as GrandpaAuthorityList,
};
+use pallet_mmr_primitives::{
+ DataOrHash, EncodableOpaqueLeaf, Error as MmrError, LeafDataProvider, Proof as MmrProof,
+};
use pallet_transaction_payment::{FeeDetails, Multiplier, RuntimeDispatchInfo};
use sp_api::impl_runtime_apis;
use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId;
use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
use sp_runtime::{
create_runtime_str, generic, impl_opaque_keys,
- traits::{AccountIdLookup, Block as BlockT, NumberFor, OpaqueKeys},
+ traits::{AccountIdLookup, Block as BlockT, Keccak256, NumberFor, OpaqueKeys},
transaction_validity::{TransactionSource, TransactionValidity},
ApplyExtrinsicResult, FixedPointNumber, MultiSignature, MultiSigner, Perquintill,
};
@@ -122,6 +126,7 @@ impl_opaque_keys! {
pub struct SessionKeys {
pub babe: Babe,
pub grandpa: Grandpa,
+ pub beefy: Beefy,
pub para_validator: Initializer,
pub para_assignment: SessionInfo,
pub authority_discovery: AuthorityDiscovery,
@@ -242,6 +247,10 @@ impl pallet_babe::Config for Runtime {
type WeightInfo = ();
}
+impl pallet_beefy::Config for Runtime {
+ type BeefyId = BeefyId;
+}
+
impl pallet_bridge_dispatch::Config for Runtime {
type Event = Event;
type BridgeMessageId = (bp_messages::LaneId, bp_messages::MessageNonce);
@@ -270,6 +279,38 @@ impl pallet_grandpa::Config for Runtime {
type WeightInfo = ();
}
+impl pallet_mmr::Config for Runtime {
+ const INDEXING_PREFIX: &'static [u8] = b"mmr";
+ type Hashing = Keccak256;
+ type Hash = ::Output;
+ type OnNewRoot = pallet_beefy_mmr::DepositBeefyDigest;
+ type WeightInfo = ();
+ type LeafData = pallet_beefy_mmr::Pallet;
+}
+
+parameter_types! {
+ /// Version of the produced MMR leaf.
+ ///
+ /// The version consists of two parts;
+ /// - `major` (3 bits)
+ /// - `minor` (5 bits)
+ ///
+ /// `major` should be updated only if decoding the previous MMR Leaf format from the payload
+ /// is not possible (i.e. backward incompatible change).
+ /// `minor` should be updated if fields are added to the previous MMR Leaf, which given SCALE
+ /// encoding does not prevent old leafs from being decoded.
+ ///
+ /// Hence we expect `major` to be changed really rarely (think never).
+ /// See [`MmrLeafVersion`] type documentation for more details.
+ pub LeafVersion: MmrLeafVersion = MmrLeafVersion::new(0, 0);
+}
+
+impl pallet_beefy_mmr::Config for Runtime {
+ type LeafVersion = LeafVersion;
+ type BeefyAuthorityToMerkleLeaf = pallet_beefy_mmr::BeefyEcdsaToEthereum;
+ type ParachainHeads = ();
+}
+
parameter_types! {
pub const MinimumPeriod: u64 = bp_rialto::SLOT_DURATION / 2;
}
@@ -463,6 +504,11 @@ construct_runtime!(
Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event},
ShiftSessionManager: pallet_shift_session_manager::{Pallet},
+ // BEEFY Bridges support.
+ Beefy: pallet_beefy::{Pallet, Storage, Config},
+ Mmr: pallet_mmr::{Pallet, Storage},
+ MmrLeaf: pallet_beefy_mmr::{Pallet, Storage},
+
// Millau bridge modules.
BridgeMillauGrandpa: pallet_bridge_grandpa::{Pallet, Call, Storage},
BridgeDispatch: pallet_bridge_dispatch::{Pallet, Event},
@@ -572,6 +618,45 @@ impl_runtime_apis! {
}
}
+ impl beefy_primitives::BeefyApi for Runtime {
+ fn validator_set() -> ValidatorSet {
+ Beefy::validator_set()
+ }
+ }
+
+ impl pallet_mmr_primitives::MmrApi for Runtime {
+ fn generate_proof(leaf_index: u64)
+ -> Result<(EncodableOpaqueLeaf, MmrProof), MmrError>
+ {
+ Mmr::generate_proof(leaf_index)
+ .map(|(leaf, proof)| (EncodableOpaqueLeaf::from_leaf(&leaf), proof))
+ }
+
+ fn verify_proof(leaf: EncodableOpaqueLeaf, proof: MmrProof)
+ -> Result<(), MmrError>
+ {
+ pub type Leaf = <
+ ::LeafData as LeafDataProvider
+ >::LeafData;
+
+ let leaf: Leaf = leaf
+ .into_opaque_leaf()
+ .try_decode()
+ .ok_or(MmrError::Verify)?;
+ Mmr::verify_leaf(leaf, proof)
+ }
+
+ fn verify_proof_stateless(
+ root: Hash,
+ leaf: EncodableOpaqueLeaf,
+ proof: MmrProof
+ ) -> Result<(), MmrError> {
+ type MmrHashing = ::Hashing;
+ let node = DataOrHash::Data(leaf.into_opaque_leaf());
+ pallet_mmr::verify_leaf_proof::(root, node, proof)
+ }
+ }
+
impl bp_millau::MillauFinalityApi for Runtime {
fn best_finalized() -> (bp_millau::BlockNumber, bp_millau::Hash) {
let header = BridgeMillauGrandpa::best_finalized();
@@ -1147,7 +1232,10 @@ mod tests {
#[test]
fn call_size() {
- const MAX_CALL_SIZE: usize = 230; // value from polkadot-runtime tests
- assert!(core::mem::size_of::() <= MAX_CALL_SIZE);
+ const DOT_MAX_CALL_SZ: usize = 230;
+ assert!(core::mem::size_of::>() <= DOT_MAX_CALL_SZ);
+ // FIXME: get this down to 230. https://github.com/paritytech/grandpa-bridge-gadget/issues/359
+ const BEEFY_MAX_CALL_SZ: usize = 232;
+ assert!(core::mem::size_of::>() <= BEEFY_MAX_CALL_SZ);
}
}
diff --git a/bridges/relays/bin-substrate/src/cli/encode_call.rs b/bridges/relays/bin-substrate/src/cli/encode_call.rs
index ca0e6dd8abff..e17854662e5c 100644
--- a/bridges/relays/bin-substrate/src/cli/encode_call.rs
+++ b/bridges/relays/bin-substrate/src/cli/encode_call.rs
@@ -345,7 +345,7 @@ mod tests {
// then
assert!(format!("{:?}", call_hex).starts_with(
- "0x0c030000000001000000381409000000000001d43593c715fdd31c61141abd04a99fd6822c8558854cc\
+ "0x0f030000000001000000381409000000000001d43593c715fdd31c61141abd04a99fd6822c8558854cc\
de39a5684e7a56da27d01d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01"
))
}