Merge pull request #696 from logos-blockchain/Pravdyvy/ffi-tx-status-poll

feat(wallet_ffi): Tx status polling
This commit is contained in:
Pravdyvy 2026-08-10 14:35:07 +03:00 committed by GitHub
commit 87fca2a176
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 93 additions and 1 deletions

1
Cargo.lock generated
View File

@ -11574,6 +11574,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"bip39", "bip39",
"cbindgen", "cbindgen",
"common",
"key_protocol", "key_protocol",
"lee", "lee",
"lee_core", "lee_core",

View File

@ -284,6 +284,12 @@ unsafe extern "C" {
) -> LabelList; ) -> LabelList;
fn wallet_ffi_free_label_list(label_list: *mut LabelList) -> error::WalletFfiError; fn wallet_ffi_free_label_list(label_list: *mut LabelList) -> error::WalletFfiError;
fn wallet_ffi_poll_transaction_status(
handle: *mut WalletHandle,
tx_hash: FfiBytes32,
transaction_status: *mut bool,
) -> error::WalletFfiError;
} }
fn new_wallet_ffi_with_test_context_config( fn new_wallet_ffi_with_test_context_config(
@ -987,8 +993,18 @@ fn test_wallet_ffi_transfer_public() -> Result<()> {
assert_eq!(from_balance, 9900); assert_eq!(from_balance, 9900);
assert_eq!(to_balance, 20100); assert_eq!(to_balance, 20100);
// Also check for transaction inclusion
let hash_bytes = unsafe { transfer_result.tx_hash_bytes() };
let mut is_included = false;
unsafe {
wallet_ffi_poll_transaction_status(wallet_ffi_handle, hash_bytes, &raw mut is_included)
.unwrap();
}
assert!(is_included);
unsafe { unsafe {
wallet_ffi_free_transfer_result(&raw mut transfer_result);
wallet_ffi_destroy(wallet_ffi_handle); wallet_ffi_destroy(wallet_ffi_handle);
} }

View File

@ -14,6 +14,7 @@ crate-type = ["rlib", "cdylib", "staticlib"]
wallet.workspace = true wallet.workspace = true
lee.workspace = true lee.workspace = true
lee_core.workspace = true lee_core.workspace = true
common.workspace = true
programs.workspace = true programs.workspace = true
tokio.workspace = true tokio.workspace = true

View File

@ -3,6 +3,7 @@ use std::{
ffi::{c_char, CString}, ffi::{c_char, CString},
}; };
use common::HashType;
use lee::{privacy_preserving_transaction::circuit::ProgramWithDependencies, program::Program}; use lee::{privacy_preserving_transaction::circuit::ProgramWithDependencies, program::Program};
use crate::{ use crate::{
@ -390,6 +391,43 @@ pub unsafe extern "C" fn wallet_ffi_send_generic_private_transaction(
} }
} }
/// Poll transaction for its status.
///
/// # Parameters
/// - `handle`: Valid pointer to wallet handle.
/// - `tx_hash`: Bytes of a transaction hash,
/// - `transaction_status`: Valid pointer into `bool`.
///
/// # Returns
/// - `true` if seen included, `false` othervise.
///
/// # Safety
/// - `handle` must be a valid pointer.
#[no_mangle]
pub unsafe extern "C" fn wallet_ffi_poll_transaction_status(
handle: *mut WalletHandle,
tx_hash: FfiBytes32,
// ToDo: Replace with status enum.
transaction_status: *mut bool,
) -> WalletFfiError {
let wrapper = match get_wallet(handle) {
Ok(w) => w,
Err(e) => return e,
};
let wallet = match wrapper.core.lock() {
Ok(w) => w,
Err(e) => {
print_error(format!("Failed to lock wallet: {e}"));
return WalletFfiError::InternalError;
}
};
*transaction_status = block_on(wallet.poll_transaction(HashType(tx_hash.data))).is_ok();
WalletFfiError::Success
}
/// Free a transaction result returned by `wallet_ffi_send_generic_public_transaction` or /// Free a transaction result returned by `wallet_ffi_send_generic_public_transaction` or
/// `wallet_ffi_send_generic_private_transaction`. /// `wallet_ffi_send_generic_private_transaction`.
/// ///

View File

@ -7,6 +7,7 @@ use std::{
str::FromStr as _, str::FromStr as _,
}; };
use common::HashType;
use lee::{Data, ProgramId, SharedSecretKey}; use lee::{Data, ProgramId, SharedSecretKey};
use lee_core::{ use lee_core::{
encryption::MlKem768EncapsulationKey, program::PdaSeed, AuthorizationSecretKey, encryption::MlKem768EncapsulationKey, program::PdaSeed, AuthorizationSecretKey,
@ -159,6 +160,7 @@ impl Default for FfiAccountList {
/// Result of a transfer operation. /// Result of a transfer operation.
#[repr(C)] #[repr(C)]
#[derive(Debug)]
pub struct FfiTransferResult { pub struct FfiTransferResult {
// TODO: Replace with HashType FFI representation // TODO: Replace with HashType FFI representation
/// Transaction hash (null-terminated string, or null on failure). /// Transaction hash (null-terminated string, or null on failure).
@ -176,6 +178,22 @@ impl Default for FfiTransferResult {
} }
} }
impl FfiTransferResult {
#[must_use]
/// Casting valid results hash into bytes. Effectively frees `FfiTransferResult`.
///
/// # Safety
/// Field `tx_hash` must be a valid pointer into transaction hash.
pub unsafe fn tx_hash_bytes(self) -> FfiBytes32 {
let cstring = unsafe { CString::from_raw(self.tx_hash) };
let rstring = cstring.into_string().expect("Must be a valid Rust string");
let hash_val = HashType::from_str(&rstring).expect("Must be a valid hex string");
FfiBytes32 { data: hash_val.0 }
}
}
// Helper functions to convert between Rust and FFI types // Helper functions to convert between Rust and FFI types
impl FfiBytes32 { impl FfiBytes32 {

View File

@ -669,6 +669,24 @@ enum WalletFfiError wallet_ffi_send_generic_private_transaction(struct WalletHan
const struct FfiProgramWithDependencies *program_with_dependencies, const struct FfiProgramWithDependencies *program_with_dependencies,
struct FfiTransactionResult *out_result); struct FfiTransactionResult *out_result);
/**
* Poll transaction for its status.
*
* # Parameters
* - `handle`: Valid pointer to wallet handle.
* - `tx_hash`: Bytes of a transaction hash,
* - `transaction_status`: Valid pointer into `bool`.
*
* # Returns
* - `true` if seen included, `false` othervise.
*
* # Safety
* - `handle` must be a valid pointer.
*/
enum WalletFfiError wallet_ffi_poll_transaction_status(struct WalletHandle *handle,
struct FfiBytes32 tx_hash,
bool *transaction_status);
/** /**
* Free a transaction result returned by `wallet_ffi_send_generic_public_transaction` or * Free a transaction result returned by `wallet_ffi_send_generic_public_transaction` or
* `wallet_ffi_send_generic_private_transaction`. * `wallet_ffi_send_generic_private_transaction`.