Skip to content
Open
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
13 changes: 13 additions & 0 deletions dash-spv-ffi/include/dash_spv_ffi.h
Original file line number Diff line number Diff line change
Expand Up @@ -375,12 +375,24 @@ typedef struct FFINetworkEventCallbacks {
* copy any data they need to retain after the callback returns.
*/
typedef void (*OnTransactionReceivedCallback)(const char *wallet_id,
FFITransactionContext status,
uint32_t account_index,
const uint8_t (*txid)[32],
int64_t amount,
const char *addresses,
void *user_data);

/**
* Callback for WalletEvent::TransactionStatusChanged
*
* The `wallet_id` string pointer and `txid` hash pointer are borrowed and only
* valid for the duration of the callback.
*/
typedef void (*OnTransactionStatusChangedCallback)(const char *wallet_id,
const uint8_t (*txid)[32],
FFITransactionContext status,
void *user_data);

/**
* Callback for WalletEvent::BalanceUpdated
*
Expand All @@ -406,6 +418,7 @@ typedef void (*OnBalanceUpdatedCallback)(const char *wallet_id,
*/
typedef struct FFIWalletEventCallbacks {
OnTransactionReceivedCallback on_transaction_received;
OnTransactionStatusChangedCallback on_transaction_status_changed;
OnBalanceUpdatedCallback on_balance_updated;
void *user_data;
} FFIWalletEventCallbacks;
Expand Down
17 changes: 15 additions & 2 deletions dash-spv-ffi/src/bin/ffi_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::ptr;
use clap::{Arg, ArgAction, Command};

use dash_spv_ffi::*;
use key_wallet_ffi::types::FFITransactionContext;
use key_wallet_ffi::wallet_manager::wallet_manager_add_wallet_from_mnemonic;
use key_wallet_ffi::{FFIError, FFINetwork};

Expand Down Expand Up @@ -150,6 +151,7 @@ extern "C" fn on_peers_updated(connected_count: u32, best_height: u32, _user_dat

extern "C" fn on_transaction_received(
wallet_id: *const c_char,
status: FFITransactionContext,
account_index: u32,
txid: *const [u8; 32],
amount: i64,
Expand All @@ -165,11 +167,21 @@ extern "C" fn on_transaction_received(
};
let txid_hex = unsafe { hex::encode(*txid) };
println!(
"[Wallet] TX received: wallet={}..., txid={}, account={}, amount={} duffs, addresses={}",
wallet_short, txid_hex, account_index, amount, addr_str
"[Wallet] TX received: wallet={}..., txid={}, account={}, amount={} duffs, status={:?}, addresses={}",
wallet_short, txid_hex, account_index, amount, status, addr_str
);
}

extern "C" fn on_transaction_status_changed(
_wallet_id: *const c_char,
txid: *const [u8; 32],
status: FFITransactionContext,
_user_data: *mut c_void,
) {
let txid_hex = unsafe { hex::encode(*txid) };
println!("[Wallet] TX status changed: txid={}, status={:?}", txid_hex, status);
}

extern "C" fn on_balance_updated(
wallet_id: *const c_char,
spendable: u64,
Expand Down Expand Up @@ -431,6 +443,7 @@ fn main() {

let wallet_callbacks = FFIWalletEventCallbacks {
on_transaction_received: Some(on_transaction_received),
on_transaction_status_changed: Some(on_transaction_status_changed),
on_balance_updated: Some(on_balance_updated),
user_data: ptr::null_mut(),
};
Expand Down
36 changes: 36 additions & 0 deletions dash-spv-ffi/src/callbacks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use crate::{dash_spv_ffi_sync_progress_destroy, FFISyncProgress};
use dashcore::hashes::Hash;
use key_wallet::manager::WalletEvent;
use key_wallet_ffi::types::FFITransactionContext;
use std::ffi::CString;
use std::os::raw::{c_char, c_void};

Expand Down Expand Up @@ -523,6 +524,7 @@ impl FFINetworkEventCallbacks {
pub type OnTransactionReceivedCallback = Option<
extern "C" fn(
wallet_id: *const c_char,
status: FFITransactionContext,
account_index: u32,
txid: *const [u8; 32],
amount: i64,
Expand All @@ -531,6 +533,19 @@ pub type OnTransactionReceivedCallback = Option<
),
>;

/// Callback for WalletEvent::TransactionStatusChanged
///
/// The `wallet_id` string pointer and `txid` hash pointer are borrowed and only
/// valid for the duration of the callback.
pub type OnTransactionStatusChangedCallback = Option<
extern "C" fn(
wallet_id: *const c_char,
txid: *const [u8; 32],
status: FFITransactionContext,
user_data: *mut c_void,
),
>;

/// Callback for WalletEvent::BalanceUpdated
///
/// The `wallet_id` string pointer is borrowed and only valid for the duration
Expand Down Expand Up @@ -558,6 +573,7 @@ pub type OnBalanceUpdatedCallback = Option<
#[derive(Clone)]
pub struct FFIWalletEventCallbacks {
pub on_transaction_received: OnTransactionReceivedCallback,
pub on_transaction_status_changed: OnTransactionStatusChangedCallback,
pub on_balance_updated: OnBalanceUpdatedCallback,
pub user_data: *mut c_void,
}
Expand All @@ -570,6 +586,7 @@ impl Default for FFIWalletEventCallbacks {
fn default() -> Self {
Self {
on_transaction_received: None,
on_transaction_status_changed: None,
on_balance_updated: None,
user_data: std::ptr::null_mut(),
}
Expand Down Expand Up @@ -624,6 +641,7 @@ impl FFIWalletEventCallbacks {
match event {
WalletEvent::TransactionReceived {
wallet_id,
status,
account_index,
txid,
amount,
Expand All @@ -638,6 +656,7 @@ impl FFIWalletEventCallbacks {
let c_addresses = CString::new(addresses_str.join(",")).unwrap_or_default();
cb(
c_wallet_id.as_ptr(),
FFITransactionContext::from(*status),
*account_index,
txid_bytes as *const [u8; 32],
*amount,
Expand All @@ -646,6 +665,23 @@ impl FFIWalletEventCallbacks {
);
}
}
WalletEvent::TransactionStatusChanged {
wallet_id,
txid,
status,
} => {
if let Some(cb) = self.on_transaction_status_changed {
let wallet_id_hex = hex::encode(wallet_id);
let c_wallet_id = CString::new(wallet_id_hex).unwrap_or_default();
let txid_bytes = txid.as_byte_array();
cb(
c_wallet_id.as_ptr(),
txid_bytes as *const [u8; 32],
FFITransactionContext::from(*status),
self.user_data,
);
}
}
WalletEvent::BalanceUpdated {
wallet_id,
spendable,
Expand Down
17 changes: 17 additions & 0 deletions dash-spv-ffi/tests/dashd_sync/callbacks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::sync::{Arc, Mutex};
use std::time::Duration;

use dash_spv_ffi::*;
use key_wallet_ffi::types::FFITransactionContext;

/// Tracks callback invocations for verification.
///
Expand Down Expand Up @@ -36,6 +37,7 @@ pub(super) struct CallbackTracker {

// Wallet event tracking
pub(super) transaction_received_count: AtomicU32,
pub(super) transaction_status_changed_count: AtomicU32,
pub(super) balance_updated_count: AtomicU32,

// Data from callbacks
Expand Down Expand Up @@ -334,6 +336,7 @@ extern "C" fn on_peers_updated(connected_count: u32, best_height: u32, user_data

extern "C" fn on_transaction_received(
wallet_id: *const c_char,
_status: FFITransactionContext,
account_index: u32,
txid: *const [u8; 32],
amount: i64,
Expand All @@ -358,6 +361,19 @@ extern "C" fn on_transaction_received(
);
}

extern "C" fn on_transaction_status_changed(
_wallet_id: *const c_char,
_txid: *const [u8; 32],
status: FFITransactionContext,
user_data: *mut c_void,
) {
let Some(tracker) = (unsafe { tracker_from(user_data) }) else {
return;
};
tracker.transaction_status_changed_count.fetch_add(1, Ordering::SeqCst);
tracing::debug!("on_transaction_status_changed: status={:?}", status);
}

extern "C" fn on_balance_updated(
wallet_id: *const c_char,
spendable: u64,
Expand Down Expand Up @@ -427,6 +443,7 @@ pub(super) fn create_network_callbacks(tracker: &Arc<CallbackTracker>) -> FFINet
pub(super) fn create_wallet_callbacks(tracker: &Arc<CallbackTracker>) -> FFIWalletEventCallbacks {
FFIWalletEventCallbacks {
on_transaction_received: Some(on_transaction_received),
on_transaction_status_changed: Some(on_transaction_status_changed),
on_balance_updated: Some(on_balance_updated),
user_data: Arc::as_ptr(tracker) as *mut c_void,
}
Expand Down
12 changes: 11 additions & 1 deletion dash-spv-ffi/tests/dashd_sync/tests_callback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,23 @@ fn test_all_callbacks_during_sync() {
// Validate wallet event callbacks (test wallet has transactions)
let tx_received = tracker.transaction_received_count.load(Ordering::SeqCst);
let balance_updated = tracker.balance_updated_count.load(Ordering::SeqCst);
let tx_status_changed = tracker.transaction_status_changed_count.load(Ordering::SeqCst);

tracing::info!("Wallet: tx_received={}, balance_updated={}", tx_received, balance_updated);
tracing::info!(
"Wallet: tx_received={}, tx_status_changed={}, balance_updated={}",
tx_received,
tx_status_changed,
balance_updated
);

assert!(
tx_received > 0,
"on_transaction_received should fire for wallet with transactions"
);
assert_eq!(
tx_status_changed, 0,
"on_transaction_status_changed should not fire here, all transactions are confirmed."
);
assert!(balance_updated > 0, "on_balance_updated should fire for wallet with transactions");

// Validate sync cycle (initial sync is cycle 0)
Expand Down
Loading
Loading