From 1474fae4b8a0ac3b7911694220caffeb4e8f7f72 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Sat, 9 Mar 2019 03:47:49 +0000 Subject: [PATCH] Move SQL backend into librustzcash Also some tweaks due to error-handling changes in librustzcash. --- Cargo.lock | 202 ++---- Cargo.toml | 21 +- src/main/rust/lib.rs | 34 +- src/main/rust/sql.rs | 1461 ------------------------------------------ 4 files changed, 86 insertions(+), 1632 deletions(-) delete mode 100644 src/main/rust/sql.rs diff --git a/Cargo.lock b/Cargo.lock index c68f2938..5afc5a76 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,15 +43,6 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "argon2rs" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", - "scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "arrayvec" version = "0.4.10" @@ -103,23 +94,23 @@ dependencies = [ [[package]] name = "bech32" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bellman" version = "0.1.0" -source = "git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3#59c57e260d09a054a99d4b0060fe71abeef7add3" +source = "git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8#fe22862d3910f617ff58dfd0fff6fe6d60436db8" dependencies = [ "bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ff 0.4.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", + "ff 0.4.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "group 0.1.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", + "group 0.1.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.14.2 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", + "pairing 0.14.2 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -143,15 +134,6 @@ dependencies = [ "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "blake2-rfc" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "block-buffer" version = "0.7.0" @@ -327,16 +309,6 @@ dependencies = [ "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "dirs" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_users 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "either" version = "1.5.0" @@ -375,17 +347,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ff" version = "0.4.0" -source = "git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3#59c57e260d09a054a99d4b0060fe71abeef7add3" +source = "git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8#fe22862d3910f617ff58dfd0fff6fe6d60436db8" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ff_derive 0.3.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", + "ff_derive 0.3.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ff_derive" version = "0.3.0" -source = "git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3#59c57e260d09a054a99d4b0060fe71abeef7add3" +source = "git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8#fe22862d3910f617ff58dfd0fff6fe6d60436db8" dependencies = [ "num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", @@ -459,9 +431,9 @@ dependencies = [ [[package]] name = "group" version = "0.1.0" -source = "git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3#59c57e260d09a054a99d4b0060fe71abeef7add3" +source = "git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8#fe22862d3910f617ff58dfd0fff6fe6d60436db8" dependencies = [ - "ff 0.4.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", + "ff 0.4.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -736,11 +708,11 @@ dependencies = [ [[package]] name = "pairing" version = "0.14.2" -source = "git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3#59c57e260d09a054a99d4b0060fe71abeef7add3" +source = "git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8#fe22862d3910f617ff58dfd0fff6fe6d60436db8" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ff 0.4.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", - "group 0.1.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", + "ff 0.4.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", + "group 0.1.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -932,25 +904,6 @@ name = "redox_syscall" version = "0.1.51" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "redox_users" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "remove_dir_all" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rusqlite" version = "0.15.0" @@ -991,14 +944,14 @@ dependencies = [ [[package]] name = "sapling-crypto" version = "0.0.1" -source = "git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3#59c57e260d09a054a99d4b0060fe71abeef7add3" +source = "git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8#fe22862d3910f617ff58dfd0fff6fe6d60436db8" dependencies = [ - "bellman 0.1.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", + "bellman 0.1.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", "blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", - "ff 0.4.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", - "pairing 0.14.2 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", + "ff 0.4.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", + "pairing 0.14.2 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1007,11 +960,6 @@ name = "scoped-tls" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "scoped_threadpool" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "scopeguard" version = "0.3.3" @@ -1103,19 +1051,6 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "tempfile" -version = "3.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "time" version = "0.1.42" @@ -1463,95 +1398,87 @@ name = "zcash-android-wallet-sdk" version = "0.0.1" dependencies = [ "android_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dirs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ff 0.4.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", + "ff 0.4.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "grpc 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "jni 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "log-panics 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.14.2 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", - "protobuf 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rusqlite 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sapling-crypto 0.0.1 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", - "tempfile 3.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "zcash_client_backend 0.0.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", - "zcash_primitives 0.0.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", - "zip32 0.0.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", + "pairing 0.14.2 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", + "sapling-crypto 0.0.1 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", + "zcash_client_backend 0.0.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", + "zcash_primitives 0.0.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", + "zip32 0.0.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", ] [[package]] name = "zcash_client_backend" version = "0.0.0" -source = "git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3#59c57e260d09a054a99d4b0060fe71abeef7add3" +source = "git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8#fe22862d3910f617ff58dfd0fff6fe6d60436db8" dependencies = [ - "bech32 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bellman 0.1.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", - "blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "chacha20-poly1305-aead 0.1.2 (git+https://github.com/gtank/chacha20-poly1305-aead?rev=aefc71f95e8bc43f2070e3c5b08130d9c86bbf4f)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ff 0.4.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", + "bech32 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bellman 0.1.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", + "ff 0.4.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.14.2 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", + "pairing 0.14.2 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", "protobuf 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "protobuf-codegen-pure 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "sapling-crypto 0.0.1 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", - "zcash_primitives 0.0.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", - "zcash_proofs 0.0.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", - "zip32 0.0.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", + "rusqlite 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sapling-crypto 0.0.1 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "zcash_primitives 0.0.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", + "zcash_proofs 0.0.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", + "zip32 0.0.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", ] [[package]] name = "zcash_primitives" version = "0.0.0" -source = "git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3#59c57e260d09a054a99d4b0060fe71abeef7add3" +source = "git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8#fe22862d3910f617ff58dfd0fff6fe6d60436db8" dependencies = [ "blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ff 0.4.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", + "chacha20-poly1305-aead 0.1.2 (git+https://github.com/gtank/chacha20-poly1305-aead?rev=aefc71f95e8bc43f2070e3c5b08130d9c86bbf4f)", + "ff 0.4.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.14.2 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", + "pairing 0.14.2 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "sapling-crypto 0.0.1 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", + "sapling-crypto 0.0.1 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "zcash_proofs" version = "0.0.0" -source = "git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3#59c57e260d09a054a99d4b0060fe71abeef7add3" +source = "git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8#fe22862d3910f617ff58dfd0fff6fe6d60436db8" dependencies = [ - "bellman 0.1.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", + "bellman 0.1.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", "blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ff 0.4.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", - "pairing 0.14.2 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", + "ff 0.4.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", + "pairing 0.14.2 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "sapling-crypto 0.0.1 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", - "zcash_primitives 0.0.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", + "sapling-crypto 0.0.1 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", + "zcash_primitives 0.0.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", ] [[package]] name = "zip32" version = "0.0.0" -source = "git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3#59c57e260d09a054a99d4b0060fe71abeef7add3" +source = "git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8#fe22862d3910f617ff58dfd0fff6fe6d60436db8" dependencies = [ "aes 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ff 0.4.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", + "ff 0.4.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", "fpe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "pairing 0.14.2 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", - "sapling-crypto 0.0.1 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", - "zcash_primitives 0.0.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)", + "pairing 0.14.2 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", + "sapling-crypto 0.0.1 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", + "zcash_primitives 0.0.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)", ] [metadata] @@ -1560,19 +1487,17 @@ dependencies = [ "checksum aesni 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6810b7fb9f2bb4f76f05ac1c170b8dde285b6308955dc3afd89710268c958d9e" "checksum android_log-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b8052e2d8aabbb8d556d6abbcce2a22b9590996c5f849b9c7ce4544a2e3b984e" "checksum android_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bad99185bc195e796e1591740c26716667b58ac9210a48731f71f803fc6ca43a" -"checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392" "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" "checksum ascii 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5fc969a8ce2c9c0c4b0429bb8431544f6658283c8326ba5ff8c762b75369335" "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" "checksum backtrace 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "b5b493b66e03090ebc4343eb02f94ff944e0cbc9ac6571491d170ba026741eb5" "checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" "checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" -"checksum bech32 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad20b907fd16610c3960c7fe9dae13dd243343409bab80299774c9a8b5d7bed8" -"checksum bellman 0.1.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)" = "" +"checksum bech32 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "58946044516aa9dc922182e0d6e9d124a31aafe6b421614654eb27cf90cec09c" +"checksum bellman 0.1.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)" = "" "checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)" = "" -"checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" "checksum block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d" "checksum block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "370424437b9459f3dfd68428ed9376ddfe03d8b70ede29cc533b3557df186ab4" "checksum block-padding 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d75255892aeb580d3c566f213a2b6fdc1c66667839f45719ee1d30ebf2aea591" @@ -1595,14 +1520,13 @@ dependencies = [ "checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" "checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90" "checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c" -"checksum dirs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "88972de891f6118092b643d85a0b28e0678e0f948d7f879aa32f2d5aafe97d2a" "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" "checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" -"checksum ff 0.4.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)" = "" -"checksum ff_derive 0.3.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)" = "" +"checksum ff 0.4.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)" = "" +"checksum ff_derive 0.3.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)" = "" "checksum fpe 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce3371c82bfbd984f624cab093f55e7336f5a6e589f8518e1258f54f011b89ad" "checksum fuchsia-cprng 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81f7f8eb465745ea9b02e2704612a9946a59fa40572086c6fd49d6ddcf30bf31" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" @@ -1611,7 +1535,7 @@ dependencies = [ "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" "checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" -"checksum group 0.1.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)" = "" +"checksum group 0.1.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)" = "" "checksum grpc 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8e530ef7894a104a1c8525ce68787b3491efa2098ce5e5454e8324ea78893548" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum httpbis 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7689cfa896b2a71da4f16206af167542b75d242b6906313e53857972a92d5614" @@ -1643,7 +1567,7 @@ dependencies = [ "checksum opaque-debug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d620c9c26834b34f039489ac0dfdb12c7ac15ccaf818350a64c9b5334a452ad7" "checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409" "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" -"checksum pairing 0.14.2 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)" = "" +"checksum pairing 0.14.2 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)" = "" "checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" "checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" @@ -1665,16 +1589,13 @@ dependencies = [ "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85" -"checksum redox_users 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "214a97e49be64fd2c86f568dd0cb2c757d2cc53de95b273b6ad0a1c908482f26" -"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" "checksum rusqlite 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "39bae767eb27866f5c0be918635ae54af705bc09db11be2c43a3c6b361cf3462" "checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9" "checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" -"checksum sapling-crypto 0.0.1 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)" = "" +"checksum sapling-crypto 0.0.1 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)" = "" "checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" -"checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" @@ -1687,7 +1608,6 @@ dependencies = [ "checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" "checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9" "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" -"checksum tempfile 3.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "37daa55a7240c4931c84559f03b3cad7d19535840d1c4a0cc4e9b2fb0dcf70ff" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum tls-api 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "e452fe2fdf40a10715adb3a5f244c7411cdf2ecc887b07160310939785db9182" "checksum tls-api-stub 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "25a2dcddd0fd52bdbedf9b4f0fd1cb884abfa0984e6a54121d4cefdf3d234e4c" @@ -1722,7 +1642,7 @@ dependencies = [ "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -"checksum zcash_client_backend 0.0.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)" = "" -"checksum zcash_primitives 0.0.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)" = "" -"checksum zcash_proofs 0.0.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)" = "" -"checksum zip32 0.0.0 (git+https://github.com/str4d/librustzcash.git?rev=59c57e260d09a054a99d4b0060fe71abeef7add3)" = "" +"checksum zcash_client_backend 0.0.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)" = "" +"checksum zcash_primitives 0.0.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)" = "" +"checksum zcash_proofs 0.0.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)" = "" +"checksum zip32 0.0.0 (git+https://github.com/str4d/librustzcash.git?rev=fe22862d3910f617ff58dfd0fff6fe6d60436db8)" = "" diff --git a/Cargo.toml b/Cargo.toml index 60d30e7c..b3752311 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,38 +18,31 @@ hex = "0.3" jni = { version = "0.10", default-features = false } log = "0.4" log-panics = "2.0.0" -protobuf = "2" -rand = "0.4" -rusqlite = { version = "0.15", features = ["bundled"] } -time = "0.1" [dependencies.ff] git = "https://github.com/str4d/librustzcash.git" -rev = "59c57e260d09a054a99d4b0060fe71abeef7add3" +rev = "fe22862d3910f617ff58dfd0fff6fe6d60436db8" [dependencies.pairing] git = "https://github.com/str4d/librustzcash.git" -rev = "59c57e260d09a054a99d4b0060fe71abeef7add3" +rev = "fe22862d3910f617ff58dfd0fff6fe6d60436db8" [dependencies.sapling-crypto] git = "https://github.com/str4d/librustzcash.git" -rev = "59c57e260d09a054a99d4b0060fe71abeef7add3" +rev = "fe22862d3910f617ff58dfd0fff6fe6d60436db8" [dependencies.zcash_client_backend] git = "https://github.com/str4d/librustzcash.git" -rev = "59c57e260d09a054a99d4b0060fe71abeef7add3" +rev = "fe22862d3910f617ff58dfd0fff6fe6d60436db8" +features = ["sqlite"] [dependencies.zcash_primitives] git = "https://github.com/str4d/librustzcash.git" -rev = "59c57e260d09a054a99d4b0060fe71abeef7add3" +rev = "fe22862d3910f617ff58dfd0fff6fe6d60436db8" [dependencies.zip32] git = "https://github.com/str4d/librustzcash.git" -rev = "59c57e260d09a054a99d4b0060fe71abeef7add3" - -[dev-dependencies] -dirs = "1" -tempfile = "3" +rev = "fe22862d3910f617ff58dfd0fff6fe6d60436db8" [features] updater = ["futures", "grpc"] diff --git a/src/main/rust/lib.rs b/src/main/rust/lib.rs index d1dbe2db..69c24a78 100644 --- a/src/main/rust/lib.rs +++ b/src/main/rust/lib.rs @@ -1,8 +1,6 @@ #[macro_use] extern crate log; -extern crate hex; -mod sql; mod utils; const SAPLING_CONSENSUS_BRANCH_ID: u32 = 0x76b8_09bb; @@ -24,19 +22,17 @@ use zcash_client_backend::{ decode_extended_spending_key, decode_payment_address, encode_extended_spending_key, }, keystore::spending_key, - note_encryption::Memo, prover::LocalTxProver, + sqlite::{ + get_address, get_balance, get_received_memo_as_utf8, get_sent_memo_as_utf8, + get_verified_balance, init_accounts_table, init_blocks_table, init_data_database, + scan_cached_blocks, send_to_address, + }, }; -use zcash_primitives::transaction::components::Amount; +use zcash_primitives::{note_encryption::Memo, transaction::components::Amount}; use zip32::ExtendedFullViewingKey; -use crate::{ - sql::{ - get_address, get_balance, get_verified_balance, init_accounts_table, init_blocks_table, - init_data_database, scan_cached_blocks, send_to_address, - }, - utils::exception::unwrap_exc_or, -}; +use crate::utils::exception::unwrap_exc_or; #[no_mangle] pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_initLogs( @@ -222,7 +218,7 @@ pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_getReceivedMemo let res = panic::catch_unwind(|| { let db_data = utils::java_string_to_rust(&env, db_data); - let memo = match crate::sql::get_received_memo_as_utf8(db_data, id_note) { + let memo = match get_received_memo_as_utf8(db_data, id_note) { Ok(memo) => memo.unwrap_or_default(), Err(e) => return Err(format_err!("Error while fetching memo: {}", e)), }; @@ -243,7 +239,7 @@ pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_getSentMemoAsUt let res = panic::catch_unwind(|| { let db_data = utils::java_string_to_rust(&env, db_data); - let memo = match crate::sql::get_sent_memo_as_utf8(db_data, id_note) { + let memo = match get_sent_memo_as_utf8(db_data, id_note) { Ok(memo) => memo.unwrap_or_default(), Err(e) => return Err(format_err!("Error while fetching memo: {}", e)), }; @@ -302,20 +298,26 @@ pub unsafe extern "C" fn Java_cash_z_wallet_sdk_jni_JniConverter_sendToAddress( let extsk = match decode_extended_spending_key(HRP_SAPLING_EXTENDED_SPENDING_KEY_TEST, &extsk) { - Ok(extsk) => extsk, + Ok(Some(extsk)) => extsk, + Ok(None) => { + return Err(format_err!("ExtendedSpendingKey is for the wrong network")); + } Err(e) => { return Err(format_err!("Invalid ExtendedSpendingKey: {}", e)); } }; let to = match decode_payment_address(HRP_SAPLING_PAYMENT_ADDRESS_TEST, &to) { - Ok(to) => to, + Ok(Some(to)) => to, + Ok(None) => { + return Err(format_err!("PaymentAddress is for the wrong network")); + } Err(e) => { return Err(format_err!("Invalid PaymentAddress: {}", e)); } }; - let memo = Some(Memo::from_str(&memo)?); + let memo = Memo::from_str(&memo); let prover = LocalTxProver::new( Path::new(&spend_params), diff --git a/src/main/rust/sql.rs b/src/main/rust/sql.rs deleted file mode 100644 index c0935b3d..00000000 --- a/src/main/rust/sql.rs +++ /dev/null @@ -1,1461 +0,0 @@ -use failure::{format_err, Error}; -use ff::{PrimeField, PrimeFieldRepr}; -use pairing::bls12_381::Bls12; -use protobuf::parse_from_bytes; -use rusqlite::{types::ToSql, Connection, NO_PARAMS}; -use sapling_crypto::{ - jubjub::fs::{Fs, FsRepr}, - primitives::{Diversifier, Note, PaymentAddress}, -}; -use std::cmp; -use std::path::Path; -use zcash_client_backend::{ - constants::{HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY_TEST, HRP_SAPLING_PAYMENT_ADDRESS_TEST}, - encoding::{ - decode_extended_full_viewing_key, encode_extended_full_viewing_key, encode_payment_address, - }, - note_encryption::Memo, - proto::compact_formats::CompactBlock, - prover::TxProver, - transaction::Builder, - welding_rig::scan_block, -}; -use zcash_primitives::{ - merkle_tree::{CommitmentTree, IncrementalWitness}, - transaction::components::Amount, - JUBJUB, -}; -use zip32::{ExtendedFullViewingKey, ExtendedSpendingKey}; - -// TODO: Expose this in zcash_client_backend -const DEFAULT_FEE: i64 = 10000; -const ANCHOR_OFFSET: u32 = 10; -const SAPLING_ACTIVATION_HEIGHT: i32 = 280_000; - -fn address_from_extfvk(extfvk: &ExtendedFullViewingKey) -> String { - let addr = extfvk.default_address().unwrap().1; - encode_payment_address(HRP_SAPLING_PAYMENT_ADDRESS_TEST, &addr) -} - -/// Determine the target height for a transaction, and the height from which to -/// select anchors, based on the current synchronised block chain. -fn get_target_and_anchor_heights(data: &Connection) -> Result<(u32, u32), Error> { - data.query_row_and_then( - "SELECT MIN(height), MAX(height) FROM blocks", - NO_PARAMS, - |row| match (row.get_checked::<_, u32>(0), row.get_checked::<_, u32>(1)) { - // If there are no blocks, the query returns NULL. - (Err(rusqlite::Error::InvalidColumnType(_, _)), _) - | (_, Err(rusqlite::Error::InvalidColumnType(_, _))) => { - Err(format_err!("Must scan blocks first")) - } - (Err(e), _) | (_, Err(e)) => Err(e.into()), - (Ok(min_height), Ok(max_height)) => { - let target_height = max_height + 1; - - // Select an anchor ANCHOR_OFFSET back from the target block, - // unless that would be before the earliest block we have. - let anchor_height = - cmp::max(target_height.saturating_sub(ANCHOR_OFFSET), min_height); - - Ok((target_height, anchor_height)) - } - }, - ) -} - -pub fn init_cache_database>(db_cache: P) -> Result<(), Error> { - let cache = Connection::open(db_cache)?; - cache.execute( - "CREATE TABLE IF NOT EXISTS compactblocks ( - height INTEGER PRIMARY KEY, - data BLOB NOT NULL - )", - NO_PARAMS, - )?; - Ok(()) -} - -pub fn init_data_database>(db_data: P) -> Result<(), Error> { - let data = Connection::open(db_data)?; - data.execute( - "CREATE TABLE IF NOT EXISTS accounts ( - account INTEGER PRIMARY KEY, - extfvk TEXT NOT NULL, - address TEXT NOT NULL - )", - NO_PARAMS, - )?; - data.execute( - "CREATE TABLE IF NOT EXISTS blocks ( - height INTEGER PRIMARY KEY, - time INTEGER NOT NULL, - sapling_tree BLOB NOT NULL - )", - NO_PARAMS, - )?; - data.execute( - "CREATE TABLE IF NOT EXISTS transactions ( - id_tx INTEGER PRIMARY KEY, - txid BLOB NOT NULL UNIQUE, - created TEXT, - block INTEGER, - tx_index INTEGER, - expiry_height INTEGER, - raw BLOB, - FOREIGN KEY (block) REFERENCES blocks(height) - )", - NO_PARAMS, - )?; - data.execute( - "CREATE TABLE IF NOT EXISTS received_notes ( - id_note INTEGER PRIMARY KEY, - tx INTEGER NOT NULL, - output_index INTEGER NOT NULL, - account INTEGER NOT NULL, - diversifier BLOB NOT NULL, - value INTEGER NOT NULL, - rcm BLOB NOT NULL, - nf BLOB NOT NULL UNIQUE, - is_change BOOLEAN NOT NULL, - memo BLOB, - spent INTEGER, - FOREIGN KEY (tx) REFERENCES transactions(id_tx), - FOREIGN KEY (account) REFERENCES accounts(account), - FOREIGN KEY (spent) REFERENCES transactions(id_tx), - CONSTRAINT tx_output UNIQUE (tx, output_index) - )", - NO_PARAMS, - )?; - data.execute( - "CREATE TABLE IF NOT EXISTS sapling_witnesses ( - id_witness INTEGER PRIMARY KEY, - note INTEGER NOT NULL, - block INTEGER NOT NULL, - witness BLOB NOT NULL, - FOREIGN KEY (note) REFERENCES received_notes(id_note), - FOREIGN KEY (block) REFERENCES blocks(height), - CONSTRAINT witness_height UNIQUE (note, block) - )", - NO_PARAMS, - )?; - data.execute( - "CREATE TABLE IF NOT EXISTS sent_notes ( - id_note INTEGER PRIMARY KEY, - tx INTEGER NOT NULL, - output_index INTEGER NOT NULL, - from_account INTEGER NOT NULL, - address TEXT NOT NULL, - value INTEGER NOT NULL, - memo BLOB, - FOREIGN KEY (tx) REFERENCES transactions(id_tx), - FOREIGN KEY (from_account) REFERENCES accounts(account), - CONSTRAINT tx_output UNIQUE (tx, output_index) - )", - NO_PARAMS, - )?; - Ok(()) -} - -pub fn init_accounts_table>( - db_data: P, - extfvks: &[ExtendedFullViewingKey], -) -> Result<(), Error> { - let data = Connection::open(db_data)?; - - let mut empty_check = data.prepare("SELECT * FROM accounts LIMIT 1")?; - if empty_check.exists(NO_PARAMS)? { - return Err(format_err!("accounts table is not empty")); - } - - // Insert accounts atomically - data.execute("BEGIN IMMEDIATE", NO_PARAMS)?; - for (account, extfvk) in extfvks.iter().enumerate() { - let address = address_from_extfvk(extfvk); - let extfvk = - encode_extended_full_viewing_key(HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY_TEST, extfvk); - data.execute( - "INSERT INTO accounts (account, extfvk, address) - VALUES (?, ?, ?)", - &[ - (account as u32).to_sql()?, - extfvk.to_sql()?, - address.to_sql()?, - ], - )?; - } - data.execute("COMMIT", NO_PARAMS)?; - - Ok(()) -} - -pub fn init_blocks_table>( - db_data: P, - height: i32, - time: u32, - sapling_tree: &[u8], -) -> Result<(), Error> { - let data = Connection::open(db_data)?; - - let mut empty_check = data.prepare("SELECT * FROM blocks LIMIT 1")?; - if empty_check.exists(NO_PARAMS)? { - return Err(format_err!("blocks table is not empty")); - } - - data.execute( - "INSERT INTO blocks (height, time, sapling_tree) - VALUES (?, ?, ?)", - &[height.to_sql()?, time.to_sql()?, sapling_tree.to_sql()?], - )?; - - Ok(()) -} - -struct CompactBlockRow { - height: i32, - data: Vec, -} - -#[derive(Clone)] -struct WitnessRow { - id_note: i64, - witness: IncrementalWitness, -} - -pub fn get_address>(db_data: P, account: u32) -> Result { - let data = Connection::open(db_data)?; - - let addr = data.query_row( - "SELECT address FROM accounts - WHERE account = ?", - &[account], - |row| row.get(0), - )?; - - Ok(addr) -} - -pub fn get_balance>(db_data: P, account: u32) -> Result { - let data = Connection::open(db_data)?; - - let balance = data.query_row( - "SELECT SUM(value) FROM received_notes - WHERE account = ? AND spent IS NULL", - &[account], - |row| row.get_checked(0).unwrap_or(0), - )?; - - Ok(Amount(balance)) -} - -/// Returns the verified balance for the account, which ignores notes that have been -/// received too recently and are not yet deemed spendable. -pub fn get_verified_balance>(db_data: P, account: u32) -> Result { - let data = Connection::open(db_data)?; - - let (_, anchor_height) = get_target_and_anchor_heights(&data)?; - - let balance = data.query_row( - "SELECT SUM(value) FROM received_notes - INNER JOIN transactions ON transactions.id_tx = received_notes.tx - WHERE account = ? AND spent IS NULL AND transactions.block <= ?", - &[account, anchor_height], - |row| row.get_checked(0).unwrap_or(0), - )?; - - Ok(Amount(balance)) -} - -pub fn get_received_memo_as_utf8>( - db_data: P, - id_note: i64, -) -> Result, Error> { - let data = Connection::open(db_data)?; - - let memo: Vec<_> = data.query_row( - "SELECT memo FROM received_notes - WHERE id_note = ?", - &[id_note], - |row| row.get(0), - )?; - - Memo::from_bytes(&memo).and_then(|memo| memo.to_utf8()) -} - -pub fn get_sent_memo_as_utf8>( - db_data: P, - id_note: i64, -) -> Result, Error> { - let data = Connection::open(db_data)?; - - let memo: Vec<_> = data.query_row( - "SELECT memo FROM sent_notes - WHERE id_note = ?", - &[id_note], - |row| row.get(0), - )?; - - Memo::from_bytes(&memo).and_then(|memo| memo.to_utf8()) -} - -/// Scans new blocks added to the cache for any transactions received by the -/// tracked accounts. -/// -/// Assumes that the caller is handling rollbacks. -pub fn scan_cached_blocks, Q: AsRef>( - db_cache: P, - db_data: Q, -) -> Result<(), Error> { - let cache = Connection::open(db_cache)?; - let data = Connection::open(db_data)?; - - // Recall where we synced up to previously. - // If we have never synced, use sapling activation height to select all cached CompactBlocks. - let mut last_height = - data.query_row( - "SELECT MAX(height) FROM blocks", - NO_PARAMS, - |row| match row.get_checked(0) { - Ok(h) => h, - Err(_) => SAPLING_ACTIVATION_HEIGHT - 1, - }, - )?; - - // Prepare necessary SQL statements - let mut stmt_blocks = cache - .prepare("SELECT height, data FROM compactblocks WHERE height > ? ORDER BY height ASC")?; - let mut stmt_fetch_tree = data.prepare("SELECT sapling_tree FROM blocks WHERE height = ?")?; - let mut stmt_fetch_witnesses = - data.prepare("SELECT note, witness FROM sapling_witnesses WHERE block = ?")?; - let mut stmt_fetch_nullifiers = - data.prepare("SELECT id_note, nf, account FROM received_notes WHERE spent IS NULL")?; - let mut stmt_insert_block = data.prepare( - "INSERT INTO blocks (height, time, sapling_tree) - VALUES (?, ?, ?)", - )?; - let mut stmt_update_tx = data.prepare( - "UPDATE transactions - SET block = ?, tx_index = ? WHERE txid = ?", - )?; - let mut stmt_insert_tx = data.prepare( - "INSERT INTO transactions (txid, block, tx_index) - VALUES (?, ?, ?)", - )?; - let mut stmt_select_tx = data.prepare("SELECT id_tx FROM transactions WHERE txid = ?")?; - let mut stmt_mark_spent_note = - data.prepare("UPDATE received_notes SET spent = ? WHERE nf = ?")?; - let mut stmt_insert_note = data.prepare( - "INSERT INTO received_notes (tx, output_index, account, diversifier, value, rcm, nf, is_change) - VALUES (?, ?, ?, ?, ?, ?, ?, ?)", - )?; - let mut stmt_insert_witness = data.prepare( - "INSERT INTO sapling_witnesses (note, block, witness) - VALUES (?, ?, ?)", - )?; - let mut stmt_prune_witnesses = data.prepare("DELETE FROM sapling_witnesses WHERE block < ?")?; - let mut stmt_update_expired = data.prepare( - "UPDATE received_notes SET spent = NULL WHERE EXISTS ( - SELECT id_tx FROM transactions - WHERE id_tx = received_notes.spent AND block IS NULL AND expiry_height < ? - )", - )?; - - // Fetch the CompactBlocks we need to scan - let rows = stmt_blocks.query_map(&[last_height], |row| CompactBlockRow { - height: row.get(0), - data: row.get(1), - })?; - - // Fetch the ExtendedFullViewingKeys we are tracking - let mut stmt_fetch_accounts = - data.prepare("SELECT extfvk FROM accounts ORDER BY account ASC")?; - let extfvks = stmt_fetch_accounts.query_map(NO_PARAMS, |row| { - let extfvk: String = row.get(0); - decode_extended_full_viewing_key(HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY_TEST, &extfvk) - })?; - // Raise SQL errors from the query, and IO errors from parsing. - let extfvks: Vec<_> = extfvks.collect::, _>>()??; - - // Get the most recent CommitmentTree - let mut tree = match stmt_fetch_tree.query_row(&[last_height], |row| match row.get_checked(0) { - Ok(data) => { - let data: Vec<_> = data; - CommitmentTree::read(&data[..]) - } - Err(_) => Ok(CommitmentTree::new()), - }) { - Ok(tree) => tree, - Err(_) => Ok(CommitmentTree::new()), - }?; - - // Get most recent incremental witnesses for the notes we are tracking - let witnesses = stmt_fetch_witnesses.query_map(&[last_height], |row| { - let data: Vec<_> = row.get(1); - IncrementalWitness::read(&data[..]).map(|witness| WitnessRow { - id_note: row.get(0), - witness, - }) - })?; - let mut witnesses: Vec<_> = witnesses.collect::, _>>()??; - - // Get the nullifiers for the notes we are tracking - let nullifiers = stmt_fetch_nullifiers.query_map(NO_PARAMS, |row| { - let nf: Vec<_> = row.get(1); - let account: i64 = row.get(2); - (nf, account as usize) - })?; - let mut nullifiers: Vec<_> = nullifiers.collect::>()?; - - for row in rows { - let row = row?; - - // Start an SQL transaction for this block. - data.execute("BEGIN IMMEDIATE", NO_PARAMS)?; - - // Scanned blocks MUST be height-sequential. - if row.height != (last_height + 1) { - return Err(format_err!( - "Expected height of next CompactBlock to be {}, but was {}", - last_height + 1, - row.height - )); - } - last_height = row.height; - - let block: CompactBlock = parse_from_bytes(&row.data)?; - let block_time = block.time; - - let txs = { - let nf_refs: Vec<_> = nullifiers.iter().map(|(nf, acc)| (&nf[..], *acc)).collect(); - let mut witness_refs: Vec<_> = witnesses.iter_mut().map(|w| &mut w.witness).collect(); - scan_block( - block, - &extfvks[..], - &nf_refs, - &mut tree, - &mut witness_refs[..], - ) - }; - - // Enforce that all roots match - { - let cur_root = tree.root(); - for row in &witnesses { - if row.witness.root() != cur_root { - return Err(format_err!( - "Witness for note {} has incorrect anchor after scanning block {}", - row.id_note, - last_height - )); - } - } - for (tx, new_witnesses) in &txs { - for (i, witness) in new_witnesses.iter().enumerate() { - if witness.root() != cur_root { - return Err(format_err!( - "New witness for output {} in tx {} has incorrect anchor after scanning block {}: {:?}", - tx.shielded_outputs[i].index, - tx.txid, - last_height, - witness.root(), - )); - } - } - } - } - - // Insert the block into the database. - let mut encoded_tree = Vec::new(); - tree.write(&mut encoded_tree) - .expect("Should be able to write to a Vec"); - stmt_insert_block.execute(&[ - row.height.to_sql()?, - block_time.to_sql()?, - encoded_tree.to_sql()?, - ])?; - - for (tx, new_witnesses) in txs { - // First try update an existing transaction in the database. - let txid = tx.txid.0.to_vec(); - let tx_row = if stmt_update_tx.execute(&[ - row.height.to_sql()?, - (tx.index as i64).to_sql()?, - txid.to_sql()?, - ])? == 0 - { - // It isn't there, so insert our transaction into the database. - stmt_insert_tx.execute(&[ - txid.to_sql()?, - row.height.to_sql()?, - (tx.index as i64).to_sql()?, - ])?; - data.last_insert_rowid() - } else { - // It was there, so grab its row number. - stmt_select_tx.query_row(&[txid], |row| row.get(0))? - }; - - // Mark notes as spent and remove them from the scanning cache - for spend in &tx.shielded_spends { - stmt_mark_spent_note.execute(&[tx_row.to_sql()?, spend.nf.to_sql()?])?; - } - nullifiers = nullifiers - .into_iter() - .filter(|(nf, _acc)| { - tx.shielded_spends - .iter() - .find(|spend| &spend.nf == nf) - .is_none() - }) - .collect(); - - for (output, witness) in tx - .shielded_outputs - .into_iter() - .zip(new_witnesses.into_iter()) - { - let mut rcm = [0; 32]; - output.note.r.into_repr().write_le(&mut rcm[..])?; - let nf = output.note.nf( - &extfvks[output.account].fvk.vk, - witness.position() as u64, - &JUBJUB, - ); - - // Insert received note into the database. - // Assumptions: - // - A transaction will not contain more than 2^63 shielded outputs. - // - A note value will never exceed 2^63 zatoshis. - stmt_insert_note.execute(&[ - tx_row.to_sql()?, - (output.index as i64).to_sql()?, - (output.account as i64).to_sql()?, - output.to.diversifier.0.to_sql()?, - (output.note.value as i64).to_sql()?, - rcm.to_sql()?, - nf.to_sql()?, - output.is_change.to_sql()?, - ])?; - let note_row = data.last_insert_rowid(); - - // Save witness for note. - witnesses.push(WitnessRow { - id_note: note_row, - witness, - }); - - // Cache nullifier for note (to detect subsequent spends in this scan). - nullifiers.push((nf, output.account)); - } - } - - // Insert current witnesses into the database. - let mut encoded = Vec::new(); - for witness_row in witnesses.iter() { - encoded.clear(); - witness_row - .witness - .write(&mut encoded) - .expect("Should be able to write to a Vec"); - stmt_insert_witness.execute(&[ - witness_row.id_note.to_sql()?, - last_height.to_sql()?, - encoded.to_sql()?, - ])?; - } - - // Prune the stored witnesses (we only expect rollbacks of at most 100 blocks). - stmt_prune_witnesses.execute(&[last_height - 100])?; - - // Update now-expired transactions that didn't get mined. - stmt_update_expired.execute(&[last_height])?; - - // Commit the SQL transaction, writing this block's data atomically. - data.execute("COMMIT", NO_PARAMS)?; - } - - Ok(()) -} - -struct SelectedNoteRow { - diversifier: Diversifier, - note: Note, - witness: IncrementalWitness, -} - -/// Creates a transaction paying the specified address. -/// -/// Do not call this multiple times in parallel, or you will generate transactions that -/// double-spend the same notes. -pub fn send_to_address>( - db_data: P, - consensus_branch_id: u32, - prover: impl TxProver, - (account, extsk): (u32, &ExtendedSpendingKey), - to: &PaymentAddress, - value: Amount, - memo: Option, -) -> Result { - let data = Connection::open(db_data)?; - - // Check that the ExtendedSpendingKey we have been given corresponds to the - // ExtendedFullViewingKey for the account we are spending from. - let extfvk = ExtendedFullViewingKey::from(extsk); - if !data - .prepare("SELECT * FROM accounts WHERE account = ? AND extfvk = ?")? - .exists(&[ - account.to_sql()?, - encode_extended_full_viewing_key(HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY_TEST, &extfvk) - .to_sql()?, - ])? - { - return Err(format_err!( - "Incorrect ExtendedSpendingKey for account {}", - account - )); - } - let ovk = extfvk.fvk.ovk; - - // Target the next block, assuming we are up-to-date. - let (height, anchor_height) = { - let (target_height, anchor_height) = get_target_and_anchor_heights(&data)?; - (target_height, i64::from(anchor_height)) - }; - - // The goal of this SQL statement is to select the oldest notes until the required - // value has been reached, and then fetch the witnesses at the desired height for the - // selected notes. This is achieved in several steps: - // - // 1) Use a window function to create a view of all notes, ordered from oldest to - // newest, with an additional column containing a running sum: - // - Unspent notes accumulate the values of all unspent notes in that note's - // account, up to itself. - // - Spent notes accumulate the values of all notes in the transaction they were - // spent in, up to itself. - // - // 2) Select all unspent notes in the desired account, along with their running sum. - // - // 3) Select all notes for which the running sum was less than the required value, as - // well as a single note for which the sum was greater than or equal to the - // required value, bringing the sum of all selected notes across the threshold. - // - // 4) Match the selected notes against the witnesses at the desired height. - let target_value = value.0 + DEFAULT_FEE; - debug!( - "Selecting notes from account {} targeting {} zatoshis and anchor height {}", - account, target_value, anchor_height, - ); - let mut stmt_select_notes = data.prepare( - "WITH selected AS ( - WITH eligible AS ( - SELECT id_note, diversifier, value, rcm, - SUM(value) OVER - (PARTITION BY account, spent ORDER BY id_note) AS so_far - FROM received_notes - INNER JOIN transactions ON transactions.id_tx = received_notes.tx - WHERE account = ? AND spent IS NULL AND transactions.block <= ? - ) - SELECT * FROM eligible WHERE so_far < ? - UNION - SELECT * FROM (SELECT * FROM eligible WHERE so_far >= ? LIMIT 1) - ), witnesses AS ( - SELECT note, witness FROM sapling_witnesses - WHERE block = ? - ) - SELECT selected.diversifier, selected.value, selected.rcm, witnesses.witness - FROM selected - INNER JOIN witnesses ON selected.id_note = witnesses.note", - )?; - - // Select notes - let notes = stmt_select_notes.query_and_then::<_, Error, _, _>( - &[ - i64::from(account), - anchor_height, - target_value, - target_value, - anchor_height, - ], - |row| { - let mut diversifier = Diversifier([0; 11]); - let d: Vec<_> = row.get(0); - diversifier.0.copy_from_slice(&d); - - let note_value: i64 = row.get(1); - debug!("Selected note with value {}", note_value); - - let d: Vec<_> = row.get(2); - let rcm = { - let mut tmp = FsRepr::default(); - tmp.read_le(&d[..])?; - Fs::from_repr(tmp)? - }; - - let from = extfvk - .fvk - .vk - .into_payment_address(diversifier, &JUBJUB) - .unwrap(); - let note = from.create_note(note_value as u64, rcm, &JUBJUB).unwrap(); - - let d: Vec<_> = row.get(3); - let witness = IncrementalWitness::read(&d[..])?; - - Ok(SelectedNoteRow { - diversifier, - note, - witness, - }) - }, - )?; - let notes: Vec = notes.collect::>()?; - - // Confirm we were able to select sufficient value - let selected_value = notes - .iter() - .fold(0, |acc, selected| acc + selected.note.value); - if selected_value < target_value as u64 { - return Err(format_err!( - "Insufficient balance (have {}, need {} including fee)", - selected_value, - target_value - )); - } - - // Create the transaction - let mut builder = Builder::new(height); - for selected in notes { - builder.add_sapling_spend( - extsk.clone(), - selected.diversifier, - selected.note, - selected.witness, - )?; - } - builder.add_sapling_output(ovk, to.clone(), value, memo.clone())?; - let (tx, tx_metadata) = builder.build(consensus_branch_id, prover)?; - // We only called add_sapling_output() once. - let output_index = match tx_metadata.output_index(0) { - Some(idx) => idx as i64, - None => panic!("Output 0 should exist in the transaction"), - }; - let created = time::get_time(); - - // Update the database atomically, to ensure the result is internally consistent. - data.execute("BEGIN IMMEDIATE", NO_PARAMS)?; - - // Save the transaction in the database. - let mut raw_tx = vec![]; - tx.write(&mut raw_tx)?; - let mut stmt_insert_tx = data.prepare( - "INSERT INTO transactions (txid, created, expiry_height, raw) - VALUES (?, ?, ?, ?)", - )?; - stmt_insert_tx.execute(&[ - tx.txid().0.to_sql()?, - created.to_sql()?, - tx.expiry_height.to_sql()?, - raw_tx.to_sql()?, - ])?; - let id_tx = data.last_insert_rowid(); - - // Mark notes as spent. - // - // This locks the notes so they aren't selected again by a subsequent call to - // send_to_address() before this transaction has been mined (at which point the notes - // get re-marked as spent). - // - // Assumes that send_to_address() will never be called in parallel, which is a - // reasonable assumption for a light client such as a mobile phone. - let mut stmt_mark_spent_note = - data.prepare("UPDATE received_notes SET spent = ? WHERE nf = ?")?; - for spend in &tx.shielded_spends { - stmt_mark_spent_note.execute(&[id_tx.to_sql()?, spend.nullifier.to_sql()?])?; - } - - // Save the sent note in the database. - let to_str = encode_payment_address(HRP_SAPLING_PAYMENT_ADDRESS_TEST, to); - if let Some(memo) = memo { - let mut stmt_insert_sent_note = data.prepare( - "INSERT INTO sent_notes (tx, output_index, from_account, address, value, memo) - VALUES (?, ?, ?, ?, ?, ?)", - )?; - stmt_insert_sent_note.execute(&[ - id_tx.to_sql()?, - output_index.to_sql()?, - account.to_sql()?, - to_str.to_sql()?, - value.0.to_sql()?, - memo.as_bytes().to_sql()?, - ])?; - } else { - let mut stmt_insert_sent_note = data.prepare( - "INSERT INTO sent_notes (tx, output_index, from_account, address, value) - VALUES (?, ?, ?, ?, ?)", - )?; - stmt_insert_sent_note.execute(&[ - id_tx.to_sql()?, - output_index.to_sql()?, - account.to_sql()?, - to_str.to_sql()?, - value.0.to_sql()?, - ])?; - } - - data.execute("COMMIT", NO_PARAMS)?; - - // Return the row number of the transaction, so the caller can fetch it for sending. - Ok(id_tx) -} - -#[cfg(test)] -mod tests { - use ff::{PrimeField, PrimeFieldRepr}; - use pairing::bls12_381::Bls12; - use protobuf::Message; - use rand::{thread_rng, Rand, Rng}; - use rusqlite::{types::ToSql, Connection}; - use sapling_crypto::{ - jubjub::fs::Fs, - primitives::{Note, PaymentAddress}, - }; - use std::path::Path; - use tempfile::NamedTempFile; - use zcash_client_backend::{ - constants::HRP_SAPLING_PAYMENT_ADDRESS_TEST, - encoding::decode_payment_address, - note_encryption::{Memo, SaplingNoteEncryption}, - proto::compact_formats::{CompactBlock, CompactOutput, CompactSpend, CompactTx}, - prover::{LocalTxProver, TxProver}, - }; - use zcash_primitives::{transaction::components::Amount, JUBJUB}; - use zip32::{ExtendedFullViewingKey, ExtendedSpendingKey}; - - use super::{ - get_address, get_balance, get_verified_balance, init_accounts_table, init_blocks_table, - init_cache_database, init_data_database, scan_cached_blocks, send_to_address, - }; - - fn test_prover() -> impl TxProver { - let unix_params_dir = dirs::home_dir().map(|path| path.join(".zcash-params")); - let win_osx_params_dir = dirs::data_dir().map(|path| path.join("ZcashParams")); - let (spend_path, output_path) = match (unix_params_dir, win_osx_params_dir) { - (Some(ref params_dir), _) if params_dir.exists() => ( - params_dir.join("sapling-spend.params"), - params_dir.join("sapling-output.params"), - ), - (_, Some(ref params_dir)) if params_dir.exists() => ( - params_dir.join("sapling-spend.params"), - params_dir.join("sapling-output.params"), - ), - _ => { - panic!("Cannot locate the Zcash parameters. Please run zcash-fetch-params or fetch-params.sh to download the parameters, and then re-run the tests."); - } - }; - - LocalTxProver::new( - &spend_path, - "8270785a1a0d0bc77196f000ee6d221c9c9894f55307bd9357c3f0105d31ca63991ab91324160d8f53e2bbd3c2633a6eb8bdf5205d822e7f3f73edac51b2b70c", - &output_path, - "657e3d38dbb5cb5e7dd2970e8b03d69b4787dd907285b5a7f0790dcc8072f60bf593b32cc2d1c030e00ff5ae64bf84c5c3beb84ddc841d48264b4a171744d028", - ) - } - - /// Create a fake CompactBlock at the given height, containing a single output paying - /// the given address. Returns the CompactBlock and the nullifier for the new note. - fn fake_compact_block( - height: i32, - extfvk: ExtendedFullViewingKey, - value: Amount, - ) -> (CompactBlock, Vec) { - let to = extfvk.default_address().unwrap().1; - - // Create a fake Note for the account - let mut rng = thread_rng(); - let note = Note { - g_d: to.diversifier.g_d::(&JUBJUB).unwrap(), - pk_d: to.pk_d.clone(), - value: value.0 as u64, - r: Fs::rand(&mut rng), - }; - let encryptor = - SaplingNoteEncryption::new(extfvk.fvk.ovk, note.clone(), to.clone(), Memo::default()); - let mut cmu = vec![]; - note.cm(&JUBJUB).into_repr().write_le(&mut cmu).unwrap(); - let mut epk = vec![]; - encryptor.epk().write(&mut epk).unwrap(); - let enc_ciphertext = encryptor.encrypt_note_plaintext(); - - // Create a fake CompactBlock containing the note - let mut cout = CompactOutput::new(); - cout.set_cmu(cmu); - cout.set_epk(epk); - cout.set_ciphertext(enc_ciphertext[..52].to_vec()); - let mut ctx = CompactTx::new(); - let mut txid = vec![0; 32]; - rng.fill_bytes(&mut txid); - ctx.set_hash(txid); - ctx.outputs.push(cout); - let mut cb = CompactBlock::new(); - cb.set_height(height as u64); - cb.vtx.push(ctx); - (cb, note.nf(&extfvk.fvk.vk, 0, &JUBJUB)) - } - - /// Create a fake CompactBlock at the given height, spending a single note from the - /// given address. - fn fake_compact_block_spending( - height: i32, - (nf, in_value): (Vec, Amount), - extfvk: ExtendedFullViewingKey, - to: PaymentAddress, - value: Amount, - ) -> CompactBlock { - let mut rng = thread_rng(); - - // Create a fake CompactBlock containing the note - let mut cspend = CompactSpend::new(); - cspend.set_nf(nf); - let mut ctx = CompactTx::new(); - let mut txid = vec![0; 32]; - rng.fill_bytes(&mut txid); - ctx.set_hash(txid); - ctx.spends.push(cspend); - - // Create a fake Note for the payment - ctx.outputs.push({ - let note = Note { - g_d: to.diversifier.g_d::(&JUBJUB).unwrap(), - pk_d: to.pk_d.clone(), - value: value.0 as u64, - r: Fs::rand(&mut rng), - }; - let encryptor = - SaplingNoteEncryption::new(extfvk.fvk.ovk, note.clone(), to, Memo::default()); - let mut cmu = vec![]; - note.cm(&JUBJUB).into_repr().write_le(&mut cmu).unwrap(); - let mut epk = vec![]; - encryptor.epk().write(&mut epk).unwrap(); - let enc_ciphertext = encryptor.encrypt_note_plaintext(); - - let mut cout = CompactOutput::new(); - cout.set_cmu(cmu); - cout.set_epk(epk); - cout.set_ciphertext(enc_ciphertext[..52].to_vec()); - cout - }); - - // Create a fake Note for the change - ctx.outputs.push({ - let change_addr = extfvk.default_address().unwrap().1; - let note = Note { - g_d: change_addr.diversifier.g_d::(&JUBJUB).unwrap(), - pk_d: change_addr.pk_d.clone(), - value: (in_value.0 - value.0) as u64, - r: Fs::rand(&mut rng), - }; - let encryptor = SaplingNoteEncryption::new( - extfvk.fvk.ovk, - note.clone(), - change_addr, - Memo::default(), - ); - let mut cmu = vec![]; - note.cm(&JUBJUB).into_repr().write_le(&mut cmu).unwrap(); - let mut epk = vec![]; - encryptor.epk().write(&mut epk).unwrap(); - let enc_ciphertext = encryptor.encrypt_note_plaintext(); - - let mut cout = CompactOutput::new(); - cout.set_cmu(cmu); - cout.set_epk(epk); - cout.set_ciphertext(enc_ciphertext[..52].to_vec()); - cout - }); - - let mut cb = CompactBlock::new(); - cb.set_height(height as u64); - cb.vtx.push(ctx); - cb - } - - /// Insert a fake CompactBlock into the cache DB. - fn insert_into_cache>(db_cache: P, cb: &CompactBlock) { - let cb_bytes = cb.write_to_bytes().unwrap(); - let cache = Connection::open(&db_cache).unwrap(); - cache - .prepare("INSERT INTO compactblocks (height, data) VALUES (?, ?)") - .unwrap() - .execute(&[ - (cb.height as i32).to_sql().unwrap(), - cb_bytes.to_sql().unwrap(), - ]) - .unwrap(); - } - - #[test] - fn init_accounts_table_only_works_once() { - let data_file = NamedTempFile::new().unwrap(); - let db_data = data_file.path(); - init_data_database(&db_data).unwrap(); - - // We can call the function as many times as we want with no data - init_accounts_table(&db_data, &[]).unwrap(); - init_accounts_table(&db_data, &[]).unwrap(); - - // First call with data should initialise the accounts table - let extfvks = [ExtendedFullViewingKey::from(&ExtendedSpendingKey::master( - &[], - ))]; - init_accounts_table(&db_data, &extfvks).unwrap(); - - // Subsequent calls should return an error - init_accounts_table(&db_data, &[]).unwrap_err(); - init_accounts_table(&db_data, &extfvks).unwrap_err(); - } - - #[test] - fn init_blocks_table_only_works_once() { - let data_file = NamedTempFile::new().unwrap(); - let db_data = data_file.path(); - init_data_database(&db_data).unwrap(); - - // First call with data should initialise the blocks table - init_blocks_table(&db_data, 1, 1, &[]).unwrap(); - - // Subsequent calls should return an error - init_blocks_table(&db_data, 2, 2, &[]).unwrap_err(); - } - - #[test] - fn init_accounts_table_stores_correct_address() { - let data_file = NamedTempFile::new().unwrap(); - let db_data = data_file.path(); - init_data_database(&db_data).unwrap(); - - // Add an account to the wallet - let extsk = ExtendedSpendingKey::master(&[]); - let extfvks = [ExtendedFullViewingKey::from(&extsk)]; - init_accounts_table(&db_data, &extfvks).unwrap(); - - // The account's address should be in the data DB - let addr = get_address(&db_data, 0).unwrap(); - let pa = decode_payment_address(HRP_SAPLING_PAYMENT_ADDRESS_TEST, &addr).unwrap(); - assert_eq!(pa, extsk.default_address().unwrap().1); - } - - #[test] - fn scan_cached_blocks_requires_sequential_blocks() { - let cache_file = NamedTempFile::new().unwrap(); - let db_cache = cache_file.path(); - init_cache_database(&db_cache).unwrap(); - - let data_file = NamedTempFile::new().unwrap(); - let db_data = data_file.path(); - init_data_database(&db_data).unwrap(); - - // Add an account to the wallet - let extsk = ExtendedSpendingKey::master(&[]); - let extfvk = ExtendedFullViewingKey::from(&extsk); - init_accounts_table(&db_data, &[extfvk.clone()]).unwrap(); - - // Create a block with height 1 - let value = Amount(50000); - let (cb1, _) = fake_compact_block(1, extfvk.clone(), value); - insert_into_cache(db_cache, &cb1); - scan_cached_blocks(db_cache, db_data).unwrap(); - assert_eq!(get_balance(db_data, 0).unwrap(), value); - - // We cannot scan a block of height 3 next - let (cb3, _) = fake_compact_block(3, extfvk.clone(), value); - insert_into_cache(db_cache, &cb3); - match scan_cached_blocks(db_cache, db_data) { - Ok(_) => panic!("Should have failed"), - Err(e) => assert_eq!( - e.to_string(), - "Expected height of next CompactBlock to be 2, but was 3" - ), - } - - // If we add a block of height 2, we can now scan both - let (cb2, _) = fake_compact_block(2, extfvk.clone(), value); - insert_into_cache(db_cache, &cb2); - scan_cached_blocks(db_cache, db_data).unwrap(); - assert_eq!(get_balance(db_data, 0).unwrap(), Amount(150_000)); - } - - #[test] - fn scan_cached_blocks_finds_received_notes() { - let cache_file = NamedTempFile::new().unwrap(); - let db_cache = cache_file.path(); - init_cache_database(&db_cache).unwrap(); - - let data_file = NamedTempFile::new().unwrap(); - let db_data = data_file.path(); - init_data_database(&db_data).unwrap(); - - // Add an account to the wallet - let extsk = ExtendedSpendingKey::master(&[]); - let extfvk = ExtendedFullViewingKey::from(&extsk); - init_accounts_table(&db_data, &[extfvk.clone()]).unwrap(); - - // Account balance should be zero - assert_eq!(get_balance(db_data, 0).unwrap(), Amount(0)); - - // Create a fake CompactBlock sending value to the address - let value = Amount(5); - let (cb, _) = fake_compact_block(1, extfvk.clone(), value); - insert_into_cache(db_cache, &cb); - - // Scan the cache - scan_cached_blocks(db_cache, db_data).unwrap(); - - // Account balance should reflect the received note - assert_eq!(get_balance(db_data, 0).unwrap(), value); - - // Create a second fake CompactBlock sending more value to the address - let value2 = Amount(7); - let (cb2, _) = fake_compact_block(2, extfvk, value2); - insert_into_cache(db_cache, &cb2); - - // Scan the cache again - scan_cached_blocks(db_cache, db_data).unwrap(); - - // Account balance should reflect both received notes - // TODO: impl Sum for Amount - assert_eq!(get_balance(db_data, 0).unwrap(), Amount(value.0 + value2.0)); - } - - #[test] - fn scan_cached_blocks_finds_change_notes() { - let cache_file = NamedTempFile::new().unwrap(); - let db_cache = cache_file.path(); - init_cache_database(&db_cache).unwrap(); - - let data_file = NamedTempFile::new().unwrap(); - let db_data = data_file.path(); - init_data_database(&db_data).unwrap(); - - // Add an account to the wallet - let extsk = ExtendedSpendingKey::master(&[]); - let extfvk = ExtendedFullViewingKey::from(&extsk); - init_accounts_table(&db_data, &[extfvk.clone()]).unwrap(); - - // Account balance should be zero - assert_eq!(get_balance(db_data, 0).unwrap(), Amount(0)); - - // Create a fake CompactBlock sending value to the address - let value = Amount(5); - let (cb, nf) = fake_compact_block(1, extfvk.clone(), value); - insert_into_cache(db_cache, &cb); - - // Scan the cache - scan_cached_blocks(db_cache, db_data).unwrap(); - - // Account balance should reflect the received note - assert_eq!(get_balance(db_data, 0).unwrap(), value); - - // Create a second fake CompactBlock spending value from the address - let extsk2 = ExtendedSpendingKey::master(&[0]); - let to2 = extsk2.default_address().unwrap().1; - let value2 = Amount(2); - insert_into_cache( - db_cache, - &fake_compact_block_spending(2, (nf, value), extfvk, to2, value2), - ); - - // Scan the cache again - scan_cached_blocks(db_cache, db_data).unwrap(); - - // Account balance should equal the change - // TODO: impl Sum for Amount - assert_eq!(get_balance(db_data, 0).unwrap(), Amount(value.0 - value2.0)); - } - - #[test] - fn send_to_address_fails_on_incorrect_extsk() { - let data_file = NamedTempFile::new().unwrap(); - let db_data = data_file.path(); - init_data_database(&db_data).unwrap(); - - // Add two accounts to the wallet - let extsk0 = ExtendedSpendingKey::master(&[]); - let extsk1 = ExtendedSpendingKey::master(&[0]); - let extfvks = [ - ExtendedFullViewingKey::from(&extsk0), - ExtendedFullViewingKey::from(&extsk1), - ]; - init_accounts_table(&db_data, &extfvks).unwrap(); - let to = extsk0.default_address().unwrap().1; - - // Invalid extsk for the given account should cause an error - match send_to_address( - db_data, - 1, - test_prover(), - (0, &extsk1), - &to, - Amount(1), - None, - ) { - Ok(_) => panic!("Should have failed"), - Err(e) => assert_eq!(e.to_string(), "Incorrect ExtendedSpendingKey for account 0"), - } - match send_to_address( - db_data, - 1, - test_prover(), - (1, &extsk0), - &to, - Amount(1), - None, - ) { - Ok(_) => panic!("Should have failed"), - Err(e) => assert_eq!(e.to_string(), "Incorrect ExtendedSpendingKey for account 1"), - } - } - - #[test] - fn send_to_address_fails_with_no_blocks() { - let data_file = NamedTempFile::new().unwrap(); - let db_data = data_file.path(); - init_data_database(&db_data).unwrap(); - - // Add an account to the wallet - let extsk = ExtendedSpendingKey::master(&[]); - let extfvks = [ExtendedFullViewingKey::from(&extsk)]; - init_accounts_table(&db_data, &extfvks).unwrap(); - let to = extsk.default_address().unwrap().1; - - // We cannot do anything if we aren't synchronised - match send_to_address(db_data, 1, test_prover(), (0, &extsk), &to, Amount(1), None) { - Ok(_) => panic!("Should have failed"), - Err(e) => assert_eq!(e.to_string(), "Must scan blocks first"), - } - } - - #[test] - fn send_to_address_fails_on_insufficient_balance() { - let data_file = NamedTempFile::new().unwrap(); - let db_data = data_file.path(); - init_data_database(&db_data).unwrap(); - init_blocks_table(&db_data, 1, 1, &[]).unwrap(); - - // Add an account to the wallet - let extsk = ExtendedSpendingKey::master(&[]); - let extfvks = [ExtendedFullViewingKey::from(&extsk)]; - init_accounts_table(&db_data, &extfvks).unwrap(); - let to = extsk.default_address().unwrap().1; - - // Account balance should be zero - assert_eq!(get_balance(db_data, 0).unwrap(), Amount(0)); - - // We cannot spend anything - match send_to_address(db_data, 1, test_prover(), (0, &extsk), &to, Amount(1), None) { - Ok(_) => panic!("Should have failed"), - Err(e) => assert_eq!( - e.to_string(), - "Insufficient balance (have 0, need 10001 including fee)" - ), - } - } - - #[test] - fn send_to_address_fails_on_unverified_notes() { - let cache_file = NamedTempFile::new().unwrap(); - let db_cache = cache_file.path(); - init_cache_database(&db_cache).unwrap(); - - let data_file = NamedTempFile::new().unwrap(); - let db_data = data_file.path(); - init_data_database(&db_data).unwrap(); - - // Add an account to the wallet - let extsk = ExtendedSpendingKey::master(&[]); - let extfvk = ExtendedFullViewingKey::from(&extsk); - init_accounts_table(&db_data, &[extfvk.clone()]).unwrap(); - - // Add funds to the wallet in a single note - let value = Amount(50000); - let (cb, _) = fake_compact_block(1, extfvk.clone(), value); - insert_into_cache(db_cache, &cb); - scan_cached_blocks(db_cache, db_data).unwrap(); - - // Verified balance matches total balance - assert_eq!(get_balance(db_data, 0).unwrap(), value); - assert_eq!(get_verified_balance(db_data, 0).unwrap(), value); - - // Add more funds to the wallet in a second note - let (cb, _) = fake_compact_block(2, extfvk.clone(), value); - insert_into_cache(db_cache, &cb); - scan_cached_blocks(db_cache, db_data).unwrap(); - - // Verified balance does not include the second note - assert_eq!(get_balance(db_data, 0).unwrap().0, 2 * value.0); - assert_eq!(get_verified_balance(db_data, 0).unwrap(), value); - - // Spend fails because there are insufficient verified notes - let extsk2 = ExtendedSpendingKey::master(&[]); - let to = extsk2.default_address().unwrap().1; - match send_to_address( - db_data, - 1, - test_prover(), - (0, &extsk), - &to, - Amount(70000), - None, - ) { - Ok(_) => panic!("Should have failed"), - Err(e) => assert_eq!( - e.to_string(), - "Insufficient balance (have 50000, need 80000 including fee)" - ), - } - - // Mine blocks 3 to 10 until just before the second note is verified - for i in 3..11 { - let (cb, _) = fake_compact_block(i, extfvk.clone(), value); - insert_into_cache(db_cache, &cb); - } - scan_cached_blocks(db_cache, db_data).unwrap(); - - // Second spend still fails - match send_to_address( - db_data, - 1, - test_prover(), - (0, &extsk), - &to, - Amount(70000), - None, - ) { - Ok(_) => panic!("Should have failed"), - Err(e) => assert_eq!( - e.to_string(), - "Insufficient balance (have 50000, need 80000 including fee)" - ), - } - - // Mine block 11 so that the second note becomes verified - let (cb, _) = fake_compact_block(11, extfvk.clone(), value); - insert_into_cache(db_cache, &cb); - scan_cached_blocks(db_cache, db_data).unwrap(); - - // Second spend should now succeed - send_to_address( - db_data, - 1, - test_prover(), - (0, &extsk), - &to, - Amount(70000), - None, - ) - .unwrap(); - } - - #[test] - fn send_to_address_fails_on_locked_notes() { - let cache_file = NamedTempFile::new().unwrap(); - let db_cache = cache_file.path(); - init_cache_database(&db_cache).unwrap(); - - let data_file = NamedTempFile::new().unwrap(); - let db_data = data_file.path(); - init_data_database(&db_data).unwrap(); - - // Add an account to the wallet - let extsk = ExtendedSpendingKey::master(&[]); - let extfvk = ExtendedFullViewingKey::from(&extsk); - init_accounts_table(&db_data, &[extfvk.clone()]).unwrap(); - - // Add funds to the wallet in a single note - let value = Amount(50000); - let (cb, _) = fake_compact_block(1, extfvk.clone(), value); - insert_into_cache(db_cache, &cb); - scan_cached_blocks(db_cache, db_data).unwrap(); - assert_eq!(get_balance(db_data, 0).unwrap(), value); - - // Send some of the funds to another address - let extsk2 = ExtendedSpendingKey::master(&[]); - let to = extsk2.default_address().unwrap().1; - send_to_address( - db_data, - 1, - test_prover(), - (0, &extsk), - &to, - Amount(15000), - None, - ) - .unwrap(); - - // A second spend fails because there are no usable notes - match send_to_address( - db_data, - 1, - test_prover(), - (0, &extsk), - &to, - Amount(2000), - None, - ) { - Ok(_) => panic!("Should have failed"), - Err(e) => assert_eq!( - e.to_string(), - "Insufficient balance (have 0, need 12000 including fee)" - ), - } - - // Mine blocks 2 to 22 (that don't send us funds) until just before the first - // transaction expires - for i in 2..23 { - let (cb, _) = fake_compact_block( - i, - ExtendedFullViewingKey::from(&ExtendedSpendingKey::master(&[i as u8])), - value, - ); - insert_into_cache(db_cache, &cb); - } - scan_cached_blocks(db_cache, db_data).unwrap(); - - // Second spend still fails - match send_to_address( - db_data, - 1, - test_prover(), - (0, &extsk), - &to, - Amount(2000), - None, - ) { - Ok(_) => panic!("Should have failed"), - Err(e) => assert_eq!( - e.to_string(), - "Insufficient balance (have 0, need 12000 including fee)" - ), - } - - // Mine block 23 so that the first transaction expires - let (cb, _) = fake_compact_block( - 23, - ExtendedFullViewingKey::from(&ExtendedSpendingKey::master(&[23])), - value, - ); - insert_into_cache(db_cache, &cb); - scan_cached_blocks(db_cache, db_data).unwrap(); - - // Second spend should now succeed - send_to_address( - db_data, - 1, - test_prover(), - (0, &extsk), - &to, - Amount(2000), - None, - ) - .unwrap(); - } -}