diff --git a/Cargo.lock b/Cargo.lock index ee6ba20..62c96f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,6 +14,21 @@ dependencies = [ "syn", ] +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +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.5.2" @@ -62,12 +77,56 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "async-trait" +version = "0.1.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "autocfg" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bech32" version = "0.9.1" @@ -95,6 +154,20 @@ dependencies = [ "subtle", ] +[[package]] +name = "bip0039" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "568b6890865156d9043af490d4c4081c385dd68ea10acd6ca15733d511e6b51c" +dependencies = [ + "hmac", + "pbkdf2", + "rand", + "sha2", + "unicode-normalization", + "zeroize", +] + [[package]] name = "bip32" version = "0.5.2" @@ -344,6 +417,15 @@ dependencies = [ "syn", ] +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + [[package]] name = "digest" version = "0.10.7" @@ -373,7 +455,7 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "equihash" version = "0.2.0" -source = "git+https://github.com/zcash/librustzcash?rev=5a4a3e06dcd2cf5bdf79a7cd48709b58693c65f0#5a4a3e06dcd2cf5bdf79a7cd48709b58693c65f0" +source = "git+https://github.com/ChainSafe/librustzcash?rev=c30f614ce2d78afebb0ef2587f71851e740ef28d#c30f614ce2d78afebb0ef2587f71851e740ef28d" dependencies = [ "blake2b_simd", "byteorder", @@ -398,7 +480,7 @@ dependencies = [ [[package]] name = "f4jumble" version = "0.1.0" -source = "git+https://github.com/zcash/librustzcash?rev=5a4a3e06dcd2cf5bdf79a7cd48709b58693c65f0#5a4a3e06dcd2cf5bdf79a7cd48709b58693c65f0" +source = "git+https://github.com/ChainSafe/librustzcash?rev=c30f614ce2d78afebb0ef2587f71851e740ef28d#c30f614ce2d78afebb0ef2587f71851e740ef28d" dependencies = [ "blake2b_simd", ] @@ -438,6 +520,12 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "fpe" version = "0.6.1" @@ -458,6 +546,58 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -481,6 +621,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + [[package]] name = "group" version = "0.13.0" @@ -575,11 +721,78 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" + +[[package]] +name = "hyper" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +dependencies = [ + "bytes", + "http", + "http-body", + "tokio", +] + +[[package]] +name = "hyper-util" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "tokio", +] + [[package]] name = "incrementalmerkletree" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1872810fb725b06b8c153dde9e86f3ec26747b9b60096da7a869883b549cbe" +checksum = "75346da3bd8e3d8891d02508245ed2df34447ca6637e343829f8d08986e9cde2" dependencies = [ "either", ] @@ -629,6 +842,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + [[package]] name = "js-sys" version = "0.3.69" @@ -763,18 +982,65 @@ dependencies = [ "nonempty", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi", + "libc", + "wasi", + "windows-sys 0.52.0", +] + [[package]] name = "multimap" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "nonempty" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9e591e719385e6ebaeb5ce5d3887f7d5676fceca6411d1925ccc95745f3d6f7" +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -785,6 +1051,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-integer" version = "0.1.46" @@ -813,6 +1085,15 @@ dependencies = [ "libc", ] +[[package]] +name = "object" +version = "0.36.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.19.0" @@ -827,9 +1108,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "orchard" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0462569fc8b0d1b158e4d640571867a4e4319225ebee2ab6647e60c70af19ae3" +checksum = "4dc7bde644aeb980be296cd908c6650894dc8541deb56f9f5294c52ed7ca568f" dependencies = [ "aes", "bitvec", @@ -850,11 +1131,18 @@ dependencies = [ "serde", "subtle", "tracing", + "visibility", "zcash_note_encryption", "zcash_spec", "zip32", ] +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "pairing" version = "0.23.0" @@ -864,6 +1152,17 @@ dependencies = [ "group", ] +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + [[package]] name = "pasta_curves" version = "0.5.1" @@ -879,6 +1178,22 @@ dependencies = [ "subtle", ] +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest", + "password-hash", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + [[package]] name = "petgraph" version = "0.6.5" @@ -889,12 +1204,38 @@ dependencies = [ "indexmap", ] +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "pin-project-lite" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "poly1305" version = "0.8.0" @@ -906,6 +1247,12 @@ dependencies = [ "universal-hash", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.20" @@ -939,6 +1286,15 @@ name = "prost" version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" +dependencies = [ + "bytes", +] + +[[package]] +name = "prost" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2ecbe40f08db5c006b5764a2645f7f3f141ce756412ac9e1dd6087e6d32995" dependencies = [ "bytes", "prost-derive", @@ -946,9 +1302,9 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.12.6" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" +checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302" dependencies = [ "bytes", "heck", @@ -958,7 +1314,7 @@ dependencies = [ "once_cell", "petgraph", "prettyplease", - "prost", + "prost 0.13.2", "prost-types", "regex", "syn", @@ -967,9 +1323,9 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.12.6" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" +checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac" dependencies = [ "anyhow", "itertools", @@ -980,11 +1336,11 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.12.6" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" +checksum = "60caa6738c7369b940c3d49246a8d1749323674c65cb13010134f5c9bad5b519" dependencies = [ - "prost", + "prost 0.13.2", ] [[package]] @@ -1121,6 +1477,12 @@ dependencies = [ "digest", ] +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + [[package]] name = "rustix" version = "0.38.34" @@ -1136,9 +1498,9 @@ dependencies = [ [[package]] name = "sapling-crypto" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02f4270033afcb0c74c5c7d59c73cfd1040367f67f224fe7ed9a919ae618f1b7" +checksum = "15e379398fffad84e49f9a45a05635fc004f66086e65942dbf4eb95332c26d2a" dependencies = [ "aes", "bellman", @@ -1230,6 +1592,52 @@ dependencies = [ "digest", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shardtree" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78222845cd8bbe5eb95687407648ff17693a35de5e8abaa39a4681fb21e033f9" +dependencies = [ + "bitflags", + "either", + "incrementalmerkletree", + "tracing", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "spin" version = "0.9.8" @@ -1298,6 +1706,35 @@ dependencies = [ "syn", ] +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + [[package]] name = "tinyvec" version = "1.8.0" @@ -1313,11 +1750,57 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "tokio" +version = "1.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +dependencies = [ + "backtrace", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-stream" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tonic" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f6ba989e4b2c58ae83d862d3a3e27690b6e3ae630d0deb59f3697f32aa88ad" +dependencies = [ + "async-trait", + "base64 0.22.1", + "bytes", + "http", + "http-body", + "http-body-util", + "percent-encoding", + "pin-project", + "prost 0.13.2", + "tokio-stream", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tonic-build" -version = "0.11.0" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4ef6dd70a610078cb4e338a0f79d06bc759ff1b22d2120c2ff02ae264ba9c2" +checksum = "fe4ee8877250136bd7e3d2331632810a4df4ea5e004656990d8d66d2f5ee8a67" dependencies = [ "prettyplease", "proc-macro2", @@ -1326,6 +1809,43 @@ dependencies = [ "syn", ] +[[package]] +name = "tonic-web-wasm-client" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5ca6e7bdd0042c440d36b6df97c1436f1d45871ce18298091f114004b1beb4" +dependencies = [ + "base64 0.22.1", + "byteorder", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "httparse", + "js-sys", + "pin-project", + "thiserror", + "tonic", + "tower-service", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + [[package]] name = "tracing" version = "0.1.40" @@ -1355,6 +1875,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "tracing-web" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e6a141feebd51f8d91ebfd785af50fca223c570b86852166caa3b141defe7c" +dependencies = [ + "js-sys", + "tracing-core", + "tracing-subscriber", + "wasm-bindgen", + "web-sys", ] [[package]] @@ -1381,6 +1940,15 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + [[package]] name = "universal-hash" version = "0.5.1" @@ -1401,12 +1969,29 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "visibility" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d674d135b4a8c1d7e813e2f8d1c9a58308aee4a680323066025e53132218bd91" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1504,6 +2089,19 @@ dependencies = [ "syn", ] +[[package]] +name = "wasm-streams" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.69" @@ -1518,19 +2116,28 @@ dependencies = [ name = "webz-core" version = "0.1.0" dependencies = [ + "bip0039", "console_error_panic_hook", + "futures-util", "getrandom", "indexed_db_futures", "js-sys", + "prost 0.12.6", "ripemd", + "secrecy", "sha2", "thiserror", - "tonic-build", + "tonic", + "tonic-web-wasm-client", + "tracing", + "tracing-subscriber", + "tracing-web", "wasm-bindgen", "wasm-bindgen-futures", "wasm-bindgen-test", "web-sys", - "which", + "zcash_client_backend", + "zcash_client_memory", "zcash_keys", "zcash_primitives", ] @@ -1547,6 +2154,28 @@ dependencies = [ "rustix", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-sys" version = "0.52.0" @@ -1640,8 +2269,8 @@ dependencies = [ [[package]] name = "zcash_address" -version = "0.3.2" -source = "git+https://github.com/zcash/librustzcash?rev=5a4a3e06dcd2cf5bdf79a7cd48709b58693c65f0#5a4a3e06dcd2cf5bdf79a7cd48709b58693c65f0" +version = "0.5.0" +source = "git+https://github.com/ChainSafe/librustzcash?rev=c30f614ce2d78afebb0ef2587f71851e740ef28d#c30f614ce2d78afebb0ef2587f71851e740ef28d" dependencies = [ "bech32", "bs58", @@ -1650,10 +2279,83 @@ dependencies = [ "zcash_protocol", ] +[[package]] +name = "zcash_client_backend" +version = "0.13.0" +source = "git+https://github.com/ChainSafe/librustzcash?rev=c30f614ce2d78afebb0ef2587f71851e740ef28d#c30f614ce2d78afebb0ef2587f71851e740ef28d" +dependencies = [ + "base64 0.21.7", + "bech32", + "bls12_381", + "bs58", + "byteorder", + "crossbeam-channel", + "document-features", + "group", + "hex", + "hyper-util", + "incrementalmerkletree", + "memuse", + "nom", + "nonempty", + "orchard", + "percent-encoding", + "prost 0.13.2", + "rand_core", + "rayon", + "sapling-crypto", + "secrecy", + "shardtree", + "subtle", + "time", + "tonic", + "tonic-build", + "tracing", + "which", + "zcash_address", + "zcash_encoding", + "zcash_keys", + "zcash_note_encryption", + "zcash_primitives", + "zcash_protocol", + "zip32", + "zip321", +] + +[[package]] +name = "zcash_client_memory" +version = "0.1.0" +source = "git+https://github.com/ChainSafe/librustzcash?rev=c30f614ce2d78afebb0ef2587f71851e740ef28d#c30f614ce2d78afebb0ef2587f71851e740ef28d" +dependencies = [ + "bs58", + "byteorder", + "group", + "incrementalmerkletree", + "jubjub", + "maybe-rayon", + "nonempty", + "orchard", + "prost 0.13.2", + "sapling-crypto", + "secrecy", + "shardtree", + "static_assertions", + "subtle", + "thiserror", + "tracing", + "zcash_address", + "zcash_client_backend", + "zcash_encoding", + "zcash_keys", + "zcash_primitives", + "zcash_protocol", + "zip32", +] + [[package]] name = "zcash_encoding" -version = "0.2.0" -source = "git+https://github.com/zcash/librustzcash?rev=5a4a3e06dcd2cf5bdf79a7cd48709b58693c65f0#5a4a3e06dcd2cf5bdf79a7cd48709b58693c65f0" +version = "0.2.1" +source = "git+https://github.com/ChainSafe/librustzcash?rev=c30f614ce2d78afebb0ef2587f71851e740ef28d#c30f614ce2d78afebb0ef2587f71851e740ef28d" dependencies = [ "byteorder", "nonempty", @@ -1661,8 +2363,8 @@ dependencies = [ [[package]] name = "zcash_keys" -version = "0.2.0" -source = "git+https://github.com/zcash/librustzcash?rev=5a4a3e06dcd2cf5bdf79a7cd48709b58693c65f0#5a4a3e06dcd2cf5bdf79a7cd48709b58693c65f0" +version = "0.3.0" +source = "git+https://github.com/ChainSafe/librustzcash?rev=c30f614ce2d78afebb0ef2587f71851e740ef28d#c30f614ce2d78afebb0ef2587f71851e740ef28d" dependencies = [ "bech32", "bip32", @@ -1702,8 +2404,8 @@ dependencies = [ [[package]] name = "zcash_primitives" -version = "0.15.1" -source = "git+https://github.com/zcash/librustzcash?rev=5a4a3e06dcd2cf5bdf79a7cd48709b58693c65f0#5a4a3e06dcd2cf5bdf79a7cd48709b58693c65f0" +version = "0.17.0" +source = "git+https://github.com/ChainSafe/librustzcash?rev=c30f614ce2d78afebb0ef2587f71851e740ef28d#c30f614ce2d78afebb0ef2587f71851e740ef28d" dependencies = [ "aes", "bip32", @@ -1740,8 +2442,8 @@ dependencies = [ [[package]] name = "zcash_protocol" -version = "0.1.1" -source = "git+https://github.com/zcash/librustzcash?rev=5a4a3e06dcd2cf5bdf79a7cd48709b58693c65f0#5a4a3e06dcd2cf5bdf79a7cd48709b58693c65f0" +version = "0.3.0" +source = "git+https://github.com/ChainSafe/librustzcash?rev=c30f614ce2d78afebb0ef2587f71851e740ef28d#c30f614ce2d78afebb0ef2587f71851e740ef28d" dependencies = [ "document-features", "memuse", @@ -1800,10 +2502,21 @@ dependencies = [ [[package]] name = "zip32" version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4226d0aee9c9407c27064dfeec9d7b281c917de3374e1e5a2e2cfad9e09de19e" +source = "git+https://github.com/zcash/zip32.git?branch=diversifier_index_ord#38e39b7086bbd5747dc61a84faf54ec9a58fa535" dependencies = [ "blake2b_simd", "memuse", "subtle", ] + +[[package]] +name = "zip321" +version = "0.1.0" +source = "git+https://github.com/ChainSafe/librustzcash?rev=c30f614ce2d78afebb0ef2587f71851e740ef28d#c30f614ce2d78afebb0ef2587f71851e740ef28d" +dependencies = [ + "base64 0.21.7", + "nom", + "percent-encoding", + "zcash_address", + "zcash_protocol", +] diff --git a/Cargo.toml b/Cargo.toml index 5212fe4..02de2bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,24 +20,40 @@ codegen-units = 1 wasm-opt = ["-O4", "-O4"] [dependencies] +## Web dependencies wasm-bindgen = "0.2.84" js-sys = "0.3.69" -zcash_keys = { git = "https://github.com/zcash/librustzcash", rev = "5a4a3e06dcd2cf5bdf79a7cd48709b58693c65f0", features = ["transparent-inputs", "orchard", "sapling", "unstable"] } -zcash_primitives = { git = "https://github.com/zcash/librustzcash", rev = "5a4a3e06dcd2cf5bdf79a7cd48709b58693c65f0" } +wasm-bindgen-futures = "0.4.42" +web-sys = { version = "0.3.69", features = ["console"] } + +## Zcash dependencies +zcash_keys = { git = "https://github.com/ChainSafe/librustzcash", rev = "c30f614ce2d78afebb0ef2587f71851e740ef28d", features = ["transparent-inputs", "orchard", "sapling", "unstable"] } +zcash_client_backend = { git = "https://github.com/ChainSafe/librustzcash", rev = "c30f614ce2d78afebb0ef2587f71851e740ef28d", features = ["lightwalletd-tonic"] } +zcash_client_memory = { git = "https://github.com/ChainSafe/librustzcash", rev = "c30f614ce2d78afebb0ef2587f71851e740ef28d", features = ["orchard"] } +zcash_primitives = { git = "https://github.com/ChainSafe/librustzcash", rev = "c30f614ce2d78afebb0ef2587f71851e740ef28d" } + +## gRPC Web dependencies +prost = { version = "0.12", default-features = false } +tonic = { version = "0.12", default-features = false, features = [ + "prost", +] } +tonic-web-wasm-client = "0.6.0" + getrandom = { version = "0.2", features = ["js"] } thiserror = "1.0.63" console_error_panic_hook = { version = "0.1.7", optional = true } -wasm-bindgen-futures = "0.4.42" indexed_db_futures = "0.5.0" -web-sys = { version = "0.3.69", features = ["console"] } sha2 = "0.10" ripemd = "0.1" +bip0039 = "0.12.0" +secrecy = "0.8.0" +futures-util = "0.3.30" +tracing-web = "0.1.3" +tracing-subscriber = "0.3.18" +tracing = "0.1.40" [dev-dependencies] wasm-bindgen-test = "0.3.42" -[build-dependencies] -tonic-build = { version = "0.11", default-features = false, features = [ - "prost", -] } -which = "4" +[patch.crates-io] +zip32 = { git = "https://github.com/zcash/zip32.git", branch = "diversifier_index_ord"} diff --git a/build.rs b/build.rs deleted file mode 100644 index 31001c2..0000000 --- a/build.rs +++ /dev/null @@ -1,85 +0,0 @@ -use std::env; -use std::fs; -use std::io; -use std::path::{Path, PathBuf}; - -// This build script is mostly copied from librustzcash - -const COMPACT_FORMATS_PROTO: &str = "protos/compact_formats.proto"; - -const SERVICE_PROTO: &str = "protos/service.proto"; - -fn main() -> io::Result<()> { - // - We don't include the proto files in releases so that downstreams do not need to - // regenerate the bindings even if protoc is present. - // - We check for the existence of protoc in the same way as prost_build, so that - // people building from source do not need to have protoc installed. If they make - // changes to the proto files, the discrepancy will be caught by CI. - if Path::new(COMPACT_FORMATS_PROTO).exists() - && env::var_os("PROTOC") - .map(PathBuf::from) - .or_else(|| which::which("protoc").ok()) - .is_some() - { - build()?; - } - - Ok(()) -} - -fn build() -> io::Result<()> { - let out: PathBuf = env::var_os("OUT_DIR") - .expect("Cannot find OUT_DIR environment variable") - .into(); - - // Build the compact format types. - tonic_build::compile_protos(COMPACT_FORMATS_PROTO)?; - - // Copy the generated types into the source tree so changes can be committed. - fs::copy( - out.join("cash.z.wallet.sdk.rpc.rs"), - "src/proto/compact_formats.rs", - )?; - - // Build the gRPC types and client. - tonic_build::configure() - .build_server(false) - .build_client(true) - // .client_mod_attribute( - // "cash.z.wallet.sdk.rpc", - // r#"#[cfg(feature = "lightwalletd-tonic")]"#, - // ) - .type_attribute(".cash.z.wallet.sdk.rpc.ChainMetadata", "#[derive(Debug)]") - .extern_path( - ".cash.z.wallet.sdk.rpc.ChainMetadata", - "crate::proto::compact_formats::ChainMetadata", - ) - .extern_path( - ".cash.z.wallet.sdk.rpc.CompactBlock", - "crate::proto::compact_formats::CompactBlock", - ) - .extern_path( - ".cash.z.wallet.sdk.rpc.CompactTx", - "crate::proto::compact_formats::CompactTx", - ) - .extern_path( - ".cash.z.wallet.sdk.rpc.CompactSaplingSpend", - "crate::proto::compact_formats::CompactSaplingSpend", - ) - .extern_path( - ".cash.z.wallet.sdk.rpc.CompactSaplingOutput", - "crate::proto::compact_formats::CompactSaplingOutput", - ) - .extern_path( - ".cash.z.wallet.sdk.rpc.CompactOrchardAction", - "crate::proto::compact_formats::CompactOrchardAction", - ) - .compile(&[SERVICE_PROTO], &["protos/"])?; - - // Copy the generated types into the source tree so changes can be committed. The - // file has the same name as for the compact format types because they have the - // same package, but we've set things up so this only contains the service types. - fs::copy(out.join("cash.z.wallet.sdk.rpc.rs"), "src/proto/service.rs")?; - - Ok(()) -} diff --git a/justfile b/justfile index 2d63c47..56b8dbf 100644 --- a/justfile +++ b/justfile @@ -5,7 +5,7 @@ build: wasm-pack build -t web --release --out-dir ./packages/webz-core test-web: - WASM_BINDGEN_TEST_TIMEOUT=99999 wasm-pack test --release --headless --chrome + WASM_BINDGEN_TEST_TIMEOUT=99999 wasm-pack test --release --firefox check: cargo check diff --git a/rust-toolchain.toml b/rust-toolchain.toml index ec8ccbf..d3ad8c1 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,4 @@ [toolchain] channel = "nightly-2024-08-07" -components = ["rust-src"] \ No newline at end of file +components = ["rust-src"] +targets = ["wasm32-unknown-unknown"] diff --git a/src/account.rs b/src/account.rs deleted file mode 100644 index c3b6e0d..0000000 --- a/src/account.rs +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2024 ChainSafe Systems -// SPDX-License-Identifier: Apache-2.0, MIT - -use sha2::{Digest, Sha256}; -use wasm_bindgen::prelude::*; -use zcash_keys::encoding::AddressCodec; -use zcash_keys::keys::{Era, UnifiedAddressRequest, UnifiedSpendingKey}; -use zcash_primitives::consensus::MAIN_NETWORK; -use zcash_primitives::legacy::TransparentAddress; -use zcash_primitives::zip32::{AccountId, DiversifierIndex}; - -use crate::error::Error; - -pub type AccountIndex = u32; - -#[wasm_bindgen] -pub struct Account { - #[wasm_bindgen(skip)] - pub usk: UnifiedSpendingKey, -} - -#[wasm_bindgen] -impl Account { - #[wasm_bindgen] - /// Derive a Zcash unified account from a seed and index for a given network configuration. - /// This will throw an error if the seed does not have at least 32 bits or if the account index is invalid - pub fn from_seed(seed: &[u8], account_index: AccountIndex) -> Result { - Ok(Account { - usk: UnifiedSpendingKey::from_seed( - &MAIN_NETWORK, - seed, - AccountId::try_from(account_index)?, - ) - .unwrap(), - }) - } - - #[wasm_bindgen] - pub fn to_bytes(&self) -> Vec { - self.usk.to_bytes(Era::Orchard) - } - - #[wasm_bindgen] - pub fn from_bytes(encoded: &[u8]) -> Result { - Ok(Account { - usk: UnifiedSpendingKey::from_bytes(Era::Orchard, encoded).unwrap(), - }) - } - - #[wasm_bindgen] - /// Return the string encoded address for this account. This returns a unified address with all address subtypes (orchard, sapling, p2pkh) - /// The diversifier index can be used to derive different valid addresses for the same account. Diversifier index must be > 0 - pub fn unified_address(&self, diversifier_index: u64) -> Result { - Ok(self - .usk - .to_unified_full_viewing_key() - .address( - DiversifierIndex::from(diversifier_index), - UnifiedAddressRequest::all().unwrap(), - )? - .encode(&MAIN_NETWORK)) - } - - #[wasm_bindgen] - /// Return the string encoded address for this accounts transparent address - /// Should this also support a diversifier? - pub fn transparent_address(&self) -> Result { - let pubkey = self.usk.transparent().to_account_pubkey(); - let t_address = TransparentAddress::PublicKeyHash( - *ripemd::Ripemd160::digest(Sha256::digest(pubkey.serialize())).as_ref(), - ); - Ok(t_address.encode(&MAIN_NETWORK)) - } -} diff --git a/src/bindgen/mod.rs b/src/bindgen/mod.rs new file mode 100644 index 0000000..2fff25c --- /dev/null +++ b/src/bindgen/mod.rs @@ -0,0 +1 @@ +pub mod wallet; diff --git a/src/bindgen/wallet.rs b/src/bindgen/wallet.rs new file mode 100644 index 0000000..0bc8c0b --- /dev/null +++ b/src/bindgen/wallet.rs @@ -0,0 +1,257 @@ +use std::collections::HashMap; + +use wasm_bindgen::prelude::*; + +use bip0039::{English, Mnemonic}; +use futures_util::{StreamExt, TryStreamExt}; +use secrecy::{SecretVec, Zeroize}; +use tonic_web_wasm_client::Client; + +use zcash_client_backend::data_api::{AccountBirthday, NullifierQuery, WalletRead, WalletWrite}; +use zcash_client_backend::proto::service; +use zcash_client_backend::proto::service::compact_tx_streamer_client::CompactTxStreamerClient; +use zcash_client_backend::scanning::{scan_block, Nullifiers, ScanningKeys}; +use zcash_client_memory::MemoryWalletDb; +use zcash_primitives::consensus; + +use crate::error::Error; + +/// # A Zcash wallet +/// +/// A wallet is a set of accounts that can be synchronized together with the blockchain. +/// Once synchronized these can be used to build transactions that spend notes +/// +/// ## Adding Accounts +/// +/// TODO +/// +/// ## Synchronizing +/// +/// A wallet can be syncced with the blockchain by feeding it blocks. The accounts currently managed by the wallet will be used to +/// scan the blocks and retrieve relevant transactions. The wallet itself keeps track of blocks it has seen and can be queried for +/// the suggest range of blocks that should be retrieved for it to process next. +/// +/// ## Building Transactions +/// +/// TODO +/// +#[wasm_bindgen] +pub struct Wallet { + /// Internal database used to maintain wallet data (e.g. accounts, transactions, cached blocks) + db: MemoryWalletDb, + // gRPC client used to connect to a lightwalletd instance for network data + client: CompactTxStreamerClient, + network: consensus::Network, + min_confirmations: u32, +} + +#[wasm_bindgen] +impl Wallet { + /// Create a new instance of a Zcash wallet for a given network + #[wasm_bindgen(constructor)] + pub fn new( + network: &str, + lightwalletd_url: &str, + max_checkpoints: usize, + min_confirmations: u32, + ) -> Result { + let network = match network { + "main" => consensus::Network::MainNetwork, + "test" => consensus::Network::TestNetwork, + _ => { + return Err(Error::InvalidNetwork(network.to_string())); + } + }; + + Ok(Wallet { + db: MemoryWalletDb::new(network, max_checkpoints), + client: CompactTxStreamerClient::new(Client::new(lightwalletd_url.to_string())), + network, + min_confirmations, + }) + } + + /// Add a new account to the wallet + /// + /// # Arguments + /// seed_phrase - mnemonic phrase to initialise the wallet + /// birthday_height - The block height at which the account was created, optionally None and the current height is used + /// + pub async fn create_account( + &mut self, + seed_phrase: &str, + birthday_height: Option, + ) -> Result { + // decode the mnemonic + let mnemonic = >::from_phrase(seed_phrase).unwrap(); + let seed = { + let mut seed = mnemonic.to_seed(""); + let secret = seed.to_vec(); + seed.zeroize(); + SecretVec::new(secret) + }; + + let birthday = match birthday_height { + Some(height) => height, + None => { + let chain_tip: u32 = self + .client + .get_latest_block(service::ChainSpec::default()) + .await? + .into_inner() + .height + .try_into() + .expect("block heights must fit into u32"); + chain_tip - 100 + } + }; + // Construct an `AccountBirthday` for the account's birthday. + let birthday = { + // Fetch the tree state corresponding to the last block prior to the wallet's + // birthday height. NOTE: THIS APPROACH LEAKS THE BIRTHDAY TO THE SERVER! + let request = service::BlockId { + height: (birthday - 1).into(), + ..Default::default() + }; + let treestate = self.client.get_tree_state(request).await?.into_inner(); + AccountBirthday::from_treestate(treestate, None).map_err(|_| Error::BirthdayError)? + }; + + let (id, _spending_key) = self.db.create_account(&seed, &birthday)?; + Ok(id.to_string()) + } + + pub fn suggest_scan_ranges(&self) -> Result, Error> { + Ok(self.db.suggest_scan_ranges().map(|ranges| { + ranges + .iter() + .map(|scan_range| { + BlockRange( + scan_range.block_range().start.into(), + scan_range.block_range().end.into(), + ) + }) + .collect() + })?) + } + + /// Fully sync the wallet with the blockchain calling the provided callback with progress updates + pub async fn get_and_scan_range(&mut self, start: u32, end: u32) -> Result<(), Error> { + let range = service::BlockRange { + start: Some(service::BlockId { + height: start.into(), + ..Default::default() + }), + end: Some(service::BlockId { + height: end.into(), + ..Default::default() + }), + }; + + // get the chainstate prior to the range + let tree_state = self + .client + .get_tree_state(service::BlockId { + height: (start - 1).into(), + ..Default::default() + }) + .await?; + + let chainstate = tree_state.into_inner().to_chain_state()?; + + // Get the scanning keys from the DB + let account_ufvks = self.db.get_unified_full_viewing_keys()?; + let scanning_keys = ScanningKeys::from_account_ufvks(account_ufvks); + + // Get the nullifiers for the unspent notes we are tracking + let nullifiers = Nullifiers::new( + self.db.get_sapling_nullifiers(NullifierQuery::Unspent)?, + self.db.get_orchard_nullifiers(NullifierQuery::Unspent)?, + ); + + // convert the compact blocks into ScannedBlocks + // TODO: We can tweak how we batch and collect this stream in the future + // to optimize for parallelism and memory usage + let scanned_blocks = self + .client + .get_block_range(range) + .await? + .into_inner() + .map(|compact_block| { + scan_block( + &self.network, + compact_block.unwrap(), + &scanning_keys, + &nullifiers, + None, + ) + }) + .try_collect() + .await?; + + self.db.put_blocks(&chainstate, scanned_blocks)?; + Ok(()) + } + + pub fn get_wallet_summary(&self) -> Result, Error> { + Ok(self + .db + .get_wallet_summary(self.min_confirmations)? + .map(Into::into)) + } +} + +#[wasm_bindgen] +pub struct BlockRange(pub u32, pub u32); + +#[wasm_bindgen] +#[allow(dead_code)] +#[derive(Debug)] +pub struct WalletSummary { + account_balances: HashMap, + chain_tip_height: u32, + fully_scanned_height: u32, + // scan_progress: Option>, + next_sapling_subtree_index: u64, + next_orchard_subtree_index: u64, +} + +#[wasm_bindgen] +#[allow(dead_code)] +#[derive(Debug)] +pub struct AccountBalance { + sapling_balance: u64, + orchard_balance: u64, + unshielded_balance: u64, +} + +impl From for AccountBalance { + fn from(balance: zcash_client_backend::data_api::AccountBalance) -> Self { + AccountBalance { + sapling_balance: balance.sapling_balance().spendable_value().into(), + orchard_balance: balance.orchard_balance().spendable_value().into(), + unshielded_balance: balance.unshielded().into(), + } + } +} + +impl From> for WalletSummary +where + T: std::cmp::Eq + std::hash::Hash + std::ops::Deref + Clone, +{ + fn from(summary: zcash_client_backend::data_api::WalletSummary) -> Self { + let account_balances = summary + .account_balances() + .iter() + .map(|(k, v)| (*(*k).clone().deref(), (*v).into())) + .collect(); + + WalletSummary { + account_balances, + chain_tip_height: summary.chain_tip_height().into(), + fully_scanned_height: summary.fully_scanned_height().into(), + next_sapling_subtree_index: summary.next_sapling_subtree_index(), + next_orchard_subtree_index: summary.next_orchard_subtree_index(), + } + } +} diff --git a/src/error.rs b/src/error.rs index ae791ec..2f6a0d5 100644 --- a/src/error.rs +++ b/src/error.rs @@ -21,6 +21,18 @@ pub enum Error { }, #[error("Address generation error")] AddressGenerationError(#[from] zcash_keys::keys::AddressGenerationError), + #[error("Invalid network string given: {0}")] + InvalidNetwork(String), + #[error("Error returned from GRPC server: {0}")] + GrpcError(#[from] tonic::Status), + #[error("Error handling wallet birthday")] + BirthdayError, + #[error("Memory client error: {0}")] + MemoryClientError(#[from] zcash_client_memory::Error), + #[error("Error scanning: {0}")] + ScanError(zcash_client_backend::scanning::ScanError), + #[error("IO Error: {0}")] + IoError(#[from] std::io::Error), } impl From for JsValue { @@ -44,3 +56,9 @@ impl From for Error { } } } + +impl From for Error { + fn from(e: zcash_client_backend::scanning::ScanError) -> Self { + Self::ScanError(e) + } +} diff --git a/src/init.rs b/src/init.rs index 5c8592e..e528a90 100644 --- a/src/init.rs +++ b/src/init.rs @@ -3,7 +3,9 @@ use wasm_bindgen::prelude::*; -pub fn set_panic_hook() { +use tracing_web::MakeWebConsoleWriter; + +fn set_panic_hook() { // When the `console_error_panic_hook` feature is enabled, we can call the // `set_panic_hook` function at least once during initialization, and then // we will get better error messages if our code ever panics. @@ -14,7 +16,17 @@ pub fn set_panic_hook() { console_error_panic_hook::set_once(); } +fn setup_tracing() { + let subscriber = tracing_subscriber::fmt() + .with_ansi(false) + .with_writer(MakeWebConsoleWriter::new()) + .without_time() // time breaks if used in browser + .finish(); + tracing::subscriber::set_global_default(subscriber).expect("setting default subscriber failed"); +} + #[wasm_bindgen(start)] pub fn start() { set_panic_hook(); + setup_tracing(); } diff --git a/src/lib.rs b/src/lib.rs index 76ea0d3..56de117 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,10 +2,9 @@ // SPDX-License-Identifier: Apache-2.0, MIT //! This is the top level documentation! -#![allow(async_fn_in_trait)] -pub mod account; +pub mod bindgen; pub mod error; pub mod init; -pub mod store; -pub mod wallet; + +pub use bindgen::wallet::Wallet; diff --git a/src/proto/compact_formats.rs b/src/proto/compact_formats.rs deleted file mode 100644 index 67acb4c..0000000 --- a/src/proto/compact_formats.rs +++ /dev/null @@ -1,119 +0,0 @@ -// This file is @generated by prost-build. -/// ChainMetadata represents information about the state of the chain as of a given block. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ChainMetadata { - /// the size of the Sapling note commitment tree as of the end of this block - #[prost(uint32, tag = "1")] - pub sapling_commitment_tree_size: u32, - /// the size of the Orchard note commitment tree as of the end of this block - #[prost(uint32, tag = "2")] - pub orchard_commitment_tree_size: u32, -} -/// CompactBlock is a packaging of ONLY the data from a block that's needed to: -/// 1. Detect a payment to your shielded Sapling address -/// 2. Detect a spend of your shielded Sapling notes -/// 3. Update your witnesses to generate new Sapling spend proofs. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct CompactBlock { - /// the version of this wire format, for storage - #[prost(uint32, tag = "1")] - pub proto_version: u32, - /// the height of this block - #[prost(uint64, tag = "2")] - pub height: u64, - /// the ID (hash) of this block, same as in block explorers - #[prost(bytes = "vec", tag = "3")] - pub hash: ::prost::alloc::vec::Vec, - /// the ID (hash) of this block's predecessor - #[prost(bytes = "vec", tag = "4")] - pub prev_hash: ::prost::alloc::vec::Vec, - /// Unix epoch time when the block was mined - #[prost(uint32, tag = "5")] - pub time: u32, - /// (hash, prevHash, and time) OR (full header) - #[prost(bytes = "vec", tag = "6")] - pub header: ::prost::alloc::vec::Vec, - /// zero or more compact transactions from this block - #[prost(message, repeated, tag = "7")] - pub vtx: ::prost::alloc::vec::Vec, - /// information about the state of the chain as of this block - #[prost(message, optional, tag = "8")] - pub chain_metadata: ::core::option::Option, -} -/// CompactTx contains the minimum information for a wallet to know if this transaction -/// is relevant to it (either pays to it or spends from it) via shielded elements -/// only. This message will not encode a transparent-to-transparent transaction. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct CompactTx { - /// Index and hash will allow the receiver to call out to chain - /// explorers or other data structures to retrieve more information - /// about this transaction. - /// - /// the index within the full block - #[prost(uint64, tag = "1")] - pub index: u64, - /// the ID (hash) of this transaction, same as in block explorers - #[prost(bytes = "vec", tag = "2")] - pub hash: ::prost::alloc::vec::Vec, - /// The transaction fee: present if server can provide. In the case of a - /// stateless server and a transaction with transparent inputs, this will be - /// unset because the calculation requires reference to prior transactions. - /// If there are no transparent inputs, the fee will be calculable as: - /// valueBalanceSapling + valueBalanceOrchard + sum(vPubNew) - sum(vPubOld) - sum(tOut) - #[prost(uint32, tag = "3")] - pub fee: u32, - #[prost(message, repeated, tag = "4")] - pub spends: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "5")] - pub outputs: ::prost::alloc::vec::Vec, - #[prost(message, repeated, tag = "6")] - pub actions: ::prost::alloc::vec::Vec, -} -/// CompactSaplingSpend is a Sapling Spend Description as described in 7.3 of the Zcash -/// protocol specification. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct CompactSaplingSpend { - /// nullifier (see the Zcash protocol specification) - #[prost(bytes = "vec", tag = "1")] - pub nf: ::prost::alloc::vec::Vec, -} -/// output encodes the `cmu` field, `ephemeralKey` field, and a 52-byte prefix of the -/// `encCiphertext` field of a Sapling Output Description. These fields are described in -/// section 7.4 of the Zcash protocol spec: -/// -/// Total size is 116 bytes. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct CompactSaplingOutput { - /// note commitment u-coordinate - #[prost(bytes = "vec", tag = "1")] - pub cmu: ::prost::alloc::vec::Vec, - /// ephemeral public key - #[prost(bytes = "vec", tag = "2")] - pub ephemeral_key: ::prost::alloc::vec::Vec, - /// first 52 bytes of ciphertext - #[prost(bytes = "vec", tag = "3")] - pub ciphertext: ::prost::alloc::vec::Vec, -} -/// -/// (but not all fields are needed) -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct CompactOrchardAction { - /// \[32\] The nullifier of the input note - #[prost(bytes = "vec", tag = "1")] - pub nullifier: ::prost::alloc::vec::Vec, - /// \[32\] The x-coordinate of the note commitment for the output note - #[prost(bytes = "vec", tag = "2")] - pub cmx: ::prost::alloc::vec::Vec, - /// \[32\] An encoding of an ephemeral Pallas public key - #[prost(bytes = "vec", tag = "3")] - pub ephemeral_key: ::prost::alloc::vec::Vec, - /// \[52\] The first 52 bytes of the encCiphertext field - #[prost(bytes = "vec", tag = "4")] - pub ciphertext: ::prost::alloc::vec::Vec, -} diff --git a/src/proto/service.rs b/src/proto/service.rs deleted file mode 100644 index 26dfa93..0000000 --- a/src/proto/service.rs +++ /dev/null @@ -1,927 +0,0 @@ -// This file is @generated by prost-build. -/// A BlockID message contains identifiers to select a block: a height or a -/// hash. Specification by hash is not implemented, but may be in the future. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BlockId { - #[prost(uint64, tag = "1")] - pub height: u64, - #[prost(bytes = "vec", tag = "2")] - pub hash: ::prost::alloc::vec::Vec, -} -/// BlockRange specifies a series of blocks from start to end inclusive. -/// Both BlockIDs must be heights; specification by hash is not yet supported. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct BlockRange { - #[prost(message, optional, tag = "1")] - pub start: ::core::option::Option, - #[prost(message, optional, tag = "2")] - pub end: ::core::option::Option, -} -/// A TxFilter contains the information needed to identify a particular -/// transaction: either a block and an index, or a direct transaction hash. -/// Currently, only specification by hash is supported. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct TxFilter { - /// block identifier, height or hash - #[prost(message, optional, tag = "1")] - pub block: ::core::option::Option, - /// index within the block - #[prost(uint64, tag = "2")] - pub index: u64, - /// transaction ID (hash, txid) - #[prost(bytes = "vec", tag = "3")] - pub hash: ::prost::alloc::vec::Vec, -} -/// RawTransaction contains the complete transaction data. It also optionally includes -/// the block height in which the transaction was included, or, when returned -/// by GetMempoolStream(), the latest block height. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct RawTransaction { - /// exact data returned by Zcash 'getrawtransaction' - #[prost(bytes = "vec", tag = "1")] - pub data: ::prost::alloc::vec::Vec, - /// height that the transaction was mined (or -1) - #[prost(uint64, tag = "2")] - pub height: u64, -} -/// A SendResponse encodes an error code and a string. It is currently used -/// only by SendTransaction(). If error code is zero, the operation was -/// successful; if non-zero, it and the message specify the failure. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SendResponse { - #[prost(int32, tag = "1")] - pub error_code: i32, - #[prost(string, tag = "2")] - pub error_message: ::prost::alloc::string::String, -} -/// Chainspec is a placeholder to allow specification of a particular chain fork. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct ChainSpec {} -/// Empty is for gRPCs that take no arguments, currently only GetLightdInfo. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Empty {} -/// LightdInfo returns various information about this lightwalletd instance -/// and the state of the blockchain. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct LightdInfo { - #[prost(string, tag = "1")] - pub version: ::prost::alloc::string::String, - #[prost(string, tag = "2")] - pub vendor: ::prost::alloc::string::String, - /// true - #[prost(bool, tag = "3")] - pub taddr_support: bool, - /// either "main" or "test" - #[prost(string, tag = "4")] - pub chain_name: ::prost::alloc::string::String, - /// depends on mainnet or testnet - #[prost(uint64, tag = "5")] - pub sapling_activation_height: u64, - /// protocol identifier, see consensus/upgrades.cpp - #[prost(string, tag = "6")] - pub consensus_branch_id: ::prost::alloc::string::String, - /// latest block on the best chain - #[prost(uint64, tag = "7")] - pub block_height: u64, - #[prost(string, tag = "8")] - pub git_commit: ::prost::alloc::string::String, - #[prost(string, tag = "9")] - pub branch: ::prost::alloc::string::String, - #[prost(string, tag = "10")] - pub build_date: ::prost::alloc::string::String, - #[prost(string, tag = "11")] - pub build_user: ::prost::alloc::string::String, - /// less than tip height if zcashd is syncing - #[prost(uint64, tag = "12")] - pub estimated_height: u64, - /// example: "v4.1.1-877212414" - #[prost(string, tag = "13")] - pub zcashd_build: ::prost::alloc::string::String, - /// example: "/MagicBean:4.1.1/" - #[prost(string, tag = "14")] - pub zcashd_subversion: ::prost::alloc::string::String, -} -/// TransparentAddressBlockFilter restricts the results to the given address -/// or block range. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct TransparentAddressBlockFilter { - /// t-address - #[prost(string, tag = "1")] - pub address: ::prost::alloc::string::String, - /// start, end heights - #[prost(message, optional, tag = "2")] - pub range: ::core::option::Option, -} -/// Duration is currently used only for testing, so that the Ping rpc -/// can simulate a delay, to create many simultaneous connections. Units -/// are microseconds. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Duration { - #[prost(int64, tag = "1")] - pub interval_us: i64, -} -/// PingResponse is used to indicate concurrency, how many Ping rpcs -/// are executing upon entry and upon exit (after the delay). -/// This rpc is used for testing only. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct PingResponse { - #[prost(int64, tag = "1")] - pub entry: i64, - #[prost(int64, tag = "2")] - pub exit: i64, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Address { - #[prost(string, tag = "1")] - pub address: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct AddressList { - #[prost(string, repeated, tag = "1")] - pub addresses: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Balance { - #[prost(int64, tag = "1")] - pub value_zat: i64, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct Exclude { - #[prost(bytes = "vec", repeated, tag = "1")] - pub txid: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec>, -} -/// The TreeState is derived from the Zcash z_gettreestate rpc. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct TreeState { - /// "main" or "test" - #[prost(string, tag = "1")] - pub network: ::prost::alloc::string::String, - /// block height - #[prost(uint64, tag = "2")] - pub height: u64, - /// block id - #[prost(string, tag = "3")] - pub hash: ::prost::alloc::string::String, - /// Unix epoch time when the block was mined - #[prost(uint32, tag = "4")] - pub time: u32, - /// sapling commitment tree state - #[prost(string, tag = "5")] - pub sapling_tree: ::prost::alloc::string::String, - /// orchard commitment tree state - #[prost(string, tag = "6")] - pub orchard_tree: ::prost::alloc::string::String, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GetSubtreeRootsArg { - /// Index identifying where to start returning subtree roots - #[prost(uint32, tag = "1")] - pub start_index: u32, - /// Shielded protocol to return subtree roots for - #[prost(enumeration = "ShieldedProtocol", tag = "2")] - pub shielded_protocol: i32, - /// Maximum number of entries to return, or 0 for all entries. - #[prost(uint32, tag = "3")] - pub max_entries: u32, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct SubtreeRoot { - /// The 32-byte Merkle root of the subtree. - #[prost(bytes = "vec", tag = "2")] - pub root_hash: ::prost::alloc::vec::Vec, - /// The hash of the block that completed this subtree. - #[prost(bytes = "vec", tag = "3")] - pub completing_block_hash: ::prost::alloc::vec::Vec, - /// The height of the block that completed this subtree in the main chain. - #[prost(uint64, tag = "4")] - pub completing_block_height: u64, -} -/// Results are sorted by height, which makes it easy to issue another -/// request that picks up from where the previous left off. -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GetAddressUtxosArg { - #[prost(string, repeated, tag = "1")] - pub addresses: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, - #[prost(uint64, tag = "2")] - pub start_height: u64, - /// zero means unlimited - #[prost(uint32, tag = "3")] - pub max_entries: u32, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GetAddressUtxosReply { - #[prost(string, tag = "6")] - pub address: ::prost::alloc::string::String, - #[prost(bytes = "vec", tag = "1")] - pub txid: ::prost::alloc::vec::Vec, - #[prost(int32, tag = "2")] - pub index: i32, - #[prost(bytes = "vec", tag = "3")] - pub script: ::prost::alloc::vec::Vec, - #[prost(int64, tag = "4")] - pub value_zat: i64, - #[prost(uint64, tag = "5")] - pub height: u64, -} -#[allow(clippy::derive_partial_eq_without_eq)] -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct GetAddressUtxosReplyList { - #[prost(message, repeated, tag = "1")] - pub address_utxos: ::prost::alloc::vec::Vec, -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] -#[repr(i32)] -pub enum ShieldedProtocol { - Sapling = 0, - Orchard = 1, -} -impl ShieldedProtocol { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - ShieldedProtocol::Sapling => "sapling", - ShieldedProtocol::Orchard => "orchard", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "sapling" => Some(Self::Sapling), - "orchard" => Some(Self::Orchard), - _ => None, - } - } -} -/// Generated client implementations. -pub mod compact_tx_streamer_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] - use tonic::codegen::*; - use tonic::codegen::http::Uri; - #[derive(Debug, Clone)] - pub struct CompactTxStreamerClient { - inner: tonic::client::Grpc, - } - impl CompactTxStreamerClient - where - T: tonic::client::GrpcService, - T::Error: Into, - T::ResponseBody: Body + Send + 'static, - ::Error: Into + Send, - { - pub fn new(inner: T) -> Self { - let inner = tonic::client::Grpc::new(inner); - Self { inner } - } - pub fn with_origin(inner: T, origin: Uri) -> Self { - let inner = tonic::client::Grpc::with_origin(inner, origin); - Self { inner } - } - pub fn with_interceptor( - inner: T, - interceptor: F, - ) -> CompactTxStreamerClient> - where - F: tonic::service::Interceptor, - T::ResponseBody: Default, - T: tonic::codegen::Service< - http::Request, - Response = http::Response< - >::ResponseBody, - >, - >, - , - >>::Error: Into + Send + Sync, - { - CompactTxStreamerClient::new(InterceptedService::new(inner, interceptor)) - } - /// Compress requests with the given encoding. - /// - /// This requires the server to support it otherwise it might respond with an - /// error. - #[must_use] - pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.send_compressed(encoding); - self - } - /// Enable decompressing responses. - #[must_use] - pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.accept_compressed(encoding); - self - } - /// Limits the maximum size of a decoded message. - /// - /// Default: `4MB` - #[must_use] - pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_decoding_message_size(limit); - self - } - /// Limits the maximum size of an encoded message. - /// - /// Default: `usize::MAX` - #[must_use] - pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_encoding_message_size(limit); - self - } - /// Return the height of the tip of the best chain - pub async fn get_latest_block( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetLatestBlock", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new( - "cash.z.wallet.sdk.rpc.CompactTxStreamer", - "GetLatestBlock", - ), - ); - self.inner.unary(req, path, codec).await - } - /// Return the compact block corresponding to the given block identifier - pub async fn get_block( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetBlock", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new( - "cash.z.wallet.sdk.rpc.CompactTxStreamer", - "GetBlock", - ), - ); - self.inner.unary(req, path, codec).await - } - /// Same as GetBlock except actions contain only nullifiers - pub async fn get_block_nullifiers( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetBlockNullifiers", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new( - "cash.z.wallet.sdk.rpc.CompactTxStreamer", - "GetBlockNullifiers", - ), - ); - self.inner.unary(req, path, codec).await - } - /// Return a list of consecutive compact blocks - pub async fn get_block_range( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response< - tonic::codec::Streaming, - >, - tonic::Status, - > { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetBlockRange", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new( - "cash.z.wallet.sdk.rpc.CompactTxStreamer", - "GetBlockRange", - ), - ); - self.inner.server_streaming(req, path, codec).await - } - /// Same as GetBlockRange except actions contain only nullifiers - pub async fn get_block_range_nullifiers( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response< - tonic::codec::Streaming, - >, - tonic::Status, - > { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetBlockRangeNullifiers", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new( - "cash.z.wallet.sdk.rpc.CompactTxStreamer", - "GetBlockRangeNullifiers", - ), - ); - self.inner.server_streaming(req, path, codec).await - } - /// Return the requested full (not compact) transaction (as from zcashd) - pub async fn get_transaction( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetTransaction", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new( - "cash.z.wallet.sdk.rpc.CompactTxStreamer", - "GetTransaction", - ), - ); - self.inner.unary(req, path, codec).await - } - /// Submit the given transaction to the Zcash network - pub async fn send_transaction( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/cash.z.wallet.sdk.rpc.CompactTxStreamer/SendTransaction", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new( - "cash.z.wallet.sdk.rpc.CompactTxStreamer", - "SendTransaction", - ), - ); - self.inner.unary(req, path, codec).await - } - /// Return the transactions corresponding to the given t-address within the given block range - /// NB - this method is misnamed, it returns transactions, not transaction IDs. - pub async fn get_taddress_txids( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response>, - tonic::Status, - > { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetTaddressTxids", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new( - "cash.z.wallet.sdk.rpc.CompactTxStreamer", - "GetTaddressTxids", - ), - ); - self.inner.server_streaming(req, path, codec).await - } - pub async fn get_taddress_balance( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetTaddressBalance", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new( - "cash.z.wallet.sdk.rpc.CompactTxStreamer", - "GetTaddressBalance", - ), - ); - self.inner.unary(req, path, codec).await - } - pub async fn get_taddress_balance_stream( - &mut self, - request: impl tonic::IntoStreamingRequest, - ) -> std::result::Result, tonic::Status> { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetTaddressBalanceStream", - ); - let mut req = request.into_streaming_request(); - req.extensions_mut() - .insert( - GrpcMethod::new( - "cash.z.wallet.sdk.rpc.CompactTxStreamer", - "GetTaddressBalanceStream", - ), - ); - self.inner.client_streaming(req, path, codec).await - } - /// Return the compact transactions currently in the mempool; the results - /// can be a few seconds out of date. If the Exclude list is empty, return - /// all transactions; otherwise return all *except* those in the Exclude list - /// (if any); this allows the client to avoid receiving transactions that it - /// already has (from an earlier call to this rpc). The transaction IDs in the - /// Exclude list can be shortened to any number of bytes to make the request - /// more bandwidth-efficient; if two or more transactions in the mempool - /// match a shortened txid, they are all sent (none is excluded). Transactions - /// in the exclude list that don't exist in the mempool are ignored. - pub async fn get_mempool_tx( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response< - tonic::codec::Streaming, - >, - tonic::Status, - > { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetMempoolTx", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new( - "cash.z.wallet.sdk.rpc.CompactTxStreamer", - "GetMempoolTx", - ), - ); - self.inner.server_streaming(req, path, codec).await - } - /// Return a stream of current Mempool transactions. This will keep the output stream open while - /// there are mempool transactions. It will close the returned stream when a new block is mined. - pub async fn get_mempool_stream( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response>, - tonic::Status, - > { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetMempoolStream", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new( - "cash.z.wallet.sdk.rpc.CompactTxStreamer", - "GetMempoolStream", - ), - ); - self.inner.server_streaming(req, path, codec).await - } - /// GetTreeState returns the note commitment tree state corresponding to the given block. - /// See section 3.7 of the Zcash protocol specification. It returns several other useful - /// values also (even though they can be obtained using GetBlock). - /// The block can be specified by either height or hash. - pub async fn get_tree_state( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetTreeState", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new( - "cash.z.wallet.sdk.rpc.CompactTxStreamer", - "GetTreeState", - ), - ); - self.inner.unary(req, path, codec).await - } - pub async fn get_latest_tree_state( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetLatestTreeState", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new( - "cash.z.wallet.sdk.rpc.CompactTxStreamer", - "GetLatestTreeState", - ), - ); - self.inner.unary(req, path, codec).await - } - /// Returns a stream of information about roots of subtrees of the note commitment tree - /// for the specified shielded protocol (Sapling or Orchard). - pub async fn get_subtree_roots( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response>, - tonic::Status, - > { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetSubtreeRoots", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new( - "cash.z.wallet.sdk.rpc.CompactTxStreamer", - "GetSubtreeRoots", - ), - ); - self.inner.server_streaming(req, path, codec).await - } - pub async fn get_address_utxos( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetAddressUtxos", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new( - "cash.z.wallet.sdk.rpc.CompactTxStreamer", - "GetAddressUtxos", - ), - ); - self.inner.unary(req, path, codec).await - } - pub async fn get_address_utxos_stream( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response>, - tonic::Status, - > { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetAddressUtxosStream", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new( - "cash.z.wallet.sdk.rpc.CompactTxStreamer", - "GetAddressUtxosStream", - ), - ); - self.inner.server_streaming(req, path, codec).await - } - /// Return information about this lightwalletd instance and the blockchain - pub async fn get_lightd_info( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/cash.z.wallet.sdk.rpc.CompactTxStreamer/GetLightdInfo", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new( - "cash.z.wallet.sdk.rpc.CompactTxStreamer", - "GetLightdInfo", - ), - ); - self.inner.unary(req, path, codec).await - } - /// Testing-only, requires lightwalletd --ping-very-insecure (do not enable in production) - pub async fn ping( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { - self.inner - .ready() - .await - .map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/cash.z.wallet.sdk.rpc.CompactTxStreamer/Ping", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert( - GrpcMethod::new("cash.z.wallet.sdk.rpc.CompactTxStreamer", "Ping"), - ); - self.inner.unary(req, path, codec).await - } - } -} diff --git a/src/store/indexed_db_store.rs b/src/store/indexed_db_store.rs deleted file mode 100644 index 88eecc7..0000000 --- a/src/store/indexed_db_store.rs +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2024 ChainSafe Systems -// SPDX-License-Identifier: Apache-2.0, MIT - -use crate::error::Error; -use crate::store::WalletStore; -use indexed_db_futures::prelude::*; -use js_sys::Uint8Array; -use wasm_bindgen::JsValue; - -static DB_NAME: &str = "test_db"; -static KV_STORE: &str = "kv_store"; -/// A simple IndexedDb store for wallet data -pub struct IdbStore { - pub inner: indexed_db_futures::IdbDatabase, -} - -impl WalletStore for IdbStore { - async fn update(&mut self, key: &str, value: &[u8]) -> Result<(), Error> { - let tx = self - .inner - .transaction_on_one_with_mode(KV_STORE, IdbTransactionMode::Readwrite)?; - let store = tx.object_store(KV_STORE)?; - - store.put_key_val_owned(JsValue::from_str(key), &Uint8Array::from(value))?; - tx.await.into_result()?; - Ok(()) - } - - async fn get(&self, key: &str) -> Result>, Error> { - let tx = self - .inner - .transaction_on_one_with_mode(KV_STORE, IdbTransactionMode::Readonly)?; - let store = tx.object_store(KV_STORE)?; - match store.get(&JsValue::from_str(key))?.await? { - Some(v) => { - let v = Uint8Array::from(v); - Ok(Some(v.to_vec())) - } - None => Ok(None), - } - } - - async fn clear(&mut self, key: &str) -> Result<(), Error> { - let tx = self - .inner - .transaction_on_one_with_mode(KV_STORE, IdbTransactionMode::Readwrite)?; - let store = tx.object_store(KV_STORE)?; - store.delete_owned(JsValue::from_str(key))?; - tx.await.into_result()?; - Ok(()) - } -} - -impl IdbStore { - pub async fn new() -> Result { - let mut db_req = IdbDatabase::open_u32(DB_NAME, 1)?; - // let db = open.await?; - db_req.set_on_upgrade_needed(Some(|evt: &IdbVersionChangeEvent| -> Result<(), JsValue> { - let create_store_if_needed = - |evt: &IdbVersionChangeEvent, store_key: &'static str| -> Result<(), JsValue> { - if !evt.db().object_store_names().any(|n| n == store_key) { - evt.db().create_object_store(store_key)?; - } - Ok(()) - }; - create_store_if_needed(evt, KV_STORE)?; - Ok(()) - })); - Ok(Self { - inner: db_req.await?, - }) - } -} diff --git a/src/store/injected_store.rs b/src/store/injected_store.rs deleted file mode 100644 index c3b0f47..0000000 --- a/src/store/injected_store.rs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2024 ChainSafe Systems -// SPDX-License-Identifier: Apache-2.0, MIT - -use crate::error::Error; -use crate::store::WalletStore; -use wasm_bindgen::prelude::*; - -#[wasm_bindgen(typescript_custom_section)] -const IWALLET_STORAGE: &'static str = r#" -/** - * Interface over a string indexed key-value store for byte payloads - */ -interface IWalletStore { - /** - * Update the value for a given key in store (or set it for the first time) - */ - update(key: string, value: Uint8Array): Promise; - /** - * Get the value at a given key - */ - get(key: string): Promise; - /** - * Clear the value at a given key - */ - clear(key: string): Promise; -} -"#; - -#[wasm_bindgen] -extern "C" { - #[wasm_bindgen(typescript_type = "IWalletStore")] - /// This is a store implementation injected by the host js environment - /// This allows for writing thin wrappers in javascript to use BrowserStorage, Local Storage, - /// or Snap Storage to store data for the wallet - pub type InjectedStore; - - #[wasm_bindgen(method, catch)] - pub async fn update(this: &InjectedStore, index: &str, value: &[u8]) -> Result<(), JsValue>; - - #[wasm_bindgen(method, catch)] - pub async fn get(this: &InjectedStore, index: &str) -> Result; - - #[wasm_bindgen(method, catch)] - pub async fn clear(this: &InjectedStore, index: &str) -> Result<(), JsValue>; -} - -impl WalletStore for InjectedStore { - async fn update(&mut self, key: &str, value: &[u8]) -> Result<(), Error> { - InjectedStore::update(self, key, value).await?; - Ok(()) - } - - async fn get(&self, key: &str) -> Result>, Error> { - let result = InjectedStore::get(self, key).await?; - if result.is_null() { - return Ok(None); - } - Ok(Some(js_sys::Uint8Array::new(&result).to_vec())) - } - - async fn clear(&mut self, key: &str) -> Result<(), Error> { - InjectedStore::clear(self, key).await?; - Ok(()) - } -} diff --git a/src/store/memory_store.rs b/src/store/memory_store.rs deleted file mode 100644 index 748ff4f..0000000 --- a/src/store/memory_store.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2024 ChainSafe Systems -// SPDX-License-Identifier: Apache-2.0, MIT - -use crate::error::Error; -use crate::store::WalletStore; - -/// A simple in-memory store for wallet data. Useful for testing -pub struct MemoryStore { - inner: std::collections::HashMap>, -} - -impl WalletStore for MemoryStore { - async fn update(&mut self, key: &str, value: &[u8]) -> Result<(), Error> { - self.inner.insert(key.to_string(), value.to_vec()); - Ok(()) - } - - async fn get(&self, key: &str) -> Result>, Error> { - Ok(self.inner.get(key).cloned()) - } - - async fn clear(&mut self, key: &str) -> Result<(), Error> { - self.inner.remove(key); - Ok(()) - } -} diff --git a/src/store/mod.rs b/src/store/mod.rs deleted file mode 100644 index aa88268..0000000 --- a/src/store/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -mod indexed_db_store; -mod injected_store; -mod memory_store; -mod wallet_store; - -pub use indexed_db_store::IdbStore; -pub use injected_store::InjectedStore; -pub use memory_store::MemoryStore; -pub use wallet_store::WalletStore; diff --git a/src/store/wallet_store.rs b/src/store/wallet_store.rs deleted file mode 100644 index 7a27ac9..0000000 --- a/src/store/wallet_store.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2024 ChainSafe Systems -// SPDX-License-Identifier: Apache-2.0, MIT - -use crate::error::Error; - -pub trait WalletStore { - async fn update(&mut self, key: &str, value: &[u8]) -> Result<(), Error>; - async fn get(&self, key: &str) -> Result>, Error>; - async fn clear(&mut self, key: &str) -> Result<(), Error>; -} diff --git a/src/wallet.rs b/src/wallet.rs deleted file mode 100644 index 4b7d828..0000000 --- a/src/wallet.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2024 ChainSafe Systems -// SPDX-License-Identifier: Apache-2.0, MIT - -use wasm_bindgen::prelude::*; - -use crate::account::{Account, AccountIndex}; -use crate::error::Error; -use crate::store::{InjectedStore, WalletStore}; - -/// A wallet is a collection of a number of accounts that can be synchronized together. -struct Wallet { - store: S, -} - -impl Wallet { - pub fn new(store: S) -> Self { - Wallet { store } - } - - pub fn add(&self, _account: Account) {} - - pub async fn get(&self, _index: AccountIndex) -> Result { - Account::from_bytes(&self.store.get("yer").await?.unwrap()) - } -} - -#[wasm_bindgen(js_name = Wallet)] -/// A wallet is a collection of a number of accounts that can be synchronized together. -struct WalletInjectedStore(Wallet); - -#[wasm_bindgen(js_class = Wallet)] -impl WalletInjectedStore { - #[wasm_bindgen(constructor)] - pub fn new(store: InjectedStore) -> Self { - WalletInjectedStore(Wallet::new(store)) - } - - pub fn add(&self, account: Account) { - self.0.add(account) - } - - pub async fn get(&self, index: AccountIndex) -> Result { - self.0.get(index).await - } -} diff --git a/tests/indexed_db_store.rs b/tests/indexed_db_store.rs deleted file mode 100644 index 0b35ebe..0000000 --- a/tests/indexed_db_store.rs +++ /dev/null @@ -1,24 +0,0 @@ -use wasm_bindgen_test::*; -wasm_bindgen_test_configure!(run_in_browser); -use webz_core::store::{self, WalletStore as _}; - -#[wasm_bindgen_test] -async fn idb() { - let k = "key"; - let v = vec![1, 2, 3]; - let v2 = vec![1, 2, 3, 4]; - // Add to store - let mut store = store::IdbStore::new().await.unwrap(); - store.update(k, &v).await.unwrap(); - - // Get from store - assert_eq!(store.get(k).await.unwrap().unwrap(), v); - - // Update Key - store.update(k, &v2).await.unwrap(); - assert_eq!(store.get(k).await.unwrap().unwrap(), v2); - - // Clear Key - store.clear(k).await.unwrap(); - assert_eq!(store.get(k).await.unwrap(), None); -} diff --git a/tests/tests.rs b/tests/tests.rs new file mode 100644 index 0000000..d213706 --- /dev/null +++ b/tests/tests.rs @@ -0,0 +1,38 @@ +use wasm_bindgen_test::*; +wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + +use webz_core::bindgen::wallet::Wallet; + +const SEED: &str = "visit armed kite pen cradle toward reward clay marble oil write dove blind oyster silk oyster original message skate bench tone enable stadium element"; +const BIRTHDAY: Option = Some(2577329); + +// Required to initialize the logger and panic hooks only once +use std::sync::Once; +static INIT: Once = Once::new(); +pub fn initialize() { + INIT.call_once(|| { + webz_core::init::start(); + }); +} + +#[wasm_bindgen_test] +fn tests_working() { + initialize(); + + assert!(true); +} + +#[wasm_bindgen_test] +async fn test_get_and_scan_range() { + initialize(); + + let mut w = Wallet::new("main", "https://zcash-mainnet.chainsafe.dev", 10, 0).unwrap(); + + let id = w.create_account(SEED, BIRTHDAY).await.unwrap(); + tracing::info!("Created account with id: {}", id); + + w.get_and_scan_range(2406739, 2406739 + 1000).await.unwrap(); + + let summary = w.get_wallet_summary().unwrap(); + tracing::info!("Wallet summary: {:?}", summary); +} diff --git a/tests/web_accounts.rs b/tests/web_accounts.rs deleted file mode 100644 index 2ab462e..0000000 --- a/tests/web_accounts.rs +++ /dev/null @@ -1,20 +0,0 @@ -use wasm_bindgen_test::*; -wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); - -use webz_core::account::Account; - -#[wasm_bindgen_test] -fn test_unified_address_encoding() { - let seed = [0; 32]; - let a = Account::from_seed(&seed, 0).unwrap(); - let address = a.unified_address(1).unwrap(); - assert_eq!(address.len(), 213); -} - -#[wasm_bindgen_test] -fn test_transparent_address_encoding() { - let seed = [0; 32]; - let a = Account::from_seed(&seed, 0).unwrap(); - let address = a.transparent_address().unwrap(); - assert_eq!(address.len(), 35); -}