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  }