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
24 changes: 2 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**: 68
**Total Functions**: 67

## Table of Contents

Expand Down Expand Up @@ -66,14 +66,13 @@ Functions: 25

### Synchronization

Functions: 7
Functions: 6

| Function | Description | Module |
|----------|-------------|--------|
| `dash_spv_ffi_client_cancel_sync` | Cancels the sync operation | client |
| `dash_spv_ffi_client_get_sync_progress` | Get the current sync progress snapshot | client |
| `dash_spv_ffi_client_is_filter_sync_available` | Check if compact filter sync is currently available | client |
| `dash_spv_ffi_client_sync_to_tip` | Sync the SPV client to the chain tip | client |
| `dash_spv_ffi_client_sync_to_tip_with_progress` | Sync the SPV client to the chain tip with detailed progress updates | client |
| `dash_spv_ffi_client_test_sync` | Performs a test synchronization of the SPV client # Parameters - `client`:... | client |
| `dash_spv_ffi_sync_progress_destroy` | Destroy a `FFISyncProgress` object returned by this crate | client |
Expand Down Expand Up @@ -661,22 +660,6 @@ Check if compact filter sync is currently available. # Safety - `client` must b

---

#### `dash_spv_ffi_client_sync_to_tip`

```c
dash_spv_ffi_client_sync_to_tip(client: *mut FFIDashSpvClient, completion_callback: Option<extern "C" fn(bool, *const c_char, *mut c_void)>, user_data: *mut c_void,) -> i32
```

**Description:**
Sync the SPV client to the chain tip. # Safety This function is unsafe because: - `client` must be a valid pointer to an initialized `FFIDashSpvClient` - `user_data` must satisfy thread safety requirements: - If non-null, it must point to data that is safe to access from multiple threads - The caller must ensure proper synchronization if the data is mutable - The data must remain valid for the entire duration of the sync operation - `completion_callback` must be thread-safe and can be called from any thread # Parameters - `client`: Pointer to the SPV client - `completion_callback`: Optional callback invoked on completion - `user_data`: Optional user data pointer passed to callbacks # Returns 0 on success, error code on failure

**Safety:**
This function is unsafe because: - `client` must be a valid pointer to an initialized `FFIDashSpvClient` - `user_data` must satisfy thread safety requirements: - If non-null, it must point to data that is safe to access from multiple threads - The caller must ensure proper synchronization if the data is mutable - The data must remain valid for the entire duration of the sync operation - `completion_callback` must be thread-safe and can be called from any thread

**Module:** `client`

---

#### `dash_spv_ffi_client_sync_to_tip_with_progress`

```c
Expand Down Expand Up @@ -1258,9 +1241,6 @@ if (result != 0) {
// Handle error
}

// Sync to chain tip
dash_spv_ffi_client_sync_to_tip(client, NULL, NULL);

// Get wallet manager (shares ownership with the client)
FFIWalletManager* wallet_manager = dash_spv_ffi_client_get_wallet_manager(client);

Expand Down
20 changes: 0 additions & 20 deletions dash-spv-ffi/FFI_DOCS_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,26 +73,6 @@ When adding new FFI functions:
4. Run `make update-docs` to regenerate documentation
5. Commit both the code changes and updated `FFI_API.md`

## Example FFI Function

```rust
/// Sync the SPV client to the chain tip
///
/// # Safety
///
/// - `client` must be a valid pointer to an FFIDashSpvClient
/// - `on_progress` callback may be invoked from any thread
/// - `on_completion` will be called exactly once
#[no_mangle]
pub unsafe extern "C" fn dash_spv_ffi_client_sync_to_tip(
client: *mut FFIDashSpvClient,
on_progress: Option<SyncProgressCallback>,
on_completion: Option<CompletionCallback>,
) -> i32 {
// Implementation
}
```

## CI/CD Integration

The documentation verification is integrated into the CI pipeline:
Expand Down
1 change: 0 additions & 1 deletion dash-spv-ffi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ dash_spv_ffi_config_destroy(config);
- `dash_spv_ffi_client_new(config)` - Create new client
- `dash_spv_ffi_client_start(client)` - Start the client
- `dash_spv_ffi_client_stop(client)` - Stop the client
- `dash_spv_ffi_client_sync_to_tip(client, callbacks)` - Sync to chain tip
- `dash_spv_ffi_client_get_sync_progress(client)` - Get sync progress
- `dash_spv_ffi_client_get_stats(client)` - Get client statistics
- `dash_spv_ffi_client_destroy(client)` - Free client memory
Expand Down
29 changes: 0 additions & 29 deletions dash-spv-ffi/include/dash_spv_ffi.h
Original file line number Diff line number Diff line change
Expand Up @@ -322,35 +322,6 @@ int32_t dash_spv_ffi_client_update_config(struct FFIDashSpvClient *client,
*/
int32_t dash_spv_ffi_client_stop(struct FFIDashSpvClient *client) ;

/**
* Sync the SPV client to the chain tip.
*
* # Safety
*
* This function is unsafe because:
* - `client` must be a valid pointer to an initialized `FFIDashSpvClient`
* - `user_data` must satisfy thread safety requirements:
* - If non-null, it must point to data that is safe to access from multiple threads
* - The caller must ensure proper synchronization if the data is mutable
* - The data must remain valid for the entire duration of the sync operation
* - `completion_callback` must be thread-safe and can be called from any thread
*
* # Parameters
*
* - `client`: Pointer to the SPV client
* - `completion_callback`: Optional callback invoked on completion
* - `user_data`: Optional user data pointer passed to callbacks
*
* # Returns
*
* 0 on success, error code on failure
*/

int32_t dash_spv_ffi_client_sync_to_tip(struct FFIDashSpvClient *client,
void (*completion_callback)(bool, const char*, void*),
void *user_data)
;

/**
* Performs a test synchronization of the SPV client
*
Expand Down
3 changes: 0 additions & 3 deletions dash-spv-ffi/scripts/generate_ffi_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,9 +317,6 @@ def generate_markdown(functions: List[FFIFunction]) -> str:
md.append(" // Handle error")
md.append("}")
md.append("")
md.append("// Sync to chain tip")
md.append("dash_spv_ffi_client_sync_to_tip(client, NULL, NULL);")
md.append("")
md.append("// Get wallet manager (shares ownership with the client)")
md.append("FFIWalletManager* wallet_manager = dash_spv_ffi_client_get_wallet_manager(client);")
md.append("")
Expand Down
128 changes: 1 addition & 127 deletions dash-spv-ffi/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,6 @@ enum CallbackInfo {
completion_callback: Option<extern "C" fn(bool, *const c_char, *mut c_void)>,
user_data: *mut c_void,
},
/// Simple progress callbacks (used by sync_to_tip)
Simple {
completion_callback: Option<extern "C" fn(bool, *const c_char, *mut c_void)>,
user_data: *mut c_void,
},
}

/// # Safety
Expand Down Expand Up @@ -541,115 +536,6 @@ pub unsafe extern "C" fn dash_spv_ffi_client_stop(client: *mut FFIDashSpvClient)
}
}

/// Sync the SPV client to the chain tip.
///
/// # Safety
///
/// This function is unsafe because:
/// - `client` must be a valid pointer to an initialized `FFIDashSpvClient`
/// - `user_data` must satisfy thread safety requirements:
/// - If non-null, it must point to data that is safe to access from multiple threads
/// - The caller must ensure proper synchronization if the data is mutable
/// - The data must remain valid for the entire duration of the sync operation
/// - `completion_callback` must be thread-safe and can be called from any thread
///
/// # Parameters
///
/// - `client`: Pointer to the SPV client
/// - `completion_callback`: Optional callback invoked on completion
/// - `user_data`: Optional user data pointer passed to callbacks
///
/// # Returns
///
/// 0 on success, error code on failure
#[no_mangle]
pub unsafe extern "C" fn dash_spv_ffi_client_sync_to_tip(
client: *mut FFIDashSpvClient,
completion_callback: Option<extern "C" fn(bool, *const c_char, *mut c_void)>,
user_data: *mut c_void,
) -> i32 {
null_check!(client);

let client = &(*client);
let inner = client.inner.clone();
let runtime = client.runtime.clone();

// Register callbacks in the global registry for safe lifetime management
let callback_info = CallbackInfo::Simple {
completion_callback,
user_data,
};
let callback_id = CALLBACK_REGISTRY.lock().unwrap().register(callback_info);

// Execute sync in the runtime
let result = runtime.block_on(async {
let mut spv_client = {
let mut guard = inner.lock().unwrap();
match guard.take() {
Some(client) => client,
None => {
return Err(dash_spv::SpvError::Storage(dash_spv::StorageError::NotFound(
"Client not initialized".to_string(),
)))
}
}
};
match spv_client.sync_to_tip().await {
Ok(_sync_result) => {
// sync_to_tip returns a SyncResult, not a stream
// Progress callbacks removed as sync_to_tip doesn't provide real progress updates

// Report completion and unregister callbacks
let mut registry = CALLBACK_REGISTRY.lock().unwrap();
if let Some(CallbackInfo::Simple {
completion_callback: Some(callback),
user_data,
}) = registry.unregister(callback_id)
{
let msg = CString::new("Sync completed successfully").unwrap_or_else(|_| {
CString::new("Sync completed").expect("hardcoded string is safe")
});
callback(true, msg.as_ptr(), user_data);
}

// Put client back
let mut guard = inner.lock().unwrap();
*guard = Some(spv_client);

Ok(())
}
Err(e) => {
// Report error and unregister callbacks
let mut registry = CALLBACK_REGISTRY.lock().unwrap();
if let Some(CallbackInfo::Simple {
completion_callback: Some(callback),
user_data,
}) = registry.unregister(callback_id)
{
let msg = match CString::new(format!("Sync failed: {}", e)) {
Ok(s) => s,
Err(_) => CString::new("Sync failed").expect("hardcoded string is safe"),
};
callback(false, msg.as_ptr(), user_data);
}

// Put client back
let mut guard = inner.lock().unwrap();
*guard = Some(spv_client);
Err(e)
}
}
});

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

/// Performs a test synchronization of the SPV client
///
/// # Parameters
Expand All @@ -668,7 +554,7 @@ pub unsafe extern "C" fn dash_spv_ffi_client_test_sync(client: *mut FFIDashSpvCl

let client = &(*client);
let result = client.runtime.block_on(async {
let mut spv_client = {
let spv_client = {
let mut guard = client.inner.lock().unwrap();
match guard.take() {
Some(client) => client,
Expand All @@ -689,18 +575,6 @@ pub unsafe extern "C" fn dash_spv_ffi_client_test_sync(client: *mut FFIDashSpvCl
};
tracing::info!("Initial height: {}", start_height);

// Start sync
match spv_client.sync_to_tip().await {
Ok(_) => tracing::info!("Sync started successfully"),
Err(e) => {
tracing::error!("Failed to start sync: {}", e);
// put back before returning
let mut guard = client.inner.lock().unwrap();
*guard = Some(spv_client);
return Err(e);
}
}

// Wait a bit for headers to download
tokio::time::sleep(Duration::from_secs(10)).await;

Expand Down
16 changes: 0 additions & 16 deletions dash-spv-ffi/tests/c_tests/test_advanced.c
Original file line number Diff line number Diff line change
Expand Up @@ -299,25 +299,9 @@ void test_callbacks_with_operations() {
FFIDashSpvClient* client = dash_spv_ffi_client_new(config);
TEST_ASSERT(client != NULL);

CallbackData callback_data = {0};

FFICallbacks callbacks = {0};
callbacks.on_progress = real_progress_callback;
callbacks.on_completion = real_completion_callback;
callbacks.on_data = NULL;
callbacks.user_data = &callback_data;

// Start sync operation
int32_t result = dash_spv_ffi_client_sync_to_tip(client, callbacks);

// Wait a bit for callbacks
usleep(100000); // 100ms

// Callbacks might or might not be called depending on network
printf("Progress callbacks: %d, Completion: %d\n",
callback_data.progress_count,
callback_data.completion_called);

dash_spv_ffi_client_destroy(client);
dash_spv_ffi_config_destroy(config);

Expand Down
20 changes: 1 addition & 19 deletions dash-spv-ffi/tests/integration/test_full_workflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,6 @@ mod tests {
// Start the client
let result = dash_spv_ffi_client_start(ctx.client);

// Start syncing
let sync_result = dash_spv_ffi_client_sync_to_tip(ctx.client, callbacks);

// Wait for sync to complete or timeout
let start = Instant::now();
let timeout = Duration::from_secs(10);
Expand Down Expand Up @@ -391,11 +388,7 @@ mod tests {
// 1. Start without peers
let result = dash_spv_ffi_client_start(ctx.client);

// 2. Try to sync without being started (if not started above)
let callbacks = FFICallbacks::default();
let sync_result = dash_spv_ffi_client_sync_to_tip(ctx.client, callbacks);

// 3. Add invalid address
// 2. Add invalid address
let invalid_addr = CString::new("invalid_address").unwrap();
let watch_result = dash_spv_ffi_client_watch_address(ctx.client, invalid_addr.as_ptr());
assert_eq!(watch_result, FFIErrorCode::InvalidArgument as i32);
Expand Down Expand Up @@ -516,17 +509,6 @@ mod tests {
// Start with network issues
let start_result = dash_spv_ffi_client_start(ctx.client);

// Try to sync with poor connectivity
let sync_start = Instant::now();
let callbacks = FFICallbacks {
on_progress: None,
on_completion: None,
on_data: None,
user_data: std::ptr::null_mut(),
};

dash_spv_ffi_client_sync_to_tip(ctx.client, callbacks);

// Should handle timeouts gracefully
thread::sleep(Duration::from_secs(3));

Expand Down
7 changes: 0 additions & 7 deletions dash-spv-ffi/tests/test_event_callbacks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,13 +186,6 @@ fn test_event_callbacks_setup() {

println!("Client started, waiting for events...");

// Try to sync for a short time to see if we get any events
println!("Starting sync to trigger events...");
let sync_result = dash_spv_ffi_client_test_sync(client);
if sync_result != 0 {
println!("Warning: Test sync failed");
}

// Wait a bit for events to be processed
thread::sleep(Duration::from_secs(5));

Expand Down
Loading
Loading