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"
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)
102 chainX := []*types.Block{}
103 chainX = append(chainX, baseChain[:30]...)
104 chainX = append(chainX, mockBlocks(baseChain[30], 500)...)
106 syncTimeout time.Duration
107 aBlocks []*types.Block
108 bBlocks []*types.Block
113 syncTimeout: 30 * time.Second,
114 aBlocks: baseChain[:50],
115 bBlocks: baseChain[:301],
116 want: baseChain[:150],
120 syncTimeout: 30 * time.Second,
121 aBlocks: baseChain[:2],
122 bBlocks: baseChain[:300],
123 want: baseChain[:102],
127 syncTimeout: 30 * time.Second,
128 aBlocks: baseChain[:2],
129 bBlocks: baseChain[:53],
130 want: baseChain[:48],
134 syncTimeout: 30 * time.Second,
135 aBlocks: baseChain[:2],
136 bBlocks: baseChain[:53],
137 want: baseChain[:48],
141 syncTimeout: 30 * time.Second,
142 aBlocks: baseChain[:2],
143 bBlocks: baseChain[:10],
148 syncTimeout: 0 * time.Second,
149 aBlocks: baseChain[:50],
150 bBlocks: baseChain[:301],
151 want: baseChain[:50],
152 err: errSkeletonSize,
155 syncTimeout: 30 * time.Second,
156 aBlocks: chainX[:50],
157 bBlocks: baseChain[:301],
158 want: baseChain[:128],
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)
175 a.blockKeeper.syncPeer = a.peers.GetPeer("test node B")
176 a.blockKeeper.fastSync.setSyncPeer(a.blockKeeper.syncPeer)
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)
183 got := []*types.Block{}
184 for i := uint64(0); i <= a.chain.BestBlockHeight(); i++ {
185 block, err := a.chain.GetBlockByHeight(i)
187 t.Errorf("case %d got err %v", i, err)
189 got = append(got, block)
191 if !testutil.DeepEqual(got, c.want) {
192 t.Errorf("case %d: got %v want %v", i, got, c.want)
197 type mockFetcher struct {
198 baseChain []*types.Block
199 peerStatus map[string][]*types.Block
204 func (mf *mockFetcher) resetParameter() {
208 func (mf *mockFetcher) addSyncPeer(peerID string) {
212 func (mf *mockFetcher) requireBlock(peerID string, height uint64) (*types.Block, error) {
216 func (mf *mockFetcher) parallelFetchBlocks(work []*fetchBlocksWork, downloadNotifyCh chan struct{}, ProcessStopCh chan struct{}, wg *sync.WaitGroup) {
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)
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,
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,
234 result["peer1"] = []*types.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, &mf.peerStatus["peer2"][1800].BlockHeader,
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,
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,
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 {
264 irreversibleHeight uint64
271 wantTasks []*fetchBlocksWork
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},
280 mainSyncPeer: "peer1",
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},
292 peers: []*syncPeer{},
293 mainSyncPeer: "peer1",
296 wantErr: errNoSyncPeer,
298 // primary sync peer skeleton size error
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},
304 mainSyncPeer: "peer1",
307 wantErr: errSkeletonSize,
309 // no skeleton return
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},
315 mainSyncPeer: "peer1",
318 wantErr: errNoSkeletonFound,
320 // no main skeleton found
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},
326 mainSyncPeer: "peer1",
329 wantErr: errNoMainSkeleton,
331 // skeleton length mismatch
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},
337 mainSyncPeer: "peer1",
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},
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)
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)
363 if !reflect.DeepEqual(tasks, c.wantTasks) {
364 t.Errorf("case %d: got %v want %v", i, tasks, c.wantTasks)