Skip to content

chore(key-wallet-ffi): cbindgen.toml cleanup#629

Open
ZocoLini wants to merge 1 commit intov0.42-devfrom
chore/rm-opaque-types
Open

chore(key-wallet-ffi): cbindgen.toml cleanup#629
ZocoLini wants to merge 1 commit intov0.42-devfrom
chore/rm-opaque-types

Conversation

@ZocoLini
Copy link
Copy Markdown
Collaborator

@ZocoLini ZocoLini commented Apr 3, 2026

Removed cbindgen instructions that are not having any real effect

Summary by CodeRabbit

  • Chores
    • Simplified FFI (Foreign Function Interface) configuration by removing export control sections and type mapping customizations. Core behavior for generating functions and data structures remains unchanged, with no impact to end-user functionality.

@ZocoLini ZocoLini marked this pull request as draft April 3, 2026 19:38
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 3, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4e977089-7294-48df-a54f-015f02e50bd0

📥 Commits

Reviewing files that changed from the base of the PR and between 66b0097 and 1e66026.

📒 Files selected for processing (1)
  • key-wallet-ffi/cbindgen.toml
💤 Files with no reviewable changes (1)
  • key-wallet-ffi/cbindgen.toml

📝 Walkthrough

Walkthrough

Removed export configuration sections from the cbindgen.toml file, including the [export] section with item type controls, the [export.body] section defining Swift-compatible opaque type bodies, and the [export.rename] section for C-convention type renaming.

Changes

Cohort / File(s) Summary
CBindgen Export Configuration
key-wallet-ffi/cbindgen.toml
Removed [export], [export.body], and [export.rename] sections that previously controlled FFI type emission, Swift opaque placeholder bodies, and C-convention type renaming for FFIErrorCode, FFINetwork, and FFIDerivationPathType.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 A rabbit hops through config lines so fine,
Trimming export rules, making bindings align,
Opaque bodies vanish, renames take flight,
Simpler generation—the C bindings shine bright!

🚥 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 title accurately describes the main change: removing configuration instructions from cbindgen.toml that have no real effect, which aligns with the PR description and file modifications.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/rm-opaque-types

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.

@ZocoLini ZocoLini changed the title (choreremove opaque types from FFI chore(key-wallet-ffi): remove opaque types from FFI Apr 3, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 3, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 67.96%. Comparing base (7e2aa23) to head (1e66026).
⚠️ Report is 10 commits behind head on v0.42-dev.

Additional details and impacted files
@@              Coverage Diff              @@
##           v0.42-dev     #629      +/-   ##
=============================================
- Coverage      67.99%   67.96%   -0.04%     
=============================================
  Files            319      319              
  Lines          67970    67970              
=============================================
- Hits           46216    46193      -23     
- Misses         21754    21777      +23     
Flag Coverage Δ
core 75.25% <ø> (ø)
ffi 38.99% <ø> (-0.21%) ⬇️
rpc 20.00% <ø> (ø)
spv 85.36% <ø> (-0.01%) ⬇️
wallet 67.62% <ø> (ø)
see 18 files with indirect coverage changes

Copy link
Copy Markdown
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: 6

Caution

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

⚠️ Outside diff range comments (3)
key-wallet-ffi/src/keys.rs (1)

377-393: ⚠️ Potential issue | 🔴 Critical

Reclaim the erased inner key objects in the free functions.

The new opaque wrappers own a second heap allocation in inner (created via Box::into_raw(Box::new(...))), but the free functions at lines 379, 392, 744, and 759 only drop the outer FFI*Key box. This leaks all four key allocations, and for the private variants (private_key_free and extended_private_key_free) it also leaves secret material resident in memory after the destructor returns, violating the requirement to never expose private keys.

Proposed fix
 pub unsafe extern "C" fn private_key_free(key: *mut FFIPrivateKey) {
     if !key.is_null() {
-        let _ = unsafe { Box::from_raw(key) };
+        let key = unsafe { Box::from_raw(key) };
+        if !key.inner.is_null() {
+            let _ = unsafe { Box::from_raw(key.inner as *mut secp256k1::SecretKey) };
+        }
     }
 }
 
 pub unsafe extern "C" fn extended_private_key_free(key: *mut FFIExtendedPrivateKey) {
     if !key.is_null() {
-        let _ = unsafe { Box::from_raw(key) };
+        let key = unsafe { Box::from_raw(key) };
+        if !key.inner.is_null() {
+            let _ = unsafe { Box::from_raw(key.inner as *mut key_wallet::bip32::ExtendedPrivKey) };
+        }
     }
 }
 
 pub unsafe extern "C" fn public_key_free(key: *mut FFIPublicKey) {
     if !key.is_null() {
-        unsafe {
-            let _ = Box::from_raw(key);
-        }
+        let key = unsafe { Box::from_raw(key) };
+        if !key.inner.is_null() {
+            let _ = unsafe { Box::from_raw(key.inner as *mut secp256k1::PublicKey) };
+        }
     }
 }
 
 pub unsafe extern "C" fn extended_public_key_free(key: *mut FFIExtendedPublicKey) {
     if !key.is_null() {
-        unsafe {
-            let _ = Box::from_raw(key);
-        }
+        let key = unsafe { Box::from_raw(key) };
+        if !key.inner.is_null() {
+            let _ = unsafe { Box::from_raw(key.inner as *mut key_wallet::bip32::ExtendedPubKey) };
+        }
     }
 }

Also applies to: 741-760

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@key-wallet-ffi/src/keys.rs` around lines 377 - 393, The free functions
(private_key_free, extended_private_key_free and their counterparts around the
other indices) only drop the outer FFI*Key Box and leak the inner heap
allocation (FFI*Key.inner), leaving secret material in memory; fix by: for each
free function (e.g., private_key_free, extended_private_key_free, and the other
two free functions), first check for null, reconstruct the outer Box from the
raw pointer, then if outer.inner is a raw pointer to a heap allocation
reconstruct and drop (and for private keys overwrite/zeroize the secret if
applicable) that inner Box before letting the outer Box go out of scope so both
allocations are reclaimed and secrets are cleared. Ensure you reference and use
the FFIPrivateKey.inner / FFIExtendedPrivateKey.inner fields when freeing.
key-wallet-ffi/src/derivation.rs (2)

45-50: ⚠️ Potential issue | 🟠 Major

This public FFI rename needs a breaking-change plan.

Changing these exported signatures from FFIExtendedPrivKey / FFIExtendedPubKey to FFIExtendedPrivateKey / FFIExtendedPublicKey changes the generated C surface and will break existing bindings at compile time. Please either keep compatibility aliases for a transition release or ship this as an explicit breaking change instead of a chore.

As per coding guidelines, "Check whether the PR title prefix allowed in the pr-title.yml workflow accurately describes the changes."

Also applies to: 425-431, 501-508, 535-542, 577-584, 619-627

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@key-wallet-ffi/src/derivation.rs` around lines 45 - 50, The exported FFI
type/name changes (e.g., replacing FFIExtendedPrivKey/FFIExtendedPubKey with
FFIExtendedPrivateKey/FFIExtendedPublicKey, as seen in the signature of
derivation_new_master_key and the other renamed FFI functions) will break
downstream C bindings; either restore backward-compatible aliases for the old
symbols (typedefs and exported function wrappers that forward to the new
types/functions) so both names exist for a transition release, or mark and
publish this as an explicit breaking change in the PR title and changelog;
update symbol references for derivation_new_master_key, its related derivation_*
functions, and the FFI type declarations to implement aliases if choosing
compatibility.

649-671: ⚠️ Potential issue | 🔴 Critical

Memory leak: derivation_xpriv_free() and derivation_xpub_free() do not free inner allocations.

Both derivation_xpriv_free() and derivation_xpub_free() call Box::from_raw() on the wrapper struct, which only drops the outer FFIExtendedPrivateKey / FFIExtendedPublicKey container (a single pointer). The inner ExtendedPrivKey / ExtendedPubKey allocations—created via Box::into_raw(Box::new(inner)) in from_inner()—are never freed because:

  1. The wrapper types have no Drop implementation
  2. The free functions do not reconstruct and drop the inner raw pointer

Every call to derivation_xpriv_free() or derivation_xpub_free() leaks memory. The fix is to either implement Drop for the wrappers that reconstructs and drops the inner pointer, or have the free functions explicitly recover and drop the inner allocation.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@key-wallet-ffi/src/derivation.rs` around lines 649 - 671, The free functions
derivation_xpriv_free and derivation_xpub_free currently only call Box::from_raw
on the wrapper structs and thus leak the inner allocations; update them to
reconstruct and drop the inner raw pointer stored inside FFIExtendedPrivateKey /
FFIExtendedPublicKey (the pointer created by from_inner via Box::into_raw)
before dropping the outer wrapper, or alternatively implement Drop for
FFIExtendedPrivateKey and FFIExtendedPublicKey to recover and free the inner
ExtendedPrivKey / ExtendedPubKey; ensure you locate the inner pointer field on
FFIExtendedPrivateKey/FFIExtendedPublicKey, convert it back into a Box and let
it drop, then convert the outer pointer back into a Box (Box::from_raw) so both
inner and outer allocations are freed (apply this for both derivation_xpriv_free
and derivation_xpub_free).
🧹 Nitpick comments (1)
key-wallet-ffi/src/types.rs (1)

145-149: Please call out this FFI contract change in the PR title/notes.

Switching exported handles to raw void* ownership wrappers changes the consumer-visible layout/lifetime contract, so this reads larger than a routine chore.

As per coding guidelines, "Check whether the PR title prefix allowed in the pr-title.yml workflow accurately describes the changes."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@key-wallet-ffi/src/types.rs` around lines 145 - 149, The PR changed the FFI
handle layout by replacing the typed Arc<Wallet> wrapper with a raw void pointer
in the FFIWallet struct (see FFIWallet and its inner field), which changes
consumer-visible layout and ownership/lifetime semantics; update the PR title
and description to explicitly call out this breaking FFI contract change
(mention FFIWallet.inner, Arc<Wallet> -> *mut c_void swap), note the impact on
ABI/lifetimes and consumers, and ensure the pr-title.yml prefix reflects a
breaking or major change per the repo guidelines.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@key-wallet-ffi/FFI_API.md`:
- Around line 3127-3130: The safety doc incorrectly instructs consumers to free
the returned address pool with `[-]` instead of the actual destructor; update
the rustdoc/generator that produces the FFI documentation so the safety contract
for the function that returns the external address pool from an
FFIManagedCoreAccount (the function that returns the external/receive address
pool for Standard accounts) references the correct free function
`address_pool_free`, then regenerate FFl_API.md so the returned pool's release
instruction reads "The returned pool must be freed with `address_pool_free` when
no longer needed."

In `@key-wallet-ffi/src/account_collection.rs`:
- Around line 23-31: The FFI wrapper allocates a cloned AccountCollection into
inner (in FFIAccountCollection::new) but never frees that boxed clone, causing
leaks; implement Drop for FFIAccountCollection to reconstruct and drop the boxed
key_wallet::AccountCollection from the raw inner pointer (e.g., if self.inner !=
std::ptr::null_mut() then unsafe { Box::from_raw(self.inner as *mut
key_wallet::AccountCollection); } ), and ensure account_collection_free consumes
the FFIAccountCollection pointer via Box::from_raw to trigger Drop; update
inner() if needed to handle nulls safely.

In `@key-wallet-ffi/src/account.rs`:
- Around line 21-24: The FFIAccount::new creates a Box<Arc<...>> and stores its
raw pointer in FFIAccount.inner, but the corresponding free functions
(account_free, bls_account_free, eddsa_account_free) currently only drop the
outer wrapper and leak the boxed Arc; update each free path to reconstruct and
drop the original Box<Arc<...>> by casting inner back to *mut
Box<Arc<key_wallet::Account>> (or the appropriate concrete type) and letting it
fall out of scope, or alternatively implement Drop for FFIAccount (and the
bls/eddsa wrapper types) to perform the same Box::from_raw -> drop logic so the
heap-allocated Box<Arc<...>> is properly reclaimed.

In `@key-wallet-ffi/src/managed_account.rs`:
- Around line 872-873: The safety docs currently contain the placeholder '[-]'
as the destructor for the returned pool; replace that placeholder with the real
destructor name `address_pool_free` so callers know how to free the returned
pool (i.e., change the line "- The returned pool must be freed with `[-]` when
no longer needed" to "- The returned pool must be freed with `address_pool_free`
when no longer needed"). Ensure the doc comment in managed_account.rs updates
the exact safety paragraph that mentions the returned pool and uses the
backticked symbol `address_pool_free`.
- Around line 57-60: The FFIManagedPlatformAccount::new currently allocates
Box::new(Arc::new(account.clone())) and stores a raw pointer in
FFIManagedPlatformAccount.inner but managed_platform_account_free only drops the
outer struct, leaking that boxed allocation; update
managed_platform_account_free to reconstruct the
Box<Arc<ManagedPlatformAccount>> from inner (e.g. Box::from_raw(inner as *mut
Arc<ManagedPlatformAccount>)) so it gets dropped, and ensure any null checks are
handled safely before reconstructing; also fix the safety doc placeholder `[-]`
to the actual destructor name `managed_platform_account_free` in the safety
documentation for the FFI type to avoid the incomplete reference.

In `@key-wallet-ffi/src/types.rs`:
- Around line 145-166: The FFIWallet currently exposes a public raw pointer
field (inner) and public safe accessors (inner() and inner_mut()) and lacks
Drop, leading to leaks and UB; make the inner field private, implement Drop for
FFIWallet that reconstructs the Box<Arc<Wallet>> (using Box::from_raw) and lets
it drop, and change the raw-pointer accessors: either make inner() and
inner_mut() crate-private and unsafe (or rename to unsafe fn inner_raw() /
inner_raw_mut()) so all raw-pointer dereferencing is confined to private/unsafe
code; keep new() public but ensure it is the only safe constructor that sets
inner via Box::into_raw(Box::new(Arc::new(wallet))).

---

Outside diff comments:
In `@key-wallet-ffi/src/derivation.rs`:
- Around line 45-50: The exported FFI type/name changes (e.g., replacing
FFIExtendedPrivKey/FFIExtendedPubKey with
FFIExtendedPrivateKey/FFIExtendedPublicKey, as seen in the signature of
derivation_new_master_key and the other renamed FFI functions) will break
downstream C bindings; either restore backward-compatible aliases for the old
symbols (typedefs and exported function wrappers that forward to the new
types/functions) so both names exist for a transition release, or mark and
publish this as an explicit breaking change in the PR title and changelog;
update symbol references for derivation_new_master_key, its related derivation_*
functions, and the FFI type declarations to implement aliases if choosing
compatibility.
- Around line 649-671: The free functions derivation_xpriv_free and
derivation_xpub_free currently only call Box::from_raw on the wrapper structs
and thus leak the inner allocations; update them to reconstruct and drop the
inner raw pointer stored inside FFIExtendedPrivateKey / FFIExtendedPublicKey
(the pointer created by from_inner via Box::into_raw) before dropping the outer
wrapper, or alternatively implement Drop for FFIExtendedPrivateKey and
FFIExtendedPublicKey to recover and free the inner ExtendedPrivKey /
ExtendedPubKey; ensure you locate the inner pointer field on
FFIExtendedPrivateKey/FFIExtendedPublicKey, convert it back into a Box and let
it drop, then convert the outer pointer back into a Box (Box::from_raw) so both
inner and outer allocations are freed (apply this for both derivation_xpriv_free
and derivation_xpub_free).

In `@key-wallet-ffi/src/keys.rs`:
- Around line 377-393: The free functions (private_key_free,
extended_private_key_free and their counterparts around the other indices) only
drop the outer FFI*Key Box and leak the inner heap allocation (FFI*Key.inner),
leaving secret material in memory; fix by: for each free function (e.g.,
private_key_free, extended_private_key_free, and the other two free functions),
first check for null, reconstruct the outer Box from the raw pointer, then if
outer.inner is a raw pointer to a heap allocation reconstruct and drop (and for
private keys overwrite/zeroize the secret if applicable) that inner Box before
letting the outer Box go out of scope so both allocations are reclaimed and
secrets are cleared. Ensure you reference and use the FFIPrivateKey.inner /
FFIExtendedPrivateKey.inner fields when freeing.

---

Nitpick comments:
In `@key-wallet-ffi/src/types.rs`:
- Around line 145-149: The PR changed the FFI handle layout by replacing the
typed Arc<Wallet> wrapper with a raw void pointer in the FFIWallet struct (see
FFIWallet and its inner field), which changes consumer-visible layout and
ownership/lifetime semantics; update the PR title and description to explicitly
call out this breaking FFI contract change (mention FFIWallet.inner, Arc<Wallet>
-> *mut c_void swap), note the impact on ABI/lifetimes and consumers, and ensure
the pr-title.yml prefix reflects a breaking or major change per the repo
guidelines.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2654fd21-937c-4a35-9ba2-df925d603ba4

📥 Commits

Reviewing files that changed from the base of the PR and between dda1db7 and 66b0097.

📒 Files selected for processing (11)
  • key-wallet-ffi/FFI_API.md
  • key-wallet-ffi/cbindgen.toml
  • key-wallet-ffi/src/account.rs
  • key-wallet-ffi/src/account_collection.rs
  • key-wallet-ffi/src/address_pool.rs
  • key-wallet-ffi/src/derivation.rs
  • key-wallet-ffi/src/derivation_tests.rs
  • key-wallet-ffi/src/keys.rs
  • key-wallet-ffi/src/managed_account.rs
  • key-wallet-ffi/src/managed_wallet.rs
  • key-wallet-ffi/src/types.rs
💤 Files with no reviewable changes (1)
  • key-wallet-ffi/cbindgen.toml

Comment thread key-wallet-ffi/FFI_API.md Outdated
Comment thread key-wallet-ffi/src/account_collection.rs Outdated
Comment thread key-wallet-ffi/src/account.rs
Comment thread key-wallet-ffi/src/managed_account.rs
Comment thread key-wallet-ffi/src/managed_account.rs Outdated
Comment thread key-wallet-ffi/src/types.rs Outdated
@github-actions github-actions Bot added the merge-conflict The PR conflicts with the target branch. label Apr 14, 2026
@github-actions
Copy link
Copy Markdown

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

@ZocoLini ZocoLini force-pushed the chore/rm-opaque-types branch from 66b0097 to bbd2fda Compare April 17, 2026 19:28
@github-actions github-actions Bot removed the merge-conflict The PR conflicts with the target branch. label Apr 17, 2026
@ZocoLini ZocoLini changed the title chore(key-wallet-ffi): remove opaque types from FFI chore(key-wallet-ffi): cbindgen.toml cleanup Apr 17, 2026
@ZocoLini ZocoLini force-pushed the chore/rm-opaque-types branch from bbd2fda to 1e66026 Compare April 17, 2026 19:31
@ZocoLini ZocoLini marked this pull request as ready for review April 20, 2026 15:51
@ZocoLini ZocoLini requested a review from xdustinface April 24, 2026 22:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant