feat: Rebrand Polkadot/Substrate references to PezkuwiChain
This commit systematically rebrands various references from Parity Technologies' Polkadot/Substrate ecosystem to PezkuwiChain within the kurdistan-sdk. Key changes include: - Updated external repository URLs (zombienet-sdk, parity-db, parity-scale-codec, wasm-instrument) to point to pezkuwichain forks. - Modified internal documentation and code comments to reflect PezkuwiChain naming and structure. - Replaced direct references to with or specific paths within the for XCM, Pezkuwi, and other modules. - Cleaned up deprecated issue and PR references in various and files, particularly in and modules. - Adjusted image and logo URLs in documentation to point to PezkuwiChain assets. - Removed or rephrased comments related to external Polkadot/Substrate PRs and issues. This is a significant step towards fully customizing the SDK for the PezkuwiChain ecosystem.
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
[package]
|
||||
name = "pezpallet-beefy-mmr"
|
||||
version = "28.0.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
license = "Apache-2.0"
|
||||
description = "BEEFY + MMR runtime utilities"
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
array-bytes = { optional = true, workspace = true, default-features = true }
|
||||
binary-merkle-tree = { workspace = true }
|
||||
codec = { features = ["derive"], workspace = true }
|
||||
pezframe-benchmarking = { optional = true, workspace = true }
|
||||
pezframe-support = { workspace = true }
|
||||
pezframe-system = { workspace = true }
|
||||
log = { workspace = true }
|
||||
pezpallet-beefy = { workspace = true }
|
||||
pezpallet-mmr = { workspace = true }
|
||||
pezpallet-session = { workspace = true }
|
||||
scale-info = { features = ["derive"], workspace = true }
|
||||
serde = { optional = true, workspace = true, default-features = true }
|
||||
pezsp-api = { workspace = true }
|
||||
pezsp-consensus-beefy = { workspace = true }
|
||||
pezsp-core = { workspace = true }
|
||||
pezsp-io = { workspace = true }
|
||||
pezsp-runtime = { workspace = true }
|
||||
pezsp-state-machine = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
array-bytes = { workspace = true, default-features = true }
|
||||
pezpallet-balances = { workspace = true }
|
||||
pezsp-staking = { workspace = true, default-features = true }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"array-bytes",
|
||||
"binary-merkle-tree/std",
|
||||
"codec/std",
|
||||
"pezframe-benchmarking/std",
|
||||
"pezframe-support/std",
|
||||
"pezframe-system/std",
|
||||
"log/std",
|
||||
"pezpallet-balances/std",
|
||||
"pezpallet-beefy/std",
|
||||
"pezpallet-mmr/std",
|
||||
"pezpallet-session/std",
|
||||
"scale-info/std",
|
||||
"serde",
|
||||
"pezsp-api/std",
|
||||
"pezsp-consensus-beefy/std",
|
||||
"pezsp-core/std",
|
||||
"pezsp-io/std",
|
||||
"pezsp-runtime/std",
|
||||
"pezsp-staking/std",
|
||||
"pezsp-state-machine/std",
|
||||
]
|
||||
try-runtime = [
|
||||
"pezframe-support/try-runtime",
|
||||
"pezframe-system/try-runtime",
|
||||
"pezpallet-balances/try-runtime",
|
||||
"pezpallet-beefy/try-runtime",
|
||||
"pezpallet-mmr/try-runtime",
|
||||
"pezpallet-session/try-runtime",
|
||||
"pezsp-runtime/try-runtime",
|
||||
]
|
||||
runtime-benchmarks = [
|
||||
"binary-merkle-tree/runtime-benchmarks",
|
||||
"pezframe-benchmarking/runtime-benchmarks",
|
||||
"pezframe-support/runtime-benchmarks",
|
||||
"pezframe-system/runtime-benchmarks",
|
||||
"pezpallet-balances/runtime-benchmarks",
|
||||
"pezpallet-beefy/runtime-benchmarks",
|
||||
"pezpallet-mmr/runtime-benchmarks",
|
||||
"pezpallet-session/runtime-benchmarks",
|
||||
"pezsp-api/runtime-benchmarks",
|
||||
"pezsp-consensus-beefy/runtime-benchmarks",
|
||||
"pezsp-io/runtime-benchmarks",
|
||||
"pezsp-runtime/runtime-benchmarks",
|
||||
"pezsp-staking/runtime-benchmarks",
|
||||
"pezsp-state-machine/runtime-benchmarks",
|
||||
]
|
||||
@@ -0,0 +1,141 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Beefy pallet benchmarking.
|
||||
|
||||
#![cfg(feature = "runtime-benchmarks")]
|
||||
|
||||
use super::*;
|
||||
use crate::Pallet as BeefyMmr;
|
||||
use codec::Encode;
|
||||
use pezframe_benchmarking::v2::*;
|
||||
use pezframe_support::traits::Hooks;
|
||||
use pezframe_system::{Config as SystemConfig, Pallet as System};
|
||||
use pezpallet_mmr::{Nodes, Pallet as Mmr};
|
||||
use pezsp_consensus_beefy::Payload;
|
||||
use pezsp_runtime::traits::One;
|
||||
|
||||
pub trait Config:
|
||||
pezpallet_mmr::Config<Hashing = pezsp_consensus_beefy::MmrHashing> + crate::Config
|
||||
{
|
||||
}
|
||||
|
||||
impl<T> Config for T where
|
||||
T: pezpallet_mmr::Config<Hashing = pezsp_consensus_beefy::MmrHashing> + crate::Config
|
||||
{
|
||||
}
|
||||
|
||||
fn init_block<T: Config>(block_num: u32) {
|
||||
let block_num = block_num.into();
|
||||
System::<T>::initialize(&block_num, &<T as SystemConfig>::Hash::default(), &Default::default());
|
||||
Mmr::<T>::on_initialize(block_num);
|
||||
}
|
||||
|
||||
#[benchmarks]
|
||||
mod benchmarks {
|
||||
use super::*;
|
||||
|
||||
/// Generate ancestry proofs with `n` leafs and benchmark the logic that checks
|
||||
/// if the proof is optimal.
|
||||
#[benchmark]
|
||||
fn n_leafs_proof_is_optimal(n: Linear<2, 512>) {
|
||||
pezpallet_mmr::UseLocalStorage::<T>::set(true);
|
||||
|
||||
for block_num in 1..=n {
|
||||
init_block::<T>(block_num);
|
||||
}
|
||||
let proof = Mmr::<T>::generate_mock_ancestry_proof().unwrap();
|
||||
assert_eq!(proof.leaf_count, n as u64);
|
||||
|
||||
#[block]
|
||||
{
|
||||
<BeefyMmr<T> as AncestryHelper<HeaderFor<T>>>::is_proof_optimal(&proof);
|
||||
};
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn extract_validation_context() {
|
||||
pezpallet_mmr::UseLocalStorage::<T>::set(true);
|
||||
|
||||
init_block::<T>(1);
|
||||
let header = System::<T>::finalize();
|
||||
pezframe_system::BlockHash::<T>::insert(BlockNumberFor::<T>::one(), header.hash());
|
||||
|
||||
let validation_context;
|
||||
#[block]
|
||||
{
|
||||
validation_context =
|
||||
<BeefyMmr<T> as AncestryHelper<HeaderFor<T>>>::extract_validation_context(header);
|
||||
}
|
||||
|
||||
assert!(validation_context.is_some());
|
||||
}
|
||||
|
||||
#[benchmark]
|
||||
fn read_peak() {
|
||||
pezpallet_mmr::UseLocalStorage::<T>::set(true);
|
||||
|
||||
init_block::<T>(1);
|
||||
|
||||
let peak;
|
||||
#[block]
|
||||
{
|
||||
peak = Nodes::<T>::get(0)
|
||||
}
|
||||
|
||||
assert!(peak.is_some());
|
||||
}
|
||||
|
||||
/// Generate ancestry proofs with `n` nodes and benchmark the verification logic.
|
||||
/// These proofs are inflated, containing all the leafs, so we won't read any peak during
|
||||
/// the verification. We need to account for the peaks separately.
|
||||
#[benchmark]
|
||||
fn n_items_proof_is_non_canonical(n: Linear<2, 512>) {
|
||||
pezpallet_mmr::UseLocalStorage::<T>::set(true);
|
||||
|
||||
for block_num in 1..=n {
|
||||
init_block::<T>(block_num);
|
||||
}
|
||||
let proof = Mmr::<T>::generate_mock_ancestry_proof().unwrap();
|
||||
assert_eq!(proof.items.len(), n as usize);
|
||||
|
||||
let is_non_canonical;
|
||||
#[block]
|
||||
{
|
||||
is_non_canonical = <BeefyMmr<T> as AncestryHelper<HeaderFor<T>>>::is_non_canonical(
|
||||
&Commitment {
|
||||
payload: Payload::from_single_entry(
|
||||
known_payloads::MMR_ROOT_ID,
|
||||
MerkleRootOf::<T>::default().encode(),
|
||||
),
|
||||
block_number: n.into(),
|
||||
validator_set_id: 0,
|
||||
},
|
||||
proof,
|
||||
Mmr::<T>::mmr_root(),
|
||||
);
|
||||
};
|
||||
|
||||
assert_eq!(is_non_canonical, true);
|
||||
}
|
||||
|
||||
impl_benchmark_test_suite!(
|
||||
Pallet,
|
||||
crate::mock::new_test_ext(Default::default()),
|
||||
crate::mock::Test
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,374 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
//! A BEEFY+MMR pallet combo.
|
||||
//!
|
||||
//! While both BEEFY and Merkle Mountain Range (MMR) can be used separately,
|
||||
//! these tools were designed to work together in unison.
|
||||
//!
|
||||
//! The pallet provides a standardized MMR Leaf format that can be used
|
||||
//! to bridge BEEFY+MMR-based networks (both standalone and Pezkuwi-like).
|
||||
//!
|
||||
//! The MMR leaf contains:
|
||||
//! 1. Block number and parent block hash.
|
||||
//! 2. Merkle Tree Root Hash of next BEEFY validator set.
|
||||
//! 3. Arbitrary extra leaf data to be used by downstream pallets to include custom data.
|
||||
//!
|
||||
//! and thanks to versioning can be easily updated in the future.
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use pezsp_runtime::{
|
||||
generic::OpaqueDigestItemId,
|
||||
traits::{Convert, Header, Member},
|
||||
SaturatedConversion,
|
||||
};
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use codec::Decode;
|
||||
use pezpallet_mmr::{primitives::AncestryProof, LeafDataProvider, NodesUtils, ParentNumberAndHash};
|
||||
use pezsp_consensus_beefy::{
|
||||
known_payloads,
|
||||
mmr::{BeefyAuthoritySet, BeefyDataProvider, BeefyNextAuthoritySet, MmrLeaf, MmrLeafVersion},
|
||||
AncestryHelper, AncestryHelperWeightInfo, Commitment, ConsensusLog,
|
||||
ValidatorSet as BeefyValidatorSet,
|
||||
};
|
||||
|
||||
use pezframe_support::{crypto::ecdsa::ECDSAExt, pezpallet_prelude::Weight, traits::Get};
|
||||
use pezframe_system::pezpallet_prelude::{BlockNumberFor, HeaderFor};
|
||||
|
||||
pub use pallet::*;
|
||||
pub use weights::WeightInfo;
|
||||
|
||||
mod benchmarking;
|
||||
#[cfg(test)]
|
||||
mod mock;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod weights;
|
||||
|
||||
/// A BEEFY consensus digest item with MMR root hash.
|
||||
pub struct DepositBeefyDigest<T>(core::marker::PhantomData<T>);
|
||||
|
||||
impl<T> pezpallet_mmr::primitives::OnNewRoot<pezsp_consensus_beefy::MmrRootHash> for DepositBeefyDigest<T>
|
||||
where
|
||||
T: pezpallet_mmr::Config<Hashing = pezsp_consensus_beefy::MmrHashing>,
|
||||
T: pezpallet_beefy::Config,
|
||||
{
|
||||
fn on_new_root(root: &pezsp_consensus_beefy::MmrRootHash) {
|
||||
let digest = pezsp_runtime::generic::DigestItem::Consensus(
|
||||
pezsp_consensus_beefy::BEEFY_ENGINE_ID,
|
||||
codec::Encode::encode(&pezsp_consensus_beefy::ConsensusLog::<
|
||||
<T as pezpallet_beefy::Config>::BeefyId,
|
||||
>::MmrRoot(*root)),
|
||||
);
|
||||
pezframe_system::Pallet::<T>::deposit_log(digest);
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert BEEFY secp256k1 public keys into Ethereum addresses
|
||||
pub struct BeefyEcdsaToEthereum;
|
||||
impl Convert<pezsp_consensus_beefy::ecdsa_crypto::AuthorityId, Vec<u8>> for BeefyEcdsaToEthereum {
|
||||
fn convert(beefy_id: pezsp_consensus_beefy::ecdsa_crypto::AuthorityId) -> Vec<u8> {
|
||||
pezsp_core::ecdsa::Public::from(beefy_id)
|
||||
.to_eth_address()
|
||||
.map(|v| v.to_vec())
|
||||
.map_err(|_| {
|
||||
log::debug!(target: "runtime::beefy", "Failed to convert BEEFY PublicKey to ETH address!");
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
type MerkleRootOf<T> = <<T as pezpallet_mmr::Config>::Hashing as pezsp_runtime::traits::Hash>::Output;
|
||||
|
||||
#[pezframe_support::pallet]
|
||||
pub mod pallet {
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use super::*;
|
||||
use pezframe_support::pezpallet_prelude::*;
|
||||
|
||||
/// BEEFY-MMR pallet.
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
|
||||
/// The module's configuration trait.
|
||||
#[pallet::config]
|
||||
#[pallet::disable_pezframe_system_supertrait_check]
|
||||
pub trait Config: pezpallet_mmr::Config + pezpallet_beefy::Config {
|
||||
/// Current leaf version.
|
||||
///
|
||||
/// Specifies the version number added to every leaf that get's appended to the MMR.
|
||||
/// Read more in [`MmrLeafVersion`] docs about versioning leaves.
|
||||
type LeafVersion: Get<MmrLeafVersion>;
|
||||
|
||||
/// Convert BEEFY AuthorityId to a form that would end up in the Merkle Tree.
|
||||
///
|
||||
/// For instance for ECDSA (secp256k1) we want to store uncompressed public keys (65 bytes)
|
||||
/// and later to Ethereum Addresses (160 bits) to simplify using them on Ethereum chain,
|
||||
/// but the rest of the Bizinikiwi codebase is storing them compressed (33 bytes) for
|
||||
/// efficiency reasons.
|
||||
type BeefyAuthorityToMerkleLeaf: Convert<<Self as pezpallet_beefy::Config>::BeefyId, Vec<u8>>;
|
||||
|
||||
/// The type expected for the leaf extra data
|
||||
type LeafExtra: Member + codec::FullCodec;
|
||||
|
||||
/// Retrieve arbitrary data that should be added to the mmr leaf
|
||||
type BeefyDataProvider: BeefyDataProvider<Self::LeafExtra>;
|
||||
|
||||
type WeightInfo: WeightInfo;
|
||||
}
|
||||
|
||||
/// Details of current BEEFY authority set.
|
||||
#[pallet::storage]
|
||||
pub type BeefyAuthorities<T: Config> =
|
||||
StorageValue<_, BeefyAuthoritySet<MerkleRootOf<T>>, ValueQuery>;
|
||||
|
||||
/// Details of next BEEFY authority set.
|
||||
///
|
||||
/// This storage entry is used as cache for calls to `update_beefy_next_authority_set`.
|
||||
#[pallet::storage]
|
||||
pub type BeefyNextAuthorities<T: Config> =
|
||||
StorageValue<_, BeefyNextAuthoritySet<MerkleRootOf<T>>, ValueQuery>;
|
||||
}
|
||||
|
||||
impl<T: Config> LeafDataProvider for Pallet<T> {
|
||||
type LeafData = MmrLeaf<
|
||||
BlockNumberFor<T>,
|
||||
<T as pezframe_system::Config>::Hash,
|
||||
MerkleRootOf<T>,
|
||||
T::LeafExtra,
|
||||
>;
|
||||
|
||||
fn leaf_data() -> Self::LeafData {
|
||||
MmrLeaf {
|
||||
version: T::LeafVersion::get(),
|
||||
parent_number_and_hash: ParentNumberAndHash::<T>::leaf_data(),
|
||||
leaf_extra: T::BeefyDataProvider::extra_data(),
|
||||
beefy_next_authority_set: BeefyNextAuthorities::<T>::get(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> pezsp_consensus_beefy::OnNewValidatorSet<<T as pezpallet_beefy::Config>::BeefyId> for Pallet<T>
|
||||
where
|
||||
T: pallet::Config,
|
||||
{
|
||||
/// Compute and cache BEEFY authority sets based on updated BEEFY validator sets.
|
||||
fn on_new_validator_set(
|
||||
current_set: &BeefyValidatorSet<<T as pezpallet_beefy::Config>::BeefyId>,
|
||||
next_set: &BeefyValidatorSet<<T as pezpallet_beefy::Config>::BeefyId>,
|
||||
) {
|
||||
let current = Pallet::<T>::compute_authority_set(current_set);
|
||||
let next = Pallet::<T>::compute_authority_set(next_set);
|
||||
// cache the result
|
||||
BeefyAuthorities::<T>::put(¤t);
|
||||
BeefyNextAuthorities::<T>::put(&next);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> AncestryHelper<HeaderFor<T>> for Pallet<T>
|
||||
where
|
||||
T: pezpallet_mmr::Config<Hashing = pezsp_consensus_beefy::MmrHashing>,
|
||||
{
|
||||
type Proof = AncestryProof<MerkleRootOf<T>>;
|
||||
type ValidationContext = MerkleRootOf<T>;
|
||||
|
||||
fn is_proof_optimal(proof: &Self::Proof) -> bool {
|
||||
let is_proof_optimal = pezpallet_mmr::Pallet::<T>::is_ancestry_proof_optimal(proof);
|
||||
|
||||
// We don't check the proof size when running benchmarks, since we use mock proofs
|
||||
// which would cause the test to fail.
|
||||
if cfg!(feature = "runtime-benchmarks") {
|
||||
return true;
|
||||
}
|
||||
|
||||
is_proof_optimal
|
||||
}
|
||||
|
||||
fn extract_validation_context(header: HeaderFor<T>) -> Option<Self::ValidationContext> {
|
||||
// Check if the provided header is canonical.
|
||||
let expected_hash = pezframe_system::Pallet::<T>::block_hash(header.number());
|
||||
if expected_hash != header.hash() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Extract the MMR root from the header digest
|
||||
header.digest().convert_first(|l| {
|
||||
l.try_to(OpaqueDigestItemId::Consensus(&pezsp_consensus_beefy::BEEFY_ENGINE_ID))
|
||||
.and_then(|log: ConsensusLog<<T as pezpallet_beefy::Config>::BeefyId>| match log {
|
||||
ConsensusLog::MmrRoot(mmr_root) => Some(mmr_root),
|
||||
_ => None,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn is_non_canonical(
|
||||
commitment: &Commitment<BlockNumberFor<T>>,
|
||||
proof: Self::Proof,
|
||||
context: Self::ValidationContext,
|
||||
) -> bool {
|
||||
let commitment_leaf_count =
|
||||
match pezpallet_mmr::Pallet::<T>::block_num_to_leaf_count(commitment.block_number) {
|
||||
Ok(commitment_leaf_count) => commitment_leaf_count,
|
||||
Err(_) => {
|
||||
// We can't prove that the commitment is non-canonical if the
|
||||
// `commitment.block_number` is invalid.
|
||||
return false;
|
||||
},
|
||||
};
|
||||
if commitment_leaf_count != proof.prev_leaf_count {
|
||||
// Can't prove that the commitment is non-canonical if the `commitment.block_number`
|
||||
// doesn't match the ancestry proof.
|
||||
return false;
|
||||
}
|
||||
|
||||
let canonical_mmr_root = context;
|
||||
let canonical_prev_root =
|
||||
match pezpallet_mmr::Pallet::<T>::verify_ancestry_proof(canonical_mmr_root, proof) {
|
||||
Ok(canonical_prev_root) => canonical_prev_root,
|
||||
Err(_) => {
|
||||
// Can't prove that the commitment is non-canonical if the proof
|
||||
// is invalid.
|
||||
return false;
|
||||
},
|
||||
};
|
||||
|
||||
let mut found_commitment_root = false;
|
||||
let commitment_roots = commitment
|
||||
.payload
|
||||
.get_all_decoded::<MerkleRootOf<T>>(&known_payloads::MMR_ROOT_ID);
|
||||
for maybe_commitment_root in commitment_roots {
|
||||
match maybe_commitment_root {
|
||||
Some(commitment_root) => {
|
||||
found_commitment_root = true;
|
||||
if canonical_prev_root != commitment_root {
|
||||
// If the commitment contains an MMR root, that is not equal to
|
||||
// `canonical_prev_root`, the commitment is invalid
|
||||
return true;
|
||||
}
|
||||
},
|
||||
None => {
|
||||
// If the commitment contains an MMR root, that can't be decoded, it is invalid.
|
||||
return true;
|
||||
},
|
||||
}
|
||||
}
|
||||
if !found_commitment_root {
|
||||
// If the commitment doesn't contain any MMR root, while the proof is valid,
|
||||
// the commitment is invalid
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> AncestryHelperWeightInfo<HeaderFor<T>> for Pallet<T>
|
||||
where
|
||||
T: pezpallet_mmr::Config<Hashing = pezsp_consensus_beefy::MmrHashing>,
|
||||
{
|
||||
fn is_proof_optimal(proof: &<Self as AncestryHelper<HeaderFor<T>>>::Proof) -> Weight {
|
||||
<T as Config>::WeightInfo::n_leafs_proof_is_optimal(proof.leaf_count.saturated_into())
|
||||
}
|
||||
|
||||
fn extract_validation_context() -> Weight {
|
||||
<T as Config>::WeightInfo::extract_validation_context()
|
||||
}
|
||||
|
||||
fn is_non_canonical(proof: &<Self as AncestryHelper<HeaderFor<T>>>::Proof) -> Weight {
|
||||
let mmr_utils = NodesUtils::new(proof.leaf_count);
|
||||
let num_peaks = mmr_utils.number_of_peaks();
|
||||
|
||||
// The approximated cost of verifying an ancestry proof with `n` nodes.
|
||||
// We add the previous peaks to the total number of nodes,
|
||||
// since they have to be processed as well.
|
||||
<T as Config>::WeightInfo::n_items_proof_is_non_canonical(
|
||||
proof.items.len().saturating_add(proof.prev_peaks.len()).saturated_into(),
|
||||
)
|
||||
// `n_items_proof_is_non_canonical()` uses inflated proofs that contain all the leafs,
|
||||
// where no peak needs to be read. So we need to also add the cost of reading the peaks.
|
||||
.saturating_add(<T as Config>::WeightInfo::read_peak().saturating_mul(num_peaks))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Config> Pallet<T> {
|
||||
/// Return the currently active BEEFY authority set proof.
|
||||
pub fn authority_set_proof() -> BeefyAuthoritySet<MerkleRootOf<T>> {
|
||||
BeefyAuthorities::<T>::get()
|
||||
}
|
||||
|
||||
/// Return the next/queued BEEFY authority set proof.
|
||||
pub fn next_authority_set_proof() -> BeefyNextAuthoritySet<MerkleRootOf<T>> {
|
||||
BeefyNextAuthorities::<T>::get()
|
||||
}
|
||||
|
||||
/// Returns details of a BEEFY authority set.
|
||||
///
|
||||
/// Details contain authority set id, authority set length and a merkle root,
|
||||
/// constructed from uncompressed secp256k1 public keys converted to Ethereum addresses
|
||||
/// of the next BEEFY authority set.
|
||||
fn compute_authority_set(
|
||||
validator_set: &BeefyValidatorSet<<T as pezpallet_beefy::Config>::BeefyId>,
|
||||
) -> BeefyAuthoritySet<MerkleRootOf<T>> {
|
||||
let id = validator_set.id();
|
||||
let beefy_addresses = validator_set
|
||||
.validators()
|
||||
.into_iter()
|
||||
.cloned()
|
||||
.map(T::BeefyAuthorityToMerkleLeaf::convert)
|
||||
.collect::<Vec<_>>();
|
||||
let default_eth_addr = [0u8; 20];
|
||||
let len = beefy_addresses.len() as u32;
|
||||
let uninitialized_addresses = beefy_addresses
|
||||
.iter()
|
||||
.filter(|&addr| addr.as_slice().eq(&default_eth_addr))
|
||||
.count();
|
||||
if uninitialized_addresses > 0 {
|
||||
log::error!(
|
||||
target: "runtime::beefy",
|
||||
"Failed to convert {} out of {} BEEFY PublicKeys to ETH addresses!",
|
||||
uninitialized_addresses,
|
||||
len,
|
||||
);
|
||||
}
|
||||
let keyset_commitment = binary_merkle_tree::merkle_root::<
|
||||
<T as pezpallet_mmr::Config>::Hashing,
|
||||
_,
|
||||
>(beefy_addresses)
|
||||
.into();
|
||||
BeefyAuthoritySet { id, len, keyset_commitment }
|
||||
}
|
||||
}
|
||||
|
||||
pezsp_api::decl_runtime_apis! {
|
||||
/// API useful for BEEFY light clients.
|
||||
pub trait BeefyMmrApi<H>
|
||||
where
|
||||
BeefyAuthoritySet<H>: Decode,
|
||||
{
|
||||
/// Return the currently active BEEFY authority set proof.
|
||||
fn authority_set_proof() -> BeefyAuthoritySet<H>;
|
||||
|
||||
/// Return the next/queued BEEFY authority set proof.
|
||||
fn next_authority_set_proof() -> BeefyNextAuthoritySet<H>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::vec;
|
||||
|
||||
use codec::Encode;
|
||||
use pezframe_support::{
|
||||
construct_runtime, derive_impl, parameter_types,
|
||||
traits::{ConstU32, ConstU64},
|
||||
};
|
||||
use pezsp_consensus_beefy::mmr::MmrLeafVersion;
|
||||
use pezsp_io::TestExternalities;
|
||||
use pezsp_runtime::{
|
||||
app_crypto::ecdsa::Public,
|
||||
impl_opaque_keys,
|
||||
traits::{ConvertInto, Keccak256, OpaqueKeys},
|
||||
BuildStorage,
|
||||
};
|
||||
use pezsp_state_machine::BasicExternalities;
|
||||
|
||||
use crate as pezpallet_beefy_mmr;
|
||||
|
||||
pub use pezsp_consensus_beefy::{
|
||||
ecdsa_crypto::AuthorityId as BeefyId, mmr::BeefyDataProvider, ConsensusLog, BEEFY_ENGINE_ID,
|
||||
};
|
||||
use pezsp_core::offchain::{testing::TestOffchainExt, OffchainDbExt, OffchainWorkerExt};
|
||||
|
||||
impl_opaque_keys! {
|
||||
pub struct MockSessionKeys {
|
||||
pub dummy: pezpallet_beefy::Pallet<Test>,
|
||||
}
|
||||
}
|
||||
|
||||
type Block = pezframe_system::mocking::MockBlock<Test>;
|
||||
|
||||
construct_runtime!(
|
||||
pub enum Test
|
||||
{
|
||||
System: pezframe_system,
|
||||
Session: pezpallet_session,
|
||||
Balances: pezpallet_balances,
|
||||
Mmr: pezpallet_mmr,
|
||||
Beefy: pezpallet_beefy,
|
||||
BeefyMmr: pezpallet_beefy_mmr,
|
||||
}
|
||||
);
|
||||
#[derive_impl(pezframe_system::config_preludes::TestDefaultConfig)]
|
||||
impl pezframe_system::Config for Test {
|
||||
type AccountData = pezpallet_balances::AccountData<u64>;
|
||||
type Block = Block;
|
||||
}
|
||||
|
||||
#[derive_impl(pezpallet_balances::config_preludes::TestDefaultConfig)]
|
||||
impl pezpallet_balances::Config for Test {
|
||||
type AccountStore = System;
|
||||
}
|
||||
|
||||
impl pezpallet_session::Config for Test {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type ValidatorId = u64;
|
||||
type ValidatorIdOf = ConvertInto;
|
||||
type ShouldEndSession = pezpallet_session::PeriodicSessions<ConstU64<1>, ConstU64<0>>;
|
||||
type NextSessionRotation = pezpallet_session::PeriodicSessions<ConstU64<1>, ConstU64<0>>;
|
||||
type SessionManager = MockSessionManager;
|
||||
type SessionHandler = <MockSessionKeys as OpaqueKeys>::KeyTypeIdProviders;
|
||||
type Keys = MockSessionKeys;
|
||||
type DisablingStrategy = ();
|
||||
type WeightInfo = ();
|
||||
type Currency = Balances;
|
||||
type KeyDeposit = ();
|
||||
}
|
||||
|
||||
pub type MmrLeaf = pezsp_consensus_beefy::mmr::MmrLeaf<
|
||||
pezframe_system::pezpallet_prelude::BlockNumberFor<Test>,
|
||||
<Test as pezframe_system::Config>::Hash,
|
||||
crate::MerkleRootOf<Test>,
|
||||
Vec<u8>,
|
||||
>;
|
||||
|
||||
impl pezpallet_mmr::Config for Test {
|
||||
const INDEXING_PREFIX: &'static [u8] = b"mmr";
|
||||
|
||||
type Hashing = Keccak256;
|
||||
|
||||
type LeafData = BeefyMmr;
|
||||
|
||||
type OnNewRoot = pezpallet_beefy_mmr::DepositBeefyDigest<Test>;
|
||||
|
||||
type BlockHashProvider = pezpallet_mmr::DefaultBlockHashProvider<Test>;
|
||||
|
||||
type WeightInfo = ();
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
type BenchmarkHelper = ();
|
||||
}
|
||||
|
||||
impl pezpallet_beefy::Config for Test {
|
||||
type BeefyId = BeefyId;
|
||||
type MaxAuthorities = ConstU32<100>;
|
||||
type MaxNominators = ConstU32<1000>;
|
||||
type MaxSetIdSessionEntries = ConstU64<100>;
|
||||
type OnNewValidatorSet = BeefyMmr;
|
||||
type AncestryHelper = BeefyMmr;
|
||||
type WeightInfo = ();
|
||||
type KeyOwnerProof = pezsp_core::Void;
|
||||
type EquivocationReportSystem = ();
|
||||
}
|
||||
|
||||
parameter_types! {
|
||||
pub LeafVersion: MmrLeafVersion = MmrLeafVersion::new(1, 5);
|
||||
}
|
||||
|
||||
impl pezpallet_beefy_mmr::Config for Test {
|
||||
type LeafVersion = LeafVersion;
|
||||
|
||||
type BeefyAuthorityToMerkleLeaf = pezpallet_beefy_mmr::BeefyEcdsaToEthereum;
|
||||
|
||||
type LeafExtra = Vec<u8>;
|
||||
|
||||
type BeefyDataProvider = DummyDataProvider;
|
||||
type WeightInfo = ();
|
||||
}
|
||||
|
||||
pub struct DummyDataProvider;
|
||||
impl BeefyDataProvider<Vec<u8>> for DummyDataProvider {
|
||||
fn extra_data() -> Vec<u8> {
|
||||
let mut col = vec![(15, vec![1, 2, 3]), (5, vec![4, 5, 6])];
|
||||
col.sort();
|
||||
binary_merkle_tree::merkle_root::<<Test as pezpallet_mmr::Config>::Hashing, _>(
|
||||
col.into_iter().map(|pair| pair.encode()),
|
||||
)
|
||||
.as_ref()
|
||||
.to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MockSessionManager;
|
||||
impl pezpallet_session::SessionManager<u64> for MockSessionManager {
|
||||
fn end_session(_: pezsp_staking::SessionIndex) {}
|
||||
fn start_session(_: pezsp_staking::SessionIndex) {}
|
||||
fn new_session(idx: pezsp_staking::SessionIndex) -> Option<Vec<u64>> {
|
||||
if idx == 0 || idx == 1 {
|
||||
Some(vec![1, 2])
|
||||
} else if idx == 2 {
|
||||
Some(vec![3, 4])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note, that we can't use `UintAuthorityId` here. Reason is that the implementation
|
||||
// of `to_public_key()` assumes, that a public key is 32 bytes long. This is true for
|
||||
// ed25519 and sr25519 but *not* for ecdsa. A compressed ecdsa public key is 33 bytes,
|
||||
// with the first one containing information to reconstruct the uncompressed key.
|
||||
pub fn mock_beefy_id(id: u8) -> BeefyId {
|
||||
let mut buf: [u8; 33] = [id; 33];
|
||||
// Set to something valid.
|
||||
buf[0] = 0x02;
|
||||
let pk = Public::from_raw(buf);
|
||||
BeefyId::from(pk)
|
||||
}
|
||||
|
||||
pub fn mock_authorities(vec: Vec<u8>) -> Vec<(u64, BeefyId)> {
|
||||
vec.into_iter().map(|id| ((id as u64), mock_beefy_id(id))).collect()
|
||||
}
|
||||
|
||||
pub fn new_test_ext(ids: Vec<u8>) -> TestExternalities {
|
||||
new_test_ext_raw_authorities(mock_authorities(ids))
|
||||
}
|
||||
|
||||
pub fn new_test_ext_raw_authorities(authorities: Vec<(u64, BeefyId)>) -> TestExternalities {
|
||||
let mut t = pezframe_system::GenesisConfig::<Test>::default().build_storage().unwrap();
|
||||
|
||||
let session_keys: Vec<_> = authorities
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(_, id)| (id.0 as u64, id.0 as u64, MockSessionKeys { dummy: id.1.clone() }))
|
||||
.collect();
|
||||
|
||||
BasicExternalities::execute_with_storage(&mut t, || {
|
||||
for (ref id, ..) in &session_keys {
|
||||
pezframe_system::Pallet::<Test>::inc_providers(id);
|
||||
}
|
||||
});
|
||||
|
||||
pezpallet_session::GenesisConfig::<Test> { keys: session_keys, ..Default::default() }
|
||||
.assimilate_storage(&mut t)
|
||||
.unwrap();
|
||||
|
||||
let mut ext: TestExternalities = t.into();
|
||||
let (offchain, _offchain_state) = TestOffchainExt::with_offchain_db(ext.offchain_db());
|
||||
ext.register_extension(OffchainDbExt::new(offchain.clone()));
|
||||
ext.register_extension(OffchainWorkerExt::new(offchain));
|
||||
|
||||
ext
|
||||
}
|
||||
@@ -0,0 +1,391 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::vec;
|
||||
|
||||
use codec::{Decode, Encode};
|
||||
use pezsp_consensus_beefy::{
|
||||
known_payloads,
|
||||
mmr::{BeefyNextAuthoritySet, MmrLeafVersion},
|
||||
AncestryHelper, Commitment, Payload, ValidatorSet,
|
||||
};
|
||||
|
||||
use pezsp_core::H256;
|
||||
use pezsp_io::TestExternalities;
|
||||
use pezsp_runtime::{traits::Keccak256, DigestItem};
|
||||
|
||||
use pezframe_support::traits::OnInitialize;
|
||||
|
||||
use crate::mock::*;
|
||||
|
||||
fn init_block(block: u64, maybe_parent_hash: Option<H256>) {
|
||||
let parent_hash = maybe_parent_hash.unwrap_or(H256::repeat_byte(block as u8));
|
||||
System::initialize(&block, &parent_hash, &Default::default());
|
||||
Session::on_initialize(block);
|
||||
Mmr::on_initialize(block);
|
||||
}
|
||||
|
||||
pub fn beefy_log(log: ConsensusLog<BeefyId>) -> DigestItem {
|
||||
DigestItem::Consensus(BEEFY_ENGINE_ID, log.encode())
|
||||
}
|
||||
|
||||
fn read_mmr_leaf(ext: &mut TestExternalities, key: Vec<u8>) -> MmrLeaf {
|
||||
type Node = pezpallet_mmr::primitives::DataOrHash<Keccak256, MmrLeaf>;
|
||||
ext.persist_offchain_overlay();
|
||||
let offchain_db = ext.offchain_db();
|
||||
offchain_db
|
||||
.get(&key)
|
||||
.map(|d| Node::decode(&mut &*d).unwrap())
|
||||
.map(|n| match n {
|
||||
Node::Data(d) => d,
|
||||
_ => panic!("Unexpected MMR node."),
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_contain_mmr_digest() {
|
||||
let mut ext = new_test_ext(vec![1, 2, 3, 4]);
|
||||
ext.execute_with(|| {
|
||||
init_block(1, None);
|
||||
assert_eq!(
|
||||
System::digest().logs,
|
||||
vec![
|
||||
beefy_log(ConsensusLog::AuthoritiesChange(
|
||||
ValidatorSet::new(vec![mock_beefy_id(1), mock_beefy_id(2)], 1).unwrap()
|
||||
)),
|
||||
beefy_log(ConsensusLog::MmrRoot(H256::from_slice(&[
|
||||
117, 0, 56, 25, 185, 195, 71, 232, 67, 213, 27, 178, 64, 168, 137, 220, 64,
|
||||
184, 64, 240, 83, 245, 18, 93, 185, 202, 125, 205, 17, 254, 18, 143
|
||||
])))
|
||||
]
|
||||
);
|
||||
|
||||
// unique every time
|
||||
init_block(2, None);
|
||||
assert_eq!(
|
||||
System::digest().logs,
|
||||
vec![
|
||||
beefy_log(ConsensusLog::AuthoritiesChange(
|
||||
ValidatorSet::new(vec![mock_beefy_id(3), mock_beefy_id(4)], 2).unwrap()
|
||||
)),
|
||||
beefy_log(ConsensusLog::MmrRoot(H256::from_slice(&[
|
||||
193, 246, 48, 7, 89, 204, 186, 109, 167, 226, 188, 211, 8, 243, 203, 154, 234,
|
||||
235, 136, 210, 245, 7, 209, 27, 241, 90, 156, 113, 137, 65, 191, 139
|
||||
]))),
|
||||
]
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_contain_valid_leaf_data() {
|
||||
fn node_offchain_key(pos: usize, parent_hash: H256) -> Vec<u8> {
|
||||
(<Test as pezpallet_mmr::Config>::INDEXING_PREFIX, pos as u64, parent_hash).encode()
|
||||
}
|
||||
|
||||
let mut ext = new_test_ext(vec![1, 2, 3, 4]);
|
||||
let parent_hash = ext.execute_with(|| {
|
||||
init_block(1, None);
|
||||
pezframe_system::Pallet::<Test>::parent_hash()
|
||||
});
|
||||
|
||||
let mmr_leaf = read_mmr_leaf(&mut ext, node_offchain_key(0, parent_hash));
|
||||
assert_eq!(
|
||||
mmr_leaf,
|
||||
MmrLeaf {
|
||||
version: MmrLeafVersion::new(1, 5),
|
||||
parent_number_and_hash: (0_u64, H256::repeat_byte(1)),
|
||||
beefy_next_authority_set: BeefyNextAuthoritySet {
|
||||
id: 2,
|
||||
len: 2,
|
||||
keyset_commitment: array_bytes::hex_n_into_unchecked(
|
||||
"9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5"
|
||||
)
|
||||
},
|
||||
leaf_extra: array_bytes::hex2bytes_unchecked(
|
||||
"55b8e9e1cc9f0db7776fac0ca66318ef8acfb8ec26db11e373120583e07ee648"
|
||||
)
|
||||
}
|
||||
);
|
||||
|
||||
// build second block on top
|
||||
let parent_hash = ext.execute_with(|| {
|
||||
init_block(2, None);
|
||||
pezframe_system::Pallet::<Test>::parent_hash()
|
||||
});
|
||||
|
||||
let mmr_leaf = read_mmr_leaf(&mut ext, node_offchain_key(1, parent_hash));
|
||||
assert_eq!(
|
||||
mmr_leaf,
|
||||
MmrLeaf {
|
||||
version: MmrLeafVersion::new(1, 5),
|
||||
parent_number_and_hash: (1_u64, H256::repeat_byte(2)),
|
||||
beefy_next_authority_set: BeefyNextAuthoritySet {
|
||||
id: 3,
|
||||
len: 2,
|
||||
keyset_commitment: array_bytes::hex_n_into_unchecked(
|
||||
"9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5"
|
||||
)
|
||||
},
|
||||
leaf_extra: array_bytes::hex2bytes_unchecked(
|
||||
"55b8e9e1cc9f0db7776fac0ca66318ef8acfb8ec26db11e373120583e07ee648"
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_update_authorities() {
|
||||
new_test_ext(vec![1, 2, 3, 4]).execute_with(|| {
|
||||
let auth_set = BeefyMmr::authority_set_proof();
|
||||
let next_auth_set = BeefyMmr::next_authority_set_proof();
|
||||
|
||||
// check current authority set
|
||||
assert_eq!(0, auth_set.id);
|
||||
assert_eq!(2, auth_set.len);
|
||||
let want = array_bytes::hex_n_into_unchecked::<_, H256, 32>(
|
||||
"176e73f1bf656478b728e28dd1a7733c98621b8acf830bff585949763dca7a96",
|
||||
);
|
||||
assert_eq!(want, auth_set.keyset_commitment);
|
||||
|
||||
// next authority set should have same validators but different id
|
||||
assert_eq!(1, next_auth_set.id);
|
||||
assert_eq!(auth_set.len, next_auth_set.len);
|
||||
assert_eq!(auth_set.keyset_commitment, next_auth_set.keyset_commitment);
|
||||
|
||||
let announced_set = next_auth_set;
|
||||
init_block(1, None);
|
||||
let auth_set = BeefyMmr::authority_set_proof();
|
||||
let next_auth_set = BeefyMmr::next_authority_set_proof();
|
||||
|
||||
// check new auth are expected ones
|
||||
assert_eq!(announced_set, auth_set);
|
||||
assert_eq!(1, auth_set.id);
|
||||
// check next auth set
|
||||
assert_eq!(2, next_auth_set.id);
|
||||
let want = array_bytes::hex_n_into_unchecked::<_, H256, 32>(
|
||||
"9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5",
|
||||
);
|
||||
assert_eq!(2, next_auth_set.len);
|
||||
assert_eq!(want, next_auth_set.keyset_commitment);
|
||||
|
||||
let announced_set = next_auth_set;
|
||||
init_block(2, None);
|
||||
let auth_set = BeefyMmr::authority_set_proof();
|
||||
let next_auth_set = BeefyMmr::next_authority_set_proof();
|
||||
|
||||
// check new auth are expected ones
|
||||
assert_eq!(announced_set, auth_set);
|
||||
assert_eq!(2, auth_set.id);
|
||||
// check next auth set
|
||||
assert_eq!(3, next_auth_set.id);
|
||||
let want = array_bytes::hex_n_into_unchecked::<_, H256, 32>(
|
||||
"9c6b2c1b0d0b25a008e6c882cc7b415f309965c72ad2b944ac0931048ca31cd5",
|
||||
);
|
||||
assert_eq!(2, next_auth_set.len);
|
||||
assert_eq!(want, next_auth_set.keyset_commitment);
|
||||
});
|
||||
}
|
||||
|
||||
// If you need to modify the test because you added a new event or something to the block or block
|
||||
// header you need to update the test by replacing the expected_mmr_root with the new one
|
||||
// you can get the new one by running the test while commenting out the first assert
|
||||
// and then copy pasting the new mmr root from the log of the second assert
|
||||
#[test]
|
||||
fn extract_validation_context_should_work_correctly() {
|
||||
let mut ext = new_test_ext(vec![1, 2]);
|
||||
|
||||
ext.execute_with(|| {
|
||||
init_block(1, None);
|
||||
let h1 = System::finalize();
|
||||
init_block(2, Some(h1.hash()));
|
||||
let h2 = System::finalize();
|
||||
|
||||
// Check the MMR root log
|
||||
let expected_mmr_root: [u8; 32] = array_bytes::hex_n_into_unchecked(
|
||||
"322c6a46ac00d3455c87bd9af42ebafb388f589a1b562f5e39b1d0d71bcbe8e0",
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
System::digest().logs,
|
||||
vec![beefy_log(ConsensusLog::MmrRoot(H256::from_slice(&expected_mmr_root)))]
|
||||
);
|
||||
|
||||
// Make sure that all the info about h2 was stored on-chain
|
||||
init_block(3, Some(h2.hash()));
|
||||
|
||||
// `extract_validation_context` should return the MMR root when the provided header
|
||||
// is part of the chain,
|
||||
assert_eq!(
|
||||
BeefyMmr::extract_validation_context(h2.clone()),
|
||||
Some(H256::from_slice(&expected_mmr_root))
|
||||
);
|
||||
|
||||
// `extract_validation_context` should return `None` when the provided header
|
||||
// is not part of the chain.
|
||||
let mut fork_h2 = h2;
|
||||
fork_h2.state_root = H256::repeat_byte(0);
|
||||
assert_eq!(BeefyMmr::extract_validation_context(fork_h2), None);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_non_canonical_should_work_correctly() {
|
||||
let mut ext = new_test_ext(vec![1, 2]);
|
||||
|
||||
let mut prev_roots = vec![];
|
||||
ext.execute_with(|| {
|
||||
for block_num in 1..=500 {
|
||||
init_block(block_num, None);
|
||||
prev_roots.push(Mmr::mmr_root())
|
||||
}
|
||||
});
|
||||
ext.persist_offchain_overlay();
|
||||
|
||||
ext.execute_with(|| {
|
||||
let valid_proof = Mmr::generate_ancestry_proof(250, None).unwrap();
|
||||
let mut invalid_proof = valid_proof.clone();
|
||||
invalid_proof.items.push((300, Default::default()));
|
||||
|
||||
// The commitment is invalid if it has no MMR root payload and the proof is valid.
|
||||
assert_eq!(
|
||||
BeefyMmr::is_non_canonical(
|
||||
&Commitment {
|
||||
payload: Payload::from_single_entry([0, 0], vec![]),
|
||||
block_number: 250,
|
||||
validator_set_id: 0
|
||||
},
|
||||
valid_proof.clone(),
|
||||
Mmr::mmr_root(),
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
// If the `commitment.payload` contains an MMR root that doesn't match the ancestry proof,
|
||||
// it's non-canonical.
|
||||
assert_eq!(
|
||||
BeefyMmr::is_non_canonical(
|
||||
&Commitment {
|
||||
payload: Payload::from_single_entry(
|
||||
known_payloads::MMR_ROOT_ID,
|
||||
prev_roots[250 - 1].encode()
|
||||
)
|
||||
.push_raw(known_payloads::MMR_ROOT_ID, H256::repeat_byte(0).encode(),),
|
||||
block_number: 250,
|
||||
validator_set_id: 0,
|
||||
},
|
||||
valid_proof.clone(),
|
||||
Mmr::mmr_root(),
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
// If the `commitment.payload` contains an MMR root that can't be decoded,
|
||||
// it's non-canonical.
|
||||
assert_eq!(
|
||||
BeefyMmr::is_non_canonical(
|
||||
&Commitment {
|
||||
payload: Payload::from_single_entry(
|
||||
known_payloads::MMR_ROOT_ID,
|
||||
prev_roots[250 - 1].encode()
|
||||
)
|
||||
.push_raw(known_payloads::MMR_ROOT_ID, vec![],),
|
||||
block_number: 250,
|
||||
validator_set_id: 0,
|
||||
},
|
||||
valid_proof.clone(),
|
||||
Mmr::mmr_root(),
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
// Should return false if the proof is invalid, no matter the payload.
|
||||
assert_eq!(
|
||||
BeefyMmr::is_non_canonical(
|
||||
&Commitment {
|
||||
payload: Payload::from_single_entry(
|
||||
known_payloads::MMR_ROOT_ID,
|
||||
H256::repeat_byte(0).encode(),
|
||||
),
|
||||
block_number: 250,
|
||||
validator_set_id: 0
|
||||
},
|
||||
invalid_proof,
|
||||
Mmr::mmr_root(),
|
||||
),
|
||||
false
|
||||
);
|
||||
|
||||
// Can't prove that the commitment is non-canonical if the `commitment.block_number`
|
||||
// doesn't match the ancestry proof.
|
||||
assert_eq!(
|
||||
BeefyMmr::is_non_canonical(
|
||||
&Commitment {
|
||||
payload: Payload::from_single_entry(
|
||||
known_payloads::MMR_ROOT_ID,
|
||||
prev_roots[250 - 1].encode(),
|
||||
),
|
||||
block_number: 300,
|
||||
validator_set_id: 0,
|
||||
},
|
||||
valid_proof,
|
||||
Mmr::mmr_root(),
|
||||
),
|
||||
false
|
||||
);
|
||||
|
||||
// For each previous block, the check:
|
||||
// - should return false, if the commitment is targeting the canonical chain
|
||||
// - should return true if the commitment is NOT targeting the canonical chain
|
||||
for prev_block_number in 1usize..=500 {
|
||||
let proof = Mmr::generate_ancestry_proof(prev_block_number as u64, None).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
BeefyMmr::is_non_canonical(
|
||||
&Commitment {
|
||||
payload: Payload::from_single_entry(
|
||||
known_payloads::MMR_ROOT_ID,
|
||||
prev_roots[prev_block_number - 1].encode(),
|
||||
),
|
||||
block_number: prev_block_number as u64,
|
||||
validator_set_id: 0,
|
||||
},
|
||||
proof.clone(),
|
||||
Mmr::mmr_root(),
|
||||
),
|
||||
false
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
BeefyMmr::is_non_canonical(
|
||||
&Commitment {
|
||||
payload: Payload::from_single_entry(
|
||||
known_payloads::MMR_ROOT_ID,
|
||||
H256::repeat_byte(0).encode(),
|
||||
),
|
||||
block_number: prev_block_number as u64,
|
||||
validator_set_id: 0,
|
||||
},
|
||||
proof,
|
||||
Mmr::mmr_root(),
|
||||
),
|
||||
true
|
||||
)
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Autogenerated weights for `pezpallet_beefy_mmr`
|
||||
//!
|
||||
//! THIS FILE WAS AUTO-GENERATED USING THE BIZINIKIWI BENCHMARK CLI VERSION 32.0.0
|
||||
//! DATE: 2025-02-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
|
||||
//! WORST CASE MAP SIZE: `1000000`
|
||||
//! HOSTNAME: `4563561839a5`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
|
||||
//! WASM-EXECUTION: `Compiled`, CHAIN: `None`, DB CACHE: `1024`
|
||||
|
||||
// Executed Command:
|
||||
// frame-omni-bencher
|
||||
// v1
|
||||
// benchmark
|
||||
// pallet
|
||||
// --extrinsic=*
|
||||
// --runtime=target/production/wbuild/kitchensink-runtime/kitchensink_runtime.wasm
|
||||
// --pallet=pezpallet_beefy_mmr
|
||||
// --header=/__w/pezkuwi-sdk/pezkuwi-sdk/bizinikiwi/HEADER-APACHE2
|
||||
// --output=/__w/pezkuwi-sdk/pezkuwi-sdk/bizinikiwi/pezframe/beefy-mmr/src/weights.rs
|
||||
// --wasm-execution=compiled
|
||||
// --steps=50
|
||||
// --repeat=20
|
||||
// --heap-pages=4096
|
||||
// --template=bizinikiwi/.maintain/frame-weight-template.hbs
|
||||
// --no-storage-info
|
||||
// --no-min-squares
|
||||
// --no-median-slopes
|
||||
// --genesis-builder-policy=none
|
||||
// --exclude-pallets=pezpallet_xcm,pezpallet_xcm_benchmarks::fungible,pezpallet_xcm_benchmarks::generic,pezpallet_nomination_pools,pezpallet_remark,pezpallet_transaction_storage,pezpallet_election_provider_multi_block,pezpallet_election_provider_multi_block::signed,pezpallet_election_provider_multi_block::unsigned,pezpallet_election_provider_multi_block::verifier
|
||||
|
||||
#![cfg_attr(rustfmt, rustfmt_skip)]
|
||||
#![allow(unused_parens)]
|
||||
#![allow(unused_imports)]
|
||||
#![allow(missing_docs)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
use pezframe_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
|
||||
use core::marker::PhantomData;
|
||||
|
||||
/// Weight functions needed for `pezpallet_beefy_mmr`.
|
||||
pub trait WeightInfo {
|
||||
fn n_leafs_proof_is_optimal(n: u32, ) -> Weight;
|
||||
fn extract_validation_context() -> Weight;
|
||||
fn read_peak() -> Weight;
|
||||
fn n_items_proof_is_non_canonical(n: u32, ) -> Weight;
|
||||
}
|
||||
|
||||
/// Weights for `pezpallet_beefy_mmr` using the Bizinikiwi node and recommended hardware.
|
||||
pub struct BizinikiwiWeight<T>(PhantomData<T>);
|
||||
impl<T: pezframe_system::Config> WeightInfo for BizinikiwiWeight<T> {
|
||||
/// The range of component `n` is `[2, 512]`.
|
||||
fn n_leafs_proof_is_optimal(n: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `0`
|
||||
// Minimum execution time: 624_000 picoseconds.
|
||||
Weight::from_parts(1_113_539, 0)
|
||||
// Standard Error: 66
|
||||
.saturating_add(Weight::from_parts(1_511, 0).saturating_mul(n.into()))
|
||||
}
|
||||
/// Storage: `System::BlockHash` (r:1 w:0)
|
||||
/// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`)
|
||||
fn extract_validation_context() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `14`
|
||||
// Estimated: `3509`
|
||||
// Minimum execution time: 4_653_000 picoseconds.
|
||||
Weight::from_parts(4_840_000, 3509)
|
||||
.saturating_add(T::DbWeight::get().reads(1_u64))
|
||||
}
|
||||
/// Storage: `Mmr::Nodes` (r:1 w:0)
|
||||
/// Proof: `Mmr::Nodes` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
|
||||
fn read_peak() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `129`
|
||||
// Estimated: `3505`
|
||||
// Minimum execution time: 4_524_000 picoseconds.
|
||||
Weight::from_parts(4_667_000, 3505)
|
||||
.saturating_add(T::DbWeight::get().reads(1_u64))
|
||||
}
|
||||
/// Storage: `Mmr::RootHash` (r:1 w:0)
|
||||
/// Proof: `Mmr::RootHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Mmr::NumberOfLeaves` (r:1 w:0)
|
||||
/// Proof: `Mmr::NumberOfLeaves` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`)
|
||||
/// The range of component `n` is `[2, 512]`.
|
||||
fn n_items_proof_is_non_canonical(n: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `121`
|
||||
// Estimated: `1517`
|
||||
// Minimum execution time: 8_958_000 picoseconds.
|
||||
Weight::from_parts(14_508_704, 1517)
|
||||
// Standard Error: 1_624
|
||||
.saturating_add(Weight::from_parts(982_244, 0).saturating_mul(n.into()))
|
||||
.saturating_add(T::DbWeight::get().reads(2_u64))
|
||||
}
|
||||
}
|
||||
|
||||
// For backwards compatibility and tests.
|
||||
impl WeightInfo for () {
|
||||
/// The range of component `n` is `[2, 512]`.
|
||||
fn n_leafs_proof_is_optimal(n: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `0`
|
||||
// Estimated: `0`
|
||||
// Minimum execution time: 624_000 picoseconds.
|
||||
Weight::from_parts(1_113_539, 0)
|
||||
// Standard Error: 66
|
||||
.saturating_add(Weight::from_parts(1_511, 0).saturating_mul(n.into()))
|
||||
}
|
||||
/// Storage: `System::BlockHash` (r:1 w:0)
|
||||
/// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`)
|
||||
fn extract_validation_context() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `14`
|
||||
// Estimated: `3509`
|
||||
// Minimum execution time: 4_653_000 picoseconds.
|
||||
Weight::from_parts(4_840_000, 3509)
|
||||
.saturating_add(RocksDbWeight::get().reads(1_u64))
|
||||
}
|
||||
/// Storage: `Mmr::Nodes` (r:1 w:0)
|
||||
/// Proof: `Mmr::Nodes` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`)
|
||||
fn read_peak() -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `129`
|
||||
// Estimated: `3505`
|
||||
// Minimum execution time: 4_524_000 picoseconds.
|
||||
Weight::from_parts(4_667_000, 3505)
|
||||
.saturating_add(RocksDbWeight::get().reads(1_u64))
|
||||
}
|
||||
/// Storage: `Mmr::RootHash` (r:1 w:0)
|
||||
/// Proof: `Mmr::RootHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
|
||||
/// Storage: `Mmr::NumberOfLeaves` (r:1 w:0)
|
||||
/// Proof: `Mmr::NumberOfLeaves` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`)
|
||||
/// The range of component `n` is `[2, 512]`.
|
||||
fn n_items_proof_is_non_canonical(n: u32, ) -> Weight {
|
||||
// Proof Size summary in bytes:
|
||||
// Measured: `121`
|
||||
// Estimated: `1517`
|
||||
// Minimum execution time: 8_958_000 picoseconds.
|
||||
Weight::from_parts(14_508_704, 1517)
|
||||
// Standard Error: 1_624
|
||||
.saturating_add(Weight::from_parts(982_244, 0).saturating_mul(n.into()))
|
||||
.saturating_add(RocksDbWeight::get().reads(2_u64))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user