diff --git a/crates/core/app/tests/mock_consensus_staking.rs b/crates/core/app/tests/mock_consensus_staking.rs index 26755d3ef1..613f8f372f 100644 --- a/crates/core/app/tests/mock_consensus_staking.rs +++ b/crates/core/app/tests/mock_consensus_staking.rs @@ -186,6 +186,95 @@ async fn mock_consensus_can_define_and_delegate_to_a_validator() -> anyhow::Resu ); } + // Now, create a transaction that delegates to the new validator. + let plan = { + use { + penumbra_num::Amount, + penumbra_sct::component::clock::EpochRead, + penumbra_stake::Delegate, + penumbra_transaction::{ActionPlan, TransactionParameters, TransactionPlan}, + }; + let action = ActionPlan::Delegate(Delegate { + validator_identity: new_validator_id, + epoch_index: storage.latest_snapshot().get_current_epoch().await?.index, + unbonded_amount: Amount::zero(), // TODO: use a non-zero value here. + delegation_amount: 1000000_u32.into(), + }); + let mut plan = TransactionPlan { + actions: vec![action.into()], + // Now fill out the remaining parts of the transaction needed for verification: + memo: None, + detection_data: None, // We'll set this automatically below + transaction_parameters: TransactionParameters { + chain_id: TestNode::<()>::CHAIN_ID.to_string(), + ..Default::default() + }, + }; + plan.populate_detection_data(rand_core::OsRng, 0); + plan + }; + let tx = client.witness_auth_build(&plan).await?; + + // Execute the transaction, applying it to the chain state. + node.block().add_tx(tx.encode_to_vec()).execute().await?; + let post_delegate_snapshot = storage.latest_snapshot(); + + // 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; + // The original validator should still be active. + assert_eq!( + snapshot.get_validator_state(&existing_validator_id).await?, + Some(State::Active), + "validator should be active" + ); + // The new validator should be defined, but not yet active. It should not be inclueded in + // consensus yet. + assert_eq!( + snapshot.get_validator_state(&new_validator_id).await?, + Some(State::Defined), + "new validator definition should be defined but not active" + ); + // The original validator should still be the only validator in the consensus set. + assert_eq!( + snapshot.get_consensus_set().await?.len(), + 1, + "the new validator should not be part of the consensus set yet" + ); + } + + // Fast forward to the next epoch. + node.fast_forward(EPOCH_LENGTH) + .instrument(error_span!("fast forwarding test node to next epoch")) + .await + .context("fast forwarding {EPOCH_LENGTH} blocks")?; + let post_delegate_next_epoch_snapshot = storage.latest_snapshot(); + + // Show that now, after an epoch and with a delegation, the validator is marked active. + { + use penumbra_stake::{component::ConsensusIndexRead, validator::State}; + let snapshot = post_delegate_next_epoch_snapshot; + // The original validator should still be active. + assert_eq!( + snapshot.get_validator_state(&existing_validator_id).await?, + Some(State::Active), + "validator should be active" + ); + // The new validator should now be active. + assert_eq!( + snapshot.get_validator_state(&new_validator_id).await?, + Some(State::Active), + "new validator should be active" + ); + // There should now be two validators in the consensus set. + assert_eq!( + snapshot.get_consensus_set().await?.len(), + 2, + "the new validator should now be part of the consensus set" + ); + } + // The test passed. Free our temporary storage and drop our tracing subscriber. Ok(()) .tap(|_| drop(node))