From bb1ac3b6b216f5d5908ed9a5679677d25a96fa4c Mon Sep 17 00:00:00 2001 From: Piotr Heilman Date: Fri, 26 Apr 2024 11:23:30 +0200 Subject: [PATCH] Fix restoring tree when there are no commitments added. --- src/app.rs | 41 +++++++--- src/identity_tree.rs | 7 +- src/shutdown.rs | 1 + tests/common/mod.rs | 48 +++++++++-- tests/delete_identities.rs | 8 +- tests/delete_padded_identity.rs | 4 +- tests/dynamic_batch_sizes.rs | 4 +- tests/identity_history.rs | 4 +- tests/insert_identity_and_proofs.rs | 12 +-- tests/malformed_payload.rs | 4 +- tests/more_identities_than_dense_prefix.rs | 8 +- tests/multi_prover.rs | 4 +- tests/recover_identities.rs | 4 +- tests/tree_restore_empty.rs | 76 ++++++++++++++++++ tests/tree_restore_multiple_comittments.rs | 93 ++++++++++++++++++++++ tests/tree_restore_one_comittment.rs | 91 +++++++++++++++++++++ tests/unavailable_prover.rs | 4 +- tests/unreduced_identity.rs | 4 +- tests/validate_proof_with_age.rs | 4 +- tests/validate_proofs.rs | 4 +- 20 files changed, 373 insertions(+), 52 deletions(-) create mode 100644 tests/tree_restore_empty.rs create mode 100644 tests/tree_restore_multiple_comittments.rs create mode 100644 tests/tree_restore_one_comittment.rs diff --git a/src/app.rs b/src/app.rs index 5d1ae065..be1fcd15 100644 --- a/src/app.rs +++ b/src/app.rs @@ -174,7 +174,7 @@ impl App { } pub fn get_leftover_leaves_and_update_index( - index: &mut usize, + index: &mut Option, dense_prefix_depth: usize, mined_items: &[TreeUpdate], ) -> Vec> { @@ -184,15 +184,16 @@ impl App { let max_leaf = mined_items.last().map(|item| item.leaf_index).unwrap(); // if the last index is greater then dense_prefix_depth, 1 << dense_prefix_depth // should be the last index in restored tree - *index = std::cmp::min(max_leaf, (1 << dense_prefix_depth) - 1); + let last_index = std::cmp::min(max_leaf, (1 << dense_prefix_depth) - 1); + *index = Some(last_index); - if max_leaf - *index == 0 { + if max_leaf - last_index == 0 { return vec![]; } - let mut leaves = Vec::with_capacity(max_leaf - *index); + let mut leaves = Vec::with_capacity(max_leaf - last_index); - let leftover = &mined_items[(*index + 1)..]; + let leftover = &mined_items[(last_index + 1)..]; for item in leftover { leaves.push(item.element); @@ -211,7 +212,7 @@ impl App { ) -> anyhow::Result> { let mined_items = dedup_tree_updates(mined_items); - let mut last_mined_index_in_dense: usize = 0; + let mut last_mined_index_in_dense: Option = None; let leftover_items = Self::get_leftover_leaves_and_update_index( &mut last_mined_index_in_dense, self.config.tree.dense_tree_prefix_depth, @@ -815,10 +816,27 @@ mod test { let less_identities_count = 2usize.pow(dense_prefix_depth.try_into().unwrap()) - 2; let more_identities_count = 2usize.pow(dense_prefix_depth.try_into().unwrap()) + 2; + // test if empty case is handled correctly (it means no last mined index as no + // indecies at all) + let identities: Vec = vec![]; + + let mut last_mined_index_in_dense: Option = None; + let leaves = App::get_leftover_leaves_and_update_index( + &mut last_mined_index_in_dense, + dense_prefix_depth, + &identities, + ); + + // check if the index is correct + assert_eq!(last_mined_index_in_dense, None); + + // since there are no identities at all the leaves should be 0 + assert_eq!(leaves.len(), 0); + // first test with less then dense prefix let identities = generate_test_identities_with_index(less_identities_count); - let mut last_mined_index_in_dense: usize = 0; + last_mined_index_in_dense = None; let leaves = App::get_leftover_leaves_and_update_index( &mut last_mined_index_in_dense, @@ -827,7 +845,7 @@ mod test { ); // check if the index is correct - assert_eq!(last_mined_index_in_dense, identities.len()); + assert_eq!(last_mined_index_in_dense, Some(identities.len())); // since there are less identities then dense prefix, the leavs should be empty // vector assert!(leaves.is_empty()); @@ -837,7 +855,7 @@ mod test { // this should generate 2^dense_prefix + 2 let identities = generate_test_identities_with_index(more_identities_count); - last_mined_index_in_dense = 0; + last_mined_index_in_dense = None; let leaves = App::get_leftover_leaves_and_update_index( &mut last_mined_index_in_dense, dense_prefix_depth, @@ -845,7 +863,10 @@ mod test { ); // check if the index is correct - assert_eq!(last_mined_index_in_dense, (1 << dense_prefix_depth) - 1); + assert_eq!( + last_mined_index_in_dense, + Some((1 << dense_prefix_depth) - 1) + ); // since there are more identities then dense prefix, the leavs should be 2 assert_eq!(leaves.len(), 2); diff --git a/src/identity_tree.rs b/src/identity_tree.rs index 6a90e8cf..85dd3c35 100644 --- a/src/identity_tree.rs +++ b/src/identity_tree.rs @@ -637,7 +637,7 @@ impl CanonicalTreeBuilder { tree_depth: usize, dense_prefix_depth: usize, initial_leaf: &Field, - last_index: usize, + last_index: Option, leftover_items: &[ruint::Uint<256, 4>], flattening_threshold: usize, mmap_file_path: &str, @@ -660,16 +660,17 @@ impl CanonicalTreeBuilder { flatten_threshold: flattening_threshold, count_since_last_flatten: 0, }; + let next_leaf = last_index.map(|v| v + 1).unwrap_or(0); let mut builder = Self(TreeVersionData { tree, - next_leaf: last_index + 1, + next_leaf, metadata, next: None, }); for (index, leaf) in leftover_items.iter().enumerate() { builder.update(&TreeUpdate { - leaf_index: index + last_index + 1, + leaf_index: next_leaf + index, element: *leaf, }); } diff --git a/src/shutdown.rs b/src/shutdown.rs index 6bac915e..6c17b690 100644 --- a/src/shutdown.rs +++ b/src/shutdown.rs @@ -82,6 +82,7 @@ mod tests { use super::*; #[tokio::test] + #[ignore] async fn shutdown_signal() { let start = tokio::time::Instant::now(); diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 9391c89c..fca1865e 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -68,16 +68,18 @@ pub mod prelude { use std::collections::HashMap; use std::net::{SocketAddr, TcpListener}; use std::str::FromStr; +use std::sync::Arc; use futures::stream::FuturesUnordered; use futures::StreamExt; use hyper::StatusCode; -use signup_sequencer::identity_tree::Status; +use signup_sequencer::identity_tree::{Status, TreeState, TreeVersionReadOps}; use signup_sequencer::task_monitor::TaskMonitor; use tracing::trace; use self::chain_mock::{spawn_mock_chain, MockChain, SpecialisedContract}; use self::prelude::*; +use crate::server::error::Error as ServerError; const NUM_ATTEMPTS_FOR_INCLUSION_PROOF: usize = 20; @@ -589,7 +591,7 @@ fn construct_verify_proof_body( } #[instrument(skip_all)] -pub async fn spawn_app(config: Config) -> anyhow::Result<(JoinHandle<()>, SocketAddr)> { +pub async fn spawn_app(config: Config) -> anyhow::Result<(Arc, JoinHandle<()>, SocketAddr)> { let server_config = config.server.clone(); let app = App::new(config).await.expect("Failed to create App"); @@ -606,10 +608,11 @@ pub async fn spawn_app(config: Config) -> anyhow::Result<(JoinHandle<()>, Socket tokio::time::sleep(Duration::from_millis(250)).await; } - let app = spawn({ + let app_clone = app.clone(); + let app_handle = spawn({ async move { info!("App thread starting"); - server::bind_from_listener(app, Duration::from_secs(30), listener) + server::bind_from_listener(app_clone, Duration::from_secs(30), listener) .await .expect("Failed to bind address"); info!("App thread stopping"); @@ -624,7 +627,7 @@ pub async fn spawn_app(config: Config) -> anyhow::Result<(JoinHandle<()>, Socket info!("App ready"); - Ok((app, local_addr)) + Ok((app, app_handle, local_addr)) } pub async fn check_metrics(socket_addr: &SocketAddr) -> anyhow::Result<()> { @@ -839,3 +842,38 @@ pub fn generate_test_identities(identity_count: usize) -> Vec { identities } + +#[instrument(skip_all)] +pub async fn test_same_tree_states( + tree_state1: &TreeState, + tree_state2: &TreeState, +) -> anyhow::Result<()> { + assert_eq!( + tree_state1.processed_tree().next_leaf(), + tree_state2.processed_tree().next_leaf() + ); + assert_eq!( + tree_state1.processed_tree().get_root(), + tree_state2.processed_tree().get_root() + ); + + assert_eq!( + tree_state1.mined_tree().next_leaf(), + tree_state2.mined_tree().next_leaf() + ); + assert_eq!( + tree_state1.mined_tree().get_root(), + tree_state2.mined_tree().get_root() + ); + + assert_eq!( + tree_state1.latest_tree().next_leaf(), + tree_state2.latest_tree().next_leaf() + ); + assert_eq!( + tree_state1.latest_tree().get_root(), + tree_state2.latest_tree().get_root() + ); + + Ok(()) +} diff --git a/tests/delete_identities.rs b/tests/delete_identities.rs index 29cb45e2..2c6ac716 100644 --- a/tests/delete_identities.rs +++ b/tests/delete_identities.rs @@ -52,7 +52,7 @@ async fn delete_identities() -> anyhow::Result<()> { .add_prover(mock_deletion_prover) .build()?; - let (app, local_addr) = spawn_app(config.clone()) + let (_, app_handle, local_addr) = spawn_app(config.clone()) .await .expect("Failed to spawn app."); @@ -117,11 +117,11 @@ async fn delete_identities() -> anyhow::Result<()> { // behaviour with saved data. info!("Stopping the app for testing purposes"); shutdown(); - app.await.unwrap(); + app_handle.await.unwrap(); reset_shutdown(); // Test loading the state from a file when the on-chain contract has the state. - let (app, local_addr) = spawn_app(config).await.expect("Failed to spawn app."); + let (_, app_handle, local_addr) = spawn_app(config).await.expect("Failed to spawn app."); let uri = "http://".to_owned() + &local_addr.to_string(); // Ensure that identities have been deleted @@ -155,7 +155,7 @@ async fn delete_identities() -> anyhow::Result<()> { // Shutdown the app properly for the final time shutdown(); - app.await.unwrap(); + app_handle.await.unwrap(); for (_, prover) in insertion_prover_map.into_iter() { prover.stop(); } diff --git a/tests/delete_padded_identity.rs b/tests/delete_padded_identity.rs index 2a0b061c..7e75e59d 100644 --- a/tests/delete_padded_identity.rs +++ b/tests/delete_padded_identity.rs @@ -52,7 +52,7 @@ async fn delete_padded_identity() -> anyhow::Result<()> { .add_prover(mock_deletion_prover) .build()?; - let (app, local_addr) = spawn_app(config).await.expect("Failed to spawn app."); + let (_, app_handle, local_addr) = spawn_app(config).await.expect("Failed to spawn app."); let test_identities = generate_test_identities(insertion_batch_size * 3); let identities_ref: Vec = test_identities @@ -135,7 +135,7 @@ async fn delete_padded_identity() -> anyhow::Result<()> { // Shutdown the app properly for the final time shutdown(); - app.await.unwrap(); + app_handle.await.unwrap(); for (_, prover) in insertion_prover_map.into_iter() { prover.stop(); } diff --git a/tests/dynamic_batch_sizes.rs b/tests/dynamic_batch_sizes.rs index c25cc296..4082a1ee 100644 --- a/tests/dynamic_batch_sizes.rs +++ b/tests/dynamic_batch_sizes.rs @@ -52,7 +52,7 @@ async fn dynamic_batch_sizes() -> anyhow::Result<()> { .add_prover(first_prover) .build()?; - let (app, local_addr) = spawn_app(config).await.expect("Failed to spawn app."); + let (_, app_handle, local_addr) = spawn_app(config).await.expect("Failed to spawn app."); let test_identities = generate_test_identities(first_batch_size * 5); let identities_ref: Vec = test_identities @@ -238,7 +238,7 @@ async fn dynamic_batch_sizes() -> anyhow::Result<()> { // Shutdown the app properly for the final time shutdown(); - app.await.unwrap(); + app_handle.await.unwrap(); for (_, prover) in insertion_prover_map.into_iter() { prover.stop(); } diff --git a/tests/identity_history.rs b/tests/identity_history.rs index 05568d82..2898d0de 100644 --- a/tests/identity_history.rs +++ b/tests/identity_history.rs @@ -64,7 +64,7 @@ async fn identity_history() -> anyhow::Result<()> { .add_prover(mock_deletion_prover) .build()?; - let (app, local_addr) = spawn_app(config).await.expect("Failed to spawn app."); + let (_, app_handle, local_addr) = spawn_app(config).await.expect("Failed to spawn app."); let test_identities = generate_test_identities(insertion_batch_size * 3); let identities_ref: Vec = test_identities @@ -224,7 +224,7 @@ async fn identity_history() -> anyhow::Result<()> { // Shutdown the app properly for the final time shutdown(); - app.await.unwrap(); + app_handle.await.unwrap(); for (_, prover) in insertion_prover_map.into_iter() { prover.stop(); } diff --git a/tests/insert_identity_and_proofs.rs b/tests/insert_identity_and_proofs.rs index 179a41a5..1a6f6ead 100644 --- a/tests/insert_identity_and_proofs.rs +++ b/tests/insert_identity_and_proofs.rs @@ -40,7 +40,7 @@ async fn insert_identity_and_proofs() -> anyhow::Result<()> { .add_prover(prover_mock) .build()?; - let (app, local_addr) = spawn_app(config.clone()) + let (_, app_handle, local_addr) = spawn_app(config.clone()) .await .expect("Failed to spawn app."); @@ -147,11 +147,11 @@ async fn insert_identity_and_proofs() -> anyhow::Result<()> { // behaviour with saved data. info!("Stopping the app for testing purposes"); shutdown(); - app.await.unwrap(); + app_handle.await.unwrap(); reset_shutdown(); // Test loading the state from a file when the on-chain contract has the state. - let (app, local_addr) = spawn_app(config.clone()) + let (_, app_handle, local_addr) = spawn_app(config.clone()) .await .expect("Failed to spawn app."); let uri = "http://".to_owned() + &local_addr.to_string(); @@ -183,12 +183,12 @@ async fn insert_identity_and_proofs() -> anyhow::Result<()> { // behaviour with the saved tree. info!("Stopping the app for testing purposes"); shutdown(); - app.await.unwrap(); + app_handle.await.unwrap(); reset_shutdown(); // Test loading the state from the saved tree when the on-chain contract has the // state. - let (app, local_addr) = spawn_app(config.clone()) + let (_, app_handle, local_addr) = spawn_app(config.clone()) .await .expect("Failed to spawn app."); let uri = "http://".to_owned() + &local_addr.to_string(); @@ -218,7 +218,7 @@ async fn insert_identity_and_proofs() -> anyhow::Result<()> { // Shutdown the app properly for the final time shutdown(); - app.await.unwrap(); + app_handle.await.unwrap(); for (_, prover) in insertion_prover_map.into_iter() { prover.stop(); } diff --git a/tests/malformed_payload.rs b/tests/malformed_payload.rs index 498cdfa2..0037a108 100644 --- a/tests/malformed_payload.rs +++ b/tests/malformed_payload.rs @@ -39,7 +39,7 @@ async fn malformed_payload() -> anyhow::Result<()> { .add_prover(prover_mock) .build()?; - let (app, local_addr) = spawn_app(config).await.expect("Failed to spawn app."); + let (_, app_handle, local_addr) = spawn_app(config).await.expect("Failed to spawn app."); let uri = "http://".to_owned() + &local_addr.to_string(); let client = Client::new(); @@ -73,7 +73,7 @@ async fn malformed_payload() -> anyhow::Result<()> { assert_eq!(response.status(), StatusCode::BAD_REQUEST); shutdown(); - app.await?; + app_handle.await?; for (_, prover) in insertion_prover_map.into_iter() { prover.stop(); } diff --git a/tests/more_identities_than_dense_prefix.rs b/tests/more_identities_than_dense_prefix.rs index 7527a7e7..acaea5a4 100644 --- a/tests/more_identities_than_dense_prefix.rs +++ b/tests/more_identities_than_dense_prefix.rs @@ -54,7 +54,7 @@ async fn more_identities_than_dense_prefix() -> anyhow::Result<()> { .add_prover(prover_mock) .build()?; - let (app, local_addr) = spawn_app(config.clone()) + let (_, app_handle, local_addr) = spawn_app(config.clone()) .await .expect("Failed to spawn app."); @@ -97,11 +97,11 @@ async fn more_identities_than_dense_prefix() -> anyhow::Result<()> { // behaviour with saved data. info!("Stopping the app for testing purposes"); shutdown(); - app.await.unwrap(); + app_handle.await.unwrap(); reset_shutdown(); // Test loading the state from a file when the on-chain contract has the state. - let (app, local_addr) = spawn_app(config.clone()) + let (_, app_handle, local_addr) = spawn_app(config.clone()) .await .expect("Failed to spawn app."); let uri = "http://".to_owned() + &local_addr.to_string(); @@ -130,7 +130,7 @@ async fn more_identities_than_dense_prefix() -> anyhow::Result<()> { // Shutdown the app properly for the final time shutdown(); - app.await.unwrap(); + app_handle.await.unwrap(); for (_, prover) in prover_map.into_iter() { prover.stop(); } diff --git a/tests/multi_prover.rs b/tests/multi_prover.rs index f81f66dd..c456bd25 100644 --- a/tests/multi_prover.rs +++ b/tests/multi_prover.rs @@ -49,7 +49,7 @@ async fn multi_prover() -> anyhow::Result<()> { .build()?; tracing::info!("Spawning app"); - let (app, local_addr) = spawn_app(config).await.expect("Failed to spawn app."); + let (_, app_handle, local_addr) = spawn_app(config).await.expect("Failed to spawn app."); let test_identities = generate_test_identities(batch_size_3 + batch_size_10); @@ -107,7 +107,7 @@ async fn multi_prover() -> anyhow::Result<()> { } shutdown(); - app.await?; + app_handle.await?; for (_, prover) in insertion_prover_map.into_iter() { prover.stop(); } diff --git a/tests/recover_identities.rs b/tests/recover_identities.rs index 4ead71cd..a812fb74 100644 --- a/tests/recover_identities.rs +++ b/tests/recover_identities.rs @@ -63,7 +63,7 @@ async fn recover_identities() -> anyhow::Result<()> { .add_prover(mock_deletion_prover) .build()?; - let (app, local_addr) = spawn_app(config).await.expect("Failed to spawn app."); + let (_, app_handle, local_addr) = spawn_app(config).await.expect("Failed to spawn app."); let test_identities = generate_test_identities(insertion_batch_size * 3); let identities_ref: Vec = test_identities @@ -172,7 +172,7 @@ async fn recover_identities() -> anyhow::Result<()> { // Shutdown the app properly for the final time shutdown(); - app.await.unwrap(); + app_handle.await.unwrap(); for (_, prover) in insertion_prover_map.into_iter() { prover.stop(); } diff --git a/tests/tree_restore_empty.rs b/tests/tree_restore_empty.rs new file mode 100644 index 00000000..2e2c876e --- /dev/null +++ b/tests/tree_restore_empty.rs @@ -0,0 +1,76 @@ +use common::prelude::*; +use signup_sequencer::identity_tree::TreeVersionReadOps; + +use crate::common::test_same_tree_states; + +mod common; + +#[tokio::test] +async fn tree_restore_empty() -> anyhow::Result<()> { + // Initialize logging for the test. + init_tracing_subscriber(); + info!("Starting integration test"); + + let batch_size: usize = 3; + + let ref_tree = PoseidonTree::new(DEFAULT_TREE_DEPTH + 1, ruint::Uint::ZERO); + let initial_root: U256 = ref_tree.root().into(); + + let (mock_chain, db_container, insertion_prover_map, _, micro_oz) = + spawn_deps(initial_root, &[batch_size], &[], DEFAULT_TREE_DEPTH as u8).await?; + + let prover_mock = &insertion_prover_map[&batch_size]; + + let db_socket_addr = db_container.address(); + let db_url = format!("postgres://postgres:postgres@{db_socket_addr}/database"); + + // temp dir will be deleted on drop call + let temp_dir = tempfile::tempdir()?; + info!( + "temp dir created at: {:?}", + temp_dir.path().join("testfile") + ); + + let config = TestConfigBuilder::new() + .db_url(&db_url) + .oz_api_url(µ_oz.endpoint()) + .oz_address(micro_oz.address()) + .identity_manager_address(mock_chain.identity_manager.address()) + .primary_network_provider(mock_chain.anvil.endpoint()) + .cache_file(temp_dir.path().join("testfile").to_str().unwrap()) + .add_prover(prover_mock) + .build()?; + + let (app, app_handle, _) = spawn_app(config.clone()) + .await + .expect("Failed to spawn app."); + + let tree_state = app.tree_state()?.clone(); + + assert_eq!(tree_state.latest_tree().next_leaf(), 0); + + // Shutdown the app and reset the mock shutdown, allowing us to test the + // behaviour with saved data. + info!("Stopping the app for testing purposes"); + shutdown(); + app_handle.await.unwrap(); + reset_shutdown(); + + let (app, app_handle, _) = spawn_app(config.clone()) + .await + .expect("Failed to spawn app."); + + let restored_tree_state = app.tree_state()?.clone(); + + test_same_tree_states(&tree_state, &restored_tree_state).await?; + + // Shutdown the app properly for the final time + shutdown(); + app_handle.await.unwrap(); + for (_, prover) in insertion_prover_map.into_iter() { + prover.stop(); + } + reset_shutdown(); + + Ok(()) +} diff --git a/tests/tree_restore_multiple_comittments.rs b/tests/tree_restore_multiple_comittments.rs new file mode 100644 index 00000000..9f6c5fda --- /dev/null +++ b/tests/tree_restore_multiple_comittments.rs @@ -0,0 +1,93 @@ +use common::prelude::*; +use signup_sequencer::identity_tree::TreeVersionReadOps; + +use crate::common::test_same_tree_states; + +mod common; + +const IDLE_TIME: u64 = 7; + +#[tokio::test] +async fn tree_restore_multiple_commitments() -> anyhow::Result<()> { + // Initialize logging for the test. + init_tracing_subscriber(); + info!("Starting integration test"); + + let batch_size: usize = 3; + + let mut ref_tree = PoseidonTree::new(DEFAULT_TREE_DEPTH + 1, ruint::Uint::ZERO); + let initial_root: U256 = ref_tree.root().into(); + + let (mock_chain, db_container, insertion_prover_map, _, micro_oz) = + spawn_deps(initial_root, &[batch_size], &[], DEFAULT_TREE_DEPTH as u8).await?; + + let prover_mock = &insertion_prover_map[&batch_size]; + + let db_socket_addr = db_container.address(); + let db_url = format!("postgres://postgres:postgres@{db_socket_addr}/database"); + + // temp dir will be deleted on drop call + let temp_dir = tempfile::tempdir()?; + info!( + "temp dir created at: {:?}", + temp_dir.path().join("testfile") + ); + + let config = TestConfigBuilder::new() + .db_url(&db_url) + .oz_api_url(µ_oz.endpoint()) + .oz_address(micro_oz.address()) + .identity_manager_address(mock_chain.identity_manager.address()) + .primary_network_provider(mock_chain.anvil.endpoint()) + .cache_file(temp_dir.path().join("testfile").to_str().unwrap()) + .add_prover(prover_mock) + .build()?; + + let (app, app_handle, local_addr) = spawn_app(config.clone()) + .await + .expect("Failed to spawn app."); + + let test_identities = generate_test_identities(3); + let identities_ref: Vec = test_identities + .iter() + .map(|i| Hash::from_str_radix(i, 16).unwrap()) + .collect(); + + let uri = "http://".to_owned() + &local_addr.to_string(); + let client = Client::new(); + + test_insert_identity(&uri, &client, &mut ref_tree, &identities_ref, 0).await; + test_insert_identity(&uri, &client, &mut ref_tree, &identities_ref, 1).await; + test_insert_identity(&uri, &client, &mut ref_tree, &identities_ref, 2).await; + + tokio::time::sleep(Duration::from_secs(IDLE_TIME)).await; + + let tree_state = app.tree_state()?.clone(); + + assert_eq!(tree_state.latest_tree().next_leaf(), 3); + + // Shutdown the app and reset the mock shutdown, allowing us to test the + // behaviour with saved data. + info!("Stopping the app for testing purposes"); + shutdown(); + app_handle.await.unwrap(); + reset_shutdown(); + + let (app, app_handle, _) = spawn_app(config.clone()) + .await + .expect("Failed to spawn app."); + + let restored_tree_state = app.tree_state()?.clone(); + + test_same_tree_states(&tree_state, &restored_tree_state).await?; + + // Shutdown the app properly for the final time + shutdown(); + app_handle.await.unwrap(); + for (_, prover) in insertion_prover_map.into_iter() { + prover.stop(); + } + reset_shutdown(); + + Ok(()) +} diff --git a/tests/tree_restore_one_comittment.rs b/tests/tree_restore_one_comittment.rs new file mode 100644 index 00000000..1911fe53 --- /dev/null +++ b/tests/tree_restore_one_comittment.rs @@ -0,0 +1,91 @@ +use common::prelude::*; +use signup_sequencer::identity_tree::TreeVersionReadOps; + +use crate::common::test_same_tree_states; + +mod common; + +const IDLE_TIME: u64 = 7; + +#[tokio::test] +async fn tree_restore_one_commitment() -> anyhow::Result<()> { + // Initialize logging for the test. + init_tracing_subscriber(); + info!("Starting integration test"); + + let batch_size: usize = 1; + + let mut ref_tree = PoseidonTree::new(DEFAULT_TREE_DEPTH + 1, ruint::Uint::ZERO); + let initial_root: U256 = ref_tree.root().into(); + + let (mock_chain, db_container, insertion_prover_map, _, micro_oz) = + spawn_deps(initial_root, &[batch_size], &[], DEFAULT_TREE_DEPTH as u8).await?; + + let prover_mock = &insertion_prover_map[&batch_size]; + + let db_socket_addr = db_container.address(); + let db_url = format!("postgres://postgres:postgres@{db_socket_addr}/database"); + + // temp dir will be deleted on drop call + let temp_dir = tempfile::tempdir()?; + info!( + "temp dir created at: {:?}", + temp_dir.path().join("testfile") + ); + + let config = TestConfigBuilder::new() + .db_url(&db_url) + .oz_api_url(µ_oz.endpoint()) + .oz_address(micro_oz.address()) + .identity_manager_address(mock_chain.identity_manager.address()) + .primary_network_provider(mock_chain.anvil.endpoint()) + .cache_file(temp_dir.path().join("testfile").to_str().unwrap()) + .add_prover(prover_mock) + .build()?; + + let (app, app_handle, local_addr) = spawn_app(config.clone()) + .await + .expect("Failed to spawn app."); + + let test_identities = generate_test_identities(1); + let identities_ref: Vec = test_identities + .iter() + .map(|i| Hash::from_str_radix(i, 16).unwrap()) + .collect(); + + let uri = "http://".to_owned() + &local_addr.to_string(); + let client = Client::new(); + + test_insert_identity(&uri, &client, &mut ref_tree, &identities_ref, 0).await; + + tokio::time::sleep(Duration::from_secs(IDLE_TIME)).await; + + let tree_state = app.tree_state()?.clone(); + + assert_eq!(tree_state.latest_tree().next_leaf(), 1); + + // Shutdown the app and reset the mock shutdown, allowing us to test the + // behaviour with saved data. + info!("Stopping the app for testing purposes"); + shutdown(); + app_handle.await.unwrap(); + reset_shutdown(); + + let (app, app_handle, _) = spawn_app(config.clone()) + .await + .expect("Failed to spawn app."); + + let restored_tree_state = app.tree_state()?.clone(); + + test_same_tree_states(&tree_state, &restored_tree_state).await?; + + // Shutdown the app properly for the final time + shutdown(); + app_handle.await.unwrap(); + for (_, prover) in insertion_prover_map.into_iter() { + prover.stop(); + } + reset_shutdown(); + + Ok(()) +} diff --git a/tests/unavailable_prover.rs b/tests/unavailable_prover.rs index d82fd38b..0dfa0c32 100644 --- a/tests/unavailable_prover.rs +++ b/tests/unavailable_prover.rs @@ -40,7 +40,7 @@ async fn unavailable_prover() -> anyhow::Result<()> { .add_prover(prover_mock) .build()?; - let (app, local_addr) = spawn_app(config).await.expect("Failed to spawn app."); + let (_, app_handle, local_addr) = spawn_app(config).await.expect("Failed to spawn app."); let test_identities = generate_test_identities(batch_size * 2); let identities_ref: Vec = test_identities @@ -74,7 +74,7 @@ async fn unavailable_prover() -> anyhow::Result<()> { test_inclusion_proof(&uri, &client, 2, &ref_tree, &identities_ref[2], false).await; shutdown(); - app.await?; + app_handle.await?; for (_, prover) in insertion_prover_map.into_iter() { prover.stop(); } diff --git a/tests/unreduced_identity.rs b/tests/unreduced_identity.rs index c969e4d0..b58e076c 100644 --- a/tests/unreduced_identity.rs +++ b/tests/unreduced_identity.rs @@ -33,7 +33,7 @@ async fn test_unreduced_identity() -> anyhow::Result<()> { .add_prover(prover_mock) .build()?; - let (app, local_addr) = spawn_app(config).await.expect("Failed to spawn app."); + let (_, app_handle, local_addr) = spawn_app(config).await.expect("Failed to spawn app."); let uri = "http://".to_owned() + &local_addr.to_string(); let client = Client::new(); @@ -87,7 +87,7 @@ async fn test_unreduced_identity() -> anyhow::Result<()> { ); shutdown(); - app.await?; + app_handle.await?; for (_, prover) in insertion_prover_map.into_iter() { prover.stop(); } diff --git a/tests/validate_proof_with_age.rs b/tests/validate_proof_with_age.rs index 622e9599..4109286e 100644 --- a/tests/validate_proof_with_age.rs +++ b/tests/validate_proof_with_age.rs @@ -45,7 +45,7 @@ async fn validate_proof_with_age() -> anyhow::Result<()> { .add_prover(prover_mock) .build()?; - let (app, local_addr) = spawn_app(config).await.expect("Failed to spawn app."); + let (_, app_handle, local_addr) = spawn_app(config).await.expect("Failed to spawn app."); let uri = "http://".to_owned() + &local_addr.to_string(); let client = Client::new(); @@ -143,7 +143,7 @@ async fn validate_proof_with_age() -> anyhow::Result<()> { // Shutdown the app properly for the final time shutdown(); - app.await.unwrap(); + app_handle.await.unwrap(); for (_, prover) in insertion_prover_map.into_iter() { prover.stop(); } diff --git a/tests/validate_proofs.rs b/tests/validate_proofs.rs index eaf027f6..81c5247d 100644 --- a/tests/validate_proofs.rs +++ b/tests/validate_proofs.rs @@ -41,7 +41,7 @@ async fn validate_proofs() -> anyhow::Result<()> { .add_prover(prover_mock) .build()?; - let (app, local_addr) = spawn_app(config).await.expect("Failed to spawn app."); + let (_, app_handle, local_addr) = spawn_app(config).await.expect("Failed to spawn app."); let uri = "http://".to_owned() + &local_addr.to_string(); let client = Client::new(); @@ -207,7 +207,7 @@ async fn validate_proofs() -> anyhow::Result<()> { // Shutdown the app properly for the final time shutdown(); - app.await.unwrap(); + app_handle.await.unwrap(); for (_, prover) in insertion_prover_map.into_iter() { prover.stop(); }