Skip to content

Commit b30e15f

Browse files
committed
kernel: Add functions for the block validation state to C header
These allow for the interpretation of the data in a `BlockChecked` validation interface callback. The validation state passed through `BlockChecked` is the source of truth for the validity of a block (the mode). It is also useful to get richer information in case a block failed to validate (the result).
1 parent aa262da commit b30e15f

File tree

4 files changed

+151
-1
lines changed

4 files changed

+151
-1
lines changed

src/kernel/bitcoinkernel.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,40 @@ void btck_context_destroy(btck_Context* context)
769769
delete context;
770770
}
771771

772+
btck_ValidationMode btck_block_validation_state_get_validation_mode(const btck_BlockValidationState* block_validation_state_)
773+
{
774+
auto& block_validation_state = btck_BlockValidationState::get(block_validation_state_);
775+
if (block_validation_state.IsValid()) return btck_ValidationMode_VALID;
776+
if (block_validation_state.IsInvalid()) return btck_ValidationMode_INVALID;
777+
return btck_ValidationMode_INTERNAL_ERROR;
778+
}
779+
780+
btck_BlockValidationResult btck_block_validation_state_get_block_validation_result(const btck_BlockValidationState* block_validation_state_)
781+
{
782+
auto& block_validation_state = btck_BlockValidationState::get(block_validation_state_);
783+
switch (block_validation_state.GetResult()) {
784+
case BlockValidationResult::BLOCK_RESULT_UNSET:
785+
return btck_BlockValidationResult_UNSET;
786+
case BlockValidationResult::BLOCK_CONSENSUS:
787+
return btck_BlockValidationResult_CONSENSUS;
788+
case BlockValidationResult::BLOCK_CACHED_INVALID:
789+
return btck_BlockValidationResult_CACHED_INVALID;
790+
case BlockValidationResult::BLOCK_INVALID_HEADER:
791+
return btck_BlockValidationResult_INVALID_HEADER;
792+
case BlockValidationResult::BLOCK_MUTATED:
793+
return btck_BlockValidationResult_MUTATED;
794+
case BlockValidationResult::BLOCK_MISSING_PREV:
795+
return btck_BlockValidationResult_MISSING_PREV;
796+
case BlockValidationResult::BLOCK_INVALID_PREV:
797+
return btck_BlockValidationResult_INVALID_PREV;
798+
case BlockValidationResult::BLOCK_TIME_FUTURE:
799+
return btck_BlockValidationResult_TIME_FUTURE;
800+
case BlockValidationResult::BLOCK_HEADER_LOW_WORK:
801+
return btck_BlockValidationResult_HEADER_LOW_WORK;
802+
} // no default case, so the compiler can warn about missing cases
803+
assert(false);
804+
}
805+
772806
btck_ChainstateManagerOptions* btck_chainstate_manager_options_create(const btck_Context* context, const char* data_dir, size_t data_dir_len, const char* blocks_dir, size_t blocks_dir_len)
773807
{
774808
try {

src/kernel/bitcoinkernel.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,29 @@ typedef void (*btck_ValidationInterfacePoWValidBlock)(void* user_data, btck_Bloc
249249
typedef void (*btck_ValidationInterfaceBlockConnected)(void* user_data, btck_Block* block, const btck_BlockTreeEntry* entry);
250250
typedef void (*btck_ValidationInterfaceBlockDisconnected)(void* user_data, btck_Block* block, const btck_BlockTreeEntry* entry);
251251

252+
/**
253+
* Whether a validated data structure is valid, invalid, or an error was
254+
* encountered during processing.
255+
*/
256+
typedef uint8_t btck_ValidationMode;
257+
#define btck_ValidationMode_VALID ((btck_ValidationMode)(0))
258+
#define btck_ValidationMode_INVALID ((btck_ValidationMode)(1))
259+
#define btck_ValidationMode_INTERNAL_ERROR ((btck_ValidationMode)(2))
260+
261+
/**
262+
* A granular "reason" why a block was invalid.
263+
*/
264+
typedef uint32_t btck_BlockValidationResult;
265+
#define btck_BlockValidationResult_UNSET ((btck_BlockValidationResult)(0)) //!< initial value. Block has not yet been rejected
266+
#define btck_BlockValidationResult_CONSENSUS ((btck_BlockValidationResult)(1)) //!< invalid by consensus rules (excluding any below reasons)
267+
#define btck_BlockValidationResult_CACHED_INVALID ((btck_BlockValidationResult)(2)) //!< this block was cached as being invalid and we didn't store the reason why
268+
#define btck_BlockValidationResult_INVALID_HEADER ((btck_BlockValidationResult)(3)) //!< invalid proof of work or time too old
269+
#define btck_BlockValidationResult_MUTATED ((btck_BlockValidationResult)(4)) //!< the block's data didn't match the data committed to by the PoW
270+
#define btck_BlockValidationResult_MISSING_PREV ((btck_BlockValidationResult)(5)) //!< We don't have the previous block the checked one is built on
271+
#define btck_BlockValidationResult_INVALID_PREV ((btck_BlockValidationResult)(6)) //!< A block this one builds on is invalid
272+
#define btck_BlockValidationResult_TIME_FUTURE ((btck_BlockValidationResult)(7)) //!< block timestamp was > 2 hours in the future (or our clock is bad)
273+
#define btck_BlockValidationResult_HEADER_LOW_WORK ((btck_BlockValidationResult)(8)) //!< the block header may be on a too-little-work chain
274+
252275
/**
253276
* Holds the validation interface callbacks. The user data pointer may be used
254277
* to point to user-defined structures to make processing the validation
@@ -967,6 +990,25 @@ BITCOINKERNEL_API void btck_block_destroy(btck_Block* block);
967990

968991
///@}
969992

993+
/** @name BlockValidationState
994+
* Functions for working with block validation states.
995+
*/
996+
///@{
997+
998+
/**
999+
* Returns the validation mode from an opaque block validation state pointer.
1000+
*/
1001+
BITCOINKERNEL_API btck_ValidationMode btck_block_validation_state_get_validation_mode(
1002+
const btck_BlockValidationState* block_validation_state) BITCOINKERNEL_ARG_NONNULL(1);
1003+
1004+
/**
1005+
* Returns the validation result from an opaque block validation state pointer.
1006+
*/
1007+
BITCOINKERNEL_API btck_BlockValidationResult btck_block_validation_state_get_block_validation_result(
1008+
const btck_BlockValidationState* block_validation_state) BITCOINKERNEL_ARG_NONNULL(1);
1009+
1010+
///@}
1011+
9701012
#ifdef __cplusplus
9711013
} // extern "C"
9721014
#endif // __cplusplus

src/kernel/bitcoinkernel_wrapper.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,24 @@ enum class Warning : btck_Warning {
5858
LARGE_WORK_INVALID_CHAIN = btck_Warning_LARGE_WORK_INVALID_CHAIN
5959
};
6060

61+
enum class ValidationMode : btck_ValidationMode {
62+
VALID = btck_ValidationMode_VALID,
63+
INVALID = btck_ValidationMode_INVALID,
64+
INTERNAL_ERROR = btck_ValidationMode_INTERNAL_ERROR
65+
};
66+
67+
enum class BlockValidationResult : btck_BlockValidationResult {
68+
UNSET = btck_BlockValidationResult_UNSET,
69+
CONSENSUS = btck_BlockValidationResult_CONSENSUS,
70+
CACHED_INVALID = btck_BlockValidationResult_CACHED_INVALID,
71+
INVALID_HEADER = btck_BlockValidationResult_INVALID_HEADER,
72+
MUTATED = btck_BlockValidationResult_MUTATED,
73+
MISSING_PREV = btck_BlockValidationResult_MISSING_PREV,
74+
INVALID_PREV = btck_BlockValidationResult_INVALID_PREV,
75+
TIME_FUTURE = btck_BlockValidationResult_TIME_FUTURE,
76+
HEADER_LOW_WORK = btck_BlockValidationResult_HEADER_LOW_WORK
77+
};
78+
6179
enum class ScriptVerifyStatus : btck_ScriptVerifyStatus {
6280
OK = btck_ScriptVerifyStatus_OK,
6381
ERROR_INVALID_FLAGS_COMBINATION = btck_ScriptVerifyStatus_ERROR_INVALID_FLAGS_COMBINATION,
@@ -616,6 +634,16 @@ class BlockValidationState
616634
BlockValidationState& operator=(const BlockValidationState&) = delete;
617635
BlockValidationState(BlockValidationState&&) = delete;
618636
BlockValidationState& operator=(BlockValidationState&&) = delete;
637+
638+
ValidationMode GetValidationMode() const
639+
{
640+
return static_cast<ValidationMode>(btck_block_validation_state_get_validation_mode(m_state));
641+
}
642+
643+
BlockValidationResult GetBlockValidationResult() const
644+
{
645+
return static_cast<BlockValidationResult>(btck_block_validation_state_get_block_validation_result(m_state));
646+
}
619647
};
620648

621649
class ValidationInterface

src/test/kernel/test_kernel.cpp

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,53 @@ class TestValidationInterface : public ValidationInterface
131131
public:
132132
void BlockChecked(Block block, const BlockValidationState state) override
133133
{
134-
std::cout << "Block checked." << std::endl;
134+
std::cout << "Block checked: ";
135+
136+
auto mode{state.GetValidationMode()};
137+
switch (mode) {
138+
case ValidationMode::VALID: {
139+
std::cout << "Valid block" << std::endl;
140+
return;
141+
}
142+
case ValidationMode::INVALID: {
143+
std::cout << "Invalid block: ";
144+
auto result{state.GetBlockValidationResult()};
145+
switch (result) {
146+
case BlockValidationResult::UNSET:
147+
std::cout << "initial value. Block has not yet been rejected" << std::endl;
148+
break;
149+
case BlockValidationResult::HEADER_LOW_WORK:
150+
std::cout << "the block header may be on a too-little-work chain" << std::endl;
151+
break;
152+
case BlockValidationResult::CONSENSUS:
153+
std::cout << "invalid by consensus rules (excluding any below reasons)" << std::endl;
154+
break;
155+
case BlockValidationResult::CACHED_INVALID:
156+
std::cout << "this block was cached as being invalid and we didn't store the reason why" << std::endl;
157+
break;
158+
case BlockValidationResult::INVALID_HEADER:
159+
std::cout << "invalid proof of work or time too old" << std::endl;
160+
break;
161+
case BlockValidationResult::MUTATED:
162+
std::cout << "the block's data didn't match the data committed to by the PoW" << std::endl;
163+
break;
164+
case BlockValidationResult::MISSING_PREV:
165+
std::cout << "We don't have the previous block the checked one is built on" << std::endl;
166+
break;
167+
case BlockValidationResult::INVALID_PREV:
168+
std::cout << "A block this one builds on is invalid" << std::endl;
169+
break;
170+
case BlockValidationResult::TIME_FUTURE:
171+
std::cout << "block timestamp was > 2 hours in the future (or our clock is bad)" << std::endl;
172+
break;
173+
}
174+
return;
175+
}
176+
case ValidationMode::INTERNAL_ERROR: {
177+
std::cout << "Internal error" << std::endl;
178+
return;
179+
}
180+
}
135181
}
136182

137183
void BlockConnected(Block block, BlockTreeEntry entry) override

0 commit comments

Comments
 (0)