mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-09 20:11:09 +00:00
Refactor epoch changes to a separate crate (#4785)
* Init epoch changes module * Initial integration of new epoch changes module for BABE * Fix all initial compile errors * rename: digest -> digests * Fix babe tests * Bump impl_version * Fix more test issues * Remove test flag for tree It unfortunately won't work for multiple crates. * Update cargo lock * Fix duplicate parking_lot version * Add missing license header
This commit is contained in:
Generated
+13
@@ -5805,6 +5805,7 @@ dependencies = [
|
||||
"sc-block-builder",
|
||||
"sc-client",
|
||||
"sc-client-api",
|
||||
"sc-consensus-epochs",
|
||||
"sc-consensus-slots",
|
||||
"sc-consensus-uncles",
|
||||
"sc-executor",
|
||||
@@ -5832,6 +5833,18 @@ dependencies = [
|
||||
"tokio 0.1.22",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sc-consensus-epochs"
|
||||
version = "0.8.0"
|
||||
dependencies = [
|
||||
"fork-tree",
|
||||
"parity-scale-codec",
|
||||
"parking_lot 0.10.0",
|
||||
"sc-client-api",
|
||||
"sp-blockchain",
|
||||
"sp-runtime",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sc-consensus-manual-seal"
|
||||
version = "0.8.0"
|
||||
|
||||
@@ -25,8 +25,9 @@ members = [
|
||||
"client/consensus/babe",
|
||||
"client/consensus/manual-seal",
|
||||
"client/consensus/pow",
|
||||
"client/consensus/slots",
|
||||
"client/consensus/uncles",
|
||||
"client/consensus/slots",
|
||||
"client/consensus/epochs",
|
||||
"client/db",
|
||||
"client/executor",
|
||||
"client/executor/common",
|
||||
|
||||
@@ -80,7 +80,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
// implementation changes and behavior does not, then leave spec_version as
|
||||
// is and increment impl_version.
|
||||
spec_version: 214,
|
||||
impl_version: 0,
|
||||
impl_version: 1,
|
||||
apis: RUNTIME_API_VERSIONS,
|
||||
};
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ sc-telemetry = { version = "2.0.0", path = "../../telemetry" }
|
||||
sc-keystore = { version = "2.0.0", path = "../../keystore" }
|
||||
sc-client-api = { version = "2.0.0", path = "../../api" }
|
||||
sc-client = { version = "0.8", path = "../../" }
|
||||
sc-consensus-epochs = { version = "0.8", path = "../epochs" }
|
||||
sp-api = { version = "2.0.0", path = "../../../primitives/api" }
|
||||
sp-block-builder = { version = "2.0.0", path = "../../../primitives/block-builder" }
|
||||
sp-blockchain = { version = "2.0.0", path = "../../../primitives/blockchain" }
|
||||
|
||||
@@ -17,13 +17,17 @@
|
||||
//! BABE authority selection and slot claiming.
|
||||
|
||||
use merlin::Transcript;
|
||||
use sp_consensus_babe::{AuthorityId, BabeAuthorityWeight, BABE_ENGINE_ID, BABE_VRF_PREFIX};
|
||||
use sp_consensus_babe::{Epoch, SlotNumber, AuthorityPair, BabePreDigest, BabeConfiguration};
|
||||
use sp_consensus_babe::{
|
||||
AuthorityId, BabeAuthorityWeight, BABE_ENGINE_ID, BABE_VRF_PREFIX,
|
||||
SlotNumber, AuthorityPair, BabeConfiguration
|
||||
};
|
||||
use sp_consensus_babe::digests::PreDigest;
|
||||
use sp_core::{U256, blake2_256};
|
||||
use codec::Encode;
|
||||
use schnorrkel::vrf::VRFInOut;
|
||||
use sp_core::Pair;
|
||||
use sc_keystore::KeyStorePtr;
|
||||
use super::Epoch;
|
||||
|
||||
/// Calculates the primary selection threshold for a given authority, taking
|
||||
/// into account `c` (`1 - c` represents the probability of a slot being empty).
|
||||
@@ -104,7 +108,7 @@ fn claim_secondary_slot(
|
||||
authorities: &[(AuthorityId, BabeAuthorityWeight)],
|
||||
keystore: &KeyStorePtr,
|
||||
randomness: [u8; 32],
|
||||
) -> Option<(BabePreDigest, AuthorityPair)> {
|
||||
) -> Option<(PreDigest, AuthorityPair)> {
|
||||
if authorities.is_empty() {
|
||||
return None;
|
||||
}
|
||||
@@ -124,7 +128,7 @@ fn claim_secondary_slot(
|
||||
})
|
||||
{
|
||||
if pair.public() == *expected_author {
|
||||
let pre_digest = BabePreDigest::Secondary {
|
||||
let pre_digest = PreDigest::Secondary {
|
||||
slot_number,
|
||||
authority_index: authority_index as u32,
|
||||
};
|
||||
@@ -145,7 +149,7 @@ pub(super) fn claim_slot(
|
||||
epoch: &Epoch,
|
||||
config: &BabeConfiguration,
|
||||
keystore: &KeyStorePtr,
|
||||
) -> Option<(BabePreDigest, AuthorityPair)> {
|
||||
) -> Option<(PreDigest, AuthorityPair)> {
|
||||
claim_primary_slot(slot_number, epoch, config.c, keystore)
|
||||
.or_else(|| {
|
||||
if config.secondary_slots {
|
||||
@@ -175,7 +179,7 @@ fn claim_primary_slot(
|
||||
epoch: &Epoch,
|
||||
c: (u64, u64),
|
||||
keystore: &KeyStorePtr,
|
||||
) -> Option<(BabePreDigest, AuthorityPair)> {
|
||||
) -> Option<(PreDigest, AuthorityPair)> {
|
||||
let Epoch { authorities, randomness, epoch_index, .. } = epoch;
|
||||
let keystore = keystore.read();
|
||||
|
||||
@@ -196,7 +200,7 @@ fn claim_primary_slot(
|
||||
let pre_digest = get_keypair(&pair)
|
||||
.vrf_sign_after_check(transcript, |inout| super::authorship::check_primary_threshold(inout, threshold))
|
||||
.map(|s| {
|
||||
BabePreDigest::Primary {
|
||||
PreDigest::Primary {
|
||||
slot_number,
|
||||
vrf_output: s.0.to_output(),
|
||||
vrf_proof: s.1,
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
//! Schema for BABE epoch changes in the aux-db.
|
||||
|
||||
use std::sync::Arc;
|
||||
use parking_lot::Mutex;
|
||||
use log::info;
|
||||
use codec::{Decode, Encode};
|
||||
|
||||
@@ -23,8 +25,8 @@ use sc_client_api::backend::AuxStore;
|
||||
use sp_blockchain::{Result as ClientResult, Error as ClientError};
|
||||
use sp_runtime::traits::Block as BlockT;
|
||||
use sp_consensus_babe::BabeBlockWeight;
|
||||
|
||||
use super::{epoch_changes::EpochChangesFor, SharedEpochChanges};
|
||||
use sc_consensus_epochs::{EpochChangesFor, SharedEpochChanges};
|
||||
use crate::Epoch;
|
||||
|
||||
const BABE_EPOCH_CHANGES: &[u8] = b"babe_epoch_changes";
|
||||
|
||||
@@ -49,14 +51,14 @@ fn load_decode<B, T>(backend: &B, key: &[u8]) -> ClientResult<Option<T>>
|
||||
/// Load or initialize persistent epoch change data from backend.
|
||||
pub(crate) fn load_epoch_changes<Block: BlockT, B: AuxStore>(
|
||||
backend: &B,
|
||||
) -> ClientResult<SharedEpochChanges<Block>> {
|
||||
let epoch_changes = load_decode::<_, EpochChangesFor<Block>>(backend, BABE_EPOCH_CHANGES)?
|
||||
.map(Into::into)
|
||||
) -> ClientResult<SharedEpochChanges<Block, Epoch>> {
|
||||
let epoch_changes = load_decode::<_, EpochChangesFor<Block, Epoch>>(backend, BABE_EPOCH_CHANGES)?
|
||||
.map(|v| Arc::new(Mutex::new(v)))
|
||||
.unwrap_or_else(|| {
|
||||
info!(target: "babe",
|
||||
"Creating empty BABE epoch changes on what appears to be first startup."
|
||||
);
|
||||
SharedEpochChanges::new()
|
||||
SharedEpochChanges::<Block, Epoch>::default()
|
||||
});
|
||||
|
||||
// rebalance the tree after deserialization. this isn't strictly necessary
|
||||
@@ -70,7 +72,7 @@ pub(crate) fn load_epoch_changes<Block: BlockT, B: AuxStore>(
|
||||
|
||||
/// Update the epoch changes on disk after a change.
|
||||
pub(crate) fn write_epoch_changes<Block: BlockT, F, R>(
|
||||
epoch_changes: &EpochChangesFor<Block>,
|
||||
epoch_changes: &EpochChangesFor<Block, Epoch>,
|
||||
write_aux: F,
|
||||
) -> R where
|
||||
F: FnOnce(&[(&'static [u8], &[u8])]) -> R,
|
||||
|
||||
@@ -59,8 +59,10 @@
|
||||
#![forbid(unsafe_code)]
|
||||
#![warn(missing_docs)]
|
||||
pub use sp_consensus_babe::{
|
||||
BabeApi, ConsensusLog, BABE_ENGINE_ID, BabePreDigest, SlotNumber, BabeConfiguration,
|
||||
CompatibleDigestItem,
|
||||
BabeApi, ConsensusLog, BABE_ENGINE_ID, SlotNumber, BabeConfiguration,
|
||||
AuthorityId, AuthorityPair, AuthoritySignature,
|
||||
BabeAuthorityWeight, VRF_OUTPUT_LENGTH,
|
||||
digests::{PreDigest, CompatibleDigestItem, NextEpochDescriptor},
|
||||
};
|
||||
pub use sp_consensus::SyncOracle;
|
||||
use std::{collections::HashMap, sync::Arc, u64, pin::Pin, time::{Instant, Duration}};
|
||||
@@ -101,26 +103,58 @@ use log::{warn, debug, info, trace};
|
||||
use sc_consensus_slots::{
|
||||
SlotWorker, SlotInfo, SlotCompatible, StorageChanges, CheckedHeader, check_equivocation,
|
||||
};
|
||||
use epoch_changes::descendent_query;
|
||||
use sc_consensus_epochs::{descendent_query, SharedEpochChanges, EpochChangesFor, Epoch as EpochT};
|
||||
use sp_blockchain::{
|
||||
Result as ClientResult, Error as ClientError,
|
||||
HeaderBackend, ProvideCache, HeaderMetadata
|
||||
};
|
||||
use schnorrkel::SignatureError;
|
||||
|
||||
use codec::{Encode, Decode};
|
||||
use sp_api::ApiExt;
|
||||
|
||||
mod aux_schema;
|
||||
mod verification;
|
||||
mod epoch_changes;
|
||||
mod authorship;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
pub use sp_consensus_babe::{
|
||||
AuthorityId, AuthorityPair, AuthoritySignature, Epoch, NextEpochDescriptor,
|
||||
};
|
||||
pub use epoch_changes::{EpochChanges, EpochChangesFor, SharedEpochChanges};
|
||||
|
||||
/// BABE epoch information
|
||||
#[derive(Decode, Encode, Default, PartialEq, Eq, Clone, Debug)]
|
||||
pub struct Epoch {
|
||||
/// The epoch index
|
||||
pub epoch_index: u64,
|
||||
/// The starting slot of the epoch,
|
||||
pub start_slot: SlotNumber,
|
||||
/// The duration of this epoch
|
||||
pub duration: SlotNumber,
|
||||
/// The authorities and their weights
|
||||
pub authorities: Vec<(AuthorityId, BabeAuthorityWeight)>,
|
||||
/// Randomness for this epoch
|
||||
pub randomness: [u8; VRF_OUTPUT_LENGTH],
|
||||
}
|
||||
|
||||
impl EpochT for Epoch {
|
||||
type NextEpochDescriptor = NextEpochDescriptor;
|
||||
type SlotNumber = SlotNumber;
|
||||
|
||||
fn increment(&self, descriptor: NextEpochDescriptor) -> Epoch {
|
||||
Epoch {
|
||||
epoch_index: self.epoch_index + 1,
|
||||
start_slot: self.start_slot + self.duration,
|
||||
duration: self.duration,
|
||||
authorities: descriptor.authorities,
|
||||
randomness: descriptor.randomness,
|
||||
}
|
||||
}
|
||||
|
||||
fn start_slot(&self) -> SlotNumber {
|
||||
self.start_slot
|
||||
}
|
||||
|
||||
fn end_slot(&self) -> SlotNumber {
|
||||
self.start_slot + self.duration
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(derive_more::Display, Debug)]
|
||||
enum Error<B: BlockT> {
|
||||
@@ -343,7 +377,7 @@ struct BabeWorker<B: BlockT, C, E, I, SO> {
|
||||
sync_oracle: SO,
|
||||
force_authoring: bool,
|
||||
keystore: KeyStorePtr,
|
||||
epoch_changes: SharedEpochChanges<B>,
|
||||
epoch_changes: SharedEpochChanges<B, Epoch>,
|
||||
config: Config,
|
||||
}
|
||||
|
||||
@@ -361,7 +395,7 @@ impl<B, C, E, I, Error, SO> sc_consensus_slots::SimpleSlotWorker<B> for BabeWork
|
||||
Error: std::error::Error + Send + From<ConsensusError> + From<I::Error> + 'static,
|
||||
{
|
||||
type EpochData = Epoch;
|
||||
type Claim = (BabePreDigest, AuthorityPair);
|
||||
type Claim = (PreDigest, AuthorityPair);
|
||||
type SyncOracle = SO;
|
||||
type CreateProposer = Pin<Box<
|
||||
dyn Future<Output = Result<E::Proposer, sp_consensus::Error>> + Send + 'static
|
||||
@@ -533,12 +567,12 @@ impl<B, C, E, I, Error, SO> SlotWorker<B> for BabeWorker<B, C, E, I, SO> where
|
||||
|
||||
/// Extract the BABE pre digest from the given header. Pre-runtime digests are
|
||||
/// mandatory, the function will return `Err` if none is found.
|
||||
fn find_pre_digest<B: BlockT>(header: &B::Header) -> Result<BabePreDigest, Error<B>>
|
||||
fn find_pre_digest<B: BlockT>(header: &B::Header) -> Result<PreDigest, Error<B>>
|
||||
{
|
||||
// genesis block doesn't contain a pre digest so let's generate a
|
||||
// dummy one to not break any invariants in the rest of the code
|
||||
if header.number().is_zero() {
|
||||
return Ok(BabePreDigest::Secondary {
|
||||
return Ok(PreDigest::Secondary {
|
||||
slot_number: 0,
|
||||
authority_index: 0,
|
||||
});
|
||||
@@ -597,7 +631,7 @@ impl SlotCompatible for TimeSource {
|
||||
#[derive(Clone)]
|
||||
pub struct BabeLink<Block: BlockT> {
|
||||
time_source: TimeSource,
|
||||
epoch_changes: SharedEpochChanges<Block>,
|
||||
epoch_changes: SharedEpochChanges<Block, Epoch>,
|
||||
config: Config,
|
||||
}
|
||||
/// A verifier for Babe blocks.
|
||||
@@ -606,7 +640,7 @@ pub struct BabeVerifier<B, E, Block: BlockT, RA, PRA> {
|
||||
api: Arc<PRA>,
|
||||
inherent_data_providers: sp_inherents::InherentDataProviders,
|
||||
config: Config,
|
||||
epoch_changes: SharedEpochChanges<Block>,
|
||||
epoch_changes: SharedEpochChanges<Block, Epoch>,
|
||||
time_source: TimeSource,
|
||||
}
|
||||
|
||||
@@ -711,7 +745,7 @@ impl<B, E, Block, RA, PRA> Verifier<Block> for BabeVerifier<B, E, Block, RA, PRA
|
||||
let mut inherent_data = self
|
||||
.inherent_data_providers
|
||||
.create_inherent_data()
|
||||
.map_err( Error::<Block>::Runtime)?;
|
||||
.map_err(Error::<Block>::Runtime)?;
|
||||
|
||||
let (_, slot_now, _) = self.time_source.extract_timestamp_and_slot(&inherent_data)
|
||||
.map_err(Error::<Block>::Extraction)?;
|
||||
@@ -855,7 +889,7 @@ pub struct BabeBlockImport<B, E, Block: BlockT, I, RA, PRA> {
|
||||
inner: I,
|
||||
client: Arc<Client<B, E, Block, RA>>,
|
||||
api: Arc<PRA>,
|
||||
epoch_changes: SharedEpochChanges<Block>,
|
||||
epoch_changes: SharedEpochChanges<Block, Epoch>,
|
||||
config: Config,
|
||||
}
|
||||
|
||||
@@ -875,7 +909,7 @@ impl<B, E, Block: BlockT, I, RA, PRA> BabeBlockImport<B, E, Block, I, RA, PRA> {
|
||||
fn new(
|
||||
client: Arc<Client<B, E, Block, RA>>,
|
||||
api: Arc<PRA>,
|
||||
epoch_changes: SharedEpochChanges<Block>,
|
||||
epoch_changes: SharedEpochChanges<Block, Epoch>,
|
||||
block_import: I,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
@@ -1114,7 +1148,7 @@ impl<B, E, Block, I, RA, PRA> BlockImport<Block> for BabeBlockImport<B, E, Block
|
||||
/// Gets the best finalized block and its slot, and prunes the given epoch tree.
|
||||
fn prune_finalized<B, E, Block, RA>(
|
||||
client: &Client<B, E, Block, RA>,
|
||||
epoch_changes: &mut EpochChangesFor<Block>,
|
||||
epoch_changes: &mut EpochChangesFor<Block, Epoch>,
|
||||
) -> Result<(), ConsensusError> where
|
||||
Block: BlockT,
|
||||
E: CallExecutor<Block> + Send + Sync,
|
||||
@@ -1161,7 +1195,7 @@ pub fn block_import<B, E, Block: BlockT, I, RA, PRA>(
|
||||
RA: Send + Sync,
|
||||
Client<B, E, Block, RA>: AuxStore,
|
||||
{
|
||||
let epoch_changes = aux_schema::load_epoch_changes(&*client)?;
|
||||
let epoch_changes = aux_schema::load_epoch_changes::<Block, _>(&*client)?;
|
||||
let link = BabeLink {
|
||||
epoch_changes: epoch_changes.clone(),
|
||||
time_source: Default::default(),
|
||||
@@ -1245,7 +1279,7 @@ pub mod test_helpers {
|
||||
client: &C,
|
||||
keystore: &KeyStorePtr,
|
||||
link: &BabeLink<B>,
|
||||
) -> Option<BabePreDigest> where
|
||||
) -> Option<PreDigest> where
|
||||
B: BlockT,
|
||||
C: ProvideRuntimeApi<B> +
|
||||
ProvideCache<B> +
|
||||
|
||||
@@ -59,7 +59,7 @@ type Mutator = Arc<dyn Fn(&mut TestHeader, Stage) + Send + Sync>;
|
||||
#[derive(Clone)]
|
||||
struct DummyFactory {
|
||||
client: Arc<TestClient>,
|
||||
epoch_changes: crate::SharedEpochChanges<TestBlock>,
|
||||
epoch_changes: SharedEpochChanges<TestBlock, Epoch>,
|
||||
config: Config,
|
||||
mutator: Mutator,
|
||||
}
|
||||
@@ -105,7 +105,6 @@ impl DummyProposer {
|
||||
>
|
||||
>
|
||||
{
|
||||
use codec::Encode;
|
||||
let block_builder = self.factory.client.new_block_at(
|
||||
&BlockId::Hash(self.parent_hash),
|
||||
pre_digests,
|
||||
@@ -558,7 +557,7 @@ fn propose_and_import_block<Transaction>(
|
||||
let pre_digest = sp_runtime::generic::Digest {
|
||||
logs: vec![
|
||||
Item::babe_pre_digest(
|
||||
BabePreDigest::Secondary {
|
||||
PreDigest::Secondary {
|
||||
authority_index: 0,
|
||||
slot_number,
|
||||
},
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
use schnorrkel::vrf::{VRFOutput, VRFProof};
|
||||
use sp_runtime::{traits::Header, traits::DigestItemFor};
|
||||
use sp_core::{Pair, Public};
|
||||
use sp_consensus_babe::{Epoch, BabePreDigest, CompatibleDigestItem, AuthorityId};
|
||||
use sp_consensus_babe::{AuthoritySignature, SlotNumber, AuthorityIndex, AuthorityPair};
|
||||
use sp_consensus_babe::{AuthoritySignature, SlotNumber, AuthorityIndex, AuthorityPair, AuthorityId};
|
||||
use sp_consensus_babe::digests::{PreDigest, CompatibleDigestItem};
|
||||
use sc_consensus_slots::CheckedHeader;
|
||||
use log::{debug, trace};
|
||||
use super::{find_pre_digest, babe_err, BlockT, Error};
|
||||
use super::{find_pre_digest, babe_err, Epoch, BlockT, Error};
|
||||
use super::authorship::{make_transcript, calculate_primary_threshold, check_primary_threshold, secondary_slot_author};
|
||||
|
||||
/// BABE verification parameters
|
||||
@@ -32,7 +32,7 @@ pub(super) struct VerificationParams<'a, B: 'a + BlockT> {
|
||||
/// the pre-digest of the header being verified. this is optional - if prior
|
||||
/// verification code had to read it, it can be included here to avoid duplicate
|
||||
/// work.
|
||||
pub(super) pre_digest: Option<BabePreDigest>,
|
||||
pub(super) pre_digest: Option<PreDigest>,
|
||||
/// the slot number of the current time.
|
||||
pub(super) slot_now: SlotNumber,
|
||||
/// epoch descriptor of the epoch this block _should_ be under, if it's valid.
|
||||
@@ -93,7 +93,7 @@ pub(super) fn check_header<B: BlockT + Sized>(
|
||||
};
|
||||
|
||||
match &pre_digest {
|
||||
BabePreDigest::Primary { vrf_output, vrf_proof, authority_index, slot_number } => {
|
||||
PreDigest::Primary { vrf_output, vrf_proof, authority_index, slot_number } => {
|
||||
debug!(target: "babe", "Verifying Primary block");
|
||||
|
||||
let digest = (vrf_output, vrf_proof, *authority_index, *slot_number);
|
||||
@@ -106,7 +106,7 @@ pub(super) fn check_header<B: BlockT + Sized>(
|
||||
config.c,
|
||||
)?;
|
||||
},
|
||||
BabePreDigest::Secondary { authority_index, slot_number } if config.secondary_slots => {
|
||||
PreDigest::Secondary { authority_index, slot_number } if config.secondary_slots => {
|
||||
debug!(target: "babe", "Verifying Secondary block");
|
||||
|
||||
let digest = (*authority_index, *slot_number);
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "sc-consensus-epochs"
|
||||
version = "0.8.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
description = "Generic epochs-based utilities for consensus"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
codec = { package = "parity-scale-codec", version = "1.0.0", features = ["derive"] }
|
||||
parking_lot = "0.10.0"
|
||||
fork-tree = { version = "2.0.0", path = "../../../utils/fork-tree" }
|
||||
sp-runtime = { path = "../../../primitives/runtime" }
|
||||
sp-blockchain = { version = "2.0.0", path = "../../../primitives/blockchain" }
|
||||
sc-client-api = { path = "../../api" }
|
||||
+109
-94
@@ -14,20 +14,15 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Handling epoch changes in BABE.
|
||||
//!
|
||||
//! This exposes the `SharedEpochChanges`, which is a wrapper around a
|
||||
//! persistent DAG superimposed over the forks of the blockchain.
|
||||
//! Generic utilities for epoch-based consensus engines.
|
||||
|
||||
use std::sync::Arc;
|
||||
use sp_consensus_babe::{Epoch, SlotNumber, NextEpochDescriptor};
|
||||
use fork_tree::ForkTree;
|
||||
use parking_lot::{Mutex, MutexGuard};
|
||||
use sp_runtime::traits::{Block as BlockT, NumberFor, One, Zero};
|
||||
use std::{sync::Arc, ops::Add};
|
||||
use parking_lot::Mutex;
|
||||
use codec::{Encode, Decode};
|
||||
use fork_tree::ForkTree;
|
||||
use sc_client_api::utils::is_descendent_of;
|
||||
use sp_blockchain::{HeaderMetadata, HeaderBackend, Error as ClientError};
|
||||
use std::ops::Add;
|
||||
use sp_runtime::traits::{Block as BlockT, NumberFor, One, Zero};
|
||||
|
||||
/// A builder for `is_descendent_of` functions.
|
||||
pub trait IsDescendentOfBuilder<Hash> {
|
||||
@@ -48,13 +43,13 @@ pub trait IsDescendentOfBuilder<Hash> {
|
||||
}
|
||||
|
||||
/// Produce a descendent query object given the client.
|
||||
pub(crate) fn descendent_query<H, Block>(client: &H) -> HeaderBackendDescendentBuilder<&H, Block> {
|
||||
pub fn descendent_query<H, Block>(client: &H) -> HeaderBackendDescendentBuilder<&H, Block> {
|
||||
HeaderBackendDescendentBuilder(client, std::marker::PhantomData)
|
||||
}
|
||||
|
||||
/// Wrapper to get around unconstrained type errors when implementing
|
||||
/// `IsDescendentOfBuilder` for header backends.
|
||||
pub(crate) struct HeaderBackendDescendentBuilder<H, Block>(H, std::marker::PhantomData<Block>);
|
||||
pub struct HeaderBackendDescendentBuilder<H, Block>(H, std::marker::PhantomData<Block>);
|
||||
|
||||
impl<'a, H, Block> IsDescendentOfBuilder<Block::Hash>
|
||||
for HeaderBackendDescendentBuilder<&'a H, Block> where
|
||||
@@ -71,49 +66,73 @@ impl<'a, H, Block> IsDescendentOfBuilder<Block::Hash>
|
||||
}
|
||||
}
|
||||
|
||||
/// Epoch data, distinguish whether it is genesis or not.
|
||||
pub trait Epoch {
|
||||
/// Descriptor for the next epoch.
|
||||
type NextEpochDescriptor;
|
||||
/// Type of the slot number.
|
||||
type SlotNumber: Ord;
|
||||
|
||||
/// Increment the epoch data, using the next epoch descriptor.
|
||||
fn increment(&self, descriptor: Self::NextEpochDescriptor) -> Self;
|
||||
|
||||
/// Produce the "end slot" of the epoch. This is NOT inclusive to the epoch,
|
||||
/// i.e. the slots covered by the epoch are `self.start_slot() .. self.end_slot()`.
|
||||
fn end_slot(&self) -> Self::SlotNumber;
|
||||
/// Produce the "start slot" of the epoch.
|
||||
fn start_slot(&self) -> Self::SlotNumber;
|
||||
}
|
||||
|
||||
/// An unimported genesis epoch.
|
||||
pub struct UnimportedGenesis(Epoch);
|
||||
pub struct UnimportedGenesisEpoch<Epoch>(Epoch);
|
||||
|
||||
/// The viable epoch under which a block can be verified.
|
||||
///
|
||||
/// If this is the first non-genesis block in the chain, then it will
|
||||
/// hold an `UnimportedGenesis` epoch.
|
||||
pub enum ViableEpoch {
|
||||
Genesis(UnimportedGenesis),
|
||||
pub enum ViableEpoch<Epoch> {
|
||||
/// Genesis viable epoch data.
|
||||
Genesis(UnimportedGenesisEpoch<Epoch>),
|
||||
/// Regular viable epoch data.
|
||||
Regular(Epoch),
|
||||
}
|
||||
|
||||
impl From<Epoch> for ViableEpoch {
|
||||
fn from(epoch: Epoch) -> ViableEpoch {
|
||||
impl<Epoch> From<Epoch> for ViableEpoch<Epoch> {
|
||||
fn from(epoch: Epoch) -> ViableEpoch<Epoch> {
|
||||
ViableEpoch::Regular(epoch)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Epoch> for ViableEpoch {
|
||||
impl<Epoch> AsRef<Epoch> for ViableEpoch<Epoch> {
|
||||
fn as_ref(&self) -> &Epoch {
|
||||
match *self {
|
||||
ViableEpoch::Genesis(UnimportedGenesis(ref e)) => e,
|
||||
ViableEpoch::Genesis(UnimportedGenesisEpoch(ref e)) => e,
|
||||
ViableEpoch::Regular(ref e) => e,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ViableEpoch {
|
||||
impl<Epoch> ViableEpoch<Epoch> where
|
||||
Epoch: crate::Epoch + Clone,
|
||||
{
|
||||
/// Extract the underlying epoch, disregarding the fact that a genesis
|
||||
/// epoch may be unimported.
|
||||
pub fn into_inner(self) -> Epoch {
|
||||
match self {
|
||||
ViableEpoch::Genesis(UnimportedGenesis(e)) => e,
|
||||
ViableEpoch::Genesis(UnimportedGenesisEpoch(e)) => e,
|
||||
ViableEpoch::Regular(e) => e,
|
||||
}
|
||||
}
|
||||
|
||||
/// Increment the epoch, yielding an `IncrementedEpoch` to be imported
|
||||
/// into the fork-tree.
|
||||
pub fn increment(&self, next_descriptor: NextEpochDescriptor) -> IncrementedEpoch {
|
||||
pub fn increment(
|
||||
&self,
|
||||
next_descriptor: Epoch::NextEpochDescriptor
|
||||
) -> IncrementedEpoch<Epoch> {
|
||||
let next = self.as_ref().increment(next_descriptor);
|
||||
let to_persist = match *self {
|
||||
ViableEpoch::Genesis(UnimportedGenesis(ref epoch_0)) =>
|
||||
ViableEpoch::Genesis(UnimportedGenesisEpoch(ref epoch_0)) =>
|
||||
PersistedEpoch::Genesis(epoch_0.clone(), next),
|
||||
ViableEpoch::Regular(_) => PersistedEpoch::Regular(next),
|
||||
};
|
||||
@@ -123,12 +142,11 @@ impl ViableEpoch {
|
||||
}
|
||||
|
||||
/// The datatype encoded on disk.
|
||||
// This really shouldn't be public, but the encode/decode derives force it to be.
|
||||
#[derive(Clone, Encode, Decode)]
|
||||
pub enum PersistedEpoch {
|
||||
// epoch_0, epoch_1,
|
||||
pub enum PersistedEpoch<Epoch> {
|
||||
/// Genesis persisted epoch data. epoch_0, epoch_1.
|
||||
Genesis(Epoch, Epoch),
|
||||
// epoch_n
|
||||
/// Regular persisted epoch data. epoch_n.
|
||||
Regular(Epoch),
|
||||
}
|
||||
|
||||
@@ -136,9 +154,9 @@ pub enum PersistedEpoch {
|
||||
///
|
||||
/// Create this with `ViableEpoch::increment`.
|
||||
#[must_use = "Freshly-incremented epoch must be imported with `EpochChanges::import`"]
|
||||
pub struct IncrementedEpoch(PersistedEpoch);
|
||||
pub struct IncrementedEpoch<Epoch>(PersistedEpoch<Epoch>);
|
||||
|
||||
impl AsRef<Epoch> for IncrementedEpoch {
|
||||
impl<Epoch> AsRef<Epoch> for IncrementedEpoch<Epoch> {
|
||||
fn as_ref(&self) -> &Epoch {
|
||||
match self.0 {
|
||||
PersistedEpoch::Genesis(_, ref epoch_1) => epoch_1,
|
||||
@@ -151,7 +169,7 @@ impl AsRef<Epoch> for IncrementedEpoch {
|
||||
/// the hash and block number of the block signaling the epoch change, and the
|
||||
/// epoch that was signalled at that block.
|
||||
///
|
||||
/// BABE special-cases the first epoch, epoch_0, by saying that it starts at
|
||||
/// The first epoch, epoch_0, is special cased by saying that it starts at
|
||||
/// slot number of the first block in the chain. When bootstrapping a chain,
|
||||
/// there can be multiple competing block #1s, so we have to ensure that the overlayed
|
||||
/// DAG doesn't get confused.
|
||||
@@ -163,8 +181,8 @@ impl AsRef<Epoch> for IncrementedEpoch {
|
||||
///
|
||||
/// Further epochs (epoch_2, ..., epoch_n) each get their own entry.
|
||||
#[derive(Clone, Encode, Decode)]
|
||||
pub struct EpochChanges<Hash, Number> {
|
||||
inner: ForkTree<Hash, Number, PersistedEpoch>,
|
||||
pub struct EpochChanges<Hash, Number, Epoch> {
|
||||
inner: ForkTree<Hash, Number, PersistedEpoch<Epoch>>,
|
||||
}
|
||||
|
||||
// create a fake header hash which hasn't been included in the chain.
|
||||
@@ -176,13 +194,23 @@ fn fake_head_hash<H: AsRef<[u8]> + AsMut<[u8]> + Clone>(parent_hash: &H) -> H {
|
||||
h
|
||||
}
|
||||
|
||||
impl<Hash, Number> EpochChanges<Hash, Number> where
|
||||
impl<Hash, Number, Epoch> Default for EpochChanges<Hash, Number, Epoch> where
|
||||
Hash: PartialEq,
|
||||
Number: Ord,
|
||||
{
|
||||
fn default() -> Self {
|
||||
EpochChanges { inner: ForkTree::new() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Hash, Number, Epoch> EpochChanges<Hash, Number, Epoch> where
|
||||
Hash: PartialEq + AsRef<[u8]> + AsMut<[u8]> + Copy,
|
||||
Number: Ord + One + Zero + Add<Output=Number> + Copy,
|
||||
Epoch: crate::Epoch + Clone,
|
||||
{
|
||||
/// Create a new epoch-change tracker.
|
||||
fn new() -> Self {
|
||||
EpochChanges { inner: ForkTree::new() }
|
||||
/// Create a new epoch change.
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Rebalances the tree of epoch changes so that it is sorted by length of
|
||||
@@ -199,12 +227,12 @@ impl<Hash, Number> EpochChanges<Hash, Number> where
|
||||
descendent_of_builder: D,
|
||||
hash: &Hash,
|
||||
number: Number,
|
||||
slot: SlotNumber,
|
||||
slot: Epoch::SlotNumber,
|
||||
) -> Result<(), fork_tree::Error<D::Error>> {
|
||||
let is_descendent_of = descendent_of_builder
|
||||
.build_is_descendent_of(None);
|
||||
|
||||
let predicate = |epoch: &PersistedEpoch| match *epoch {
|
||||
let predicate = |epoch: &PersistedEpoch<Epoch>| match *epoch {
|
||||
PersistedEpoch::Genesis(_, ref epoch_1) =>
|
||||
slot >= epoch_1.end_slot(),
|
||||
PersistedEpoch::Regular(ref epoch_n) =>
|
||||
@@ -233,10 +261,10 @@ impl<Hash, Number> EpochChanges<Hash, Number> where
|
||||
descendent_of_builder: D,
|
||||
parent_hash: &Hash,
|
||||
parent_number: Number,
|
||||
slot_number: SlotNumber,
|
||||
slot_number: Epoch::SlotNumber,
|
||||
make_genesis: G,
|
||||
) -> Result<Option<ViableEpoch>, fork_tree::Error<D::Error>>
|
||||
where G: FnOnce(SlotNumber) -> Epoch
|
||||
) -> Result<Option<ViableEpoch<Epoch>>, fork_tree::Error<D::Error>>
|
||||
where G: FnOnce(Epoch::SlotNumber) -> Epoch
|
||||
{
|
||||
// find_node_where will give you the node in the fork-tree which is an ancestor
|
||||
// of the `parent_hash` by default. if the last epoch was signalled at the parent_hash,
|
||||
@@ -250,7 +278,7 @@ impl<Hash, Number> EpochChanges<Hash, Number> where
|
||||
if parent_number == Zero::zero() {
|
||||
// need to insert the genesis epoch.
|
||||
let genesis_epoch = make_genesis(slot_number);
|
||||
return Ok(Some(ViableEpoch::Genesis(UnimportedGenesis(genesis_epoch))));
|
||||
return Ok(Some(ViableEpoch::Genesis(UnimportedGenesisEpoch(genesis_epoch))));
|
||||
}
|
||||
|
||||
// We want to find the deepest node in the tree which is an ancestor
|
||||
@@ -258,11 +286,11 @@ impl<Hash, Number> EpochChanges<Hash, Number> where
|
||||
// slot of our block. The genesis special-case doesn't need to look
|
||||
// at epoch_1 -- all we're doing here is figuring out which node
|
||||
// we need.
|
||||
let predicate = |epoch: &PersistedEpoch| match *epoch {
|
||||
let predicate = |epoch: &PersistedEpoch<Epoch>| match *epoch {
|
||||
PersistedEpoch::Genesis(ref epoch_0, _) =>
|
||||
epoch_0.start_slot <= slot_number,
|
||||
epoch_0.start_slot() <= slot_number,
|
||||
PersistedEpoch::Regular(ref epoch_n) =>
|
||||
epoch_n.start_slot <= slot_number,
|
||||
epoch_n.start_slot() <= slot_number,
|
||||
};
|
||||
|
||||
self.inner.find_node_where(
|
||||
@@ -276,7 +304,7 @@ impl<Hash, Number> EpochChanges<Hash, Number> where
|
||||
// and here we figure out which of the internal epochs
|
||||
// of a genesis node to use based on their start slot.
|
||||
PersistedEpoch::Genesis(ref epoch_0, ref epoch_1) =>
|
||||
if epoch_1.start_slot <= slot_number {
|
||||
if epoch_1.start_slot() <= slot_number {
|
||||
epoch_1.clone()
|
||||
} else {
|
||||
epoch_0.clone()
|
||||
@@ -296,7 +324,7 @@ impl<Hash, Number> EpochChanges<Hash, Number> where
|
||||
hash: Hash,
|
||||
number: Number,
|
||||
parent_hash: Hash,
|
||||
epoch: IncrementedEpoch,
|
||||
epoch: IncrementedEpoch<Epoch>,
|
||||
) -> Result<(), fork_tree::Error<D::Error>> {
|
||||
let is_descendent_of = descendent_of_builder
|
||||
.build_is_descendent_of(Some((hash, parent_hash)));
|
||||
@@ -314,47 +342,22 @@ impl<Hash, Number> EpochChanges<Hash, Number> where
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the inner fork tree, useful for testing purposes.
|
||||
#[cfg(test)]
|
||||
pub fn tree(&self) -> &ForkTree<Hash, Number, PersistedEpoch> {
|
||||
/// Return the inner fork tree.
|
||||
pub fn tree(&self) -> &ForkTree<Hash, Number, PersistedEpoch<Epoch>> {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
/// Type alias to produce the epoch-changes tree from a block type.
|
||||
pub type EpochChangesFor<Block> = EpochChanges<<Block as BlockT>::Hash, NumberFor<Block>>;
|
||||
pub type EpochChangesFor<Block, Epoch> = EpochChanges<<Block as BlockT>::Hash, NumberFor<Block>, Epoch>;
|
||||
|
||||
/// A shared epoch changes tree.
|
||||
#[derive(Clone)]
|
||||
pub struct SharedEpochChanges<Block: BlockT> {
|
||||
inner: Arc<Mutex<EpochChangesFor<Block>>>,
|
||||
}
|
||||
|
||||
impl<Block: BlockT> SharedEpochChanges<Block> {
|
||||
/// Create a new instance of the `SharedEpochChanges`.
|
||||
pub fn new() -> Self {
|
||||
SharedEpochChanges {
|
||||
inner: Arc::new(Mutex::new(EpochChanges::<_, _>::new()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Lock the shared epoch changes,
|
||||
pub fn lock(&self) -> MutexGuard<EpochChangesFor<Block>> {
|
||||
self.inner.lock()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block: BlockT> From<EpochChangesFor<Block>> for SharedEpochChanges<Block> {
|
||||
fn from(epoch_changes: EpochChangesFor<Block>) -> Self {
|
||||
SharedEpochChanges {
|
||||
inner: Arc::new(Mutex::new(epoch_changes))
|
||||
}
|
||||
}
|
||||
}
|
||||
pub type SharedEpochChanges<Block, Epoch> = Arc<Mutex<EpochChangesFor<Block, Epoch>>>;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use super::Epoch as EpochT;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct TestError;
|
||||
@@ -396,6 +399,33 @@ mod tests {
|
||||
}
|
||||
|
||||
type Hash = [u8; 1];
|
||||
type SlotNumber = u64;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
struct Epoch {
|
||||
start_slot: SlotNumber,
|
||||
duration: SlotNumber,
|
||||
}
|
||||
|
||||
impl EpochT for Epoch {
|
||||
type NextEpochDescriptor = ();
|
||||
type SlotNumber = SlotNumber;
|
||||
|
||||
fn increment(&self, _: ()) -> Self {
|
||||
Epoch {
|
||||
start_slot: self.start_slot + self.duration,
|
||||
duration: self.duration,
|
||||
}
|
||||
}
|
||||
|
||||
fn end_slot(&self) -> SlotNumber {
|
||||
self.start_slot + self.duration
|
||||
}
|
||||
|
||||
fn start_slot(&self) -> SlotNumber {
|
||||
self.start_slot
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn genesis_epoch_is_created_but_not_imported() {
|
||||
@@ -414,11 +444,8 @@ mod tests {
|
||||
};
|
||||
|
||||
let make_genesis = |slot| Epoch {
|
||||
epoch_index: 0,
|
||||
start_slot: slot,
|
||||
duration: 100,
|
||||
authorities: Vec::new(),
|
||||
randomness: [0; 32],
|
||||
};
|
||||
|
||||
let epoch_changes = EpochChanges::new();
|
||||
@@ -468,11 +495,8 @@ mod tests {
|
||||
};
|
||||
|
||||
let make_genesis = |slot| Epoch {
|
||||
epoch_index: 0,
|
||||
start_slot: slot,
|
||||
duration: 100,
|
||||
authorities: Vec::new(),
|
||||
randomness: [0; 32],
|
||||
};
|
||||
|
||||
let mut epoch_changes = EpochChanges::new();
|
||||
@@ -486,10 +510,7 @@ mod tests {
|
||||
|
||||
assert_eq!(genesis_epoch.as_ref(), &make_genesis(100));
|
||||
|
||||
let import_epoch_1 = genesis_epoch.increment(NextEpochDescriptor {
|
||||
authorities: Vec::new(),
|
||||
randomness: [1; 32],
|
||||
});
|
||||
let import_epoch_1 = genesis_epoch.increment(());
|
||||
let epoch_1 = import_epoch_1.as_ref().clone();
|
||||
|
||||
epoch_changes.import(
|
||||
@@ -566,18 +587,12 @@ mod tests {
|
||||
let duration = 100;
|
||||
|
||||
let make_genesis = |slot| Epoch {
|
||||
epoch_index: 0,
|
||||
start_slot: slot,
|
||||
duration,
|
||||
authorities: Vec::new(),
|
||||
randomness: [0; 32],
|
||||
};
|
||||
|
||||
let mut epoch_changes = EpochChanges::new();
|
||||
let next_descriptor = NextEpochDescriptor {
|
||||
authorities: Vec::new(),
|
||||
randomness: [0; 32],
|
||||
};
|
||||
let next_descriptor = ();
|
||||
|
||||
// insert genesis epoch for A
|
||||
{
|
||||
@@ -35,8 +35,9 @@ use sp_staking::{
|
||||
use codec::{Encode, Decode};
|
||||
use sp_inherents::{InherentIdentifier, InherentData, ProvideInherent, MakeFatalError};
|
||||
use sp_consensus_babe::{
|
||||
BABE_ENGINE_ID, ConsensusLog, BabeAuthorityWeight, NextEpochDescriptor, RawBabePreDigest,
|
||||
SlotNumber, inherents::{INHERENT_IDENTIFIER, BabeInherentData}
|
||||
BABE_ENGINE_ID, ConsensusLog, BabeAuthorityWeight, SlotNumber,
|
||||
inherents::{INHERENT_IDENTIFIER, BabeInherentData},
|
||||
digests::{NextEpochDescriptor, RawPreDigest},
|
||||
};
|
||||
pub use sp_consensus_babe::{AuthorityId, VRF_OUTPUT_LENGTH, PUBLIC_KEY_LENGTH};
|
||||
|
||||
@@ -205,11 +206,11 @@ impl<T: Trait> FindAuthor<u32> for Module<T> {
|
||||
{
|
||||
for (id, mut data) in digests.into_iter() {
|
||||
if id == BABE_ENGINE_ID {
|
||||
let pre_digest = RawBabePreDigest::decode(&mut data).ok()?;
|
||||
let pre_digest = RawPreDigest::decode(&mut data).ok()?;
|
||||
return Some(match pre_digest {
|
||||
RawBabePreDigest::Primary { authority_index, .. } =>
|
||||
RawPreDigest::Primary { authority_index, .. } =>
|
||||
authority_index,
|
||||
RawBabePreDigest::Secondary { authority_index, .. } =>
|
||||
RawPreDigest::Secondary { authority_index, .. } =>
|
||||
authority_index,
|
||||
});
|
||||
}
|
||||
@@ -397,7 +398,7 @@ impl<T: Trait> Module<T> {
|
||||
.iter()
|
||||
.filter_map(|s| s.as_pre_runtime())
|
||||
.filter_map(|(id, mut data)| if id == BABE_ENGINE_ID {
|
||||
RawBabePreDigest::decode(&mut data).ok()
|
||||
RawPreDigest::decode(&mut data).ok()
|
||||
} else {
|
||||
None
|
||||
})
|
||||
@@ -424,7 +425,7 @@ impl<T: Trait> Module<T> {
|
||||
|
||||
CurrentSlot::put(digest.slot_number());
|
||||
|
||||
if let RawBabePreDigest::Primary { vrf_output, .. } = digest {
|
||||
if let RawPreDigest::Primary { vrf_output, .. } = digest {
|
||||
// place the VRF output into the `Initialized` storage item
|
||||
// and it'll be put onto the under-construction randomness
|
||||
// later, once we've decided which epoch this block is in.
|
||||
|
||||
@@ -34,7 +34,7 @@ fn make_pre_digest(
|
||||
vrf_output: [u8; sp_consensus_babe::VRF_OUTPUT_LENGTH],
|
||||
vrf_proof: [u8; sp_consensus_babe::VRF_PROOF_LENGTH],
|
||||
) -> Digest {
|
||||
let digest_data = sp_consensus_babe::RawBabePreDigest::Primary {
|
||||
let digest_data = sp_consensus_babe::digests::RawPreDigest::Primary {
|
||||
authority_index,
|
||||
slot_number,
|
||||
vrf_output,
|
||||
@@ -110,7 +110,7 @@ fn first_block_epoch_zero_start() {
|
||||
|
||||
let authorities = Babe::authorities();
|
||||
let consensus_log = sp_consensus_babe::ConsensusLog::NextEpochData(
|
||||
sp_consensus_babe::NextEpochDescriptor {
|
||||
sp_consensus_babe::digests::NextEpochDescriptor {
|
||||
authorities,
|
||||
randomness: Babe::randomness(),
|
||||
}
|
||||
|
||||
+27
-30
@@ -41,7 +41,7 @@ use sp_std::vec::Vec;
|
||||
/// (VRF based) and to a secondary (slot number based).
|
||||
#[cfg(feature = "std")]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum BabePreDigest {
|
||||
pub enum PreDigest {
|
||||
/// A primary VRF-based slot assignment.
|
||||
Primary {
|
||||
/// VRF output
|
||||
@@ -63,20 +63,20 @@ pub enum BabePreDigest {
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl BabePreDigest {
|
||||
impl PreDigest {
|
||||
/// Returns the slot number of the pre digest.
|
||||
pub fn authority_index(&self) -> AuthorityIndex {
|
||||
match self {
|
||||
BabePreDigest::Primary { authority_index, .. } => *authority_index,
|
||||
BabePreDigest::Secondary { authority_index, .. } => *authority_index,
|
||||
PreDigest::Primary { authority_index, .. } => *authority_index,
|
||||
PreDigest::Secondary { authority_index, .. } => *authority_index,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the slot number of the pre digest.
|
||||
pub fn slot_number(&self) -> SlotNumber {
|
||||
match self {
|
||||
BabePreDigest::Primary { slot_number, .. } => *slot_number,
|
||||
BabePreDigest::Secondary { slot_number, .. } => *slot_number,
|
||||
PreDigest::Primary { slot_number, .. } => *slot_number,
|
||||
PreDigest::Secondary { slot_number, .. } => *slot_number,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,18 +84,15 @@ impl BabePreDigest {
|
||||
/// of the chain.
|
||||
pub fn added_weight(&self) -> crate::BabeBlockWeight {
|
||||
match self {
|
||||
BabePreDigest::Primary { .. } => 1,
|
||||
BabePreDigest::Secondary { .. } => 0,
|
||||
PreDigest::Primary { .. } => 1,
|
||||
PreDigest::Secondary { .. } => 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The prefix used by BABE for its VRF keys.
|
||||
pub const BABE_VRF_PREFIX: &[u8] = b"substrate-babe-vrf";
|
||||
|
||||
/// A raw version of `BabePreDigest`, usable on `no_std`.
|
||||
#[derive(Copy, Clone, Encode, Decode)]
|
||||
pub enum RawBabePreDigest {
|
||||
pub enum RawPreDigest {
|
||||
/// A primary VRF-based slot assignment.
|
||||
#[codec(index = "1")]
|
||||
Primary {
|
||||
@@ -123,38 +120,38 @@ pub enum RawBabePreDigest {
|
||||
},
|
||||
}
|
||||
|
||||
impl RawBabePreDigest {
|
||||
impl RawPreDigest {
|
||||
/// Returns the slot number of the pre digest.
|
||||
pub fn slot_number(&self) -> SlotNumber {
|
||||
match self {
|
||||
RawBabePreDigest::Primary { slot_number, .. } => *slot_number,
|
||||
RawBabePreDigest::Secondary { slot_number, .. } => *slot_number,
|
||||
RawPreDigest::Primary { slot_number, .. } => *slot_number,
|
||||
RawPreDigest::Secondary { slot_number, .. } => *slot_number,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Encode for BabePreDigest {
|
||||
impl Encode for PreDigest {
|
||||
fn encode(&self) -> Vec<u8> {
|
||||
let raw = match self {
|
||||
BabePreDigest::Primary {
|
||||
PreDigest::Primary {
|
||||
vrf_output,
|
||||
vrf_proof,
|
||||
authority_index,
|
||||
slot_number,
|
||||
} => {
|
||||
RawBabePreDigest::Primary {
|
||||
RawPreDigest::Primary {
|
||||
vrf_output: *vrf_output.as_bytes(),
|
||||
vrf_proof: vrf_proof.to_bytes(),
|
||||
authority_index: *authority_index,
|
||||
slot_number: *slot_number,
|
||||
}
|
||||
},
|
||||
BabePreDigest::Secondary {
|
||||
PreDigest::Secondary {
|
||||
authority_index,
|
||||
slot_number,
|
||||
} => {
|
||||
RawBabePreDigest::Secondary {
|
||||
RawPreDigest::Secondary {
|
||||
authority_index: *authority_index,
|
||||
slot_number: *slot_number,
|
||||
}
|
||||
@@ -166,26 +163,26 @@ impl Encode for BabePreDigest {
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl codec::EncodeLike for BabePreDigest {}
|
||||
impl codec::EncodeLike for PreDigest {}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl Decode for BabePreDigest {
|
||||
impl Decode for PreDigest {
|
||||
fn decode<R: Input>(i: &mut R) -> Result<Self, Error> {
|
||||
let pre_digest = match Decode::decode(i)? {
|
||||
RawBabePreDigest::Primary { vrf_output, vrf_proof, authority_index, slot_number } => {
|
||||
RawPreDigest::Primary { vrf_output, vrf_proof, authority_index, slot_number } => {
|
||||
// Verify (at compile time) that the sizes in babe_primitives are correct
|
||||
let _: [u8; super::VRF_OUTPUT_LENGTH] = vrf_output;
|
||||
let _: [u8; super::VRF_PROOF_LENGTH] = vrf_proof;
|
||||
|
||||
BabePreDigest::Primary {
|
||||
PreDigest::Primary {
|
||||
vrf_proof: VRFProof::from_bytes(&vrf_proof).map_err(convert_error)?,
|
||||
vrf_output: VRFOutput::from_bytes(&vrf_output).map_err(convert_error)?,
|
||||
authority_index,
|
||||
slot_number,
|
||||
}
|
||||
},
|
||||
RawBabePreDigest::Secondary { authority_index, slot_number } => {
|
||||
BabePreDigest::Secondary { authority_index, slot_number }
|
||||
RawPreDigest::Secondary { authority_index, slot_number } => {
|
||||
PreDigest::Secondary { authority_index, slot_number }
|
||||
},
|
||||
};
|
||||
|
||||
@@ -208,10 +205,10 @@ pub struct NextEpochDescriptor {
|
||||
#[cfg(feature = "std")]
|
||||
pub trait CompatibleDigestItem: Sized {
|
||||
/// Construct a digest item which contains a BABE pre-digest.
|
||||
fn babe_pre_digest(seal: BabePreDigest) -> Self;
|
||||
fn babe_pre_digest(seal: PreDigest) -> Self;
|
||||
|
||||
/// If this item is an BABE pre-digest, return it.
|
||||
fn as_babe_pre_digest(&self) -> Option<BabePreDigest>;
|
||||
fn as_babe_pre_digest(&self) -> Option<PreDigest>;
|
||||
|
||||
/// Construct a digest item which contains a BABE seal.
|
||||
fn babe_seal(signature: AuthoritySignature) -> Self;
|
||||
@@ -227,11 +224,11 @@ pub trait CompatibleDigestItem: Sized {
|
||||
impl<Hash> CompatibleDigestItem for DigestItem<Hash> where
|
||||
Hash: Debug + Send + Sync + Eq + Clone + Codec + 'static
|
||||
{
|
||||
fn babe_pre_digest(digest: BabePreDigest) -> Self {
|
||||
fn babe_pre_digest(digest: PreDigest) -> Self {
|
||||
DigestItem::PreRuntime(BABE_ENGINE_ID, digest.encode())
|
||||
}
|
||||
|
||||
fn as_babe_pre_digest(&self) -> Option<BabePreDigest> {
|
||||
fn as_babe_pre_digest(&self) -> Option<PreDigest> {
|
||||
self.try_to(OpaqueDigestItemId::PreRuntime(&BABE_ENGINE_ID))
|
||||
}
|
||||
|
||||
@@ -19,22 +19,22 @@
|
||||
#![forbid(unsafe_code, missing_docs, unused_variables, unused_imports)]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
mod digest;
|
||||
pub mod digests;
|
||||
pub mod inherents;
|
||||
|
||||
use codec::{Encode, Decode};
|
||||
use sp_std::vec::Vec;
|
||||
use sp_runtime::{ConsensusEngineId, RuntimeDebug};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use digest::{BabePreDigest, CompatibleDigestItem};
|
||||
pub use digest::{BABE_VRF_PREFIX, RawBabePreDigest, NextEpochDescriptor};
|
||||
use crate::digests::NextEpochDescriptor;
|
||||
|
||||
mod app {
|
||||
use sp_application_crypto::{app_crypto, key_types::BABE, sr25519};
|
||||
app_crypto!(sr25519, BABE);
|
||||
}
|
||||
|
||||
/// The prefix used by BABE for its VRF keys.
|
||||
pub const BABE_VRF_PREFIX: &[u8] = b"substrate-babe-vrf";
|
||||
|
||||
/// A Babe authority keypair. Necessarily equivalent to the schnorrkel public key used in
|
||||
/// the main Babe module. If that ever changes, then this must, too.
|
||||
#[cfg(feature = "std")]
|
||||
@@ -78,40 +78,6 @@ pub type BabeAuthorityWeight = u64;
|
||||
/// The weight of a BABE block.
|
||||
pub type BabeBlockWeight = u32;
|
||||
|
||||
/// BABE epoch information
|
||||
#[derive(Decode, Encode, Default, PartialEq, Eq, Clone, RuntimeDebug)]
|
||||
pub struct Epoch {
|
||||
/// The epoch index
|
||||
pub epoch_index: u64,
|
||||
/// The starting slot of the epoch,
|
||||
pub start_slot: SlotNumber,
|
||||
/// The duration of this epoch
|
||||
pub duration: SlotNumber,
|
||||
/// The authorities and their weights
|
||||
pub authorities: Vec<(AuthorityId, BabeAuthorityWeight)>,
|
||||
/// Randomness for this epoch
|
||||
pub randomness: [u8; VRF_OUTPUT_LENGTH],
|
||||
}
|
||||
|
||||
impl Epoch {
|
||||
/// "increment" the epoch, with given descriptor for the next.
|
||||
pub fn increment(&self, descriptor: NextEpochDescriptor) -> Epoch {
|
||||
Epoch {
|
||||
epoch_index: self.epoch_index + 1,
|
||||
start_slot: self.start_slot + self.duration,
|
||||
duration: self.duration,
|
||||
authorities: descriptor.authorities,
|
||||
randomness: descriptor.randomness,
|
||||
}
|
||||
}
|
||||
|
||||
/// Produce the "end slot" of the epoch. This is NOT inclusive to the epoch,
|
||||
// i.e. the slots covered by the epoch are `self.start_slot .. self.end_slot()`.
|
||||
pub fn end_slot(&self) -> SlotNumber {
|
||||
self.start_slot + self.duration
|
||||
}
|
||||
}
|
||||
|
||||
/// An consensus log item for BABE.
|
||||
#[derive(Decode, Encode, Clone, PartialEq, Eq)]
|
||||
pub enum ConsensusLog {
|
||||
|
||||
Reference in New Issue
Block a user