Skip to content

Commit cc22b8f

Browse files
committed
Remove ContextOptions public destructor and disallow setting callbacks more than once
User should not be able to free resources (callback handles) that could have already been shared with Context
1 parent b70dcb0 commit cc22b8f

File tree

5 files changed

+20
-32
lines changed

5 files changed

+20
-32
lines changed

kernel/chainstate_manager_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,6 @@ func (s *ChainstateManagerTestSuite) Setup(t *testing.T) {
228228
if err != nil {
229229
t.Fatalf("NewContextOptions() error = %v", err)
230230
}
231-
t.Cleanup(func() { contextOpts.Destroy() })
232231

233232
chainParams, err := NewChainParameters(ChainTypeRegtest)
234233
if err != nil {

kernel/context.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func (ctx *Context) destroy() {
6868
ctx.ptr = nil
6969
}
7070
if ctx.options != nil {
71-
ctx.options.Destroy()
71+
ctx.options.destroy()
7272
ctx.options = nil
7373
}
7474
}

kernel/context_options.go

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,20 @@ extern void go_validation_interface_block_checked_bridge(void* user_data, const
1818
*/
1919
import "C"
2020
import (
21+
"fmt"
2122
"runtime"
2223
"runtime/cgo"
2324
"unsafe"
2425
)
2526

26-
var _ cManagedResource = &ContextOptions{}
27+
var _ cResource = &ContextOptions{}
2728

2829
// ContextOptions wraps the C btck_ContextOptions.
29-
// Once the options is set on a context, the context is responsible for its lifetime and should not be destroyed manually.
30+
// Once the options is set on a context, the context is responsible for its lifetime; otherwise it is garbage collected
3031
type ContextOptions struct {
3132
ptr *C.btck_ContextOptions
32-
notificationHandle cgo.Handle // Prevents notification callbacks GC until Destroy() called
33-
validationHandle cgo.Handle // Prevents validation callbacks GC until Destroy() called
33+
notificationHandle cgo.Handle
34+
validationHandle cgo.Handle
3435
}
3536

3637
func NewContextOptions() (*ContextOptions, error) {
@@ -40,7 +41,7 @@ func NewContextOptions() (*ContextOptions, error) {
4041
}
4142

4243
opts := &ContextOptions{ptr: ptr}
43-
runtime.SetFinalizer(opts, (*ContextOptions).destroy)
44+
runtime.SetFinalizer(opts, (*ContextOptions).finalize)
4445
return opts, nil
4546
}
4647

@@ -60,13 +61,10 @@ func (opts *ContextOptions) SetChainParams(chainParams *ChainParameters) {
6061
func (opts *ContextOptions) SetNotifications(callbacks *NotificationCallbacks) error {
6162
checkReady(opts)
6263
if callbacks == nil {
63-
return ErrNilNotificationCallbacks
64+
return fmt.Errorf("nil notification callbacks")
6465
}
65-
66-
// Clean up existing handle if present
6766
if opts.notificationHandle != 0 {
68-
opts.notificationHandle.Delete()
69-
opts.notificationHandle = 0
67+
return fmt.Errorf("notification callbacks already set")
7068
}
7169

7270
// Create a handle for the callbacks - this prevents garbage collection
@@ -94,13 +92,10 @@ func (opts *ContextOptions) SetNotifications(callbacks *NotificationCallbacks) e
9492
func (opts *ContextOptions) SetValidationInterface(callbacks *ValidationInterfaceCallbacks) error {
9593
checkReady(opts)
9694
if callbacks == nil {
97-
return ErrNilValidationInterfaceCallbacks
95+
return fmt.Errorf("nil validation interface callbacks")
9896
}
99-
100-
// Clean up existing handle if present
10197
if opts.validationHandle != 0 {
102-
opts.validationHandle.Delete()
103-
opts.validationHandle = 0
98+
return fmt.Errorf("validation interface callbacks already set")
10499
}
105100

106101
// Create a handle for the callbacks - this prevents garbage collection
@@ -118,6 +113,11 @@ func (opts *ContextOptions) SetValidationInterface(callbacks *ValidationInterfac
118113
}
119114

120115
func (opts *ContextOptions) destroy() {
116+
opts.finalize()
117+
runtime.SetFinalizer(opts, nil)
118+
}
119+
120+
func (opts *ContextOptions) finalize() {
121121
if opts.ptr != nil {
122122
C.btck_context_options_destroy(opts.ptr)
123123
opts.ptr = nil
@@ -134,11 +134,6 @@ func (opts *ContextOptions) destroy() {
134134
}
135135
}
136136

137-
func (opts *ContextOptions) Destroy() {
138-
runtime.SetFinalizer(opts, nil)
139-
opts.destroy()
140-
}
141-
142137
func (opts *ContextOptions) isReady() bool {
143138
return opts != nil && opts.ptr != nil
144139
}

kernel/context_test.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,6 @@ func TestNewContext(t *testing.T) {
4141
for _, tt := range tests {
4242
t.Run(tt.name, func(t *testing.T) {
4343
opts := tt.setupOption()
44-
if opts != nil {
45-
defer opts.Destroy()
46-
}
4744

4845
ctx, err := NewContext(opts)
4946

kernel/errors.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ var (
4242
ErrKernelScriptPubkeyCreate = &KernelError{Operation: "btck_script_pubkey_create"}
4343
ErrKernelScriptPubkeyCopy = &KernelError{Operation: "btck_script_pubkey_copy"}
4444
ErrKernelScriptVerify = &KernelError{Operation: "btck_verify_script"}
45-
ErrKernelScriptVerifyInvalidFlags = &KernelError{Operation: "btck_verify_script", Detail: "the provided bitfield for the flags was invalid"}
4645
ErrKernelScriptVerifyInvalidFlagsCombination = &KernelError{Operation: "btck_verify_script", Detail: "the flags were combined in an invalid way"}
4746
ErrKernelScriptVerifySpentOutputsRequired = &KernelError{Operation: "btck_verify_script", Detail: "the taproot flag was set, so valid spent_outputs have to be provided"}
4847
ErrEmptyScriptPubkeyData = errors.New("empty script pubkey data") // constructor error
@@ -75,12 +74,10 @@ var (
7574
ErrLoggingConnectionUninitialized = &UninitializedError{ObjectName: "loggingConnection"}
7675
ErrKernelLoggingConnectionCreate = &KernelError{Operation: "btck_logging_connection_create"}
7776

78-
ErrInvalidChainType = errors.New("invalid chain type")
79-
ErrInvalidLogLevel = errors.New("invalid log level")
80-
ErrInvalidLogCategory = errors.New("invalid log category")
81-
ErrInvalidScriptVerifyStatus = errors.New("invalid script verify status")
82-
ErrNilNotificationCallbacks = errors.New("nil notification callbacks")
83-
ErrNilValidationInterfaceCallbacks = errors.New("nil validation interface callbacks")
77+
ErrInvalidChainType = errors.New("invalid chain type")
78+
ErrInvalidLogLevel = errors.New("invalid log level")
79+
ErrInvalidLogCategory = errors.New("invalid log category")
80+
ErrInvalidScriptVerifyStatus = errors.New("invalid script verify status")
8481
)
8582

8683
// UninitializedError is returned when an operation is attempted on a

0 commit comments

Comments
 (0)