From 1381ca8a2646db126f19672130a8e2b06e3e1630 Mon Sep 17 00:00:00 2001 From: katelyn martin Date: Thu, 22 Feb 2024 10:36:40 -0500 Subject: [PATCH] =?UTF-8?q?mock-consensus:=20=F0=9F=92=B0=20execute=20a=20?= =?UTF-8?q?spend=20via=20mock=20consensus=20(#3857)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ~f/ixes #3788.~ this introduces a new `mock_consensus_can_send_a_spend_action` test which, as the name implies, shows that the mock consensus harness can send and execute a `Spend` action via our consensus service. a `MockClient::with_sync_to_storage` helper (bikesheds are welcome here) is introduced, to facilitate syncing to the latest snapshot of the temporary storage. * #3588 * #3788 --- crates/core/app/tests/mock_consensus.rs | 84 +++++++++++++++++++++++++ crates/test/mock-client/src/lib.rs | 14 ++++- 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/crates/core/app/tests/mock_consensus.rs b/crates/core/app/tests/mock_consensus.rs index 8ab4d947a0..e4b12d1a08 100644 --- a/crates/core/app/tests/mock_consensus.rs +++ b/crates/core/app/tests/mock_consensus.rs @@ -6,7 +6,10 @@ mod common; use { + anyhow::anyhow, cnidarium::TempStorage, + penumbra_keys::test_keys, + penumbra_mock_client::MockClient, penumbra_sct::component::clock::EpochRead, tracing::{error_span, Instrument}, }; @@ -65,3 +68,84 @@ async fn mock_consensus_can_send_a_sequence_of_empty_blocks() -> anyhow::Result< Ok(()) } + +#[tokio::test] +async fn mock_consensus_can_send_a_spend_action() -> anyhow::Result<()> { + // Install a test logger, acquire some temporary storage, and start the test node. + let guard = common::set_tracing_subscriber(); + let storage = TempStorage::new().await?; + let mut test_node = common::start_test_node(&storage).await?; + let mut rng = ::seed_from_u64(0xBEEF); + + // Sync the mock client, using the test account's full viewing key, to the latest snapshot. + let MockClient { notes, sct, .. } = MockClient::new(test_keys::FULL_VIEWING_KEY.clone()) + .with_sync_to_storage(&storage) + .await?; + + // Take one of the test account's notes... + let note = notes + .values() + .cloned() + .next() + .ok_or_else(|| anyhow!("mock client had no note"))?; + let asset_id = note.asset_id(); + let proof = sct + .witness(note.commit()) + .ok_or_else(|| anyhow!("index is not witnessed"))?; + + // ...and use it to craft a `Spend`. + let (spend, spend_key) = { + use {decaf377_rdsa::SigningKey, penumbra_shielded_pool::SpendPlan}; + let spend_plan = SpendPlan::new(&mut rng, note, proof.position()); + let auth_sig = test_keys::SPEND_KEY + .spend_auth_key() + .randomize(&spend_plan.randomizer) + .sign(&mut rng, [0u8; 64].as_ref()); + let spend = spend_plan.spend(&test_keys::FULL_VIEWING_KEY, auth_sig, proof, sct.root()); + let key = SigningKey::from(spend_plan.value_blinding); + (spend, key) + }; + + // Next, craft a transaction, containing this `Spend`. + let tx = { + use { + penumbra_asset::Value, + penumbra_fee::Fee, + penumbra_num::Amount, + penumbra_transaction::{Action, Transaction, TransactionBody, TransactionParameters}, + penumbra_txhash::AuthorizingData, + }; + let transaction_parameters = TransactionParameters { + expiry_height: 0, + chain_id: "i-wonder-if-this-is-load-bearing".to_owned(), + fee: Fee(Value { + amount: Amount::zero(), + asset_id, + }), + }; + let transaction_body = TransactionBody { + actions: vec![Action::Spend(spend)], + transaction_parameters, + ..Default::default() + }; + let binding_sig = spend_key.sign(rng, transaction_body.auth_hash().as_bytes()); + let transaction = Transaction { + transaction_body, + binding_sig, + anchor: sct.root(), + }; + ::encode_to_vec(&transaction) + }; + + // Execute the transaction, and sync another mock client up to the latest snapshot. + test_node.block().with_data(vec![tx]).execute().await?; + MockClient::new(test_keys::FULL_VIEWING_KEY.clone()) + .with_sync_to_storage(&storage) + .await?; + + // Free our temporary storage. + drop(storage); + drop(guard); + + Ok(()) +} diff --git a/crates/test/mock-client/src/lib.rs b/crates/test/mock-client/src/lib.rs index abb616abb3..141dd08e10 100644 --- a/crates/test/mock-client/src/lib.rs +++ b/crates/test/mock-client/src/lib.rs @@ -2,7 +2,7 @@ use cnidarium::StateRead; use penumbra_compact_block::{component::StateReadExt as _, CompactBlock, StatePayload}; use penumbra_dex::swap::SwapPlaintext; use penumbra_keys::FullViewingKey; -use penumbra_sct::component::tree::SctRead; +use penumbra_sct::component::{clock::EpochRead, tree::SctRead}; use penumbra_shielded_pool::{note, Note}; use penumbra_tct as tct; use std::collections::BTreeMap; @@ -27,6 +27,18 @@ impl MockClient { } } + pub async fn with_sync_to_storage( + mut self, + storage: impl AsRef, + ) -> anyhow::Result { + let latest = storage.as_ref().latest_snapshot(); + let height = latest.get_block_height().await?; + let state = cnidarium::StateDelta::new(latest); + self.sync_to(height, state).await?; + + Ok(self) + } + pub async fn sync_to( &mut self, target_height: u64,