Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
eb016f5
ci: add Manki AI code review configuration (#73)
xdustinface Mar 30, 2026
5c746ac
chore: update manki action reference to `manki-review/manki` (#88)
xdustinface Apr 6, 2026
1e2a317
feat: track and persist session peer outcomes (#106)
xdustinface Apr 17, 2026
53b25c4
refactor: heights per wallet (#117)
xdustinface Apr 27, 2026
efbd98a
refactor: make wallet events atomic
xdustinface Apr 25, 2026
d35594d
fix: gate post-sync block mining on mempool callback in `tests_callback`
xdustinface Apr 27, 2026
e5154cf
test: assert `mempool_received == 0` during initial historical sync
xdustinface Apr 27, 2026
ebf8d81
test: assert `SyncedHeightUpdated` fires and reaches tip during sync
xdustinface Apr 27, 2026
3747aa8
fix: don't bump `last_processed_height` from `update_synced_height`
xdustinface Apr 27, 2026
92a6e52
fix: pass null `updates` pointer when `BlockProcessChange` is empty
xdustinface Apr 27, 2026
376c863
test: separate mempool/block trackers and assert action and account_path
xdustinface Apr 27, 2026
ec47c4c
test: pin down late IS-lock-after-confirmation emission behavior
xdustinface Apr 27, 2026
538c440
test: bump callback counter before record counter to avoid race
xdustinface Apr 27, 2026
a3bfe37
refactor: apply rustfmt to test callback assertions
xdustinface Apr 27, 2026
b173f54
test: tighten ffi callback ordering and assertions
xdustinface Apr 27, 2026
51bf6e7
feat: surface dropped-record count in `CheckTransactionsResult`
xdustinface Apr 27, 2026
a9b17e1
refactor: apply `cargo fmt` to test files
xdustinface Apr 27, 2026
3d22754
fix: address review feedback on wallet event atomicity
xdustinface Apr 27, 2026
b374bb2
fix: tighten test slice bounds and mempool path assertion
xdustinface Apr 27, 2026
c4a3a91
refactor: rename wallet event variants and switch FFI to typed accoun…
xdustinface Apr 27, 2026
1e70d77
refactor: store `account_type` on `TransactionRecord`
xdustinface Apr 27, 2026
5e678d7
refactor: rename `RecordChange` to `TransactionRecordUpdate`
xdustinface Apr 27, 2026
178feb7
refactor: consolidate FFI wallet types in `key-wallet-ffi`
xdustinface Apr 27, 2026
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
29 changes: 29 additions & 0 deletions .github/workflows/manki.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Manki Review

on:
pull_request:
types: [opened, synchronize]
issue_comment:
types: [created, edited]
pull_request_review:
types: [submitted]

permissions:
contents: read
pull-requests: write
issues: write
id-token: write

concurrency:
group: manki-${{ github.event_name }}-${{ github.event.pull_request.number || github.event.issue.number || github.run_id }}
cancel-in-progress: false

jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: manki-review/manki@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
18 changes: 18 additions & 0 deletions .manki.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Manki — AI Code Review Configuration
# https://github.com/manki-review/manki

auto_review: true
auto_approve: true

exclude_paths:
- "*.lock"
- "fuzz/**"

instructions: |
This is a Rust implementation of the Dash cryptocurrency protocol.
Pay special attention to:
- Consensus-critical code paths — changes here can cause chain splits
- FFI safety for C/Swift bindings in dash-spv-* crates
- Proper error handling — prefer Result over unwrap/expect in library code
- DIP (Dash Improvement Proposal) compliance for protocol changes
- Memory safety in hash/crypto implementations
104 changes: 66 additions & 38 deletions dash-spv-ffi/src/bin/ffi_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ use std::ptr;
use clap::{Arg, ArgAction, Command};
use dash_network::ffi::FFINetwork;
use dash_spv_ffi::*;
use key_wallet_ffi::managed_account::FFITransactionRecord;
use key_wallet_ffi::types::FFITransactionContext;
use key_wallet_ffi::types::FFIBalance;
use key_wallet_ffi::wallet_manager::wallet_manager_add_wallet_from_mnemonic;
use key_wallet_ffi::FFIError;

Expand Down Expand Up @@ -156,63 +155,91 @@ extern "C" fn on_peers_updated(connected_count: u32, best_height: u32, _user_dat
// Wallet Event Callbacks
// ============================================================================

fn short_wallet(wallet_id: *const c_char) -> String {
let s = ffi_string_to_rust(wallet_id);
if s.len() > 8 {
s[..8].to_string()
} else {
s
}
}

fn read_balance(balance: *const FFIBalance) -> FFIBalance {
if balance.is_null() {
tracing::warn!("read_balance: null pointer, returning zero balance");
return FFIBalance::default();
}
unsafe { *balance }
}

Comment thread
xdustinface marked this conversation as resolved.
extern "C" fn on_transaction_received(
wallet_id: *const c_char,
account_index: u32,
record: *const FFITransactionRecord,
update: *const FFITransactionRecordUpdate,
balance: *const FFIBalance,
_user_data: *mut c_void,
) {
let wallet_str = ffi_string_to_rust(wallet_id);
let wallet_short = if wallet_str.len() > 8 {
&wallet_str[..8]
} else {
&wallet_str
};
if record.is_null() {
println!(
"[Wallet] TX received: wallet={}..., account={}, record=null",
wallet_short, account_index
);
let wallet_short = short_wallet(wallet_id);
if update.is_null() {
println!("[Wallet] TX received: wallet={}..., update=null", wallet_short);
return;
}
let r = unsafe { &*record };
let txid_hex = hex::encode(r.txid);
let u = unsafe { &*update };
let b = read_balance(balance);
let txid_hex = hex::encode(u.record.txid);
println!(
"[Wallet] TX received: wallet={}..., txid={}, account={}, amount={} duffs, tx_size={}",
wallet_short, txid_hex, account_index, r.net_amount, r.tx_len
"[Wallet] TX received: wallet={}..., txid={}, account_type={:?}, account_index={}, amount={} duffs, balance[confirmed={}, unconfirmed={}]",
wallet_short,
txid_hex,
u.record.account_type,
u.record.account_index,
u.record.net_amount,
b.confirmed,
b.unconfirmed
);
}

extern "C" fn on_transaction_status_changed(
_wallet_id: *const c_char,
extern "C" fn on_transaction_instant_send_locked(
wallet_id: *const c_char,
txid: *const [u8; 32],
status: FFITransactionContext,
_islock_data: *const u8,
_islock_len: usize,
balance: *const FFIBalance,
_user_data: *mut c_void,
) {
let wallet_short = short_wallet(wallet_id);
let txid_hex = unsafe { hex::encode(*txid) };
println!("[Wallet] TX status changed: txid={}, status={:?}", txid_hex, status);
let b = read_balance(balance);
println!(
"[Wallet] IS lock: wallet={}..., txid={}, balance[confirmed={}]",
wallet_short, txid_hex, b.confirmed
);
}

extern "C" fn on_balance_updated(
extern "C" fn on_wallet_block_processed(
wallet_id: *const c_char,
spendable: u64,
unconfirmed: u64,
immature: u64,
locked: u64,
height: u32,
_updates: *const FFITransactionRecordUpdate,
update_count: u32,
balance: *const FFIBalance,
_user_data: *mut c_void,
) {
let wallet_str = ffi_string_to_rust(wallet_id);
let wallet_short = if wallet_str.len() > 8 {
&wallet_str[..8]
} else {
&wallet_str
};
let wallet_short = short_wallet(wallet_id);
let b = read_balance(balance);
println!(
"[Wallet] Balance updated: wallet={}..., spendable={}, unconfirmed={}, immature={}, locked={}",
wallet_short, spendable, unconfirmed, immature, locked
"[Wallet] Block processed: wallet={}..., height={}, updates={}, balance[confirmed={}, unconfirmed={}, immature={}, locked={}]",
wallet_short, height, update_count, b.confirmed, b.unconfirmed, b.immature, b.locked
);
}

extern "C" fn on_synced_height_updated(
wallet_id: *const c_char,
height: u32,
_user_data: *mut c_void,
) {
let wallet_short = short_wallet(wallet_id);
println!("[Wallet] Synced height updated: wallet={}..., height={}", wallet_short, height);
}

// ============================================================================
// Progress Callback
// ============================================================================
Expand Down Expand Up @@ -435,8 +462,9 @@ fn main() {
},
wallet: FFIWalletEventCallbacks {
on_transaction_received: Some(on_transaction_received),
on_transaction_status_changed: Some(on_transaction_status_changed),
on_balance_updated: Some(on_balance_updated),
on_transaction_instant_send_locked: Some(on_transaction_instant_send_locked),
on_block_processed: Some(on_wallet_block_processed),
on_synced_height_updated: Some(on_synced_height_updated),
user_data: ptr::null_mut(),
},
error: FFIClientErrorCallback {
Expand Down
Loading
Loading