forked from MystenLabs/sui
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Consensus] add
Committee
type (MystenLabs#15455)
## Description Add `Committee` config and crypto key types to the `consensus-config` crate. ## Test Plan CI --- If your changes are not user-facing and not a breaking change, you can skip the following section. Otherwise, please indicate what changed, and then add to the Release Notes section as highlighted during the release process. ### Type of Change (Check all that apply) - [ ] protocol change - [ ] user-visible impact - [ ] breaking change for a client SDKs - [ ] breaking change for FNs (FN binary must upgrade) - [ ] breaking change for validators or node operators (must upgrade binaries) - [ ] breaking change for on-chain data layout - [ ] necessitate either a data wipe or data migration ### Release notes
- Loading branch information
Showing
7 changed files
with
307 additions
and
2 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
// Copyright (c) Mysten Labs, Inc. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use std::fmt::{Display, Formatter}; | ||
|
||
use multiaddr::Multiaddr; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
use crate::{NetworkPublicKey, ProtocolPublicKey}; | ||
|
||
/// Committee of the consensus protocol is updated each epoch. | ||
pub type Epoch = u64; | ||
|
||
/// Voting power of an authority, roughly proportional to the actual amount of Sui staked | ||
/// by the authority. | ||
/// Total stake / voting power of all authorities should sum to 10,000. | ||
pub type Stake = u64; | ||
|
||
/// Committee is the set of authorities that participate in the consensus protocol for this epoch. | ||
/// Its configuration is stored and computed on chain. | ||
#[derive(Serialize, Deserialize)] | ||
pub struct Committee { | ||
/// The epoch number of this committee | ||
epoch: Epoch, | ||
/// Total stake in the committee. | ||
total_stake: Stake, | ||
/// The quorum threshold (2f+1). | ||
quorum_threshold: Stake, | ||
/// The validity threshold (f+1). | ||
validity_threshold: Stake, | ||
/// Protocol and network info of each authority. | ||
authorities: Vec<Authority>, | ||
} | ||
|
||
impl Committee { | ||
pub fn new(epoch: Epoch, authorities: Vec<Authority>) -> Self { | ||
assert!(!authorities.is_empty(), "Committee cannot be empty!"); | ||
assert!( | ||
authorities.len() < u32::MAX as usize, | ||
"Too many authorities ({})!", | ||
authorities.len() | ||
); | ||
let total_stake = authorities.iter().map(|a| a.stake).sum(); | ||
assert_ne!(total_stake, 0, "Total stake cannot be zero!"); | ||
let quorum_threshold = 2 * total_stake / 3 + 1; | ||
let validity_threshold = (total_stake + 2) / 3; | ||
Self { | ||
epoch, | ||
total_stake, | ||
quorum_threshold, | ||
validity_threshold, | ||
authorities, | ||
} | ||
} | ||
|
||
/// Public accessors for Committee data. | ||
pub fn epoch(&self) -> Epoch { | ||
self.epoch | ||
} | ||
|
||
pub fn total_stake(&self) -> Stake { | ||
self.total_stake | ||
} | ||
|
||
pub fn quorum_threshold(&self) -> Stake { | ||
self.quorum_threshold | ||
} | ||
|
||
pub fn validity_threshold(&self) -> Stake { | ||
self.validity_threshold | ||
} | ||
|
||
pub fn stake(&self, authority_index: AuthorityIndex) -> Stake { | ||
self.authorities[authority_index.value()].stake | ||
} | ||
|
||
pub fn authority(&self, authority_index: AuthorityIndex) -> &Authority { | ||
&self.authorities[authority_index.value()] | ||
} | ||
|
||
pub fn authorities(&self) -> impl Iterator<Item = (AuthorityIndex, &Authority)> { | ||
self.authorities | ||
.iter() | ||
.enumerate() | ||
.map(|(i, a)| (AuthorityIndex(i as u32), a)) | ||
} | ||
|
||
pub fn size(&self) -> usize { | ||
self.authorities.len() | ||
} | ||
} | ||
|
||
/// Represents one authority in the committee. | ||
/// | ||
/// NOTE: this is intentionally un-cloneable, to encourage only copying relevant fields. | ||
/// AuthorityIndex should be used to reference an authority instead. | ||
#[derive(Serialize, Deserialize)] | ||
pub struct Authority { | ||
/// Voting power of the authority in the committee. | ||
pub stake: Stake, | ||
/// Network address for communicating with the authority. | ||
pub address: Multiaddr, | ||
/// The validator's hostname, for metrics and logging. | ||
pub hostname: String, | ||
/// The authority's ed25519 publicKey for signing network messages and blocks. | ||
pub network_key: NetworkPublicKey, | ||
/// The authority's bls public key for random beacon. | ||
pub protocol_key: ProtocolPublicKey, | ||
} | ||
|
||
/// Each authority is uniquely identified by its AuthorityIndex in the Committee. | ||
/// AuthorityIndex is between 0 (inclusive) and the total number of authorities (exclusive). | ||
/// | ||
/// NOTE: AuthorityIndex should not need to be created outside of this file or incremented. | ||
#[derive( | ||
Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug, Default, Hash, Serialize, Deserialize, | ||
)] | ||
pub struct AuthorityIndex(u32); | ||
|
||
impl AuthorityIndex { | ||
pub fn value(&self) -> usize { | ||
self.0 as usize | ||
} | ||
} | ||
|
||
impl Display for AuthorityIndex { | ||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | ||
f.write_str(self.0.to_string().as_str()) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use crate::{Authority, Committee, NetworkKeyPair, ProtocolKeyPair, Stake}; | ||
use fastcrypto::traits::KeyPair as _; | ||
use multiaddr::Multiaddr; | ||
use rand::{rngs::StdRng, SeedableRng}; | ||
|
||
#[test] | ||
fn committee_basic() { | ||
// GIVEN | ||
let epoch = 100; | ||
|
||
let mut authorities = vec![]; | ||
let mut rng = StdRng::from_seed([9; 32]); | ||
let num_of_authorities = 9; | ||
for i in 1..=num_of_authorities { | ||
let network_keypair = NetworkKeyPair::generate(&mut rng); | ||
let protocol_keypair = ProtocolKeyPair::generate(&mut rng); | ||
authorities.push(Authority { | ||
stake: i as Stake, | ||
address: Multiaddr::empty(), | ||
hostname: "test_host".to_string(), | ||
network_key: network_keypair.public().clone(), | ||
protocol_key: protocol_keypair.public().clone(), | ||
}); | ||
} | ||
|
||
let committee = Committee::new(epoch, authorities); | ||
|
||
// THEN make sure the output Committee fields are populated correctly. | ||
assert_eq!(committee.size(), num_of_authorities); | ||
for (i, authority) in committee.authorities() { | ||
assert_eq!((i.value() + 1) as Stake, authority.stake); | ||
} | ||
|
||
// AND ensure thresholds are calculated correctly. | ||
assert_eq!(committee.total_stake(), 45); | ||
assert_eq!(committee.quorum_threshold(), 31); | ||
assert_eq!(committee.validity_threshold(), 15); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// Copyright (c) Mysten Labs, Inc. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use fastcrypto::{bls12381, ed25519}; | ||
|
||
//////////////////////////////////////////////////////////////////////// | ||
// Type aliases selecting the cryptography algorithms for the code base. | ||
//////////////////////////////////////////////////////////////////////// | ||
// Here we select the types that are used by default in the code base. | ||
// The whole code base should only: | ||
// - refer to those aliases and not use the individual scheme implementations | ||
// - not use the schemes in a way that break genericity (e.g. using their Struct impl functions) | ||
// - swap one of those aliases to point to another type if necessary | ||
// | ||
// Beware: if you change those aliases to point to another scheme implementation, you will have | ||
// to change all four aliases to point to concrete types that work with each other. Failure to do | ||
// so will result in a ton of compilation errors, and worse: it will not make sense! | ||
|
||
/// Network key signs network messages and blocks. | ||
pub type NetworkPublicKey = ed25519::Ed25519PublicKey; | ||
pub type NetworkPrivateKey = ed25519::Ed25519PrivateKey; | ||
pub type NetworkKeyPair = ed25519::Ed25519KeyPair; | ||
|
||
/// Protocol key is used in random beacon. | ||
pub type ProtocolPublicKey = bls12381::min_sig::BLS12381PublicKey; | ||
pub type ProtocolPublicKeyBytes = bls12381::min_sig::BLS12381PublicKeyAsBytes; | ||
pub type ProtocolPrivateKey = bls12381::min_sig::BLS12381PrivateKey; | ||
pub type ProtocolKeyPair = bls12381::min_sig::BLS12381KeyPair; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,10 @@ | ||
// Copyright (c) Mysten Labs, Inc. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
pub mod parameters; | ||
mod committee; | ||
mod crypto; | ||
mod parameters; | ||
|
||
pub use parameters::Parameters; | ||
pub use committee::*; | ||
pub use crypto::*; | ||
pub use parameters::*; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// Copyright (c) Mysten Labs, Inc. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use consensus_config::{Authority, Committee, NetworkKeyPair, ProtocolKeyPair, Stake}; | ||
use fastcrypto::traits::KeyPair as _; | ||
use insta::assert_yaml_snapshot; | ||
use multiaddr::Multiaddr; | ||
use rand::{rngs::StdRng, SeedableRng as _}; | ||
|
||
// Committee is not sent over network or stored on disk itself, but some of its fields are. | ||
// So this test can still be useful to detect accidental format changes. | ||
#[test] | ||
fn committee_snapshot_matches() { | ||
let epoch = 100; | ||
|
||
let mut authorities: Vec<_> = vec![]; | ||
let mut rng = StdRng::from_seed([9; 32]); | ||
let num_of_authorities = 10; | ||
for i in 1..=num_of_authorities { | ||
let network_keypair = NetworkKeyPair::generate(&mut rng); | ||
let protocol_keypair = ProtocolKeyPair::generate(&mut rng); | ||
authorities.push(Authority { | ||
stake: i as Stake, | ||
address: Multiaddr::empty(), | ||
hostname: "test_host".to_string(), | ||
network_key: network_keypair.public().clone(), | ||
protocol_key: protocol_keypair.public().clone(), | ||
}); | ||
} | ||
|
||
let committee = Committee::new(epoch, authorities); | ||
|
||
assert_yaml_snapshot!("committee", committee) | ||
} |
60 changes: 60 additions & 0 deletions
60
consensus/config/tests/snapshots/committee_test__committee.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
--- | ||
source: consensus/config/tests/committee_test.rs | ||
expression: committee | ||
--- | ||
epoch: 100 | ||
total_stake: 55 | ||
quorum_threshold: 37 | ||
validity_threshold: 19 | ||
authorities: | ||
- stake: 1 | ||
address: "" | ||
hostname: test_host | ||
network_key: lscBzpFcgepvETNDWHp61B+teyauHrk6kb5XBszDufg= | ||
protocol_key: tembhBjGw+XVGXywAYDja1R67d8pSKGhYypbgeRUJmTTdzfNnr/LHJ3U0bZY49ChGXw6mKwBVJV4KP3na8YFaef9wQuHKgwjvhJT3FnimCPyBwIz4cFasq1d3As4/yeP | ||
- stake: 2 | ||
address: "" | ||
hostname: test_host | ||
network_key: VnXFtZxaTby9AquydHFr9dy8+GlVoPcsm8icljGTbWQ= | ||
protocol_key: hLIJiig6cqajwuIlnxjL+bxhZxCgEWUGdN9VyJSqMAvuN6tDm7qTcBplvDICmgSlGJwHZ5IzyOH6N+Wj1Fa1odxsM86eLf9g+MjzT/h869sqV9EpyXtpYbufPYCW0fkT | ||
- stake: 3 | ||
address: "" | ||
hostname: test_host | ||
network_key: +yTI/ZSBZa9CmHP/Qhjtf2bgTR0lC+9NUP8BgQq0OPw= | ||
protocol_key: kci5lWPW4LlAr1jLSyEkGtYeSfstp3daJ0pChi5zo4KaDOOQd7IbnRPyP/zMqkfTE9MIyymjSkhnI72/Wogbqedrc5lhIp+C2wtbv79mdC8SrbHb2Y/LHvYD7w1mOJFM | ||
- stake: 4 | ||
address: "" | ||
hostname: test_host | ||
network_key: TLb93AG1NlYtf9dVMnS6LJE5aRfqt2LsSBJeuoa3wHk= | ||
protocol_key: onGDFBk46p2hpQFq3QJbyAVD0G05FOxRaJQH3LacRTRRfdXWLtewyUi1Z0MMX4H3CpoldjqoGeMbESvqgTZeKt6HE3d8pn6TApMzf632WI3DfUGUUMBM7ciCivNaKTBS | ||
- stake: 5 | ||
address: "" | ||
hostname: test_host | ||
network_key: 7DYZ4De7EKRhhH0GBMTKlBqUeXnFMgkzLKjekMAuesw= | ||
protocol_key: iM3E2wCApVtOKv1I/jSpNXO1kPRCnHo0c6H/qgyxvJngmgW1KYnWtycts8drNLIUGLtinT83V8D3Xnc3whUAqiKYrJ5vu2knQXqFBCmgrqo7N0xZ0T/uuKVWjoNqyHHl | ||
- stake: 6 | ||
address: "" | ||
hostname: test_host | ||
network_key: B2I7VErvTa/POXtLemf+iDEt/966mNqq3F+DdHcvi8U= | ||
protocol_key: pEiGWt/9mL2YXfHkYntXWy7OzGdS1psbJQ2D5Xp5FS7XZWYQzh7+zz/bkOfgWCRaFoV8bbsmb7eVwuMvOTnPvCSamtyUQ3pc+SKVTsXtRbwRNvWtXjTVHGQQSXE5R1kp | ||
- stake: 7 | ||
address: "" | ||
hostname: test_host | ||
network_key: wCXBPdpdazlmPWntDXu+LQJiJZb72na9EY3njPLgBGY= | ||
protocol_key: irfuZhbsh3mvm53TmiAPGWzDUEmr89RhBBtwNGwZOW36BOaSpxcgOZXfrOPTJDstDFU+o1XRq2T0t39P4tKagKjC50TFtMSVFU/4Qf6bHqEPzuZiOtCa3W3mKQUXz8wE | ||
- stake: 8 | ||
address: "" | ||
hostname: test_host | ||
network_key: +0ebVcUY7X8QIafWGbUmzlhy/Vc2LtNRqqLzk4NgLoU= | ||
protocol_key: jDvXpT0oTY7w9BWERszWiLBu9Aajj9WbbPkfmE9M+ijxGCooLK14P1lsqOZ67XMoAIfh8Z5t/hNanV5fH+3PtJT6o8APO5pCoTcLi5SoScRSQKMCevHqHAizI57wG4cl | ||
- stake: 9 | ||
address: "" | ||
hostname: test_host | ||
network_key: YxoEz+3fDnLfrOkpqVkRxfj/HqlqsoQqt9bzSLjxJEc= | ||
protocol_key: iIEIwu3rHEXU1fy+2VNUKjqV2tFLcu35a5Uo+qO99rQ63nywUvOsiDxrUvzOpJYoDZ/Xa4PnzgkhFTiGVi/Qt6ASIBhu/66jjxhDs6Pt7h1CtRFnD3zWRkgYinIzmxuQ | ||
- stake: 10 | ||
address: "" | ||
hostname: test_host | ||
network_key: lT6jnl+ZiC2MhDfooUetAJFDd6cRQy1Lq9KKjKqOevo= | ||
protocol_key: lxvqS7Rm/l8gmFj6Q3CJ3Qv994gzsM/hSt5YoBrE8v4UmfoyuvQ0JQ9gw2qNbMuiDwvkCAxotLiCa0yjKjZe5Kk8QS37dGZw5akNHQ2SHkc+CK7bccWVkdfRnF4iQal5 | ||
|