Skip to content

Commit 9d0a4cd

Browse files
committed
Add TransactionOutput
1 parent a94a1b4 commit 9d0a4cd

File tree

4 files changed

+149
-22
lines changed

4 files changed

+149
-22
lines changed

TODO.md

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,10 @@
11
# Bitcoin Kernel Go Wrapper - TODO
22

3-
This document lists the remaining C API functions and data structures from `bitcoinkernel.h` that haven't been wrapped yet in the Go kernel package.
4-
5-
## Current Status
6-
7-
**Implemented:**
8-
- Chain parameters and context management
9-
- Block and block index operations
10-
- Chainstate manager functionality
11-
- Basic logging support
12-
13-
**Missing:**
14-
- Transaction processing pipeline
15-
- Script validation system
16-
- Block undo data handling
17-
- Complete callback system integration
3+
This document lists the remaining C API functions and data structures from [`bitcoinkernel.h`](./depend/bitcoin/src/kernel/bitcoinkernel.h) that haven't been wrapped yet in the Go kernel package.
184

195
## Missing Data Structures
206

217
### Core Transaction Types
22-
- **`kernel_TransactionOutput`** - Transaction output operations
238
- **`kernel_BlockPointer`** - Non-owned block pointers (from callbacks)
249
- **`kernel_BlockUndo`** - Block undo data operations
2510

@@ -28,12 +13,6 @@ This document lists the remaining C API functions and data structures from `bitc
2813
### Script Operations
2914
- [ ] `kernel_verify_script()` - **Script verification (IMPORTANT!)**
3015

31-
### Transaction Output Operations
32-
- [ ] `kernel_transaction_output_create()` - Create transaction output
33-
- [ ] `kernel_transaction_output_destroy()` - Cleanup transaction output
34-
- [ ] `kernel_copy_script_pubkey_from_output()` - Extract script from output
35-
- [ ] `kernel_get_transaction_output_amount()` - Get output amount
36-
3716
### Block Operations (Additional)
3817
- [ ] `kernel_block_pointer_get_hash()` - Get hash from block pointer
3918
- [ ] `kernel_copy_block_pointer_data()` - Copy data from block pointer

kernel/errors.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,7 @@ var (
2525
ErrInvalidScriptPubkeyData = errors.New("invalid script pubkey data")
2626
ErrInvalidScriptPubkey = errors.New("invalid script pubkey")
2727
ErrScriptPubkeyDataCopy = errors.New("failed to copy script pubkey data")
28+
ErrTransactionOutputCreation = errors.New("failed to create transaction output")
29+
ErrInvalidTransactionOutput = errors.New("invalid transaction output")
30+
ErrScriptPubkeyCopyFromOutput = errors.New("failed to copy script pubkey from output")
2831
)

kernel/transaction_output.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package kernel
2+
3+
/*
4+
#include "kernel/bitcoinkernel.h"
5+
*/
6+
import "C"
7+
import (
8+
"runtime"
9+
)
10+
11+
// TransactionOutput wraps the C kernel_TransactionOutput
12+
type TransactionOutput struct {
13+
ptr *C.kernel_TransactionOutput
14+
}
15+
16+
func NewTransactionOutput(scriptPubkey *ScriptPubkey, amount int64) (*TransactionOutput, error) {
17+
if scriptPubkey == nil || scriptPubkey.ptr == nil {
18+
return nil, ErrInvalidScriptPubkey
19+
}
20+
21+
ptr := C.kernel_transaction_output_create(scriptPubkey.ptr, C.int64_t(amount))
22+
if ptr == nil {
23+
return nil, ErrTransactionOutputCreation
24+
}
25+
26+
output := &TransactionOutput{ptr: ptr}
27+
runtime.SetFinalizer(output, (*TransactionOutput).destroy)
28+
return output, nil
29+
}
30+
31+
// ScriptPubkey returns a copy of the script pubkey from this transaction output
32+
func (t *TransactionOutput) ScriptPubkey() (*ScriptPubkey, error) {
33+
if t.ptr == nil {
34+
return nil, ErrInvalidTransactionOutput
35+
}
36+
37+
ptr := C.kernel_copy_script_pubkey_from_output(t.ptr)
38+
if ptr == nil {
39+
return nil, ErrScriptPubkeyCopyFromOutput
40+
}
41+
42+
scriptPubkey := &ScriptPubkey{ptr: ptr}
43+
runtime.SetFinalizer(scriptPubkey, (*ScriptPubkey).destroy)
44+
return scriptPubkey, nil
45+
}
46+
47+
func (t *TransactionOutput) Amount() int64 {
48+
if t.ptr == nil {
49+
return 0
50+
}
51+
52+
return int64(C.kernel_get_transaction_output_amount(t.ptr))
53+
}
54+
55+
func (t *TransactionOutput) destroy() {
56+
if t.ptr != nil {
57+
C.kernel_transaction_output_destroy(t.ptr)
58+
t.ptr = nil
59+
}
60+
}
61+
62+
func (t *TransactionOutput) Destroy() {
63+
runtime.SetFinalizer(t, nil)
64+
t.destroy()
65+
}

kernel/transaction_output_test.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package kernel
2+
3+
import (
4+
"encoding/hex"
5+
"errors"
6+
"testing"
7+
)
8+
9+
func TestInvalidTransactionOutput(t *testing.T) {
10+
_, err := NewTransactionOutput(nil, 1000)
11+
if !errors.Is(err, ErrInvalidScriptPubkey) {
12+
t.Errorf("Expected ErrInvalidScriptPubkey, got %v", err)
13+
}
14+
15+
_, err = NewTransactionOutput(&ScriptPubkey{ptr: nil}, 1000)
16+
if !errors.Is(err, ErrInvalidScriptPubkey) {
17+
t.Errorf("Expected ErrInvalidScriptPubkey, got %v", err)
18+
}
19+
}
20+
21+
func TestTransactionOutputCreation(t *testing.T) {
22+
scriptHex := "76a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe26158088ac"
23+
scriptBytes, err := hex.DecodeString(scriptHex)
24+
if err != nil {
25+
t.Fatalf("Failed to decode script hex: %v", err)
26+
}
27+
28+
scriptPubkey, err := NewScriptPubkeyFromRaw(scriptBytes)
29+
if err != nil {
30+
t.Fatalf("Failed to create script pubkey: %v", err)
31+
}
32+
defer scriptPubkey.Destroy()
33+
34+
amount := int64(5000000000)
35+
output, err := NewTransactionOutput(scriptPubkey, amount)
36+
if err != nil {
37+
t.Fatalf("NewTransactionOutput() error = %v", err)
38+
}
39+
defer output.Destroy()
40+
41+
gotAmount := output.Amount()
42+
if gotAmount != amount {
43+
t.Errorf("Expected amount %d, got %d", amount, gotAmount)
44+
}
45+
46+
// Test getting script pubkey
47+
gotScript, err := output.ScriptPubkey()
48+
if err != nil {
49+
t.Fatalf("TransactionOutput.ScriptPubkey() error = %v", err)
50+
}
51+
defer gotScript.Destroy()
52+
53+
scriptData, err := gotScript.Data()
54+
if err != nil {
55+
t.Fatalf("ScriptPubkey.Data() error = %v", err)
56+
}
57+
58+
if len(scriptData) != len(scriptBytes) {
59+
t.Errorf("Expected script length %d, got %d", len(scriptBytes), len(scriptData))
60+
}
61+
62+
scriptHexGot := hex.EncodeToString(scriptData)
63+
if scriptHexGot != scriptHex {
64+
t.Errorf("Expected script hex: %s, got %s", scriptHex, scriptHexGot)
65+
}
66+
}
67+
68+
func TestTransactionOutputNilOperations(t *testing.T) {
69+
output := &TransactionOutput{ptr: nil}
70+
71+
amount := output.Amount()
72+
if amount != 0 {
73+
t.Errorf("Expected amount 0 for nil ptr, got %d", amount)
74+
}
75+
76+
_, err := output.ScriptPubkey()
77+
if !errors.Is(err, ErrInvalidTransactionOutput) {
78+
t.Errorf("Expected ErrInvalidTransactionOutput, got %v", err)
79+
}
80+
}

0 commit comments

Comments
 (0)