Skip to content

Comments

feat(dash-spv-ffi): transaction broadcast ffi function#458

Merged
xdustinface merged 1 commit intov0.42-devfrom
feat/ffi-transaction-broadcast
Feb 21, 2026
Merged

feat(dash-spv-ffi): transaction broadcast ffi function#458
xdustinface merged 1 commit intov0.42-devfrom
feat/ffi-transaction-broadcast

Conversation

@ZocoLini
Copy link
Collaborator

@ZocoLini ZocoLini commented Feb 20, 2026

Summary by CodeRabbit

  • New Features

    • Transaction broadcasting functionality is now available through the FFI interface for network operations.
  • Refactor

    • Platform activation height function updated with revised naming convention and explicit output parameter structure for improved API consistency.

@ZocoLini ZocoLini requested a review from xdustinface February 20, 2026 19:48
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 20, 2026

📝 Walkthrough

Walkthrough

This pull request introduces a new FFI function dash_spv_ffi_client_broadcast_transaction for broadcasting transactions to the Dash network, along with a platform activation height function signature update. Changes span documentation, C header declarations, and Rust implementation with input validation and error handling.

Changes

Cohort / File(s) Summary
Documentation
dash-spv-ffi/FFI_API.md
Added Transaction Management section documenting the new broadcast transaction function. Renamed dash_spv_ffi_get_platform_activation_height to ffi_dash_spv_get_platform_activation_height with updated signature (uses out-parameter and FFIResult return type).
Header Declaration
dash-spv-ffi/include/dash_spv_ffi.h
Declared new public FFI function dash_spv_ffi_client_broadcast_transaction with safety documentation, accepting client pointer, transaction bytes, and length; returns int32_t status code.
Implementation
dash-spv-ffi/src/client.rs
Implemented dash_spv_ffi_client_broadcast_transaction with pointer validation, transaction byte deserialization, async broadcast via runtime, and error handling that maps failures to FFI error codes and stores error messages.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A new broadcast call hops into our code,
Transactions now fly down the network road,
With safety checks and errors tamed just right,
The FFI layer shines ever so 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 'feat(dash-spv-ffi): transaction broadcast ffi function' directly and clearly summarizes the main change—adding a new FFI function for transaction broadcasting to the dash-spv-ffi module.
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 (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/ffi-transaction-broadcast

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


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

🧹 Nitpick comments (1)
dash-spv-ffi/src/client.rs (1)

489-489: Consider guarding against length == 0 before creating the slice.

While from_raw_parts with length == 0 is technically safe (no memory is read), and deserialization would fail anyway, an explicit zero-length check would provide a clearer error message to FFI callers ("empty transaction data") rather than a cryptic deserialization error.

🛡️ Optional: add zero-length guard
     null_check!(client);
     null_check!(tx_bytes);
 
+    if length == 0 {
+        set_last_error("Invalid transaction: empty transaction data");
+        return FFIErrorCode::InvalidArgument as i32;
+    }
+
     let tx_bytes = std::slice::from_raw_parts(tx_bytes, length);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@dash-spv-ffi/src/client.rs` at line 489, Add an explicit guard before the
slice creation: check if length == 0 before the line that creates tx_bytes with
std::slice::from_raw_parts, and if so return an FFI-friendly error (e.g.,
propagate the module’s existing error/return pattern with a clear message like
"empty transaction data") instead of attempting deserialization; this ensures
the tx_bytes/length check happens early and callers receive a descriptive error
rather than a cryptic deserialization failure.
🤖 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/client.rs`:
- Around line 473-512: Add unit and C tests covering
dash_spv_ffi_client_broadcast_transaction: create a Rust unit test file
(tests/unit/test_broadcast_transaction.rs) with tests that (1) call
dash_spv_ffi_client_broadcast_transaction with a valid serialized
dashcore::Transaction and a test FFIDashSpvClient whose inner DashSpvClient mock
returns Ok => assert return is FFIErrorCode::Success and no last error, (2) call
with malformed tx bytes => assert it returns FFIErrorCode::InvalidArgument and
set_last_error contains "Invalid transaction", and (3) mock
inner.broadcast_transaction to return an error => assert returned code equals
FFIErrorCode::from(err) and last error contains "Failed to broadcast
transaction". Also add a C test (tests/c_tests/test_broadcast_transaction.c)
that links the FFI, invokes dash_spv_ffi_client_broadcast_transaction for the
same three scenarios, checks return codes and reads error text via
dash_spv_ffi_get_last_error, and cleans up the test client; reference the
function dash_spv_ffi_client_broadcast_transaction, the FFIDashSpvClient
construction helper used elsewhere in tests, set_last_error, and
dash_spv_ffi_get_last_error to locate relevant helpers. Ensure mocks or test
helpers initialize client.runtime consistently with other tests.

---

Nitpick comments:
In `@dash-spv-ffi/src/client.rs`:
- Line 489: Add an explicit guard before the slice creation: check if length ==
0 before the line that creates tx_bytes with std::slice::from_raw_parts, and if
so return an FFI-friendly error (e.g., propagate the module’s existing
error/return pattern with a clear message like "empty transaction data") instead
of attempting deserialization; this ensures the tx_bytes/length check happens
early and callers receive a descriptive error rather than a cryptic
deserialization failure.

Comment on lines +473 to +512
/// Broadcasts a transaction to the Dash network via connected peers.
///
/// # Safety
///
/// - `client` must be a valid, non-null pointer to an initialized FFIDashSpvClient
/// - `tx_bytes` must be a valid, non-null pointer to the transaction data
/// - `length` must be the length of the transaction data in bytes
#[no_mangle]
pub unsafe extern "C" fn dash_spv_ffi_client_broadcast_transaction(
client: *mut FFIDashSpvClient,
tx_bytes: *const u8,
length: usize,
) -> i32 {
null_check!(client);
null_check!(tx_bytes);

let tx_bytes = std::slice::from_raw_parts(tx_bytes, length);

let tx = match dashcore::consensus::deserialize::<dashcore::Transaction>(tx_bytes) {
Ok(t) => t,
Err(e) => {
set_last_error(&format!("Invalid transaction: {}", e));
return FFIErrorCode::InvalidArgument as i32;
}
};

let client = &(*client);

let spv_client = client.inner.clone();

let result = client.runtime.block_on(async { spv_client.broadcast_transaction(&tx).await });

match result {
Ok(_) => FFIErrorCode::Success as i32,
Err(e) => {
set_last_error(&format!("Failed to broadcast transaction: {}", e));
FFIErrorCode::from(e) as i32
}
}
}
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 | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

echo "=== Searching for broadcast_transaction method definition ==="
rg -n 'fn broadcast_transaction' --type=rust -C 3

echo ""
echo "=== Searching for unit tests related to broadcast_transaction ==="
rg -n 'broadcast_transaction' --type=rust dash-spv-ffi/tests/ 2>/dev/null || echo "No matches in tests/"

echo ""
echo "=== Checking dash-spv-ffi test directory structure ==="
find dash-spv-ffi/tests -type f -name "*.rs" 2>/dev/null | head -20

echo ""
echo "=== Checking for test modules in client.rs ==="
rg -n '#\[cfg\(test\)\]' dash-spv-ffi/src/client.rs -A 30 || echo "No test module found in client.rs"

Repository: dashpay/rust-dashcore

Length of output: 2128


🏁 Script executed:

#!/bin/bash

echo "=== Checking for C tests directory ==="
find dash-spv-ffi/tests -type d -name 'c_tests' -o -type d -name '*c*test*'

echo ""
echo "=== Checking if broadcast_transaction FFI function appears in C tests ==="
fd -t f '\.(c|h)$' dash-spv-ffi/tests/ -x grep -l 'broadcast_transaction' {} \;

echo ""
echo "=== Looking at the test file that uses broadcast_transaction ==="
head -50 dash-spv-ffi/tests/integration/test_full_workflow.rs | tail -30

Repository: dashpay/rust-dashcore

Length of output: 1459


Add unit and C tests for dash_spv_ffi_client_broadcast_transaction.

The implementation is correct and follows existing FFI patterns. The broadcast_transaction method exists on DashSpvClient and accepts the expected &dashcore::Transaction parameter.

However, per project conventions, new FFI functions require:

  • Unit tests in tests/unit/ (currently missing; only integration and security tests exist)
  • C tests in tests/c_tests/ (currently missing)

Existing test coverage in tests/integration/test_full_workflow.rs and tests/security/test_security.rs is helpful but does not satisfy the unit test requirements outlined in the coding guidelines.

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

In `@dash-spv-ffi/src/client.rs` around lines 473 - 512, Add unit and C tests
covering dash_spv_ffi_client_broadcast_transaction: create a Rust unit test file
(tests/unit/test_broadcast_transaction.rs) with tests that (1) call
dash_spv_ffi_client_broadcast_transaction with a valid serialized
dashcore::Transaction and a test FFIDashSpvClient whose inner DashSpvClient mock
returns Ok => assert return is FFIErrorCode::Success and no last error, (2) call
with malformed tx bytes => assert it returns FFIErrorCode::InvalidArgument and
set_last_error contains "Invalid transaction", and (3) mock
inner.broadcast_transaction to return an error => assert returned code equals
FFIErrorCode::from(err) and last error contains "Failed to broadcast
transaction". Also add a C test (tests/c_tests/test_broadcast_transaction.c)
that links the FFI, invokes dash_spv_ffi_client_broadcast_transaction for the
same three scenarios, checks return codes and reads error text via
dash_spv_ffi_get_last_error, and cleans up the test client; reference the
function dash_spv_ffi_client_broadcast_transaction, the FFIDashSpvClient
construction helper used elsewhere in tests, set_last_error, and
dash_spv_ffi_get_last_error to locate relevant helpers. Ensure mocks or test
helpers initialize client.runtime consistently with other tests.

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.

Agree with CodeRabbit, a test would have been nice.

@xdustinface xdustinface merged commit 84f701c into v0.42-dev Feb 21, 2026
53 checks passed
@xdustinface xdustinface deleted the feat/ffi-transaction-broadcast branch February 21, 2026 01:13
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.

2 participants