-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathblock_finality_test.go
More file actions
153 lines (138 loc) · 3.81 KB
/
block_finality_test.go
File metadata and controls
153 lines (138 loc) · 3.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package main
import (
"strings"
"testing"
)
func TestEnforceReorgFinalityLocked_RejectsDeepReorg(t *testing.T) {
chain, _, cleanup := mustCreateTestChain(t)
defer cleanup()
mustAddGenesisBlock(t, chain)
chain.mu.Lock()
defer chain.mu.Unlock()
genesis := chain.getBlockByHeightLocked(0)
if genesis == nil {
t.Fatal("expected genesis block")
}
buildChild := func(parent *Block, height uint64) ([32]byte, *Block) {
block := &Block{
Header: BlockHeader{
Version: 1,
Height: height,
PrevHash: parent.Hash(),
Timestamp: parent.Header.Timestamp + BlockIntervalSec,
Difficulty: MinDifficulty,
},
}
hash := block.Hash()
chain.blocks[hash] = block
chain.workAt[hash] = height + 1
return hash, block
}
// Build main chain to height 105 (finalized boundary = 5).
mainByHeight := make(map[uint64][32]byte)
mainByHeight[0] = genesis.Hash()
parent := genesis
var mainTip [32]byte
for h := uint64(1); h <= 105; h++ {
hash, block := buildChild(parent, h)
chain.byHeight[h] = hash
mainByHeight[h] = hash
parent = block
mainTip = hash
}
chain.bestHash = mainTip
chain.height = 105
chain.totalWork = 106
// Build heavier fork from height 1, which crosses finalized boundary.
forkParent := chain.blocks[mainByHeight[1]]
var forkTip [32]byte
for h := uint64(2); h <= 107; h++ {
block := &Block{
Header: BlockHeader{
Version: 1,
Height: h,
PrevHash: forkParent.Hash(),
// Keep increasing time but skew by +1s so hashes diverge
// from the main-chain lineage at the fork point.
Timestamp: forkParent.Header.Timestamp + BlockIntervalSec + 1,
Difficulty: MinDifficulty,
},
}
hash := block.Hash()
chain.blocks[hash] = block
chain.workAt[hash] = h + 1
forkParent = block
forkTip = hash
}
err := chain.enforceReorgFinalityLocked(forkTip)
if err == nil {
t.Fatal("expected deep finalized reorg to be rejected")
}
if !strings.Contains(err.Error(), "reorg crosses finalized boundary") {
t.Fatalf("unexpected error: %v", err)
}
}
func TestEnforceReorgFinalityLocked_AllowsShallowReorg(t *testing.T) {
chain, _, cleanup := mustCreateTestChain(t)
defer cleanup()
mustAddGenesisBlock(t, chain)
chain.mu.Lock()
defer chain.mu.Unlock()
genesis := chain.getBlockByHeightLocked(0)
if genesis == nil {
t.Fatal("expected genesis block")
}
buildChild := func(parent *Block, height uint64) ([32]byte, *Block) {
block := &Block{
Header: BlockHeader{
Version: 1,
Height: height,
PrevHash: parent.Hash(),
Timestamp: parent.Header.Timestamp + BlockIntervalSec,
Difficulty: MinDifficulty,
},
}
hash := block.Hash()
chain.blocks[hash] = block
chain.workAt[hash] = height + 1
return hash, block
}
// Main chain height 105 (boundary = 5).
mainByHeight := make(map[uint64][32]byte)
mainByHeight[0] = genesis.Hash()
parent := genesis
var mainTip [32]byte
for h := uint64(1); h <= 105; h++ {
hash, block := buildChild(parent, h)
chain.byHeight[h] = hash
mainByHeight[h] = hash
parent = block
mainTip = hash
}
chain.bestHash = mainTip
chain.height = 105
chain.totalWork = 106
// Fork from height 10 (within reorg depth window), should be allowed.
forkParent := chain.blocks[mainByHeight[10]]
var forkTip [32]byte
for h := uint64(11); h <= 107; h++ {
block := &Block{
Header: BlockHeader{
Version: 1,
Height: h,
PrevHash: forkParent.Hash(),
// Diverge from main chain while staying monotonically increasing.
Timestamp: forkParent.Header.Timestamp + BlockIntervalSec + 1,
Difficulty: MinDifficulty,
},
}
hash := block.Hash()
chain.blocks[hash] = block
chain.workAt[hash] = h + 1
forkParent = block
forkTip = hash
}
if err := chain.enforceReorgFinalityLocked(forkTip); err != nil {
t.Fatalf("expected shallow reorg to be allowed, got: %v", err)
}
}