diff --git a/Cargo.toml b/Cargo.toml index 0a3fd794d..2576be00f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = ["dash", "dash-network", "dash-network-ffi", "hashes", "internals", "f resolver = "2" [workspace.package] -version = "0.39.6" +version = "0.40.0" [patch.crates-io] dashcore_hashes = { path = "hashes" } diff --git a/dash-network-ffi/Cargo.toml b/dash-network-ffi/Cargo.toml index 873eadf76..4cab02429 100644 --- a/dash-network-ffi/Cargo.toml +++ b/dash-network-ffi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dash-network-ffi" -version.workspace = true +version = { workspace = true } edition = "2021" authors = ["Quantum Explorer "] license = "CC0-1.0" diff --git a/dash-network/README.md b/dash-network/README.md index 9aa6a7a79..dc945abd7 100644 --- a/dash-network/README.md +++ b/dash-network/README.md @@ -19,7 +19,7 @@ Add this to your `Cargo.toml`: ```toml [dependencies] -dash-network = "0.39.6" +dash-network = "0.40.0" ``` ### Basic Example diff --git a/dash-spv-ffi/Cargo.toml b/dash-spv-ffi/Cargo.toml index 1e6a5d831..c95dac4e5 100644 --- a/dash-spv-ffi/Cargo.toml +++ b/dash-spv-ffi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dash-spv-ffi" -version = "0.1.0" +version = { workspace = true } edition = "2021" authors = ["Dash Core Developers"] license = "MIT" diff --git a/dash-spv-ffi/FFI_API.md b/dash-spv-ffi/FFI_API.md index fb661feb8..03e4e18cb 100644 --- a/dash-spv-ffi/FFI_API.md +++ b/dash-spv-ffi/FFI_API.md @@ -59,7 +59,7 @@ Functions: 25 | `dash_spv_ffi_config_set_persist_mempool` | Sets whether to persist mempool state to disk # Safety - `config` must be a ... | config | | `dash_spv_ffi_config_set_relay_transactions` | Sets whether to relay transactions (currently a no-op) # Safety - `config` m... | config | | `dash_spv_ffi_config_set_start_from_height` | Sets the starting block height for synchronization # Safety - `config` must ... | config | -| `dash_spv_ffi_config_set_user_agent` | Sets the user agent string (currently not supported) # Safety - `config` mus... | config | +| `dash_spv_ffi_config_set_user_agent` | Sets the user agent string to advertise in the P2P handshake # Safety - `con... | config | | `dash_spv_ffi_config_set_validation_mode` | Sets the validation mode for the SPV client # Safety - `config` must be a va... | config | | `dash_spv_ffi_config_set_wallet_creation_time` | Sets the wallet creation timestamp for synchronization optimization # Safety... | config | | `dash_spv_ffi_config_testnet` | No description | config | @@ -555,7 +555,7 @@ dash_spv_ffi_config_set_user_agent(config: *mut FFIClientConfig, user_agent: *co ``` **Description:** -Sets the user agent string (currently not supported) # Safety - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet - `user_agent` must be a valid null-terminated C string - The caller must ensure both pointers remain valid for the duration of this call +Sets the user agent string to advertise in the P2P handshake # Safety - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet - `user_agent` must be a valid null-terminated C string - The caller must ensure both pointers remain valid for the duration of this call **Safety:** - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet - `user_agent` must be a valid null-terminated C string - The caller must ensure both pointers remain valid for the duration of this call diff --git a/dash-spv-ffi/include/dash_spv_ffi.h b/dash-spv-ffi/include/dash_spv_ffi.h index 5af7ebab3..f156d8b3e 100644 --- a/dash-spv-ffi/include/dash_spv_ffi.h +++ b/dash-spv-ffi/include/dash_spv_ffi.h @@ -518,7 +518,7 @@ int32_t dash_spv_ffi_config_add_peer(FFIClientConfig *config, const char *addr); /** - * Sets the user agent string (currently not supported) + * Sets the user agent string to advertise in the P2P handshake * * # Safety * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet diff --git a/dash-spv-ffi/src/config.rs b/dash-spv-ffi/src/config.rs index 31eb16501..60318b65c 100644 --- a/dash-spv-ffi/src/config.rs +++ b/dash-spv-ffi/src/config.rs @@ -146,7 +146,7 @@ pub unsafe extern "C" fn dash_spv_ffi_config_add_peer( } } -/// Sets the user agent string (currently not supported) +/// Sets the user agent string to advertise in the P2P handshake /// /// # Safety /// - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet @@ -162,10 +162,11 @@ pub unsafe extern "C" fn dash_spv_ffi_config_set_user_agent( // Validate the user_agent string match CStr::from_ptr(user_agent).to_str() { - Ok(_agent_str) => { - // user_agent is not directly settable in current ClientConfig - set_last_error("Setting user agent is not supported in current implementation"); - FFIErrorCode::ConfigError as i32 + Ok(agent_str) => { + // Store as-is; normalization/length capping is applied at handshake build time + let cfg = &mut (*config).inner; + cfg.user_agent = Some(agent_str.to_string()); + FFIErrorCode::Success as i32 } Err(e) => { set_last_error(&format!("Invalid UTF-8 in user agent: {}", e)); diff --git a/dash-spv-ffi/tests/test_config.rs b/dash-spv-ffi/tests/test_config.rs index 92d1e6232..4531ed109 100644 --- a/dash-spv-ffi/tests/test_config.rs +++ b/dash-spv-ffi/tests/test_config.rs @@ -127,7 +127,7 @@ mod tests { let agent = CString::new("TestAgent/1.0").unwrap(); let result = dash_spv_ffi_config_set_user_agent(config, agent.as_ptr()); - assert_eq!(result, FFIErrorCode::ConfigError as i32); + assert_eq!(result, FFIErrorCode::Success as i32); dash_spv_ffi_config_destroy(config); } diff --git a/dash-spv-ffi/tests/unit/test_configuration.rs b/dash-spv-ffi/tests/unit/test_configuration.rs index 2f4f794bc..47b68349e 100644 --- a/dash-spv-ffi/tests/unit/test_configuration.rs +++ b/dash-spv-ffi/tests/unit/test_configuration.rs @@ -185,7 +185,7 @@ mod tests { let user_agent = CString::new("TestAgent/1.0").unwrap(); assert_eq!( dash_spv_ffi_config_set_user_agent(config, user_agent.as_ptr()), - FFIErrorCode::ConfigError as i32 + FFIErrorCode::Success as i32 ); assert_eq!( diff --git a/dash-spv/Cargo.toml b/dash-spv/Cargo.toml index fffe0e2bf..b05847d11 100644 --- a/dash-spv/Cargo.toml +++ b/dash-spv/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dash-spv" -version = "0.1.0" +version = { workspace = true } edition = "2021" authors = ["Dash Core Team"] description = "Dash SPV (Simplified Payment Verification) client library" diff --git a/dash-spv/src/client/config.rs b/dash-spv/src/client/config.rs index 69736603e..3ce0862bf 100644 --- a/dash-spv/src/client/config.rs +++ b/dash-spv/src/client/config.rs @@ -69,6 +69,10 @@ pub struct ClientConfig { /// Log level for tracing. pub log_level: String, + /// Optional user agent string to advertise in the P2P version message. + /// If not set, a sensible default is used (includes crate version). + pub user_agent: Option, + /// Maximum concurrent filter requests (default: 8). pub max_concurrent_filter_requests: usize, @@ -192,6 +196,7 @@ impl Default for ClientConfig { max_peers: 8, enable_persistence: true, log_level: "info".to_string(), + user_agent: None, max_concurrent_filter_requests: 16, enable_filter_flow_control: true, filter_request_delay_ms: 0, @@ -306,6 +311,13 @@ impl ClientConfig { self } + /// Set custom user agent string for the P2P handshake. + /// The library will lightly validate and normalize it during handshake. + pub fn with_user_agent(mut self, agent: impl Into) -> Self { + self.user_agent = Some(agent.into()); + self + } + /// Set maximum concurrent filter requests. pub fn with_max_concurrent_filter_requests(mut self, max_requests: usize) -> Self { self.max_concurrent_filter_requests = max_requests; diff --git a/dash-spv/src/network/handshake.rs b/dash-spv/src/network/handshake.rs index cd24b1642..9784e870d 100644 --- a/dash-spv/src/network/handshake.rs +++ b/dash-spv/src/network/handshake.rs @@ -40,11 +40,16 @@ pub struct HandshakeManager { verack_received: bool, version_sent: bool, mempool_strategy: MempoolStrategy, + user_agent: Option, } impl HandshakeManager { /// Create a new handshake manager. - pub fn new(network: Network, mempool_strategy: MempoolStrategy) -> Self { + pub fn new( + network: Network, + mempool_strategy: MempoolStrategy, + user_agent: Option, + ) -> Self { Self { _network: network, state: HandshakeState::Init, @@ -55,6 +60,7 @@ impl HandshakeManager { verack_received: false, version_sent: false, mempool_strategy, + user_agent, } } @@ -254,6 +260,21 @@ impl HandshakeManager { .parse() .map_err(|_| NetworkError::AddressParse("Failed to parse local address".to_string()))?; + // Determine user agent: prefer configured value, else default to crate/version. + let default_agent = format!("/rust-dash-spv:{}/", env!("CARGO_PKG_VERSION")); + let mut ua = self.user_agent.clone().unwrap_or(default_agent); + // Normalize: ensure it starts and ends with '/'; trim if excessively long. + if !ua.starts_with('/') { + ua.insert(0, '/'); + } + if !ua.ends_with('/') { + ua.push('/'); + } + // Keep within a reasonable bound (match peer validation bound of 256) + if ua.len() > 256 { + ua.truncate(256); + } + Ok(VersionMessage { version: self.our_version, services, @@ -261,7 +282,7 @@ impl HandshakeManager { receiver: dashcore::network::address::Address::new(&address, ServiceFlags::NETWORK), sender: dashcore::network::address::Address::new(&local_addr, services), nonce: rand::random(), - user_agent: "/rust-dash-spv:0.1.0/".to_string(), + user_agent: ua, start_height: 0, // SPV client starts at 0 relay: match self.mempool_strategy { MempoolStrategy::FetchAll => true, // Want all transactions for FetchAll strategy diff --git a/dash-spv/src/network/mod.rs b/dash-spv/src/network/mod.rs index c7cb9e795..a05147e5c 100644 --- a/dash-spv/src/network/mod.rs +++ b/dash-spv/src/network/mod.rs @@ -168,7 +168,11 @@ impl TcpNetworkManager { Ok(Self { config: config.clone(), connection: None, - handshake: HandshakeManager::new(config.network, config.mempool_strategy), + handshake: HandshakeManager::new( + config.network, + config.mempool_strategy, + config.user_agent.clone(), + ), _message_handler: MessageHandler::new(), message_sender, dsq_preference: false, diff --git a/dash-spv/src/network/multi_peer.rs b/dash-spv/src/network/multi_peer.rs index bbbfe7f53..331e52767 100644 --- a/dash-spv/src/network/multi_peer.rs +++ b/dash-spv/src/network/multi_peer.rs @@ -66,6 +66,8 @@ pub struct MultiPeerNetworkManager { read_timeout: Duration, /// Track which peers have sent us Headers2 messages peers_sent_headers2: Arc>>, + /// Optional user agent to advertise + user_agent: Option, } impl MultiPeerNetworkManager { @@ -114,6 +116,7 @@ impl MultiPeerNetworkManager { last_message_peer: Arc::new(Mutex::new(None)), read_timeout: config.read_timeout, peers_sent_headers2: Arc::new(Mutex::new(HashSet::new())), + user_agent: config.user_agent.clone(), }) } @@ -202,6 +205,7 @@ impl MultiPeerNetworkManager { let reputation_manager = self.reputation_manager.clone(); let mempool_strategy = self.mempool_strategy; let read_timeout = self.read_timeout; + let user_agent = self.user_agent.clone(); // Spawn connection task let mut tasks = self.tasks.lock().await; @@ -213,7 +217,8 @@ impl MultiPeerNetworkManager { { Ok(mut conn) => { // Perform handshake - let mut handshake_manager = HandshakeManager::new(network, mempool_strategy); + let mut handshake_manager = + HandshakeManager::new(network, mempool_strategy, user_agent); match handshake_manager.perform_handshake(&mut conn).await { Ok(_) => { log::info!("Successfully connected to {}", addr); @@ -971,6 +976,7 @@ impl Clone for MultiPeerNetworkManager { last_message_peer: self.last_message_peer.clone(), read_timeout: self.read_timeout, peers_sent_headers2: self.peers_sent_headers2.clone(), + user_agent: self.user_agent.clone(), } } } diff --git a/dash-spv/src/network/tests.rs b/dash-spv/src/network/tests.rs index 4aa14e625..4dffa7a72 100644 --- a/dash-spv/src/network/tests.rs +++ b/dash-spv/src/network/tests.rs @@ -178,6 +178,7 @@ mod multi_peer_tests { // QRInfo fields qr_info_extra_share: true, qr_info_timeout: Duration::from_secs(30), + user_agent: None, } } diff --git a/dash-spv/tests/test_handshake_logic.rs b/dash-spv/tests/test_handshake_logic.rs index d4b3b1f58..6cc89f620 100644 --- a/dash-spv/tests/test_handshake_logic.rs +++ b/dash-spv/tests/test_handshake_logic.rs @@ -6,7 +6,7 @@ use dashcore::Network; #[test] fn test_handshake_state_transitions() { - let mut handshake = HandshakeManager::new(Network::Dash, MempoolStrategy::Selective); + let mut handshake = HandshakeManager::new(Network::Dash, MempoolStrategy::Selective, None); // Initial state should be Init assert_eq!(*handshake.state(), HandshakeState::Init); diff --git a/key-wallet-ffi/Cargo.toml b/key-wallet-ffi/Cargo.toml index 7cb307f86..9a99bdf38 100644 --- a/key-wallet-ffi/Cargo.toml +++ b/key-wallet-ffi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "key-wallet-ffi" -version = "0.39.6" +version = { workspace = true } authors = ["The Dash Core Developers"] edition = "2021" description = "FFI bindings for key-wallet library" diff --git a/key-wallet-ffi/include/key_wallet_ffi.h b/key-wallet-ffi/include/key_wallet_ffi.h index ae35cbaea..fcec5a290 100644 --- a/key-wallet-ffi/include/key_wallet_ffi.h +++ b/key-wallet-ffi/include/key_wallet_ffi.h @@ -1375,214 +1375,6 @@ FFIAccountCollectionSummary *account_collection_summary_data(const FFIAccountCol void account_collection_summary_free(FFIAccountCollectionSummary *summary) ; -/* - Free address string - - # Safety - - - `address` must be a valid pointer created by address functions or null - - After calling this function, the pointer becomes invalid - */ - void address_free(char *address) ; - -/* - Free address array - - # Safety - - - `addresses` must be a valid pointer to an array of address strings or null - - Each address in the array must be a valid C string pointer - - `count` must be the correct number of addresses in the array - - After calling this function, all pointers become invalid - */ - void address_array_free(char **addresses, size_t count) ; - -/* - Validate an address - - # Safety - - - `address` must be a valid null-terminated C string - - `error` must be a valid pointer to an FFIError - */ - bool address_validate(const char *address, FFINetwork network, FFIError *error) ; - -/* - Get address type - - Returns: - - 0: P2PKH address - - 1: P2SH address - - 2: Other address type - - u8::MAX (255): Error occurred - - # Safety - - - `address` must be a valid null-terminated C string - - `error` must be a valid pointer to an FFIError - */ - unsigned char address_get_type(const char *address, FFINetwork network, FFIError *error) ; - -/* - Free an address pool handle - - # Safety - - - `pool` must be a valid pointer to an FFIAddressPool that was allocated by this library - - The pointer must not be used after calling this function - - This function must only be called once per allocation - */ - void address_pool_free(FFIAddressPool *pool) ; - -/* - Get address pool information for an account - - # Safety - - - `managed_wallet` must be a valid pointer to an FFIManagedWallet - - `info_out` must be a valid pointer to store the pool info - - `error` must be a valid pointer to an FFIError or null - */ - -bool managed_wallet_get_address_pool_info(const FFIManagedWallet *managed_wallet, - FFINetwork network, - FFIAccountType account_type, - unsigned int account_index, - FFIAddressPoolType pool_type, - FFIAddressPoolInfo *info_out, - FFIError *error) -; - -/* - Set the gap limit for an address pool - - The gap limit determines how many unused addresses to maintain at the end - of the pool. This is important for wallet recovery and address discovery. - - # Safety - - - `managed_wallet` must be a valid pointer to an FFIManagedWallet - - `error` must be a valid pointer to an FFIError or null - */ - -bool managed_wallet_set_gap_limit(FFIManagedWallet *managed_wallet, - FFINetwork network, - FFIAccountType account_type, - unsigned int account_index, - FFIAddressPoolType pool_type, - unsigned int gap_limit, - FFIError *error) -; - -/* - Generate addresses up to a specific index in a pool - - This ensures that addresses up to and including the specified index exist - in the pool. This is useful for wallet recovery or when specific indices - are needed. - - # Safety - - - `managed_wallet` must be a valid pointer to an FFIManagedWallet - - `wallet` must be a valid pointer to an FFIWallet (for key derivation) - - `error` must be a valid pointer to an FFIError or null - */ - -bool managed_wallet_generate_addresses_to_index(FFIManagedWallet *managed_wallet, - const FFIWallet *wallet, - FFINetwork network, - FFIAccountType account_type, - unsigned int account_index, - FFIAddressPoolType pool_type, - unsigned int target_index, - FFIError *error) -; - -/* - Mark an address as used in the pool - - This updates the pool's tracking of which addresses have been used, - which is important for gap limit management and wallet recovery. - - # Safety - - - `managed_wallet` must be a valid pointer to an FFIManagedWallet - - `address` must be a valid C string - - `error` must be a valid pointer to an FFIError or null - */ - -bool managed_wallet_mark_address_used(FFIManagedWallet *managed_wallet, - FFINetwork network, - const char *address, - FFIError *error) -; - -/* - Get a single address info at a specific index from the pool - - Returns detailed information about the address at the given index, or NULL - if the index is out of bounds or not generated yet. - - # Safety - - - `pool` must be a valid pointer to an FFIAddressPool - - `error` must be a valid pointer to an FFIError or null - - The returned FFIAddressInfo must be freed using `address_info_free` - */ - -FFIAddressInfo *address_pool_get_address_at_index(const FFIAddressPool *pool, - uint32_t index, - FFIError *error) -; - -/* - Get a range of addresses from the pool - - Returns an array of FFIAddressInfo structures for addresses in the range [start_index, end_index). - The count_out parameter will be set to the actual number of addresses returned. - - Note: This function only reads existing addresses from the pool. It does not generate new addresses. - Use managed_wallet_generate_addresses_to_index if you need to generate addresses first. - - # Safety - - - `pool` must be a valid pointer to an FFIAddressPool - - `count_out` must be a valid pointer to store the count - - `error` must be a valid pointer to an FFIError or null - - The returned array must be freed using `address_info_array_free` - */ - -FFIAddressInfo **address_pool_get_addresses_in_range(const FFIAddressPool *pool, - uint32_t start_index, - uint32_t end_index, - size_t *count_out, - FFIError *error) -; - -/* - Free a single FFIAddressInfo structure - - # Safety - - - `info` must be a valid pointer to an FFIAddressInfo allocated by this library or null - - The pointer must not be used after calling this function - */ - void address_info_free(FFIAddressInfo *info) ; - -/* - Free an array of FFIAddressInfo structures - - # Safety - - - `infos` must be a valid pointer to an array of FFIAddressInfo pointers allocated by this library or null - - `count` must be the exact number of elements in the array - - The pointers must not be used after calling this function - */ - -void address_info_array_free(FFIAddressInfo **infos, - size_t count) -; - /* Derive an extended private key from an account at a given index, using the provided master xpriv. @@ -1801,6 +1593,214 @@ FFIPrivateKey *account_derive_private_key_from_mnemonic(const FFIAccount *accoun FFIError *error) ; +/* + Free address string + + # Safety + + - `address` must be a valid pointer created by address functions or null + - After calling this function, the pointer becomes invalid + */ + void address_free(char *address) ; + +/* + Free address array + + # Safety + + - `addresses` must be a valid pointer to an array of address strings or null + - Each address in the array must be a valid C string pointer + - `count` must be the correct number of addresses in the array + - After calling this function, all pointers become invalid + */ + void address_array_free(char **addresses, size_t count) ; + +/* + Validate an address + + # Safety + + - `address` must be a valid null-terminated C string + - `error` must be a valid pointer to an FFIError + */ + bool address_validate(const char *address, FFINetwork network, FFIError *error) ; + +/* + Get address type + + Returns: + - 0: P2PKH address + - 1: P2SH address + - 2: Other address type + - u8::MAX (255): Error occurred + + # Safety + + - `address` must be a valid null-terminated C string + - `error` must be a valid pointer to an FFIError + */ + unsigned char address_get_type(const char *address, FFINetwork network, FFIError *error) ; + +/* + Free an address pool handle + + # Safety + + - `pool` must be a valid pointer to an FFIAddressPool that was allocated by this library + - The pointer must not be used after calling this function + - This function must only be called once per allocation + */ + void address_pool_free(FFIAddressPool *pool) ; + +/* + Get address pool information for an account + + # Safety + + - `managed_wallet` must be a valid pointer to an FFIManagedWallet + - `info_out` must be a valid pointer to store the pool info + - `error` must be a valid pointer to an FFIError or null + */ + +bool managed_wallet_get_address_pool_info(const FFIManagedWallet *managed_wallet, + FFINetwork network, + FFIAccountType account_type, + unsigned int account_index, + FFIAddressPoolType pool_type, + FFIAddressPoolInfo *info_out, + FFIError *error) +; + +/* + Set the gap limit for an address pool + + The gap limit determines how many unused addresses to maintain at the end + of the pool. This is important for wallet recovery and address discovery. + + # Safety + + - `managed_wallet` must be a valid pointer to an FFIManagedWallet + - `error` must be a valid pointer to an FFIError or null + */ + +bool managed_wallet_set_gap_limit(FFIManagedWallet *managed_wallet, + FFINetwork network, + FFIAccountType account_type, + unsigned int account_index, + FFIAddressPoolType pool_type, + unsigned int gap_limit, + FFIError *error) +; + +/* + Generate addresses up to a specific index in a pool + + This ensures that addresses up to and including the specified index exist + in the pool. This is useful for wallet recovery or when specific indices + are needed. + + # Safety + + - `managed_wallet` must be a valid pointer to an FFIManagedWallet + - `wallet` must be a valid pointer to an FFIWallet (for key derivation) + - `error` must be a valid pointer to an FFIError or null + */ + +bool managed_wallet_generate_addresses_to_index(FFIManagedWallet *managed_wallet, + const FFIWallet *wallet, + FFINetwork network, + FFIAccountType account_type, + unsigned int account_index, + FFIAddressPoolType pool_type, + unsigned int target_index, + FFIError *error) +; + +/* + Mark an address as used in the pool + + This updates the pool's tracking of which addresses have been used, + which is important for gap limit management and wallet recovery. + + # Safety + + - `managed_wallet` must be a valid pointer to an FFIManagedWallet + - `address` must be a valid C string + - `error` must be a valid pointer to an FFIError or null + */ + +bool managed_wallet_mark_address_used(FFIManagedWallet *managed_wallet, + FFINetwork network, + const char *address, + FFIError *error) +; + +/* + Get a single address info at a specific index from the pool + + Returns detailed information about the address at the given index, or NULL + if the index is out of bounds or not generated yet. + + # Safety + + - `pool` must be a valid pointer to an FFIAddressPool + - `error` must be a valid pointer to an FFIError or null + - The returned FFIAddressInfo must be freed using `address_info_free` + */ + +FFIAddressInfo *address_pool_get_address_at_index(const FFIAddressPool *pool, + uint32_t index, + FFIError *error) +; + +/* + Get a range of addresses from the pool + + Returns an array of FFIAddressInfo structures for addresses in the range [start_index, end_index). + The count_out parameter will be set to the actual number of addresses returned. + + Note: This function only reads existing addresses from the pool. It does not generate new addresses. + Use managed_wallet_generate_addresses_to_index if you need to generate addresses first. + + # Safety + + - `pool` must be a valid pointer to an FFIAddressPool + - `count_out` must be a valid pointer to store the count + - `error` must be a valid pointer to an FFIError or null + - The returned array must be freed using `address_info_array_free` + */ + +FFIAddressInfo **address_pool_get_addresses_in_range(const FFIAddressPool *pool, + uint32_t start_index, + uint32_t end_index, + size_t *count_out, + FFIError *error) +; + +/* + Free a single FFIAddressInfo structure + + # Safety + + - `info` must be a valid pointer to an FFIAddressInfo allocated by this library or null + - The pointer must not be used after calling this function + */ + void address_info_free(FFIAddressInfo *info) ; + +/* + Free an array of FFIAddressInfo structures + + # Safety + + - `infos` must be a valid pointer to an array of FFIAddressInfo pointers allocated by this library or null + - `count` must be the exact number of elements in the array + - The pointers must not be used after calling this function + */ + +void address_info_array_free(FFIAddressInfo **infos, + size_t count) +; + /* Create a new master extended private key from seed diff --git a/key-wallet-manager/Cargo.toml b/key-wallet-manager/Cargo.toml index eeabee5f7..1293fed1f 100644 --- a/key-wallet-manager/Cargo.toml +++ b/key-wallet-manager/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "key-wallet-manager" -version = "0.1.0" +version = { workspace = true } authors = ["The Dash Core Developers"] edition = "2021" description = "High-level wallet management for Dash using key-wallet primitives" diff --git a/key-wallet/Cargo.toml b/key-wallet/Cargo.toml index 0023939ea..99d755fc3 100644 --- a/key-wallet/Cargo.toml +++ b/key-wallet/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "key-wallet" -version = "0.40.0-dev" +version = { workspace = true } authors = ["The Dash Core Developers"] edition = "2021" description = "Key derivation and wallet functionality for Dash" diff --git a/swift-dash-core-sdk/Sources/DashSPVFFI/include/dash_spv_ffi.h b/swift-dash-core-sdk/Sources/DashSPVFFI/include/dash_spv_ffi.h index 6b00b1311..d58a1c940 100644 --- a/swift-dash-core-sdk/Sources/DashSPVFFI/include/dash_spv_ffi.h +++ b/swift-dash-core-sdk/Sources/DashSPVFFI/include/dash_spv_ffi.h @@ -387,7 +387,7 @@ int32_t dash_spv_ffi_config_add_peer(FFIClientConfig *config, const char *addr); /** - * Sets the user agent string (currently not supported) + * Sets the user agent string to advertise in the P2P handshake * * # Safety * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet diff --git a/swift-dash-core-sdk/Sources/SwiftDashCoreSDK/Core/SPVClientConfiguration.swift b/swift-dash-core-sdk/Sources/SwiftDashCoreSDK/Core/SPVClientConfiguration.swift index 885bd1d47..df677d179 100644 --- a/swift-dash-core-sdk/Sources/SwiftDashCoreSDK/Core/SPVClientConfiguration.swift +++ b/swift-dash-core-sdk/Sources/SwiftDashCoreSDK/Core/SPVClientConfiguration.swift @@ -84,11 +84,11 @@ public final class SPVClientConfiguration { result = dash_spv_ffi_config_set_max_peers(config, maxPeers) try FFIBridge.checkError(result) - // User agent setting is not supported in current implementation - // result = FFIBridge.withCString(userAgent) { agent in - // dash_spv_ffi_config_set_user_agent(config, agent) - // } - // try FFIBridge.checkError(result) + // Configure user agent advertised during P2P handshake + result = FFIBridge.withCString(userAgent) { agent in + dash_spv_ffi_config_set_user_agent(config, agent) + } + try FFIBridge.checkError(result) result = dash_spv_ffi_config_set_filter_load(config, enableFilterLoad) try FFIBridge.checkError(result)