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

Feat/multiple commits #599

Closed
wants to merge 14 commits into from

Conversation

distributedstatemachine
Copy link
Collaborator

@distributedstatemachine distributedstatemachine commented Jul 1, 2024

Description

Motivation for change

The current weight commitment system lacks flexibility and doesn't allow validators to queue multiple weight updates. This limitation can lead to inefficiencies in the network, especially during periods of high activity or when validators need to make rapid adjustments to their weights.

Behaviour pre-change

  • Validators could only commit and reveal one set of weights at a time.
  • There was no mechanism to handle multiple commits or to enforce the order of processing.
  • Old commits were not automatically removed, potentially leading to storage bloat.

Behaviour post-change

  • Validators can now commit multiple weight updates, which are processed in a First-In-First-Out (FIFO) order.
  • A nonce system has been introduced to ensure monotonicity and prevent replay attacks.
  • The system now enforces a limit of 10 pending commits per validator, automatically removing the oldest commit when this limit is reached.
  • Old commits are now automatically removed after successful processing, improving storage efficiency.
  • The do_commit_weights function now checks for nonce monotonicity and prevents duplicate nonces within the current interval.

Alternatives considered

  1. Batch commits: We considered allowing validators to submit multiple weight updates in a single transaction. This was rejected due to increased complexity in processing and potential issues with transaction size limits.

  2. Time-based expiry: An alternative to the FIFO system was to expire commits based on time. This was not implemented as it could lead to issues with network congestion and block time variations.

  3. Unlimited commits: We considered allowing unlimited pending commits per validator. This was rejected to prevent potential DoS attacks and to limit storage usage.

Related Issue(s)

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Other (please describe):

##Breaking Change

If this PR introduces a breaking change, please provide a detailed description of the impact and the migration path for existing applications.

Checklist

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have run cargo fmt and cargo clippy to ensure my code is formatted and linted correctly
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Screenshots (if applicable)

Please include any relevant screenshots or GIFs that demonstrate the changes made.

Additional Notes

Please provide any additional information or context that may be helpful for reviewers.

pallets/subtensor/src/benchmarks.rs Outdated Show resolved Hide resolved
pallets/subtensor/src/errors.rs Outdated Show resolved Hide resolved
Comment on lines 923 to 931
pub type WeightCommits<T: Config> = StorageDoubleMap<
_,
Twox64Concat,
u16,
u16, // netuid
Twox64Concat,
T::AccountId,
(H256, u64),
OptionQuery,
BTreeMap<u64, (H256, u64)>, // nonce -> (hash, block_number)
ValueQuery,
>;
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this need a migration?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

done. Can you please review the implementation and test

Copy link
Contributor

Choose a reason for hiding this comment

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

Looks good, you should also

pallets/subtensor/src/lib.rs Show resolved Hide resolved
pallets/subtensor/src/weights.rs Outdated Show resolved Hide resolved
),
Error::<Test>::InvalidRevealCommitHashNotMatch
);
});
}

#[test]
fn test_multiple_commit_reveal() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Also test for out-of-order reveal.

pallets/subtensor/src/migration.rs Outdated Show resolved Hide resolved
Comment on lines 923 to 931
pub type WeightCommits<T: Config> = StorageDoubleMap<
_,
Twox64Concat,
u16,
u16, // netuid
Twox64Concat,
T::AccountId,
(H256, u64),
OptionQuery,
BTreeMap<u64, (H256, u64)>, // nonce -> (hash, block_number)
ValueQuery,
>;
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks good, you should also

pallets/subtensor/src/lib.rs Show resolved Hide resolved
pallets/subtensor/src/migration.rs Outdated Show resolved Hide resolved
Comment on lines 58 to 59
let last_processed_nonce = Self::get_last_processed_nonce(netuid, &who);
ensure!(nonce > last_processed_nonce, Error::<T>::NonMonotonicNonce);
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you brick your subnet by using a nonce that's u64 max? Should we enforce cur nonce + 1 instead?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

You couldnt brick your subnet by doing this , what would happen is that you would brick your validator , as the nonces are per validator, not subnet

pallets/subtensor/src/weights.rs Outdated Show resolved Hide resolved
Comment on lines 551 to 570
/// Get the last processed nonce for a given netuid and account
///
/// # Arguments
///
/// * `netuid` - The network ID
/// * `account` - The account ID
///
/// # Returns
///
/// Returns the last processed nonce for the given netuid and account, or 0 if not found
///
/// # Note
///
/// This function is used to retrieve the last nonce that was processed for a specific account
/// in a specific subnet. It's crucial for maintaining the order of transactions and
/// preventing replay attacks.
pub fn get_last_processed_nonce(netuid: u16, account: &T::AccountId) -> u64 {
LastProcessedNonce::<T>::get(netuid, account)
// ^ If no nonce is found, we return 0 as the default value
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should just use LastProcessedNonce::<T>::get(netuid, account) directly in-line in our code, instead of adding all this boilerplate

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We have not decided on whether or not to start accessing storage values directly in code , and this follows the current pattern of creating getters and setters for storage values.

Comment on lines 572 to 592
/// Set the last processed nonce for a given netuid and account
///
/// # Arguments
///
/// * `netuid` - The network ID
/// * `account` - The account ID
/// * `nonce` - The nonce to set
///
/// # Note
///
/// This function updates the last processed nonce for a specific account in a specific subnet.
/// It's important for maintaining the state of processed transactions and ensuring
/// that each nonce is only processed once.
///
/// # TODO
///
/// Consider adding error handling or logging for cases where the nonce update fails.
pub fn set_last_processed_nonce(netuid: u16, account: &T::AccountId, nonce: u64) {
LastProcessedNonce::<T>::insert(netuid, account, nonce);
// ^ This operation overwrites any existing nonce for the given netuid and account
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should just use LastProcessedNonce::<T>::insert(netuid, account, nonce) directly in-line in our code, instead of adding all this boilerplate

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

same as above

sam0x17
sam0x17 previously approved these changes Sep 4, 2024
Copy link
Contributor

@sam0x17 sam0x17 left a comment

Choose a reason for hiding this comment

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

everything looks solid to me

ensure!(!commits.contains_key(&nonce), Error::<T>::DuplicateNonce);

// Check if there are already 10 commits
if commits.len() >= 10 {
Copy link
Contributor

Choose a reason for hiding this comment

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

do we want to maybe make this configurable and/or are we happy with 10?

Copy link
Contributor

Choose a reason for hiding this comment

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

The commit-reveal interval duration is configurable per subnet so I think the maximum commits within that interval should be customizable as well.

JohnReedV
JohnReedV previously approved these changes Sep 4, 2024
@sam0x17
Copy link
Contributor

sam0x17 commented Sep 5, 2024

bunch of merge conflicts now btw

@distributedstatemachine distributedstatemachine changed the base branch from main to devnet-ready September 5, 2024 17:04
@distributedstatemachine distributedstatemachine dismissed stale reviews from JohnReedV and sam0x17 September 5, 2024 17:04

The base branch was changed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Enhance Commit/Reveal Mechanism to Allow Multiple Pending Commits
7 participants