From: yahtoo Date: Tue, 30 Jul 2019 02:58:00 +0000 (+0800) Subject: netsync add test case (#365) X-Git-Tag: v1.0.5~69 X-Git-Url: http://git.osdn.net/view?p=bytom%2Fvapor.git;a=commitdiff_plain;h=669d176c004324fe81a26261a6e41ddea95b6f17;hp=bc213b29d91743bb9cb23c043f2856f47b34bb3e;ds=sidebyside netsync add test case (#365) --- diff --git a/netsync/chainmgr/block_keeper.go b/netsync/chainmgr/block_keeper.go index b810a1a5..80c12779 100644 --- a/netsync/chainmgr/block_keeper.go +++ b/netsync/chainmgr/block_keeper.go @@ -112,7 +112,7 @@ func (bk *blockKeeper) locateHeaders(locator []*bc.Hash, stopHash *bc.Hash, skip headers := make([]*types.BlockHeader, 0) stopHeader, err := bk.chain.GetHeaderByHash(stopHash) if err != nil { - return headers, nil + return headers, err } if !bk.chain.InMainChain(*stopHash) || stopHeader.Height < startHeader.Height { @@ -191,16 +191,13 @@ func (bk *blockKeeper) start() { } func (bk *blockKeeper) checkSyncType() int { - peer := bk.peers.BestIrreversiblePeer(consensus.SFFullNode | consensus.SFFastSync) - if peer == nil { - log.WithFields(log.Fields{"module": logModule}).Debug("can't find fast sync peer") - return noNeedSync - } - bestHeight := bk.chain.BestBlockHeight() - if peerIrreversibleHeight := peer.IrreversibleHeight(); peerIrreversibleHeight >= bestHeight+minGapStartFastSync { - bk.fastSync.setSyncPeer(peer) - return fastSyncType + peer := bk.peers.BestIrreversiblePeer(consensus.SFFullNode | consensus.SFFastSync) + if peer != nil { + if peerIrreversibleHeight := peer.IrreversibleHeight(); peerIrreversibleHeight >= bestHeight+minGapStartFastSync { + bk.fastSync.setSyncPeer(peer) + return fastSyncType + } } peer = bk.peers.BestPeer(consensus.SFFullNode) @@ -209,8 +206,7 @@ func (bk *blockKeeper) checkSyncType() int { return noNeedSync } - peerHeight := peer.Height() - if peerHeight > bestHeight { + if peer.Height() > bestHeight { bk.syncPeer = peer return regularSyncType } @@ -230,6 +226,8 @@ func (bk *blockKeeper) startSync() bool { log.WithFields(log.Fields{"module": logModule, "err": err}).Warning("fail on regularBlockSync") return false } + default: + return false } return true diff --git a/netsync/chainmgr/block_keeper_test.go b/netsync/chainmgr/block_keeper_test.go index 06a36d24..9472f21c 100644 --- a/netsync/chainmgr/block_keeper_test.go +++ b/netsync/chainmgr/block_keeper_test.go @@ -11,17 +11,108 @@ import ( dbm "github.com/vapor/database/leveldb" "github.com/vapor/errors" msgs "github.com/vapor/netsync/messages" + "github.com/vapor/netsync/peers" + "github.com/vapor/protocol" "github.com/vapor/protocol/bc" "github.com/vapor/protocol/bc/types" "github.com/vapor/test/mock" "github.com/vapor/testutil" ) +func TestCheckSyncType(t *testing.T) { + tmp, err := ioutil.TempDir(".", "") + if err != nil { + t.Fatalf("failed to create temporary data folder: %v", err) + } + fastSyncDB := dbm.NewDB("testdb", "leveldb", tmp) + defer func() { + fastSyncDB.Close() + os.RemoveAll(tmp) + }() + + blocks := mockBlocks(nil, 50) + chain := mock.NewChain(nil) + chain.SetBestBlockHeader(&blocks[len(blocks)-1].BlockHeader) + for _, block := range blocks { + chain.SetBlockByHeight(block.Height, block) + } + + type syncPeer struct { + peer *P2PPeer + bestHeight uint64 + irreversibleHeight uint64 + } + + cases := []struct { + peers []*syncPeer + syncType int + }{ + { + peers: []*syncPeer{}, + syncType: noNeedSync, + }, + { + peers: []*syncPeer{ + {peer: &P2PPeer{id: "peer1", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 1000, irreversibleHeight: 500}, + {peer: &P2PPeer{id: "peer2", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 50, irreversibleHeight: 50}, + }, + syncType: fastSyncType, + }, + { + peers: []*syncPeer{ + {peer: &P2PPeer{id: "peer1", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 1000, irreversibleHeight: 100}, + {peer: &P2PPeer{id: "peer2", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 500, irreversibleHeight: 50}, + }, + syncType: regularSyncType, + }, + { + peers: []*syncPeer{ + {peer: &P2PPeer{id: "peer1", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 51, irreversibleHeight: 50}, + }, + syncType: regularSyncType, + }, + { + peers: []*syncPeer{ + {peer: &P2PPeer{id: "peer1", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 30, irreversibleHeight: 30}, + }, + syncType: noNeedSync, + }, + { + peers: []*syncPeer{ + {peer: &P2PPeer{id: "peer1", flag: consensus.SFFullNode}, bestHeight: 1000, irreversibleHeight: 1000}, + }, + syncType: regularSyncType, + }, + { + peers: []*syncPeer{ + {peer: &P2PPeer{id: "peer1", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 1000, irreversibleHeight: 50}, + {peer: &P2PPeer{id: "peer2", flag: consensus.SFFullNode | consensus.SFFastSync}, bestHeight: 800, irreversibleHeight: 800}, + }, + syncType: fastSyncType, + }, + } + + for i, c := range cases { + peers := peers.NewPeerSet(NewPeerSet()) + blockKeeper := newBlockKeeper(chain, peers, fastSyncDB) + for _, syncPeer := range c.peers { + blockKeeper.peers.AddPeer(syncPeer.peer) + blockKeeper.peers.SetStatus(syncPeer.peer.id, syncPeer.bestHeight, nil) + blockKeeper.peers.SetIrreversibleStatus(syncPeer.peer.id, syncPeer.irreversibleHeight, nil) + } + gotType := blockKeeper.checkSyncType() + if c.syncType != gotType { + t.Errorf("case %d: got %d want %d", i, gotType, c.syncType) + } + } +} + func TestRegularBlockSync(t *testing.T) { baseChain := mockBlocks(nil, 50) chainX := append(baseChain, mockBlocks(baseChain[50], 60)...) chainY := append(baseChain, mockBlocks(baseChain[50], 70)...) chainZ := append(baseChain, mockBlocks(baseChain[50], 200)...) + chainE := append(baseChain, mockErrorBlocks(baseChain[50], 200, 60)...) cases := []struct { syncTimeout time.Duration @@ -58,6 +149,20 @@ func TestRegularBlockSync(t *testing.T) { want: chainZ[:180], err: nil, }, + { + syncTimeout: 0 * time.Second, + aBlocks: chainX[:52], + bBlocks: chainZ, + want: chainX[:52], + err: errRequestTimeout, + }, + { + syncTimeout: 30 * time.Second, + aBlocks: chainX[:52], + bBlocks: chainE, + want: chainE[:60], + err: protocol.ErrBadStateRoot, + }, } tmp, err := ioutil.TempDir(".", "") if err != nil { @@ -84,6 +189,7 @@ func TestRegularBlockSync(t *testing.T) { go A2B.postMan() } + requireBlockTimeout = c.syncTimeout a.blockKeeper.syncPeer = a.peers.GetPeer("test node B") if err := a.blockKeeper.regularBlockSync(); errors.Root(err) != c.err { t.Errorf("case %d: got %v want %v", i, err, c.err) @@ -308,11 +414,19 @@ func TestLocateBlocks(t *testing.T) { locator []uint64 stopHash bc.Hash wantHeight []uint64 + wantErr error }{ { locator: []uint64{20}, stopHash: blocks[100].Hash(), wantHeight: []uint64{20, 21, 22, 23, 24}, + wantErr: nil, + }, + { + locator: []uint64{20}, + stopHash: bc.NewHash([32]byte{0x01, 0x02}), + wantHeight: []uint64{}, + wantErr: mock.ErrFoundHeaderByHash, }, } @@ -334,7 +448,11 @@ func TestLocateBlocks(t *testing.T) { want = append(want, blocks[i]) } - got, _ := bk.locateBlocks(locator, &c.stopHash) + got, err := bk.locateBlocks(locator, &c.stopHash) + if err != c.wantErr { + t.Errorf("case %d: got %v want err = %v", i, err, c.wantErr) + } + if !testutil.DeepEqual(got, want) { t.Errorf("case %d: got %v want %v", i, got, want) } @@ -358,7 +476,7 @@ func TestLocateHeaders(t *testing.T) { stopHash *bc.Hash skip uint64 wantHeight []uint64 - err bool + err error }{ { chainHeight: 100, @@ -366,7 +484,7 @@ func TestLocateHeaders(t *testing.T) { stopHash: &blocksHash[100], skip: 0, wantHeight: []uint64{90, 91, 92, 93, 94, 95, 96, 97, 98, 99}, - err: false, + err: nil, }, { chainHeight: 100, @@ -374,28 +492,28 @@ func TestLocateHeaders(t *testing.T) { stopHash: &blocksHash[24], skip: 0, wantHeight: []uint64{20, 21, 22, 23, 24}, - err: false, + err: nil, }, { chainHeight: 100, locator: []uint64{20}, stopHash: &blocksHash[20], wantHeight: []uint64{20}, - err: false, + err: nil, }, { chainHeight: 100, locator: []uint64{20}, stopHash: &blocksHash[120], wantHeight: []uint64{}, - err: false, + err: mock.ErrFoundHeaderByHash, }, { chainHeight: 100, locator: []uint64{120, 70}, stopHash: &blocksHash[78], wantHeight: []uint64{70, 71, 72, 73, 74, 75, 76, 77, 78}, - err: false, + err: nil, }, { chainHeight: 100, @@ -403,7 +521,7 @@ func TestLocateHeaders(t *testing.T) { stopHash: &blocksHash[10], skip: 10, wantHeight: []uint64{}, - err: false, + err: nil, }, { chainHeight: 100, @@ -411,7 +529,7 @@ func TestLocateHeaders(t *testing.T) { stopHash: &blocksHash[80], skip: 10, wantHeight: []uint64{15, 26, 37, 48, 59, 70, 80}, - err: false, + err: nil, }, { chainHeight: 100, @@ -419,7 +537,7 @@ func TestLocateHeaders(t *testing.T) { stopHash: &blocksHash[100], skip: 9, wantHeight: []uint64{0, 10, 20, 30, 40, 50, 60, 70, 80, 90}, - err: false, + err: nil, }, } @@ -442,7 +560,7 @@ func TestLocateHeaders(t *testing.T) { } got, err := bk.locateHeaders(locator, c.stopHash, c.skip, maxNumOfHeadersPerMsg) - if err != nil != c.err { + if err != c.err { t.Errorf("case %d: got %v want err = %v", i, err, c.err) } if !testutil.DeepEqual(got, want) { diff --git a/netsync/chainmgr/block_process_test.go b/netsync/chainmgr/block_process_test.go index 5bc2075f..7663dc84 100644 --- a/netsync/chainmgr/block_process_test.go +++ b/netsync/chainmgr/block_process_test.go @@ -8,6 +8,8 @@ import ( "time" dbm "github.com/vapor/database/leveldb" + "github.com/vapor/netsync/peers" + "github.com/vapor/protocol/bc/types" "github.com/vapor/test/mock" ) @@ -21,30 +23,52 @@ func TestBlockProcess(t *testing.T) { testDB := dbm.NewDB("testdb", "leveldb", tmp) defer testDB.Close() + cases := []struct { + blocks []*types.Block + startHeight uint64 + stopHeight uint64 + }{ + { + blocks: mockBlocks(nil, 200), + startHeight: 100, + stopHeight: 200, + }, + { + blocks: mockBlocks(nil, 200), + startHeight: 110, + stopHeight: 100, + }, + { + blocks: mockErrorBlocks(nil, 200, 150), + startHeight: 100, + stopHeight: 149, + }, + } s := newStorage(testDB) mockChain := mock.NewChain(nil) - blockNum := 200 - blocks := mockBlocks(nil, uint64(blockNum)) - for i := 0; i <= blockNum/2; i++ { - mockChain.SetBlockByHeight(uint64(i), blocks[i]) - mockChain.SetBestBlockHeader(&blocks[i].BlockHeader) - } + for i, c := range cases { + for i := 0; i <= len(c.blocks)/2; i++ { + mockChain.SetBlockByHeight(uint64(i), c.blocks[i]) + mockChain.SetBestBlockHeader(&c.blocks[i].BlockHeader) + } - if err := s.writeBlocks("testPeer", blocks); err != nil { - t.Fatal(err) - } + if err := s.writeBlocks("testPeer", c.blocks); err != nil { + t.Fatal(err) + } + + bp := newBlockProcessor(mockChain, s, peers.NewPeerSet(nil)) + downloadNotifyCh := make(chan struct{}, 1) + ProcessStopCh := make(chan struct{}) + var wg sync.WaitGroup + go func() { + time.Sleep(1 * time.Second) + close(downloadNotifyCh) + }() + wg.Add(1) - bp := newBlockProcessor(mockChain, s, nil) - downloadNotifyCh := make(chan struct{}, 1) - ProcessStopCh := make(chan struct{}) - var wg sync.WaitGroup - go func() { - time.Sleep(1 * time.Second) - close(downloadNotifyCh) - }() - wg.Add(1) - bp.process(downloadNotifyCh, ProcessStopCh, uint64(blockNum/2), &wg) - if bp.chain.BestBlockHeight() != uint64(blockNum) { - t.Fatalf("TestBlockProcess fail: got %d want %d", bp.chain.BestBlockHeight(), blockNum) + bp.process(downloadNotifyCh, ProcessStopCh, c.startHeight, &wg) + if bp.chain.BestBlockHeight() != c.stopHeight { + t.Fatalf("TestBlockProcess index: %d fail: got %d want %d", i, bp.chain.BestBlockHeight(), c.stopHeight) + } } } diff --git a/netsync/chainmgr/tool_test.go b/netsync/chainmgr/tool_test.go index 63b6a2f5..4a3badd9 100644 --- a/netsync/chainmgr/tool_test.go +++ b/netsync/chainmgr/tool_test.go @@ -161,6 +161,33 @@ func mockBlocks(startBlock *types.Block, height uint64) []*types.Block { return blocks } +func mockErrorBlocks(startBlock *types.Block, height uint64, errBlockHeight uint64) []*types.Block { + blocks := []*types.Block{} + indexBlock := &types.Block{} + if startBlock == nil { + indexBlock = &types.Block{BlockHeader: types.BlockHeader{Version: uint64(rand.Uint32())}} + blocks = append(blocks, indexBlock) + } else { + indexBlock = startBlock + } + + for indexBlock.Height < height { + block := &types.Block{ + BlockHeader: types.BlockHeader{ + Height: indexBlock.Height + 1, + PreviousBlockHash: indexBlock.Hash(), + Version: uint64(rand.Uint32()), + }, + } + if block.Height == errBlockHeight { + block.TransactionsMerkleRoot = bc.NewHash([32]byte{0x1}) + } + blocks = append(blocks, block) + indexBlock = block + } + return blocks +} + func mockSync(blocks []*types.Block, mempool *mock.Mempool, fastSyncDB dbm.DB) *Manager { chain := mock.NewChain(mempool) peers := peers.NewPeerSet(NewPeerSet()) diff --git a/netsync/peers/peer.go b/netsync/peers/peer.go index 431de06e..ef90812f 100644 --- a/netsync/peers/peer.go +++ b/netsync/peers/peer.go @@ -673,6 +673,15 @@ func (ps *PeerSet) SetStatus(peerID string, height uint64, hash *bc.Hash) { peer.SetBestStatus(height, hash) } +func (ps *PeerSet) SetIrreversibleStatus(peerID string, height uint64, hash *bc.Hash) { + peer := ps.GetPeer(peerID) + if peer == nil { + return + } + + peer.SetIrreversibleStatus(height, hash) +} + func (ps *PeerSet) Size() int { ps.mtx.RLock() defer ps.mtx.RUnlock() diff --git a/test/mock/chain.go b/test/mock/chain.go index 700891f5..69ef7c43 100644 --- a/test/mock/chain.go +++ b/test/mock/chain.go @@ -4,10 +4,16 @@ import ( "errors" "math/rand" + "github.com/vapor/protocol" "github.com/vapor/protocol/bc" "github.com/vapor/protocol/bc/types" ) +var ( + ErrFoundHeaderByHash = errors.New("can't find header by hash") + ErrFoundHeaderByHeight = errors.New("can't find header by height") +) + type mempool interface { AddTx(tx *types.Tx) } @@ -64,7 +70,7 @@ func (c *Chain) GetBlockByHeight(height uint64) (*types.Block, error) { func (c *Chain) GetHeaderByHash(hash *bc.Hash) (*types.BlockHeader, error) { block, ok := c.blockMap[*hash] if !ok { - return nil, errors.New("can't find block") + return nil, ErrFoundHeaderByHash } return &block.BlockHeader, nil } @@ -72,7 +78,7 @@ func (c *Chain) GetHeaderByHash(hash *bc.Hash) (*types.BlockHeader, error) { func (c *Chain) GetHeaderByHeight(height uint64) (*types.BlockHeader, error) { block, ok := c.heightMap[height] if !ok { - return nil, errors.New("can't find block") + return nil, ErrFoundHeaderByHeight } return &block.BlockHeader, nil } @@ -107,6 +113,10 @@ func (c *Chain) InMainChain(hash bc.Hash) bool { } func (c *Chain) ProcessBlock(block *types.Block) (bool, error) { + if block.TransactionsMerkleRoot == bc.NewHash([32]byte{0x1}) { + return false, protocol.ErrBadStateRoot + } + if c.bestBlockHeader.Hash() == block.PreviousBlockHash { c.heightMap[block.Height] = block c.blockMap[block.Hash()] = block