Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
24 changes: 24 additions & 0 deletions src/core/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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() {
Expand Down
44 changes: 43 additions & 1 deletion src/notifications/types.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -230,6 +233,15 @@ impl FromMutPtr<btck_BlockValidationState> 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 {
Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -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"));
}
}
26 changes: 25 additions & 1 deletion src/state/chainstate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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(_)));
}
}
Loading