From 51a6790178b584631b0fca2f7230132c3a473721 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Mon, 20 Apr 2026 13:48:43 +0200 Subject: [PATCH 1/4] chore(deps): bump platform to 2cc4cdcf8 (rust-dashcore 309fac8) Adapts dash-evo-tool to rust-dashcore 309fac8 API changes shipped via platform rev 2cc4cdcf85ce62b437031671336bf622b3aafaa5. API surface changes handled: - `MasternodeListEngine::feed_qr_info` signature changed: now takes `&QRInfoBlockData` rather than an `Option` height-lookup closure. Both call sites in `masternode_list_diff_screen.rs` now pre-populate the bundle via a new `build_qr_info_block_data` helper that resolves hash->height from the screen's cache/Core RPC and height->hash for cycle boundary blocks via `get_block_hash` (Core RPC). - `MasternodeListEngine::rotated_quorums_per_cycle` is now a `BTreeMap>` (was a `Vec`). `render_last_commitments` now destructures the inner map directly and the quorum index comes from the map key. - `AddressProvider::on_address_found` / `on_address_absent` are now `async fn` (via the trait's `#[async_trait]`). `WalletAddressProvider` is annotated with `#[async_trait]` and both callbacks made `async`. - `sml::quorum_validation_error::ClientDataRetrievalError` was removed upstream. The only DET uses were inside the feed_qr_info closure that is now replaced wholesale; the import is gone. No behavioural change - this is pure API adaptation. All existing SPV fixes on this branch (DB fallback for start_spv, atomic BIP44 pool extension, SPV restart on mid-session import) continue to behave identically and their tests still pass. Co-Authored-By: Claude Opus 4.7 (1M context) --- Cargo.lock | 139 ++++++++++++++------ Cargo.toml | 4 +- src/model/wallet/mod.rs | 6 +- src/ui/tools/masternode_list_diff_screen.rs | 115 ++++++++-------- 4 files changed, 164 insertions(+), 100 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 44c9918eb..b16d1bc92 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1279,6 +1279,25 @@ dependencies = [ "cipher", ] +[[package]] +name = "cbindgen" +version = "0.29.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "befbfd072a8e81c02f8c507aefce431fe5e7d051f83d48a23ffc9b9fe5a11799" +dependencies = [ + "clap", + "heck", + "indexmap 2.13.0", + "log", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn 2.0.117", + "tempfile", + "toml 0.9.12+spec-1.1.0", +] + [[package]] name = "cc" version = "1.2.57" @@ -1848,7 +1867,7 @@ dependencies = [ [[package]] name = "dapi-grpc" version = "3.1.0-dev.1" -source = "git+https://github.com/dashpay/platform?rev=9d799d339f961bed5aa21d3e3e3efe9374b7929c#9d799d339f961bed5aa21d3e3e3efe9374b7929c" +source = "git+https://github.com/dashpay/platform?rev=2cc4cdcf85ce62b437031671336bf622b3aafaa5#2cc4cdcf85ce62b437031671336bf622b3aafaa5" dependencies = [ "dash-platform-macros", "futures-core", @@ -1950,7 +1969,7 @@ dependencies = [ [[package]] name = "dash-context-provider" version = "3.1.0-dev.1" -source = "git+https://github.com/dashpay/platform?rev=9d799d339f961bed5aa21d3e3e3efe9374b7929c#9d799d339f961bed5aa21d3e3e3efe9374b7929c" +source = "git+https://github.com/dashpay/platform?rev=2cc4cdcf85ce62b437031671336bf622b3aafaa5#2cc4cdcf85ce62b437031671336bf622b3aafaa5" dependencies = [ "dpp", "drive", @@ -2039,7 +2058,7 @@ dependencies = [ [[package]] name = "dash-platform-macros" version = "3.1.0-dev.1" -source = "git+https://github.com/dashpay/platform?rev=9d799d339f961bed5aa21d3e3e3efe9374b7929c#9d799d339f961bed5aa21d3e3e3efe9374b7929c" +source = "git+https://github.com/dashpay/platform?rev=2cc4cdcf85ce62b437031671336bf622b3aafaa5#2cc4cdcf85ce62b437031671336bf622b3aafaa5" dependencies = [ "heck", "quote", @@ -2049,7 +2068,7 @@ dependencies = [ [[package]] name = "dash-sdk" version = "3.1.0-dev.1" -source = "git+https://github.com/dashpay/platform?rev=9d799d339f961bed5aa21d3e3e3efe9374b7929c#9d799d339f961bed5aa21d3e3e3efe9374b7929c" +source = "git+https://github.com/dashpay/platform?rev=2cc4cdcf85ce62b437031671336bf622b3aafaa5#2cc4cdcf85ce62b437031671336bf622b3aafaa5" dependencies = [ "arc-swap", "async-trait", @@ -2085,12 +2104,9 @@ dependencies = [ [[package]] name = "dash-spv" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=88e8a9aa1eadce79c8177f757f6741f8a55a83f5#88e8a9aa1eadce79c8177f757f6741f8a55a83f5" +source = "git+https://github.com/dashpay/rust-dashcore?rev=309fac869bb96a6c7f5812a594c0ce28baa1ea71#309fac869bb96a6c7f5812a594c0ce28baa1ea71" dependencies = [ - "anyhow", "async-trait", - "bincode 2.0.1", - "blsful", "chrono", "clap", "dashcore", @@ -2098,10 +2114,8 @@ dependencies = [ "futures", "hex", "hickory-resolver", - "indexmap 2.13.0", "key-wallet", "key-wallet-manager", - "log", "rand 0.8.5", "rayon", "serde", @@ -2118,7 +2132,7 @@ dependencies = [ [[package]] name = "dashcore" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=88e8a9aa1eadce79c8177f757f6741f8a55a83f5#88e8a9aa1eadce79c8177f757f6741f8a55a83f5" +source = "git+https://github.com/dashpay/rust-dashcore?rev=309fac869bb96a6c7f5812a594c0ce28baa1ea71#309fac869bb96a6c7f5812a594c0ce28baa1ea71" dependencies = [ "anyhow", "base64-compat", @@ -2128,40 +2142,41 @@ dependencies = [ "bitvec", "blake3", "blsful", + "cbindgen", "dashcore-private", "dashcore_hashes", "ed25519-dalek", "hex", "hex_lit", - "log", "rustversion", "secp256k1", "serde", "thiserror 2.0.18", + "tracing", ] [[package]] name = "dashcore-private" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=88e8a9aa1eadce79c8177f757f6741f8a55a83f5#88e8a9aa1eadce79c8177f757f6741f8a55a83f5" +source = "git+https://github.com/dashpay/rust-dashcore?rev=309fac869bb96a6c7f5812a594c0ce28baa1ea71#309fac869bb96a6c7f5812a594c0ce28baa1ea71" [[package]] name = "dashcore-rpc" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=88e8a9aa1eadce79c8177f757f6741f8a55a83f5#88e8a9aa1eadce79c8177f757f6741f8a55a83f5" +source = "git+https://github.com/dashpay/rust-dashcore?rev=309fac869bb96a6c7f5812a594c0ce28baa1ea71#309fac869bb96a6c7f5812a594c0ce28baa1ea71" dependencies = [ "dashcore-rpc-json", "hex", "jsonrpc", - "log", "serde", "serde_json", + "tracing", ] [[package]] name = "dashcore-rpc-json" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=88e8a9aa1eadce79c8177f757f6741f8a55a83f5#88e8a9aa1eadce79c8177f757f6741f8a55a83f5" +source = "git+https://github.com/dashpay/rust-dashcore?rev=309fac869bb96a6c7f5812a594c0ce28baa1ea71#309fac869bb96a6c7f5812a594c0ce28baa1ea71" dependencies = [ "bincode 2.0.1", "dashcore", @@ -2176,12 +2191,11 @@ dependencies = [ [[package]] name = "dashcore_hashes" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=88e8a9aa1eadce79c8177f757f6741f8a55a83f5#88e8a9aa1eadce79c8177f757f6741f8a55a83f5" +source = "git+https://github.com/dashpay/rust-dashcore?rev=309fac869bb96a6c7f5812a594c0ce28baa1ea71#309fac869bb96a6c7f5812a594c0ce28baa1ea71" dependencies = [ "bincode 2.0.1", "dashcore-private", "rs-x11-hash", - "secp256k1", "serde", ] @@ -2201,7 +2215,7 @@ dependencies = [ [[package]] name = "dashpay-contract" version = "3.1.0-dev.1" -source = "git+https://github.com/dashpay/platform?rev=9d799d339f961bed5aa21d3e3e3efe9374b7929c#9d799d339f961bed5aa21d3e3e3efe9374b7929c" +source = "git+https://github.com/dashpay/platform?rev=2cc4cdcf85ce62b437031671336bf622b3aafaa5#2cc4cdcf85ce62b437031671336bf622b3aafaa5" dependencies = [ "platform-value", "platform-version", @@ -2212,7 +2226,7 @@ dependencies = [ [[package]] name = "data-contracts" version = "3.1.0-dev.1" -source = "git+https://github.com/dashpay/platform?rev=9d799d339f961bed5aa21d3e3e3efe9374b7929c#9d799d339f961bed5aa21d3e3e3efe9374b7929c" +source = "git+https://github.com/dashpay/platform?rev=2cc4cdcf85ce62b437031671336bf622b3aafaa5#2cc4cdcf85ce62b437031671336bf622b3aafaa5" dependencies = [ "dashpay-contract", "dpns-contract", @@ -2465,7 +2479,7 @@ checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" [[package]] name = "dpns-contract" version = "3.1.0-dev.1" -source = "git+https://github.com/dashpay/platform?rev=9d799d339f961bed5aa21d3e3e3efe9374b7929c#9d799d339f961bed5aa21d3e3e3efe9374b7929c" +source = "git+https://github.com/dashpay/platform?rev=2cc4cdcf85ce62b437031671336bf622b3aafaa5#2cc4cdcf85ce62b437031671336bf622b3aafaa5" dependencies = [ "platform-value", "platform-version", @@ -2476,7 +2490,7 @@ dependencies = [ [[package]] name = "dpp" version = "3.1.0-dev.1" -source = "git+https://github.com/dashpay/platform?rev=9d799d339f961bed5aa21d3e3e3efe9374b7929c#9d799d339f961bed5aa21d3e3e3efe9374b7929c" +source = "git+https://github.com/dashpay/platform?rev=2cc4cdcf85ce62b437031671336bf622b3aafaa5#2cc4cdcf85ce62b437031671336bf622b3aafaa5" dependencies = [ "anyhow", "async-trait", @@ -2526,7 +2540,7 @@ dependencies = [ [[package]] name = "dpp-json-convertible-derive" version = "3.1.0-dev.1" -source = "git+https://github.com/dashpay/platform?rev=9d799d339f961bed5aa21d3e3e3efe9374b7929c#9d799d339f961bed5aa21d3e3e3efe9374b7929c" +source = "git+https://github.com/dashpay/platform?rev=2cc4cdcf85ce62b437031671336bf622b3aafaa5#2cc4cdcf85ce62b437031671336bf622b3aafaa5" dependencies = [ "proc-macro2", "quote", @@ -2536,7 +2550,7 @@ dependencies = [ [[package]] name = "drive" version = "3.1.0-dev.1" -source = "git+https://github.com/dashpay/platform?rev=9d799d339f961bed5aa21d3e3e3efe9374b7929c#9d799d339f961bed5aa21d3e3e3efe9374b7929c" +source = "git+https://github.com/dashpay/platform?rev=2cc4cdcf85ce62b437031671336bf622b3aafaa5#2cc4cdcf85ce62b437031671336bf622b3aafaa5" dependencies = [ "bincode 2.0.1", "byteorder", @@ -2561,7 +2575,7 @@ dependencies = [ [[package]] name = "drive-proof-verifier" version = "3.1.0-dev.1" -source = "git+https://github.com/dashpay/platform?rev=9d799d339f961bed5aa21d3e3e3efe9374b7929c#9d799d339f961bed5aa21d3e3e3efe9374b7929c" +source = "git+https://github.com/dashpay/platform?rev=2cc4cdcf85ce62b437031671336bf622b3aafaa5#2cc4cdcf85ce62b437031671336bf622b3aafaa5" dependencies = [ "bincode 2.0.1", "dapi-grpc", @@ -3151,7 +3165,7 @@ dependencies = [ [[package]] name = "feature-flags-contract" version = "3.1.0-dev.1" -source = "git+https://github.com/dashpay/platform?rev=9d799d339f961bed5aa21d3e3e3efe9374b7929c#9d799d339f961bed5aa21d3e3e3efe9374b7929c" +source = "git+https://github.com/dashpay/platform?rev=2cc4cdcf85ce62b437031671336bf622b3aafaa5#2cc4cdcf85ce62b437031671336bf622b3aafaa5" dependencies = [ "platform-value", "platform-version", @@ -4895,7 +4909,7 @@ dependencies = [ [[package]] name = "key-wallet" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=88e8a9aa1eadce79c8177f757f6741f8a55a83f5#88e8a9aa1eadce79c8177f757f6741f8a55a83f5" +source = "git+https://github.com/dashpay/rust-dashcore?rev=309fac869bb96a6c7f5812a594c0ce28baa1ea71#309fac869bb96a6c7f5812a594c0ce28baa1ea71" dependencies = [ "async-trait", "base58ck", @@ -4917,7 +4931,7 @@ dependencies = [ [[package]] name = "key-wallet-manager" version = "0.42.0" -source = "git+https://github.com/dashpay/rust-dashcore?rev=88e8a9aa1eadce79c8177f757f6741f8a55a83f5#88e8a9aa1eadce79c8177f757f6741f8a55a83f5" +source = "git+https://github.com/dashpay/rust-dashcore?rev=309fac869bb96a6c7f5812a594c0ce28baa1ea71#309fac869bb96a6c7f5812a594c0ce28baa1ea71" dependencies = [ "async-trait", "dashcore", @@ -4930,7 +4944,7 @@ dependencies = [ [[package]] name = "keyword-search-contract" version = "3.1.0-dev.1" -source = "git+https://github.com/dashpay/platform?rev=9d799d339f961bed5aa21d3e3e3efe9374b7929c#9d799d339f961bed5aa21d3e3e3efe9374b7929c" +source = "git+https://github.com/dashpay/platform?rev=2cc4cdcf85ce62b437031671336bf622b3aafaa5#2cc4cdcf85ce62b437031671336bf622b3aafaa5" dependencies = [ "platform-value", "platform-version", @@ -5136,7 +5150,7 @@ dependencies = [ [[package]] name = "masternode-reward-shares-contract" version = "3.1.0-dev.1" -source = "git+https://github.com/dashpay/platform?rev=9d799d339f961bed5aa21d3e3e3efe9374b7929c#9d799d339f961bed5aa21d3e3e3efe9374b7929c" +source = "git+https://github.com/dashpay/platform?rev=2cc4cdcf85ce62b437031671336bf622b3aafaa5#2cc4cdcf85ce62b437031671336bf622b3aafaa5" dependencies = [ "platform-value", "platform-version", @@ -6284,7 +6298,7 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "platform-encryption" version = "2.1.1" -source = "git+https://github.com/dashpay/platform?rev=9d799d339f961bed5aa21d3e3e3efe9374b7929c#9d799d339f961bed5aa21d3e3e3efe9374b7929c" +source = "git+https://github.com/dashpay/platform?rev=2cc4cdcf85ce62b437031671336bf622b3aafaa5#2cc4cdcf85ce62b437031671336bf622b3aafaa5" dependencies = [ "aes", "cbc", @@ -6295,7 +6309,7 @@ dependencies = [ [[package]] name = "platform-serialization" version = "3.1.0-dev.1" -source = "git+https://github.com/dashpay/platform?rev=9d799d339f961bed5aa21d3e3e3efe9374b7929c#9d799d339f961bed5aa21d3e3e3efe9374b7929c" +source = "git+https://github.com/dashpay/platform?rev=2cc4cdcf85ce62b437031671336bf622b3aafaa5#2cc4cdcf85ce62b437031671336bf622b3aafaa5" dependencies = [ "bincode 2.0.1", "platform-version", @@ -6304,7 +6318,7 @@ dependencies = [ [[package]] name = "platform-serialization-derive" version = "3.1.0-dev.1" -source = "git+https://github.com/dashpay/platform?rev=9d799d339f961bed5aa21d3e3e3efe9374b7929c#9d799d339f961bed5aa21d3e3e3efe9374b7929c" +source = "git+https://github.com/dashpay/platform?rev=2cc4cdcf85ce62b437031671336bf622b3aafaa5#2cc4cdcf85ce62b437031671336bf622b3aafaa5" dependencies = [ "proc-macro2", "quote", @@ -6315,7 +6329,7 @@ dependencies = [ [[package]] name = "platform-value" version = "3.1.0-dev.1" -source = "git+https://github.com/dashpay/platform?rev=9d799d339f961bed5aa21d3e3e3efe9374b7929c#9d799d339f961bed5aa21d3e3e3efe9374b7929c" +source = "git+https://github.com/dashpay/platform?rev=2cc4cdcf85ce62b437031671336bf622b3aafaa5#2cc4cdcf85ce62b437031671336bf622b3aafaa5" dependencies = [ "base64 0.22.1", "bincode 2.0.1", @@ -6335,7 +6349,7 @@ dependencies = [ [[package]] name = "platform-version" version = "3.1.0-dev.1" -source = "git+https://github.com/dashpay/platform?rev=9d799d339f961bed5aa21d3e3e3efe9374b7929c#9d799d339f961bed5aa21d3e3e3efe9374b7929c" +source = "git+https://github.com/dashpay/platform?rev=2cc4cdcf85ce62b437031671336bf622b3aafaa5#2cc4cdcf85ce62b437031671336bf622b3aafaa5" dependencies = [ "bincode 2.0.1", "grovedb-version 4.0.0 (git+https://github.com/dashpay/grovedb?rev=8f25b20d04bfc0e8bdfb3870676d647a0d74918b)", @@ -6346,7 +6360,7 @@ dependencies = [ [[package]] name = "platform-versioning" version = "3.1.0-dev.1" -source = "git+https://github.com/dashpay/platform?rev=9d799d339f961bed5aa21d3e3e3efe9374b7929c#9d799d339f961bed5aa21d3e3e3efe9374b7929c" +source = "git+https://github.com/dashpay/platform?rev=2cc4cdcf85ce62b437031671336bf622b3aafaa5#2cc4cdcf85ce62b437031671336bf622b3aafaa5" dependencies = [ "proc-macro2", "quote", @@ -7216,7 +7230,7 @@ dependencies = [ [[package]] name = "rs-dapi-client" version = "3.1.0-dev.1" -source = "git+https://github.com/dashpay/platform?rev=9d799d339f961bed5aa21d3e3e3efe9374b7929c#9d799d339f961bed5aa21d3e3e3efe9374b7929c" +source = "git+https://github.com/dashpay/platform?rev=2cc4cdcf85ce62b437031671336bf622b3aafaa5#2cc4cdcf85ce62b437031671336bf622b3aafaa5" dependencies = [ "backon", "chrono", @@ -7242,7 +7256,7 @@ dependencies = [ [[package]] name = "rs-sdk-trusted-context-provider" version = "3.1.0-dev.1" -source = "git+https://github.com/dashpay/platform?rev=9d799d339f961bed5aa21d3e3e3efe9374b7929c#9d799d339f961bed5aa21d3e3e3efe9374b7929c" +source = "git+https://github.com/dashpay/platform?rev=2cc4cdcf85ce62b437031671336bf622b3aafaa5#2cc4cdcf85ce62b437031671336bf622b3aafaa5" dependencies = [ "arc-swap", "dash-context-provider", @@ -7720,6 +7734,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -8471,7 +8494,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "token-history-contract" version = "3.1.0-dev.1" -source = "git+https://github.com/dashpay/platform?rev=9d799d339f961bed5aa21d3e3e3efe9374b7929c#9d799d339f961bed5aa21d3e3e3efe9374b7929c" +source = "git+https://github.com/dashpay/platform?rev=2cc4cdcf85ce62b437031671336bf622b3aafaa5#2cc4cdcf85ce62b437031671336bf622b3aafaa5" dependencies = [ "platform-value", "platform-version", @@ -8591,11 +8614,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", - "serde_spanned", + "serde_spanned 0.6.9", "toml_datetime 0.6.11", "toml_edit 0.22.27", ] +[[package]] +name = "toml" +version = "0.9.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" +dependencies = [ + "indexmap 2.13.0", + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 0.7.15", +] + [[package]] name = "toml_datetime" version = "0.6.11" @@ -8605,6 +8643,15 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_datetime" version = "1.1.0+spec-1.1.0" @@ -8633,7 +8680,7 @@ checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap 2.13.0", "serde", - "serde_spanned", + "serde_spanned 0.6.9", "toml_datetime 0.6.11", "winnow 0.7.15", ] @@ -8659,6 +8706,12 @@ dependencies = [ "winnow 1.0.0", ] +[[package]] +name = "toml_writer" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" + [[package]] name = "tonic" version = "0.14.5" @@ -9270,7 +9323,7 @@ dependencies = [ [[package]] name = "wallet-utils-contract" version = "3.1.0-dev.1" -source = "git+https://github.com/dashpay/platform?rev=9d799d339f961bed5aa21d3e3e3efe9374b7929c#9d799d339f961bed5aa21d3e3e3efe9374b7929c" +source = "git+https://github.com/dashpay/platform?rev=2cc4cdcf85ce62b437031671336bf622b3aafaa5#2cc4cdcf85ce62b437031671336bf622b3aafaa5" dependencies = [ "platform-value", "platform-version", @@ -10661,7 +10714,7 @@ dependencies = [ [[package]] name = "withdrawals-contract" version = "3.1.0-dev.1" -source = "git+https://github.com/dashpay/platform?rev=9d799d339f961bed5aa21d3e3e3efe9374b7929c#9d799d339f961bed5aa21d3e3e3efe9374b7929c" +source = "git+https://github.com/dashpay/platform?rev=2cc4cdcf85ce62b437031671336bf622b3aafaa5#2cc4cdcf85ce62b437031671336bf622b3aafaa5" dependencies = [ "num_enum 0.5.11", "platform-value", diff --git a/Cargo.toml b/Cargo.toml index 5b0be9dce..d6854d846 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ qrcode = "0.14.1" nix = { version = "0.31.1", features = ["signal"] } eframe = { version = "0.33.3", features = ["persistence", "wgpu"] } base64 = "0.22.1" -dash-sdk = { git = "https://github.com/dashpay/platform", rev = "9d799d339f961bed5aa21d3e3e3efe9374b7929c", features = [ +dash-sdk = { git = "https://github.com/dashpay/platform", rev = "2cc4cdcf85ce62b437031671336bf622b3aafaa5", features = [ "core_key_wallet", "core_key_wallet_manager", "core_bincode", @@ -28,7 +28,7 @@ dash-sdk = { git = "https://github.com/dashpay/platform", rev = "9d799d339f961be "core_spv", "shielded", ] } -rs-sdk-trusted-context-provider = { git = "https://github.com/dashpay/platform", rev = "9d799d339f961bed5aa21d3e3e3efe9374b7929c" } +rs-sdk-trusted-context-provider = { git = "https://github.com/dashpay/platform", rev = "2cc4cdcf85ce62b437031671336bf622b3aafaa5" } zip32 = "0.2.0" grovestark = { git = "https://www.github.com/dashpay/grovestark", rev = "5b9e289cca54c79b1305d5f4f40bf1148f1eb0e3" } rayon = "1.8" diff --git a/src/model/wallet/mod.rs b/src/model/wallet/mod.rs index 6646ff1d8..7897398b5 100644 --- a/src/model/wallet/mod.rs +++ b/src/model/wallet/mod.rs @@ -9,6 +9,7 @@ use crate::database::{Database, WalletError}; use crate::model::secret::Secret; use dash_sdk::dpp::ProtocolError; use dash_sdk::dpp::address_funds::{AddressWitness, PlatformAddress}; +use dash_sdk::dpp::async_trait::async_trait; use dash_sdk::dpp::identity::signer::Signer; use dash_sdk::dpp::key_wallet::account::AccountType; use dash_sdk::dpp::key_wallet::bip32::{ @@ -2644,6 +2645,7 @@ impl WalletAddressProvider { } } +#[async_trait] impl AddressProvider for WalletAddressProvider { fn gap_limit(&self) -> AddressIndex { self.gap_limit @@ -2657,7 +2659,7 @@ impl AddressProvider for WalletAddressProvider { .collect() } - fn on_address_found(&mut self, index: AddressIndex, _key: &[u8], funds: AddressFunds) { + async fn on_address_found(&mut self, index: AddressIndex, _key: &[u8], funds: AddressFunds) { self.resolved.insert(index); // Log what the SDK is returning @@ -2698,7 +2700,7 @@ impl AddressProvider for WalletAddressProvider { } } - fn on_address_absent(&mut self, index: AddressIndex, _key: &[u8]) { + async fn on_address_absent(&mut self, index: AddressIndex, _key: &[u8]) { self.resolved.insert(index); } diff --git a/src/ui/tools/masternode_list_diff_screen.rs b/src/ui/tools/masternode_list_diff_screen.rs index 542db74ec..4c040a7e2 100644 --- a/src/ui/tools/masternode_list_diff_screen.rs +++ b/src/ui/tools/masternode_list_diff_screen.rs @@ -23,14 +23,13 @@ use dash_sdk::dpp::dashcore::sml::llmq_entry_verification::LLMQEntryVerification use dash_sdk::dpp::dashcore::sml::llmq_type::LLMQType; use dash_sdk::dpp::dashcore::sml::masternode_list::MasternodeList; use dash_sdk::dpp::dashcore::sml::masternode_list_engine::{ - MasternodeListEngine, MasternodeListEngineBlockContainer, + MasternodeListEngine, MasternodeListEngineBlockContainer, QRInfoBlockData, WORK_DIFF_DEPTH, }; use dash_sdk::dpp::dashcore::sml::masternode_list_entry::EntryMasternodeType; use dash_sdk::dpp::dashcore::sml::masternode_list_entry::qualified_masternode_list_entry::QualifiedMasternodeListEntry; use dash_sdk::dpp::dashcore::sml::quorum_entry::qualified_quorum_entry::{ QualifiedQuorumEntry, VerifyingChainLockSignaturesType, }; -use dash_sdk::dpp::dashcore::sml::quorum_validation_error::ClientDataRetrievalError; use dash_sdk::dpp::dashcore::transaction::special_transaction::quorum_commitment::QuorumEntry; use dash_sdk::dpp::dashcore::{ Block, BlockHash as BlockHash2, ChainLock, InstantLock, Transaction, @@ -407,6 +406,47 @@ impl MasternodeListDiffScreen { Ok(height) } + /// Build the hash↔height bundle the engine requires in [`MasternodeListEngine::feed_qr_info`]. + /// + /// Walks the hash sets the engine enumerates from the QRInfo and resolves each from + /// our local cache first, then via Core RPC (populating the cache on success). Cycle + /// boundary blocks (`work_height + WORK_DIFF_DEPTH`) are fetched from Core by height. + fn build_qr_info_block_data(&mut self, qr_info: &QRInfo) -> Result { + let mut block_data = QRInfoBlockData::default(); + + for hash in MasternodeListEngine::qr_info_referenced_block_hashes(qr_info) { + if hash.as_byte_array() == &[0; 32] { + continue; + } + let height = self.get_height_and_cache(&hash)?; + block_data.insert_height(hash, height); + } + + for work_hash in MasternodeListEngine::qr_info_work_block_hashes(qr_info) { + if work_hash.as_byte_array() == &[0; 32] { + continue; + } + let work_height = self.get_height_and_cache(&work_hash)?; + let cycle_boundary_height = work_height + WORK_DIFF_DEPTH; + let cycle_boundary_hash = match self + .app_context + .core_client + .read() + .unwrap() + .get_block_hash(cycle_boundary_height) + { + Ok(hash) => hash, + Err(e) => return Err(e.to_string()), + }; + block_data.insert_hash(cycle_boundary_height, cycle_boundary_hash); + self.cache + .block_height_cache + .insert(cycle_boundary_hash, cycle_boundary_height); + } + + Ok(block_data) + } + #[allow(dead_code)] fn get_chain_lock_sig_and_cache( &mut self, @@ -1356,37 +1396,20 @@ impl MasternodeListDiffScreen { Some(core_p2phandler) => core_p2phandler, }; - // Extracting immutable references before calling `feed_qr_info` - let get_height_fn = { - let block_height_cache = &self.cache.block_height_cache; - let app_context = &self.app_context; - - move |block_hash: &BlockHash| { - if block_hash.as_byte_array() == &[0; 32] { - return Ok(0); - } - if let Some(height) = block_height_cache.get(block_hash) { - return Ok(*height); - } - match app_context - .core_client - .read() - .unwrap() - .get_block_header_info( - &(BlockHash2::from_byte_array(block_hash.to_byte_array())), - ) { - Ok(block_info) => Ok(block_info.height as CoreBlockHeight), - Err(_) => Err(ClientDataRetrievalError::RequiredBlockNotPresent( - *block_hash, - )), - } + // Pre-populate hash↔height data the engine needs (cycle boundary hashes are + // not carried in the QRInfo message and must be resolved locally). + let block_data = match self.build_qr_info_block_data(&qr_info) { + Ok(data) => data, + Err(e) => { + self.ui_state.error = Some(e); + return; } }; if let Err(e) = self.data .masternode_list_engine - .feed_qr_info(qr_info, false, true, Some(get_height_fn)) + .feed_qr_info(qr_info, false, true, &block_data) { self.ui_state.error = Some(e.to_string()); return; @@ -3558,7 +3581,7 @@ impl MasternodeListDiffScreen { cycle_hash )); } - for (index, commitment) in cycle_quorums.iter().enumerate() { + for (quorum_index, commitment) in cycle_quorums.iter() { // Determine the appropriate symbol based on verification status let verification_symbol = match commitment.verified { LLMQEntryVerificationStatus::Verified => "✔", // Checkmark @@ -3568,16 +3591,16 @@ impl MasternodeListDiffScreen { } // Box }; - let label_text = format!("{} Quorum at Index {}", verification_symbol, index); + let label_text = format!("{} Quorum at Index {}", verification_symbol, quorum_index); if ui .selectable_label( - self.selection.selected_qr_list_index == Some(index.to_string()), + self.selection.selected_qr_list_index == Some(quorum_index.to_string()), label_text, ) .clicked() { - self.selection.selected_qr_list_index = Some(index.to_string()); + self.selection.selected_qr_list_index = Some(quorum_index.to_string()); self.selection.selected_qr_item = Some(SelectedQRItem::QuorumEntry(Box::new(commitment.clone()))); } @@ -4241,34 +4264,20 @@ impl ScreenLike for MasternodeListDiffScreen { self.insert_mn_list_diff(d); } - // Apply to engine using the same closure as before to resolve heights - let block_height_cache = self.cache.block_height_cache.clone(); - let app_context = self.app_context.clone(); - let get_height_fn = move |block_hash: &BlockHash| { - if block_hash.as_byte_array() == &[0; 32] { - return Ok(0); - } - if let Some(height) = block_height_cache.get(block_hash) { - return Ok(*height); - } - match app_context - .core_client - .read() - .unwrap() - .get_block_header_info( - &(BlockHash2::from_byte_array(block_hash.to_byte_array())), - ) { - Ok(block_info) => Ok(block_info.height as CoreBlockHeight), - Err(_) => Err(ClientDataRetrievalError::RequiredBlockNotPresent( - *block_hash, - )), + // Pre-populate hash↔height data the engine needs (cycle boundary hashes + // are not carried in the QRInfo message and must be resolved locally). + let block_data = match self.build_qr_info_block_data(&qr_info) { + Ok(data) => data, + Err(e) => { + self.ui_state.error = Some(e); + return; } }; if let Err(e) = self.data.masternode_list_engine.feed_qr_info( qr_info.clone(), false, true, - Some(get_height_fn), + &block_data, ) { self.ui_state.error = Some(e.to_string()); } From 6aba82a3107da322e5b73f1813117e5daaec59a8 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Mon, 20 Apr 2026 16:03:15 +0200 Subject: [PATCH 2/4] fix(spv): reset filter_committed_height on Clear SPV Data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At rust-dashcore 309fac8, WalletManager gained an independent filter_committed_height field. FiltersManager::new() reads filter_committed_height() for its "already synced" guard; the field is no longer derived from synced_height. Previously clear_data_dir called update_synced_height(0), which pre-bump effectively reset both fields via the trait's default impl. Post-bump it only resets synced_height, leaving filter_committed_height at its stale previous value. FiltersManager then logs "Filters already synced to N" and skips the rescan, producing zero balance after a Clear SPV Data. Switch clear_data_dir to update_filter_committed_height(0), which unconditionally sets the field and only bumps synced_height upward if the incoming height is larger — exactly the semantics we need for a rescan-floor reset. Adds a regression test asserting filter_committed_height is lowered to 0 after clear_data_dir(). Co-Authored-By: Claude Sonnet 4.6 --- src/spv/manager.rs | 13 +++++++++---- src/spv/tests.rs | 47 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/src/spv/manager.rs b/src/spv/manager.rs index 5fbdad92e..1c442ac4d 100644 --- a/src/spv/manager.rs +++ b/src/spv/manager.rs @@ -813,14 +813,19 @@ impl SpvManager { wallet_map.clear(); } - // Reset the in-memory WalletManager's synced_height so the next SPV session - // scans filters from genesis instead of the stale height from the previous run. + // Reset the in-memory WalletManager's filter_committed_height so the next + // SPV session scans filters from genesis instead of the stale height from the + // previous run. We reset filter_committed_height (not synced_height) because at + // rust-dashcore 309fac8 these became independent fields — FiltersManager::new() + // reads filter_committed_height() for its "already synced" guard. match self.wallet.try_write() { Ok(mut wm) => { - wm.update_synced_height(0); + wm.update_filter_committed_height(0); } Err(_) => { - tracing::warn!("Failed to reset WalletManager synced_height during SPV data clear"); + tracing::warn!( + "Failed to reset WalletManager filter_committed_height during SPV data clear" + ); } } diff --git a/src/spv/tests.rs b/src/spv/tests.rs index 7b75baed9..735397f21 100644 --- a/src/spv/tests.rs +++ b/src/spv/tests.rs @@ -5,6 +5,7 @@ use crate::spv::SpvStatus; use crate::spv::manager::SpvManager; use crate::utils::tasks::TaskManager; use dash_sdk::dpp::dashcore::Network; +use dash_sdk::dpp::key_wallet_manager::WalletInterface; use std::sync::{Arc, RwLock}; use tokio::time::{Duration, timeout}; @@ -637,3 +638,49 @@ async fn test_live_testnet_sync_and_shutdown() { let _ = task_manager.shutdown(); } + +/// Regression test: clear_data_dir must reset filter_committed_height (not just synced_height). +/// +/// At rust-dashcore 309fac8, WalletManager gained an independent filter_committed_height +/// field. FiltersManager::new() reads filter_committed_height() for its "already synced" +/// guard — the field is no longer derived from synced_height. Calling update_synced_height(0) +/// alone leaves filter_committed_height stale and causes the next SPV session to declare +/// itself "already synced" and skip the rescan, producing zero balance after a Clear SPV Data. +/// +/// Given a manager with a non-zero filter_committed_height, +/// When clear_data_dir() is called, +/// Then filter_committed_height is reset to 0. +#[tokio::test(flavor = "multi_thread", worker_threads = 4)] +async fn test_clear_data_dir_resets_filter_committed_height() { + let (manager, _tm, _tmp_dir) = create_test_manager(); + + // Pre-seed a non-zero filter_committed_height to simulate a previous session. + const PRESEED_HEIGHT: u32 = 5_000; + let wallet_arc = manager.wallet(); + { + let mut wm = wallet_arc.write().await; + wm.update_filter_committed_height(PRESEED_HEIGHT); + } + + // Verify pre-condition. + { + let wm = wallet_arc.read().await; + assert_eq!( + wm.filter_committed_height(), + PRESEED_HEIGHT, + "pre-condition: filter_committed_height should be PRESEED_HEIGHT" + ); + } + + manager + .clear_data_dir() + .expect("clear_data_dir should succeed"); + + // After clearing, filter_committed_height must be 0. + let wm = wallet_arc.read().await; + assert_eq!( + wm.filter_committed_height(), + 0, + "clear_data_dir must reset filter_committed_height to 0" + ); +} From 2b16d6f752c1527c9234f98aa64431199e6c0361 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 23 Apr 2026 15:28:58 +0200 Subject: [PATCH 3/4] fix: address review feedback on skipped-rescan and QR cache - spv/manager.rs: propagate try_write() failure in clear_data_dir instead of logging-and-continuing. A contended or poisoned RwLock would have left filter_committed_height stale in memory while the on-disk data was wiped, re-triggering the exact skipped-rescan bug this PR is meant to fix. - ui/tools/masternode_list_diff_screen.rs: use get_block_hash_and_cache helper in build_qr_info_block_data so both engine block_container and caches are consulted/populated consistently; drops redundant direct RPC call and redundant block_height_cache write. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/spv/manager.rs | 20 +++++++++++--------- src/ui/tools/masternode_list_diff_screen.rs | 14 +------------- 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/src/spv/manager.rs b/src/spv/manager.rs index 1c442ac4d..5a05f871b 100644 --- a/src/spv/manager.rs +++ b/src/spv/manager.rs @@ -818,15 +818,17 @@ impl SpvManager { // previous run. We reset filter_committed_height (not synced_height) because at // rust-dashcore 309fac8 these became independent fields — FiltersManager::new() // reads filter_committed_height() for its "already synced" guard. - match self.wallet.try_write() { - Ok(mut wm) => { - wm.update_filter_committed_height(0); - } - Err(_) => { - tracing::warn!( - "Failed to reset WalletManager filter_committed_height during SPV data clear" - ); - } + // + // This must succeed before we wipe the on-disk data; otherwise the in-memory + // height would stay stale while on-disk filters are gone, re-triggering the + // skipped-rescan bug this clear is meant to prevent. + { + let mut wm = self.wallet.try_write().map_err(|e| { + format!( + "Failed to reset WalletManager filter_committed_height during SPV data clear: {e}" + ) + })?; + wm.update_filter_committed_height(0); } self.write_sync_progress(None).map_err(|e| e.to_string())?; diff --git a/src/ui/tools/masternode_list_diff_screen.rs b/src/ui/tools/masternode_list_diff_screen.rs index 4c040a7e2..aa445efdd 100644 --- a/src/ui/tools/masternode_list_diff_screen.rs +++ b/src/ui/tools/masternode_list_diff_screen.rs @@ -428,20 +428,8 @@ impl MasternodeListDiffScreen { } let work_height = self.get_height_and_cache(&work_hash)?; let cycle_boundary_height = work_height + WORK_DIFF_DEPTH; - let cycle_boundary_hash = match self - .app_context - .core_client - .read() - .unwrap() - .get_block_hash(cycle_boundary_height) - { - Ok(hash) => hash, - Err(e) => return Err(e.to_string()), - }; + let cycle_boundary_hash = self.get_block_hash_and_cache(cycle_boundary_height)?; block_data.insert_hash(cycle_boundary_height, cycle_boundary_hash); - self.cache - .block_height_cache - .insert(cycle_boundary_hash, cycle_boundary_height); } Ok(block_data) From fd8df3d3e756c0f99a03dacb95d55de104a7a24b Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 23 Apr 2026 15:53:01 +0200 Subject: [PATCH 4/4] fix(masternode-diff): clear pending task on error returns Error paths in `feed_qr_info_and_get_dmls` and the `MnListFetchedQrInfo` handler returned early after setting `ui_state.error` without clearing `self.task.pending`, leaving the pending spinner stuck after a failure. Clear `self.task.pending = None` on every error return so the UI is always returned to an idle state. Also move `build_qr_info_block_data` above the `insert_mn_list_diff` calls in the `MnListFetchedQrInfo` handler so a failure does not leave the diff cache partially populated. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/ui/tools/masternode_list_diff_screen.rs | 25 ++++++++++++--------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/ui/tools/masternode_list_diff_screen.rs b/src/ui/tools/masternode_list_diff_screen.rs index aa445efdd..dd97d2d88 100644 --- a/src/ui/tools/masternode_list_diff_screen.rs +++ b/src/ui/tools/masternode_list_diff_screen.rs @@ -1390,6 +1390,7 @@ impl MasternodeListDiffScreen { Ok(data) => data, Err(e) => { self.ui_state.error = Some(e); + self.task.pending = None; return; } }; @@ -1400,6 +1401,7 @@ impl MasternodeListDiffScreen { .feed_qr_info(qr_info, false, true, &block_data) { self.ui_state.error = Some(e.to_string()); + self.task.pending = None; return; } @@ -4239,6 +4241,19 @@ impl ScreenLike for MasternodeListDiffScreen { self.selection.selected_quorum_in_diff_index = None; } BackendTaskSuccessResult::MnListFetchedQrInfo { qr_info } => { + // Pre-populate hash↔height data the engine needs (cycle boundary hashes + // are not carried in the QRInfo message and must be resolved locally). + // Build this BEFORE inserting diffs into the cache so a failure does not + // leave the cache partially populated. + let block_data = match self.build_qr_info_block_data(&qr_info) { + Ok(data) => data, + Err(e) => { + self.ui_state.error = Some(e); + self.task.pending = None; + return; + } + }; + // Warm heights and cache diffs before feed_qr_info (replicates old flow) self.insert_mn_list_diff(&qr_info.mn_list_diff_tip); self.insert_mn_list_diff(&qr_info.mn_list_diff_h); @@ -4251,16 +4266,6 @@ impl ScreenLike for MasternodeListDiffScreen { for d in &qr_info.mn_list_diff_list { self.insert_mn_list_diff(d); } - - // Pre-populate hash↔height data the engine needs (cycle boundary hashes - // are not carried in the QRInfo message and must be resolved locally). - let block_data = match self.build_qr_info_block_data(&qr_info) { - Ok(data) => data, - Err(e) => { - self.ui_state.error = Some(e); - return; - } - }; if let Err(e) = self.data.masternode_list_engine.feed_qr_info( qr_info.clone(), false,