Skip to content
Merged
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
27 changes: 5 additions & 22 deletions dash-spv-ffi/FFI_API.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This document provides a comprehensive reference for all FFI (Foreign Function I

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

**Total Functions**: 49
**Total Functions**: 48

## Table of Contents

Expand All @@ -22,13 +22,12 @@ This document provides a comprehensive reference for all FFI (Foreign Function I

### Client Management

Functions: 4
Functions: 3

| Function | Description | Module |
|----------|-------------|--------|
| `dash_spv_ffi_client_destroy` | Destroy the client and free associated resources | client |
| `dash_spv_ffi_client_new` | Create a new SPV client and return an opaque pointer | client |
| `dash_spv_ffi_client_start` | Start the SPV client | client |
| `dash_spv_ffi_client_stop` | Stop the SPV client | client |

### Configuration
Expand Down Expand Up @@ -168,22 +167,6 @@ Create a new SPV client and return an opaque pointer. # Safety - `config` must

---

#### `dash_spv_ffi_client_start`

```c
dash_spv_ffi_client_start(client: *mut FFIDashSpvClient) -> i32
```

**Description:**
Start the SPV client. # Safety - `client` must be a valid, non-null pointer to a created client.

**Safety:**
- `client` must be a valid, non-null pointer to a created client.

**Module:** `client`

---

#### `dash_spv_ffi_client_stop`

```c
Expand Down Expand Up @@ -791,7 +774,7 @@ dash_spv_ffi_client_run(client: *mut FFIDashSpvClient) -> i32
```

**Description:**
Start the SPV client and begin syncing in the background. This is the streamlined entry point that combines `start()` and continuous monitoring into a single non-blocking call. Use event callbacks (set via `set_sync_event_callbacks`, `set_network_event_callbacks`, `set_wallet_event_callbacks`) to receive notifications about sync progress, peer connections, and wallet activity. Workflow: 1. Configure event callbacks before calling `run()` 2. Call `run()` - it returns immediately after spawning background tasks 3. Receive notifications via callbacks as sync progresses 4. Call `stop()` when done # Safety - `client` must be a valid, non-null pointer to a created client. # Returns 0 on success, error code on failure.
Start the SPV client and begin syncing in the background. Subscribes to events, spawns monitoring threads, then spawns a background thread that calls `run()` (which handles start + sync loop + stop internally). Returns immediately after spawning. Use event callbacks (set via `set_sync_event_callbacks`, `set_network_event_callbacks`, `set_wallet_event_callbacks`) to receive notifications. Configure callbacks before calling `run()`. # Safety - `client` must be a valid, non-null pointer to a created client. # Returns 0 on success, error code on failure.

**Safety:**
- `client` must be a valid, non-null pointer to a created client.
Expand Down Expand Up @@ -946,8 +929,8 @@ FFIClientConfig* config = dash_spv_ffi_config_testnet();
// Create client
FFIDashSpvClient* client = dash_spv_ffi_client_new(config);

// Start the client
int32_t result = dash_spv_ffi_client_start(client);
// Start the client and begin syncing
int32_t result = dash_spv_ffi_client_run(client);
if (result != 0) {
const char* error = dash_spv_ffi_get_last_error();
// Handle error
Expand Down
6 changes: 3 additions & 3 deletions dash-spv-ffi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ if (client == NULL) {
// Handle error
}

// Start the client
if (dash_spv_ffi_client_start(client) != 0) {
// Start the client and begin syncing in the background
if (dash_spv_ffi_client_run(client) != 0) {
// Handle error
}

Expand All @@ -88,7 +88,7 @@ dash_spv_ffi_config_destroy(config);
### Client Operations

- `dash_spv_ffi_client_new(config)` - Create new client
- `dash_spv_ffi_client_start(client)` - Start the client
- `dash_spv_ffi_client_run(client)` - Start the client and begin syncing in the background
- `dash_spv_ffi_client_stop(client)` - Stop the client
- `dash_spv_ffi_client_get_sync_progress(client)` - Get sync progress
- `dash_spv_ffi_client_get_stats(client)` - Get client statistics
Expand Down
23 changes: 6 additions & 17 deletions dash-spv-ffi/include/dash_spv_ffi.h
Original file line number Diff line number Diff line change
Expand Up @@ -468,14 +468,6 @@ int32_t dash_spv_ffi_client_update_config(struct FFIDashSpvClient *client,
const struct FFIClientConfig *config)
;

/**
* Start the SPV client.
*
* # Safety
* - `client` must be a valid, non-null pointer to a created client.
*/
int32_t dash_spv_ffi_client_start(struct FFIDashSpvClient *client) ;

/**
* Stop the SPV client.
*
Expand All @@ -487,16 +479,13 @@ int32_t dash_spv_ffi_client_update_config(struct FFIDashSpvClient *client,
/**
* Start the SPV client and begin syncing in the background.
*
* This is the streamlined entry point that combines `start()` and continuous monitoring
* into a single non-blocking call. Use event callbacks (set via `set_sync_event_callbacks`,
* `set_network_event_callbacks`, `set_wallet_event_callbacks`) to receive notifications
* about sync progress, peer connections, and wallet activity.
* Subscribes to events, spawns monitoring threads, then spawns a background
* thread that calls `run()` (which handles start + sync loop + stop internally).
* Returns immediately after spawning.
*
* Workflow:
* 1. Configure event callbacks before calling `run()`
* 2. Call `run()` - it returns immediately after spawning background tasks
* 3. Receive notifications via callbacks as sync progresses
* 4. Call `stop()` when done
* Use event callbacks (set via `set_sync_event_callbacks`,
* `set_network_event_callbacks`, `set_wallet_event_callbacks`) to receive
* notifications. Configure callbacks before calling `run()`.
*
* # Safety
* - `client` must be a valid, non-null pointer to a created client.
Expand Down
4 changes: 2 additions & 2 deletions dash-spv-ffi/scripts/generate_ffi_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,8 +308,8 @@ def generate_markdown(functions: List[FFIFunction]) -> str:
md.append("// Create client")
md.append("FFIDashSpvClient* client = dash_spv_ffi_client_new(config);")
md.append("")
md.append("// Start the client")
md.append("int32_t result = dash_spv_ffi_client_start(client);")
md.append("// Start the client and begin syncing")
md.append("int32_t result = dash_spv_ffi_client_run(client);")
md.append("if (result != 0) {")
md.append(" const char* error = dash_spv_ffi_get_last_error();")
md.append(" // Handle error")
Expand Down
55 changes: 10 additions & 45 deletions dash-spv-ffi/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,27 +250,6 @@ pub unsafe extern "C" fn dash_spv_ffi_client_update_config(
}
}

/// Start the SPV client.
///
/// # Safety
/// - `client` must be a valid, non-null pointer to a created client.
#[no_mangle]
pub unsafe extern "C" fn dash_spv_ffi_client_start(client: *mut FFIDashSpvClient) -> i32 {
null_check!(client);

let client = &(*client);

let result = client.runtime.block_on(async { client.inner.start().await });

match result {
Ok(()) => FFIErrorCode::Success as i32,
Err(e) => {
set_last_error(&e.to_string());
FFIErrorCode::from(e) as i32
}
}
}

/// Stop the SPV client.
///
/// # Safety
Expand All @@ -291,16 +270,13 @@ pub unsafe extern "C" fn dash_spv_ffi_client_stop(client: *mut FFIDashSpvClient)

/// Start the SPV client and begin syncing in the background.
///
/// This is the streamlined entry point that combines `start()` and continuous monitoring
/// into a single non-blocking call. Use event callbacks (set via `set_sync_event_callbacks`,
/// `set_network_event_callbacks`, `set_wallet_event_callbacks`) to receive notifications
/// about sync progress, peer connections, and wallet activity.
/// Subscribes to events, spawns monitoring threads, then spawns a background
/// thread that calls `run()` (which handles start + sync loop + stop internally).
/// Returns immediately after spawning.
///
/// Workflow:
/// 1. Configure event callbacks before calling `run()`
/// 2. Call `run()` - it returns immediately after spawning background tasks
/// 3. Receive notifications via callbacks as sync progresses
/// 4. Call `stop()` when done
/// Use event callbacks (set via `set_sync_event_callbacks`,
/// `set_network_event_callbacks`, `set_wallet_event_callbacks`) to receive
/// notifications. Configure callbacks before calling `run()`.
///
/// # Safety
/// - `client` must be a valid, non-null pointer to a created client.
Expand All @@ -313,18 +289,7 @@ pub unsafe extern "C" fn dash_spv_ffi_client_run(client: *mut FFIDashSpvClient)

let client = &(*client);

tracing::info!("dash_spv_ffi_client_run: starting client");

// Start the client first
let start_result = client.runtime.block_on(async { client.inner.start().await });

if let Err(e) = start_result {
tracing::error!("dash_spv_ffi_client_run: start failed: {}", e);
set_last_error(&e.to_string());
return FFIErrorCode::from(e) as i32;
}

tracing::info!("dash_spv_ffi_client_run: client started, setting up event monitoring");
tracing::info!("dash_spv_ffi_client_run: setting up event monitoring");

let shutdown_token = client.shutdown_token.clone();

Expand Down Expand Up @@ -389,10 +354,10 @@ pub unsafe extern "C" fn dash_spv_ffi_client_run(client: *mut FFIDashSpvClient)
// Spawn the sync monitoring task
let spv_client = client.inner.clone();
tasks.push(client.runtime.spawn(async move {
tracing::debug!("Sync task: starting monitor_network");
tracing::debug!("Sync task: starting run");

if let Err(e) = spv_client.monitor_network(shutdown_token).await {
tracing::error!("Sync task: sync error: {}", e);
if let Err(e) = spv_client.run(shutdown_token).await {
tracing::error!("Sync task: error: {}", e);
}

tracing::debug!("Sync task: exiting");
Expand Down
2 changes: 1 addition & 1 deletion dash-spv-ffi/tests/c_tests/test_basic.c
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ void test_null_pointer_handling() {

// Client functions
TEST_ASSERT(dash_spv_ffi_client_new(NULL) == NULL);
TEST_ASSERT(dash_spv_ffi_client_start(NULL) == FFIErrorCode_NullPointer);
TEST_ASSERT(dash_spv_ffi_client_run(NULL) == FFIErrorCode_NullPointer);
TEST_ASSERT(dash_spv_ffi_client_stop(NULL) == FFIErrorCode_NullPointer);

// Destruction functions (should handle NULL gracefully)
Expand Down
4 changes: 2 additions & 2 deletions dash-spv-ffi/tests/test_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ mod tests {
let client = dash_spv_ffi_client_new(config);

// Note: Start/stop may fail in test environment without network
let _result = dash_spv_ffi_client_start(client);
let _result = dash_spv_ffi_client_run(client);
let _result = dash_spv_ffi_client_stop(client);

dash_spv_ffi_client_destroy(client);
Expand All @@ -68,7 +68,7 @@ mod tests {
#[serial]
fn test_client_null_checks() {
unsafe {
let result = dash_spv_ffi_client_start(std::ptr::null_mut());
let result = dash_spv_ffi_client_run(std::ptr::null_mut());
assert_eq!(result, FFIErrorCode::NullPointer as i32);

let result = dash_spv_ffi_client_stop(std::ptr::null_mut());
Expand Down
2 changes: 1 addition & 1 deletion dash-spv-ffi/tests/unit/test_async_operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ mod tests {
println!("Testing callback thread safety with concurrent invocations");

// Start the client
let start_result = dash_spv_ffi_client_start(client);
let start_result = dash_spv_ffi_client_run(client);
assert_eq!(start_result, 0);
thread::sleep(Duration::from_millis(100));

Expand Down
12 changes: 6 additions & 6 deletions dash-spv-ffi/tests/unit/test_client_lifecycle.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Note: Many tests in this file are marked with #[ignore] because they call
// dash_spv_ffi_client_start() which hangs indefinitely when using regtest
// dash_spv_ffi_client_run() which hangs indefinitely when using regtest
// network with no configured peers. These tests should be run with a proper
// test network setup or mocked networking layer.

Expand Down Expand Up @@ -72,14 +72,14 @@ mod tests {
assert!(!client.is_null());

// Start
let _result = dash_spv_ffi_client_start(client);
let _result = dash_spv_ffi_client_run(client);
// May fail in test environment, but should handle gracefully

// Stop
let _result = dash_spv_ffi_client_stop(client);

// Restart
let _result = dash_spv_ffi_client_start(client);
let _result = dash_spv_ffi_client_run(client);
let _result = dash_spv_ffi_client_stop(client);

dash_spv_ffi_client_destroy(client);
Expand All @@ -98,7 +98,7 @@ mod tests {

// Start a sync operation in background
// Start sync (non-blocking)
dash_spv_ffi_client_start(client);
dash_spv_ffi_client_run(client);

// Immediately destroy client (should handle pending operations)
dash_spv_ffi_client_destroy(client);
Expand All @@ -121,7 +121,7 @@ mod tests {
assert!(!client.is_null());

// Try to start (should handle no peers gracefully)
let _result = dash_spv_ffi_client_start(client);
let _result = dash_spv_ffi_client_run(client);

dash_spv_ffi_client_destroy(client);
dash_spv_ffi_config_destroy(config);
Expand Down Expand Up @@ -164,7 +164,7 @@ mod tests {
unsafe {
// Test all client operations with null
assert_eq!(
dash_spv_ffi_client_start(std::ptr::null_mut()),
dash_spv_ffi_client_run(std::ptr::null_mut()),
FFIErrorCode::NullPointer as i32
);

Expand Down
10 changes: 3 additions & 7 deletions dash-spv/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = ClientConfig::mainnet()
.with_storage_path("/path/to/data".into());

// Create and start client
let mut client = DashSpvClient::new(config).await?;
client.start().await?;

let (_command_sender, command_receiver) = tokio::sync::mpsc::unbounded_channel();
// Create and run the client
let client = DashSpvClient::new(config).await?;
let shutdown_token = CancellationToken::new();

client.run(command_receiver, shutdown_token).await?;
client.run(shutdown_token).await?;
Comment thread
xdustinface marked this conversation as resolved.

Ok(())
}
Expand Down
3 changes: 0 additions & 3 deletions dash-spv/examples/filter_sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create the client
let client = DashSpvClient::new(config, network_manager, storage_manager, wallet).await?;

// Start the client
client.start().await?;

println!("Starting synchronization with filter support...");
println!("Watching address: {:?}", watch_address);

Expand Down
3 changes: 0 additions & 3 deletions dash-spv/examples/simple_sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create the client
let client = DashSpvClient::new(config, network_manager, storage_manager, wallet).await?;

// Start the client
client.start().await?;

println!("Starting header synchronization...");

let shutdown_token = CancellationToken::new();
Expand Down
4 changes: 0 additions & 4 deletions dash-spv/examples/spv_with_wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create the SPV client with all components
let client = DashSpvClient::new(config, network_manager, storage_manager, wallet).await?;

// Start the client
println!("Starting SPV client...");
client.start().await?;

// The wallet will automatically be notified of:
// - New blocks via process_block()
// - Mempool transactions via process_mempool_transaction()
Expand Down
2 changes: 1 addition & 1 deletion dash-spv/src/client/lifecycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ impl<W: WalletInterface, N: NetworkManager, S: StorageManager> DashSpvClient<W,
}

/// Start the SPV client.
pub async fn start(&self) -> Result<()> {
pub(super) async fn start(&self) -> Result<()> {
{
let running = self.running.read().await;
if *running {
Expand Down
Loading
Loading