Merge pull request #5574 from daira/zcashd-wallet-tool
Make a zcashd-wallet-tool executable
This commit is contained in:
commit
2dcaac5fcb
|
@ -1,3 +1,6 @@
|
|||
[target.aarch64-unknown-linux-gnu]
|
||||
linker = "aarch64-linux-gnu-gcc"
|
||||
|
||||
[source.crates-io]
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*.exe
|
||||
src/bitcoin
|
||||
src/zcashd
|
||||
src/zcashd-wallet-tool
|
||||
src/zcash-cli
|
||||
src/zcash-gtest
|
||||
src/zcash-tx
|
||||
|
|
|
@ -2,6 +2,21 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "aead"
|
||||
version = "0.4.3"
|
||||
|
@ -17,7 +32,7 @@ version = "0.7.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"cipher",
|
||||
"cpufeatures",
|
||||
"opaque-debug",
|
||||
|
@ -52,6 +67,12 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd"
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.6"
|
||||
|
@ -85,6 +106,21 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e121dee8023ce33ab248d9ce1493df03c3b38a659b240096fcbd7048ff9c31f"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.0.1"
|
||||
|
@ -136,7 +172,7 @@ checksum = "d0830ae4cc96b0617cc912970c2b17e89456fecbf55e8eed53a956f37ab50c41"
|
|||
dependencies = [
|
||||
"hmac",
|
||||
"pbkdf2",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"sha2",
|
||||
"unicode-normalization",
|
||||
"zeroize",
|
||||
|
@ -284,6 +320,12 @@ version = "1.0.73"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
|
@ -296,7 +338,7 @@ version = "0.8.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01b72a433d0cf2aef113ba70f62634c56fddb0f244e6377185c56a7cadbd8f91"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"cipher",
|
||||
"cpufeatures",
|
||||
"zeroize",
|
||||
|
@ -324,6 +366,19 @@ dependencies = [
|
|||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clearscreen"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7ed49b0e894fe6264a58496c7ec4e9d3c46f66b59efae527cd5bee429d0a418"
|
||||
dependencies = [
|
||||
"nix",
|
||||
"terminfo",
|
||||
"thiserror",
|
||||
"which",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.5"
|
||||
|
@ -345,7 +400,7 @@ version = "0.5.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
|
@ -355,7 +410,7 @@ version = "0.8.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
@ -366,7 +421,7 @@ version = "0.9.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"crossbeam-utils",
|
||||
"lazy_static",
|
||||
"memoffset",
|
||||
|
@ -379,7 +434,7 @@ version = "0.8.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
|
@ -428,7 +483,7 @@ version = "4.0.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
|
@ -460,6 +515,16 @@ dependencies = [
|
|||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.3.6"
|
||||
|
@ -601,7 +666,7 @@ version = "0.1.16"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"wasi 0.9.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
@ -612,11 +677,17 @@ version = "0.2.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"wasi 0.10.2+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.26.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
|
||||
|
||||
[[package]]
|
||||
name = "group"
|
||||
version = "0.11.0"
|
||||
|
@ -629,6 +700,26 @@ dependencies = [
|
|||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gumdrop"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46571f5d540478cf70d2a42dd0d6d8e9f4b9cc7531544b93311e657b86568a0b"
|
||||
dependencies = [
|
||||
"gumdrop_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gumdrop_derive"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "915ef07c710d84733522461de2a734d4d62a3fd39a4d4f404c2f385ef8618d05"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "halo2"
|
||||
version = "0.1.0-beta.1"
|
||||
|
@ -639,7 +730,7 @@ dependencies = [
|
|||
"ff",
|
||||
"group",
|
||||
"pasta_curves",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rayon",
|
||||
]
|
||||
|
||||
|
@ -770,7 +861,7 @@ version = "0.1.12"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -836,13 +927,17 @@ checksum = "33a33a362ce288760ec6a508b94caaec573ae7d3bbbd91b87aa0bad4456839db"
|
|||
name = "librustzcash"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"backtrace",
|
||||
"bellman",
|
||||
"blake2b_simd 1.0.0",
|
||||
"blake2s_simd 1.0.0",
|
||||
"bls12_381",
|
||||
"byteorder",
|
||||
"clearscreen",
|
||||
"ed25519-zebra",
|
||||
"group",
|
||||
"gumdrop",
|
||||
"hyper",
|
||||
"incrementalmerkletree",
|
||||
"ipnet",
|
||||
|
@ -853,10 +948,13 @@ dependencies = [
|
|||
"metrics-exporter-prometheus",
|
||||
"nonempty",
|
||||
"orchard",
|
||||
"rand 0.8.5",
|
||||
"rand_core 0.6.3",
|
||||
"secp256k1",
|
||||
"secrecy",
|
||||
"subtle",
|
||||
"thiserror",
|
||||
"time",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-appender",
|
||||
|
@ -885,7 +983,7 @@ version = "0.4.14"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -992,6 +1090,16 @@ dependencies = [
|
|||
"sketches-ddsketch",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
|
||||
dependencies = [
|
||||
"adler",
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.0"
|
||||
|
@ -1023,6 +1131,29 @@ dependencies = [
|
|||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.22.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cc",
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"memoffset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "5.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nonempty"
|
||||
version = "0.7.0"
|
||||
|
@ -1087,6 +1218,15 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.27.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.9.0"
|
||||
|
@ -1119,7 +1259,7 @@ dependencies = [
|
|||
"memuse",
|
||||
"nonempty",
|
||||
"pasta_curves",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"reddsa",
|
||||
"serde",
|
||||
"subtle",
|
||||
|
@ -1161,7 +1301,7 @@ version = "0.8.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
|
@ -1190,7 +1330,7 @@ dependencies = [
|
|||
"ff",
|
||||
"group",
|
||||
"lazy_static",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"static_assertions",
|
||||
"subtle",
|
||||
]
|
||||
|
@ -1205,6 +1345,44 @@ dependencies = [
|
|||
"password-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
|
||||
dependencies = [
|
||||
"phf_shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_codegen"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815"
|
||||
dependencies = [
|
||||
"phf_generator",
|
||||
"phf_shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_generator"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526"
|
||||
dependencies = [
|
||||
"phf_shared",
|
||||
"rand 0.7.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7"
|
||||
dependencies = [
|
||||
"siphasher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.0.10"
|
||||
|
@ -1304,6 +1482,20 @@ dependencies = [
|
|||
"nibble_vec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||
dependencies = [
|
||||
"getrandom 0.1.16",
|
||||
"libc",
|
||||
"rand_chacha 0.2.2",
|
||||
"rand_core 0.5.1",
|
||||
"rand_hc",
|
||||
"rand_pcg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
|
@ -1311,10 +1503,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_chacha 0.3.1",
|
||||
"rand_core 0.6.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
|
@ -1343,6 +1545,24 @@ dependencies = [
|
|||
"getrandom 0.2.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||
dependencies = [
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_pcg"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
|
||||
dependencies = [
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "raw-cpuid"
|
||||
version = "10.2.0"
|
||||
|
@ -1464,6 +1684,12 @@ dependencies = [
|
|||
"digest 0.10.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
|
@ -1488,6 +1714,15 @@ dependencies = [
|
|||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "secrecy"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e"
|
||||
dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.136"
|
||||
|
@ -1515,7 +1750,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
|
||||
dependencies = [
|
||||
"block-buffer 0.9.0",
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"cpufeatures",
|
||||
"digest 0.9.0",
|
||||
"opaque-debug",
|
||||
|
@ -1530,6 +1765,12 @@ dependencies = [
|
|||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a86232ab60fa71287d7f2ddae4a7073f6b7aac33631c3015abb556f08c6d0a3e"
|
||||
|
||||
[[package]]
|
||||
name = "sketches-ddsketch"
|
||||
version = "0.1.2"
|
||||
|
@ -1548,7 +1789,7 @@ version = "0.3.19"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
@ -1610,6 +1851,19 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||
|
||||
[[package]]
|
||||
name = "terminfo"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76971977e6121664ec1b960d1313aacfa75642adc93b9d4d53b247bd4cb1747e"
|
||||
dependencies = [
|
||||
"dirs",
|
||||
"fnv",
|
||||
"nom",
|
||||
"phf",
|
||||
"phf_codegen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.30"
|
||||
|
@ -1648,8 +1902,15 @@ dependencies = [
|
|||
"itoa 1.0.1",
|
||||
"libc",
|
||||
"num_threads",
|
||||
"time-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25eb0ca3468fc0acc11828786797f6ef9aa1555e4a211a60d64cc8e4d1be47d6"
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.5.1"
|
||||
|
@ -1702,7 +1963,7 @@ version = "0.1.31"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6c650a8ef0cd2dd93736f033d21cbd1224c5a967aa0c258d00fcf7dafef9b9f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
|
@ -1840,7 +2101,7 @@ version = "0.2.79"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cfg-if 1.0.0",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
|
@ -1898,6 +2159,17 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "4.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a5a7e487e921cf220206864a94a89b6c6905bfc19f1057fa26a4cb360e5c1d2"
|
||||
dependencies = [
|
||||
"either",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
@ -1996,7 +2268,7 @@ dependencies = [
|
|||
"memuse",
|
||||
"nonempty",
|
||||
"orchard",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"rand_core 0.6.3",
|
||||
"ripemd",
|
||||
"secp256k1",
|
||||
|
|
16
Cargo.toml
16
Cargo.toml
|
@ -25,6 +25,10 @@ name = "rustzcash"
|
|||
path = "src/rust/src/rustzcash.rs"
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[[bin]]
|
||||
name = "zcashd-wallet-tool"
|
||||
path = "src/rust/bin/wallet_tool.rs"
|
||||
|
||||
[dependencies]
|
||||
bellman = "0.11"
|
||||
blake2b_simd = "1"
|
||||
|
@ -60,10 +64,20 @@ metrics-exporter-prometheus = "0.6"
|
|||
thiserror = "1"
|
||||
tokio = { version = "1.0", features = ["rt", "net", "time", "macros"] }
|
||||
|
||||
# Wallet tool
|
||||
# (also depends on thiserror, tracing, and tracing-subscriber with "env-filter" and "fmt" features)
|
||||
anyhow = "1.0"
|
||||
backtrace = "0.3"
|
||||
clearscreen = "1.0"
|
||||
gumdrop = "0.8"
|
||||
rand = "0.8"
|
||||
secrecy = "0.8"
|
||||
time = { version = "0.3", features = ["formatting", "macros"] }
|
||||
|
||||
[dependencies.tracing-subscriber]
|
||||
version = "0.3"
|
||||
default-features = false
|
||||
features = ["ansi", "env-filter", "time"]
|
||||
features = ["ansi", "env-filter", "fmt", "time"]
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
|
|
@ -48,6 +48,12 @@ $(BITCOIND_BIN): FORCE
|
|||
$(BITCOIN_CLI_BIN): FORCE
|
||||
$(MAKE) -C src $(@F)
|
||||
|
||||
check-security: FORCE
|
||||
$(MAKE) -C src check-security
|
||||
|
||||
check-symbols: FORCE
|
||||
$(MAKE) -C src check-symbols
|
||||
|
||||
if USE_LCOV
|
||||
|
||||
baseline.info:
|
||||
|
|
|
@ -189,8 +189,12 @@ def identify_executable(executable):
|
|||
return None
|
||||
|
||||
if __name__ == '__main__':
|
||||
args = sys.argv[1:]
|
||||
allow_no_canary = "--allow-no-canary" in args
|
||||
files = [arg for arg in args if not arg.startswith("--")]
|
||||
|
||||
retval = 0
|
||||
for filename in sys.argv[1:]:
|
||||
for filename in files:
|
||||
try:
|
||||
etype = identify_executable(filename)
|
||||
if etype is None:
|
||||
|
@ -201,6 +205,8 @@ if __name__ == '__main__':
|
|||
failed = []
|
||||
warning = []
|
||||
for (name, func) in CHECKS[etype]:
|
||||
if name == "Canary" and allow_no_canary:
|
||||
continue
|
||||
if not func(filename):
|
||||
if name in NONFATAL:
|
||||
warning.append(name)
|
||||
|
|
|
@ -13,23 +13,23 @@ be generated on load of the wallet, or the first time the wallet is unlocked,
|
|||
and is available via the `z_exportwallet` RPC call. All new addresses produced
|
||||
by the wallet are now derived from this seed using the HD wallet functionality
|
||||
described in ZIP 32 and ZIP 316. For users upgrading an existing Zcashd wallet,
|
||||
it is recommended that the wallet be backed up prior to upgrading to the 4.5.2
|
||||
it is recommended that the wallet be backed up prior to upgrading to the 4.7.0
|
||||
Zcashd release.
|
||||
|
||||
Following the upgrade to 4.5.2, Zcashd will require that the user confirm that
|
||||
Following the upgrade to 4.7.0, Zcashd will require that the user confirm that
|
||||
they have backed up their new emergency recovery phrase, which may be obtained
|
||||
from the output of the `z_exportwallet` RPC call. This confirmation can be
|
||||
performed manually using the `zcashd-wallet-tool` utility that is supplied with
|
||||
this release. The wallet will not allow the generation of new addresses until
|
||||
this confirmation has been performed. It is recommended that after this
|
||||
upgrade, that funds tied to preexisting addresses be migrated to newly
|
||||
generated addresses so that all wallet funds are recoverable using the
|
||||
emergency recovery phrase going forward. If you choose not to migrate funds in
|
||||
this fashion, you will continue to need to securely back up the entire
|
||||
`wallet.dat` file to ensure that you do not lose access to existing funds;
|
||||
EXISTING FUNDS WILL NOT BE RECOVERABLE USING THE EMERGENCY RECOVERY PHRASE
|
||||
UNLESS THEY HAVE BEEN MOVED TO A NEWLY GENERATED ADDRESS FOLLOWING THE 4.5.2
|
||||
UPGRADE.
|
||||
performed manually using the `zcashd-wallet-tool` utility that is supplied
|
||||
with this release (built or installed in the same directory as `zcashd`).
|
||||
The wallet will not allow the generation of new addresses until this
|
||||
confirmation has been performed. It is recommended that after this upgrade,
|
||||
that funds tied to preexisting addresses be migrated to newly generated
|
||||
addresses so that all wallet funds are recoverable using the emergency
|
||||
recovery phrase going forward. If you choose not to migrate funds in this
|
||||
fashion, you will continue to need to securely back up the entire `wallet.dat`
|
||||
file to ensure that you do not lose access to existing funds; EXISTING FUNDS
|
||||
WILL NOT BE RECOVERABLE USING THE EMERGENCY RECOVERY PHRASE UNLESS THEY HAVE
|
||||
BEEN MOVED TO A NEWLY GENERATED ADDRESS FOLLOWING THE 4.7.0 UPGRADE.
|
||||
|
||||
New RPC Methods
|
||||
---------------
|
||||
|
|
|
@ -46,6 +46,17 @@ RE_RPATH_RUNPATH = re.compile('No RPATH.*No RUNPATH')
|
|||
RE_FORTIFY_AVAILABLE = re.compile('FORTIFY_SOURCE support available.*Yes')
|
||||
RE_FORTIFY_USED = re.compile('Binary compiled with FORTIFY_SOURCE support.*Yes')
|
||||
|
||||
CXX_BINARIES = [
|
||||
'src/zcashd',
|
||||
'src/zcash-cli',
|
||||
'src/zcash-gtest',
|
||||
'src/zcash-tx',
|
||||
'src/test/test_bitcoin',
|
||||
]
|
||||
RUST_BINARIES = [
|
||||
'src/zcashd-wallet-tool',
|
||||
]
|
||||
|
||||
def test_rpath_runpath(filename):
|
||||
output = subprocess.check_output(
|
||||
[repofile('qa/zcash/checksec.sh'), '--file=' + repofile(filename)]
|
||||
|
@ -86,21 +97,14 @@ def check_security_hardening():
|
|||
if not magic.startswith(b'\x7fELF'):
|
||||
return ret
|
||||
|
||||
ret &= test_rpath_runpath('src/zcashd')
|
||||
ret &= test_rpath_runpath('src/zcash-cli')
|
||||
ret &= test_rpath_runpath('src/zcash-gtest')
|
||||
ret &= test_rpath_runpath('src/zcash-tx')
|
||||
ret &= test_rpath_runpath('src/test/test_bitcoin')
|
||||
for bin in CXX_BINARIES + RUST_BINARIES:
|
||||
ret &= test_rpath_runpath(bin)
|
||||
|
||||
# NOTE: checksec.sh does not reliably determine whether FORTIFY_SOURCE
|
||||
# is enabled for the entire binary. See issue #915.
|
||||
# FORTIFY_SOURCE does mostly nothing for Clang before 10, which we don't
|
||||
# pin yet, so we disable these tests.
|
||||
# ret &= test_fortify_source('src/zcashd')
|
||||
# ret &= test_fortify_source('src/zcash-cli')
|
||||
# ret &= test_fortify_source('src/zcash-gtest')
|
||||
# ret &= test_fortify_source('src/zcash-tx')
|
||||
# ret &= test_fortify_source('src/test/test_bitcoin')
|
||||
# FORTIFY_SOURCE is not applicable to Rust binaries.
|
||||
for bin in CXX_BINARIES:
|
||||
ret &= test_fortify_source(bin)
|
||||
|
||||
return ret
|
||||
|
||||
|
|
|
@ -29,6 +29,9 @@ LIBSECP256K1=secp256k1/libsecp256k1.la
|
|||
LIBUNIVALUE=univalue/libunivalue.la
|
||||
LIBZCASH=libzcash.a
|
||||
|
||||
WALLET_TOOL_BIN=zcashd-wallet-tool$(EXEEXT)
|
||||
WALLET_TOOL_BUILD=$(top_builddir)/target/$(RUST_TARGET)/release/zcashd-wallet-tool$(EXEEXT)
|
||||
|
||||
if ENABLE_ZMQ
|
||||
LIBBITCOIN_ZMQ=libbitcoin_zmq.a
|
||||
endif
|
||||
|
@ -47,7 +50,7 @@ endif
|
|||
# - Note that this does not prevent the secp256k1-sys vendored code from being built; this
|
||||
# requires https://github.com/rust-bitcoin/rust-secp256k1/issues/380 to be addressed.
|
||||
RUST_ENV_VARS = RUSTC="$(RUSTC)" TERM=dumb RUSTFLAGS="--cfg=rust_secp_no_symbol_renaming"
|
||||
RUST_BUILD_OPTS = --lib --release --target $(RUST_TARGET)
|
||||
RUST_BUILD_OPTS = --release --target $(RUST_TARGET) --manifest-path $(top_srcdir)/Cargo.toml
|
||||
|
||||
rust_verbose = $(rust_verbose_@AM_V@)
|
||||
rust_verbose_ = $(rust_verbose_@AM_DEFAULT_V@)
|
||||
|
@ -72,10 +75,16 @@ $(CARGO_CONFIGURED): $(top_srcdir)/.cargo/config.offline
|
|||
$(AM_V_at)touch $@
|
||||
endif
|
||||
|
||||
cargo-build: $(CARGO_CONFIGURED)
|
||||
$(RUST_ENV_VARS) $(CARGO) build $(RUST_BUILD_OPTS) $(rust_verbose) --manifest-path $(top_srcdir)/Cargo.toml
|
||||
cargo-build-lib: $(CARGO_CONFIGURED)
|
||||
$(RUST_ENV_VARS) $(CARGO) build --lib $(RUST_BUILD_OPTS) $(rust_verbose)
|
||||
|
||||
$(LIBRUSTZCASH): cargo-build
|
||||
cargo-build-bins: $(CARGO_CONFIGURED)
|
||||
$(RUST_ENV_VARS) $(CARGO) build --bins $(RUST_BUILD_OPTS) $(rust_verbose)
|
||||
|
||||
$(WALLET_TOOL_BIN): cargo-build-bins
|
||||
$(AM_V_at)cp $(WALLET_TOOL_BUILD) $@
|
||||
|
||||
$(LIBRUSTZCASH): cargo-build-lib
|
||||
|
||||
$(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*)
|
||||
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F)
|
||||
|
@ -99,6 +108,7 @@ lib_LTLIBRARIES = $(LIBZCASH_SCRIPT)
|
|||
|
||||
bin_PROGRAMS =
|
||||
noinst_PROGRAMS =
|
||||
bin_SCRIPTS =
|
||||
TESTS =
|
||||
BENCHMARKS =
|
||||
|
||||
|
@ -108,6 +118,7 @@ endif
|
|||
|
||||
if BUILD_BITCOIN_UTILS
|
||||
bin_PROGRAMS += zcash-cli zcash-tx
|
||||
bin_SCRIPTS += $(WALLET_TOOL_BIN)
|
||||
endif
|
||||
|
||||
LIBZCASH_H = \
|
||||
|
@ -129,7 +140,7 @@ LIBZCASH_H = \
|
|||
zcash/util.h \
|
||||
zcash/Zcash.h
|
||||
|
||||
.PHONY: FORCE cargo-build check-symbols check-security
|
||||
.PHONY: FORCE cargo-build-lib cargo-build-bins check-symbols check-security
|
||||
# bitcoin core #
|
||||
BITCOIN_CORE_H = \
|
||||
addrdb.h \
|
||||
|
@ -601,7 +612,7 @@ CTAES_DIST += crypto/ctaes/ctaes.h
|
|||
CTAES_DIST += crypto/ctaes/README.md
|
||||
CTAES_DIST += crypto/ctaes/test.c
|
||||
|
||||
CLEANFILES = *.gcda *.gcno */*.gcno wallet/*/*.gcno
|
||||
CLEANFILES = *.gcda *.gcno */*.gcno wallet/*/*.gcno $(bin_SCRIPTS)
|
||||
|
||||
DISTCLEANFILES = obj/build.h
|
||||
|
||||
|
@ -625,16 +636,17 @@ clean-local:
|
|||
$(AM_V_CXX) $(OBJCXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||
$(CPPFLAGS) $(AM_CXXFLAGS) $(AM_CXXFLAGS) $(PIE_FLAGS) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
check-symbols: $(bin_PROGRAMS)
|
||||
check-symbols: $(bin_PROGRAMS) $(bin_SCRIPTS)
|
||||
if GLIBC_BACK_COMPAT
|
||||
@echo "Checking glibc back compat of [$(bin_PROGRAMS)]..."
|
||||
$(AM_V_at) READELF=$(READELF) CPPFILT=$(CPPFILT) $(top_srcdir)/contrib/devtools/symbol-check.py $(bin_PROGRAMS)
|
||||
@echo "Checking glibc back compat of [$(bin_PROGRAMS) $(bin_SCRIPTS)]..."
|
||||
$(AM_V_at) READELF=$(READELF) CPPFILT=$(CPPFILT) $(top_srcdir)/contrib/devtools/symbol-check.py $(bin_PROGRAMS) $(bin_SCRIPTS)
|
||||
endif
|
||||
|
||||
check-security: $(bin_PROGRAMS)
|
||||
check-security: $(bin_PROGRAMS) $(bin_SCRIPTS)
|
||||
if HARDEN
|
||||
@echo "Checking binary security of [$(bin_PROGRAMS)]..."
|
||||
@echo "Checking binary security of [$(bin_PROGRAMS) $(bin_SCRIPTS)]..."
|
||||
$(AM_V_at) READELF=$(READELF) OBJDUMP=$(OBJDUMP) $(top_srcdir)/contrib/devtools/security-check.py $(bin_PROGRAMS)
|
||||
$(AM_V_at) READELF=$(READELF) OBJDUMP=$(OBJDUMP) $(top_srcdir)/contrib/devtools/security-check.py --allow-no-canary $(bin_SCRIPTS)
|
||||
endif
|
||||
|
||||
%.pb.cc %.pb.h: %.proto
|
||||
|
|
|
@ -39,7 +39,7 @@ std::string HelpMessageCli()
|
|||
strUsage += HelpMessageGroup(_("Options:"));
|
||||
strUsage += HelpMessageOpt("-?", _("This help message"));
|
||||
strUsage += HelpMessageOpt("-conf=<file>", strprintf(_("Specify configuration file (default: %s)"), BITCOIN_CONF_FILENAME));
|
||||
strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory"));
|
||||
strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory (this path cannot use '~')"));
|
||||
strUsage += HelpMessageOpt("-stdin", _("Read extra arguments from standard input, one per line until EOF/Ctrl-D (recommended for sensitive information such as passphrases). If first extra argument is `walletpassphrase` then the first line(password) will not be echoed."));
|
||||
AppendParamsHelpMessages(strUsage);
|
||||
strUsage += HelpMessageOpt("-rpcconnect=<ip>", strprintf(_("Send commands to node running on <ip> (default: %s)"), DEFAULT_RPCCONNECT));
|
||||
|
|
|
@ -341,7 +341,7 @@ std::string HelpMessage(HelpMessageMode mode)
|
|||
strUsage += HelpMessageOpt("-daemon", _("Run in the background as a daemon and accept commands"));
|
||||
#endif
|
||||
}
|
||||
strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory"));
|
||||
strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory (this path cannot use '~')"));
|
||||
strUsage += HelpMessageOpt("-paramsdir=<dir>", _("Specify Zcash network parameters directory"));
|
||||
strUsage += HelpMessageOpt("-dbcache=<n>", strprintf(_("Set database cache size in megabytes (%d to %d, default: %d)"), nMinDbCache, nMaxDbCache, nDefaultDbCache));
|
||||
strUsage += HelpMessageOpt("-debuglogfile=<file>", strprintf(_("Specify location of debug log file: this can be an absolute path or a path relative to the data directory (default: %s)"), DEFAULT_DEBUGLOGFILE));
|
||||
|
|
|
@ -6,6 +6,11 @@ the `zcashd` full node.
|
|||
The FFI API does not have any stability guarantees, and will change as required
|
||||
by `zcashd`.
|
||||
|
||||
# zcashd-wallet-tool
|
||||
|
||||
`zcashd-wallet-tool` is a command-line tool that allows confirming to a `zcashd`
|
||||
node that the emergency recovery phrase of the node's wallet has been backed up.
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of
|
||||
|
|
|
@ -0,0 +1,646 @@
|
|||
use std::cmp::min;
|
||||
use std::env::{self, consts::EXE_EXTENSION};
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufRead, Stdin, Write};
|
||||
use std::iter;
|
||||
use std::panic;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::{self, ChildStdin, Command, Output, Stdio};
|
||||
use std::str::from_utf8;
|
||||
use std::time::SystemTime;
|
||||
|
||||
use anyhow::{self, Context};
|
||||
use backtrace::Backtrace;
|
||||
use gumdrop::{Options, ParsingStyle};
|
||||
use rand::{thread_rng, Rng};
|
||||
use secrecy::{ExposeSecret, SecretString};
|
||||
use thiserror::Error;
|
||||
use time::macros::format_description;
|
||||
use time::OffsetDateTime;
|
||||
use tracing::debug;
|
||||
use tracing_subscriber::{fmt, EnvFilter};
|
||||
|
||||
#[derive(Debug, Options)]
|
||||
struct CliOptions {
|
||||
#[options(no_short, help = "Print this help output")]
|
||||
help: bool,
|
||||
|
||||
#[options(
|
||||
no_short,
|
||||
help = "Specify configuration filename, relative to the data directory (default: zcash.conf)",
|
||||
meta = "FILENAME"
|
||||
)]
|
||||
conf: Option<String>,
|
||||
|
||||
#[options(
|
||||
no_short,
|
||||
help = "Specify data directory (this path cannot use '~')",
|
||||
meta = "PATH"
|
||||
)]
|
||||
datadir: Option<String>,
|
||||
|
||||
#[options(no_short, help = "Use the test chain")]
|
||||
testnet: bool,
|
||||
|
||||
#[options(
|
||||
no_short,
|
||||
help = "Send commands to node running on IPADDR (default: 127.0.0.1)",
|
||||
meta = "IPADDR"
|
||||
)]
|
||||
rpcconnect: Option<String>,
|
||||
|
||||
#[options(
|
||||
no_short,
|
||||
help = "Connect to JSON-RPC on PORT (default: 8232 or testnet: 18232)",
|
||||
meta = "PORT"
|
||||
)]
|
||||
rpcport: Option<u16>,
|
||||
|
||||
#[options(
|
||||
no_short,
|
||||
help = "Username for JSON-RPC connections",
|
||||
meta = "USERNAME"
|
||||
)]
|
||||
rpcuser: Option<String>,
|
||||
|
||||
#[options(
|
||||
no_short,
|
||||
help = "Password for JSON-RPC connections",
|
||||
meta = "PASSWORD"
|
||||
)]
|
||||
rpcpassword: Option<String>,
|
||||
|
||||
#[options(
|
||||
no_short,
|
||||
help = "Timeout in seconds during HTTP requests, or 0 for no timeout. (default: 900)",
|
||||
meta = "SECONDS"
|
||||
)]
|
||||
rpcclienttimeout: Option<u32>,
|
||||
}
|
||||
|
||||
impl CliOptions {
|
||||
fn to_zcash_cli_options(&self) -> Vec<String> {
|
||||
iter::empty::<String>()
|
||||
.chain(self.conf.as_ref().map(|o| format!("-conf={}", o)))
|
||||
.chain(self.datadir.as_ref().map(|o| format!("-datadir={}", o)))
|
||||
.chain(if self.testnet {
|
||||
Some("-testnet".into())
|
||||
} else {
|
||||
None
|
||||
})
|
||||
.chain(
|
||||
self.rpcconnect
|
||||
.as_ref()
|
||||
.map(|o| format!("-rpcconnect={}", o)),
|
||||
)
|
||||
.chain(self.rpcport.as_ref().map(|o| format!("-rpcport={}", o)))
|
||||
.chain(self.rpcuser.as_ref().map(|o| format!("-rpcuser={}", o)))
|
||||
.chain(
|
||||
self.rpcpassword
|
||||
.as_ref()
|
||||
.map(|o| format!("-rpcpassword={}", o)),
|
||||
)
|
||||
.chain(
|
||||
self.rpcclienttimeout
|
||||
.as_ref()
|
||||
.map(|o| format!("-rpcclienttimeout={}", o)),
|
||||
)
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
enum WalletToolError {
|
||||
#[error("zcash-cli executable not found")]
|
||||
ZcashCliNotFound,
|
||||
|
||||
#[error("Unexpected response from zcash-cli or zcashd")]
|
||||
UnexpectedResponse,
|
||||
|
||||
#[error("Could not connect to zcashd")]
|
||||
ZcashdConnection,
|
||||
|
||||
#[error("zcashd -exportdir option not set")]
|
||||
ExportDirNotSet,
|
||||
|
||||
#[error("Could not parse a recovery phrase from the export file")]
|
||||
RecoveryPhraseNotFound,
|
||||
|
||||
#[error("Unexpected EOF in input")]
|
||||
UnexpectedEof,
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
// Log to stderr, configured by the RUST_LOG environment variable.
|
||||
fmt()
|
||||
.with_writer(io::stderr)
|
||||
.with_env_filter(EnvFilter::from_default_env())
|
||||
.init();
|
||||
|
||||
// Allow either Bitcoin-style or GNU-style arguments.
|
||||
let mut args = env::args();
|
||||
let command = args.next().expect("argv[0] should exist");
|
||||
let args: Vec<_> = args
|
||||
.map(|s| {
|
||||
if s.starts_with('-') && !s.starts_with("--") {
|
||||
format!("-{}", s)
|
||||
} else {
|
||||
s
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
const USAGE_NOTE: &str = concat!(
|
||||
"Options can be given in GNU style (`--conf=CONF` or `--conf CONF`),\n",
|
||||
"or in Bitcoin style with a single hyphen (`-conf=CONF`).\n\n",
|
||||
"The environment variable RUST_LOG controls debug output, e.g.\n",
|
||||
"`RUST_LOG=debug`.\n",
|
||||
);
|
||||
|
||||
let opts = CliOptions::parse_args(&args, ParsingStyle::default()).unwrap_or_else(|e| {
|
||||
eprintln!(
|
||||
"{}: {}\n\nUsage: {} [OPTIONS]\n\n{}\n\n{}",
|
||||
command,
|
||||
e,
|
||||
command,
|
||||
CliOptions::usage(),
|
||||
USAGE_NOTE,
|
||||
);
|
||||
process::exit(2);
|
||||
});
|
||||
|
||||
if opts.help_requested() {
|
||||
println!(
|
||||
"Usage: {} [OPTIONS]\n\n{}\n\n{}",
|
||||
command,
|
||||
opts.self_usage(),
|
||||
USAGE_NOTE
|
||||
);
|
||||
process::exit(0);
|
||||
}
|
||||
|
||||
if let Err(e) = run(&opts) {
|
||||
eprintln!("{}: {}", command, e);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn run(opts: &CliOptions) -> anyhow::Result<()> {
|
||||
let cli_options: Vec<String> = opts.to_zcash_cli_options();
|
||||
|
||||
println!(concat!(
|
||||
"To reduce the risk of loss of funds, we're going to confirm that the\n",
|
||||
"zcashd wallet is backed up reliably.\n\n",
|
||||
" 👛 ➜ 🗃️ \n"
|
||||
));
|
||||
|
||||
println!("Checking that we can connect to zcashd...");
|
||||
let zcash_cli = zcash_cli_path()?;
|
||||
|
||||
// Pass an invalid filename, "\x01", and use the error message to distinguish
|
||||
// whether zcashd is running with the -exportdir option, running without that
|
||||
// option, or not running / cannot connect.
|
||||
let mut cli_args = cli_options.clone();
|
||||
cli_args.extend_from_slice(&["z_exportwallet".to_string(), "\x01".to_string()]);
|
||||
let out = exec(&zcash_cli, &cli_args, None)?;
|
||||
let cli_err: Vec<_> = from_utf8(&out.stderr)
|
||||
.with_context(|| "Output from zcash-cli was not UTF-8")?
|
||||
.lines()
|
||||
.map(|s| s.trim_end_matches('\r'))
|
||||
.collect();
|
||||
debug!("stderr {:?}", cli_err);
|
||||
|
||||
if !cli_err.is_empty() {
|
||||
if cli_err[0].starts_with("Error reading configuration file") {
|
||||
println!(
|
||||
"\nNo, we could not read the zcashd configuration file, expected to be at\n{:?}.",
|
||||
Path::new(opts.datadir.as_ref().map_or("~/.zcash", |s| &s[..])).join(Path::new(
|
||||
opts.conf.as_ref().map_or("zcash.conf", |s| &s[..])
|
||||
)),
|
||||
);
|
||||
println!(concat!(
|
||||
"If it is not at that path, please try again with the '-datadir' and/or\n",
|
||||
"'-conf' options set correctly (see '--help' for details). Also make sure\n",
|
||||
"that the current user has permission to read the configuration file.\n",
|
||||
));
|
||||
return Err(WalletToolError::ZcashdConnection.into());
|
||||
}
|
||||
if cli_err[0].starts_with("error: couldn't connect") {
|
||||
println!(concat!(
|
||||
"\nNo, we could not connect. zcashd might not be running; in that case\n",
|
||||
"please start it. The '-exportdir' option should be set to the absolute\n",
|
||||
"path of the directory you want to save the wallet export file to.\n\n",
|
||||
"(Don't forget to restart zcashd without '-exportdir' after finishing\n",
|
||||
"the backup, if running it long-term with that option is not desired\n",
|
||||
"or would be a security hazard in your environment.)\n\n",
|
||||
"If you believe zcashd is running, it might be using an unexpected port,\n",
|
||||
"address, or authentication options for the RPC interface, for example.\n",
|
||||
"In that case try to connect to it using zcash-cli, and if successful,\n",
|
||||
"use the same connection options for zcashd-wallet-tool (see '--help' for\n",
|
||||
"accepted options) as for zcash-cli.\n"
|
||||
));
|
||||
return Err(WalletToolError::ZcashdConnection.into());
|
||||
}
|
||||
if cli_err[0] == "error code: -28" {
|
||||
println!(concat!(
|
||||
"\nNo, we could not connect. zcashd seems to be initializing; please try\n",
|
||||
"again once it has finished.\n",
|
||||
));
|
||||
return Err(WalletToolError::ZcashdConnection.into());
|
||||
}
|
||||
}
|
||||
|
||||
const REMINDER_MSG: &str = concat!(
|
||||
"\n\nPlease start or restart zcashd with '-exportdir' set to the absolute\n",
|
||||
"path of the directory you want to save the wallet export file to.\n",
|
||||
"(Don't forget to restart zcashd without '-exportdir' after finishing\n",
|
||||
"the backup, if running it long-term with that option is not desired\n",
|
||||
"or would be a security hazard in your environment.)\n",
|
||||
);
|
||||
|
||||
if cli_err.len() >= 3
|
||||
&& cli_err[0] == "error code: -4"
|
||||
&& cli_err[2].contains("zcashd -exportdir")
|
||||
{
|
||||
println!(
|
||||
"\nIt looks like zcashd is running without the '-exportdir' option.{}",
|
||||
REMINDER_MSG
|
||||
);
|
||||
return Err(WalletToolError::ExportDirNotSet.into());
|
||||
}
|
||||
if !(cli_err.len() >= 3
|
||||
&& cli_err[0] == "error code: -4"
|
||||
&& cli_err[2].starts_with("Filename is invalid"))
|
||||
{
|
||||
println!(
|
||||
"\nThere was an unexpected response from zcash-cli or zcashd:\n> {}{}",
|
||||
cli_err.join("\n> "),
|
||||
REMINDER_MSG,
|
||||
);
|
||||
return Err(WalletToolError::UnexpectedResponse.into());
|
||||
}
|
||||
println!("Yes, and it is running with the '-exportdir' option as required.");
|
||||
|
||||
let mut stdin = io::stdin();
|
||||
|
||||
let base = default_filename_base();
|
||||
let mut r = 0u32;
|
||||
let out = loop {
|
||||
let default_filename = if r != 0 {
|
||||
format!("{}r{}", base, r)
|
||||
} else {
|
||||
base.to_string()
|
||||
};
|
||||
println!(
|
||||
concat!(
|
||||
"\nEnter the filename for the wallet export file, using only characters\n",
|
||||
"a-z, A-Z and 0-9 (default '{}')."
|
||||
),
|
||||
default_filename
|
||||
);
|
||||
let response = prompt(&mut stdin)?;
|
||||
let response = strip(&response);
|
||||
let filename = if response.is_empty() {
|
||||
r = r.saturating_add(1);
|
||||
&default_filename
|
||||
} else {
|
||||
response
|
||||
};
|
||||
debug!("Using filename {:?}", filename);
|
||||
|
||||
let mut cli_args = cli_options.clone();
|
||||
cli_args.extend_from_slice(&["z_exportwallet".to_string(), filename.to_string()]);
|
||||
let out = exec(&zcash_cli, &cli_args, None)?;
|
||||
let cli_err: Vec<_> = from_utf8(&out.stderr)
|
||||
.with_context(|| "Output from zcash-cli was not UTF-8")?
|
||||
.lines()
|
||||
.map(|s| s.trim_end_matches('\r'))
|
||||
.collect();
|
||||
debug!("stderr {:?}", cli_err);
|
||||
|
||||
if cli_err.len() >= 3
|
||||
&& cli_err[0] == "error code: -8"
|
||||
&& cli_err[1] == "error message:"
|
||||
&& cli_err[2].contains("overwrite existing")
|
||||
{
|
||||
println!(concat!(
|
||||
"That file already exists. Please pick a unique filename in the\n",
|
||||
"directory specified by the '-exportdir' option to zcashd."
|
||||
));
|
||||
continue;
|
||||
} else {
|
||||
break out;
|
||||
}
|
||||
};
|
||||
|
||||
let cli_out: Vec<_> = from_utf8(&out.stdout)
|
||||
.with_context(|| "Output from zcash-cli was not UTF-8")?
|
||||
.lines()
|
||||
.map(|s| s.trim_end_matches('\r'))
|
||||
.collect();
|
||||
debug!("stdout {:?}", cli_out);
|
||||
|
||||
if cli_out.is_empty() {
|
||||
return Err(WalletToolError::UnexpectedResponse.into());
|
||||
}
|
||||
let export_path = cli_out[0];
|
||||
|
||||
println!("\nSaved the export file to '{}'.", export_path);
|
||||
println!("IMPORTANT: This file contains secrets that allow spending all wallet funds.\n");
|
||||
|
||||
let export_file = File::open(export_path)
|
||||
.with_context(|| format!("Could not open {:?} for reading", export_path))?;
|
||||
|
||||
// TODO: ensure the buffer will be zeroized (#5650)
|
||||
let phrase_line: Vec<_> = io::BufReader::new(export_file)
|
||||
.lines()
|
||||
.map(|line| line.map(SecretString::new))
|
||||
.filter(|s| {
|
||||
s.as_ref()
|
||||
.map(|t| t.expose_secret().starts_with("# - recovery_phrase=\""))
|
||||
.unwrap_or(false)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let phrase = match &phrase_line[..] {
|
||||
[Ok(line)] => line
|
||||
.expose_secret()
|
||||
.trim_start_matches("# - recovery_phrase=\"")
|
||||
.trim_end_matches('"'),
|
||||
_ => return Err(WalletToolError::RecoveryPhraseNotFound.into()),
|
||||
};
|
||||
|
||||
// This panic hook allows us to make a best effort to clear the screen (and then print
|
||||
// another reminder about secrets in the export file) even if a panic occurs.
|
||||
|
||||
let old_hook = panic::take_hook();
|
||||
{
|
||||
let export_path = export_path.to_string();
|
||||
panic::set_hook(Box::new(move |panic_info| {
|
||||
clear_and_show_cautions(&export_path);
|
||||
|
||||
let s = panic_info.payload().downcast_ref::<&str>().unwrap_or(&"");
|
||||
eprintln!("\nPanic: {}\n{:?}", s, Backtrace::new());
|
||||
}));
|
||||
}
|
||||
|
||||
let res = (|| -> anyhow::Result<()> {
|
||||
println!("The recovery phrase is:\n");
|
||||
|
||||
const WORDS_PER_LINE: usize = 3;
|
||||
|
||||
let words: Vec<_> = phrase.split(' ').collect();
|
||||
let max_len = words.iter().map(|w| w.len()).max().unwrap_or(0);
|
||||
|
||||
for (i, word) in words.iter().enumerate() {
|
||||
print!("{0:2}: {1:2$}", i + 1, word, max_len + 2);
|
||||
if (i + 1) % WORDS_PER_LINE == 0 {
|
||||
println!();
|
||||
}
|
||||
}
|
||||
if words.len() % WORDS_PER_LINE != 0 {
|
||||
println!();
|
||||
}
|
||||
|
||||
println!(concat!(
|
||||
"\nPlease write down this phrase (including the numbering of words) on\n",
|
||||
"something durable that you will keep in a secure location.\n",
|
||||
"Press Enter when finished; then the phrase will disappear and you'll be\n",
|
||||
"asked to re-enter a selection of words from it."
|
||||
));
|
||||
|
||||
let mut stdin = io::stdin();
|
||||
prompt(&mut stdin)?;
|
||||
|
||||
// The only reliable and portable way to make sure the recovery phrase
|
||||
// is no longer displayed is to clear the whole terminal (including
|
||||
// scrollback, if possible). The text is only printed if clearing fails.
|
||||
try_to_clear(concat!(
|
||||
"\n\n\n\n\n\n\n\n\n\n\n\n",
|
||||
"Please adjust the terminal window so that you can't see the\n",
|
||||
"recovery phrase above. After finishing the backup, close the\n",
|
||||
"terminal window or clear it"
|
||||
));
|
||||
|
||||
println!("\nNow we're going to confirm that you backed up the recovery phrase.");
|
||||
|
||||
let mut rng = thread_rng();
|
||||
let mut unconfirmed: Vec<usize> = (0..words.len()).collect();
|
||||
for _ in 0..min(3, words.len()) {
|
||||
let index: usize = rng.gen_range(0..unconfirmed.len());
|
||||
let n = unconfirmed[index];
|
||||
unconfirmed[index] = unconfirmed[unconfirmed.len() - 1];
|
||||
unconfirmed.pop().expect("should be nonempty");
|
||||
|
||||
loop {
|
||||
println!("\nPlease enter the {} word:", ordinal(n + 1));
|
||||
let line = prompt(&mut stdin)?;
|
||||
if words[n] == strip(&line) {
|
||||
break;
|
||||
}
|
||||
println!("That's not correct, please try again.");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})();
|
||||
|
||||
panic::set_hook(old_hook);
|
||||
clear_and_show_cautions(export_path);
|
||||
res?;
|
||||
|
||||
let mut cli_args = cli_options;
|
||||
cli_args.extend_from_slice(&["-stdin".to_string(), "walletconfirmbackup".to_string()]);
|
||||
exec(&zcash_cli, &cli_args, Some(phrase))
|
||||
.and_then(|out| {
|
||||
let cli_err: Vec<_> = from_utf8(&out.stderr)
|
||||
.with_context(|| "Output from zcash-cli was not UTF-8")?
|
||||
.lines()
|
||||
.map(|s| s.trim_end_matches('\r'))
|
||||
.collect();
|
||||
debug!("stderr {:?}", cli_err);
|
||||
|
||||
if !cli_err.is_empty() {
|
||||
if cli_err[0].starts_with("error: couldn't connect") {
|
||||
println!("\nWe could not connect to zcashd; it may have exited.");
|
||||
return Err(WalletToolError::ZcashdConnection.into());
|
||||
} else {
|
||||
println!(
|
||||
"\nThere was an unexpected response from zcash-cli or zcashd:\n> {}",
|
||||
cli_err.join("\n> "),
|
||||
);
|
||||
return Err(WalletToolError::UnexpectedResponse.into());
|
||||
}
|
||||
}
|
||||
println!(concat!(
|
||||
"\nThe backup of the emergency recovery phrase for the zcashd\n",
|
||||
"wallet has been successfully confirmed 🙂. You can now use the\n",
|
||||
"zcashd RPC methods that create keys and addresses in that wallet.\n\n",
|
||||
"If you use other wallets, their recovery information will need\n",
|
||||
"to be backed up separately.\n"
|
||||
));
|
||||
Ok(())
|
||||
})
|
||||
.map_err(|e| {
|
||||
println!(concat!(
|
||||
"\nzcash-wallet-tool was unable to communicate to zcashd that the\n",
|
||||
"backup was confirmed. This can happen if zcashd stopped, in which\n",
|
||||
"case you should try again. If zcashd is still running, please seek\n",
|
||||
"help or try to use 'zcash-cli -stdin walletconfirmbackup' manually.\n"
|
||||
));
|
||||
e
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
const MAX_USER_INPUT_LEN: usize = 100;
|
||||
|
||||
fn prompt(input: &mut Stdin) -> anyhow::Result<SecretString> {
|
||||
let mut buf = String::with_capacity(MAX_USER_INPUT_LEN);
|
||||
let res = input
|
||||
.read_line(&mut buf)
|
||||
.with_context(|| "Error reading from stdin");
|
||||
|
||||
// Ensure the buffer is zeroized even on error.
|
||||
let line = SecretString::new(buf);
|
||||
res.and_then(|_| {
|
||||
if line.expose_secret().ends_with('\n') {
|
||||
Ok(line)
|
||||
} else {
|
||||
Err(WalletToolError::UnexpectedEof.into())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn strip(input: &SecretString) -> &str {
|
||||
input
|
||||
.expose_secret()
|
||||
.trim_end_matches(|c| c == '\r' || c == '\n')
|
||||
.trim()
|
||||
}
|
||||
|
||||
fn ordinal(num: usize) -> String {
|
||||
let suffix = if (11..=13).contains(&(num % 100)) {
|
||||
"th"
|
||||
} else {
|
||||
match num % 10 {
|
||||
1 => "st",
|
||||
2 => "nd",
|
||||
3 => "rd",
|
||||
_ => "th",
|
||||
}
|
||||
};
|
||||
format!("{}{}", num, suffix)
|
||||
}
|
||||
|
||||
fn zcash_cli_path() -> anyhow::Result<PathBuf> {
|
||||
// First look for `zcash_cli[.exe]` as a sibling of the executable.
|
||||
let mut exe = env::current_exe()
|
||||
.with_context(|| "Cannot determine the path of the running executable")?;
|
||||
exe.set_file_name("zcash-cli");
|
||||
exe.set_extension(EXE_EXTENSION);
|
||||
|
||||
debug!("Testing for zcash-cli at {:?}", exe);
|
||||
if exe.exists() {
|
||||
return Ok(exe);
|
||||
}
|
||||
// If not found there, look in `../src/zcash_cli[.exe]` provided
|
||||
// that `src` is a sibling of `target`.
|
||||
exe.pop(); // strip filename
|
||||
exe.pop(); // ..
|
||||
if exe.file_name() != Some(OsStr::new("target")) {
|
||||
// or in `../../src/zcash_cli[.exe]` under the same proviso
|
||||
exe.pop(); // ../..
|
||||
if exe.file_name() != Some(OsStr::new("target")) {
|
||||
return Err(WalletToolError::ZcashCliNotFound.into());
|
||||
}
|
||||
}
|
||||
// Replace 'target/' with 'src/'.
|
||||
exe.set_file_name("src");
|
||||
exe.push("zcash-cli");
|
||||
exe.set_extension(EXE_EXTENSION);
|
||||
|
||||
debug!("Testing for zcash-cli at {:?}", exe);
|
||||
if !exe.exists() {
|
||||
return Err(WalletToolError::ZcashCliNotFound.into());
|
||||
}
|
||||
Ok(exe)
|
||||
}
|
||||
|
||||
fn exec(exe_path: &Path, args: &[String], stdin: Option<&str>) -> anyhow::Result<Output> {
|
||||
debug!("Running {:?} {:?}", exe_path, args);
|
||||
let mut cmd = Command::new(exe_path);
|
||||
let cli = cmd.args(args);
|
||||
match stdin {
|
||||
None => Ok(cli.output()?),
|
||||
Some(data) => {
|
||||
let mut cli_process = cli
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()?;
|
||||
cli_process
|
||||
.stdin
|
||||
.take()
|
||||
.with_context(|| "Could not open pipe to zcash-cli's stdin")
|
||||
.and_then(|mut pipe: ChildStdin| -> anyhow::Result<()> {
|
||||
pipe.write_all(data.as_bytes())?;
|
||||
pipe.write_all("\n".as_bytes())?;
|
||||
Ok(())
|
||||
})
|
||||
.with_context(|| "Could not write to zcash-cli's stdin")?;
|
||||
Ok(cli_process.wait_with_output()?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn default_filename_base() -> String {
|
||||
let format = format_description!("export[year][month][day]");
|
||||
|
||||
// We use the UTC date because there is a security issue in obtaining the local date
|
||||
// from either `chrono` or `time`: <https://github.com/chronotope/chrono/issues/602>.
|
||||
// We could use the approach in
|
||||
// <https://github.com/ArekPiekarz/rusty-tax-break/commit/3aac8f0c26fd96b7365619509a544f78b59627fe>
|
||||
// if it were important, but it isn't worth the dependency on `tz-rs`.
|
||||
|
||||
OffsetDateTime::from(SystemTime::now())
|
||||
.format(&format)
|
||||
.unwrap_or_else(|_| "export".to_string())
|
||||
}
|
||||
|
||||
fn clear_and_show_cautions(export_path: &str) {
|
||||
try_to_clear(concat!(
|
||||
"\nCAUTION: This terminal window might be showing secrets (or have\n",
|
||||
"them in the scrollback). Please copy any useful information and\n",
|
||||
"then close it, or clear it"
|
||||
));
|
||||
|
||||
println!(
|
||||
concat!(
|
||||
"\nIMPORTANT: Secrets that allow spending all zcashd wallet funds\n",
|
||||
"have been left in the file '{}'.\n\n",
|
||||
"Don't forget to restart zcashd without '-exportdir', if running it\n",
|
||||
"long-term with that option is not desired or would be a security\n",
|
||||
"hazard in your environment.\n\n",
|
||||
"When choosing a location for the physical backup of your emergency\n",
|
||||
"recovery phrase, please make sure to consider both risk of theft,\n",
|
||||
"and your long-term ability to remember where it is kept."
|
||||
),
|
||||
export_path,
|
||||
);
|
||||
}
|
||||
|
||||
fn try_to_clear(error_blurb: &str) {
|
||||
if let Err(e) = clearscreen::clear() {
|
||||
eprintln!("Unable to clear screen: {}.", e);
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
const HOW_TO_CLEAR: &str = "using 'cls'";
|
||||
#[cfg(target_os = "macos")]
|
||||
const HOW_TO_CLEAR: &str = "by pressing Command + K";
|
||||
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
|
||||
const HOW_TO_CLEAR: &str = "using 'clear'";
|
||||
|
||||
println!("{} {}.", error_blurb, HOW_TO_CLEAR);
|
||||
}
|
||||
}
|
|
@ -1750,7 +1750,11 @@ UniValue walletconfirmbackup(const UniValue& params, bool fHelp)
|
|||
if (fHelp || params.size() != 1)
|
||||
throw runtime_error(
|
||||
"walletconfirmbackup \"emergency recovery phrase\"\n"
|
||||
"\nNotify the wallet that the user has backed up the emergency recovery phrase,\n"
|
||||
"\nCAUTION: This is an internal method that is not intended to be called directly by\n"
|
||||
"users. Please use the zcashd-wallet-tool utility (built or installed in the same directory\n"
|
||||
"as zcashd) instead. In particular, this method should not be used from zcash-cli, in order\n"
|
||||
"to avoid exposing the recovery phrase on the command line.\n\n"
|
||||
"Notify the wallet that the user has backed up the emergency recovery phrase,\n"
|
||||
"which can be obtained by making a call to z_exportwallet. The zcashd embedded wallet\n"
|
||||
"requires confirmation that the emergency recovery phrase has been backed up before it\n"
|
||||
"will permit new spending keys or addresses to be generated.\n"
|
||||
|
|
|
@ -80,6 +80,7 @@ clean_dirs __pycache__
|
|||
clean_exe src/bench/bench_bitcoin
|
||||
clean_exe src/zcash-cli
|
||||
clean_exe src/zcashd
|
||||
clean_exe src/zcashd-wallet-tool
|
||||
clean_exe src/zcash-gtest
|
||||
clean_exe src/zcash-tx
|
||||
clean_exe src/test/test_bitcoin
|
||||
|
|
Loading…
Reference in New Issue