1
// This file is part of Substrate.
2

            
3
// Copyright (C) Parity Technologies (UK) Ltd.
4
// SPDX-License-Identifier: Apache-2.0
5

            
6
// Licensed under the Apache License, Version 2.0 (the "License");
7
// you may not use this file except in compliance with the License.
8
// You may obtain a copy of the License at
9
//
10
// 	http://www.apache.org/licenses/LICENSE-2.0
11
//
12
// Unless required by applicable law or agreed to in writing, software
13
// distributed under the License is distributed on an "AS IS" BASIS,
14
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
// See the License for the specific language governing permissions and
16
// limitations under the License.
17

            
18
#![cfg_attr(not(feature = "std"), no_std)]
19

            
20
extern crate alloc;
21

            
22
use alloc::{boxed::Box, vec::Vec};
23
use codec::{Encode, MaxEncodedLen};
24

            
25
use frame_support::{
26
	dispatch::{DispatchResultWithPostInfo, Pays},
27
	pallet_prelude::*,
28
	traits::{Get, OneSessionHandler},
29
	weights::Weight,
30
	BoundedSlice, BoundedVec, Parameter,
31
};
32
use frame_system::{
33
	ensure_none, ensure_signed,
34
	pallet_prelude::{BlockNumberFor, HeaderFor, OriginFor},
35
};
36
use log;
37
use sp_runtime::{
38
	generic::DigestItem,
39
	traits::{IsMember, Member, One},
40
	RuntimeAppPublic,
41
};
42
use sp_session::{GetSessionNumber, GetValidatorCount};
43
use sp_staking::{offence::OffenceReportSystem, SessionIndex};
44

            
45
use sp_consensus_beefy::{
46
	AncestryHelper, AuthorityIndex, BeefyAuthorityId, ConsensusLog, DoubleVotingProof,
47
	ForkVotingProof, FutureBlockVotingProof, OnNewValidatorSet, ValidatorSet, BEEFY_ENGINE_ID,
48
	GENESIS_AUTHORITY_SET_ID,
49
};
50

            
51
mod default_weights;
52
mod equivocation;
53
#[cfg(test)]
54
mod mock;
55
#[cfg(test)]
56
mod tests;
57

            
58
pub use crate::equivocation::{EquivocationOffence, EquivocationReportSystem, TimeSlot};
59
pub use pallet::*;
60

            
61
use crate::equivocation::EquivocationEvidenceFor;
62

            
63
const LOG_TARGET: &str = "runtime::beefy";
64

            
65
1098
#[frame_support::pallet]
66
pub mod pallet {
67
	use super::*;
68
	use frame_system::{ensure_root, pallet_prelude::BlockNumberFor};
69

            
70
	#[pallet::config]
71
	pub trait Config: frame_system::Config {
72
		/// Authority identifier type
73
		type BeefyId: Member
74
			+ Parameter
75
			// todo: use custom signature hashing type instead of hardcoded `Keccak256`
76
			+ BeefyAuthorityId<sp_runtime::traits::Keccak256>
77
			+ MaybeSerializeDeserialize
78
			+ MaxEncodedLen;
79

            
80
		/// The maximum number of authorities that can be added.
81
		#[pallet::constant]
82
		type MaxAuthorities: Get<u32>;
83

            
84
		/// The maximum number of nominators for each validator.
85
		#[pallet::constant]
86
		type MaxNominators: Get<u32>;
87

            
88
		/// The maximum number of entries to keep in the set id to session index mapping.
89
		///
90
		/// Since the `SetIdSession` map is only used for validating equivocations this
91
		/// value should relate to the bonding duration of whatever staking system is
92
		/// being used (if any). If equivocation handling is not enabled then this value
93
		/// can be zero.
94
		#[pallet::constant]
95
		type MaxSetIdSessionEntries: Get<u64>;
96

            
97
		/// A hook to act on the new BEEFY validator set.
98
		///
99
		/// For some applications it might be beneficial to make the BEEFY validator set available
100
		/// externally apart from having it in the storage. For instance you might cache a light
101
		/// weight MMR root over validators and make it available for Light Clients.
102
		type OnNewValidatorSet: OnNewValidatorSet<<Self as Config>::BeefyId>;
103

            
104
		/// Hook for checking commitment canonicity.
105
		type AncestryHelper: AncestryHelper<HeaderFor<Self>>;
106

            
107
		/// Weights for this pallet.
108
		type WeightInfo: WeightInfo;
109

            
110
		/// The proof of key ownership, used for validating equivocation reports
111
		/// The proof must include the session index and validator count of the
112
		/// session at which the equivocation occurred.
113
		type KeyOwnerProof: Parameter + GetSessionNumber + GetValidatorCount;
114

            
115
		/// The equivocation handling subsystem.
116
		///
117
		/// Defines methods to publish, check and process an equivocation offence.
118
		type EquivocationReportSystem: OffenceReportSystem<
119
			Option<Self::AccountId>,
120
			EquivocationEvidenceFor<Self>,
121
		>;
122
	}
123

            
124
1698
	#[pallet::pallet]
125
	pub struct Pallet<T>(_);
126

            
127
	/// The current authorities set
128
377748
	#[pallet::storage]
129
	pub type Authorities<T: Config> =
130
		StorageValue<_, BoundedVec<T::BeefyId, T::MaxAuthorities>, ValueQuery>;
131

            
132
	/// The current validator set id
133
918666
	#[pallet::storage]
134
	pub type ValidatorSetId<T: Config> =
135
		StorageValue<_, sp_consensus_beefy::ValidatorSetId, ValueQuery>;
136

            
137
	/// Authorities set scheduled to be used with the next session
138
377742
	#[pallet::storage]
139
	pub type NextAuthorities<T: Config> =
140
		StorageValue<_, BoundedVec<T::BeefyId, T::MaxAuthorities>, ValueQuery>;
141

            
142
	/// A mapping from BEEFY set ID to the index of the *most recent* session for which its
143
	/// members were responsible.
144
	///
145
	/// This is only used for validating equivocation proofs. An equivocation proof must
146
	/// contains a key-ownership proof for a given session, therefore we need a way to tie
147
	/// together sessions and BEEFY set ids, i.e. we need to validate that a validator
148
	/// was the owner of a given key on a given session, and what the active set ID was
149
	/// during that session.
150
	///
151
	/// TWOX-NOTE: `ValidatorSetId` is not under user control.
152
193092
	#[pallet::storage]
153
	pub type SetIdSession<T: Config> =
154
		StorageMap<_, Twox64Concat, sp_consensus_beefy::ValidatorSetId, SessionIndex>;
155

            
156
	/// Block number where BEEFY consensus is enabled/started.
157
	/// By changing this (through privileged `set_new_genesis()`), BEEFY consensus is effectively
158
	/// restarted from the newly set block number.
159
6
	#[pallet::storage]
160
	pub type GenesisBlock<T: Config> = StorageValue<_, Option<BlockNumberFor<T>>, ValueQuery>;
161

            
162
	#[pallet::genesis_config]
163
	pub struct GenesisConfig<T: Config> {
164
		/// Initial set of BEEFY authorities.
165
		pub authorities: Vec<T::BeefyId>,
166
		/// Block number where BEEFY consensus should start.
167
		/// Should match the session where initial authorities are active.
168
		/// *Note:* Ideally use block number where GRANDPA authorities are changed,
169
		/// to guarantee the client gets a finality notification for exactly this block.
170
		pub genesis_block: Option<BlockNumberFor<T>>,
171
	}
172

            
173
	impl<T: Config> Default for GenesisConfig<T> {
174
		fn default() -> Self {
175
			// BEEFY genesis will be first BEEFY-MANDATORY block,
176
			// use block number one instead of chain-genesis.
177
			let genesis_block = Some(One::one());
178
			Self { authorities: Vec::new(), genesis_block }
179
		}
180
	}
181

            
182
	#[pallet::genesis_build]
183
	impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
184
3
		fn build(&self) {
185
3
			Pallet::<T>::initialize(&self.authorities)
186
3
				// we panic here as runtime maintainers can simply reconfigure genesis and restart
187
3
				// the chain easily
188
3
				.expect("Authorities vec too big");
189
3
			GenesisBlock::<T>::put(&self.genesis_block);
190
3
		}
191
	}
192

            
193
1542
	#[pallet::error]
194
	pub enum Error<T> {
195
		/// A key ownership proof provided as part of an equivocation report is invalid.
196
		InvalidKeyOwnershipProof,
197
		/// A double voting proof provided as part of an equivocation report is invalid.
198
		InvalidDoubleVotingProof,
199
		/// A fork voting proof provided as part of an equivocation report is invalid.
200
		InvalidForkVotingProof,
201
		/// A future block voting proof provided as part of an equivocation report is invalid.
202
		InvalidFutureBlockVotingProof,
203
		/// The session of the equivocation proof is invalid
204
		InvalidEquivocationProofSession,
205
		/// A given equivocation report is valid but already previously reported.
206
		DuplicateOffenceReport,
207
		/// Submitted configuration is invalid.
208
		InvalidConfiguration,
209
	}
210

            
211
6600
	#[pallet::call]
212
	impl<T: Config> Pallet<T> {
213
		/// Report voter equivocation/misbehavior. This method will verify the
214
		/// equivocation proof and validate the given key ownership proof
215
		/// against the extracted offender. If both are valid, the offence
216
		/// will be reported.
217
		#[pallet::call_index(0)]
218
		#[pallet::weight(T::WeightInfo::report_double_voting(
219
			key_owner_proof.validator_count(),
220
			T::MaxNominators::get(),
221
		))]
222
		pub fn report_double_voting(
223
			origin: OriginFor<T>,
224
			equivocation_proof: Box<
225
				DoubleVotingProof<
226
					BlockNumberFor<T>,
227
					T::BeefyId,
228
					<T::BeefyId as RuntimeAppPublic>::Signature,
229
				>,
230
			>,
231
			key_owner_proof: T::KeyOwnerProof,
232
546
		) -> DispatchResultWithPostInfo {
233
546
			let reporter = ensure_signed(origin)?;
234

            
235
546
			T::EquivocationReportSystem::process_evidence(
236
546
				Some(reporter),
237
546
				EquivocationEvidenceFor::DoubleVotingProof(*equivocation_proof, key_owner_proof),
238
546
			)?;
239
			// Waive the fee since the report is valid and beneficial
240
			Ok(Pays::No.into())
241
		}
242

            
243
		/// Report voter equivocation/misbehavior. This method will verify the
244
		/// equivocation proof and validate the given key ownership proof
245
		/// against the extracted offender. If both are valid, the offence
246
		/// will be reported.
247
		///
248
		/// This extrinsic must be called unsigned and it is expected that only
249
		/// block authors will call it (validated in `ValidateUnsigned`), as such
250
		/// if the block author is defined it will be defined as the equivocation
251
		/// reporter.
252
		#[pallet::call_index(1)]
253
		#[pallet::weight(T::WeightInfo::report_double_voting(
254
			key_owner_proof.validator_count(),
255
			T::MaxNominators::get(),
256
		))]
257
		pub fn report_double_voting_unsigned(
258
			origin: OriginFor<T>,
259
			equivocation_proof: Box<
260
				DoubleVotingProof<
261
					BlockNumberFor<T>,
262
					T::BeefyId,
263
					<T::BeefyId as RuntimeAppPublic>::Signature,
264
				>,
265
			>,
266
			key_owner_proof: T::KeyOwnerProof,
267
129
		) -> DispatchResultWithPostInfo {
268
129
			ensure_none(origin)?;
269

            
270
			T::EquivocationReportSystem::process_evidence(
271
				None,
272
				EquivocationEvidenceFor::DoubleVotingProof(*equivocation_proof, key_owner_proof),
273
			)?;
274
			Ok(Pays::No.into())
275
		}
276

            
277
		/// Reset BEEFY consensus by setting a new BEEFY genesis at `delay_in_blocks` blocks in the
278
		/// future.
279
		///
280
		/// Note: `delay_in_blocks` has to be at least 1.
281
		#[pallet::call_index(2)]
282
		#[pallet::weight(<T as Config>::WeightInfo::set_new_genesis())]
283
		pub fn set_new_genesis(
284
			origin: OriginFor<T>,
285
			delay_in_blocks: BlockNumberFor<T>,
286
12
		) -> DispatchResult {
287
12
			ensure_root(origin)?;
288
			ensure!(delay_in_blocks >= One::one(), Error::<T>::InvalidConfiguration);
289
			let genesis_block = frame_system::Pallet::<T>::block_number() + delay_in_blocks;
290
			GenesisBlock::<T>::put(Some(genesis_block));
291
			Ok(())
292
		}
293

            
294
		/// Report fork voting equivocation. This method will verify the equivocation proof
295
		/// and validate the given key ownership proof against the extracted offender.
296
		/// If both are valid, the offence will be reported.
297
		#[pallet::call_index(3)]
298
		#[pallet::weight(T::WeightInfo::report_fork_voting(
299
			key_owner_proof.validator_count(),
300
			T::MaxNominators::get(),
301
		))]
302
		pub fn report_fork_voting(
303
			origin: OriginFor<T>,
304
			equivocation_proof: Box<
305
				ForkVotingProof<
306
					HeaderFor<T>,
307
					T::BeefyId,
308
					<T::AncestryHelper as AncestryHelper<HeaderFor<T>>>::Proof,
309
				>,
310
			>,
311
			key_owner_proof: T::KeyOwnerProof,
312
		) -> DispatchResultWithPostInfo {
313
			let reporter = ensure_signed(origin)?;
314

            
315
			T::EquivocationReportSystem::process_evidence(
316
				Some(reporter),
317
				EquivocationEvidenceFor::ForkVotingProof(*equivocation_proof, key_owner_proof),
318
			)?;
319
			// Waive the fee since the report is valid and beneficial
320
			Ok(Pays::No.into())
321
		}
322

            
323
		/// Report fork voting equivocation. This method will verify the equivocation proof
324
		/// and validate the given key ownership proof against the extracted offender.
325
		/// If both are valid, the offence will be reported.
326
		///
327
		/// This extrinsic must be called unsigned and it is expected that only
328
		/// block authors will call it (validated in `ValidateUnsigned`), as such
329
		/// if the block author is defined it will be defined as the equivocation
330
		/// reporter.
331
		#[pallet::call_index(4)]
332
		#[pallet::weight(T::WeightInfo::report_fork_voting(
333
			key_owner_proof.validator_count(),
334
			T::MaxNominators::get(),
335
		))]
336
		pub fn report_fork_voting_unsigned(
337
			origin: OriginFor<T>,
338
			equivocation_proof: Box<
339
				ForkVotingProof<
340
					HeaderFor<T>,
341
					T::BeefyId,
342
					<T::AncestryHelper as AncestryHelper<HeaderFor<T>>>::Proof,
343
				>,
344
			>,
345
			key_owner_proof: T::KeyOwnerProof,
346
		) -> DispatchResultWithPostInfo {
347
			ensure_none(origin)?;
348

            
349
			T::EquivocationReportSystem::process_evidence(
350
				None,
351
				EquivocationEvidenceFor::ForkVotingProof(*equivocation_proof, key_owner_proof),
352
			)?;
353
			// Waive the fee since the report is valid and beneficial
354
			Ok(Pays::No.into())
355
		}
356

            
357
		/// Report future block voting equivocation. This method will verify the equivocation proof
358
		/// and validate the given key ownership proof against the extracted offender.
359
		/// If both are valid, the offence will be reported.
360
		#[pallet::call_index(5)]
361
		#[pallet::weight(T::WeightInfo::report_future_block_voting(
362
			key_owner_proof.validator_count(),
363
			T::MaxNominators::get(),
364
		))]
365
		pub fn report_future_block_voting(
366
			origin: OriginFor<T>,
367
			equivocation_proof: Box<FutureBlockVotingProof<BlockNumberFor<T>, T::BeefyId>>,
368
			key_owner_proof: T::KeyOwnerProof,
369
225
		) -> DispatchResultWithPostInfo {
370
225
			let reporter = ensure_signed(origin)?;
371

            
372
225
			T::EquivocationReportSystem::process_evidence(
373
225
				Some(reporter),
374
225
				EquivocationEvidenceFor::FutureBlockVotingProof(
375
225
					*equivocation_proof,
376
225
					key_owner_proof,
377
225
				),
378
225
			)?;
379
			// Waive the fee since the report is valid and beneficial
380
			Ok(Pays::No.into())
381
		}
382

            
383
		/// Report future block voting equivocation. This method will verify the equivocation proof
384
		/// and validate the given key ownership proof against the extracted offender.
385
		/// If both are valid, the offence will be reported.
386
		///
387
		/// This extrinsic must be called unsigned and it is expected that only
388
		/// block authors will call it (validated in `ValidateUnsigned`), as such
389
		/// if the block author is defined it will be defined as the equivocation
390
		/// reporter.
391
		#[pallet::call_index(6)]
392
		#[pallet::weight(T::WeightInfo::report_future_block_voting(
393
			key_owner_proof.validator_count(),
394
			T::MaxNominators::get(),
395
		))]
396
		pub fn report_future_block_voting_unsigned(
397
			origin: OriginFor<T>,
398
			equivocation_proof: Box<FutureBlockVotingProof<BlockNumberFor<T>, T::BeefyId>>,
399
			key_owner_proof: T::KeyOwnerProof,
400
180
		) -> DispatchResultWithPostInfo {
401
180
			ensure_none(origin)?;
402

            
403
			T::EquivocationReportSystem::process_evidence(
404
				None,
405
				EquivocationEvidenceFor::FutureBlockVotingProof(
406
					*equivocation_proof,
407
					key_owner_proof,
408
				),
409
			)?;
410
			// Waive the fee since the report is valid and beneficial
411
			Ok(Pays::No.into())
412
		}
413
	}
414

            
415
554367
	#[pallet::hooks]
416
	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
417
		#[cfg(feature = "try-runtime")]
418
53637
		fn try_state(_n: BlockNumberFor<T>) -> Result<(), sp_runtime::TryRuntimeError> {
419
53637
			Self::do_try_state()
420
53637
		}
421
	}
422

            
423
	#[pallet::validate_unsigned]
424
	impl<T: Config> ValidateUnsigned for Pallet<T> {
425
		type Call = Call<T>;
426

            
427
		fn pre_dispatch(call: &Self::Call) -> Result<(), TransactionValidityError> {
428
			Self::pre_dispatch(call)
429
		}
430

            
431
		fn validate_unsigned(source: TransactionSource, call: &Self::Call) -> TransactionValidity {
432
			Self::validate_unsigned(source, call)
433
		}
434
	}
435

            
436
	impl<T: Config> Call<T> {
437
		pub fn to_equivocation_evidence_for(&self) -> Option<EquivocationEvidenceFor<T>> {
438
			match self {
439
				Call::report_double_voting_unsigned { equivocation_proof, key_owner_proof } =>
440
					Some(EquivocationEvidenceFor::<T>::DoubleVotingProof(
441
						*equivocation_proof.clone(),
442
						key_owner_proof.clone(),
443
					)),
444
				Call::report_fork_voting_unsigned { equivocation_proof, key_owner_proof } =>
445
					Some(EquivocationEvidenceFor::<T>::ForkVotingProof(
446
						*equivocation_proof.clone(),
447
						key_owner_proof.clone(),
448
					)),
449
				_ => None,
450
			}
451
		}
452
	}
453

            
454
	impl<T: Config> From<EquivocationEvidenceFor<T>> for Call<T> {
455
		fn from(evidence: EquivocationEvidenceFor<T>) -> Self {
456
			match evidence {
457
				EquivocationEvidenceFor::DoubleVotingProof(equivocation_proof, key_owner_proof) =>
458
					Call::report_double_voting_unsigned {
459
						equivocation_proof: Box::new(equivocation_proof),
460
						key_owner_proof,
461
					},
462
				EquivocationEvidenceFor::ForkVotingProof(equivocation_proof, key_owner_proof) =>
463
					Call::report_fork_voting_unsigned {
464
						equivocation_proof: Box::new(equivocation_proof),
465
						key_owner_proof,
466
					},
467
				EquivocationEvidenceFor::FutureBlockVotingProof(
468
					equivocation_proof,
469
					key_owner_proof,
470
				) => Call::report_future_block_voting_unsigned {
471
					equivocation_proof: Box::new(equivocation_proof),
472
					key_owner_proof,
473
				},
474
			}
475
		}
476
	}
477
}
478

            
479
#[cfg(any(feature = "try-runtime", test))]
480
impl<T: Config> Pallet<T> {
481
	/// Ensure the correctness of the state of this pallet.
482
	///
483
	/// This should be valid before or after each state transition of this pallet.
484
53637
	pub fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> {
485
53637
		Self::try_state_authorities()?;
486
53637
		Self::try_state_validators()?;
487

            
488
53637
		Ok(())
489
53637
	}
490

            
491
	/// # Invariants
492
	///
493
	/// * `Authorities` should not exceed the `MaxAuthorities` capacity.
494
	/// * `NextAuthorities` should not exceed the `MaxAuthorities` capacity.
495
53637
	fn try_state_authorities() -> Result<(), sp_runtime::TryRuntimeError> {
496
53637
		if let Some(authorities_len) = <Authorities<T>>::decode_len() {
497
53637
			ensure!(
498
53637
				authorities_len as u32 <= T::MaxAuthorities::get(),
499
				"Authorities number exceeds what the pallet config allows."
500
			);
501
		} else {
502
			return Err(sp_runtime::TryRuntimeError::Other(
503
				"Failed to decode length of authorities",
504
			));
505
		}
506

            
507
53637
		if let Some(next_authorities_len) = <NextAuthorities<T>>::decode_len() {
508
53637
			ensure!(
509
53637
				next_authorities_len as u32 <= T::MaxAuthorities::get(),
510
				"Next authorities number exceeds what the pallet config allows."
511
			);
512
		} else {
513
			return Err(sp_runtime::TryRuntimeError::Other(
514
				"Failed to decode length of next authorities",
515
			));
516
		}
517
53637
		Ok(())
518
53637
	}
519

            
520
	/// # Invariants
521
	///
522
	/// `ValidatorSetId` must be present in `SetIdSession`
523
53637
	fn try_state_validators() -> Result<(), sp_runtime::TryRuntimeError> {
524
53637
		let validator_set_id = <ValidatorSetId<T>>::get();
525
53637
		ensure!(
526
53637
			SetIdSession::<T>::get(validator_set_id).is_some(),
527
			"Validator set id must be present in SetIdSession"
528
		);
529
53637
		Ok(())
530
53637
	}
531
}
532

            
533
impl<T: Config> Pallet<T> {
534
	/// Return the current active BEEFY validator set.
535
	pub fn validator_set() -> Option<ValidatorSet<T::BeefyId>> {
536
		let validators: BoundedVec<T::BeefyId, T::MaxAuthorities> = Authorities::<T>::get();
537
		let id: sp_consensus_beefy::ValidatorSetId = ValidatorSetId::<T>::get();
538
		ValidatorSet::<T::BeefyId>::new(validators, id)
539
	}
540

            
541
	/// Submits an extrinsic to report an equivocation. This method will create
542
	/// an unsigned extrinsic with a call to `report_equivocation_unsigned` and
543
	/// will push the transaction to the pool. Only useful in an offchain context.
544
	pub fn submit_unsigned_double_voting_report(
545
		equivocation_proof: DoubleVotingProof<
546
			BlockNumberFor<T>,
547
			T::BeefyId,
548
			<T::BeefyId as RuntimeAppPublic>::Signature,
549
		>,
550
		key_owner_proof: T::KeyOwnerProof,
551
	) -> Option<()> {
552
		T::EquivocationReportSystem::publish_evidence(EquivocationEvidenceFor::DoubleVotingProof(
553
			equivocation_proof,
554
			key_owner_proof,
555
		))
556
		.ok()
557
	}
558

            
559
135231
	fn change_authorities(
560
135231
		new: BoundedVec<T::BeefyId, T::MaxAuthorities>,
561
135231
		queued: BoundedVec<T::BeefyId, T::MaxAuthorities>,
562
135231
	) {
563
135231
		Authorities::<T>::put(&new);
564
135231

            
565
135231
		let new_id = ValidatorSetId::<T>::get() + 1u64;
566
135231
		ValidatorSetId::<T>::put(new_id);
567
135231

            
568
135231
		NextAuthorities::<T>::put(&queued);
569

            
570
135231
		if let Some(validator_set) = ValidatorSet::<T::BeefyId>::new(new, new_id) {
571
			let log = DigestItem::Consensus(
572
				BEEFY_ENGINE_ID,
573
				ConsensusLog::AuthoritiesChange(validator_set.clone()).encode(),
574
			);
575
			frame_system::Pallet::<T>::deposit_log(log);
576

            
577
			let next_id = new_id + 1;
578
			if let Some(next_validator_set) = ValidatorSet::<T::BeefyId>::new(queued, next_id) {
579
				<T::OnNewValidatorSet as OnNewValidatorSet<_>>::on_new_validator_set(
580
					&validator_set,
581
					&next_validator_set,
582
				);
583
			}
584
135231
		}
585
135231
	}
586

            
587
6
	fn initialize(authorities: &Vec<T::BeefyId>) -> Result<(), ()> {
588
6
		if authorities.is_empty() {
589
3
			return Ok(())
590
3
		}
591
3

            
592
3
		if !Authorities::<T>::get().is_empty() {
593
			return Err(())
594
3
		}
595

            
596
3
		let bounded_authorities =
597
3
			BoundedSlice::<T::BeefyId, T::MaxAuthorities>::try_from(authorities.as_slice())
598
3
				.map_err(|_| ())?;
599

            
600
3
		let id = GENESIS_AUTHORITY_SET_ID;
601
3
		Authorities::<T>::put(bounded_authorities);
602
3
		ValidatorSetId::<T>::put(id);
603
3
		// Like `pallet_session`, initialize the next validator set as well.
604
3
		NextAuthorities::<T>::put(bounded_authorities);
605

            
606
3
		if let Some(validator_set) = ValidatorSet::<T::BeefyId>::new(authorities.clone(), id) {
607
3
			let next_id = id + 1;
608
3
			if let Some(next_validator_set) =
609
3
				ValidatorSet::<T::BeefyId>::new(authorities.clone(), next_id)
610
3
			{
611
3
				<T::OnNewValidatorSet as OnNewValidatorSet<_>>::on_new_validator_set(
612
3
					&validator_set,
613
3
					&next_validator_set,
614
3
				);
615
3
			}
616
		}
617

            
618
		// NOTE: initialize first session of first set. this is necessary for
619
		// the genesis set and session since we only update the set -> session
620
		// mapping whenever a new session starts, i.e. through `on_new_session`.
621
3
		SetIdSession::<T>::insert(0, 0);
622
3

            
623
3
		Ok(())
624
6
	}
625
}
626

            
627
impl<T: Config> sp_runtime::BoundToRuntimeAppPublic for Pallet<T> {
628
	type Public = T::BeefyId;
629
}
630

            
631
impl<T: Config> OneSessionHandler<T::AccountId> for Pallet<T>
632
where
633
	T: pallet_session::Config,
634
{
635
	type Key = T::BeefyId;
636

            
637
3
	fn on_genesis_session<'a, I: 'a>(validators: I)
638
3
	where
639
3
		I: Iterator<Item = (&'a T::AccountId, T::BeefyId)>,
640
3
	{
641
3
		let authorities = validators.map(|(_, k)| k).collect::<Vec<_>>();
642
3
		// we panic here as runtime maintainers can simply reconfigure genesis and restart the
643
3
		// chain easily
644
3
		Self::initialize(&authorities).expect("Authorities vec too big");
645
3
	}
646

            
647
135231
	fn on_new_session<'a, I: 'a>(_changed: bool, validators: I, queued_validators: I)
648
135231
	where
649
135231
		I: Iterator<Item = (&'a T::AccountId, T::BeefyId)>,
650
135231
	{
651
135231
		let next_authorities = validators.map(|(_, k)| k).collect::<Vec<_>>();
652
135231
		if next_authorities.len() as u32 > T::MaxAuthorities::get() {
653
			log::error!(
654
				target: LOG_TARGET,
655
				"authorities list {:?} truncated to length {}",
656
				next_authorities,
657
				T::MaxAuthorities::get(),
658
			);
659
135231
		}
660
135231
		let bounded_next_authorities =
661
135231
			BoundedVec::<_, T::MaxAuthorities>::truncate_from(next_authorities);
662
135231

            
663
135231
		let next_queued_authorities = queued_validators.map(|(_, k)| k).collect::<Vec<_>>();
664
135231
		if next_queued_authorities.len() as u32 > T::MaxAuthorities::get() {
665
			log::error!(
666
				target: LOG_TARGET,
667
				"queued authorities list {:?} truncated to length {}",
668
				next_queued_authorities,
669
				T::MaxAuthorities::get(),
670
			);
671
135231
		}
672
135231
		let bounded_next_queued_authorities =
673
135231
			BoundedVec::<_, T::MaxAuthorities>::truncate_from(next_queued_authorities);
674
135231

            
675
135231
		// Always issue a change on each `session`, even if validator set hasn't changed.
676
135231
		// We want to have at least one BEEFY mandatory block per session.
677
135231
		Self::change_authorities(bounded_next_authorities, bounded_next_queued_authorities);
678
135231

            
679
135231
		let validator_set_id = ValidatorSetId::<T>::get();
680
135231
		// Update the mapping for the new set id that corresponds to the latest session (i.e. now).
681
135231
		let session_index = pallet_session::Pallet::<T>::current_index();
682
135231
		SetIdSession::<T>::insert(validator_set_id, &session_index);
683
135231
		// Prune old entry if limit reached.
684
135231
		let max_set_id_session_entries = T::MaxSetIdSessionEntries::get().max(1);
685
135231
		if validator_set_id >= max_set_id_session_entries {
686
3450
			SetIdSession::<T>::remove(validator_set_id - max_set_id_session_entries);
687
131781
		}
688
135231
	}
689

            
690
	fn on_disabled(i: u32) {
691
		let log = DigestItem::Consensus(
692
			BEEFY_ENGINE_ID,
693
			ConsensusLog::<T::BeefyId>::OnDisabled(i as AuthorityIndex).encode(),
694
		);
695

            
696
		frame_system::Pallet::<T>::deposit_log(log);
697
	}
698
}
699

            
700
impl<T: Config> IsMember<T::BeefyId> for Pallet<T> {
701
	fn is_member(authority_id: &T::BeefyId) -> bool {
702
		Authorities::<T>::get().iter().any(|id| id == authority_id)
703
	}
704
}
705

            
706
pub trait WeightInfo {
707
	fn report_voting_equivocation(
708
		votes_count: u32,
709
		validator_count: u32,
710
		max_nominators_per_validator: u32,
711
	) -> Weight;
712
852
	fn report_double_voting(validator_count: u32, max_nominators_per_validator: u32) -> Weight {
713
852
		Self::report_voting_equivocation(2, validator_count, max_nominators_per_validator)
714
852
	}
715
	fn report_fork_voting(validator_count: u32, max_nominators_per_validator: u32) -> Weight;
716
444
	fn report_future_block_voting(
717
444
		validator_count: u32,
718
444
		max_nominators_per_validator: u32,
719
444
	) -> Weight {
720
444
		Self::report_voting_equivocation(1, validator_count, max_nominators_per_validator)
721
444
	}
722
	fn set_new_genesis() -> Weight;
723
}