Skip to content

Commit 07918ec

Browse files
authored
change: Correct handling of provided accounts for block producers (#1037)
1 parent 5074408 commit 07918ec

File tree

3 files changed

+69
-46
lines changed

3 files changed

+69
-46
lines changed

dev/local-environment/configurations/partner-chains-setup/entrypoint.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ echo "Inserting D parameter..."
7272
--ogmios-url http://ogmios:$OGMIOS_PORT \
7373
--genesis-utxo $GENESIS_UTXO \
7474
--permissioned-candidates-count 3 \
75-
--registered-candidates-count 2 \
75+
--registered-candidates-count 1 \
7676
--payment-key-file /keys/funded_address.skey
7777

7878
if [ $? -eq 0 ]; then

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ pub use weights::WeightInfo;
3939
#[frame_support::pallet]
4040
pub mod pallet {
4141
use super::*;
42-
use crate::pallet_session_support::provide_committee_accounts;
4342
use frame_support::pallet_prelude::*;
4443
use frame_system::pallet_prelude::*;
4544
use log::{info, warn};
@@ -48,6 +47,7 @@ pub mod pallet {
4847
use sp_core::blake2_256;
4948
use sp_runtime::traits::{MaybeSerializeDeserialize, One, Zero};
5049
use sp_session_validator_management::*;
50+
use sp_std::collections::btree_set::BTreeSet;
5151
use sp_std::fmt::Display;
5252
use sp_std::{ops::Add, vec::Vec};
5353

@@ -147,6 +147,10 @@ pub mod pallet {
147147
}
148148
}
149149

150+
#[pallet::storage]
151+
pub type ProvidedAccounts<T: Config> =
152+
StorageValue<_, BoundedBTreeSet<T::AccountId, T::MaxValidators>, ValueQuery>;
153+
150154
#[pallet::storage]
151155
pub type CurrentCommittee<T: Config> = StorageValue<
152156
_,
@@ -186,7 +190,14 @@ pub mod pallet {
186190
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
187191
fn build(&self) {
188192
let initial_authorities = BoundedVec::truncate_from(self.initial_authorities.clone());
189-
provide_committee_accounts::<T>(&initial_authorities);
193+
194+
let provided_accounts: BTreeSet<T::AccountId> =
195+
initial_authorities.iter().map(|m| m.authority_id().into()).collect();
196+
for account in &provided_accounts {
197+
frame_system::Pallet::<T>::inc_providers(&account);
198+
}
199+
ProvidedAccounts::<T>::set(provided_accounts.try_into().unwrap());
200+
190201
let committee_info =
191202
CommitteeInfo { epoch: T::ScEpochNumber::zero(), committee: initial_authorities };
192203
CurrentCommittee::<T>::put(committee_info);

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

Lines changed: 55 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,35 @@ where
3232
/// Updates the session index of [`pallet_session`].
3333
// Instead of Some((*).expect) we could just use (*). However, we rather panic in presence of important programming errors.
3434
fn new_session(new_index: SessionIndex) -> Option<Vec<T::AccountId>> {
35-
info!("Session manager: new_session {new_index}");
35+
info!("💼 Session manager: new_session {new_index}");
3636
let new_committee = crate::Pallet::<T>::rotate_committee_to_next_epoch().expect(
3737
"Session should never end without current epoch validators defined. \
3838
Check ShouldEndSession implementation or if it is used before starting new session",
3939
);
4040

41-
provide_committee_accounts::<T>(&new_committee);
42-
register_committee_keys::<T>(&new_committee);
41+
let old_committee_accounts = crate::ProvidedAccounts::<T>::take();
42+
let mut new_committee_accounts: BTreeSet<T::AccountId> = BTreeSet::new();
4343

44-
let new_committee_accounts =
45-
new_committee.into_iter().map(|member| member.authority_id().into()).collect();
44+
for member in new_committee.iter() {
45+
let account = member.authority_id().into();
4646

47-
Some(new_committee_accounts)
47+
if !new_committee_accounts.contains(&account) {
48+
new_committee_accounts.insert(account.clone());
49+
50+
// Members that were already in the old committee have their accounts and keys set up already
51+
if !old_committee_accounts.contains(&account) {
52+
setup_block_producer::<T>(account, member.authority_keys());
53+
}
54+
}
55+
}
56+
57+
for account in old_committee_accounts.difference(&new_committee_accounts) {
58+
teardown_block_producer::<T>(account)
59+
}
60+
61+
crate::ProvidedAccounts::<T>::set(new_committee_accounts.clone().try_into().unwrap());
62+
63+
Some(new_committee.into_iter().map(|member| member.authority_id().into()).collect())
4864
}
4965

5066
fn end_session(end_index: SessionIndex) {
@@ -58,51 +74,47 @@ where
5874
}
5975
}
6076

61-
// Registers keys of new committee members in the session pallet. This is necessary, as the pallet
62-
// requires the keys to be registered prior to session start and we do not wish to force block
63-
// producers to do it manually.
64-
fn register_committee_keys<T: crate::Config + pallet_session::Config>(
65-
new_committee: &[T::CommitteeMember],
77+
/// Provides accounts and registers keys for new committee members
78+
fn setup_block_producer<T: crate::Config + pallet_session::Config>(
79+
account: T::AccountId,
80+
keys: T::AuthorityKeys,
6681
) where
6782
<T as pallet_session::Config>::Keys: From<T::AuthorityKeys>,
6883
{
69-
let mut keys_added: BTreeSet<T::AccountId> = BTreeSet::new();
70-
for member in new_committee.iter() {
71-
let account_id = member.authority_id().into();
84+
log::debug!(
85+
"➕💼 Incrementing provider count and registering keys for block producer {account:?}"
86+
);
7287

73-
if keys_added.contains(&account_id) {
74-
continue;
75-
}
88+
frame_system::Pallet::<T>::inc_providers(&account);
7689

77-
keys_added.insert(account_id.clone());
78-
let call = pallet_session::Call::<T>::set_keys {
79-
keys: From::from(member.authority_keys()),
80-
proof: vec![],
81-
};
82-
let call_result = call.dispatch_bypass_filter(RawOrigin::Signed(account_id.clone()).into());
83-
match call_result {
84-
Ok(_) => debug!("set_keys for {account_id:?}"),
85-
Err(e) => info!("Could not set_keys for {account_id:?}, error: {:?}", e.error),
86-
}
90+
let set_keys_result = pallet_session::Call::<T>::set_keys { keys: keys.into(), proof: vec![] }
91+
.dispatch_bypass_filter(RawOrigin::Signed(account.clone()).into());
92+
93+
match set_keys_result {
94+
Ok(_) => debug!("set_keys for {account:?}"),
95+
Err(e) => {
96+
info!("Could not set_keys for {account:?}, error: {:?}", e.error)
97+
},
8798
}
8899
}
89100

90-
// Ensures that all accounts tied to new committee members exist by incrementing their
91-
// account provider counts. This is a necessary temporary solution, because we don't check
92-
// whether a block producer's account exists or not, when selecting them to a committee.
93-
// A proper solution would either be:
94-
// - increasing provider count for an account for as long as it is in the active committee
95-
// and decreasing it afterwards, or
96-
// - considering account existence when selecting the committee
97-
// This will be addressed in later development.
98-
pub(crate) fn provide_committee_accounts<T: crate::Config>(new_committee: &[T::CommitteeMember]) {
99-
let new_accs: BTreeSet<T::AccountId> =
100-
new_committee.iter().map(|m| m.authority_id().into()).collect();
101-
for account in new_accs {
102-
if !frame_system::Pallet::<T>::account_exists(&account) {
103-
frame_system::Pallet::<T>::inc_providers(&account);
104-
}
101+
/// Removes account provisions and purges keys for outgoing old committee members
102+
fn teardown_block_producer<T: crate::Config + pallet_session::Config>(account: &T::AccountId)
103+
where
104+
<T as pallet_session::Config>::Keys: From<T::AuthorityKeys>,
105+
{
106+
let purge_keys_result = pallet_session::Call::<T>::purge_keys {}
107+
.dispatch_bypass_filter(RawOrigin::Signed(account.clone()).into());
108+
match purge_keys_result {
109+
Ok(_) => debug!("purge_keys for {account:?}"),
110+
Err(e) => info!("Could not purge_keys for {account:?}, error: {:?}", e.error),
105111
}
112+
log::info!(
113+
"➖💼 Decrementing provider count and deregisteringkeys for block producer {account:?}"
114+
);
115+
frame_system::Pallet::<T>::dec_providers(&account).expect(
116+
"We always match dec_providers with corresponding inc_providers, thus it cannot fail",
117+
);
106118
}
107119

108120
/// Tries to end each session in the first block of each partner chains epoch in which the committee for the epoch is defined.
@@ -126,7 +138,7 @@ where
126138
false
127139
}
128140
} else {
129-
debug!("PalletSessionSupport: should_end_session({n:?}) = false");
141+
debug!("Session manager: should_end_session({n:?}) = false");
130142
false
131143
}
132144
}

0 commit comments

Comments
 (0)