polkadot_node_primitives/approval/
mod.rs1pub mod criteria;
21
22pub mod time;
24
25pub mod v1 {
27 use sp_consensus_babe as babe_primitives;
28 pub use sp_consensus_babe::{
29 Randomness, Slot, VrfPreOutput, VrfProof, VrfSignature, VrfTranscript,
30 };
31
32 use codec::{Decode, Encode};
33 use polkadot_primitives::{
34 BlockNumber, CandidateHash, CoreIndex, GroupIndex, Hash, Header, SessionIndex,
35 };
36 use sp_application_crypto::ByteArray;
37
38 pub type DelayTranche = u32;
41
42 pub const RELAY_VRF_STORY_CONTEXT: &[u8] = b"A&V RC-VRF";
45
46 pub const RELAY_VRF_MODULO_CONTEXT: &[u8] = b"A&V MOD";
48
49 pub const RELAY_VRF_DELAY_CONTEXT: &[u8] = b"A&V DELAY";
51
52 pub const ASSIGNED_CORE_CONTEXT: &[u8] = b"A&V ASSIGNED";
54
55 pub const CORE_RANDOMNESS_CONTEXT: &[u8] = b"A&V CORE";
57
58 pub const TRANCHE_RANDOMNESS_CONTEXT: &[u8] = b"A&V TRANCHE";
60
61 #[derive(Debug, Clone, Encode, Decode, PartialEq)]
64 pub struct RelayVRFStory(pub [u8; 32]);
65
66 #[derive(Debug, Clone)]
68 pub struct BlockApprovalMeta {
69 pub hash: Hash,
71 pub number: BlockNumber,
73 pub parent_hash: Hash,
75 pub candidates: Vec<(CandidateHash, CoreIndex, GroupIndex)>,
78 pub slot: Slot,
80 pub session: SessionIndex,
82 pub vrf_story: RelayVRFStory,
84 }
85
86 #[derive(Debug, thiserror::Error)]
88 #[allow(missing_docs)]
89 pub enum ApprovalError {
90 #[error("Schnorrkel signature error")]
91 SchnorrkelSignature(schnorrkel::errors::SignatureError),
92 #[error("Authority index {0} out of bounds")]
93 AuthorityOutOfBounds(usize),
94 }
95
96 pub struct UnsafeVRFPreOutput {
98 vrf_pre_output: VrfPreOutput,
99 slot: Slot,
100 authority_index: u32,
101 }
102
103 impl UnsafeVRFPreOutput {
104 pub fn slot(&self) -> Slot {
106 self.slot
107 }
108
109 pub fn compute_randomness(
111 self,
112 authorities: &[(babe_primitives::AuthorityId, babe_primitives::BabeAuthorityWeight)],
113 randomness: &babe_primitives::Randomness,
114 epoch_index: u64,
115 ) -> Result<RelayVRFStory, ApprovalError> {
116 let author = match authorities.get(self.authority_index as usize) {
117 None => return Err(ApprovalError::AuthorityOutOfBounds(self.authority_index as _)),
118 Some(x) => &x.0,
119 };
120
121 let pubkey = schnorrkel::PublicKey::from_bytes(author.as_slice())
122 .map_err(ApprovalError::SchnorrkelSignature)?;
123
124 let transcript =
125 sp_consensus_babe::make_vrf_transcript(randomness, self.slot, epoch_index);
126
127 let inout = self
128 .vrf_pre_output
129 .0
130 .attach_input_hash(&pubkey, transcript.0)
131 .map_err(ApprovalError::SchnorrkelSignature)?;
132 Ok(RelayVRFStory(inout.make_bytes(super::v1::RELAY_VRF_STORY_CONTEXT)))
133 }
134 }
135
136 pub fn babe_unsafe_vrf_info(header: &Header) -> Option<UnsafeVRFPreOutput> {
142 use babe_primitives::digests::CompatibleDigestItem;
143
144 for digest in &header.digest.logs {
145 if let Some(pre) = digest.as_babe_pre_digest() {
146 let slot = pre.slot();
147 let authority_index = pre.authority_index();
148
149 return pre.vrf_signature().map(|sig| UnsafeVRFPreOutput {
150 vrf_pre_output: sig.pre_output.clone(),
151 slot,
152 authority_index,
153 });
154 }
155 }
156
157 None
158 }
159}
160
161pub mod v2 {
163 use codec::{Decode, Encode};
164 pub use sp_consensus_babe::{
165 Randomness, Slot, VrfPreOutput, VrfProof, VrfSignature, VrfTranscript,
166 };
167 use std::ops::BitOr;
168
169 use bitvec::{prelude::Lsb0, vec::BitVec};
170 use polkadot_primitives::{
171 CandidateIndex, CoreIndex, Hash, ValidatorIndex, ValidatorSignature,
172 };
173
174 pub const CORE_RANDOMNESS_CONTEXT: &[u8] = b"A&V CORE v2";
176 pub const ASSIGNED_CORE_CONTEXT: &[u8] = b"A&V ASSIGNED v2";
178 pub const RELAY_VRF_MODULO_CONTEXT: &[u8] = b"A&V MOD v2";
180 #[derive(Clone, Debug, Encode, Decode, Hash, PartialEq, Eq)]
182 pub struct Bitfield<T>(BitVec<u8, bitvec::order::Lsb0>, std::marker::PhantomData<T>);
183
184 pub type CandidateBitfield = Bitfield<CandidateIndex>;
187 pub type CoreBitfield = Bitfield<CoreIndex>;
189
190 #[derive(Debug)]
192 pub enum BitfieldError {
193 NullAssignment,
195 }
196
197 #[cfg_attr(test, derive(PartialEq, Clone))]
199 pub struct BitIndex(pub usize);
200
201 pub trait AsBitIndex {
203 fn as_bit_index(&self) -> BitIndex;
205 }
206
207 impl<T> Bitfield<T> {
208 pub fn bit_at(&self, index: BitIndex) -> bool {
211 if self.0.len() <= index.0 {
212 false
213 } else {
214 self.0[index.0]
215 }
216 }
217
218 pub fn len(&self) -> usize {
220 self.0.len()
221 }
222
223 pub fn count_ones(&self) -> usize {
225 self.0.count_ones()
226 }
227
228 pub fn first_one(&self) -> Option<usize> {
230 self.0.first_one()
231 }
232
233 pub fn iter_ones(&self) -> bitvec::slice::IterOnes<'_, u8, bitvec::order::Lsb0> {
235 self.0.iter_ones()
236 }
237
238 pub fn inner_mut(&mut self) -> &mut BitVec<u8, bitvec::order::Lsb0> {
240 &mut self.0
241 }
242
243 pub fn into_inner(self) -> BitVec<u8, bitvec::order::Lsb0> {
245 self.0
246 }
247 }
248
249 impl AsBitIndex for CandidateIndex {
250 fn as_bit_index(&self) -> BitIndex {
251 BitIndex(*self as usize)
252 }
253 }
254
255 impl AsBitIndex for CoreIndex {
256 fn as_bit_index(&self) -> BitIndex {
257 BitIndex(self.0 as usize)
258 }
259 }
260
261 impl AsBitIndex for usize {
262 fn as_bit_index(&self) -> BitIndex {
263 BitIndex(*self)
264 }
265 }
266
267 impl<T> From<T> for Bitfield<T>
268 where
269 T: AsBitIndex,
270 {
271 fn from(value: T) -> Self {
272 Self(
273 {
274 let mut bv = bitvec::bitvec![u8, Lsb0; 0; value.as_bit_index().0 + 1];
275 bv.set(value.as_bit_index().0, true);
276 bv
277 },
278 Default::default(),
279 )
280 }
281 }
282
283 impl<T> TryFrom<Vec<T>> for Bitfield<T>
284 where
285 T: Into<Bitfield<T>>,
286 {
287 type Error = BitfieldError;
288
289 fn try_from(mut value: Vec<T>) -> Result<Self, Self::Error> {
290 if value.is_empty() {
291 return Err(BitfieldError::NullAssignment);
292 }
293
294 let initial_bitfield =
295 value.pop().expect("Just checked above it's not empty; qed").into();
296
297 Ok(Self(
298 value.into_iter().fold(initial_bitfield.0, |initial_bitfield, element| {
299 let mut bitfield: Bitfield<T> = element.into();
300 bitfield
301 .0
302 .resize(std::cmp::max(initial_bitfield.len(), bitfield.0.len()), false);
303 bitfield.0.bitor(initial_bitfield)
304 }),
305 Default::default(),
306 ))
307 }
308 }
309
310 #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
315 pub enum AssignmentCertKindV2 {
316 #[codec(index = 0)]
321 RelayVRFModuloCompact {
322 core_bitfield: CoreBitfield,
324 },
325 #[codec(index = 1)]
330 RelayVRFDelay {
331 core_index: CoreIndex,
333 },
334 }
335
336 #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
338 pub struct AssignmentCertV2 {
339 pub kind: AssignmentCertKindV2,
341 pub vrf: VrfSignature,
343 }
344
345 #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
348 pub struct IndirectAssignmentCertV2 {
349 pub block_hash: Hash,
351 pub validator: ValidatorIndex,
353 pub cert: AssignmentCertV2,
355 }
356
357 #[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
362 pub struct IndirectSignedApprovalVoteV2 {
363 pub block_hash: Hash,
365 pub candidate_indices: CandidateBitfield,
367 pub validator: ValidatorIndex,
369 pub signature: ValidatorSignature,
371 }
372}
373
374#[cfg(test)]
375mod test {
376 use super::v2::{BitIndex, Bitfield};
377
378 use polkadot_primitives::{CandidateIndex, CoreIndex};
379
380 #[test]
381 fn test_assignment_bitfield_from_vec() {
382 let candidate_indices = vec![1u32, 7, 3, 10, 45, 8, 200, 2];
383 let max_index = *candidate_indices.iter().max().unwrap();
384 let bitfield = Bitfield::try_from(candidate_indices.clone()).unwrap();
385 let candidate_indices =
386 candidate_indices.into_iter().map(|i| BitIndex(i as usize)).collect::<Vec<_>>();
387
388 for index in candidate_indices.clone() {
390 assert!(bitfield.bit_at(index));
391 }
392
393 for index in 0..max_index {
395 if candidate_indices.contains(&BitIndex(index as usize)) {
396 continue;
397 }
398 assert!(!bitfield.bit_at(BitIndex(index as usize)));
399 }
400 }
401
402 #[test]
403 fn test_assignment_bitfield_invariant_msb() {
404 let core_indices = vec![CoreIndex(1), CoreIndex(3), CoreIndex(10), CoreIndex(20)];
405 let mut bitfield = Bitfield::try_from(core_indices.clone()).unwrap();
406 assert!(bitfield.inner_mut().pop().unwrap());
407
408 for i in 0..1024 {
409 assert!(Bitfield::try_from(CoreIndex(i)).unwrap().inner_mut().pop().unwrap());
410 assert!(Bitfield::try_from(i).unwrap().inner_mut().pop().unwrap());
411 }
412 }
413
414 #[test]
415 fn test_assignment_bitfield_basic() {
416 let bitfield = Bitfield::try_from(CoreIndex(0)).unwrap();
417 assert!(bitfield.bit_at(BitIndex(0)));
418 assert!(!bitfield.bit_at(BitIndex(1)));
419 assert_eq!(bitfield.len(), 1);
420
421 let mut bitfield = Bitfield::try_from(20 as CandidateIndex).unwrap();
422 assert!(bitfield.bit_at(BitIndex(20)));
423 assert_eq!(bitfield.inner_mut().count_ones(), 1);
424 assert_eq!(bitfield.len(), 21);
425 }
426
427 #[test]
428 fn assignment_cert_kind_v2_codec_indices_are_stable() {
429 use super::v2::{AssignmentCertKindV2, CoreBitfield};
430 use codec::Encode;
431
432 let compact = AssignmentCertKindV2::RelayVRFModuloCompact {
437 core_bitfield: CoreBitfield::try_from(vec![CoreIndex(0)]).unwrap(),
438 };
439 let delay = AssignmentCertKindV2::RelayVRFDelay { core_index: CoreIndex(0) };
440
441 assert_eq!(compact.encode()[0], 0);
442 assert_eq!(delay.encode()[0], 1);
443 }
444}