Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit 426c26b

Browse files
authored
Fixing BABE epochs to change between blocks (#3583)
* always fetch epoch from runtime * node integration tests don't test light nodes * give stand-in full node a FULL role * rejig babe APIs * introduce next-epoch-descriptor type * overhaul srml-BABE epoch logic * ensure VRF outputs end up in the right epoch-randomness * rewrite `do_initialize` to remove unnecessary loop * begin accounting for next epoch in epoch function * slots passes header to epoch_data * pass slot_number to SlotWorker::epoch_data * begin extracting epoch-change logic into its own module * aux methods for block weight * aux methods for genesis configuration * comment-out most, refactor header-check pipeline * mostly flesh out verifier again * reinstantiate babe BlockImport implementation * reinstate import-queue instantiation * reintroduce slot-worker implementation * reinstate pretty much all the rest * move fork-choice logic to BlockImport * fix some, but not all errors * patch test-runtime * make is_descendent of slightly more generic * get skeleton compiling when passing is_descendent_of * make descendent-of-builder more succinct * restore ordering of authority_index / slot_number * start fiddling with tests * fix warnings * improve initialization architecture and handle genesis * tests use correct block-import * fix BABE tests * fix some compiler errors * fix node-cli compilation * all crates compile * bump runtime versions and fix some warnings * tweak fork-tree search implementation * do backtracking search in fork-tree * node-cli integration tests now work * fix broken assumption in test_connectivity * babe tests fail for the right reasons. * test genesis epoch logic for epoch_changes * test that epochs can change between blocks * First BABE SRML test * Testing infrastructure for BABE Also includes a trivial additional test. * Apply suggestions from code review Co-Authored-By: Bastian Köcher <[email protected]> * A little more test progress * More work on BABE testing * Try to get the tests working * Implement `UintAuthorityId`-based test mocks * Fix compilation errors * Adjust to upstream changes * Block numbers are ignored in BABE epoch calculation * authority_index() should ignore invalid authorities * Fix compile error * Add tests that session transitions happen * Check if BABE produces logs It currently does not. * Fix test suite This was really nasty, due to a type confusion that showed up as an off-by-1 buffer error. * Add additional tests Most of these were derived from the current output, so they are only useful to guard against regressions. * Make the tests more readable Also bump impl_version. * Fix excessive line width * Remove unused imports * Update srml/babe/src/lib.rs Co-Authored-By: André Silva <[email protected]> * try to fix imports * Fix build errors in test suite * tests did not pass * Try to get at least one digest to be output Currently, the code emits either no digests (if I don’t call `Session::rotate_session()` or two digests (if I do), which is wrong. * More tests They still don’t work, but this should help debugging. * fix silly error * Don’t even try to compile a broken test * remove broken check_epoch test and add one for genesis epoch * Check that the length of the pre-digests is correct * Bump `impl_version` * use epoch_for_descendent_of even for genesis * account for competing block 1s * finish srml-babe docs Co-Authored-By: André Silva <[email protected]> * address grumbles
1 parent 9abf27c commit 426c26b

File tree

34 files changed

+2171
-992
lines changed

34 files changed

+2171
-992
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/client/src/client.rs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1482,6 +1482,9 @@ impl<B, E, Block, RA> CallRuntimeAt<Block> for Client<B, E, Block, RA> where
14821482
}
14831483
}
14841484

1485+
/// NOTE: only use this implementation when you are sure there are NO consensus-level BlockImport
1486+
/// objects. Otherwise, importing blocks directly into the client would be bypassing
1487+
/// important verification work.
14851488
impl<'a, B, E, Block, RA> consensus::BlockImport<Block> for &'a Client<B, E, Block, RA> where
14861489
B: backend::Backend<Block, Blake2Hasher>,
14871490
E: CallExecutor<Block, Blake2Hasher> + Clone + Send + Sync,
@@ -1491,6 +1494,13 @@ impl<'a, B, E, Block, RA> consensus::BlockImport<Block> for &'a Client<B, E, Blo
14911494

14921495
/// Import a checked and validated block. If a justification is provided in
14931496
/// `BlockImportParams` then `finalized` *must* be true.
1497+
///
1498+
/// NOTE: only use this implementation when there are NO consensus-level BlockImport
1499+
/// objects. Otherwise, importing blocks directly into the client would be bypassing
1500+
/// important verification work.
1501+
///
1502+
/// If you are not sure that there are no BlockImport objects provided by the consensus
1503+
/// algorithm, don't use this function.
14941504
fn import_block(
14951505
&mut self,
14961506
import_block: BlockImportParams<Block>,
@@ -1899,25 +1909,27 @@ where
18991909
/// Utility methods for the client.
19001910
pub mod utils {
19011911
use super::*;
1902-
use crate::{backend::Backend, blockchain, error};
1912+
use crate::{blockchain, error};
19031913
use primitives::H256;
1914+
use std::borrow::Borrow;
19041915

19051916
/// Returns a function for checking block ancestry, the returned function will
19061917
/// return `true` if the given hash (second parameter) is a descendent of the
19071918
/// base (first parameter). If the `current` parameter is defined, it should
19081919
/// represent the current block `hash` and its `parent hash`, if given the
19091920
/// function that's returned will assume that `hash` isn't part of the local DB
19101921
/// yet, and all searches in the DB will instead reference the parent.
1911-
pub fn is_descendent_of<'a, B, E, Block: BlockT<Hash=H256>, RA>(
1912-
client: &'a Client<B, E, Block, RA>,
1913-
current: Option<(&'a H256, &'a H256)>,
1922+
pub fn is_descendent_of<'a, Block: BlockT<Hash=H256>, T, H: Borrow<H256> + 'a>(
1923+
client: &'a T,
1924+
current: Option<(H, H)>,
19141925
) -> impl Fn(&H256, &H256) -> Result<bool, error::Error> + 'a
1915-
where B: Backend<Block, Blake2Hasher>,
1916-
E: CallExecutor<Block, Blake2Hasher> + Send + Sync,
1926+
where T: ChainHeaderBackend<Block>,
19171927
{
19181928
move |base, hash| {
19191929
if base == hash { return Ok(false); }
19201930

1931+
let current = current.as_ref().map(|(c, p)| (c.borrow(), p.borrow()));
1932+
19211933
let mut hash = hash;
19221934
if let Some((current_hash, current_parent_hash)) = current {
19231935
if base == current_hash { return Ok(false); }
@@ -1931,7 +1943,7 @@ pub mod utils {
19311943
}
19321944

19331945
let tree_route = blockchain::tree_route(
1934-
|id| client.header(&id)?.ok_or_else(|| Error::UnknownBlock(format!("{:?}", id))),
1946+
|id| client.header(id)?.ok_or_else(|| Error::UnknownBlock(format!("{:?}", id))),
19351947
BlockId::Hash(*hash),
19361948
BlockId::Hash(*base),
19371949
)?;

core/consensus/aura/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,8 @@ impl<H, B, C, E, I, P, Error, SO> slots::SimpleSlotWorker<B> for AuraWorker<C, E
218218
self.block_import.clone()
219219
}
220220

221-
fn epoch_data(&self, block: &B::Hash) -> Result<Self::EpochData, consensus_common::Error> {
222-
authorities(self.client.as_ref(), &BlockId::Hash(*block))
221+
fn epoch_data(&self, header: &B::Header, _slot_number: u64) -> Result<Self::EpochData, consensus_common::Error> {
222+
authorities(self.client.as_ref(), &BlockId::Hash(header.hash()))
223223
}
224224

225225
fn authorities_len(&self, epoch_data: &Self::EpochData) -> usize {
@@ -741,7 +741,7 @@ mod tests {
741741
}
742742
}
743743

744-
fn make_verifier(&self, client: PeersClient, _cfg: &ProtocolConfig)
744+
fn make_verifier(&self, client: PeersClient, _cfg: &ProtocolConfig, _peer_data: &())
745745
-> Self::Verifier
746746
{
747747
match client {

core/consensus/babe/primitives/src/digest.rs

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,10 @@
1717
//! Private implementation details of BABE digests.
1818
1919
#[cfg(feature = "std")]
20-
use super::AuthoritySignature;
21-
#[cfg(feature = "std")]
22-
use super::{BABE_ENGINE_ID, Epoch};
20+
use super::{BABE_ENGINE_ID, AuthoritySignature};
2321
#[cfg(not(feature = "std"))]
2422
use super::{VRF_OUTPUT_LENGTH, VRF_PROOF_LENGTH};
25-
use super::{AuthorityIndex, BabeBlockWeight, SlotNumber};
23+
use super::{AuthorityId, AuthorityIndex, SlotNumber, BabeAuthorityWeight};
2624
#[cfg(feature = "std")]
2725
use sr_primitives::{DigestItem, generic::OpaqueDigestItemId};
2826
#[cfg(feature = "std")]
@@ -35,6 +33,8 @@ use schnorrkel::{
3533
SignatureError, errors::MultiSignatureStage,
3634
vrf::{VRFProof, VRFOutput, VRF_OUTPUT_LENGTH, VRF_PROOF_LENGTH}
3735
};
36+
use rstd::vec::Vec;
37+
3838

3939
/// A BABE pre-runtime digest. This contains all data required to validate a
4040
/// block and for the BABE runtime module. Slots can be assigned to a primary
@@ -52,17 +52,13 @@ pub enum BabePreDigest {
5252
authority_index: super::AuthorityIndex,
5353
/// Slot number
5454
slot_number: SlotNumber,
55-
/// Chain weight (measured in number of Primary blocks)
56-
weight: BabeBlockWeight,
5755
},
5856
/// A secondary deterministic slot assignment.
5957
Secondary {
6058
/// Authority index
6159
authority_index: super::AuthorityIndex,
6260
/// Slot number
6361
slot_number: SlotNumber,
64-
/// Chain weight (measured in number of Primary blocks)
65-
weight: BabeBlockWeight,
6662
},
6763
}
6864

@@ -84,11 +80,12 @@ impl BabePreDigest {
8480
}
8581
}
8682

87-
/// Returns the weight of the pre digest.
88-
pub fn weight(&self) -> BabeBlockWeight {
83+
/// Returns the weight _added_ by this digest, not the cumulative weight
84+
/// of the chain.
85+
pub fn added_weight(&self) -> crate::BabeBlockWeight {
8986
match self {
90-
BabePreDigest::Primary { weight, .. } => *weight,
91-
BabePreDigest::Secondary { weight, .. } => *weight,
87+
BabePreDigest::Primary { .. } => 1,
88+
BabePreDigest::Secondary { .. } => 0,
9289
}
9390
}
9491
}
@@ -100,26 +97,29 @@ pub const BABE_VRF_PREFIX: &'static [u8] = b"substrate-babe-vrf";
10097
#[derive(Copy, Clone, Encode, Decode)]
10198
pub enum RawBabePreDigest {
10299
/// A primary VRF-based slot assignment.
100+
#[codec(index = "1")]
103101
Primary {
104102
/// Authority index
105103
authority_index: AuthorityIndex,
106104
/// Slot number
107105
slot_number: SlotNumber,
108-
/// Chain weight (measured in number of Primary blocks)
109-
weight: BabeBlockWeight,
110106
/// VRF output
111107
vrf_output: [u8; VRF_OUTPUT_LENGTH],
112108
/// VRF proof
113109
vrf_proof: [u8; VRF_PROOF_LENGTH],
114110
},
115111
/// A secondary deterministic slot assignment.
112+
#[codec(index = "2")]
116113
Secondary {
117114
/// Authority index
115+
///
116+
/// This is not strictly-speaking necessary, since the secondary slots
117+
/// are assigned based on slot number and epoch randomness. But including
118+
/// it makes things easier for higher-level users of the chain data to
119+
/// be aware of the author of a secondary-slot block.
118120
authority_index: AuthorityIndex,
119121
/// Slot number
120122
slot_number: SlotNumber,
121-
/// Chain weight (measured in number of Primary blocks)
122-
weight: BabeBlockWeight,
123123
},
124124
}
125125

@@ -142,25 +142,21 @@ impl Encode for BabePreDigest {
142142
vrf_proof,
143143
authority_index,
144144
slot_number,
145-
weight,
146145
} => {
147146
RawBabePreDigest::Primary {
148147
vrf_output: *vrf_output.as_bytes(),
149148
vrf_proof: vrf_proof.to_bytes(),
150149
authority_index: *authority_index,
151150
slot_number: *slot_number,
152-
weight: *weight,
153151
}
154152
},
155153
BabePreDigest::Secondary {
156154
authority_index,
157155
slot_number,
158-
weight,
159156
} => {
160157
RawBabePreDigest::Secondary {
161158
authority_index: *authority_index,
162159
slot_number: *slot_number,
163-
weight: *weight,
164160
}
165161
},
166162
};
@@ -176,7 +172,7 @@ impl codec::EncodeLike for BabePreDigest {}
176172
impl Decode for BabePreDigest {
177173
fn decode<R: Input>(i: &mut R) -> Result<Self, Error> {
178174
let pre_digest = match Decode::decode(i)? {
179-
RawBabePreDigest::Primary { vrf_output, vrf_proof, authority_index, slot_number, weight } => {
175+
RawBabePreDigest::Primary { vrf_output, vrf_proof, authority_index, slot_number } => {
180176
// Verify (at compile time) that the sizes in babe_primitives are correct
181177
let _: [u8; super::VRF_OUTPUT_LENGTH] = vrf_output;
182178
let _: [u8; super::VRF_PROOF_LENGTH] = vrf_proof;
@@ -186,18 +182,29 @@ impl Decode for BabePreDigest {
186182
vrf_output: VRFOutput::from_bytes(&vrf_output).map_err(convert_error)?,
187183
authority_index,
188184
slot_number,
189-
weight,
190185
}
191186
},
192-
RawBabePreDigest::Secondary { authority_index, slot_number, weight } => {
193-
BabePreDigest::Secondary { authority_index, slot_number, weight }
187+
RawBabePreDigest::Secondary { authority_index, slot_number } => {
188+
BabePreDigest::Secondary { authority_index, slot_number }
194189
},
195190
};
196191

197192
Ok(pre_digest)
198193
}
199194
}
200195

196+
/// Information about the next epoch. This is broadcast in the first block
197+
/// of the epoch.
198+
#[derive(Decode, Encode, Default, PartialEq, Eq, Clone)]
199+
#[cfg_attr(any(feature = "std", test), derive(Debug))]
200+
pub struct NextEpochDescriptor {
201+
/// The authorities.
202+
pub authorities: Vec<(AuthorityId, BabeAuthorityWeight)>,
203+
204+
/// The value of randomness to use for the slot-assignment.
205+
pub randomness: [u8; VRF_OUTPUT_LENGTH],
206+
}
207+
201208
/// A digest item which is usable with BABE consensus.
202209
#[cfg(feature = "std")]
203210
pub trait CompatibleDigestItem: Sized {
@@ -214,7 +221,7 @@ pub trait CompatibleDigestItem: Sized {
214221
fn as_babe_seal(&self) -> Option<AuthoritySignature>;
215222

216223
/// If this item is a BABE epoch, return it.
217-
fn as_babe_epoch(&self) -> Option<Epoch>;
224+
fn as_next_epoch_descriptor(&self) -> Option<NextEpochDescriptor>;
218225
}
219226

220227
#[cfg(feature = "std")]
@@ -237,8 +244,12 @@ impl<Hash> CompatibleDigestItem for DigestItem<Hash> where
237244
self.try_to(OpaqueDigestItemId::Seal(&BABE_ENGINE_ID))
238245
}
239246

240-
fn as_babe_epoch(&self) -> Option<Epoch> {
247+
fn as_next_epoch_descriptor(&self) -> Option<NextEpochDescriptor> {
241248
self.try_to(OpaqueDigestItemId::Consensus(&BABE_ENGINE_ID))
249+
.and_then(|x: super::ConsensusLog| match x {
250+
super::ConsensusLog::NextEpochData(n) => Some(n),
251+
_ => None,
252+
})
242253
}
243254
}
244255

0 commit comments

Comments
 (0)