From 53fd41e1cac0785d50d7aa86b7aa7204e05805fe Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 24 Aug 2022 07:48:31 -0600 Subject: [PATCH] Use librustzcash's built-in database migrations. (#33) Co-authored-by: str4d --- rust/Cargo.lock | 93 +++++++++++++++++++++++++++++++++++++++++++------ rust/Cargo.toml | 10 +++--- rust/src/lib.rs | 91 +++++++++++++++++++++++------------------------ 3 files changed, 132 insertions(+), 62 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 26bdb34..6096e41 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -468,6 +468,15 @@ dependencies = [ "subtle", ] +[[package]] +name = "daggy" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2099ef075418d7b252af69583c831cde749af9423c2a212dea8895e8ea78841" +dependencies = [ + "petgraph", +] + [[package]] name = "digest" version = "0.8.1" @@ -531,7 +540,7 @@ checksum = "3f107b87b6afc2a64fd13cac55fe06d6c8859f12d4b14cbcdd2c67d0976781be" [[package]] name = "equihash" version = "0.2.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=37fc28634e811fdf8db9274a0080cff17c6b6a09#37fc28634e811fdf8db9274a0080cff17c6b6a09" +source = "git+https://github.com/zcash/librustzcash.git?rev=5dceb93ec8aba7d831f6fdacdbbcf3ee3667779d#5dceb93ec8aba7d831f6fdacdbbcf3ee3667779d" dependencies = [ "blake2b_simd", "byteorder", @@ -540,7 +549,7 @@ dependencies = [ [[package]] name = "f4jumble" version = "0.1.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=37fc28634e811fdf8db9274a0080cff17c6b6a09#37fc28634e811fdf8db9274a0080cff17c6b6a09" +source = "git+https://github.com/zcash/librustzcash.git?rev=5dceb93ec8aba7d831f6fdacdbbcf3ee3667779d#5dceb93ec8aba7d831f6fdacdbbcf3ee3667779d" dependencies = [ "blake2b_simd", ] @@ -610,6 +619,12 @@ dependencies = [ "libc", ] +[[package]] +name = "fixedbitset" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" + [[package]] name = "fpe" version = "0.5.1" @@ -873,7 +888,9 @@ dependencies = [ "hdwallet", "hdwallet-bitcoin", "hex", + "schemer", "secp256k1", + "secrecy", "zcash_client_backend", "zcash_client_sqlite", "zcash_primitives", @@ -1090,6 +1107,15 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +[[package]] +name = "petgraph" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3659d1ee90221741f65dd128d9998311b0e40c5d3c23a62445938214abce4f" +dependencies = [ + "fixedbitset", +] + [[package]] name = "pin-project-lite" version = "0.2.9" @@ -1362,6 +1388,29 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" +[[package]] +name = "schemer" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48f0ed79b582101b59740acd981e58eaa3bf8c4b1179e9a0124a7df1e08e98b3" +dependencies = [ + "daggy", + "log", + "thiserror", + "uuid", +] + +[[package]] +name = "schemer-rusqlite" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f2b83ba5d80561f0ac602bd539a22d34015e332b82dd9d29c94aa84adbd55d7" +dependencies = [ + "rusqlite", + "schemer", + "uuid", +] + [[package]] name = "scopeguard" version = "1.1.0" @@ -1386,6 +1435,15 @@ dependencies = [ "cc", ] +[[package]] +name = "secrecy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "zeroize", +] + [[package]] name = "semver" version = "0.9.0" @@ -1792,6 +1850,12 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "uuid" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f" + [[package]] name = "vcpkg" version = "0.2.15" @@ -1914,7 +1978,7 @@ dependencies = [ [[package]] name = "zcash_address" version = "0.1.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=37fc28634e811fdf8db9274a0080cff17c6b6a09#37fc28634e811fdf8db9274a0080cff17c6b6a09" +source = "git+https://github.com/zcash/librustzcash.git?rev=5dceb93ec8aba7d831f6fdacdbbcf3ee3667779d#5dceb93ec8aba7d831f6fdacdbbcf3ee3667779d" dependencies = [ "bech32", "bs58", @@ -1925,12 +1989,13 @@ dependencies = [ [[package]] name = "zcash_client_backend" version = "0.5.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=37fc28634e811fdf8db9274a0080cff17c6b6a09#37fc28634e811fdf8db9274a0080cff17c6b6a09" +source = "git+https://github.com/zcash/librustzcash.git?rev=5dceb93ec8aba7d831f6fdacdbbcf3ee3667779d#5dceb93ec8aba7d831f6fdacdbbcf3ee3667779d" dependencies = [ "base64", "bech32", "bls12_381", "bs58", + "crossbeam-channel", "ff", "group", "hdwallet", @@ -1943,20 +2008,22 @@ dependencies = [ "protobuf", "protobuf-codegen-pure", "rand_core", + "rayon", "ripemd", "secp256k1", "sha2 0.10.2", "subtle", "time", + "tracing", "zcash_address", - "zcash_note_encryption 0.1.0 (git+https://github.com/zcash/librustzcash.git?rev=37fc28634e811fdf8db9274a0080cff17c6b6a09)", + "zcash_note_encryption 0.1.0 (git+https://github.com/zcash/librustzcash.git?rev=5dceb93ec8aba7d831f6fdacdbbcf3ee3667779d)", "zcash_primitives", ] [[package]] name = "zcash_client_sqlite" version = "0.3.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=37fc28634e811fdf8db9274a0080cff17c6b6a09#37fc28634e811fdf8db9274a0080cff17c6b6a09" +source = "git+https://github.com/zcash/librustzcash.git?rev=5dceb93ec8aba7d831f6fdacdbbcf3ee3667779d#5dceb93ec8aba7d831f6fdacdbbcf3ee3667779d" dependencies = [ "bech32", "bs58", @@ -1966,8 +2033,12 @@ dependencies = [ "protobuf", "rand_core", "rusqlite", + "schemer", + "schemer-rusqlite", "secp256k1", + "secrecy", "time", + "uuid", "zcash_client_backend", "zcash_primitives", ] @@ -1975,7 +2046,7 @@ dependencies = [ [[package]] name = "zcash_encoding" version = "0.1.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=37fc28634e811fdf8db9274a0080cff17c6b6a09#37fc28634e811fdf8db9274a0080cff17c6b6a09" +source = "git+https://github.com/zcash/librustzcash.git?rev=5dceb93ec8aba7d831f6fdacdbbcf3ee3667779d#5dceb93ec8aba7d831f6fdacdbbcf3ee3667779d" dependencies = [ "byteorder", "nonempty", @@ -1996,7 +2067,7 @@ dependencies = [ [[package]] name = "zcash_note_encryption" version = "0.1.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=37fc28634e811fdf8db9274a0080cff17c6b6a09#37fc28634e811fdf8db9274a0080cff17c6b6a09" +source = "git+https://github.com/zcash/librustzcash.git?rev=5dceb93ec8aba7d831f6fdacdbbcf3ee3667779d#5dceb93ec8aba7d831f6fdacdbbcf3ee3667779d" dependencies = [ "chacha20", "chacha20poly1305", @@ -2007,7 +2078,7 @@ dependencies = [ [[package]] name = "zcash_primitives" version = "0.7.0" -source = "git+https://github.com/zcash/librustzcash.git?rev=37fc28634e811fdf8db9274a0080cff17c6b6a09#37fc28634e811fdf8db9274a0080cff17c6b6a09" +source = "git+https://github.com/zcash/librustzcash.git?rev=5dceb93ec8aba7d831f6fdacdbbcf3ee3667779d#5dceb93ec8aba7d831f6fdacdbbcf3ee3667779d" dependencies = [ "aes", "bip0039", @@ -2038,13 +2109,13 @@ dependencies = [ "subtle", "zcash_address", "zcash_encoding", - "zcash_note_encryption 0.1.0 (git+https://github.com/zcash/librustzcash.git?rev=37fc28634e811fdf8db9274a0080cff17c6b6a09)", + "zcash_note_encryption 0.1.0 (git+https://github.com/zcash/librustzcash.git?rev=5dceb93ec8aba7d831f6fdacdbbcf3ee3667779d)", ] [[package]] name = "zcash_proofs" version = "0.7.1" -source = "git+https://github.com/zcash/librustzcash.git?rev=37fc28634e811fdf8db9274a0080cff17c6b6a09#37fc28634e811fdf8db9274a0080cff17c6b6a09" +source = "git+https://github.com/zcash/librustzcash.git?rev=5dceb93ec8aba7d831f6fdacdbbcf3ee3667779d#5dceb93ec8aba7d831f6fdacdbbcf3ee3667779d" dependencies = [ "bellman", "blake2b_simd", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 970da4c..82cc95c 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -13,7 +13,9 @@ ffi_helpers = "0.2" hdwallet = "0.3.1" hdwallet-bitcoin = "0.3" hex = "0.4" +schemer = "0.2" secp256k1 = "0.21" +secrecy = "0.8" zcash_client_backend = { version = "0.5", features = ["transparent-inputs"] } zcash_client_sqlite = { version = "0.3", features = ["transparent-inputs"] } @@ -35,10 +37,10 @@ lto = true # We also need zcash_client_backend and zcash_client_sqlite, which haven't been published # with NU5 updates yet. [patch.crates-io] -zcash_client_backend = { git = 'https://github.com/zcash/librustzcash.git', rev='37fc28634e811fdf8db9274a0080cff17c6b6a09' } -zcash_client_sqlite = { git = 'https://github.com/zcash/librustzcash.git', rev='37fc28634e811fdf8db9274a0080cff17c6b6a09' } -zcash_primitives = { git = 'https://github.com/zcash/librustzcash.git', rev='37fc28634e811fdf8db9274a0080cff17c6b6a09' } -zcash_proofs = { git = 'https://github.com/zcash/librustzcash.git', rev='37fc28634e811fdf8db9274a0080cff17c6b6a09' } +zcash_client_backend = { git = 'https://github.com/zcash/librustzcash.git', rev='5dceb93ec8aba7d831f6fdacdbbcf3ee3667779d' } +zcash_client_sqlite = { git = 'https://github.com/zcash/librustzcash.git', rev='5dceb93ec8aba7d831f6fdacdbbcf3ee3667779d' } +zcash_primitives = { git = 'https://github.com/zcash/librustzcash.git', rev='5dceb93ec8aba7d831f6fdacdbbcf3ee3667779d' } +zcash_proofs = { git = 'https://github.com/zcash/librustzcash.git', rev='5dceb93ec8aba7d831f6fdacdbbcf3ee3667779d' } [features] mainnet = ["zcash_client_sqlite/mainnet"] diff --git a/rust/src/lib.rs b/rust/src/lib.rs index b8f388f..a2d7598 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -4,7 +4,9 @@ use hdwallet::{ traits::{Deserialize, Serialize}, ExtendedPrivKey, KeyChain, }; +use schemer::MigratorError; use secp256k1::PublicKey; +use secrecy::Secret; use std::collections::HashMap; use std::convert::TryFrom; use std::ffi::{CStr, CString, OsStr}; @@ -36,7 +38,7 @@ use zcash_client_backend::{ use zcash_client_sqlite::wallet::{delete_utxos_above, get_rewind_height}; use zcash_client_sqlite::{ error::SqliteClientError, - wallet::init::{init_accounts_table, init_blocks_table, init_wallet_db}, + wallet::init::{init_accounts_table, init_blocks_table, init_wallet_db, WalletMigrationError}, BlockDb, NoteId, WalletDb, }; use zcash_primitives::consensus::Network::{MainNetwork, TestNetwork}; @@ -110,25 +112,39 @@ pub extern "C" fn zcashlc_clear_last_error() { ffi_helpers::error_handling::clear_last_error() } -/// Sets up the internal structure of the data database. +/// Sets up the internal structure of the data database. The value for `seed` may be provided as a +/// null pointer if the caller wishes to attempt migrations without providing the wallet's seed +/// value. +/// +/// Returns 0 if successful, 1 if the seed must be provided in order to execute the requested +/// migrations, or -1 otherwise. #[no_mangle] pub extern "C" fn zcashlc_init_data_database( db_data: *const u8, db_data_len: usize, + seed: *const u8, + seed_len: usize, network_id: u32, ) -> i32 { let res = catch_panic(|| { let network = parse_network(network_id)?; - let db_data = Path::new(OsStr::from_bytes(unsafe { - slice::from_raw_parts(db_data, db_data_len) - })); + let mut db_data = wallet_db(db_data, db_data_len, network)?; - WalletDb::for_path(db_data, network) - .map(|db| init_wallet_db(&db)) - .map(|_| 1) - .map_err(|e| format_err!("Error while initializing data DB: {}", e)) + let seed = if seed.is_null() { + None + } else { + Some(Secret::new( + (unsafe { slice::from_raw_parts(seed, seed_len) }).to_vec(), + )) + }; + + match init_wallet_db(&mut db_data, seed) { + Ok(_) => Ok(0), + Err(MigratorError::Adapter(WalletMigrationError::SeedRequired)) => Ok(1), + Err(e) => Err(format_err!("Error while initializing data DB: {}", e)), + } }); - unwrap_exc_or_null(res) + unwrap_exc_or(res, -1) } /// Initialises the data database with the given number of accounts using the given seed. @@ -501,21 +517,17 @@ pub unsafe extern "C" fn zcashlc_derive_extended_full_viewing_key( let res = catch_panic(|| { let network = parse_network(network_id)?; let extsk = CStr::from_ptr(extsk).to_str()?; - let extfvk = match decode_extended_spending_key( - network.hrp_sapling_extended_spending_key(), - &extsk, - ) { - Ok(Some(extsk)) => ExtendedFullViewingKey::from(&extsk), - Ok(None) => { - return Err(format_err!("Deriving viewing key from spending key returned no results. Encoding was valid but type was incorrect.")); - } - Err(e) => { - return Err(format_err!( - "Error while deriving viewing key from spending key: {}", - e - )); - } - }; + let extfvk = + match decode_extended_spending_key(network.hrp_sapling_extended_spending_key(), &extsk) + { + Ok(extsk) => ExtendedFullViewingKey::from(&extsk), + Err(e) => { + return Err(format_err!( + "Error while deriving viewing key from spending key: {}", + e + )); + } + }; let encoded = encode_extended_full_viewing_key( network.hrp_sapling_extended_full_viewing_key(), @@ -650,16 +662,11 @@ pub unsafe extern "C" fn zcashlc_is_valid_viewing_key(key: *const c_char, networ let network = parse_network(network_id)?; let vkstr = CStr::from_ptr(key).to_str()?; - match decode_extended_full_viewing_key( + Ok(decode_extended_full_viewing_key( &network.hrp_sapling_extended_full_viewing_key(), &vkstr, - ) { - Ok(s) => match s { - None => Ok(false), - _ => Ok(true), - }, - Err(_) => Ok(false), - } + ) + .is_ok()) }); unwrap_exc_or(res, false) } @@ -1225,10 +1232,7 @@ pub extern "C" fn zcashlc_create_to_address( let extsk = match decode_extended_spending_key(network.hrp_sapling_extended_spending_key(), &extsk) { - Ok(Some(extsk)) => extsk, - Ok(None) => { - return Err(format_err!("ExtendedSpendingKey is for the wrong network")); - } + Ok(extsk) => extsk, Err(e) => { return Err(format_err!("Invalid ExtendedSpendingKey: {}", e)); } @@ -1480,16 +1484,9 @@ pub extern "C" fn zcashlc_shield_funds( let sk = legacy::keys::AccountPrivKey::from_extended_privkey(xprv.extended_key); let extfvk = - match decode_extended_spending_key(network.hrp_sapling_extended_spending_key(), &extsk) - { - Ok(Some(extsk)) => ExtendedFullViewingKey::from(&extsk), - Ok(None) => { - return Err(format_err!("ExtendedSpendingKey is for the wrong network")); - } - Err(e) => { - return Err(format_err!("Invalid ExtendedSpendingKey: {}", e)); - } - }; + decode_extended_spending_key(network.hrp_sapling_extended_spending_key(), &extsk) + .map(|extsk| ExtendedFullViewingKey::from(&extsk)) + .map_err(|e| format_err!("Invalid ExtendedSpendingKey: {}", e))?; let memo = Memo::from_str(&memo).map_err(|_| format_err!("Invalid memo"))?; let memo_bytes = MemoBytes::from(memo);