diff --git a/.github/actions/setup-build-environment/action.yml b/.github/actions/setup-build-environment/action.yml index e45bc0648..38f16755d 100644 --- a/.github/actions/setup-build-environment/action.yml +++ b/.github/actions/setup-build-environment/action.yml @@ -32,7 +32,7 @@ runs: npm install --global yarn@1 - name: Install Rust stable - uses: dtolnay/rust-toolchain@1.87 + uses: dtolnay/rust-toolchain@1.88 with: targets: ${{ inputs.target }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f7c961ac3..28e3e3c78 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -111,6 +111,8 @@ jobs: test_name: happy_path - package: swap test_name: happy_path_alice_developer_tip + - package: swap + test_name: happy_path_alice_developer_tip_subaddress - package: swap test_name: happy_path_restart_bob_after_xmr_locked - package: swap @@ -147,6 +149,10 @@ jobs: test_name: alice_empty_balance_after_started_btc_early_refund - package: swap test_name: alice_broken_wallet_rpc_after_started_btc_early_refund + - package: monero-tests + test_name: transfers + - package: monero-tests + test_name: transfers_wrong_key runs-on: ubuntu-22.04 if: github.event_name == 'push' || !github.event.pull_request.draft diff --git a/.vscode/settings.json b/.vscode/settings.json index 4ee485c36..104cee660 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -73,9 +73,17 @@ "shared_mutex": "cpp", "source_location": "cpp", "strstream": "cpp", - "typeindex": "cpp" + "typeindex": "cpp", + "valarray": "cpp", + "*.ipp": "cpp" }, "rust-analyzer.cargo.extraEnv": { "CARGO_TARGET_DIR": "target-check" - } -} + }, + "[cpp]": { + "editor.formatOnSave": false + }, + "[c]": { + "editor.formatOnSave": false + }, +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 3739e723e..b5f73dddd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- Update Rust version to 1.88 to satisfy depenency requirements. ## [3.2.11] - 2025-11-09 - GUI + SWAP: Assume double spend safety of Monero transactions after 6 confirmations. This means we are assuming that there won't be any re-orgs deeper than 5 blocks. We believe this is a safe assumption given that there were almost no orphaned blocks over the last two weeks. Qubic (which was behind the re-orgs) has mined less than 1% of the last 1000 blocks. diff --git a/Cargo.lock b/Cargo.lock index 0a09342dd..8a0ad7efd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -69,9 +69,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -272,7 +272,7 @@ source = "git+https://github.com/eigenwallet/arti?rev=537dd8755817aa2b21c41e66ed dependencies = [ "async-trait", "cfg-if", - "derive-deftly 1.3.0", + "derive-deftly", "derive_builder_fork_arti", "derive_more 2.0.1", "educe", @@ -410,7 +410,7 @@ checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", "synstructure 0.13.2", ] @@ -422,7 +422,7 @@ checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", "synstructure 0.13.2", ] @@ -445,7 +445,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -591,7 +591,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -631,7 +631,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -648,7 +648,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -857,7 +857,7 @@ checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -1008,7 +1008,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b59a3f7fbe678874fa34354097644a171276e02a49934c13b3d61c54610ddf39" dependencies = [ "bdk_core", - "electrum-client 0.24.0", + "electrum-client 0.24.1", ] [[package]] @@ -1097,7 +1097,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -1283,7 +1283,7 @@ checksum = "e0b121a9fe0df916e362fb3271088d071159cdf11db0e4182d02152850756eff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -1375,7 +1375,7 @@ dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -1431,9 +1431,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" dependencies = [ "memchr", "regex-automata", @@ -1619,9 +1619,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.43" +version = "1.2.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "739eb0f94557554b3ca9a86d2d37bebd49c5e6d0c1d2bda35ba5bdac830befc2" +checksum = "37521ac7aabe3d13122dc382493e20c9416f299d2ccd5b3a5340a2570cdeb0f3" dependencies = [ "find-msvc-tools", "jobserver", @@ -1804,9 +1804,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.50" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623" +checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" dependencies = [ "clap_builder", "clap_derive", @@ -1814,9 +1814,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.50" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0" +checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" dependencies = [ "anstream", "anstyle", @@ -1833,7 +1833,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -1942,7 +1942,7 @@ checksum = "b77735bd89be8da01c8d7e61faec5a9ccb0e313cece3c773c6b3ae251b90c7d4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2176,7 +2176,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.5.50", + "clap 4.5.51", "criterion-plot", "itertools 0.13.0", "num-traits", @@ -2342,7 +2342,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2352,7 +2352,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" dependencies = [ "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2367,7 +2367,7 @@ dependencies = [ [[package]] name = "cuprate-epee-encoding" version = "0.5.0" -source = "git+https://github.com/Cuprate/cuprate.git#fb0ffbe331036fa436f8d21ad89fc8eb7c06629f" +source = "git+https://github.com/Cuprate/cuprate.git#023700ae2ae18d9feac9e1fe123344ab48447cd1" dependencies = [ "bytes", "cuprate-fixed-bytes", @@ -2380,7 +2380,7 @@ dependencies = [ [[package]] name = "cuprate-fixed-bytes" version = "0.1.0" -source = "git+https://github.com/Cuprate/cuprate.git#fb0ffbe331036fa436f8d21ad89fc8eb7c06629f" +source = "git+https://github.com/Cuprate/cuprate.git#023700ae2ae18d9feac9e1fe123344ab48447cd1" dependencies = [ "bytes", "thiserror 2.0.17", @@ -2389,7 +2389,7 @@ dependencies = [ [[package]] name = "cuprate-hex" version = "0.0.0" -source = "git+https://github.com/Cuprate/cuprate.git#fb0ffbe331036fa436f8d21ad89fc8eb7c06629f" +source = "git+https://github.com/Cuprate/cuprate.git#023700ae2ae18d9feac9e1fe123344ab48447cd1" dependencies = [ "hex", "serde", @@ -2435,7 +2435,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2479,7 +2479,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2488,12 +2488,12 @@ version = "1.0.187" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94ca2ad69673c4b35585edfa379617ac364bccd0ba0adf319811ba3a74ffa48a" dependencies = [ - "clap 4.5.50", + "clap 4.5.51", "codespan-reporting", "indexmap 2.12.0", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2511,7 +2511,7 @@ dependencies = [ "indexmap 2.12.0", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2630,7 +2630,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2644,7 +2644,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2677,7 +2677,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2688,7 +2688,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2714,7 +2714,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d162beedaa69905488a8da94f5ac3edb4dd4788b732fadb7bd120b2625c1976" dependencies = [ "data-encoding", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2778,52 +2778,24 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", "serde_core", ] -[[package]] -name = "derive-deftly" -version = "0.14.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8ea84d0109517cc2253d4a679bdda1e8989e9bd86987e9e4f75ffdda0095fd1" -dependencies = [ - "derive-deftly-macros 0.14.6", - "heck 0.5.0", -] - [[package]] name = "derive-deftly" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d308ebe4b10924331bd079044b418da7b227d724d3e2408567a47ad7c3da2a0" dependencies = [ - "derive-deftly-macros 1.3.0", + "derive-deftly-macros", "heck 0.5.0", ] -[[package]] -name = "derive-deftly-macros" -version = "0.14.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357422a457ccb850dc8f1c1680e0670079560feaad6c2e247e3f345c4fab8a3f" -dependencies = [ - "heck 0.5.0", - "indexmap 2.12.0", - "itertools 0.14.0", - "proc-macro-crate 3.4.0", - "proc-macro2", - "quote", - "sha3", - "strum 0.27.2", - "syn 2.0.108", - "void", -] - [[package]] name = "derive-deftly-macros" version = "1.3.0" @@ -2838,7 +2810,7 @@ dependencies = [ "quote", "sha3", "strum 0.27.2", - "syn 2.0.108", + "syn 2.0.109", "void", ] @@ -2850,7 +2822,7 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2871,7 +2843,7 @@ dependencies = [ "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2902,7 +2874,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2925,7 +2897,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -2946,7 +2918,7 @@ dependencies = [ "convert_case 0.7.1", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", "unicode-xid", ] @@ -3069,7 +3041,7 @@ dependencies = [ "libc", "option-ext", "redox_users 0.5.2", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -3109,7 +3081,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -3141,7 +3113,7 @@ checksum = "788160fb30de9cdd857af31c6a2675904b16ece8fc2737b2c7127ba368c9d0f4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -3323,15 +3295,15 @@ dependencies = [ [[package]] name = "electrum-client" -version = "0.24.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7b07e2578a6df0093b101915c79dca0119d7f7810099ad9eef11341d2ae57" +checksum = "a5059f13888a90486e7268bbce59b175f5f76b1c55e5b9c568ceaa42d2b8507c" dependencies = [ "bitcoin 0.32.7", "byteorder", "libc", "log", - "rustls 0.23.34", + "rustls 0.23.35", "serde", "serde_json", "webpki-roots 0.25.4", @@ -3428,7 +3400,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -3441,7 +3413,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -3453,7 +3425,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -3474,7 +3446,7 @@ checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -3511,7 +3483,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -3587,7 +3559,7 @@ checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -3773,7 +3745,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -3964,7 +3936,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -3984,7 +3956,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f2f12607f92c69b12ed746fabf9ca4f5c482cba46679c1a75b874ed7c26adb" dependencies = [ "futures-io", - "rustls 0.23.34", + "rustls 0.23.35", "rustls-pki-types", ] @@ -4228,7 +4200,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -4320,7 +4292,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -4428,7 +4400,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -4613,9 +4585,9 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "hex-literal" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcaaec4551594c969335c98c903c1397853d4198408ea609190f420500f6be71" +checksum = "e712f64ec3850b98572bffac52e2c6f282b29fe6c5fa6d42334b30be438d95c1" [[package]] name = "hex_fmt" @@ -4695,11 +4667,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -4867,13 +4839,13 @@ dependencies = [ "hyper 1.7.0", "hyper-util", "log", - "rustls 0.23.34", + "rustls 0.23.35", "rustls-native-certs 0.8.2", "rustls-pki-types", "tokio", "tokio-rustls 0.26.4", "tower-service", - "webpki-roots 1.0.3", + "webpki-roots 1.0.4", ] [[package]] @@ -4951,9 +4923,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -4964,9 +4936,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -4977,11 +4949,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -4992,42 +4963,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -5239,9 +5206,9 @@ dependencies = [ [[package]] name = "iri-string" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" dependencies = [ "memchr", "serde", @@ -5353,9 +5320,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" dependencies = [ "once_cell", "wasm-bindgen", @@ -5469,7 +5436,7 @@ dependencies = [ "hyper-util", "jsonrpsee-core", "jsonrpsee-types", - "rustls 0.23.34", + "rustls 0.23.35", "rustls-platform-verifier", "serde", "serde_json", @@ -5489,7 +5456,7 @@ dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -6031,7 +5998,7 @@ dependencies = [ "quinn", "rand 0.8.5", "ring 0.17.14", - "rustls 0.23.34", + "rustls 0.23.35", "socket2 0.5.10", "thiserror 1.0.69", "tokio", @@ -6118,7 +6085,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -6169,7 +6136,7 @@ dependencies = [ "libp2p-identity", "rcgen", "ring 0.17.14", - "rustls 0.23.34", + "rustls 0.23.35", "rustls-webpki 0.101.7", "thiserror 1.0.69", "x509-parser 0.16.0", @@ -6321,9 +6288,9 @@ checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "litrs" @@ -6409,7 +6376,7 @@ checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -6767,7 +6734,7 @@ version = "0.1.4-alpha" source = "git+https://github.com/monero-oxide/monero-oxide.git#7c288b058ae7f1e3d36600a2af11b3176102bcfc" dependencies = [ "curve25519-dalek 4.1.3", - "hex-literal 1.0.0", + "hex-literal 1.1.0", "monero-borromean", "monero-bulletproofs", "monero-clsag", @@ -6836,7 +6803,7 @@ dependencies = [ "arti-client", "axum", "chrono", - "clap 4.5.50", + "clap 4.5.51", "crossbeam", "cuprate-epee-encoding", "futures", @@ -6864,7 +6831,7 @@ dependencies = [ "typeshare", "url", "uuid", - "webpki-roots 1.0.3", + "webpki-roots 1.0.4", ] [[package]] @@ -6922,11 +6889,23 @@ dependencies = [ "uuid", ] +[[package]] +name = "monero-tests" +version = "0.1.0" +dependencies = [ + "anyhow", + "monero", + "monero-harness", + "tokio", + "tracing", + "tracing-subscriber", +] + [[package]] name = "moxcms" -version = "0.7.7" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c588e11a3082784af229e23e8e4ecf5bcc6fbe4f69101e0421ce8d79da7f0b40" +checksum = "0fbdd3d7436f8b5e892b8b7ea114271ff0fa00bc5acae845d53b07d498616ef6" dependencies = [ "num-traits", "pxfm", @@ -7225,7 +7204,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -7240,11 +7219,10 @@ dependencies = [ [[package]] name = "num-bigint-dig" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +checksum = "82c79c15c05d4bf82b6f5ef163104cc81a760d8e874d38ac50ab67c8877b647b" dependencies = [ - "byteorder", "lazy_static", "libm", "num-integer", @@ -7320,7 +7298,7 @@ dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -7703,7 +7681,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -7756,7 +7734,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967" dependencies = [ "libc", - "windows-sys 0.45.0", + "windows-sys 0.61.2", ] [[package]] @@ -7976,7 +7954,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -8124,7 +8102,7 @@ dependencies = [ "phf_shared 0.11.3", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -8137,7 +8115,7 @@ dependencies = [ "phf_shared 0.13.1", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -8193,7 +8171,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -8373,9 +8351,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -8388,9 +8366,9 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppmd-rust" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c834641d8ad1b348c9ee86dec3b9840d805acd5f24daa5f90c788951a52ff59b" +checksum = "d558c559f0450f16f2a27a1f017ef38468c1090c9ce63c8e51366232d53717b4" [[package]] name = "ppv-lite86" @@ -8414,7 +8392,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -8519,7 +8497,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -8557,19 +8535,18 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] name = "proptest" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb0be07becd10686a0bb407298fb425360a5c44a663774406340c59a22de4ce" +checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40" dependencies = [ "bit-set", "bit-vec", "bitflags 2.10.0", - "lazy_static", "num-traits", "rand 0.9.2", "rand_chacha 0.9.0", @@ -8602,14 +8579,14 @@ dependencies = [ [[package]] name = "pwd-grp" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94fdf3867b7f2889a736f0022ea9386766280d2cca4bdbe41629ada9e4f3b8f" +checksum = "0e2023f41b5fcb7c30eb5300a5733edfaa9e0e0d502d51b586f65633fd39e40c" dependencies = [ - "derive-deftly 0.14.6", + "derive-deftly", "libc", "paste", - "thiserror 1.0.69", + "thiserror 2.0.17", ] [[package]] @@ -8705,7 +8682,7 @@ checksum = "f71ee38b42f8459a88d3362be6f9b841ad2d5421844f61eb1c59c11bff3ac14a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -8721,7 +8698,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.34", + "rustls 0.23.35", "socket2 0.6.1", "thiserror 2.0.17", "tokio", @@ -8741,7 +8718,7 @@ dependencies = [ "rand 0.9.2", "ring 0.17.14", "rustc-hash", - "rustls 0.23.34", + "rustls 0.23.35", "rustls-pki-types", "slab", "thiserror 2.0.17", @@ -9038,7 +9015,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -9163,7 +9140,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.34", + "rustls 0.23.35", "rustls-native-certs 0.8.2", "rustls-pki-types", "serde", @@ -9181,7 +9158,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots 1.0.3", + "webpki-roots 1.0.4", ] [[package]] @@ -9371,7 +9348,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae8c0cb48f413ebe24dc2d148788e0efbe09ba3e011d9277162f2eaf8e1069a3" dependencies = [ "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -9427,7 +9404,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.11.0", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -9469,16 +9446,16 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.34" +version = "0.23.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9586e9ee2b4f8fab52a0048ca7334d7024eef48e2cb9407e3497bb7cab7fa7" +checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" dependencies = [ "aws-lc-rs", "log", "once_cell", "ring 0.17.14", "rustls-pki-types", - "rustls-webpki 0.103.7", + "rustls-webpki 0.103.8", "subtle", "zeroize", ] @@ -9518,9 +9495,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" dependencies = [ "web-time", "zeroize", @@ -9537,10 +9514,10 @@ dependencies = [ "jni", "log", "once_cell", - "rustls 0.23.34", + "rustls 0.23.35", "rustls-native-certs 0.8.2", "rustls-platform-verifier-android", - "rustls-webpki 0.103.7", + "rustls-webpki 0.103.8", "security-framework 3.5.1", "security-framework-sys", "webpki-root-certs 0.26.11", @@ -9565,9 +9542,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.7" +version = "0.103.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" dependencies = [ "aws-lc-rs", "ring 0.17.14", @@ -9709,9 +9686,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" +checksum = "9558e172d4e8533736ba97870c4b2cd63f84b382a3d6eb063da41b91cce17289" dependencies = [ "dyn-clone", "ref-cast", @@ -9728,7 +9705,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -10043,7 +10020,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -10054,7 +10031,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -10099,7 +10076,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -10154,7 +10131,7 @@ dependencies = [ "indexmap 1.9.3", "indexmap 2.12.0", "schemars 0.9.0", - "schemars 1.0.4", + "schemars 1.1.0", "serde_core", "serde_json", "serde_with_macros 3.15.1", @@ -10182,7 +10159,7 @@ dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -10230,7 +10207,7 @@ checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -10252,7 +10229,7 @@ checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -10732,7 +10709,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -10755,7 +10732,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.108", + "syn 2.0.109", "tempfile", "tokio", "url", @@ -11038,7 +11015,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -11050,7 +11027,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -11122,7 +11099,7 @@ dependencies = [ "reqwest 0.12.24", "rust_decimal", "rust_decimal_macros", - "rustls 0.23.34", + "rustls 0.23.35", "semver", "serde", "serde_cbor", @@ -11179,7 +11156,7 @@ dependencies = [ "monero-rpc-pool", "monero-sys", "rust_decimal", - "rustls 0.23.34", + "rustls 0.23.35", "serde", "serde_json", "structopt", @@ -11202,7 +11179,7 @@ name = "swap-controller" version = "3.2.11" dependencies = [ "anyhow", - "clap 4.5.50", + "clap 4.5.51", "jsonrpsee", "monero", "rustyline", @@ -11426,9 +11403,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.108" +version = "2.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" +checksum = "2f17c7e013e88258aa9543dcbe81aca68a667a9ac37cd69c9fbc07858bfe0e2f" dependencies = [ "proc-macro2", "quote", @@ -11470,7 +11447,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -11596,7 +11573,7 @@ checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -11624,9 +11601,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "2.9.1" +version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9871670c6711f50fddd4e20350be6b9dd6e6c2b5d77d8ee8900eb0d58cd837a" +checksum = "8bceb52453e507c505b330afe3398510e87f428ea42b6e76ecb6bd63b15965b5" dependencies = [ "anyhow", "bytes", @@ -11713,7 +11690,7 @@ dependencies = [ "serde", "serde_json", "sha2 0.10.9", - "syn 2.0.108", + "syn 2.0.109", "tauri-utils", "thiserror 2.0.17", "time 0.3.44", @@ -11731,7 +11708,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", "tauri-codegen", "tauri-utils", ] @@ -11755,11 +11732,11 @@ dependencies = [ [[package]] name = "tauri-plugin-cli" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e76101cc9848adfb6a04aae48a389062be457a785bb4349ae1423ddab5a82d" +checksum = "28e78fb2c09a81546bcd376d34db4bda5769270d00990daa9f0d6e7ac1107e25" dependencies = [ - "clap 4.5.50", + "clap 4.5.51", "log", "serde", "serde_json", @@ -11770,9 +11747,9 @@ dependencies = [ [[package]] name = "tauri-plugin-clipboard-manager" -version = "2.3.0" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adddd9e9275b20e77af3061d100a25a884cced3c4c9ef680bd94dd0f7e26c1ca" +checksum = "206dc20af4ed210748ba945c2774e60fd0acd52b9a73a028402caf809e9b6ecf" dependencies = [ "arboard", "log", @@ -11785,9 +11762,9 @@ dependencies = [ [[package]] name = "tauri-plugin-dialog" -version = "2.4.0" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0beee42a4002bc695550599b011728d9dfabf82f767f134754ed6655e434824e" +checksum = "313f8138692ddc4a2127c4c9607d616a46f5c042e77b3722450866da0aad2f19" dependencies = [ "log", "raw-window-handle", @@ -11803,9 +11780,9 @@ dependencies = [ [[package]] name = "tauri-plugin-fs" -version = "2.4.2" +version = "2.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "315784ec4be45e90a987687bae7235e6be3d6e9e350d2b75c16b8a4bf22c1db7" +checksum = "47df422695255ecbe7bac7012440eddaeefd026656171eac9559f5243d3230d9" dependencies = [ "anyhow", "dunce", @@ -11825,9 +11802,9 @@ dependencies = [ [[package]] name = "tauri-plugin-opener" -version = "2.5.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786156aa8e89e03d271fbd3fe642207da8e65f3c961baa9e2930f332bf80a1f5" +checksum = "c26b72571d25dee25667940027114e60f569fc3974f8cefbe50c2cbc5fd65e3b" dependencies = [ "dunce", "glob", @@ -11847,9 +11824,9 @@ dependencies = [ [[package]] name = "tauri-plugin-process" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7461c622a5ea00eb9cd9f7a08dbd3bf79484499fd5c21aa2964677f64ca651ab" +checksum = "d55511a7bf6cd70c8767b02c97bf8134fa434daf3926cfc1be0a0f94132d165a" dependencies = [ "tauri", "tauri-plugin", @@ -11857,9 +11834,9 @@ dependencies = [ [[package]] name = "tauri-plugin-shell" -version = "2.3.1" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54777d0c0d8add34eea3ced84378619ef5b97996bd967d3038c668feefd21071" +checksum = "c374b6db45f2a8a304f0273a15080d98c70cde86178855fc24653ba657a1144c" dependencies = [ "encoding_rs", "log", @@ -11878,9 +11855,9 @@ dependencies = [ [[package]] name = "tauri-plugin-single-instance" -version = "2.3.4" +version = "2.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb9cac815bf11c4a80fb498666bcdad66d65b89e3ae24669e47806febb76389c" +checksum = "dd707f8c86b4e3004e2c141fa24351f1909ba40ce1b8437e30d5ed5277dd3710" dependencies = [ "serde", "serde_json", @@ -11893,9 +11870,9 @@ dependencies = [ [[package]] name = "tauri-plugin-store" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d85dd80d60a76ee2c2fdce09e9ef30877b239c2a6bb76e6d7d03708aa5f13a19" +checksum = "59a77036340a97eb5bbe1b3209c31e5f27f75e6f92a52fd9dd4b211ef08bf310" dependencies = [ "dunce", "serde", @@ -12050,7 +12027,7 @@ dependencies = [ "getrandom 0.3.4", "once_cell", "rustix 1.1.2", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -12135,7 +12112,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -12146,7 +12123,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -12234,11 +12211,12 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", + "serde_core", "zerovec", ] @@ -12293,7 +12271,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -12323,7 +12301,7 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.23.34", + "rustls 0.23.35", "tokio", ] @@ -12386,9 +12364,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.16" +version = "0.7.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" dependencies = [ "bytes", "futures-core", @@ -12500,7 +12478,7 @@ name = "tor-async-utils" version = "0.35.0" source = "git+https://github.com/eigenwallet/arti?rev=537dd8755817aa2b21c41e66edbd5f05f3c04373#537dd8755817aa2b21c41e66edbd5f05f3c04373" dependencies = [ - "derive-deftly 1.3.0", + "derive-deftly", "educe", "futures", "oneshot-fused-workaround", @@ -12534,7 +12512,7 @@ version = "0.35.0" source = "git+https://github.com/eigenwallet/arti?rev=537dd8755817aa2b21c41e66edbd5f05f3c04373#537dd8755817aa2b21c41e66edbd5f05f3c04373" dependencies = [ "bytes", - "derive-deftly 1.3.0", + "derive-deftly", "digest 0.10.7", "educe", "getrandom 0.3.4", @@ -12554,7 +12532,7 @@ dependencies = [ "bitflags 2.10.0", "bytes", "caret", - "derive-deftly 1.3.0", + "derive-deftly", "derive_more 2.0.1", "educe", "itertools 0.14.0", @@ -12644,7 +12622,7 @@ dependencies = [ "amplify", "async-trait", "cfg-if", - "derive-deftly 1.3.0", + "derive-deftly", "derive_builder_fork_arti", "derive_more 2.0.1", "downcast-rs 2.0.2", @@ -12691,7 +12669,7 @@ source = "git+https://github.com/eigenwallet/arti?rev=537dd8755817aa2b21c41e66ed dependencies = [ "amplify", "cfg-if", - "derive-deftly 1.3.0", + "derive-deftly", "derive_builder_fork_arti", "educe", "either", @@ -12874,7 +12852,7 @@ source = "git+https://github.com/eigenwallet/arti?rev=537dd8755817aa2b21c41e66ed dependencies = [ "amplify", "base64ct", - "derive-deftly 1.3.0", + "derive-deftly", "derive_builder_fork_arti", "derive_more 2.0.1", "dyn-clone", @@ -12915,7 +12893,7 @@ version = "0.35.0" source = "git+https://github.com/eigenwallet/arti?rev=537dd8755817aa2b21c41e66edbd5f05f3c04373#537dd8755817aa2b21c41e66edbd5f05f3c04373" dependencies = [ "async-trait", - "derive-deftly 1.3.0", + "derive-deftly", "derive_more 2.0.1", "educe", "either", @@ -12959,7 +12937,7 @@ source = "git+https://github.com/eigenwallet/arti?rev=537dd8755817aa2b21c41e66ed dependencies = [ "cipher", "data-encoding", - "derive-deftly 1.3.0", + "derive-deftly", "derive_more 2.0.1", "digest 0.10.7", "hex", @@ -12992,7 +12970,7 @@ dependencies = [ "async-trait", "base64ct", "cfg-if", - "derive-deftly 1.3.0", + "derive-deftly", "derive_builder_fork_arti", "derive_more 2.0.1", "digest 0.10.7", @@ -13045,7 +13023,7 @@ name = "tor-key-forge" version = "0.35.0" source = "git+https://github.com/eigenwallet/arti?rev=537dd8755817aa2b21c41e66edbd5f05f3c04373#537dd8755817aa2b21c41e66edbd5f05f3c04373" dependencies = [ - "derive-deftly 1.3.0", + "derive-deftly", "derive_more 2.0.1", "downcast-rs 2.0.2", "paste", @@ -13069,7 +13047,7 @@ dependencies = [ "amplify", "arrayvec", "cfg-if", - "derive-deftly 1.3.0", + "derive-deftly", "derive_builder_fork_arti", "derive_more 2.0.1", "downcast-rs 2.0.2", @@ -13108,7 +13086,7 @@ dependencies = [ "base64ct", "by_address", "caret", - "derive-deftly 1.3.0", + "derive-deftly", "derive_builder_fork_arti", "derive_more 2.0.1", "hex", @@ -13136,7 +13114,7 @@ dependencies = [ "ctr", "curve25519-dalek 4.1.3", "der-parser 10.0.0", - "derive-deftly 1.3.0", + "derive-deftly", "derive_more 2.0.1", "digest 0.10.7", "ed25519-dalek 2.2.0", @@ -13185,7 +13163,7 @@ version = "0.35.0" source = "git+https://github.com/eigenwallet/arti?rev=537dd8755817aa2b21c41e66edbd5f05f3c04373#537dd8755817aa2b21c41e66edbd5f05f3c04373" dependencies = [ "cfg-if", - "derive-deftly 1.3.0", + "derive-deftly", "derive_more 2.0.1", "dyn-clone", "educe", @@ -13248,7 +13226,7 @@ dependencies = [ "base64ct", "bitflags 2.10.0", "cipher", - "derive-deftly 1.3.0", + "derive-deftly", "derive_builder_fork_arti", "derive_more 2.0.1", "digest 0.10.7", @@ -13291,7 +13269,7 @@ version = "0.35.0" source = "git+https://github.com/eigenwallet/arti?rev=537dd8755817aa2b21c41e66edbd5f05f3c04373#537dd8755817aa2b21c41e66edbd5f05f3c04373" dependencies = [ "amplify", - "derive-deftly 1.3.0", + "derive-deftly", "derive_more 2.0.1", "filetime", "fs-mistrust", @@ -13327,7 +13305,7 @@ dependencies = [ "cipher", "coarsetime", "criterion-cycles-per-byte", - "derive-deftly 1.3.0", + "derive-deftly", "derive_builder_fork_arti", "derive_more 2.0.1", "digest 0.10.7", @@ -13421,7 +13399,7 @@ dependencies = [ "paste", "pin-project", "rustls-pki-types", - "rustls-webpki 0.103.7", + "rustls-webpki 0.103.8", "thiserror 2.0.17", "tokio", "tokio-util", @@ -13439,7 +13417,7 @@ dependencies = [ "amplify", "assert_matches", "async-trait", - "derive-deftly 1.3.0", + "derive-deftly", "derive_more 2.0.1", "educe", "futures", @@ -13466,7 +13444,7 @@ source = "git+https://github.com/eigenwallet/arti?rev=537dd8755817aa2b21c41e66ed dependencies = [ "amplify", "caret", - "derive-deftly 1.3.0", + "derive-deftly", "educe", "safelog", "subtle", @@ -13480,7 +13458,7 @@ name = "tor-units" version = "0.35.0" source = "git+https://github.com/eigenwallet/arti?rev=537dd8755817aa2b21c41e66edbd5f05f3c04373#537dd8755817aa2b21c41e66edbd5f05f3c04373" dependencies = [ - "derive-deftly 1.3.0", + "derive-deftly", "derive_more 2.0.1", "serde", "thiserror 2.0.17", @@ -13565,7 +13543,7 @@ dependencies = [ "futures-util", "http 1.3.1", "http-body 1.0.1", - "iri-string 0.7.8", + "iri-string 0.7.9", "pin-project-lite", "tower 0.5.2", "tower-layer", @@ -13616,7 +13594,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -13691,7 +13669,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568" dependencies = [ "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -13797,7 +13775,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a615d6c2764852a2e88a4f16e9ce1ea49bb776b5872956309e170d63a042a34f" dependencies = [ "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -13899,24 +13877,24 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-normalization" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" dependencies = [ "tinyvec", ] [[package]] name = "unicode-properties" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" [[package]] name = "unicode-segmentation" @@ -13992,7 +13970,7 @@ dependencies = [ "anyhow", "dfx-swiss-sdk", "monero-rpc-pool", - "rustls 0.23.34", + "rustls 0.23.35", "serde", "serde_json", "swap", @@ -14158,9 +14136,9 @@ dependencies = [ [[package]] name = "version-compare" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" +checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" [[package]] name = "version_check" @@ -14182,7 +14160,7 @@ checksum = "d674d135b4a8c1d7e813e2f8d1c9a58308aee4a680323066025e53132218bd91" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -14283,9 +14261,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ "cfg-if", "once_cell", @@ -14294,25 +14272,11 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.108", - "wasm-bindgen-shared", -] - [[package]] name = "wasm-bindgen-futures" -version = "0.4.54" +version = "0.4.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c" +checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" dependencies = [ "cfg-if", "js-sys", @@ -14323,9 +14287,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -14333,22 +14297,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.108", - "wasm-bindgen-backend", + "syn 2.0.109", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" dependencies = [ "unicode-ident", ] @@ -14447,9 +14411,9 @@ checksum = "323f4da9523e9a669e1eaf9c6e763892769b1d38c623913647bfdc1532fe4549" [[package]] name = "web-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" dependencies = [ "js-sys", "wasm-bindgen", @@ -14535,14 +14499,14 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e" dependencies = [ - "webpki-root-certs 1.0.3", + "webpki-root-certs 1.0.4", ] [[package]] name = "webpki-root-certs" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d651ec480de84b762e7be71e6efa7461699c19d9e2c272c8d93455f567786e" +checksum = "ee3e3b5f5e80bc89f30ce8d0343bf4e5f12341c51f3e26cbeecbc7c85443e85b" dependencies = [ "rustls-pki-types", ] @@ -14573,9 +14537,9 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b130c0d2d49f8b6889abc456e795e82525204f27c42cf767cf0d7734e089b8" +checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" dependencies = [ "rustls-pki-types", ] @@ -14602,7 +14566,7 @@ checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -14660,7 +14624,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] @@ -14771,7 +14735,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -14782,7 +14746,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -15243,9 +15207,9 @@ dependencies = [ [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "wry" @@ -15397,9 +15361,9 @@ dependencies = [ [[package]] name = "xml-rs" -version = "0.8.27" +version = "0.8.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fd8403733700263c6eb89f192880191f1b83e332f7a20371ddcf421c4a337c7" +checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" [[package]] name = "xmltree" @@ -15458,11 +15422,10 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -15470,13 +15433,13 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", "synstructure 0.13.2", ] @@ -15524,7 +15487,7 @@ dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", "zbus_names", "zvariant", "zvariant_utils", @@ -15559,7 +15522,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -15579,7 +15542,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", "synstructure 0.13.2", ] @@ -15600,14 +15563,14 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -15616,10 +15579,11 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ + "serde", "yoke", "zerofrom", "zerovec-derive", @@ -15627,13 +15591,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", ] [[package]] @@ -15685,9 +15649,9 @@ checksum = "2f06ae92f42f5e5c42443fd094f245eb656abf56dd7cce9b8b263236565e00f2" [[package]] name = "zopfli" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7" +checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" dependencies = [ "bumpalo", "crc32fast", @@ -15762,7 +15726,7 @@ dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.108", + "syn 2.0.109", "zvariant_utils", ] @@ -15775,6 +15739,6 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.108", + "syn 2.0.109", "winnow 0.7.13", ] diff --git a/Cargo.toml b/Cargo.toml index ceb4305ca..486f46300 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ members = [ "monero-rpc", "monero-rpc-pool", "monero-sys", + "monero-tests", "src-tauri", "swap", "swap-asb", diff --git a/justfile b/justfile index 8c5dc41ef..addd94ef1 100644 --- a/justfile +++ b/justfile @@ -18,6 +18,9 @@ monero_sys: just update_submodules cd monero-sys && cargo build +undo-monero-changes: + cd monero-sys/monero && git restore . + # Test the FFI bindings using various sanitizers, that can detect memory safety issues. test-ffi: test-ffi-address diff --git a/monero-harness/src/lib.rs b/monero-harness/src/lib.rs index 889f549d1..5160232aa 100644 --- a/monero-harness/src/lib.rs +++ b/monero-harness/src/lib.rs @@ -23,14 +23,14 @@ use std::time::Duration; use anyhow::{anyhow, bail, Context, Result}; -use testcontainers::clients::Cli; +pub use testcontainers::clients::Cli; use testcontainers::{Container, RunnableImage}; use tokio::time; use monero::{Address, Amount}; use monero_rpc::monerod::MonerodRpc as _; use monero_rpc::monerod::{self, GenerateBlocks}; -use monero_sys::{no_listener, Daemon, SyncProgress, TxReceipt, WalletHandle}; +use monero_sys::{no_listener, Daemon, SyncProgress, TxReceipt, TxStatus, WalletHandle}; use crate::image::{MONEROD_DAEMON_CONTAINER_NAME, MONEROD_DEFAULT_NETWORK, RPC_PORT}; @@ -47,6 +47,18 @@ pub struct Monero { } impl<'c> Monero { + /// Same as `new_with_sync_specified` but with sync specified as true. + pub async fn new( + cli: &'c Cli, + additional_wallets: Vec<&'static str>, + ) -> Result<( + Self, + Container<'c, image::Monerod>, + Vec>, + )> { + Self::new_with_sync_specified(cli, additional_wallets, true).await + } + /// Starts a new regtest monero container setup consisting out of 1 monerod /// node and n wallets. The docker container and network will be prefixed /// with a randomly generated `prefix`. One miner wallet is started @@ -54,9 +66,10 @@ impl<'c> Monero { /// monerod container name is: `prefix`_`monerod` /// network is: `prefix`_`monero` /// miner wallet container name is: `miner` - pub async fn new( + pub async fn new_with_sync_specified( cli: &'c Cli, additional_wallets: Vec<&'static str>, + background_synced: bool, ) -> Result<( Self, Container<'c, image::Monerod>, @@ -118,7 +131,14 @@ impl<'c> Monero { let wallet_instance = tokio::time::timeout(Duration::from_secs(300), async { loop { - match MoneroWallet::new(wallet, daemon.clone(), prefix.clone()).await { + match MoneroWallet::new_with_sync_specified( + wallet, + daemon.clone(), + prefix.clone(), + background_synced, + ) + .await + { Ok(w) => break w, Err(e) => { tracing::warn!( @@ -411,6 +431,16 @@ impl<'c> Monerod { impl MoneroWallet { /// Create a new wallet using monero-sys bindings connected to the provided monerod instance. async fn new(name: &str, daemon: Daemon, prefix: String) -> Result { + Self::new_with_sync_specified(name, daemon, prefix, true).await + } + + /// Create a new wallet using monero-sys bindings connected to the provided monerod instance. + async fn new_with_sync_specified( + name: &str, + daemon: Daemon, + prefix: String, + background_sync: bool, + ) -> Result { // Wallet files will be stored in the system temporary directory with the prefix to avoid clashes let mut wallet_path = std::env::temp_dir(); wallet_path.push(format!("{}{}", prefix, name)); @@ -421,7 +451,7 @@ impl MoneroWallet { wallet_path.display().to_string(), daemon, monero::Network::Mainnet, - true, + background_sync, ) .await .context("Failed to create or open wallet")?; @@ -451,7 +481,7 @@ impl MoneroWallet { tracing::debug!("Wallet connected to daemon: {}", connected); // Force a refresh first - self.refresh().await?; + // self.refresh().await?; let total = self.wallet.total_balance().await.as_pico(); tracing::debug!( @@ -462,6 +492,17 @@ impl MoneroWallet { Ok(total) } + pub async fn check_tx_key(&self, txid: String, txkey: monero::PrivateKey) -> Result { + let status = self + .wallet + .check_tx_status(txid.clone(), txkey, &self.address().await?) + .await?; + + self.wallet.scan_transaction(txid).await?; + + Ok(status) + } + pub async fn unlocked_balance(&self) -> Result { Ok(self.wallet.unlocked_balance().await.as_pico()) } @@ -516,10 +557,6 @@ impl MoneroWallet { .await .context("Failed to perform sweep") } - - pub async fn blockchain_height(&self) -> Result { - self.wallet.blockchain_height().await - } } /// Mine a block ever BLOCK_TIME_SECS seconds. diff --git a/monero-sys/build.rs b/monero-sys/build.rs index 7fdf8379d..7b6a30c8e 100644 --- a/monero-sys/build.rs +++ b/monero-sys/build.rs @@ -71,9 +71,9 @@ const EMBEDDED_PATCHES: &[EmbeddedPatch] = &[ "patches/eigenwallet_0002_wallet2_increase_rpc_retries.patch" ), embedded_patch!( - "eigenwallet_0003_pendingTransaction_getTxKey", + "eigenwallet_0003_pending_transaction_tx_keys", "Adds txKeys() to PendingTransaction in wallet2_api.h", - "patches/eigenwallet_0003_pendingTransaction_getTxKey.patch" + "patches/eigenwallet_0003_pending_transaction_tx_keys.patch" ), ]; diff --git a/monero-sys/patches/eigenwallet_0003_pendingTransaction_getTxKey.patch b/monero-sys/patches/eigenwallet_0003_pendingTransaction_getTxKey.patch deleted file mode 100644 index 4cbc2e574..000000000 --- a/monero-sys/patches/eigenwallet_0003_pendingTransaction_getTxKey.patch +++ /dev/null @@ -1,64 +0,0 @@ -diff --git a/src/wallet/api/pending_transaction.cpp b/src/wallet/api/pending_transaction.cpp -index 2dd118ea3..fd7cbca9b 100644 ---- a/src/wallet/api/pending_transaction.cpp -+++ b/src/wallet/api/pending_transaction.cpp -@@ -78,6 +78,35 @@ std::vector PendingTransactionImpl::txid() const - return txid; - } - -+// This function returns **all** tx keys for the transaction with the given tx hash in the [`PendingTransaction`]. -+// A [`PendingTransaction`] can contain multiple transactions. A single transaction can have multiple tx keys. -+std::vector PendingTransactionImpl::txKeys(const std::string &tx_hash) const -+{ -+ std::vector keys; -+ -+ for (const auto &ptx : m_pending_tx) -+ { -+ std::string current_tx_hash = epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx)); -+ -+ if (current_tx_hash == tx_hash) -+ { -+ std::string key = epee::string_tools::pod_to_hex(unwrap(unwrap(ptx.tx_key))); -+ keys.emplace_back(std::move(key)); -+ -+ // TODO: According to moneromoo, its non standard behavior to have multiple tx keys -+ // We still provide return them here for the sake of correctness. -+ // Our Rust wrapper will then fail if it detects multiple tx keys. -+ for (const auto &additional_key : ptx.additional_tx_keys) { -+ keys.emplace_back(epee::string_tools::pod_to_hex(unwrap(unwrap(additional_key)))); -+ } -+ -+ break; -+ } -+ } -+ -+ return keys; -+} -+ - bool PendingTransactionImpl::commit(const std::string &filename, bool overwrite) - { - -diff --git a/src/wallet/api/pending_transaction.h b/src/wallet/api/pending_transaction.h -index c5f4328a8..f2ee483c9 100644 ---- a/src/wallet/api/pending_transaction.h -+++ b/src/wallet/api/pending_transaction.h -@@ -50,6 +50,7 @@ public: - uint64_t dust() const override; - uint64_t fee() const override; - std::vector txid() const override; -+ std::vector txKeys(const std::string &tx_hash) const override; - uint64_t txCount() const override; - std::vector subaddrAccount() const override; - std::vector> subaddrIndices() const override; -diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h -index ca807ac87..53df045c9 100644 ---- a/src/wallet/api/wallet2_api.h -+++ b/src/wallet/api/wallet2_api.h -@@ -131,6 +131,7 @@ struct PendingTransaction - virtual uint64_t dust() const = 0; - virtual uint64_t fee() const = 0; - virtual std::vector txid() const = 0; -+ virtual std::vector txKeys(const std::string &tx_hash) const = 0; - /*! - * \brief txCount - number of transactions current transaction will be splitted to - * \return diff --git a/monero-sys/patches/eigenwallet_0003_pending_transaction_tx_keys.patch b/monero-sys/patches/eigenwallet_0003_pending_transaction_tx_keys.patch new file mode 100644 index 000000000..f6c50d91c --- /dev/null +++ b/monero-sys/patches/eigenwallet_0003_pending_transaction_tx_keys.patch @@ -0,0 +1,140 @@ +diff --git a/src/wallet/api/pending_transaction.cpp b/src/wallet/api/pending_transaction.cpp +index 2dd118ea3..0972089d1 100644 +--- a/src/wallet/api/pending_transaction.cpp ++++ b/src/wallet/api/pending_transaction.cpp +@@ -78,6 +78,103 @@ std::vector PendingTransactionImpl::txid() const + return txid; + } + ++// This function returns **all** tx keys for the transaction with the given tx hash in the [`PendingTransaction`]. ++// A [`PendingTransaction`] can contain multiple transactions. A single transaction can have multiple tx keys. ++std::vector> PendingTransactionImpl::txKeys(const std::string &tx_hash) const ++{ ++ std::vector> keys; ++ ++ for (const auto &ptx : m_pending_tx) ++ { ++ const std::string current_tx_hash = epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx)); ++ ++ if (current_tx_hash != tx_hash) ++ { ++ continue; ++ } ++ ++ const std::string main_tx_key = epee::string_tools::pod_to_hex(unwrap(unwrap(ptx.tx_key))); ++ ++ if (ptx.tx.vout.size() != ptx.construction_data.splitted_dsts.size()) { ++ throw std::runtime_error( ++ "Number of outputs in transaction " ++ + current_tx_hash ++ + " (" + std::to_string(ptx.tx.vout.size()) + ")" ++ + " does not match number of destinations (" ++ + std::to_string(ptx.construction_data.splitted_dsts.size()) + ")"); ++ } ++ ++ // Prepare change-derivation data for change detection ++ const crypto::public_key tx_pub_key = cryptonote::get_tx_pub_key_from_extra(ptx.tx); ++ const crypto::secret_key &view_secret_key = m_wallet.m_wallet->get_account().get_keys().m_view_secret_key; ++ crypto::key_derivation change_derivation; ++ if (!crypto::generate_key_derivation(tx_pub_key, view_secret_key, change_derivation)) { ++ throw std::runtime_error("Failed to generate change derivation"); ++ } ++ const crypto::public_key change_spend_pub = ptx.construction_data.change_dts.addr.m_spend_public_key; ++ ++ for (size_t i = 0; i < ptx.tx.vout.size(); i++) { ++ const cryptonote::tx_out tx_output = ptx.tx.vout[i]; ++ const cryptonote::tx_destination_entry dest_entry = ptx.construction_data.splitted_dsts[i]; ++ ++ crypto::public_key out_pk; ++ if (!cryptonote::get_output_public_key(ptx.tx.vout[i], out_pk)) { ++ throw std::runtime_error("Unable to get output public key from transaction out"); ++ } ++ ++ // Detect change outputs by checking if the output public key matches our private view key. ++ crypto::public_key expected_change_pk; ++ if (!crypto::derive_public_key(change_derivation, i, change_spend_pub, expected_change_pk)) { ++ throw std::runtime_error("Failed to derive change public key"); ++ } ++ // If it's a change output, skip it. Otherwise look for the tx key. ++ if (expected_change_pk == out_pk) { ++ continue; ++ } ++ ++ std::vector keys_to_try = ptx.additional_tx_keys; ++ keys_to_try.push_back(ptx.tx_key); ++ ++ bool found_key = false; ++ crypto::secret_key matched_key = crypto::null_skey; ++ ++ for (const auto &candidate_key: keys_to_try) { ++ // compute derivation from recipient view pubkey and our tx secret key ++ crypto::key_derivation derivation; ++ if (!crypto::generate_key_derivation(dest_entry.addr.m_view_public_key, candidate_key, derivation)) { ++ throw std::runtime_error("Failed to generate key derivation for output " + std::to_string(i)); ++ } ++ ++ // derive expected output public key and compare. We check if the K^0 we derive matches the expected one. ++ crypto::public_key expected_out_pk; ++ if (!crypto::derive_public_key(derivation, i, dest_entry.addr.m_spend_public_key, expected_out_pk)) { ++ throw std::runtime_error("Failed to derive public key for output " + std::to_string(i)); ++ } ++ ++ if (expected_out_pk == out_pk) { ++ found_key = true; ++ matched_key = candidate_key; ++ break; ++ } ++ } ++ ++ if (!found_key || matched_key == crypto::null_skey) { ++ throw std::runtime_error("No matching tx key found for output"); ++ } ++ ++ // push (txid, destination address (human-readable), hex(tx_secret_key)) ++ const std::string dest_addr_str = dest_entry.address(m_wallet.m_wallet->nettype(), crypto::null_hash); ++ keys.emplace_back( ++ current_tx_hash, ++ dest_addr_str, ++ epee::string_tools::pod_to_hex(unwrap(unwrap(matched_key))) ++ ); ++ } ++ } ++ ++ return keys; ++} ++ + bool PendingTransactionImpl::commit(const std::string &filename, bool overwrite) + { + +diff --git a/src/wallet/api/pending_transaction.h b/src/wallet/api/pending_transaction.h +index c5f4328a8..0377eb79c 100644 +--- a/src/wallet/api/pending_transaction.h ++++ b/src/wallet/api/pending_transaction.h +@@ -33,6 +33,7 @@ + + #include + #include ++#include + + + namespace Monero { +@@ -50,6 +51,7 @@ public: + uint64_t dust() const override; + uint64_t fee() const override; + std::vector txid() const override; ++ std::vector> txKeys(const std::string &tx_hash) const override; + uint64_t txCount() const override; + std::vector subaddrAccount() const override; + std::vector> subaddrIndices() const override; +diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h +index ca807ac87..29a89f273 100644 +--- a/src/wallet/api/wallet2_api.h ++++ b/src/wallet/api/wallet2_api.h +@@ -131,6 +131,7 @@ struct PendingTransaction + virtual uint64_t dust() const = 0; + virtual uint64_t fee() const = 0; + virtual std::vector txid() const = 0; ++ virtual std::vector> txKeys(const std::string &tx_hash) const = 0; + /*! + * \brief txCount - number of transactions current transaction will be splitted to + * \return diff --git a/monero-sys/src/bridge.h b/monero-sys/src/bridge.h index 5e47a1a4c..3aaf4f473 100644 --- a/monero-sys/src/bridge.h +++ b/monero-sys/src/bridge.h @@ -5,6 +5,7 @@ #include "../monero/src/wallet/api/wallet2_api.h" #include "../monero/src/wallet/api/wallet_manager.h" + /** * This file contains some C++ glue code needed to make the FFI work. * This consists mainly of two use-cases: @@ -60,7 +61,7 @@ namespace Monero auto addr = wallet.address(account_index, address_index); return std::make_unique(addr); } - + inline void rescanBlockchainAsync(Wallet &wallet) { wallet.rescanBlockchainAsync(); @@ -163,8 +164,7 @@ namespace Monero const std::vector &amounts, // If set to true, the fee will be subtracted from output with the highest amount // If set to false, the fee will be paid by the wallet and the exact amounts will be sent to the destinations - bool subtract_fee_from_outputs - ) + bool subtract_fee_from_outputs) { size_t n = dest_addresses.size(); @@ -185,27 +185,28 @@ namespace Monero // Build the actual multi‐dest transaction // No change left -> wallet drops it // N outputs, fee should be the same as the one estimated above - + // Find the highest output and choose it for subtract_fee_indices std::set subtract_fee_indices; // If subtract_fee_from_outputs = false, this will not be executed and // subtract_fee_indices will remain empty which symbolizes that the fee will be paid by the wallet // and the exact amounts will be sent to the destinations - if (subtract_fee_from_outputs) { + if (subtract_fee_from_outputs) + { auto max_it = std::max_element(amounts.begin(), amounts.end()); size_t max_index = std::distance(amounts.begin(), max_it); - subtract_fee_indices.insert(static_cast(max_index)); + subtract_fee_indices.insert(static_cast(max_index)); } - + return wallet.createTransactionMultDest( dest_addresses, "", // No Payment ID Monero::optional>(amounts), 0, // No mixin count PendingTransaction::Priority_Default, - 0, // subaddr_account - {}, // subaddr_indices + 0, // subaddr_account + {}, // subaddr_indices subtract_fee_indices); // Subtract fee from all outputs } @@ -215,15 +216,6 @@ namespace Monero return wallet.setDaemon(daemon_address, ssl); } - /** - * Get the transaction key for a given transaction id - */ - inline std::unique_ptr walletGetTxKey(const Wallet &wallet, const std::string &txid) - { - auto key = wallet.getTxKey(txid); - return std::make_unique(key); - } - /** * Sign a message with the wallet's private key */ @@ -244,7 +236,7 @@ namespace Monero /** * Get the transaction ids of a pending transaction. - * + * * A pending transaction can contain multiple transactions, so we return a vector of txids. */ inline std::unique_ptr> pendingTransactionTxIds(const PendingTransaction &tx) @@ -290,15 +282,9 @@ namespace Monero return static_cast(tx_info.timestamp()); } - inline std::unique_ptr> pendingTransactionTxKeys(const PendingTransaction &tx, const std::string &tx_hash) - { - auto keys = tx.txKeys(tx_hash); - auto vec = std::make_unique>(); - vec->reserve(keys.size()); - for (auto &key : keys) - vec->push_back(std::move(key)); - return vec; - } + + + // bridge.h #pragma once @@ -306,138 +292,156 @@ namespace Monero #include #include "wallet/api/wallet2_api.h" + using CB_StringU64 = uintptr_t; + using CB_U64 = uintptr_t; + using CB_Void = uintptr_t; + using CB_Reorg = uintptr_t; + using CB_String = uintptr_t; + using CB_GetPassword = uintptr_t; -using CB_StringU64 = uintptr_t; -using CB_U64 = uintptr_t; -using CB_Void = uintptr_t; -using CB_Reorg = uintptr_t; -using CB_String = uintptr_t; -using CB_GetPassword = uintptr_t; - -class FunctionBasedListener final : public Monero::WalletListener { -public: - FunctionBasedListener( - CB_StringU64 on_spent, - CB_StringU64 on_received, - CB_StringU64 on_unconfirmed_received, - CB_U64 on_new_block, - CB_Void on_updated, - CB_Void on_refreshed, - CB_Reorg on_reorg, - CB_String on_pool_tx_removed, - CB_GetPassword on_get_password) - : - on_spent_(on_spent), - on_received_(on_received), - on_unconfirmed_received_(on_unconfirmed_received), - on_new_block_(on_new_block), - on_updated_(on_updated), - on_refreshed_(on_refreshed), - on_reorg_(on_reorg), - on_pool_tx_removed_(on_pool_tx_removed), - on_get_password_(on_get_password) {} - - void moneySpent(const std::string& txid, uint64_t amt) override { - if (on_spent_) { - auto* spent = reinterpret_cast(on_spent_); - spent(txid, amt); + class FunctionBasedListener final : public Monero::WalletListener + { + public: + FunctionBasedListener( + CB_StringU64 on_spent, + CB_StringU64 on_received, + CB_StringU64 on_unconfirmed_received, + CB_U64 on_new_block, + CB_Void on_updated, + CB_Void on_refreshed, + CB_Reorg on_reorg, + CB_String on_pool_tx_removed, + CB_GetPassword on_get_password) + : on_spent_(on_spent), + on_received_(on_received), + on_unconfirmed_received_(on_unconfirmed_received), + on_new_block_(on_new_block), + on_updated_(on_updated), + on_refreshed_(on_refreshed), + on_reorg_(on_reorg), + on_pool_tx_removed_(on_pool_tx_removed), + on_get_password_(on_get_password) {} + + void moneySpent(const std::string &txid, uint64_t amt) override + { + if (on_spent_) + { + auto *spent = reinterpret_cast(on_spent_); + spent(txid, amt); + } } - } - void moneyReceived(const std::string& txid, uint64_t amt) override - { if (on_received_) { - auto* received = reinterpret_cast(on_received_); - received(txid, amt); + void moneyReceived(const std::string &txid, uint64_t amt) override + { + if (on_received_) + { + auto *received = reinterpret_cast(on_received_); + received(txid, amt); + } } - } - void unconfirmedMoneyReceived(const std::string& txid, uint64_t amt) override - { if (on_unconfirmed_received_) { - auto* unconfirmed_received = reinterpret_cast(on_unconfirmed_received_); - unconfirmed_received(txid, amt); + void unconfirmedMoneyReceived(const std::string &txid, uint64_t amt) override + { + if (on_unconfirmed_received_) + { + auto *unconfirmed_received = reinterpret_cast(on_unconfirmed_received_); + unconfirmed_received(txid, amt); + } } - } - void newBlock(uint64_t h) override - { if (on_new_block_) { - auto* new_block = reinterpret_cast(on_new_block_); - new_block(h); + void newBlock(uint64_t h) override + { + if (on_new_block_) + { + auto *new_block = reinterpret_cast(on_new_block_); + new_block(h); + } } - } - void updated() override + void updated() override { - if (on_updated_) { - auto* updated = reinterpret_cast(on_updated_); - updated(); + if (on_updated_) + { + auto *updated = reinterpret_cast(on_updated_); + updated(); + } } - } - void refreshed() override - { if (on_refreshed_) { - auto* refreshed = reinterpret_cast(on_refreshed_); - refreshed(); + void refreshed() override + { + if (on_refreshed_) + { + auto *refreshed = reinterpret_cast(on_refreshed_); + refreshed(); + } } - } - void onReorg(uint64_t h, uint64_t d, size_t t) override - { if (on_reorg_) { - auto* reorg = reinterpret_cast(on_reorg_); - reorg(h, d, t); + void onReorg(uint64_t h, uint64_t d, size_t t) override + { + if (on_reorg_) + { + auto *reorg = reinterpret_cast(on_reorg_); + reorg(h, d, t); + } } - } - void onPoolTxRemoved(const std::string& txid) override - { if (on_pool_tx_removed_) { - auto* pool_tx_removed = reinterpret_cast(on_pool_tx_removed_); - pool_tx_removed(txid); + void onPoolTxRemoved(const std::string &txid) override + { + if (on_pool_tx_removed_) + { + auto *pool_tx_removed = reinterpret_cast(on_pool_tx_removed_); + pool_tx_removed(txid); + } } - } - optional onGetPassword(const char* reason) override { - if (on_get_password_) { - auto* get_password = reinterpret_cast(on_get_password_); - return std::string(get_password(reason)); + optional onGetPassword(const char *reason) override + { + if (on_get_password_) + { + auto *get_password = reinterpret_cast(on_get_password_); + return std::string(get_password(reason)); + } + return optional(); } - return optional(); - } -private: - CB_StringU64 on_spent_; - CB_StringU64 on_received_; - CB_StringU64 on_unconfirmed_received_; - CB_U64 on_new_block_; - CB_Void on_updated_; - CB_Void on_refreshed_; - CB_Reorg on_reorg_; - CB_String on_pool_tx_removed_; - CB_GetPassword on_get_password_; -}; - -extern "C" { - WalletListener* create_listener( - CB_StringU64 on_spent, - CB_StringU64 on_received, - CB_StringU64 on_unconfirmed_received, - CB_U64 on_new_block, - CB_Void on_updated, - CB_Void on_refreshed, - CB_Reorg on_reorg, - CB_String on_pool_tx_removed, - CB_GetPassword on_get_password) - { - return new FunctionBasedListener( - on_spent,on_received,on_unconfirmed_received,on_new_block, - on_updated,on_refreshed,on_reorg,on_pool_tx_removed,on_get_password); - } + private: + CB_StringU64 on_spent_; + CB_StringU64 on_received_; + CB_StringU64 on_unconfirmed_received_; + CB_U64 on_new_block_; + CB_Void on_updated_; + CB_Void on_refreshed_; + CB_Reorg on_reorg_; + CB_String on_pool_tx_removed_; + CB_GetPassword on_get_password_; + }; - void destroy_listener(FunctionBasedListener* p) { delete p; } -} + extern "C" + { + WalletListener *create_listener( + CB_StringU64 on_spent, + CB_StringU64 on_received, + CB_StringU64 on_unconfirmed_received, + CB_U64 on_new_block, + CB_Void on_updated, + CB_Void on_refreshed, + CB_Reorg on_reorg, + CB_String on_pool_tx_removed, + CB_GetPassword on_get_password) + { + return new FunctionBasedListener( + on_spent, on_received, on_unconfirmed_received, on_new_block, + on_updated, on_refreshed, on_reorg, on_pool_tx_removed, on_get_password); + } + + void destroy_listener(FunctionBasedListener *p) { delete p; } + } } #include "easylogging++.h" #include "bridge.h" #include "monero-sys/src/bridge.rs.h" + /** * This section is us capturing the log messages from easylogging++ @@ -559,63 +563,94 @@ using StringVec = std::vector; static std::pair _monero_sys_pair_instantiation; -namespace Monero { - -// Adapter class that forwards Monero::WalletListener callbacks to Rust -class RustListenerAdapter final : public Monero::WalletListener { -public: - explicit RustListenerAdapter(rust::Box listener) - : inner_(std::move(listener)) {} +namespace Monero +{ - // --- Required overrides ------------------------------------------------ - void moneySpent(const std::string &txid, uint64_t amount) override { - wallet_listener::money_spent(*inner_, txid, amount); + inline std::unique_ptr> pendingTransactionTxKeys(const PendingTransaction &tx, const std::string &tx_hash) + { + const std::vector> tuple_keys = tx.txKeys(tx_hash); + std::unique_ptr> result = std::make_unique>(); + result->reserve(tuple_keys.size()); + + for (const auto& [tx, addr, key] : tuple_keys) { + result->emplace_back(TxKey{ + std::make_unique(tx), + std::make_unique(addr), + std::make_unique(key) + }); + } + + return result; } - void moneyReceived(const std::string &txid, uint64_t amount) override { - wallet_listener::money_received(*inner_, txid, amount); - } + // Adapter class that forwards Monero::WalletListener callbacks to Rust + class RustListenerAdapter final : public Monero::WalletListener + { + public: + explicit RustListenerAdapter(rust::Box listener) + : inner_(std::move(listener)) {} - void unconfirmedMoneyReceived(const std::string &txid, uint64_t amount) override { - wallet_listener::unconfirmed_money_received(*inner_, txid, amount); - } + // --- Required overrides ------------------------------------------------ + void moneySpent(const std::string &txid, uint64_t amount) override + { + wallet_listener::money_spent(*inner_, txid, amount); + } - void newBlock(uint64_t height) override { - wallet_listener::new_block(*inner_, height); - } + void moneyReceived(const std::string &txid, uint64_t amount) override + { + wallet_listener::money_received(*inner_, txid, amount); + } - void updated() override { - wallet_listener::updated(*inner_); - } + void unconfirmedMoneyReceived(const std::string &txid, uint64_t amount) override + { + wallet_listener::unconfirmed_money_received(*inner_, txid, amount); + } - void refreshed() override { - wallet_listener::refreshed(*inner_); - } + void newBlock(uint64_t height) override + { + wallet_listener::new_block(*inner_, height); + } - void onReorg(std::uint64_t height, std::uint64_t blocks_detached, std::size_t transfers_detached) override { - wallet_listener::on_reorg(*inner_, height, blocks_detached, transfers_detached); - } + void updated() override + { + wallet_listener::updated(*inner_); + } - optional onGetPassword(const char * /*reason*/) override { - return optional(); // Not implemented - } + void refreshed() override + { + wallet_listener::refreshed(*inner_); + } - void onPoolTxRemoved(const std::string &txid) override { - wallet_listener::pool_tx_removed(*inner_, txid); - } + void onReorg(std::uint64_t height, std::uint64_t blocks_detached, std::size_t transfers_detached) override + { + wallet_listener::on_reorg(*inner_, height, blocks_detached, transfers_detached); + } + + optional onGetPassword(const char * /*reason*/) override + { + return optional(); // Not implemented + } + + void onPoolTxRemoved(const std::string &txid) override + { + wallet_listener::pool_tx_removed(*inner_, txid); + } -private: - rust::Box inner_; -}; + private: + rust::Box inner_; + }; } // namespace Monero -namespace wallet_listener { - Monero::WalletListener* create_rust_listener_adapter(rust::Box listener) { +namespace wallet_listener +{ + Monero::WalletListener *create_rust_listener_adapter(rust::Box listener) + { return new Monero::RustListenerAdapter(std::move(listener)); } - void destroy_rust_listener_adapter(Monero::WalletListener* ptr) { + void destroy_rust_listener_adapter(Monero::WalletListener *ptr) + { delete ptr; } } diff --git a/monero-sys/src/bridge.rs b/monero-sys/src/bridge.rs index 14e62759f..29d38ba82 100644 --- a/monero-sys/src/bridge.rs +++ b/monero-sys/src/bridge.rs @@ -35,6 +35,13 @@ pub mod ffi { ConnectionStatus_WrongVersion = 2, } + /// A transaction key corresponding to a specific output in a specific transaction. + struct TxKey { + txid: UniquePtr, + address: UniquePtr, + key: UniquePtr, + } + unsafe extern "C++" { include!("wallet/api/wallet2_api.h"); include!("bridge.h"); @@ -289,7 +296,7 @@ pub mod ffi { fn pendingTransactionTxKeys( tx: &PendingTransaction, tx_hash: &CxxString, - ) -> Result>>; + ) -> Result>>; /// Get the fee of a pending transaction. fn pendingTransactionFee(tx: &PendingTransaction) -> Result; @@ -297,9 +304,6 @@ pub mod ffi { /// Get the amount of a pending transaction. fn pendingTransactionAmount(tx: &PendingTransaction) -> Result; - /// Get the transaction key (r) for a given txid. - fn walletGetTxKey(wallet: &Wallet, txid: &CxxString) -> Result>; - /// Commit a pending transaction to the blockchain. fn commit( self: Pin<&mut PendingTransaction>, @@ -666,6 +670,9 @@ fn forward_cpp_log( // We don't want to log the performance timer. if func_str.starts_with("tools::LoggingPerformanceTimer") + || func_str.starts_with("void tools::detail::print_source_entry(") + || func_str.starts_with("bool cryptonote::construct_tx_with_tx_key(") + || func_str.starts_with("void tools::wallet2::get_outs(") || msg_str.starts_with("Processed block: <") || msg_str.starts_with("Found new pool tx: <") { diff --git a/monero-sys/src/lib.rs b/monero-sys/src/lib.rs index fc7f99ce8..4ad1486ca 100644 --- a/monero-sys/src/lib.rs +++ b/monero-sys/src/lib.rs @@ -127,6 +127,7 @@ pub struct SyncProgress { } /// The status of a transaction. +#[derive(Debug, Clone)] pub struct TxStatus { /// The amount received in the transaction. pub received: monero::Amount, @@ -140,7 +141,11 @@ pub struct TxStatus { /// Contains basic information needed for later verification. pub struct TxReceipt { pub txid: String, - pub tx_key: String, + /// A map that has an entry for each non-change output + /// where the key is the output's address and the value is the transfer key + /// corresponding to that output. We use these for our transfer proofs. + /// In Monero lingo, this is the r for each K^s/K^v. + pub tx_keys: HashMap, /// The blockchain height at the time of publication. pub height: u64, } @@ -436,6 +441,12 @@ impl WalletHandle { self.call(move |wallet| wallet.main_address()).await } + /// Get the address of the wallet for a given account and address index. + pub async fn address(&self, account_index: u32, address_index: u32) -> monero::Address { + self.call(move |wallet| wallet.address(account_index, address_index)) + .await + } + /// Get the current height of the blockchain. /// May involve an RPC call to the daemon. /// Returns `None` if the wallet is not connected to a daemon. @@ -793,7 +804,7 @@ impl WalletHandle { } /// Check the status of a transaction. - async fn check_tx_status( + pub async fn check_tx_status( &self, txid: String, tx_key: monero::PrivateKey, @@ -903,7 +914,7 @@ impl WalletHandle { // Closure that returns (txid, amount, fee) or error let result = (|| -> Result<(String, monero::Amount, monero::Amount), anyhow::Error> { - let (txid, _) = pending_tx.validate_single_txid_single_tx_key() + let (txid, _) = pending_tx.validate_single_txid(&[address]) .context("Failed to validate PendingTransaction to have single txid and single tx key")?; let amount = ffi::pendingTransactionAmount(&pending_tx) @@ -946,7 +957,8 @@ impl WalletHandle { // Publish the transaction if approved { - let receipt_result = wallet.publish_pending_transaction(&mut pending_tx); + let receipt_result = + wallet.publish_pending_transaction(&mut pending_tx, &[address]); // Dispose the pending transaction independent of whether the publish was successful or not wallet.dispose_pending_transaction(pending_tx); @@ -1537,7 +1549,7 @@ impl FfiWallet { /// Get the address for the given account and address index. /// address(0, 0) is the main address. /// We don't use anything besides the main address so this is a private method (for now). - fn address(&self, account_index: u32, address_index: u32) -> monero::Address { + pub fn address(&self, account_index: u32, address_index: u32) -> monero::Address { let address = ffi::address(&self.inner, account_index, address_index) .context("Failed to get wallet address: FFI call failed with exception") .expect("Wallet address should never fail"); @@ -2004,7 +2016,7 @@ impl FfiWallet { // Publish the transaction let result = self - .publish_pending_transaction(&mut pending_tx) + .publish_pending_transaction(&mut pending_tx, &[*address]) .context("Failed to publish sweep transaction"); // Dispose the pending transaction after we're done with it @@ -2060,7 +2072,7 @@ impl FfiWallet { // Publish the transaction let result = self - .publish_pending_transaction(&mut pending_tx) + .publish_pending_transaction(&mut pending_tx, &addresses) .context("Failed to publish multi-sweep transaction"); // Dispose the pending transaction after we're done with it @@ -2080,11 +2092,16 @@ impl FfiWallet { self.ensure_synchronized_blocking() .context("Cannot transfer when wallet is not synchronized")?; + let output_addresses = destinations + .iter() + .map(|(address, _)| *address) + .collect::>(); + // Construct the pending transaction let mut pending_tx = self.create_pending_transaction_multi_dest(destinations, false)?; // Publish the transaction - let result = self.publish_pending_transaction(&mut pending_tx); + let result = self.publish_pending_transaction(&mut pending_tx, &output_addresses); // Dispose the pending transaction after we're done with it // independent of whether the publish was successful or not @@ -2182,15 +2199,19 @@ impl FfiWallet { /// Publish a pending transaction and return a receipt. /// Note: Caller is responsible for disposing the pending transaction afterwards. + /// + /// `output_addresses` is a list of monero address which are mentioned in outputs for which we + /// need a tx key. fn publish_pending_transaction( &mut self, pending_tx: &mut PendingTransaction, + output_addresses: &[monero::Address], ) -> anyhow::Result { // Ensure the transaction only has a single txid and tx key // // We forbid splitting transactions. We forbid multiple tx keys. - let (txid, tx_key) = pending_tx.validate_single_txid_single_tx_key().context( - "Failed to ensure transaction has one txid and one tx key before publishing", + let (txid, tx_keys) = pending_tx.validate_single_txid(output_addresses).context( + "Failed to ensure transaction has one txid and at least one tx key before publishing", )?; // Get current blockchain height @@ -2211,7 +2232,7 @@ impl FfiWallet { Ok(_) => { return Ok(TxReceipt { txid, - tx_key, + tx_keys, height, }); } @@ -2503,9 +2524,12 @@ impl PendingTransaction { } } - fn validate_single_txid_single_tx_key( + /// Validates that the pending tx isn't split and returns the tx id as well as + /// the transfer key for each output. + fn validate_single_txid( self: &mut Self, - ) -> Result<(String, String), anyhow::Error> { + output_addresses: &[monero::Address], + ) -> Result<(String, HashMap), anyhow::Error> { // This can return multiple txids if wallet2 decided to split the transaction let txids = ffi::pendingTransactionTxIds(self) .context("Failed to get txid from pending transaction: FFI call failed with exception")? @@ -2516,10 +2540,13 @@ impl PendingTransaction { // Ensure it only created one transaction let txid = match txids.as_slice() { [txid] => txid.clone(), - _ => anyhow::bail!( - "Expected 1 txid, got {}. We do not allow splitting transactions", - txids.len() - ), + _ => { + tracing::debug!(txids=?txids,"Got the transaction id's"); + anyhow::bail!( + "Expected 1 txid, got {}. We do not allow splitting transactions", + txids.len() + ) + } }; // Sanity check that the txid is at least the correct length @@ -2532,38 +2559,61 @@ impl PendingTransaction { ); } - // This could theoretically return multiple tx keys as Monero does allow multiple tx keys for a single transaction - // According to moneromoo, its non standard behavior though so wallet2 should never do this + // This returns only one tx key, if the destinations included at most one subaddress + // + // If there were more than one subaddress, we will get 1 + number of outputs tx keys + // - one primary tx key + // - one tx key for each output let_cxx_string!(txid_cxx = &txid); - let tx_keys = ffi::pendingTransactionTxKeys(self, &txid_cxx) - .context( - "Failed to get tx key from pending transaction: FFI call failed with exception", - )? - .into_iter() - .map(|s| s.to_string()) - .collect::>(); - - // Ensure we only have one tx key - // If we have multiple tx keys, we would need to create multiple transfer proofs - let tx_key = match tx_keys.as_slice() { - [key] => key.clone(), - _ => anyhow::bail!( - "Expected 1 tx key, got {}. We do not allow splitting transactions", - tx_keys.len() - ), - }; - - // Ensure we didn't get junk from wallet2 - { - monero::PrivateKey::from_str(&tx_key) - .with_context(|| format!("Invalid tx key: {tx_key}"))?; + let tx_keys: Vec<(monero::Address, monero::PrivateKey)> = + ffi::pendingTransactionTxKeys(self, &txid_cxx) + .context( + "Failed to get tx key from pending transaction: FFI call failed with exception", + )? + .into_iter() + .map(|tx_key| -> Result<(monero::Address, monero::PrivateKey)> { + Ok(( + tx_key + .address + .to_str() + .context("Got non-utf8 address string")? + .parse() + .context("Got invalid Monero address")?, + tx_key + .key + .to_str() + .context("Got non-utf8 key string")? + .parse() + .context("Got invalid Monero private key")?, + )) + }) + .collect::, anyhow::Error>>()?; + + if tx_keys.is_empty() { + anyhow::bail!("Expected at least one tx key, got 0"); + } + + let mut keys_map = HashMap::new(); + for (address, tx_key) in tx_keys { + if keys_map.contains_key(&address) { + anyhow::bail!("Address {} is used for multiple outputs", address); + } else { + keys_map.insert(address, tx_key); + } + } - if txid.is_empty() { - anyhow::bail!("Got an empty txid"); + for address in output_addresses { + if !keys_map.contains_key(address) { + anyhow::bail!( + "Output address {} is not mentioned in tx keys for tx {}. tx_keys.len() = {}. Sending funds to your own primary address is NOT supported.", + address, + txid, + keys_map.len() + ); } } - Ok((txid, tx_key)) + Ok((txid, keys_map)) } } diff --git a/monero-sys/tests/transaction_keys_testnet.rs b/monero-sys/tests/transaction_keys_testnet.rs new file mode 100644 index 000000000..ddb186a53 --- /dev/null +++ b/monero-sys/tests/transaction_keys_testnet.rs @@ -0,0 +1,90 @@ +/// Construct, publish and return the transaction keys of a complex transaction +/// (sending to multiple addresses, some of which are subaddresses) +use monero::Amount; +use monero_sys::{Daemon, SyncProgress, WalletHandle}; + +const STAGENET_REMOTE_NODE: &str = "http://node.sethforprivacy.com:38089"; +const STAGENET_WALLET_SEED: &str = "echo ourselves ruined oven masterful wives enough addicted future cottage illness adopt lucky movement tiger taboo imbalance antics iceberg hobby oval aloof tuesday uttered oval"; +const STAGENET_WALLET_RESTORE_HEIGHT: u64 = 1728128; + +#[tokio::test] +async fn main() -> anyhow::Result<()> { + tracing_subscriber::fmt() + .with_env_filter( + "info,test=debug,monero_harness=debug,monero_rpc=debug,transaction_keys=trace,monero_sys=trace", + ) + .with_test_writer() + .init(); + + let temp_dir = tempfile::tempdir().unwrap(); + let daemon = Daemon::try_from(STAGENET_REMOTE_NODE).unwrap(); + + let wallet_name = "recovered_wallet"; + let wallet_path = temp_dir.path().join(wallet_name).display().to_string(); + + tracing::info!("Recovering wallet from seed"); + let wallet = WalletHandle::open_or_create_from_seed( + wallet_path, + STAGENET_WALLET_SEED.to_string(), + monero::Network::Stagenet, + STAGENET_WALLET_RESTORE_HEIGHT, + true, + daemon, + ) + .await + .expect("Failed to recover wallet"); + + tracing::info!("Primary address: {}", wallet.main_address().await); + + // Wait for a while to let the wallet sync, checking sync status + tracing::info!("Waiting for wallet to sync..."); + + wallet + .wait_until_synced(Some(|sync_progress: SyncProgress| { + tracing::info!("Sync progress: {}%", sync_progress.percentage()); + })) + .await + .expect("Failed to sync wallet"); + + wallet.store_in_current_file().await?; + + // Test sending to some (sub)addresses + let subaddress1 = wallet.address(1, 0).await; + let subaddress2 = wallet.address(0, 2).await; + let subaddress3 = wallet.address(1, 2).await; + let subaddress4 = wallet.address(2, 2).await; + + let addresses = [ + subaddress1.to_string(), + subaddress2.to_string(), + subaddress3.to_string(), + subaddress4.to_string(), + ]; + tracing::info!(addresses=?addresses, "Got the destination addresses"); + + let amount = Amount::from_xmr(0.02)?; + + let tx_receipt = wallet + .transfer_multi_destination(&[ + (subaddress1, amount), + (subaddress2, amount), + (subaddress3, amount), + (subaddress4, amount), + ]) + .await?; + + // at this point we managed to publish the transaction and + // got all transaction keys (for each output). + // The test passed, the logs are just for debugging. + tracing::info!(tx_id = &tx_receipt.txid, "Transaction published! (good)"); + assert_eq!( + tx_receipt.tx_keys.len(), + 4, + "Expect one tx key per output (none for change)" + ); + for (addr, key) in tx_receipt.tx_keys { + tracing::info!(address=%addr, %key, "Got transaction key"); + } + + Ok(()) +} diff --git a/monero-tests/Cargo.toml b/monero-tests/Cargo.toml new file mode 100644 index 000000000..18ea2af6d --- /dev/null +++ b/monero-tests/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "monero-tests" +version = "0.1.0" +edition = "2024" + +[dependencies] +monero-harness = { path = "../monero-harness" } + +monero = { workspace = true } + +anyhow = { workspace = true } +tokio = { workspace = true, features = ["macros", "rt"] } +tracing = { workspace = true } +tracing-subscriber = { workspace = true } + +[lints] +workspace = true diff --git a/monero-tests/src/lib.rs b/monero-tests/src/lib.rs new file mode 100644 index 000000000..2235e7095 --- /dev/null +++ b/monero-tests/src/lib.rs @@ -0,0 +1 @@ +// Empty but necessary for cargo diff --git a/monero-tests/tests/transaction_keys.rs b/monero-tests/tests/transaction_keys.rs new file mode 100644 index 000000000..46ec8b464 --- /dev/null +++ b/monero-tests/tests/transaction_keys.rs @@ -0,0 +1,62 @@ +use anyhow::Context; +use monero_harness::Cli; + +/// Create a transaction with transaction proofs, and verify them. +/// Fails if the publishing fails due to the transfer keys not being extracted successfully +/// or due to them not being able to be verified by the recipients. +#[tokio::test] +async fn monero_transfers() -> anyhow::Result<()> { + tracing_subscriber::fmt() + .with_env_filter( + "info,test=debug,monero_harness=debug,monero_rpc=debug,monero_sys=trace,transfers=trace,monero_cpp=info", + ).init(); + + let cli = Cli::default(); + let wallets = vec!["alice", "bob", "candice"]; + // Disbale background sync for these wallet -- this way we _have_ to use the transfer proof to discover the transactions. + let (monero, _container, _wallet_conainers) = + monero_harness::Monero::new_with_sync_specified(&cli, wallets, false).await?; + + tracing::info!("Starting miner"); + + monero.init_and_start_miner().await?; + + let miner = monero.wallet("miner")?; + let alice = monero.wallet("alice")?; + let bob = monero.wallet("bob")?; + let candice = monero.wallet("candice")?; + + tracing::info!("Checking miner balance"); + + assert!(miner.balance().await? > 0); + + tracing::info!("Sending money"); + + let proof = miner + .sweep_multi( + &[ + alice.address().await?, + bob.address().await?, + candice.address().await?, + ], + &[0.33333333, 0.333333333, 0.3333333333], + ) + .await?; + + assert_eq!( + proof.tx_keys.len(), + 3, + "Expect one transaction key per non-change output" + ); + + alice + .check_tx_key( + proof.txid.clone(), + proof.tx_keys.get(alice.address().await?), + ) + .await?; + + assert_eq!(alice.sweep(bob.address().await?).await?.tx_keys.len(), 1); + + Ok(()) +} diff --git a/monero-tests/tests/transfers.rs b/monero-tests/tests/transfers.rs new file mode 100644 index 000000000..fac027e1b --- /dev/null +++ b/monero-tests/tests/transfers.rs @@ -0,0 +1,83 @@ +use anyhow::Context; +use monero_harness::Cli; + +/// Create a transaction with transaction proofs, and verify them. +/// Fails if the publishing fails due to the transfer keys not being extracted successfully +/// or due to them not being able to be verified by the recipients. +#[tokio::test] +async fn monero_transfers() -> anyhow::Result<()> { + tracing_subscriber::fmt() + .with_env_filter( + "info,test=debug,monero_harness=debug,monero_rpc=debug,monero_sys=trace,transfers=trace,monero_cpp=info", + ).init(); + + let cli = Cli::default(); + let wallets = vec!["alice", "bob"]; + // Disbale background sync for these wallet -- this way we _have_ to use the transfer proof to discover the transactions. + let (monero, _container, _wallet_conainers) = + monero_harness::Monero::new_with_sync_specified(&cli, wallets, false).await?; + + tracing::info!("Starting miner"); + + monero.init_and_start_miner().await?; + + let miner_wallet = monero.wallet("miner")?; + let alice = monero.wallet("alice")?; + let bob = monero.wallet("bob")?; + + tracing::info!("Checking miner balance"); + + assert!(miner_wallet.balance().await? > 0); + + tracing::info!("Sending money"); + + let tx_receipt = miner_wallet + .sweep_multi(&[alice.address().await?, bob.address().await?], &[0.5, 0.5]) + .await?; + + assert_eq!( + tx_receipt.tx_keys.len(), + 2, + "Expect one tx key for each non-change output" + ); + + monero.generate_block().await?; + + let alice_txkey = tx_receipt + .tx_keys + .get(&alice.address().await?) + .context("tx key not found for alice")?; + + let bob_txkey = tx_receipt + .tx_keys + .get(&bob.address().await?) + .context("tx key not found for bob")?; + + tracing::info!("Importing tx keys"); + + let alice_status = alice + .check_tx_key(tx_receipt.txid.clone(), *alice_txkey) + .await?; + let bob_status = bob + .check_tx_key(tx_receipt.txid.clone(), *bob_txkey) + .await?; + + tracing::info!( + ?alice_status, + ?bob_status, + "Successfully checked transactions keys!" + ); + + // sanity check: we should have actually received the money... + + assert!( + alice.balance().await? > 0, + "Alice expected to have received funds" + ); + assert!( + bob.balance().await? > 0, + "Bob expected to have received funds" + ); + + Ok(()) +} diff --git a/monero-tests/tests/transfers_wrong_key.rs b/monero-tests/tests/transfers_wrong_key.rs new file mode 100644 index 000000000..a6f5ba1e3 --- /dev/null +++ b/monero-tests/tests/transfers_wrong_key.rs @@ -0,0 +1,64 @@ +use anyhow::bail; +use monero_harness::Cli; + +/// Verify that checking a transaction with a wrong/random transfer key fails. +#[tokio::test] +async fn monero_transfers_wrong_key() { + tracing_subscriber::fmt() + .with_env_filter( + "info,test=debug,monero_harness=debug,monero_rpc=debug,monero_sys=trace,transfers=trace,monero_cpp=info", + ).init(); + + let cli = Cli::default(); + let wallets = vec!["alice"]; + // Disable background sync for this wallet -- this way we _have_ to use the transfer proof to discover the transactions. + let (monero, _container, _wallet_conainers) = + monero_harness::Monero::new_with_sync_specified(&cli, wallets, false) + .await + .unwrap(); + + tracing::info!("Starting miner"); + + monero.init_and_start_miner().await.unwrap(); + + let miner_wallet = monero.wallet("miner").unwrap(); + let alice = monero.wallet("alice").unwrap(); + + tracing::info!("Checking miner balance"); + + assert!(miner_wallet.balance().await.unwrap() > 0); + + tracing::info!("Sending money"); + + let tx_receipt = miner_wallet + .sweep(&alice.address().await.unwrap()) + .await + .unwrap(); + + assert_eq!( + tx_receipt.tx_keys.len(), + 1, + "Expect one tx key for the output" + ); + + monero.generate_block().await.unwrap(); + + // Use a wrong private key (just a simple constant key, not the real transfer key) + let wrong_key = monero::PrivateKey::from_slice(&[ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + ]) + .unwrap(); + + tracing::info!("Importing tx key with wrong key - should fail"); + + let status = alice + .check_tx_key(tx_receipt.txid.clone(), wrong_key) + .await + .unwrap(); + + // Wrong tx key -> amount is zero. + if status.received != monero::Amount::ZERO { + panic!("could decrypt payment - this is not supposed to happen since we got a bogus key"); + } +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 45f5f19cc..6498d5dd8 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] # also update this in the readme, changelog, and github actions -channel = "1.87.0" +channel = "1.88.0" components = ["clippy"] targets = ["armv7-unknown-linux-gnueabihf"] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 3ed282c20..df8db0c8c 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -27,9 +27,9 @@ uuid = "1.16.0" zip = "4.0.0" # Tauri -tauri = { version = "2.*", features = [ "config-json5" ] } +tauri = { version = "2.8.0", features = [ "config-json5" ] } tauri-plugin-clipboard-manager = "2.*" -tauri-plugin-dialog = "2.2.2" +tauri-plugin-dialog = "2.3.3" tauri-plugin-opener = "2.*" tauri-plugin-process = "2.*" tauri-plugin-shell = "2.*" diff --git a/swap/src/protocol/alice/swap.rs b/swap/src/protocol/alice/swap.rs index d6ede89ec..dddff38e0 100644 --- a/swap/src/protocol/alice/swap.rs +++ b/swap/src/protocol/alice/swap.rs @@ -164,12 +164,12 @@ where .context("Failed to get Monero wallet block height") .map_err(backoff::Error::transient)?; - let (address, amount) = state3 + let (lock_address, amount) = state3 .lock_xmr_transfer_request() .address_and_amount(env_config.monero_network); let destinations = - build_transfer_destinations(address, amount, developer_tip.clone())?; + build_transfer_destinations(lock_address, amount, developer_tip.clone())?; // Lock the Monero let receipt = monero_wallet @@ -186,12 +186,13 @@ where ))); }; + let tx_key = receipt.tx_keys.get(&lock_address).expect("monero-sys guarantees that the address has a valid tx key or the tx isn't published"); + Ok(Some(( monero_wallet_restore_blockheight, TransferProof::new( monero::TxHash(receipt.txid), - monero::PrivateKey::from_str(&receipt.tx_key) - .expect("tx key to be valid private key"), + *tx_key, ), ))) }, diff --git a/swap/tests/happy_path_alice_developer_tip.rs b/swap/tests/happy_path_alice_developer_tip.rs index 4009cd674..eba9df567 100644 --- a/swap/tests/happy_path_alice_developer_tip.rs +++ b/swap/tests/happy_path_alice_developer_tip.rs @@ -10,7 +10,7 @@ use tokio::join; async fn happy_path_alice_developer_tip() { harness::setup_test( SlowCancelConfig, - Some(Decimal::from_f32_retain(0.1).unwrap()), + Some((Decimal::from_f32_retain(0.1).unwrap(), false)), |mut ctx| async move { let (bob_swap, _) = ctx.bob_swap().await; let bob_swap = tokio::spawn(bob::run(bob_swap)); diff --git a/swap/tests/happy_path_alice_developer_tip_subaddress.rs b/swap/tests/happy_path_alice_developer_tip_subaddress.rs new file mode 100644 index 000000000..df34d3c6d --- /dev/null +++ b/swap/tests/happy_path_alice_developer_tip_subaddress.rs @@ -0,0 +1,31 @@ +pub mod harness; + +use harness::SlowCancelConfig; +use rust_decimal::Decimal; +use swap::asb::FixedRate; +use swap::protocol::{alice, bob}; +use tokio::join; + +#[tokio::test] +async fn happy_path_alice_developer_tip_subaddress() { + harness::setup_test( + SlowCancelConfig, + Some((Decimal::from_f32_retain(0.1).unwrap(), true)), + |mut ctx| async move { + let (bob_swap, _) = ctx.bob_swap().await; + let bob_swap = tokio::spawn(bob::run(bob_swap)); + + let alice_swap = ctx.alice_next_swap().await; + let alice_swap = tokio::spawn(alice::run(alice_swap, FixedRate::default())); + + let (bob_state, alice_state) = join!(bob_swap, alice_swap); + + ctx.assert_alice_redeemed(alice_state??).await; + ctx.assert_bob_redeemed(bob_state??).await; + ctx.assert_alice_developer_tip_received().await; + + Ok(()) + }, + ) + .await; +} diff --git a/swap/tests/harness/mod.rs b/swap/tests/harness/mod.rs index af27448b3..6fe6f8db6 100644 --- a/swap/tests/harness/mod.rs +++ b/swap/tests/harness/mod.rs @@ -44,7 +44,11 @@ use tokio::time::{interval, timeout}; use url::Url; use uuid::Uuid; -pub async fn setup_test(_config: C, developer_tip_ratio: Option, testfn: T) +/// developer_tip_ratio is a tuple of (ratio, use_subaddress) +/// +/// If use_subaddress is true, we will use a subaddress for the developer tip. We do this +/// because using a subaddress changes things about the tx keys involved +pub async fn setup_test(_config: C, developer_tip_ratio: Option<(Decimal, bool)>, testfn: T) where T: Fn(TestContext) -> F, F: Future>, @@ -77,6 +81,7 @@ where .unwrap() .path() .join("developer_tip-monero-wallets"); + let (_, developer_tip_monero_wallet) = init_test_wallets( "developer_tip", containers.bitcoind_url.clone(), @@ -89,16 +94,29 @@ where env_config, ) .await; - let developer_tip_monero_wallet_address = developer_tip_monero_wallet + + let developer_tip_monero_wallet_main_address = developer_tip_monero_wallet .main_wallet() .await .main_address() .await .into(); + let developer_tip_monero_wallet_subaddress = developer_tip_monero_wallet + .main_wallet() + .await + // explicitly use a suabddress here to test the addtional tx key logic + .address(0, 2) + .await + .into(); + let developer_tip = TipConfig { - ratio: developer_tip_ratio.unwrap_or(Decimal::ZERO), - address: developer_tip_monero_wallet_address, + ratio: developer_tip_ratio.unwrap_or((Decimal::ZERO, false)).0, + address: match developer_tip_ratio { + Some((_, true)) => developer_tip_monero_wallet_subaddress, + Some((_, false)) => developer_tip_monero_wallet_main_address, + None => developer_tip_monero_wallet_main_address, + }, }; let alice_starting_balances =