Skip to content

Commit 1656d76

Browse files
feat: add functions for checkpoint retrieval in FFI API
1 parent 66b18fb commit 1656d76

File tree

4 files changed

+268
-17
lines changed

4 files changed

+268
-17
lines changed

dash-spv-ffi/FFI_API.md

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ This document provides a comprehensive reference for all FFI (Foreign Function I
44

55
**Auto-generated**: This documentation is automatically generated from the source code. Do not edit manually.
66

7-
**Total Functions**: 57
7+
**Total Functions**: 61
88

99
## Table of Contents
1010

@@ -132,11 +132,15 @@ Functions: 2
132132

133133
### Utility Functions
134134

135-
Functions: 11
135+
Functions: 15
136136

137137
| Function | Description | Module |
138138
|----------|-------------|--------|
139139
| `dash_spv_ffi_array_destroy` | No description | types |
140+
| `dash_spv_ffi_checkpoint_before_height` | Get the last checkpoint at or before a given height | checkpoints |
141+
| `dash_spv_ffi_checkpoint_before_timestamp` | Get the last checkpoint at or before a given UNIX timestamp (seconds) | checkpoints |
142+
| `dash_spv_ffi_checkpoint_latest` | Get the latest checkpoint for the given network | checkpoints |
143+
| `dash_spv_ffi_checkpoints_between_heights` | Get all checkpoints between two heights (inclusive) | checkpoints |
140144
| `dash_spv_ffi_client_get_stats` | No description | client |
141145
| `dash_spv_ffi_client_get_wallet_manager` | Get the wallet manager from the SPV client Returns an opaque pointer to FFIW... | client |
142146
| `dash_spv_ffi_client_record_send` | No description | client |
@@ -826,6 +830,67 @@ dash_spv_ffi_array_destroy(arr: *mut FFIArray) -> ()
826830
827831
---
828832
833+
#### `dash_spv_ffi_checkpoint_before_height`
834+
835+
```c
836+
dash_spv_ffi_checkpoint_before_height(network: FFINetwork, height: u32, out_height: *mut u32, out_hash: *mut u8, // expects at least 32 bytes) -> i32
837+
```
838+
839+
**Description:**
840+
Get the last checkpoint at or before a given height. # Safety - `out_height` must be a valid pointer to a `u32`. - `out_hash` must point to at least 32 writable bytes.
841+
842+
**Safety:**
843+
- `out_height` must be a valid pointer to a `u32`. - `out_hash` must point to at least 32 writable bytes.
844+
845+
**Module:** `checkpoints`
846+
847+
---
848+
849+
#### `dash_spv_ffi_checkpoint_before_timestamp`
850+
851+
```c
852+
dash_spv_ffi_checkpoint_before_timestamp(network: FFINetwork, timestamp: u32, out_height: *mut u32, out_hash: *mut u8, // expects at least 32 bytes) -> i32
853+
```
854+
855+
**Description:**
856+
Get the last checkpoint at or before a given UNIX timestamp (seconds). # Safety - `out_height` must be a valid pointer to a `u32`. - `out_hash` must point to at least 32 writable bytes.
857+
858+
**Safety:**
859+
- `out_height` must be a valid pointer to a `u32`. - `out_hash` must point to at least 32 writable bytes.
860+
861+
**Module:** `checkpoints`
862+
863+
---
864+
865+
#### `dash_spv_ffi_checkpoint_latest`
866+
867+
```c
868+
dash_spv_ffi_checkpoint_latest(network: FFINetwork, out_height: *mut u32, out_hash: *mut u8, // expects at least 32 bytes) -> i32
869+
```
870+
871+
**Description:**
872+
Get the latest checkpoint for the given network. # Safety - `out_height` must be a valid pointer to a `u32`. - `out_hash` must point to at least 32 writable bytes.
873+
874+
**Safety:**
875+
- `out_height` must be a valid pointer to a `u32`. - `out_hash` must point to at least 32 writable bytes.
876+
877+
**Module:** `checkpoints`
878+
879+
---
880+
881+
#### `dash_spv_ffi_checkpoints_between_heights`
882+
883+
```c
884+
dash_spv_ffi_checkpoints_between_heights(network: FFINetwork, start_height: u32, end_height: u32,) -> FFIArray
885+
```
886+
887+
**Description:**
888+
Get all checkpoints between two heights (inclusive). 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.
889+
890+
**Module:** `checkpoints`
891+
892+
---
893+
829894
#### `dash_spv_ffi_client_get_stats`
830895
831896
```c

dash-spv-ffi/include/dash_spv_ffi.h

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -129,21 +129,6 @@ typedef struct FFIEventCallbacks {
129129
void *user_data;
130130
} FFIEventCallbacks;
131131

132-
/**
133-
* Handle for Core SDK that can be passed to Platform SDK
134-
*/
135-
typedef struct CoreSDKHandle {
136-
struct FFIDashSpvClient *client;
137-
} CoreSDKHandle;
138-
139-
/**
140-
* FFIResult type for error handling
141-
*/
142-
typedef struct FFIResult {
143-
int32_t error_code;
144-
const char *error_message;
145-
} FFIResult;
146-
147132
/**
148133
* FFI-safe array that transfers ownership of memory to the C caller.
149134
*
@@ -163,6 +148,21 @@ typedef struct FFIArray {
163148
uintptr_t elem_align;
164149
} FFIArray;
165150

151+
/**
152+
* Handle for Core SDK that can be passed to Platform SDK
153+
*/
154+
typedef struct CoreSDKHandle {
155+
struct FFIDashSpvClient *client;
156+
} CoreSDKHandle;
157+
158+
/**
159+
* FFIResult type for error handling
160+
*/
161+
typedef struct FFIResult {
162+
int32_t error_code;
163+
const char *error_message;
164+
} FFIResult;
165+
166166
/**
167167
* FFI-safe representation of an unconfirmed transaction
168168
*
@@ -541,6 +541,22 @@ int32_t dash_spv_ffi_config_set_start_from_height(FFIClientConfig *config,
541541
int32_t dash_spv_ffi_config_set_wallet_creation_time(FFIClientConfig *config,
542542
uint32_t timestamp);
543543

544+
int32_t dash_spv_ffi_checkpoint_latest(FFINetwork network, uint32_t *out_height, uint8_t *out_hash);
545+
546+
int32_t dash_spv_ffi_checkpoint_before_height(FFINetwork network,
547+
uint32_t height,
548+
uint32_t *out_height,
549+
uint8_t *out_hash);
550+
551+
int32_t dash_spv_ffi_checkpoint_before_timestamp(FFINetwork network,
552+
uint32_t timestamp,
553+
uint32_t *out_height,
554+
uint8_t *out_hash);
555+
556+
struct FFIArray dash_spv_ffi_checkpoints_between_heights(FFINetwork network,
557+
uint32_t start_height,
558+
uint32_t end_height);
559+
544560
const char *dash_spv_ffi_get_last_error(void);
545561

546562
void dash_spv_ffi_clear_error(void);

dash-spv-ffi/src/checkpoints.rs

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
use crate::{set_last_error, FFIArray, FFIErrorCode};
2+
use dash_spv::chain::checkpoints::{mainnet_checkpoints, testnet_checkpoints, CheckpointManager};
3+
use dashcore::Network;
4+
use dashcore::hashes::Hash;
5+
use key_wallet_ffi::FFINetwork;
6+
7+
/// FFI representation of a checkpoint (height + block hash)
8+
#[repr(C)]
9+
pub struct FFICheckpoint {
10+
pub height: u32,
11+
pub block_hash: [u8; 32],
12+
}
13+
14+
fn manager_for_network(network: FFINetwork) -> Result<CheckpointManager, String> {
15+
let net: Network = network.into();
16+
match net {
17+
Network::Dash => Ok(CheckpointManager::new(mainnet_checkpoints())),
18+
Network::Testnet => Ok(CheckpointManager::new(testnet_checkpoints())),
19+
_ => Err("Checkpoints are only available for Dash and Testnet".to_string()),
20+
}
21+
}
22+
23+
/// Get the latest checkpoint for the given network.
24+
///
25+
/// # Safety
26+
/// - `out_height` must be a valid pointer to a `u32`.
27+
/// - `out_hash` must point to at least 32 writable bytes.
28+
#[no_mangle]
29+
pub extern "C" fn dash_spv_ffi_checkpoint_latest(
30+
network: FFINetwork,
31+
out_height: *mut u32,
32+
out_hash: *mut u8, // expects at least 32 bytes
33+
) -> i32 {
34+
if out_height.is_null() || out_hash.is_null() {
35+
set_last_error("Null output pointer provided");
36+
return FFIErrorCode::NullPointer as i32;
37+
}
38+
let mgr = match manager_for_network(network) {
39+
Ok(m) => m,
40+
Err(e) => {
41+
set_last_error(&e);
42+
return FFIErrorCode::InvalidArgument as i32;
43+
}
44+
};
45+
if let Some(cp) = mgr.last_checkpoint() {
46+
unsafe {
47+
*out_height = cp.height;
48+
let hash = cp.block_hash.to_byte_array();
49+
std::ptr::copy_nonoverlapping(hash.as_ptr(), out_hash, 32);
50+
}
51+
FFIErrorCode::Success as i32
52+
} else {
53+
set_last_error("No checkpoints available for network");
54+
FFIErrorCode::NotImplemented as i32
55+
}
56+
}
57+
58+
/// Get the last checkpoint at or before a given height.
59+
///
60+
/// # Safety
61+
/// - `out_height` must be a valid pointer to a `u32`.
62+
/// - `out_hash` must point to at least 32 writable bytes.
63+
#[no_mangle]
64+
pub extern "C" fn dash_spv_ffi_checkpoint_before_height(
65+
network: FFINetwork,
66+
height: u32,
67+
out_height: *mut u32,
68+
out_hash: *mut u8, // expects at least 32 bytes
69+
) -> i32 {
70+
if out_height.is_null() || out_hash.is_null() {
71+
set_last_error("Null output pointer provided");
72+
return FFIErrorCode::NullPointer as i32;
73+
}
74+
let mgr = match manager_for_network(network) {
75+
Ok(m) => m,
76+
Err(e) => {
77+
set_last_error(&e);
78+
return FFIErrorCode::InvalidArgument as i32;
79+
}
80+
};
81+
if let Some(cp) = mgr.last_checkpoint_before_height(height) {
82+
unsafe {
83+
*out_height = cp.height;
84+
let hash = cp.block_hash.to_byte_array();
85+
std::ptr::copy_nonoverlapping(hash.as_ptr(), out_hash, 32);
86+
}
87+
FFIErrorCode::Success as i32
88+
} else {
89+
set_last_error("No checkpoint at or before given height");
90+
FFIErrorCode::ValidationError as i32
91+
}
92+
}
93+
94+
/// Get the last checkpoint at or before a given UNIX timestamp (seconds).
95+
///
96+
/// # Safety
97+
/// - `out_height` must be a valid pointer to a `u32`.
98+
/// - `out_hash` must point to at least 32 writable bytes.
99+
#[no_mangle]
100+
pub extern "C" fn dash_spv_ffi_checkpoint_before_timestamp(
101+
network: FFINetwork,
102+
timestamp: u32,
103+
out_height: *mut u32,
104+
out_hash: *mut u8, // expects at least 32 bytes
105+
) -> i32 {
106+
if out_height.is_null() || out_hash.is_null() {
107+
set_last_error("Null output pointer provided");
108+
return FFIErrorCode::NullPointer as i32;
109+
}
110+
let mgr = match manager_for_network(network) {
111+
Ok(m) => m,
112+
Err(e) => {
113+
set_last_error(&e);
114+
return FFIErrorCode::InvalidArgument as i32;
115+
}
116+
};
117+
if let Some(cp) = mgr.last_checkpoint_before_timestamp(timestamp) {
118+
unsafe {
119+
*out_height = cp.height;
120+
let hash = cp.block_hash.to_byte_array();
121+
std::ptr::copy_nonoverlapping(hash.as_ptr(), out_hash, 32);
122+
}
123+
FFIErrorCode::Success as i32
124+
} else {
125+
set_last_error("No checkpoint at or before given timestamp");
126+
FFIErrorCode::ValidationError as i32
127+
}
128+
}
129+
130+
/// Get all checkpoints between two heights (inclusive).
131+
///
132+
/// Returns an `FFIArray` of `FFICheckpoint` items. The caller owns the memory and
133+
/// must free the array buffer using `dash_spv_ffi_array_destroy` when done.
134+
#[no_mangle]
135+
pub extern "C" fn dash_spv_ffi_checkpoints_between_heights(
136+
network: FFINetwork,
137+
start_height: u32,
138+
end_height: u32,
139+
) -> FFIArray {
140+
match manager_for_network(network) {
141+
Ok(mgr) => {
142+
// Collect checkpoints within inclusive range
143+
let mut out: Vec<FFICheckpoint> = Vec::new();
144+
for &h in mgr.checkpoint_heights() {
145+
if h >= start_height && h <= end_height {
146+
if let Some(cp) = mgr.get_checkpoint(h) {
147+
out.push(FFICheckpoint {
148+
height: cp.height,
149+
block_hash: cp.block_hash.to_byte_array(),
150+
});
151+
}
152+
}
153+
}
154+
FFIArray::new(out)
155+
}
156+
Err(e) => {
157+
set_last_error(&e);
158+
// Return empty array on error
159+
FFIArray {
160+
data: std::ptr::null_mut(),
161+
len: 0,
162+
capacity: 0,
163+
elem_size: std::mem::size_of::<FFICheckpoint>(),
164+
elem_align: std::mem::align_of::<FFICheckpoint>(),
165+
}
166+
}
167+
}
168+
}

dash-spv-ffi/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
pub mod callbacks;
22
pub mod client;
33
pub mod config;
4+
pub mod checkpoints;
45
pub mod error;
56
pub mod platform_integration;
67
pub mod types;
@@ -9,6 +10,7 @@ pub mod utils;
910
pub use callbacks::*;
1011
pub use client::*;
1112
pub use config::*;
13+
pub use checkpoints::*;
1214
pub use error::*;
1315
pub use platform_integration::*;
1416
pub use types::*;

0 commit comments

Comments
 (0)