Skip to content

Commit f5ba0de

Browse files
committed
feat: fix linter issues, naming issues, clean up
1 parent c402dbe commit f5ba0de

16 files changed

+357
-313
lines changed

README.md

Lines changed: 41 additions & 95 deletions
Large diffs are not rendered by default.

coinbase_placeholder.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// Package subtree provides utilities for working with Bitcoin SV merkle tree subtrees,
2+
// including coinbase placeholder handling and subtree data structures.
13
package subtree
24

35
import (
@@ -14,18 +16,23 @@ var (
1416
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1517
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1618
}
19+
// CoinbasePlaceholderHashValue is the hash representation of the coinbase placeholder
1720
CoinbasePlaceholderHashValue = chainhash.Hash(CoinbasePlaceholder)
18-
CoinbasePlaceholderHash = &CoinbasePlaceholderHashValue
21+
// CoinbasePlaceholderHash is a pointer to the coinbase placeholder hash value
22+
CoinbasePlaceholderHash = &CoinbasePlaceholderHashValue
1923

24+
// FrozenBytes represents the frozen transaction bytes used for placeholder transactions
2025
FrozenBytes = [36]byte{
2126
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
2227
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
2328
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
2429
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
2530
0xFF, 0xFF, 0xFF, 0xFF,
2631
}
32+
// FrozenBytesTxBytes represents the transaction bytes portion of FrozenBytes
2733
FrozenBytesTxBytes = FrozenBytes[0:32]
28-
FrozenBytesTxHash = chainhash.Hash(FrozenBytesTxBytes)
34+
// FrozenBytesTxHash is the hash of the frozen transaction bytes
35+
FrozenBytesTxHash = chainhash.Hash(FrozenBytesTxBytes)
2936
)
3037

3138
func generateCoinbasePlaceholderTx() *bt.Tx {

coinbase_placeholder_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ func TestCoinbasePlaceholderTx(t *testing.T) {
1212
coinbasePlaceholderTxHash := coinbasePlaceholderTx.TxIDChainHash()
1313
assert.True(t, IsCoinbasePlaceHolderTx(coinbasePlaceholderTx))
1414
assert.Equal(t, uint32(0xFFFFFFFF), coinbasePlaceholderTx.Version)
15-
assert.Equal(t, coinbasePlaceholderTx.LockTime, uint32(0xFFFFFFFF))
16-
assert.Equal(t, coinbasePlaceholderTx.TxIDChainHash(), coinbasePlaceholderTxHash)
15+
assert.Equal(t, uint32(0xFFFFFFFF), coinbasePlaceholderTx.LockTime)
16+
assert.Equal(t, coinbasePlaceholderTxHash, coinbasePlaceholderTx.TxIDChainHash())
1717
assert.False(t, IsCoinbasePlaceHolderTx(bt.NewTx()))
1818
assert.Equal(t, "a8502e9c08b3c851201a71d25bf29fd38a664baedb777318b12d19242f0e46ab", coinbasePlaceholderTx.TxIDChainHash().String())
1919
}

compare.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package subtree
22

33
import "golang.org/x/exp/constraints"
44

5+
// Min returns the minimum of two ordered values
56
func Min[T constraints.Ordered](a, b T) T {
67
if a < b {
78
return a
@@ -10,6 +11,7 @@ func Min[T constraints.Ordered](a, b T) T {
1011
return b
1112
}
1213

14+
// Max returns the maximum of two ordered values
1315
func Max[T constraints.Ordered](a, b T) T {
1416
if a > b {
1517
return a

errors.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package subtree
2+
3+
import "errors"
4+
5+
// Sentinel errors for the subtree package
6+
7+
// Range and bounds errors
8+
var (
9+
// ErrIndexOutOfRange is returned when an index is out of range
10+
ErrIndexOutOfRange = errors.New("index out of range")
11+
12+
// ErrTxIndexOutOfBounds is returned when a transaction index is out of bounds
13+
ErrTxIndexOutOfBounds = errors.New("transaction index out of bounds")
14+
)
15+
16+
// Validation errors
17+
var (
18+
// ErrHeightNegative is returned when height is negative
19+
ErrHeightNegative = errors.New("height must be at least 0")
20+
21+
// ErrNotPowerOfTwo is returned when the number of leaves must be a power of two
22+
ErrNotPowerOfTwo = errors.New("numberOfLeaves must be a power of two")
23+
24+
// ErrSubtreeFull is returned when trying to add a node to a full subtree
25+
ErrSubtreeFull = errors.New("subtree is full")
26+
27+
// ErrSubtreeNil is returned when the subtree is nil
28+
ErrSubtreeNil = errors.New("subtree is nil")
29+
30+
// ErrSubtreeNotEmpty is returned when subtree should be empty before adding a coinbase node
31+
ErrSubtreeNotEmpty = errors.New("subtree should be empty before adding a coinbase node")
32+
33+
// ErrSubtreeNodesEmpty is returned when subtree nodes slice is empty
34+
ErrSubtreeNodesEmpty = errors.New("subtree nodes slice is empty")
35+
36+
// ErrNoSubtreesAvailable is returned when no subtrees are available
37+
ErrNoSubtreesAvailable = errors.New("no subtrees available")
38+
39+
// ErrCoinbasePlaceholderMisuse is returned when coinbase placeholder node should be added with AddCoinbaseNode
40+
ErrCoinbasePlaceholderMisuse = errors.New("coinbase placeholder node should be added with AddCoinbaseNode")
41+
42+
// ErrConflictingNodeNotInSubtree is returned when conflicting node is not in the subtree
43+
ErrConflictingNodeNotInSubtree = errors.New("conflicting node is not in the subtree")
44+
45+
// ErrNodeNotFound is returned when a node is not found
46+
ErrNodeNotFound = errors.New("node not found")
47+
)
48+
49+
// Data mismatch errors
50+
var (
51+
// ErrParentTxHashesMismatch is returned when parent tx hashes and indexes length mismatch
52+
ErrParentTxHashesMismatch = errors.New("parent tx hashes and indexes length mismatch")
53+
54+
// ErrTxHashMismatch is returned when transaction hash does not match subtree node hash
55+
ErrTxHashMismatch = errors.New("transaction hash does not match subtree node hash")
56+
57+
// ErrSubtreeLengthMismatch is returned when subtree length does not match tx data length
58+
ErrSubtreeLengthMismatch = errors.New("subtree length does not match tx data length")
59+
)
60+
61+
// Serialization errors
62+
var (
63+
// ErrCannotSerializeSubtreeNotSet is returned when cannot serialize because subtree is not set
64+
ErrCannotSerializeSubtreeNotSet = errors.New("cannot serialize, subtree is not set")
65+
66+
// ErrReadError is a generic read error for testing
67+
ErrReadError = errors.New("read error")
68+
)

inpoints.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ func (p *TxInpoints) GetParentTxHashes() []chainhash.Hash {
9090
// GetParentTxHashAtIndex returns the parent transaction hash at the specified index.
9191
func (p *TxInpoints) GetParentTxHashAtIndex(index int) (chainhash.Hash, error) {
9292
if index >= len(p.ParentTxHashes) {
93-
return chainhash.Hash{}, fmt.Errorf("index out of range")
93+
return chainhash.Hash{}, ErrIndexOutOfRange
9494
}
9595

9696
return p.ParentTxHashes[index], nil
@@ -115,7 +115,7 @@ func (p *TxInpoints) GetTxInpoints() []Inpoint {
115115
// GetParentVoutsAtIndex returns the parent transaction output indexes at the specified index.
116116
func (p *TxInpoints) GetParentVoutsAtIndex(index int) ([]uint32, error) {
117117
if index >= len(p.ParentTxHashes) {
118-
return nil, fmt.Errorf("index out of range")
118+
return nil, ErrIndexOutOfRange
119119
}
120120

121121
return p.Idxs[index], nil
@@ -124,7 +124,7 @@ func (p *TxInpoints) GetParentVoutsAtIndex(index int) ([]uint32, error) {
124124
// Serialize serializes the TxInpoints object into a byte slice.
125125
func (p *TxInpoints) Serialize() ([]byte, error) {
126126
if len(p.ParentTxHashes) != len(p.Idxs) {
127-
return nil, fmt.Errorf("parent tx hashes and indexes length mismatch")
127+
return nil, ErrParentTxHashesMismatch
128128
}
129129

130130
bufBytes := make([]byte, 0, 1024) // 1KB (arbitrary size, should be enough for most cases)

inpoints_test.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ func TestTxInpoints(t *testing.T) {
1313
p, err := NewTxInpointsFromTx(tx)
1414
require.NoError(t, err)
1515

16-
assert.Equal(t, 1, len(p.ParentTxHashes))
17-
assert.Equal(t, 1, len(p.Idxs[0]))
16+
assert.Len(t, p.ParentTxHashes, 1)
17+
assert.Len(t, p.Idxs[0], 1)
1818
})
1919

2020
t.Run("serialize", func(t *testing.T) {
@@ -23,13 +23,13 @@ func TestTxInpoints(t *testing.T) {
2323

2424
b, err := p.Serialize()
2525
require.NoError(t, err)
26-
assert.Equal(t, 44, len(b))
26+
assert.Len(t, b, 44)
2727

2828
p2, err := NewTxInpointsFromBytes(b)
2929
require.NoError(t, err)
3030

31-
assert.Equal(t, 1, len(p2.ParentTxHashes))
32-
assert.Equal(t, 1, len(p2.Idxs[0]))
31+
assert.Len(t, p2.ParentTxHashes, 1)
32+
assert.Len(t, p2.Idxs[0], 1)
3333

3434
assert.Equal(t, p.ParentTxHashes[0], p2.ParentTxHashes[0])
3535
assert.Equal(t, p.Idxs[0][0], p2.Idxs[0][0])
@@ -52,8 +52,8 @@ func TestTxInpoints(t *testing.T) {
5252
require.NoError(t, err)
5353

5454
// make sure they are the same
55-
assert.Equal(t, len(p.ParentTxHashes), len(p2.ParentTxHashes))
56-
assert.Equal(t, len(p.Idxs), len(p2.Idxs))
55+
assert.Len(t, p2.ParentTxHashes, len(p.ParentTxHashes))
56+
assert.Len(t, p2.Idxs, len(p.Idxs))
5757
assert.Equal(t, p.ParentTxHashes[0], p2.ParentTxHashes[0])
5858
assert.Equal(t, p.Idxs[0][0], p2.Idxs[0][0])
5959
})
@@ -65,7 +65,7 @@ func TestGetTxInpoints(t *testing.T) {
6565

6666
// Test getting inpoints
6767
inpoints := p.GetTxInpoints()
68-
assert.Equal(t, 1, len(inpoints))
68+
assert.Len(t, inpoints, 1)
6969
assert.Equal(t, uint32(5), inpoints[0].Index)
7070
assert.Equal(t, *tx.Inputs[0].PreviousTxIDChainHash(), inpoints[0].Hash)
7171
}
@@ -103,7 +103,7 @@ func TestGetParentVoutsAtIndex(t *testing.T) {
103103
vouts, err := p.GetParentVoutsAtIndex(0)
104104
require.NoError(t, err)
105105

106-
assert.Equal(t, 1, len(vouts))
106+
assert.Len(t, vouts, 1)
107107
assert.Equal(t, uint32(5), vouts[0])
108108
})
109109

merkle_tree.go

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
// GetMerkleProofForCoinbase returns a merkle proof for the coinbase transaction
1313
func GetMerkleProofForCoinbase(subtrees []*Subtree) ([]*chainhash.Hash, error) {
1414
if len(subtrees) == 0 {
15-
return nil, fmt.Errorf("no subtrees available")
15+
return nil, ErrNoSubtreesAvailable
1616
}
1717

1818
merkleProof, err := subtrees[0].GetMerkleProof(0)
@@ -42,7 +42,7 @@ func GetMerkleProofForCoinbase(subtrees []*Subtree) ([]*chainhash.Hash, error) {
4242
}
4343

4444
// BuildMerkleTreeStoreFromBytes builds a merkle tree from the given nodes.
45-
func BuildMerkleTreeStoreFromBytes(nodes []SubtreeNode) (*[]chainhash.Hash, error) {
45+
func BuildMerkleTreeStoreFromBytes(nodes []Node) (*[]chainhash.Hash, error) {
4646
if len(nodes) == 0 {
4747
return &[]chainhash.Hash{}, nil
4848
}
@@ -94,7 +94,7 @@ func BuildMerkleTreeStoreFromBytes(nodes []SubtreeNode) (*[]chainhash.Hash, erro
9494
}
9595

9696
// calcMerkles calculates the merkle hashes for the given nodes in the range
97-
func calcMerkles(nodes []SubtreeNode, merkleFrom, merkleTo, nextPoT, length int, merkles []chainhash.Hash) {
97+
func calcMerkles(nodes []Node, merkleFrom, merkleTo, nextPoT, length int, merkles []chainhash.Hash) {
9898
var offset int
9999

100100
var currentMerkle chainhash.Hash
@@ -103,30 +103,37 @@ func calcMerkles(nodes []SubtreeNode, merkleFrom, merkleTo, nextPoT, length int,
103103

104104
for i := merkleFrom; i < merkleTo; i += 2 {
105105
offset = i / 2
106+
currentMerkle, currentMerkle1 = getMerklePair(nodes, merkles, i, nextPoT, length)
107+
merkles[offset] = calcMerkle(currentMerkle, currentMerkle1)
108+
}
109+
}
106110

107-
if i < nextPoT {
108-
if i >= length {
109-
currentMerkle = chainhash.Hash{}
110-
} else {
111-
currentMerkle = nodes[i].Hash
112-
}
111+
// getMerklePair returns a pair of merkle hashes at the given index
112+
func getMerklePair(nodes []Node, merkles []chainhash.Hash, i, nextPoT, length int) (chainhash.Hash, chainhash.Hash) {
113+
var currentMerkle, currentMerkle1 chainhash.Hash
113114

114-
if i+1 >= length {
115-
currentMerkle1 = chainhash.Hash{}
116-
} else {
117-
currentMerkle1 = nodes[i+1].Hash
118-
}
119-
} else {
120-
currentMerkle = merkles[i-nextPoT]
121-
currentMerkle1 = merkles[i-nextPoT+1]
122-
}
115+
if i < nextPoT {
116+
currentMerkle = getNodeHashAt(nodes, i, length)
117+
currentMerkle1 = getNodeHashAt(nodes, i+1, length)
118+
} else {
119+
currentMerkle = merkles[i-nextPoT]
120+
currentMerkle1 = merkles[i-nextPoT+1]
121+
}
123122

124-
merkles[offset] = calcMerkle(currentMerkle, currentMerkle1)
123+
return currentMerkle, currentMerkle1
124+
}
125+
126+
// getNodeHashAt returns the hash at the given index, or an empty hash if out of bounds
127+
func getNodeHashAt(nodes []Node, index, length int) chainhash.Hash {
128+
if index >= length {
129+
return chainhash.Hash{}
125130
}
131+
132+
return nodes[index].Hash
126133
}
127134

128135
// calcMerkle calculates the parent node hash from the left and right child nodes
129-
func calcMerkle(currentMerkle chainhash.Hash, currentMerkle1 chainhash.Hash) [32]byte {
136+
func calcMerkle(currentMerkle, currentMerkle1 chainhash.Hash) [32]byte {
130137
switch {
131138
// When there is no left child node, the parent is nil ("") too.
132139
case currentMerkle.Equal(chainhash.Hash{}):

power_of_two.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"math/bits"
66
)
77

8+
// CeilPowerOfTwo returns the smallest power of two that is greater than or equal to the given number
89
func CeilPowerOfTwo(num int) int {
910
if num <= 0 {
1011
return 1
@@ -19,6 +20,7 @@ func CeilPowerOfTwo(num int) int {
1920
return ceilValue
2021
}
2122

23+
// IsPowerOfTwo returns true if the given number is a power of two
2224
func IsPowerOfTwo(num int) bool {
2325
if num <= 0 {
2426
return false

power_of_two_test.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package subtree
22

33
import (
4-
"fmt"
54
"testing"
65

76
"github.com/stretchr/testify/assert"
@@ -11,12 +10,12 @@ func TestIsPowerOf2(t *testing.T) {
1110
// Testing the function
1211
numbers := []int{1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 1048576, 70368744177664}
1312
for _, num := range numbers {
14-
assert.True(t, IsPowerOfTwo(num), fmt.Sprintf("%d should be a power of 2", num))
13+
assert.True(t, IsPowerOfTwo(num), "%d should be a power of 2", num)
1514
}
1615

1716
numbers = []int{-1, 0, 41, 13}
1817
for _, num := range numbers {
19-
assert.False(t, IsPowerOfTwo(num), fmt.Sprintf("%d should be a power of 2", num))
18+
assert.False(t, IsPowerOfTwo(num), "%d should be a power of 2", num)
2019
}
2120
}
2221

@@ -26,6 +25,6 @@ func TestNextLowerPowerOf2(t *testing.T) {
2625
expected := []uint{16, 32, 64, 128, 0, 131072}
2726

2827
for i, num := range numbers {
29-
assert.Equal(t, expected[i], NextLowerPowerOfTwo(num), fmt.Sprintf("%d should be a power of 2", num))
28+
assert.Equal(t, expected[i], NextLowerPowerOfTwo(num), "%d should be a power of 2", num)
3029
}
3130
}

0 commit comments

Comments
 (0)