Skip to content

Conversation

@ZocoLini
Copy link
Collaborator

@ZocoLini ZocoLini commented Jan 22, 2026

This are all the functions that are not being used in any place in platform repo, branch feat/iOSSupport along with structs or functions that ended up being unused after the removals. For sure there are more thing that are not being used in the crate but I wanted to focus on the ones not used when this is added as a dependency.

IMO, if we need something in a future to implement a feature though ffi we can recover it from this PR or re-implemente it with the API we had at that moment in time. Having this many things makes everything harder to work with by adding a lot fo noise and probably useless changes

Test updated removing references to the functions dropped. Discovered a LOT of stuff being tested more than once and tests that are basically useless IMO but didnt touch those, just making a note about things that can be improved

Summary by CodeRabbit

  • Documentation

    • Public API reference streamlined: documented entries reduced significantly (surface trimmed).
  • Refactor

    • Leaner FFI surface: many configuration options, sync/query helpers, broadcast and checkpoint features, platform handle management, and several memory-management helpers were removed.
    • Simplified CLI sync behavior and reduced config setters/getters.
  • Tests

    • Test suite pared back to match the smaller public surface; several tests and assertions removed or adapted.

✏️ Tip: You can customize this high-level summary in your review settings.

@ZocoLini ZocoLini marked this pull request as draft January 22, 2026 22:23
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 22, 2026

📝 Walkthrough

Walkthrough

The PR drastically shrinks the FFI public surface: ~25+ exported C functions, several FFI types/enums (FFIArray, FFIUnconfirmedTransaction, CoreSDKHandle, DashSpvValidationMode, etc.), memory-management helpers, broadcast/checkpoint APIs, and many tests are removed; remaining API centers on core client lifecycle and simplified config setters.

Changes

Cohort / File(s) Summary
API surface & headers
FFI_API.md, include/dash_spv_ffi.h
Removed numerous C header declarations and docs—enum DashSpvValidationMode, structs FFIArray, CoreSDKHandle, FFIUnconfirmedTransaction, and many function declarations; overall API trimmed from ~66 to ~41 functions.
Configuration
src/config.rs, tests/test_config.rs, tests/unit/test_configuration.rs
Removed many config getters/setters (validation mode, max peers, mempool settings, worker threads, filter load, data-dir getter). Added/retained a few setters (masternode sync, mempool fetch/persist). Tests for removed APIs deleted.
Client & sync
src/client.rs, tests/test_client.rs, tests/unit/test_async_operations.rs, tests/unit/test_client_lifecycle.rs
Dropped C-ABI functions: client_test_sync (made Rust-only), is_filter_sync_available, rescan_blockchain, record_send. Tests updated to call Rust wrapper where applicable.
Broadcast & checkpoints
src/broadcast.rs, src/checkpoints.rs, src/lib.rs
Removed broadcast FFI (client_broadcast_transaction) and checkpoints FFI (checkpoints_between_heights); removed mod broadcast from crate root.
Types & memory helpers
src/types.rs, tests/test_types.rs, tests/unit/test_memory_management.rs, tests/unit/test_type_conversions.rs
Removed FFIArray, FFIChainState, FFIPeerInfo, FFIUnconfirmedTransaction and array/string/transaction destroy helpers. Kept a Rust-side dash_spv_ffi_string_destroy. Large set of array/type conversion tests removed.
Platform integration & utils
src/platform_integration.rs, src/utils.rs, tests/test_platform_integration_*.rs, tests/test_utils.rs
Removed ffi_dash_spv_get_core_handle / ffi_dash_spv_release_core_handle and dash_spv_ffi_enable_test_mode. Tests referencing core-handle lifecycle and enable_test_mode removed or simplified.
CLI & progress logic
src/bin/ffi_cli.rs
Removed CLI flags --workers and --no-filters; simplified filter-sync completion logic to rely purely on header/filter heights.
Error handling
src/error.rs, tests/unit/test_error_handling.rs, other tests
Removed public dash_spv_ffi_clear_error export; some tests updated to use internal clear_last_error() or drop final clear assertions.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐇 I nibbled APIs through the night,

Trimmed the edges, made them light,
Fewer hops, a tidier trail,
FFI bushes neat and frail,
Hooray — simpler paths in sight!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately and specifically describes the main change: removal of unused FFI functions from the dash-spv-ffi crate, which is the core objective of this changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Collaborator

@xdustinface xdustinface left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a good plan. If we don't need/use it in there at the moment i agree there is no reason to keep it. Easy enough to bring it back and even improve on it if we actually need it and know how and where we actually want to use it.

@ZocoLini ZocoLini force-pushed the chore/ffi-cleanup-example branch 2 times, most recently from abfa99e to 8714ec8 Compare January 23, 2026 20:46
@ZocoLini ZocoLini marked this pull request as ready for review January 23, 2026 20:50
@ZocoLini ZocoLini requested a review from xdustinface January 23, 2026 20:50
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
dash-spv-ffi/tests/unit/test_error_handling.rs (1)

109-133: Correct misleading comment at line 130 about "public API".

The comment "Clear using public API" is incorrect—clear_last_error() is an internal Rust function (no #[no_mangle] decorator) and is not exported to C callers.

The actual design pattern is that errors are automatically cleared on successful FFI operations (confirmed by test assertions at lines 170 and 178). However, C callers have no way to manually clear the error state between failed operations, which the comment misrepresents. Update the comment to clarify that this tests the internal clearing mechanism, not a public API function:

// Clear using internal function (not public API)
clear_last_error();
dash-spv-ffi/src/client.rs (1)

537-571: Restore the client handle before early returns.

If the initial sync_progress() call fails, the function returns without putting spv_client back into client.inner, leaving the client in a None state and dropping the running instance.

🐛 Proposed fix
-        let start_height = match spv_client.sync_progress().await {
-            Ok(progress) => progress.header_height,
-            Err(e) => {
-                tracing::error!("Failed to get initial height: {}", e);
-                return Err(e);
-            }
-        };
+        let start_height = match spv_client.sync_progress().await {
+            Ok(progress) => progress.header_height,
+            Err(e) => {
+                tracing::error!("Failed to get initial height: {}", e);
+                let mut guard = client.inner.lock().unwrap();
+                *guard = Some(spv_client);
+                return Err(e);
+            }
+        };
🤖 Fix all issues with AI agents
In `@dash-spv-ffi/src/bin/ffi_cli.rs`:
- Around line 196-199: The loop's completion check can hang if filter sync is
disabled because filters_complete is computed unconditionally; update the
condition that sets filters_complete to only require filter heights when
filter_sync_available is true (e.g., compute filters_complete as
filter_sync_available && prog.filter_header_height >= prog.header_height &&
prog.last_synced_filter_height >= prog.filter_header_height), and then use that
guarded filters_complete together with SYNC_COMPLETED.load(Ordering::SeqCst) in
the if check so the loop can complete when filters are not available.
🧹 Nitpick comments (3)
dash-spv-ffi/src/types.rs (1)

45-52: Consider narrowing visibility of the internal string destructor.

This helper is only used inside the crate, but it’s publicly exported with an FFI-style name. Making it pub(crate) avoids suggesting a public API surface that was intentionally reduced.

♻️ Proposed tweak
-pub unsafe fn dash_spv_ffi_string_destroy(s: FFIString) {
+pub(crate) unsafe fn dash_spv_ffi_string_destroy(s: FFIString) {
     if !s.ptr.is_null() {
         let _ = CString::from_raw(s.ptr);
     }
 }
dash-spv-ffi/tests/test_platform_integration_safety.rs (1)

1-8: Module docstring claims coverage that was removed.

The module docstring at lines 3-8 claims to test "Memory safety (double-free, use-after-free)" but the test_memory_safety_patterns function (lines 207-227) now only tests buffer overflow prevention. The use-after-free and double-free tests appear to have been removed as part of this cleanup.

Consider updating the docstring to reflect the actual test coverage, or add a note that these scenarios are covered elsewhere.

📝 Suggested docstring update
 //! Comprehensive safety tests for platform_integration FFI functions
 //!
 //! Tests focus on:
 //! - Null pointer handling
 //! - Buffer overflow prevention
-//! - Memory safety (double-free, use-after-free)
+//! - Memory safety (buffer overflow prevention)
 //! - Thread safety
 //! - Error propagation
dash-spv-ffi/tests/unit/test_async_operations.rs (1)

243-282: Redundant inner unsafe block after adding unsafe to function signature.

Adding unsafe to the extern "C" function signature is a good practice to document that it performs unsafe operations. However, the inner unsafe block at line 248 is now redundant since the entire function body is already an unsafe context.

♻️ Remove redundant inner unsafe block
             unsafe extern "C" fn reentrant_callback(
                 _success: bool,
                 _error: *const c_char,
                 user_data: *mut c_void,
             ) {
-                let data = unsafe { &*(user_data as *const ReentrantData) };
+                let data = &*(user_data as *const ReentrantData);
                 let count = data.count.fetch_add(1, Ordering::SeqCst);

Comment on lines 196 to +199
let headers_done = SYNC_COMPLETED.load(Ordering::SeqCst);
let filters_complete = if disable_filter_sync || !prog.filter_sync_available {
false
} else {
prog.filter_header_height >= prog.header_height
&& prog.last_synced_filter_height >= prog.filter_header_height
};
if headers_done && (filters_complete || disable_filter_sync) {
let filters_complete = prog.filter_header_height >= prog.header_height
&& prog.last_synced_filter_height >= prog.filter_header_height;
if headers_done && filters_complete {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Prevent a potential hang when filter sync is unavailable.

If filter_sync_available is false, filter heights can stay at 0 while header_height advances, so filters_complete never becomes true and the polling loop can run forever. Gate the condition on filter_sync_available (or otherwise allow completion without filters).

🐛 Proposed fix
-                let filters_complete = prog.filter_header_height >= prog.header_height
-                    && prog.last_synced_filter_height >= prog.filter_header_height;
+                let filters_complete = !prog.filter_sync_available
+                    || (prog.filter_header_height >= prog.header_height
+                        && prog.last_synced_filter_height >= prog.filter_header_height);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let headers_done = SYNC_COMPLETED.load(Ordering::SeqCst);
let filters_complete = if disable_filter_sync || !prog.filter_sync_available {
false
} else {
prog.filter_header_height >= prog.header_height
&& prog.last_synced_filter_height >= prog.filter_header_height
};
if headers_done && (filters_complete || disable_filter_sync) {
let filters_complete = prog.filter_header_height >= prog.header_height
&& prog.last_synced_filter_height >= prog.filter_header_height;
if headers_done && filters_complete {
let headers_done = SYNC_COMPLETED.load(Ordering::SeqCst);
let filters_complete = !prog.filter_sync_available
|| (prog.filter_header_height >= prog.header_height
&& prog.last_synced_filter_height >= prog.filter_header_height);
if headers_done && filters_complete {
🤖 Prompt for AI Agents
In `@dash-spv-ffi/src/bin/ffi_cli.rs` around lines 196 - 199, The loop's
completion check can hang if filter sync is disabled because filters_complete is
computed unconditionally; update the condition that sets filters_complete to
only require filter heights when filter_sync_available is true (e.g., compute
filters_complete as filter_sync_available && prog.filter_header_height >=
prog.header_height && prog.last_synced_filter_height >=
prog.filter_header_height), and then use that guarded filters_complete together
with SYNC_COMPLETED.load(Ordering::SeqCst) in the if check so the loop can
complete when filters are not available.

@github-actions
Copy link

This PR has merge conflicts with the base branch. Please rebase or merge the base branch into your branch to resolve them.

@github-actions github-actions bot added the merge-conflict The PR conflicts with the target branch. label Jan 25, 2026
@ZocoLini ZocoLini force-pushed the chore/ffi-cleanup-example branch from 8714ec8 to c107192 Compare January 26, 2026 21:17
@github-actions github-actions bot removed the merge-conflict The PR conflicts with the target branch. label Jan 26, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
dash-spv-ffi/src/client.rs (1)

537-597: Missing required FFI attributes: #[no_mangle] extern "C" and unsafe keyword

The function lacks the required FFI annotations. All other FFI functions in client.rs use #[no_mangle] pub unsafe extern "C", but client_test_sync is defined as pub fn without these attributes. Additionally, the function signature is incorrect for FFI boundaries: it takes a safe reference &FFIDashSpvClient instead of a raw pointer *mut FFIDashSpvClient like other FFI functions, and it lacks the unsafe keyword required when crossing the FFI boundary.

Per the coding guidelines for dash-spv-ffi/src/**/*.rs: Use #[no_mangle] extern "C" attribute when implementing new FFI functions in Rust. The function needs:

  • #[no_mangle] attribute
  • unsafe keyword
  • Change parameter from &FFIDashSpvClient to *mut FFIDashSpvClient
  • Appropriate null-pointer checks and casting
dash-spv-ffi/FFI_API.md (1)

753-771: Type Definitions section has stale entries and incorrect enum variants.

Several inconsistencies with the actual code:

  1. FFIUnconfirmedTransaction - listed but removed per PR changes
  2. CoreSDKHandle - listed but related FFI functions were removed
  3. FFITransaction - listed but not found in types.rs
  4. FFIMempoolStrategy lists "Selective" variant which doesn't exist; code only has FetchAll and BloomFilter
📝 Suggested corrections
 ### Core Types

 - `FFIDashSpvClient` - SPV client handle
 - `FFIClientConfig` - Client configuration
 - `FFISyncProgress` - Synchronization progress
 - `FFIDetailedSyncProgress` - Detailed sync progress
 - `FFISpvStats` - SPV statistics
-- `FFITransaction` - Transaction information
-- `FFIUnconfirmedTransaction` - Unconfirmed transaction
 - `FFIEventCallbacks` - Event callback structure
-- `CoreSDKHandle` - Platform SDK integration handle
+- `FFIWalletManager` - Wallet manager handle

 ### Enumerations

 - `FFINetwork` - Network type (Dash, Testnet, Regtest, Devnet)
 - `FFIValidationMode` - Validation mode (None, Basic, Full)
-- `FFIMempoolStrategy` - Mempool strategy (FetchAll, BloomFilter, Selective)
+- `FFIMempoolStrategy` - Mempool strategy (FetchAll, BloomFilter)
+- `FFIMempoolRemovalReason` - Mempool removal reason (Expired, Replaced, DoubleSpent, Confirmed, Manual)
 - `FFISyncStage` - Synchronization stage
🤖 Fix all issues with AI agents
In `@dash-spv-ffi/src/types.rs`:
- Around line 45-52: The destructor dash_spv_ffi_string_destroy is not exported
as a C ABI symbol, so C callers (e.g. receivers of
FFIDetailedSyncProgress::stage_message via
dash_spv_ffi_client_sync_to_tip_with_progress) cannot call it to free the
buffer; change its declaration to a public C ABI function by adding #[no_mangle]
pub extern "C" fn dash_spv_ffi_string_destroy(s: FFIString) { ... } while
preserving the existing safety doc and body (CString::from_raw(s.ptr) if not
null) so the function is callable from C to free the FFIString memory.

Comment on lines +45 to +52
/// # Safety
/// - `s.ptr` must be a pointer previously returned by `FFIString::new` or compatible.
/// - It must not be used after this call.
pub unsafe fn dash_spv_ffi_string_destroy(s: FFIString) {
if !s.ptr.is_null() {
let _ = CString::from_raw(s.ptr);
}
}
Copy link
Contributor

@coderabbitai coderabbitai bot Jan 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing #[no_mangle] extern "C" prevents C callers from freeing FFIString.

FFIString is still used in FFIDetailedSyncProgress::stage_message (line 130), which is passed to C callbacks via dash_spv_ffi_client_sync_to_tip_with_progress. Without a C-callable destructor, C consumers cannot free the string buffer, causing memory leaks.

Per coding guidelines, FFI types must have corresponding _destroy() functions with #[no_mangle] extern "C" attributes for explicit memory management.

🔧 Proposed fix to expose as C ABI
 /// # Safety
 /// - `s.ptr` must be a pointer previously returned by `FFIString::new` or compatible.
 /// - It must not be used after this call.
+#[no_mangle]
+pub unsafe extern "C" fn dash_spv_ffi_string_destroy(s: FFIString) {
-pub unsafe fn dash_spv_ffi_string_destroy(s: FFIString) {
     if !s.ptr.is_null() {
         let _ = CString::from_raw(s.ptr);
     }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/// # Safety
/// - `s.ptr` must be a pointer previously returned by `FFIString::new` or compatible.
/// - It must not be used after this call.
pub unsafe fn dash_spv_ffi_string_destroy(s: FFIString) {
if !s.ptr.is_null() {
let _ = CString::from_raw(s.ptr);
}
}
/// # Safety
/// - `s.ptr` must be a pointer previously returned by `FFIString::new` or compatible.
/// - It must not be used after this call.
#[no_mangle]
pub unsafe extern "C" fn dash_spv_ffi_string_destroy(s: FFIString) {
if !s.ptr.is_null() {
let _ = CString::from_raw(s.ptr);
}
}
🤖 Prompt for AI Agents
In `@dash-spv-ffi/src/types.rs` around lines 45 - 52, The destructor
dash_spv_ffi_string_destroy is not exported as a C ABI symbol, so C callers
(e.g. receivers of FFIDetailedSyncProgress::stage_message via
dash_spv_ffi_client_sync_to_tip_with_progress) cannot call it to free the
buffer; change its declaration to a public C ABI function by adding #[no_mangle]
pub extern "C" fn dash_spv_ffi_string_destroy(s: FFIString) { ... } while
preserving the existing safety doc and body (CString::from_raw(s.ptr) if not
null) so the function is callable from C to free the FFIString memory.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ZocoLini What about this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment on lines +45 to +52
/// # Safety
/// - `s.ptr` must be a pointer previously returned by `FFIString::new` or compatible.
/// - It must not be used after this call.
pub unsafe fn dash_spv_ffi_string_destroy(s: FFIString) {
if !s.ptr.is_null() {
let _ = CString::from_raw(s.ptr);
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ZocoLini What about this?

.help("Disable masternode list synchronization"),
)
.arg(
Arg::new("no-filters")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you want to remove this?

@github-actions
Copy link

This PR has merge conflicts with the base branch. Please rebase or merge the base branch into your branch to resolve them.

@github-actions github-actions bot added the merge-conflict The PR conflicts with the target branch. label Jan 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-conflict The PR conflicts with the target branch.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants