mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 00:41:08 +00:00
babe: secondary blocks with VRF (#5501)
* babe: secondary blocks with VRF * Fix node runtime compile * Fix test-utils runtime interface * Fix babe tests * typo: v == 2 * babe: support online configuration upgrades * Fix rpc tests * Fix runtime version tests * Switch to use NextConfigDescriptor instead of changing runtime interface * Fix tests * epoch-changes: map function that allows converting with different epoch types * Add migration script for the epoch config change * Fix docs for PrimaryAndSecondaryVRFSlots * Add docs of `SecondaryVRF` in babe crate * babe-primitives: Secondary -> SecondaryPlain * babe-client: Secondary -> SecondaryPlain * Fix migration tests * test-utils-runtime: Secondary -> SecondaryPlain * Fix missing name change in test-utils-runtime * Fix migration: Epoch should be EpochV0 * Update client/consensus/babe/src/lib.rs Co-Authored-By: André Silva <123550+andresilva@users.noreply.github.com> * Fix new epochChanges version * Fix babe-primitives naming changes * Fix merge issues in babe-client Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> Co-authored-by: André Silva <andre.beat@gmail.com>
This commit is contained in:
@@ -805,7 +805,7 @@ impl_runtime_apis! {
|
||||
c: PRIMARY_PROBABILITY,
|
||||
genesis_authorities: Babe::authorities(),
|
||||
randomness: Babe::randomness(),
|
||||
secondary_slots: true,
|
||||
allowed_slots: sp_consensus_babe::AllowedSlots::PrimaryAndSecondaryPlainSlots,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -123,9 +123,12 @@ impl<B, C, SC> BabeApi for BabeRPCHandler<B, C, SC>
|
||||
PreDigest::Primary { .. } => {
|
||||
claims.entry(key.public()).or_default().primary.push(slot_number);
|
||||
}
|
||||
PreDigest::Secondary { .. } => {
|
||||
PreDigest::SecondaryPlain { .. } => {
|
||||
claims.entry(key.public()).or_default().secondary.push(slot_number);
|
||||
}
|
||||
PreDigest::SecondaryVRF { .. } => {
|
||||
claims.entry(key.public()).or_default().secondary_vrf.push(slot_number);
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -144,6 +147,8 @@ pub struct EpochAuthorship {
|
||||
primary: Vec<u64>,
|
||||
/// the array of secondary slots that can be claimed
|
||||
secondary: Vec<u64>,
|
||||
/// The array of secondary VRF slots that can be claimed.
|
||||
secondary_vrf: Vec<u64>,
|
||||
}
|
||||
|
||||
/// Errors encountered by the RPC
|
||||
@@ -236,7 +241,7 @@ mod tests {
|
||||
|
||||
io.extend_with(BabeApi::to_delegate(handler));
|
||||
let request = r#"{"jsonrpc":"2.0","method":"babe_epochAuthorship","params": [],"id":1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY":{"primary":[0],"secondary":[1,2,4]}},"id":1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY":{"primary":[0],"secondary":[1,2,4],"secondary_vrf":[]}},"id":1}"#;
|
||||
|
||||
assert_eq!(Some(response.into()), io.handle_request_sync(request));
|
||||
}
|
||||
|
||||
@@ -21,7 +21,9 @@ use sp_consensus_babe::{
|
||||
AuthorityId, BabeAuthorityWeight, BABE_ENGINE_ID, BABE_VRF_PREFIX,
|
||||
SlotNumber, AuthorityPair,
|
||||
};
|
||||
use sp_consensus_babe::digests::{PreDigest, PrimaryPreDigest, SecondaryPreDigest};
|
||||
use sp_consensus_babe::digests::{
|
||||
PreDigest, PrimaryPreDigest, SecondaryPlainPreDigest, SecondaryVRFPreDigest,
|
||||
};
|
||||
use sp_consensus_vrf::schnorrkel::{VRFOutput, VRFProof};
|
||||
use sp_core::{U256, blake2_256};
|
||||
use codec::Encode;
|
||||
@@ -105,10 +107,12 @@ pub(super) fn make_transcript(
|
||||
/// to propose.
|
||||
fn claim_secondary_slot(
|
||||
slot_number: SlotNumber,
|
||||
authorities: &[(AuthorityId, BabeAuthorityWeight)],
|
||||
epoch: &Epoch,
|
||||
keystore: &KeyStorePtr,
|
||||
randomness: [u8; 32],
|
||||
author_secondary_vrf: bool,
|
||||
) -> Option<(PreDigest, AuthorityPair)> {
|
||||
let Epoch { authorities, randomness, epoch_index, .. } = epoch;
|
||||
|
||||
if authorities.is_empty() {
|
||||
return None;
|
||||
}
|
||||
@@ -116,7 +120,7 @@ fn claim_secondary_slot(
|
||||
let expected_author = super::authorship::secondary_slot_author(
|
||||
slot_number,
|
||||
authorities,
|
||||
randomness,
|
||||
*randomness,
|
||||
)?;
|
||||
|
||||
let keystore = keystore.read();
|
||||
@@ -128,10 +132,27 @@ fn claim_secondary_slot(
|
||||
})
|
||||
{
|
||||
if pair.public() == *expected_author {
|
||||
let pre_digest = PreDigest::Secondary(SecondaryPreDigest {
|
||||
slot_number,
|
||||
authority_index: authority_index as u32,
|
||||
});
|
||||
let pre_digest = if author_secondary_vrf {
|
||||
let transcript = super::authorship::make_transcript(
|
||||
randomness,
|
||||
slot_number,
|
||||
*epoch_index,
|
||||
);
|
||||
|
||||
let s = get_keypair(&pair).vrf_sign(transcript);
|
||||
|
||||
PreDigest::SecondaryVRF(SecondaryVRFPreDigest {
|
||||
slot_number,
|
||||
vrf_output: VRFOutput(s.0.to_output()),
|
||||
vrf_proof: VRFProof(s.1),
|
||||
authority_index: authority_index as u32,
|
||||
})
|
||||
} else {
|
||||
PreDigest::SecondaryPlain(SecondaryPlainPreDigest {
|
||||
slot_number,
|
||||
authority_index: authority_index as u32,
|
||||
})
|
||||
};
|
||||
|
||||
return Some((pre_digest, pair));
|
||||
}
|
||||
@@ -151,12 +172,14 @@ pub fn claim_slot(
|
||||
) -> Option<(PreDigest, AuthorityPair)> {
|
||||
claim_primary_slot(slot_number, epoch, epoch.config.c, keystore)
|
||||
.or_else(|| {
|
||||
if epoch.config.secondary_slots {
|
||||
if epoch.config.allowed_slots.is_secondary_plain_slots_allowed() ||
|
||||
epoch.config.allowed_slots.is_secondary_vrf_slots_allowed()
|
||||
{
|
||||
claim_secondary_slot(
|
||||
slot_number,
|
||||
&epoch.authorities,
|
||||
&epoch,
|
||||
keystore,
|
||||
epoch.randomness,
|
||||
epoch.config.allowed_slots.is_secondary_vrf_slots_allowed(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
|
||||
@@ -141,7 +141,7 @@ mod test {
|
||||
use substrate_test_runtime_client;
|
||||
use sp_core::H256;
|
||||
use sp_runtime::traits::NumberFor;
|
||||
use sp_consensus_babe::BabeGenesisConfiguration;
|
||||
use sp_consensus_babe::{AllowedSlots, BabeGenesisConfiguration};
|
||||
use sc_consensus_epochs::{PersistedEpoch, PersistedEpochHeader, EpochHeader};
|
||||
use sp_consensus::Error as ConsensusError;
|
||||
use sc_network_test::Block as TestBlock;
|
||||
@@ -182,7 +182,7 @@ mod test {
|
||||
c: (3, 10),
|
||||
genesis_authorities: Vec::new(),
|
||||
randomness: Default::default(),
|
||||
secondary_slots: true,
|
||||
allowed_slots: AllowedSlots::PrimaryAndSecondaryPlainSlots,
|
||||
},
|
||||
).unwrap();
|
||||
|
||||
|
||||
@@ -49,6 +49,11 @@
|
||||
//!
|
||||
//! `blake2_256(epoch_randomness ++ slot_number) % authorities_len`.
|
||||
//!
|
||||
//! The secondary slots supports either a `SecondaryPlain` or `SecondaryVRF`
|
||||
//! variant. Comparing with `SecondaryPlain` variant, the `SecondaryVRF` variant
|
||||
//! generates an additional VRF output. The output is not included in beacon
|
||||
//! randomness, but can be consumed by parachains.
|
||||
//!
|
||||
//! The fork choice rule is weight-based, where weight equals the number of
|
||||
//! primary blocks in the chain. We will pick the heaviest chain (more primary
|
||||
//! blocks) and will go with the longest one in case of a tie.
|
||||
@@ -64,8 +69,8 @@ pub use sp_consensus_babe::{
|
||||
AuthorityId, AuthorityPair, AuthoritySignature,
|
||||
BabeAuthorityWeight, VRF_OUTPUT_LENGTH,
|
||||
digests::{
|
||||
CompatibleDigestItem, NextEpochDescriptor, NextConfigDescriptor,
|
||||
PreDigest, PrimaryPreDigest, SecondaryPreDigest,
|
||||
CompatibleDigestItem, NextEpochDescriptor, NextConfigDescriptor, PreDigest,
|
||||
PrimaryPreDigest, SecondaryPlainPreDigest,
|
||||
},
|
||||
};
|
||||
pub use sp_consensus::SyncOracle;
|
||||
@@ -184,7 +189,7 @@ impl Epoch {
|
||||
randomness: genesis_config.randomness.clone(),
|
||||
config: BabeEpochConfiguration {
|
||||
c: genesis_config.c,
|
||||
secondary_slots: genesis_config.secondary_slots,
|
||||
allowed_slots: genesis_config.allowed_slots,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -279,7 +284,26 @@ impl Config {
|
||||
C: AuxStore + ProvideRuntimeApi<B>, C::Api: BabeApi<B, Error = sp_blockchain::Error>,
|
||||
{
|
||||
trace!(target: "babe", "Getting slot duration");
|
||||
match sc_consensus_slots::SlotDuration::get_or_compute(client, |a, b| a.configuration(b)).map(Self) {
|
||||
match sc_consensus_slots::SlotDuration::get_or_compute(client, |a, b| {
|
||||
let has_api_v1 = a.has_api_with::<dyn BabeApi<B, Error = sp_blockchain::Error>, _>(
|
||||
&b, |v| v == 1,
|
||||
)?;
|
||||
let has_api_v2 = a.has_api_with::<dyn BabeApi<B, Error = sp_blockchain::Error>, _>(
|
||||
&b, |v| v == 2,
|
||||
)?;
|
||||
|
||||
if has_api_v1 {
|
||||
#[allow(deprecated)] {
|
||||
Ok(a.configuration_before_version_2(b)?.into())
|
||||
}
|
||||
} else if has_api_v2 {
|
||||
a.configuration(b)
|
||||
} else {
|
||||
Err(sp_blockchain::Error::VersionInvalid(
|
||||
"Unsupported or invalid BabeApi version".to_string()
|
||||
))
|
||||
}
|
||||
}).map(Self) {
|
||||
Ok(s) => Ok(s),
|
||||
Err(s) => {
|
||||
warn!(target: "babe", "Failed to get slot duration");
|
||||
@@ -583,7 +607,7 @@ 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(PreDigest::Secondary(SecondaryPreDigest {
|
||||
return Ok(PreDigest::SecondaryPlain(SecondaryPlainPreDigest {
|
||||
slot_number: 0,
|
||||
authority_index: 0,
|
||||
}));
|
||||
@@ -1044,7 +1068,7 @@ impl<Block, Client, Inner> BlockImport<Block> for BabeBlockImport<Block, Client,
|
||||
let epoch_config = next_config_digest.unwrap_or_else(
|
||||
|| viable_epoch.as_ref().config.clone()
|
||||
);
|
||||
|
||||
|
||||
// restrict info logging during initial sync to avoid spam
|
||||
let log_level = if block.origin == BlockOrigin::NetworkInitialSync {
|
||||
log::Level::Debug
|
||||
@@ -1053,7 +1077,7 @@ impl<Block, Client, Inner> BlockImport<Block> for BabeBlockImport<Block, Client,
|
||||
};
|
||||
|
||||
log!(target: "babe",
|
||||
log_level,
|
||||
log_level,
|
||||
"👶 New epoch {} launching at block {} (block slot {} >= start slot {}).",
|
||||
viable_epoch.as_ref().epoch_index,
|
||||
hash,
|
||||
|
||||
@@ -57,7 +57,7 @@ impl EpochV0 {
|
||||
randomness: self.randomness,
|
||||
config: BabeEpochConfiguration {
|
||||
c: config.c,
|
||||
secondary_slots: config.secondary_slots,
|
||||
allowed_slots: config.allowed_slots,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
use super::*;
|
||||
use authorship::claim_slot;
|
||||
|
||||
use sp_consensus_babe::{AuthorityPair, SlotNumber};
|
||||
use sp_consensus_babe::{AuthorityPair, SlotNumber, AllowedSlots};
|
||||
use sc_block_builder::{BlockBuilder, BlockBuilderProvider};
|
||||
use sp_consensus::{
|
||||
NoNetwork as DummyOracle, Proposal, RecordProof,
|
||||
@@ -507,7 +507,7 @@ fn can_author_block() {
|
||||
duration: 100,
|
||||
config: BabeEpochConfiguration {
|
||||
c: (3, 10),
|
||||
secondary_slots: true,
|
||||
allowed_slots: AllowedSlots::PrimaryAndSecondaryPlainSlots,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -517,7 +517,7 @@ fn can_author_block() {
|
||||
c: (3, 10),
|
||||
genesis_authorities: Vec::new(),
|
||||
randomness: [0; 32],
|
||||
secondary_slots: true,
|
||||
allowed_slots: AllowedSlots::PrimaryAndSecondaryPlainSlots,
|
||||
};
|
||||
|
||||
// with secondary slots enabled it should never be empty
|
||||
@@ -528,7 +528,7 @@ fn can_author_block() {
|
||||
|
||||
// otherwise with only vrf-based primary slots we might need to try a couple
|
||||
// of times.
|
||||
config.secondary_slots = false;
|
||||
config.allowed_slots = AllowedSlots::PrimarySlots;
|
||||
loop {
|
||||
match claim_slot(i, &epoch, &keystore) {
|
||||
None => i += 1,
|
||||
@@ -557,7 +557,7 @@ fn propose_and_import_block<Transaction>(
|
||||
let pre_digest = sp_runtime::generic::Digest {
|
||||
logs: vec![
|
||||
Item::babe_pre_digest(
|
||||
PreDigest::Secondary(SecondaryPreDigest {
|
||||
PreDigest::SecondaryPlain(SecondaryPlainPreDigest {
|
||||
authority_index: 0,
|
||||
slot_number,
|
||||
}),
|
||||
|
||||
@@ -19,7 +19,8 @@ use sp_runtime::{traits::Header, traits::DigestItemFor};
|
||||
use sp_core::{Pair, Public};
|
||||
use sp_consensus_babe::{AuthoritySignature, SlotNumber, AuthorityPair, AuthorityId};
|
||||
use sp_consensus_babe::digests::{
|
||||
PreDigest, PrimaryPreDigest, SecondaryPreDigest, CompatibleDigestItem
|
||||
PreDigest, PrimaryPreDigest, SecondaryPlainPreDigest, SecondaryVRFPreDigest,
|
||||
CompatibleDigestItem
|
||||
};
|
||||
use sc_consensus_slots::CheckedHeader;
|
||||
use log::{debug, trace};
|
||||
@@ -28,15 +29,15 @@ use super::authorship::{make_transcript, calculate_primary_threshold, check_prim
|
||||
|
||||
/// BABE verification parameters
|
||||
pub(super) struct VerificationParams<'a, B: 'a + BlockT> {
|
||||
/// the header being verified.
|
||||
/// The header being verified.
|
||||
pub(super) header: B::Header,
|
||||
/// the pre-digest of the header being verified. this is optional - if prior
|
||||
/// 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<PreDigest>,
|
||||
/// the slot number of the current time.
|
||||
/// 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.
|
||||
/// Epoch descriptor of the epoch this block _should_ be under, if it's valid.
|
||||
pub(super) epoch: &'a Epoch,
|
||||
}
|
||||
|
||||
@@ -102,10 +103,18 @@ pub(super) fn check_header<B: BlockT + Sized>(
|
||||
epoch.config.c,
|
||||
)?;
|
||||
},
|
||||
PreDigest::Secondary(secondary) if epoch.config.secondary_slots => {
|
||||
debug!(target: "babe", "Verifying Secondary block");
|
||||
|
||||
check_secondary_header::<B>(
|
||||
PreDigest::SecondaryPlain(secondary) if epoch.config.allowed_slots.is_secondary_plain_slots_allowed() => {
|
||||
debug!(target: "babe", "Verifying Secondary plain block");
|
||||
check_secondary_plain_header::<B>(
|
||||
pre_hash,
|
||||
secondary,
|
||||
sig,
|
||||
&epoch,
|
||||
)?;
|
||||
},
|
||||
PreDigest::SecondaryVRF(secondary) if epoch.config.allowed_slots.is_secondary_vrf_slots_allowed() => {
|
||||
debug!(target: "babe", "Verifying Secondary VRF block");
|
||||
check_secondary_vrf_header::<B>(
|
||||
pre_hash,
|
||||
secondary,
|
||||
sig,
|
||||
@@ -179,9 +188,9 @@ fn check_primary_header<B: BlockT + Sized>(
|
||||
/// properly signed by the expected authority, which we have a deterministic way
|
||||
/// of computing. Additionally, the weight of this block must stay the same
|
||||
/// compared to its parent since it is a secondary block.
|
||||
fn check_secondary_header<B: BlockT>(
|
||||
fn check_secondary_plain_header<B: BlockT>(
|
||||
pre_hash: B::Hash,
|
||||
pre_digest: &SecondaryPreDigest,
|
||||
pre_digest: &SecondaryPlainPreDigest,
|
||||
signature: AuthoritySignature,
|
||||
epoch: &Epoch,
|
||||
) -> Result<(), Error<B>> {
|
||||
@@ -205,3 +214,43 @@ fn check_secondary_header<B: BlockT>(
|
||||
Err(Error::BadSignature(pre_hash))
|
||||
}
|
||||
}
|
||||
|
||||
/// Check a secondary VRF slot proposal header.
|
||||
fn check_secondary_vrf_header<B: BlockT>(
|
||||
pre_hash: B::Hash,
|
||||
pre_digest: &SecondaryVRFPreDigest,
|
||||
signature: AuthoritySignature,
|
||||
epoch: &Epoch,
|
||||
) -> Result<(), Error<B>> {
|
||||
// check the signature is valid under the expected authority and
|
||||
// chain state.
|
||||
let expected_author = secondary_slot_author(
|
||||
pre_digest.slot_number,
|
||||
&epoch.authorities,
|
||||
epoch.randomness,
|
||||
).ok_or_else(|| Error::NoSecondaryAuthorExpected)?;
|
||||
|
||||
let author = &epoch.authorities[pre_digest.authority_index as usize].0;
|
||||
|
||||
if expected_author != author {
|
||||
return Err(Error::InvalidAuthor(expected_author.clone(), author.clone()));
|
||||
}
|
||||
|
||||
if AuthorityPair::verify(&signature, pre_hash.as_ref(), author) {
|
||||
let transcript = make_transcript(
|
||||
&epoch.randomness,
|
||||
pre_digest.slot_number,
|
||||
epoch.epoch_index,
|
||||
);
|
||||
|
||||
schnorrkel::PublicKey::from_bytes(author.as_slice()).and_then(|p| {
|
||||
p.vrf_verify(transcript, &pre_digest.vrf_output, &pre_digest.vrf_proof)
|
||||
}).map_err(|s| {
|
||||
babe_err(Error::VRFVerificationFailed(s))
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::BadSignature(pre_hash))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -432,7 +432,7 @@ fn should_return_runtime_version() {
|
||||
let result = "{\"specName\":\"test\",\"implName\":\"parity-test\",\"authoringVersion\":1,\
|
||||
\"specVersion\":2,\"implVersion\":2,\"apis\":[[\"0xdf6acb689907609b\",3],\
|
||||
[\"0x37e397fc7c91f5e4\",1],[\"0xd2bc9897eed08f15\",2],[\"0x40fe3ad401f8959a\",4],\
|
||||
[\"0xc6e9a76309f39b09\",1],[\"0xdd718d5cc53262d4\",1],[\"0xcbca25e39f142387\",1],\
|
||||
[\"0xc6e9a76309f39b09\",1],[\"0xdd718d5cc53262d4\",1],[\"0xcbca25e39f142387\",2],\
|
||||
[\"0xf78b278be53f454c\",2],[\"0xab3c0572291feb8b\",1],[\"0xbc9d89904f5b923f\",1]],\
|
||||
\"transactionVersion\":1}";
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ impl TryFrom<RawPrimaryPreDigest> for PrimaryPreDigest {
|
||||
|
||||
/// BABE secondary slot assignment pre-digest.
|
||||
#[derive(Clone, RuntimeDebug, Encode, Decode)]
|
||||
pub struct SecondaryPreDigest {
|
||||
pub struct SecondaryPlainPreDigest {
|
||||
/// Authority index
|
||||
///
|
||||
/// This is not strictly-speaking necessary, since the secondary slots
|
||||
@@ -77,6 +77,37 @@ pub struct SecondaryPreDigest {
|
||||
pub slot_number: SlotNumber,
|
||||
}
|
||||
|
||||
/// BABE secondary deterministic slot assignment with VRF outputs.
|
||||
#[derive(Clone, RuntimeDebug, Encode, Decode)]
|
||||
pub struct RawSecondaryVRFPreDigest<VRFOutput=schnorrkel::RawVRFOutput, VRFProof=schnorrkel::RawVRFProof> {
|
||||
/// Authority index
|
||||
pub authority_index: super::AuthorityIndex,
|
||||
/// Slot number
|
||||
pub slot_number: SlotNumber,
|
||||
/// VRF output
|
||||
pub vrf_output: VRFOutput,
|
||||
/// VRF proof
|
||||
pub vrf_proof: VRFProof,
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
/// BABE secondary slot assignment with VRF outputs pre-digest, for std environment.
|
||||
pub type SecondaryVRFPreDigest = RawSecondaryVRFPreDigest<schnorrkel::VRFOutput, schnorrkel::VRFProof>;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl TryFrom<RawSecondaryVRFPreDigest> for SecondaryVRFPreDigest {
|
||||
type Error = SignatureError;
|
||||
|
||||
fn try_from(raw: RawSecondaryVRFPreDigest) -> Result<SecondaryVRFPreDigest, SignatureError> {
|
||||
Ok(SecondaryVRFPreDigest {
|
||||
authority_index: raw.authority_index,
|
||||
slot_number: raw.slot_number,
|
||||
vrf_output: raw.vrf_output.try_into()?,
|
||||
vrf_proof: raw.vrf_proof.try_into()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// A BABE pre-runtime digest. This contains all data required to validate a
|
||||
/// block and for the BABE runtime module. Slots can be assigned to a primary
|
||||
/// (VRF based) and to a secondary (slot number based).
|
||||
@@ -87,7 +118,10 @@ pub enum RawPreDigest<VRFOutput=schnorrkel::RawVRFOutput, VRFProof=schnorrkel::R
|
||||
Primary(RawPrimaryPreDigest<VRFOutput, VRFProof>),
|
||||
/// A secondary deterministic slot assignment.
|
||||
#[codec(index = "2")]
|
||||
Secondary(SecondaryPreDigest),
|
||||
SecondaryPlain(SecondaryPlainPreDigest),
|
||||
/// A secondary deterministic slot assignment with VRF outputs.
|
||||
#[codec(index = "3")]
|
||||
SecondaryVRF(RawSecondaryVRFPreDigest<VRFOutput, VRFProof>),
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
@@ -99,7 +133,8 @@ impl<VRFOutput, VRFProof> RawPreDigest<VRFOutput, VRFProof> {
|
||||
pub fn authority_index(&self) -> AuthorityIndex {
|
||||
match self {
|
||||
RawPreDigest::Primary(primary) => primary.authority_index,
|
||||
RawPreDigest::Secondary(secondary) => secondary.authority_index,
|
||||
RawPreDigest::SecondaryPlain(secondary) => secondary.authority_index,
|
||||
RawPreDigest::SecondaryVRF(secondary) => secondary.authority_index,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +142,8 @@ impl<VRFOutput, VRFProof> RawPreDigest<VRFOutput, VRFProof> {
|
||||
pub fn slot_number(&self) -> SlotNumber {
|
||||
match self {
|
||||
RawPreDigest::Primary(primary) => primary.slot_number,
|
||||
RawPreDigest::Secondary(secondary) => secondary.slot_number,
|
||||
RawPreDigest::SecondaryPlain(secondary) => secondary.slot_number,
|
||||
RawPreDigest::SecondaryVRF(secondary) => secondary.slot_number,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,7 +152,7 @@ impl<VRFOutput, VRFProof> RawPreDigest<VRFOutput, VRFProof> {
|
||||
pub fn added_weight(&self) -> crate::BabeBlockWeight {
|
||||
match self {
|
||||
RawPreDigest::Primary(_) => 1,
|
||||
RawPreDigest::Secondary(_) => 0,
|
||||
RawPreDigest::SecondaryPlain(_) | RawPreDigest::SecondaryVRF(_) => 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,7 +164,8 @@ impl TryFrom<RawPreDigest> for PreDigest {
|
||||
fn try_from(raw: RawPreDigest) -> Result<PreDigest, SignatureError> {
|
||||
Ok(match raw {
|
||||
RawPreDigest::Primary(primary) => PreDigest::Primary(primary.try_into()?),
|
||||
RawPreDigest::Secondary(secondary) => PreDigest::Secondary(secondary),
|
||||
RawPreDigest::SecondaryPlain(secondary) => PreDigest::SecondaryPlain(secondary),
|
||||
RawPreDigest::SecondaryVRF(secondary) => PreDigest::SecondaryVRF(secondary.try_into()?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ pub enum ConsensusLog {
|
||||
|
||||
/// Configuration data used by the BABE consensus engine.
|
||||
#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)]
|
||||
pub struct BabeGenesisConfiguration {
|
||||
pub struct BabeGenesisConfigurationV1 {
|
||||
/// The slot duration in milliseconds for BABE. Currently, only
|
||||
/// the value provided by this type at genesis will be used.
|
||||
///
|
||||
@@ -124,6 +124,76 @@ pub struct BabeGenesisConfiguration {
|
||||
pub secondary_slots: bool,
|
||||
}
|
||||
|
||||
impl From<BabeGenesisConfigurationV1> for BabeGenesisConfiguration {
|
||||
fn from(v1: BabeGenesisConfigurationV1) -> Self {
|
||||
Self {
|
||||
slot_duration: v1.slot_duration,
|
||||
epoch_length: v1.epoch_length,
|
||||
c: v1.c,
|
||||
genesis_authorities: v1.genesis_authorities,
|
||||
randomness: v1.randomness,
|
||||
allowed_slots: if v1.secondary_slots {
|
||||
AllowedSlots::PrimaryAndSecondaryPlainSlots
|
||||
} else {
|
||||
AllowedSlots::PrimarySlots
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Configuration data used by the BABE consensus engine.
|
||||
#[derive(Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)]
|
||||
pub struct BabeGenesisConfiguration {
|
||||
/// The slot duration in milliseconds for BABE. Currently, only
|
||||
/// the value provided by this type at genesis will be used.
|
||||
///
|
||||
/// Dynamic slot duration may be supported in the future.
|
||||
pub slot_duration: u64,
|
||||
|
||||
/// The duration of epochs in slots.
|
||||
pub epoch_length: SlotNumber,
|
||||
|
||||
/// A constant value that is used in the threshold calculation formula.
|
||||
/// Expressed as a rational where the first member of the tuple is the
|
||||
/// numerator and the second is the denominator. The rational should
|
||||
/// represent a value between 0 and 1.
|
||||
/// In the threshold formula calculation, `1 - c` represents the probability
|
||||
/// of a slot being empty.
|
||||
pub c: (u64, u64),
|
||||
|
||||
/// The authorities for the genesis epoch.
|
||||
pub genesis_authorities: Vec<(AuthorityId, BabeAuthorityWeight)>,
|
||||
|
||||
/// The randomness for the genesis epoch.
|
||||
pub randomness: Randomness,
|
||||
|
||||
/// Type of allowed slots.
|
||||
pub allowed_slots: AllowedSlots,
|
||||
}
|
||||
|
||||
/// Types of allowed slots.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode, RuntimeDebug)]
|
||||
pub enum AllowedSlots {
|
||||
/// Only allow primary slots.
|
||||
PrimarySlots,
|
||||
/// Allow primary and secondary plain slots.
|
||||
PrimaryAndSecondaryPlainSlots,
|
||||
/// Allow primary and secondary VRF slots.
|
||||
PrimaryAndSecondaryVRFSlots,
|
||||
}
|
||||
|
||||
impl AllowedSlots {
|
||||
/// Whether plain secondary slots are allowed.
|
||||
pub fn is_secondary_plain_slots_allowed(&self) -> bool {
|
||||
*self == Self::PrimaryAndSecondaryPlainSlots
|
||||
}
|
||||
|
||||
/// Whether VRF secondary slots are allowed.
|
||||
pub fn is_secondary_vrf_slots_allowed(&self) -> bool {
|
||||
*self == Self::PrimaryAndSecondaryVRFSlots
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl sp_consensus::SlotData for BabeGenesisConfiguration {
|
||||
fn slot_duration(&self) -> u64 {
|
||||
@@ -146,15 +216,20 @@ pub struct BabeEpochConfiguration {
|
||||
|
||||
/// Whether this chain should run with secondary slots, which are assigned
|
||||
/// in round-robin manner.
|
||||
pub secondary_slots: bool,
|
||||
pub allowed_slots: AllowedSlots,
|
||||
}
|
||||
|
||||
sp_api::decl_runtime_apis! {
|
||||
/// API necessary for block authorship with BABE.
|
||||
#[api_version(2)]
|
||||
pub trait BabeApi {
|
||||
/// Return the genesis configuration for BABE. The configuration is only read on genesis.
|
||||
fn configuration() -> BabeGenesisConfiguration;
|
||||
|
||||
/// Return the configuration for BABE. Version 1.
|
||||
#[changed_in(2)]
|
||||
fn configuration() -> BabeGenesisConfigurationV1;
|
||||
|
||||
/// Returns the slot number that started the current epoch.
|
||||
fn current_epoch_start() -> SlotNumber;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ use sp_inherents::{CheckInherentsResult, InherentData};
|
||||
use cfg_if::cfg_if;
|
||||
|
||||
// Ensure Babe and Aura use the same crypto to simplify things a bit.
|
||||
pub use sp_consensus_babe::{AuthorityId, SlotNumber};
|
||||
pub use sp_consensus_babe::{AuthorityId, SlotNumber, AllowedSlots};
|
||||
pub type AuraId = sp_consensus_aura::sr25519::AuthorityId;
|
||||
|
||||
// Include the WASM binary
|
||||
@@ -641,7 +641,7 @@ cfg_if! {
|
||||
genesis_authorities: system::authorities()
|
||||
.into_iter().map(|x|(x, 1)).collect(),
|
||||
randomness: <pallet_babe::Module<Runtime>>::randomness(),
|
||||
secondary_slots: true,
|
||||
allowed_slots: AllowedSlots::PrimaryAndSecondaryPlainSlots,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -835,7 +835,7 @@ cfg_if! {
|
||||
genesis_authorities: system::authorities()
|
||||
.into_iter().map(|x|(x, 1)).collect(),
|
||||
randomness: <pallet_babe::Module<Runtime>>::randomness(),
|
||||
secondary_slots: true,
|
||||
allowed_slots: AllowedSlots::PrimaryAndSecondaryPlainSlots,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user