diff --git a/crates/core/app/tests/app_can_define_and_delegate_to_a_validator.rs b/crates/core/app/tests/app_can_define_and_delegate_to_a_validator.rs index 606bd684d5..7c94a4d794 100644 --- a/crates/core/app/tests/app_can_define_and_delegate_to_a_validator.rs +++ b/crates/core/app/tests/app_can_define_and_delegate_to_a_validator.rs @@ -282,6 +282,7 @@ async fn app_can_define_and_delegate_to_a_validator() -> anyhow::Result<()> { let tx = client.witness_auth_build(&plan).await?; // Execute the transaction, applying it to the chain state. + let pre_delegate_snapshot = storage.latest_snapshot(); node.block() .add_tx(tx.encode_to_vec()) .execute() @@ -292,7 +293,7 @@ async fn app_can_define_and_delegate_to_a_validator() -> anyhow::Result<()> { // Show that the set of validators still looks correct. We should not see any changes yet. { use penumbra_stake::{component::ConsensusIndexRead, validator::State}; - let snapshot = post_delegate_snapshot; + let snapshot = post_delegate_snapshot.clone(); info!("checking consensus set in block after delegation"); // The original validator should still be active. assert_eq!( @@ -315,6 +316,30 @@ async fn app_can_define_and_delegate_to_a_validator() -> anyhow::Result<()> { ); } + // Confirm that the new validator's voting power has not changed immeditaly. + let new_validator_original_power = { + use penumbra_sct::component::clock::EpochRead; + let pre_delegate_power = pre_delegate_snapshot + .get_validator_power(&new_validator_id) + .await? + .expect("should have voting power before delegating"); + let post_delegate_power = post_delegate_snapshot + .get_validator_power(&new_validator_id) + .await? + .expect("should have voting power after delegating"); + debug_assert_eq!( + pre_delegate_snapshot.get_current_epoch().await?, + post_delegate_snapshot.get_current_epoch().await?, + "avoid puzzling errors by confirming that pre- and post-delegation snapshots do not \ + sit upon an epoch boundary" + ); + assert_eq!( + pre_delegate_power, post_delegate_power, + "a delegated validator" + ); + pre_delegate_power + }; + // Fast forward to the next epoch. node.fast_forward(EPOCH_DURATION) .instrument(error_span!( @@ -328,7 +353,7 @@ async fn app_can_define_and_delegate_to_a_validator() -> anyhow::Result<()> { { use penumbra_stake::{component::ConsensusIndexRead, validator::State}; info!("checking consensus set in epoch after delegation"); - let snapshot = post_delegate_next_epoch_snapshot; + let snapshot = post_delegate_next_epoch_snapshot.clone(); // The original validator should still be active. assert_eq!( snapshot.get_validator_state(&existing_validator_id).await?, @@ -349,6 +374,19 @@ async fn app_can_define_and_delegate_to_a_validator() -> anyhow::Result<()> { ); } + // Show that the new validator's voting power has changed, now that we are in a new epoch + // after the delegation. + let new_validator_epoch_after_delegation_power = post_delegate_next_epoch_snapshot + .get_validator_power(&new_validator_id) + .await? + .expect("should have voting power before delegating") + .tap(|&power| { + assert!( + power > new_validator_original_power, + "new validator should now have more voting power after receiving a delegation" + ) + }); + // Build a transaction that will now undelegate from the validator. let plan = { use { @@ -419,7 +457,7 @@ async fn app_can_define_and_delegate_to_a_validator() -> anyhow::Result<()> { // Show that the consensus set has not changed yet. { use penumbra_stake::{component::ConsensusIndexRead, validator::State}; - let snapshot = post_undelegate_snapshot; + let snapshot = post_undelegate_snapshot.clone(); info!("checking consensus set in block after undelegation"); // The original validator should still be active. assert_eq!( @@ -441,6 +479,18 @@ async fn app_can_define_and_delegate_to_a_validator() -> anyhow::Result<()> { ); } + // Compute the current voting power, confirm that it has not changed yet. + post_undelegate_snapshot + .get_validator_power(&new_validator_id) + .await? + .expect("should have voting power before delegating") + .tap(|&power| { + assert_eq!( + power, new_validator_epoch_after_delegation_power, + "validator power should not change immediately after an undelegation" + ) + }); + // Fast forward to the next epoch. node.fast_forward(EPOCH_DURATION) .instrument(error_span!( @@ -454,7 +504,7 @@ async fn app_can_define_and_delegate_to_a_validator() -> anyhow::Result<()> { { use penumbra_stake::{component::ConsensusIndexRead, validator::State}; info!("checking consensus set in epoch after undelegation"); - let snapshot = post_undelegate_next_epoch_snapshot; + let snapshot = post_undelegate_next_epoch_snapshot.clone(); // The original validator should still be active. assert_eq!( snapshot.get_validator_state(&existing_validator_id).await?, @@ -475,6 +525,18 @@ async fn app_can_define_and_delegate_to_a_validator() -> anyhow::Result<()> { ); } + // Show that now, the validator's voting power has returned to its original state. + post_undelegate_next_epoch_snapshot + .get_validator_power(&new_validator_id) + .await? + .expect("should have voting power before delegating") + .tap(|&power| { + assert_eq!( + power, new_validator_original_power, + "validator power should not change immediately after an undelegation" + ) + }); + // The test passed. Free our temporary storage and drop our tracing subscriber. Ok(()) .tap(|_| drop(node))