From 9f89611a1506785c4fac36f26aca2d3e43236520 Mon Sep 17 00:00:00 2001 From: Alexander Wiederin Date: Tue, 26 May 2026 18:05:51 +0200 Subject: [PATCH] feat(core): implement Debug for BlockValidationState and related types Implements Debug for BlockValidationState, BlockValidationStateRef, ProcessBlockHeaderResult and BlockCheckResult. Also derives Clone for BlockCheckResult for consistency with ProcessBlockHeaderResult. --- CHANGELOG.md | 1 + src/core/block.rs | 24 +++++++++++++++++++++ src/notifications/types.rs | 44 +++++++++++++++++++++++++++++++++++++- src/state/chainstate.rs | 26 +++++++++++++++++++++- 4 files changed, 93 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a7e11228..a679f763 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added `Block::check` to perform context-free validation of a block (size, weight, coinbase, transactions, sigops), with optional proof-of-work and merkle-root checks toggled via the `BLOCK_CHECK_BASE` / `_POW` / `_MERKLE` / `_ALL` flags. Returns a `BlockCheckResult` enum carrying the validation state on failure. +- Implemented `Debug` for `BlockValidationResult`, `BlockValidationStateRef`, `ProcessBlockHeaderresult` and `BlockCheckResult`, enabling inspection via `{:?}` in logs and test output. ### Changed - The `verify` function's `flags` parameter now uses `ScriptVerificationFlags` instead of `u32`, making the type explicit in the public API. diff --git a/src/core/block.rs b/src/core/block.rs index 5b2de2e0..2f583499 100644 --- a/src/core/block.rs +++ b/src/core/block.rs @@ -176,6 +176,7 @@ pub const BLOCK_CHECK_ALL: BlockCheckFlags = btck_BlockCheckFlags_ALL; /// /// On failure, the [`BlockValidationState`] carries details that can be /// inspected via [`BlockValidationStateExt`](crate::notifications::BlockValidationStateExt). +#[derive(Clone, Debug)] pub enum BlockCheckResult { /// The block passed the requested context-free checks. Valid, @@ -2347,6 +2348,29 @@ mod tests { "00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048" ); } + #[test] + fn test_block_check_result_debug() { + let valid = BlockCheckResult::Valid; + let debug_str = format!("{:?}", valid); + assert_eq!(debug_str, "Valid"); + + let state = BlockValidationState::new(); + let invalid = BlockCheckResult::Invalid(state); + let debug_str = format!("{:?}", invalid); + assert!(debug_str.contains("Invalid")); + } + + #[test] + fn test_block_check_result_clone() { + let valid = BlockCheckResult::Valid; + let cloned = valid.clone(); + assert!(matches!(cloned, BlockCheckResult::Valid)); + + let state = BlockValidationState::new(); + let invalid = BlockCheckResult::Invalid(state); + let cloned = invalid.clone(); + assert!(matches!(cloned, BlockCheckResult::Invalid(_))); + } #[test] fn check_valid_block_passes_base_and_all() { diff --git a/src/notifications/types.rs b/src/notifications/types.rs index a33694eb..39eb8a18 100644 --- a/src/notifications/types.rs +++ b/src/notifications/types.rs @@ -1,4 +1,7 @@ -use std::marker::PhantomData; +use std::{ + fmt::{Debug, Formatter, Result}, + marker::PhantomData, +}; use libbitcoinkernel_sys::{ btck_BlockValidationResult, btck_BlockValidationResult_CACHED_INVALID, @@ -230,6 +233,15 @@ impl FromMutPtr for BlockValidationState { impl BlockValidationStateExt for BlockValidationState {} +impl Debug for BlockValidationState { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + f.debug_struct("BlockValidationState") + .field("mode", &self.mode()) + .field("result", &self.result()) + .finish() + } +} + impl Clone for BlockValidationState { fn clone(&self) -> Self { BlockValidationState { @@ -275,6 +287,15 @@ impl<'a> Clone for BlockValidationStateRef<'a> { } } +impl<'a> Debug for BlockValidationStateRef<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + f.debug_struct("BlockValidationStateRef") + .field("mode", &self.mode()) + .field("result", &self.result()) + .finish() + } +} + impl<'a> BlockValidationStateExt for BlockValidationStateRef<'a> {} #[cfg(test)] @@ -621,4 +642,25 @@ mod tests { assert_eq!(result, back); } } + + #[test] + fn test_block_validation_state_debug() { + let state = BlockValidationState::new(); + let s = format!("{:?}", state); + assert!(s.contains("BlockValidationState")); + assert!(s.contains("mode")); + assert!(s.contains("result")); + } + + #[test] + fn test_block_validation_state_ref_debug() { + use crate::ffi::sealed::FromPtr; + let state = BlockValidationState::new(); + let state_ref: BlockValidationStateRef<'_> = + unsafe { BlockValidationStateRef::from_ptr(state.as_ptr()) }; + let s = format!("{:?}", state_ref); + assert!(s.contains("BlockValidationStateRef")); + assert!(s.contains("mode")); + assert!(s.contains("result")); + } } diff --git a/src/state/chainstate.rs b/src/state/chainstate.rs index afaf2dca..33fa00e4 100644 --- a/src/state/chainstate.rs +++ b/src/state/chainstate.rs @@ -73,7 +73,7 @@ pub enum ProcessBlockResult { /// Result of proceesing a header with the [`ChainstateManager`] /// /// Indicates whether a block header was processed, or rejected, and whether it is valid. -#[derive(Clone)] +#[derive(Clone, Debug)] pub enum ProcessBlockHeaderResult { /// Header was succssfully processed and added to the block tree Success(BlockValidationState), @@ -817,4 +817,28 @@ mod tests { let debug_str = format!("{:?}", result); assert_eq!(debug_str, "NewBlock"); } + + #[test] + fn test_process_block_header_result_debug() { + let state = BlockValidationState::new(); + let success = ProcessBlockHeaderResult::Success(state.clone()); + let debug_str = format!("{:?}", success); + assert!(debug_str.contains("Success")); + + let failed = ProcessBlockHeaderResult::Failed(state); + let debug_str = format!("{:?}", failed); + assert!(debug_str.contains("Failed")); + } + + #[test] + fn test_process_block_header_result_clone() { + let state = BlockValidationState::new(); + let success = ProcessBlockHeaderResult::Success(state.clone()); + let cloned = success.clone(); + assert!(matches!(cloned, ProcessBlockHeaderResult::Success(_))); + + let failed = ProcessBlockHeaderResult::Failed(state); + let cloned = failed.clone(); + assert!(matches!(cloned, ProcessBlockHeaderResult::Failed(_))); + } }