Skip to content

Commit c17b53a

Browse files
authored
fix(lib/blocktree): fix blocktree bug (#2060)
1 parent 0d5e989 commit c17b53a

File tree

4 files changed

+100
-112
lines changed

4 files changed

+100
-112
lines changed

lib/blocktree/blocktree.go

Lines changed: 19 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,15 @@ type BlockTree struct {
2323
root *node
2424
leaves *leafMap
2525
sync.RWMutex
26-
nodeCache map[Hash]*node
27-
runtime *sync.Map
26+
runtime *sync.Map // map[Hash]runtime.Instance
2827
}
2928

3029
// NewEmptyBlockTree creates a BlockTree with a nil head
3130
func NewEmptyBlockTree() *BlockTree {
3231
return &BlockTree{
33-
root: nil,
34-
leaves: newEmptyLeafMap(),
35-
nodeCache: make(map[Hash]*node),
36-
runtime: &sync.Map{}, // map[Hash]runtime.Instance
32+
root: nil,
33+
leaves: newEmptyLeafMap(),
34+
runtime: &sync.Map{},
3735
}
3836
}
3937

@@ -49,20 +47,12 @@ func NewBlockTreeFromRoot(root *types.Header) *BlockTree {
4947
}
5048

5149
return &BlockTree{
52-
root: n,
53-
leaves: newLeafMap(n),
54-
nodeCache: make(map[Hash]*node),
55-
runtime: &sync.Map{},
50+
root: n,
51+
leaves: newLeafMap(n),
52+
runtime: &sync.Map{},
5653
}
5754
}
5855

59-
// GenesisHash returns the hash of the genesis block
60-
func (bt *BlockTree) GenesisHash() Hash {
61-
bt.RLock()
62-
defer bt.RUnlock()
63-
return bt.root.hash
64-
}
65-
6656
// AddBlock inserts the block as child of its parent node
6757
// Note: Assumes block has no children
6858
func (bt *BlockTree) AddBlock(header *types.Header, arrivalTime time.Time) error {
@@ -75,8 +65,7 @@ func (bt *BlockTree) AddBlock(header *types.Header, arrivalTime time.Time) error
7565
}
7666

7767
// Check if it already exists
78-
n := bt.getNode(header.Hash())
79-
if n != nil {
68+
if n := bt.getNode(header.Hash()); n != nil {
8069
return ErrBlockExists
8170
}
8271

@@ -87,17 +76,16 @@ func (bt *BlockTree) AddBlock(header *types.Header, arrivalTime time.Time) error
8776
return errUnexpectedNumber
8877
}
8978

90-
n = &node{
79+
n := &node{
9180
hash: header.Hash(),
9281
parent: parent,
9382
children: []*node{},
9483
number: number,
9584
arrivalTime: arrivalTime,
9685
}
86+
9787
parent.addChild(n)
9888
bt.leaves.replace(parent, n)
99-
bt.setInCache(n)
100-
10189
return nil
10290
}
10391

@@ -121,24 +109,8 @@ func (bt *BlockTree) GetAllBlocksAtNumber(hash common.Hash) (hashes []common.Has
121109
return bt.root.getNodesWithNumber(number, hashes)
122110
}
123111

124-
func (bt *BlockTree) setInCache(b *node) {
125-
if b == nil {
126-
return
127-
}
128-
129-
if _, has := bt.nodeCache[b.hash]; !has {
130-
bt.nodeCache[b.hash] = b
131-
}
132-
}
133-
134112
// getNode finds and returns a node based on its Hash. Returns nil if not found.
135113
func (bt *BlockTree) getNode(h Hash) (ret *node) {
136-
defer func() { bt.setInCache(ret) }()
137-
138-
if b, ok := bt.nodeCache[h]; ok {
139-
return b
140-
}
141-
142114
if bt.root.hash == h {
143115
return bt.root
144116
}
@@ -164,12 +136,6 @@ func (bt *BlockTree) getNode(h Hash) (ret *node) {
164136
func (bt *BlockTree) Prune(finalised Hash) (pruned []Hash) {
165137
bt.Lock()
166138
defer bt.Unlock()
167-
defer func() {
168-
for _, hash := range pruned {
169-
delete(bt.nodeCache, hash)
170-
bt.runtime.Delete(hash)
171-
}
172-
}()
173139

174140
if finalised == bt.root.hash {
175141
return pruned
@@ -190,6 +156,10 @@ func (bt *BlockTree) Prune(finalised Hash) (pruned []Hash) {
190156
bt.leaves.store(leaf.hash, leaf)
191157
}
192158

159+
for _, hash := range pruned {
160+
bt.runtime.Delete(hash)
161+
}
162+
193163
return pruned
194164
}
195165

@@ -218,7 +188,7 @@ func (bt *BlockTree) String() string {
218188
return fmt.Sprintf("%s\n%s\n", metadata, tree.Print())
219189
}
220190

221-
// longestPath returns the path from the root to leftmost deepest leaf in BlockTree BT
191+
// longestPath returns the path from the root to the deepest leaf in the blocktree
222192
func (bt *BlockTree) longestPath() []*node {
223193
dl := bt.deepestLeaf()
224194
var path []*node
@@ -260,7 +230,7 @@ func (bt *BlockTree) SubBlockchain(start, end Hash) ([]Hash, error) {
260230

261231
}
262232

263-
// deepestLeaf returns the leftmost deepest leaf in the block tree.
233+
// deepestLeaf returns the deepest leaf in the block tree.
264234
func (bt *BlockTree) deepestLeaf() *node {
265235
return bt.leaves.deepestLeaf()
266236
}
@@ -392,8 +362,8 @@ func (bt *BlockTree) GetArrivalTime(hash common.Hash) (time.Time, error) {
392362
bt.RLock()
393363
defer bt.RUnlock()
394364

395-
n, has := bt.nodeCache[hash]
396-
if !has {
365+
n := bt.getNode(hash)
366+
if n == nil {
397367
return time.Time{}, ErrNodeNotFound
398368
}
399369

@@ -405,9 +375,7 @@ func (bt *BlockTree) DeepCopy() *BlockTree {
405375
bt.RLock()
406376
defer bt.RUnlock()
407377

408-
btCopy := &BlockTree{
409-
nodeCache: make(map[Hash]*node),
410-
}
378+
btCopy := &BlockTree{}
411379

412380
if bt.root == nil {
413381
return btCopy
@@ -424,10 +392,6 @@ func (bt *BlockTree) DeepCopy() *BlockTree {
424392
}
425393
}
426394

427-
for hash := range bt.nodeCache {
428-
btCopy.nodeCache[hash] = btCopy.getNode(hash)
429-
}
430-
431395
return btCopy
432396
}
433397

lib/blocktree/blocktree_test.go

Lines changed: 3 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -283,12 +283,7 @@ func TestBlockTree_GetNode(t *testing.T) {
283283
}
284284

285285
block := bt.getNode(branches[0].hash)
286-
287-
cachedBlock, ok := bt.nodeCache[block.hash]
288-
require.True(t, len(bt.nodeCache) > 0)
289-
require.True(t, ok)
290-
require.NotNil(t, cachedBlock)
291-
require.Equal(t, cachedBlock, block)
286+
require.NotNil(t, block)
292287
}
293288

294289
func TestBlockTree_GetAllBlocksAtNumber(t *testing.T) {
@@ -458,38 +453,15 @@ func TestBlockTree_Prune(t *testing.T) {
458453
}
459454
}
460455

461-
func TestBlockTree_PruneCache(t *testing.T) {
462-
var bt *BlockTree
463-
var branches []testBranch
464-
465-
for {
466-
bt, branches = createTestBlockTree(t, testHeader, 5)
467-
if len(branches) > 0 && len(bt.getNode(branches[0].hash).children) > 1 {
468-
break
469-
}
470-
}
471-
472-
// pick some block to finalise
473-
finalised := bt.root.children[0].children[0].children[0]
474-
pruned := bt.Prune(finalised.hash)
475-
476-
for _, prunedHash := range pruned {
477-
block, ok := bt.nodeCache[prunedHash]
478-
479-
require.False(t, ok)
480-
require.Nil(t, block)
481-
}
482-
}
483-
484456
func TestBlockTree_GetHashByNumber(t *testing.T) {
485457
bt, _ := createTestBlockTree(t, testHeader, 8)
486458
best := bt.DeepestBlockHash()
487-
bn := bt.nodeCache[best]
459+
bn := bt.getNode(best)
488460

489461
for i := int64(0); i < bn.number.Int64(); i++ {
490462
hash, err := bt.GetHashByNumber(big.NewInt(i))
491463
require.NoError(t, err)
492-
require.Equal(t, big.NewInt(i), bt.nodeCache[hash].number)
464+
require.Equal(t, big.NewInt(i), bt.getNode(hash).number)
493465
desc, err := bt.IsDescendantOf(hash, best)
494466
require.NoError(t, err)
495467
require.True(t, desc, fmt.Sprintf("index %d failed, got hash=%s", i, hash))
@@ -506,17 +478,6 @@ func TestBlockTree_DeepCopy(t *testing.T) {
506478
bt, _ := createFlatTree(t, 8)
507479

508480
btCopy := bt.DeepCopy()
509-
for hash := range bt.nodeCache {
510-
b, ok := btCopy.nodeCache[hash]
511-
b2 := bt.nodeCache[hash]
512-
513-
require.True(t, ok)
514-
require.True(t, b != b2)
515-
516-
require.True(t, equalNodeValue(b, b2))
517-
518-
}
519-
520481
require.True(t, equalNodeValue(bt.root, btCopy.root), "BlockTree heads not equal")
521482
require.True(t, equalLeaves(bt.leaves, btCopy.leaves), "BlockTree leaves not equal")
522483

lib/blocktree/leaves.go

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313

1414
// leafMap provides quick lookup for existing leaves
1515
type leafMap struct {
16+
sync.RWMutex
1617
smap *sync.Map // map[common.Hash]*node
1718
}
1819

@@ -24,21 +25,21 @@ func newEmptyLeafMap() *leafMap {
2425

2526
func newLeafMap(n *node) *leafMap {
2627
smap := &sync.Map{}
27-
for _, child := range n.getLeaves(nil) {
28-
smap.Store(child.hash, child)
28+
for _, leaf := range n.getLeaves(nil) {
29+
smap.Store(leaf.hash, leaf)
2930
}
3031

3132
return &leafMap{
3233
smap: smap,
3334
}
3435
}
3536

36-
func (ls *leafMap) store(key Hash, value *node) {
37-
ls.smap.Store(key, value)
37+
func (lm *leafMap) store(key Hash, value *node) {
38+
lm.smap.Store(key, value)
3839
}
3940

40-
func (ls *leafMap) load(key Hash) (*node, error) {
41-
v, ok := ls.smap.Load(key)
41+
func (lm *leafMap) load(key Hash) (*node, error) {
42+
v, ok := lm.smap.Load(key)
4243
if !ok {
4344
return nil, errors.New("key not found")
4445
}
@@ -47,18 +48,23 @@ func (ls *leafMap) load(key Hash) (*node, error) {
4748
}
4849

4950
// Replace deletes the old node from the map and inserts the new one
50-
func (ls *leafMap) replace(oldNode, newNode *node) {
51-
ls.smap.Delete(oldNode.hash)
52-
ls.store(newNode.hash, newNode)
51+
func (lm *leafMap) replace(oldNode, newNode *node) {
52+
lm.Lock()
53+
defer lm.Unlock()
54+
lm.smap.Delete(oldNode.hash)
55+
lm.store(newNode.hash, newNode)
5356
}
5457

5558
// DeepestLeaf searches the stored leaves to the find the one with the greatest number.
5659
// If there are two leaves with the same number, choose the one with the earliest arrival time.
57-
func (ls *leafMap) deepestLeaf() *node {
60+
func (lm *leafMap) deepestLeaf() *node {
61+
lm.RLock()
62+
defer lm.RUnlock()
63+
5864
max := big.NewInt(-1)
5965

6066
var dLeaf *node
61-
ls.smap.Range(func(h, n interface{}) bool {
67+
lm.smap.Range(func(h, n interface{}) bool {
6268
if n == nil {
6369
return true
6470
}
@@ -78,10 +84,13 @@ func (ls *leafMap) deepestLeaf() *node {
7884
return dLeaf
7985
}
8086

81-
func (ls *leafMap) toMap() map[common.Hash]*node {
87+
func (lm *leafMap) toMap() map[common.Hash]*node {
88+
lm.RLock()
89+
defer lm.RUnlock()
90+
8291
mmap := make(map[common.Hash]*node)
8392

84-
ls.smap.Range(func(h, n interface{}) bool {
93+
lm.smap.Range(func(h, n interface{}) bool {
8594
hash := h.(Hash)
8695
node := n.(*node)
8796
mmap[hash] = node
@@ -91,10 +100,13 @@ func (ls *leafMap) toMap() map[common.Hash]*node {
91100
return mmap
92101
}
93102

94-
func (ls *leafMap) nodes() []*node {
103+
func (lm *leafMap) nodes() []*node {
104+
lm.RLock()
105+
defer lm.RUnlock()
106+
95107
nodes := []*node{}
96108

97-
ls.smap.Range(func(h, n interface{}) bool {
109+
lm.smap.Range(func(h, n interface{}) bool {
98110
node := n.(*node)
99111
nodes = append(nodes, node)
100112
return true

0 commit comments

Comments
 (0)