OSDN Git Service

rename (#465)
[bytom/vapor.git] / netsync / chainmgr / fast_sync_test.go
1 package chainmgr
2
3 import (
4         "io/ioutil"
5         "os"
6         "reflect"
7         "sync"
8         "testing"
9         "time"
10
11         "github.com/bytom/vapor/consensus"
12         dbm "github.com/bytom/vapor/database/leveldb"
13         "github.com/bytom/vapor/errors"
14         "github.com/bytom/vapor/netsync/peers"
15         "github.com/bytom/vapor/protocol/bc"
16         "github.com/bytom/vapor/protocol/bc/types"
17         "github.com/bytom/vapor/test/mock"
18         "github.com/bytom/vapor/testutil"
19 )
20
21 func TestBlockLocator(t *testing.T) {
22         blocks := mockBlocks(nil, 500)
23         cases := []struct {
24                 bestHeight uint64
25                 wantHeight []uint64
26         }{
27                 {
28                         bestHeight: 0,
29                         wantHeight: []uint64{0},
30                 },
31                 {
32                         bestHeight: 1,
33                         wantHeight: []uint64{1, 0},
34                 },
35                 {
36                         bestHeight: 7,
37                         wantHeight: []uint64{7, 6, 5, 4, 3, 2, 1, 0},
38                 },
39                 {
40                         bestHeight: 10,
41                         wantHeight: []uint64{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
42                 },
43                 {
44                         bestHeight: 100,
45                         wantHeight: []uint64{100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 89, 85, 77, 61, 29, 0},
46                 },
47                 {
48                         bestHeight: 500,
49                         wantHeight: []uint64{500, 499, 498, 497, 496, 495, 494, 493, 492, 491, 489, 485, 477, 461, 429, 365, 237, 0},
50                 },
51         }
52
53         for i, c := range cases {
54                 mockChain := mock.NewChain(nil)
55                 fs := &fastSync{chain: mockChain}
56                 mockChain.SetBestBlockHeader(&blocks[c.bestHeight].BlockHeader)
57                 for i := uint64(0); i <= c.bestHeight; i++ {
58                         mockChain.SetBlockByHeight(i, blocks[i])
59                 }
60
61                 want := []*bc.Hash{}
62                 for _, i := range c.wantHeight {
63                         hash := blocks[i].Hash()
64                         want = append(want, &hash)
65                 }
66
67                 if got := fs.blockLocator(); !testutil.DeepEqual(got, want) {
68                         t.Errorf("case %d: got %v want %v", i, got, want)
69                 }
70         }
71 }
72
73 func TestFastBlockSync(t *testing.T) {
74         tmp, err := ioutil.TempDir(".", "")
75         if err != nil {
76                 t.Fatalf("failed to create temporary data folder: %v", err)
77         }
78         testDBA := dbm.NewDB("testdba", "leveldb", tmp)
79         testDBB := dbm.NewDB("testdbb", "leveldb", tmp)
80         defer func() {
81                 testDBA.Close()
82                 testDBB.Close()
83                 os.RemoveAll(tmp)
84         }()
85
86         maxSizeOfSyncSkeleton = 11
87         numOfBlocksSkeletonGap = 10
88         maxNumOfBlocksPerSync = numOfBlocksSkeletonGap * uint64(maxSizeOfSyncSkeleton-1)
89         fastSyncPivotGap = uint64(5)
90         minGapStartFastSync = uint64(6)
91
92         defer func() {
93                 maxSizeOfSyncSkeleton = 11
94                 numOfBlocksSkeletonGap = maxNumOfBlocksPerMsg
95                 maxNumOfBlocksPerSync = numOfBlocksSkeletonGap * uint64(maxSizeOfSyncSkeleton-1)
96                 fastSyncPivotGap = uint64(64)
97                 minGapStartFastSync = uint64(128)
98                 requireHeadersTimeout = 30 * time.Second
99         }()
100
101         baseChain := mockBlocks(nil, 300)
102         chainX := []*types.Block{}
103         chainX = append(chainX, baseChain[:30]...)
104         chainX = append(chainX, mockBlocks(baseChain[30], 500)...)
105         cases := []struct {
106                 syncTimeout time.Duration
107                 aBlocks     []*types.Block
108                 bBlocks     []*types.Block
109                 want        []*types.Block
110                 err         error
111         }{
112                 {
113                         syncTimeout: 30 * time.Second,
114                         aBlocks:     baseChain[:50],
115                         bBlocks:     baseChain[:301],
116                         want:        baseChain[:150],
117                         err:         nil,
118                 },
119                 {
120                         syncTimeout: 30 * time.Second,
121                         aBlocks:     baseChain[:2],
122                         bBlocks:     baseChain[:300],
123                         want:        baseChain[:102],
124                         err:         nil,
125                 },
126                 {
127                         syncTimeout: 30 * time.Second,
128                         aBlocks:     baseChain[:2],
129                         bBlocks:     baseChain[:53],
130                         want:        baseChain[:48],
131                         err:         nil,
132                 },
133                 {
134                         syncTimeout: 30 * time.Second,
135                         aBlocks:     baseChain[:2],
136                         bBlocks:     baseChain[:53],
137                         want:        baseChain[:48],
138                         err:         nil,
139                 },
140                 {
141                         syncTimeout: 30 * time.Second,
142                         aBlocks:     baseChain[:2],
143                         bBlocks:     baseChain[:10],
144                         want:        baseChain[:5],
145                         err:         nil,
146                 },
147                 {
148                         syncTimeout: 0 * time.Second,
149                         aBlocks:     baseChain[:50],
150                         bBlocks:     baseChain[:301],
151                         want:        baseChain[:50],
152                         err:         errSkeletonSize,
153                 },
154                 {
155                         syncTimeout: 30 * time.Second,
156                         aBlocks:     chainX[:50],
157                         bBlocks:     baseChain[:301],
158                         want:        baseChain[:128],
159                         err:         nil,
160                 },
161         }
162
163         for i, c := range cases {
164                 a := mockSync(c.aBlocks, nil, testDBA)
165                 b := mockSync(c.bBlocks, nil, testDBB)
166                 netWork := NewNetWork()
167                 netWork.Register(a, "192.168.0.1", "test node A", consensus.SFFullNode|consensus.SFFastSync)
168                 netWork.Register(b, "192.168.0.2", "test node B", consensus.SFFullNode|consensus.SFFastSync)
169                 if B2A, A2B, err := netWork.HandsShake(a, b); err != nil {
170                         t.Errorf("fail on peer hands shake %v", err)
171                 } else {
172                         go B2A.postMan()
173                         go A2B.postMan()
174                 }
175                 a.blockKeeper.syncPeer = a.peers.GetPeer("test node B")
176                 a.blockKeeper.fastSync.setSyncPeer(a.blockKeeper.syncPeer)
177
178                 requireHeadersTimeout = c.syncTimeout
179                 if err := a.blockKeeper.fastSync.process(); errors.Root(err) != c.err {
180                         t.Errorf("case %d: got %v want %v", i, err, c.err)
181                 }
182
183                 got := []*types.Block{}
184                 for i := uint64(0); i <= a.chain.BestBlockHeight(); i++ {
185                         block, err := a.chain.GetBlockByHeight(i)
186                         if err != nil {
187                                 t.Errorf("case %d got err %v", i, err)
188                         }
189                         got = append(got, block)
190                 }
191                 if !testutil.DeepEqual(got, c.want) {
192                         t.Errorf("case %d: got %v want %v", i, got, c.want)
193                 }
194         }
195 }
196
197 type mockFetcher struct {
198         baseChain  []*types.Block
199         peerStatus map[string][]*types.Block
200         peers      []string
201         testType   int
202 }
203
204 func (mf *mockFetcher) resetParameter() {
205         return
206 }
207
208 func (mf *mockFetcher) addSyncPeer(peerID string) {
209         return
210 }
211
212 func (mf *mockFetcher) requireBlock(peerID string, height uint64) (*types.Block, error) {
213         return nil, nil
214 }
215
216 func (mf *mockFetcher) parallelFetchBlocks(work []*fetchBlocksWork, downloadNotifyCh chan struct{}, ProcessStopCh chan struct{}, wg *sync.WaitGroup) {
217         return
218 }
219
220 func (mf *mockFetcher) parallelFetchHeaders(peers []*peers.Peer, locator []*bc.Hash, stopHash *bc.Hash, skip uint64) map[string][]*types.BlockHeader {
221         result := make(map[string][]*types.BlockHeader)
222         switch mf.testType {
223         case 1:
224                 result["peer1"] = []*types.BlockHeader{&mf.peerStatus["peer1"][1000].BlockHeader, &mf.peerStatus["peer1"][1100].BlockHeader, &mf.peerStatus["peer1"][1200].BlockHeader,
225                         &mf.peerStatus["peer1"][1300].BlockHeader, &mf.peerStatus["peer1"][1400].BlockHeader, &mf.peerStatus["peer1"][1500].BlockHeader,
226                         &mf.peerStatus["peer1"][1600].BlockHeader, &mf.peerStatus["peer1"][1700].BlockHeader, &mf.peerStatus["peer1"][1800].BlockHeader,
227                 }
228                 result["peer2"] = []*types.BlockHeader{&mf.peerStatus["peer2"][1000].BlockHeader, &mf.peerStatus["peer2"][1100].BlockHeader, &mf.peerStatus["peer2"][1200].BlockHeader,
229                         &mf.peerStatus["peer2"][1300].BlockHeader, &mf.peerStatus["peer2"][1400].BlockHeader, &mf.peerStatus["peer2"][1500].BlockHeader,
230                         &mf.peerStatus["peer2"][1600].BlockHeader, &mf.peerStatus["peer2"][1700].BlockHeader, &mf.peerStatus["peer2"][1800].BlockHeader,
231                 }
232
233         case 2:
234                 result["peer1"] = []*types.BlockHeader{}
235         case 3:
236         case 4:
237                 result["peer2"] = []*types.BlockHeader{&mf.peerStatus["peer2"][1000].BlockHeader, &mf.peerStatus["peer2"][1100].BlockHeader, &mf.peerStatus["peer2"][1200].BlockHeader,
238                         &mf.peerStatus["peer2"][1300].BlockHeader, &mf.peerStatus["peer2"][1400].BlockHeader, &mf.peerStatus["peer2"][1500].BlockHeader,
239                         &mf.peerStatus["peer2"][1600].BlockHeader, &mf.peerStatus["peer2"][1700].BlockHeader, &mf.peerStatus["peer2"][1800].BlockHeader,
240                 }
241         case 5:
242                 result["peer1"] = []*types.BlockHeader{&mf.peerStatus["peer1"][1000].BlockHeader, &mf.peerStatus["peer1"][1100].BlockHeader, &mf.peerStatus["peer1"][1200].BlockHeader,
243                         &mf.peerStatus["peer1"][1300].BlockHeader, &mf.peerStatus["peer1"][1400].BlockHeader, &mf.peerStatus["peer1"][1500].BlockHeader,
244                         &mf.peerStatus["peer1"][1600].BlockHeader, &mf.peerStatus["peer1"][1700].BlockHeader, &mf.peerStatus["peer1"][1800].BlockHeader,
245                 }
246                 result["peer2"] = []*types.BlockHeader{&mf.peerStatus["peer2"][1000].BlockHeader, &mf.peerStatus["peer2"][1100].BlockHeader, &mf.peerStatus["peer2"][1200].BlockHeader,
247                         &mf.peerStatus["peer2"][1300].BlockHeader, &mf.peerStatus["peer2"][1400].BlockHeader, &mf.peerStatus["peer2"][1500].BlockHeader,
248                         &mf.peerStatus["peer2"][1600].BlockHeader, &mf.peerStatus["peer2"][1700].BlockHeader,
249                 }
250         }
251         return result
252 }
253
254 func TestCreateFetchBlocksTasks(t *testing.T) {
255         baseChain := mockBlocks(nil, 1000)
256         chainX := append(baseChain, mockBlocks(baseChain[1000], 2000)...)
257         chainY := append(baseChain, mockBlocks(baseChain[1000], 1900)...)
258         peerStatus := make(map[string][]*types.Block)
259         peerStatus["peer1"] = chainX
260         peerStatus["peer2"] = chainY
261         type syncPeer struct {
262                 peer               *P2PPeer
263                 bestHeight         uint64
264                 irreversibleHeight uint64
265         }
266
267         cases := []struct {
268                 peers        []*syncPeer
269                 mainSyncPeer string
270                 testType     int
271                 wantTasks    []*fetchBlocksWork
272                 wantErr      error
273         }{
274                 // normal test
275                 {
276                         peers: []*syncPeer{
277                                 {peer: &P2PPeer{id: "peer1", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 1000, irreversibleHeight: 1000},
278                                 {peer: &P2PPeer{id: "peer2", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 800, irreversibleHeight: 800},
279                         },
280                         mainSyncPeer: "peer1",
281                         testType:     1,
282                         wantTasks: []*fetchBlocksWork{
283                                 {&chainX[1000].BlockHeader, &chainX[1100].BlockHeader}, {&chainX[1100].BlockHeader, &chainX[1200].BlockHeader},
284                                 {&chainX[1200].BlockHeader, &chainX[1300].BlockHeader}, {&chainX[1300].BlockHeader, &chainX[1400].BlockHeader},
285                                 {&chainX[1400].BlockHeader, &chainX[1500].BlockHeader}, {&chainX[1500].BlockHeader, &chainX[1600].BlockHeader},
286                                 {&chainX[1600].BlockHeader, &chainX[1700].BlockHeader}, {&chainX[1700].BlockHeader, &chainX[1800].BlockHeader},
287                         },
288                         wantErr: nil,
289                 },
290                 // test no sync peer
291                 {
292                         peers:        []*syncPeer{},
293                         mainSyncPeer: "peer1",
294                         testType:     0,
295                         wantTasks:    nil,
296                         wantErr:      errNoSyncPeer,
297                 },
298                 // primary sync peer skeleton size error
299                 {
300                         peers: []*syncPeer{
301                                 {peer: &P2PPeer{id: "peer1", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 1000, irreversibleHeight: 1000},
302                                 {peer: &P2PPeer{id: "peer2", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 800, irreversibleHeight: 800},
303                         },
304                         mainSyncPeer: "peer1",
305                         testType:     2,
306                         wantTasks:    nil,
307                         wantErr:      errSkeletonSize,
308                 },
309                 // no skeleton return
310                 {
311                         peers: []*syncPeer{
312                                 {peer: &P2PPeer{id: "peer1", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 1000, irreversibleHeight: 1000},
313                                 {peer: &P2PPeer{id: "peer2", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 800, irreversibleHeight: 800},
314                         },
315                         mainSyncPeer: "peer1",
316                         testType:     3,
317                         wantTasks:    nil,
318                         wantErr:      errNoSkeletonFound,
319                 },
320                 // no main skeleton found
321                 {
322                         peers: []*syncPeer{
323                                 {peer: &P2PPeer{id: "peer1", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 1000, irreversibleHeight: 1000},
324                                 {peer: &P2PPeer{id: "peer2", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 800, irreversibleHeight: 800},
325                         },
326                         mainSyncPeer: "peer1",
327                         testType:     4,
328                         wantTasks:    nil,
329                         wantErr:      errNoMainSkeleton,
330                 },
331                 // skeleton length mismatch
332                 {
333                         peers: []*syncPeer{
334                                 {peer: &P2PPeer{id: "peer1", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 1000, irreversibleHeight: 1000},
335                                 {peer: &P2PPeer{id: "peer2", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 800, irreversibleHeight: 800},
336                         },
337                         mainSyncPeer: "peer1",
338                         testType:     5,
339                         wantTasks: []*fetchBlocksWork{
340                                 {&chainX[1000].BlockHeader, &chainX[1100].BlockHeader}, {&chainX[1100].BlockHeader, &chainX[1200].BlockHeader},
341                                 {&chainX[1200].BlockHeader, &chainX[1300].BlockHeader}, {&chainX[1300].BlockHeader, &chainX[1400].BlockHeader},
342                                 {&chainX[1400].BlockHeader, &chainX[1500].BlockHeader}, {&chainX[1500].BlockHeader, &chainX[1600].BlockHeader},
343                                 {&chainX[1600].BlockHeader, &chainX[1700].BlockHeader}, {&chainX[1700].BlockHeader, &chainX[1800].BlockHeader},
344                         },
345                         wantErr: nil,
346                 },
347         }
348
349         for i, c := range cases {
350                 peers := peers.NewPeerSet(NewPeerSet())
351                 for _, syncPeer := range c.peers {
352                         peers.AddPeer(syncPeer.peer)
353                         peers.SetStatus(syncPeer.peer.id, syncPeer.bestHeight, nil)
354                         peers.SetIrreversibleStatus(syncPeer.peer.id, syncPeer.irreversibleHeight, nil)
355                 }
356                 mockChain := mock.NewChain(nil)
357                 fs := newFastSync(mockChain, &mockFetcher{baseChain: baseChain, peerStatus: peerStatus, testType: c.testType}, nil, peers)
358                 fs.mainSyncPeer = fs.peers.GetPeer(c.mainSyncPeer)
359                 tasks, err := fs.createFetchBlocksTasks(baseChain[700])
360                 if err != c.wantErr {
361                         t.Errorf("case %d: got %v want %v", i, err, c.wantErr)
362                 }
363                 if !reflect.DeepEqual(tasks, c.wantTasks) {
364                         t.Errorf("case %d: got %v want %v", i, tasks, c.wantTasks)
365                 }
366         }
367 }