-
Notifications
You must be signed in to change notification settings - Fork 305
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
staking: enshrine consensus key indexing requirement in unit-test (#4148
- Loading branch information
Showing
5 changed files
with
142 additions
and
22 deletions.
There are no files selected for viewing
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
104 changes: 104 additions & 0 deletions
104
crates/core/component/stake/src/component/stake/tests.rs
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,104 @@ | ||
use anyhow::ensure; | ||
use cnidarium::{StateDelta, TempStorage}; | ||
use decaf377_rdsa::SigningKey; | ||
use rand_core::OsRng; | ||
use tendermint::PublicKey; | ||
|
||
use crate::{ | ||
component::{stake::address::validator_address, validator_handler::ValidatorDataRead}, | ||
IdentityKey, StateWriteExt, | ||
}; | ||
|
||
#[tokio::test] | ||
/// Test that we do not delete rotated consensus keys from the [consensus key -> identity key] index.A | ||
/// This is important to maintain because we want to be able to resolve byzantine evidence to a validator's | ||
/// persistent identity even if they have rotated their consensus keys. | ||
async fn test_persistent_identity_by_ck() -> anyhow::Result<()> { | ||
let _ = tracing_subscriber::fmt::try_init(); | ||
let storage = TempStorage::new().await?; | ||
let mut state = StateDelta::new(storage.latest_snapshot()); | ||
|
||
let rng = OsRng; | ||
let persistent_identity = IdentityKey(SigningKey::new(rng).into()); | ||
|
||
let old_ck_raw = ed25519_consensus::SigningKey::new(rng) | ||
.verification_key() | ||
.to_bytes(); | ||
let new_ck_raw = ed25519_consensus::SigningKey::new(rng) | ||
.verification_key() | ||
.to_bytes(); | ||
|
||
let old_ck = PublicKey::from_raw_ed25519(&old_ck_raw).expect("valid vk"); | ||
let new_ck = PublicKey::from_raw_ed25519(&new_ck_raw).expect("valid vk"); | ||
anyhow::ensure!( | ||
old_ck.to_hex() != new_ck.to_hex(), | ||
"the keys must encode to different hex strings for the test to be useful" | ||
); | ||
|
||
let old_address = validator_address(&old_ck); | ||
let new_address = validator_address(&new_ck); | ||
|
||
state.register_consensus_key(&persistent_identity, &old_ck); | ||
|
||
let retrieved_ck = state | ||
.lookup_consensus_key_by_comet_address(&old_address) | ||
.await | ||
.expect("key is registered"); | ||
|
||
ensure!( | ||
retrieved_ck == old_ck, | ||
"the retrieved consensus key must match the initial ck" | ||
); | ||
|
||
let retrieved_id = state | ||
.lookup_identity_key_by_consensus_key(&retrieved_ck) | ||
.await | ||
.expect("key is found"); | ||
ensure!( | ||
retrieved_id == persistent_identity, | ||
"the retrieved identity must match its persistent identity" | ||
); | ||
|
||
state.register_consensus_key(&persistent_identity, &new_ck); | ||
// We want to do a basic check that we can reach for the updated values | ||
// but CRUCIALLY, we want to make sure that we can associate an identity to | ||
// the old consenus key. | ||
let retrieved_ck = state | ||
.lookup_consensus_key_by_comet_address(&new_address) | ||
.await | ||
.expect("key is registered"); | ||
ensure!( | ||
retrieved_ck == new_ck, | ||
"we must be able to find the updated ck" | ||
); | ||
|
||
let retrieved_id = state | ||
.lookup_identity_key_by_consensus_key(&retrieved_ck) | ||
.await | ||
.expect("key is found"); | ||
ensure!( | ||
retrieved_id == persistent_identity, | ||
"the retrieved id must match the persistent identity, even after an update" | ||
); | ||
|
||
// CRUCIAL PART: can we find the persistent identity from a rotated comet address/consensus key? | ||
let culprit_ck = state | ||
.lookup_consensus_key_by_comet_address(&old_address) | ||
.await | ||
.expect("key must be found!"); | ||
ensure!( | ||
culprit_ck == old_ck, | ||
"the old address must be associated with the old ck" | ||
); | ||
|
||
let culprit_id = state | ||
.lookup_identity_key_by_consensus_key(&culprit_ck) | ||
.await | ||
.expect("consensus key -> identity index is persistent across validator updates"); | ||
ensure!( | ||
culprit_id == persistent_identity, | ||
"the retrieved identity must match the persistent identity that we setup" | ||
); | ||
|
||
Ok(()) | ||
} |
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