mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 19:51:02 +00:00
Wire Finality Verifier Pallet Into Runtimes (#696)
* Add Finality Verifier pallet to runtimes * Implement simple ancestry checker * Use the new checker in runtimes * Remove unused import warning * Bump max allowed ancestry proof size * Add a few optimization suggestions when verifying ancestry * Use session length as upper bound for ancestry proof size * Remove unused time units
This commit is contained in:
committed by
Bastian Köcher
parent
d73100cb30
commit
8c7d0ca35d
@@ -14,12 +14,14 @@ serde = { version = "1.0.121", optional = true, features = ["derive"] }
|
|||||||
|
|
||||||
# Bridge dependencies
|
# Bridge dependencies
|
||||||
|
|
||||||
|
bp-header-chain = { path = "../../../primitives/header-chain", default-features = false }
|
||||||
bp-message-lane = { path = "../../../primitives/message-lane", default-features = false }
|
bp-message-lane = { path = "../../../primitives/message-lane", default-features = false }
|
||||||
bp-millau = { path = "../../../primitives/millau", default-features = false }
|
bp-millau = { path = "../../../primitives/millau", default-features = false }
|
||||||
bp-rialto = { path = "../../../primitives/rialto", default-features = false }
|
bp-rialto = { path = "../../../primitives/rialto", default-features = false }
|
||||||
bp-runtime = { path = "../../../primitives/runtime", default-features = false }
|
bp-runtime = { path = "../../../primitives/runtime", default-features = false }
|
||||||
bridge-runtime-common = { path = "../../runtime-common", default-features = false }
|
bridge-runtime-common = { path = "../../runtime-common", default-features = false }
|
||||||
pallet-bridge-call-dispatch = { path = "../../../modules/call-dispatch", default-features = false }
|
pallet-bridge-call-dispatch = { path = "../../../modules/call-dispatch", default-features = false }
|
||||||
|
pallet-finality-verifier = { path = "../../../modules/finality-verifier", default-features = false }
|
||||||
pallet-message-lane = { path = "../../../modules/message-lane", default-features = false }
|
pallet-message-lane = { path = "../../../modules/message-lane", default-features = false }
|
||||||
pallet-shift-session-manager = { path = "../../../modules/shift-session-manager", default-features = false }
|
pallet-shift-session-manager = { path = "../../../modules/shift-session-manager", default-features = false }
|
||||||
pallet-substrate-bridge = { path = "../../../modules/substrate", default-features = false }
|
pallet-substrate-bridge = { path = "../../../modules/substrate", default-features = false }
|
||||||
@@ -58,6 +60,7 @@ wasm-builder-runner = { package = "substrate-wasm-builder-runner", version = "2.
|
|||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
std = [
|
std = [
|
||||||
|
"bp-header-chain/std",
|
||||||
"bp-message-lane/std",
|
"bp-message-lane/std",
|
||||||
"bp-millau/std",
|
"bp-millau/std",
|
||||||
"bp-rialto/std",
|
"bp-rialto/std",
|
||||||
@@ -71,6 +74,7 @@ std = [
|
|||||||
"pallet-aura/std",
|
"pallet-aura/std",
|
||||||
"pallet-balances/std",
|
"pallet-balances/std",
|
||||||
"pallet-bridge-call-dispatch/std",
|
"pallet-bridge-call-dispatch/std",
|
||||||
|
"pallet-finality-verifier/std",
|
||||||
"pallet-grandpa/std",
|
"pallet-grandpa/std",
|
||||||
"pallet-message-lane/std",
|
"pallet-message-lane/std",
|
||||||
"pallet-randomness-collective-flip/std",
|
"pallet-randomness-collective-flip/std",
|
||||||
|
|||||||
@@ -132,15 +132,6 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
|||||||
transaction_version: 1,
|
transaction_version: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const MILLISECS_PER_BLOCK: u64 = 6000;
|
|
||||||
|
|
||||||
pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
|
|
||||||
|
|
||||||
// These time units are defined in number of blocks.
|
|
||||||
pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
|
|
||||||
pub const HOURS: BlockNumber = MINUTES * 60;
|
|
||||||
pub const DAYS: BlockNumber = HOURS * 24;
|
|
||||||
|
|
||||||
/// The version information used to identify this runtime when compiled natively.
|
/// The version information used to identify this runtime when compiled natively.
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub fn native_version() -> NativeVersion {
|
pub fn native_version() -> NativeVersion {
|
||||||
@@ -236,7 +227,7 @@ impl pallet_grandpa::Config for Runtime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parameter_types! {
|
parameter_types! {
|
||||||
pub const MinimumPeriod: u64 = SLOT_DURATION / 2;
|
pub const MinimumPeriod: u64 = bp_millau::SLOT_DURATION / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl pallet_timestamp::Config for Runtime {
|
impl pallet_timestamp::Config for Runtime {
|
||||||
@@ -287,7 +278,7 @@ impl pallet_sudo::Config for Runtime {
|
|||||||
|
|
||||||
parameter_types! {
|
parameter_types! {
|
||||||
/// Authorities are changing every 5 minutes.
|
/// Authorities are changing every 5 minutes.
|
||||||
pub const Period: BlockNumber = 5 * MINUTES;
|
pub const Period: BlockNumber = bp_millau::SESSION_LENGTH;
|
||||||
pub const Offset: BlockNumber = 0;
|
pub const Offset: BlockNumber = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,6 +300,19 @@ impl pallet_substrate_bridge::Config for Runtime {
|
|||||||
type BridgedChain = bp_rialto::Rialto;
|
type BridgedChain = bp_rialto::Rialto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parameter_types! {
|
||||||
|
// We'll use the length of a session on the bridged chain as our bound since GRANDPA is
|
||||||
|
// guaranteed to produce a justification every session.
|
||||||
|
pub const MaxHeadersInSingleProof: bp_rialto::BlockNumber = bp_rialto::SESSION_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl pallet_finality_verifier::Config for Runtime {
|
||||||
|
type BridgedChain = bp_rialto::Rialto;
|
||||||
|
type HeaderChain = pallet_substrate_bridge::Module<Runtime>;
|
||||||
|
type AncestryChecker = bp_header_chain::LinearAncestryChecker;
|
||||||
|
type MaxHeadersInSingleProof = MaxHeadersInSingleProof;
|
||||||
|
}
|
||||||
|
|
||||||
impl pallet_shift_session_manager::Config for Runtime {}
|
impl pallet_shift_session_manager::Config for Runtime {}
|
||||||
|
|
||||||
parameter_types! {
|
parameter_types! {
|
||||||
@@ -362,6 +366,7 @@ construct_runtime!(
|
|||||||
BridgeRialto: pallet_substrate_bridge::{Module, Call, Storage, Config<T>},
|
BridgeRialto: pallet_substrate_bridge::{Module, Call, Storage, Config<T>},
|
||||||
BridgeRialtoMessageLane: pallet_message_lane::{Module, Call, Storage, Event<T>},
|
BridgeRialtoMessageLane: pallet_message_lane::{Module, Call, Storage, Event<T>},
|
||||||
BridgeCallDispatch: pallet_bridge_call_dispatch::{Module, Event<T>},
|
BridgeCallDispatch: pallet_bridge_call_dispatch::{Module, Event<T>},
|
||||||
|
BridgeFinalityVerifier: pallet_finality_verifier::{Module, Call},
|
||||||
System: frame_system::{Module, Call, Config, Storage, Event<T>},
|
System: frame_system::{Module, Call, Config, Storage, Event<T>},
|
||||||
RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Module, Call, Storage},
|
RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Module, Call, Storage},
|
||||||
Timestamp: pallet_timestamp::{Module, Call, Storage, Inherent},
|
Timestamp: pallet_timestamp::{Module, Call, Storage, Inherent},
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ bridge-runtime-common = { path = "../../runtime-common", default-features = fals
|
|||||||
pallet-bridge-eth-poa = { path = "../../../modules/ethereum", default-features = false }
|
pallet-bridge-eth-poa = { path = "../../../modules/ethereum", default-features = false }
|
||||||
pallet-bridge-call-dispatch = { path = "../../../modules/call-dispatch", default-features = false }
|
pallet-bridge-call-dispatch = { path = "../../../modules/call-dispatch", default-features = false }
|
||||||
pallet-bridge-currency-exchange = { path = "../../../modules/currency-exchange", default-features = false }
|
pallet-bridge-currency-exchange = { path = "../../../modules/currency-exchange", default-features = false }
|
||||||
|
pallet-finality-verifier = { path = "../../../modules/finality-verifier", default-features = false }
|
||||||
pallet-substrate-bridge = { path = "../../../modules/substrate", default-features = false }
|
pallet-substrate-bridge = { path = "../../../modules/substrate", default-features = false }
|
||||||
pallet-message-lane = { path = "../../../modules/message-lane", default-features = false }
|
pallet-message-lane = { path = "../../../modules/message-lane", default-features = false }
|
||||||
pallet-shift-session-manager = { path = "../../../modules/shift-session-manager", default-features = false }
|
pallet-shift-session-manager = { path = "../../../modules/shift-session-manager", default-features = false }
|
||||||
@@ -90,6 +91,7 @@ std = [
|
|||||||
"pallet-bridge-eth-poa/std",
|
"pallet-bridge-eth-poa/std",
|
||||||
"pallet-bridge-call-dispatch/std",
|
"pallet-bridge-call-dispatch/std",
|
||||||
"pallet-bridge-currency-exchange/std",
|
"pallet-bridge-currency-exchange/std",
|
||||||
|
"pallet-finality-verifier/std",
|
||||||
"pallet-grandpa/std",
|
"pallet-grandpa/std",
|
||||||
"pallet-message-lane/std",
|
"pallet-message-lane/std",
|
||||||
"pallet-randomness-collective-flip/std",
|
"pallet-randomness-collective-flip/std",
|
||||||
|
|||||||
@@ -140,15 +140,6 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
|||||||
transaction_version: 1,
|
transaction_version: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const MILLISECS_PER_BLOCK: u64 = 6000;
|
|
||||||
|
|
||||||
pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
|
|
||||||
|
|
||||||
// These time units are defined in number of blocks.
|
|
||||||
pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
|
|
||||||
pub const HOURS: BlockNumber = MINUTES * 60;
|
|
||||||
pub const DAYS: BlockNumber = HOURS * 24;
|
|
||||||
|
|
||||||
/// The version information used to identify this runtime when compiled natively.
|
/// The version information used to identify this runtime when compiled natively.
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub fn native_version() -> NativeVersion {
|
pub fn native_version() -> NativeVersion {
|
||||||
@@ -344,7 +335,7 @@ impl pallet_grandpa::Config for Runtime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parameter_types! {
|
parameter_types! {
|
||||||
pub const MinimumPeriod: u64 = SLOT_DURATION / 2;
|
pub const MinimumPeriod: u64 = bp_rialto::SLOT_DURATION / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl pallet_timestamp::Config for Runtime {
|
impl pallet_timestamp::Config for Runtime {
|
||||||
@@ -394,7 +385,7 @@ impl pallet_sudo::Config for Runtime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parameter_types! {
|
parameter_types! {
|
||||||
pub const Period: BlockNumber = 4;
|
pub const Period: BlockNumber = bp_rialto::SESSION_LENGTH;
|
||||||
pub const Offset: BlockNumber = 0;
|
pub const Offset: BlockNumber = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -416,6 +407,19 @@ impl pallet_substrate_bridge::Config for Runtime {
|
|||||||
type BridgedChain = bp_millau::Millau;
|
type BridgedChain = bp_millau::Millau;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parameter_types! {
|
||||||
|
// We'll use the length of a session on the bridged chain as our bound since GRANDPA is
|
||||||
|
// guaranteed to produce a justification every session.
|
||||||
|
pub const MaxHeadersInSingleProof: bp_millau::BlockNumber = bp_millau::SESSION_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl pallet_finality_verifier::Config for Runtime {
|
||||||
|
type BridgedChain = bp_millau::Millau;
|
||||||
|
type HeaderChain = pallet_substrate_bridge::Module<Runtime>;
|
||||||
|
type AncestryChecker = bp_header_chain::LinearAncestryChecker;
|
||||||
|
type MaxHeadersInSingleProof = MaxHeadersInSingleProof;
|
||||||
|
}
|
||||||
|
|
||||||
impl pallet_shift_session_manager::Config for Runtime {}
|
impl pallet_shift_session_manager::Config for Runtime {}
|
||||||
|
|
||||||
parameter_types! {
|
parameter_types! {
|
||||||
@@ -471,6 +475,7 @@ construct_runtime!(
|
|||||||
BridgeRialtoCurrencyExchange: pallet_bridge_currency_exchange::<Instance1>::{Module, Call},
|
BridgeRialtoCurrencyExchange: pallet_bridge_currency_exchange::<Instance1>::{Module, Call},
|
||||||
BridgeKovanCurrencyExchange: pallet_bridge_currency_exchange::<Instance2>::{Module, Call},
|
BridgeKovanCurrencyExchange: pallet_bridge_currency_exchange::<Instance2>::{Module, Call},
|
||||||
BridgeMillau: pallet_substrate_bridge::{Module, Call, Storage, Config<T>},
|
BridgeMillau: pallet_substrate_bridge::{Module, Call, Storage, Config<T>},
|
||||||
|
BridgeFinalityVerifier: pallet_finality_verifier::{Module, Call},
|
||||||
BridgeCallDispatch: pallet_bridge_call_dispatch::{Module, Event<T>},
|
BridgeCallDispatch: pallet_bridge_call_dispatch::{Module, Event<T>},
|
||||||
BridgeMillauMessageLane: pallet_message_lane::{Module, Call, Storage, Event<T>},
|
BridgeMillauMessageLane: pallet_message_lane::{Module, Call, Storage, Event<T>},
|
||||||
System: frame_system::{Module, Call, Config, Storage, Event<T>},
|
System: frame_system::{Module, Call, Config, Storage, Event<T>},
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
|
|||||||
codec = { package = "parity-scale-codec", version = "1.3.1", default-features = false }
|
codec = { package = "parity-scale-codec", version = "1.3.1", default-features = false }
|
||||||
finality-grandpa = { version = "0.12.3", default-features = false }
|
finality-grandpa = { version = "0.12.3", default-features = false }
|
||||||
serde = { version = "1.0", optional = true }
|
serde = { version = "1.0", optional = true }
|
||||||
|
num-traits = { version = "0.2", default-features = false }
|
||||||
|
|
||||||
# Bridge Dependencies
|
# Bridge Dependencies
|
||||||
|
|
||||||
@@ -39,6 +40,7 @@ std = [
|
|||||||
"finality-grandpa/std",
|
"finality-grandpa/std",
|
||||||
"frame-support/std",
|
"frame-support/std",
|
||||||
"frame-system/std",
|
"frame-system/std",
|
||||||
|
"num-traits/std",
|
||||||
"serde",
|
"serde",
|
||||||
"sp-runtime/std",
|
"sp-runtime/std",
|
||||||
"sp-std/std",
|
"sp-std/std",
|
||||||
|
|||||||
@@ -37,11 +37,16 @@ use bp_runtime::{Chain, HeaderOf};
|
|||||||
use finality_grandpa::voter_set::VoterSet;
|
use finality_grandpa::voter_set::VoterSet;
|
||||||
use frame_support::{dispatch::DispatchError, ensure, traits::Get};
|
use frame_support::{dispatch::DispatchError, ensure, traits::Get};
|
||||||
use frame_system::ensure_signed;
|
use frame_system::ensure_signed;
|
||||||
|
use num_traits::AsPrimitive;
|
||||||
use sp_runtime::traits::Header as HeaderT;
|
use sp_runtime::traits::Header as HeaderT;
|
||||||
|
use sp_std::vec::Vec;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod mock;
|
mod mock;
|
||||||
|
|
||||||
|
// Re-export in crate namespace for `construct_runtime!`
|
||||||
|
pub use pallet::*;
|
||||||
|
|
||||||
#[frame_support::pallet]
|
#[frame_support::pallet]
|
||||||
pub mod pallet {
|
pub mod pallet {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -69,7 +74,7 @@ pub mod pallet {
|
|||||||
/// The maximum length of headers we can have in a single ancestry proof. This prevents
|
/// The maximum length of headers we can have in a single ancestry proof. This prevents
|
||||||
/// unbounded iteration when verifying proofs.
|
/// unbounded iteration when verifying proofs.
|
||||||
#[pallet::constant]
|
#[pallet::constant]
|
||||||
type MaxHeadersInSingleProof: Get<u8>;
|
type MaxHeadersInSingleProof: Get<<Self::BridgedChain as Chain>::BlockNumber>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pallet::pallet]
|
#[pallet::pallet]
|
||||||
@@ -100,7 +105,7 @@ pub mod pallet {
|
|||||||
let _ = ensure_signed(origin)?;
|
let _ = ensure_signed(origin)?;
|
||||||
|
|
||||||
ensure!(
|
ensure!(
|
||||||
ancestry_proof.len() <= T::MaxHeadersInSingleProof::get() as usize,
|
ancestry_proof.len() <= T::MaxHeadersInSingleProof::get().as_(),
|
||||||
<Error<T>>::OversizedAncestryProof
|
<Error<T>>::OversizedAncestryProof
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -149,7 +154,6 @@ pub mod pallet {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::pallet::*;
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::mock::{run_test, test_header, Origin, TestRuntime};
|
use crate::mock::{run_test, test_header, Origin, TestRuntime};
|
||||||
use bp_test_utils::{authority_list, make_justification_for_header};
|
use bp_test_utils::{authority_list, make_justification_for_header};
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ use core::fmt::Debug;
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sp_finality_grandpa::{AuthorityList, SetId};
|
use sp_finality_grandpa::{AuthorityList, SetId};
|
||||||
|
use sp_runtime::traits::Header as HeaderT;
|
||||||
use sp_runtime::RuntimeDebug;
|
use sp_runtime::RuntimeDebug;
|
||||||
|
use sp_std::vec::Vec;
|
||||||
|
|
||||||
pub mod justification;
|
pub mod justification;
|
||||||
|
|
||||||
@@ -110,3 +112,101 @@ impl<H, P> AncestryChecker<H, P> for () {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A simple ancestry checker which verifies ancestry by walking every header between `child` and
|
||||||
|
/// `ancestor`.
|
||||||
|
pub struct LinearAncestryChecker;
|
||||||
|
|
||||||
|
impl<H: HeaderT> AncestryChecker<H, Vec<H>> for LinearAncestryChecker {
|
||||||
|
fn are_ancestors(ancestor: &H, child: &H, proof: &Vec<H>) -> bool {
|
||||||
|
// You can't be your own parent
|
||||||
|
if proof.len() < 2 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let's make sure that the given headers are actually in the proof
|
||||||
|
match proof.first() {
|
||||||
|
Some(first) if first == ancestor => {}
|
||||||
|
_ => return false,
|
||||||
|
}
|
||||||
|
|
||||||
|
match proof.last() {
|
||||||
|
Some(last) if last == child => {}
|
||||||
|
_ => return false,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we actually check the proof
|
||||||
|
for i in 1..proof.len() {
|
||||||
|
if &proof[i - 1].hash() != proof[i].parent_hash() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use bp_test_utils::test_header;
|
||||||
|
use sp_runtime::testing::Header;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_verify_ancestry_correctly() {
|
||||||
|
let ancestor: Header = test_header(1);
|
||||||
|
let header2: Header = test_header(2);
|
||||||
|
let header3: Header = test_header(3);
|
||||||
|
let child: Header = test_header(4);
|
||||||
|
|
||||||
|
let ancestry_proof = vec![ancestor.clone(), header2, header3, child.clone()];
|
||||||
|
|
||||||
|
assert!(LinearAncestryChecker::are_ancestors(&ancestor, &child, &ancestry_proof));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn does_not_verify_invalid_proof() {
|
||||||
|
let ancestor: Header = test_header(1);
|
||||||
|
let header2: Header = test_header(2);
|
||||||
|
let header3: Header = test_header(3);
|
||||||
|
let child: Header = test_header(4);
|
||||||
|
|
||||||
|
let ancestry_proof = vec![ancestor.clone(), header3, header2, child.clone()];
|
||||||
|
|
||||||
|
let invalid = !LinearAncestryChecker::are_ancestors(&ancestor, &child, &ancestry_proof);
|
||||||
|
assert!(invalid);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn header_is_not_allowed_to_be_its_own_ancestor() {
|
||||||
|
let ancestor: Header = test_header(1);
|
||||||
|
let child: Header = ancestor.clone();
|
||||||
|
let ancestry_proof = vec![ancestor.clone()];
|
||||||
|
|
||||||
|
let invalid = !LinearAncestryChecker::are_ancestors(&ancestor, &child, &ancestry_proof);
|
||||||
|
assert!(invalid);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn proof_is_considered_invalid_if_child_and_ancestor_do_not_match() {
|
||||||
|
let ancestor: Header = test_header(1);
|
||||||
|
let header2: Header = test_header(2);
|
||||||
|
let header3: Header = test_header(3);
|
||||||
|
let child: Header = test_header(4);
|
||||||
|
|
||||||
|
let ancestry_proof = vec![ancestor, header3.clone(), header2.clone(), child];
|
||||||
|
|
||||||
|
let invalid = !LinearAncestryChecker::are_ancestors(&header2, &header3, &ancestry_proof);
|
||||||
|
assert!(invalid);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn empty_proof_is_invalid() {
|
||||||
|
let ancestor: Header = test_header(1);
|
||||||
|
let child: Header = ancestor.clone();
|
||||||
|
let ancestry_proof = vec![];
|
||||||
|
|
||||||
|
let invalid = !LinearAncestryChecker::are_ancestors(&ancestor, &child, &ancestry_proof);
|
||||||
|
assert!(invalid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -83,6 +83,24 @@ pub const MAX_SINGLE_MESSAGE_DELIVERY_TX_WEIGHT: Weight = 1_500_000_000;
|
|||||||
/// runtime upgrades.
|
/// runtime upgrades.
|
||||||
pub const MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT: Weight = 2_000_000_000;
|
pub const MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT: Weight = 2_000_000_000;
|
||||||
|
|
||||||
|
/// The length of a session (how often authorities change) on Millau measured in of number of blocks.
|
||||||
|
pub const SESSION_LENGTH: BlockNumber = 5 * time_units::MINUTES;
|
||||||
|
|
||||||
|
/// Re-export `time_units` to make usage easier.
|
||||||
|
pub use time_units::*;
|
||||||
|
|
||||||
|
/// Human readable time units defined in terms of number of blocks.
|
||||||
|
pub mod time_units {
|
||||||
|
use super::BlockNumber;
|
||||||
|
|
||||||
|
pub const MILLISECS_PER_BLOCK: u64 = 6000;
|
||||||
|
pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
|
||||||
|
|
||||||
|
pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
|
||||||
|
pub const HOURS: BlockNumber = MINUTES * 60;
|
||||||
|
pub const DAYS: BlockNumber = HOURS * 24;
|
||||||
|
}
|
||||||
|
|
||||||
/// Block number type used in Millau.
|
/// Block number type used in Millau.
|
||||||
pub type BlockNumber = u64;
|
pub type BlockNumber = u64;
|
||||||
|
|
||||||
|
|||||||
@@ -74,6 +74,24 @@ pub const MAX_SINGLE_MESSAGE_DELIVERY_TX_WEIGHT: Weight = 1_500_000_000;
|
|||||||
/// runtime upgrades.
|
/// runtime upgrades.
|
||||||
pub const MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT: Weight = 2_000_000_000;
|
pub const MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT: Weight = 2_000_000_000;
|
||||||
|
|
||||||
|
/// The length of a session (how often authorities change) on Rialto measured in of number of blocks.
|
||||||
|
pub const SESSION_LENGTH: BlockNumber = 4;
|
||||||
|
|
||||||
|
/// Re-export `time_units` to make usage easier.
|
||||||
|
pub use time_units::*;
|
||||||
|
|
||||||
|
/// Human readable time units defined in terms of number of blocks.
|
||||||
|
pub mod time_units {
|
||||||
|
use super::BlockNumber;
|
||||||
|
|
||||||
|
pub const MILLISECS_PER_BLOCK: u64 = 6000;
|
||||||
|
pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
|
||||||
|
|
||||||
|
pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
|
||||||
|
pub const HOURS: BlockNumber = MINUTES * 60;
|
||||||
|
pub const DAYS: BlockNumber = HOURS * 24;
|
||||||
|
}
|
||||||
|
|
||||||
/// Block number type used in Rialto.
|
/// Block number type used in Rialto.
|
||||||
pub type BlockNumber = u32;
|
pub type BlockNumber = u32;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user