Skip to content

Commit 6593eb2

Browse files
committed
checkpoint rewrite
1 parent 8236af5 commit 6593eb2

File tree

11 files changed

+377
-917
lines changed

11 files changed

+377
-917
lines changed

dash-spv-ffi/FFI_API.md

Lines changed: 2 additions & 16 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**: 66
7+
**Total Functions**: 65
88

99
## Table of Contents
1010

@@ -125,15 +125,14 @@ Functions: 2
125125

126126
### Utility Functions
127127

128-
Functions: 19
128+
Functions: 18
129129

130130
| Function | Description | Module |
131131
|----------|-------------|--------|
132132
| `dash_spv_ffi_array_destroy` | No description | types |
133133
| `dash_spv_ffi_checkpoint_before_height` | Get the last checkpoint at or before a given height | checkpoints |
134134
| `dash_spv_ffi_checkpoint_before_timestamp` | Get the last checkpoint at or before a given UNIX timestamp (seconds) | checkpoints |
135135
| `dash_spv_ffi_checkpoint_latest` | Get the latest checkpoint for the given network | checkpoints |
136-
| `dash_spv_ffi_checkpoints_between_heights` | Get all checkpoints between two heights (inclusive) | checkpoints |
137136
| `dash_spv_ffi_client_clear_storage` | Clear all persisted SPV storage (headers, filters, metadata, sync state) | client |
138137
| `dash_spv_ffi_client_get_stats` | Get current runtime statistics for the SPV client | client |
139138
| `dash_spv_ffi_client_get_tip_hash` | Get the current chain tip hash (32 bytes) if available | client |
@@ -949,19 +948,6 @@ Get the latest checkpoint for the given network. # Safety - `out_height` must b
949948

950949
---
951950

952-
#### `dash_spv_ffi_checkpoints_between_heights`
953-
954-
```c
955-
dash_spv_ffi_checkpoints_between_heights(network: FFINetwork, start_height: u32, end_height: u32,) -> FFIArray
956-
```
957-
958-
**Description:**
959-
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.
960-
961-
**Module:** `checkpoints`
962-
963-
---
964-
965951
#### `dash_spv_ffi_client_clear_storage`
966952

967953
```c

dash-spv-ffi/include/dash_spv_ffi.h

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -42,25 +42,6 @@ typedef enum FFIMempoolStrategy {
4242

4343
typedef struct FFIDashSpvClient FFIDashSpvClient;
4444

45-
/**
46-
* FFI-safe array that transfers ownership of memory to the C caller.
47-
*
48-
* # Safety
49-
*
50-
* This struct represents memory that has been allocated by Rust but ownership
51-
* has been transferred to the C caller. The caller is responsible for:
52-
* - Not accessing the memory after it has been freed
53-
* - Calling `dash_spv_ffi_array_destroy` to properly deallocate the memory
54-
* - Ensuring the data, len, and capacity fields remain consistent
55-
*/
56-
typedef struct FFIArray {
57-
void *data;
58-
uintptr_t len;
59-
uintptr_t capacity;
60-
uintptr_t elem_size;
61-
uintptr_t elem_align;
62-
} FFIArray;
63-
6445
typedef struct FFIClientConfig {
6546
void *inner;
6647
uint32_t worker_threads;
@@ -186,6 +167,25 @@ typedef struct FFIResult {
186167
const char *error_message;
187168
} FFIResult;
188169

170+
/**
171+
* FFI-safe array that transfers ownership of memory to the C caller.
172+
*
173+
* # Safety
174+
*
175+
* This struct represents memory that has been allocated by Rust but ownership
176+
* has been transferred to the C caller. The caller is responsible for:
177+
* - Not accessing the memory after it has been freed
178+
* - Calling `dash_spv_ffi_array_destroy` to properly deallocate the memory
179+
* - Ensuring the data, len, and capacity fields remain consistent
180+
*/
181+
typedef struct FFIArray {
182+
void *data;
183+
uintptr_t len;
184+
uintptr_t capacity;
185+
uintptr_t elem_size;
186+
uintptr_t elem_align;
187+
} FFIArray;
188+
189189
/**
190190
* FFI-safe representation of an unconfirmed transaction
191191
*
@@ -264,18 +264,6 @@ int32_t dash_spv_ffi_checkpoint_before_timestamp(FFINetwork network,
264264
uint8_t *out_hash)
265265
;
266266

267-
/**
268-
* Get all checkpoints between two heights (inclusive).
269-
*
270-
* Returns an `FFIArray` of `FFICheckpoint` items. The caller owns the memory and
271-
* must free the array buffer using `dash_spv_ffi_array_destroy` when done.
272-
*/
273-
274-
struct FFIArray dash_spv_ffi_checkpoints_between_heights(FFINetwork network,
275-
uint32_t start_height,
276-
uint32_t end_height)
277-
;
278-
279267
/**
280268
* Create a new SPV client and return an opaque pointer.
281269
*

dash-spv-ffi/src/checkpoints.rs

Lines changed: 18 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
use crate::{set_last_error, FFIArray, FFIErrorCode};
2-
use dash_spv::chain::checkpoints::{mainnet_checkpoints, testnet_checkpoints, CheckpointManager};
1+
use crate::{set_last_error, FFIErrorCode};
2+
use dash_spv::chain::CheckpointManager;
33
use dashcore::hashes::Hash;
4-
use dashcore::Network;
54
use key_wallet_ffi::FFINetwork;
65

76
/// FFI representation of a checkpoint (height + block hash)
@@ -11,15 +10,6 @@ pub struct FFICheckpoint {
1110
pub block_hash: [u8; 32],
1211
}
1312

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-
2313
/// Get the latest checkpoint for the given network.
2414
///
2515
/// # Safety
@@ -31,26 +21,7 @@ pub unsafe extern "C" fn dash_spv_ffi_checkpoint_latest(
3121
out_height: *mut u32,
3222
out_hash: *mut u8, // expects at least 32 bytes
3323
) -> 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-
*out_height = cp.height;
47-
let hash = cp.block_hash.to_byte_array();
48-
std::ptr::copy_nonoverlapping(hash.as_ptr(), out_hash, 32);
49-
FFIErrorCode::Success as i32
50-
} else {
51-
set_last_error("No checkpoints available for network");
52-
FFIErrorCode::NotImplemented as i32
53-
}
24+
dash_spv_ffi_checkpoint_before_height(network, u32::MAX, out_height, out_hash)
5425
}
5526

5627
/// Get the last checkpoint at or before a given height.
@@ -69,22 +40,14 @@ pub unsafe extern "C" fn dash_spv_ffi_checkpoint_before_height(
6940
set_last_error("Null output pointer provided");
7041
return FFIErrorCode::NullPointer as i32;
7142
}
72-
let mgr = match manager_for_network(network) {
73-
Ok(m) => m,
74-
Err(e) => {
75-
set_last_error(&e);
76-
return FFIErrorCode::InvalidArgument as i32;
77-
}
78-
};
79-
if let Some(cp) = mgr.last_checkpoint_before_height(height) {
80-
*out_height = cp.height;
81-
let hash = cp.block_hash.to_byte_array();
82-
std::ptr::copy_nonoverlapping(hash.as_ptr(), out_hash, 32);
83-
FFIErrorCode::Success as i32
84-
} else {
85-
set_last_error("No checkpoint at or before given height");
86-
FFIErrorCode::ValidationError as i32
87-
}
43+
44+
let mgr = CheckpointManager::new(network.into());
45+
46+
let (height, cp) = mgr.last_checkpoint_before_height(height);
47+
*out_height = height;
48+
let hash = cp.hash().to_byte_array();
49+
std::ptr::copy_nonoverlapping(hash.as_ptr(), out_hash, 32);
50+
FFIErrorCode::Success as i32
8851
}
8952

9053
/// Get the last checkpoint at or before a given UNIX timestamp (seconds).
@@ -103,60 +66,12 @@ pub unsafe extern "C" fn dash_spv_ffi_checkpoint_before_timestamp(
10366
set_last_error("Null output pointer provided");
10467
return FFIErrorCode::NullPointer as i32;
10568
}
106-
let mgr = match manager_for_network(network) {
107-
Ok(m) => m,
108-
Err(e) => {
109-
set_last_error(&e);
110-
return FFIErrorCode::InvalidArgument as i32;
111-
}
112-
};
113-
if let Some(cp) = mgr.last_checkpoint_before_timestamp(timestamp) {
114-
*out_height = cp.height;
115-
let hash = cp.block_hash.to_byte_array();
116-
std::ptr::copy_nonoverlapping(hash.as_ptr(), out_hash, 32);
117-
FFIErrorCode::Success as i32
118-
} else {
119-
set_last_error("No checkpoint at or before given timestamp");
120-
FFIErrorCode::ValidationError as i32
121-
}
122-
}
12369

124-
/// Get all checkpoints between two heights (inclusive).
125-
///
126-
/// Returns an `FFIArray` of `FFICheckpoint` items. The caller owns the memory and
127-
/// must free the array buffer using `dash_spv_ffi_array_destroy` when done.
128-
#[no_mangle]
129-
pub extern "C" fn dash_spv_ffi_checkpoints_between_heights(
130-
network: FFINetwork,
131-
start_height: u32,
132-
end_height: u32,
133-
) -> FFIArray {
134-
match manager_for_network(network) {
135-
Ok(mgr) => {
136-
// Collect checkpoints within inclusive range
137-
let mut out: Vec<FFICheckpoint> = Vec::new();
138-
for &h in mgr.checkpoint_heights() {
139-
if h >= start_height && h <= end_height {
140-
if let Some(cp) = mgr.get_checkpoint(h) {
141-
out.push(FFICheckpoint {
142-
height: cp.height,
143-
block_hash: cp.block_hash.to_byte_array(),
144-
});
145-
}
146-
}
147-
}
148-
FFIArray::new(out)
149-
}
150-
Err(e) => {
151-
set_last_error(&e);
152-
// Return empty array on error
153-
FFIArray {
154-
data: std::ptr::null_mut(),
155-
len: 0,
156-
capacity: 0,
157-
elem_size: std::mem::size_of::<FFICheckpoint>(),
158-
elem_align: std::mem::align_of::<FFICheckpoint>(),
159-
}
160-
}
161-
}
70+
let mgr = CheckpointManager::new(network.into());
71+
72+
let (height, cp) = mgr.last_checkpoint_before_timestamp(timestamp);
73+
*out_height = height;
74+
let hash = cp.hash().to_byte_array();
75+
std::ptr::copy_nonoverlapping(hash.as_ptr(), out_hash, 32);
76+
FFIErrorCode::Success as i32
16277
}
812 Bytes
Binary file not shown.
464 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)