Skip to content
Draft
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
63 changes: 40 additions & 23 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**: 50

## 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 @@ -95,12 +94,14 @@ Functions: 2

### Event Callbacks

Functions: 4
Functions: 6

| Function | Description | Module |
|----------|-------------|--------|
| `dash_spv_ffi_client_clear_client_error_callback` | Clear the client error callback | client |
| `dash_spv_ffi_client_clear_network_event_callbacks` | Clear network event callbacks | client |
| `dash_spv_ffi_client_clear_progress_callback` | Clear progress callback | client |
| `dash_spv_ffi_client_set_client_error_callback` | Set a callback for fatal client errors (start failure, sync thread crash) | client |
| `dash_spv_ffi_client_set_network_event_callbacks` | Set network event callbacks for push-based event notifications | client |
| `dash_spv_ffi_client_set_progress_callback` | Set progress callback for sync progress updates | client |

Expand Down Expand Up @@ -168,22 +169,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 @@ -626,6 +611,22 @@ This function is unsafe because: - The caller must ensure all pointers are valid

### Event Callbacks - Detailed

#### `dash_spv_ffi_client_clear_client_error_callback`

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

**Description:**
Clear the client error callback. # Safety - `client` must be a valid, non-null pointer to an `FFIDashSpvClient`.

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

**Module:** `client`

---

#### `dash_spv_ffi_client_clear_network_event_callbacks`

```c
Expand Down Expand Up @@ -658,6 +659,22 @@ Clear progress callback. # Safety - `client` must be a valid, non-null pointer

---

#### `dash_spv_ffi_client_set_client_error_callback`

```c
dash_spv_ffi_client_set_client_error_callback(client: *mut FFIDashSpvClient, callback: FFIClientErrorCallback,) -> i32
```

**Description:**
Set a callback for fatal client errors (start failure, sync thread crash). # Safety - `client` must be a valid, non-null pointer to an `FFIDashSpvClient`. - The `callback` struct and its `user_data` must remain valid until the callback is cleared. - The callback must be thread-safe as it may be called from a background thread.

**Safety:**
- `client` must be a valid, non-null pointer to an `FFIDashSpvClient`. - The `callback` struct and its `user_data` must remain valid until the callback is cleared. - The callback must be thread-safe as it may be called from a background thread.

**Module:** `client`

---

#### `dash_spv_ffi_client_set_network_event_callbacks`

```c
Expand Down Expand Up @@ -791,7 +808,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 +963,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
61 changes: 44 additions & 17 deletions dash-spv-ffi/include/dash_spv_ffi.h
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,23 @@ typedef struct FFIProgressCallback {
void *user_data;
} FFIProgressCallback;

/**
* Callback for fatal client errors (e.g. start failure, monitor thread crash).
*
* The `error` string pointer is borrowed and only valid for the duration
* of the callback. Callers must copy the string if they need to retain it
* after the callback returns.
*/
typedef void (*OnClientErrorCallback)(const char *error, void *user_data);

/**
* Client error callback configuration.
*/
typedef struct FFIClientErrorCallback {
OnClientErrorCallback on_error;
void *user_data;
} FFIClientErrorCallback;

/**
* FFIResult type for error handling
*/
Expand Down Expand Up @@ -468,14 +485,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 +496,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 Expand Up @@ -695,6 +701,27 @@ int32_t dash_spv_ffi_client_set_progress_callback(struct FFIDashSpvClient *clien
*/
int32_t dash_spv_ffi_client_clear_progress_callback(struct FFIDashSpvClient *client) ;

/**
* Set a callback for fatal client errors (start failure, sync thread crash).
*
* # Safety
* - `client` must be a valid, non-null pointer to an `FFIDashSpvClient`.
* - The `callback` struct and its `user_data` must remain valid until the callback is cleared.
* - The callback must be thread-safe as it may be called from a background thread.
*/

int32_t dash_spv_ffi_client_set_client_error_callback(struct FFIDashSpvClient *client,
struct FFIClientErrorCallback callback)
;

/**
* Clear the client error callback.
*
* # Safety
* - `client` must be a valid, non-null pointer to an `FFIDashSpvClient`.
*/
int32_t dash_spv_ffi_client_clear_client_error_callback(struct FFIDashSpvClient *client) ;

struct FFIClientConfig *dash_spv_ffi_config_new(FFINetwork network) ;

struct FFIClientConfig *dash_spv_ffi_config_mainnet(void) ;
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
42 changes: 42 additions & 0 deletions dash-spv-ffi/src/callbacks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,48 @@ impl Default for FFIWalletEventCallbacks {
}
}

// ============================================================================
// FFIClientErrorCallback - Fatal client-level errors
// ============================================================================

/// Callback for fatal client errors (e.g. start failure, monitor thread crash).
///
/// The `error` string pointer is borrowed and only valid for the duration
/// of the callback. Callers must copy the string if they need to retain it
/// after the callback returns.
pub type OnClientErrorCallback =
Option<extern "C" fn(error: *const c_char, user_data: *mut c_void)>;

/// Client error callback configuration.
#[repr(C)]
#[derive(Clone)]
pub struct FFIClientErrorCallback {
pub on_error: OnClientErrorCallback,
pub user_data: *mut c_void,
}

unsafe impl Send for FFIClientErrorCallback {}
unsafe impl Sync for FFIClientErrorCallback {}

impl Default for FFIClientErrorCallback {
fn default() -> Self {
Self {
on_error: None,
user_data: std::ptr::null_mut(),
}
}
}

impl FFIClientErrorCallback {
/// Dispatch a client error to the callback.
pub fn dispatch(&self, error: &str) {
if let Some(cb) = self.on_error {
let c_error = CString::new(error).unwrap_or_default();
cb(c_error.as_ptr(), self.user_data);
}
}
}

impl FFIWalletEventCallbacks {
/// Dispatch a WalletEvent to the appropriate callback.
pub fn dispatch(&self, event: &key_wallet_manager::WalletEvent) {
Expand Down
Loading
Loading