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): 🐣 add stubs for mock consensus tests #3781

Merged
merged 10 commits into from
Feb 8, 2024
1 change: 1 addition & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ jobs:
if [[ -n "$s" ]]; then
echo "ERROR: found modified files that should be committed:"
echo "$s"
git diff | head -n 128
exit 1
else
echo "OK: no uncommitted changes detected"
Expand Down
40 changes: 40 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,13 @@ members = [
"crates/bin/pclientd",
"crates/bin/pcli",
"crates/wasm",
"crates/test/mock-client",
"crates/test/mock-consensus",
"crates/test/tct-property-test",
"crates/misc/measure",
"crates/misc/tct-visualize",
"crates/bench",
"tools/summonerd", "crates/core/component/funding",
"tools/summonerd", "crates/core/component/funding", "crates/core/genesis",
]

# Optimize for small binaries in just the wasm crate.
Expand Down Expand Up @@ -171,8 +173,11 @@ penumbra-distributions = {default-features = false, path = "crates/core/componen
penumbra-fee = {default-features = false, path = "crates/core/component/fee"}
penumbra-funding = {default-features = false, path = "crates/core/component/funding"}
penumbra-governance = {default-features = false, path = "crates/core/component/governance"}
penumbra-genesis = { path = "crates/core/genesis" }
penumbra-ibc = {default-features = false, path = "crates/core/component/ibc"}
penumbra-keys = {default-features = false, path = "crates/core/keys"}
penumbra-mock-client = {path = "crates/test/mock-client"}
penumbra-mock-consensus = {path = "crates/test/mock-consensus"}
penumbra-num = {default-features = false, path = "crates/core/num"}
penumbra-proof-params = {default-features = false, path = "crates/crypto/proof-params"}
penumbra-proof-setup = {path = "crates/crypto/proof-setup"}
Expand Down
1 change: 1 addition & 0 deletions crates/bin/pd/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ penumbra-custody = {workspace = true}
penumbra-tower-trace = { path = "../../util/tower-trace" }
penumbra-tendermint-proxy = { path = "../../util/tendermint-proxy" }
penumbra-auto-https = { path = "../../util/auto-https" }
penumbra-genesis = {workspace = true}
decaf377 = {workspace = true, features = ["parallel"], default-features = true}
decaf377-rdsa = {workspace = true}
tower-abci = "0.11"
Expand Down
10 changes: 5 additions & 5 deletions crates/bin/pd/src/consensus.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use anyhow::Result;

use cnidarium::Storage;
use penumbra_app::genesis;
use tendermint::abci::Event;
use tendermint::v0_37::abci::{
request, response, ConsensusRequest as Request, ConsensusResponse as Response,
Expand Down Expand Up @@ -104,8 +103,9 @@ impl Consensus {
/// the database.
async fn init_chain(&mut self, init_chain: request::InitChain) -> Result<response::InitChain> {
// Note that errors cannot be handled in InitChain, the application must crash.
let app_state: genesis::AppState = serde_json::from_slice(&init_chain.app_state_bytes)
.expect("can parse app_state in genesis file");
let app_state: penumbra_genesis::AppState =
serde_json::from_slice(&init_chain.app_state_bytes)
.expect("can parse app_state in genesis file");

self.app.init_chain(&app_state).await;

Expand All @@ -118,13 +118,13 @@ impl Consensus {
let validators = self.app.tendermint_validator_updates();

let app_hash = match &app_state {
genesis::AppState::Checkpoint(h) => {
penumbra_genesis::AppState::Checkpoint(h) => {
tracing::info!(?h, "genesis state is a checkpoint");
// If we're starting from a checkpoint, we just need to forward the app hash
// back to CometBFT.
self.storage.latest_snapshot().root_hash().await?
}
genesis::AppState::Content(_) => {
penumbra_genesis::AppState::Content(_) => {
tracing::info!("genesis state is a full configuration");
// Check that we haven't got a duplicated InitChain message for some reason:
if self.storage.latest_version() != u64::MAX {
Expand Down
4 changes: 2 additions & 2 deletions crates/bin/pd/src/migrate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::path::PathBuf;

use cnidarium::{StateDelta, StateWrite, Storage};
use jmt::RootHash;
use penumbra_app::{genesis, SUBSTORE_PREFIXES};
use penumbra_app::SUBSTORE_PREFIXES;
use penumbra_sct::component::clock::{EpochManager, EpochRead};
use penumbra_stake::{
component::validator_handler::ValidatorDataRead, genesis::Content as StakeContent,
Expand Down Expand Up @@ -66,7 +66,7 @@ impl Migration {

/* ---------- generate genesis ------------ */
let validators = migrated_state.validator_definitions().await?;
let app_state = genesis::Content {
let app_state = penumbra_genesis::Content {
stake_content: StakeContent {
// TODO(erwan): should remove this.
validators: validators.into_iter().map(Into::into).collect(),
Expand Down
2 changes: 1 addition & 1 deletion crates/bin/pd/src/testnet/config.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use anyhow::Context;
use decaf377_rdsa::{SigningKey, SpendAuth, VerificationKey};
use directories::UserDirs;
use penumbra_app::genesis::AppState;
use penumbra_custody::soft_kms::Config as SoftKmsConfig;
use penumbra_genesis::AppState;
use penumbra_keys::keys::{SpendKey, SpendKeyBytes};
use rand::Rng;
use rand_core::OsRng;
Expand Down
26 changes: 14 additions & 12 deletions crates/bin/pd/src/testnet/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! for Penumbra.
use crate::testnet::config::{get_testnet_dir, TestnetTendermintConfig, ValidatorKeys};
use anyhow::{Context, Result};
use penumbra_app::{genesis, params::AppParameters};
use penumbra_app::params::AppParameters;
use penumbra_governance::genesis::Content as GovernanceContent;
use penumbra_keys::{keys::SpendKey, Address};
use penumbra_sct::genesis::Content as SctContent;
Expand Down Expand Up @@ -35,7 +35,7 @@ pub struct TestnetConfig {
/// The name of the network
pub name: String,
/// The Tendermint genesis for initial chain state.
pub genesis: Genesis<genesis::AppState>,
pub genesis: Genesis<penumbra_genesis::AppState>,
/// Path to local directory where config files will be written to
pub testnet_dir: PathBuf,
/// Set of validators at genesis. Uses the convenient wrapper type
Expand Down Expand Up @@ -186,7 +186,7 @@ impl TestnetConfig {
epoch_duration: Option<u64>,
unbonding_epochs: Option<u64>,
proposal_voting_blocks: Option<u64>,
) -> anyhow::Result<genesis::Content> {
) -> anyhow::Result<penumbra_genesis::Content> {
let default_gov_params = penumbra_governance::params::GovernanceParameters::default();

let gov_params = penumbra_governance::params::GovernanceParameters {
Expand All @@ -198,7 +198,7 @@ impl TestnetConfig {
// Look up default app params, so we can fill in defaults.
let default_app_params = AppParameters::default();

let app_state = genesis::Content {
let app_state = penumbra_genesis::Content {
chain_id: chain_id.to_string(),
stake_content: StakeContent {
validators: validators.into_iter().map(Into::into).collect(),
Expand Down Expand Up @@ -230,8 +230,8 @@ impl TestnetConfig {

/// Build Tendermint genesis data, based on Penumbra initial application state.
pub(crate) fn make_genesis(
app_state: genesis::Content,
) -> anyhow::Result<Genesis<genesis::AppState>> {
app_state: penumbra_genesis::Content,
) -> anyhow::Result<Genesis<penumbra_genesis::AppState>> {
// Use now as genesis time
let genesis_time = Time::from_unix_timestamp(
SystemTime::now()
Expand Down Expand Up @@ -272,7 +272,7 @@ impl TestnetConfig {
},
// always empty in genesis json
app_hash: tendermint::AppHash::default(),
app_state: genesis::AppState::Content(app_state),
app_state: penumbra_genesis::AppState::Content(app_state),
// Set empty validator set for Tendermint config, which falls back to reading
// validators from the AppState, via ResponseInitChain:
// https://docs.tendermint.com/v0.32/tendermint-core/using-tendermint.html
Expand All @@ -282,12 +282,12 @@ impl TestnetConfig {
}

pub(crate) fn make_checkpoint(
genesis: Genesis<genesis::AppState>,
genesis: Genesis<penumbra_genesis::AppState>,
checkpoint: Option<Vec<u8>>,
) -> Genesis<genesis::AppState> {
) -> Genesis<penumbra_genesis::AppState> {
match checkpoint {
Some(checkpoint) => Genesis {
app_state: genesis::AppState::Checkpoint(checkpoint),
app_state: penumbra_genesis::AppState::Checkpoint(checkpoint),
..genesis
},
None => genesis,
Expand Down Expand Up @@ -672,7 +672,8 @@ mod tests {
assert_eq!(testnet_config.name, "test-chain-1234");
assert_eq!(testnet_config.genesis.validators.len(), 0);
// No external address template was given, so only 1 validator will be present.
let genesis::AppState::Content(app_state) = testnet_config.genesis.app_state else {
let penumbra_genesis::AppState::Content(app_state) = testnet_config.genesis.app_state
else {
unimplemented!("TODO: support checkpointed app state")
};
assert_eq!(app_state.stake_content.validators.len(), 1);
Expand All @@ -699,7 +700,8 @@ mod tests {
)?;
assert_eq!(testnet_config.name, "test-chain-4567");
assert_eq!(testnet_config.genesis.validators.len(), 0);
let genesis::AppState::Content(app_state) = testnet_config.genesis.app_state else {
let penumbra_genesis::AppState::Content(app_state) = testnet_config.genesis.app_state
else {
unimplemented!("TODO: support checkpointed app state")
};
assert_eq!(app_state.stake_content.validators.len(), 2);
Expand Down
11 changes: 11 additions & 0 deletions crates/core/app/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ penumbra-ibc = {workspace = true, features = ["component"], default-features = t
penumbra-distributions = {workspace = true, default-features = true}
penumbra-compact-block = {workspace = true, default-features = true}
penumbra-transaction = {workspace = true, features = ["parallel"], default-features = true}
penumbra-genesis = {workspace = true}
decaf377 = {workspace = true, default-features = true}
decaf377-rdsa = {workspace = true}
jmt = {workspace = true}
Expand Down Expand Up @@ -75,6 +76,16 @@ ibc-proto = {workspace = true, default-features = false, features = [

[dev-dependencies]
ed25519-consensus = {workspace = true}
penumbra-mock-consensus = {workspace = true}
penumbra-mock-client = {workspace = true}
rand_core = {workspace = true}
rand_chacha = {workspace = true}
tracing-subscriber = {workspace = true}

# Enable the feature flags to get proving keys when running tests.
[dev-dependencies.penumbra-proof-params]
workspace = true
features = [
"bundled-proving-keys",
"download-proving-keys",
]
9 changes: 5 additions & 4 deletions crates/core/app/src/app/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use penumbra_distributions::component::{Distributions, StateReadExt as _, StateW
use penumbra_fee::component::{Fee, StateReadExt as _, StateWriteExt as _};
use penumbra_funding::component::Funding;
use penumbra_funding::component::{StateReadExt as _, StateWriteExt as _};
use penumbra_genesis::AppState;
use penumbra_governance::component::{Governance, StateReadExt as _};
use penumbra_governance::StateWriteExt as _;
use penumbra_ibc::component::{Ibc, StateWriteExt as _};
Expand All @@ -38,7 +39,7 @@ use tracing::Instrument;

use crate::action_handler::ActionHandler;
use crate::params::AppParameters;
use crate::{genesis, CommunityPoolStateReadExt, PenumbraHost};
use crate::{CommunityPoolStateReadExt, PenumbraHost};

pub mod state_key;

Expand Down Expand Up @@ -94,13 +95,13 @@ impl App {
events
}

pub async fn init_chain(&mut self, app_state: &genesis::AppState) {
pub async fn init_chain(&mut self, app_state: &AppState) {
let mut state_tx = self
.state
.try_begin_transaction()
.expect("state Arc should not be referenced elsewhere");
match app_state {
genesis::AppState::Content(genesis) => {
AppState::Content(genesis) => {
state_tx.put_chain_id(genesis.chain_id.clone());
Sct::init_chain(&mut state_tx, Some(&genesis.sct_content)).await;
ShieldedPool::init_chain(&mut state_tx, Some(&genesis.shielded_pool_content)).await;
Expand All @@ -127,7 +128,7 @@ impl App {
.await
.expect("must be able to finish compact block");
}
genesis::AppState::Checkpoint(_) => {
AppState::Checkpoint(_) => {
ShieldedPool::init_chain(&mut state_tx, None).await;
Distributions::init_chain(&mut state_tx, None).await;
Staking::init_chain(&mut state_tx, None).await;
Expand Down
4 changes: 0 additions & 4 deletions crates/core/app/src/genesis.rs

This file was deleted.

8 changes: 1 addition & 7 deletions crates/core/app/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,18 @@
#![cfg_attr(docsrs, feature(doc_auto_cfg))]

pub mod app;
pub mod genesis;
pub mod metrics;
pub mod params;
pub mod rpc;

mod action_handler;
mod community_pool_ext;
mod mock_client;
mod penumbra_host_chain;
mod temp_storage_ext;

#[cfg(test)]
mod tests;

pub use crate::{
action_handler::ActionHandler, app::StateWriteExt,
community_pool_ext::CommunityPoolStateReadExt, metrics::register_metrics,
mock_client::MockClient, penumbra_host_chain::PenumbraHost, temp_storage_ext::TempStorageExt,
penumbra_host_chain::PenumbraHost,
};

use once_cell::sync::Lazy;
Expand Down
2 changes: 0 additions & 2 deletions crates/core/app/src/tests/mod.rs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
use std::ops::Deref;

use crate::genesis;
use async_trait::async_trait;
use cnidarium::TempStorage;

use crate::app::App;
use penumbra_app::app::App;
use penumbra_genesis::AppState;
use std::ops::Deref;

#[async_trait]
pub trait TempStorageExt: Sized {
async fn apply_genesis(self, genesis: genesis::AppState) -> anyhow::Result<Self>;
async fn apply_genesis(self, genesis: AppState) -> anyhow::Result<Self>;
async fn apply_default_genesis(self) -> anyhow::Result<Self>;
}

#[async_trait]
impl TempStorageExt for TempStorage {
async fn apply_genesis(self, genesis: genesis::AppState) -> anyhow::Result<Self> {
async fn apply_genesis(self, genesis: AppState) -> anyhow::Result<Self> {
// Check that we haven't already applied a genesis state:
if self.latest_version() != u64::MAX {
anyhow::bail!("database already initialized");
Expand Down
Loading
Loading