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

tests(app): 😌 deduplicate staking test boilerplate #4173

Merged
merged 3 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions crates/core/app/src/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,30 @@ impl DomainType for AppState {
type Proto = pb::GenesisAppState;
}

impl Content {
pub fn with_epoch_duration(self, epoch_duration: u64) -> Self {
Self {
sct_content: penumbra_sct::genesis::Content {
sct_params: penumbra_sct::params::SctParameters { epoch_duration },
},
..self
}
}

pub fn with_unbonding_delay(self, unbonding_delay: u64) -> Self {
Self {
stake_content: penumbra_stake::genesis::Content {
stake_params: penumbra_stake::params::StakeParameters {
unbonding_delay,
..self.stake_content.stake_params
},
..self.stake_content
},
..self
}
}
}

#[cfg(test)]
mod test {
use super::*;
Expand Down
57 changes: 18 additions & 39 deletions crates/core/app/tests/app_can_define_and_delegate_to_a_validator.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
mod common;

use {
self::common::BuilderExt,
anyhow::{anyhow, Context},
self::common::{BuilderExt, TestNodeExt},
anyhow::anyhow,
cnidarium::TempStorage,
decaf377_rdsa::{SigningKey, SpendAuth, VerificationKey},
penumbra_app::{genesis::AppState, server::consensus::Consensus},
penumbra_app::{
genesis::{self, AppState},
server::consensus::Consensus,
},
penumbra_keys::test_keys,
penumbra_mock_client::MockClient,
penumbra_mock_consensus::TestNode,
Expand All @@ -19,6 +20,8 @@ use {
tracing::{error_span, info, Instrument},
};

mod common;

/// The length of the [`penumbra_sct`] epoch.
cratelyn marked this conversation as resolved.
Show resolved Hide resolved
///
/// This test relies on many epochs turning over, so we will work with a shorter epoch duration.
Expand All @@ -31,14 +34,8 @@ async fn app_can_define_and_delegate_to_a_validator() -> anyhow::Result<()> {
let storage = TempStorage::new().await?;

// Configure an AppState with slightly shorter epochs than usual.
let app_state = AppState::Content(penumbra_app::genesis::Content {
sct_content: penumbra_sct::genesis::Content {
sct_params: penumbra_sct::params::SctParameters {
epoch_duration: EPOCH_DURATION,
},
},
..Default::default()
});
let app_state =
AppState::Content(genesis::Content::default().with_epoch_duration(EPOCH_DURATION));

// Start the test node.
let mut node = {
Expand All @@ -58,24 +55,16 @@ async fn app_can_define_and_delegate_to_a_validator() -> anyhow::Result<()> {

// Fast forward to the next epoch.
let snapshot_start = storage.latest_snapshot();
node.fast_forward(EPOCH_DURATION)
.instrument(error_span!("fast forwarding test node to second epoch"))
.await
.context("fast forwarding {EPOCH_LENGTH} blocks")?;
node.fast_forward_to_next_epoch(&storage).await?;
let snapshot_end = storage.latest_snapshot();

// Retrieve the validator definition from the latest snapshot.
let existing_validator = match snapshot_end
.validator_definitions()
.tap(|_| info!("getting validator definitions"))
let [existing_validator_id] = storage
.latest_snapshot()
.validator_identity_keys()
.await?
.as_slice()
{
[v] => v.clone(),
unexpected => panic!("there should be one validator, got: {unexpected:?}"),
};

let existing_validator_id = existing_validator.identity_key;
.try_into()
.map_err(|keys| anyhow::anyhow!("expected one key, got: {keys:?}"))?;

// Check that we are now in a new epoch.
{
Expand Down Expand Up @@ -340,12 +329,7 @@ async fn app_can_define_and_delegate_to_a_validator() -> anyhow::Result<()> {
};

// Fast forward to the next epoch.
node.fast_forward(EPOCH_DURATION)
.instrument(error_span!(
"fast forwarding test node to epoch after delegation"
))
.await
.context("fast forwarding {EPOCH_LENGTH} blocks")?;
node.fast_forward_to_next_epoch(&storage).await?;
let post_delegate_next_epoch_snapshot = storage.latest_snapshot();

// Show that now, after an epoch and with a delegation, the validator is marked active.
Expand Down Expand Up @@ -491,12 +475,7 @@ async fn app_can_define_and_delegate_to_a_validator() -> anyhow::Result<()> {
});

// Fast forward to the next epoch.
node.fast_forward(EPOCH_DURATION)
.instrument(error_span!(
"fast forwarding test node to epoch after undelegation"
))
.await
.context("fast forwarding {EPOCH_LENGTH} blocks")?;
node.fast_forward_to_next_epoch(&storage).await?;
let post_undelegate_next_epoch_snapshot = storage.latest_snapshot();

// Show that after undelegating, the validator is no longer marked active.
Expand Down
58 changes: 19 additions & 39 deletions crates/core/app/tests/app_can_undelegate_from_a_validator.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
use penumbra_num::fixpoint::U128x128;

mod common;

use {
self::common::BuilderExt,
self::common::{BuilderExt, TestNodeExt},
anyhow::anyhow,
ark_ff::UniformRand,
cnidarium::TempStorage,
penumbra_app::{genesis::AppState, server::consensus::Consensus},
penumbra_app::{
genesis::{self, AppState},
server::consensus::Consensus,
},
penumbra_keys::test_keys,
penumbra_mock_client::MockClient,
penumbra_mock_consensus::TestNode,
penumbra_num::fixpoint::U128x128,
penumbra_proto::DomainType,
penumbra_sct::component::clock::EpochRead as _,
penumbra_stake::{
component::validator_handler::ValidatorDataRead as _, validator::Validator,
UndelegateClaimPlan,
},
penumbra_stake::{component::validator_handler::ValidatorDataRead as _, UndelegateClaimPlan},
penumbra_transaction::{
memo::MemoPlaintext, plan::MemoPlan, TransactionParameters, TransactionPlan,
},
Expand All @@ -25,6 +22,8 @@ use {
tracing::{error_span, info, Instrument},
};

mod common;

/// The length of the [`penumbra_sct`] epoch.
///
/// This test relies on many epochs turning over, so we will work with a shorter epoch duration.
Expand Down Expand Up @@ -58,21 +57,11 @@ async fn app_can_undelegate_from_a_validator() -> anyhow::Result<()> {
};

// Configure an AppState with slightly shorter epochs than usual.
let app_state = AppState::Content(penumbra_app::genesis::Content {
sct_content: penumbra_sct::genesis::Content {
sct_params: penumbra_sct::params::SctParameters {
epoch_duration: EPOCH_DURATION,
},
},
stake_content: penumbra_stake::genesis::Content {
stake_params: penumbra_stake::params::StakeParameters {
unbonding_delay: UNBONDING_DELAY,
..Default::default()
},
..Default::default()
},
..Default::default()
});
let app_state = AppState::Content(
genesis::Content::default()
.with_epoch_duration(EPOCH_DURATION)
.with_unbonding_delay(UNBONDING_DELAY),
);

Comment on lines -61 to +64
Copy link
Contributor Author

Choose a reason for hiding this comment

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

a nice example of these methods simplifying test setup.

// Start the test node.
let mut node = {
Expand All @@ -85,16 +74,12 @@ async fn app_can_undelegate_from_a_validator() -> anyhow::Result<()> {
}?;

// Retrieve the validator definition from the latest snapshot.
let Validator { identity_key, .. } = match storage
let [identity_key] = storage
.latest_snapshot()
.validator_definitions()
.tap(|_| info!("getting validator definitions"))
.validator_identity_keys()
.await?
.as_slice()
{
[v] => v.clone(),
unexpected => panic!("there should be one validator, got: {unexpected:?}"),
}; // ..and note the asset id for delegation tokens tied to this validator.
.try_into()
.map_err(|keys| anyhow::anyhow!("expected one key, got: {keys:?}"))?;
let delegate_token_id = penumbra_stake::DelegationToken::new(identity_key).id();

// Sync the mock client, using the test wallet's spend key, to the latest snapshot.
Expand Down Expand Up @@ -203,12 +188,7 @@ async fn app_can_undelegate_from_a_validator() -> anyhow::Result<()> {
}

// Fast forward to the next epoch.
{
let start = get_latest_epoch().await.index;
while get_latest_epoch().await.index < start {
node.block().execute().await?;
}
}
node.fast_forward_to_next_epoch(&storage).await?;

// Build a transaction that will now undelegate from the validator.
let undelegate_rate = storage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@ use {
cnidarium::TempStorage,
penumbra_app::{genesis::AppState, server::consensus::Consensus},
penumbra_mock_consensus::TestNode,
penumbra_stake::{
component::validator_handler::validator_store::ValidatorDataRead, validator::Validator,
},
penumbra_stake::component::validator_handler::validator_store::ValidatorDataRead,
tap::Tap,
tracing::{error_span, info, trace, Instrument},
tracing::{error_span, trace, Instrument},
};

#[tokio::test]
Expand All @@ -31,16 +29,12 @@ async fn app_tracks_uptime_for_genesis_validator_missing_blocks() -> anyhow::Res
}?;

// Retrieve the validator definition from the latest snapshot.
let Validator { identity_key, .. } = match storage
let [identity_key] = storage
.latest_snapshot()
.validator_definitions()
.tap(|_| info!("getting validator definitions"))
.validator_identity_keys()
.await?
.as_slice()
{
[v] => v.clone(),
unexpected => panic!("there should be one validator, got: {unexpected:?}"),
};
.try_into()
.map_err(|keys| anyhow::anyhow!("expected one key, got: {keys:?}"))?;
let get_uptime = || async {
storage
.latest_snapshot()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
mod common;

use {
self::common::BuilderExt,
anyhow::Context,
cnidarium::TempStorage,
penumbra_app::{genesis::AppState, server::consensus::Consensus},
penumbra_mock_consensus::TestNode,
penumbra_stake::{
component::validator_handler::validator_store::ValidatorDataRead, validator::Validator,
},
penumbra_stake::component::validator_handler::validator_store::ValidatorDataRead,
tap::Tap,
tracing::{error_span, info, Instrument},
tracing::{error_span, Instrument},
};

mod common;

#[tokio::test]
async fn app_tracks_uptime_for_genesis_validator_missing_blocks() -> anyhow::Result<()> {
// Install a test logger, acquire some temporary storage, and start the test node.
Expand All @@ -31,16 +29,12 @@ async fn app_tracks_uptime_for_genesis_validator_missing_blocks() -> anyhow::Res
}?;

// Retrieve the validator definition from the latest snapshot.
let Validator { identity_key, .. } = match storage
let [identity_key] = storage
.latest_snapshot()
.validator_definitions()
.tap(|_| info!("getting validator definitions"))
.validator_identity_keys()
.await?
.as_slice()
{
[v] => v.clone(),
unexpected => panic!("there should be one validator, got: {unexpected:?}"),
};
.try_into()
.map_err(|keys| anyhow::anyhow!("expected one key, got: {keys:?}"))?;
let get_uptime = || async {
storage
.latest_snapshot()
Expand Down
Loading
Loading