Skip to content

Commit a293d1f

Browse files
committed
Add BlockIndex and ChainManager
1 parent b634adf commit a293d1f

File tree

7 files changed

+864
-9
lines changed

7 files changed

+864
-9
lines changed

data/regtest/blocks.txt

Lines changed: 206 additions & 0 deletions
Large diffs are not rendered by default.

kernel/block_index.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package kernel
2+
3+
/*
4+
#include "kernel/bitcoinkernel.h"
5+
*/
6+
import "C"
7+
import (
8+
"runtime"
9+
)
10+
11+
// BlockIndex wraps the C kernel_BlockIndex
12+
type BlockIndex struct {
13+
ptr *C.kernel_BlockIndex
14+
}
15+
16+
func (bi *BlockIndex) Height() int32 {
17+
if bi.ptr == nil {
18+
return -1
19+
}
20+
return int32(C.kernel_block_index_get_height(bi.ptr))
21+
}
22+
23+
func (bi *BlockIndex) Hash() (*BlockHash, error) {
24+
if bi.ptr == nil {
25+
return nil, ErrInvalidBlockIndex
26+
}
27+
28+
ptr := C.kernel_block_index_get_block_hash(bi.ptr)
29+
if ptr == nil {
30+
return nil, ErrHashCalculation
31+
}
32+
33+
hash := &BlockHash{ptr: ptr}
34+
runtime.SetFinalizer(hash, (*BlockHash).destroy)
35+
return hash, nil
36+
}
37+
38+
func (bi *BlockIndex) Previous() *BlockIndex {
39+
if bi.ptr == nil {
40+
return nil
41+
}
42+
43+
ptr := C.kernel_get_previous_block_index(bi.ptr)
44+
if ptr == nil {
45+
return nil
46+
}
47+
48+
prevIndex := &BlockIndex{ptr: ptr}
49+
runtime.SetFinalizer(prevIndex, (*BlockIndex).destroy)
50+
return prevIndex
51+
}
52+
53+
func (bi *BlockIndex) destroy() {
54+
if bi.ptr != nil {
55+
C.kernel_block_index_destroy(bi.ptr)
56+
bi.ptr = nil
57+
}
58+
}
59+
60+
func (bi *BlockIndex) Destroy() {
61+
runtime.SetFinalizer(bi, nil)
62+
bi.destroy()
63+
}

kernel/block_validation_state.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package kernel
2+
3+
/*
4+
#include "kernel/bitcoinkernel.h"
5+
*/
6+
import "C"
7+
8+
// ValidationMode represents the validation state mode
9+
type ValidationMode int
10+
11+
const (
12+
ValidationStateValid ValidationMode = iota
13+
ValidationStateInvalid
14+
ValidationStateError
15+
)
16+
17+
// BlockValidationResult represents the validation result for a block
18+
type BlockValidationResult int
19+
20+
const (
21+
BlockResultUnset BlockValidationResult = iota
22+
BlockConsensus
23+
BlockCachedInvalid
24+
BlockInvalidHeader
25+
BlockMutated
26+
BlockMissingPrev
27+
BlockInvalidPrev
28+
BlockTimeFuture
29+
BlockHeaderLowWork
30+
)
31+
32+
// BlockValidationState wraps the C kernel_BlockValidationState
33+
type BlockValidationState struct {
34+
ptr *C.kernel_BlockValidationState
35+
}
36+
37+
func (bvs *BlockValidationState) ValidationMode() ValidationMode {
38+
if bvs.ptr == nil {
39+
return ValidationStateError
40+
}
41+
mode := C.kernel_get_validation_mode_from_block_validation_state(bvs.ptr)
42+
return ValidationMode(mode)
43+
}
44+
45+
func (bvs *BlockValidationState) ValidationResult() BlockValidationResult {
46+
if bvs.ptr == nil {
47+
return BlockResultUnset
48+
}
49+
result := C.kernel_get_block_validation_result_from_block_validation_state(bvs.ptr)
50+
return BlockValidationResult(result)
51+
}

kernel/chainstate_manager.go

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
package kernel
2+
3+
/*
4+
#include "kernel/bitcoinkernel.h"
5+
#include <stdlib.h>
6+
*/
7+
import "C"
8+
import (
9+
"runtime"
10+
"unsafe"
11+
)
12+
13+
// ChainstateManager wraps the C kernel_ChainstateManager
14+
type ChainstateManager struct {
15+
ptr *C.kernel_ChainstateManager
16+
context *Context
17+
}
18+
19+
// NewChainstateManager creates a new chainstate manager.
20+
// Kernel copies all necessary data from the options during construction,
21+
// so the caller can safely free the options object after this call returns successfully.
22+
// However, the context must remain valid for the entire lifetime of the returned ChainstateManager.
23+
func NewChainstateManager(context *Context, options *ChainstateManagerOptions) (*ChainstateManager, error) {
24+
if context == nil || context.ptr == nil {
25+
return nil, ErrContextCreation
26+
}
27+
if options == nil || options.ptr == nil {
28+
return nil, ErrChainstateManagerOptionsCreation
29+
}
30+
31+
ptr := C.kernel_chainstate_manager_create(context.ptr, options.ptr)
32+
if ptr == nil {
33+
return nil, ErrChainstateManagerCreation
34+
}
35+
36+
manager := &ChainstateManager{
37+
ptr: ptr,
38+
context: context,
39+
}
40+
runtime.SetFinalizer(manager, (*ChainstateManager).destroy)
41+
return manager, nil
42+
}
43+
44+
// ReadBlockFromDisk reads a block from disk using the provided block index
45+
func (cm *ChainstateManager) ReadBlockFromDisk(blockIndex *BlockIndex) (*Block, error) {
46+
if cm.ptr == nil || cm.context == nil || cm.context.ptr == nil {
47+
return nil, ErrChainstateManagerCreation
48+
}
49+
if blockIndex == nil || blockIndex.ptr == nil {
50+
return nil, ErrInvalidBlockIndex
51+
}
52+
53+
ptr := C.kernel_read_block_from_disk(cm.context.ptr, cm.ptr, blockIndex.ptr)
54+
if ptr == nil {
55+
return nil, ErrBlockRead
56+
}
57+
58+
block := &Block{ptr: ptr}
59+
runtime.SetFinalizer(block, (*Block).destroy)
60+
return block, nil
61+
}
62+
63+
// ProcessBlock processes and validates a block
64+
func (cm *ChainstateManager) ProcessBlock(block *Block) (bool, bool, error) {
65+
if cm.ptr == nil || cm.context == nil || cm.context.ptr == nil {
66+
return false, false, ErrChainstateManagerCreation
67+
}
68+
if block == nil || block.ptr == nil {
69+
return false, false, ErrInvalidBlock
70+
}
71+
72+
var newBlock C.bool
73+
success := C.kernel_chainstate_manager_process_block(
74+
cm.context.ptr,
75+
cm.ptr,
76+
block.ptr,
77+
&newBlock,
78+
)
79+
80+
return bool(success), bool(newBlock), nil
81+
}
82+
83+
// GetBlockIndexFromTip returns the block index of the current chain tip
84+
func (cm *ChainstateManager) GetBlockIndexFromTip() (*BlockIndex, error) {
85+
if cm.ptr == nil || cm.context == nil || cm.context.ptr == nil {
86+
return nil, ErrChainstateManagerCreation
87+
}
88+
89+
ptr := C.kernel_get_block_index_from_tip(cm.context.ptr, cm.ptr)
90+
if ptr == nil {
91+
return nil, ErrInvalidBlockIndex
92+
}
93+
94+
blockIndex := &BlockIndex{ptr: ptr}
95+
runtime.SetFinalizer(blockIndex, (*BlockIndex).destroy)
96+
return blockIndex, nil
97+
}
98+
99+
// GetBlockIndexFromGenesis returns the block index of the genesis block
100+
func (cm *ChainstateManager) GetBlockIndexFromGenesis() (*BlockIndex, error) {
101+
if cm.ptr == nil || cm.context == nil || cm.context.ptr == nil {
102+
return nil, ErrChainstateManagerCreation
103+
}
104+
105+
ptr := C.kernel_get_block_index_from_genesis(cm.context.ptr, cm.ptr)
106+
if ptr == nil {
107+
return nil, ErrInvalidBlockIndex
108+
}
109+
110+
blockIndex := &BlockIndex{ptr: ptr}
111+
runtime.SetFinalizer(blockIndex, (*BlockIndex).destroy)
112+
return blockIndex, nil
113+
}
114+
115+
// GetBlockIndexFromHash returns the block index for a given block hash
116+
func (cm *ChainstateManager) GetBlockIndexFromHash(blockHash *BlockHash) (*BlockIndex, error) {
117+
if cm.ptr == nil || cm.context == nil || cm.context.ptr == nil {
118+
return nil, ErrChainstateManagerCreation
119+
}
120+
if blockHash == nil || blockHash.ptr == nil {
121+
return nil, ErrHashCalculation
122+
}
123+
124+
ptr := C.kernel_get_block_index_from_hash(cm.context.ptr, cm.ptr, blockHash.ptr)
125+
if ptr == nil {
126+
return nil, ErrInvalidBlockIndex
127+
}
128+
129+
blockIndex := &BlockIndex{ptr: ptr}
130+
runtime.SetFinalizer(blockIndex, (*BlockIndex).destroy)
131+
return blockIndex, nil
132+
}
133+
134+
// GetBlockIndexFromHeight returns the block index for a given height in the currently active chain
135+
func (cm *ChainstateManager) GetBlockIndexFromHeight(height int) (*BlockIndex, error) {
136+
if cm.ptr == nil || cm.context == nil || cm.context.ptr == nil {
137+
return nil, ErrChainstateManagerCreation
138+
}
139+
140+
ptr := C.kernel_get_block_index_from_height(cm.context.ptr, cm.ptr, C.int(height))
141+
if ptr == nil {
142+
return nil, ErrInvalidBlockIndex
143+
}
144+
145+
blockIndex := &BlockIndex{ptr: ptr}
146+
runtime.SetFinalizer(blockIndex, (*BlockIndex).destroy)
147+
return blockIndex, nil
148+
}
149+
150+
// GetNextBlockIndex returns the next block index in the active chain
151+
func (cm *ChainstateManager) GetNextBlockIndex(blockIndex *BlockIndex) (*BlockIndex, error) {
152+
if cm.ptr == nil || cm.context == nil || cm.context.ptr == nil {
153+
return nil, ErrChainstateManagerCreation
154+
}
155+
if blockIndex == nil || blockIndex.ptr == nil {
156+
return nil, ErrInvalidBlockIndex
157+
}
158+
159+
ptr := C.kernel_get_next_block_index(cm.context.ptr, cm.ptr, blockIndex.ptr)
160+
if ptr == nil {
161+
return nil, nil // No next block (tip or invalid)
162+
}
163+
164+
nextIndex := &BlockIndex{ptr: ptr}
165+
runtime.SetFinalizer(nextIndex, (*BlockIndex).destroy)
166+
return nextIndex, nil
167+
}
168+
169+
// ImportBlocks imports blocks from the specified file paths
170+
func (cm *ChainstateManager) ImportBlocks(blockFilePaths []string) error {
171+
if cm.ptr == nil || cm.context == nil || cm.context.ptr == nil {
172+
return ErrChainstateManagerCreation
173+
}
174+
175+
if len(blockFilePaths) == 0 {
176+
// Import with no files triggers reindex if wipe options were set
177+
success := C.kernel_import_blocks(cm.context.ptr, cm.ptr, nil, nil, 0)
178+
if !success {
179+
return ErrBlockProcessing
180+
}
181+
return nil
182+
}
183+
184+
// Convert Go strings to C strings
185+
cPaths := make([]*C.char, len(blockFilePaths))
186+
cLens := make([]C.size_t, len(blockFilePaths))
187+
188+
for i, path := range blockFilePaths {
189+
cPaths[i] = C.CString(path)
190+
cLens[i] = C.size_t(len(path))
191+
}
192+
193+
// Clean up C strings
194+
defer func() {
195+
for i := range cPaths {
196+
C.free(unsafe.Pointer(cPaths[i]))
197+
}
198+
}()
199+
200+
success := C.kernel_import_blocks(
201+
cm.context.ptr,
202+
cm.ptr,
203+
(**C.char)(unsafe.Pointer(&cPaths[0])),
204+
(*C.size_t)(unsafe.Pointer(&cLens[0])),
205+
C.size_t(len(blockFilePaths)),
206+
)
207+
208+
if !success {
209+
return ErrBlockProcessing
210+
}
211+
return nil
212+
}
213+
214+
func (cm *ChainstateManager) destroy() {
215+
if cm.ptr != nil && cm.context != nil && cm.context.ptr != nil {
216+
C.kernel_chainstate_manager_destroy(cm.ptr, cm.context.ptr)
217+
cm.ptr = nil
218+
cm.context = nil
219+
}
220+
}
221+
222+
func (cm *ChainstateManager) Destroy() {
223+
runtime.SetFinalizer(cm, nil)
224+
cm.destroy()
225+
}

0 commit comments

Comments
 (0)