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