From 201fe4873523f6d86ba9caf4d919c045abf574e7 Mon Sep 17 00:00:00 2001 From: katelyn martin Date: Mon, 15 Apr 2024 13:49:20 -0400 Subject: [PATCH] =?UTF-8?q?tests(app):=20=F0=9F=8F=8A=20test=20a=20communi?= =?UTF-8?q?ty=20pool=20deposit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit first, we write a test that can be used to make a deposit into the community pool. show that the balance is updated accordingly. --- .../app_can_deposit_into_community_pool.rs | 129 ++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 crates/core/app/tests/app_can_deposit_into_community_pool.rs diff --git a/crates/core/app/tests/app_can_deposit_into_community_pool.rs b/crates/core/app/tests/app_can_deposit_into_community_pool.rs new file mode 100644 index 0000000000..ecdee26f92 --- /dev/null +++ b/crates/core/app/tests/app_can_deposit_into_community_pool.rs @@ -0,0 +1,129 @@ +use { + self::common::BuilderExt, + anyhow::anyhow, + cnidarium::TempStorage, + penumbra_app::{genesis::AppState, server::consensus::Consensus}, + penumbra_asset::asset, + penumbra_community_pool::{CommunityPoolDeposit, StateReadExt}, + penumbra_keys::test_keys, + penumbra_mock_client::MockClient, + penumbra_mock_consensus::TestNode, + penumbra_num::Amount, + penumbra_proto::DomainType, + penumbra_shielded_pool::SpendPlan, + penumbra_transaction::{TransactionParameters, TransactionPlan}, + rand_core::OsRng, + std::collections::BTreeMap, + tap::{Tap, TapFallible}, + tracing::info, +}; + +mod common; + +/// Exercises that the app can deposit a note into the community pool. +#[tokio::test] +async fn app_can_deposit_into_community_pool() -> anyhow::Result<()> { + // Install a test logger, and acquire some temporary storage. + let guard = common::set_tracing_subscriber(); + let storage = TempStorage::new().await?; + + // Define our application state, and start the test node. + let mut test_node = { + let app_state = AppState::default(); + let consensus = Consensus::new(storage.as_ref().clone()); + TestNode::builder() + .single_validator() + .with_penumbra_auto_app_state(app_state)? + .init_chain(consensus) + .await + .tap_ok(|e| tracing::info!(hash = %e.last_app_hash_hex(), "finished init chain"))? + }; + + // Sync the mock client, using the test wallet's spend key, to the latest snapshot. + let client = MockClient::new(test_keys::SPEND_KEY.clone()) + .with_sync_to_storage(&storage) + .await? + .tap(|c| info!(client.notes = %c.notes.len(), "mock client synced to test storage")); + + // Take one of the test wallet's notes, and prepare to deposit it in the community pool. + let note = client + .notes + .values() + .cloned() + .next() + .ok_or_else(|| anyhow!("mock client had no note"))?; + + // Create a community pool transaction. + let mut plan = { + let value = note.value(); + let spend = SpendPlan::new( + &mut OsRng, + note.clone(), + client + .position(note.commit()) + .ok_or_else(|| anyhow!("input note commitment was unknown to mock client"))?, + ) + .into(); + let deposit = CommunityPoolDeposit { value }.into(); + TransactionPlan { + actions: vec![spend, deposit], + // 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(OsRng, 0); + let tx = client.witness_auth_build(&plan).await?; + + // Execute the transaction, applying it to the chain state. + let pre_tx_snapshot = storage.latest_snapshot(); + test_node + .block() + .with_data(vec![tx.encode_to_vec()]) + .execute() + .await?; + let post_tx_snapshot = storage.latest_snapshot(); + + // Assert that the community pool balance looks correct for the deposited asset id, and that + // other amounts were not affected by the deposit. + { + type Balance = BTreeMap; + + let id = note.asset_id(); + let pre_tx_balance = pre_tx_snapshot.community_pool_balance().await?; + let post_tx_balance = post_tx_snapshot.community_pool_balance().await?; + + let get_balance_for_id = |balance: &Balance| balance.get(&id).copied().unwrap_or_default(); + let pre_tx_amount = get_balance_for_id(&pre_tx_balance); + let post_tx_amount = get_balance_for_id(&post_tx_balance); + assert_eq!( + pre_tx_amount + note.amount(), + post_tx_amount, + "community pool balance should include the deposited note" + ); + + let count_other_assets_in_pool = |balance: &Balance| { + balance + .into_iter() + // Skip the amount for our note's asset id. + .filter(|(&entry_id, _)| entry_id != id) + .map(|(_, &amount)| amount) + .sum::() + }; + assert_eq!( + count_other_assets_in_pool(&pre_tx_balance), + count_other_assets_in_pool(&post_tx_balance), + "other community pool balance amounts should not have changed" + ); + } + + // Free our temporary storage. + Ok(()) + .tap(|_| drop(test_node)) + .tap(|_| drop(storage)) + .tap(|_| drop(guard)) +}