Add BEEFY capabilities to Westend and Kusama (#7591)

* runtime: add BEEFY and MMR to Westend

Signed-off-by: Adrian Catangiu <adrian@parity.io>

* runtime: add BEEFY and MMR to Kusama

Signed-off-by: Adrian Catangiu <adrian@parity.io>

* node/service: enable BEEFY for Westend and Kusama

Signed-off-by: Adrian Catangiu <adrian@parity.io>

* node/service: regenerate genesis keys for westend-native and kusama-native

Since these keys are only used for development/local chains, also publish
the secret seeds used to generate the public keys, so that developers can
recover/generate the private key pairs if needed.

Signed-off-by: Adrian Catangiu <adrian@parity.io>

* runtime: add session keys migration to add BEEFY to Westend and Kusama

* runtime: fix migration

* fix try-runtime build

* cargo fmt

* fix parachains slashing benchmark

* address review comments

* Apply suggestions from code review

Co-authored-by: Bastian Köcher <git@kchr.de>

* runtime: fix session keys migration

---------

Signed-off-by: Adrian Catangiu <adrian@parity.io>
Co-authored-by: parity-processbot <>
Co-authored-by: Bastian Köcher <git@kchr.de>
This commit is contained in:
Adrian Catangiu
2023-08-22 12:08:54 +03:00
committed by GitHub
parent 515ec1a98b
commit ce728be008
14 changed files with 638 additions and 247 deletions
+12
View File
@@ -19,9 +19,11 @@ smallvec = "1.8.0"
authority-discovery-primitives = { package = "sp-authority-discovery", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
babe-primitives = { package = "sp-consensus-babe", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
beefy-primitives = { package = "sp-consensus-beefy", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
binary-merkle-tree = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
inherents = { package = "sp-inherents", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
offchain-primitives = { package = "sp-offchain", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-application-crypto = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-std = { package = "sp-std", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-mmr-primitives = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
@@ -45,6 +47,8 @@ pallet-authorship = { git = "https://github.com/paritytech/substrate", branch =
pallet-babe = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-bags-list = { 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-collective = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-democracy = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-elections-phragmen = { package = "pallet-elections-phragmen", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
@@ -56,6 +60,7 @@ pallet-im-online = { git = "https://github.com/paritytech/substrate", branch = "
pallet-indices = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-membership = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-message-queue = { 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-multisig = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-nomination-pools = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-offences = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
@@ -134,6 +139,8 @@ std = [
"pallet-authority-discovery/std",
"pallet-authorship/std",
"pallet-balances/std",
"pallet-beefy/std",
"pallet-beefy-mmr/std",
"pallet-transaction-payment/std",
"pallet-transaction-payment-rpc-runtime-api/std",
"pallet-collective/std",
@@ -147,6 +154,7 @@ std = [
"pallet-indices/std",
"pallet-membership/std",
"pallet-message-queue/std",
"pallet-mmr/std",
"beefy-primitives/std",
"pallet-multisig/std",
"pallet-nomination-pools/std",
@@ -170,6 +178,7 @@ std = [
"pallet-babe/std",
"pallet-bags-list/std",
"frame-executive/std",
"sp-application-crypto/std",
"sp-mmr-primitives/std",
"sp-runtime/std",
"sp-staking/std",
@@ -243,6 +252,8 @@ try-runtime = [
"pallet-authority-discovery/try-runtime",
"pallet-authorship/try-runtime",
"pallet-balances/try-runtime",
"pallet-beefy/try-runtime",
"pallet-beefy-mmr/try-runtime",
"pallet-transaction-payment/try-runtime",
"pallet-collective/try-runtime",
"pallet-elections-phragmen/try-runtime",
@@ -255,6 +266,7 @@ try-runtime = [
"pallet-indices/try-runtime",
"pallet-membership/try-runtime",
"pallet-message-queue/try-runtime",
"pallet-mmr/try-runtime",
"pallet-multisig/try-runtime",
"pallet-nomination-pools/try-runtime",
"pallet-offences/try-runtime",
+193 -29
View File
@@ -17,11 +17,14 @@
//! The Westend runtime. This can be compiled with `#[no_std]`, ready for Wasm.
#![cfg_attr(not(feature = "std"), no_std)]
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
#![recursion_limit = "256"]
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 512.
#![recursion_limit = "512"]
use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId;
use beefy_primitives::ecdsa_crypto::{AuthorityId as BeefyId, Signature as BeefySignature};
use beefy_primitives::{
ecdsa_crypto::{AuthorityId as BeefyId, Signature as BeefySignature},
mmr::{BeefyDataProvider, MmrLeafVersion},
};
use frame_election_provider_support::{bounds::ElectionBoundsBuilder, onchain, SequentialPhragmen};
use frame_support::{
construct_runtime, parameter_types,
@@ -64,15 +67,14 @@ use runtime_parachains::{
shared as parachains_shared,
};
use scale_info::TypeInfo;
use sp_core::{OpaqueMetadata, RuntimeDebug};
use sp_mmr_primitives as mmr;
use sp_core::{OpaqueMetadata, RuntimeDebug, H256};
use sp_runtime::{
create_runtime_str,
curve::PiecewiseLinear,
generic, impl_opaque_keys,
traits::{
AccountIdLookup, BlakeTwo256, Block as BlockT, ConvertInto, Extrinsic as ExtrinsicT,
OpaqueKeys, SaturatedConversion, Verify,
Keccak256, OpaqueKeys, SaturatedConversion, Verify,
},
transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity},
ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill,
@@ -271,6 +273,81 @@ impl pallet_balances::Config for Runtime {
type MaxFreezes = ConstU32<0>;
}
parameter_types! {
pub const BeefySetIdSessionEntries: u32 = BondingDuration::get() * SessionsPerEra::get();
}
impl pallet_beefy::Config for Runtime {
type BeefyId = BeefyId;
type MaxAuthorities = MaxAuthorities;
type MaxNominators = MaxNominatorRewardedPerValidator;
type MaxSetIdSessionEntries = BeefySetIdSessionEntries;
type OnNewValidatorSet = BeefyMmrLeaf;
type WeightInfo = ();
type KeyOwnerProof = <Historical as KeyOwnerProofSystem<(KeyTypeId, BeefyId)>>::Proof;
type EquivocationReportSystem =
pallet_beefy::EquivocationReportSystem<Self, Offences, Historical, ReportLongevity>;
}
impl pallet_mmr::Config for Runtime {
const INDEXING_PREFIX: &'static [u8] = mmr::INDEXING_PREFIX;
type Hashing = Keccak256;
type OnNewRoot = pallet_beefy_mmr::DepositBeefyDigest<Runtime>;
type WeightInfo = ();
type LeafData = pallet_beefy_mmr::Pallet<Runtime>;
}
/// MMR helper types.
mod mmr {
use super::Runtime;
pub use pallet_mmr::primitives::*;
pub type Leaf = <<Runtime as pallet_mmr::Config>::LeafData as LeafDataProvider>::LeafData;
pub type Hashing = <Runtime as pallet_mmr::Config>::Hashing;
pub type Hash = <Hashing as sp_runtime::traits::Hash>::Output;
}
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);
}
/// A BEEFY data provider that merkelizes all the parachain heads at the current block
/// (sorted by their parachain id).
pub struct ParaHeadsRootProvider;
impl BeefyDataProvider<H256> for ParaHeadsRootProvider {
fn extra_data() -> H256 {
let mut para_heads: Vec<(u32, Vec<u8>)> = Paras::parachains()
.into_iter()
.filter_map(|id| Paras::para_head(&id).map(|head| (id.into(), head.0)))
.collect();
para_heads.sort_by_key(|k| k.0);
binary_merkle_tree::merkle_root::<mmr::Hashing, _>(
para_heads.into_iter().map(|pair| pair.encode()),
)
.into()
}
}
impl pallet_beefy_mmr::Config for Runtime {
type LeafVersion = LeafVersion;
type BeefyAuthorityToMerkleLeaf = pallet_beefy_mmr::BeefyEcdsaToEthereum;
type LeafExtra = H256;
type BeefyDataProvider = ParaHeadsRootProvider;
}
parameter_types! {
pub const TransactionByteFee: Balance = 10 * MILLICENTS;
/// This value increases the priority of `Operational` transactions by adding
@@ -307,6 +384,17 @@ parameter_types! {
pub const Offset: BlockNumber = 0;
}
impl_opaque_keys! {
pub struct OldSessionKeys {
pub grandpa: Grandpa,
pub babe: Babe,
pub im_online: ImOnline,
pub para_validator: Initializer,
pub para_assignment: ParaSessionInfo,
pub authority_discovery: AuthorityDiscovery,
}
}
impl_opaque_keys! {
pub struct SessionKeys {
pub grandpa: Grandpa,
@@ -315,6 +403,33 @@ impl_opaque_keys! {
pub para_validator: Initializer,
pub para_assignment: ParaSessionInfo,
pub authority_discovery: AuthorityDiscovery,
pub beefy: Beefy,
}
}
// remove this when removing `OldSessionKeys`
fn transform_session_keys(v: AccountId, old: OldSessionKeys) -> SessionKeys {
SessionKeys {
grandpa: old.grandpa,
babe: old.babe,
im_online: old.im_online,
para_validator: old.para_validator,
para_assignment: old.para_assignment,
authority_discovery: old.authority_discovery,
beefy: {
// From Session::upgrade_keys():
//
// Care should be taken that the raw versions of the
// added keys are unique for every `ValidatorId, KeyTypeId` combination.
// This is an invariant that the session pallet typically maintains internally.
//
// So, produce a dummy value that's unique for the `ValidatorId, KeyTypeId` combination.
let mut id: BeefyId = sp_application_crypto::ecdsa::Public::from_raw([0u8; 33]).into();
let id_raw: &mut [u8] = id.as_mut();
id_raw[1..33].copy_from_slice(v.as_ref());
id_raw[0..4].copy_from_slice(b"beef");
id
},
}
}
@@ -1167,6 +1282,14 @@ construct_runtime! {
Staking: pallet_staking::{Pallet, Call, Storage, Config<T>, Event<T>} = 6,
Offences: pallet_offences::{Pallet, Storage, Event} = 7,
Historical: session_historical::{Pallet} = 27,
// BEEFY Bridges support.
Beefy: pallet_beefy::{Pallet, Call, Storage, Config<T>, ValidateUnsigned} = 200,
// MMR leaf construction must be before session in order to have leaf contents
// refer to block<N-1> consistently. see substrate issue #11797 for details.
Mmr: pallet_mmr::{Pallet, Storage} = 201,
BeefyMmrLeaf: pallet_beefy_mmr::{Pallet, Storage} = 202,
Session: pallet_session::{Pallet, Call, Storage, Event, Config<T>} = 8,
Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config<T>, Event, ValidateUnsigned} = 10,
ImOnline: pallet_im_online::{Pallet, Call, Storage, Event<T>, ValidateUnsigned, Config<T>} = 11,
@@ -1284,6 +1407,16 @@ pub type Migrations = migrations::Unreleased;
pub mod migrations {
use super::*;
/// Upgrade Session keys to include BEEFY key.
/// When this is removed, should also remove `OldSessionKeys`.
pub struct UpgradeSessionKeys;
impl frame_support::traits::OnRuntimeUpgrade for UpgradeSessionKeys {
fn on_runtime_upgrade() -> Weight {
Session::upgrade_keys::<OldSessionKeys, _>(transform_session_keys);
Perbill::from_percent(50) * BlockWeights::get().max_block
}
}
/// Unreleased migrations. Add new ones here:
pub type Unreleased = (
pallet_im_online::migration::v1::Migration<Runtime>,
@@ -1291,6 +1424,7 @@ pub mod migrations {
assigned_slots::migration::v1::VersionCheckedMigrateToV1<Runtime>,
parachains_scheduler::migration::v1::MigrateToV1<Runtime>,
parachains_configuration::migration::v8::MigrateToV8<Runtime>,
UpgradeSessionKeys,
);
}
@@ -1561,64 +1695,94 @@ sp_api::impl_runtime_apis! {
impl beefy_primitives::BeefyApi<Block, BeefyId> for Runtime {
fn beefy_genesis() -> Option<BlockNumber> {
// dummy implementation due to lack of BEEFY pallet.
None
Beefy::genesis_block()
}
fn validator_set() -> Option<beefy_primitives::ValidatorSet<BeefyId>> {
// dummy implementation due to lack of BEEFY pallet.
None
Beefy::validator_set()
}
fn submit_report_equivocation_unsigned_extrinsic(
_equivocation_proof: beefy_primitives::EquivocationProof<
equivocation_proof: beefy_primitives::EquivocationProof<
BlockNumber,
BeefyId,
BeefySignature,
>,
_key_owner_proof: beefy_primitives::OpaqueKeyOwnershipProof,
key_owner_proof: beefy_primitives::OpaqueKeyOwnershipProof,
) -> Option<()> {
None
let key_owner_proof = key_owner_proof.decode()?;
Beefy::submit_unsigned_equivocation_report(
equivocation_proof,
key_owner_proof,
)
}
fn generate_key_ownership_proof(
_set_id: beefy_primitives::ValidatorSetId,
_authority_id: BeefyId,
authority_id: BeefyId,
) -> Option<beefy_primitives::OpaqueKeyOwnershipProof> {
None
use parity_scale_codec::Encode;
Historical::prove((beefy_primitives::KEY_TYPE, authority_id))
.map(|p| p.encode())
.map(beefy_primitives::OpaqueKeyOwnershipProof::new)
}
}
impl mmr::MmrApi<Block, Hash, BlockNumber> for Runtime {
fn mmr_root() -> Result<Hash, mmr::Error> {
Err(mmr::Error::PalletNotIncluded)
fn mmr_root() -> Result<mmr::Hash, mmr::Error> {
Ok(Mmr::mmr_root())
}
fn mmr_leaf_count() -> Result<mmr::LeafIndex, mmr::Error> {
Err(mmr::Error::PalletNotIncluded)
Ok(Mmr::mmr_leaves())
}
fn generate_proof(
_block_numbers: Vec<BlockNumber>,
_best_known_block_number: Option<BlockNumber>,
) -> Result<(Vec<mmr::EncodableOpaqueLeaf>, mmr::Proof<Hash>), mmr::Error> {
Err(mmr::Error::PalletNotIncluded)
block_numbers: Vec<BlockNumber>,
best_known_block_number: Option<BlockNumber>,
) -> Result<(Vec<mmr::EncodableOpaqueLeaf>, mmr::Proof<mmr::Hash>), mmr::Error> {
Mmr::generate_proof(block_numbers, best_known_block_number).map(
|(leaves, proof)| {
(
leaves
.into_iter()
.map(|leaf| mmr::EncodableOpaqueLeaf::from_leaf(&leaf))
.collect(),
proof,
)
},
)
}
fn verify_proof(_leaves: Vec<mmr::EncodableOpaqueLeaf>, _proof: mmr::Proof<Hash>)
fn verify_proof(leaves: Vec<mmr::EncodableOpaqueLeaf>, proof: mmr::Proof<mmr::Hash>)
-> Result<(), mmr::Error>
{
Err(mmr::Error::PalletNotIncluded)
let leaves = leaves.into_iter().map(|leaf|
leaf.into_opaque_leaf()
.try_decode()
.ok_or(mmr::Error::Verify)).collect::<Result<Vec<mmr::Leaf>, mmr::Error>>()?;
Mmr::verify_leaves(leaves, proof)
}
fn verify_proof_stateless(
_root: Hash,
_leaves: Vec<mmr::EncodableOpaqueLeaf>,
_proof: mmr::Proof<Hash>
root: mmr::Hash,
leaves: Vec<mmr::EncodableOpaqueLeaf>,
proof: mmr::Proof<mmr::Hash>
) -> Result<(), mmr::Error> {
let nodes = leaves.into_iter().map(|leaf|mmr::DataOrHash::Data(leaf.into_opaque_leaf())).collect();
pallet_mmr::verify_leaves_proof::<mmr::Hashing, _>(root, nodes, proof)
}
}
Err(mmr::Error::PalletNotIncluded)
impl pallet_beefy_mmr::BeefyMmrApi<Block, Hash> for RuntimeApi {
fn authority_set_proof() -> beefy_primitives::mmr::BeefyAuthoritySet<Hash> {
BeefyMmrLeaf::authority_set_proof()
}
fn next_authority_set_proof() -> beefy_primitives::mmr::BeefyNextAuthoritySet<Hash> {
BeefyMmrLeaf::next_authority_set_proof()
}
}
+1 -6
View File
@@ -46,12 +46,7 @@ fn sample_size_is_sensible() {
#[test]
fn call_size() {
assert!(
core::mem::size_of::<RuntimeCall>() <= 230,
"size of RuntimeCall is more than 230 bytes: some calls have too big arguments, use Box to reduce \
the size of RuntimeCall.
If the limit is too strong, maybe consider increase the limit to 300.",
);
RuntimeCall::assert_size_under(256);
}
#[test]