11 "github.com/vapor/consensus"
12 dbm "github.com/vapor/database/leveldb"
13 "github.com/vapor/errors"
14 "github.com/vapor/netsync/peers"
15 "github.com/vapor/protocol/bc"
16 "github.com/vapor/protocol/bc/types"
17 "github.com/vapor/test/mock"
18 "github.com/vapor/testutil"
21 func TestBlockLocator(t *testing.T) {
22 blocks := mockBlocks(nil, 500)
29 wantHeight: []uint64{0},
33 wantHeight: []uint64{1, 0},
37 wantHeight: []uint64{7, 6, 5, 4, 3, 2, 1, 0},
41 wantHeight: []uint64{10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
45 wantHeight: []uint64{100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 89, 85, 77, 61, 29, 0},
49 wantHeight: []uint64{500, 499, 498, 497, 496, 495, 494, 493, 492, 491, 489, 485, 477, 461, 429, 365, 237, 0},
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])
62 for _, i := range c.wantHeight {
63 hash := blocks[i].Hash()
64 want = append(want, &hash)
67 if got := fs.blockLocator(); !testutil.DeepEqual(got, want) {
68 t.Errorf("case %d: got %v want %v", i, got, want)
73 func TestFastBlockSync(t *testing.T) {
74 tmp, err := ioutil.TempDir(".", "")
76 t.Fatalf("failed to create temporary data folder: %v", err)
78 testDBA := dbm.NewDB("testdba", "leveldb", tmp)
79 testDBB := dbm.NewDB("testdbb", "leveldb", tmp)
86 maxSizeOfSyncSkeleton = 11
87 numOfBlocksSkeletonGap = 10
88 maxNumOfBlocksPerSync = numOfBlocksSkeletonGap * uint64(maxSizeOfSyncSkeleton-1)
89 fastSyncPivotGap = uint64(5)
90 minGapStartFastSync = uint64(6)
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
101 baseChain := mockBlocks(nil, 300)
104 syncTimeout time.Duration
105 aBlocks []*types.Block
106 bBlocks []*types.Block
111 syncTimeout: 30 * time.Second,
112 aBlocks: baseChain[:50],
113 bBlocks: baseChain[:301],
114 want: baseChain[:150],
118 syncTimeout: 30 * time.Second,
119 aBlocks: baseChain[:2],
120 bBlocks: baseChain[:300],
121 want: baseChain[:102],
125 syncTimeout: 30 * time.Second,
126 aBlocks: baseChain[:2],
127 bBlocks: baseChain[:53],
128 want: baseChain[:48],
132 syncTimeout: 30 * time.Second,
133 aBlocks: baseChain[:2],
134 bBlocks: baseChain[:53],
135 want: baseChain[:48],
139 syncTimeout: 30 * time.Second,
140 aBlocks: baseChain[:2],
141 bBlocks: baseChain[:10],
146 syncTimeout: 0 * time.Second,
147 aBlocks: baseChain[:50],
148 bBlocks: baseChain[:301],
149 want: baseChain[:50],
150 err: errSkeletonSize,
154 for i, c := range cases {
155 a := mockSync(c.aBlocks, nil, testDBA)
156 b := mockSync(c.bBlocks, nil, testDBB)
157 netWork := NewNetWork()
158 netWork.Register(a, "192.168.0.1", "test node A", consensus.SFFullNode|consensus.SFFastSync)
159 netWork.Register(b, "192.168.0.2", "test node B", consensus.SFFullNode|consensus.SFFastSync)
160 if B2A, A2B, err := netWork.HandsShake(a, b); err != nil {
161 t.Errorf("fail on peer hands shake %v", err)
166 a.blockKeeper.syncPeer = a.peers.GetPeer("test node B")
167 a.blockKeeper.fastSync.setSyncPeer(a.blockKeeper.syncPeer)
169 requireHeadersTimeout = c.syncTimeout
170 if err := a.blockKeeper.fastSync.process(); errors.Root(err) != c.err {
171 t.Errorf("case %d: got %v want %v", i, err, c.err)
174 got := []*types.Block{}
175 for i := uint64(0); i <= a.chain.BestBlockHeight(); i++ {
176 block, err := a.chain.GetBlockByHeight(i)
178 t.Errorf("case %d got err %v", i, err)
180 got = append(got, block)
182 if !testutil.DeepEqual(got, c.want) {
183 t.Errorf("case %d: got %v want %v", i, got, c.want)
188 type mockFetcher struct {
189 baseChain []*types.Block
190 peerStatus map[string][]*types.Block
195 func (mf *mockFetcher) resetParameter() {
199 func (mf *mockFetcher) addSyncPeer(peerID string) {
203 func (mf *mockFetcher) requireBlock(peerID string, height uint64) (*types.Block, error) {
207 func (mf *mockFetcher) parallelFetchBlocks(work []*fetchBlocksWork, downloadNotifyCh chan struct{}, ProcessStopCh chan struct{}, wg *sync.WaitGroup) {
211 func (mf *mockFetcher) parallelFetchHeaders(peers []*peers.Peer, locator []*bc.Hash, stopHash *bc.Hash, skip uint64) map[string][]*types.BlockHeader {
212 result := make(map[string][]*types.BlockHeader)
215 result["peer1"] = []*types.BlockHeader{&mf.peerStatus["peer1"][1000].BlockHeader, &mf.peerStatus["peer1"][1100].BlockHeader, &mf.peerStatus["peer1"][1200].BlockHeader,
216 &mf.peerStatus["peer1"][1300].BlockHeader, &mf.peerStatus["peer1"][1400].BlockHeader, &mf.peerStatus["peer1"][1500].BlockHeader,
217 &mf.peerStatus["peer1"][1600].BlockHeader, &mf.peerStatus["peer1"][1700].BlockHeader, &mf.peerStatus["peer1"][1800].BlockHeader,
219 result["peer2"] = []*types.BlockHeader{&mf.peerStatus["peer2"][1000].BlockHeader, &mf.peerStatus["peer2"][1100].BlockHeader, &mf.peerStatus["peer2"][1200].BlockHeader,
220 &mf.peerStatus["peer2"][1300].BlockHeader, &mf.peerStatus["peer2"][1400].BlockHeader, &mf.peerStatus["peer2"][1500].BlockHeader,
221 &mf.peerStatus["peer2"][1600].BlockHeader, &mf.peerStatus["peer2"][1700].BlockHeader, &mf.peerStatus["peer2"][1800].BlockHeader,
225 result["peer1"] = []*types.BlockHeader{}
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,
233 result["peer1"] = []*types.BlockHeader{&mf.peerStatus["peer1"][1000].BlockHeader, &mf.peerStatus["peer1"][1100].BlockHeader, &mf.peerStatus["peer1"][1200].BlockHeader,
234 &mf.peerStatus["peer1"][1300].BlockHeader, &mf.peerStatus["peer1"][1400].BlockHeader, &mf.peerStatus["peer1"][1500].BlockHeader,
235 &mf.peerStatus["peer1"][1600].BlockHeader, &mf.peerStatus["peer1"][1700].BlockHeader, &mf.peerStatus["peer1"][1800].BlockHeader,
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,
245 func TestCreateFetchBlocksTasks(t *testing.T) {
246 baseChain := mockBlocks(nil, 1000)
247 chainX := append(baseChain, mockBlocks(baseChain[1000], 2000)...)
248 chainY := append(baseChain, mockBlocks(baseChain[1000], 1900)...)
249 peerStatus := make(map[string][]*types.Block)
250 peerStatus["peer1"] = chainX
251 peerStatus["peer2"] = chainY
252 type syncPeer struct {
255 irreversibleHeight uint64
262 wantTasks []*fetchBlocksWork
268 {peer: &P2PPeer{id: "peer1", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 1000, irreversibleHeight: 1000},
269 {peer: &P2PPeer{id: "peer2", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 800, irreversibleHeight: 800},
271 mainSyncPeer: "peer1",
273 wantTasks: []*fetchBlocksWork{
274 {&chainX[1000].BlockHeader, &chainX[1100].BlockHeader}, {&chainX[1100].BlockHeader, &chainX[1200].BlockHeader},
275 {&chainX[1200].BlockHeader, &chainX[1300].BlockHeader}, {&chainX[1300].BlockHeader, &chainX[1400].BlockHeader},
276 {&chainX[1400].BlockHeader, &chainX[1500].BlockHeader}, {&chainX[1500].BlockHeader, &chainX[1600].BlockHeader},
277 {&chainX[1600].BlockHeader, &chainX[1700].BlockHeader}, {&chainX[1700].BlockHeader, &chainX[1800].BlockHeader},
283 peers: []*syncPeer{},
284 mainSyncPeer: "peer1",
287 wantErr: errNoSyncPeer,
289 // primary sync peer skeleton size error
292 {peer: &P2PPeer{id: "peer1", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 1000, irreversibleHeight: 1000},
293 {peer: &P2PPeer{id: "peer2", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 800, irreversibleHeight: 800},
295 mainSyncPeer: "peer1",
298 wantErr: errSkeletonSize,
300 // no skeleton return
303 {peer: &P2PPeer{id: "peer1", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 1000, irreversibleHeight: 1000},
304 {peer: &P2PPeer{id: "peer2", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 800, irreversibleHeight: 800},
306 mainSyncPeer: "peer1",
309 wantErr: errNoSkeletonFound,
311 // no main skeleton found
314 {peer: &P2PPeer{id: "peer1", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 1000, irreversibleHeight: 1000},
315 {peer: &P2PPeer{id: "peer2", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 800, irreversibleHeight: 800},
317 mainSyncPeer: "peer1",
320 wantErr: errNoMainSkeleton,
322 // skeleton length mismatch
325 {peer: &P2PPeer{id: "peer1", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 1000, irreversibleHeight: 1000},
326 {peer: &P2PPeer{id: "peer2", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 800, irreversibleHeight: 800},
328 mainSyncPeer: "peer1",
330 wantTasks: []*fetchBlocksWork{
331 {&chainX[1000].BlockHeader, &chainX[1100].BlockHeader}, {&chainX[1100].BlockHeader, &chainX[1200].BlockHeader},
332 {&chainX[1200].BlockHeader, &chainX[1300].BlockHeader}, {&chainX[1300].BlockHeader, &chainX[1400].BlockHeader},
333 {&chainX[1400].BlockHeader, &chainX[1500].BlockHeader}, {&chainX[1500].BlockHeader, &chainX[1600].BlockHeader},
334 {&chainX[1600].BlockHeader, &chainX[1700].BlockHeader}, {&chainX[1700].BlockHeader, &chainX[1800].BlockHeader},
340 for i, c := range cases {
341 peers := peers.NewPeerSet(NewPeerSet())
342 for _, syncPeer := range c.peers {
343 peers.AddPeer(syncPeer.peer)
344 peers.SetStatus(syncPeer.peer.id, syncPeer.bestHeight, nil)
345 peers.SetIrreversibleStatus(syncPeer.peer.id, syncPeer.irreversibleHeight, nil)
347 mockChain := mock.NewChain(nil)
348 fs := newFastSync(mockChain, &mockFetcher{baseChain: baseChain, peerStatus: peerStatus, testType: c.testType}, nil, peers)
349 fs.mainSyncPeer = fs.peers.GetPeer(c.mainSyncPeer)
350 tasks, err := fs.createFetchBlocksTasks(baseChain[700])
351 if err != c.wantErr {
352 t.Errorf("case %d: got %v want %v", i, err, c.wantErr)
354 if !reflect.DeepEqual(tasks, c.wantTasks) {
355 t.Errorf("case %d: got %v want %v", i, tasks, c.wantTasks)