github.com/turingchain2020/turingchain@v1.1.21/blockchain/chunkshard_test.go (about)

     1  // Copyright Turing Corp. 2018 All Rights Reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package blockchain
     6  
     7  import (
     8  	"fmt"
     9  	"io/ioutil"
    10  	"os"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/turingchain2020/turingchain/queue"
    15  	"github.com/turingchain2020/turingchain/types"
    16  	"github.com/stretchr/testify/mock"
    17  
    18  	dbm "github.com/turingchain2020/turingchain/common/db"
    19  	qmocks "github.com/turingchain2020/turingchain/queue/mocks"
    20  	"github.com/stretchr/testify/assert"
    21  )
    22  
    23  func TestCheckGenChunkNum(t *testing.T) {
    24  	dir, err := ioutil.TempDir("", "example")
    25  	assert.Nil(t, err)
    26  	defer os.RemoveAll(dir) // clean up
    27  	os.RemoveAll(dir)       //删除已存在目录
    28  
    29  	chain := InitEnv()
    30  	blockStoreDB := dbm.NewDB("blockchain", "leveldb", dir, 100)
    31  	blockStore := NewBlockStore(chain, blockStoreDB, chain.client)
    32  	assert.NotNil(t, blockStore)
    33  	chain.blockStore = blockStore
    34  	// mock client
    35  	client := &qmocks.Client{}
    36  	chain.client = client
    37  	data := &types.ChunkInfo{}
    38  	client.On("NewMessage", mock.Anything, mock.Anything, mock.Anything).Return(&queue.Message{Data: data})
    39  	client.On("Send", mock.Anything, mock.Anything).Return(nil)
    40  	rspMsg := &queue.Message{Data: &types.Reply{IsOk: true}}
    41  	client.On("Wait", mock.Anything).Return(rspMsg, nil)
    42  	// set config
    43  	chain.cfg.ChunkblockNum = 5
    44  
    45  	start := int64(0)
    46  	end := int64(150)
    47  	saveBlockToDB(chain, start, end)
    48  	//just for test
    49  	chain.blockStore.UpdateHeight2(MaxRollBlockNum + 150)
    50  	// check
    51  	for i := int64(0); i < 5; i++ {
    52  		chain.CheckGenChunkNum()
    53  		// check
    54  		serChunkNum := chain.getMaxSerialChunkNum()
    55  		curChunkNum := chain.GetCurChunkNum()
    56  		assert.Equal(t, serChunkNum, curChunkNum)
    57  	}
    58  }
    59  
    60  func TestDeleteBlockBody(t *testing.T) {
    61  	dir, err := ioutil.TempDir("", "example")
    62  	assert.Nil(t, err)
    63  	defer os.RemoveAll(dir) // clean up
    64  	os.RemoveAll(dir)       //删除已存在目录
    65  
    66  	chain := InitEnv()
    67  	blockStoreDB := dbm.NewDB("blockchain", "leveldb", dir, 100)
    68  	blockStore := NewBlockStore(chain, blockStoreDB, chain.client)
    69  	assert.NotNil(t, blockStore)
    70  	chain.blockStore = blockStore
    71  	start := int64(0)
    72  	end := int64(15)
    73  	saveBlockToDB(chain, start, end)
    74  	var hashs [][]byte
    75  	for i := start; i <= end; i++ {
    76  		head, err := chain.blockStore.loadHeaderByIndex(i)
    77  		assert.NoError(t, err)
    78  		hashs = append(hashs, head.Hash)
    79  	}
    80  	blockStore.Set(calcChunkNumToHash(1), types.Encode(&types.ChunkInfo{Start: 0, End: 10}))
    81  	kvs := chain.DeleteBlockBody(1)
    82  	chain.blockStore.mustSaveKvset(&types.LocalDBSet{KV: kvs})
    83  	for i := start; i <= 10; i++ {
    84  		_, err = getBodyByIndex(blockStore.db, "", calcHeightHashKey(i, hashs[int(i)]), nil)
    85  		assert.Error(t, err, types.ErrNotFound)
    86  	}
    87  	for i := 11; i <= 15; i++ {
    88  		_, err = getBodyByIndex(blockStore.db, "", calcHeightHashKey(int64(i), hashs[i]), nil)
    89  		assert.NoError(t, err)
    90  	}
    91  }
    92  
    93  func TestMaxSerialChunkNum(t *testing.T) {
    94  	dir, err := ioutil.TempDir("", "example")
    95  	assert.Nil(t, err)
    96  	defer os.RemoveAll(dir) // clean up
    97  	os.RemoveAll(dir)       //删除已存在目录
    98  
    99  	chain := InitEnv()
   100  	blockStoreDB := dbm.NewDB("blockchain", "leveldb", dir, 100)
   101  	blockStore := NewBlockStore(chain, blockStoreDB, chain.client)
   102  	assert.NotNil(t, blockStore)
   103  	chain.blockStore = blockStore
   104  	// test noerror
   105  	for i := 0; i < 100; i++ {
   106  		err = chain.updateMaxSerialChunkNum(int64(i))
   107  		assert.NoError(t, err)
   108  		chunkNum := chain.getMaxSerialChunkNum()
   109  		assert.Equal(t, int64(i), chunkNum)
   110  	}
   111  }
   112  
   113  func TestNotifyStoreChunkToP2P(t *testing.T) {
   114  	client := &qmocks.Client{}
   115  	chain := BlockChain{client: client}
   116  	data := &types.ChunkInfo{
   117  		ChunkNum:  1,
   118  		ChunkHash: []byte("1111111111111"),
   119  		Start:     1,
   120  		End:       2,
   121  	}
   122  	client.On("NewMessage", mock.Anything, mock.Anything, mock.Anything).Return(&queue.Message{Data: data})
   123  	client.On("Send", mock.Anything, mock.Anything).Return(nil)
   124  	rspMsg := &queue.Message{Data: &types.Reply{IsOk: true}}
   125  	client.On("Wait", mock.Anything).Return(rspMsg, nil)
   126  	err := chain.notifyStoreChunkToP2P(data)
   127  	assert.Nil(t, err)
   128  }
   129  
   130  func TestGenChunkBlocks(t *testing.T) {
   131  	dir, err := ioutil.TempDir("", "example")
   132  	assert.Nil(t, err)
   133  	defer os.RemoveAll(dir) // clean up
   134  	os.RemoveAll(dir)       //删除已存在目录
   135  
   136  	chain := InitEnv()
   137  	blockStoreDB := dbm.NewDB("blockchain", "leveldb", dir, 100)
   138  	blockStore := NewBlockStore(chain, blockStoreDB, chain.client)
   139  	assert.NotNil(t, blockStore)
   140  	chain.blockStore = blockStore
   141  	start := int64(0)
   142  	end := int64(10)
   143  	saveBlockToDB(chain, start, end)
   144  	chunkHash, bodys, err := chain.genChunkBlocks(start, end)
   145  	assert.NoError(t, err)
   146  	assert.NotNil(t, chunkHash)
   147  	assert.Equal(t, int(end-start+1), len(bodys.Items))
   148  	// for error
   149  	end = int64(11)
   150  	chunkHash, bodys, err = chain.genChunkBlocks(start, end)
   151  	assert.Nil(t, chunkHash)
   152  	assert.Nil(t, bodys)
   153  	assert.Error(t, err, types.ErrHashNotExist)
   154  }
   155  
   156  func TestGetChunkBlockBody(t *testing.T) {
   157  	dir, err := ioutil.TempDir("", "example")
   158  	assert.Nil(t, err)
   159  	defer os.RemoveAll(dir) // clean up
   160  	os.RemoveAll(dir)       //删除已存在目录
   161  
   162  	chain := InitEnv()
   163  	blockStoreDB := dbm.NewDB("blockchain", "leveldb", dir, 100)
   164  	blockStore := NewBlockStore(chain, blockStoreDB, chain.client)
   165  	assert.NotNil(t, blockStore)
   166  	chain.blockStore = blockStore
   167  	req := &types.ChunkInfoMsg{
   168  		ChunkHash: nil,
   169  		Start:     2,
   170  		End:       0,
   171  	}
   172  	body, err := chain.GetChunkBlockBody(req)
   173  	assert.Error(t, err, types.ErrInvalidParam)
   174  	assert.Nil(t, body)
   175  }
   176  
   177  func TestGetChunkRecord(t *testing.T) {
   178  	dir, err := ioutil.TempDir("", "example")
   179  	assert.Nil(t, err)
   180  	defer os.RemoveAll(dir) // clean up
   181  	os.RemoveAll(dir)       //删除已存在目录
   182  
   183  	chain := InitEnv()
   184  	blockStoreDB := dbm.NewDB("blockchain", "leveldb", dir, 100)
   185  	blockStore := NewBlockStore(chain, blockStoreDB, chain.client)
   186  	assert.NotNil(t, blockStore)
   187  	chain.blockStore = blockStore
   188  	chunk := &types.ChunkInfo{
   189  		ChunkHash: []byte("11111111111"),
   190  	}
   191  	for i := 0; i < 5; i++ {
   192  		chunk.ChunkNum = int64(i)
   193  		blockStore.Set(calcChunkNumToHash(int64(i)), types.Encode(chunk))
   194  	}
   195  	req := &types.ReqChunkRecords{
   196  		Start:    2,
   197  		End:      1,
   198  		IsDetail: false,
   199  		Pid:      nil,
   200  	}
   201  	record, err := chain.GetChunkRecord(req)
   202  	assert.Error(t, err, types.ErrInvalidParam)
   203  	assert.Nil(t, record)
   204  	req.Start = 0
   205  	req.End = 0
   206  	record, err = chain.GetChunkRecord(req)
   207  	assert.NoError(t, err)
   208  	assert.Equal(t, len(record.Infos), 1)
   209  	req.Start = 0
   210  	req.End = 4
   211  	record, err = chain.GetChunkRecord(req)
   212  	assert.NoError(t, err)
   213  	assert.Equal(t, len(record.Infos), 5)
   214  	for i, info := range record.Infos {
   215  		assert.Equal(t, int64(i), info.ChunkNum)
   216  	}
   217  	req.End = 5
   218  	record, err = chain.GetChunkRecord(req)
   219  	assert.Error(t, err, types.ErrNotFound)
   220  }
   221  
   222  func TestCaclChunkInfo(t *testing.T) {
   223  	dir, err := ioutil.TempDir("", "example")
   224  	assert.Nil(t, err)
   225  	defer os.RemoveAll(dir) // clean up
   226  	os.RemoveAll(dir)       //删除已存在目录
   227  
   228  	chain := InitEnv()
   229  	cfg := chain.client.GetConfig()
   230  	blockStoreDB := dbm.NewDB("blockchain", "leveldb", dir, 100)
   231  	blockStore := NewBlockStore(chain, blockStoreDB, chain.client)
   232  	assert.NotNil(t, blockStore)
   233  	chain.blockStore = blockStore
   234  
   235  	chainCfg := cfg.GetModuleConfig().BlockChain
   236  	chainCfg.ChunkblockNum = 1
   237  	chunkNum, start, end := chain.CalcChunkInfo(0)
   238  	assert.Equal(t, chunkNum, int64(0))
   239  	assert.Equal(t, start, int64(0))
   240  	assert.Equal(t, end, int64(0))
   241  
   242  	chunkNum, start, end = chain.CalcChunkInfo(1)
   243  	assert.Equal(t, chunkNum, int64(1))
   244  	assert.Equal(t, start, int64(1))
   245  	assert.Equal(t, end, int64(1))
   246  
   247  	chainCfg.ChunkblockNum = 2
   248  	chunkNum, start, end = chain.CalcChunkInfo(0)
   249  	assert.Equal(t, chunkNum, int64(0))
   250  	assert.Equal(t, start, int64(0))
   251  	assert.Equal(t, end, int64(1))
   252  	chunkNum, start, end = chain.CalcChunkInfo(2)
   253  	assert.Equal(t, chunkNum, int64(1))
   254  	assert.Equal(t, start, int64(2))
   255  	assert.Equal(t, end, int64(3))
   256  	chunkNum, start, end = chain.CalcChunkInfo(3)
   257  	assert.Equal(t, chunkNum, int64(1))
   258  	assert.Equal(t, start, int64(2))
   259  	assert.Equal(t, end, int64(3))
   260  	chunkNum, start, end = chain.CalcChunkInfo(4)
   261  	assert.Equal(t, chunkNum, int64(2))
   262  	assert.Equal(t, start, int64(4))
   263  	assert.Equal(t, end, int64(5))
   264  }
   265  
   266  func TestGenChunkRecord(t *testing.T) {
   267  	chunk := &types.ChunkInfo{
   268  		ChunkNum:  1,
   269  		ChunkHash: []byte("111111111111111111111"),
   270  		Start:     1,
   271  		End:       10,
   272  	}
   273  	bodys := &types.BlockBodys{
   274  		Items: []*types.BlockBody{
   275  			{Hash: []byte("123")},
   276  			{Hash: []byte("456")},
   277  		},
   278  	}
   279  	kvs := genChunkRecord(chunk, bodys)
   280  	assert.Equal(t, 2, len(kvs))
   281  	//assert.Equal(t, kvs[0].Key, calcBlockHashToChunkHash([]byte("123")))
   282  	//assert.Equal(t, kvs[0].Value, chunk.ChunkHash)
   283  	//assert.Equal(t, kvs[1].Key, calcBlockHashToChunkHash([]byte("456")))
   284  	//assert.Equal(t, kvs[1].Value, chunk.ChunkHash)
   285  
   286  	assert.Equal(t, kvs[0].Key, calcChunkNumToHash(1))
   287  	assert.Equal(t, kvs[0].Value, types.Encode(chunk))
   288  	assert.Equal(t, kvs[1].Key, calcChunkHashToNum(chunk.ChunkHash))
   289  	assert.Equal(t, kvs[1].Value, types.Encode(chunk))
   290  }
   291  
   292  func TestFetchChunkBlock(t *testing.T) {
   293  	dir, err := ioutil.TempDir("", "example")
   294  	assert.Nil(t, err)
   295  	defer os.RemoveAll(dir) // clean up
   296  	os.RemoveAll(dir)       //删除已存在目录
   297  
   298  	chain := InitEnv()
   299  	blockStoreDB := dbm.NewDB("blockchain", "leveldb", dir, 100)
   300  	blockStore := NewBlockStore(chain, blockStoreDB, chain.client)
   301  	assert.NotNil(t, blockStore)
   302  	chain.blockStore = blockStore
   303  	// mock client
   304  	client := &qmocks.Client{}
   305  	chain.client = client
   306  	data := &types.ChunkInfo{}
   307  	client.On("NewMessage", mock.Anything, mock.Anything, mock.Anything).Return(&queue.Message{Data: data})
   308  	client.On("Send", mock.Anything, mock.Anything).Return(nil)
   309  	rspMsg := &queue.Message{Data: &types.BlockBodys{Items: []*types.BlockBody{{}, {}}}}
   310  	client.On("Wait", mock.Anything).Return(rspMsg, nil)
   311  	// set config
   312  	chain.cfg.ChunkblockNum = 5
   313  	start := int64(0)
   314  	end := int64(51)
   315  	chain.InitDownLoadInfo(start, end, []string{"1", "2"})
   316  	// set RecvChunkHash
   317  	for i := start; i <= end; i++ {
   318  		chain.blockStore.Set(calcRecvChunkNumToHash(i), types.Encode(&types.ChunkInfo{ChunkHash: []byte("hash")}))
   319  	}
   320  	// check for updata
   321  	go func() {
   322  		for i := int64(0); i <= end; i++ {
   323  			time.Sleep(time.Microsecond * 500)
   324  			chain.downLoadTask.Done(i)
   325  			fmt.Println("done i", i)
   326  		}
   327  	}()
   328  	chain.ReqDownLoadChunkBlocks()
   329  	time.Sleep(time.Second)
   330  }
   331  
   332  func TestFetchChunkRecords(t *testing.T) {
   333  	dir, err := ioutil.TempDir("", "example")
   334  	assert.Nil(t, err)
   335  	defer os.RemoveAll(dir) // clean up
   336  	os.RemoveAll(dir)       //删除已存在目录
   337  
   338  	chain := InitEnv()
   339  	blockStoreDB := dbm.NewDB("blockchain", "leveldb", dir, 100)
   340  	blockStore := NewBlockStore(chain, blockStoreDB, chain.client)
   341  	assert.NotNil(t, blockStore)
   342  	chain.blockStore = blockStore
   343  	// mock client
   344  	client := &qmocks.Client{}
   345  	chain.client = client
   346  	data := &types.ChunkInfo{}
   347  	client.On("NewMessage", mock.Anything, mock.Anything, mock.Anything).Return(&queue.Message{Data: data})
   348  	client.On("Send", mock.Anything, mock.Anything).Return(nil)
   349  	rspMsg := &queue.Message{Data: &types.BlockBodys{Items: []*types.BlockBody{{}, {}}}}
   350  	client.On("Wait", mock.Anything).Return(rspMsg, nil)
   351  
   352  	// set config
   353  	chain.cfg.ChunkblockNum = 5
   354  	// 设置最大对端节点高度
   355  	peerInfo := &PeerInfo{
   356  		Name:   "123",
   357  		Height: 9,
   358  	}
   359  	chain.peerList = PeerInfoList{peerInfo}
   360  	chain.bestChainPeerList["123"] = &BestPeerInfo{Peer: peerInfo, IsBestChain: true}
   361  
   362  	// case 1 peerMaxBlkHeight < curheight
   363  	chain.blockStore.UpdateHeight2(MaxRollBlockNum + 100)
   364  	chain.ChunkRecordSync()
   365  	// case 2 peerMaxBlkHeight - MaxRollBlockNum > curheight
   366  	// 设置从0开始
   367  	end := MaxRollBlockNum + 6000
   368  	chain.blockStore.UpdateHeight2(-1)
   369  	chain.peerList[0].Height = end
   370  	// check for updata
   371  	go func() {
   372  		count := end / chain.cfg.ChunkblockNum / int64(MaxReqChunkRecord)
   373  		for i := int64(0); i <= count; i++ {
   374  			time.Sleep(time.Microsecond * 200)
   375  			for j := i * int64(MaxReqChunkRecord); j < (i+1)*int64(MaxReqChunkRecord); j++ {
   376  				chain.blockStore.Set(calcRecvChunkNumToHash(j), types.Encode(&types.ChunkInfo{ChunkHash: []byte("hash")}))
   377  			}
   378  			chain.chunkRecordTask.Done(i)
   379  			fmt.Println("done i", i)
   380  		}
   381  	}()
   382  	chain.ChunkRecordSync()
   383  	time.Sleep(time.Second)
   384  }
   385  
   386  func saveBlockToDB(chain *BlockChain, start, end int64) {
   387  	batch := chain.blockStore.NewBatch(true)
   388  	for i := start; i <= end; i++ {
   389  		blockdetail := &types.BlockDetail{
   390  			Block: &types.Block{
   391  				Version: 0,
   392  				Height:  i,
   393  			},
   394  		}
   395  		batch.Reset()
   396  		chain.blockStore.SaveBlock(batch, blockdetail, i)
   397  		batch.Write()
   398  		chain.blockStore.UpdateHeight2(i)
   399  	}
   400  }