Skip to content

Commit 8a5f06c

Browse files
authored
fix: ETCM-12463 Correctly handle key changes for sitting committee members (#1108)
1 parent 288e1e0 commit 8a5f06c

File tree

1 file changed

+70
-16
lines changed

1 file changed

+70
-16
lines changed

toolkit/committee-selection/pallet/src/pallet_session_support.rs

Lines changed: 70 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -49,20 +49,29 @@ where
4949
let mut new_committee_accounts: BTreeSet<T::AccountId> = BTreeSet::new();
5050

5151
for member in new_committee.iter() {
52-
let account = member.authority_id().into();
52+
let account: T::AccountId = member.authority_id().into();
5353

5454
if !new_committee_accounts.contains(&account) {
5555
new_committee_accounts.insert(account.clone());
5656

57-
// Members that were already in the old committee have their accounts and keys set up already
57+
// Members that were already in the old committee have their accounts provided
5858
if !old_committee_accounts.contains(&account) {
59-
setup_block_producer::<T>(account, member.authority_keys());
59+
provide_account::<T>(&account);
60+
}
61+
62+
let new_keys = member.authority_keys();
63+
let current_keys = load_keys::<T>(&account);
64+
65+
if current_keys != Some(new_keys.clone().into()) {
66+
purge_keys::<T>(&account);
67+
set_keys::<T>(&account, new_keys.clone());
6068
}
6169
}
6270
}
6371

6472
for account in old_committee_accounts.difference(&new_committee_accounts) {
65-
teardown_block_producer::<T>(account)
73+
purge_keys::<T>(account);
74+
unprovide_account::<T>(account);
6675
}
6776

6877
crate::ProvidedAccounts::<T>::set(new_committee_accounts.clone().try_into().unwrap());
@@ -81,19 +90,19 @@ where
8190
}
8291
}
8392

84-
/// Provides accounts and registers keys for new committee members
85-
fn setup_block_producer<T: crate::Config + pallet_session::Config>(
86-
account: T::AccountId,
93+
fn load_keys<T: pallet_session::Config>(account: &T::AccountId) -> Option<T::Keys> {
94+
<T as pallet_session::Config>::ValidatorId::try_from(account.clone())
95+
.ok()
96+
.as_ref()
97+
.and_then(pallet_session::Pallet::<T>::load_keys)
98+
}
99+
100+
fn set_keys<T: crate::Config + pallet_session::Config>(
101+
account: &T::AccountId,
87102
keys: T::AuthorityKeys,
88103
) where
89104
<T as pallet_session::Config>::Keys: From<T::AuthorityKeys>,
90105
{
91-
log::debug!(
92-
"➕💼 Incrementing provider count and registering keys for block producer {account:?}"
93-
);
94-
95-
frame_system::Pallet::<T>::inc_providers(&account);
96-
97106
let set_keys_result = pallet_session::Call::<T>::set_keys { keys: keys.into(), proof: vec![] }
98107
.dispatch_bypass_filter(RawOrigin::Signed(account.clone()).into());
99108

@@ -105,8 +114,7 @@ fn setup_block_producer<T: crate::Config + pallet_session::Config>(
105114
}
106115
}
107116

108-
/// Removes account provisions and purges keys for outgoing old committee members
109-
fn teardown_block_producer<T: crate::Config + pallet_session::Config>(account: &T::AccountId)
117+
fn purge_keys<T: crate::Config + pallet_session::Config>(account: &T::AccountId)
110118
where
111119
<T as pallet_session::Config>::Keys: From<T::AuthorityKeys>,
112120
{
@@ -116,8 +124,19 @@ where
116124
Ok(_) => debug!("purge_keys for {account:?}"),
117125
Err(e) => info!("Could not purge_keys for {account:?}, error: {:?}", e.error),
118126
}
127+
}
128+
129+
fn provide_account<T: crate::Config + pallet_session::Config>(account: &T::AccountId) {
130+
log::debug!(
131+
"➕💼 Incrementing provider count and registering keys for block producer {account:?}"
132+
);
133+
134+
frame_system::Pallet::<T>::inc_providers(&account);
135+
}
136+
137+
fn unprovide_account<T: crate::Config + pallet_session::Config>(account: &T::AccountId) {
119138
log::info!(
120-
"➖💼 Decrementing provider count and deregisteringkeys for block producer {account:?}"
139+
"➖💼 Decrementing provider count and deregistering keys for block producer {account:?}"
121140
);
122141
frame_system::Pallet::<T>::dec_providers(&account).expect(
123142
"We always match dec_providers with corresponding inc_providers, thus it cannot fail",
@@ -167,6 +186,7 @@ mod tests {
167186
use pallet_session::ShouldEndSession;
168187
pub const IRRELEVANT: u64 = 2;
169188
use sidechain_domain::ScEpochNumber;
189+
use sp_runtime::testing::UintAuthorityId;
170190

171191
type Manager = crate::Pallet<Test>;
172192

@@ -209,6 +229,40 @@ mod tests {
209229
});
210230
}
211231

232+
#[test]
233+
fn reregister_changed_session_keys_for_sitting_authority() {
234+
new_test_ext().execute_with(|| {
235+
set_validators_directly(&[dave(), eve()], 1).unwrap();
236+
// By default, the session keys are not set for the account.
237+
assert_eq!(Session::load_keys(&dave().account_id()), None);
238+
assert_eq!(Session::load_keys(&eve().account_id()), None);
239+
increment_epoch();
240+
241+
start_session(1);
242+
243+
// After setting the keys, they should be stored in the session.
244+
assert_eq!(Session::load_keys(&dave().account_id()), Some(dave().authority_keys));
245+
assert_eq!(Session::load_keys(&eve().account_id()), Some(eve().authority_keys));
246+
247+
let eve_with_different_keys = MockValidator {
248+
name: "Eve with different keys",
249+
authority_keys: SessionKeys { foo: UintAuthorityId(44) },
250+
..eve()
251+
};
252+
253+
// Eve is re-elected to the committee, but is using different keys now
254+
set_validators_directly(&[dave(), eve_with_different_keys.clone()], 2).unwrap();
255+
increment_epoch();
256+
start_session(2);
257+
258+
// Eve's keys were updated
259+
assert_eq!(
260+
Session::load_keys(&eve().account_id()),
261+
Some(eve_with_different_keys.authority_keys)
262+
);
263+
});
264+
}
265+
212266
#[test]
213267
fn ends_two_sessions_and_rotates_once_when_committee_changes() {
214268
new_test_ext().execute_with(|| {

0 commit comments

Comments
 (0)