Skip to content

Commit 2aa14d7

Browse files
committed
Adapt to kernelApi_65 and refactor resource management and error handling
1 parent 29e7ee7 commit 2aa14d7

37 files changed

+866
-1616
lines changed

.gitignore

Lines changed: 0 additions & 2 deletions
This file was deleted.

README.md

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -87,24 +87,12 @@ replace github.com/stringintech/go-bitcoinkernel => /path/to/go-bitcoinkernel
8787

8888
### Memory Management
8989

90-
The library handles memory management automatically through Go's finalizers, but it's highly recommended to explicitly
91-
call `Destroy()` methods when you're done with objects to free resources immediately.
90+
The library handles memory management automatically through Go's finalizers (see [common.go](./kernel/common.go)), but it's highly recommended to explicitly
91+
call `Destroy()` methods when you're done with owned objects to free resources immediately.
9292

93-
### Error Handling and Resource Initialization
93+
### Error Handling
9494

95-
The library uses structured error types for better error handling (see [errors.go](./kernel/errors.go)):
96-
97-
- **`UninitializedError`**: Returned when attempting operations on uninitialized resources
98-
- **`KernelError`**: Returned when underlying C library operations fail
99-
100-
**Important**: Method calls on uninitialized objects (where the internal C pointer is nil) will **panic** rather than return errors. This is by design to catch programming bugs early:
101-
102-
```go
103-
m := kernel.ChainstateManager{}
104-
chain, _ := m.GetActiveChain() // panic: chainstateManager is not initialized
105-
```
106-
107-
Always ensure objects are properly initialized (and not destroyed) before calling methods on them. Constructor functions like `NewChainstateManager()` return errors for validation, but method calls on receivers expect valid objects.
95+
The library uses structured error types for better error handling (see [errors.go](./kernel/errors.go)).
10896

10997
### Runtime Dependencies
11098

kernel/block.go

Lines changed: 34 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -5,108 +5,64 @@ package kernel
55
*/
66
import "C"
77
import (
8-
"runtime"
98
"unsafe"
109
)
1110

12-
var _ cManagedResource = &Block{}
11+
type blockCFuncs struct{}
1312

14-
// Block wraps the C btck_Block
15-
type Block struct {
16-
ptr *C.btck_Block
13+
func (blockCFuncs) destroy(ptr unsafe.Pointer) {
14+
C.btck_block_destroy((*C.btck_Block)(ptr))
1715
}
1816

19-
// NewBlockFromRaw creates a new block from raw serialized data
20-
func NewBlockFromRaw(rawBlock []byte) (*Block, error) {
21-
if len(rawBlock) == 0 {
22-
return nil, ErrEmptyBlockData
23-
}
24-
ptr := C.btck_block_create(unsafe.Pointer(&rawBlock[0]), C.size_t(len(rawBlock)))
25-
if ptr == nil {
26-
return nil, ErrKernelBlockCreate
27-
}
28-
return newBlockFromPtr(ptr), nil
17+
func (blockCFuncs) copy(ptr unsafe.Pointer) unsafe.Pointer {
18+
return unsafe.Pointer(C.btck_block_copy((*C.btck_Block)(ptr)))
2919
}
3020

31-
func newBlockFromPtr(ptr *C.btck_Block) *Block {
32-
block := &Block{ptr: ptr}
33-
runtime.SetFinalizer(block, (*Block).destroy)
34-
return block
21+
type Block struct {
22+
*handle
3523
}
3624

37-
func (b *Block) Hash() (*BlockHash, error) {
38-
checkReady(b)
25+
func newBlock(ptr *C.btck_Block, fromOwned bool) *Block {
26+
h := newHandle(unsafe.Pointer(ptr), blockCFuncs{}, fromOwned)
27+
return &Block{handle: h}
28+
}
3929

40-
ptr := C.btck_block_get_hash(b.ptr)
30+
// NewBlock creates a new block from raw serialized data
31+
func NewBlock(rawBlock []byte) (*Block, error) {
32+
ptr := C.btck_block_create(unsafe.Pointer(&rawBlock[0]), C.size_t(len(rawBlock)))
4133
if ptr == nil {
42-
return nil, ErrKernelBlockGetHash
34+
return nil, &InternalError{"Failed to create block from bytes"}
4335
}
36+
return newBlock(ptr, true), nil
37+
}
4438

45-
hash := &BlockHash{ptr: ptr}
46-
runtime.SetFinalizer(hash, (*BlockHash).destroy)
47-
return hash, nil
39+
func (b *Block) Hash() *BlockHash {
40+
return newBlockHash(C.btck_block_get_hash((*C.btck_Block)(b.ptr)))
4841
}
4942

50-
// Bytes returns the serialized block
43+
// Bytes returns the consensus serialized block
5144
func (b *Block) Bytes() ([]byte, error) {
52-
checkReady(b)
53-
54-
// Use the callback helper to collect bytes from btck_block_to_bytes
55-
return writeToBytes(func(writer C.btck_WriteBytes, userData unsafe.Pointer) C.int {
56-
return C.btck_block_to_bytes(b.ptr, writer, userData)
45+
bytes, ok := writeToBytes(func(writer C.btck_WriteBytes, userData unsafe.Pointer) C.int {
46+
return C.btck_block_to_bytes((*C.btck_Block)(b.ptr), writer, userData)
5747
})
58-
}
59-
60-
// Copy creates a copy of the block
61-
func (b *Block) Copy() (*Block, error) {
62-
checkReady(b)
63-
64-
ptr := C.btck_block_copy(b.ptr)
65-
if ptr == nil {
66-
return nil, ErrKernelBlockCopy
48+
if !ok {
49+
return nil, &SerializationError{"Failed to serialize block"}
6750
}
68-
69-
return newBlockFromPtr(ptr), nil
51+
return bytes, nil
7052
}
7153

72-
// CountTransactions returns the number of transactions in the block
73-
func (b *Block) CountTransactions() (uint64, error) {
74-
checkReady(b)
75-
76-
count := C.btck_block_count_transactions(b.ptr)
77-
return uint64(count), nil
54+
func (b *Block) Copy() *Block {
55+
return newBlock((*C.btck_Block)(b.ptr), false)
7856
}
7957

80-
// GetTransactionAt returns the transaction at the specified index.
81-
func (b *Block) GetTransactionAt(index uint64) (*Transaction, error) {
82-
checkReady(b)
83-
84-
ptr := C.btck_block_get_transaction_at(b.ptr, C.size_t(index))
85-
if ptr == nil {
86-
return nil, ErrKernelBlockGetTransaction
87-
}
88-
89-
transaction := &Transaction{ptr: ptr}
90-
runtime.SetFinalizer(transaction, (*Transaction).destroy)
91-
return transaction, nil
58+
func (b *Block) CountTransactions() uint64 {
59+
return uint64(C.btck_block_count_transactions((*C.btck_Block)(b.ptr)))
9260
}
9361

94-
func (b *Block) destroy() {
95-
if b.ptr != nil {
96-
C.btck_block_destroy(b.ptr)
97-
b.ptr = nil
62+
func (b *Block) GetTransactionAt(index uint64) (*TransactionView, error) {
63+
if index >= b.CountTransactions() {
64+
return nil, ErrKernelIndexOutOfBounds
9865
}
99-
}
100-
101-
func (b *Block) Destroy() {
102-
runtime.SetFinalizer(b, nil)
103-
b.destroy()
104-
}
105-
106-
func (b *Block) isReady() bool {
107-
return b != nil && b.ptr != nil
108-
}
109-
110-
func (b *Block) uninitializedError() error {
111-
return ErrBlockUninitialized
66+
ptr := C.btck_block_get_transaction_at((*C.btck_Block)(b.ptr), C.size_t(index))
67+
return newTransactionView(check(ptr)), nil
11268
}

kernel/block_hash.go

Lines changed: 12 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,40 +5,26 @@ package kernel
55
*/
66
import "C"
77
import (
8-
"runtime"
98
"unsafe"
109
)
1110

12-
var _ cManagedResource = &BlockHash{}
11+
type blockHashCFuncs struct{}
1312

14-
// BlockHash wraps the C btck_BlockHash
15-
type BlockHash struct {
16-
ptr *C.btck_BlockHash
17-
}
18-
19-
// Bytes returns the raw hash bytes
20-
func (bh *BlockHash) Bytes() []byte {
21-
checkReady(bh)
22-
// BlockHash is a 32-byte array in the C struct
23-
return C.GoBytes(unsafe.Pointer(&bh.ptr.hash[0]), 32)
13+
func (blockHashCFuncs) destroy(ptr unsafe.Pointer) {
14+
C.btck_block_hash_destroy((*C.btck_BlockHash)(ptr))
2415
}
2516

26-
func (bh *BlockHash) destroy() {
27-
if bh.ptr != nil {
28-
C.btck_block_hash_destroy(bh.ptr)
29-
bh.ptr = nil
30-
}
31-
}
32-
33-
func (bh *BlockHash) Destroy() {
34-
runtime.SetFinalizer(bh, nil)
35-
bh.destroy()
17+
type BlockHash struct {
18+
*uniqueHandle
3619
}
3720

38-
func (bh *BlockHash) isReady() bool {
39-
return bh != nil && bh.ptr != nil
21+
func newBlockHash(ptr *C.btck_BlockHash) *BlockHash {
22+
h := newUniqueHandle(unsafe.Pointer(ptr), blockHashCFuncs{})
23+
return &BlockHash{uniqueHandle: h}
4024
}
4125

42-
func (bh *BlockHash) uninitializedError() error {
43-
return ErrBlockHashUninitialized
26+
// Bytes returns the raw hash bytes
27+
func (bh *BlockHash) Bytes() []byte {
28+
// BlockHash is a 32-byte array in the C struct
29+
return C.GoBytes(unsafe.Pointer(&(*C.btck_BlockHash)(bh.ptr).hash[0]), 32)
4430
}

kernel/block_spent_outputs.go

Lines changed: 22 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -5,65 +5,41 @@ package kernel
55
*/
66
import "C"
77
import (
8-
"runtime"
8+
"unsafe"
99
)
1010

11-
var _ cManagedResource = &BlockSpentOutputs{}
11+
type blockSpentOutputsCFuncs struct{}
1212

13-
// BlockSpentOutputs wraps the C btck_BlockSpentOutputs
14-
type BlockSpentOutputs struct {
15-
ptr *C.btck_BlockSpentOutputs
16-
}
17-
18-
// Count returns the number of transaction spent outputs contained in block spent outputs
19-
func (bso *BlockSpentOutputs) Count() uint64 {
20-
checkReady(bso)
21-
return uint64(C.btck_block_spent_outputs_count(bso.ptr))
13+
func (blockSpentOutputsCFuncs) destroy(ptr unsafe.Pointer) {
14+
C.btck_block_spent_outputs_destroy((*C.btck_BlockSpentOutputs)(ptr))
2215
}
2316

24-
// GetTransactionSpentOutputsAt returns the transaction spent outputs at the specified index
25-
func (bso *BlockSpentOutputs) GetTransactionSpentOutputsAt(index uint64) (*TransactionSpentOutputs, error) {
26-
checkReady(bso)
27-
ptr := C.btck_block_spent_outputs_get_transaction_spent_outputs_at(bso.ptr, C.size_t(index))
28-
if ptr == nil {
29-
return nil, ErrKernelBlockSpentOutputsGetTransactionSpentOutputsAt
30-
}
31-
32-
txSpentOutputs := &TransactionSpentOutputs{ptr: ptr}
33-
runtime.SetFinalizer(txSpentOutputs, (*TransactionSpentOutputs).destroy)
34-
return txSpentOutputs, nil
17+
func (blockSpentOutputsCFuncs) copy(ptr unsafe.Pointer) unsafe.Pointer {
18+
return unsafe.Pointer(C.btck_block_spent_outputs_copy((*C.btck_BlockSpentOutputs)(ptr)))
3519
}
3620

37-
// Copy creates a copy of the block spent outputs
38-
func (bso *BlockSpentOutputs) Copy() (*BlockSpentOutputs, error) {
39-
checkReady(bso)
40-
41-
ptr := C.btck_block_spent_outputs_copy(bso.ptr)
42-
if ptr == nil {
43-
return nil, ErrKernelBlockSpentOutputsCopy
44-
}
45-
46-
outputs := &BlockSpentOutputs{ptr: ptr}
47-
runtime.SetFinalizer(outputs, (*BlockSpentOutputs).destroy)
48-
return outputs, nil
21+
type BlockSpentOutputs struct {
22+
*handle
4923
}
5024

51-
func (bso *BlockSpentOutputs) destroy() {
52-
if bso.ptr != nil {
53-
C.btck_block_spent_outputs_destroy(bso.ptr)
54-
bso.ptr = nil
55-
}
25+
func newBlockSpentOutputs(ptr *C.btck_BlockSpentOutputs, fromOwned bool) *BlockSpentOutputs {
26+
h := newHandle(unsafe.Pointer(ptr), blockSpentOutputsCFuncs{}, fromOwned)
27+
return &BlockSpentOutputs{handle: h}
5628
}
5729

58-
func (bso *BlockSpentOutputs) Destroy() {
59-
runtime.SetFinalizer(bso, nil)
60-
bso.destroy()
30+
func (bso *BlockSpentOutputs) Count() uint64 {
31+
return uint64(C.btck_block_spent_outputs_count((*C.btck_BlockSpentOutputs)(bso.ptr)))
6132
}
6233

63-
func (bso *BlockSpentOutputs) isReady() bool {
64-
return bso != nil && bso.ptr != nil
34+
// GetTransactionSpentOutputsAt returns the transaction spent outputs at the specified index
35+
func (bso *BlockSpentOutputs) GetTransactionSpentOutputsAt(index uint64) (*TransactionSpentOutputsView, error) {
36+
if index >= bso.Count() {
37+
return nil, ErrKernelIndexOutOfBounds
38+
}
39+
ptr := C.btck_block_spent_outputs_get_transaction_spent_outputs_at((*C.btck_BlockSpentOutputs)(bso.ptr), C.size_t(index))
40+
return newTransactionSpentOutputsView(check(ptr)), nil
6541
}
6642

67-
func (bso *BlockSpentOutputs) uninitializedError() error {
68-
return ErrBlockSpentOutputsUninitialized
43+
func (bso *BlockSpentOutputs) Copy() *BlockSpentOutputs {
44+
return newBlockSpentOutputs((*C.btck_BlockSpentOutputs)(bso.ptr), false)
6945
}

0 commit comments

Comments
 (0)