diff --git a/README.md b/README.md index c08ee66..a08c25a 100644 --- a/README.md +++ b/README.md @@ -1,88 +1,20 @@ -ZecWallet is a z-Addr first, Sapling compatible wallet and full node for zcashd that runs on Linux, Windows and macOS. - -![Screenshot](docs/screenshot-main.png?raw=true) -![Screenshots](docs/screenshot-sub.png?raw=true) -# Installation - -Head over to the releases page and grab the latest installers or binary. https://github.com/ZcashFoundation/zecwallet/releases - -### Linux - -If you are on Debian/Ubuntu, please download the `.deb` package and install it. -``` -sudo dpkg -i linux-deb-zecwallet-v0.7.9.deb -sudo apt install -f -``` - -Or you can download and run the binaries directly. -``` -tar -xvf zecwallet-v0.7.9.tar.gz -./zecwallet-v0.7.9/zecwallet -``` - -### Windows -Download and run the `.msi` installer and follow the prompts. Alternately, you can download the release binary, unzip it and double click on `zecwallet.exe` to start. - -### macOS -Double-click on the `.dmg` file to open it, and drag `zecwallet` on to the Applications link to install. - -## zcashd -ZecWallet needs a Zcash node running zcashd. If you already have a zcashd node running, ZecWallet will connect to it. - -If you don't have one, ZecWallet will start its embedded zcashd node. - -Additionally, if this is the first time you're running ZecWallet or a zcashd daemon, ZecWallet will download the zcash params (~1.7 GB) and configure `zcash.conf` for you. - -Pass `--no-embedded` to disable the embedded zcashd and force ZecWallet to connect to an external node. +ZecWallet-lite is z-Addr first, Sapling compatible wallet lightwallet for Zcash ## Compiling from source -ZecWallet is written in C++ 14, and can be compiled with g++/clang++/visual c++. It also depends on Qt5, which you can get from [here](https://www.qt.io/download). Note that if you are compiling from source, you won't get the embedded zcashd by default. You can either run an external zcashd, or compile zcashd as well. - -See detailed build instructions [on the wiki](https://github.com/ZcashFoundation/zecwallet/wiki/Compiling-from-source-code) +* ZecWallet is written in C++ 14, and can be compiled with g++/clang++/visual c++. +* It also depends on Qt5, which you can get from [here](https://www.qt.io/download). +* You'll need Rust v1.37 + ### Building on Linux ``` -git clone https://github.com/ZcashFoundation/zecwallet.git +git clone https://github.com/adityapk/zecwallet-lite.git cd zecwallet -/path/to/qt5/bin/qmake zec-qt-wallet.pro CONFIG+=debug +/path/to/qt5/bin/qmake zecwallet-lite.pro CONFIG+=debug make -j$(nproc) ./zecwallet ``` - -### Building on Windows -You need Visual Studio 2017 (The free C++ Community Edition works just fine). - -From the VS Tools command prompt -``` -git clone https://github.com/ZcashFoundation/zecwallet.git -cd zecwallet -c:\Qt5\bin\qmake.exe zec-qt-wallet.pro -spec win32-msvc CONFIG+=debug -nmake - -debug\zecwallet.exe -``` - -To create the Visual Studio project files so you can compile and run from Visual Studio: -``` -c:\Qt5\bin\qmake.exe zec-qt-wallet.pro -tp vc CONFIG+=debug -``` - -### Building on macOS -You need to install the Xcode app or the Xcode command line tools first, and then install Qt. - -``` -git clone https://github.com/ZcashFoundation/zecwallet.git -cd zecwallet -/path/to/qt5/bin/qmake zec-qt-wallet.pro CONFIG+=debug -make - -./zecwallet.app/Contents/MacOS/zecwallet -``` - -### [Troubleshooting Guide & FAQ](https://github.com/ZcashFoundation/zecwallet/wiki/Troubleshooting-&-FAQ) -Please read the [troubleshooting guide](https://docs.zecwallet.co/troubleshooting/) for common problems and solutions. -For support or other questions, tweet at [@zecwallet](https://twitter.com/zecwallet) or [file an issue](https://github.com/ZcashFoundation/zecwallet/issues). +Right now, you'll also need to run `lightwalletd` on your local machine for Zecwallet to connect to. _PS: ZecWallet is NOT an official wallet, and is not affiliated with the Electric Coin Company in any way._ diff --git a/lib/Cargo.lock b/lib/Cargo.lock index 3df45e5..8b7d65d 100644 --- a/lib/Cargo.lock +++ b/lib/Cargo.lock @@ -64,22 +64,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "backtrace" -version = "0.3.38" +version = "0.3.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "backtrace-sys" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -125,7 +125,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitflags" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -214,7 +214,7 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.45" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -227,7 +227,7 @@ name = "chrono" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", @@ -238,7 +238,7 @@ name = "cloudabi" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -351,7 +351,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -371,7 +371,7 @@ name = "failure" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -426,7 +426,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "miniz_oxide 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -457,7 +457,7 @@ name = "fuchsia-zircon" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -494,7 +494,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -517,7 +517,7 @@ dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", "indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -558,7 +558,7 @@ dependencies = [ [[package]] name = "http" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -573,7 +573,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -582,7 +582,7 @@ name = "http-connection" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -604,7 +604,7 @@ name = "iovec" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -644,7 +644,7 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.62" +version = "0.2.65" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -693,7 +693,7 @@ dependencies = [ "flate2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "log-mdc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", @@ -731,7 +731,7 @@ dependencies = [ "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -745,7 +745,7 @@ version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -771,7 +771,7 @@ version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -812,7 +812,7 @@ name = "num_cpus" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -871,7 +871,7 @@ name = "parking_lot_core" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -885,7 +885,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1010,8 +1010,8 @@ name = "qtlib" version = "0.1.0" dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "zecwalletlitelib 0.1.0 (git+https://github.com/adityapk00/zecwallet-lite-lib)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "zecwalletlitelib 0.1.0 (git+https://github.com/adityapk00/zecwallet-light-cli?rev=e3a0fd2dea59c0cf6434148bf77fef84830cce02)", ] [[package]] @@ -1046,7 +1046,7 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1064,7 +1064,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1138,7 +1138,7 @@ name = "rand_jitter" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1150,7 +1150,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1227,9 +1227,9 @@ name = "ring" version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1312,7 +1312,7 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1347,7 +1347,7 @@ name = "secp256k1" version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1393,7 +1393,7 @@ version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1517,7 +1517,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1529,7 +1529,7 @@ name = "thread-id" version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1539,7 +1539,7 @@ name = "time" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1750,7 +1750,7 @@ dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1807,7 +1807,7 @@ dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", "http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1834,7 +1834,7 @@ dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-connect 0.1.0 (git+https://github.com/carllerche/tokio-connect)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1858,7 +1858,7 @@ version = "0.1.0" source = "git+https://github.com/tower-rs/tower-http#cb393c933f5167f934abde9d4f902e44d9ea2d50" dependencies = [ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", "http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "http-connection 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1904,7 +1904,7 @@ version = "0.1.0" source = "git+https://github.com/tower-rs/tower-http#cb393c933f5167f934abde9d4f902e44d9ea2d50" dependencies = [ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", "tower-service 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2069,7 +2069,7 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2182,7 +2182,7 @@ dependencies = [ [[package]] name = "zecwalletlitelib" version = "0.1.0" -source = "git+https://github.com/adityapk00/zecwallet-lite-lib#93830f9e99651a7845c15dc992eab9941d251355" +source = "git+https://github.com/adityapk00/zecwallet-light-cli?rev=e3a0fd2dea59c0cf6434148bf77fef84830cce02#e3a0fd2dea59c0cf6434148bf77fef84830cce02" dependencies = [ "base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "bellman 0.1.0 (git+https://github.com/adityapk00/librustzcash.git?rev=188537ea025fcb7fbdfc11266f307a084a5451e4)", @@ -2192,7 +2192,7 @@ dependencies = [ "ff 0.4.0 (git+https://github.com/adityapk00/librustzcash.git?rev=188537ea025fcb7fbdfc11266f307a084a5451e4)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", "json 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2233,14 +2233,14 @@ dependencies = [ "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" "checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" "checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" -"checksum backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "690a62be8920ccf773ee00ef0968649b0e724cda8bd5b12286302b4ae955fdf5" -"checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b" +"checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea" +"checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" "checksum base58 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum bech32 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0089c35ab7c6f2bc55ab23f769913f0ac65b1023e7e74638a1f43128dd5df2" "checksum bellman 0.1.0 (git+https://github.com/adityapk00/librustzcash.git?rev=188537ea025fcb7fbdfc11266f307a084a5451e4)" = "" "checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" -"checksum bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a606a02debe2813760609f57a64a2ffd27d9fdf5b2f133eaca0b248dd92cdd2" +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "5850aeee1552f495dd0250014cf64b82b7c8879a89d83b33bbdace2cc4f63182" "checksum blake2s_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "979da0ce13c897d6be19e005ea77ac12b0fea0157aeeee7feb8c49f91386f0ea" "checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" @@ -2251,7 +2251,7 @@ dependencies = [ "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" -"checksum cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc9a35e1f4290eb9e5fc54ba6cf40671ed2a2514c3eeb2b2a908dda2ea5a1be" +"checksum cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" @@ -2293,7 +2293,7 @@ dependencies = [ "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" -"checksum http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "372bcb56f939e449117fb0869c2e8fd8753a8223d92a172c6e808cf123a5b6e4" +"checksum http 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "d7e06e336150b178206af098a055e3621e8336027e2b4d126bda0bc64824baaf" "checksum http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" "checksum http-connection 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f6080cea47f7371d4da9a46dd52787c598ce93886393e400bc178f9039bac27" "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" @@ -2304,7 +2304,7 @@ dependencies = [ "checksum json 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3ca41abbeb7615d56322a984e63be5e5d0a117dfaca86c14393e32a762ccac1" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" +"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" "checksum lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8912e782533a93a167888781b836336a6ca5da6175c05944c86cf28c31104dc" @@ -2377,7 +2377,7 @@ dependencies = [ "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rustls 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f271e3552cd835fa28c541c34a7e8fdd8cdff09d77fe4eb8f6c42e87a11b096e" -"checksum ryu 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "19d2271fa48eaf61e53cc88b4ad9adcbafa2d512c531e7fadb6dc11a4d3656c5" +"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" "checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" @@ -2467,4 +2467,4 @@ dependencies = [ "checksum zcash_client_backend 0.0.0 (git+https://github.com/adityapk00/librustzcash.git?rev=188537ea025fcb7fbdfc11266f307a084a5451e4)" = "" "checksum zcash_primitives 0.0.0 (git+https://github.com/adityapk00/librustzcash.git?rev=188537ea025fcb7fbdfc11266f307a084a5451e4)" = "" "checksum zcash_proofs 0.0.0 (git+https://github.com/adityapk00/librustzcash.git?rev=188537ea025fcb7fbdfc11266f307a084a5451e4)" = "" -"checksum zecwalletlitelib 0.1.0 (git+https://github.com/adityapk00/zecwallet-lite-lib)" = "" +"checksum zecwalletlitelib 0.1.0 (git+https://github.com/adityapk00/zecwallet-light-cli?rev=e3a0fd2dea59c0cf6434148bf77fef84830cce02)" = "" diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 3153fc2..e65a82b 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -11,4 +11,4 @@ crate-type = ["staticlib"] [dependencies] libc = "0.2.58" lazy_static = "1.4.0" -zecwalletlitelib = { git = "https://github.com/adityapk00/zecwallet-lite-lib" } \ No newline at end of file +zecwalletlitelib = { git = "https://github.com/adityapk00/zecwallet-light-cli", rev = "e3a0fd2dea59c0cf6434148bf77fef84830cce02" } \ No newline at end of file diff --git a/lib/src/lib.rs b/lib/src/lib.rs index c76bf1b..8d77adc 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -49,13 +49,19 @@ pub extern fn litelib_initialze(dangerous: bool, server: *const c_char) -> *mut } #[no_mangle] -pub extern fn litelib_execute(cmd: *const c_char) -> *mut c_char { +pub extern fn litelib_execute(cmd: *const c_char, args: *const c_char) -> *mut c_char { let cmd_str = unsafe { assert!(!cmd.is_null()); CStr::from_ptr(cmd).to_string_lossy().into_owned() }; + let arg_str = unsafe { + assert!(!args.is_null()); + + CStr::from_ptr(args).to_string_lossy().into_owned() + }; + let resp: String; { let lc = LIGHTCLIENT.lock().unwrap(); @@ -65,7 +71,9 @@ pub extern fn litelib_execute(cmd: *const c_char) -> *mut c_char { return e_str.into_raw(); } - resp = commands::do_user_command(&cmd_str, &vec![], lc.borrow().as_ref().unwrap()).clone(); + let args = if arg_str.is_empty() { vec![] } else { vec![arg_str.as_ref()] }; + + resp = commands::do_user_command(&cmd_str, &args, lc.borrow().as_ref().unwrap()).clone(); }; let c_str = CString::new(resp.as_bytes()).unwrap(); diff --git a/lib/zecwalletlitelib.h b/lib/zecwalletlitelib.h index 8297964..d1d18ec 100644 --- a/lib/zecwalletlitelib.h +++ b/lib/zecwalletlitelib.h @@ -6,7 +6,7 @@ extern "C"{ #endif extern char * litelib_initialze (bool dangerous, const char* server); -extern char * litelib_execute (const char* s); +extern char * litelib_execute (const char* s, const char* args); extern void litelib_rust_free_string (char* s); #ifdef __cplusplus diff --git a/src/connection.cpp b/src/connection.cpp index 14bdbe9..ac06208 100644 --- a/src/connection.cpp +++ b/src/connection.cpp @@ -100,7 +100,7 @@ void ConnectionLoader::showError(QString explanation) { * Connection, Executor and Callback Class ************************************************************************************/ void Executor::run() { - char* resp = litelib_execute(this->cmd.toStdString().c_str()); + char* resp = litelib_execute(this->cmd.toStdString().c_str(), this->args.toStdString().c_str()); // Copy the string, since we need to return this back to rust char* resp_copy = new char[strlen(resp) + 1]; @@ -111,14 +111,17 @@ void Executor::run() { memset(resp_copy, '-', strlen(resp_copy)); delete[] resp_copy; - qDebug() << "Reply=" << reply; + qDebug() << "Reply=" << reply; auto parsed = json::parse(reply.toStdString().c_str(), nullptr, false); - - const bool isGuiThread = - QThread::currentThread() == QCoreApplication::instance()->thread(); + if (parsed.is_discarded() || parsed.is_null()) { + emit handleError(reply); + } else { + const bool isGuiThread = + QThread::currentThread() == QCoreApplication::instance()->thread(); qDebug() << "executing RPC: isGUI=" << isGuiThread; - emit responseReady(parsed); + emit responseReady(parsed); + } } diff --git a/src/controller.cpp b/src/controller.cpp index 7021187..0a78f56 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -2,7 +2,6 @@ #include "addressbook.h" #include "settings.h" -#include "senttxstore.h" #include "version.h" #include "websockets.h" @@ -40,14 +39,6 @@ Controller::Controller(MainWindow* main) { }); timer->start(Settings::updateSpeed); - // Set up the timer to watch for tx status - txTimer = new QTimer(main); - QObject::connect(txTimer, &QTimer::timeout, [=]() { - watchTxStatus(); - }); - // Start at every 10s. When an operation is pending, this will change to every second - txTimer->start(Settings::updateSpeed); - // Create the data model model = new DataModel(); @@ -95,10 +86,8 @@ void Controller::setConnection(Connection* c) { // Build the RPC JSON Parameters for this tx -void Controller::fillTxJsonParams(json& params, Tx tx) { - Q_ASSERT(params.is_array()); - // Get all the addresses and amounts - json allRecepients = json::array(); +void Controller::fillTxJsonParams(json& allRecepients, Tx tx) { + Q_ASSERT(allRecepients.is_array()); // For each addr/amt/memo, construct the JSON and also build the confirm dialog box for (int i=0; i < tx.toAddrs.size(); i++) { @@ -107,24 +96,18 @@ void Controller::fillTxJsonParams(json& params, Tx tx) { // Construct the JSON params json rec = json::object(); rec["address"] = toAddr.addr.toStdString(); - // Force it through string for rounding. Without this, decimal points beyond 8 places - // will appear, causing an "invalid amount" error - rec["amount"] = Settings::getDecimalString(toAddr.amount).toStdString(); //.toDouble(); - if (Settings::isZAddress(toAddr.addr) && !toAddr.encodedMemo.trimmed().isEmpty()) - rec["memo"] = toAddr.encodedMemo.toStdString(); + rec["amount"] = toAddr.amount; + if (Settings::isZAddress(toAddr.addr) && !toAddr.memo.trimmed().isEmpty()) + rec["memo"] = toAddr.memo.toStdString(); allRecepients.push_back(rec); } - // Add sender - params.push_back(tx.fromAddr.toStdString()); - params.push_back(allRecepients); - - // Add fees if custom fees are allowed. - if (Settings::getInstance()->getAllowCustomFees()) { - params.push_back(1); // minconf - params.push_back(tx.fee); - } + // // Add fees if custom fees are allowed. + // if (Settings::getInstance()->getAllowCustomFees()) { + // params.push_back(1); // minconf + // params.push_back(tx.fee); + // } } @@ -143,9 +126,7 @@ void Controller::noConnection() { // Clear Transactions table. QList emptyTxs; - transactionsTableModel->addTData(emptyTxs); - transactionsTableModel->addZRecvData(emptyTxs); - transactionsTableModel->addZSentData(emptyTxs); + transactionsTableModel->replaceData(emptyTxs); // Clear balances ui->balSheilded->setText(""); @@ -160,28 +141,6 @@ void Controller::noConnection() { ui->inputsCombo->clear(); } -// Refresh received z txs by calling z_listreceivedbyaddress/gettransaction -void Controller::refreshReceivedZTrans(QList zaddrs) { - if (!zrpc->haveConnection()) - return noConnection(); - - // We'll only refresh the received Z txs if settings allows us. - if (!Settings::getInstance()->getSaveZtxs()) { - QList emptylist; - transactionsTableModel->addZRecvData(emptylist); - return; - } - - zrpc->fetchReceivedZTrans(zaddrs, - [=] (QString addr) { - model->markAddressUsed(addr); - }, - [=] (QList txdata) { - transactionsTableModel->addZRecvData(txdata); - } - ); -} - /// This will refresh all the balance data from zcashd void Controller::refresh(bool force) { if (!zrpc->haveConnection()) @@ -190,7 +149,6 @@ void Controller::refresh(bool force) { getInfoThenRefresh(force); } - void Controller::getInfoThenRefresh(bool force) { if (!zrpc->haveConnection()) return noConnection(); @@ -217,6 +175,7 @@ void Controller::getInfoThenRefresh(bool force) { static int lastBlock = 0; int curBlock = reply["latest_block_height"].get(); + model->setLatestBlock(curBlock); //int version = reply["version"].get(); int version = 1; Settings::getInstance()->setZcashdVersion(version); @@ -254,31 +213,30 @@ void Controller::refreshAddresses() { return noConnection(); auto newzaddresses = new QList(); + auto newtaddresses = new QList(); - zrpc->fetchZAddresses([=] (json reply) { - for (auto& it : reply.get()) { + zrpc->fetchAddresses([=] (json reply) { + auto zaddrs = reply["z_addresses"].get(); + for (auto& it : zaddrs) { auto addr = QString::fromStdString(it.get()); newzaddresses->push_back(addr); } model->replaceZaddresses(newzaddresses); - // Refresh the sent and received txs from all these z-addresses - refreshSentZTrans(); - refreshReceivedZTrans(model->getAllZAddresses()); - }); - - - auto newtaddresses = new QList(); - zrpc->fetchTAddresses([=] (json reply) { - for (auto& it : reply.get()) { + auto taddrs = reply["t_addresses"].get(); + for (auto& it : taddrs) { auto addr = QString::fromStdString(it.get()); if (Settings::isTAddress(addr)) newtaddresses->push_back(addr); } model->replaceTaddresses(newtaddresses); + + // Refresh the sent and received txs from all these z-addresses + refreshTransactions(); }); + } // Function to create the data model and update the views, used below. @@ -361,77 +319,80 @@ void Controller::refreshTransactions() { return noConnection(); zrpc->fetchTransactions([=] (json reply) { - QList txdata; + QList txdata; for (auto& it : reply.get()) { - double fee = 0; - if (!it["fee"].is_null()) { - fee = it["fee"].get(); - } + QString address; + qint64 total_amount; + QList items; + + // First, check if there's outgoing metadata + if (!it["outgoing_metadata"].is_null()) { + + for (auto o: it["outgoing_metadata"].get()) { + QString address = QString::fromStdString(o["address"]); + qint64 amount = -1 * o["value"].get(); // Sent items are -ve + + QString memo; + if (!o["memo"].is_null()) { + memo = QString::fromStdString(o["memo"]); + } - QString address = (it["address"].is_null() ? "" : QString::fromStdString(it["address"])); + items.push_back(TransactionItemDetail{address, amount, memo}); + total_amount += amount; + } - TransactionItem tx{ - QString::fromStdString(it["category"]), - (qint64)it["time"].get(), - address, - QString::fromStdString(it["txid"]), - it["amount"].get() + fee, - static_cast(it["confirmations"].get()), - "", "" }; + if (items.length() == 1) { + address = items[0].address; + } else { + address = "(Multiple)"; + } - txdata.push_back(tx); - if (!address.isEmpty()) + txdata.push_back(TransactionItem{ + "Sent", + it["datetime"].get(), + address, + QString::fromStdString(it["txid"]), + model->getLatestBlock() - it["block_height"].get(), + items + }); + } else { + // Incoming Transaction + address = (it["address"].is_null() ? "" : QString::fromStdString(it["address"])); model->markAddressUsed(address); + + items.push_back(TransactionItemDetail{ + address, + it["amount"].get(), + "" + }); + + TransactionItem tx{ + "Receive", + it["datetime"].get(), + address, + QString::fromStdString(it["txid"]), + model->getLatestBlock() - it["block_height"].get(), + items + }; + + txdata.push_back(tx); + } + } // Update model data, which updates the table view - transactionsTableModel->addTData(txdata); + transactionsTableModel->replaceData(txdata); }); } -// Read sent Z transactions from the file. -void Controller::refreshSentZTrans() { - if (!zrpc->haveConnection()) - return noConnection(); - - auto sentZTxs = SentTxStore::readSentTxFile(); - - // If there are no sent z txs, then empty the table. - // This happens when you clear history. - if (sentZTxs.isEmpty()) { - transactionsTableModel->addZSentData(sentZTxs); - return; - } - - QList txids; - - for (auto sentTx: sentZTxs) { - txids.push_back(sentTx.txid); - } - - // Look up all the txids to get the confirmation count for them. - zrpc->fetchReceivedTTrans(txids, sentZTxs, [=](auto newSentZTxs) { - transactionsTableModel->addZSentData(newSentZTxs); - }); -} - -void Controller::addNewTxToWatch(const QString& newOpid, WatchedTx wtx) { - watchingOps.insert(newOpid, wtx); - - watchTxStatus(); -} - /** * Execute a transaction with the standard UI. i.e., standard status bar message and standard error * handling */ void Controller::executeStandardUITransaction(Tx tx) { - executeTransaction(tx, - [=] (QString opid) { - ui->statusBar->showMessage(QObject::tr("Computing Tx: ") % opid); - }, - [=] (QString, QString txid) { + executeTransaction(tx, + [=] (QString txid) { ui->statusBar->showMessage(Settings::txidStatusMessage + " " + txid); }, [=] (QString opid, QString errStr) { @@ -448,20 +409,20 @@ void Controller::executeStandardUITransaction(Tx tx) { // Execute a transaction! void Controller::executeTransaction(Tx tx, - const std::function submitted, - const std::function computed, - const std::function error) { + const std::function submitted, + const std::function error) { // First, create the json params json params = json::array(); fillTxJsonParams(params, tx); std::cout << std::setw(2) << params << std::endl; - zrpc->sendZTransaction(params, [=](const json& reply) { - QString opid = QString::fromStdString(reply.get()); + zrpc->sendTransaction(QString::fromStdString(params.dump()), [=](const json& reply) { + if (reply["result"].is_null() || reply["result"] != "success") { + error("", "Couldn't understand Response: " + QString::fromStdString(reply.dump())); + } - // And then start monitoring the transaction - addNewTxToWatch( opid, WatchedTx { opid, tx, computed, error} ); - submitted(opid); + QString txid = QString::fromStdString(reply["txid"].get()); + submitted(txid); }, [=](QString errStr) { error("", errStr); @@ -469,58 +430,6 @@ void Controller::executeTransaction(Tx tx, } -void Controller::watchTxStatus() { - if (!zrpc->haveConnection()) - return noConnection(); - - zrpc->fetchOpStatus([=] (const json& reply) { - // There's an array for each item in the status - for (auto& it : reply.get()) { - // If we were watching this Tx and its status became "success", then we'll show a status bar alert - QString id = QString::fromStdString(it["id"]); - if (watchingOps.contains(id)) { - // And if it ended up successful - QString status = QString::fromStdString(it["status"]); - main->loadingLabel->setVisible(false); - - if (status == "success") { - auto txid = QString::fromStdString(it["result"]["txid"]); - - SentTxStore::addToSentTx(watchingOps[id].tx, txid); - - auto wtx = watchingOps[id]; - watchingOps.remove(id); - wtx.completed(id, txid); - - // Refresh balances to show unconfirmed balances - refresh(true); - } else if (status == "failed") { - // If it failed, then we'll actually show a warning. - auto errorMsg = QString::fromStdString(it["error"]["message"]); - - auto wtx = watchingOps[id]; - watchingOps.remove(id); - wtx.error(id, errorMsg); - } - } - - if (watchingOps.isEmpty()) { - txTimer->start(Settings::updateSpeed); - } else { - txTimer->start(Settings::quickUpdateSpeed); - } - } - - // If there is some op that we are watching, then show the loading bar, otherwise hide it - if (watchingOps.empty()) { - main->loadingLabel->setVisible(false); - } else { - main->loadingLabel->setVisible(true); - main->loadingLabel->setToolTip(QString::number(watchingOps.size()) + QObject::tr(" tx computing. This can take several minutes.")); - } - }); -} - void Controller::checkForUpdate(bool silent) { if (!zrpc->haveConnection()) return noConnection(); diff --git a/src/controller.h b/src/controller.h index 5c9c43b..811ac18 100644 --- a/src/controller.h +++ b/src/controller.h @@ -50,17 +50,11 @@ public: void executeStandardUITransaction(Tx tx); void executeTransaction(Tx tx, - const std::function submitted, - const std::function computed, - const std::function error); + const std::function submitted, + const std::function error); void fillTxJsonParams(json& params, Tx tx); - void watchTxStatus(); - - const QMap getWatchingTxns() { return watchingOps; } - void addNewTxToWatch(const QString& newOpid, WatchedTx wtx); - const TxTableModel* getTransactionsModel() { return transactionsTableModel; } void shutdownZcashd(); @@ -70,14 +64,11 @@ public: void createNewZaddr(bool sapling, const std::function& cb) { zrpc->createNewZaddr(sapling, cb); } void createNewTaddr(const std::function& cb) { zrpc->createNewTaddr(cb); } - void validateAddress(QString address, const std::function& cb) { zrpc->validateAddress(address, cb); } + void fetchPrivKey(QString addr, const std::function& cb) { zrpc->fetchPrivKey(addr, cb); } + void fetchAllPrivKeys(const std::function cb) { zrpc->fetchAllPrivKeys(cb); } - void fetchZPrivKey(QString addr, const std::function& cb) { zrpc->fetchZPrivKey(addr, cb); } - void fetchTPrivKey(QString addr, const std::function& cb) { zrpc->fetchTPrivKey(addr, cb); } - void fetchAllPrivKeys(const std::function>)> cb) { zrpc->fetchAllPrivKeys(cb); } - - void importZPrivKey(QString addr, bool rescan, const std::function& cb) { zrpc->importZPrivKey(addr, rescan, cb); } - void importTPrivKey(QString addr, bool rescan, const std::function& cb) { zrpc->importTPrivKey(addr, rescan, cb); } + // void importZPrivKey(QString addr, bool rescan, const std::function& cb) { zrpc->importZPrivKey(addr, rescan, cb); } + // void importTPrivKey(QString addr, bool rescan, const std::function& cb) { zrpc->importTPrivKey(addr, rescan, cb); } QString getDefaultSaplingAddress(); QString getDefaultTAddress(); @@ -86,8 +77,6 @@ private: void refreshBalances(); void refreshTransactions(); - void refreshSentZTrans(); - void refreshReceivedZTrans(QList zaddresses); bool processUnspent (const json& reply, QMap* newBalances, QList* newUtxos); void updateUI (bool anyUnconfirmed); @@ -96,8 +85,6 @@ private: QProcess* ezcashd = nullptr; - QMap watchingOps; - TxTableModel* transactionsTableModel = nullptr; BalancesTableModel* balancesTableModel = nullptr; diff --git a/src/datamodel.cpp b/src/datamodel.cpp index 5004a7d..60990c4 100644 --- a/src/datamodel.cpp +++ b/src/datamodel.cpp @@ -23,6 +23,10 @@ DataModel::~DataModel() { delete taddresses; } +void DataModel::setLatestBlock(int blockHeight) { + this->latestBlock = blockHeight; +} + void DataModel::replaceZaddresses(QList* newZ) { QWriteLocker locker(lock); Q_ASSERT(newZ); diff --git a/src/datamodel.h b/src/datamodel.h index edca668..f69b3d8 100644 --- a/src/datamodel.h +++ b/src/datamodel.h @@ -23,6 +23,9 @@ public: void markAddressUsed(QString address); + void setLatestBlock(int blockHeight); + int getLatestBlock() { return this->latestBlock; } + const QList getAllZAddresses() { QReadLocker locker(lock); return *zaddresses; } const QList getAllTAddresses() { QReadLocker locker(lock); return *taddresses; } const QList getUTXOs() { QReadLocker locker(lock); return *utxos; } @@ -33,7 +36,7 @@ public: DataModel(); ~DataModel(); private: - + int latestBlock; QList* utxos = nullptr; QMap* balances = nullptr; diff --git a/src/liteinterface.cpp b/src/liteinterface.cpp index 82bd0c6..5f74074 100644 --- a/src/liteinterface.cpp +++ b/src/liteinterface.cpp @@ -20,148 +20,70 @@ bool LiteInterface::haveConnection() { return conn != nullptr; } -void LiteInterface::fetchTAddresses(const std::function& cb) { +void LiteInterface::fetchAddresses(const std::function& cb) { if (conn == nullptr) return; - // json payload = { - // {"jsonrpc", "1.0"}, - // {"id", "someid"}, - // {"method", "getaddressesbyaccount"}, - // {"params", {""}} - // }; - - // conn->doRPCWithDefaultErrorHandling(payload, cb); + conn->doRPCWithDefaultErrorHandling("addresses", "", cb); } -void LiteInterface::fetchZAddresses(const std::function& cb) { - if (conn == nullptr) - return; - - // json payload = { - // {"jsonrpc", "1.0"}, - // {"id", "someid"}, - // {"method", "z_listaddresses"}, - // }; - - // conn->doRPCWithDefaultErrorHandling(payload, cb); -} void LiteInterface::fetchUnspent(const std::function& cb) { if (conn == nullptr) return; conn->doRPCWithDefaultErrorHandling("notes", "", cb); - - // json payload = { - // {"jsonrpc", "1.0"}, - // {"id", "someid"}, - // {"method", "listunspent"}, - // {"params", {0}} // Get UTXOs with 0 confirmations as well. - // }; - - // conn->doRPCWithDefaultErrorHandling(payload, cb); } -void LiteInterface::createNewZaddr(bool sapling, const std::function& cb) { +void LiteInterface::createNewZaddr(bool, const std::function& cb) { if (conn == nullptr) return; - // json payload = { - // {"jsonrpc", "1.0"}, - // {"id", "someid"}, - // {"method", "z_getnewaddress"}, - // {"params", { sapling ? "sapling" : "sprout" }}, - // }; - - // conn->doRPCWithDefaultErrorHandling(payload, cb); + conn->doRPCWithDefaultErrorHandling("new", "z", cb); } void LiteInterface::createNewTaddr(const std::function& cb) { if (conn == nullptr) return; - // json payload = { - // {"jsonrpc", "1.0"}, - // {"id", "someid"}, - // {"method", "getnewaddress"}, - // }; - - // conn->doRPCWithDefaultErrorHandling(payload, cb); + conn->doRPCWithDefaultErrorHandling("new", "t", cb); } -void LiteInterface::fetchZPrivKey(QString addr, const std::function& cb) { +void LiteInterface::fetchPrivKey(QString addr, const std::function& cb) { if (conn == nullptr) return; - // json payload = { - // {"jsonrpc", "1.0"}, - // {"id", "someid"}, - // {"method", "z_exportkey"}, - // {"params", { addr.toStdString() }}, - // }; - - // conn->doRPCWithDefaultErrorHandling(payload, cb); + conn->doRPCWithDefaultErrorHandling("export", addr, cb); } -void LiteInterface::fetchTPrivKey(QString addr, const std::function& cb) { - if (conn == nullptr) - return; +// void LiteInterface::importZPrivKey(QString addr, bool rescan, const std::function& cb) { +// if (conn == nullptr) +// return; - // json payload = { - // {"jsonrpc", "1.0"}, - // {"id", "someid"}, - // {"method", "dumpprivkey"}, - // {"params", { addr.toStdString() }}, - // }; +// // json payload = { +// // {"jsonrpc", "1.0"}, +// // {"id", "someid"}, +// // {"method", "z_importkey"}, +// // {"params", { addr.toStdString(), (rescan? "yes" : "no") }}, +// // }; - // conn->doRPCWithDefaultErrorHandling(payload, cb); -} +// // conn->doRPCWithDefaultErrorHandling(payload, cb); +// } -void LiteInterface::importZPrivKey(QString addr, bool rescan, const std::function& cb) { - if (conn == nullptr) - return; - - // json payload = { - // {"jsonrpc", "1.0"}, - // {"id", "someid"}, - // {"method", "z_importkey"}, - // {"params", { addr.toStdString(), (rescan? "yes" : "no") }}, - // }; - - // conn->doRPCWithDefaultErrorHandling(payload, cb); -} +// void LiteInterface::importTPrivKey(QString addr, bool rescan, const std::function& cb) { +// if (conn == nullptr) +// return; -void LiteInterface::importTPrivKey(QString addr, bool rescan, const std::function& cb) { - if (conn == nullptr) - return; - - // json payload = { - // {"jsonrpc", "1.0"}, - // {"id", "someid"}, - // {"method", "importprivkey"}, - // {"params", { addr.toStdString(), (rescan? "yes" : "no") }}, - // }; - - // conn->doRPCWithDefaultErrorHandling(payload, cb); -} - -void LiteInterface::validateAddress(QString address, const std::function& cb) { - if (conn == nullptr) - return; - - // QString method = Settings::isZAddress(address) ? "z_validateaddress" : "validateaddress"; - - // json payload = { - // {"jsonrpc", "1.0"}, - // {"id", "someid"}, - // {"method", method.toStdString() }, - // {"params", { address.toStdString() } }, - // }; +// // json payload = { +// // {"jsonrpc", "1.0"}, +// // {"id", "someid"}, +// // {"method", "importprivkey"}, +// // {"params", { addr.toStdString(), (rescan? "yes" : "no") }}, +// // }; - // conn->doRPCWithDefaultErrorHandling(payload, cb); -} +// // conn->doRPCWithDefaultErrorHandling(payload, cb); +// } void LiteInterface::fetchBalance(const std::function& cb) { if (conn == nullptr) @@ -174,34 +96,15 @@ void LiteInterface::fetchTransactions(const std::function& cb) { if (conn == nullptr) return; - // json payload = { - // {"jsonrpc", "1.0"}, - // {"id", "someid"}, - // {"method", "listtransactions"} - // }; - - // conn->doRPCWithDefaultErrorHandling(payload, cb); + conn->doRPCWithDefaultErrorHandling("list", "", cb); } -void LiteInterface::sendZTransaction(json params, const std::function& cb, +void LiteInterface::sendTransaction(QString params, const std::function& cb, const std::function& err) { if (conn == nullptr) return; - // json payload = { - // {"jsonrpc", "1.0"}, - // {"id", "someid"}, - // {"method", "z_sendmany"}, - // {"params", params} - // }; - - // conn->doRPC(payload, cb, [=] (auto reply, auto parsed) { - // if (!parsed.is_discarded() && !parsed["error"]["message"].is_null()) { - // err(QString::fromStdString(parsed["error"]["message"])); - // } else { - // err(reply->errorString()); - // } - // }); + conn->doRPC("send", params, cb, err); } void LiteInterface::fetchInfo(const std::function& cb, @@ -212,309 +115,17 @@ void LiteInterface::fetchInfo(const std::function& cb, conn->doRPC("info", "", cb, err); } -void LiteInterface::fetchBlockchainInfo(const std::function& cb) { - if (conn == nullptr) - return; - - // json payload = { - // {"jsonrpc", "1.0"}, - // {"id", "someid"}, - // {"method", "getblockchaininfo"} - // }; - - // conn->doRPCIgnoreError(payload, cb); -} - -void LiteInterface::fetchNetSolOps(const std::function cb) { - if (conn == nullptr) - return; - - // json payload = { - // {"jsonrpc", "1.0"}, - // {"id", "someid"}, - // {"method", "getnetworksolps"} - // }; - - // conn->doRPCIgnoreError(payload, [=](const json& reply) { - // qint64 solrate = reply.get(); - // cb(solrate); - // }); -} - -void LiteInterface::fetchMigrationStatus(const std::function& cb) { - if (conn == nullptr) - return; - - // json payload = { - // {"jsonrpc", "1.0"}, - // {"id", "someid"}, - // {"method", "z_getmigrationstatus"}, - // }; - - // conn->doRPCWithDefaultErrorHandling(payload, cb); -} - - -void LiteInterface::setMigrationStatus(bool enabled) { - if (conn == nullptr) - return; - - // json payload = { - // {"jsonrpc", "1.0"}, - // {"id", "someid"}, - // {"method", "z_setmigration"}, - // {"params", {enabled}} - // }; - - // conn->doRPCWithDefaultErrorHandling(payload, [=](json) { - // // Ignore return value. - // }); -} - - /** * Method to get all the private keys for both z and t addresses. It will make 2 batch calls, * combine the result, and call the callback with a single list containing both the t-addr and z-addr * private keys */ -void LiteInterface::fetchAllPrivKeys(const std::function>)> cb) { +void LiteInterface::fetchAllPrivKeys(const std::function cb) { if (conn == nullptr) { // No connection, just return return; } - // // A special function that will call the callback when two lists have been added - // auto holder = new QPair>>(); - // holder->first = 0; // This is the number of times the callback has been called, initialized to 0 - // auto fnCombineTwoLists = [=] (QList> list) { - // // Increment the callback counter - // holder->first++; - - // // Add all - // std::copy(list.begin(), list.end(), std::back_inserter(holder->second)); - - // // And if the caller has been called twice, do the parent callback with the - // // collected list - // if (holder->first == 2) { - // // Sort so z addresses are on top - // std::sort(holder->second.begin(), holder->second.end(), - // [=] (auto a, auto b) { return a.first > b.first; }); - - // cb(holder->second); - // delete holder; - // } - // }; - - // // A utility fn to do the batch calling - // auto fnDoBatchGetPrivKeys = [=](json getAddressPayload, std::string privKeyDumpMethodName) { - // conn->doRPCWithDefaultErrorHandling(getAddressPayload, [=] (json resp) { - // QList addrs; - // for (auto addr : resp.get()) { - // addrs.push_back(QString::fromStdString(addr.get())); - // } - - // // Then, do a batch request to get all the private keys - // conn->doBatchRPC( - // addrs, - // [=] (auto addr) { - // json payload = { - // {"jsonrpc", "1.0"}, - // {"id", "someid"}, - // {"method", privKeyDumpMethodName}, - // {"params", { addr.toStdString() }}, - // }; - // return payload; - // }, - // [=] (QMap* privkeys) { - // QList> allTKeys; - // for (QString addr: privkeys->keys()) { - // allTKeys.push_back( - // QPair( - // addr, - // QString::fromStdString(privkeys->value(addr).get()))); - // } - - // fnCombineTwoLists(allTKeys); - // delete privkeys; - // } - // ); - // }); - // }; - - // // First get all the t and z addresses. - // json payloadT = { - // {"jsonrpc", "1.0"}, - // {"id", "someid"}, - // {"method", "getaddressesbyaccount"}, - // {"params", {""} } - // }; - - // json payloadZ = { - // {"jsonrpc", "1.0"}, - // {"id", "someid"}, - // {"method", "z_listaddresses"} - // }; - - // fnDoBatchGetPrivKeys(payloadT, "dumpprivkey"); - // fnDoBatchGetPrivKeys(payloadZ, "z_exportkey"); -} - -void LiteInterface::fetchOpStatus(const std::function& cb) { - if (conn == nullptr) - return; - - // Make an RPC to load pending operation statues - // json payload = { - // {"jsonrpc", "1.0"}, - // {"id", "someid"}, - // {"method", "z_getoperationstatus"}, - // }; - - // conn->doRPCIgnoreError(payload, cb); -} - -void LiteInterface::fetchReceivedTTrans(QList txids, QList sentZTxs, - const std::function)> txdataFn) { - if (conn == nullptr) - return; - - // Look up all the txids to get the confirmation count for them. - // conn->doBatchRPC(txids, - // [=] (QString txid) { - // json payload = { - // {"jsonrpc", "1.0"}, - // {"id", "senttxid"}, - // {"method", "gettransaction"}, - // {"params", {txid.toStdString()}} - // }; - - // return payload; - // }, - // [=] (QMap* txidList) { - // auto newSentZTxs = sentZTxs; - // // Update the original sent list with the confirmation count - // // TODO: This whole thing is kinda inefficient. We should probably just update the file - // // with the confirmed block number, so we don't have to keep calling gettransaction for the - // // sent items. - // for (TransactionItem& sentTx: newSentZTxs) { - // auto j = txidList->value(sentTx.txid); - // if (j.is_null()) - // continue; - // auto error = j["confirmations"].is_null(); - // if (!error) - // sentTx.confirmations = j["confirmations"].get(); - // } - - // txdataFn(newSentZTxs); - // delete txidList; - // } - // ); + conn->doRPCWithDefaultErrorHandling("export", "", cb); } - -// Refresh received z txs by calling z_listreceivedbyaddress/gettransaction -void LiteInterface::fetchReceivedZTrans(QList zaddrs, const std::function usedAddrFn, - const std::function)> txdataFn) { - if (conn == nullptr) - return; - - - // This method is complicated because z_listreceivedbyaddress only returns the txid, and - // we have to make a follow up call to gettransaction to get details of that transaction. - // Additionally, it has to be done in batches, because there are multiple z-Addresses, - // and each z-Addr can have multiple received txs. - - // 1. For each z-Addr, get list of received txs - // conn->doBatchRPC(zaddrs, - // [=] (QString zaddr) { - // json payload = { - // {"jsonrpc", "1.0"}, - // {"id", "z_lrba"}, - // {"method", "z_listreceivedbyaddress"}, - // {"params", {zaddr.toStdString(), 0}} // Accept 0 conf as well. - // }; - - // return payload; - // }, - // [=] (QMap* zaddrTxids) { - // // Process all txids, removing duplicates. This can happen if the same address - // // appears multiple times in a single tx's outputs. - // QSet txids; - // QMap memos; - // for (auto it = zaddrTxids->constBegin(); it != zaddrTxids->constEnd(); it++) { - // auto zaddr = it.key(); - // for (auto& i : it.value().get()) { - // // Mark the address as used - // usedAddrFn(zaddr); - - // // Filter out change txs - // if (! i["change"].get()) { - // auto txid = QString::fromStdString(i["txid"].get()); - // txids.insert(txid); - - // // Check for Memos - // QString memoBytes = QString::fromStdString(i["memo"].get()); - // if (!memoBytes.startsWith("f600")) { - // QString memo(QByteArray::fromHex( - // QByteArray::fromStdString(i["memo"].get()))); - // if (!memo.trimmed().isEmpty()) - // memos[zaddr + txid] = memo; - // } - // } - // } - // } - - // // 2. For all txids, go and get the details of that txid. - // conn->doBatchRPC(txids.toList(), - // [=] (QString txid) { - // json payload = { - // {"jsonrpc", "1.0"}, - // {"id", "gettx"}, - // {"method", "gettransaction"}, - // {"params", {txid.toStdString()}} - // }; - - // return payload; - // }, - // [=] (QMap* txidDetails) { - // QList txdata; - - // // Combine them both together. For every zAddr's txid, get the amount, fee, confirmations and time - // for (auto it = zaddrTxids->constBegin(); it != zaddrTxids->constEnd(); it++) { - // for (auto& i : it.value().get()) { - // // Filter out change txs - // if (i["change"].get()) - // continue; - - // auto zaddr = it.key(); - // auto txid = QString::fromStdString(i["txid"].get()); - - // // Lookup txid in the map - // auto txidInfo = txidDetails->value(txid); - - // qint64 timestamp; - // if (txidInfo.find("time") != txidInfo.end()) { - // timestamp = txidInfo["time"].get(); - // } else { - // timestamp = txidInfo["blocktime"].get(); - // } - - // auto amount = i["amount"].get(); - // auto confirmations = static_cast(txidInfo["confirmations"].get()); - - // TransactionItem tx{ QString("receive"), timestamp, zaddr, txid, amount, - // confirmations, "", memos.value(zaddr + txid, "") }; - // txdata.push_front(tx); - // } - // } - - // txdataFn(txdata); - - // // Cleanup both responses; - // delete zaddrTxids; - // delete txidDetails; - // } - // ); - // } - // ); -} diff --git a/src/liteinterface.h b/src/liteinterface.h index 1e8b243..6df9662 100644 --- a/src/liteinterface.h +++ b/src/liteinterface.h @@ -7,15 +7,24 @@ using json = nlohmann::json; +// Since each transaction can contain multiple outputs, we separate them out individually +// into a struct with address, amount, memo +struct TransactionItemDetail { + QString address; + qint64 amount; + QString memo; +}; + +// Represents a row in the transactions table. Note that each transaction can contain +// multiple addresses (i.e., Multiple TransctionItemDetail) struct TransactionItem { QString type; qint64 datetime; QString address; QString txid; - double amount; long confirmations; - QString fromAddr; - QString memo; + + QList items; }; @@ -30,37 +39,23 @@ public: void fetchUnspent (const std::function& cb); void fetchTransactions (const std::function& cb); - void fetchZAddresses (const std::function& cb); - void fetchTAddresses (const std::function& cb); - - void fetchReceivedZTrans(QList zaddrs, const std::function usedAddrFn, - const std::function)> txdataFn); - void fetchReceivedTTrans(QList txids, QList sentZtxs, - const std::function)> txdataFn); + void fetchAddresses (const std::function& cb); void fetchInfo(const std::function& cb, const std::function& err); - void fetchBlockchainInfo(const std::function& cb); - void fetchNetSolOps(const std::function cb); - void fetchOpStatus(const std::function& cb); - - void fetchMigrationStatus(const std::function& cb); - void setMigrationStatus(bool enabled); - + void fetchBalance(const std::function& cb); void createNewZaddr(bool sapling, const std::function& cb); void createNewTaddr(const std::function& cb); - void fetchZPrivKey(QString addr, const std::function& cb); - void fetchTPrivKey(QString addr, const std::function& cb); - void importZPrivKey(QString addr, bool rescan, const std::function& cb); - void importTPrivKey(QString addr, bool rescan, const std::function& cb); - void validateAddress(QString address, const std::function& cb); - - void fetchAllPrivKeys(const std::function>)>); + void fetchPrivKey(QString addr, const std::function& cb); + void fetchAllPrivKeys(const std::function); - void sendZTransaction(json params, const std::function& cb, const std::function& err); + //void importZPrivKey(QString addr, bool rescan, const std::function& cb); + //void importTPrivKey(QString addr, bool rescan, const std::function& cb); + + void sendTransaction(QString params, const std::function& cb, const std::function& err); private: Connection* conn = nullptr; diff --git a/src/main.cpp b/src/main.cpp index a10d9ac..bc93ab5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -147,17 +147,9 @@ public: // Command line parser QCommandLineParser parser; - parser.setApplicationDescription("Shielded desktop wallet and embedded full node for Zcash"); + parser.setApplicationDescription("Shielded desktop light wallet for Zcash"); parser.addHelpOption(); - // A boolean option for running it headless - QCommandLineOption headlessOption(QStringList() << "headless", "Running it via GUI."); - parser.addOption(headlessOption); - - // No embedded will disable the embedded zcashd node - QCommandLineOption noembeddedOption(QStringList() << "no-embedded", "Disable embedded zcashd"); - parser.addOption(noembeddedOption); - // Add an option to specify the conf file QCommandLineOption confOption(QStringList() << "conf", "Use the zcash.conf specified instead of looking for the default one.", "confFile"); @@ -177,8 +169,8 @@ public: return 0; } - QCoreApplication::setOrganizationName("zec-qt-wallet-org"); - QCoreApplication::setApplicationName("zec-qt-wallet"); + QCoreApplication::setOrganizationName("zecwallet-org"); + QCoreApplication::setApplicationName("zecwallet"); QString locale = QLocale::system().name(); locale.truncate(locale.lastIndexOf('_')); // Get the language code @@ -214,20 +206,15 @@ public: exit(0); } - // Check for embedded option - if (parser.isSet(noembeddedOption)) { - Settings::getInstance()->setUseEmbedded(false); - } else { - Settings::getInstance()->setUseEmbedded(true); - } - + Settings::getInstance()->setUseEmbedded(false); + // Check to see if a conf location was specified if (parser.isSet(confOption)) { Settings::getInstance()->setUsingZcashConf(parser.value(confOption)); } w = new MainWindow(); - w->setWindowTitle("ZecWallet FullNode v" + QString(APP_VERSION)); + w->setWindowTitle("Zecwallet v" + QString(APP_VERSION)); // If there was a payment URI on the command line, pay it if (parser.positionalArguments().length() > 0) { @@ -246,14 +233,9 @@ public: a.installEventFilter(w); // Check if starting headless - if (parser.isSet(headlessOption)) { - Settings::getInstance()->setHeadless(true); - a.setQuitOnLastWindowClosed(false); - } else { - Settings::getInstance()->setHeadless(false); - w->show(); - } - + Settings::getInstance()->setHeadless(false); + w->show(); + return QApplication::exec(); } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index fd49487..448e1d7 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1,7 +1,6 @@ #include "mainwindow.h" #include "addressbook.h" #include "viewalladdresses.h" -#include "validateaddress.h" #include "ui_mainwindow.h" #include "ui_mobileappconnector.h" #include "ui_addressbook.h" @@ -9,15 +8,12 @@ #include "ui_privkey.h" #include "ui_about.h" #include "ui_settings.h" -#include "ui_turnstile.h" #include "ui_turnstileprogress.h" #include "ui_viewalladdresses.h" -#include "ui_validateaddress.h" #include "controller.h" #include "balancestablemodel.h" #include "settings.h" #include "version.h" -#include "senttxstore.h" #include "connection.h" #include "requestdialog.h" #include "websockets.h" @@ -85,9 +81,6 @@ MainWindow::MainWindow(QWidget *parent) : payZcashURI(); }); - // Import Private Key - QObject::connect(ui->actionImport_Private_Key, &QAction::triggered, this, &MainWindow::importPrivKey); - // Export All Private Keys QObject::connect(ui->actionExport_All_Private_Keys, &QAction::triggered, this, &MainWindow::exportAllKeys); @@ -97,13 +90,6 @@ MainWindow::MainWindow(QWidget *parent) : // Export transactions QObject::connect(ui->actionExport_transactions, &QAction::triggered, this, &MainWindow::exportTransactions); - // Z-board seems to have been abandoned - // z-Board.net - // QObject::connect(ui->actionz_board_net, &QAction::triggered, this, &MainWindow::postToZBoard); - - // Validate Address - QObject::connect(ui->actionValidate_Address, &QAction::triggered, this, &MainWindow::validateAddress); - // Connect mobile app QObject::connect(ui->actionConnect_Mobile_App, &QAction::triggered, this, [=] () { if (rpc->getConnection() == nullptr) @@ -276,17 +262,6 @@ void MainWindow::setupSettingsModal() { Settings::getInstance()->setSaveZtxs(checked); }); - // Setup clear button - QObject::connect(settings.btnClearSaved, &QCheckBox::clicked, [=]() { - if (QMessageBox::warning(this, "Clear saved history?", - "Shielded z-Address transactions are stored locally in your wallet, outside zcashd. You may delete this saved information safely any time for your privacy.\nDo you want to delete the saved shielded transactions now?", - QMessageBox::Yes, QMessageBox::Cancel)) { - SentTxStore::deleteHistory(); - // Reload after the clear button so existing txs disappear - rpc->refresh(true); - } - }); - // Setup theme combo int theme_index = settings.comboBoxTheme->findText(Settings::getInstance()->get_theme_name(), Qt::MatchExactly); settings.comboBoxTheme->setCurrentIndex(theme_index); @@ -460,73 +435,30 @@ void MainWindow::donate() { ui->tabWidget->setCurrentIndex(1); } -/** - * Validate an address - */ -void MainWindow::validateAddress() { - // Make sure everything is up and running - if (!getRPC() || !getRPC()->getConnection()) - return; - - // First thing is ask the user for an address - bool ok; - auto address = QInputDialog::getText(this, tr("Enter Address to validate"), - tr("Transparent or Shielded Address:") + QString(" ").repeated(140), // Pad the label so the dialog box is wide enough - QLineEdit::Normal, "", &ok); - if (!ok) - return; - - getRPC()->validateAddress(address, [=] (json props) { - QDialog d(this); - Ui_ValidateAddress va; - va.setupUi(&d); - Settings::saveRestore(&d); - Settings::saveRestoreTableHeader(va.tblProps, &d, "validateaddressprops"); - va.tblProps->horizontalHeader()->setStretchLastSection(true); - - va.lblAddress->setText(address); - - QList> propsList; - for (auto it = props.begin(); it != props.end(); it++) { - - propsList.append( - QPair( - QString::fromStdString(it.key()), QString::fromStdString(it.value().dump())) - ); - } - - ValidateAddressesModel model(va.tblProps, propsList); - va.tblProps->setModel(&model); - - d.exec(); - }); - -} - -void MainWindow::doImport(QList* keys) { - if (rpc->getConnection() == nullptr) { - // No connection, just return - return; - } +// void MainWindow::doImport(QList* keys) { +// if (rpc->getConnection() == nullptr) { +// // No connection, just return +// return; +// } - if (keys->isEmpty()) { - delete keys; - ui->statusBar->showMessage(tr("Private key import rescan finished")); - return; - } +// if (keys->isEmpty()) { +// delete keys; +// ui->statusBar->showMessage(tr("Private key import rescan finished")); +// return; +// } - // Pop the first key - QString key = keys->first(); - keys->pop_front(); - bool rescan = keys->isEmpty(); +// // Pop the first key +// QString key = keys->first(); +// keys->pop_front(); +// bool rescan = keys->isEmpty(); - if (key.startsWith("SK") || - key.startsWith("secret")) { // Z key - rpc->importZPrivKey(key, rescan, [=] (auto) { this->doImport(keys); }); - } else { - rpc->importTPrivKey(key, rescan, [=] (auto) { this->doImport(keys); }); - } -} +// if (key.startsWith("SK") || +// key.startsWith("secret")) { // Z key +// rpc->importZPrivKey(key, rescan, [=] (auto) { this->doImport(keys); }); +// } else { +// rpc->importTPrivKey(key, rescan, [=] (auto) { this->doImport(keys); }); +// } +// } // Callback invoked when the RPC has finished loading all the balances, and the UI @@ -619,50 +551,50 @@ void MainWindow::payZcashURI(QString uri, QString myAddr) { } -void MainWindow::importPrivKey() { - QDialog d(this); - Ui_PrivKey pui; - pui.setupUi(&d); - Settings::saveRestore(&d); - - pui.buttonBox->button(QDialogButtonBox::Save)->setVisible(false); - pui.helpLbl->setText(QString() % - tr("Please paste your private keys (z-Addr or t-Addr) here, one per line") % ".\n" % - tr("The keys will be imported into your connected zcashd node")); - - if (d.exec() == QDialog::Accepted && !pui.privKeyTxt->toPlainText().trimmed().isEmpty()) { - auto rawkeys = pui.privKeyTxt->toPlainText().trimmed().split("\n"); - - QList keysTmp; - // Filter out all the empty keys. - std::copy_if(rawkeys.begin(), rawkeys.end(), std::back_inserter(keysTmp), [=] (auto key) { - return !key.startsWith("#") && !key.trimmed().isEmpty(); - }); - - auto keys = new QList(); - std::transform(keysTmp.begin(), keysTmp.end(), std::back_inserter(*keys), [=](auto key) { - return key.trimmed().split(" ")[0]; - }); - - // Special case. - // Sometimes, when importing from a paperwallet or such, the key is split by newlines, and might have - // been pasted like that. So check to see if the whole thing is one big private key - if (Settings::getInstance()->isValidSaplingPrivateKey(keys->join(""))) { - auto multiline = keys; - keys = new QList(); - keys->append(multiline->join("")); - delete multiline; - } - - // Start the import. The function takes ownership of keys - QTimer::singleShot(1, [=]() {doImport(keys);}); - - // Show the dialog that keys will be imported. - QMessageBox::information(this, - "Imported", tr("The keys were imported. It may take several minutes to rescan the blockchain. Until then, functionality may be limited"), - QMessageBox::Ok); - } -} +// void MainWindow::importPrivKey() { +// QDialog d(this); +// Ui_PrivKey pui; +// pui.setupUi(&d); +// Settings::saveRestore(&d); + +// pui.buttonBox->button(QDialogButtonBox::Save)->setVisible(false); +// pui.helpLbl->setText(QString() % +// tr("Please paste your private keys (z-Addr or t-Addr) here, one per line") % ".\n" % +// tr("The keys will be imported into your connected zcashd node")); + +// if (d.exec() == QDialog::Accepted && !pui.privKeyTxt->toPlainText().trimmed().isEmpty()) { +// auto rawkeys = pui.privKeyTxt->toPlainText().trimmed().split("\n"); + +// QList keysTmp; +// // Filter out all the empty keys. +// std::copy_if(rawkeys.begin(), rawkeys.end(), std::back_inserter(keysTmp), [=] (auto key) { +// return !key.startsWith("#") && !key.trimmed().isEmpty(); +// }); + +// auto keys = new QList(); +// std::transform(keysTmp.begin(), keysTmp.end(), std::back_inserter(*keys), [=](auto key) { +// return key.trimmed().split(" ")[0]; +// }); + +// // Special case. +// // Sometimes, when importing from a paperwallet or such, the key is split by newlines, and might have +// // been pasted like that. So check to see if the whole thing is one big private key +// if (Settings::getInstance()->isValidSaplingPrivateKey(keys->join(""))) { +// auto multiline = keys; +// keys = new QList(); +// keys->append(multiline->join("")); +// delete multiline; +// } + +// // Start the import. The function takes ownership of keys +// QTimer::singleShot(1, [=]() {doImport(keys);}); + +// // Show the dialog that keys will be imported. +// QMessageBox::information(this, +// "Imported", tr("The keys were imported. It may take several minutes to rescan the blockchain. Until then, functionality may be limited"), +// QMessageBox::Ok); +// } +// } /** * Export transaction history into a CSV file @@ -763,13 +695,20 @@ void MainWindow::exportKeys(QString addr) { // Call the API auto isDialogAlive = std::make_shared(true); - auto fnUpdateUIWithKeys = [=](QList> privKeys) { + auto fnUpdateUIWithKeys = [=](json reply) { // Check to see if we are still showing. if (! *(isDialogAlive.get()) ) return; + if (reply.is_discarded() || !reply.is_array()) { + pui.privKeyTxt->setPlainText(tr("Error loading private keys")); + pui.buttonBox->button(QDialogButtonBox::Save)->setEnabled(false); + + return; + } + QString allKeysTxt; - for (auto keypair : privKeys) { - allKeysTxt = allKeysTxt % keypair.second % " # addr=" % keypair.first % "\n"; + for (auto i : reply.get()) { + allKeysTxt = allKeysTxt % QString::fromStdString(i["private_key"]) % " # addr=" % QString::fromStdString(i["address"]) % "\n"; } pui.privKeyTxt->setPlainText(allKeysTxt); @@ -779,19 +718,8 @@ void MainWindow::exportKeys(QString addr) { if (allKeys) { rpc->fetchAllPrivKeys(fnUpdateUIWithKeys); } - else { - auto fnAddKey = [=](json key) { - QList> singleAddrKey; - singleAddrKey.push_back(QPair(addr, QString::fromStdString(key.get()))); - fnUpdateUIWithKeys(singleAddrKey); - }; - - if (Settings::getInstance()->isZAddress(addr)) { - rpc->fetchZPrivKey(addr, fnAddKey); - } - else { - rpc->fetchTPrivKey(addr, fnAddKey); - } + else { + rpc->fetchPrivKey(addr, fnUpdateUIWithKeys); } d.exec(); @@ -980,7 +908,7 @@ void MainWindow::setupTransactionsTab() { void MainWindow::addNewZaddr(bool sapling) { rpc->createNewZaddr(sapling, [=] (json reply) { - QString addr = QString::fromStdString(reply.get()); + QString addr = QString::fromStdString(reply.get()[0]); // Make sure the RPC class reloads the z-addrs for future use rpc->refreshAddresses(); @@ -1031,7 +959,7 @@ std::function MainWindow::addZAddrsToComboList(bool sapling) { void MainWindow::setupReceiveTab() { auto addNewTAddr = [=] () { rpc->createNewTaddr([=] (json reply) { - QString addr = QString::fromStdString(reply.get()); + QString addr = QString::fromStdString(reply.get()[0]); // Make sure the RPC class reloads the t-addrs for future use rpc->refreshAddresses(); diff --git a/src/mainwindow.h b/src/mainwindow.h index 4012fb9..ca6432d 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -18,8 +18,7 @@ using json = nlohmann::json; struct ToFields { QString addr; double amount; - QString txtMemo; - QString encodedMemo; + QString memo; }; // Struct used to represent a Transaction. @@ -58,8 +57,6 @@ public: void balancesReady(); void payZcashURI(QString uri = "", QString myAddr = ""); - void validateAddress(); - void updateLabels(); void updateTAddrCombo(bool checked); void updateFromCombo(); @@ -120,7 +117,6 @@ private: void donate(); void addressBook(); - //void postToZBoard(); void importPrivKey(); void exportAllKeys(); void exportKeys(QString addr = ""); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 44287c1..b578c02 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -1062,7 +1062,6 @@ - @@ -1084,10 +1083,6 @@ &Apps - - - - @@ -1131,19 +1126,6 @@ Check github.com for &updates - - - Sapling &turnstile - - - Ctrl+A, Ctrl+T - - - - - &Import private key - - &Export all private keys @@ -1195,11 +1177,6 @@ File a bug... - - - Validate Address - - diff --git a/src/recurring.cpp b/src/recurring.cpp index 501f727..304ad0e 100644 --- a/src/recurring.cpp +++ b/src/recurring.cpp @@ -137,7 +137,7 @@ RecurringPaymentInfo* Recurring::getNewRecurringFromTx(QWidget* parent, MainWind // Default is USD ui.lblAmt->setText(Settings::getUSDFromZecAmount(tx.toAddrs[0].amount)); - ui.txtMemo->setPlainText(tx.toAddrs[0].txtMemo); + ui.txtMemo->setPlainText(tx.toAddrs[0].memo); ui.txtMemo->setEnabled(false); } @@ -199,7 +199,7 @@ RecurringPaymentInfo* Recurring::getNewRecurringFromTx(QWidget* parent, MainWind void Recurring::updateInfoWithTx(RecurringPaymentInfo* r, Tx tx) { r->toAddr = tx.toAddrs[0].addr; - r->memo = tx.toAddrs[0].txtMemo; + r->memo = tx.toAddrs[0].memo; r->fromAddr = tx.fromAddr; if (r->currency.isEmpty() || r->currency == "USD") { r->currency = "USD"; @@ -485,7 +485,7 @@ void Recurring::executeRecurringPayment(MainWindow* main, RecurringPaymentInfo r if (paymentNumbers.size() > 1) amt *= paymentNumbers.size(); - tx.toAddrs.append(ToFields { rpi.toAddr, amt, rpi.memo, rpi.memo.toUtf8().toHex() }); + tx.toAddrs.append(ToFields { rpi.toAddr, amt, rpi.memo }); // To prevent some weird race conditions, we immediately mark the payment as paid. // If something goes wrong, we'll get the error callback below, and the status will be @@ -514,10 +514,8 @@ void Recurring::executeRecurringPayment(MainWindow* main, RecurringPaymentInfo r * Execute a send Tx */ void Recurring::doSendTx(MainWindow* mainwindow, Tx tx, std::function cb) { - mainwindow->getRPC()->executeTransaction(tx, [=] (QString opid) { - mainwindow->ui->statusBar->showMessage(QObject::tr("Computing Recurring Tx: ") % opid); - }, - [=] (QString /*opid*/, QString txid) { + mainwindow->getRPC()->executeTransaction(tx, + [=] (QString txid) { mainwindow->ui->statusBar->showMessage(Settings::txidStatusMessage + " " + txid); cb(txid, ""); }, diff --git a/src/sendtab.cpp b/src/sendtab.cpp index 62a0226..ddbf6f3 100644 --- a/src/sendtab.cpp +++ b/src/sendtab.cpp @@ -521,7 +521,7 @@ Tx MainWindow::createTxFromSendPage() { totalAmt += amt; QString memo = ui->sendToWidgets->findChild(QString("MemoTxt") % QString::number(i+1))->text().trimmed(); - tx.toAddrs.push_back( ToFields{addr, amt, memo, memo.toUtf8().toHex()} ); + tx.toAddrs.push_back( ToFields{addr, amt, memo} ); } if (Settings::getInstance()->getAllowCustomFees()) { @@ -550,7 +550,7 @@ Tx MainWindow::createTxFromSendPage() { if (Settings::getDecimalString(change) != "0") { QString changeMemo = tr("Change from ") + tx.fromAddr; - tx.toAddrs.push_back(ToFields{ *saplingAddr, change, changeMemo, changeMemo.toUtf8().toHex() }); + tx.toAddrs.push_back(ToFields{ *saplingAddr, change, changeMemo }); } } } @@ -649,11 +649,11 @@ bool MainWindow::confirmTx(Tx tx, RecurringPaymentInfo* rpi) { confirm.gridLayout->addWidget(AmtUSD, row, 2, 1, 1); // Memo - if (Settings::isZAddress(toAddr.addr) && !toAddr.txtMemo.isEmpty()) { + if (Settings::isZAddress(toAddr.addr) && !toAddr.memo.isEmpty()) { row++; auto Memo = new QLabel(confirm.sendToAddrs); Memo->setObjectName(QStringLiteral("Memo") % QString::number(i + 1)); - Memo->setText(toAddr.txtMemo); + Memo->setText(toAddr.memo); QFont font1 = Addr->font(); font1.setPointSize(font1.pointSize() - 1); Memo->setFont(font1); @@ -769,12 +769,7 @@ void MainWindow::sendButton() { // And send the Tx rpc->executeTransaction(tx, - // Submitted - [=] (QString opid) { - ui->statusBar->showMessage(tr("Computing Tx: ") % opid); - }, - // Accepted - [=] (QString, QString txid) { + [=] (QString txid) { ui->statusBar->showMessage(Settings::txidStatusMessage + " " + txid); // If this was a recurring payment, update the payment with the info diff --git a/src/senttxstore.cpp b/src/senttxstore.cpp deleted file mode 100644 index 5341664..0000000 --- a/src/senttxstore.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include "senttxstore.h" -#include "settings.h" - -/// Get the location of the app data file to be written. -QString SentTxStore::writeableFile() { - auto filename = QStringLiteral("senttxstore.dat"); - - auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); - if (!dir.exists()) - QDir().mkpath(dir.absolutePath()); - - if (Settings::getInstance()->isTestnet()) { - return dir.filePath("testnet-" % filename); - } else { - return dir.filePath(filename); - } -} - -// delete the sent history. -void SentTxStore::deleteHistory() { - QFile data(writeableFile()); - data.remove(); - data.close(); -} - -QList SentTxStore::readSentTxFile() { - QFile data(writeableFile()); - if (!data.exists()) { - return QList(); - } - - QJsonDocument jsonDoc; - - data.open(QFile::ReadOnly); - jsonDoc = QJsonDocument::fromJson(data.readAll()); - data.close(); - - QList items; - - for (auto i : jsonDoc.array()) { - auto sentTx = i.toObject(); - TransactionItem t{"send", (qint64)sentTx["datetime"].toVariant().toLongLong(), - sentTx["address"].toString(), - sentTx["txid"].toString(), - sentTx["amount"].toDouble() + sentTx["fee"].toDouble(), - 0, sentTx["from"].toString(), ""}; - items.push_back(t); - } - - return items; -} - -void SentTxStore::addToSentTx(Tx tx, QString txid) { - // Save transactions only if the settings are allowed - if (!Settings::getInstance()->getSaveZtxs()) - return; - - // Also, only store outgoing txs where the from address is a z-Addr. Else, regular zcashd - // stores it just fine - if (! Settings::isZAddress(tx.fromAddr)) - return; - - QFile data(writeableFile()); - QJsonDocument jsonDoc; - - // If data doesn't exist, then create a blank one - if (!data.exists()) { - QJsonArray a; - jsonDoc.setArray(a); - - QFile newFile(writeableFile()); - newFile.open(QFile::WriteOnly); - newFile.write(jsonDoc.toJson()); - newFile.close(); - } else { - data.open(QFile::ReadOnly); - jsonDoc = QJsonDocument().fromJson(data.readAll()); - data.close(); - } - - // Calculate total amount in this tx - double totalAmount = 0; - for (auto i : tx.toAddrs) { - totalAmount += i.amount; - } - - QString toAddresses; - if (tx.toAddrs.length() == 1) { - toAddresses = tx.toAddrs[0].addr; - } else { - // Concatenate all the toAddresses - for (auto a : tx.toAddrs) { - toAddresses += a.addr % "(" % Settings::getZECDisplayFormat(a.amount) % ") "; - } - } - - auto list = jsonDoc.array(); - QJsonObject txItem; - txItem["type"] = "sent"; - txItem["from"] = tx.fromAddr; - txItem["datetime"] = QDateTime::currentMSecsSinceEpoch() / (qint64)1000; - txItem["address"] = toAddresses; - txItem["txid"] = txid; - txItem["amount"] = -totalAmount; - txItem["fee"] = -tx.fee; - list.append(txItem); - - jsonDoc.setArray(list); - - QFile writer(writeableFile()); - if (writer.open(QFile::WriteOnly | QFile::Truncate)) { - writer.write(jsonDoc.toJson()); - } - writer.close(); -} diff --git a/src/senttxstore.h b/src/senttxstore.h deleted file mode 100644 index 9093a00..0000000 --- a/src/senttxstore.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef SENTTXSTORE_H -#define SENTTXSTORE_H - -#include "precompiled.h" -#include "mainwindow.h" -#include "controller.h" - -class SentTxStore { -public: - static void deleteHistory(); - - static QList readSentTxFile(); - static void addToSentTx(Tx tx, QString txid); - -private: - static QString writeableFile(); - -}; - -#endif // SENTTXSTORE_H diff --git a/src/turnstileprogress.ui b/src/turnstileprogress.ui deleted file mode 100644 index d52b72e..0000000 --- a/src/turnstileprogress.ui +++ /dev/null @@ -1,192 +0,0 @@ - - - TurnstileProgress - - - - 0 - 0 - 400 - 300 - - - - Turnstile Migration Progress - - - - - - From - - - - - - - To - - - - - - - From Address - - - - - - - 4 / 12 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - Please ensure you have your wallet.dat backed up! - - - true - - - - - - - Next Transaction in 4 hours - - - - - - - 33 - - - - - - - Qt::Horizontal - - - - - - - Migration Progress - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Close|QDialogButtonBox::Discard - - - false - - - - - - - - 0 - 0 - - - - TextLabel - - - Qt::AlignCenter - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Horizontal - - - - - - - To Address - - - - - - - Qt::Horizontal - - - - - - - - - buttonBox - accepted() - TurnstileProgress - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - TurnstileProgress - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/src/txtablemodel.cpp b/src/txtablemodel.cpp index 395d82f..af389b0 100644 --- a/src/txtablemodel.cpp +++ b/src/txtablemodel.cpp @@ -9,34 +9,20 @@ TxTableModel::TxTableModel(QObject *parent) TxTableModel::~TxTableModel() { delete modeldata; - delete tTrans; - delete zsTrans; - delete zrTrans; -} - -void TxTableModel::addZSentData(const QList& data) { - delete zsTrans; - zsTrans = new QList(); - std::copy(data.begin(), data.end(), std::back_inserter(*zsTrans)); - - updateAllData(); -} - -void TxTableModel::addZRecvData(const QList& data) { - delete zrTrans; - zrTrans = new QList(); - std::copy(data.begin(), data.end(), std::back_inserter(*zrTrans)); - - updateAllData(); } +void TxTableModel::replaceData(const QList& data) { + delete modeldata; + modeldata = new QList(); -void TxTableModel::addTData(const QList& data) { - delete tTrans; - tTrans = new QList(); - std::copy(data.begin(), data.end(), std::back_inserter(*tTrans)); + // Copy over the data and sort it + std::copy(data.begin(), data.end(), std::back_inserter(*modeldata)); + std::sort(modeldata->begin(), modeldata->end(), [=] (auto a, auto b) { + return a.datetime > b.datetime; // reverse sort + }); - updateAllData(); + dataChanged(index(0, 0), index(modeldata->size()-1, columnCount(index(0,0))-1)); + layoutChanged(); } bool TxTableModel::exportToCsv(QString fileName) const { @@ -61,8 +47,9 @@ bool TxTableModel::exportToCsv(QString fileName) const { for (int col = 0; col < headers.length(); col++) { out << "\"" << data(index(row, col), Qt::DisplayRole).toString() << "\","; } + // Memo - out << "\"" << modeldata->at(row).memo << "\""; + out << "\"" << this->getMemo(row) << "\""; out << endl; } @@ -70,25 +57,6 @@ bool TxTableModel::exportToCsv(QString fileName) const { return true; } -void TxTableModel::updateAllData() { - auto newmodeldata = new QList(); - - if (tTrans != nullptr) std::copy( tTrans->begin(), tTrans->end(), std::back_inserter(*newmodeldata)); - if (zsTrans != nullptr) std::copy(zsTrans->begin(), zsTrans->end(), std::back_inserter(*newmodeldata)); - if (zrTrans != nullptr) std::copy(zrTrans->begin(), zrTrans->end(), std::back_inserter(*newmodeldata)); - - // Sort by reverse time - std::sort(newmodeldata->begin(), newmodeldata->end(), [=] (auto a, auto b) { - return a.datetime > b.datetime; // reverse sort - }); - - // And then swap out the modeldata with the new one. - delete modeldata; - modeldata = newmodeldata; - - dataChanged(index(0, 0), index(modeldata->size()-1, columnCount(index(0,0))-1)); - layoutChanged(); -} int TxTableModel::rowCount(const QModelIndex&) const { @@ -135,18 +103,31 @@ void TxTableModel::updateAllData() { } case Column::Time: return QDateTime::fromMSecsSinceEpoch(dat.datetime * (qint64)1000).toLocalTime().toString(); case Column::Confirmations: return QString::number(dat.confirmations); - case Column::Amount: return Settings::getZECDisplayFormat(dat.amount); + case Column::Amount: { + // Sum up all the amounts + qint64 total = 0; + for (int i=0; i < dat.items.length(); i++) { + total += dat.items[i].amount; + } + return Settings::getZECDisplayFormat(total); + } } } if (role == Qt::ToolTipRole) { switch (index.column()) { case Column::Type: { - if (dat.memo.startsWith("zcash:")) { - return Settings::paymentURIPretty(Settings::parseURI(dat.memo)); + // If there are multiple memos, then mark them as such + if (dat.items.length() == 1) { + auto memo = dat.items[0].memo; + if (memo.startsWith("zcash:")) { + return Settings::paymentURIPretty(Settings::parseURI(memo)); + } else { + return modeldata->at(index.row()).type + + (memo.isEmpty() ? "" : " tx memo: \"" + memo + "\""); + } } else { - return modeldata->at(index.row()).type + - (dat.memo.isEmpty() ? "" : " tx memo: \"" + dat.memo + "\""); + return "Multiple"; } } case Column::Address: { @@ -158,21 +139,33 @@ void TxTableModel::updateAllData() { } case Column::Time: return QDateTime::fromMSecsSinceEpoch(modeldata->at(index.row()).datetime * (qint64)1000).toLocalTime().toString(); case Column::Confirmations: return QString("%1 Network Confirmations").arg(QString::number(dat.confirmations)); - case Column::Amount: return Settings::getInstance()->getUSDFromZecAmount(modeldata->at(index.row()).amount); + case Column::Amount: { + // Sum up all the amounts + qint64 total = 0; + for (int i=0; i < dat.items.length(); i++) { + total += dat.items[i].amount; + } + return Settings::getInstance()->getUSDFromZecAmount(total); } + } } if (role == Qt::DecorationRole && index.column() == 0) { - if (!dat.memo.isEmpty()) { - // If the memo is a Payment URI, then show a payment request icon - if (dat.memo.startsWith("zcash:")) { - QIcon icon(":/icons/res/paymentreq.gif"); - return QVariant(icon.pixmap(16, 16)); - } else { - // Return the info pixmap to indicate memo - QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation); - return QVariant(icon.pixmap(16, 16)); - } + bool hasMemo = false; + for (int i=0; i < dat.items.length(); i++) { + if (!dat.items[i].memo.isEmpty()) { + hasMemo = true; + } + } + + // If the memo is a Payment URI, then show a payment request icon + if (dat.items.length() == 1 && dat.items[0].memo.startsWith("zcash:")) { + QIcon icon(":/icons/res/paymentreq.gif"); + return QVariant(icon.pixmap(16, 16)); + } else if (hasMemo) { + // Return the info pixmap to indicate memo + QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation); + return QVariant(icon.pixmap(16, 16)); } else { // Empty pixmap to make it align QPixmap p(16, 16); @@ -208,7 +201,21 @@ QString TxTableModel::getTxId(int row) const { } QString TxTableModel::getMemo(int row) const { - return modeldata->at(row).memo; + auto dat = modeldata->at(row); + bool hasMemo = false; + for (int i=0; i < dat.items.length(); i++) { + if (!dat.items[i].memo.isEmpty()) { + hasMemo = true; + } + } + + if (dat.items.length() == 1) { + return dat.items[0].memo; + } else if (hasMemo) { + return "(Multiple)"; + } else { + return ""; + } } qint64 TxTableModel::getConfirmations(int row) const { @@ -228,5 +235,11 @@ QString TxTableModel::getType(int row) const { } QString TxTableModel::getAmt(int row) const { - return Settings::getDecimalString(modeldata->at(row).amount); + auto dat = modeldata->at(row); + + qint64 total = 0; + for (int i=0; i < dat.items.length(); i++) { + total += dat.items[i].amount; + } + return Settings::getDecimalString(total); } diff --git a/src/txtablemodel.h b/src/txtablemodel.h index f295bc5..8e60ea7 100644 --- a/src/txtablemodel.h +++ b/src/txtablemodel.h @@ -20,9 +20,7 @@ public: Amount = 4 }; - void addTData (const QList& data); - void addZSentData(const QList& data); - void addZRecvData(const QList& data); + void replaceData (const QList& data); QString getTxId(int row) const; QString getMemo(int row) const; @@ -40,12 +38,6 @@ public: QVariant headerData(int section, Qt::Orientation orientation, int role) const; private: - void updateAllData(); - - QList* tTrans = nullptr; - QList* zrTrans = nullptr; // Z received - QList* zsTrans = nullptr; // Z sent - QList* modeldata = nullptr; QList headers; diff --git a/src/validateaddress.cpp b/src/validateaddress.cpp deleted file mode 100644 index d82e82e..0000000 --- a/src/validateaddress.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "validateaddress.h" - - -ValidateAddressesModel::ValidateAddressesModel(QTableView *parent, QList> props) - : QAbstractTableModel(parent) { - headers << tr("Property") << tr("Value"); - this->props = props; -} - - -int ValidateAddressesModel::rowCount(const QModelIndex&) const { - return props.size(); -} - -int ValidateAddressesModel::columnCount(const QModelIndex&) const { - return headers.size(); -} - -QVariant ValidateAddressesModel::data(const QModelIndex &index, int role) const { - QPair p = props.at(index.row()); - if (role == Qt::DisplayRole) { - switch(index.column()) { - case 0: return p.first; - case 1: return p.second; - } - } - return QVariant(); -} - - -QVariant ValidateAddressesModel::headerData(int section, Qt::Orientation orientation, int role) const { - if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { - return headers.at(section); - } - - return QVariant(); -} diff --git a/src/validateaddress.h b/src/validateaddress.h deleted file mode 100644 index 19db4cb..0000000 --- a/src/validateaddress.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef VALIDATEADDRESS_H -#define VALIDATEADDRESS_H - -#include "precompiled.h" - -class ValidateAddressesModel : public QAbstractTableModel { - -public: - ValidateAddressesModel(QTableView* parent, QList> props); - ~ValidateAddressesModel() = default; - - int rowCount(const QModelIndex &parent) const; - int columnCount(const QModelIndex &parent) const; - QVariant data(const QModelIndex &index, int role) const; - QVariant headerData(int section, Qt::Orientation orientation, int role) const; - -private: - QList> props; - QStringList headers; -}; - - -#endif // VALIDATEADDRESS_H diff --git a/src/validateaddress.ui b/src/validateaddress.ui deleted file mode 100644 index 20caebb..0000000 --- a/src/validateaddress.ui +++ /dev/null @@ -1,85 +0,0 @@ - - - ValidateAddress - - - - 0 - 0 - 400 - 300 - - - - Validate Address - - - - - - TextLabel - - - - - - - Address: - - - - - - - true - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Close - - - - - - - - - buttonBox - accepted() - ValidateAddress - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - ValidateAddress - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/src/websockets.cpp b/src/websockets.cpp index 78822da..660f06a 100644 --- a/src/websockets.cpp +++ b/src/websockets.cpp @@ -683,7 +683,7 @@ void AppDataServer::processSendTx(QJsonObject sendTx, MainWindow* mainwindow, st }); tx.fromAddr = bals[0].first; - tx.toAddrs = { ToFields{ sendTx["to"].toString(), amt, sendTx["memo"].toString(), sendTx["memo"].toString().toUtf8().toHex()} }; + tx.toAddrs = { ToFields{ sendTx["to"].toString(), amt, sendTx["memo"].toString()} }; // TODO: Respect the autoshield change setting @@ -699,9 +699,7 @@ void AppDataServer::processSendTx(QJsonObject sendTx, MainWindow* mainwindow, st // And send the Tx mainwindow->getRPC()->executeTransaction(tx, - [=] (QString) {}, - // Submitted Tx successfully - [=] (QString, QString txid) { + [=] (QString txid) { auto r = QJsonDocument(QJsonObject{ {"version", 1.0}, {"command", "sendTxSubmitted"}, @@ -771,20 +769,6 @@ void AppDataServer::processGetInfo(QJsonObject jobj, MainWindow* mainWindow, std void AppDataServer::processGetTransactions(MainWindow* mainWindow, std::shared_ptr pClient) { QJsonArray txns; auto model = mainWindow->getRPC()->getTransactionsModel(); - - // Manually add pending ops, so that computing transactions will also show up - auto wtxns = mainWindow->getRPC()->getWatchingTxns(); - for (auto opid : wtxns.keys()) { - txns.append(QJsonObject{ - {"type", "send"}, - {"datetime", QDateTime::currentSecsSinceEpoch()}, - {"amount", Settings::getDecimalString(wtxns[opid].tx.toAddrs[0].amount)}, - {"txid", ""}, - {"address", wtxns[opid].tx.toAddrs[0].addr}, - {"memo", wtxns[opid].tx.toAddrs[0].txtMemo}, - {"confirmations", 0} - }); - } // Add transactions for (int i = 0; i < model->rowCount(QModelIndex()) && i < Settings::getMaxMobileAppTxns(); i++) { diff --git a/src/zboard.ui b/src/zboard.ui deleted file mode 100644 index b21db5e..0000000 --- a/src/zboard.ui +++ /dev/null @@ -1,170 +0,0 @@ - - - zboard - - - - 0 - 0 - 588 - 431 - - - - Post to z-board.net - - - - - - Total Fee - - - - - - - feeamount - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - 0 / 512 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - Memo - - - - - - - (optional) - - - - - - - Send From - - - - - - - Post As: - - - - - - - <html><head/><body><p>ZBoard: Fully anonymous and untraceable chat messages based on the ZCash blockchain. <a href="http://www.z-board.net/"><span style=" text-decoration: underline; color:#0000ff;">http://www.z-board.net/</span></a></p></body></html> - - - true - - - true - - - - - - - - - - - - - color:red; - - - Warning - - - - - - - Qt::Horizontal - - - - - - - - - - Posting to Board - - - - - - - fromAddr - postAs - memoTxt - - - - - buttonBox - accepted() - zboard - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - zboard - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/zecwallet-lite.pro b/zecwallet-lite.pro index a35333c..85c1c0a 100644 --- a/zecwallet-lite.pro +++ b/zecwallet-lite.pro @@ -44,7 +44,6 @@ SOURCES += \ src/3rdparty/qrcode/QrSegment.cpp \ src/settings.cpp \ src/sendtab.cpp \ - src/senttxstore.cpp \ src/txtablemodel.cpp \ src/qrcodelabel.cpp \ src/connection.cpp \ @@ -52,7 +51,6 @@ SOURCES += \ src/addressbook.cpp \ src/logger.cpp \ src/addresscombo.cpp \ - src/validateaddress.cpp \ src/websockets.cpp \ src/mobileappconnector.cpp \ src/recurring.cpp \ @@ -73,14 +71,12 @@ HEADERS += \ src/3rdparty/json/json.hpp \ src/settings.h \ src/txtablemodel.h \ - src/senttxstore.h \ src/qrcodelabel.h \ src/connection.h \ src/fillediconlabel.h \ src/addressbook.h \ src/logger.h \ src/addresscombo.h \ - src/validateaddress.h \ src/websockets.h \ src/mobileappconnector.h \ src/recurring.h \ @@ -99,13 +95,10 @@ FORMS += \ src/settings.ui \ src/about.ui \ src/confirm.ui \ - src/turnstileprogress.ui \ src/privkey.ui \ src/memodialog.ui \ - src/validateaddress.ui \ src/viewalladdresses.ui \ src/connection.ui \ - src/zboard.ui \ src/addressbook.ui \ src/mobileappconnector.ui \ src/createzcashconfdialog.ui \