OSDN Git Service

fa3b6ffae7753db474bc8fd73bfae92acef9211a
[bytom/bytom.git] / netsync / block_keeper_test.go
1 package netsync
2
3 import (
4         "container/list"
5         "testing"
6         "time"
7
8         "github.com/bytom/consensus"
9         "github.com/bytom/errors"
10         "github.com/bytom/protocol/bc"
11         "github.com/bytom/protocol/bc/types"
12         "github.com/bytom/test/mock"
13         "github.com/bytom/testutil"
14 )
15
16 func TestAppendHeaderList(t *testing.T) {
17         blocks := mockBlocks(nil, 7)
18         cases := []struct {
19                 originalHeaders []*types.BlockHeader
20                 inputHeaders    []*types.BlockHeader
21                 wantHeaders     []*types.BlockHeader
22                 err             error
23         }{
24                 {
25                         originalHeaders: []*types.BlockHeader{&blocks[0].BlockHeader},
26                         inputHeaders:    []*types.BlockHeader{&blocks[1].BlockHeader, &blocks[2].BlockHeader},
27                         wantHeaders:     []*types.BlockHeader{&blocks[0].BlockHeader, &blocks[1].BlockHeader, &blocks[2].BlockHeader},
28                         err:             nil,
29                 },
30                 {
31                         originalHeaders: []*types.BlockHeader{&blocks[5].BlockHeader},
32                         inputHeaders:    []*types.BlockHeader{&blocks[6].BlockHeader},
33                         wantHeaders:     []*types.BlockHeader{&blocks[5].BlockHeader, &blocks[6].BlockHeader},
34                         err:             nil,
35                 },
36                 {
37                         originalHeaders: []*types.BlockHeader{&blocks[5].BlockHeader},
38                         inputHeaders:    []*types.BlockHeader{&blocks[7].BlockHeader},
39                         wantHeaders:     []*types.BlockHeader{&blocks[5].BlockHeader},
40                         err:             errAppendHeaders,
41                 },
42                 {
43                         originalHeaders: []*types.BlockHeader{&blocks[5].BlockHeader},
44                         inputHeaders:    []*types.BlockHeader{&blocks[7].BlockHeader, &blocks[6].BlockHeader},
45                         wantHeaders:     []*types.BlockHeader{&blocks[5].BlockHeader},
46                         err:             errAppendHeaders,
47                 },
48                 {
49                         originalHeaders: []*types.BlockHeader{&blocks[2].BlockHeader},
50                         inputHeaders:    []*types.BlockHeader{&blocks[3].BlockHeader, &blocks[4].BlockHeader, &blocks[6].BlockHeader},
51                         wantHeaders:     []*types.BlockHeader{&blocks[2].BlockHeader, &blocks[3].BlockHeader, &blocks[4].BlockHeader},
52                         err:             errAppendHeaders,
53                 },
54         }
55
56         for i, c := range cases {
57                 bk := &blockKeeper{headerList: list.New()}
58                 for _, header := range c.originalHeaders {
59                         bk.headerList.PushBack(header)
60                 }
61
62                 if err := bk.appendHeaderList(c.inputHeaders); err != c.err {
63                         t.Errorf("case %d: got error %v want error %v", i, err, c.err)
64                 }
65
66                 gotHeaders := []*types.BlockHeader{}
67                 for e := bk.headerList.Front(); e != nil; e = e.Next() {
68                         gotHeaders = append(gotHeaders, e.Value.(*types.BlockHeader))
69                 }
70
71                 if !testutil.DeepEqual(gotHeaders, c.wantHeaders) {
72                         t.Errorf("case %d: got %v want %v", i, gotHeaders, c.wantHeaders)
73                 }
74         }
75 }
76
77 func TestBlockLocator(t *testing.T) {
78         blocks := mockBlocks(nil, 500)
79         cases := []struct {
80                 bestHeight uint64
81                 wantHeight []uint64
82         }{
83                 {
84                         bestHeight: 0,
85                         wantHeight: []uint64{0},
86                 },
87                 {
88                         bestHeight: 1,
89                         wantHeight: []uint64{1, 0},
90                 },
91                 {
92                         bestHeight: 7,
93                         wantHeight: []uint64{7, 6, 5, 4, 3, 2, 1, 0},
94                 },
95                 {
96                         bestHeight: 10,
97                         wantHeight: []uint64{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
98                 },
99                 {
100                         bestHeight: 100,
101                         wantHeight: []uint64{100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 89, 85, 77, 61, 29, 0},
102                 },
103                 {
104                         bestHeight: 500,
105                         wantHeight: []uint64{500, 499, 498, 497, 496, 495, 494, 493, 492, 491, 489, 485, 477, 461, 429, 365, 237, 0},
106                 },
107         }
108
109         for i, c := range cases {
110                 mockChain := mock.NewChain()
111                 bk := &blockKeeper{chain: mockChain}
112                 mockChain.SetBestBlockHeader(&blocks[c.bestHeight].BlockHeader)
113                 for i := uint64(0); i <= c.bestHeight; i++ {
114                         mockChain.SetBlockByHeight(i, blocks[i])
115                 }
116
117                 want := []*bc.Hash{}
118                 for _, i := range c.wantHeight {
119                         hash := blocks[i].Hash()
120                         want = append(want, &hash)
121                 }
122
123                 if got := bk.blockLocator(); !testutil.DeepEqual(got, want) {
124                         t.Errorf("case %d: got %v want %v", i, got, want)
125                 }
126         }
127 }
128
129 func TestFastBlockSync(t *testing.T) {
130         maxBlockPerMsg = 5
131         maxBlockHeadersPerMsg = 10
132         baseChain := mockBlocks(nil, 300)
133
134         cases := []struct {
135                 syncTimeout time.Duration
136                 aBlocks     []*types.Block
137                 bBlocks     []*types.Block
138                 checkPoint  *consensus.Checkpoint
139                 want        []*types.Block
140                 err         error
141         }{
142                 {
143                         syncTimeout: 30 * time.Second,
144                         aBlocks:     baseChain[:100],
145                         bBlocks:     baseChain[:301],
146                         checkPoint: &consensus.Checkpoint{
147                                 Height: baseChain[250].Height,
148                                 Hash:   baseChain[250].Hash(),
149                         },
150                         want: baseChain[:251],
151                         err:  nil,
152                 },
153                 {
154                         syncTimeout: 30 * time.Second,
155                         aBlocks:     baseChain[:100],
156                         bBlocks:     baseChain[:301],
157                         checkPoint: &consensus.Checkpoint{
158                                 Height: baseChain[100].Height,
159                                 Hash:   baseChain[100].Hash(),
160                         },
161                         want: baseChain[:101],
162                         err:  nil,
163                 },
164                 {
165                         syncTimeout: 1 * time.Millisecond,
166                         aBlocks:     baseChain[:100],
167                         bBlocks:     baseChain[:100],
168                         checkPoint: &consensus.Checkpoint{
169                                 Height: baseChain[200].Height,
170                                 Hash:   baseChain[200].Hash(),
171                         },
172                         want: baseChain[:100],
173                         err:  errRequestTimeout,
174                 },
175         }
176
177         for i, c := range cases {
178                 syncTimeout = c.syncTimeout
179                 a := mockSync(c.aBlocks)
180                 b := mockSync(c.bBlocks)
181                 netWork := NewNetWork()
182                 netWork.Register(a, "192.168.0.1", "test node A", consensus.SFFullNode)
183                 netWork.Register(b, "192.168.0.2", "test node B", consensus.SFFullNode)
184                 if err := netWork.HandsShake(a, b); err != nil {
185                         t.Errorf("fail on peer hands shake %v", err)
186                 }
187
188                 a.blockKeeper.syncPeer = a.peers.getPeer("test node B")
189                 if err := a.blockKeeper.fastBlockSync(c.checkPoint); errors.Root(err) != c.err {
190                         t.Errorf("case %d: got %v want %v", i, err, c.err)
191                 }
192
193                 got := []*types.Block{}
194                 for i := uint64(0); i <= a.chain.BestBlockHeight(); i++ {
195                         block, err := a.chain.GetBlockByHeight(i)
196                         if err != nil {
197                                 t.Errorf("case %d got err %v", i, err)
198                         }
199                         got = append(got, block)
200                 }
201
202                 if !testutil.DeepEqual(got, c.want) {
203                         t.Errorf("case %d: got %v want %v", i, got, c.want)
204                 }
205         }
206 }
207
208 func TestLocateBlocks(t *testing.T) {
209         maxBlockPerMsg = 5
210         blocks := mockBlocks(nil, 100)
211         cases := []struct {
212                 locator    []uint64
213                 stopHash   bc.Hash
214                 wantHeight []uint64
215         }{
216                 {
217                         locator:    []uint64{20},
218                         stopHash:   blocks[100].Hash(),
219                         wantHeight: []uint64{21, 22, 23, 24, 25},
220                 },
221         }
222
223         mockChain := mock.NewChain()
224         bk := &blockKeeper{chain: mockChain}
225         for _, block := range blocks {
226                 mockChain.SetBlockByHeight(block.Height, block)
227         }
228
229         for i, c := range cases {
230                 locator := []*bc.Hash{}
231                 for _, i := range c.locator {
232                         hash := blocks[i].Hash()
233                         locator = append(locator, &hash)
234                 }
235
236                 want := []*types.Block{}
237                 for _, i := range c.wantHeight {
238                         want = append(want, blocks[i])
239                 }
240
241                 got, _ := bk.locateBlocks(locator, &c.stopHash)
242                 if !testutil.DeepEqual(got, want) {
243                         t.Errorf("case %d: got %v want %v", i, got, want)
244                 }
245         }
246 }
247
248 func TestLocateHeaders(t *testing.T) {
249         maxBlockHeadersPerMsg = 10
250         blocks := mockBlocks(nil, 150)
251         cases := []struct {
252                 chainHeight uint64
253                 locator     []uint64
254                 stopHash    bc.Hash
255                 wantHeight  []uint64
256                 err         bool
257         }{
258                 {
259                         chainHeight: 100,
260                         locator:     []uint64{},
261                         stopHash:    blocks[100].Hash(),
262                         wantHeight:  []uint64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
263                         err:         false,
264                 },
265                 {
266                         chainHeight: 100,
267                         locator:     []uint64{20},
268                         stopHash:    blocks[100].Hash(),
269                         wantHeight:  []uint64{21, 22, 23, 24, 25, 26, 27, 28, 29, 30},
270                         err:         false,
271                 },
272                 {
273                         chainHeight: 100,
274                         locator:     []uint64{20},
275                         stopHash:    blocks[24].Hash(),
276                         wantHeight:  []uint64{21, 22, 23, 24},
277                         err:         false,
278                 },
279                 {
280                         chainHeight: 100,
281                         locator:     []uint64{20},
282                         stopHash:    blocks[20].Hash(),
283                         wantHeight:  []uint64{},
284                         err:         false,
285                 },
286                 {
287                         chainHeight: 100,
288                         locator:     []uint64{20},
289                         stopHash:    bc.Hash{},
290                         wantHeight:  []uint64{},
291                         err:         true,
292                 },
293                 {
294                         chainHeight: 100,
295                         locator:     []uint64{120, 70},
296                         stopHash:    blocks[78].Hash(),
297                         wantHeight:  []uint64{71, 72, 73, 74, 75, 76, 77, 78},
298                         err:         false,
299                 },
300         }
301
302         for i, c := range cases {
303                 mockChain := mock.NewChain()
304                 bk := &blockKeeper{chain: mockChain}
305                 for i := uint64(0); i <= c.chainHeight; i++ {
306                         mockChain.SetBlockByHeight(i, blocks[i])
307                 }
308
309                 locator := []*bc.Hash{}
310                 for _, i := range c.locator {
311                         hash := blocks[i].Hash()
312                         locator = append(locator, &hash)
313                 }
314
315                 want := []*types.BlockHeader{}
316                 for _, i := range c.wantHeight {
317                         want = append(want, &blocks[i].BlockHeader)
318                 }
319
320                 got, err := bk.locateHeaders(locator, &c.stopHash)
321                 if err != nil != c.err {
322                         t.Errorf("case %d: got %v want err = %v", i, err, c.err)
323                 }
324                 if !testutil.DeepEqual(got, want) {
325                         t.Errorf("case %d: got %v want %v", i, got, want)
326                 }
327         }
328 }
329
330 func TestNextCheckpoint(t *testing.T) {
331         cases := []struct {
332                 checkPoints []consensus.Checkpoint
333                 bestHeight  uint64
334                 want        *consensus.Checkpoint
335         }{
336                 {
337                         checkPoints: []consensus.Checkpoint{},
338                         bestHeight:  5000,
339                         want:        nil,
340                 },
341                 {
342                         checkPoints: []consensus.Checkpoint{
343                                 {10000, bc.Hash{V0: 1}},
344                         },
345                         bestHeight: 5000,
346                         want:       &consensus.Checkpoint{10000, bc.Hash{V0: 1}},
347                 },
348                 {
349                         checkPoints: []consensus.Checkpoint{
350                                 {10000, bc.Hash{V0: 1}},
351                                 {20000, bc.Hash{V0: 2}},
352                                 {30000, bc.Hash{V0: 3}},
353                         },
354                         bestHeight: 15000,
355                         want:       &consensus.Checkpoint{20000, bc.Hash{V0: 2}},
356                 },
357                 {
358                         checkPoints: []consensus.Checkpoint{
359                                 {10000, bc.Hash{V0: 1}},
360                                 {20000, bc.Hash{V0: 2}},
361                                 {30000, bc.Hash{V0: 3}},
362                         },
363                         bestHeight: 10000,
364                         want:       &consensus.Checkpoint{20000, bc.Hash{V0: 2}},
365                 },
366                 {
367                         checkPoints: []consensus.Checkpoint{
368                                 {10000, bc.Hash{V0: 1}},
369                                 {20000, bc.Hash{V0: 2}},
370                                 {30000, bc.Hash{V0: 3}},
371                         },
372                         bestHeight: 35000,
373                         want:       nil,
374                 },
375         }
376
377         mockChain := mock.NewChain()
378         for i, c := range cases {
379                 consensus.ActiveNetParams.Checkpoints = c.checkPoints
380                 mockChain.SetBestBlockHeader(&types.BlockHeader{Height: c.bestHeight})
381                 bk := &blockKeeper{chain: mockChain}
382
383                 if got := bk.nextCheckpoint(); !testutil.DeepEqual(got, c.want) {
384                         t.Errorf("case %d: got %v want %v", i, got, c.want)
385                 }
386         }
387 }
388
389 func TestRegularBlockSync(t *testing.T) {
390         baseChain := mockBlocks(nil, 50)
391         chainX := append(baseChain, mockBlocks(baseChain[50], 60)...)
392         chainY := append(baseChain, mockBlocks(baseChain[50], 70)...)
393         cases := []struct {
394                 syncTimeout time.Duration
395                 aBlocks     []*types.Block
396                 bBlocks     []*types.Block
397                 syncHeight  uint64
398                 want        []*types.Block
399                 err         error
400         }{
401                 {
402                         syncTimeout: 30 * time.Second,
403                         aBlocks:     baseChain[:20],
404                         bBlocks:     baseChain[:50],
405                         syncHeight:  45,
406                         want:        baseChain[:46],
407                         err:         nil,
408                 },
409                 {
410                         syncTimeout: 30 * time.Second,
411                         aBlocks:     chainX,
412                         bBlocks:     chainY,
413                         syncHeight:  70,
414                         want:        chainY,
415                         err:         nil,
416                 },
417                 {
418                         syncTimeout: 30 * time.Second,
419                         aBlocks:     chainX[:52],
420                         bBlocks:     chainY[:53],
421                         syncHeight:  52,
422                         want:        chainY[:53],
423                         err:         nil,
424                 },
425                 {
426                         syncTimeout: 1 * time.Millisecond,
427                         aBlocks:     baseChain,
428                         bBlocks:     baseChain,
429                         syncHeight:  52,
430                         want:        baseChain,
431                         err:         errRequestTimeout,
432                 },
433         }
434
435         for i, c := range cases {
436                 syncTimeout = c.syncTimeout
437                 a := mockSync(c.aBlocks)
438                 b := mockSync(c.bBlocks)
439                 netWork := NewNetWork()
440                 netWork.Register(a, "192.168.0.1", "test node A", consensus.SFFullNode)
441                 netWork.Register(b, "192.168.0.2", "test node B", consensus.SFFullNode)
442                 if err := netWork.HandsShake(a, b); err != nil {
443                         t.Errorf("fail on peer hands shake %v", err)
444                 }
445
446                 a.blockKeeper.syncPeer = a.peers.getPeer("test node B")
447                 if err := a.blockKeeper.regularBlockSync(c.syncHeight); errors.Root(err) != c.err {
448                         t.Errorf("case %d: got %v want %v", i, err, c.err)
449                 }
450
451                 got := []*types.Block{}
452                 for i := uint64(0); i <= a.chain.BestBlockHeight(); i++ {
453                         block, err := a.chain.GetBlockByHeight(i)
454                         if err != nil {
455                                 t.Errorf("case %d got err %v", i, err)
456                         }
457                         got = append(got, block)
458                 }
459
460                 if !testutil.DeepEqual(got, c.want) {
461                         t.Errorf("case %d: got %v want %v", i, got, c.want)
462                 }
463         }
464 }
465
466 func TestRequireBlock(t *testing.T) {
467         blocks := mockBlocks(nil, 5)
468         a := mockSync(blocks[:1])
469         b := mockSync(blocks[:5])
470         netWork := NewNetWork()
471         netWork.Register(a, "192.168.0.1", "test node A", consensus.SFFullNode)
472         netWork.Register(b, "192.168.0.2", "test node B", consensus.SFFullNode)
473         if err := netWork.HandsShake(a, b); err != nil {
474                 t.Errorf("fail on peer hands shake %v", err)
475         }
476
477         a.blockKeeper.syncPeer = a.peers.getPeer("test node B")
478         b.blockKeeper.syncPeer = b.peers.getPeer("test node A")
479         cases := []struct {
480                 syncTimeout   time.Duration
481                 testNode      *SyncManager
482                 requireHeight uint64
483                 want          *types.Block
484                 err           error
485         }{
486                 {
487                         syncTimeout:   30 * time.Second,
488                         testNode:      a,
489                         requireHeight: 4,
490                         want:          blocks[4],
491                         err:           nil,
492                 },
493                 {
494                         syncTimeout:   1 * time.Millisecond,
495                         testNode:      b,
496                         requireHeight: 4,
497                         want:          nil,
498                         err:           errRequestTimeout,
499                 },
500         }
501
502         for i, c := range cases {
503                 syncTimeout = c.syncTimeout
504                 got, err := c.testNode.blockKeeper.requireBlock(c.requireHeight)
505                 if !testutil.DeepEqual(got, c.want) {
506                         t.Errorf("case %d: got %v want %v", i, got, c.want)
507                 }
508                 if errors.Root(err) != c.err {
509                         t.Errorf("case %d: got %v want %v", i, err, c.err)
510                 }
511         }
512 }