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

Commit 49fa611

Browse files
authored
frame/beefy: prune entries in set id session mapping (#13411)
Add limit for the number of entries in the `SetIdSession` mapping. For example, it can be set to the bonding duration (in sessions). Signed-off-by: acatangiu <[email protected]>
1 parent 5b6519a commit 49fa611

File tree

4 files changed

+59
-1
lines changed

4 files changed

+59
-1
lines changed

frame/beefy-mmr/src/mock.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ impl pallet_beefy::Config for Test {
133133
)>>::IdentificationTuple;
134134
type HandleEquivocation = ();
135135
type MaxAuthorities = ConstU32<100>;
136+
type MaxSetIdSessionEntries = ConstU64<100>;
136137
type OnNewValidatorSet = BeefyMmr;
137138
type WeightInfo = ();
138139
}

frame/beefy/src/lib.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,18 @@ pub mod pallet {
9999
type HandleEquivocation: HandleEquivocation<Self>;
100100

101101
/// The maximum number of authorities that can be added.
102+
#[pallet::constant]
102103
type MaxAuthorities: Get<u32>;
103104

105+
/// The maximum number of entries to keep in the set id to session index mapping.
106+
///
107+
/// Since the `SetIdSession` map is only used for validating equivocations this
108+
/// value should relate to the bonding duration of whatever staking system is
109+
/// being used (if any). If equivocation handling is not enabled then this value
110+
/// can be zero.
111+
#[pallet::constant]
112+
type MaxSetIdSessionEntries: Get<u64>;
113+
104114
/// A hook to act on the new BEEFY validator set.
105115
///
106116
/// For some applications it might be beneficial to make the BEEFY validator set available
@@ -136,6 +146,12 @@ pub mod pallet {
136146
/// A mapping from BEEFY set ID to the index of the *most recent* session for which its
137147
/// members were responsible.
138148
///
149+
/// This is only used for validating equivocation proofs. An equivocation proof must
150+
/// contains a key-ownership proof for a given session, therefore we need a way to tie
151+
/// together sessions and BEEFY set ids, i.e. we need to validate that a validator
152+
/// was the owner of a given key on a given session, and what the active set ID was
153+
/// during that session.
154+
///
139155
/// TWOX-NOTE: `ValidatorSetId` is not under user control.
140156
#[pallet::storage]
141157
#[pallet::getter(fn session_for_set)]
@@ -462,9 +478,15 @@ where
462478
// We want to have at least one BEEFY mandatory block per session.
463479
Self::change_authorities(bounded_next_authorities, bounded_next_queued_authorities);
464480

481+
let validator_set_id = Self::validator_set_id();
465482
// Update the mapping for the new set id that corresponds to the latest session (i.e. now).
466483
let session_index = <pallet_session::Pallet<T>>::current_index();
467-
SetIdSession::<T>::insert(Self::validator_set_id(), &session_index);
484+
SetIdSession::<T>::insert(validator_set_id, &session_index);
485+
// Prune old entry if limit reached.
486+
let max_set_id_session_entries = T::MaxSetIdSessionEntries::get().max(1);
487+
if validator_set_id >= max_set_id_session_entries {
488+
SetIdSession::<T>::remove(validator_set_id - max_set_id_session_entries);
489+
}
468490
}
469491

470492
fn on_disabled(i: u32) {

frame/beefy/src/mock.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ parameter_types! {
111111
pub const Period: u64 = 1;
112112
pub const ReportLongevity: u64 =
113113
BondingDuration::get() as u64 * SessionsPerEra::get() as u64 * Period::get();
114+
pub const MaxSetIdSessionEntries: u32 = BondingDuration::get() * SessionsPerEra::get();
114115
}
115116

116117
impl pallet_beefy::Config for Test {
@@ -125,6 +126,7 @@ impl pallet_beefy::Config for Test {
125126
type HandleEquivocation =
126127
super::EquivocationHandler<u64, Self::KeyOwnerIdentification, Offences, ReportLongevity>;
127128
type MaxAuthorities = ConstU32<100>;
129+
type MaxSetIdSessionEntries = MaxSetIdSessionEntries;
128130
type OnNewValidatorSet = ();
129131
type WeightInfo = ();
130132
}

frame/beefy/src/tests.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,39 @@ fn validator_set_updates_work() {
162162
});
163163
}
164164

165+
#[test]
166+
fn cleans_up_old_set_id_session_mappings() {
167+
new_test_ext(vec![1, 2, 3, 4]).execute_with(|| {
168+
let max_set_id_session_entries = MaxSetIdSessionEntries::get();
169+
170+
// we have 3 sessions per era
171+
let era_limit = max_set_id_session_entries / 3;
172+
// sanity check against division precision loss
173+
assert_eq!(0, max_set_id_session_entries % 3);
174+
// go through `max_set_id_session_entries` sessions
175+
start_era(era_limit);
176+
177+
// we should have a session id mapping for all the set ids from
178+
// `max_set_id_session_entries` eras we have observed
179+
for i in 1..=max_set_id_session_entries {
180+
assert!(Beefy::session_for_set(i as u64).is_some());
181+
}
182+
183+
// go through another `max_set_id_session_entries` sessions
184+
start_era(era_limit * 2);
185+
186+
// we should keep tracking the new mappings for new sessions
187+
for i in max_set_id_session_entries + 1..=max_set_id_session_entries * 2 {
188+
assert!(Beefy::session_for_set(i as u64).is_some());
189+
}
190+
191+
// but the old ones should have been pruned by now
192+
for i in 1..=max_set_id_session_entries {
193+
assert!(Beefy::session_for_set(i as u64).is_none());
194+
}
195+
});
196+
}
197+
165198
/// Returns a list with 3 authorities with known keys:
166199
/// Alice, Bob and Charlie.
167200
pub fn test_authorities() -> Vec<BeefyId> {

0 commit comments

Comments
 (0)