diff --git a/zcash_client_sqlite/CHANGELOG.md b/zcash_client_sqlite/CHANGELOG.md index e8841bfd7..a04973c7f 100644 --- a/zcash_client_sqlite/CHANGELOG.md +++ b/zcash_client_sqlite/CHANGELOG.md @@ -7,6 +7,10 @@ and this library adheres to Rust's notion of ## [Unreleased] +### Fixed +- The dependencies of the `tx_retrieval_queue` migration have been fixed to + enable migrating wallets containing certain kinds of transactions. + ## [0.11.0] - 2024-08-20 `zcash_client_sqlite` now provides capabilities for the management of ephemeral diff --git a/zcash_client_sqlite/src/wallet/init/migrations.rs b/zcash_client_sqlite/src/wallet/init/migrations.rs index 3ca427b57..10c97b790 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations.rs @@ -31,6 +31,7 @@ use std::rc::Rc; use schemer_rusqlite::RusqliteMigration; use secrecy::SecretVec; +use uuid::Uuid; use zcash_protocol::consensus; use super::WalletMigrationError; @@ -51,26 +52,28 @@ pub(super) fn all_migrations( // | // v_transactions_net // | - // received_notes_nullable_nf------ - // / | \ - // / | \ - // --------------- shardtree_support sapling_memo_consistency nullifier_map - // / / \ \ - // orchard_shardtree add_account_birthdays receiving_key_scopes v_transactions_transparent_history - // | \ | | - // v_sapling_shard_unscanned_ranges \ | v_tx_outputs_use_legacy_false - // | \ | | - // wallet_summaries \ | v_transactions_shielding_balance - // \ \ | | - // \ \ | v_transactions_note_uniqueness - // \ \ | / - // -------------------- full_account_ids - // | \ - // orchard_received_notes spend_key_available - // / \ - // ensure_orchard_ua_receiver utxos_to_txos - // / \ - // ephemeral_addresses tx_retrieval_queue + // received_notes_nullable_nf---------------------- + // / | \ + // / | \ + // --------------- shardtree_support sapling_memo_consistency nullifier_map + // / / \ \ | + // orchard_shardtree add_account_birthdays receiving_key_scopes v_transactions_transparent_history | + // | | \ | | | + // | v_sapling_shard_unscanned_ranges \ | v_tx_outputs_use_legacy_false | + // | | \ | | | + // | wallet_summaries \ | v_transactions_shielding_balance | + // | \ \ | | / + // \ \ \ | v_transactions_note_uniqueness / + // \ \ \ | / / + // \ -------------------- full_account_ids / + // \ / \ / + // \ orchard_received_notes spend_key_available / + // \ / \ / / + // \ ensure_orchard_ua_receiver utxos_to_txos / / + // \ \ | / / + // \ \ ephemeral_addresses / / + // \ \ | / / + // ------------------------------ tx_retrieval_queue ---------------------------- vec![ Box::new(initial_setup::Migration {}), Box::new(utxos_table::Migration {}), @@ -131,8 +134,69 @@ pub(super) fn all_migrations( ] } +/// All states of the migration DAG that have been exposed in a public crate release, in +/// the order that crate users would have encountered them. +/// +/// Omitted versions had the same migration state as the first prior version that is +/// included. +#[allow(dead_code)] +const PUBLIC_MIGRATION_STATES: &[&[Uuid]] = &[ + V_0_4_0, V_0_6_0, V_0_8_0, V_0_9_0, V_0_10_0, V_0_10_3, V_0_11_0, V_0_11_1, +]; + +/// Leaf migrations in the 0.4.0 release. +const V_0_4_0: &[Uuid] = &[add_transaction_views::MIGRATION_ID]; + +/// Leaf migrations in the 0.6.0 release. +const V_0_6_0: &[Uuid] = &[v_transactions_net::MIGRATION_ID]; + +/// Leaf migrations in the 0.8.0 release. +const V_0_8_0: &[Uuid] = &[ + nullifier_map::MIGRATION_ID, + v_transactions_note_uniqueness::MIGRATION_ID, + wallet_summaries::MIGRATION_ID, +]; + +/// Leaf migrations in the 0.9.0 release. +const V_0_9_0: &[Uuid] = &[ + nullifier_map::MIGRATION_ID, + receiving_key_scopes::MIGRATION_ID, + v_transactions_note_uniqueness::MIGRATION_ID, + wallet_summaries::MIGRATION_ID, +]; + +/// Leaf migrations in the 0.10.0 release. +const V_0_10_0: &[Uuid] = &[ + nullifier_map::MIGRATION_ID, + orchard_received_notes::MIGRATION_ID, + orchard_shardtree::MIGRATION_ID, +]; + +/// Leaf migrations in the 0.10.3 release. +const V_0_10_3: &[Uuid] = &[ + ensure_orchard_ua_receiver::MIGRATION_ID, + nullifier_map::MIGRATION_ID, + orchard_shardtree::MIGRATION_ID, +]; + +/// Leaf migrations in the 0.11.0 release. +const V_0_11_0: &[Uuid] = &[ + ensure_orchard_ua_receiver::MIGRATION_ID, + ephemeral_addresses::MIGRATION_ID, + nullifier_map::MIGRATION_ID, + orchard_shardtree::MIGRATION_ID, + spend_key_available::MIGRATION_ID, + tx_retrieval_queue::MIGRATION_ID, +]; + +/// Leaf migrations in the 0.11.1 release. +const V_0_11_1: &[Uuid] = &[tx_retrieval_queue::MIGRATION_ID]; + #[cfg(test)] mod tests { + use std::collections::HashSet; + + use rusqlite::Connection; use secrecy::Secret; use tempfile::NamedTempFile; use uuid::Uuid; @@ -157,4 +221,55 @@ mod tests { Ok(_) ); } + + #[test] + fn migrate_between_releases_without_data() { + let data_file = NamedTempFile::new().unwrap(); + let mut db_data = WalletDb::for_path(data_file.path(), Network::TestNetwork).unwrap(); + + let seed = [0xab; 32].to_vec(); + + let mut prev_state = HashSet::new(); + let mut ensure_migration_state_changed = |conn: &Connection| { + let new_state = conn + .prepare_cached("SELECT * FROM schemer_migrations") + .unwrap() + .query_map([], |row| row.get::<_, [u8; 16]>(0).map(Uuid::from_bytes)) + .unwrap() + .collect::, _>>() + .unwrap(); + assert!(prev_state != new_state); + prev_state = new_state; + }; + + let mut prev_leaves: &[Uuid] = &[]; + for migrations in super::PUBLIC_MIGRATION_STATES { + assert_matches!( + init_wallet_db_internal( + &mut db_data, + Some(Secret::new(seed.clone())), + migrations, + false + ), + Ok(_) + ); + + // If we have any new leaves, ensure the migration state changed. This lets us + // represent releases that changed the graph edges without introducing any new + // migrations. + if migrations.iter().any(|m| !prev_leaves.contains(m)) { + ensure_migration_state_changed(&db_data.conn); + } + + prev_leaves = *migrations; + } + + // Now check that we can migrate from the last public release to the current + // migration state in this branch. + assert_matches!( + init_wallet_db_internal(&mut db_data, Some(Secret::new(seed)), &[], false), + Ok(_) + ); + // We don't ensure that the migration state changed, because it may not have. + } } diff --git a/zcash_client_sqlite/src/wallet/init/migrations/add_account_birthdays.rs b/zcash_client_sqlite/src/wallet/init/migrations/add_account_birthdays.rs index fc1fb2fc1..0f0ca6335 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/add_account_birthdays.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/add_account_birthdays.rs @@ -12,7 +12,7 @@ use super::shardtree_support; pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0xeeec0d0d_fee0_4231_8c68_5f3a7c7c2245); -const DEPENDENCIES: [Uuid; 1] = [shardtree_support::MIGRATION_ID]; +const DEPENDENCIES: &[Uuid] = &[shardtree_support::MIGRATION_ID]; pub(super) struct Migration

{ pub(super) params: P, @@ -24,7 +24,7 @@ impl

schemer::Migration for Migration

{ } fn dependencies(&self) -> HashSet { - DEPENDENCIES.into_iter().collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str { @@ -91,7 +91,7 @@ mod tests { init_wallet_db_internal( &mut db_data, Some(Secret::new(seed_bytes.clone())), - &DEPENDENCIES, + DEPENDENCIES, false, ) .unwrap(); diff --git a/zcash_client_sqlite/src/wallet/init/migrations/add_transaction_views.rs b/zcash_client_sqlite/src/wallet/init/migrations/add_transaction_views.rs index b73c7af89..27fcef593 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/add_transaction_views.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/add_transaction_views.rs @@ -18,6 +18,11 @@ use crate::wallet::init::WalletMigrationError; pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0x282fad2e_8372_4ca0_8bed_71821320909f); +const DEPENDENCIES: &[Uuid] = &[ + add_utxo_account::MIGRATION_ID, + sent_notes_to_internal::MIGRATION_ID, +]; + pub(crate) struct Migration; impl schemer::Migration for Migration { @@ -26,12 +31,7 @@ impl schemer::Migration for Migration { } fn dependencies(&self) -> HashSet { - [ - add_utxo_account::MIGRATION_ID, - sent_notes_to_internal::MIGRATION_ID, - ] - .into_iter() - .collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str { diff --git a/zcash_client_sqlite/src/wallet/init/migrations/add_utxo_account.rs b/zcash_client_sqlite/src/wallet/init/migrations/add_utxo_account.rs index 5ac20471a..cf430641e 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/add_utxo_account.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/add_utxo_account.rs @@ -28,6 +28,8 @@ use { /// This migration adds an account identifier column to the UTXOs table. pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0x761884d6_30d8_44ef_b204_0b82551c4ca1); +const DEPENDENCIES: &[Uuid] = &[utxos_table::MIGRATION_ID, addresses_table::MIGRATION_ID]; + pub(super) struct Migration

{ pub(super) _params: P, } @@ -38,9 +40,7 @@ impl

schemer::Migration for Migration

{ } fn dependencies(&self) -> HashSet { - [utxos_table::MIGRATION_ID, addresses_table::MIGRATION_ID] - .into_iter() - .collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str { diff --git a/zcash_client_sqlite/src/wallet/init/migrations/addresses_table.rs b/zcash_client_sqlite/src/wallet/init/migrations/addresses_table.rs index 8ee5a9811..cbdd681e7 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/addresses_table.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/addresses_table.rs @@ -20,6 +20,8 @@ use super::ufvk_support; /// the `accounts` table. pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0xd956978c_9c87_4d6e_815d_fb8f088d094c); +const DEPENDENCIES: &[Uuid] = &[ufvk_support::MIGRATION_ID]; + pub(crate) struct Migration { pub(crate) params: P, } @@ -30,7 +32,7 @@ impl schemer::Migration for Migration

{ } fn dependencies(&self) -> HashSet { - [ufvk_support::MIGRATION_ID].into_iter().collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str { diff --git a/zcash_client_sqlite/src/wallet/init/migrations/ensure_orchard_ua_receiver.rs b/zcash_client_sqlite/src/wallet/init/migrations/ensure_orchard_ua_receiver.rs index 11d38dc61..31a57f44c 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/ensure_orchard_ua_receiver.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/ensure_orchard_ua_receiver.rs @@ -15,6 +15,8 @@ use crate::{wallet::init::WalletMigrationError, UA_ORCHARD, UA_TRANSPARENT}; pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0x604349c7_5ce5_4768_bea6_12d106ccda93); +const DEPENDENCIES: &[Uuid] = &[orchard_received_notes::MIGRATION_ID]; + pub(super) struct Migration

{ pub(super) params: P, } @@ -25,7 +27,7 @@ impl

schemer::Migration for Migration

{ } fn dependencies(&self) -> HashSet { - [orchard_received_notes::MIGRATION_ID].into_iter().collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str { diff --git a/zcash_client_sqlite/src/wallet/init/migrations/ephemeral_addresses.rs b/zcash_client_sqlite/src/wallet/init/migrations/ephemeral_addresses.rs index 686719722..40135cae0 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/ephemeral_addresses.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/ephemeral_addresses.rs @@ -16,7 +16,7 @@ use super::utxos_to_txos; pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0x0e1d4274_1f8e_44e2_909d_689a4bc2967b); -const DEPENDENCIES: [Uuid; 1] = [utxos_to_txos::MIGRATION_ID]; +const DEPENDENCIES: &[Uuid] = &[utxos_to_txos::MIGRATION_ID]; #[allow(dead_code)] pub(super) struct Migration

{ @@ -29,7 +29,7 @@ impl

schemer::Migration for Migration

{ } fn dependencies(&self) -> HashSet { - DEPENDENCIES.into_iter().collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str { @@ -210,7 +210,7 @@ mod tests { init_wallet_db_internal( &mut db_data, Some(Secret::new(seed0.clone())), - &super::DEPENDENCIES, + super::DEPENDENCIES, false, ) .unwrap(); diff --git a/zcash_client_sqlite/src/wallet/init/migrations/full_account_ids.rs b/zcash_client_sqlite/src/wallet/init/migrations/full_account_ids.rs index dd2de2360..91ad456cf 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/full_account_ids.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/full_account_ids.rs @@ -26,20 +26,20 @@ pub(crate) struct Migration { pub(super) params: P, } +const DEPENDENCIES: &[Uuid] = &[ + receiving_key_scopes::MIGRATION_ID, + add_account_birthdays::MIGRATION_ID, + v_transactions_note_uniqueness::MIGRATION_ID, + wallet_summaries::MIGRATION_ID, +]; + impl schemer::Migration for Migration

{ fn id(&self) -> Uuid { MIGRATION_ID } fn dependencies(&self) -> HashSet { - [ - receiving_key_scopes::MIGRATION_ID, - add_account_birthdays::MIGRATION_ID, - v_transactions_note_uniqueness::MIGRATION_ID, - wallet_summaries::MIGRATION_ID, - ] - .into_iter() - .collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str { diff --git a/zcash_client_sqlite/src/wallet/init/migrations/nullifier_map.rs b/zcash_client_sqlite/src/wallet/init/migrations/nullifier_map.rs index fbdbe8c0d..5c2e9fb08 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/nullifier_map.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/nullifier_map.rs @@ -13,6 +13,8 @@ use super::received_notes_nullable_nf; pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0xe2d71ac5_6a44_4c6b_a9a0_6d0a79d355f1); +const DEPENDENCIES: &[Uuid] = &[received_notes_nullable_nf::MIGRATION_ID]; + pub(super) struct Migration; impl schemer::Migration for Migration { @@ -21,9 +23,7 @@ impl schemer::Migration for Migration { } fn dependencies(&self) -> HashSet { - [received_notes_nullable_nf::MIGRATION_ID] - .into_iter() - .collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str { diff --git a/zcash_client_sqlite/src/wallet/init/migrations/orchard_received_notes.rs b/zcash_client_sqlite/src/wallet/init/migrations/orchard_received_notes.rs index c44239605..66931cccf 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/orchard_received_notes.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/orchard_received_notes.rs @@ -12,6 +12,8 @@ use crate::wallet::{init::WalletMigrationError, pool_code}; pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0x51d7a273_aa19_4109_9325_80e4a5545048); +const DEPENDENCIES: &[Uuid] = &[full_account_ids::MIGRATION_ID]; + pub(super) struct Migration; impl schemer::Migration for Migration { @@ -20,7 +22,7 @@ impl schemer::Migration for Migration { } fn dependencies(&self) -> HashSet { - [full_account_ids::MIGRATION_ID].into_iter().collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str { diff --git a/zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs b/zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs index dc44f1e08..5357b5e03 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/orchard_shardtree.rs @@ -15,6 +15,8 @@ use crate::wallet::{chain_tip_height, init::WalletMigrationError, scanning::prio pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0x3a6487f7_e068_42bb_9d12_6bb8dbe6da00); +const DEPENDENCIES: &[Uuid] = &[shardtree_support::MIGRATION_ID]; + pub(super) struct Migration

{ pub(super) params: P, } @@ -25,7 +27,7 @@ impl

schemer::Migration for Migration

{ } fn dependencies(&self) -> HashSet { - [shardtree_support::MIGRATION_ID].into_iter().collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str { diff --git a/zcash_client_sqlite/src/wallet/init/migrations/received_notes_nullable_nf.rs b/zcash_client_sqlite/src/wallet/init/migrations/received_notes_nullable_nf.rs index e5800cdcc..4b1dabdc4 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/received_notes_nullable_nf.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/received_notes_nullable_nf.rs @@ -13,6 +13,8 @@ use crate::wallet::init::WalletMigrationError; pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0xbdcdcedc_7b29_4f1c_8307_35f937f0d32a); +const DEPENDENCIES: &[Uuid] = &[v_transactions_net::MIGRATION_ID]; + pub(crate) struct Migration; impl schemer::Migration for Migration { @@ -21,7 +23,7 @@ impl schemer::Migration for Migration { } fn dependencies(&self) -> HashSet { - [v_transactions_net::MIGRATION_ID].into_iter().collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str { diff --git a/zcash_client_sqlite/src/wallet/init/migrations/receiving_key_scopes.rs b/zcash_client_sqlite/src/wallet/init/migrations/receiving_key_scopes.rs index d27015383..84b8d8cee 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/receiving_key_scopes.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/receiving_key_scopes.rs @@ -38,6 +38,8 @@ use crate::{ pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0xee89ed2b_c1c2_421e_9e98_c1e3e54a7fc2); +const DEPENDENCIES: &[Uuid] = &[shardtree_support::MIGRATION_ID]; + pub(super) struct Migration

{ pub(super) params: P, } @@ -48,7 +50,7 @@ impl

schemer::Migration for Migration

{ } fn dependencies(&self) -> HashSet { - [shardtree_support::MIGRATION_ID].into_iter().collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str { diff --git a/zcash_client_sqlite/src/wallet/init/migrations/sapling_memo_consistency.rs b/zcash_client_sqlite/src/wallet/init/migrations/sapling_memo_consistency.rs index ce7adbbf8..590d773d6 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/sapling_memo_consistency.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/sapling_memo_consistency.rs @@ -19,6 +19,8 @@ use super::received_notes_nullable_nf; pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0x7029b904_6557_4aa1_9da5_6904b65d2ba5); +const DEPENDENCIES: &[Uuid] = &[received_notes_nullable_nf::MIGRATION_ID]; + pub(super) struct Migration

{ pub(super) params: P, } @@ -29,9 +31,7 @@ impl

schemer::Migration for Migration

{ } fn dependencies(&self) -> HashSet { - [received_notes_nullable_nf::MIGRATION_ID] - .into_iter() - .collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str { diff --git a/zcash_client_sqlite/src/wallet/init/migrations/sent_notes_to_internal.rs b/zcash_client_sqlite/src/wallet/init/migrations/sent_notes_to_internal.rs index 27f156dea..881e80397 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/sent_notes_to_internal.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/sent_notes_to_internal.rs @@ -13,6 +13,8 @@ use crate::wallet::init::WalletMigrationError; /// This migration adds the `to_account` field to the `sent_notes` table. pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0x0ddbe561_8259_4212_9ab7_66fdc4a74e1d); +const DEPENDENCIES: &[Uuid] = &[ufvk_support::MIGRATION_ID]; + pub(super) struct Migration; impl schemer::Migration for Migration { @@ -21,7 +23,7 @@ impl schemer::Migration for Migration { } fn dependencies(&self) -> HashSet { - [ufvk_support::MIGRATION_ID].into_iter().collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str { diff --git a/zcash_client_sqlite/src/wallet/init/migrations/shardtree_support.rs b/zcash_client_sqlite/src/wallet/init/migrations/shardtree_support.rs index 793475979..88743518e 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/shardtree_support.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/shardtree_support.rs @@ -33,6 +33,8 @@ use crate::{ pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0x7da6489d_e835_4657_8be5_f512bcce6cbf); +const DEPENDENCIES: &[Uuid] = &[received_notes_nullable_nf::MIGRATION_ID]; + pub(super) struct Migration

{ pub(super) params: P, } @@ -43,9 +45,7 @@ impl

schemer::Migration for Migration

{ } fn dependencies(&self) -> HashSet { - [received_notes_nullable_nf::MIGRATION_ID] - .into_iter() - .collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str { diff --git a/zcash_client_sqlite/src/wallet/init/migrations/spend_key_available.rs b/zcash_client_sqlite/src/wallet/init/migrations/spend_key_available.rs index ac74e2bf6..d38be3ab5 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/spend_key_available.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/spend_key_available.rs @@ -12,7 +12,7 @@ use super::full_account_ids; pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0x07610aac_b0e3_4ba8_aaa6_cda606f0fd7b); -const DEPENDENCIES: [Uuid; 1] = [full_account_ids::MIGRATION_ID]; +const DEPENDENCIES: &[Uuid] = &[full_account_ids::MIGRATION_ID]; #[allow(dead_code)] pub(super) struct Migration; @@ -23,7 +23,7 @@ impl schemer::Migration for Migration { } fn dependencies(&self) -> HashSet { - DEPENDENCIES.into_iter().collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str { diff --git a/zcash_client_sqlite/src/wallet/init/migrations/tx_retrieval_queue.rs b/zcash_client_sqlite/src/wallet/init/migrations/tx_retrieval_queue.rs index 4c17103e0..5c94abbc2 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/tx_retrieval_queue.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/tx_retrieval_queue.rs @@ -10,10 +10,21 @@ use zcash_protocol::consensus::{self, BlockHeight, BranchId}; use crate::wallet::{self, init::WalletMigrationError}; -use super::utxos_to_txos; +use super::{ + ensure_orchard_ua_receiver, ephemeral_addresses, nullifier_map, orchard_shardtree, + spend_key_available, +}; pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0xfec02b61_3988_4b4f_9699_98977fac9e7f); +const DEPENDENCIES: &[Uuid] = &[ + orchard_shardtree::MIGRATION_ID, + ensure_orchard_ua_receiver::MIGRATION_ID, + ephemeral_addresses::MIGRATION_ID, + spend_key_available::MIGRATION_ID, + nullifier_map::MIGRATION_ID, +]; + pub(super) struct Migration

{ pub(super) params: P, } @@ -24,7 +35,7 @@ impl

schemer::Migration for Migration

{ } fn dependencies(&self) -> HashSet { - [utxos_to_txos::MIGRATION_ID].into_iter().collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str { @@ -133,10 +144,89 @@ impl RusqliteMigration for Migration

{ #[cfg(test)] mod tests { - use crate::wallet::init::migrations::tests::test_migrate; + use rusqlite::named_params; + use secrecy::Secret; + use tempfile::NamedTempFile; + use zcash_primitives::{ + legacy::{Script, TransparentAddress}, + transaction::{components::transparent, Authorized, TransactionData, TxVersion}, + }; + use zcash_protocol::{ + consensus::{BranchId, Network}, + value::Zatoshis, + }; + + use crate::{ + wallet::init::{init_wallet_db_internal, migrations::tests::test_migrate}, + WalletDb, + }; + + use super::{DEPENDENCIES, MIGRATION_ID}; #[test] fn migrate() { - test_migrate(&[super::MIGRATION_ID]); + test_migrate(&[MIGRATION_ID]); + } + + #[test] + fn migrate_with_data() { + let data_file = NamedTempFile::new().unwrap(); + let mut db_data = WalletDb::for_path(data_file.path(), Network::TestNetwork).unwrap(); + + let seed_bytes = vec![0xab; 32]; + + // Migrate to database state just prior to this migration. + init_wallet_db_internal( + &mut db_data, + Some(Secret::new(seed_bytes.clone())), + DEPENDENCIES, + false, + ) + .unwrap(); + + // Add transactions to the wallet that exercise the data migration. + let add_tx_to_wallet = |tx: TransactionData| { + let tx = tx.freeze().unwrap(); + let txid = tx.txid(); + let mut raw_tx = vec![]; + tx.write(&mut raw_tx).unwrap(); + db_data + .conn + .execute( + r#"INSERT INTO transactions (txid, raw) VALUES (:txid, :raw);"#, + named_params! {":txid": txid.as_ref(), ":raw": raw_tx}, + ) + .unwrap(); + }; + add_tx_to_wallet(TransactionData::from_parts( + TxVersion::Zip225, + BranchId::Nu5, + 0, + 12345678.into(), + Some(transparent::Bundle { + vin: vec![transparent::TxIn { + prevout: transparent::OutPoint::fake(), + script_sig: Script(vec![]), + sequence: 0, + }], + vout: vec![transparent::TxOut { + value: Zatoshis::const_from_u64(10_000), + script_pubkey: TransparentAddress::PublicKeyHash([7; 20]).script(), + }], + authorization: transparent::Authorized, + }), + None, + None, + None, + )); + + // Check that we can apply this migration. + init_wallet_db_internal( + &mut db_data, + Some(Secret::new(seed_bytes)), + &[MIGRATION_ID], + false, + ) + .unwrap(); } } diff --git a/zcash_client_sqlite/src/wallet/init/migrations/ufvk_support.rs b/zcash_client_sqlite/src/wallet/init/migrations/ufvk_support.rs index e3c128b5b..f4354d1d7 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/ufvk_support.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/ufvk_support.rs @@ -27,6 +27,8 @@ use crate::{ pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0xbe57ef3b_388e_42ea_97e2_678dafcf9754); +const DEPENDENCIES: &[Uuid] = &[initial_setup::MIGRATION_ID]; + pub(super) struct Migration

{ pub(super) params: P, pub(super) seed: Option>>, @@ -38,7 +40,7 @@ impl

schemer::Migration for Migration

{ } fn dependencies(&self) -> HashSet { - [initial_setup::MIGRATION_ID].into_iter().collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str { diff --git a/zcash_client_sqlite/src/wallet/init/migrations/utxos_table.rs b/zcash_client_sqlite/src/wallet/init/migrations/utxos_table.rs index c0541a1dc..09f5fe16c 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/utxos_table.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/utxos_table.rs @@ -10,6 +10,8 @@ use crate::wallet::init::{migrations::initial_setup, WalletMigrationError}; pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0xa2e0ed2e_8852_475e_b0a4_f154b15b9dbe); +const DEPENDENCIES: &[Uuid] = &[initial_setup::MIGRATION_ID]; + pub(super) struct Migration; impl schemer::Migration for Migration { @@ -18,7 +20,7 @@ impl schemer::Migration for Migration { } fn dependencies(&self) -> HashSet { - [initial_setup::MIGRATION_ID].into_iter().collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str { diff --git a/zcash_client_sqlite/src/wallet/init/migrations/utxos_to_txos.rs b/zcash_client_sqlite/src/wallet/init/migrations/utxos_to_txos.rs index dd8ce7ce8..60ab72214 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/utxos_to_txos.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/utxos_to_txos.rs @@ -11,6 +11,8 @@ use crate::wallet::init::{migrations::orchard_received_notes, WalletMigrationErr pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0x3a2562b3_f174_46a1_aa8c_1d122ca2e884); +const DEPENDENCIES: &[Uuid] = &[orchard_received_notes::MIGRATION_ID]; + pub(super) struct Migration; impl schemer::Migration for Migration { @@ -19,7 +21,7 @@ impl schemer::Migration for Migration { } fn dependencies(&self) -> HashSet { - [orchard_received_notes::MIGRATION_ID].into_iter().collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str { diff --git a/zcash_client_sqlite/src/wallet/init/migrations/v_sapling_shard_unscanned_ranges.rs b/zcash_client_sqlite/src/wallet/init/migrations/v_sapling_shard_unscanned_ranges.rs index 3eab3dacb..cf7465d2f 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/v_sapling_shard_unscanned_ranges.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/v_sapling_shard_unscanned_ranges.rs @@ -14,6 +14,8 @@ use super::add_account_birthdays; pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0xfa934bdc_97b6_4980_8a83_b2cb1ac465fd); +const DEPENDENCIES: &[Uuid] = &[add_account_birthdays::MIGRATION_ID]; + pub(super) struct Migration

{ pub(super) params: P, } @@ -24,7 +26,7 @@ impl

schemer::Migration for Migration

{ } fn dependencies(&self) -> HashSet { - [add_account_birthdays::MIGRATION_ID].into_iter().collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str { diff --git a/zcash_client_sqlite/src/wallet/init/migrations/v_transactions_net.rs b/zcash_client_sqlite/src/wallet/init/migrations/v_transactions_net.rs index 8b4aa6d19..db0d43f31 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/v_transactions_net.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/v_transactions_net.rs @@ -13,6 +13,8 @@ use crate::wallet::{init::WalletMigrationError, pool_code}; pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0x2aa4d24f_51aa_4a4c_8d9b_e5b8a762865f); +const DEPENDENCIES: &[Uuid] = &[add_transaction_views::MIGRATION_ID]; + pub(crate) struct Migration; impl schemer::Migration for Migration { @@ -21,7 +23,7 @@ impl schemer::Migration for Migration { } fn dependencies(&self) -> HashSet { - [add_transaction_views::MIGRATION_ID].into_iter().collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str { diff --git a/zcash_client_sqlite/src/wallet/init/migrations/v_transactions_note_uniqueness.rs b/zcash_client_sqlite/src/wallet/init/migrations/v_transactions_note_uniqueness.rs index 3b507d817..3d48d6abf 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/v_transactions_note_uniqueness.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/v_transactions_note_uniqueness.rs @@ -12,6 +12,8 @@ use super::v_transactions_shielding_balance; pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0xdba47c86_13b5_4601_94b2_0cde0abe1e45); +const DEPENDENCIES: &[Uuid] = &[v_transactions_shielding_balance::MIGRATION_ID]; + pub(super) struct Migration; impl schemer::Migration for Migration { @@ -20,9 +22,7 @@ impl schemer::Migration for Migration { } fn dependencies(&self) -> HashSet { - [v_transactions_shielding_balance::MIGRATION_ID] - .into_iter() - .collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str { diff --git a/zcash_client_sqlite/src/wallet/init/migrations/v_transactions_shielding_balance.rs b/zcash_client_sqlite/src/wallet/init/migrations/v_transactions_shielding_balance.rs index 368b4ce44..a783f972e 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/v_transactions_shielding_balance.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/v_transactions_shielding_balance.rs @@ -12,6 +12,8 @@ use super::v_tx_outputs_use_legacy_false; pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0xb8fe5112_4365_473c_8b42_2b07c0f0adaf); +const DEPENDENCIES: &[Uuid] = &[v_tx_outputs_use_legacy_false::MIGRATION_ID]; + pub(super) struct Migration; impl schemer::Migration for Migration { @@ -20,9 +22,7 @@ impl schemer::Migration for Migration { } fn dependencies(&self) -> HashSet { - [v_tx_outputs_use_legacy_false::MIGRATION_ID] - .into_iter() - .collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str { diff --git a/zcash_client_sqlite/src/wallet/init/migrations/v_transactions_transparent_history.rs b/zcash_client_sqlite/src/wallet/init/migrations/v_transactions_transparent_history.rs index 6e710d8ae..4904c252c 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/v_transactions_transparent_history.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/v_transactions_transparent_history.rs @@ -12,6 +12,8 @@ use super::sapling_memo_consistency; pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0xaa0a4168_b41b_44c5_a47d_c4c66603cfab); +const DEPENDENCIES: &[Uuid] = &[sapling_memo_consistency::MIGRATION_ID]; + pub(super) struct Migration; impl schemer::Migration for Migration { @@ -20,9 +22,7 @@ impl schemer::Migration for Migration { } fn dependencies(&self) -> HashSet { - [sapling_memo_consistency::MIGRATION_ID] - .into_iter() - .collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str { diff --git a/zcash_client_sqlite/src/wallet/init/migrations/v_tx_outputs_use_legacy_false.rs b/zcash_client_sqlite/src/wallet/init/migrations/v_tx_outputs_use_legacy_false.rs index 35f43c118..2d4051945 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/v_tx_outputs_use_legacy_false.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/v_tx_outputs_use_legacy_false.rs @@ -13,6 +13,8 @@ use super::v_transactions_transparent_history; pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0xb3e21434_286f_41f3_8d71_44cce968ab2b); +const DEPENDENCIES: &[Uuid] = &[v_transactions_transparent_history::MIGRATION_ID]; + pub(super) struct Migration; impl schemer::Migration for Migration { @@ -21,9 +23,7 @@ impl schemer::Migration for Migration { } fn dependencies(&self) -> HashSet { - [v_transactions_transparent_history::MIGRATION_ID] - .into_iter() - .collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str { diff --git a/zcash_client_sqlite/src/wallet/init/migrations/wallet_summaries.rs b/zcash_client_sqlite/src/wallet/init/migrations/wallet_summaries.rs index 3a103e282..18940c61b 100644 --- a/zcash_client_sqlite/src/wallet/init/migrations/wallet_summaries.rs +++ b/zcash_client_sqlite/src/wallet/init/migrations/wallet_summaries.rs @@ -11,6 +11,8 @@ use super::v_sapling_shard_unscanned_ranges; pub(super) const MIGRATION_ID: Uuid = Uuid::from_u128(0xc5bf7f71_2297_41ff_89e1_75e07c4e8838); +const DEPENDENCIES: &[Uuid] = &[v_sapling_shard_unscanned_ranges::MIGRATION_ID]; + pub(super) struct Migration; impl schemer::Migration for Migration { @@ -19,9 +21,7 @@ impl schemer::Migration for Migration { } fn dependencies(&self) -> HashSet { - [v_sapling_shard_unscanned_ranges::MIGRATION_ID] - .into_iter() - .collect() + DEPENDENCIES.iter().copied().collect() } fn description(&self) -> &'static str {