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 }