Skip to content

Commit 8a8ebd4

Browse files
refactor(state): process_block to return ProcessBlockResult struct
Replace tuple return (bool, bool) with a ProcessBlockResult struct containing named fields (accepted, new_block) and helper methods (is_new_block, is_duplicate, is_rejected). This improves API clarity and fixes a misleading comment in the old code that labeled the second boolean as "duplicate" when it actually represented "new_block".
1 parent bf80aff commit 8a8ebd4

File tree

2 files changed

+138
-17
lines changed

2 files changed

+138
-17
lines changed

src/state/chainstate.rs

Lines changed: 119 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,32 @@ use crate::{
2222

2323
use super::{Chain, Context};
2424

25+
/// Result of processing a block with the chainstate manager
26+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27+
pub struct ProcessBlockResult {
28+
/// Whether the block was accepted
29+
pub accepted: bool,
30+
/// Whether this is a new block
31+
pub new_block: bool,
32+
}
33+
34+
impl ProcessBlockResult {
35+
/// Returns true if the block was accepted and is new
36+
pub fn is_new_block(&self) -> bool {
37+
self.accepted && self.new_block
38+
}
39+
40+
/// Returns true if the block was accepted but was already known
41+
pub fn is_duplicate(&self) -> bool {
42+
self.accepted && !self.new_block
43+
}
44+
45+
/// Returns true if the block was rejected
46+
pub fn is_rejected(&self) -> bool {
47+
!self.accepted
48+
}
49+
}
50+
2551
/// The chainstate manager is the central object for doing validation tasks as
2652
/// well as retrieving data from the chain. Internally it is a complex data
2753
/// structure with diverse functionality.
@@ -54,12 +80,16 @@ impl ChainstateManager {
5480
/// also be retrieved through a registered validation interface. If the block
5581
/// fails to validate the `block_checked` callback's ['BlockValidationState'] will
5682
/// contain details.
57-
pub fn process_block(&self, block: &Block) -> (bool /* accepted */, bool /* duplicate */) {
83+
pub fn process_block(&self, block: &Block) -> ProcessBlockResult {
5884
let mut new_block: i32 = 0;
5985
let accepted = unsafe {
6086
btck_chainstate_manager_process_block(self.inner, block.as_ptr(), &mut new_block)
6187
};
62-
(c_helpers::success(accepted), c_helpers::enabled(new_block))
88+
89+
ProcessBlockResult {
90+
accepted: c_helpers::success(accepted),
91+
new_block: c_helpers::enabled(new_block),
92+
}
6393
}
6494

6595
/// May be called after load_chainstate to initialize the
@@ -273,4 +303,91 @@ mod tests {
273303
let chainman = ChainstateManager::new(opts);
274304
assert!(chainman.is_ok());
275305
}
306+
307+
#[test]
308+
fn test_process_block_result_new_block() {
309+
let result = ProcessBlockResult {
310+
accepted: true,
311+
new_block: true,
312+
};
313+
314+
assert!(result.accepted);
315+
assert!(result.new_block);
316+
assert!(result.is_new_block());
317+
assert!(!result.is_duplicate());
318+
assert!(!result.is_rejected());
319+
}
320+
321+
#[test]
322+
fn test_process_block_result_duplicate() {
323+
let result = ProcessBlockResult {
324+
accepted: true,
325+
new_block: false,
326+
};
327+
328+
assert!(result.accepted);
329+
assert!(!result.new_block);
330+
assert!(!result.is_new_block());
331+
assert!(result.is_duplicate());
332+
assert!(!result.is_rejected());
333+
}
334+
335+
#[test]
336+
fn test_process_block_result_rejected() {
337+
let result = ProcessBlockResult {
338+
accepted: false,
339+
new_block: false,
340+
};
341+
342+
assert!(!result.accepted);
343+
assert!(!result.is_new_block());
344+
assert!(!result.is_duplicate());
345+
assert!(result.is_rejected());
346+
}
347+
348+
#[test]
349+
fn test_process_block_result_rejected_new_block_flag() {
350+
// Edge case: rejected but new_block=true (shouldn't happen in practice)
351+
let result = ProcessBlockResult {
352+
accepted: false,
353+
new_block: true,
354+
};
355+
356+
assert!(!result.accepted);
357+
assert!(result.new_block);
358+
assert!(!result.is_new_block()); // Not considered new if rejected
359+
assert!(!result.is_duplicate()); // Not considered duplicate if rejected
360+
assert!(result.is_rejected());
361+
}
362+
363+
#[test]
364+
fn test_process_block_result_equality() {
365+
let result1 = ProcessBlockResult {
366+
accepted: true,
367+
new_block: true,
368+
};
369+
let result2 = ProcessBlockResult {
370+
accepted: true,
371+
new_block: true,
372+
};
373+
let result3 = ProcessBlockResult {
374+
accepted: false,
375+
new_block: false,
376+
};
377+
378+
assert_eq!(result1, result2);
379+
assert_ne!(result1, result3);
380+
}
381+
382+
#[test]
383+
fn test_process_block_result_debug() {
384+
let result = ProcessBlockResult {
385+
accepted: true,
386+
new_block: true,
387+
};
388+
389+
let debug_str = format!("{:?}", result);
390+
assert!(debug_str.contains("accepted"));
391+
assert!(debug_str.contains("new_block"));
392+
}
276393
}

tests/test.rs

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,10 @@ mod tests {
117117

118118
for raw_block in block_data.iter() {
119119
let block = Block::new(raw_block.as_slice()).unwrap();
120-
let (accepted, new_block) = chainman.process_block(&block);
121-
assert!(accepted);
122-
assert!(new_block);
120+
let result = chainman.process_block(&block);
121+
assert!(result.is_new_block());
122+
assert!(!result.is_duplicate());
123+
assert!(!result.is_rejected());
123124
}
124125

125126
chainman
@@ -138,9 +139,10 @@ mod tests {
138139
.unwrap();
139140
for raw_block in block_data.iter() {
140141
let block = Block::try_from(raw_block.as_slice()).unwrap();
141-
let (accepted, new_block) = chainman.process_block(&block);
142-
assert!(accepted);
143-
assert!(new_block);
142+
let result = chainman.process_block(&block);
143+
assert!(result.is_new_block());
144+
assert!(!result.is_duplicate());
145+
assert!(!result.is_rejected());
144146
}
145147
}
146148

@@ -178,9 +180,10 @@ mod tests {
178180
1e73a82cbf2342c858eeac00000000").unwrap().as_slice()
179181
)
180182
.unwrap();
181-
let (accepted, new_block) = chainman.process_block(&block_1);
182-
assert!(!accepted);
183-
assert!(!new_block);
183+
let result = chainman.process_block(&block_1);
184+
assert!(result.is_rejected());
185+
assert!(!result.is_new_block());
186+
assert!(!result.is_duplicate())
184187
}
185188
}
186189

@@ -275,9 +278,10 @@ mod tests {
275278

276279
for raw_block in block_data.iter() {
277280
let block = Block::try_from(raw_block.as_slice()).unwrap();
278-
let (accepted, new_block) = chainman.process_block(&block);
279-
assert!(accepted);
280-
assert!(new_block);
281+
let result = chainman.process_block(&block);
282+
assert!(result.is_new_block());
283+
assert!(!result.is_rejected());
284+
assert!(!result.is_duplicate());
281285
}
282286
}
283287

@@ -293,9 +297,9 @@ mod tests {
293297

294298
chainman.import_blocks().unwrap();
295299
let block_2 = Block::try_from(block_data[1].clone().as_slice()).unwrap();
296-
let (accepted, new_block) = chainman.process_block(&block_2);
297-
assert!(!accepted);
298-
assert!(!new_block);
300+
let result = chainman.process_block(&block_2);
301+
assert!(result.is_rejected());
302+
assert!(!result.is_new_block());
299303
}
300304

301305
#[test]

0 commit comments

Comments
 (0)