diff --git a/dash-spv-ffi/Cargo.toml b/dash-spv-ffi/Cargo.toml index c95dac4e5..6341e94eb 100644 --- a/dash-spv-ffi/Cargo.toml +++ b/dash-spv-ffi/Cargo.toml @@ -37,4 +37,4 @@ env_logger = "0.10" dashcore-test-utils = { path = "../test-utils" } [build-dependencies] -cbindgen = "0.26" \ No newline at end of file +cbindgen = "0.29" diff --git a/dash-spv-ffi/FFI_API.md b/dash-spv-ffi/FFI_API.md index 009478074..bb3c087c2 100644 --- a/dash-spv-ffi/FFI_API.md +++ b/dash-spv-ffi/FFI_API.md @@ -536,7 +536,7 @@ Sets whether to relay transactions (currently a no-op) # Safety - `config` must #### `dash_spv_ffi_config_set_restrict_to_configured_peers` ```c -dash_spv_ffi_config_set_restrict_to_configured_peers(config: *mut FFIClientConfig, restrict: bool,) -> i32 +dash_spv_ffi_config_set_restrict_to_configured_peers(config: *mut FFIClientConfig, restrict_peers: bool,) -> i32 ``` **Description:** diff --git a/dash-spv-ffi/build.rs b/dash-spv-ffi/build.rs index cea5ee209..bd1de9edc 100644 --- a/dash-spv-ffi/build.rs +++ b/dash-spv-ffi/build.rs @@ -7,13 +7,21 @@ fn main() { std::fs::create_dir_all(&output_path).unwrap(); - let config = cbindgen::Config::default(); + // Ensure the build script reruns when header-relevant files change + println!("cargo:rerun-if-changed=cbindgen.toml"); + println!("cargo:rerun-if-changed=src"); - cbindgen::Builder::new() - .with_crate(crate_dir) - .with_config(config) - .with_language(cbindgen::Language::C) - .generate() - .expect("Unable to generate bindings") - .write_to_file(output_path.join("dash_spv_ffi.h")); + let config = cbindgen::Config::from_file("cbindgen.toml") + .expect("cbindgen config missing or invalid: cbindgen.toml"); + + match cbindgen::Builder::new().with_crate(&crate_dir).with_config(config).generate() { + Ok(bindings) => { + bindings.write_to_file(output_path.join("dash_spv_ffi.h")); + println!("cargo:warning=Generated C header at {:?}", output_path); + } + Err(e) => { + // Fail the build to avoid shipping stale headers + panic!("Failed to generate C header via cbindgen: {}", e); + } + } } diff --git a/dash-spv-ffi/cbindgen.toml b/dash-spv-ffi/cbindgen.toml index 56077bb51..97954dc4a 100644 --- a/dash-spv-ffi/cbindgen.toml +++ b/dash-spv-ffi/cbindgen.toml @@ -11,7 +11,11 @@ cpp_compat = true [export] include = ["FFI"] exclude = ["Option_BlockCallback", "Option_TransactionCallback", "Option_BalanceCallback"] -prefix = "dash_spv_ffi_" +prefix = "" + +[export.body] +# Forward-declare FFIClientConfig to avoid aliasing to internal ClientConfig in C headers +"FFIClientConfig" = "" [export.rename] "FFIValidationMode" = "DashSpvValidationMode" @@ -32,4 +36,4 @@ parse_deps = false include = [] [macro_expansion] -bitflags = false \ No newline at end of file +bitflags = false diff --git a/dash-spv-ffi/include/dash_spv_ffi.h b/dash-spv-ffi/include/dash_spv_ffi.h index ae4ca7397..bf2c0073e 100644 --- a/dash-spv-ffi/include/dash_spv_ffi.h +++ b/dash-spv-ffi/include/dash_spv_ffi.h @@ -1,8 +1,21 @@ +/* dash-spv-ffi C bindings - Auto-generated by cbindgen */ + +#ifndef DASH_SPV_FFI_H +#define DASH_SPV_FFI_H + +/* Generated with cbindgen:0.29.0 */ + +/* Warning: This file is auto-generated by cbindgen. Do not modify manually. */ + #include #include #include #include +#ifdef __cplusplus +namespace dash_spv_ffi { +#endif // __cplusplus + typedef enum FFIMempoolStrategy { FetchAll = 0, BloomFilter = 1, @@ -19,11 +32,11 @@ typedef enum FFISyncStage { Failed = 6, } FFISyncStage; -typedef enum FFIValidationMode { +typedef enum DashSpvValidationMode { None = 0, Basic = 1, Full = 2, -} FFIValidationMode; +} DashSpvValidationMode; typedef struct FFIDashSpvClient FFIDashSpvClient; @@ -46,7 +59,10 @@ typedef struct FFIArray { uintptr_t elem_align; } FFIArray; -typedef ClientConfig FFIClientConfig; +typedef struct FFIClientConfig { + void *inner; + +} FFIClientConfig; typedef struct FFIString { char *ptr; @@ -193,6 +209,10 @@ typedef struct FFIUnconfirmedTransaction { uintptr_t addresses_len; } FFIUnconfirmedTransaction; +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + /** * Get the latest checkpoint for the given network. * @@ -200,7 +220,11 @@ typedef struct FFIUnconfirmedTransaction { * - `out_height` must be a valid pointer to a `u32`. * - `out_hash` must point to at least 32 writable bytes. */ -int32_t dash_spv_ffi_checkpoint_latest(FFINetwork network, uint32_t *out_height, uint8_t *out_hash); + +int32_t dash_spv_ffi_checkpoint_latest(FFINetwork network, + uint32_t *out_height, + uint8_t *out_hash) +; /** * Get the last checkpoint at or before a given height. @@ -209,10 +233,12 @@ int32_t dash_spv_ffi_checkpoint_latest(FFINetwork network, uint32_t *out_height, * - `out_height` must be a valid pointer to a `u32`. * - `out_hash` must point to at least 32 writable bytes. */ + int32_t dash_spv_ffi_checkpoint_before_height(FFINetwork network, uint32_t height, uint32_t *out_height, - uint8_t *out_hash); + uint8_t *out_hash) +; /** * Get the last checkpoint at or before a given UNIX timestamp (seconds). @@ -221,10 +247,12 @@ int32_t dash_spv_ffi_checkpoint_before_height(FFINetwork network, * - `out_height` must be a valid pointer to a `u32`. * - `out_hash` must point to at least 32 writable bytes. */ + int32_t dash_spv_ffi_checkpoint_before_timestamp(FFINetwork network, uint32_t timestamp, uint32_t *out_height, - uint8_t *out_hash); + uint8_t *out_hash) +; /** * Get all checkpoints between two heights (inclusive). @@ -232,9 +260,11 @@ int32_t dash_spv_ffi_checkpoint_before_timestamp(FFINetwork network, * Returns an `FFIArray` of `FFICheckpoint` items. The caller owns the memory and * must free the array buffer using `dash_spv_ffi_array_destroy` when done. */ + struct FFIArray dash_spv_ffi_checkpoints_between_heights(FFINetwork network, uint32_t start_height, - uint32_t end_height); + uint32_t end_height) +; /** * Create a new SPV client and return an opaque pointer. @@ -243,7 +273,7 @@ struct FFIArray dash_spv_ffi_checkpoints_between_heights(FFINetwork network, * - `config` must be a valid, non-null pointer for the duration of the call. * - The returned pointer must be freed with `dash_spv_ffi_client_destroy`. */ -struct FFIDashSpvClient *dash_spv_ffi_client_new(const FFIClientConfig *config); + struct FFIDashSpvClient *dash_spv_ffi_client_new(const struct FFIClientConfig *config) ; /** * Update the running client's configuration. @@ -253,8 +283,10 @@ struct FFIDashSpvClient *dash_spv_ffi_client_new(const FFIClientConfig *config); * - `config` must be a valid pointer to an `FFIClientConfig`. * - The network in `config` must match the client's network; changing networks at runtime is not supported. */ + int32_t dash_spv_ffi_client_update_config(struct FFIDashSpvClient *client, - const FFIClientConfig *config); + const struct FFIClientConfig *config) +; /** * Start the SPV client. @@ -262,7 +294,7 @@ int32_t dash_spv_ffi_client_update_config(struct FFIDashSpvClient *client, * # Safety * - `client` must be a valid, non-null pointer to a created client. */ -int32_t dash_spv_ffi_client_start(struct FFIDashSpvClient *client); + int32_t dash_spv_ffi_client_start(struct FFIDashSpvClient *client) ; /** * Stop the SPV client. @@ -270,7 +302,7 @@ int32_t dash_spv_ffi_client_start(struct FFIDashSpvClient *client); * # Safety * - `client` must be a valid, non-null pointer to a created client. */ -int32_t dash_spv_ffi_client_stop(struct FFIDashSpvClient *client); + int32_t dash_spv_ffi_client_stop(struct FFIDashSpvClient *client) ; /** * Sync the SPV client to the chain tip. @@ -295,9 +327,11 @@ int32_t dash_spv_ffi_client_stop(struct FFIDashSpvClient *client); * * 0 on success, error code on failure */ + int32_t dash_spv_ffi_client_sync_to_tip(struct FFIDashSpvClient *client, void (*completion_callback)(bool, const char*, void*), - void *user_data); + void *user_data) +; /** * Performs a test synchronization of the SPV client @@ -313,7 +347,7 @@ int32_t dash_spv_ffi_client_sync_to_tip(struct FFIDashSpvClient *client, * This function is unsafe because it dereferences a raw pointer. * The caller must ensure that the client pointer is valid. */ -int32_t dash_spv_ffi_client_test_sync(struct FFIDashSpvClient *client); + int32_t dash_spv_ffi_client_test_sync(struct FFIDashSpvClient *client) ; /** * Sync the SPV client to the chain tip with detailed progress updates. @@ -339,13 +373,15 @@ int32_t dash_spv_ffi_client_test_sync(struct FFIDashSpvClient *client); * * 0 on success, error code on failure */ + int32_t dash_spv_ffi_client_sync_to_tip_with_progress(struct FFIDashSpvClient *client, void (*progress_callback)(const struct FFIDetailedSyncProgress*, void*), void (*completion_callback)(bool, const char*, void*), - void *user_data); + void *user_data) +; /** * Cancels the sync operation. @@ -361,7 +397,7 @@ int32_t dash_spv_ffi_client_sync_to_tip_with_progress(struct FFIDashSpvClient *c * # Returns * Returns 0 on success, or an error code on failure. */ -int32_t dash_spv_ffi_client_cancel_sync(struct FFIDashSpvClient *client); + int32_t dash_spv_ffi_client_cancel_sync(struct FFIDashSpvClient *client) ; /** * Get the current sync progress snapshot. @@ -369,7 +405,7 @@ int32_t dash_spv_ffi_client_cancel_sync(struct FFIDashSpvClient *client); * # Safety * - `client` must be a valid, non-null pointer. */ -struct FFISyncProgress *dash_spv_ffi_client_get_sync_progress(struct FFIDashSpvClient *client); + struct FFISyncProgress *dash_spv_ffi_client_get_sync_progress(struct FFIDashSpvClient *client) ; /** * Get current runtime statistics for the SPV client. @@ -377,7 +413,7 @@ struct FFISyncProgress *dash_spv_ffi_client_get_sync_progress(struct FFIDashSpvC * # Safety * - `client` must be a valid, non-null pointer. */ -struct FFISpvStats *dash_spv_ffi_client_get_stats(struct FFIDashSpvClient *client); + struct FFISpvStats *dash_spv_ffi_client_get_stats(struct FFIDashSpvClient *client) ; /** * Check if compact filter sync is currently available. @@ -385,7 +421,7 @@ struct FFISpvStats *dash_spv_ffi_client_get_stats(struct FFIDashSpvClient *clien * # Safety * - `client` must be a valid, non-null pointer. */ -bool dash_spv_ffi_client_is_filter_sync_available(struct FFIDashSpvClient *client); + bool dash_spv_ffi_client_is_filter_sync_available(struct FFIDashSpvClient *client) ; /** * Set event callbacks for the client. @@ -393,8 +429,10 @@ bool dash_spv_ffi_client_is_filter_sync_available(struct FFIDashSpvClient *clien * # Safety * - `client` must be a valid, non-null pointer. */ + int32_t dash_spv_ffi_client_set_event_callbacks(struct FFIDashSpvClient *client, - struct FFIEventCallbacks callbacks); + struct FFIEventCallbacks callbacks) +; /** * Destroy the client and free associated resources. @@ -402,7 +440,7 @@ int32_t dash_spv_ffi_client_set_event_callbacks(struct FFIDashSpvClient *client, * # Safety * - `client` must be either null or a pointer obtained from `dash_spv_ffi_client_new`. */ -void dash_spv_ffi_client_destroy(struct FFIDashSpvClient *client); + void dash_spv_ffi_client_destroy(struct FFIDashSpvClient *client) ; /** * Destroy a `FFISyncProgress` object returned by this crate. @@ -410,7 +448,7 @@ void dash_spv_ffi_client_destroy(struct FFIDashSpvClient *client); * # Safety * - `progress` must be a pointer returned from this crate, or null. */ -void dash_spv_ffi_sync_progress_destroy(struct FFISyncProgress *progress); + void dash_spv_ffi_sync_progress_destroy(struct FFISyncProgress *progress) ; /** * Destroy an `FFISpvStats` object returned by this crate. @@ -418,7 +456,7 @@ void dash_spv_ffi_sync_progress_destroy(struct FFISyncProgress *progress); * # Safety * - `stats` must be a pointer returned from this crate, or null. */ -void dash_spv_ffi_spv_stats_destroy(struct FFISpvStats *stats); + void dash_spv_ffi_spv_stats_destroy(struct FFISpvStats *stats) ; /** * Request a rescan of the blockchain from a given height (not yet implemented). @@ -426,8 +464,10 @@ void dash_spv_ffi_spv_stats_destroy(struct FFISpvStats *stats); * # Safety * - `client` must be a valid, non-null pointer. */ + int32_t dash_spv_ffi_client_rescan_blockchain(struct FFIDashSpvClient *client, - uint32_t _from_height); + uint32_t _from_height) +; /** * Enable mempool tracking with a given strategy. @@ -435,8 +475,10 @@ int32_t dash_spv_ffi_client_rescan_blockchain(struct FFIDashSpvClient *client, * # Safety * - `client` must be a valid, non-null pointer. */ + int32_t dash_spv_ffi_client_enable_mempool_tracking(struct FFIDashSpvClient *client, - enum FFIMempoolStrategy strategy); + enum FFIMempoolStrategy strategy) +; /** * Record that we attempted to send a transaction by its txid. @@ -444,7 +486,7 @@ int32_t dash_spv_ffi_client_enable_mempool_tracking(struct FFIDashSpvClient *cli * # Safety * - `client` and `txid` must be valid, non-null pointers. */ -int32_t dash_spv_ffi_client_record_send(struct FFIDashSpvClient *client, const char *txid); + int32_t dash_spv_ffi_client_record_send(struct FFIDashSpvClient *client, const char *txid) ; /** * Get the wallet manager from the SPV client @@ -467,13 +509,15 @@ int32_t dash_spv_ffi_client_record_send(struct FFIDashSpvClient *client, const c * # Safety * - `client` must be a valid, non-null pointer. */ -void *dash_spv_ffi_client_get_wallet_manager(struct FFIDashSpvClient *client); -FFIClientConfig *dash_spv_ffi_config_new(FFINetwork network); +void *dash_spv_ffi_client_get_wallet_manager(struct FFIDashSpvClient *client) +; + + struct FFIClientConfig *dash_spv_ffi_config_new(FFINetwork network) ; -FFIClientConfig *dash_spv_ffi_config_mainnet(void); + struct FFIClientConfig *dash_spv_ffi_config_mainnet(void) ; -FFIClientConfig *dash_spv_ffi_config_testnet(void); + struct FFIClientConfig *dash_spv_ffi_config_testnet(void) ; /** * Sets the data directory for storing blockchain data @@ -483,8 +527,10 @@ FFIClientConfig *dash_spv_ffi_config_testnet(void); * - `path` must be a valid null-terminated C string * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_data_dir(FFIClientConfig *config, - const char *path); + +int32_t dash_spv_ffi_config_set_data_dir(struct FFIClientConfig *config, + const char *path) +; /** * Sets the validation mode for the SPV client @@ -493,8 +539,10 @@ int32_t dash_spv_ffi_config_set_data_dir(FFIClientConfig *config, * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_validation_mode(FFIClientConfig *config, - enum FFIValidationMode mode); + +int32_t dash_spv_ffi_config_set_validation_mode(struct FFIClientConfig *config, + enum DashSpvValidationMode mode) +; /** * Sets the maximum number of peers to connect to @@ -503,8 +551,10 @@ int32_t dash_spv_ffi_config_set_validation_mode(FFIClientConfig *config, * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_max_peers(FFIClientConfig *config, - uint32_t max_peers); + +int32_t dash_spv_ffi_config_set_max_peers(struct FFIClientConfig *config, + uint32_t max_peers) +; /** * Adds a peer address to the configuration @@ -518,8 +568,10 @@ int32_t dash_spv_ffi_config_set_max_peers(FFIClientConfig *config, * - `addr` must be a valid null-terminated C string containing a socket address or IP-only string * - The caller must ensure both pointers remain valid for the duration of this call */ -int32_t dash_spv_ffi_config_add_peer(FFIClientConfig *config, - const char *addr); + +int32_t dash_spv_ffi_config_add_peer(struct FFIClientConfig *config, + const char *addr) +; /** * Sets the user agent string to advertise in the P2P handshake @@ -529,8 +581,10 @@ int32_t dash_spv_ffi_config_add_peer(FFIClientConfig *config, * - `user_agent` must be a valid null-terminated C string * - The caller must ensure both pointers remain valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_user_agent(FFIClientConfig *config, - const char *user_agent); + +int32_t dash_spv_ffi_config_set_user_agent(struct FFIClientConfig *config, + const char *user_agent) +; /** * Sets whether to relay transactions (currently a no-op) @@ -539,8 +593,10 @@ int32_t dash_spv_ffi_config_set_user_agent(FFIClientConfig *config, * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_relay_transactions(FFIClientConfig *config, - bool _relay); + +int32_t dash_spv_ffi_config_set_relay_transactions(struct FFIClientConfig *config, + bool _relay) +; /** * Sets whether to load bloom filters @@ -549,8 +605,10 @@ int32_t dash_spv_ffi_config_set_relay_transactions(FFIClientConfig *config, * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_filter_load(FFIClientConfig *config, - bool load_filters); + +int32_t dash_spv_ffi_config_set_filter_load(struct FFIClientConfig *config, + bool load_filters) +; /** * Restrict connections strictly to configured peers (disable DNS discovery and peer store) @@ -558,8 +616,10 @@ int32_t dash_spv_ffi_config_set_filter_load(FFIClientConfig *config, * # Safety * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet */ -int32_t dash_spv_ffi_config_set_restrict_to_configured_peers(FFIClientConfig *config, - bool restrict); + +int32_t dash_spv_ffi_config_set_restrict_to_configured_peers(struct FFIClientConfig *config, + bool restrict_peers) +; /** * Enables or disables masternode synchronization @@ -568,8 +628,10 @@ int32_t dash_spv_ffi_config_set_restrict_to_configured_peers(FFIClientConfig *co * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_masternode_sync_enabled(FFIClientConfig *config, - bool enable); + +int32_t dash_spv_ffi_config_set_masternode_sync_enabled(struct FFIClientConfig *config, + bool enable) +; /** * Gets the network type from the configuration @@ -578,7 +640,7 @@ int32_t dash_spv_ffi_config_set_masternode_sync_enabled(FFIClientConfig *config, * - `config` must be a valid pointer to an FFIClientConfig or null * - If null, returns FFINetwork::Dash as default */ -FFINetwork dash_spv_ffi_config_get_network(const FFIClientConfig *config); + FFINetwork dash_spv_ffi_config_get_network(const struct FFIClientConfig *config) ; /** * Gets the data directory path from the configuration @@ -588,7 +650,7 @@ FFINetwork dash_spv_ffi_config_get_network(const FFIClientConfig *config); * - If null or no data directory is set, returns an FFIString with null pointer * - The returned FFIString must be freed by the caller using `dash_spv_ffi_string_destroy` */ -struct FFIString dash_spv_ffi_config_get_data_dir(const FFIClientConfig *config); + struct FFIString dash_spv_ffi_config_get_data_dir(const struct FFIClientConfig *config) ; /** * Destroys an FFIClientConfig and frees its memory @@ -598,7 +660,9 @@ struct FFIString dash_spv_ffi_config_get_data_dir(const FFIClientConfig *config) * - After calling this function, the config pointer becomes invalid and must not be used * - This function should only be called once per config instance */ -void dash_spv_ffi_config_destroy(FFIClientConfig *config); + +void dash_spv_ffi_config_destroy(struct FFIClientConfig *config) +; /** * Enables or disables mempool tracking @@ -607,8 +671,10 @@ void dash_spv_ffi_config_destroy(FFIClientConfig *config); * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_mempool_tracking(FFIClientConfig *config, - bool enable); + +int32_t dash_spv_ffi_config_set_mempool_tracking(struct FFIClientConfig *config, + bool enable) +; /** * Sets the mempool synchronization strategy @@ -617,8 +683,10 @@ int32_t dash_spv_ffi_config_set_mempool_tracking(FFIClientConfig *config, * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_mempool_strategy(FFIClientConfig *config, - enum FFIMempoolStrategy strategy); + +int32_t dash_spv_ffi_config_set_mempool_strategy(struct FFIClientConfig *config, + enum FFIMempoolStrategy strategy) +; /** * Sets the maximum number of mempool transactions to track @@ -627,8 +695,10 @@ int32_t dash_spv_ffi_config_set_mempool_strategy(FFIClientConfig *config, * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_max_mempool_transactions(FFIClientConfig *config, - uint32_t max_transactions); + +int32_t dash_spv_ffi_config_set_max_mempool_transactions(struct FFIClientConfig *config, + uint32_t max_transactions) +; /** * Sets the mempool transaction timeout in seconds @@ -637,8 +707,10 @@ int32_t dash_spv_ffi_config_set_max_mempool_transactions(FFIClientConfig *config * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_mempool_timeout(FFIClientConfig *config, - uint64_t timeout_secs); + +int32_t dash_spv_ffi_config_set_mempool_timeout(struct FFIClientConfig *config, + uint64_t timeout_secs) +; /** * Sets whether to fetch full mempool transaction data @@ -647,8 +719,10 @@ int32_t dash_spv_ffi_config_set_mempool_timeout(FFIClientConfig *config, * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_fetch_mempool_transactions(FFIClientConfig *config, - bool fetch); + +int32_t dash_spv_ffi_config_set_fetch_mempool_transactions(struct FFIClientConfig *config, + bool fetch) +; /** * Sets whether to persist mempool state to disk @@ -657,8 +731,10 @@ int32_t dash_spv_ffi_config_set_fetch_mempool_transactions(FFIClientConfig *conf * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_persist_mempool(FFIClientConfig *config, - bool persist); + +int32_t dash_spv_ffi_config_set_persist_mempool(struct FFIClientConfig *config, + bool persist) +; /** * Gets whether mempool tracking is enabled @@ -667,7 +743,7 @@ int32_t dash_spv_ffi_config_set_persist_mempool(FFIClientConfig *config, * - `config` must be a valid pointer to an FFIClientConfig or null * - If null, returns false as default */ -bool dash_spv_ffi_config_get_mempool_tracking(const FFIClientConfig *config); + bool dash_spv_ffi_config_get_mempool_tracking(const struct FFIClientConfig *config) ; /** * Gets the mempool synchronization strategy @@ -676,7 +752,9 @@ bool dash_spv_ffi_config_get_mempool_tracking(const FFIClientConfig *config); * - `config` must be a valid pointer to an FFIClientConfig or null * - If null, returns FFIMempoolStrategy::Selective as default */ -enum FFIMempoolStrategy dash_spv_ffi_config_get_mempool_strategy(const FFIClientConfig *config); + +enum FFIMempoolStrategy dash_spv_ffi_config_get_mempool_strategy(const struct FFIClientConfig *config) +; /** * Sets the starting block height for synchronization @@ -685,8 +763,10 @@ enum FFIMempoolStrategy dash_spv_ffi_config_get_mempool_strategy(const FFIClient * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_start_from_height(FFIClientConfig *config, - uint32_t height); + +int32_t dash_spv_ffi_config_set_start_from_height(struct FFIClientConfig *config, + uint32_t height) +; /** * Sets the wallet creation timestamp for synchronization optimization @@ -695,12 +775,14 @@ int32_t dash_spv_ffi_config_set_start_from_height(FFIClientConfig *config, * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_wallet_creation_time(FFIClientConfig *config, - uint32_t timestamp); -const char *dash_spv_ffi_get_last_error(void); +int32_t dash_spv_ffi_config_set_wallet_creation_time(struct FFIClientConfig *config, + uint32_t timestamp) +; + + const char *dash_spv_ffi_get_last_error(void) ; -void dash_spv_ffi_clear_error(void); + void dash_spv_ffi_clear_error(void) ; /** * Creates a CoreSDKHandle from an FFIDashSpvClient @@ -711,7 +793,7 @@ void dash_spv_ffi_clear_error(void); * - The caller must ensure the client pointer is valid * - The returned handle must be properly released with ffi_dash_spv_release_core_handle */ -struct CoreSDKHandle *ffi_dash_spv_get_core_handle(struct FFIDashSpvClient *client); + struct CoreSDKHandle *ffi_dash_spv_get_core_handle(struct FFIDashSpvClient *client) ; /** * Releases a CoreSDKHandle @@ -722,7 +804,7 @@ struct CoreSDKHandle *ffi_dash_spv_get_core_handle(struct FFIDashSpvClient *clie * - The caller must ensure the handle pointer is valid * - The handle must not be used after this call */ -void ffi_dash_spv_release_core_handle(struct CoreSDKHandle *handle); + void ffi_dash_spv_release_core_handle(struct CoreSDKHandle *handle) ; /** * Gets a quorum public key from the Core chain @@ -735,12 +817,14 @@ void ffi_dash_spv_release_core_handle(struct CoreSDKHandle *handle); * - out_pubkey must point to a buffer of at least out_pubkey_size bytes * - out_pubkey_size must be at least 48 bytes */ + struct FFIResult ffi_dash_spv_get_quorum_public_key(struct FFIDashSpvClient *client, uint32_t quorum_type, const uint8_t *quorum_hash, uint32_t core_chain_locked_height, uint8_t *out_pubkey, - uintptr_t out_pubkey_size); + uintptr_t out_pubkey_size) +; /** * Gets the platform activation height from the Core chain @@ -751,22 +835,24 @@ struct FFIResult ffi_dash_spv_get_quorum_public_key(struct FFIDashSpvClient *cli * - The caller must ensure all pointers are valid * - out_height must point to a valid u32 */ + struct FFIResult ffi_dash_spv_get_platform_activation_height(struct FFIDashSpvClient *client, - uint32_t *out_height); + uint32_t *out_height) +; /** * # Safety * - `s.ptr` must be a pointer previously returned by `FFIString::new` or compatible. * - It must not be used after this call. */ -void dash_spv_ffi_string_destroy(struct FFIString s); + void dash_spv_ffi_string_destroy(struct FFIString s) ; /** * # Safety * - `arr` must be either null or a valid pointer to an `FFIArray` previously constructed in Rust. * - The memory referenced by `arr.data` must not be used after this call. */ -void dash_spv_ffi_array_destroy(struct FFIArray *arr); + void dash_spv_ffi_array_destroy(struct FFIArray *arr) ; /** * Destroy an array of FFIString pointers (Vec<*mut FFIString>) and their contents. @@ -780,7 +866,9 @@ void dash_spv_ffi_array_destroy(struct FFIArray *arr); * - Each element pointer must be valid or null; non-null entries are freed. * - The memory referenced by `arr.data` must not be used after this call. */ -void dash_spv_ffi_string_array_destroy(struct FFIArray *arr); + +void dash_spv_ffi_string_array_destroy(struct FFIArray *arr) +; /** * Destroys the raw transaction bytes allocated for an FFIUnconfirmedTransaction @@ -792,7 +880,7 @@ void dash_spv_ffi_string_array_destroy(struct FFIArray *arr); * - The pointer must not be used after this function is called * - This function should only be called once per allocation */ -void dash_spv_ffi_unconfirmed_transaction_destroy_raw_tx(uint8_t *raw_tx, uintptr_t raw_tx_len); + void dash_spv_ffi_unconfirmed_transaction_destroy_raw_tx(uint8_t *raw_tx, uintptr_t raw_tx_len) ; /** * Destroys the addresses array allocated for an FFIUnconfirmedTransaction @@ -805,8 +893,10 @@ void dash_spv_ffi_unconfirmed_transaction_destroy_raw_tx(uint8_t *raw_tx, uintpt * - The pointer must not be used after this function is called * - This function should only be called once per allocation */ + void dash_spv_ffi_unconfirmed_transaction_destroy_addresses(struct FFIString *addresses, - uintptr_t addresses_len); + uintptr_t addresses_len) +; /** * Destroys an FFIUnconfirmedTransaction and all its associated resources @@ -818,7 +908,7 @@ void dash_spv_ffi_unconfirmed_transaction_destroy_addresses(struct FFIString *ad * - The pointer must not be used after this function is called * - This function should only be called once per FFIUnconfirmedTransaction */ -void dash_spv_ffi_unconfirmed_transaction_destroy(struct FFIUnconfirmedTransaction *tx); + void dash_spv_ffi_unconfirmed_transaction_destroy(struct FFIUnconfirmedTransaction *tx) ; /** * Initialize logging for the SPV library. @@ -827,11 +917,23 @@ void dash_spv_ffi_unconfirmed_transaction_destroy(struct FFIUnconfirmedTransacti * - `level` may be null or point to a valid, NUL-terminated C string. * - If non-null, the pointer must remain valid for the duration of this call. */ -int32_t dash_spv_ffi_init_logging(const char *level); + int32_t dash_spv_ffi_init_logging(const char *level) ; + + const char *dash_spv_ffi_version(void) ; -const char *dash_spv_ffi_version(void); + void dash_spv_ffi_enable_test_mode(void) ; -void dash_spv_ffi_enable_test_mode(void); int32_t dash_spv_ffi_client_broadcast_transaction(struct FFIDashSpvClient *client, - const char *tx_hex); + const char *tx_hex) +; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#ifdef __cplusplus +} // namespace dash_spv_ffi +#endif // __cplusplus + +#endif /* DASH_SPV_FFI_H */ diff --git a/dash-spv-ffi/src/config.rs b/dash-spv-ffi/src/config.rs index cffae6c68..4d31a3844 100644 --- a/dash-spv-ffi/src/config.rs +++ b/dash-spv-ffi/src/config.rs @@ -22,32 +22,36 @@ impl From for ValidationMode { } } -#[repr(transparent)] +#[repr(C)] pub struct FFIClientConfig { - inner: ClientConfig, + // Opaque pointer to avoid exposing internal ClientConfig in generated C headers + inner: *mut std::ffi::c_void, } #[no_mangle] pub extern "C" fn dash_spv_ffi_config_new(network: FFINetwork) -> *mut FFIClientConfig { let config = ClientConfig::new(network.into()); + let inner = Box::into_raw(Box::new(config)) as *mut std::ffi::c_void; Box::into_raw(Box::new(FFIClientConfig { - inner: config, + inner, })) } #[no_mangle] pub extern "C" fn dash_spv_ffi_config_mainnet() -> *mut FFIClientConfig { let config = ClientConfig::mainnet(); + let inner = Box::into_raw(Box::new(config)) as *mut std::ffi::c_void; Box::into_raw(Box::new(FFIClientConfig { - inner: config, + inner, })) } #[no_mangle] pub extern "C" fn dash_spv_ffi_config_testnet() -> *mut FFIClientConfig { let config = ClientConfig::testnet(); + let inner = Box::into_raw(Box::new(config)) as *mut std::ffi::c_void; Box::into_raw(Box::new(FFIClientConfig { - inner: config, + inner, })) } @@ -65,7 +69,7 @@ pub unsafe extern "C" fn dash_spv_ffi_config_set_data_dir( null_check!(config); null_check!(path); - let config = &mut (*config).inner; + let config = unsafe { &mut *((*config).inner as *mut ClientConfig) }; match CStr::from_ptr(path).to_str() { Ok(path_str) => { config.storage_path = Some(path_str.into()); @@ -90,7 +94,7 @@ pub unsafe extern "C" fn dash_spv_ffi_config_set_validation_mode( ) -> i32 { null_check!(config); - let config = &mut (*config).inner; + let config = unsafe { &mut *((*config).inner as *mut ClientConfig) }; config.validation_mode = mode.into(); FFIErrorCode::Success as i32 } @@ -107,7 +111,7 @@ pub unsafe extern "C" fn dash_spv_ffi_config_set_max_peers( ) -> i32 { null_check!(config); - let config = &mut (*config).inner; + let config = unsafe { &mut *((*config).inner as *mut ClientConfig) }; config.max_peers = max_peers; FFIErrorCode::Success as i32 } @@ -132,7 +136,7 @@ pub unsafe extern "C" fn dash_spv_ffi_config_add_peer( null_check!(config); null_check!(addr); - let cfg = &mut (*config).inner; + let cfg = unsafe { &mut *((*config).inner as *mut ClientConfig) }; let default_port = match cfg.network { dashcore::Network::Dash => 9999, dashcore::Network::Testnet => 19999, @@ -204,7 +208,7 @@ pub unsafe extern "C" fn dash_spv_ffi_config_set_user_agent( match CStr::from_ptr(user_agent).to_str() { Ok(agent_str) => { // Store as-is; normalization/length capping is applied at handshake build time - let cfg = &mut (*config).inner; + let cfg = unsafe { &mut *((*config).inner as *mut ClientConfig) }; cfg.user_agent = Some(agent_str.to_string()); FFIErrorCode::Success as i32 } @@ -227,7 +231,7 @@ pub unsafe extern "C" fn dash_spv_ffi_config_set_relay_transactions( ) -> i32 { null_check!(config); - let _config = &mut (*config).inner; + let _config = unsafe { &mut *((*config).inner as *mut ClientConfig) }; // relay_transactions not directly settable in current ClientConfig FFIErrorCode::Success as i32 } @@ -244,7 +248,7 @@ pub unsafe extern "C" fn dash_spv_ffi_config_set_filter_load( ) -> i32 { null_check!(config); - let config = &mut (*config).inner; + let config = unsafe { &mut *((*config).inner as *mut ClientConfig) }; config.enable_filters = load_filters; FFIErrorCode::Success as i32 } @@ -256,12 +260,12 @@ pub unsafe extern "C" fn dash_spv_ffi_config_set_filter_load( #[no_mangle] pub unsafe extern "C" fn dash_spv_ffi_config_set_restrict_to_configured_peers( config: *mut FFIClientConfig, - restrict: bool, + restrict_peers: bool, ) -> i32 { null_check!(config); - let config = &mut (*config).inner; - config.restrict_to_configured_peers = restrict; + let config = unsafe { &mut *((*config).inner as *mut ClientConfig) }; + config.restrict_to_configured_peers = restrict_peers; FFIErrorCode::Success as i32 } @@ -277,7 +281,7 @@ pub unsafe extern "C" fn dash_spv_ffi_config_set_masternode_sync_enabled( ) -> i32 { null_check!(config); - let config = &mut (*config).inner; + let config = unsafe { &mut *((*config).inner as *mut ClientConfig) }; config.enable_masternodes = enable; FFIErrorCode::Success as i32 } @@ -295,7 +299,7 @@ pub unsafe extern "C" fn dash_spv_ffi_config_get_network( return FFINetwork::Dash; } - let config = &(*config).inner; + let config = unsafe { &*((*config).inner as *const ClientConfig) }; config.network.into() } @@ -316,7 +320,7 @@ pub unsafe extern "C" fn dash_spv_ffi_config_get_data_dir( }; } - let config = &(*config).inner; + let config = unsafe { &*((*config).inner as *const ClientConfig) }; match &config.storage_path { Some(dir) => FFIString::new(&dir.to_string_lossy()), None => FFIString { @@ -335,17 +339,22 @@ pub unsafe extern "C" fn dash_spv_ffi_config_get_data_dir( #[no_mangle] pub unsafe extern "C" fn dash_spv_ffi_config_destroy(config: *mut FFIClientConfig) { if !config.is_null() { - let _ = Box::from_raw(config); + // Reclaim outer struct + let cfg = Box::from_raw(config); + // Free inner ClientConfig if present + if !cfg.inner.is_null() { + let _ = Box::from_raw(cfg.inner as *mut ClientConfig); + } } } impl FFIClientConfig { pub fn get_inner(&self) -> &ClientConfig { - &self.inner + unsafe { &*(self.inner as *const ClientConfig) } } pub fn clone_inner(&self) -> ClientConfig { - self.inner.clone() + unsafe { (*(self.inner as *const ClientConfig)).clone() } } } @@ -363,7 +372,7 @@ pub unsafe extern "C" fn dash_spv_ffi_config_set_mempool_tracking( ) -> i32 { null_check!(config); - let config = &mut (*config).inner; + let config = unsafe { &mut *((*config).inner as *mut ClientConfig) }; config.enable_mempool_tracking = enable; FFIErrorCode::Success as i32 } @@ -380,7 +389,7 @@ pub unsafe extern "C" fn dash_spv_ffi_config_set_mempool_strategy( ) -> i32 { null_check!(config); - let config = &mut (*config).inner; + let config = unsafe { &mut *((*config).inner as *mut ClientConfig) }; config.mempool_strategy = strategy.into(); FFIErrorCode::Success as i32 } @@ -397,7 +406,7 @@ pub unsafe extern "C" fn dash_spv_ffi_config_set_max_mempool_transactions( ) -> i32 { null_check!(config); - let config = &mut (*config).inner; + let config = unsafe { &mut *((*config).inner as *mut ClientConfig) }; config.max_mempool_transactions = max_transactions as usize; FFIErrorCode::Success as i32 } @@ -414,7 +423,7 @@ pub unsafe extern "C" fn dash_spv_ffi_config_set_mempool_timeout( ) -> i32 { null_check!(config); - let config = &mut (*config).inner; + let config = unsafe { &mut *((*config).inner as *mut ClientConfig) }; config.mempool_timeout_secs = timeout_secs; FFIErrorCode::Success as i32 } @@ -431,7 +440,7 @@ pub unsafe extern "C" fn dash_spv_ffi_config_set_fetch_mempool_transactions( ) -> i32 { null_check!(config); - let config = &mut (*config).inner; + let config = unsafe { &mut *((*config).inner as *mut ClientConfig) }; config.fetch_mempool_transactions = fetch; FFIErrorCode::Success as i32 } @@ -448,7 +457,7 @@ pub unsafe extern "C" fn dash_spv_ffi_config_set_persist_mempool( ) -> i32 { null_check!(config); - let config = &mut (*config).inner; + let config = unsafe { &mut *((*config).inner as *mut ClientConfig) }; config.persist_mempool = persist; FFIErrorCode::Success as i32 } @@ -466,7 +475,7 @@ pub unsafe extern "C" fn dash_spv_ffi_config_get_mempool_tracking( return false; } - let config = &(*config).inner; + let config = unsafe { &*((*config).inner as *const ClientConfig) }; config.enable_mempool_tracking } @@ -483,7 +492,7 @@ pub unsafe extern "C" fn dash_spv_ffi_config_get_mempool_strategy( return FFIMempoolStrategy::Selective; } - let config = &(*config).inner; + let config = unsafe { &*((*config).inner as *const ClientConfig) }; config.mempool_strategy.into() } @@ -501,7 +510,7 @@ pub unsafe extern "C" fn dash_spv_ffi_config_set_start_from_height( ) -> i32 { null_check!(config); - let config = &mut (*config).inner; + let config = unsafe { &mut *((*config).inner as *mut ClientConfig) }; config.start_from_height = Some(height); FFIErrorCode::Success as i32 } @@ -518,7 +527,7 @@ pub unsafe extern "C" fn dash_spv_ffi_config_set_wallet_creation_time( ) -> i32 { null_check!(config); - let config = &mut (*config).inner; + let config = unsafe { &mut *((*config).inner as *mut ClientConfig) }; config.wallet_creation_time = Some(timestamp); FFIErrorCode::Success as i32 } diff --git a/dash-spv/src/client/message_handler.rs b/dash-spv/src/client/message_handler.rs index 022a252b8..9dcc37661 100644 --- a/dash-spv/src/client/message_handler.rs +++ b/dash-spv/src/client/message_handler.rs @@ -106,10 +106,23 @@ impl< }); } NetworkMessage::CFHeaders(ref cf_headers) => { - tracing::info!( - "📨 Client received CFHeaders message with {} filter headers", - cf_headers.filter_hashes.len() - ); + // Try to include the peer address for better diagnostics + let peer_addr = self.network.get_last_message_peer_addr().await; + match peer_addr { + Some(addr) => { + tracing::info!( + "📨 Client received CFHeaders message with {} filter headers from {}", + cf_headers.filter_hashes.len(), + addr + ); + } + None => { + tracing::info!( + "📨 Client received CFHeaders message with {} filter headers (peer unknown)", + cf_headers.filter_hashes.len() + ); + } + } // Move to sync manager without cloning return self .sync_manager @@ -182,9 +195,19 @@ impl< NetworkMessage::Headers(headers) => { // For post-sync headers, we need special handling if self.sync_manager.is_synced() && !headers.is_empty() { - tracing::info!( - "📋 Post-sync headers received, additional processing may be needed" - ); + let peer_addr = self.network.get_last_message_peer_addr().await; + if let Some(addr) = peer_addr { + tracing::info!( + "📋 Post-sync headers received from {} ({} headers), additional processing may be needed", + addr, + headers.len() + ); + } else { + tracing::info!( + "📋 Post-sync headers received ({} headers), additional processing may be needed", + headers.len() + ); + } } } NetworkMessage::Block(block) => { diff --git a/dash-spv/src/network/connection.rs b/dash-spv/src/network/connection.rs index b5082be2f..692f9638c 100644 --- a/dash-spv/src/network/connection.rs +++ b/dash-spv/src/network/connection.rs @@ -47,6 +47,10 @@ pub struct TcpConnection { } impl TcpConnection { + /// Get the remote peer socket address. + pub fn address(&self) -> SocketAddr { + self.address + } /// Create a new TCP connection to the given address. pub fn new( address: SocketAddr, diff --git a/dash-spv/src/network/mod.rs b/dash-spv/src/network/mod.rs index a05147e5c..57cb8ec0b 100644 --- a/dash-spv/src/network/mod.rs +++ b/dash-spv/src/network/mod.rs @@ -102,6 +102,12 @@ pub trait NetworkManager: Send + Sync { crate::types::PeerId(0) // Default implementation } + /// Get the socket address of the last peer that sent us a message. + /// Default implementation returns None; implementations with peer tracking can override. + async fn get_last_message_peer_addr(&self) -> Option { + None + } + /// Update the DSQ (CoinJoin queue) message preference for the current peer. async fn update_peer_dsq_preference(&mut self, wants_dsq: bool) -> NetworkResult<()>; @@ -364,6 +370,10 @@ impl NetworkManager for TcpNetworkManager { } } + async fn get_last_message_peer_addr(&self) -> Option { + self.connection.as_ref().map(|connection| connection.address()) + } + async fn update_peer_dsq_preference(&mut self, wants_dsq: bool) -> NetworkResult<()> { // Store the DSQ preference self.dsq_preference = wants_dsq; diff --git a/dash-spv/src/network/multi_peer.rs b/dash-spv/src/network/multi_peer.rs index 0b6f24eff..7c7863586 100644 --- a/dash-spv/src/network/multi_peer.rs +++ b/dash-spv/src/network/multi_peer.rs @@ -899,6 +899,12 @@ impl MultiPeerNetworkManager { } } + /// Get the socket address of the last peer that sent a message + pub async fn get_last_message_peer_addr(&self) -> Option { + let last_peer = self.last_message_peer.lock().await; + *last_peer + } + /// Ban a specific peer manually pub async fn ban_peer(&self, addr: &SocketAddr, reason: &str) -> Result<(), Error> { log::info!("Manually banning peer {} - reason: {}", addr, reason); diff --git a/dash-spv/src/sync/filters.rs b/dash-spv/src/sync/filters.rs index dc5e92128..c5dd21262 100644 --- a/dash-spv/src/sync/filters.rs +++ b/dash-spv/src/sync/filters.rs @@ -132,6 +132,14 @@ impl { + tracing::warn!( + "📋 Received overlapping filter headers from {}: expected start={}, received start={} (likely from recovery/retry)", + addr, + self.current_sync_height, + batch_start_height + ); + } + None => { + tracing::warn!( + "📋 Received overlapping filter headers: expected start={}, received start={} (likely from recovery/retry)", + self.current_sync_height, + batch_start_height + ); + } + } // Handle overlapping headers using the helper method let (new_headers_stored, new_current_height) = self @@ -699,6 +721,7 @@ impl= header_tip_height { tracing::info!("Filter headers already synced to header tip"); @@ -736,6 +765,12 @@ impl header_tip_height { tracing::warn!( @@ -779,10 +814,11 @@ impl { - tracing::debug!("Found header at storage height {}", storage_height); + tracing::debug!( + "Found header for batch stop at blockchain height {} (storage height {}), hash={}", + batch_end_height, + storage_height, + header.block_hash() + ); header.block_hash() } Ok(None) => { @@ -893,6 +934,14 @@ impl { + tracing::debug!( + "📡 Sent filter request for range {}-{} to {} (now {} active)", + request.start_height, + request.end_height, + addr, + self.active_filter_requests.len() + ); + } + None => { + tracing::debug!( + "📡 Sent filter request for range {}-{} (now {} active)", + request.start_height, + request.end_height, + self.active_filter_requests.len() + ); + } + } // Apply delay only for retry requests to avoid hammering peers if request.is_retry && FILTER_RETRY_DELAY_MS > 0 { @@ -1710,12 +1774,28 @@ impl tracing::debug!( + "Sending GetCFilters: start_height={}, stop_hash={}, to {}", + start_height, + stop_hash, + addr + ), + None => tracing::debug!( + "Sending GetCFilters: start_height={}, stop_hash={}", + start_height, + stop_hash + ), + } + network .send_message(NetworkMessage::GetCFilters(get_cfilters)) .await .map_err(|e| SyncError::Network(format!("Failed to send GetCFilters: {}", e)))?; - tracing::debug!("Requested filters from height {} to {}", start_height, stop_hash); + tracing::trace!("Requested filters from height {} to {}", start_height, stop_hash); Ok(()) } diff --git a/dash-spv/src/sync/sequential/mod.rs b/dash-spv/src/sync/sequential/mod.rs index 096c3e1c9..e40f25de9 100644 --- a/dash-spv/src/sync/sequential/mod.rs +++ b/dash-spv/src/sync/sequential/mod.rs @@ -1253,6 +1253,15 @@ impl< network: &mut N, storage: &mut S, ) -> SyncResult<()> { + // Log source peer for CFHeaders batches when possible + if let Some(addr) = network.get_last_message_peer_addr().await { + tracing::debug!( + "📨 Received CFHeaders ({} headers) from {} (stop_hash={})", + cfheaders.filter_hashes.len(), + addr, + cfheaders.stop_hash + ); + } let continue_sync = self.filter_sync.handle_cfheaders_message(cfheaders.clone(), storage, network).await?; @@ -1298,7 +1307,20 @@ impl< network: &mut N, storage: &mut S, ) -> SyncResult<()> { - tracing::debug!("📨 Received CFilter for block {}", cfilter.block_hash); + // Include peer address when available for diagnostics + let peer_addr = network.get_last_message_peer_addr().await; + match peer_addr { + Some(addr) => { + tracing::debug!( + "📨 Received CFilter for block {} from {}", + cfilter.block_hash, + addr + ); + } + None => { + tracing::debug!("📨 Received CFilter for block {}", cfilter.block_hash); + } + } let mut wallet = self.wallet.write().await; diff --git a/key-wallet-ffi/FFI_API.md b/key-wallet-ffi/FFI_API.md index 8d4b462ce..8a4f9aba6 100644 --- a/key-wallet-ffi/FFI_API.md +++ b/key-wallet-ffi/FFI_API.md @@ -73,7 +73,7 @@ Functions: 57 | `account_get_parent_wallet_id` | Get the parent wallet ID of an account # Safety - `account` must be a valid... | account | | `bls_account_get_parent_wallet_id` | No description | account | | `eddsa_account_get_parent_wallet_id` | No description | account | -| `ffi_managed_wallet_free` | Free a managed wallet (FFIManagedWallet type) # Safety - `managed_wallet` m... | transaction_checking | +| `ffi_managed_wallet_free` | Free a managed wallet (FFIManagedWalletInfo type) # Safety - `managed_walle... | transaction_checking | | `key_wallet_derive_address_from_key` | Derive an address from a private key # Safety - `private_key` must be a vali... | derivation | | `key_wallet_derive_address_from_seed` | Derive an address from a seed at a specific derivation path # Safety - `seed... | derivation | | `key_wallet_derive_private_key_from_seed` | Derive a private key from a seed at a specific derivation path # Safety - `s... | derivation | @@ -697,14 +697,14 @@ eddsa_account_get_parent_wallet_id(account: *const FFIEdDSAAccount,) -> *const u #### `ffi_managed_wallet_free` ```c -ffi_managed_wallet_free(managed_wallet: *mut FFIManagedWallet) -> () +ffi_managed_wallet_free(managed_wallet: *mut FFIManagedWalletInfo) -> () ``` **Description:** -Free a managed wallet (FFIManagedWallet type) # Safety - `managed_wallet` must be a valid pointer to an FFIManagedWallet - This function must only be called once per managed wallet +Free a managed wallet (FFIManagedWalletInfo type) # Safety - `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo - This function must only be called once per managed wallet **Safety:** -- `managed_wallet` must be a valid pointer to an FFIManagedWallet - This function must only be called once per managed wallet +- `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo - This function must only be called once per managed wallet **Module:** `transaction_checking` @@ -777,14 +777,14 @@ Get the parent wallet ID of a managed account Note: ManagedAccount doesn't stor #### `managed_wallet_check_transaction` ```c -managed_wallet_check_transaction(managed_wallet: *mut FFIManagedWallet, wallet: *const FFIWallet, network: FFINetwork, tx_bytes: *const u8, tx_len: usize, context_type: FFITransactionContext, block_height: c_uint, block_hash: *const u8, // 32 bytes if not null timestamp: u64, update_state: bool, result_out: *mut FFITransactionCheckResult, error: *mut FFIError,) -> bool +managed_wallet_check_transaction(managed_wallet: *mut FFIManagedWalletInfo, wallet: *const FFIWallet, network: FFINetwork, tx_bytes: *const u8, tx_len: usize, context_type: FFITransactionContext, block_height: c_uint, block_hash: *const u8, // 32 bytes if not null timestamp: u64, update_state: bool, result_out: *mut FFITransactionCheckResult, error: *mut FFIError,) -> bool ``` **Description:** -Check if a transaction belongs to the wallet This function checks a transaction against all relevant account types in the wallet and returns detailed information about which accounts are affected. # Safety - `managed_wallet` must be a valid pointer to an FFIManagedWallet - `wallet` must be a valid pointer to an FFIWallet (needed for address generation) - `tx_bytes` must be a valid pointer to transaction bytes with at least `tx_len` bytes - `result_out` must be a valid pointer to store the result - `error` must be a valid pointer to an FFIError - The affected_accounts array in the result must be freed with `transaction_check_result_free` +Check if a transaction belongs to the wallet This function checks a transaction against all relevant account types in the wallet and returns detailed information about which accounts are affected. # Safety - `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo - `wallet` must be a valid pointer to an FFIWallet (needed for address generation) - `tx_bytes` must be a valid pointer to transaction bytes with at least `tx_len` bytes - `result_out` must be a valid pointer to store the result - `error` must be a valid pointer to an FFIError - The affected_accounts array in the result must be freed with `transaction_check_result_free` **Safety:** -- `managed_wallet` must be a valid pointer to an FFIManagedWallet - `wallet` must be a valid pointer to an FFIWallet (needed for address generation) - `tx_bytes` must be a valid pointer to transaction bytes with at least `tx_len` bytes - `result_out` must be a valid pointer to store the result - `error` must be a valid pointer to an FFIError - The affected_accounts array in the result must be freed with `transaction_check_result_free` +- `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo - `wallet` must be a valid pointer to an FFIWallet (needed for address generation) - `tx_bytes` must be a valid pointer to transaction bytes with at least `tx_len` bytes - `result_out` must be a valid pointer to store the result - `error` must be a valid pointer to an FFIError - The affected_accounts array in the result must be freed with `transaction_check_result_free` **Module:** `transaction_checking` @@ -809,14 +809,14 @@ Free managed wallet info # Safety - `managed_wallet` must be a valid pointer t #### `managed_wallet_generate_addresses_to_index` ```c -managed_wallet_generate_addresses_to_index(managed_wallet: *mut FFIManagedWallet, wallet: *const FFIWallet, network: FFINetwork, account_type: FFIAccountType, account_index: c_uint, pool_type: FFIAddressPoolType, target_index: c_uint, error: *mut FFIError,) -> bool +managed_wallet_generate_addresses_to_index(managed_wallet: *mut FFIManagedWalletInfo, wallet: *const FFIWallet, network: FFINetwork, account_type: FFIAccountType, account_index: c_uint, pool_type: FFIAddressPoolType, target_index: c_uint, error: *mut FFIError,) -> bool ``` **Description:** -Generate addresses up to a specific index in a pool This ensures that addresses up to and including the specified index exist in the pool. This is useful for wallet recovery or when specific indices are needed. # Safety - `managed_wallet` must be a valid pointer to an FFIManagedWallet - `wallet` must be a valid pointer to an FFIWallet (for key derivation) - `error` must be a valid pointer to an FFIError or null +Generate addresses up to a specific index in a pool This ensures that addresses up to and including the specified index exist in the pool. This is useful for wallet recovery or when specific indices are needed. # Safety - `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo - `wallet` must be a valid pointer to an FFIWallet (for key derivation) - `error` must be a valid pointer to an FFIError or null **Safety:** -- `managed_wallet` must be a valid pointer to an FFIManagedWallet - `wallet` must be a valid pointer to an FFIWallet (for key derivation) - `error` must be a valid pointer to an FFIError or null +- `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo - `wallet` must be a valid pointer to an FFIWallet (for key derivation) - `error` must be a valid pointer to an FFIError or null **Module:** `address_pool` @@ -873,14 +873,14 @@ Get number of accounts in a managed wallet # Safety - `manager` must be a vali #### `managed_wallet_get_address_pool_info` ```c -managed_wallet_get_address_pool_info(managed_wallet: *const FFIManagedWallet, network: FFINetwork, account_type: FFIAccountType, account_index: c_uint, pool_type: FFIAddressPoolType, info_out: *mut FFIAddressPoolInfo, error: *mut FFIError,) -> bool +managed_wallet_get_address_pool_info(managed_wallet: *const FFIManagedWalletInfo, network: FFINetwork, account_type: FFIAccountType, account_index: c_uint, pool_type: FFIAddressPoolType, info_out: *mut FFIAddressPoolInfo, error: *mut FFIError,) -> bool ``` **Description:** -Get address pool information for an account # Safety - `managed_wallet` must be a valid pointer to an FFIManagedWallet - `info_out` must be a valid pointer to store the pool info - `error` must be a valid pointer to an FFIError or null +Get address pool information for an account # Safety - `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo - `info_out` must be a valid pointer to store the pool info - `error` must be a valid pointer to an FFIError or null **Safety:** -- `managed_wallet` must be a valid pointer to an FFIManagedWallet - `info_out` must be a valid pointer to store the pool info - `error` must be a valid pointer to an FFIError or null +- `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo - `info_out` must be a valid pointer to store the pool info - `error` must be a valid pointer to an FFIError or null **Module:** `address_pool` @@ -1017,14 +1017,14 @@ Free managed wallet info returned by wallet_manager_get_managed_wallet_info # S #### `managed_wallet_mark_address_used` ```c -managed_wallet_mark_address_used(managed_wallet: *mut FFIManagedWallet, network: FFINetwork, address: *const c_char, error: *mut FFIError,) -> bool +managed_wallet_mark_address_used(managed_wallet: *mut FFIManagedWalletInfo, network: FFINetwork, address: *const c_char, error: *mut FFIError,) -> bool ``` **Description:** -Mark an address as used in the pool This updates the pool's tracking of which addresses have been used, which is important for gap limit management and wallet recovery. # Safety - `managed_wallet` must be a valid pointer to an FFIManagedWallet - `address` must be a valid C string - `error` must be a valid pointer to an FFIError or null +Mark an address as used in the pool This updates the pool's tracking of which addresses have been used, which is important for gap limit management and wallet recovery. # Safety - `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo - `address` must be a valid C string - `error` must be a valid pointer to an FFIError or null **Safety:** -- `managed_wallet` must be a valid pointer to an FFIManagedWallet - `address` must be a valid C string - `error` must be a valid pointer to an FFIError or null +- `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo - `address` must be a valid C string - `error` must be a valid pointer to an FFIError or null **Module:** `address_pool` @@ -1033,14 +1033,14 @@ Mark an address as used in the pool This updates the pool's tracking of which a #### `managed_wallet_set_gap_limit` ```c -managed_wallet_set_gap_limit(managed_wallet: *mut FFIManagedWallet, network: FFINetwork, account_type: FFIAccountType, account_index: c_uint, pool_type: FFIAddressPoolType, gap_limit: c_uint, error: *mut FFIError,) -> bool +managed_wallet_set_gap_limit(managed_wallet: *mut FFIManagedWalletInfo, network: FFINetwork, account_type: FFIAccountType, account_index: c_uint, pool_type: FFIAddressPoolType, gap_limit: c_uint, error: *mut FFIError,) -> bool ``` **Description:** -Set the gap limit for an address pool The gap limit determines how many unused addresses to maintain at the end of the pool. This is important for wallet recovery and address discovery. # Safety - `managed_wallet` must be a valid pointer to an FFIManagedWallet - `error` must be a valid pointer to an FFIError or null +Set the gap limit for an address pool The gap limit determines how many unused addresses to maintain at the end of the pool. This is important for wallet recovery and address discovery. # Safety - `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo - `error` must be a valid pointer to an FFIError or null **Safety:** -- `managed_wallet` must be a valid pointer to an FFIManagedWallet - `error` must be a valid pointer to an FFIError or null +- `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo - `error` must be a valid pointer to an FFIError or null **Module:** `address_pool` @@ -1193,14 +1193,14 @@ Create a new wallet from seed with options # Safety - `seed` must be a valid p #### `wallet_create_managed_wallet` ```c -wallet_create_managed_wallet(wallet: *const FFIWallet, error: *mut FFIError,) -> *mut FFIManagedWallet +wallet_create_managed_wallet(wallet: *const FFIWallet, error: *mut FFIError,) -> *mut FFIManagedWalletInfo ``` **Description:** -Create a managed wallet from a regular wallet This creates a ManagedWalletInfo instance from a Wallet, which includes address pools and transaction checking capabilities. # Safety - `wallet` must be a valid pointer to an FFIWallet - `error` must be a valid pointer to an FFIError or null - The returned pointer must be freed with `ffi_managed_wallet_free` +Create a managed wallet from a regular wallet This creates a ManagedWalletInfo instance from a Wallet, which includes address pools and transaction checking capabilities. # Safety - `wallet` must be a valid pointer to an FFIWallet - `error` must be a valid pointer to an FFIError or null - The returned pointer must be freed with `managed_wallet_info_free` (or `ffi_managed_wallet_free` for compatibility) **Safety:** -- `wallet` must be a valid pointer to an FFIWallet - `error` must be a valid pointer to an FFIError or null - The returned pointer must be freed with `ffi_managed_wallet_free` +- `wallet` must be a valid pointer to an FFIWallet - `error` must be a valid pointer to an FFIError or null - The returned pointer must be freed with `managed_wallet_info_free` (or `ffi_managed_wallet_free` for compatibility) **Module:** `transaction_checking` diff --git a/key-wallet-ffi/cbindgen.toml b/key-wallet-ffi/cbindgen.toml index 941e34a04..379d674a2 100644 --- a/key-wallet-ffi/cbindgen.toml +++ b/key-wallet-ffi/cbindgen.toml @@ -40,10 +40,8 @@ item_types = ["functions", "enums", "structs", "typedefs", "opaque", "constants" "FFIExtendedPrivateKey" = "" "FFIPublicKey" = "" "FFIExtendedPublicKey" = "" -"FFIManagedWalletInfo" = "" "FFIWalletManager" = "" "FFIWallet" = "" -"FFIManagedWallet" = "" "FFIAccount" = "" "FFIBLSAccount" = "" "FFIEdDSAAccount" = "" @@ -96,4 +94,4 @@ extra_bindings = [] crates = [] all_features = false default_features = true -features = [] \ No newline at end of file +features = [] diff --git a/key-wallet-ffi/include/key_wallet_ffi.h b/key-wallet-ffi/include/key_wallet_ffi.h index fcec5a290..ae0749d60 100644 --- a/key-wallet-ffi/include/key_wallet_ffi.h +++ b/key-wallet-ffi/include/key_wallet_ffi.h @@ -263,11 +263,6 @@ typedef struct FFIManagedAccount FFIManagedAccount; */ typedef struct FFIManagedAccountCollection FFIManagedAccountCollection; -/* - FFI wrapper for ManagedWalletInfo - */ -typedef struct FFIManagedWalletInfo FFIManagedWalletInfo; - /* Opaque type for a private key (SecretKey) */ @@ -394,12 +389,11 @@ typedef struct { } FFIAccountCollectionSummary; /* - FFI wrapper for ManagedWalletInfo that includes transaction checking capabilities + FFI wrapper for ManagedWalletInfo (single canonical type) */ typedef struct { - ManagedWalletInfo *inner; - -} FFIManagedWallet; + void *inner; +} FFIManagedWalletInfo; /* Address pool info @@ -1657,12 +1651,12 @@ FFIPrivateKey *account_derive_private_key_from_mnemonic(const FFIAccount *accoun # Safety - - `managed_wallet` must be a valid pointer to an FFIManagedWallet + - `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo - `info_out` must be a valid pointer to store the pool info - `error` must be a valid pointer to an FFIError or null */ -bool managed_wallet_get_address_pool_info(const FFIManagedWallet *managed_wallet, +bool managed_wallet_get_address_pool_info(const FFIManagedWalletInfo *managed_wallet, FFINetwork network, FFIAccountType account_type, unsigned int account_index, @@ -1679,11 +1673,11 @@ bool managed_wallet_get_address_pool_info(const FFIManagedWallet *managed_wallet # Safety - - `managed_wallet` must be a valid pointer to an FFIManagedWallet + - `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo - `error` must be a valid pointer to an FFIError or null */ -bool managed_wallet_set_gap_limit(FFIManagedWallet *managed_wallet, +bool managed_wallet_set_gap_limit(FFIManagedWalletInfo *managed_wallet, FFINetwork network, FFIAccountType account_type, unsigned int account_index, @@ -1701,12 +1695,12 @@ bool managed_wallet_set_gap_limit(FFIManagedWallet *managed_wallet, # Safety - - `managed_wallet` must be a valid pointer to an FFIManagedWallet + - `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo - `wallet` must be a valid pointer to an FFIWallet (for key derivation) - `error` must be a valid pointer to an FFIError or null */ -bool managed_wallet_generate_addresses_to_index(FFIManagedWallet *managed_wallet, +bool managed_wallet_generate_addresses_to_index(FFIManagedWalletInfo *managed_wallet, const FFIWallet *wallet, FFINetwork network, FFIAccountType account_type, @@ -1724,12 +1718,12 @@ bool managed_wallet_generate_addresses_to_index(FFIManagedWallet *managed_wallet # Safety - - `managed_wallet` must be a valid pointer to an FFIManagedWallet + - `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo - `address` must be a valid C string - `error` must be a valid pointer to an FFIError or null */ -bool managed_wallet_mark_address_used(FFIManagedWallet *managed_wallet, +bool managed_wallet_mark_address_used(FFIManagedWalletInfo *managed_wallet, FFINetwork network, const char *address, FFIError *error) @@ -3371,9 +3365,12 @@ int32_t transaction_sign_input(FFITransaction *tx, - `wallet` must be a valid pointer to an FFIWallet - `error` must be a valid pointer to an FFIError or null - - The returned pointer must be freed with `ffi_managed_wallet_free` + - The returned pointer must be freed with `managed_wallet_info_free` (or `ffi_managed_wallet_free` for compatibility) */ - FFIManagedWallet *wallet_create_managed_wallet(const FFIWallet *wallet, FFIError *error) ; + +FFIManagedWalletInfo *wallet_create_managed_wallet(const FFIWallet *wallet, + FFIError *error) +; /* Check if a transaction belongs to the wallet @@ -3383,7 +3380,7 @@ int32_t transaction_sign_input(FFITransaction *tx, # Safety - - `managed_wallet` must be a valid pointer to an FFIManagedWallet + - `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo - `wallet` must be a valid pointer to an FFIWallet (needed for address generation) - `tx_bytes` must be a valid pointer to transaction bytes with at least `tx_len` bytes - `result_out` must be a valid pointer to store the result @@ -3391,7 +3388,7 @@ int32_t transaction_sign_input(FFITransaction *tx, - The affected_accounts array in the result must be freed with `transaction_check_result_free` */ -bool managed_wallet_check_transaction(FFIManagedWallet *managed_wallet, +bool managed_wallet_check_transaction(FFIManagedWalletInfo *managed_wallet, const FFIWallet *wallet, FFINetwork network, const uint8_t *tx_bytes, @@ -3416,14 +3413,14 @@ bool managed_wallet_check_transaction(FFIManagedWallet *managed_wallet, void transaction_check_result_free(FFITransactionCheckResult *result) ; /* - Free a managed wallet (FFIManagedWallet type) + Free a managed wallet (FFIManagedWalletInfo type) # Safety - - `managed_wallet` must be a valid pointer to an FFIManagedWallet + - `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo - This function must only be called once per managed wallet */ - void ffi_managed_wallet_free(FFIManagedWallet *managed_wallet) ; + void ffi_managed_wallet_free(FFIManagedWalletInfo *managed_wallet) ; /* Get the transaction classification for routing diff --git a/key-wallet-ffi/include/key_wallet_ffi_test.h b/key-wallet-ffi/include/key_wallet_ffi_test.h index 987427650..039d5394e 100644 --- a/key-wallet-ffi/include/key_wallet_ffi_test.h +++ b/key-wallet-ffi/include/key_wallet_ffi_test.h @@ -424,12 +424,10 @@ typedef struct { } FFIAccountCollectionSummary; /* - FFI wrapper for ManagedWalletInfo that includes transaction checking capabilities + Deprecated alias: historically a separate wrapper was used for transaction + checking. It now aliases the canonical FFIManagedWalletInfo. */ -typedef struct { - ManagedWalletInfo *inner; - -} FFIManagedWallet; +typedef FFIManagedWalletInfo FFIManagedWallet; /* Address pool info @@ -1460,7 +1458,7 @@ void account_collection_summary_free(FFIAccountCollectionSummary *summary) - `error` must be a valid pointer to an FFIError or null */ -bool managed_wallet_get_address_pool_info(const FFIManagedWallet *managed_wallet, +bool managed_wallet_get_address_pool_info(const FFIManagedWalletInfo *managed_wallet, FFINetworks network, FFIAccountType account_type, unsigned int account_index, @@ -1481,7 +1479,7 @@ bool managed_wallet_get_address_pool_info(const FFIManagedWallet *managed_wallet - `error` must be a valid pointer to an FFIError or null */ -bool managed_wallet_set_gap_limit(FFIManagedWallet *managed_wallet, +bool managed_wallet_set_gap_limit(FFIManagedWalletInfo *managed_wallet, FFINetworks network, FFIAccountType account_type, unsigned int account_index, @@ -1504,7 +1502,7 @@ bool managed_wallet_set_gap_limit(FFIManagedWallet *managed_wallet, - `error` must be a valid pointer to an FFIError or null */ -bool managed_wallet_generate_addresses_to_index(FFIManagedWallet *managed_wallet, +bool managed_wallet_generate_addresses_to_index(FFIManagedWalletInfo *managed_wallet, const FFIWallet *wallet, FFINetworks network, FFIAccountType account_type, @@ -1527,7 +1525,7 @@ bool managed_wallet_generate_addresses_to_index(FFIManagedWallet *managed_wallet - `error` must be a valid pointer to an FFIError or null */ -bool managed_wallet_mark_address_used(FFIManagedWallet *managed_wallet, +bool managed_wallet_mark_address_used(FFIManagedWalletInfo *managed_wallet, FFINetworks network, const char *address, FFIError *error) @@ -3050,7 +3048,7 @@ bool wallet_check_transaction(FFIWallet *wallet, - `error` must be a valid pointer to an FFIError or null - The returned pointer must be freed with `ffi_managed_wallet_free` */ - FFIManagedWallet *wallet_create_managed_wallet(const FFIWallet *wallet, FFIError *error) ; +FFIManagedWalletInfo *wallet_create_managed_wallet(const FFIWallet *wallet, FFIError *error) ; /* Check if a transaction belongs to the wallet @@ -3068,7 +3066,7 @@ bool wallet_check_transaction(FFIWallet *wallet, - The affected_accounts array in the result must be freed with `transaction_check_result_free` */ -bool managed_wallet_check_transaction(FFIManagedWallet *managed_wallet, +bool managed_wallet_check_transaction(FFIManagedWalletInfo *managed_wallet, const FFIWallet *wallet, FFINetworks network, const uint8_t *tx_bytes, @@ -3100,7 +3098,7 @@ bool managed_wallet_check_transaction(FFIManagedWallet *managed_wallet, - `managed_wallet` must be a valid pointer to an FFIManagedWallet - This function must only be called once per managed wallet */ - void ffi_managed_wallet_free(FFIManagedWallet *managed_wallet) ; +void ffi_managed_wallet_free(FFIManagedWalletInfo *managed_wallet) ; /* Get the transaction classification for routing @@ -3449,4 +3447,3 @@ bool wallet_manager_add_wallet_from_mnemonic(FFIWalletManager *manager, FFINetworks network, FFIError *error) ; - diff --git a/key-wallet-ffi/src/address_pool.rs b/key-wallet-ffi/src/address_pool.rs index 9ce6fa8a7..71480f265 100644 --- a/key-wallet-ffi/src/address_pool.rs +++ b/key-wallet-ffi/src/address_pool.rs @@ -7,7 +7,7 @@ use std::ffi::CString; use std::os::raw::{c_char, c_uint}; use crate::error::{FFIError, FFIErrorCode}; -use crate::transaction_checking::FFIManagedWallet; +use crate::managed_wallet::FFIManagedWalletInfo; use crate::types::{FFIAccountType, FFIWallet}; use crate::utils::rust_string_to_c; use crate::FFINetwork; @@ -241,12 +241,12 @@ pub struct FFIAddressPoolInfo { /// /// # Safety /// -/// - `managed_wallet` must be a valid pointer to an FFIManagedWallet +/// - `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo /// - `info_out` must be a valid pointer to store the pool info /// - `error` must be a valid pointer to an FFIError or null #[no_mangle] pub unsafe extern "C" fn managed_wallet_get_address_pool_info( - managed_wallet: *const FFIManagedWallet, + managed_wallet: *const FFIManagedWalletInfo, network: FFINetwork, account_type: FFIAccountType, account_index: c_uint, @@ -259,7 +259,8 @@ pub unsafe extern "C" fn managed_wallet_get_address_pool_info( return false; } - let managed_wallet = &*(*managed_wallet).inner; + let wrapper = &*managed_wallet; + let managed_wallet = wrapper.inner(); let network_rust: key_wallet::Network = network.into(); let account_type_rust = account_type.to_account_type(account_index); @@ -362,11 +363,11 @@ pub unsafe extern "C" fn managed_wallet_get_address_pool_info( /// /// # Safety /// -/// - `managed_wallet` must be a valid pointer to an FFIManagedWallet +/// - `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo /// - `error` must be a valid pointer to an FFIError or null #[no_mangle] pub unsafe extern "C" fn managed_wallet_set_gap_limit( - managed_wallet: *mut FFIManagedWallet, + managed_wallet: *mut FFIManagedWalletInfo, network: FFINetwork, account_type: FFIAccountType, account_index: c_uint, @@ -379,7 +380,7 @@ pub unsafe extern "C" fn managed_wallet_set_gap_limit( return false; } - let managed_wallet = &mut *(*managed_wallet).inner; + let managed_wallet = (&mut *managed_wallet).inner_mut(); let network_rust: key_wallet::Network = network.into(); let account_type_rust = account_type.to_account_type(account_index); @@ -470,12 +471,12 @@ pub unsafe extern "C" fn managed_wallet_set_gap_limit( /// /// # Safety /// -/// - `managed_wallet` must be a valid pointer to an FFIManagedWallet +/// - `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo /// - `wallet` must be a valid pointer to an FFIWallet (for key derivation) /// - `error` must be a valid pointer to an FFIError or null #[no_mangle] pub unsafe extern "C" fn managed_wallet_generate_addresses_to_index( - managed_wallet: *mut FFIManagedWallet, + managed_wallet: *mut FFIManagedWalletInfo, wallet: *const FFIWallet, network: FFINetwork, account_type: FFIAccountType, @@ -489,7 +490,7 @@ pub unsafe extern "C" fn managed_wallet_generate_addresses_to_index( return false; } - let managed_wallet = &mut *(*managed_wallet).inner; + let managed_wallet = (&mut *managed_wallet).inner_mut(); let wallet = &*wallet; let network_rust: key_wallet::Network = network.into(); @@ -636,12 +637,12 @@ pub unsafe extern "C" fn managed_wallet_generate_addresses_to_index( /// /// # Safety /// -/// - `managed_wallet` must be a valid pointer to an FFIManagedWallet +/// - `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo /// - `address` must be a valid C string /// - `error` must be a valid pointer to an FFIError or null #[no_mangle] pub unsafe extern "C" fn managed_wallet_mark_address_used( - managed_wallet: *mut FFIManagedWallet, + managed_wallet: *mut FFIManagedWalletInfo, network: FFINetwork, address: *const c_char, error: *mut FFIError, @@ -651,7 +652,7 @@ pub unsafe extern "C" fn managed_wallet_mark_address_used( return false; } - let managed_wallet = &mut *(*managed_wallet).inner; + let managed_wallet = (&mut *managed_wallet).inner_mut(); let network_rust: key_wallet::Network = network.into(); // Parse the address string diff --git a/key-wallet-ffi/src/managed_account_collection.rs b/key-wallet-ffi/src/managed_account_collection.rs index 917adf2a2..23cb69675 100644 --- a/key-wallet-ffi/src/managed_account_collection.rs +++ b/key-wallet-ffi/src/managed_account_collection.rs @@ -121,6 +121,8 @@ pub unsafe extern "C" fn managed_wallet_get_account_collection( Box::into_raw(Box::new(ffi_collection)) } None => { + // Capture networks before freeing the pointer to avoid use-after-free + let networks = managed_wallet.inner().networks_supported(); // Clean up the managed wallet pointer crate::managed_wallet::managed_wallet_info_free(managed_wallet_ptr); @@ -129,8 +131,7 @@ pub unsafe extern "C" fn managed_wallet_get_account_collection( FFIErrorCode::NotFound, format!( "No accounts found for network {:?}, wallet has networks {:?}", - network_rust, - managed_wallet.inner().networks_supported() + network_rust, networks ), ); ptr::null_mut() diff --git a/key-wallet-ffi/src/managed_wallet.rs b/key-wallet-ffi/src/managed_wallet.rs index c2af70287..cbe253f35 100644 --- a/key-wallet-ffi/src/managed_wallet.rs +++ b/key-wallet-ffi/src/managed_wallet.rs @@ -13,26 +13,29 @@ use crate::types::FFIWallet; use crate::FFINetwork; use key_wallet::managed_account::address_pool::KeySource; use key_wallet::wallet::managed_wallet_info::ManagedWalletInfo; +use std::ffi::c_void; -/// FFI wrapper for ManagedWalletInfo +/// FFI wrapper for ManagedWalletInfo (single canonical type) +#[repr(C)] pub struct FFIManagedWalletInfo { - inner: ManagedWalletInfo, + // Opaque pointer to avoid leaking ManagedWalletInfo into C headers + inner: *mut c_void, } impl FFIManagedWalletInfo { /// Create a new FFIManagedWalletInfo from a ManagedWalletInfo pub fn new(inner: ManagedWalletInfo) -> Self { Self { - inner, + inner: Box::into_raw(Box::new(inner)) as *mut c_void, } } pub fn inner(&self) -> &ManagedWalletInfo { - &self.inner + unsafe { &*(self.inner as *const ManagedWalletInfo) } } pub fn inner_mut(&mut self) -> &mut ManagedWalletInfo { - &mut self.inner + unsafe { &mut *(self.inner as *mut ManagedWalletInfo) } } } @@ -74,7 +77,7 @@ pub unsafe extern "C" fn managed_wallet_get_next_bip44_receive_address( let network = network.into(); // Get the account collection for the network - let account_collection = match managed_wallet.inner.accounts.get_mut(&network) { + let account_collection = match managed_wallet.inner_mut().accounts.get_mut(&network) { Some(collection) => collection, None => { FFIError::set_error( @@ -198,7 +201,7 @@ pub unsafe extern "C" fn managed_wallet_get_next_bip44_change_address( let network = network.into(); // Get the account collection for the network - let account_collection = match managed_wallet.inner.accounts.get_mut(&network) { + let account_collection = match managed_wallet.inner_mut().accounts.get_mut(&network) { Some(collection) => collection, None => { FFIError::set_error( @@ -341,7 +344,7 @@ pub unsafe extern "C" fn managed_wallet_get_bip_44_external_address_range( let network = network.into(); // Get the account collection for the network - let account_collection = match managed_wallet.inner.accounts.get_mut(&network) { + let account_collection = match managed_wallet.inner_mut().accounts.get_mut(&network) { Some(collection) => collection, None => { FFIError::set_error( @@ -527,7 +530,7 @@ pub unsafe extern "C" fn managed_wallet_get_bip_44_internal_address_range( let network = network.into(); // Get the account collection for the network - let account_collection = match managed_wallet.inner.accounts.get_mut(&network) { + let account_collection = match managed_wallet.inner_mut().accounts.get_mut(&network) { Some(collection) => collection, None => { FFIError::set_error( @@ -700,7 +703,7 @@ pub unsafe extern "C" fn managed_wallet_get_balance( } let managed_wallet = unsafe { &*managed_wallet }; - let balance = &managed_wallet.inner.balance; + let balance = &managed_wallet.inner().balance; unsafe { *confirmed_out = balance.confirmed; @@ -722,8 +725,10 @@ pub unsafe extern "C" fn managed_wallet_get_balance( #[no_mangle] pub unsafe extern "C" fn managed_wallet_free(managed_wallet: *mut FFIManagedWalletInfo) { if !managed_wallet.is_null() { - unsafe { - let _ = Box::from_raw(managed_wallet); + // Reclaim outer struct, then free inner if present + let wrapper = Box::from_raw(managed_wallet); + if !wrapper.inner.is_null() { + let _ = Box::from_raw(wrapper.inner as *mut ManagedWalletInfo); } } } @@ -737,8 +742,9 @@ pub unsafe extern "C" fn managed_wallet_free(managed_wallet: *mut FFIManagedWall #[no_mangle] pub unsafe extern "C" fn managed_wallet_info_free(wallet_info: *mut FFIManagedWalletInfo) { if !wallet_info.is_null() { - unsafe { - let _ = Box::from_raw(wallet_info); + let wrapper = Box::from_raw(wallet_info); + if !wrapper.inner.is_null() { + let _ = Box::from_raw(wrapper.inner as *mut ManagedWalletInfo); } } } diff --git a/key-wallet-ffi/src/transaction_checking.rs b/key-wallet-ffi/src/transaction_checking.rs index feb56a1fd..1b2ebd20d 100644 --- a/key-wallet-ffi/src/transaction_checking.rs +++ b/key-wallet-ffi/src/transaction_checking.rs @@ -9,6 +9,7 @@ use std::os::raw::{c_char, c_uint}; use std::slice; use crate::error::{FFIError, FFIErrorCode}; +use crate::managed_wallet::{managed_wallet_info_free, FFIManagedWalletInfo}; use crate::types::{FFINetwork, FFITransactionContext, FFIWallet}; use dashcore::consensus::Decodable; use dashcore::Transaction; @@ -17,12 +18,6 @@ use key_wallet::transaction_checking::{ }; use key_wallet::wallet::managed_wallet_info::ManagedWalletInfo; -/// FFI wrapper for ManagedWalletInfo that includes transaction checking capabilities -#[repr(C)] -pub struct FFIManagedWallet { - pub(crate) inner: *mut ManagedWalletInfo, -} - // Transaction context for checking // FFITransactionContext is imported from types module at the top /// Account type match result @@ -74,12 +69,12 @@ pub struct FFITransactionCheckResult { /// /// - `wallet` must be a valid pointer to an FFIWallet /// - `error` must be a valid pointer to an FFIError or null -/// - The returned pointer must be freed with `ffi_managed_wallet_free` +/// - The returned pointer must be freed with `managed_wallet_info_free` (or `ffi_managed_wallet_free` for compatibility) #[no_mangle] pub unsafe extern "C" fn wallet_create_managed_wallet( wallet: *const FFIWallet, error: *mut FFIError, -) -> *mut FFIManagedWallet { +) -> *mut FFIManagedWalletInfo { if wallet.is_null() { FFIError::set_error(error, FFIErrorCode::InvalidInput, "Wallet is null".to_string()); return std::ptr::null_mut(); @@ -91,9 +86,7 @@ pub unsafe extern "C" fn wallet_create_managed_wallet( let managed_info = ManagedWalletInfo::from_wallet(wallet.inner()); // Box it and return raw pointer - let managed_wallet = Box::new(FFIManagedWallet { - inner: Box::into_raw(Box::new(managed_info)), - }); + let managed_wallet = Box::new(FFIManagedWalletInfo::new(managed_info)); FFIError::set_success(error); Box::into_raw(managed_wallet) @@ -106,7 +99,7 @@ pub unsafe extern "C" fn wallet_create_managed_wallet( /// /// # Safety /// -/// - `managed_wallet` must be a valid pointer to an FFIManagedWallet +/// - `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo /// - `wallet` must be a valid pointer to an FFIWallet (needed for address generation) /// - `tx_bytes` must be a valid pointer to transaction bytes with at least `tx_len` bytes /// - `result_out` must be a valid pointer to store the result @@ -114,7 +107,7 @@ pub unsafe extern "C" fn wallet_create_managed_wallet( /// - The affected_accounts array in the result must be freed with `transaction_check_result_free` #[no_mangle] pub unsafe extern "C" fn managed_wallet_check_transaction( - managed_wallet: *mut FFIManagedWallet, + managed_wallet: *mut FFIManagedWalletInfo, wallet: *const FFIWallet, network: FFINetwork, tx_bytes: *const u8, @@ -132,7 +125,7 @@ pub unsafe extern "C" fn managed_wallet_check_transaction( return false; } - let managed_wallet = &mut *(*managed_wallet).inner; + let managed_wallet: &mut ManagedWalletInfo = (*managed_wallet).inner_mut(); let network_rust: key_wallet::Network = network.into(); let tx_slice = slice::from_raw_parts(tx_bytes, tx_len); @@ -456,20 +449,16 @@ pub unsafe extern "C" fn transaction_check_result_free(result: *mut FFITransacti } } -/// Free a managed wallet (FFIManagedWallet type) +/// Free a managed wallet (FFIManagedWalletInfo type) /// /// # Safety /// -/// - `managed_wallet` must be a valid pointer to an FFIManagedWallet +/// - `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo /// - This function must only be called once per managed wallet #[no_mangle] -pub unsafe extern "C" fn ffi_managed_wallet_free(managed_wallet: *mut FFIManagedWallet) { - if !managed_wallet.is_null() { - let wallet = Box::from_raw(managed_wallet); - if !wallet.inner.is_null() { - let _ = Box::from_raw(wallet.inner); - } - } +pub unsafe extern "C" fn ffi_managed_wallet_free(managed_wallet: *mut FFIManagedWalletInfo) { + // For compatibility, forward to canonical free + managed_wallet_info_free(managed_wallet); } /// Get the transaction classification for routing diff --git a/swift-dash-core-sdk/Sources/DashSPVFFI/include/dash_spv_ffi.h b/swift-dash-core-sdk/Sources/DashSPVFFI/include/dash_spv_ffi.h index ae4ca7397..bf2c0073e 100644 --- a/swift-dash-core-sdk/Sources/DashSPVFFI/include/dash_spv_ffi.h +++ b/swift-dash-core-sdk/Sources/DashSPVFFI/include/dash_spv_ffi.h @@ -1,8 +1,21 @@ +/* dash-spv-ffi C bindings - Auto-generated by cbindgen */ + +#ifndef DASH_SPV_FFI_H +#define DASH_SPV_FFI_H + +/* Generated with cbindgen:0.29.0 */ + +/* Warning: This file is auto-generated by cbindgen. Do not modify manually. */ + #include #include #include #include +#ifdef __cplusplus +namespace dash_spv_ffi { +#endif // __cplusplus + typedef enum FFIMempoolStrategy { FetchAll = 0, BloomFilter = 1, @@ -19,11 +32,11 @@ typedef enum FFISyncStage { Failed = 6, } FFISyncStage; -typedef enum FFIValidationMode { +typedef enum DashSpvValidationMode { None = 0, Basic = 1, Full = 2, -} FFIValidationMode; +} DashSpvValidationMode; typedef struct FFIDashSpvClient FFIDashSpvClient; @@ -46,7 +59,10 @@ typedef struct FFIArray { uintptr_t elem_align; } FFIArray; -typedef ClientConfig FFIClientConfig; +typedef struct FFIClientConfig { + void *inner; + +} FFIClientConfig; typedef struct FFIString { char *ptr; @@ -193,6 +209,10 @@ typedef struct FFIUnconfirmedTransaction { uintptr_t addresses_len; } FFIUnconfirmedTransaction; +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + /** * Get the latest checkpoint for the given network. * @@ -200,7 +220,11 @@ typedef struct FFIUnconfirmedTransaction { * - `out_height` must be a valid pointer to a `u32`. * - `out_hash` must point to at least 32 writable bytes. */ -int32_t dash_spv_ffi_checkpoint_latest(FFINetwork network, uint32_t *out_height, uint8_t *out_hash); + +int32_t dash_spv_ffi_checkpoint_latest(FFINetwork network, + uint32_t *out_height, + uint8_t *out_hash) +; /** * Get the last checkpoint at or before a given height. @@ -209,10 +233,12 @@ int32_t dash_spv_ffi_checkpoint_latest(FFINetwork network, uint32_t *out_height, * - `out_height` must be a valid pointer to a `u32`. * - `out_hash` must point to at least 32 writable bytes. */ + int32_t dash_spv_ffi_checkpoint_before_height(FFINetwork network, uint32_t height, uint32_t *out_height, - uint8_t *out_hash); + uint8_t *out_hash) +; /** * Get the last checkpoint at or before a given UNIX timestamp (seconds). @@ -221,10 +247,12 @@ int32_t dash_spv_ffi_checkpoint_before_height(FFINetwork network, * - `out_height` must be a valid pointer to a `u32`. * - `out_hash` must point to at least 32 writable bytes. */ + int32_t dash_spv_ffi_checkpoint_before_timestamp(FFINetwork network, uint32_t timestamp, uint32_t *out_height, - uint8_t *out_hash); + uint8_t *out_hash) +; /** * Get all checkpoints between two heights (inclusive). @@ -232,9 +260,11 @@ int32_t dash_spv_ffi_checkpoint_before_timestamp(FFINetwork network, * Returns an `FFIArray` of `FFICheckpoint` items. The caller owns the memory and * must free the array buffer using `dash_spv_ffi_array_destroy` when done. */ + struct FFIArray dash_spv_ffi_checkpoints_between_heights(FFINetwork network, uint32_t start_height, - uint32_t end_height); + uint32_t end_height) +; /** * Create a new SPV client and return an opaque pointer. @@ -243,7 +273,7 @@ struct FFIArray dash_spv_ffi_checkpoints_between_heights(FFINetwork network, * - `config` must be a valid, non-null pointer for the duration of the call. * - The returned pointer must be freed with `dash_spv_ffi_client_destroy`. */ -struct FFIDashSpvClient *dash_spv_ffi_client_new(const FFIClientConfig *config); + struct FFIDashSpvClient *dash_spv_ffi_client_new(const struct FFIClientConfig *config) ; /** * Update the running client's configuration. @@ -253,8 +283,10 @@ struct FFIDashSpvClient *dash_spv_ffi_client_new(const FFIClientConfig *config); * - `config` must be a valid pointer to an `FFIClientConfig`. * - The network in `config` must match the client's network; changing networks at runtime is not supported. */ + int32_t dash_spv_ffi_client_update_config(struct FFIDashSpvClient *client, - const FFIClientConfig *config); + const struct FFIClientConfig *config) +; /** * Start the SPV client. @@ -262,7 +294,7 @@ int32_t dash_spv_ffi_client_update_config(struct FFIDashSpvClient *client, * # Safety * - `client` must be a valid, non-null pointer to a created client. */ -int32_t dash_spv_ffi_client_start(struct FFIDashSpvClient *client); + int32_t dash_spv_ffi_client_start(struct FFIDashSpvClient *client) ; /** * Stop the SPV client. @@ -270,7 +302,7 @@ int32_t dash_spv_ffi_client_start(struct FFIDashSpvClient *client); * # Safety * - `client` must be a valid, non-null pointer to a created client. */ -int32_t dash_spv_ffi_client_stop(struct FFIDashSpvClient *client); + int32_t dash_spv_ffi_client_stop(struct FFIDashSpvClient *client) ; /** * Sync the SPV client to the chain tip. @@ -295,9 +327,11 @@ int32_t dash_spv_ffi_client_stop(struct FFIDashSpvClient *client); * * 0 on success, error code on failure */ + int32_t dash_spv_ffi_client_sync_to_tip(struct FFIDashSpvClient *client, void (*completion_callback)(bool, const char*, void*), - void *user_data); + void *user_data) +; /** * Performs a test synchronization of the SPV client @@ -313,7 +347,7 @@ int32_t dash_spv_ffi_client_sync_to_tip(struct FFIDashSpvClient *client, * This function is unsafe because it dereferences a raw pointer. * The caller must ensure that the client pointer is valid. */ -int32_t dash_spv_ffi_client_test_sync(struct FFIDashSpvClient *client); + int32_t dash_spv_ffi_client_test_sync(struct FFIDashSpvClient *client) ; /** * Sync the SPV client to the chain tip with detailed progress updates. @@ -339,13 +373,15 @@ int32_t dash_spv_ffi_client_test_sync(struct FFIDashSpvClient *client); * * 0 on success, error code on failure */ + int32_t dash_spv_ffi_client_sync_to_tip_with_progress(struct FFIDashSpvClient *client, void (*progress_callback)(const struct FFIDetailedSyncProgress*, void*), void (*completion_callback)(bool, const char*, void*), - void *user_data); + void *user_data) +; /** * Cancels the sync operation. @@ -361,7 +397,7 @@ int32_t dash_spv_ffi_client_sync_to_tip_with_progress(struct FFIDashSpvClient *c * # Returns * Returns 0 on success, or an error code on failure. */ -int32_t dash_spv_ffi_client_cancel_sync(struct FFIDashSpvClient *client); + int32_t dash_spv_ffi_client_cancel_sync(struct FFIDashSpvClient *client) ; /** * Get the current sync progress snapshot. @@ -369,7 +405,7 @@ int32_t dash_spv_ffi_client_cancel_sync(struct FFIDashSpvClient *client); * # Safety * - `client` must be a valid, non-null pointer. */ -struct FFISyncProgress *dash_spv_ffi_client_get_sync_progress(struct FFIDashSpvClient *client); + struct FFISyncProgress *dash_spv_ffi_client_get_sync_progress(struct FFIDashSpvClient *client) ; /** * Get current runtime statistics for the SPV client. @@ -377,7 +413,7 @@ struct FFISyncProgress *dash_spv_ffi_client_get_sync_progress(struct FFIDashSpvC * # Safety * - `client` must be a valid, non-null pointer. */ -struct FFISpvStats *dash_spv_ffi_client_get_stats(struct FFIDashSpvClient *client); + struct FFISpvStats *dash_spv_ffi_client_get_stats(struct FFIDashSpvClient *client) ; /** * Check if compact filter sync is currently available. @@ -385,7 +421,7 @@ struct FFISpvStats *dash_spv_ffi_client_get_stats(struct FFIDashSpvClient *clien * # Safety * - `client` must be a valid, non-null pointer. */ -bool dash_spv_ffi_client_is_filter_sync_available(struct FFIDashSpvClient *client); + bool dash_spv_ffi_client_is_filter_sync_available(struct FFIDashSpvClient *client) ; /** * Set event callbacks for the client. @@ -393,8 +429,10 @@ bool dash_spv_ffi_client_is_filter_sync_available(struct FFIDashSpvClient *clien * # Safety * - `client` must be a valid, non-null pointer. */ + int32_t dash_spv_ffi_client_set_event_callbacks(struct FFIDashSpvClient *client, - struct FFIEventCallbacks callbacks); + struct FFIEventCallbacks callbacks) +; /** * Destroy the client and free associated resources. @@ -402,7 +440,7 @@ int32_t dash_spv_ffi_client_set_event_callbacks(struct FFIDashSpvClient *client, * # Safety * - `client` must be either null or a pointer obtained from `dash_spv_ffi_client_new`. */ -void dash_spv_ffi_client_destroy(struct FFIDashSpvClient *client); + void dash_spv_ffi_client_destroy(struct FFIDashSpvClient *client) ; /** * Destroy a `FFISyncProgress` object returned by this crate. @@ -410,7 +448,7 @@ void dash_spv_ffi_client_destroy(struct FFIDashSpvClient *client); * # Safety * - `progress` must be a pointer returned from this crate, or null. */ -void dash_spv_ffi_sync_progress_destroy(struct FFISyncProgress *progress); + void dash_spv_ffi_sync_progress_destroy(struct FFISyncProgress *progress) ; /** * Destroy an `FFISpvStats` object returned by this crate. @@ -418,7 +456,7 @@ void dash_spv_ffi_sync_progress_destroy(struct FFISyncProgress *progress); * # Safety * - `stats` must be a pointer returned from this crate, or null. */ -void dash_spv_ffi_spv_stats_destroy(struct FFISpvStats *stats); + void dash_spv_ffi_spv_stats_destroy(struct FFISpvStats *stats) ; /** * Request a rescan of the blockchain from a given height (not yet implemented). @@ -426,8 +464,10 @@ void dash_spv_ffi_spv_stats_destroy(struct FFISpvStats *stats); * # Safety * - `client` must be a valid, non-null pointer. */ + int32_t dash_spv_ffi_client_rescan_blockchain(struct FFIDashSpvClient *client, - uint32_t _from_height); + uint32_t _from_height) +; /** * Enable mempool tracking with a given strategy. @@ -435,8 +475,10 @@ int32_t dash_spv_ffi_client_rescan_blockchain(struct FFIDashSpvClient *client, * # Safety * - `client` must be a valid, non-null pointer. */ + int32_t dash_spv_ffi_client_enable_mempool_tracking(struct FFIDashSpvClient *client, - enum FFIMempoolStrategy strategy); + enum FFIMempoolStrategy strategy) +; /** * Record that we attempted to send a transaction by its txid. @@ -444,7 +486,7 @@ int32_t dash_spv_ffi_client_enable_mempool_tracking(struct FFIDashSpvClient *cli * # Safety * - `client` and `txid` must be valid, non-null pointers. */ -int32_t dash_spv_ffi_client_record_send(struct FFIDashSpvClient *client, const char *txid); + int32_t dash_spv_ffi_client_record_send(struct FFIDashSpvClient *client, const char *txid) ; /** * Get the wallet manager from the SPV client @@ -467,13 +509,15 @@ int32_t dash_spv_ffi_client_record_send(struct FFIDashSpvClient *client, const c * # Safety * - `client` must be a valid, non-null pointer. */ -void *dash_spv_ffi_client_get_wallet_manager(struct FFIDashSpvClient *client); -FFIClientConfig *dash_spv_ffi_config_new(FFINetwork network); +void *dash_spv_ffi_client_get_wallet_manager(struct FFIDashSpvClient *client) +; + + struct FFIClientConfig *dash_spv_ffi_config_new(FFINetwork network) ; -FFIClientConfig *dash_spv_ffi_config_mainnet(void); + struct FFIClientConfig *dash_spv_ffi_config_mainnet(void) ; -FFIClientConfig *dash_spv_ffi_config_testnet(void); + struct FFIClientConfig *dash_spv_ffi_config_testnet(void) ; /** * Sets the data directory for storing blockchain data @@ -483,8 +527,10 @@ FFIClientConfig *dash_spv_ffi_config_testnet(void); * - `path` must be a valid null-terminated C string * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_data_dir(FFIClientConfig *config, - const char *path); + +int32_t dash_spv_ffi_config_set_data_dir(struct FFIClientConfig *config, + const char *path) +; /** * Sets the validation mode for the SPV client @@ -493,8 +539,10 @@ int32_t dash_spv_ffi_config_set_data_dir(FFIClientConfig *config, * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_validation_mode(FFIClientConfig *config, - enum FFIValidationMode mode); + +int32_t dash_spv_ffi_config_set_validation_mode(struct FFIClientConfig *config, + enum DashSpvValidationMode mode) +; /** * Sets the maximum number of peers to connect to @@ -503,8 +551,10 @@ int32_t dash_spv_ffi_config_set_validation_mode(FFIClientConfig *config, * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_max_peers(FFIClientConfig *config, - uint32_t max_peers); + +int32_t dash_spv_ffi_config_set_max_peers(struct FFIClientConfig *config, + uint32_t max_peers) +; /** * Adds a peer address to the configuration @@ -518,8 +568,10 @@ int32_t dash_spv_ffi_config_set_max_peers(FFIClientConfig *config, * - `addr` must be a valid null-terminated C string containing a socket address or IP-only string * - The caller must ensure both pointers remain valid for the duration of this call */ -int32_t dash_spv_ffi_config_add_peer(FFIClientConfig *config, - const char *addr); + +int32_t dash_spv_ffi_config_add_peer(struct FFIClientConfig *config, + const char *addr) +; /** * Sets the user agent string to advertise in the P2P handshake @@ -529,8 +581,10 @@ int32_t dash_spv_ffi_config_add_peer(FFIClientConfig *config, * - `user_agent` must be a valid null-terminated C string * - The caller must ensure both pointers remain valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_user_agent(FFIClientConfig *config, - const char *user_agent); + +int32_t dash_spv_ffi_config_set_user_agent(struct FFIClientConfig *config, + const char *user_agent) +; /** * Sets whether to relay transactions (currently a no-op) @@ -539,8 +593,10 @@ int32_t dash_spv_ffi_config_set_user_agent(FFIClientConfig *config, * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_relay_transactions(FFIClientConfig *config, - bool _relay); + +int32_t dash_spv_ffi_config_set_relay_transactions(struct FFIClientConfig *config, + bool _relay) +; /** * Sets whether to load bloom filters @@ -549,8 +605,10 @@ int32_t dash_spv_ffi_config_set_relay_transactions(FFIClientConfig *config, * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_filter_load(FFIClientConfig *config, - bool load_filters); + +int32_t dash_spv_ffi_config_set_filter_load(struct FFIClientConfig *config, + bool load_filters) +; /** * Restrict connections strictly to configured peers (disable DNS discovery and peer store) @@ -558,8 +616,10 @@ int32_t dash_spv_ffi_config_set_filter_load(FFIClientConfig *config, * # Safety * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet */ -int32_t dash_spv_ffi_config_set_restrict_to_configured_peers(FFIClientConfig *config, - bool restrict); + +int32_t dash_spv_ffi_config_set_restrict_to_configured_peers(struct FFIClientConfig *config, + bool restrict_peers) +; /** * Enables or disables masternode synchronization @@ -568,8 +628,10 @@ int32_t dash_spv_ffi_config_set_restrict_to_configured_peers(FFIClientConfig *co * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_masternode_sync_enabled(FFIClientConfig *config, - bool enable); + +int32_t dash_spv_ffi_config_set_masternode_sync_enabled(struct FFIClientConfig *config, + bool enable) +; /** * Gets the network type from the configuration @@ -578,7 +640,7 @@ int32_t dash_spv_ffi_config_set_masternode_sync_enabled(FFIClientConfig *config, * - `config` must be a valid pointer to an FFIClientConfig or null * - If null, returns FFINetwork::Dash as default */ -FFINetwork dash_spv_ffi_config_get_network(const FFIClientConfig *config); + FFINetwork dash_spv_ffi_config_get_network(const struct FFIClientConfig *config) ; /** * Gets the data directory path from the configuration @@ -588,7 +650,7 @@ FFINetwork dash_spv_ffi_config_get_network(const FFIClientConfig *config); * - If null or no data directory is set, returns an FFIString with null pointer * - The returned FFIString must be freed by the caller using `dash_spv_ffi_string_destroy` */ -struct FFIString dash_spv_ffi_config_get_data_dir(const FFIClientConfig *config); + struct FFIString dash_spv_ffi_config_get_data_dir(const struct FFIClientConfig *config) ; /** * Destroys an FFIClientConfig and frees its memory @@ -598,7 +660,9 @@ struct FFIString dash_spv_ffi_config_get_data_dir(const FFIClientConfig *config) * - After calling this function, the config pointer becomes invalid and must not be used * - This function should only be called once per config instance */ -void dash_spv_ffi_config_destroy(FFIClientConfig *config); + +void dash_spv_ffi_config_destroy(struct FFIClientConfig *config) +; /** * Enables or disables mempool tracking @@ -607,8 +671,10 @@ void dash_spv_ffi_config_destroy(FFIClientConfig *config); * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_mempool_tracking(FFIClientConfig *config, - bool enable); + +int32_t dash_spv_ffi_config_set_mempool_tracking(struct FFIClientConfig *config, + bool enable) +; /** * Sets the mempool synchronization strategy @@ -617,8 +683,10 @@ int32_t dash_spv_ffi_config_set_mempool_tracking(FFIClientConfig *config, * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_mempool_strategy(FFIClientConfig *config, - enum FFIMempoolStrategy strategy); + +int32_t dash_spv_ffi_config_set_mempool_strategy(struct FFIClientConfig *config, + enum FFIMempoolStrategy strategy) +; /** * Sets the maximum number of mempool transactions to track @@ -627,8 +695,10 @@ int32_t dash_spv_ffi_config_set_mempool_strategy(FFIClientConfig *config, * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_max_mempool_transactions(FFIClientConfig *config, - uint32_t max_transactions); + +int32_t dash_spv_ffi_config_set_max_mempool_transactions(struct FFIClientConfig *config, + uint32_t max_transactions) +; /** * Sets the mempool transaction timeout in seconds @@ -637,8 +707,10 @@ int32_t dash_spv_ffi_config_set_max_mempool_transactions(FFIClientConfig *config * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_mempool_timeout(FFIClientConfig *config, - uint64_t timeout_secs); + +int32_t dash_spv_ffi_config_set_mempool_timeout(struct FFIClientConfig *config, + uint64_t timeout_secs) +; /** * Sets whether to fetch full mempool transaction data @@ -647,8 +719,10 @@ int32_t dash_spv_ffi_config_set_mempool_timeout(FFIClientConfig *config, * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_fetch_mempool_transactions(FFIClientConfig *config, - bool fetch); + +int32_t dash_spv_ffi_config_set_fetch_mempool_transactions(struct FFIClientConfig *config, + bool fetch) +; /** * Sets whether to persist mempool state to disk @@ -657,8 +731,10 @@ int32_t dash_spv_ffi_config_set_fetch_mempool_transactions(FFIClientConfig *conf * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_persist_mempool(FFIClientConfig *config, - bool persist); + +int32_t dash_spv_ffi_config_set_persist_mempool(struct FFIClientConfig *config, + bool persist) +; /** * Gets whether mempool tracking is enabled @@ -667,7 +743,7 @@ int32_t dash_spv_ffi_config_set_persist_mempool(FFIClientConfig *config, * - `config` must be a valid pointer to an FFIClientConfig or null * - If null, returns false as default */ -bool dash_spv_ffi_config_get_mempool_tracking(const FFIClientConfig *config); + bool dash_spv_ffi_config_get_mempool_tracking(const struct FFIClientConfig *config) ; /** * Gets the mempool synchronization strategy @@ -676,7 +752,9 @@ bool dash_spv_ffi_config_get_mempool_tracking(const FFIClientConfig *config); * - `config` must be a valid pointer to an FFIClientConfig or null * - If null, returns FFIMempoolStrategy::Selective as default */ -enum FFIMempoolStrategy dash_spv_ffi_config_get_mempool_strategy(const FFIClientConfig *config); + +enum FFIMempoolStrategy dash_spv_ffi_config_get_mempool_strategy(const struct FFIClientConfig *config) +; /** * Sets the starting block height for synchronization @@ -685,8 +763,10 @@ enum FFIMempoolStrategy dash_spv_ffi_config_get_mempool_strategy(const FFIClient * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_start_from_height(FFIClientConfig *config, - uint32_t height); + +int32_t dash_spv_ffi_config_set_start_from_height(struct FFIClientConfig *config, + uint32_t height) +; /** * Sets the wallet creation timestamp for synchronization optimization @@ -695,12 +775,14 @@ int32_t dash_spv_ffi_config_set_start_from_height(FFIClientConfig *config, * - `config` must be a valid pointer to an FFIClientConfig created by dash_spv_ffi_config_new/mainnet/testnet * - The caller must ensure the config pointer remains valid for the duration of this call */ -int32_t dash_spv_ffi_config_set_wallet_creation_time(FFIClientConfig *config, - uint32_t timestamp); -const char *dash_spv_ffi_get_last_error(void); +int32_t dash_spv_ffi_config_set_wallet_creation_time(struct FFIClientConfig *config, + uint32_t timestamp) +; + + const char *dash_spv_ffi_get_last_error(void) ; -void dash_spv_ffi_clear_error(void); + void dash_spv_ffi_clear_error(void) ; /** * Creates a CoreSDKHandle from an FFIDashSpvClient @@ -711,7 +793,7 @@ void dash_spv_ffi_clear_error(void); * - The caller must ensure the client pointer is valid * - The returned handle must be properly released with ffi_dash_spv_release_core_handle */ -struct CoreSDKHandle *ffi_dash_spv_get_core_handle(struct FFIDashSpvClient *client); + struct CoreSDKHandle *ffi_dash_spv_get_core_handle(struct FFIDashSpvClient *client) ; /** * Releases a CoreSDKHandle @@ -722,7 +804,7 @@ struct CoreSDKHandle *ffi_dash_spv_get_core_handle(struct FFIDashSpvClient *clie * - The caller must ensure the handle pointer is valid * - The handle must not be used after this call */ -void ffi_dash_spv_release_core_handle(struct CoreSDKHandle *handle); + void ffi_dash_spv_release_core_handle(struct CoreSDKHandle *handle) ; /** * Gets a quorum public key from the Core chain @@ -735,12 +817,14 @@ void ffi_dash_spv_release_core_handle(struct CoreSDKHandle *handle); * - out_pubkey must point to a buffer of at least out_pubkey_size bytes * - out_pubkey_size must be at least 48 bytes */ + struct FFIResult ffi_dash_spv_get_quorum_public_key(struct FFIDashSpvClient *client, uint32_t quorum_type, const uint8_t *quorum_hash, uint32_t core_chain_locked_height, uint8_t *out_pubkey, - uintptr_t out_pubkey_size); + uintptr_t out_pubkey_size) +; /** * Gets the platform activation height from the Core chain @@ -751,22 +835,24 @@ struct FFIResult ffi_dash_spv_get_quorum_public_key(struct FFIDashSpvClient *cli * - The caller must ensure all pointers are valid * - out_height must point to a valid u32 */ + struct FFIResult ffi_dash_spv_get_platform_activation_height(struct FFIDashSpvClient *client, - uint32_t *out_height); + uint32_t *out_height) +; /** * # Safety * - `s.ptr` must be a pointer previously returned by `FFIString::new` or compatible. * - It must not be used after this call. */ -void dash_spv_ffi_string_destroy(struct FFIString s); + void dash_spv_ffi_string_destroy(struct FFIString s) ; /** * # Safety * - `arr` must be either null or a valid pointer to an `FFIArray` previously constructed in Rust. * - The memory referenced by `arr.data` must not be used after this call. */ -void dash_spv_ffi_array_destroy(struct FFIArray *arr); + void dash_spv_ffi_array_destroy(struct FFIArray *arr) ; /** * Destroy an array of FFIString pointers (Vec<*mut FFIString>) and their contents. @@ -780,7 +866,9 @@ void dash_spv_ffi_array_destroy(struct FFIArray *arr); * - Each element pointer must be valid or null; non-null entries are freed. * - The memory referenced by `arr.data` must not be used after this call. */ -void dash_spv_ffi_string_array_destroy(struct FFIArray *arr); + +void dash_spv_ffi_string_array_destroy(struct FFIArray *arr) +; /** * Destroys the raw transaction bytes allocated for an FFIUnconfirmedTransaction @@ -792,7 +880,7 @@ void dash_spv_ffi_string_array_destroy(struct FFIArray *arr); * - The pointer must not be used after this function is called * - This function should only be called once per allocation */ -void dash_spv_ffi_unconfirmed_transaction_destroy_raw_tx(uint8_t *raw_tx, uintptr_t raw_tx_len); + void dash_spv_ffi_unconfirmed_transaction_destroy_raw_tx(uint8_t *raw_tx, uintptr_t raw_tx_len) ; /** * Destroys the addresses array allocated for an FFIUnconfirmedTransaction @@ -805,8 +893,10 @@ void dash_spv_ffi_unconfirmed_transaction_destroy_raw_tx(uint8_t *raw_tx, uintpt * - The pointer must not be used after this function is called * - This function should only be called once per allocation */ + void dash_spv_ffi_unconfirmed_transaction_destroy_addresses(struct FFIString *addresses, - uintptr_t addresses_len); + uintptr_t addresses_len) +; /** * Destroys an FFIUnconfirmedTransaction and all its associated resources @@ -818,7 +908,7 @@ void dash_spv_ffi_unconfirmed_transaction_destroy_addresses(struct FFIString *ad * - The pointer must not be used after this function is called * - This function should only be called once per FFIUnconfirmedTransaction */ -void dash_spv_ffi_unconfirmed_transaction_destroy(struct FFIUnconfirmedTransaction *tx); + void dash_spv_ffi_unconfirmed_transaction_destroy(struct FFIUnconfirmedTransaction *tx) ; /** * Initialize logging for the SPV library. @@ -827,11 +917,23 @@ void dash_spv_ffi_unconfirmed_transaction_destroy(struct FFIUnconfirmedTransacti * - `level` may be null or point to a valid, NUL-terminated C string. * - If non-null, the pointer must remain valid for the duration of this call. */ -int32_t dash_spv_ffi_init_logging(const char *level); + int32_t dash_spv_ffi_init_logging(const char *level) ; + + const char *dash_spv_ffi_version(void) ; -const char *dash_spv_ffi_version(void); + void dash_spv_ffi_enable_test_mode(void) ; -void dash_spv_ffi_enable_test_mode(void); int32_t dash_spv_ffi_client_broadcast_transaction(struct FFIDashSpvClient *client, - const char *tx_hex); + const char *tx_hex) +; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#ifdef __cplusplus +} // namespace dash_spv_ffi +#endif // __cplusplus + +#endif /* DASH_SPV_FFI_H */ diff --git a/swift-dash-core-sdk/Sources/KeyWalletFFI/include/key_wallet_ffi.h b/swift-dash-core-sdk/Sources/KeyWalletFFI/include/key_wallet_ffi.h index fcec5a290..ae0749d60 100644 --- a/swift-dash-core-sdk/Sources/KeyWalletFFI/include/key_wallet_ffi.h +++ b/swift-dash-core-sdk/Sources/KeyWalletFFI/include/key_wallet_ffi.h @@ -263,11 +263,6 @@ typedef struct FFIManagedAccount FFIManagedAccount; */ typedef struct FFIManagedAccountCollection FFIManagedAccountCollection; -/* - FFI wrapper for ManagedWalletInfo - */ -typedef struct FFIManagedWalletInfo FFIManagedWalletInfo; - /* Opaque type for a private key (SecretKey) */ @@ -394,12 +389,11 @@ typedef struct { } FFIAccountCollectionSummary; /* - FFI wrapper for ManagedWalletInfo that includes transaction checking capabilities + FFI wrapper for ManagedWalletInfo (single canonical type) */ typedef struct { - ManagedWalletInfo *inner; - -} FFIManagedWallet; + void *inner; +} FFIManagedWalletInfo; /* Address pool info @@ -1657,12 +1651,12 @@ FFIPrivateKey *account_derive_private_key_from_mnemonic(const FFIAccount *accoun # Safety - - `managed_wallet` must be a valid pointer to an FFIManagedWallet + - `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo - `info_out` must be a valid pointer to store the pool info - `error` must be a valid pointer to an FFIError or null */ -bool managed_wallet_get_address_pool_info(const FFIManagedWallet *managed_wallet, +bool managed_wallet_get_address_pool_info(const FFIManagedWalletInfo *managed_wallet, FFINetwork network, FFIAccountType account_type, unsigned int account_index, @@ -1679,11 +1673,11 @@ bool managed_wallet_get_address_pool_info(const FFIManagedWallet *managed_wallet # Safety - - `managed_wallet` must be a valid pointer to an FFIManagedWallet + - `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo - `error` must be a valid pointer to an FFIError or null */ -bool managed_wallet_set_gap_limit(FFIManagedWallet *managed_wallet, +bool managed_wallet_set_gap_limit(FFIManagedWalletInfo *managed_wallet, FFINetwork network, FFIAccountType account_type, unsigned int account_index, @@ -1701,12 +1695,12 @@ bool managed_wallet_set_gap_limit(FFIManagedWallet *managed_wallet, # Safety - - `managed_wallet` must be a valid pointer to an FFIManagedWallet + - `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo - `wallet` must be a valid pointer to an FFIWallet (for key derivation) - `error` must be a valid pointer to an FFIError or null */ -bool managed_wallet_generate_addresses_to_index(FFIManagedWallet *managed_wallet, +bool managed_wallet_generate_addresses_to_index(FFIManagedWalletInfo *managed_wallet, const FFIWallet *wallet, FFINetwork network, FFIAccountType account_type, @@ -1724,12 +1718,12 @@ bool managed_wallet_generate_addresses_to_index(FFIManagedWallet *managed_wallet # Safety - - `managed_wallet` must be a valid pointer to an FFIManagedWallet + - `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo - `address` must be a valid C string - `error` must be a valid pointer to an FFIError or null */ -bool managed_wallet_mark_address_used(FFIManagedWallet *managed_wallet, +bool managed_wallet_mark_address_used(FFIManagedWalletInfo *managed_wallet, FFINetwork network, const char *address, FFIError *error) @@ -3371,9 +3365,12 @@ int32_t transaction_sign_input(FFITransaction *tx, - `wallet` must be a valid pointer to an FFIWallet - `error` must be a valid pointer to an FFIError or null - - The returned pointer must be freed with `ffi_managed_wallet_free` + - The returned pointer must be freed with `managed_wallet_info_free` (or `ffi_managed_wallet_free` for compatibility) */ - FFIManagedWallet *wallet_create_managed_wallet(const FFIWallet *wallet, FFIError *error) ; + +FFIManagedWalletInfo *wallet_create_managed_wallet(const FFIWallet *wallet, + FFIError *error) +; /* Check if a transaction belongs to the wallet @@ -3383,7 +3380,7 @@ int32_t transaction_sign_input(FFITransaction *tx, # Safety - - `managed_wallet` must be a valid pointer to an FFIManagedWallet + - `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo - `wallet` must be a valid pointer to an FFIWallet (needed for address generation) - `tx_bytes` must be a valid pointer to transaction bytes with at least `tx_len` bytes - `result_out` must be a valid pointer to store the result @@ -3391,7 +3388,7 @@ int32_t transaction_sign_input(FFITransaction *tx, - The affected_accounts array in the result must be freed with `transaction_check_result_free` */ -bool managed_wallet_check_transaction(FFIManagedWallet *managed_wallet, +bool managed_wallet_check_transaction(FFIManagedWalletInfo *managed_wallet, const FFIWallet *wallet, FFINetwork network, const uint8_t *tx_bytes, @@ -3416,14 +3413,14 @@ bool managed_wallet_check_transaction(FFIManagedWallet *managed_wallet, void transaction_check_result_free(FFITransactionCheckResult *result) ; /* - Free a managed wallet (FFIManagedWallet type) + Free a managed wallet (FFIManagedWalletInfo type) # Safety - - `managed_wallet` must be a valid pointer to an FFIManagedWallet + - `managed_wallet` must be a valid pointer to an FFIManagedWalletInfo - This function must only be called once per managed wallet */ - void ffi_managed_wallet_free(FFIManagedWallet *managed_wallet) ; + void ffi_managed_wallet_free(FFIManagedWalletInfo *managed_wallet) ; /* Get the transaction classification for routing