Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrate signer changes dynamically #978

Merged
merged 12 commits into from
Aug 6, 2024

Conversation

JesseAbram
Copy link
Member

@JesseAbram JesseAbram commented Aug 2, 2024

  • Have next_signers and signers bounded by N in parameters
  • Has Jumpstart bounded by N

This also adds bounding to changing N in parameters, by only allowing 1 signer to be added per session, and in session if the signer size is increased it will add one new signer and not remove a signer instead of adding 2 new ones

@JesseAbram JesseAbram marked this pull request as ready for review August 5, 2024 16:56
Copy link
Contributor

@ameba23 ameba23 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🥇 Looks good.

@@ -64,6 +64,10 @@ pub const NETWORK_PARENT_KEY: &str = "NETWORK_PARENT_KEY_FOR_ENTROPY_";
/// Total signers on the network with the parent key
pub const TOTAL_SIGNERS: u8 = 3;

/// Max signers, for bounding of total signers for benches,
/// Can be changed but requires a re-run of benches
pub const MAX_SIGNERS: u8 = 15;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

);
let current_session = pallet_session::Pallet::<T>::current_index();
ensure!(
current_session >= old_signer_info.last_session_change,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be > rather than >=?

}

#[derive(Clone, Encode, Decode, Eq, PartialEqNoBound, RuntimeDebug, TypeInfo, Default)]
pub struct SignersSize {
pub threshold: u8,
pub total_signers: u8,
pub last_session_change: u32,
Copy link
Contributor

@ameba23 ameba23 Aug 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A doccomment would be nice. If i understood right this is the session index number of the last session in which threshold or total_signers changed.

signer_info.total_signers,
signer_info.threshold
),
Error::<Runtime>::OneChangePerSession,
Copy link
Contributor

@ameba23 ameba23 Aug 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If i understood right this tests that you cannot make a change when the current session is older than last_session_change (which is hopefully an impossible state to get into), but not that you cannot make two changes in the same session.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed as per your previous comment, good catch

// removes first signer and pushes new signer to back if total signers not increased
if current_signers.len() >= signers_info.total_signers as usize {
current_signers.remove(0);
}
current_signers.push(next_signer_up.clone());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if we decrease total_signers? I guess here we have a similar if as above, and only push the next_signer_up if total_signers did not decrease.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

});
assert_ok!(Staking::new_session_handler(&[6, 5, 3, 4]));
// Signer size increased is reflected as 5 is not removed from vec
assert_eq!(Staking::next_signers().unwrap().next_signers, vec![5, 6, 3]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we also want a test for decreasing signer size

Copy link
Collaborator

@HCastano HCastano left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a few comments and questions, but overall looks good 👍

}

#[derive(Clone, Encode, Decode, Eq, PartialEqNoBound, RuntimeDebug, TypeInfo, Default)]
pub struct SignersSize {
pub threshold: u8,
pub total_signers: u8,
pub last_session_change: u32,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can probably use the SessionIndex type directly here (which is typedef'd to a u32).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ya but then I would have to pull in sp-staking pallet, a whole new crate for one type does not seem worth it

pallets/parameters/src/lib.rs Outdated Show resolved Hide resolved
pallets/parameters/src/lib.rs Outdated Show resolved Hide resolved
pallets/parameters/src/lib.rs Outdated Show resolved Hide resolved
@@ -96,12 +100,19 @@ pub mod module {
ThresholdGreaterThenSigners,
/// Threhsold has to be more than 0
ThrehsoldTooLow,
/// Signers over max signers, can happen however needs a benchmark rerun
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What benchmark are you referring to here?

If it's the change_signers_info() one this isn't required. The extrinsic is of constant time and doesn't change based off the inputs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any bench that we loop over the signers, a few, like confirm_jump_start, confirm_reshare, anything with confirm mainly because it has to check if the current signer is in the signers struct which is O(n)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JesseAbram so these actually don't scale with the number of signers. In the case of confirm_jump_start_confirm() the c parameter doesn't influence the final weight. Also reading through the extrinsic we're only doing constant time storage queries, no loops.

Maybe can you point me to where the O(n) operations are happening?

);

assert_noop!(
Parameters::change_signers_info(RuntimeOrigin::root(), 8, signer_info.threshold),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of 8 here I would do something like new_threshold = old_signer_info.threshold + 2 and use that instead

@@ -327,7 +327,8 @@ pub mod pallet {
// ensure that registration was indeed successful.
//
// If it fails we'll need to allow another jumpstart.
if jump_start_info.confirmations.len() == (TOTAL_SIGNERS as usize - 1) {
let signers_amount = pallet_parameters::Pallet::<T>::signers_info().total_signers;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let signers_amount = pallet_parameters::Pallet::<T>::signers_info().total_signers;
let total_signers = pallet_parameters::Pallet::<T>::signers_info().total_signers;

For consistency

@@ -409,7 +409,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities {
pallet_parameters::GenesisConfig::<Test> {
request_limit: 5u32,
max_instructions_per_programs: 5u64,
total_signers: 5u8,
total_signers: 2u8,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would change this to 3 to match the Registry config, and then in the test change the total_signers to 4. This makes testing across the pallets more predictable

Comment on lines 386 to 394

pallet_parameters::SignersInfo::<Test>::put(SignersSize {
total_signers: 3,
threshold: 2,
last_session_change: 0,
});
assert_ok!(Staking::new_session_handler(&[6, 5, 3, 4]));
// Signer size increased is reflected as 5 is not removed from vec
assert_eq!(Staking::next_signers().unwrap().next_signers, vec![5, 6, 3]);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you be able to throw these (and the few lines of code above) into a separate test? While it does test the session handler behaviour, it's more of specific test related to the management of the signers at the session boundary

@@ -64,6 +64,10 @@ pub const NETWORK_PARENT_KEY: &str = "NETWORK_PARENT_KEY_FOR_ENTROPY_";
/// Total signers on the network with the parent key
pub const TOTAL_SIGNERS: u8 = 3;

/// Max signers, for bounding of total signers for benches,
/// Can be changed but requires a re-run of benches
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Can be changed but requires a re-run of benches

Similar thing here, if I'm thinking of the right extrinsic it's constant time

@JesseAbram JesseAbram merged commit 7454094 into master Aug 6, 2024
14 checks passed
@JesseAbram JesseAbram deleted the incorporated-max-signers-dynamically branch August 6, 2024 16:55
@github-actions github-actions bot locked and limited conversation to collaborators Aug 6, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants