Skip to content

feat: expose full TransactionRecord through FFI and wallet events#614

Merged
QuantumExplorer merged 4 commits intov0.42-devfrom
feat/ffi-enrich-transaction-surface
Apr 1, 2026
Merged

feat: expose full TransactionRecord through FFI and wallet events#614
QuantumExplorer merged 4 commits intov0.42-devfrom
feat/ffi-enrich-transaction-surface

Conversation

@xdustinface
Copy link
Copy Markdown
Collaborator

@xdustinface xdustinface commented Apr 1, 2026

  • Add FFI types for transaction direction, type, output role, and input/output details
  • Enrich FFITransactionRecord with classification, details, label and serialized tx bytes
  • Simplify WalletEvent::TransactionReceived to carry Box<TransactionRecord>
  • Return TransactionRecord from record_transaction and propagate via TransactionCheckResult
  • Refactor OnTransactionReceivedCallback to pass *const FFITransactionRecord

Based on:

Summary by CodeRabbit

  • New Features

    • Transaction events now deliver a single, richer structured record (context, txid, net amount, type, direction, inputs/outputs, serialized data, optional label) for clearer, consistent event payloads.
  • Bug Fixes

    • Improved safety: callbacks now handle missing records gracefully and deep-clean nested transaction data to reduce memory issues.
  • Tests

    • Updated tests and helpers to assert the new record-based event shape and deep-free behavior.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 1, 2026

📝 Walkthrough

Walkthrough

Replaces multiple transaction callback parameters with a single FFITransactionRecord passed through FFI and internal events; expands FFI transaction record with serialized tx, input/output detail arrays, type/direction, and label; updates allocation/free semantics, callsites, and tests to the record-centric API.

Changes

Cohort / File(s) Summary
FFI Type Definitions
key-wallet-ffi/src/types.rs
Adds FFITransactionDirection, FFITransactionType, FFIOutputRole, FFIInputDetail, FFIOutputDetail and conversion impls; updates/restructures unit tests for these conversions.
FFI Record Structure & Managed Account
key-wallet-ffi/src/managed_account.rs
Extends FFITransactionRecord with transaction_type, direction, input_details/output_details arrays, tx_data/tx_len, and label; implements deep allocation in get_transactions and deep free in free_transactions; adds unit tests for deep-free and NULL handling.
FFI Callback Types & Dispatch
dash-spv-ffi/src/callbacks.rs
Changes exported OnTransactionReceivedCallback signature to accept record: *const FFITransactionRecord; builds a heap-backed FFITransactionRecord for callbacks, passes pointer to client, and frees nested allocations after callback returns.
FFI CLI & Tests
dash-spv-ffi/src/bin/ffi_cli.rs, dash-spv-ffi/tests/dashd_sync/callbacks.rs, dash-spv-ffi/tests/dashd_sync/tests_callback.rs, dash-spv-ffi/tests/dashd_sync/tests_transaction.rs
Updates on_transaction_received implementations and test trackers to new signature (record: *const FFITransactionRecord); adds null-checks and dereferences record for txid, net_amount, and tx size; adjusts tests to assert on received_transactions.
Wallet Event Shape & Emission
key-wallet-manager/src/events.rs, key-wallet-manager/src/lib.rs
Replaces WalletEvent::TransactionReceived fields (status, txid, amount, addresses) with record: Box<TransactionRecord>; updates event description and emission to pass boxed records from transaction recording.
Transaction Recording & Checkers
key-wallet/src/managed_account/mod.rs, key-wallet/src/transaction_checking/account_checker.rs, key-wallet/src/transaction_checking/wallet_checker.rs
ManagedCoreAccount::record_transaction now returns a TransactionRecord; TransactionCheckResult gains new_records: Vec<(u32, TransactionRecord)>; checkers collect new records and forward them for event emission.
Manager Tests & Helpers
key-wallet-manager/src/event_tests.rs, key-wallet-manager/src/test_helpers.rs, dash-spv/tests/dashd_sync/helpers.rs
Updates tests/helpers to destructure TransactionReceived { record, .. } and assert on record.context, record.txid, record.net_amount, or presence of input/output details.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant WalletCore as Wallet Core
    participant Manager as WalletManager
    participant FFI as FFI Layer
    participant Client as C Client

    rect rgba(200,200,255,0.5)
    WalletCore->>Manager: detect new transaction (tx)
    Manager->>WalletCore: record_transaction(tx) -> TransactionRecord
    Manager->>FFI: build FFITransactionRecord (tx_data, input/output details, label)
    end

    rect rgba(200,255,200,0.5)
    FFI->>Client: invoke on_transaction_received(wallet_id, account_index, record_ptr, user_data)
    Client-->>FFI: returns
    FFI->>FFI: free nested allocations for record_ptr
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

ready-for-review

Suggested reviewers

  • ZocoLini

Poem

🐰 I stitched a record, tidy and neat,

Pointers snug where fields would meet.
Inputs, outputs, labels in line,
One struct hops through C and Rust just fine.
Hooray — the rabbit winks: callbacks refined.

🚥 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 'feat: expose full TransactionRecord through FFI and wallet events' clearly and specifically summarizes the main change: enriching FFI and wallet events with the complete TransactionRecord structure.
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
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/ffi-enrich-transaction-surface

Warning

Review ran into problems

🔥 Problems

Timed out fetching pipeline failures after 30000ms


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.

@xdustinface
Copy link
Copy Markdown
Collaborator Author

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 1, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Base automatically changed from refactor/ffi-transaction-context-rename to v0.42-dev April 1, 2026 10:35
@xdustinface xdustinface force-pushed the feat/ffi-enrich-transaction-surface branch from 461105c to a2bd33f Compare April 1, 2026 10:36
@QuantumExplorer QuantumExplorer marked this pull request as ready for review April 1, 2026 10:37
@xdustinface
Copy link
Copy Markdown
Collaborator Author

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 1, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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: 3

🧹 Nitpick comments (2)
key-wallet-manager/src/event_tests.rs (1)

12-92: Add one lifecycle test for non-index account types.

Current updates validate the new record payload well, but mostly through indexed account paths. Add a TransactionReceived assertion for a non-index account type to catch dropped-event regressions in new_records propagation.

As per coding guidelines, "Write unit tests for new functionality".

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

In `@key-wallet-manager/src/event_tests.rs` around lines 12 - 92, Add a new
lifecycle test that exercises a non-index account type and asserts a
TransactionReceived event is emitted and carries the full `record` payload; use
the same helpers as other tests (setup_manager_with_wallet, create_tx_paying_to,
subscribe_events, assert_single_event) and call
manager.check_transaction_in_all_wallets(&tx, TransactionContext::Mempool, true,
true).await (or TransactionContext::InBlock for first-seen-in-block variants) to
trigger new_records propagation, then match WalletEvent::TransactionReceived and
assert record.context, record.txid == tx.txid(), ev_wid == wallet_id, and
record.net_amount == TX_AMOUNT as i64 to catch dropped-event regressions for
non-index accounts.
key-wallet-ffi/src/managed_account.rs (1)

665-667: Scope the ownership note to the owned transaction API.

FFITransactionRecord is now also passed as a borrowed callback payload in dash-spv-ffi/src/callbacks.rs:537-546. Keeping managed_core_account_free_transactions in the type-level doc makes the ownership contract look universal, which can steer FFI callers toward freeing borrowed callback memory.

Suggested wording
-/// Heap-allocated fields must be freed with `managed_core_account_free_transactions`.
+/// When returned by `managed_core_account_get_transactions`, heap-allocated fields
+/// must be freed with `managed_core_account_free_transactions`.
+///
+/// This struct is also used as a borrowed callback payload in `dash-spv-ffi`;
+/// borrowed callback records and their nested pointers are only valid for the
+/// duration of the callback and must not be freed by the caller.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@key-wallet-ffi/src/managed_account.rs` around lines 665 - 667, The type-level
doc for FFITransactionRecord wrongly implies all instances must be freed with
managed_core_account_free_transactions; update the comment to scope that
ownership contract to the "owned transaction" API only (e.g., instances returned
by managed_core_account_free_transactions or the managed account owned API) and
explicitly state that callback-provided/borrowed FFITransactionRecord payloads
are not owned and must not be freed by callers (reference FFITransactionRecord
and managed_core_account_free_transactions and the borrowed callback usage).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@dash-spv-ffi/src/callbacks.rs`:
- Around line 758-763: The code currently converts record.label into an owned
raw C string with CString::new(...).unwrap().into_raw(), leaking memory and
risking a panic on interior NULs; instead, create a local CString (e.g., let
c_label = CString::new(record.label.as_deref().unwrap_or("")).map_err(|e| /* map
to our error type */)?), keep it in scope across the cb(...) invocation and pass
c_label.as_ptr() (or c_label.as_ptr() as *mut _ if mutable is required) so it is
not into_raw'd, and propagate/handle the CString::new error instead of
unwrap/expect; apply the same change to the other occurrence mentioned (lines
~772-779) and replace unwrap() calls with proper error handling using the
crate's error type.

In `@dash-spv-ffi/tests/dashd_sync/callbacks.rs`:
- Around line 354-357: The two separate pushes to tracker.received_txids and
tracker.received_amounts can interleave across threads and break per-callback
pairing; change the callback in callbacks.rs so it captures the entire
FFITransactionRecord snapshot (use the unsafe deref of record to read r.txid,
r.net_amount and any new fields) and then perform a single lock/unlock to push
one combined snapshot (e.g., push a struct or tuple) into a new
tracker.received_snapshots Vec, replacing the two separate pushes to
received_txids and received_amounts to ensure each entry represents one callback
atomically.

In `@key-wallet/src/transaction_checking/wallet_checker.rs`:
- Around line 127-130: The code currently only pushes new_records when
account_match.account_type_match.account_index() returns Some, which discards
records for non-index account types and prevents downstream TransactionReceived
events; change the logic in the wallet checking flow so that record =
account.record_transaction(tx, &account_match, context, tx_type) is always
appended to result.new_records (e.g., push a variant that includes None for the
account index or push all records unconditionally and let downstream handle None
indices), updating any consumers to handle Option<usize> if necessary; then add
a regression unit test that simulates a non-index account receiving a
transaction and asserts that TransactionReceived is emitted for that account
type to prevent future regressions.

---

Nitpick comments:
In `@key-wallet-ffi/src/managed_account.rs`:
- Around line 665-667: The type-level doc for FFITransactionRecord wrongly
implies all instances must be freed with managed_core_account_free_transactions;
update the comment to scope that ownership contract to the "owned transaction"
API only (e.g., instances returned by managed_core_account_free_transactions or
the managed account owned API) and explicitly state that
callback-provided/borrowed FFITransactionRecord payloads are not owned and must
not be freed by callers (reference FFITransactionRecord and
managed_core_account_free_transactions and the borrowed callback usage).

In `@key-wallet-manager/src/event_tests.rs`:
- Around line 12-92: Add a new lifecycle test that exercises a non-index account
type and asserts a TransactionReceived event is emitted and carries the full
`record` payload; use the same helpers as other tests
(setup_manager_with_wallet, create_tx_paying_to, subscribe_events,
assert_single_event) and call manager.check_transaction_in_all_wallets(&tx,
TransactionContext::Mempool, true, true).await (or TransactionContext::InBlock
for first-seen-in-block variants) to trigger new_records propagation, then match
WalletEvent::TransactionReceived and assert record.context, record.txid ==
tx.txid(), ev_wid == wallet_id, and record.net_amount == TX_AMOUNT as i64 to
catch dropped-event regressions for non-index accounts.
🪄 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: f6a6bc2b-105d-48bb-a6df-bc96e0ecee56

📥 Commits

Reviewing files that changed from the base of the PR and between f61ac42 and 461105c.

📒 Files selected for processing (13)
  • dash-spv-ffi/src/bin/ffi_cli.rs
  • dash-spv-ffi/src/callbacks.rs
  • dash-spv-ffi/tests/dashd_sync/callbacks.rs
  • dash-spv/tests/dashd_sync/helpers.rs
  • key-wallet-ffi/src/managed_account.rs
  • key-wallet-ffi/src/types.rs
  • key-wallet-manager/src/event_tests.rs
  • key-wallet-manager/src/events.rs
  • key-wallet-manager/src/lib.rs
  • key-wallet-manager/src/test_helpers.rs
  • key-wallet/src/managed_account/mod.rs
  • key-wallet/src/transaction_checking/account_checker.rs
  • key-wallet/src/transaction_checking/wallet_checker.rs

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 1, 2026

Codecov Report

❌ Patch coverage is 93.23944% with 24 lines in your changes missing coverage. Please review.
✅ Project coverage is 67.53%. Comparing base (09f03e0) to head (416d91e).
⚠️ Report is 3 commits behind head on v0.42-dev.

Files with missing lines Patch % Lines
dash-spv-ffi/src/bin/ffi_cli.rs 0.00% 9 Missing ⚠️
key-wallet-ffi/src/managed_account.rs 95.38% 6 Missing ⚠️
key-wallet-ffi/src/types.rs 97.38% 4 Missing ⚠️
dash-spv-ffi/src/callbacks.rs 94.44% 3 Missing ⚠️
key-wallet-manager/src/events.rs 0.00% 2 Missing ⚠️
Additional details and impacted files
@@              Coverage Diff              @@
##           v0.42-dev     #614      +/-   ##
=============================================
+ Coverage      67.45%   67.53%   +0.08%     
=============================================
  Files            320      320              
  Lines          67949    68169     +220     
=============================================
+ Hits           45832    46038     +206     
- Misses         22117    22131      +14     
Flag Coverage Δ
core 75.21% <ø> (ø)
ffi 37.60% <93.64%> (+1.12%) ⬆️
rpc 19.92% <ø> (ø)
spv 83.90% <ø> (+0.08%) ⬆️
wallet 67.59% <77.77%> (-0.01%) ⬇️
Files with missing lines Coverage Δ
key-wallet-manager/src/lib.rs 61.71% <100.00%> (-0.79%) ⬇️
key-wallet-manager/src/test_helpers.rs 97.59% <100.00%> (ø)
key-wallet/src/managed_account/mod.rs 55.21% <100.00%> (+0.14%) ⬆️
...wallet/src/transaction_checking/account_checker.rs 66.51% <100.00%> (+0.05%) ⬆️
...-wallet/src/transaction_checking/wallet_checker.rs 97.83% <ø> (ø)
key-wallet-manager/src/events.rs 0.00% <0.00%> (ø)
dash-spv-ffi/src/callbacks.rs 82.25% <94.44%> (+1.66%) ⬆️
key-wallet-ffi/src/types.rs 79.01% <97.38%> (+2.48%) ⬆️
key-wallet-ffi/src/managed_account.rs 48.80% <95.38%> (+3.88%) ⬆️
dash-spv-ffi/src/bin/ffi_cli.rs 0.00% <0.00%> (ø)

... and 2 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.

♻️ Duplicate comments (1)
dash-spv-ffi/src/callbacks.rs (1)

758-763: ⚠️ Potential issue | 🟠 Major

Memory leak: label CString is allocated but never freed after callback.

The label field uses CString::new(...).unwrap().into_raw() which transfers ownership to the raw pointer. Unlike input_details addresses which are freed after the callback (lines 772-779), the label is never reclaimed, leaking memory for every labeled transaction event.

Additionally, unwrap() can panic on labels containing interior NUL bytes.

🔧 Suggested fix: Keep CString alive across callback
+                    let label_cstring = record
+                        .label
+                        .as_ref()
+                        .map(|l| CString::new(l.as_str()).unwrap_or_default());
+
                     let ffi_record = FFITransactionRecord {
                         // ... other fields ...
-                        label: record
-                            .label
-                            .as_ref()
-                            .map(|l| CString::new(l.as_str()).unwrap().into_raw())
-                            .unwrap_or(std::ptr::null_mut()),
+                        label: label_cstring
+                            .as_ref()
+                            .map_or(std::ptr::null_mut(), |c| c.as_ptr() as *mut _),
                     };

As per coding guidelines, **/src/**/*.rs: Avoid unwrap() and expect() in library code; use proper error types.

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

In `@dash-spv-ffi/src/callbacks.rs` around lines 758 - 763, The code allocates a
CString for record.label using CString::new(...).unwrap().into_raw() and never
frees it, leaking on every callback and risking panics from unwrap() on interior
NULs; change the approach in the callback construction (the usage around label
and record.label) to safely create the CString without unwrap (return a Result
or propagate an error) and ensure the raw pointer is reclaimed after the
callback returns (mirror how input_details pointers are freed in the block that
releases them), or keep the CString owned for the callback lifetime and convert
to a raw pointer only for the call then call CString::from_raw(...) to free it
immediately after; update any functions that build or consume label to accept a
nullable pointer safely and remove unwrap() usage.
🧹 Nitpick comments (2)
key-wallet-ffi/src/types.rs (1)

861-874: Consider adding #[derive(Debug)] to FFIInputDetail and FFIOutputDetail for consistency.

The new FFI enums (FFITransactionDirection, FFITransactionType, FFIOutputRole) all have #[derive(Debug, Clone, Copy)], but these structs lack derives. While FFIInputDetail can't derive Debug directly due to the raw pointer, FFIOutputDetail could benefit from it for debugging consistency with other FFI types.

♻️ Proposed fix for FFIOutputDetail
 /// FFI-compatible output detail
 #[repr(C)]
+#[derive(Debug, Clone, Copy)]
 pub struct FFIOutputDetail {
     pub index: u32,
     pub role: FFIOutputRole,
 }
🤖 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 861 - 874, FFIOutputDetail should
derive Debug for consistency with the other FFI types — add #[derive(Debug,
Clone, Copy)] (or at least #[derive(Debug)]) to the FFIOutputDetail declaration;
FFIInputDetail cannot use the automatic Debug derive because it contains a raw C
string pointer, so implement Debug manually for FFIInputDetail (impl
std::fmt::Debug for FFIInputDetail) and format index and value directly and
print the address safely (either as the raw pointer or by converting to &CStr
inside an unsafe block with clear fallback) to avoid deriving on the raw
pointer.
dash-spv-ffi/src/callbacks.rs (1)

740-756: Document the borrow semantics of array pointers in FFITransactionRecord.

The input_details, output_details, and tx_data pointers point to stack-allocated Vecs that become invalid after the callback returns. While the callback documentation mentions the record is "borrowed," callers might assume they can call managed_core_account_free_transactions on callback-delivered records, which would cause undefined behavior since these pointers weren't heap-allocated via that function.

Consider adding a comment clarifying that records from callbacks have different ownership semantics than records from managed_core_account_get_transactions.

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

In `@dash-spv-ffi/src/callbacks.rs` around lines 740 - 756, Add a clear comment to
FFITransactionRecord documenting that the pointers input_details,
output_details, and tx_data are borrows into stack/temporary Vecs provided only
for the duration of the callback and must not be freed or passed to
managed_core_account_free_transactions; explicitly state that ownership
semantics differ from records returned by managed_core_account_get_transactions
(which are heap-owned and must be freed), and mention callers who need
persistent data should clone or allocate their own copies before the callback
returns.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@dash-spv-ffi/src/callbacks.rs`:
- Around line 758-763: The code allocates a CString for record.label using
CString::new(...).unwrap().into_raw() and never frees it, leaking on every
callback and risking panics from unwrap() on interior NULs; change the approach
in the callback construction (the usage around label and record.label) to safely
create the CString without unwrap (return a Result or propagate an error) and
ensure the raw pointer is reclaimed after the callback returns (mirror how
input_details pointers are freed in the block that releases them), or keep the
CString owned for the callback lifetime and convert to a raw pointer only for
the call then call CString::from_raw(...) to free it immediately after; update
any functions that build or consume label to accept a nullable pointer safely
and remove unwrap() usage.

---

Nitpick comments:
In `@dash-spv-ffi/src/callbacks.rs`:
- Around line 740-756: Add a clear comment to FFITransactionRecord documenting
that the pointers input_details, output_details, and tx_data are borrows into
stack/temporary Vecs provided only for the duration of the callback and must not
be freed or passed to managed_core_account_free_transactions; explicitly state
that ownership semantics differ from records returned by
managed_core_account_get_transactions (which are heap-owned and must be freed),
and mention callers who need persistent data should clone or allocate their own
copies before the callback returns.

In `@key-wallet-ffi/src/types.rs`:
- Around line 861-874: FFIOutputDetail should derive Debug for consistency with
the other FFI types — add #[derive(Debug, Clone, Copy)] (or at least
#[derive(Debug)]) to the FFIOutputDetail declaration; FFIInputDetail cannot use
the automatic Debug derive because it contains a raw C string pointer, so
implement Debug manually for FFIInputDetail (impl std::fmt::Debug for
FFIInputDetail) and format index and value directly and print the address safely
(either as the raw pointer or by converting to &CStr inside an unsafe block with
clear fallback) to avoid deriving on the raw pointer.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e5a607be-a459-4b28-9036-25cdc4167292

📥 Commits

Reviewing files that changed from the base of the PR and between 461105c and a2bd33f.

📒 Files selected for processing (13)
  • dash-spv-ffi/src/bin/ffi_cli.rs
  • dash-spv-ffi/src/callbacks.rs
  • dash-spv-ffi/tests/dashd_sync/callbacks.rs
  • dash-spv/tests/dashd_sync/helpers.rs
  • key-wallet-ffi/src/managed_account.rs
  • key-wallet-ffi/src/types.rs
  • key-wallet-manager/src/event_tests.rs
  • key-wallet-manager/src/events.rs
  • key-wallet-manager/src/lib.rs
  • key-wallet-manager/src/test_helpers.rs
  • key-wallet/src/managed_account/mod.rs
  • key-wallet/src/transaction_checking/account_checker.rs
  • key-wallet/src/transaction_checking/wallet_checker.rs
✅ Files skipped from review due to trivial changes (1)
  • dash-spv-ffi/tests/dashd_sync/callbacks.rs
🚧 Files skipped from review as they are similar to previous changes (7)
  • dash-spv/tests/dashd_sync/helpers.rs
  • key-wallet/src/managed_account/mod.rs
  • key-wallet-manager/src/event_tests.rs
  • key-wallet/src/transaction_checking/account_checker.rs
  • key-wallet/src/transaction_checking/wallet_checker.rs
  • key-wallet-manager/src/events.rs
  • dash-spv-ffi/src/bin/ffi_cli.rs

- Add FFI types for transaction direction, type, output role, and input/output details
- Enrich `FFITransactionRecord` with classification, details, label and serialized tx bytes
- Simplify `WalletEvent::TransactionReceived` to carry `Box<TransactionRecord>`
- Return `TransactionRecord` from `record_transaction` and propagate via `TransactionCheckResult`
- Refactor `OnTransactionReceivedCallback` to pass `*const FFITransactionRecord`
xdustinface added a commit that referenced this pull request Apr 1, 2026
@xdustinface xdustinface force-pushed the feat/ffi-enrich-transaction-surface branch from a2bd33f to 0452c0a Compare April 1, 2026 11:17
@xdustinface xdustinface force-pushed the feat/ffi-enrich-transaction-surface branch from 0452c0a to 06490f9 Compare April 1, 2026 11:21
The test sends 1 DASH from the same wallet (same mnemonic) that the SPV
client tracks, making it an internal transfer where both inputs and
outputs belong to the wallet. The `net_amount` therefore equals
approximately `-fee`, not +100_000_000. Replace the strict amount pairing
assertion with a txid presence check and non-zero net_amount verification.
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.

♻️ Duplicate comments (1)
key-wallet/src/transaction_checking/wallet_checker.rs (1)

127-130: ⚠️ Potential issue | 🟠 Major

Still drops TransactionReceived records for non-index accounts.

Lines 128-130 still discard the freshly recorded transaction whenever account_index() is None, so non-index account types can update wallet state without ever reaching new_records or the downstream WalletEvent::TransactionReceived path. Please carry a richer account identifier here (Option<u32> or account-type metadata) instead of filtering the record out, and add a regression test for a non-index account match. As per coding guidelines, "Write unit tests for new functionality".

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

In `@key-wallet/src/transaction_checking/wallet_checker.rs` around lines 127 -
130, The code currently drops TransactionReceived records when
account_match.account_type_match.account_index() is None; change
result.new_records to carry a richer identifier (e.g., change its element from
(u32, Record) to (Option<u32>, Record) or include account-type metadata) so the
record is always pushed: update the push site in wallet_checker.rs (currently
using account.record_transaction and result.new_records.push((account_index,
record))) to push the Option<u32> or metadata instead, then update downstream
consumers (the collection that feeds WalletEvent::TransactionReceived) to accept
the new identifier shape and preserve behavior for Some(account_index) and None;
finally add a unit test that creates a non-index account match and asserts
WalletEvent::TransactionReceived is produced for that case.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@key-wallet/src/transaction_checking/wallet_checker.rs`:
- Around line 127-130: The code currently drops TransactionReceived records when
account_match.account_type_match.account_index() is None; change
result.new_records to carry a richer identifier (e.g., change its element from
(u32, Record) to (Option<u32>, Record) or include account-type metadata) so the
record is always pushed: update the push site in wallet_checker.rs (currently
using account.record_transaction and result.new_records.push((account_index,
record))) to push the Option<u32> or metadata instead, then update downstream
consumers (the collection that feeds WalletEvent::TransactionReceived) to accept
the new identifier shape and preserve behavior for Some(account_index) and None;
finally add a unit test that creates a non-index account match and asserts
WalletEvent::TransactionReceived is produced for that case.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f216da13-7c17-4161-bf46-5c6f5d88f5fe

📥 Commits

Reviewing files that changed from the base of the PR and between a2bd33f and 416d91e.

📒 Files selected for processing (15)
  • dash-spv-ffi/src/bin/ffi_cli.rs
  • dash-spv-ffi/src/callbacks.rs
  • dash-spv-ffi/tests/dashd_sync/callbacks.rs
  • dash-spv-ffi/tests/dashd_sync/tests_callback.rs
  • dash-spv-ffi/tests/dashd_sync/tests_transaction.rs
  • dash-spv/tests/dashd_sync/helpers.rs
  • key-wallet-ffi/src/managed_account.rs
  • key-wallet-ffi/src/types.rs
  • key-wallet-manager/src/event_tests.rs
  • key-wallet-manager/src/events.rs
  • key-wallet-manager/src/lib.rs
  • key-wallet-manager/src/test_helpers.rs
  • key-wallet/src/managed_account/mod.rs
  • key-wallet/src/transaction_checking/account_checker.rs
  • key-wallet/src/transaction_checking/wallet_checker.rs
🚧 Files skipped from review as they are similar to previous changes (6)
  • dash-spv/tests/dashd_sync/helpers.rs
  • key-wallet-manager/src/test_helpers.rs
  • key-wallet/src/transaction_checking/account_checker.rs
  • key-wallet-manager/src/event_tests.rs
  • key-wallet-manager/src/events.rs
  • dash-spv-ffi/src/bin/ffi_cli.rs

@github-actions github-actions bot added the ready-for-review CodeRabbit has approved this PR label Apr 1, 2026
@QuantumExplorer QuantumExplorer merged commit 734b35f into v0.42-dev Apr 1, 2026
43 of 44 checks passed
@QuantumExplorer QuantumExplorer deleted the feat/ffi-enrich-transaction-surface branch April 1, 2026 21:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-review CodeRabbit has approved this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants