Skip to content

Commit 1e5eb0b

Browse files
feat: add functions to update client configuration and enable masternodes (#130)
* feat: add functions to update client configuration and enable masternode sync * fmt * clippy fixes
1 parent 018a32a commit 1e5eb0b

File tree

7 files changed

+216
-58
lines changed

7 files changed

+216
-58
lines changed

dash-spv-ffi/FFI_API.md

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ This document provides a comprehensive reference for all FFI (Foreign Function I
44

55
**Auto-generated**: This documentation is automatically generated from the source code. Do not edit manually.
66

7-
**Total Functions**: 61
7+
**Total Functions**: 63
88

99
## Table of Contents
1010

@@ -34,10 +34,11 @@ Functions: 4
3434

3535
### Configuration
3636

37-
Functions: 23
37+
Functions: 25
3838

3939
| Function | Description | Module |
4040
|----------|-------------|--------|
41+
| `dash_spv_ffi_client_update_config` | Update the running client's configuration | client |
4142
| `dash_spv_ffi_config_add_peer` | Adds a peer address to the configuration # Safety - `config` must be a valid... | config |
4243
| `dash_spv_ffi_config_destroy` | Destroys an FFIClientConfig and frees its memory # Safety - `config` must be... | config |
4344
| `dash_spv_ffi_config_get_data_dir` | Gets the data directory path from the configuration # Safety - `config` must... | config |
@@ -49,6 +50,7 @@ Functions: 23
4950
| `dash_spv_ffi_config_set_data_dir` | Sets the data directory for storing blockchain data # Safety - `config` must... | config |
5051
| `dash_spv_ffi_config_set_fetch_mempool_transactions` | Sets whether to fetch full mempool transaction data # Safety - `config` must... | config |
5152
| `dash_spv_ffi_config_set_filter_load` | Sets whether to load bloom filters # Safety - `config` must be a valid point... | config |
53+
| `dash_spv_ffi_config_set_masternode_sync_enabled` | Enables or disables masternode synchronization # Safety - `config` must be a... | config |
5254
| `dash_spv_ffi_config_set_max_mempool_transactions` | Sets the maximum number of mempool transactions to track # Safety - `config`... | config |
5355
| `dash_spv_ffi_config_set_max_peers` | Sets the maximum number of peers to connect to # Safety - `config` must be a... | config |
5456
| `dash_spv_ffi_config_set_mempool_strategy` | Sets the mempool synchronization strategy # Safety - `config` must be a vali... | config |
@@ -198,6 +200,22 @@ dash_spv_ffi_client_stop(client: *mut FFIDashSpvClient) -> i32
198200

199201
### Configuration - Detailed
200202

203+
#### `dash_spv_ffi_client_update_config`
204+
205+
```c
206+
dash_spv_ffi_client_update_config(client: *mut FFIDashSpvClient, config: *const FFIClientConfig,) -> i32
207+
```
208+
209+
**Description:**
210+
Update the running client's configuration. # Safety - `client` must be a valid pointer to an `FFIDashSpvClient`. - `config` must be a valid pointer to an `FFIClientConfig`. - The network in `config` must match the client's network; changing networks at runtime is not supported.
211+
212+
**Safety:**
213+
- `client` must be a valid pointer to an `FFIDashSpvClient`. - `config` must be a valid pointer to an `FFIClientConfig`. - The network in `config` must match the client's network; changing networks at runtime is not supported.
214+
215+
**Module:** `client`
216+
217+
---
218+
201219
#### `dash_spv_ffi_config_add_peer`
202220
203221
```c
@@ -362,6 +380,22 @@ Sets whether to load bloom filters # Safety - `config` must be a valid pointer
362380

363381
---
364382

383+
#### `dash_spv_ffi_config_set_masternode_sync_enabled`
384+
385+
```c
386+
dash_spv_ffi_config_set_masternode_sync_enabled(config: *mut FFIClientConfig, enable: bool,) -> i32
387+
```
388+
389+
**Description:**
390+
Enables or disables masternode synchronization # Safety - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet - The caller must ensure the config pointer remains valid for the duration of this call
391+
392+
**Safety:**
393+
- `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet - The caller must ensure the config pointer remains valid for the duration of this call
394+
395+
**Module:** `config`
396+
397+
---
398+
365399
#### `dash_spv_ffi_config_set_max_mempool_transactions`
366400
367401
```c

dash-spv-ffi/include/dash_spv_ffi.h

Lines changed: 83 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,25 @@ typedef enum FFIValidationMode {
3030
*/
3131
typedef struct FFIDashSpvClient FFIDashSpvClient;
3232

33+
/**
34+
* FFI-safe array that transfers ownership of memory to the C caller.
35+
*
36+
* # Safety
37+
*
38+
* This struct represents memory that has been allocated by Rust but ownership
39+
* has been transferred to the C caller. The caller is responsible for:
40+
* - Not accessing the memory after it has been freed
41+
* - Calling `dash_spv_ffi_array_destroy` to properly deallocate the memory
42+
* - Ensuring the data, len, and capacity fields remain consistent
43+
*/
44+
typedef struct FFIArray {
45+
void *data;
46+
uintptr_t len;
47+
uintptr_t capacity;
48+
uintptr_t elem_size;
49+
uintptr_t elem_align;
50+
} FFIArray;
51+
3352
typedef ClientConfig FFIClientConfig;
3453

3554
typedef struct FFIString {
@@ -129,25 +148,6 @@ typedef struct FFIEventCallbacks {
129148
void *user_data;
130149
} FFIEventCallbacks;
131150

132-
/**
133-
* FFI-safe array that transfers ownership of memory to the C caller.
134-
*
135-
* # Safety
136-
*
137-
* This struct represents memory that has been allocated by Rust but ownership
138-
* has been transferred to the C caller. The caller is responsible for:
139-
* - Not accessing the memory after it has been freed
140-
* - Calling `dash_spv_ffi_array_destroy` to properly deallocate the memory
141-
* - Ensuring the data, len, and capacity fields remain consistent
142-
*/
143-
typedef struct FFIArray {
144-
void *data;
145-
uintptr_t len;
146-
uintptr_t capacity;
147-
uintptr_t elem_size;
148-
uintptr_t elem_align;
149-
} FFIArray;
150-
151151
/**
152152
* Handle for Core SDK that can be passed to Platform SDK
153153
*/
@@ -196,8 +196,62 @@ typedef struct FFIUnconfirmedTransaction {
196196
uintptr_t addresses_len;
197197
} FFIUnconfirmedTransaction;
198198

199+
/**
200+
* Get the latest checkpoint for the given network.
201+
*
202+
* # Safety
203+
* - `out_height` must be a valid pointer to a `u32`.
204+
* - `out_hash` must point to at least 32 writable bytes.
205+
*/
206+
int32_t dash_spv_ffi_checkpoint_latest(FFINetwork network, uint32_t *out_height, uint8_t *out_hash);
207+
208+
/**
209+
* Get the last checkpoint at or before a given height.
210+
*
211+
* # Safety
212+
* - `out_height` must be a valid pointer to a `u32`.
213+
* - `out_hash` must point to at least 32 writable bytes.
214+
*/
215+
int32_t dash_spv_ffi_checkpoint_before_height(FFINetwork network,
216+
uint32_t height,
217+
uint32_t *out_height,
218+
uint8_t *out_hash);
219+
220+
/**
221+
* Get the last checkpoint at or before a given UNIX timestamp (seconds).
222+
*
223+
* # Safety
224+
* - `out_height` must be a valid pointer to a `u32`.
225+
* - `out_hash` must point to at least 32 writable bytes.
226+
*/
227+
int32_t dash_spv_ffi_checkpoint_before_timestamp(FFINetwork network,
228+
uint32_t timestamp,
229+
uint32_t *out_height,
230+
uint8_t *out_hash);
231+
232+
/**
233+
* Get all checkpoints between two heights (inclusive).
234+
*
235+
* Returns an `FFIArray` of `FFICheckpoint` items. The caller owns the memory and
236+
* must free the array buffer using `dash_spv_ffi_array_destroy` when done.
237+
*/
238+
struct FFIArray dash_spv_ffi_checkpoints_between_heights(FFINetwork network,
239+
uint32_t start_height,
240+
uint32_t end_height);
241+
199242
struct FFIDashSpvClient *dash_spv_ffi_client_new(const FFIClientConfig *config);
200243

244+
/**
245+
* Update the running client's configuration.
246+
*
247+
* # Safety
248+
* - `client` must be a valid pointer to an `FFIDashSpvClient`.
249+
* - `config` must be a valid pointer to an `FFIClientConfig`.
250+
* - The network in `config` must match the client's network; changing networks at runtime is not supported.
251+
*/
252+
int32_t dash_spv_ffi_client_update_config(struct FFIDashSpvClient *client,
253+
const FFIClientConfig *config);
254+
201255
int32_t dash_spv_ffi_client_start(struct FFIDashSpvClient *client);
202256

203257
int32_t dash_spv_ffi_client_stop(struct FFIDashSpvClient *client);
@@ -414,6 +468,16 @@ int32_t dash_spv_ffi_config_set_relay_transactions(FFIClientConfig *config,
414468
int32_t dash_spv_ffi_config_set_filter_load(FFIClientConfig *config,
415469
bool load_filters);
416470

471+
/**
472+
* Enables or disables masternode synchronization
473+
*
474+
* # Safety
475+
* - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet
476+
* - The caller must ensure the config pointer remains valid for the duration of this call
477+
*/
478+
int32_t dash_spv_ffi_config_set_masternode_sync_enabled(FFIClientConfig *config,
479+
bool enable);
480+
417481
/**
418482
* Gets the network type from the configuration
419483
*
@@ -541,22 +605,6 @@ int32_t dash_spv_ffi_config_set_start_from_height(FFIClientConfig *config,
541605
int32_t dash_spv_ffi_config_set_wallet_creation_time(FFIClientConfig *config,
542606
uint32_t timestamp);
543607

544-
int32_t dash_spv_ffi_checkpoint_latest(FFINetwork network, uint32_t *out_height, uint8_t *out_hash);
545-
546-
int32_t dash_spv_ffi_checkpoint_before_height(FFINetwork network,
547-
uint32_t height,
548-
uint32_t *out_height,
549-
uint8_t *out_hash);
550-
551-
int32_t dash_spv_ffi_checkpoint_before_timestamp(FFINetwork network,
552-
uint32_t timestamp,
553-
uint32_t *out_height,
554-
uint8_t *out_hash);
555-
556-
struct FFIArray dash_spv_ffi_checkpoints_between_heights(FFINetwork network,
557-
uint32_t start_height,
558-
uint32_t end_height);
559-
560608
const char *dash_spv_ffi_get_last_error(void);
561609

562610
void dash_spv_ffi_clear_error(void);

dash-spv-ffi/src/checkpoints.rs

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{set_last_error, FFIArray, FFIErrorCode};
22
use dash_spv::chain::checkpoints::{mainnet_checkpoints, testnet_checkpoints, CheckpointManager};
3-
use dashcore::Network;
43
use dashcore::hashes::Hash;
4+
use dashcore::Network;
55
use key_wallet_ffi::FFINetwork;
66

77
/// FFI representation of a checkpoint (height + block hash)
@@ -26,7 +26,7 @@ fn manager_for_network(network: FFINetwork) -> Result<CheckpointManager, String>
2626
/// - `out_height` must be a valid pointer to a `u32`.
2727
/// - `out_hash` must point to at least 32 writable bytes.
2828
#[no_mangle]
29-
pub extern "C" fn dash_spv_ffi_checkpoint_latest(
29+
pub unsafe extern "C" fn dash_spv_ffi_checkpoint_latest(
3030
network: FFINetwork,
3131
out_height: *mut u32,
3232
out_hash: *mut u8, // expects at least 32 bytes
@@ -43,11 +43,9 @@ pub extern "C" fn dash_spv_ffi_checkpoint_latest(
4343
}
4444
};
4545
if let Some(cp) = mgr.last_checkpoint() {
46-
unsafe {
47-
*out_height = cp.height;
48-
let hash = cp.block_hash.to_byte_array();
49-
std::ptr::copy_nonoverlapping(hash.as_ptr(), out_hash, 32);
50-
}
46+
*out_height = cp.height;
47+
let hash = cp.block_hash.to_byte_array();
48+
std::ptr::copy_nonoverlapping(hash.as_ptr(), out_hash, 32);
5149
FFIErrorCode::Success as i32
5250
} else {
5351
set_last_error("No checkpoints available for network");
@@ -61,7 +59,7 @@ pub extern "C" fn dash_spv_ffi_checkpoint_latest(
6159
/// - `out_height` must be a valid pointer to a `u32`.
6260
/// - `out_hash` must point to at least 32 writable bytes.
6361
#[no_mangle]
64-
pub extern "C" fn dash_spv_ffi_checkpoint_before_height(
62+
pub unsafe extern "C" fn dash_spv_ffi_checkpoint_before_height(
6563
network: FFINetwork,
6664
height: u32,
6765
out_height: *mut u32,
@@ -79,11 +77,9 @@ pub extern "C" fn dash_spv_ffi_checkpoint_before_height(
7977
}
8078
};
8179
if let Some(cp) = mgr.last_checkpoint_before_height(height) {
82-
unsafe {
83-
*out_height = cp.height;
84-
let hash = cp.block_hash.to_byte_array();
85-
std::ptr::copy_nonoverlapping(hash.as_ptr(), out_hash, 32);
86-
}
80+
*out_height = cp.height;
81+
let hash = cp.block_hash.to_byte_array();
82+
std::ptr::copy_nonoverlapping(hash.as_ptr(), out_hash, 32);
8783
FFIErrorCode::Success as i32
8884
} else {
8985
set_last_error("No checkpoint at or before given height");
@@ -97,7 +93,7 @@ pub extern "C" fn dash_spv_ffi_checkpoint_before_height(
9793
/// - `out_height` must be a valid pointer to a `u32`.
9894
/// - `out_hash` must point to at least 32 writable bytes.
9995
#[no_mangle]
100-
pub extern "C" fn dash_spv_ffi_checkpoint_before_timestamp(
96+
pub unsafe extern "C" fn dash_spv_ffi_checkpoint_before_timestamp(
10197
network: FFINetwork,
10298
timestamp: u32,
10399
out_height: *mut u32,
@@ -115,11 +111,9 @@ pub extern "C" fn dash_spv_ffi_checkpoint_before_timestamp(
115111
}
116112
};
117113
if let Some(cp) = mgr.last_checkpoint_before_timestamp(timestamp) {
118-
unsafe {
119-
*out_height = cp.height;
120-
let hash = cp.block_hash.to_byte_array();
121-
std::ptr::copy_nonoverlapping(hash.as_ptr(), out_hash, 32);
122-
}
114+
*out_height = cp.height;
115+
let hash = cp.block_hash.to_byte_array();
116+
std::ptr::copy_nonoverlapping(hash.as_ptr(), out_hash, 32);
123117
FFIErrorCode::Success as i32
124118
} else {
125119
set_last_error("No checkpoint at or before given timestamp");

dash-spv-ffi/src/client.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,41 @@ impl FFIDashSpvClient {
339339
}
340340
}
341341

342+
/// Update the running client's configuration.
343+
///
344+
/// # Safety
345+
/// - `client` must be a valid pointer to an `FFIDashSpvClient`.
346+
/// - `config` must be a valid pointer to an `FFIClientConfig`.
347+
/// - The network in `config` must match the client's network; changing networks at runtime is not supported.
348+
#[no_mangle]
349+
pub unsafe extern "C" fn dash_spv_ffi_client_update_config(
350+
client: *mut FFIDashSpvClient,
351+
config: *const FFIClientConfig,
352+
) -> i32 {
353+
null_check!(client);
354+
null_check!(config);
355+
356+
let client = &(*client);
357+
let new_config = (&*config).clone_inner();
358+
359+
let result = client.runtime.block_on(async {
360+
let mut guard = client.inner.lock().unwrap();
361+
if let Some(ref mut spv_client) = *guard {
362+
spv_client.update_config(new_config).await.map_err(|e| e)
363+
} else {
364+
Err(dash_spv::SpvError::Config("Client not initialized".to_string()))
365+
}
366+
});
367+
368+
match result {
369+
Ok(()) => FFIErrorCode::Success as i32,
370+
Err(e) => {
371+
set_last_error(&e.to_string());
372+
FFIErrorCode::from(e) as i32
373+
}
374+
}
375+
}
376+
342377
#[no_mangle]
343378
pub unsafe extern "C" fn dash_spv_ffi_client_start(client: *mut FFIDashSpvClient) -> i32 {
344379
null_check!(client);

dash-spv-ffi/src/config.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,23 @@ pub unsafe extern "C" fn dash_spv_ffi_config_set_filter_load(
208208
FFIErrorCode::Success as i32
209209
}
210210

211+
/// Enables or disables masternode synchronization
212+
///
213+
/// # Safety
214+
/// - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet
215+
/// - The caller must ensure the config pointer remains valid for the duration of this call
216+
#[no_mangle]
217+
pub unsafe extern "C" fn dash_spv_ffi_config_set_masternode_sync_enabled(
218+
config: *mut FFIClientConfig,
219+
enable: bool,
220+
) -> i32 {
221+
null_check!(config);
222+
223+
let config = &mut (*config).inner;
224+
config.enable_masternodes = enable;
225+
FFIErrorCode::Success as i32
226+
}
227+
211228
/// Gets the network type from the configuration
212229
///
213230
/// # Safety

dash-spv-ffi/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
pub mod callbacks;
2+
pub mod checkpoints;
23
pub mod client;
34
pub mod config;
4-
pub mod checkpoints;
55
pub mod error;
66
pub mod platform_integration;
77
pub mod types;
88
pub mod utils;
99

1010
pub use callbacks::*;
11+
pub use checkpoints::*;
1112
pub use client::*;
1213
pub use config::*;
13-
pub use checkpoints::*;
1414
pub use error::*;
1515
pub use platform_integration::*;
1616
pub use types::*;

0 commit comments

Comments
 (0)