Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 22 additions & 22 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 8 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ members = [
]

[workspace.dependencies]
dashcore = { git = "https://github.com/dashpay/rust-dashcore", rev = "58d61ea50ac4c217c8e1350b57363b351a0b99d4" }
dash-network-seeds = { git = "https://github.com/dashpay/rust-dashcore", rev = "58d61ea50ac4c217c8e1350b57363b351a0b99d4" }
dash-spv = { git = "https://github.com/dashpay/rust-dashcore", rev = "58d61ea50ac4c217c8e1350b57363b351a0b99d4" }
key-wallet = { git = "https://github.com/dashpay/rust-dashcore", rev = "58d61ea50ac4c217c8e1350b57363b351a0b99d4" }
key-wallet-ffi = { git = "https://github.com/dashpay/rust-dashcore", rev = "58d61ea50ac4c217c8e1350b57363b351a0b99d4" }
key-wallet-manager = { git = "https://github.com/dashpay/rust-dashcore", rev = "58d61ea50ac4c217c8e1350b57363b351a0b99d4" }
dash-network = { git = "https://github.com/dashpay/rust-dashcore", rev = "58d61ea50ac4c217c8e1350b57363b351a0b99d4" }
dashcore-rpc = { git = "https://github.com/dashpay/rust-dashcore", rev = "58d61ea50ac4c217c8e1350b57363b351a0b99d4" }
dashcore = { git = "https://github.com/dashpay/rust-dashcore", rev = "eb889af13f667ed39c35e8e8a0830eeedf523476" }
dash-network-seeds = { git = "https://github.com/dashpay/rust-dashcore", rev = "eb889af13f667ed39c35e8e8a0830eeedf523476" }
dash-spv = { git = "https://github.com/dashpay/rust-dashcore", rev = "eb889af13f667ed39c35e8e8a0830eeedf523476" }
key-wallet = { git = "https://github.com/dashpay/rust-dashcore", rev = "eb889af13f667ed39c35e8e8a0830eeedf523476" }
key-wallet-ffi = { git = "https://github.com/dashpay/rust-dashcore", rev = "eb889af13f667ed39c35e8e8a0830eeedf523476" }
key-wallet-manager = { git = "https://github.com/dashpay/rust-dashcore", rev = "eb889af13f667ed39c35e8e8a0830eeedf523476" }
dash-network = { git = "https://github.com/dashpay/rust-dashcore", rev = "eb889af13f667ed39c35e8e8a0830eeedf523476" }
dashcore-rpc = { git = "https://github.com/dashpay/rust-dashcore", rev = "eb889af13f667ed39c35e8e8a0830eeedf523476" }

# Optimize heavy crypto crates even in dev/test builds so that
# Halo 2 proof generation and verification run at near-release speed.
Expand Down
38 changes: 32 additions & 6 deletions packages/rs-platform-wallet-ffi/src/spv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ use std::ffi::CStr;
use std::os::raw::c_char;

use dashcore::sml::llmq_type::LlmqDevnetParams;
use platform_wallet::spv::{ClientConfig, ProgressPercentage, SyncProgress, SyncState};
use platform_wallet::spv::{
ClientConfig, DevnetConfig, ProgressPercentage, SyncProgress, SyncState,
};

use crate::error::*;
use crate::handle::*;
Expand Down Expand Up @@ -252,6 +254,26 @@ pub unsafe extern "C" fn platform_wallet_manager_spv_start(
"devnet_name is only valid on devnet",
);
}
// Reject empty or `/`-containing names synchronously here rather
// than letting `DevnetConfig::validate` surface them asynchronously
// from `spawn_in_background`. Mirrors `DevnetConfig::validate` and
// saves callers without a pre-filter (other language bindings,
// integration tests) from a `(devnet.devnet-)` user agent that
// Dash Core peers silently drop.
if let Some(name) = devnet_name_str.as_deref() {
if name.is_empty() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Suggestion: FFI still accepts whitespace-only devnet_name values and produces a malformed devnet identity

This change only rejects name.is_empty() and name.contains('/'). A whitespace-only C string such as " " survives CStr::to_str()?.to_string(), is not empty, contains no slash, and therefore passes validation. It is then appended into the devnet user agent and passed to DevnetConfig::new(name), so the prior finding's explicit whitespace-only case is still reproducible at the exported FFI surface even though the empty-string case is fixed. Trim before validating, or treat name.trim().is_empty() as invalid so whitespace-only input is rejected synchronously like the prior finding requested.

source: unknown

return PlatformWalletFFIResult::err(
PlatformWalletFFIResultCode::ErrorInvalidParameter,
"devnet_name must not be empty",
);
}
if name.contains('/') {
return PlatformWalletFFIResult::err(
PlatformWalletFFIResultCode::ErrorInvalidParameter,
"devnet_name must not contain '/'",
);
}
}
if (llmq_devnet_size > 0) ^ (llmq_devnet_threshold > 0) {
return PlatformWalletFFIResult::err(
PlatformWalletFFIResultCode::ErrorInvalidParameter,
Expand Down Expand Up @@ -314,11 +336,15 @@ pub unsafe extern "C" fn platform_wallet_manager_spv_start(
config.peers.push(addr);
}
}
if llmq_devnet_size > 0 {
config.llmq_devnet_params = Some(LlmqDevnetParams {
size: llmq_devnet_size,
threshold: llmq_devnet_threshold,
});
if let Some(name) = devnet_name_str.as_deref() {
let mut devnet = DevnetConfig::new(name);
if llmq_devnet_size > 0 {
devnet = devnet.with_llmq_params(LlmqDevnetParams {
size: llmq_devnet_size,
threshold: llmq_devnet_threshold,
});
}
config.devnet = Some(devnet);
}

let _guard = runtime().enter();
Expand Down
2 changes: 1 addition & 1 deletion packages/rs-platform-wallet/src/spv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ pub use dash_spv::sync::{
BlockHeadersProgress, FilterHeadersProgress, FiltersProgress, MasternodesProgress,
ProgressPercentage, SyncProgress, SyncState,
};
pub use dash_spv::ClientConfig;
pub use dash_spv::{ClientConfig, DevnetConfig};
pub use tokio_util::sync::CancellationToken;
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use async_trait::async_trait;
use dashcore::ephemerealdata::chain_lock::ChainLock;
use dashcore::ephemerealdata::instant_lock::InstantLock;
use dashcore::prelude::CoreBlockHeight;
use dashcore::{Address as DashAddress, Transaction, Txid};
use dashcore::{Address as DashAddress, ScriptBuf, Transaction, Txid};

use key_wallet::account::AccountType;
use key_wallet::bip32::ExtendedPubKey;
Expand Down Expand Up @@ -97,6 +97,10 @@ impl WalletInfoInterface for PlatformWalletInfo {
self.core_wallet.monitored_addresses()
}

fn monitored_script_pubkeys(&self) -> Vec<ScriptBuf> {
self.core_wallet.monitored_script_pubkeys()
}

fn utxos(&self) -> BTreeSet<&Utxo> {
self.core_wallet.utxos()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -584,11 +584,23 @@ var body: some View {
let peers = spvPeerOverride()
let restrictToConfiguredPeers = !peers.isEmpty

// Devnet requires a name so `DevnetConfig` can embed
// `devnet.devnet-<name>` in the SPV user agent (Dash
// Core devnet peers drop inbound handshakes without it).
// Read from the same UserDefaults key OptionsView writes.
let devnetName: String? = platformState.currentNetwork == .devnet
? UserDefaults.standard.string(forKey: "platformDevnetName").flatMap {
let trimmed = $0.trimmingCharacters(in: .whitespaces)
return trimmed.isEmpty ? nil : trimmed
}
: nil

let config = PlatformSpvStartConfig(
dataDir: dataDirURL.path,
network: platformState.currentNetwork,
peers: peers,
restrictToConfiguredPeers: restrictToConfiguredPeers
restrictToConfiguredPeers: restrictToConfiguredPeers,
devnetName: devnetName
)
try walletManager.startSpv(config: config)
} catch {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ struct OptionsView: View {
// here redirects the next SDK construction.
@AppStorage("platformQuorumURL") private var devnetQuorumURL: String = ""

// Devnet identity (`-devnet=<name>` in Dash Core). Required by
// `DevnetConfig` so the SPV client embeds `devnet.devnet-<name>`
// in its user agent — Dash Core devnet peers drop inbound
// handshakes that don't carry the name. Read by SPV start in
// CoreContentView (`startSync`); editing here applies on the
// next SPV start.
@AppStorage("platformDevnetName") private var devnetName: String = ""

/// Default localhost peer string for a given network. Used to
/// pre-populate the peers text field when the user enables the
/// custom-SPV toggle. The FFI drops bare-IP entries (no port),
Expand Down Expand Up @@ -237,6 +245,22 @@ struct OptionsView: View {
Text("SPV Peers + DAPI nodes are auto-discovered from {Quorum URL}/masternodes. Changes apply on the next SDK build (switch network or relaunch).")
.font(.caption2)
.foregroundColor(.secondary)

Text("Devnet Name")
.font(.caption)
.foregroundColor(.secondary)
.padding(.top, 8)
TextField(
"e.g. paloma (matches dashd -devnet=<name>)",
text: $devnetName
)
.font(.system(.body, design: .monospaced))
.textInputAutocapitalization(.never)
.autocorrectionDisabled()

Text("Required to start SPV on devnet. The name is embedded in the SPV user agent (`devnet.devnet-<name>`) so Dash Core devnet peers accept the handshake. Applies on the next SPV start.")
.font(.caption2)
.foregroundColor(.secondary)
}
.padding(.top, 4)
} else {
Expand Down
Loading