1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
// This file is part of Substrate. // Copyright (C) 2019-2020 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Consensus extension module for BABE consensus. Collects on-chain randomness //! from VRF outputs and manages epoch transitions. #![cfg_attr(not(feature = "std"), no_std)] #![warn(unused_must_use, unsafe_code, unused_variables, unused_must_use)] use codec::{Decode, Encode}; use frame_support::{ decl_error, decl_module, decl_storage, traits::{FindAuthor, Get, KeyOwnerProofSystem, Randomness as RandomnessT}, weights::Weight, Parameter, }; use frame_system::{ensure_none, ensure_signed}; use sp_application_crypto::Public; use sp_runtime::{ generic::DigestItem, traits::{Hash, IsMember, One, SaturatedConversion, Saturating}, ConsensusEngineId, KeyTypeId, }; use sp_session::{GetSessionNumber, GetValidatorCount}; use sp_std::{prelude::*, result}; use sp_timestamp::OnTimestampSet; use sp_consensus_babe::{ digests::{NextConfigDescriptor, NextEpochDescriptor, PreDigest}, inherents::{BabeInherentData, INHERENT_IDENTIFIER}, BabeAuthorityWeight, ConsensusLog, EquivocationProof, SlotNumber, BABE_ENGINE_ID, }; use sp_consensus_vrf::schnorrkel; use sp_inherents::{InherentData, InherentIdentifier, MakeFatalError, ProvideInherent}; pub use sp_consensus_babe::{AuthorityId, PUBLIC_KEY_LENGTH, RANDOMNESS_LENGTH, VRF_OUTPUT_LENGTH}; mod equivocation; #[cfg(any(feature = "runtime-benchmarks", test))] mod benchmarking; #[cfg(all(feature = "std", test))] mod mock; #[cfg(all(feature = "std", test))] mod tests; pub use equivocation::{BabeEquivocationOffence, EquivocationHandler, HandleEquivocation}; pub trait Trait: pallet_timestamp::Trait { /// The amount of time, in slots, that each epoch should last. type EpochDuration: Get<SlotNumber>; /// The expected average block time at which BABE should be creating /// blocks. Since BABE is probabilistic it is not trivial to figure out /// what the expected average block time should be based on the slot /// duration and the security parameter `c` (where `1 - c` represents /// the probability of a slot being empty). type ExpectedBlockTime: Get<Self::Moment>; /// BABE requires some logic to be triggered on every block to query for whether an epoch /// has ended and to perform the transition to the next epoch. /// /// Typically, the `ExternalTrigger` type should be used. An internal trigger should only be used /// when no other module is responsible for changing authority set. type EpochChangeTrigger: EpochChangeTrigger; /// The proof of key ownership, used for validating equivocation reports. /// The proof must include the session index and validator count of the /// session at which the equivocation occurred. type KeyOwnerProof: Parameter + GetSessionNumber + GetValidatorCount; /// The identification of a key owner, used when reporting equivocations. type KeyOwnerIdentification: Parameter; /// A system for proving ownership of keys, i.e. that a given key was part /// of a validator set, needed for validating equivocation reports. type KeyOwnerProofSystem: KeyOwnerProofSystem< (KeyTypeId, AuthorityId), Proof = Self::KeyOwnerProof, IdentificationTuple = Self::KeyOwnerIdentification, >; /// The equivocation handling subsystem, defines methods to report an /// offence (after the equivocation has been validated) and for submitting a /// transaction to report an equivocation (from an offchain context). /// NOTE: when enabling equivocation handling (i.e. this type isn't set to /// `()`) you must use this pallet's `ValidateUnsigned` in the runtime /// definition. type HandleEquivocation: HandleEquivocation<Self>; } /// Trigger an epoch change, if any should take place. pub trait EpochChangeTrigger { /// Trigger an epoch change, if any should take place. This should be called /// during every block, after initialization is done. fn trigger<T: Trait>(now: T::BlockNumber); } /// A type signifying to BABE that an external trigger /// for epoch changes (e.g. pallet-session) is used. pub struct ExternalTrigger; impl EpochChangeTrigger for ExternalTrigger { fn trigger<T: Trait>(_: T::BlockNumber) { } // nothing - trigger is external. } /// A type signifying to BABE that it should perform epoch changes /// with an internal trigger, recycling the same authorities forever. pub struct SameAuthoritiesForever; impl EpochChangeTrigger for SameAuthoritiesForever { fn trigger<T: Trait>(now: T::BlockNumber) { if <Module<T>>::should_epoch_change(now) { let authorities = <Module<T>>::authorities(); let next_authorities = authorities.clone(); <Module<T>>::enact_epoch_change(authorities, next_authorities); } } } const UNDER_CONSTRUCTION_SEGMENT_LENGTH: usize = 256; type MaybeRandomness = Option<schnorrkel::Randomness>; decl_error! { pub enum Error for Module<T: Trait> { /// An equivocation proof provided as part of an equivocation report is invalid. InvalidEquivocationProof, /// A key ownership proof provided as part of an equivocation report is invalid. InvalidKeyOwnershipProof, /// A given equivocation report is valid but already previously reported. DuplicateOffenceReport, } } decl_storage! { trait Store for Module<T: Trait> as Babe { /// Current epoch index. pub EpochIndex get(fn epoch_index): u64; /// Current epoch authorities. pub Authorities get(fn authorities): Vec<(AuthorityId, BabeAuthorityWeight)>; /// The slot at which the first epoch actually started. This is 0 /// until the first block of the chain. pub GenesisSlot get(fn genesis_slot): u64; /// Current slot number. pub CurrentSlot get(fn current_slot): u64; /// The epoch randomness for the *current* epoch. /// /// # Security /// /// This MUST NOT be used for gambling, as it can be influenced by a /// malicious validator in the short term. It MAY be used in many /// cryptographic protocols, however, so long as one remembers that this /// (like everything else on-chain) it is public. For example, it can be /// used where a number is needed that cannot have been chosen by an /// adversary, for purposes such as public-coin zero-knowledge proofs. // NOTE: the following fields don't use the constants to define the // array size because the metadata API currently doesn't resolve the // variable to its underlying value. pub Randomness get(fn randomness): schnorrkel::Randomness; /// Next epoch configuration, if changed. NextEpochConfig: Option<NextConfigDescriptor>; /// Next epoch randomness. NextRandomness: schnorrkel::Randomness; /// Randomness under construction. /// /// We make a tradeoff between storage accesses and list length. /// We store the under-construction randomness in segments of up to /// `UNDER_CONSTRUCTION_SEGMENT_LENGTH`. /// /// Once a segment reaches this length, we begin the next one. /// We reset all segments and return to `0` at the beginning of every /// epoch. SegmentIndex build(|_| 0): u32; /// TWOX-NOTE: `SegmentIndex` is an increasing integer, so this is okay. UnderConstruction: map hasher(twox_64_concat) u32 => Vec<schnorrkel::Randomness>; /// Temporary value (cleared at block finalization) which is `Some` /// if per-block initialization has already been called for current block. Initialized get(fn initialized): Option<MaybeRandomness>; /// How late the current block is compared to its parent. /// /// This entry is populated as part of block execution and is cleaned up /// on block finalization. Querying this storage entry outside of block /// execution context should always yield zero. Lateness get(fn lateness): T::BlockNumber; } add_extra_genesis { config(authorities): Vec<(AuthorityId, BabeAuthorityWeight)>; build(|config| Module::<T>::initialize_authorities(&config.authorities)) } } decl_module! { /// The BABE Pallet pub struct Module<T: Trait> for enum Call where origin: T::Origin { /// The number of **slots** that an epoch takes. We couple sessions to /// epochs, i.e. we start a new session once the new epoch begins. const EpochDuration: u64 = T::EpochDuration::get(); /// The expected average block time at which BABE should be creating /// blocks. Since BABE is probabilistic it is not trivial to figure out /// what the expected average block time should be based on the slot /// duration and the security parameter `c` (where `1 - c` represents /// the probability of a slot being empty). const ExpectedBlockTime: T::Moment = T::ExpectedBlockTime::get(); /// Initialization fn on_initialize(now: T::BlockNumber) -> Weight { Self::do_initialize(now); 0 } /// Block finalization fn on_finalize() { // at the end of the block, we can safely include the new VRF output // from this block into the under-construction randomness. If we've determined // that this block was the first in a new epoch, the changeover logic has // already occurred at this point, so the under-construction randomness // will only contain outputs from the right epoch. if let Some(Some(randomness)) = Initialized::take() { Self::deposit_randomness(&randomness); } // remove temporary "environment" entry from storage Lateness::<T>::kill(); } /// Report authority equivocation/misbehavior. This method will verify /// the equivocation proof and validate the given key ownership proof /// against the extracted offender. If both are valid, the offence will /// be reported. #[weight = weight::weight_for_report_equivocation::<T>()] fn report_equivocation( origin, equivocation_proof: EquivocationProof<T::Header>, key_owner_proof: T::KeyOwnerProof, ) { let reporter = ensure_signed(origin)?; Self::do_report_equivocation( Some(reporter), equivocation_proof, key_owner_proof, )?; } /// Report authority equivocation/misbehavior. This method will verify /// the equivocation proof and validate the given key ownership proof /// against the extracted offender. If both are valid, the offence will /// be reported. /// This extrinsic must be called unsigned and it is expected that only /// block authors will call it (validated in `ValidateUnsigned`), as such /// if the block author is defined it will be defined as the equivocation /// reporter. #[weight = weight::weight_for_report_equivocation::<T>()] fn report_equivocation_unsigned( origin, equivocation_proof: EquivocationProof<T::Header>, key_owner_proof: T::KeyOwnerProof, ) { ensure_none(origin)?; Self::do_report_equivocation( T::HandleEquivocation::block_author(), equivocation_proof, key_owner_proof, )?; } } } mod weight { use frame_support::{ traits::Get, weights::{constants::WEIGHT_PER_MICROS, Weight}, }; pub fn weight_for_report_equivocation<T: super::Trait>() -> Weight { // checking membership proof (35 * WEIGHT_PER_MICROS) .saturating_add(T::DbWeight::get().reads(5)) // check equivocation proof .saturating_add(110 * WEIGHT_PER_MICROS) // report offence .saturating_add(110 * WEIGHT_PER_MICROS) // worst case we are considering is that the given offender // is backed by 200 nominators .saturating_add(T::DbWeight::get().reads(14 + 3 * 200)) .saturating_add(T::DbWeight::get().writes(10 + 3 * 200)) } } impl<T: Trait> RandomnessT<<T as frame_system::Trait>::Hash> for Module<T> { /// Some BABE blocks have VRF outputs where the block producer has exactly one bit of influence, /// either they make the block or they do not make the block and thus someone else makes the /// next block. Yet, this randomness is not fresh in all BABE blocks. /// /// If that is an insufficient security guarantee then two things can be used to improve this /// randomness: /// /// - Name, in advance, the block number whose random value will be used; ensure your module /// retains a buffer of previous random values for its subject and then index into these in /// order to obviate the ability of your user to look up the parent hash and choose when to /// transact based upon it. /// - Require your user to first commit to an additional value by first posting its hash. /// Require them to reveal the value to determine the final result, hashing it with the /// output of this random function. This reduces the ability of a cabal of block producers /// from conspiring against individuals. fn random(subject: &[u8]) -> T::Hash { let mut subject = subject.to_vec(); subject.reserve(VRF_OUTPUT_LENGTH); subject.extend_from_slice(&Self::randomness()[..]); <T as frame_system::Trait>::Hashing::hash(&subject[..]) } } /// A BABE public key pub type BabeKey = [u8; PUBLIC_KEY_LENGTH]; impl<T: Trait> FindAuthor<u32> for Module<T> { fn find_author<'a, I>(digests: I) -> Option<u32> where I: 'a + IntoIterator<Item=(ConsensusEngineId, &'a [u8])> { for (id, mut data) in digests.into_iter() { if id == BABE_ENGINE_ID { let pre_digest: PreDigest = PreDigest::decode(&mut data).ok()?; return Some(pre_digest.authority_index()) } } return None; } } impl<T: Trait> IsMember<AuthorityId> for Module<T> { fn is_member(authority_id: &AuthorityId) -> bool { <Module<T>>::authorities() .iter() .any(|id| &id.0 == authority_id) } } impl<T: Trait> pallet_session::ShouldEndSession<T::BlockNumber> for Module<T> { fn should_end_session(now: T::BlockNumber) -> bool { // it might be (and it is in current implementation) that session module is calling // should_end_session() from it's own on_initialize() handler // => because pallet_session on_initialize() is called earlier than ours, let's ensure // that we have synced with digest before checking if session should be ended. Self::do_initialize(now); Self::should_epoch_change(now) } } impl<T: Trait> Module<T> { /// Determine the BABE slot duration based on the Timestamp module configuration. pub fn slot_duration() -> T::Moment { // we double the minimum block-period so each author can always propose within // the majority of their slot. <T as pallet_timestamp::Trait>::MinimumPeriod::get().saturating_mul(2.into()) } /// Determine whether an epoch change should take place at this block. /// Assumes that initialization has already taken place. pub fn should_epoch_change(now: T::BlockNumber) -> bool { // The epoch has technically ended during the passage of time // between this block and the last, but we have to "end" the epoch now, // since there is no earlier possible block we could have done it. // // The exception is for block 1: the genesis has slot 0, so we treat // epoch 0 as having started at the slot of block 1. We want to use // the same randomness and validator set as signalled in the genesis, // so we don't rotate the epoch. now != One::one() && { let diff = CurrentSlot::get().saturating_sub(Self::current_epoch_start()); diff >= T::EpochDuration::get() } } /// Return the _best guess_ block number, at which the next epoch change is predicted to happen. /// /// Returns None if the prediction is in the past; This implies an error internally in the Babe /// and should not happen under normal circumstances. /// /// In other word, this is only accurate if no slots are missed. Given missed slots, the slot /// number will grow while the block number will not. Hence, the result can be interpreted as an /// upper bound. // -------------- IMPORTANT NOTE -------------- // This implementation is linked to how [`should_epoch_change`] is working. This might need to // be updated accordingly, if the underlying mechanics of slot and epochs change. // // WEIGHT NOTE: This function is tied to the weight of `EstimateNextSessionRotation`. If you update // this function, you must also update the corresponding weight. pub fn next_expected_epoch_change(now: T::BlockNumber) -> Option<T::BlockNumber> { let next_slot = Self::current_epoch_start().saturating_add(T::EpochDuration::get()); next_slot .checked_sub(CurrentSlot::get()) .map(|slots_remaining| { // This is a best effort guess. Drifts in the slot/block ratio will cause errors here. let blocks_remaining: T::BlockNumber = slots_remaining.saturated_into(); now.saturating_add(blocks_remaining) }) } /// Plan an epoch config change. The epoch config change is recorded and will be enacted on the /// next call to `enact_epoch_change`. The config will be activated one epoch after. Multiple calls to this /// method will replace any existing planned config change that had not been enacted yet. pub fn plan_config_change( config: NextConfigDescriptor, ) { NextEpochConfig::put(config); } /// DANGEROUS: Enact an epoch change. Should be done on every block where `should_epoch_change` has returned `true`, /// and the caller is the only caller of this function. /// /// Typically, this is not handled directly by the user, but by higher-level validator-set manager logic like /// `pallet-session`. pub fn enact_epoch_change( authorities: Vec<(AuthorityId, BabeAuthorityWeight)>, next_authorities: Vec<(AuthorityId, BabeAuthorityWeight)>, ) { // PRECONDITION: caller has done initialization and is guaranteed // by the session module to be called before this. debug_assert!(Self::initialized().is_some()); // Update epoch index let epoch_index = EpochIndex::get() .checked_add(1) .expect("epoch indices will never reach 2^64 before the death of the universe; qed"); EpochIndex::put(epoch_index); Authorities::put(authorities); // Update epoch randomness. let next_epoch_index = epoch_index .checked_add(1) .expect("epoch indices will never reach 2^64 before the death of the universe; qed"); // Returns randomness for the current epoch and computes the *next* // epoch randomness. let randomness = Self::randomness_change_epoch(next_epoch_index); Randomness::put(randomness); // After we update the current epoch, we signal the *next* epoch change // so that nodes can track changes. let next_randomness = NextRandomness::get(); let next_epoch = NextEpochDescriptor { authorities: next_authorities, randomness: next_randomness, }; Self::deposit_consensus(ConsensusLog::NextEpochData(next_epoch)); if let Some(next_config) = NextEpochConfig::take() { Self::deposit_consensus(ConsensusLog::NextConfigData(next_config)); } } // finds the start slot of the current epoch. only guaranteed to // give correct results after `do_initialize` of the first block // in the chain (as its result is based off of `GenesisSlot`). pub fn current_epoch_start() -> SlotNumber { (EpochIndex::get() * T::EpochDuration::get()) + GenesisSlot::get() } fn deposit_consensus<U: Encode>(new: U) { let log: DigestItem<T::Hash> = DigestItem::Consensus(BABE_ENGINE_ID, new.encode()); <frame_system::Module<T>>::deposit_log(log.into()) } fn deposit_randomness(randomness: &schnorrkel::Randomness) { let segment_idx = <SegmentIndex>::get(); let mut segment = <UnderConstruction>::get(&segment_idx); if segment.len() < UNDER_CONSTRUCTION_SEGMENT_LENGTH { // push onto current segment: not full. segment.push(*randomness); <UnderConstruction>::insert(&segment_idx, &segment); } else { // move onto the next segment and update the index. let segment_idx = segment_idx + 1; <UnderConstruction>::insert(&segment_idx, &vec![randomness.clone()]); <SegmentIndex>::put(&segment_idx); } } fn do_initialize(now: T::BlockNumber) { // since do_initialize can be called twice (if session module is present) // => let's ensure that we only modify the storage once per block let initialized = Self::initialized().is_some(); if initialized { return; } let maybe_pre_digest: Option<PreDigest> = <frame_system::Module<T>>::digest() .logs .iter() .filter_map(|s| s.as_pre_runtime()) .filter_map(|(id, mut data)| if id == BABE_ENGINE_ID { PreDigest::decode(&mut data).ok() } else { None }) .next(); let maybe_randomness: Option<schnorrkel::Randomness> = maybe_pre_digest.and_then(|digest| { // on the first non-zero block (i.e. block #1) // this is where the first epoch (epoch #0) actually starts. // we need to adjust internal storage accordingly. if GenesisSlot::get() == 0 { GenesisSlot::put(digest.slot_number()); debug_assert_ne!(GenesisSlot::get(), 0); // deposit a log because this is the first block in epoch #0 // we use the same values as genesis because we haven't collected any // randomness yet. let next = NextEpochDescriptor { authorities: Self::authorities(), randomness: Self::randomness(), }; Self::deposit_consensus(ConsensusLog::NextEpochData(next)) } // the slot number of the current block being initialized let current_slot = digest.slot_number(); // how many slots were skipped between current and last block let lateness = current_slot.saturating_sub(CurrentSlot::get() + 1); let lateness = T::BlockNumber::from(lateness as u32); Lateness::<T>::put(lateness); CurrentSlot::put(current_slot); if let PreDigest::Primary(primary) = 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. // // Reconstruct the bytes of VRFInOut using the authority id. Authorities::get() .get(primary.authority_index as usize) .and_then(|author| { schnorrkel::PublicKey::from_bytes(author.0.as_slice()).ok() }) .and_then(|pubkey| { let transcript = sp_consensus_babe::make_transcript( &Self::randomness(), current_slot, EpochIndex::get(), ); primary.vrf_output.0.attach_input_hash( &pubkey, transcript ).ok() }) .map(|inout| { inout.make_bytes(&sp_consensus_babe::BABE_VRF_INOUT_CONTEXT) }) } else { None } }); Initialized::put(maybe_randomness); // enact epoch change, if necessary. T::EpochChangeTrigger::trigger::<T>(now) } /// Call this function exactly once when an epoch changes, to update the /// randomness. Returns the new randomness. fn randomness_change_epoch(next_epoch_index: u64) -> schnorrkel::Randomness { let this_randomness = NextRandomness::get(); let segment_idx: u32 = <SegmentIndex>::mutate(|s| sp_std::mem::replace(s, 0)); // overestimate to the segment being full. let rho_size = segment_idx.saturating_add(1) as usize * UNDER_CONSTRUCTION_SEGMENT_LENGTH; let next_randomness = compute_randomness( this_randomness, next_epoch_index, (0..segment_idx).flat_map(|i| <UnderConstruction>::take(&i)), Some(rho_size), ); NextRandomness::put(&next_randomness); this_randomness } fn initialize_authorities(authorities: &[(AuthorityId, BabeAuthorityWeight)]) { if !authorities.is_empty() { assert!(Authorities::get().is_empty(), "Authorities are already initialized!"); Authorities::put(authorities); } } fn do_report_equivocation( reporter: Option<T::AccountId>, equivocation_proof: EquivocationProof<T::Header>, key_owner_proof: T::KeyOwnerProof, ) -> Result<(), Error<T>> { let offender = equivocation_proof.offender.clone(); let slot_number = equivocation_proof.slot_number; // validate the equivocation proof if !sp_consensus_babe::check_equivocation_proof(equivocation_proof) { return Err(Error::InvalidEquivocationProof.into()); } let validator_set_count = key_owner_proof.validator_count(); let session_index = key_owner_proof.session(); let epoch_index = (slot_number.saturating_sub(GenesisSlot::get()) / T::EpochDuration::get()) .saturated_into::<u32>(); // check that the slot number is consistent with the session index // in the key ownership proof (i.e. slot is for that epoch) if epoch_index != session_index { return Err(Error::InvalidKeyOwnershipProof.into()); } // check the membership proof and extract the offender's id let key = (sp_consensus_babe::KEY_TYPE, offender); let offender = T::KeyOwnerProofSystem::check_proof(key, key_owner_proof) .ok_or(Error::InvalidKeyOwnershipProof)?; let offence = BabeEquivocationOffence { slot: slot_number, validator_set_count, offender, session_index, }; let reporters = match reporter { Some(id) => vec![id], None => vec![], }; T::HandleEquivocation::report_offence(reporters, offence) .map_err(|_| Error::DuplicateOffenceReport)?; Ok(()) } /// Submits an extrinsic to report an equivocation. This method will create /// an unsigned extrinsic with a call to `report_equivocation_unsigned` and /// will push the transaction to the pool. Only useful in an offchain /// context. pub fn submit_unsigned_equivocation_report( equivocation_proof: EquivocationProof<T::Header>, key_owner_proof: T::KeyOwnerProof, ) -> Option<()> { T::HandleEquivocation::submit_unsigned_equivocation_report( equivocation_proof, key_owner_proof, ) .ok() } } impl<T: Trait> OnTimestampSet<T::Moment> for Module<T> { fn on_timestamp_set(_moment: T::Moment) { } } impl<T: Trait> frame_support::traits::EstimateNextSessionRotation<T::BlockNumber> for Module<T> { fn estimate_next_session_rotation(now: T::BlockNumber) -> Option<T::BlockNumber> { Self::next_expected_epoch_change(now) } // The validity of this weight depends on the implementation of `estimate_next_session_rotation` fn weight(_now: T::BlockNumber) -> Weight { // Read: Current Slot, Epoch Index, Genesis Slot T::DbWeight::get().reads(3) } } impl<T: Trait> frame_support::traits::Lateness<T::BlockNumber> for Module<T> { fn lateness(&self) -> T::BlockNumber { Self::lateness() } } impl<T: Trait> sp_runtime::BoundToRuntimeAppPublic for Module<T> { type Public = AuthorityId; } impl<T: Trait> pallet_session::OneSessionHandler<T::AccountId> for Module<T> { type Key = AuthorityId; fn on_genesis_session<'a, I: 'a>(validators: I) where I: Iterator<Item=(&'a T::AccountId, AuthorityId)> { let authorities = validators.map(|(_, k)| (k, 1)).collect::<Vec<_>>(); Self::initialize_authorities(&authorities); } fn on_new_session<'a, I: 'a>(_changed: bool, validators: I, queued_validators: I) where I: Iterator<Item=(&'a T::AccountId, AuthorityId)> { let authorities = validators.map(|(_account, k)| { (k, 1) }).collect::<Vec<_>>(); let next_authorities = queued_validators.map(|(_account, k)| { (k, 1) }).collect::<Vec<_>>(); Self::enact_epoch_change(authorities, next_authorities) } fn on_disabled(i: usize) { Self::deposit_consensus(ConsensusLog::OnDisabled(i as u32)) } } // compute randomness for a new epoch. rho is the concatenation of all // VRF outputs in the prior epoch. // // an optional size hint as to how many VRF outputs there were may be provided. fn compute_randomness( last_epoch_randomness: schnorrkel::Randomness, epoch_index: u64, rho: impl Iterator<Item=schnorrkel::Randomness>, rho_size_hint: Option<usize>, ) -> schnorrkel::Randomness { let mut s = Vec::with_capacity(40 + rho_size_hint.unwrap_or(0) * VRF_OUTPUT_LENGTH); s.extend_from_slice(&last_epoch_randomness); s.extend_from_slice(&epoch_index.to_le_bytes()); for vrf_output in rho { s.extend_from_slice(&vrf_output[..]); } sp_io::hashing::blake2_256(&s) } impl<T: Trait> ProvideInherent for Module<T> { type Call = pallet_timestamp::Call<T>; type Error = MakeFatalError<sp_inherents::Error>; const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER; fn create_inherent(_: &InherentData) -> Option<Self::Call> { None } fn check_inherent(call: &Self::Call, data: &InherentData) -> result::Result<(), Self::Error> { let timestamp = match call { pallet_timestamp::Call::set(ref timestamp) => timestamp.clone(), _ => return Ok(()), }; let timestamp_based_slot = (timestamp / Self::slot_duration()).saturated_into::<u64>(); let seal_slot = data.babe_inherent_data()?; if timestamp_based_slot == seal_slot { Ok(()) } else { Err(sp_inherents::Error::from("timestamp set in block doesn't match slot in seal").into()) } } }