Skip to content
Merged
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
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ build:

test:
go test -v ./...
go test -race ./kernel -run TestTransactionHandlePtrRaceDetector

clean:
rm -rf depend/bitcoin/build
Expand All @@ -58,4 +59,4 @@ help:
@echo " lint - Lint Go code"
@echo " deps - Install development dependencies"
@echo " update-kernel - Update Bitcoin dependency using git subtree"
@echo " help - Show this help message"
@echo " help - Show this help message"
40 changes: 28 additions & 12 deletions kernel/block_hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,35 +27,51 @@ type BlockHash struct {

func newBlockHash(ptr *C.btck_BlockHash, fromOwned bool) *BlockHash {
h := newHandle(unsafe.Pointer(ptr), blockHashCFuncs{}, fromOwned)
return &BlockHash{handle: h, blockHashApi: blockHashApi{(*C.btck_BlockHash)(h.ptr)}}
return &BlockHash{
handle: h,
blockHashApi: blockHashApi{
ptr: func() *C.btck_BlockHash {
return (*C.btck_BlockHash)(h.ptr)
},
},
}
}

// BlockHashView is a type-safe identifier for a block.
type BlockHashView struct {
blockHashApi
ptr *C.btck_BlockHash
}

func newBlockHashView(ptr *C.btck_BlockHash) *BlockHashView {
return &BlockHashView{
blockHashApi: blockHashApi{ptr},
ptr: ptr,
blockHashApi: blockHashApi{
ptr: func() *C.btck_BlockHash {
return ptr
},
},
}
}

type blockHashApi struct {
ptr *C.btck_BlockHash
ptr func() *C.btck_BlockHash
}

func (bh *blockHashApi) blockHashPtr() *C.btck_BlockHash {
return bh.ptr
func (bh *blockHashApi) cPtr() *C.btck_BlockHash {
return bh.ptr()
}

// BlockHashLike is an interface for types that can provide a block hash pointer.
// BlockHashLike is implemented by *BlockHash and *BlockHashView.
type BlockHashLike interface {
blockHashPtr() *C.btck_BlockHash
cPtr() *C.btck_BlockHash
Bytes() [32]byte
Copy() *BlockHash
Equals(BlockHashLike) bool
String() string
}

var _ BlockHashLike = (*BlockHash)(nil)
var _ BlockHashLike = (*BlockHashView)(nil)

// NewBlockHash creates a new BlockHash from a 32-byte hash value.
//
// Parameters:
Expand All @@ -68,13 +84,13 @@ func NewBlockHash(hashBytes [32]byte) *BlockHash {
// Bytes returns the 32-byte representation of the block hash.
func (bh *blockHashApi) Bytes() [32]byte {
var output [32]C.uchar
C.btck_block_hash_to_bytes(bh.ptr, &output[0])
C.btck_block_hash_to_bytes(bh.ptr(), &output[0])
return *(*[32]byte)(unsafe.Pointer(&output[0]))
}

// Copy creates a copy of the block hash.
func (bh *blockHashApi) Copy() *BlockHash {
return newBlockHash(bh.ptr, false)
return newBlockHash(bh.ptr(), false)
}

// Equals checks if two block hashes are equal.
Expand All @@ -84,7 +100,7 @@ func (bh *blockHashApi) Copy() *BlockHash {
//
// Returns true if the block hashes are equal.
func (bh *blockHashApi) Equals(other BlockHashLike) bool {
return C.btck_block_hash_equals(bh.ptr, other.blockHashPtr()) != 0
return C.btck_block_hash_equals(bh.ptr(), other.cPtr()) != 0
}

// String returns the block hash as a hex string in display order (reversed).
Expand Down
40 changes: 32 additions & 8 deletions kernel/block_validation_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,14 @@ type BlockValidationState struct {

func newBlockValidationState(ptr *C.btck_BlockValidationState, fromOwned bool) *BlockValidationState {
h := newHandle(unsafe.Pointer(ptr), blockValidationStateCFuncs{}, fromOwned)
return &BlockValidationState{handle: h, blockValidationStateApi: blockValidationStateApi{(*C.btck_BlockValidationState)(h.ptr)}}
return &BlockValidationState{
handle: h,
blockValidationStateApi: blockValidationStateApi{
ptr: func() *C.btck_BlockValidationState {
return (*C.btck_BlockValidationState)(h.ptr)
},
},
}
}

// NewBlockValidationState creates a new owned BlockValidationState.
Expand All @@ -41,23 +48,40 @@ func NewBlockValidationState() *BlockValidationState {
// It provides read-only access to validation state without managing the underlying memory.
type BlockValidationStateView struct {
blockValidationStateApi
ptr *C.btck_BlockValidationState
}

func newBlockValidationStateView(ptr *C.btck_BlockValidationState) *BlockValidationStateView {
return &BlockValidationStateView{
blockValidationStateApi: blockValidationStateApi{ptr},
ptr: ptr,
blockValidationStateApi: blockValidationStateApi{
ptr: func() *C.btck_BlockValidationState {
return ptr
},
},
}
}

type blockValidationStateApi struct {
ptr *C.btck_BlockValidationState
ptr func() *C.btck_BlockValidationState
}

func (s *blockValidationStateApi) cPtr() *C.btck_BlockValidationState {
return s.ptr()
}

// BlockValidationStateLike is implemented by *BlockValidationState and *BlockValidationStateView.
type BlockValidationStateLike interface {
cPtr() *C.btck_BlockValidationState
Copy() *BlockValidationState
ValidationMode() ValidationMode
ValidationResult() BlockValidationResult
}

var _ BlockValidationStateLike = (*BlockValidationState)(nil)
var _ BlockValidationStateLike = (*BlockValidationStateView)(nil)

// Copy creates a copy of the block validation state.
func (s *blockValidationStateApi) Copy() *BlockValidationState {
return newBlockValidationState(s.ptr, false)
return newBlockValidationState(s.ptr(), false)
}

// ValidationMode returns whether the block is valid, invalid, or encountered an error.
Expand All @@ -67,7 +91,7 @@ func (s *blockValidationStateApi) Copy() *BlockValidationState {
// - ValidationStateInvalid: Block failed validation
// - ValidationStateError: Internal error during validation
func (s *blockValidationStateApi) ValidationMode() ValidationMode {
mode := C.btck_block_validation_state_get_validation_mode(s.ptr)
mode := C.btck_block_validation_state_get_validation_mode(s.ptr())
return ValidationMode(mode)
}

Expand All @@ -76,7 +100,7 @@ func (s *blockValidationStateApi) ValidationMode() ValidationMode {
// This provides detailed information about the specific validation failure, such as
// consensus violations, invalid headers, or missing previous blocks.
func (s *blockValidationStateApi) ValidationResult() BlockValidationResult {
result := C.btck_block_validation_state_get_block_validation_result(s.ptr)
result := C.btck_block_validation_state_get_block_validation_result(s.ptr())
return BlockValidationResult(result)
}

Expand Down
2 changes: 1 addition & 1 deletion kernel/chainstate_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ func (cm *ChainstateManager) GetActiveChain() *Chain {
// BlockTreeEntry is a non-owned pointer valid for the lifetime of this chainstate
// manager.
func (cm *ChainstateManager) GetBlockTreeEntryByHash(blockHash BlockHashLike) *BlockTreeEntry {
ptr := C.btck_chainstate_manager_get_block_tree_entry_by_hash((*C.btck_ChainstateManager)(cm.ptr), blockHash.blockHashPtr())
ptr := C.btck_chainstate_manager_get_block_tree_entry_by_hash((*C.btck_ChainstateManager)(cm.ptr), blockHash.cPtr())
if ptr == nil {
return nil
}
Expand Down
43 changes: 34 additions & 9 deletions kernel/coin.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,47 +27,72 @@ type Coin struct {

func newCoin(ptr *C.btck_Coin, fromOwned bool) *Coin {
h := newHandle(unsafe.Pointer(ptr), coinCFuncs{}, fromOwned)
return &Coin{handle: h, coinApi: coinApi{(*C.btck_Coin)(h.ptr)}}
return &Coin{
handle: h,
coinApi: coinApi{
ptr: func() *C.btck_Coin {
return (*C.btck_Coin)(h.ptr)
},
},
}
}

// CoinView holds information on a transaction output, including the height it was
// spent at and whether it is a coinbase output.
type CoinView struct {
coinApi
ptr *C.btck_Coin
}

func newCoinView(ptr *C.btck_Coin) *CoinView {
return &CoinView{
coinApi: coinApi{ptr},
ptr: ptr,
coinApi: coinApi{
ptr: func() *C.btck_Coin {
return ptr
},
},
}
}

type coinApi struct {
ptr *C.btck_Coin
ptr func() *C.btck_Coin
}

func (c *coinApi) cPtr() *C.btck_Coin {
return c.ptr()
}

// CoinLike is implemented by *Coin and *CoinView.
type CoinLike interface {
cPtr() *C.btck_Coin
Copy() *Coin
GetOutput() *TransactionOutputView
ConfirmationHeight() uint32
IsCoinbase() bool
}

var _ CoinLike = (*Coin)(nil)
var _ CoinLike = (*CoinView)(nil)

// Copy creates a copy of the coin.
func (c *coinApi) Copy() *Coin {
return newCoin(c.ptr, false)
return newCoin(c.ptr(), false)
}

// GetOutput returns the transaction output contained in this coin.
//
// The returned TransactionOutputView is a non-owned pointer valid for the
// lifetime of this coin.
func (c *coinApi) GetOutput() *TransactionOutputView {
ptr := C.btck_coin_get_output(c.ptr)
ptr := C.btck_coin_get_output(c.ptr())
return newTransactionOutputView(check(ptr))
}

// ConfirmationHeight returns the block height where the transaction that created this coin was included in.
func (c *coinApi) ConfirmationHeight() uint32 {
return uint32(C.btck_coin_confirmation_height(c.ptr))
return uint32(C.btck_coin_confirmation_height(c.ptr()))
}

// IsCoinbase returns true if this coin originates from a coinbase transaction.
func (c *coinApi) IsCoinbase() bool {
return int(C.btck_coin_is_coinbase(c.ptr)) != 0
return int(C.btck_coin_is_coinbase(c.ptr())) != 0
}
14 changes: 14 additions & 0 deletions kernel/kernel.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,18 @@
// the resources automatically via finalizers. However, relying on finalizers may delay
// resource cleanup and is not recommended for long-running programs or when working
// with many objects.
//
// # Owned and View Types
//
// Some kernel objects have both an owned type and a view type, such as Transaction
// and TransactionView. Owned types hold a reference to an underlying C resource and
// provide Destroy. View types are non-owned pointers returned from another object or
// callback, and remain valid only while the object that produced them remains valid.
//
// Methods shared by an owned type and its view type are exposed through sealed
// interfaces named with the Like suffix, such as TransactionLike and TxidLike. These
// interfaces are implemented by the package's owned and view types, but cannot be
// implemented by external packages because they include an unexported pointer getter.
// This keeps APIs type-safe around kernel C pointers while still allowing callers to
// accept either owned or view values.
package kernel
6 changes: 3 additions & 3 deletions kernel/precomputed_transaction_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,18 @@ func newPrecomputedTransactionData(ptr *C.btck_PrecomputedTransactionData, fromO
// - spentOutputs: Outputs spent by the transaction. May be nil for non-taproot verification.
//
// Returns an error if the precomputation fails.
func NewPrecomputedTransactionData(txTo *Transaction, spentOutputs []*TransactionOutput) (*PrecomputedTransactionData, error) {
func NewPrecomputedTransactionData(txTo TransactionLike, spentOutputs []TransactionOutputLike) (*PrecomputedTransactionData, error) {
var cSpentOutputsPtr **C.btck_TransactionOutput
if len(spentOutputs) > 0 {
cSpentOutputs := make([]*C.btck_TransactionOutput, len(spentOutputs))
for i, output := range spentOutputs {
cSpentOutputs[i] = (*C.btck_TransactionOutput)(output.handle.ptr)
cSpentOutputs[i] = output.cPtr()
}
cSpentOutputsPtr = (**C.btck_TransactionOutput)(unsafe.Pointer(&cSpentOutputs[0]))
}

ptr := C.btck_precomputed_transaction_data_create(
(*C.btck_Transaction)(txTo.handle.ptr),
txTo.cPtr(),
cSpentOutputsPtr,
C.size_t(len(spentOutputs)),
)
Expand Down
Loading
Loading