diff --git a/Cargo.lock b/Cargo.lock index 0f8177f..514846c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,24 +20,24 @@ checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" [[package]] name = "accesskit" -version = "0.11.0" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c98a5d094590335462354da402d754fe2cb78f0e6ce5024611c28ed539c1de" +checksum = "76eb1adf08c5bcaa8490b9851fd53cca27fa9880076f178ea9d29f05196728a8" [[package]] name = "accesskit_consumer" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca541e0fdb600916d196a940228df99b86d804fd2e6ef13894d7814f2799db43" +checksum = "04bb4d9e4772fe0d47df57d0d5dbe5d85dd05e2f37ae1ddb6b105e76be58fb00" dependencies = [ "accesskit", ] [[package]] name = "accesskit_macos" -version = "0.7.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4baea9413f0daf1cd4aab199bc09f8139cd726ce7673d523c27d186b8b878325" +checksum = "134d0acf6acb667c89d3332999b1a5df4edbc8d6113910f392ebb73f2b03bb56" dependencies = [ "accesskit", "accesskit_consumer", @@ -47,9 +47,9 @@ dependencies = [ [[package]] name = "accesskit_unix" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4d1517421278cc8e67422d0786a18cf4291093ebe49eadf1cf989ff80e57f90" +checksum = "e084cb5168790c0c112626175412dc5ad127083441a8248ae49ddf6725519e83" dependencies = [ "accesskit", "accesskit_consumer", @@ -62,23 +62,23 @@ dependencies = [ [[package]] name = "accesskit_windows" -version = "0.14.0" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e11c7f177739f23bd19bb856e4a64fdd96eb8638ec0a6a6dde9a7019a9e91c53" +checksum = "9eac0a7f2d7cd7a93b938af401d3d8e8b7094217989a7c25c55a953023436e31" dependencies = [ "accesskit", "accesskit_consumer", "arrayvec 0.7.4", "once_cell", "paste", - "windows 0.44.0", + "windows 0.48.0", ] [[package]] name = "accesskit_winit" -version = "0.14.1" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f1bd64cd0b480cafb7bdd91eb489a1ff50f0f5702437b9efa32a25b8bb82a1" +checksum = "825d23acee1bd6d25cbaa3ca6ed6e73faf24122a774ec33d52c5c86c6ab423c0" dependencies = [ "accesskit", "accesskit_macos", @@ -179,9 +179,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a" dependencies = [ "memchr", ] @@ -218,15 +218,15 @@ checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" [[package]] name = "android_log-sys" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27f0fc03f560e1aebde41c2398b691cb98b5ea5996a6184a7a67bbbb77448969" +checksum = "5ecc8056bf6ab9892dcd53216c83d1597487d7dacac16c8df6b877d127df9937" [[package]] name = "android_logger" -version = "0.13.1" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fa490e751f3878eb9accb9f18988eca52c2337ce000a8bf31ef50d4c723ca9e" +checksum = "c494134f746c14dc653a35a4ea5aca24ac368529da5370ecf41fe0341c35772f" dependencies = [ "android_log-sys", "env_logger 0.10.0", @@ -397,9 +397,9 @@ dependencies = [ [[package]] name = "async-lock" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa24f727524730b077666307f2734b4a1a1c57acb79193127dcc8914d5242dd7" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" dependencies = [ "event-listener", ] @@ -430,7 +430,7 @@ checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -441,13 +441,13 @@ checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae" [[package]] name = "async-trait" -version = "0.1.72" +version = "0.1.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" +checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -458,9 +458,9 @@ checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" [[package]] name = "atomic_refcell" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79d6dc922a2792b006573f60b2648076355daeae5ce9cb59507e5908c9625d31" +checksum = "112ef6b3f6cb3cb6fc5b6b494ef7a848492cff1ab0ef4de10b0f7d572861c905" [[package]] name = "atspi" @@ -628,9 +628,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] name = "blake2-rfc" @@ -776,7 +776,7 @@ checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -835,11 +835,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.79" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01" dependencies = [ "jobserver", + "libc", ] [[package]] @@ -1223,6 +1224,27 @@ dependencies = [ "subtle", ] +[[package]] +name = "csv" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626ae34994d3d8d668f4269922248239db4ae42d538b14c398b74a52208e8086" +dependencies = [ + "csv-core", + "itoa 1.0.9", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +dependencies = [ + "memchr", +] + [[package]] name = "ct-logs" version = "0.6.0" @@ -1347,6 +1369,16 @@ dependencies = [ "dirs-sys 0.4.1", ] +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if 1.0.0", + "dirs-sys-next", +] + [[package]] name = "dirs-sys" version = "0.3.7" @@ -1370,6 +1402,17 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi 0.3.9", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -1384,7 +1427,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -1396,12 +1439,6 @@ dependencies = [ "libloading 0.8.0", ] -[[package]] -name = "doc-comment" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" - [[package]] name = "downcast-rs" version = "1.2.0" @@ -1582,6 +1619,12 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + [[package]] name = "encoding_rs" version = "0.8.32" @@ -1618,7 +1661,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -1672,9 +1715,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" dependencies = [ "errno-dragonfly", "libc", @@ -1927,7 +1970,7 @@ dependencies = [ "futures-io", "memchr", "parking", - "pin-project-lite 0.2.10", + "pin-project-lite 0.2.12", "waker-fn", ] @@ -1939,7 +1982,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -1967,7 +2010,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.10", + "pin-project-lite 0.2.12", "pin-utils", "slab", ] @@ -2067,9 +2110,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "globset" -version = "0.4.11" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1391ab1f92ffcc08911957149833e682aa3fe252b9f45f966d2ef972274c97df" +checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d" dependencies = [ "aho-corasick", "bstr", @@ -2103,9 +2146,9 @@ dependencies = [ [[package]] name = "glutin" -version = "0.30.9" +version = "0.30.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b0385782048be65f0a9dd046c469d6a758a53fe1aa63a8111dea394d2ffa2f" +checksum = "8fc93b03242719b8ad39fb26ed2b01737144ce7bd4bfc7adadcef806596760fe" dependencies = [ "bitflags 1.3.2", "cfg_aliases", @@ -2138,9 +2181,9 @@ dependencies = [ [[package]] name = "glutin_egl_sys" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b3bcbddc51573b977fc6dca5d93867e4f29682cdbaf5d13e48f4fa4346d4d87" +checksum = "af784eb26c5a68ec85391268e074f0aa618c096eadb5d6330b0911cf34fe57c5" dependencies = [ "gl_generator", "windows-sys 0.45.0", @@ -2224,10 +2267,8 @@ dependencies = [ "android-activity", "android_logger", "built", - "byteorder", "chrono", "dirs 5.0.1", - "ed25519-dalek", "eframe", "egui", "egui_extras", @@ -2242,16 +2283,15 @@ dependencies = [ "grin_servers", "grin_util", "grin_wallet_api", + "grin_wallet_controller", "grin_wallet_impls", "grin_wallet_libwallet", "grin_wallet_util", "jni", "lazy_static", "log", - "num-bigint 0.4.3", "once_cell", "openssl-sys", - "parking_lot 0.10.2", "pnet", "pollster", "rand 0.8.5", @@ -2260,19 +2300,18 @@ dependencies = [ "serde_derive", "serde_json", "sys-locale", - "tokio 1.29.1", + "tokio 1.31.0", "tokio-util 0.7.8", "toml 0.7.6", "url", - "uuid", "wgpu", "winit", ] [[package]] name = "grin_api" -version = "5.2.0-beta.2" -source = "git+https://github.com/mimblewimble/grin?branch=master#399fb19c3014a4a5c3f0575dd222e7df6fda8c83" +version = "5.2.0-beta.3" +source = "git+https://github.com/mimblewimble/grin?tag=v5.2.0-beta.3#94277bba9db2e31e713f2a4cfdc37b11e46a1630" dependencies = [ "bytes 0.5.6", "easy-jsonrpc-mw", @@ -2303,8 +2342,8 @@ dependencies = [ [[package]] name = "grin_chain" -version = "5.2.0-beta.2" -source = "git+https://github.com/mimblewimble/grin?branch=master#399fb19c3014a4a5c3f0575dd222e7df6fda8c83" +version = "5.2.0-beta.3" +source = "git+https://github.com/mimblewimble/grin?tag=v5.2.0-beta.3#94277bba9db2e31e713f2a4cfdc37b11e46a1630" dependencies = [ "bit-vec", "bitflags 1.3.2", @@ -2326,8 +2365,8 @@ dependencies = [ [[package]] name = "grin_config" -version = "5.2.0-beta.2" -source = "git+https://github.com/mimblewimble/grin?branch=master#399fb19c3014a4a5c3f0575dd222e7df6fda8c83" +version = "5.2.0-beta.3" +source = "git+https://github.com/mimblewimble/grin?tag=v5.2.0-beta.3#94277bba9db2e31e713f2a4cfdc37b11e46a1630" dependencies = [ "dirs 2.0.2", "grin_core", @@ -2342,8 +2381,8 @@ dependencies = [ [[package]] name = "grin_core" -version = "5.2.0-beta.2" -source = "git+https://github.com/mimblewimble/grin?branch=master#399fb19c3014a4a5c3f0575dd222e7df6fda8c83" +version = "5.2.0-beta.3" +source = "git+https://github.com/mimblewimble/grin?tag=v5.2.0-beta.3#94277bba9db2e31e713f2a4cfdc37b11e46a1630" dependencies = [ "blake2-rfc", "byteorder", @@ -2357,7 +2396,7 @@ dependencies = [ "log", "lru-cache", "num", - "num-bigint 0.2.6", + "num-bigint", "rand 0.6.5", "serde", "serde_derive", @@ -2368,8 +2407,8 @@ dependencies = [ [[package]] name = "grin_keychain" -version = "5.2.0-beta.2" -source = "git+https://github.com/mimblewimble/grin?branch=master#399fb19c3014a4a5c3f0575dd222e7df6fda8c83" +version = "5.2.0-beta.3" +source = "git+https://github.com/mimblewimble/grin?tag=v5.2.0-beta.3#94277bba9db2e31e713f2a4cfdc37b11e46a1630" dependencies = [ "blake2-rfc", "byteorder", @@ -2390,8 +2429,8 @@ dependencies = [ [[package]] name = "grin_p2p" -version = "5.2.0-beta.2" -source = "git+https://github.com/mimblewimble/grin?branch=master#399fb19c3014a4a5c3f0575dd222e7df6fda8c83" +version = "5.2.0-beta.3" +source = "git+https://github.com/mimblewimble/grin?tag=v5.2.0-beta.3#94277bba9db2e31e713f2a4cfdc37b11e46a1630" dependencies = [ "bitflags 1.3.2", "bytes 0.5.6", @@ -2412,8 +2451,8 @@ dependencies = [ [[package]] name = "grin_pool" -version = "5.2.0-beta.2" -source = "git+https://github.com/mimblewimble/grin?branch=master#399fb19c3014a4a5c3f0575dd222e7df6fda8c83" +version = "5.2.0-beta.3" +source = "git+https://github.com/mimblewimble/grin?tag=v5.2.0-beta.3#94277bba9db2e31e713f2a4cfdc37b11e46a1630" dependencies = [ "blake2-rfc", "chrono", @@ -2445,8 +2484,8 @@ dependencies = [ [[package]] name = "grin_servers" -version = "5.2.0-beta.2" -source = "git+https://github.com/mimblewimble/grin?branch=master#399fb19c3014a4a5c3f0575dd222e7df6fda8c83" +version = "5.2.0-beta.3" +source = "git+https://github.com/mimblewimble/grin?tag=v5.2.0-beta.3#94277bba9db2e31e713f2a4cfdc37b11e46a1630" dependencies = [ "chrono", "fs2", @@ -2475,8 +2514,8 @@ dependencies = [ [[package]] name = "grin_store" -version = "5.2.0-beta.2" -source = "git+https://github.com/mimblewimble/grin?branch=master#399fb19c3014a4a5c3f0575dd222e7df6fda8c83" +version = "5.2.0-beta.3" +source = "git+https://github.com/mimblewimble/grin?tag=v5.2.0-beta.3#94277bba9db2e31e713f2a4cfdc37b11e46a1630" dependencies = [ "byteorder", "croaring", @@ -2494,8 +2533,8 @@ dependencies = [ [[package]] name = "grin_util" -version = "5.2.0-beta.2" -source = "git+https://github.com/mimblewimble/grin?branch=master#399fb19c3014a4a5c3f0575dd222e7df6fda8c83" +version = "5.2.0-beta.3" +source = "git+https://github.com/mimblewimble/grin?tag=v5.2.0-beta.3#94277bba9db2e31e713f2a4cfdc37b11e46a1630" dependencies = [ "backtrace", "base64 0.12.3", @@ -2515,8 +2554,8 @@ dependencies = [ [[package]] name = "grin_wallet_api" -version = "5.2.0-alpha.1" -source = "git+https://github.com/mimblewimble/grin-wallet?branch=master#0b491fea0fd5aa21fd28c171ed775e70f0877661" +version = "5.2.0-beta.1" +source = "git+https://github.com/mimblewimble/grin-wallet?tag=v5.2.0-beta.1#12a25f82f1a799caa738f3d7cf42e8ee2b13f005" dependencies = [ "base64 0.12.3", "chrono", @@ -2540,8 +2579,8 @@ dependencies = [ [[package]] name = "grin_wallet_config" -version = "5.2.0-alpha.1" -source = "git+https://github.com/mimblewimble/grin-wallet?branch=master#0b491fea0fd5aa21fd28c171ed775e70f0877661" +version = "5.2.0-beta.1" +source = "git+https://github.com/mimblewimble/grin-wallet?tag=v5.2.0-beta.1#12a25f82f1a799caa738f3d7cf42e8ee2b13f005" dependencies = [ "dirs 2.0.2", "grin_core", @@ -2553,10 +2592,44 @@ dependencies = [ "toml 0.5.11", ] +[[package]] +name = "grin_wallet_controller" +version = "5.2.0-beta.1" +source = "git+https://github.com/mimblewimble/grin-wallet?tag=v5.2.0-beta.1#12a25f82f1a799caa738f3d7cf42e8ee2b13f005" +dependencies = [ + "chrono", + "easy-jsonrpc-mw", + "futures 0.3.28", + "grin_api", + "grin_core", + "grin_keychain", + "grin_util", + "grin_wallet_api", + "grin_wallet_config", + "grin_wallet_impls", + "grin_wallet_libwallet", + "grin_wallet_util", + "hyper", + "lazy_static", + "log", + "prettytable-rs", + "qr_code", + "rand 0.7.3", + "ring", + "serde", + "serde_derive", + "serde_json", + "term 0.6.1", + "thiserror", + "tokio 0.2.25", + "url", + "uuid", +] + [[package]] name = "grin_wallet_impls" -version = "5.2.0-alpha.1" -source = "git+https://github.com/mimblewimble/grin-wallet?branch=master#0b491fea0fd5aa21fd28c171ed775e70f0877661" +version = "5.2.0-beta.1" +source = "git+https://github.com/mimblewimble/grin-wallet?tag=v5.2.0-beta.1#12a25f82f1a799caa738f3d7cf42e8ee2b13f005" dependencies = [ "base64 0.12.3", "blake2-rfc", @@ -2594,8 +2667,8 @@ dependencies = [ [[package]] name = "grin_wallet_libwallet" -version = "5.2.0-alpha.1" -source = "git+https://github.com/mimblewimble/grin-wallet?branch=master#0b491fea0fd5aa21fd28c171ed775e70f0877661" +version = "5.2.0-beta.1" +source = "git+https://github.com/mimblewimble/grin-wallet?tag=v5.2.0-beta.1#12a25f82f1a799caa738f3d7cf42e8ee2b13f005" dependencies = [ "age", "base64 0.9.3", @@ -2614,7 +2687,7 @@ dependencies = [ "grin_wallet_util", "lazy_static", "log", - "num-bigint 0.2.6", + "num-bigint", "rand 0.6.5", "regex", "secrecy 0.6.0", @@ -2631,8 +2704,8 @@ dependencies = [ [[package]] name = "grin_wallet_util" -version = "5.2.0-alpha.1" -source = "git+https://github.com/mimblewimble/grin-wallet?branch=master#0b491fea0fd5aa21fd28c171ed775e70f0877661" +version = "5.2.0-beta.1" +source = "git+https://github.com/mimblewimble/grin-wallet?tag=v5.2.0-beta.1#12a25f82f1a799caa738f3d7cf42e8ee2b13f005" dependencies = [ "data-encoding", "ed25519-dalek", @@ -2951,7 +3024,7 @@ dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", "strsim 0.10.0", - "syn 2.0.27", + "syn 2.0.28", "unic-langid", ] @@ -3020,9 +3093,9 @@ dependencies = [ [[package]] name = "image" -version = "0.24.6" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527909aa81e20ac3a44803521443a765550f09b5130c2c2fa1ea59c2f8f50a3a" +checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711" dependencies = [ "bytemuck", "byteorder", @@ -3125,7 +3198,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi 0.3.2", - "rustix 0.38.4", + "rustix 0.38.8", "windows-sys 0.48.0", ] @@ -3301,9 +3374,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.10" +version = "1.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24e6ab01971eb092ffe6a7d42f49f9ff42662f17604681e2843ad65077ba47dc" +checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" dependencies = [ "cc", "libc", @@ -3325,9 +3398,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" [[package]] name = "lmdb-zero" @@ -3362,9 +3435,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" dependencies = [ "serde", ] @@ -3747,9 +3820,9 @@ dependencies = [ [[package]] name = "ntapi" -version = "0.3.7" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" +checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" dependencies = [ "winapi 0.3.9", ] @@ -3760,7 +3833,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" dependencies = [ - "num-bigint 0.2.6", + "num-bigint", "num-complex", "num-integer", "num-iter", @@ -3779,17 +3852,6 @@ dependencies = [ "num-traits 0.2.16", ] -[[package]] -name = "num-bigint" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" -dependencies = [ - "autocfg 1.1.0", - "num-integer", - "num-traits 0.2.16", -] - [[package]] name = "num-complex" version = "0.2.4" @@ -3828,7 +3890,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" dependencies = [ "autocfg 1.1.0", - "num-bigint 0.2.6", + "num-bigint", "num-integer", "num-traits 0.2.16", ] @@ -3911,7 +3973,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2 1.0.66", "quote 1.0.32", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -4014,9 +4076,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.55" +version = "0.10.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" +checksum = "729b745ad4a5575dd06a3e1af1414bd330ee561c01b3899eb584baeaa8def17e" dependencies = [ "bitflags 1.3.2", "cfg-if 1.0.0", @@ -4035,7 +4097,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -4046,18 +4108,18 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "111.26.0+1.1.1u" +version = "111.27.0+1.1.1v" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efc62c9f12b22b8f5208c23a7200a442b2e5999f8bdf80233852122b5a4f6f37" +checksum = "06e8f197c82d7511c5b014030c9b1efeda40d7d5f99d23b4ceed3524a5e63f02" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.90" +version = "0.9.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" +checksum = "866b5f16f90776b9bb8dc1e1802ac6f0513de3a7a7465867bfbc563dc737faac" dependencies = [ "cc", "libc", @@ -4074,9 +4136,9 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "orbclient" -version = "0.3.45" +version = "0.3.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "221d488cd70617f1bd599ed8ceb659df2147d9393717954d82a0f5e8032a6ab1" +checksum = "8378ac0dfbd4e7895f2d2c1f1345cab3836910baf3a300b000d04250f0c8428f" dependencies = [ "redox_syscall 0.3.5", ] @@ -4097,7 +4159,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" dependencies = [ "futures-core", - "pin-project-lite 0.2.10", + "pin-project-lite 0.2.12", ] [[package]] @@ -4159,7 +4221,7 @@ dependencies = [ "libc", "redox_syscall 0.3.5", "smallvec", - "windows-targets 0.48.1", + "windows-targets 0.48.2", ] [[package]] @@ -4215,22 +4277,22 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pin-project" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "030ad2bc4db10a8944cb0d837f158bdfec4d4a4873ab701a95046770d11f8842" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -4241,9 +4303,9 @@ checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" [[package]] name = "pin-project-lite" -version = "0.2.10" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" +checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" [[package]] name = "pin-utils" @@ -4302,7 +4364,7 @@ dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", "regex", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -4373,7 +4435,7 @@ dependencies = [ "concurrent-queue", "libc", "log", - "pin-project-lite 0.2.10", + "pin-project-lite 0.2.12", "windows-sys 0.48.0", ] @@ -4400,6 +4462,20 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "prettytable-rs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eea25e07510aa6ab6547308ebe3c036016d162b8da920dbb079e3ba8acf3d95a" +dependencies = [ + "csv", + "encode_unicode", + "is-terminal", + "lazy_static", + "term 0.7.0", + "unicode-width", +] + [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -4454,9 +4530,15 @@ dependencies = [ [[package]] name = "profiling" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "332cd62e95873ea4f41f3dfd6bbbfc5b52aec892d7e8d534197c4720a0bbbab2" +checksum = "46b2164ebdb1dfeec5e337be164292351e11daf63a05174c6776b2f47460f0c9" + +[[package]] +name = "qr_code" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5520fbcd7da152a449261c5a533a1c7fad044e9e8aa9528cfec3f464786c7926" [[package]] name = "quick-error" @@ -4752,9 +4834,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.1" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" dependencies = [ "aho-corasick", "memchr", @@ -4764,9 +4846,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.3" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" dependencies = [ "aho-corasick", "memchr", @@ -4809,7 +4891,7 @@ dependencies = [ "mime_guess", "native-tls", "percent-encoding", - "pin-project-lite 0.2.10", + "pin-project-lite 0.2.12", "rustls 0.18.1", "serde", "serde_urlencoded", @@ -4871,7 +4953,7 @@ dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", "rust-embed-utils", - "syn 2.0.27", + "syn 2.0.28", "walkdir", ] @@ -4990,14 +5072,14 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.4" +version = "0.38.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" +checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.0", "errno", "libc", - "linux-raw-sys 0.4.3", + "linux-raw-sys 0.4.5", "windows-sys 0.48.0", ] @@ -5039,6 +5121,12 @@ dependencies = [ "security-framework 0.4.4", ] +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + [[package]] name = "ryu" version = "1.0.15" @@ -5206,9 +5294,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.175" +version = "1.0.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d25439cd7397d044e2748a6fe2432b5e85db703d6d097bd014b3c0ad1ebff0b" +checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c" dependencies = [ "serde_derive", ] @@ -5225,20 +5313,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.175" +version = "1.0.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b23f7ade6f110613c0d63858ddb8b94c1041f550eab58a16b371bdf2c9c80ab4" +checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] name = "serde_json" -version = "1.0.103" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b" +checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" dependencies = [ "itoa 1.0.9", "ryu", @@ -5247,13 +5335,13 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e168eaaf71e8f9bd6037feb05190485708e019f4fd87d161b3c0a0d37daf85e5" +checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -5466,6 +5554,16 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "socket2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "spin" version = "0.5.2" @@ -5566,9 +5664,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.27" +version = "2.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0" +checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", @@ -5587,12 +5685,12 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.14.15" +version = "0.29.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2983daff11a197c7c406b130579bc362177aa54cf2cc1f34d6ac88fccaa6a5e1" +checksum = "d10ed79c22663a35a255d289a7fdcb43559fc77ff15df5ce6c341809e7867528" dependencies = [ - "cfg-if 0.1.10", - "doc-comment", + "cfg-if 1.0.0", + "core-foundation-sys 0.8.4", "libc", "ntapi", "once_cell", @@ -5602,17 +5700,38 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.7.0" +version = "3.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998" +checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651" dependencies = [ "cfg-if 1.0.0", "fastrand 2.0.0", "redox_syscall 0.3.5", - "rustix 0.38.4", + "rustix 0.38.8", "windows-sys 0.48.0", ] +[[package]] +name = "term" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" +dependencies = [ + "dirs 2.0.2", + "winapi 0.3.9", +] + +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi 0.3.9", +] + [[package]] name = "termcolor" version = "1.2.0" @@ -5648,7 +5767,7 @@ checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -5767,20 +5886,19 @@ dependencies = [ [[package]] name = "tokio" -version = "1.29.1" +version = "1.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +checksum = "40de3a2ba249dcb097e01be5e67a5ff53cf250397715a071a81543e8a832a920" dependencies = [ - "autocfg 1.1.0", "backtrace", "bytes 1.4.0", "libc", "mio 0.8.8", "num_cpus", "parking_lot 0.12.1", - "pin-project-lite 0.2.10", + "pin-project-lite 0.2.12", "signal-hook-registry", - "socket2 0.4.9", + "socket2 0.5.3", "tokio-macros 2.1.0", "windows-sys 0.48.0", ] @@ -5814,7 +5932,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -5901,8 +6019,8 @@ dependencies = [ "bytes 1.4.0", "futures-core", "futures-sink", - "pin-project-lite 0.2.10", - "tokio 1.29.1", + "pin-project-lite 0.2.12", + "tokio 1.31.0", "tracing", ] @@ -5963,7 +6081,7 @@ checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if 1.0.0", "log", - "pin-project-lite 0.2.10", + "pin-project-lite 0.2.12", "tracing-attributes", "tracing-core", ] @@ -5976,7 +6094,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] @@ -6262,7 +6380,7 @@ dependencies = [ "once_cell", "proc-macro2 1.0.66", "quote 1.0.32", - "syn 2.0.27", + "syn 2.0.28", "wasm-bindgen-shared", ] @@ -6296,7 +6414,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", - "syn 2.0.27", + "syn 2.0.28", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6470,7 +6588,7 @@ checksum = "8f478237b4bf0d5b70a39898a66fa67ca3a007d79f2520485b8b0c3dfc46f8c2" dependencies = [ "arrayvec 0.7.4", "bit-vec", - "bitflags 2.3.3", + "bitflags 2.4.0", "codespan-reporting", "log", "naga", @@ -6495,7 +6613,7 @@ dependencies = [ "arrayvec 0.7.4", "ash", "bit-set", - "bitflags 2.3.3", + "bitflags 2.4.0", "block", "core-graphics-types", "d3d12", @@ -6533,7 +6651,7 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0c153280bb108c2979eb5c7391cb18c56642dd3c072e55f52065e13e2a1252a" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.0", "js-sys", "web-sys", ] @@ -6611,8 +6729,6 @@ version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b" dependencies = [ - "windows-implement", - "windows-interface", "windows-targets 0.42.2", ] @@ -6622,14 +6738,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets 0.48.1", + "windows-implement", + "windows-interface", + "windows-targets 0.48.2", ] [[package]] name = "windows-implement" -version = "0.44.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce87ca8e3417b02dc2a8a22769306658670ec92d78f1bd420d6310a67c245c6" +checksum = "5e2ee588991b9e7e6c8338edf3333fbe4da35dc72092643958ebb43f0ab2c49c" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", @@ -6638,9 +6756,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.44.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "853f69a591ecd4f810d29f17e902d40e349fb05b0b11fff63b08b826bfe39c7f" +checksum = "e6fb8df20c9bcaa8ad6ab513f7b40104840c8867d5751126e4df3b08388d0cc7" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", @@ -6662,7 +6780,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.1", + "windows-targets 0.48.2", ] [[package]] @@ -6682,17 +6800,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "d1eeca1c172a285ee6c2c84c341ccea837e7c01b12fbb2d0fe3c9e550ce49ec8" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm 0.48.2", + "windows_aarch64_msvc 0.48.2", + "windows_i686_gnu 0.48.2", + "windows_i686_msvc 0.48.2", + "windows_x86_64_gnu 0.48.2", + "windows_x86_64_gnullvm 0.48.2", + "windows_x86_64_msvc 0.48.2", ] [[package]] @@ -6703,9 +6821,9 @@ checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "b10d0c968ba7f6166195e13d593af609ec2e3d24f916f081690695cf5eaffb2f" [[package]] name = "windows_aarch64_msvc" @@ -6715,9 +6833,9 @@ checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "571d8d4e62f26d4932099a9efe89660e8bd5087775a2ab5cdd8b747b811f1058" [[package]] name = "windows_i686_gnu" @@ -6727,9 +6845,9 @@ checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "2229ad223e178db5fbbc8bd8d3835e51e566b8474bfca58d2e6150c48bb723cd" [[package]] name = "windows_i686_msvc" @@ -6739,9 +6857,9 @@ checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "600956e2d840c194eedfc5d18f8242bc2e17c7775b6684488af3a9fff6fe3287" [[package]] name = "windows_x86_64_gnu" @@ -6751,9 +6869,9 @@ checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "ea99ff3f8b49fb7a8e0d305e5aec485bd068c2ba691b6e277d29eaeac945868a" [[package]] name = "windows_x86_64_gnullvm" @@ -6763,9 +6881,9 @@ checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "8f1a05a1ece9a7a0d5a7ccf30ba2c33e3a61a30e042ffd247567d1de1d94120d" [[package]] name = "windows_x86_64_msvc" @@ -6775,9 +6893,9 @@ checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "d419259aba16b663966e29e6d7c6ecfa0bb8425818bb96f6f1f3c3eb71a6e7b9" [[package]] name = "winit" @@ -6816,9 +6934,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.5.1" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b5872fa2e10bd067ae946f927e726d7d603eaeb6e02fa6a350e0722d2b8c11" +checksum = "5504cc7644f4b593cbc05c4a55bf9bd4e94b867c3c0bd440934174d50482427d" dependencies = [ "memchr", ] @@ -7014,7 +7132,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", - "syn 2.0.27", + "syn 2.0.28", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e2ed436..9c04d96 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,22 +16,21 @@ log = "0.4" ## node openssl-sys = { version = "0.9.82", features = ["vendored"] } -grin_api = { git = "https://github.com/mimblewimble/grin", branch = "master" } -grin_chain = { git = "https://github.com/mimblewimble/grin", branch = "master" } -grin_config = { git = "https://github.com/mimblewimble/grin", branch = "master" } -grin_core = { git = "https://github.com/mimblewimble/grin", branch = "master" } -grin_p2p = { git = "https://github.com/mimblewimble/grin", branch = "master" } -grin_servers = { git = "https://github.com/mimblewimble/grin", branch = "master" } -grin_keychain = { git = "https://github.com/mimblewimble/grin", branch = "master" } -grin_util = { git = "https://github.com/mimblewimble/grin", branch = "master" } +grin_api = { git = "https://github.com/mimblewimble/grin", tag = "v5.2.0-beta.3" } +grin_chain = { git = "https://github.com/mimblewimble/grin", tag = "v5.2.0-beta.3" } +grin_config = { git = "https://github.com/mimblewimble/grin", tag = "v5.2.0-beta.3" } +grin_core = { git = "https://github.com/mimblewimble/grin", tag = "v5.2.0-beta.3" } +grin_p2p = { git = "https://github.com/mimblewimble/grin", tag = "v5.2.0-beta.3" } +grin_servers = { git = "https://github.com/mimblewimble/grin", tag = "v5.2.0-beta.3" } +grin_keychain = { git = "https://github.com/mimblewimble/grin", tag = "v5.2.0-beta.3" } +grin_util = { git = "https://github.com/mimblewimble/grin", tag = "v5.2.0-beta.3" } ## wallet -grin_wallet_impls = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" } -grin_wallet_api = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" } -grin_wallet_libwallet = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" } -grin_wallet_util = { git = "https://github.com/mimblewimble/grin-wallet", branch = "master" } -#grin_wallet_controller = "5.1.0" -#grin_wallet_config = "5.1.0" +grin_wallet_impls = { git = "https://github.com/mimblewimble/grin-wallet", tag = "v5.2.0-beta.1" } +grin_wallet_api = { git = "https://github.com/mimblewimble/grin-wallet", tag = "v5.2.0-beta.1" } +grin_wallet_libwallet = { git = "https://github.com/mimblewimble/grin-wallet", tag = "v5.2.0-beta.1" } +grin_wallet_util = { git = "https://github.com/mimblewimble/grin-wallet", tag = "v5.2.0-beta.1" } +grin_wallet_controller = { git = "https://github.com/mimblewimble/grin-wallet", tag = "v5.2.0-beta.1" } ## ui pollster = "0.3.0" @@ -51,11 +50,6 @@ toml = "0.7.4" serde = "1" pnet = "0.34.0" url = "2.4.0" -parking_lot = "0.10.2" -uuid = { version = "0.8.2", features = ["serde", "v4"] } -num-bigint = "0.4.3" -byteorder = "1.3" -ed25519-dalek = "1.0.0-pre.4" # stratum server serde_derive = "1" diff --git a/src/wallet/keys.rs b/src/wallet/keys.rs deleted file mode 100644 index 9bb0a46..0000000 --- a/src/wallet/keys.rs +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2023 The Grim Developers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use grin_keychain::{ChildNumber, ExtKeychain, Identifier, Keychain}; -use grin_util::secp::key::SecretKey; -use grin_wallet_libwallet::{AcctPathMapping, NodeClient, WalletBackend}; -use grin_wallet_libwallet::Error; - -/// Get next available key in the wallet for a given parent -pub fn next_available_key<'a, T: ?Sized, C, K>( - wallet: &mut T, - keychain_mask: Option<&SecretKey>, -) -> Result - where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - let child = wallet.next_child(keychain_mask)?; - Ok(child) -} - -/// Retrieve an existing key from a wallet -pub fn retrieve_existing_key<'a, T: ?Sized, C, K>( - wallet: &T, - key_id: Identifier, - mmr_index: Option, -) -> Result<(Identifier, u32), Error> - where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - let existing = wallet.get(&key_id, &mmr_index)?; - let key_id = existing.key_id.clone(); - let derivation = existing.n_child; - Ok((key_id, derivation)) -} - -/// Returns a list of account to BIP32 path mappings -pub fn accounts<'a, T: ?Sized, C, K>(wallet: &mut T) -> Result, Error> - where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - Ok(wallet.acct_path_iter().collect()) -} - -/// Adds an new parent account path with a given label -pub fn new_acct_path<'a, T: ?Sized, C, K>( - wallet: &mut T, - keychain_mask: Option<&SecretKey>, - label: &str, -) -> Result - where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - let label = label.to_owned(); - if wallet.acct_path_iter().any(|l| l.label == label) { - return Err(Error::AccountLabelAlreadyExists(label)); - } - - // We're always using paths at m/k/0 for parent keys for output derivations - // so find the highest of those, then increment (to conform with external/internal - // derivation chains in BIP32 spec) - - let highest_entry = wallet.acct_path_iter().max_by(|a, b| { - ::from(a.path.to_path().path[0]).cmp(&::from(b.path.to_path().path[0])) - }); - - let return_id = { - if let Some(e) = highest_entry { - let mut p = e.path.to_path(); - p.path[0] = ChildNumber::from(::from(p.path[0]) + 1); - p.to_identifier() - } else { - ExtKeychain::derive_key_id(2, 0, 0, 0, 0) - } - }; - - let save_path = AcctPathMapping { - label, - path: return_id.clone(), - }; - - let mut batch = wallet.batch(keychain_mask)?; - batch.save_acct_path(save_path)?; - batch.commit()?; - Ok(return_id) -} - -/// Adds/sets a particular account path with a given label -pub fn set_acct_path<'a, T: ?Sized, C, K>( - wallet: &mut T, - keychain_mask: Option<&SecretKey>, - label: &str, - path: &Identifier, -) -> Result<(), Error> - where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - let label = label.to_owned(); - let save_path = AcctPathMapping { - label, - path: path.clone(), - }; - - let mut batch = wallet.batch(keychain_mask)?; - batch.save_acct_path(save_path)?; - batch.commit()?; - Ok(()) -} \ No newline at end of file diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index 7f57528..fbb6518 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -13,10 +13,6 @@ // limitations under the License. pub mod types; -pub mod updater; -pub mod selection; -pub mod tx; -pub mod keys; mod mnemonic; pub use mnemonic::Mnemonic; diff --git a/src/wallet/selection.rs b/src/wallet/selection.rs deleted file mode 100644 index 9ec7120..0000000 --- a/src/wallet/selection.rs +++ /dev/null @@ -1,714 +0,0 @@ -// Copyright 2023 The Grim Developers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::collections::HashMap; -use std::convert::TryInto; - -use grin_core::core::amount_to_hr_string; -use grin_core::libtx::{ - build, - proof::{ProofBuild, ProofBuilder}, - tx_fee, -}; -use grin_keychain::{Identifier, Keychain}; -use grin_util::secp::key::SecretKey; -use grin_util::secp::pedersen; -use grin_wallet_libwallet::{address, Context, NodeClient, OutputData, OutputStatus, StoredProofInfo, TxLogEntry, TxLogEntryType, WalletBackend}; -use grin_wallet_libwallet::Error; -use grin_wallet_libwallet::Slate; -use grin_wallet_util::OnionV3Address; -use log::debug; - -use crate::wallet::keys::next_available_key; - -/// Initialize a transaction on the sender side, returns a corresponding -/// libwallet transaction slate with the appropriate inputs selected, -/// and saves the private wallet identifiers of our selected outputs -/// into our transaction context - -pub fn build_send_tx<'a, T: ?Sized, C, K>( - wallet: &mut T, - keychain: &K, - keychain_mask: Option<&SecretKey>, - slate: &mut Slate, - current_height: u64, - minimum_confirmations: u64, - max_outputs: usize, - change_outputs: usize, - selection_strategy_is_use_all: bool, - fixed_fee: Option, - parent_key_id: Identifier, - use_test_nonce: bool, - is_initiator: bool, - amount_includes_fee: bool, -) -> Result - where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - let (elems, inputs, change_amounts_derivations, fee) = select_send_tx( - wallet, - keychain_mask, - slate.amount, - amount_includes_fee, - current_height, - minimum_confirmations, - max_outputs, - change_outputs, - selection_strategy_is_use_all, - &parent_key_id, - false, - )?; - if amount_includes_fee { - slate.amount = slate.amount.checked_sub(fee).ok_or(Error::GenericError( - format!("Transaction amount is too small to include fee").into(), - ))?; - }; - - if fixed_fee.map(|f| fee != f).unwrap_or(false) { - return Err(Error::Fee( - "The initially selected fee is not sufficient".into(), - )); - } - - // Update the fee on the slate so we account for this when building the tx. - slate.fee_fields = fee.try_into().unwrap(); - slate.add_transaction_elements(keychain, &ProofBuilder::new(keychain), elems)?; - - // Create our own private context - let mut context = Context::new( - keychain.secp(), - &parent_key_id, - use_test_nonce, - is_initiator, - ); - - context.fee = Some(slate.fee_fields); - context.amount = slate.amount; - - // Store our private identifiers for each input - for input in inputs { - context.add_input(&input.key_id, &input.mmr_index, input.value); - } - - let mut commits: HashMap> = HashMap::new(); - - // Store change output(s) and cached commits - for (change_amount, id, mmr_index) in &change_amounts_derivations { - context.add_output(&id, &mmr_index, *change_amount); - commits.insert( - id.clone(), - wallet.calc_commit_for_cache(keychain_mask, *change_amount, &id)?, - ); - } - - Ok(context) -} - -/// Locks all corresponding outputs in the context, creates -/// change outputs and tx log entry -pub fn lock_tx_context<'a, T: ?Sized, C, K>( - wallet: &mut T, - keychain_mask: Option<&SecretKey>, - slate: &Slate, - current_height: u64, - context: &Context, - excess_override: Option, -) -> Result<(), Error> - where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - let mut output_commits: HashMap, u64)> = HashMap::new(); - // Store cached commits before locking wallet - let mut total_change = 0; - for (id, _, change_amount) in &context.get_outputs() { - output_commits.insert( - id.clone(), - ( - wallet.calc_commit_for_cache(keychain_mask, *change_amount, &id)?, - *change_amount, - ), - ); - total_change += change_amount; - } - - debug!("Change amount is: {}", total_change); - - let keychain = wallet.keychain(keychain_mask)?; - - let tx_entry = { - let lock_inputs = context.get_inputs(); - let slate_id = slate.id; - let height = current_height; - let parent_key_id = context.parent_key_id.clone(); - let mut batch = wallet.batch(keychain_mask)?; - let log_id = batch.next_tx_log_id(&parent_key_id)?; - let mut t = TxLogEntry::new(parent_key_id.clone(), TxLogEntryType::TxSent, log_id); - t.tx_slate_id = Some(slate_id); - let filename = format!("{}.grintx", slate_id); - t.stored_tx = Some(filename); - t.fee = context.fee; - t.ttl_cutoff_height = match slate.ttl_cutoff_height { - 0 => None, - n => Some(n), - }; - - if let Ok(e) = slate.calc_excess(keychain.secp()) { - t.kernel_excess = Some(e) - } - if let Some(e) = excess_override { - t.kernel_excess = Some(e) - } - t.kernel_lookup_min_height = Some(current_height); - - let mut amount_debited = 0; - t.num_inputs = lock_inputs.len(); - for id in lock_inputs { - let mut coin = batch.get(&id.0, &id.1).unwrap(); - coin.tx_log_entry = Some(log_id); - amount_debited += coin.value; - batch.lock_output(&mut coin)?; - } - - t.amount_debited = amount_debited; - - // store extra payment proof info, if required - if let Some(ref p) = slate.payment_proof { - let sender_address_path = match context.payment_proof_derivation_index { - Some(p) => p, - None => { - return Err(Error::PaymentProof( - "Payment proof derivation index required".to_owned(), - ) - .into()); - } - }; - let sender_key = address::address_from_derivation_path( - &keychain, - &parent_key_id, - sender_address_path, - )?; - let sender_address = OnionV3Address::from_private(&sender_key.0)?; - t.payment_proof = Some(StoredProofInfo { - receiver_address: p.receiver_address, - receiver_signature: p.receiver_signature, - sender_address: sender_address.to_ed25519()?, - sender_address_path, - sender_signature: None, - }); - }; - - // write the output representing our change - for (id, _, _) in &context.get_outputs() { - t.num_outputs += 1; - let (commit, change_amount) = output_commits.get(&id).unwrap().clone(); - t.amount_credited += change_amount; - batch.save(OutputData { - root_key_id: parent_key_id.clone(), - key_id: id.clone(), - n_child: id.to_path().last_path_index(), - commit, - mmr_index: None, - value: change_amount, - status: OutputStatus::Unconfirmed, - height, - lock_height: 0, - is_coinbase: false, - tx_log_entry: Some(log_id), - })?; - } - batch.save_tx_log_entry(t.clone(), &parent_key_id)?; - batch.commit()?; - t - }; - wallet.store_tx( - &format!("{}", tx_entry.tx_slate_id.unwrap()), - slate.tx_or_err()?, - )?; - Ok(()) -} - -/// Creates a new output in the wallet for the recipient, -/// returning the key of the fresh output -/// Also creates a new transaction containing the output -pub fn build_recipient_output<'a, T: ?Sized, C, K>( - wallet: &mut T, - keychain_mask: Option<&SecretKey>, - slate: &mut Slate, - current_height: u64, - parent_key_id: Identifier, - use_test_rng: bool, - is_initiator: bool, -) -> Result<(Identifier, Context, TxLogEntry), Error> - where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - // Create a potential output for this transaction - let key_id = next_available_key(wallet, keychain_mask).unwrap(); - let keychain = wallet.keychain(keychain_mask)?; - let key_id_inner = key_id.clone(); - let amount = slate.amount; - let height = current_height; - - let slate_id = slate.id; - slate.add_transaction_elements( - &keychain, - &ProofBuilder::new(&keychain), - vec![build::output(amount, key_id.clone())], - )?; - - // Add blinding sum to our context - let mut context = Context::new(keychain.secp(), &parent_key_id, use_test_rng, is_initiator); - - context.add_output(&key_id, &None, amount); - context.amount = amount; - context.fee = slate.fee_fields.as_opt(); - let commit = wallet.calc_commit_for_cache(keychain_mask, amount, &key_id_inner)?; - let mut batch = wallet.batch(keychain_mask)?; - let log_id = batch.next_tx_log_id(&parent_key_id)?; - let mut t = TxLogEntry::new(parent_key_id.clone(), TxLogEntryType::TxReceived, log_id); - t.tx_slate_id = Some(slate_id); - t.amount_credited = amount; - t.num_outputs = 1; - t.ttl_cutoff_height = match slate.ttl_cutoff_height { - 0 => None, - n => Some(n), - }; - // when invoicing, this will be invalid - if let Ok(e) = slate.calc_excess(keychain.secp()) { - t.kernel_excess = Some(e) - } - t.kernel_lookup_min_height = Some(current_height); - batch.save(OutputData { - root_key_id: parent_key_id.clone(), - key_id: key_id_inner.clone(), - mmr_index: None, - n_child: key_id_inner.to_path().last_path_index(), - commit, - value: amount, - status: OutputStatus::Unconfirmed, - height, - lock_height: 0, - is_coinbase: false, - tx_log_entry: Some(log_id), - })?; - batch.save_tx_log_entry(t.clone(), &parent_key_id)?; - batch.commit()?; - - Ok((key_id, context, t)) -} - -/// Builds a transaction to send to someone from the HD seed associated with the -/// wallet and the amount to send. Handles reading through the wallet data file, -/// selecting outputs to spend and building the change. -pub fn select_send_tx<'a, T: ?Sized, C, K, B>( - wallet: &mut T, - keychain_mask: Option<&SecretKey>, - amount: u64, - amount_includes_fee: bool, - current_height: u64, - minimum_confirmations: u64, - max_outputs: usize, - change_outputs: usize, - selection_strategy_is_use_all: bool, - parent_key_id: &Identifier, - include_inputs_in_sum: bool, -) -> Result< - ( - Vec>>, - Vec, - Vec<(u64, Identifier, Option)>, // change amounts and derivations - u64, // fee - ), - Error, -> - where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, - B: ProofBuild, -{ - let (coins, _total, amount, fee) = select_coins_and_fee( - wallet, - amount, - amount_includes_fee, - current_height, - minimum_confirmations, - max_outputs, - change_outputs, - selection_strategy_is_use_all, - &parent_key_id, - )?; - - // build transaction skeleton with inputs and change - let (parts, change_amounts_derivations) = inputs_and_change( - &coins, - wallet, - keychain_mask, - amount, - fee, - change_outputs, - include_inputs_in_sum, - )?; - - Ok((parts, coins, change_amounts_derivations, fee)) -} - -/// Select outputs and calculating fee. -pub fn select_coins_and_fee<'a, T: ?Sized, C, K>( - wallet: &mut T, - amount: u64, - amount_includes_fee: bool, - current_height: u64, - minimum_confirmations: u64, - max_outputs: usize, - change_outputs: usize, - selection_strategy_is_use_all: bool, - parent_key_id: &Identifier, -) -> Result< - ( - Vec, - u64, // total - u64, // amount - u64, // fee - ), - Error, -> - where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - // select some spendable coins from the wallet - let (max_outputs, mut coins) = select_coins( - wallet, - amount, - current_height, - minimum_confirmations, - max_outputs, - selection_strategy_is_use_all, - parent_key_id, - ); - - // sender is responsible for setting the fee on the partial tx - // recipient should double check the fee calculation and not blindly trust the - // sender - - // First attempt to spend without change - let mut fee = tx_fee(coins.len(), 1, 1); - let mut total: u64 = coins.iter().map(|c| c.value).sum(); - let mut amount_with_fee = match amount_includes_fee { - true => amount, - false => amount + fee, - }; - - if total == 0 { - return Err(Error::NotEnoughFunds { - available: 0, - available_disp: amount_to_hr_string(0, false), - needed: amount_with_fee, - needed_disp: amount_to_hr_string(amount_with_fee, false), - }); - } - - // The amount with fee is more than the total values of our max outputs - if total < amount_with_fee && coins.len() == max_outputs { - return Err(Error::NotEnoughFunds { - available: total, - available_disp: amount_to_hr_string(total, false), - needed: amount_with_fee, - needed_disp: amount_to_hr_string(amount_with_fee, false), - }); - } - - let num_outputs = change_outputs + 1; - - // We need to add a change address or amount with fee is more than total - if total != amount_with_fee { - fee = tx_fee(coins.len(), num_outputs, 1); - amount_with_fee = match amount_includes_fee { - true => amount, - false => amount + fee, - }; - - // Here check if we have enough outputs for the amount including fee otherwise - // look for other outputs and check again - while total < amount_with_fee { - // End the loop if we have selected all the outputs and still not enough funds - if coins.len() == max_outputs { - return Err(Error::NotEnoughFunds { - available: total, - available_disp: amount_to_hr_string(total, false), - needed: amount_with_fee, - needed_disp: amount_to_hr_string(amount_with_fee, false), - }); - } - - // select some spendable coins from the wallet - coins = select_coins( - wallet, - amount_with_fee, - current_height, - minimum_confirmations, - max_outputs, - selection_strategy_is_use_all, - parent_key_id, - ) - .1; - fee = tx_fee(coins.len(), num_outputs, 1); - total = coins.iter().map(|c| c.value).sum(); - amount_with_fee = match amount_includes_fee { - true => amount, - false => amount + fee, - }; - } - } - // If original amount includes fee, the new amount should - // be reduced, to accommodate the fee. - let new_amount = match amount_includes_fee { - true => amount.checked_sub(fee).ok_or(Error::GenericError( - format!("Transaction amount is too small to include fee").into(), - ))?, - false => amount, - }; - Ok((coins, total, new_amount, fee)) -} - -/// Selects inputs and change for a transaction -pub fn inputs_and_change<'a, T: ?Sized, C, K, B>( - coins: &[OutputData], - wallet: &mut T, - keychain_mask: Option<&SecretKey>, - amount: u64, - fee: u64, - num_change_outputs: usize, - include_inputs_in_sum: bool, -) -> Result< - ( - Vec>>, - Vec<(u64, Identifier, Option)>, - ), - Error, -> - where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, - B: ProofBuild, -{ - let mut parts = vec![]; - - // calculate the total across all inputs, and how much is left - let total: u64 = coins.iter().map(|c| c.value).sum(); - - // if we are spending 10,000 coins to send 1,000 then our change will be 9,000 - // if the fee is 80 then the recipient will receive 1000 and our change will be - // 8,920 - let change = total - amount - fee; - - // build inputs using the appropriate derived key_ids - if include_inputs_in_sum { - for coin in coins { - if coin.is_coinbase { - parts.push(build::coinbase_input(coin.value, coin.key_id.clone())); - } else { - parts.push(build::input(coin.value, coin.key_id.clone())); - } - } - } - - let mut change_amounts_derivations = vec![]; - - if change == 0 { - debug!("No change (sending exactly amount + fee), no change outputs to build"); - } else { - debug!( - "Building change outputs: total change: {} ({} outputs)", - change, num_change_outputs - ); - - let part_change = change / num_change_outputs as u64; - let remainder_change = change % part_change; - - for x in 0..num_change_outputs { - // n-1 equal change_outputs and a final one accounting for any remainder - let change_amount = if x == (num_change_outputs - 1) { - part_change + remainder_change - } else { - part_change - }; - - let change_key = wallet.next_child(keychain_mask).unwrap(); - - change_amounts_derivations.push((change_amount, change_key.clone(), None)); - parts.push(build::output(change_amount, change_key)); - } - } - - Ok((parts, change_amounts_derivations)) -} - -/// Select spendable coins from a wallet. -/// Default strategy is to spend the maximum number of outputs (up to -/// max_outputs). Alternative strategy is to spend smallest outputs first -/// but only as many as necessary. When we introduce additional strategies -/// we should pass something other than a bool in. -pub fn select_coins<'a, T: ?Sized, C, K>( - wallet: &mut T, - amount: u64, - current_height: u64, - minimum_confirmations: u64, - max_outputs: usize, - select_all: bool, - parent_key_id: &Identifier, -) -> (usize, Vec) -// max_outputs_available, Outputs - where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - // first find all eligible outputs based on number of confirmations - let mut eligible = wallet - .iter() - .filter(|out| { - out.root_key_id == *parent_key_id - && out.eligible_to_spend(current_height, minimum_confirmations) - }) - .collect::>(); - - let max_available = eligible.len(); - - // sort eligible outputs by increasing value - eligible.sort_by_key(|out| out.value); - - // use a sliding window to identify potential sets of possible outputs to spend - // Case of amount > total amount of max_outputs(500): - // The limit exists because by default, we always select as many inputs as - // possible in a transaction, to reduce both the Output set and the fees. - // But that only makes sense up to a point, hence the limit to avoid being too - // greedy. But if max_outputs(500) is actually not enough to cover the whole - // amount, the wallet should allow going over it to satisfy what the user - // wants to send. So the wallet considers max_outputs more of a soft limit. - if eligible.len() > max_outputs { - for window in eligible.windows(max_outputs) { - let windowed_eligibles = window.to_vec(); - if let Some(outputs) = select_from(amount, select_all, windowed_eligibles) { - return (max_available, outputs); - } - } - // Not exist in any window of which total amount >= amount. - // Then take coins from the smallest one up to the total amount of selected - // coins = the amount. - if let Some(outputs) = select_from(amount, false, eligible.clone()) { - debug!( - "Extending maximum number of outputs. {} outputs selected.", - outputs.len() - ); - return (max_available, outputs); - } - } else if let Some(outputs) = select_from(amount, select_all, eligible.clone()) { - return (max_available, outputs); - } - - // we failed to find a suitable set of outputs to spend, - // so return the largest amount we can so we can provide guidance on what is - // possible - eligible.reverse(); - ( - max_available, - eligible.iter().take(max_outputs).cloned().collect(), - ) -} - -fn select_from(amount: u64, select_all: bool, outputs: Vec) -> Option> { - let total = outputs.iter().fold(0, |acc, x| acc + x.value); - if total >= amount { - if select_all { - Some(outputs.to_vec()) - } else { - let mut selected_amount = 0; - Some( - outputs - .iter() - .take_while(|out| { - let res = selected_amount < amount; - selected_amount += out.value; - res - }) - .cloned() - .collect(), - ) - } - } else { - None - } -} - -/// Repopulates output in the slate's tranacstion -/// with outputs from the stored context -/// change outputs and tx log entry -/// Remove the explicitly stored excess -pub fn repopulate_tx<'a, T: ?Sized, C, K>( - wallet: &mut T, - keychain_mask: Option<&SecretKey>, - slate: &mut Slate, - context: &Context, - update_fee: bool, -) -> Result<(), Error> - where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - // restore the original amount, fee - slate.amount = context.amount; - if update_fee { - slate.fee_fields = context - .fee - .ok_or_else(|| Error::Fee("Missing fee fields".into()))?; - } - - let keychain = wallet.keychain(keychain_mask)?; - - // restore my signature data - slate.add_participant_info(&keychain, &context, None)?; - - let mut parts = vec![]; - for (id, _, value) in &context.get_inputs() { - let input = wallet.iter().find(|out| out.key_id == *id); - if let Some(i) = input { - if i.is_coinbase { - parts.push(build::coinbase_input(*value, i.key_id.clone())); - } else { - parts.push(build::input(*value, i.key_id.clone())); - } - } - } - for (id, _, value) in &context.get_outputs() { - let output = wallet.iter().find(|out| out.key_id == *id); - if let Some(i) = output { - parts.push(build::output(*value, i.key_id.clone())); - } - } - let _ = slate.add_transaction_elements(&keychain, &ProofBuilder::new(&keychain), parts)?; - // restore the original offset - slate.tx_or_err_mut()?.offset = slate.offset.clone(); - Ok(()) -} \ No newline at end of file diff --git a/src/wallet/tx.rs b/src/wallet/tx.rs deleted file mode 100644 index 5076f5a..0000000 --- a/src/wallet/tx.rs +++ /dev/null @@ -1,547 +0,0 @@ -// Copyright 2023 The Grim Developers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::io::Cursor; - -use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; -use ed25519_dalek::{Signer, Verifier}; -use ed25519_dalek::Keypair as DalekKeypair; -use ed25519_dalek::PublicKey as DalekPublicKey; -use ed25519_dalek::SecretKey as DalekSecretKey; -use ed25519_dalek::Signature as DalekSignature; -use grin_core::consensus::valid_header_version; -use grin_core::core::FeeFields; -use grin_core::core::HeaderVersion; -use grin_keychain::{Identifier, Keychain}; -use grin_util::Mutex; -use grin_util::secp::key::SecretKey; -use grin_util::secp::pedersen; -use grin_wallet_libwallet::{Context, NodeClient, StoredProofInfo, TxLogEntryType, WalletBackend}; -use grin_wallet_libwallet::{address, Error}; -use grin_wallet_libwallet::InitTxArgs; -use grin_wallet_libwallet::Slate; -use grin_wallet_util::OnionV3Address; -use lazy_static::lazy_static; -use log::trace; -use uuid::Uuid; - -use crate::wallet::selection::{build_recipient_output, build_send_tx, select_coins_and_fee}; -use crate::wallet::updater::{cancel_tx_and_outputs, refresh_outputs, retrieve_outputs, retrieve_txs}; - -lazy_static! { - /// Static value to increment UUIDs of slates. - static ref SLATE_COUNTER: Mutex = Mutex::new(0); -} - -/// Creates a new slate for a transaction, can be called by anyone involved in -/// the transaction (sender(s), receiver(s)). -pub fn new_tx_slate<'a, T: ?Sized, C, K>( - wallet: &mut T, - amount: u64, - is_invoice: bool, - num_participants: u8, - use_test_rng: bool, - ttl_blocks: Option, -) -> Result - where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - let current_height = wallet.w2n_client().get_chain_tip()?.0; - let mut slate = Slate::blank(num_participants, is_invoice); - if let Some(b) = ttl_blocks { - slate.ttl_cutoff_height = current_height + b; - } - if use_test_rng { - { - let sc = SLATE_COUNTER.lock(); - let bytes = [4, 54, 67, 12, 43, 2, 98, 76, 32, 50, 87, 5, 1, 33, 43, *sc]; - slate.id = Uuid::from_slice(&bytes).unwrap(); - } - *SLATE_COUNTER.lock() += 1; - } - slate.amount = amount; - - if valid_header_version(current_height, HeaderVersion(1)) { - slate.version_info.block_header_version = 1; - } - - if valid_header_version(current_height, HeaderVersion(2)) { - slate.version_info.block_header_version = 2; - } - - if valid_header_version(current_height, HeaderVersion(3)) { - slate.version_info.block_header_version = 3; - } - - // Set the features explicitly to 0 here. - // This will generate a Plain kernel (rather than a HeightLocked kernel). - slate.kernel_features = 0; - - Ok(slate) -} - -/// Add inputs to the slate (effectively becoming the sender). -pub fn add_inputs_to_slate<'a, T: ?Sized, C, K>( - wallet: &mut T, - keychain_mask: Option<&SecretKey>, - slate: &mut Slate, - current_height: u64, - minimum_confirmations: u64, - max_outputs: usize, - num_change_outputs: usize, - selection_strategy_is_use_all: bool, - parent_key_id: &Identifier, - is_initiator: bool, - use_test_rng: bool, - amount_includes_fee: bool, -) -> Result - where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - // sender should always refresh outputs - refresh_outputs(wallet, keychain_mask, parent_key_id, false)?; - - // Sender selects outputs into a new slate and save our corresponding keys in - // a transaction context. The secret key in our transaction context will be - // randomly selected. This returns the public slate, and a closure that locks - // our inputs and outputs once we're convinced the transaction exchange went - // according to plan - // This function is just a big helper to do all of that, in theory - // this process can be split up in any way - let mut context = build_send_tx( - wallet, - &wallet.keychain(keychain_mask)?, - keychain_mask, - slate, - current_height, - minimum_confirmations, - max_outputs, - num_change_outputs, - selection_strategy_is_use_all, - None, - parent_key_id.clone(), - use_test_rng, - is_initiator, - amount_includes_fee, - )?; - - // Generate a kernel offset and subtract from our context's secret key. Store - // the offset in the slate's transaction kernel, and adds our public key - // information to the slate - slate.fill_round_1(&wallet.keychain(keychain_mask)?, &mut context)?; - - context.initial_sec_key = context.sec_key.clone(); - - if !is_initiator { - // perform partial sig - slate.fill_round_2( - &wallet.keychain(keychain_mask)?, - &context.sec_key, - &context.sec_nonce, - )?; - } - - Ok(context) -} - -/// Add receiver output to the slate. -pub fn add_output_to_slate<'a, T: ?Sized, C, K>( - wallet: &mut T, - keychain_mask: Option<&SecretKey>, - slate: &mut Slate, - current_height: u64, - parent_key_id: &Identifier, - is_initiator: bool, - use_test_rng: bool, -) -> Result - where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - let keychain = wallet.keychain(keychain_mask)?; - // create an output using the amount in the slate - let (_, mut context, mut tx) = build_recipient_output( - wallet, - keychain_mask, - slate, - current_height, - parent_key_id.clone(), - use_test_rng, - is_initiator, - )?; - - // fill public keys - slate.fill_round_1(&keychain, &mut context)?; - - context.initial_sec_key = context.sec_key.clone(); - - if !is_initiator { - // perform partial sig - slate.fill_round_2(&keychain, &context.sec_key, &context.sec_nonce)?; - // update excess in stored transaction - let mut batch = wallet.batch(keychain_mask)?; - tx.kernel_excess = Some(slate.calc_excess(keychain.secp())?); - batch.save_tx_log_entry(tx.clone(), &parent_key_id)?; - batch.commit()?; - } - - Ok(context) -} - -/// Create context, without adding inputs to slate. -pub fn create_late_lock_context<'a, T: ?Sized, C, K>( - wallet: &mut T, - keychain_mask: Option<&SecretKey>, - slate: &mut Slate, - current_height: u64, - init_tx_args: &InitTxArgs, - parent_key_id: &Identifier, - use_test_rng: bool, -) -> Result - where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - // sender should always refresh outputs - refresh_outputs(wallet, keychain_mask, parent_key_id, false)?; - - // we're just going to run a selection to get the potential fee, - // but this won't be locked - let (_coins, _total, _amount, fee) = select_coins_and_fee( - wallet, - init_tx_args.amount, - init_tx_args.amount_includes_fee.unwrap_or(false), - current_height, - init_tx_args.minimum_confirmations, - init_tx_args.max_outputs as usize, - init_tx_args.num_change_outputs as usize, - init_tx_args.selection_strategy_is_use_all, - &parent_key_id, - )?; - slate.fee_fields = FeeFields::new(0, fee)?; - - let keychain = wallet.keychain(keychain_mask)?; - - // Create our own private context - let mut context = Context::new(keychain.secp(), &parent_key_id, use_test_rng, true); - context.fee = Some(slate.fee_fields); - context.amount = slate.amount; - context.late_lock_args = Some(init_tx_args.clone()); - - // Generate a blinding factor for the tx and add - // public key info to the slate - slate.fill_round_1(&wallet.keychain(keychain_mask)?, &mut context)?; - - Ok(context) -} - -/// Complete a transaction. -pub fn complete_tx<'a, T: ?Sized, C, K>( - wallet: &mut T, - keychain_mask: Option<&SecretKey>, - slate: &mut Slate, - context: &Context, -) -> Result<(), Error> - where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - // when self sending invoice tx, use initiator nonce to finalize - let (sec_key, sec_nonce) = { - if context.initial_sec_key != context.sec_key - && context.initial_sec_nonce != context.sec_nonce - { - ( - context.initial_sec_key.clone(), - context.initial_sec_nonce.clone(), - ) - } else { - (context.sec_key.clone(), context.sec_nonce.clone()) - } - }; - slate.fill_round_2(&wallet.keychain(keychain_mask)?, &sec_key, &sec_nonce)?; - - // Final transaction can be built by anyone at this stage - trace!("Slate to finalize is: {}", slate); - slate.finalize(&wallet.keychain(keychain_mask)?)?; - Ok(()) -} - -/// Rollback outputs associated with a transaction in the wallet. -pub fn cancel_tx<'a, T: ?Sized, C, K>( - wallet: &mut T, - keychain_mask: Option<&SecretKey>, - parent_key_id: &Identifier, - tx_id: Option, - tx_slate_id: Option, -) -> Result<(), Error> - where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - let mut tx_id_string = String::new(); - if let Some(tx_id) = tx_id { - tx_id_string = tx_id.to_string(); - } else if let Some(tx_slate_id) = tx_slate_id { - tx_id_string = tx_slate_id.to_string(); - } - let tx_vec = retrieve_txs( - wallet, - tx_id, - tx_slate_id, - None, - Some(&parent_key_id), - false, - )?; - if tx_vec.len() != 1 { - return Err(Error::TransactionDoesntExist(tx_id_string)); - } - let tx = tx_vec[0].clone(); - match tx.tx_type { - TxLogEntryType::TxSent | TxLogEntryType::TxReceived | TxLogEntryType::TxReverted => {} - _ => return Err(Error::TransactionNotCancellable(tx_id_string)), - } - if tx.confirmed { - return Err(Error::TransactionNotCancellable(tx_id_string)); - } - // get outputs associated with tx - let res = retrieve_outputs( - wallet, - keychain_mask, - false, - Some(tx.id), - Some(&parent_key_id), - )?; - let outputs = res.iter().map(|m| m.output.clone()).collect(); - cancel_tx_and_outputs(wallet, keychain_mask, tx, outputs, parent_key_id)?; - Ok(()) -} - -/// Update the stored transaction (this update needs to happen when the TX is finalised). -pub fn update_stored_tx<'a, T: ?Sized, C, K>( - wallet: &mut T, - keychain_mask: Option<&SecretKey>, - context: &Context, - slate: &Slate, - is_invoiced: bool, -) -> Result<(), Error> - where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - // finalize command - let tx_vec = retrieve_txs(wallet, None, Some(slate.id), None, None, false)?; - let mut tx = None; - // don't want to assume this is the right tx, in case of self-sending - for t in tx_vec { - if t.tx_type == TxLogEntryType::TxSent && !is_invoiced { - tx = Some(t); - break; - } - if t.tx_type == TxLogEntryType::TxReceived && is_invoiced { - tx = Some(t); - break; - } - } - let mut tx = match tx { - Some(t) => t, - None => return Err(Error::TransactionDoesntExist(slate.id.to_string())), - }; - let parent_key = tx.parent_key_id.clone(); - { - let keychain = wallet.keychain(keychain_mask)?; - tx.kernel_excess = Some(slate.calc_excess(keychain.secp())?); - } - - if let Some(ref p) = slate.clone().payment_proof { - let derivation_index = match context.payment_proof_derivation_index { - Some(i) => i, - None => 0, - }; - let keychain = wallet.keychain(keychain_mask)?; - let parent_key_id = wallet.parent_key_id(); - let excess = slate.calc_excess(keychain.secp())?; - let sender_key = - address::address_from_derivation_path(&keychain, &parent_key_id, derivation_index)?; - let sender_address = OnionV3Address::from_private(&sender_key.0)?; - let sig = - create_payment_proof_signature(slate.amount, &excess, p.sender_address, sender_key)?; - tx.payment_proof = Some(StoredProofInfo { - receiver_address: p.receiver_address, - receiver_signature: p.receiver_signature, - sender_address_path: derivation_index, - sender_address: sender_address.to_ed25519()?, - sender_signature: Some(sig), - }) - } - - wallet.store_tx(&format!("{}", tx.tx_slate_id.unwrap()), slate.tx_or_err()?)?; - - let mut batch = wallet.batch(keychain_mask)?; - batch.save_tx_log_entry(tx, &parent_key)?; - batch.commit()?; - Ok(()) -} - -pub fn payment_proof_message( - amount: u64, - kernel_commitment: &pedersen::Commitment, - sender_address: DalekPublicKey, -) -> Result, Error> { - let mut msg = Vec::new(); - msg.write_u64::(amount)?; - msg.append(&mut kernel_commitment.0.to_vec()); - msg.append(&mut sender_address.to_bytes().to_vec()); - Ok(msg) -} - -pub fn _decode_payment_proof_message( - msg: &[u8], -) -> Result<(u64, pedersen::Commitment, DalekPublicKey), Error> { - let mut rdr = Cursor::new(msg); - let amount = rdr.read_u64::()?; - let mut commit_bytes = [0u8; 33]; - for i in 0..33 { - commit_bytes[i] = rdr.read_u8()?; - } - let mut sender_address_bytes = [0u8; 32]; - for i in 0..32 { - sender_address_bytes[i] = rdr.read_u8()?; - } - - Ok(( - amount, - pedersen::Commitment::from_vec(commit_bytes.to_vec()), - DalekPublicKey::from_bytes(&sender_address_bytes).unwrap(), - )) -} - -/// Create a payment proof. -pub fn create_payment_proof_signature( - amount: u64, - kernel_commitment: &pedersen::Commitment, - sender_address: DalekPublicKey, - sec_key: SecretKey, -) -> Result { - let msg = payment_proof_message(amount, kernel_commitment, sender_address)?; - let d_skey = match DalekSecretKey::from_bytes(&sec_key.0) { - Ok(k) => k, - Err(e) => { - return Err(Error::ED25519Key(format!("{}", e))); - } - }; - let pub_key: DalekPublicKey = (&d_skey).into(); - let keypair = DalekKeypair { - public: pub_key, - secret: d_skey, - }; - Ok(keypair.sign(&msg)) -} - -/// Verify all aspects of a completed payment proof on the current slate. -pub fn verify_slate_payment_proof<'a, T: ?Sized, C, K>( - wallet: &mut T, - keychain_mask: Option<&SecretKey>, - parent_key_id: &Identifier, - context: &Context, - slate: &Slate, -) -> Result<(), Error> - where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - let tx_vec = retrieve_txs( - wallet, - None, - Some(slate.id), - None, - Some(parent_key_id), - false, - )?; - if tx_vec.is_empty() { - return Err(Error::PaymentProof( - "TxLogEntry with original proof info not found (is account correct?)".to_owned(), - )); - } - - let orig_proof_info = tx_vec[0].clone().payment_proof; - - if orig_proof_info.is_some() && slate.payment_proof.is_none() { - return Err(Error::PaymentProof( - "Expected Payment Proof for this Transaction is not present".to_owned(), - )); - } - - if let Some(ref p) = slate.clone().payment_proof { - let orig_proof_info = match orig_proof_info { - Some(p) => p.clone(), - None => { - return Err(Error::PaymentProof( - "Original proof info not stored in tx".to_owned(), - )); - } - }; - let keychain = wallet.keychain(keychain_mask)?; - let index = match context.payment_proof_derivation_index { - Some(i) => i, - None => { - return Err(Error::PaymentProof( - "Payment proof derivation index required".to_owned(), - )); - } - }; - let orig_sender_sk = - address::address_from_derivation_path(&keychain, parent_key_id, index)?; - let orig_sender_address = OnionV3Address::from_private(&orig_sender_sk.0)?; - if p.sender_address != orig_sender_address.to_ed25519()? { - return Err(Error::PaymentProof( - "Sender address on slate does not match original sender address".to_owned(), - )); - } - - if orig_proof_info.receiver_address != p.receiver_address { - return Err(Error::PaymentProof( - "Recipient address on slate does not match original recipient address".to_owned(), - )); - } - let msg = payment_proof_message( - slate.amount, - &slate.calc_excess(&keychain.secp())?, - orig_sender_address.to_ed25519()?, - )?; - let sig = match p.receiver_signature { - Some(s) => s, - None => { - return Err(Error::PaymentProof( - "Recipient did not provide requested proof signature".to_owned(), - )); - } - }; - - if p.receiver_address.verify(&msg, &sig).is_err() { - return Err(Error::PaymentProof("Invalid proof signature".to_owned())); - }; - } - Ok(()) -} \ No newline at end of file diff --git a/src/wallet/types.rs b/src/wallet/types.rs index 3c1b4ec..74501e5 100644 --- a/src/wallet/types.rs +++ b/src/wallet/types.rs @@ -15,9 +15,9 @@ use std::sync::Arc; use grin_keychain::ExtKeychain; +use grin_util::Mutex; use grin_wallet_impls::{DefaultLCProvider, HTTPNodeClient}; use grin_wallet_libwallet::{TxLogEntry, WalletInfo, WalletInst}; -use parking_lot::Mutex; /// Mnemonic phrase setup mode. #[derive(PartialEq, Clone)] diff --git a/src/wallet/updater.rs b/src/wallet/updater.rs deleted file mode 100644 index da199e5..0000000 --- a/src/wallet/updater.rs +++ /dev/null @@ -1,837 +0,0 @@ -// Copyright 2023 The Grim Developers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::collections::{HashMap, HashSet}; - -use grin_keychain::{Identifier, Keychain, SwitchCommitmentType}; -use grin_util as util; -use grin_util::secp::key::SecretKey; -use grin_util::secp::pedersen; -use grin_util::static_secp_instance; -use grin_wallet_libwallet::{ - NodeClient, OutputData, OutputStatus, TxLogEntry, TxLogEntryType, WalletBackend, WalletInfo, -}; -use grin_wallet_libwallet::{ - OutputCommitMapping, RetrieveTxQueryArgs, RetrieveTxQuerySortField, - RetrieveTxQuerySortOrder, -}; -use grin_wallet_libwallet::Error; -use log::{debug, warn}; -use num_bigint::BigInt; -use uuid::Uuid; - -/// Retrieve all of the outputs (doesn't attempt to update from node) -pub fn retrieve_outputs<'a, T: ?Sized, C, K>( - wallet: &mut T, - keychain_mask: Option<&SecretKey>, - show_spent: bool, - tx_id: Option, - parent_key_id: Option<&Identifier>, -) -> Result, Error> -where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - // just read the wallet here, no need for a write lock - let mut outputs = wallet - .iter() - .filter(|out| show_spent || out.status != OutputStatus::Spent) - .collect::>(); - - // only include outputs with a given tx_id if provided - if let Some(id) = tx_id { - outputs = outputs - .into_iter() - .filter(|out| out.tx_log_entry == Some(id)) - .collect::>(); - } - - if let Some(k) = parent_key_id { - outputs = outputs - .iter() - .filter(|o| o.root_key_id == *k) - .cloned() - .collect() - } - - outputs.sort_by_key(|out| out.n_child); - let keychain = wallet.keychain(keychain_mask)?; - - let res = outputs - .into_iter() - .map(|output| { - let commit = match output.commit.clone() { - Some(c) => pedersen::Commitment::from_vec(util::from_hex(&c).unwrap()), - None => keychain - .commit(output.value, &output.key_id, SwitchCommitmentType::Regular) - .unwrap(), // TODO: proper support for different switch commitment schemes - }; - OutputCommitMapping { output, commit } - }) - .collect(); - Ok(res) -} - -/// Apply advanced filtering to resultset from retrieve_txs below -pub fn apply_advanced_tx_list_filtering<'a, T: ?Sized, C, K>( - wallet: &mut T, - query_args: &RetrieveTxQueryArgs, -) -> Vec -where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - // Apply simple bool, GTE or LTE fields - let txs_iter: Box> = Box::new( - wallet - .tx_log_iter() - .filter(|tx_entry| { - if let Some(v) = query_args.exclude_cancelled { - if v { - tx_entry.tx_type != TxLogEntryType::TxReceivedCancelled - && tx_entry.tx_type != TxLogEntryType::TxSentCancelled - } else { - true - } - } else { - true - } - }) - .filter(|tx_entry| { - if let Some(v) = query_args.include_outstanding_only { - if v { - !tx_entry.confirmed - } else { - true - } - } else { - true - } - }) - .filter(|tx_entry| { - if let Some(v) = query_args.include_confirmed_only { - if v { - tx_entry.confirmed - } else { - true - } - } else { - true - } - }) - .filter(|tx_entry| { - if let Some(v) = query_args.include_sent_only { - if v { - tx_entry.tx_type == TxLogEntryType::TxSent - || tx_entry.tx_type == TxLogEntryType::TxSentCancelled - } else { - true - } - } else { - true - } - }) - .filter(|tx_entry| { - if let Some(v) = query_args.include_received_only { - if v { - tx_entry.tx_type == TxLogEntryType::TxReceived - || tx_entry.tx_type == TxLogEntryType::TxReceivedCancelled - } else { - true - } - } else { - true - } - }) - .filter(|tx_entry| { - if let Some(v) = query_args.include_coinbase_only { - if v { - tx_entry.tx_type == TxLogEntryType::ConfirmedCoinbase - } else { - true - } - } else { - true - } - }) - .filter(|tx_entry| { - if let Some(v) = query_args.include_reverted_only { - if v { - tx_entry.tx_type == TxLogEntryType::TxReverted - } else { - true - } - } else { - true - } - }) - .filter(|tx_entry| { - if let Some(v) = query_args.min_id { - tx_entry.id >= v - } else { - true - } - }) - .filter(|tx_entry| { - if let Some(v) = query_args.max_id { - tx_entry.id <= v - } else { - true - } - }) - .filter(|tx_entry| { - if let Some(v) = query_args.min_amount { - if tx_entry.tx_type == TxLogEntryType::TxSent - || tx_entry.tx_type == TxLogEntryType::TxSentCancelled - { - BigInt::from(tx_entry.amount_debited) - - BigInt::from(tx_entry.amount_credited) - >= BigInt::from(v) - } else { - BigInt::from(tx_entry.amount_credited) - - BigInt::from(tx_entry.amount_debited) - >= BigInt::from(v) - } - } else { - true - } - }) - .filter(|tx_entry| { - if let Some(v) = query_args.max_amount { - if tx_entry.tx_type == TxLogEntryType::TxSent - || tx_entry.tx_type == TxLogEntryType::TxSentCancelled - { - BigInt::from(tx_entry.amount_debited) - - BigInt::from(tx_entry.amount_credited) - <= BigInt::from(v) - } else { - BigInt::from(tx_entry.amount_credited) - - BigInt::from(tx_entry.amount_debited) - <= BigInt::from(v) - } - } else { - true - } - }) - .filter(|tx_entry| { - if let Some(v) = query_args.min_creation_timestamp { - tx_entry.creation_ts >= v - } else { - true - } - }) - .filter(|tx_entry| { - if let Some(v) = query_args.min_confirmed_timestamp { - tx_entry.creation_ts <= v - } else { - true - } - }) - .filter(|tx_entry| { - if let Some(v) = query_args.min_confirmed_timestamp { - if let Some(t) = tx_entry.confirmation_ts { - t >= v - } else { - true - } - } else { - true - } - }) - .filter(|tx_entry| { - if let Some(v) = query_args.max_confirmed_timestamp { - if let Some(t) = tx_entry.confirmation_ts { - t <= v - } else { - true - } - } else { - true - } - }), - ); - - let mut return_txs: Vec = txs_iter.collect(); - - // Now apply requested sorting - if let Some(ref s) = query_args.sort_field { - match s { - RetrieveTxQuerySortField::Id => { - return_txs.sort_by_key(|tx| tx.id); - } - RetrieveTxQuerySortField::CreationTimestamp => { - return_txs.sort_by_key(|tx| tx.creation_ts); - } - RetrieveTxQuerySortField::ConfirmationTimestamp => { - return_txs.sort_by_key(|tx| tx.confirmation_ts); - } - RetrieveTxQuerySortField::TotalAmount => { - return_txs.sort_by_key(|tx| { - if tx.tx_type == TxLogEntryType::TxSent - || tx.tx_type == TxLogEntryType::TxSentCancelled - { - BigInt::from(tx.amount_debited) - BigInt::from(tx.amount_credited) - } else { - BigInt::from(tx.amount_credited) - BigInt::from(tx.amount_debited) - } - }); - } - RetrieveTxQuerySortField::AmountCredited => { - return_txs.sort_by_key(|tx| tx.amount_credited); - } - RetrieveTxQuerySortField::AmountDebited => { - return_txs.sort_by_key(|tx| tx.amount_debited); - } - } - } else { - return_txs.sort_by_key(|tx| tx.id); - } - - if let Some(ref s) = query_args.sort_order { - match s { - RetrieveTxQuerySortOrder::Desc => return_txs.reverse(), - _ => {} - } - } - - // Apply limit if requested - if let Some(l) = query_args.limit { - return_txs = return_txs.into_iter().take(l as usize).collect() - } - - return_txs -} - -/// Retrieve all of the transaction entries, or a particular entry -/// if `parent_key_id` is set, only return entries from that key -pub fn retrieve_txs<'a, T: ?Sized, C, K>( - wallet: &mut T, - tx_id: Option, - tx_slate_id: Option, - query_args: Option, - parent_key_id: Option<&Identifier>, - outstanding_only: bool, -) -> Result, Error> -where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - let mut txs; - // Adding in new transaction list query logic. If `tx_id` or `tx_slate_id` - // is provided, then `query_args` is ignored and old logic is followed. - if query_args.is_some() && tx_id.is_none() && tx_slate_id.is_none() { - txs = apply_advanced_tx_list_filtering(wallet, &query_args.unwrap()) - } else { - txs = wallet - .tx_log_iter() - .filter(|tx_entry| { - let f_pk = match parent_key_id { - Some(k) => tx_entry.parent_key_id == *k, - None => true, - }; - let f_tx_id = match tx_id { - Some(i) => tx_entry.id == i, - None => true, - }; - let f_txs = match tx_slate_id { - Some(t) => tx_entry.tx_slate_id == Some(t), - None => true, - }; - let f_outstanding = match outstanding_only { - true => { - !tx_entry.confirmed - && (tx_entry.tx_type == TxLogEntryType::TxReceived - || tx_entry.tx_type == TxLogEntryType::TxSent - || tx_entry.tx_type == TxLogEntryType::TxReverted) - } - false => true, - }; - f_pk && f_tx_id && f_txs && f_outstanding - }) - .collect(); - txs.sort_by_key(|tx| tx.creation_ts); - } - Ok(txs) -} - -/// Refreshes the outputs in a wallet with the latest information -/// from a node -pub fn refresh_outputs<'a, T: ?Sized, C, K>( - wallet: &mut T, - keychain_mask: Option<&SecretKey>, - parent_key_id: &Identifier, - update_all: bool, -) -> Result<(), Error> -where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - let height = wallet.w2n_client().get_chain_tip()?.0; - refresh_output_state(wallet, keychain_mask, height, parent_key_id, update_all)?; - Ok(()) -} - -/// build a local map of wallet outputs keyed by commit -/// and a list of outputs we want to query the node for -pub fn map_wallet_outputs<'a, T: ?Sized, C, K>( - wallet: &mut T, - keychain_mask: Option<&SecretKey>, - parent_key_id: &Identifier, - update_all: bool, -) -> Result, Option, bool)>, Error> -where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - let mut wallet_outputs = HashMap::new(); - let keychain = wallet.keychain(keychain_mask)?; - let unspents: Vec = wallet - .iter() - .filter(|x| x.root_key_id == *parent_key_id && x.status != OutputStatus::Spent) - .collect(); - - let tx_entries = retrieve_txs(wallet, None, None, None, Some(&parent_key_id), true)?; - - // Only select outputs that are actually involved in an outstanding transaction - let unspents = match update_all { - false => unspents - .into_iter() - .filter(|x| match x.tx_log_entry.as_ref() { - Some(t) => tx_entries.iter().any(|te| te.id == *t), - None => true, - }) - .collect(), - true => unspents, - }; - - for out in unspents { - let commit = match out.commit.clone() { - Some(c) => pedersen::Commitment::from_vec(util::from_hex(&c).unwrap()), - None => keychain - .commit(out.value, &out.key_id, SwitchCommitmentType::Regular) - .unwrap(), // TODO: proper support for different switch commitment schemes - }; - let val = ( - out.key_id.clone(), - out.mmr_index, - out.tx_log_entry, - out.status == OutputStatus::Unspent, - ); - wallet_outputs.insert(commit, val); - } - Ok(wallet_outputs) -} - -/// Cancel transaction and associated outputs -pub fn cancel_tx_and_outputs<'a, T: ?Sized, C, K>( - wallet: &mut T, - keychain_mask: Option<&SecretKey>, - mut tx: TxLogEntry, - outputs: Vec, - parent_key_id: &Identifier, -) -> Result<(), Error> -where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - let mut batch = wallet.batch(keychain_mask)?; - - for mut o in outputs { - // unlock locked outputs - if o.status == OutputStatus::Unconfirmed || o.status == OutputStatus::Reverted { - batch.delete(&o.key_id, &o.mmr_index)?; - } - if o.status == OutputStatus::Locked { - o.status = OutputStatus::Unspent; - batch.save(o)?; - } - } - match tx.tx_type { - TxLogEntryType::TxSent => tx.tx_type = TxLogEntryType::TxSentCancelled, - TxLogEntryType::TxReceived | TxLogEntryType::TxReverted => { - tx.tx_type = TxLogEntryType::TxReceivedCancelled - } - _ => {} - } - batch.save_tx_log_entry(tx, parent_key_id)?; - batch.commit()?; - Ok(()) -} - -/// Apply refreshed API output data to the wallet -pub fn apply_api_outputs<'a, T: ?Sized, C, K>( - wallet: &mut T, - keychain_mask: Option<&SecretKey>, - wallet_outputs: &HashMap, Option, bool)>, - api_outputs: &HashMap, - reverted_kernels: HashSet, - height: u64, - parent_key_id: &Identifier, -) -> Result<(), Error> -where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - // now for each commit, find the output in the wallet and the corresponding - // api output (if it exists) and refresh it in-place in the wallet. - // Note: minimizing the time we spend holding the wallet lock. - { - let last_confirmed_height = wallet.last_confirmed_height()?; - // If the server height is less than our confirmed height, don't apply - // these changes as the chain is syncing, incorrect or forking - if height < last_confirmed_height { - warn!( - "Not updating outputs as the height of the node's chain \ - is less than the last reported wallet update height." - ); - warn!("Please wait for sync on node to complete or fork to resolve and try again."); - return Ok(()); - } - let mut batch = wallet.batch(keychain_mask)?; - for (commit, (id, mmr_index, _, _)) in wallet_outputs.iter() { - if let Ok(mut output) = batch.get(id, mmr_index) { - match api_outputs.get(&commit) { - Some(o) => { - // if this is a coinbase tx being confirmed, it's recordable in tx log - if output.is_coinbase && output.status == OutputStatus::Unconfirmed { - let log_id = batch.next_tx_log_id(parent_key_id)?; - let mut t = TxLogEntry::new( - parent_key_id.clone(), - TxLogEntryType::ConfirmedCoinbase, - log_id, - ); - t.confirmed = true; - t.amount_credited = output.value; - t.amount_debited = 0; - t.num_outputs = 1; - // calculate kernel excess for coinbase - { - let secp = static_secp_instance(); - let secp = secp.lock(); - let over_commit = secp.commit_value(output.value)?; - let excess = secp.commit_sum(vec![*commit], vec![over_commit])?; - t.kernel_excess = Some(excess); - t.kernel_lookup_min_height = Some(height); - } - t.update_confirmation_ts(); - output.tx_log_entry = Some(log_id); - batch.save_tx_log_entry(t, &parent_key_id)?; - } - // also mark the transaction in which this output is involved as confirmed - // note that one involved input/output confirmation SHOULD be enough - // to reliably confirm the tx - if !output.is_coinbase - && (output.status == OutputStatus::Unconfirmed - || output.status == OutputStatus::Reverted) - { - let tx = batch.tx_log_iter().find(|t| { - Some(t.id) == output.tx_log_entry - && t.parent_key_id == *parent_key_id - }); - if let Some(mut t) = tx { - if t.tx_type == TxLogEntryType::TxReverted { - t.tx_type = TxLogEntryType::TxReceived; - t.reverted_after = None; - } - t.update_confirmation_ts(); - t.confirmed = true; - batch.save_tx_log_entry(t, &parent_key_id)?; - } - } - output.height = o.1; - output.mark_unspent(); - } - None => { - if !output.is_coinbase - && output - .tx_log_entry - .map(|i| reverted_kernels.contains(&i)) - .unwrap_or(false) - { - output.mark_reverted(); - } else { - output.mark_spent(); - } - } - } - batch.save(output)?; - } - } - - for mut tx in batch.tx_log_iter() { - if reverted_kernels.contains(&tx.id) && tx.parent_key_id == *parent_key_id { - tx.tx_type = TxLogEntryType::TxReverted; - tx.reverted_after = tx.confirmation_ts.clone().and_then(|t| { - let now = chrono::Utc::now(); - (now - t).to_std().ok() - }); - tx.confirmed = false; - batch.save_tx_log_entry(tx, &parent_key_id)?; - } - } - - { - batch.save_last_confirmed_height(parent_key_id, height)?; - } - batch.commit()?; - } - Ok(()) -} - -/// Builds a single api query to retrieve the latest output data from the node. -/// So we can refresh the local wallet outputs. -pub fn refresh_output_state<'a, T: ?Sized, C, K>( - wallet: &mut T, - keychain_mask: Option<&SecretKey>, - height: u64, - parent_key_id: &Identifier, - update_all: bool, -) -> Result<(), Error> -where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - debug!("Refreshing wallet outputs"); - - // build a local map of wallet outputs keyed by commit - // and a list of outputs we want to query the node for - let wallet_outputs = map_wallet_outputs(wallet, keychain_mask, parent_key_id, update_all)?; - - let wallet_output_keys = wallet_outputs.keys().copied().collect(); - - let api_outputs = wallet - .w2n_client() - .get_outputs_from_node(wallet_output_keys)?; - - // For any disappeared output, check the on-chain status of the corresponding transaction kernel - // If it is no longer present, the transaction was reverted due to a re-org - let reverted_kernels = - find_reverted_kernels(wallet, &wallet_outputs, &api_outputs, parent_key_id)?; - - apply_api_outputs( - wallet, - keychain_mask, - &wallet_outputs, - &api_outputs, - reverted_kernels, - height, - parent_key_id, - )?; - clean_old_unconfirmed(wallet, keychain_mask, height)?; - Ok(()) -} - -fn find_reverted_kernels<'a, T: ?Sized, C, K>( - wallet: &mut T, - wallet_outputs: &HashMap, Option, bool)>, - api_outputs: &HashMap, - parent_key_id: &Identifier, -) -> Result, Error> -where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - let mut client = wallet.w2n_client().clone(); - let mut ids = HashSet::new(); - - // Get transaction IDs for outputs that are no longer unspent - for (commit, (_, _, tx_id, was_unspent)) in wallet_outputs { - if let Some(tx_id) = *tx_id { - if *was_unspent && !api_outputs.contains_key(commit) { - ids.insert(tx_id); - } - } - } - - // Get corresponding kernels - let kernels = wallet - .tx_log_iter() - .filter(|t| { - ids.contains(&t.id) - && t.parent_key_id == *parent_key_id - && t.tx_type == TxLogEntryType::TxReceived - }) - .filter_map(|t| { - t.kernel_excess - .map(|e| (t.id, e, t.kernel_lookup_min_height)) - }); - - // Check each of the kernels on-chain - let mut reverted = HashSet::new(); - for (id, excess, min_height) in kernels { - if client.get_kernel(&excess, min_height, None)?.is_none() { - reverted.insert(id); - } - } - - Ok(reverted) -} - -fn clean_old_unconfirmed<'a, T: ?Sized, C, K>( - wallet: &mut T, - keychain_mask: Option<&SecretKey>, - height: u64, -) -> Result<(), Error> -where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - if height < 50 { - return Ok(()); - } - let mut ids_to_del = vec![]; - for out in wallet.iter() { - if out.status == OutputStatus::Unconfirmed - && out.height > 0 - && out.height < height - 50 - && out.is_coinbase - { - ids_to_del.push(out.key_id.clone()) - } - } - let mut batch = wallet.batch(keychain_mask)?; - for id in ids_to_del { - batch.delete(&id, &None)?; - } - batch.commit()?; - Ok(()) -} - -/// Retrieve summary info about the wallet -/// caller should refresh first if desired -pub fn retrieve_info<'a, T: ?Sized, C, K>( - wallet: &mut T, - parent_key_id: &Identifier, - minimum_confirmations: u64, -) -> Result -where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - let current_height = wallet.last_confirmed_height()?; - let outputs = wallet - .iter() - .filter(|out| out.root_key_id == *parent_key_id); - - let mut unspent_total = 0; - let mut immature_total = 0; - let mut awaiting_finalization_total = 0; - let mut unconfirmed_total = 0; - let mut locked_total = 0; - let mut reverted_total = 0; - - for out in outputs { - match out.status { - OutputStatus::Unspent => { - if out.is_coinbase && out.lock_height > current_height { - immature_total += out.value; - } else if out.num_confirmations(current_height) < minimum_confirmations { - // Treat anything less than minimum confirmations as "unconfirmed". - unconfirmed_total += out.value; - } else { - unspent_total += out.value; - } - } - OutputStatus::Unconfirmed => { - // We ignore unconfirmed coinbase outputs completely. - if !out.is_coinbase { - if minimum_confirmations == 0 { - unconfirmed_total += out.value; - } else { - awaiting_finalization_total += out.value; - } - } - } - OutputStatus::Locked => { - locked_total += out.value; - } - OutputStatus::Reverted => reverted_total += out.value, - OutputStatus::Spent => {} - } - } - - Ok(WalletInfo { - last_confirmed_height: current_height, - minimum_confirmations, - total: unspent_total + unconfirmed_total + immature_total, - amount_awaiting_finalization: awaiting_finalization_total, - amount_awaiting_confirmation: unconfirmed_total, - amount_immature: immature_total, - amount_locked: locked_total, - amount_currently_spendable: unspent_total, - amount_reverted: reverted_total, - }) -} - -/// Rollback outputs associated with a transaction in the wallet -pub fn cancel_tx<'a, T: ?Sized, C, K>( - wallet: &mut T, - keychain_mask: Option<&SecretKey>, - parent_key_id: &Identifier, - tx_id: Option, - tx_slate_id: Option, -) -> Result<(), Error> - where - T: WalletBackend<'a, C, K>, - C: NodeClient + 'a, - K: Keychain + 'a, -{ - let mut tx_id_string = String::new(); - if let Some(tx_id) = tx_id { - tx_id_string = tx_id.to_string(); - } else if let Some(tx_slate_id) = tx_slate_id { - tx_id_string = tx_slate_id.to_string(); - } - let tx_vec = retrieve_txs( - wallet, - tx_id, - tx_slate_id, - None, - Some(&parent_key_id), - false, - )?; - if tx_vec.len() != 1 { - return Err(Error::TransactionDoesntExist(tx_id_string)); - } - let tx = tx_vec[0].clone(); - match tx.tx_type { - TxLogEntryType::TxSent | TxLogEntryType::TxReceived | TxLogEntryType::TxReverted => {} - _ => return Err(Error::TransactionNotCancellable(tx_id_string)), - } - if tx.confirmed { - return Err(Error::TransactionNotCancellable(tx_id_string)); - } - // get outputs associated with tx - let res = retrieve_outputs( - wallet, - keychain_mask, - false, - Some(tx.id), - Some(&parent_key_id), - )?; - let outputs = res.iter().map(|m| m.output.clone()).collect(); - cancel_tx_and_outputs(wallet, keychain_mask, tx, outputs, parent_key_id)?; - Ok(()) -} \ No newline at end of file diff --git a/src/wallet/wallet.rs b/src/wallet/wallet.rs index 8cc2ab8..385bee7 100644 --- a/src/wallet/wallet.rs +++ b/src/wallet/wallet.rs @@ -22,13 +22,13 @@ use std::time::Duration; use grin_chain::SyncStatus; use grin_core::global; use grin_keychain::{ExtKeychain, Keychain}; +use grin_util::Mutex; use grin_util::secp::SecretKey; use grin_util::types::ZeroingString; use grin_wallet_api::Owner; use grin_wallet_impls::{DefaultLCProvider, DefaultWalletImpl, HTTPNodeClient}; use grin_wallet_libwallet::{Error, NodeClient, StatusMessage, WalletInst, WalletLCProvider}; use grin_wallet_libwallet::api_impl::owner::{retrieve_summary_info, retrieve_txs}; -use parking_lot::Mutex; use crate::node::{Node, NodeConfig}; use crate::wallet::{ConnectionsConfig, ExternalConnection, WalletConfig};