OSDN Git Service

feat(net/netsync/p2p/pow): Change network lib and remove pow (#1864)
[bytom/bytom.git] / protocol / state / blockindex_test.go
1 package state
2
3 import (
4         "math/big"
5         "reflect"
6         "testing"
7
8         "github.com/davecgh/go-spew/spew"
9
10         "github.com/bytom/bytom/consensus"
11         "github.com/bytom/bytom/protocol/bc"
12         "github.com/bytom/bytom/protocol/bc/types"
13         "github.com/bytom/bytom/testutil"
14 )
15
16 func stringToBigInt(s string, base int) *big.Int {
17         result, _ := new(big.Int).SetString(s, base)
18         return result
19 }
20
21 func TestNewBlockNode(t *testing.T) {
22         cases := []struct {
23                 blockHeader   *types.BlockHeader
24                 parentNode    *BlockNode
25                 wantBlockNode *BlockNode
26         }{
27                 {
28                         blockHeader: &types.BlockHeader{
29                                 Height:    uint64(0),
30                                 Timestamp: 0,
31                         },
32                         parentNode: &BlockNode{},
33                         wantBlockNode: &BlockNode{
34                                 Hash:   testutil.MustDecodeHash("f1a5a6ddebad7285928a07ce1534104a8d1cd435fc80e90bb9f0034bbe5f8109"),
35                                 Seed:   consensus.InitialSeed,
36                                 Parent: &BlockNode{},
37                         },
38                 },
39                 {
40                         blockHeader: &types.BlockHeader{
41                                 Height:    uint64(100),
42                                 Timestamp: 0,
43                         },
44                         parentNode: &BlockNode{},
45                         wantBlockNode: &BlockNode{
46                                 Hash:   testutil.MustDecodeHash("b14067726f09d74da89aeb97ca1b15a8b95760b47a0d71549b0aa5ab8c5e724f"),
47                                 Seed:   consensus.InitialSeed,
48                                 Height: uint64(100),
49                                 Parent: &BlockNode{},
50                         },
51                 },
52                 {
53                         blockHeader: &types.BlockHeader{
54                                 Height:    uint64(100),
55                                 Timestamp: 0,
56                         },
57                         parentNode: &BlockNode{},
58                         wantBlockNode: &BlockNode{
59                                 Hash:   testutil.MustDecodeHash("b14067726f09d74da89aeb97ca1b15a8b95760b47a0d71549b0aa5ab8c5e724f"),
60                                 Seed:   consensus.InitialSeed,
61                                 Height: uint64(100),
62                                 Parent: &BlockNode{},
63                         },
64                 },
65         }
66
67         for i, c := range cases {
68                 blockNode, err := NewBlockNode(c.blockHeader, c.parentNode)
69                 if err != nil {
70                         t.Fatal(err)
71                 }
72
73                 if !reflect.DeepEqual(blockNode, c.wantBlockNode) {
74                         t.Fatal("NewBlockNode test error, index:", i, "want:", spew.Sdump(c.wantBlockNode), "got:", spew.Sdump(blockNode))
75                 }
76         }
77 }
78
79 func TestCalcPastMedianTime(t *testing.T) {
80         cases := []struct {
81                 Timestamps []uint64
82                 MedianTime uint64
83         }{
84                 {
85                         Timestamps: []uint64{1},
86                         MedianTime: 1,
87                 },
88                 {
89                         Timestamps: []uint64{1, 2},
90                         MedianTime: 2,
91                 },
92                 {
93                         Timestamps: []uint64{1, 3, 2},
94                         MedianTime: 2,
95                 },
96                 {
97                         Timestamps: []uint64{1, 3, 2, 3},
98                         MedianTime: 3,
99                 },
100                 {
101                         Timestamps: []uint64{1, 2, 3, 4, 5, 6, 7, 8, 11, 10, 9},
102                         MedianTime: 6,
103                 },
104                 {
105                         Timestamps: []uint64{1, 2, 3, 4, 5, 6, 7, 8, 11, 10, 9, 11, 11, 11, 14},
106                         MedianTime: 10,
107                 },
108         }
109
110         for idx, c := range cases {
111                 var parentNode *BlockNode
112                 for i := range c.Timestamps {
113                         blockHeader := &types.BlockHeader{
114                                 Height:    uint64(i),
115                                 Timestamp: c.Timestamps[i],
116                         }
117
118                         blockNode, err := NewBlockNode(blockHeader, parentNode)
119                         if err != nil {
120                                 t.Fatal(err)
121                         }
122                         parentNode = blockNode
123                 }
124
125                 medianTime := parentNode.CalcPastMedianTime()
126                 if medianTime != c.MedianTime {
127                         t.Fatalf("calc median timestamp failed, index: %d, expected: %d, have: %d", idx, c.MedianTime, medianTime)
128                 }
129         }
130 }
131
132 func TestCalcNextSeed(t *testing.T) {
133         cases := []struct {
134                 node *BlockNode
135                 seed *bc.Hash
136         }{
137                 {
138                         node: &BlockNode{
139                                 Height: 0,
140                         },
141                         seed: consensus.InitialSeed,
142                 },
143                 {
144                         node: &BlockNode{
145                                 Height: consensus.SeedPerRetarget - 1,
146                                 Seed:   &bc.Hash{V1: 100},
147                         },
148                         seed: &bc.Hash{V1: 100},
149                 },
150                 {
151                         node: &BlockNode{
152                                 Height: consensus.SeedPerRetarget,
153                                 Seed:   &bc.Hash{V2: 200},
154                                 Hash:   bc.Hash{V3: 300},
155                         },
156                         seed: &bc.Hash{V3: 300},
157                 },
158         }
159
160         for i, c := range cases {
161                 seed := c.node.CalcNextSeed()
162                 if *seed != *c.seed {
163                         t.Fatalf("calc next seed failed, index: %d, expected: %v, have: %v", i, c.seed, seed)
164                 }
165         }
166 }
167
168 func TestSetMainChain(t *testing.T) {
169         blockIndex := NewBlockIndex()
170         var lastNode *BlockNode
171         for i := uint64(0); i < 4; i++ {
172                 node := &BlockNode{
173                         Height: i,
174                         Hash:   bc.Hash{V0: i},
175                         Parent: lastNode,
176                 }
177                 blockIndex.AddNode(node)
178                 lastNode = node
179         }
180
181         tailNode := lastNode
182         blockIndex.SetMainChain(lastNode)
183         for lastNode.Parent != nil {
184                 if !blockIndex.InMainchain(lastNode.Hash) {
185                         t.Fatalf("block %d, hash %v is not in main chain", lastNode.Height, lastNode.Hash)
186                 }
187                 lastNode = lastNode.Parent
188         }
189
190         // fork and set main chain
191         forkHeight := uint64(1)
192         lastNode = blockIndex.nodeByHeight(forkHeight)
193         for i := uint64(1); i <= 3; i++ {
194                 node := &BlockNode{
195                         Height: lastNode.Height + 1,
196                         Hash:   bc.Hash{V1: uint64(i)},
197                         Parent: lastNode,
198                 }
199                 blockIndex.AddNode(node)
200                 lastNode = node
201         }
202
203         bestNode := lastNode
204         blockIndex.SetMainChain(lastNode)
205         for lastNode.Parent != nil {
206                 if !blockIndex.InMainchain(lastNode.Hash) {
207                         t.Fatalf("after fork, block %d, hash %v is not in main chain", lastNode.Height, lastNode.Hash)
208                 }
209                 lastNode = lastNode.Parent
210         }
211
212         if bestNode != blockIndex.BestNode() {
213                 t.Fatalf("check best node failed")
214         }
215
216         for tailNode.Parent != nil && tailNode.Height > forkHeight {
217                 if blockIndex.InMainchain(tailNode.Hash) {
218                         t.Fatalf("old chain block %d, hash %v still in main chain", tailNode.Height, tailNode.Hash)
219                 }
220                 tailNode = tailNode.Parent
221         }
222 }
223
224 // MockBlockIndex will mock a empty BlockIndex
225 func MockBlockIndex() *BlockIndex {
226         return &BlockIndex{
227                 index:     make(map[bc.Hash]*BlockNode),
228                 mainChain: make([]*BlockNode, 0, 2),
229         }
230 }
231
232 func TestSetMainChainExtendCap(t *testing.T) {
233         blockIndex := MockBlockIndex()
234         var lastNode *BlockNode
235
236         cases := []struct {
237                 start   uint64
238                 stop    uint64
239                 wantLen int
240                 wantCap int
241         }{
242                 {
243                         start:   0,
244                         stop:    500,
245                         wantLen: 500,
246                         wantCap: 500 + approxNodesPerDay,
247                 },
248                 {
249                         start:   500,
250                         stop:    1000,
251                         wantLen: 1000,
252                         wantCap: 500 + approxNodesPerDay,
253                 },
254                 {
255                         start:   1000,
256                         stop:    2000,
257                         wantLen: 2000,
258                         wantCap: 2000 + approxNodesPerDay,
259                 },
260         }
261
262         for num, c := range cases {
263                 for i := c.start; i < c.stop; i++ {
264                         node := &BlockNode{
265                                 Height: i,
266                                 Hash:   bc.Hash{V0: i},
267                                 Parent: lastNode,
268                         }
269                         blockIndex.AddNode(node)
270                         lastNode = node
271                 }
272                 blockIndex.SetMainChain(lastNode)
273                 if c.wantLen != len(blockIndex.mainChain) || c.wantCap != cap(blockIndex.mainChain) {
274                         t.Fatalf("SetMainChain extended capacity error, index: %d, got len: %d, got cap: %d, want len: %d, want cap: %d", num, len(blockIndex.mainChain), cap(blockIndex.mainChain), c.wantLen, c.wantCap)
275                 }
276         }
277
278         for i := 0; i < len(blockIndex.mainChain); i++ {
279                 if blockIndex.mainChain[i] != blockIndex.index[blockIndex.mainChain[i].Hash] {
280                         t.Fatal("SetMainChain extended capacity error, index:", i, "want:", spew.Sdump(blockIndex.mainChain[i]), "got:", spew.Sdump(blockIndex.index[blockIndex.mainChain[i].Hash]))
281                 }
282         }
283 }