github.com/turingchain2020/turingchain@v1.1.21/blockchain/blockstore.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 "bytes" 9 "encoding/json" 10 "errors" 11 "fmt" 12 "math/big" 13 "strconv" 14 "sync" 15 "sync/atomic" 16 "time" 17 18 "github.com/turingchain2020/turingchain/common" 19 dbm "github.com/turingchain2020/turingchain/common/db" 20 "github.com/turingchain2020/turingchain/common/difficulty" 21 "github.com/turingchain2020/turingchain/common/utils" 22 "github.com/turingchain2020/turingchain/common/version" 23 "github.com/turingchain2020/turingchain/queue" 24 "github.com/turingchain2020/turingchain/types" 25 "github.com/golang/protobuf/proto" 26 ) 27 28 //var 29 var ( 30 blockLastHeight = []byte("blockLastHeight") 31 bodyPrefix = []byte("Body:") 32 LastSequence = []byte("LastSequence") 33 headerPrefix = []byte("Header:") 34 heightToHeaderPrefix = []byte("HH:") 35 hashPrefix = []byte("Hash:") 36 tdPrefix = []byte("TD:") 37 heightToHashKeyPrefix = []byte("Height:") 38 seqToHashKey = []byte("Seq:") 39 HashToSeqPrefix = []byte("HashToSeq:") 40 pushPrefix = []byte("push2subscribe:") 41 lastSeqNumPrefix = []byte("lastSeqNumPrefix:") 42 paraSeqToHashKey = []byte("ParaSeq:") 43 HashToParaSeqPrefix = []byte("HashToParaSeq:") 44 LastParaSequence = []byte("LastParaSequence") 45 // chunk相关 46 BodyHashToChunk = []byte("BodyHashToChunk:") 47 ChunkNumToHash = []byte("ChunkNumToHash:") 48 ChunkHashToNum = []byte("ChunkHashToNum:") 49 RecvChunkNumToHash = []byte("RecvChunkNumToHash:") 50 MaxSerialChunkNum = []byte("MaxSilChunkNum:") 51 MaxDeletedChunkNum = []byte("MaxDeletedChunkNum:") 52 storeLog = chainlog.New("submodule", "store") 53 ) 54 55 //GetLocalDBKeyList 获取本地键值列表 56 //增加chainBody和chainHeader对应的四个key。chainParaTx的可以在区块0高度时是没有的 57 //bodyPrefix,headerPrefix,heightToHeaderPrefix这三个key不再使用 58 func GetLocalDBKeyList() [][]byte { 59 return [][]byte{ 60 blockLastHeight, bodyPrefix, LastSequence, headerPrefix, heightToHeaderPrefix, 61 hashPrefix, tdPrefix, heightToHashKeyPrefix, seqToHashKey, HashToSeqPrefix, 62 pushPrefix, lastSeqNumPrefix, tempBlockKey, lastTempBlockKey, LastParaSequence, 63 chainParaTxPrefix, chainBodyPrefix, chainHeaderPrefix, chainReceiptPrefix, 64 BodyHashToChunk, ChunkNumToHash, ChunkHashToNum, RecvChunkNumToHash, 65 MaxSerialChunkNum, MaxDeletedChunkNum, 66 } 67 } 68 69 //存储block hash对应的blockbody信息 70 func calcHashToBlockBodyKey(hash []byte) []byte { 71 return append(bodyPrefix, hash...) 72 } 73 74 func calcPushKey(name string) []byte { 75 return []byte(string(pushPrefix) + name) 76 } 77 78 func calcLastPushSeqNumKey(name string) []byte { 79 return []byte(string(lastSeqNumPrefix) + name) 80 } 81 82 //存储block hash对应的header信息 83 func calcHashToBlockHeaderKey(hash []byte) []byte { 84 return append(headerPrefix, hash...) 85 } 86 87 func calcHeightToBlockHeaderKey(height int64) []byte { 88 return append(heightToHeaderPrefix, []byte(fmt.Sprintf("%012d", height))...) 89 } 90 91 //存储block hash对应的block height 92 func calcHashToHeightKey(hash []byte) []byte { 93 return append(hashPrefix, hash...) 94 } 95 96 //存储block hash对应的block总难度TD 97 func calcHashToTdKey(hash []byte) []byte { 98 return append(tdPrefix, hash...) 99 } 100 101 //存储block height 对应的block hash 102 func calcHeightToHashKey(height int64) []byte { 103 return append(heightToHashKeyPrefix, []byte(fmt.Sprintf("%v", height))...) 104 } 105 106 //存储block操作序列号对应的block hash,KEY=Seq:sequence 107 func calcSequenceToHashKey(sequence int64, isPara bool) []byte { 108 if isPara { 109 return append(paraSeqToHashKey, []byte(fmt.Sprintf("%v", sequence))...) 110 } 111 return append(seqToHashKey, []byte(fmt.Sprintf("%v", sequence))...) 112 } 113 114 //存储block hash对应的seq序列号,KEY=Seq:sequence,只用于平行链addblock操作,方便delblock回退是查找对应seq的hash 115 func calcHashToSequenceKey(hash []byte, isPara bool) []byte { 116 if isPara { 117 return append(HashToParaSeqPrefix, hash...) 118 } 119 return append(HashToSeqPrefix, hash...) 120 } 121 122 func calcLastSeqKey(isPara bool) []byte { 123 if isPara { 124 return LastParaSequence 125 } 126 return LastSequence 127 } 128 129 //存储block hash对应的seq序列号,KEY=Seq:sequence,只用于平行链addblock操作,方便delblock回退是查找对应seq的hash 130 func calcHashToMainSequenceKey(hash []byte) []byte { 131 return append(HashToSeqPrefix, hash...) 132 } 133 134 //存储block操作序列号对应的block hash,KEY=MainSeq:sequence 135 func calcMainSequenceToHashKey(sequence int64) []byte { 136 return append(seqToHashKey, []byte(fmt.Sprintf("%v", sequence))...) 137 } 138 139 //// 存储归档索引 blockhash--->chunkhash 140 //func calcBlockHashToChunkHash(hash []byte) []byte { 141 // return append(BodyHashToChunk, hash...) 142 //} 143 144 // 存储归档索引 chunkNum--->chunkhash 145 func calcChunkNumToHash(chunkNum int64) []byte { 146 return append(ChunkNumToHash, []byte(fmt.Sprintf("%012d", chunkNum))...) 147 } 148 149 // 存储归档索引 chunkhash--->chunkNum 150 func calcChunkHashToNum(hash []byte) []byte { 151 return append(ChunkHashToNum, hash...) 152 } 153 154 // 存储归档索引 chunkNum--->chunkhash 从对端节点同步过来的归档索引 155 func calcRecvChunkNumToHash(chunkNum int64) []byte { 156 return append(RecvChunkNumToHash, []byte(fmt.Sprintf("%012d", chunkNum))...) 157 } 158 159 //BlockStore 区块存储 TODO:有较多的冗余代码,接口函数需要进行功能梳理和重写 160 type BlockStore struct { 161 db dbm.DB 162 client queue.Client 163 height int64 164 lastBlock *types.Block 165 lastheaderlock sync.Mutex 166 saveSequence bool 167 isParaChain bool 168 batch dbm.Batch 169 170 //记录当前活跃的block,减少数据库的访问提高效率 171 activeBlocks *utils.SpaceLimitCache 172 chain *BlockChain 173 blockCache *BlockCache 174 } 175 176 //NewBlockStore new 177 func NewBlockStore(chain *BlockChain, db dbm.DB, client queue.Client) *BlockStore { 178 height, err := LoadBlockStoreHeight(db) 179 if err != nil { 180 chainlog.Info("init::LoadBlockStoreHeight::database may be crash", "err", err.Error()) 181 if err != types.ErrHeightNotExist { 182 panic(err) 183 } 184 } 185 blockStore := &BlockStore{ 186 height: height, 187 db: db, 188 client: client, 189 chain: chain, 190 blockCache: chain.blockCache, 191 } 192 if chain != nil { 193 blockStore.saveSequence = chain.isRecordBlockSequence 194 blockStore.isParaChain = chain.isParaChain 195 } 196 cfg := chain.client.GetConfig() 197 if height == -1 { 198 chainlog.Info("load block height error, may be init database", "height", height) 199 if cfg.IsEnable("quickIndex") { 200 blockStore.saveQuickIndexFlag() 201 } 202 } else { 203 blockdetail, err := blockStore.LoadBlock(height, nil) 204 if err != nil { 205 chainlog.Error("init::LoadBlock::database may be crash") 206 panic(err) 207 } 208 blockStore.lastBlock = blockdetail.GetBlock() 209 flag, err := blockStore.loadFlag(types.FlagTxQuickIndex) 210 if err != nil { 211 panic(err) 212 } 213 if cfg.IsEnable("quickIndex") { 214 if flag == 0 { 215 blockStore.initQuickIndex(height) 216 } 217 } else { 218 if flag != 0 { 219 panic("toml config disable tx quick index, but database enable quick index") 220 } 221 } 222 } 223 blockStore.batch = db.NewBatch(true) 224 225 //初始化活跃区块的缓存 226 maxActiveBlockNum := maxActiveBlocks 227 maxActiveBlockSize := maxActiveBlocksCacheSize 228 if cfg.GetModuleConfig().BlockChain.MaxActiveBlockNum > 0 { 229 maxActiveBlockNum = cfg.GetModuleConfig().BlockChain.MaxActiveBlockNum 230 } 231 if cfg.GetModuleConfig().BlockChain.MaxActiveBlockSize > 0 { 232 maxActiveBlockSize = cfg.GetModuleConfig().BlockChain.MaxActiveBlockSize 233 } 234 blockStore.activeBlocks = utils.NewSpaceLimitCache(maxActiveBlockNum, maxActiveBlockSize*1024*1024) 235 236 return blockStore 237 } 238 239 //步骤: 240 //检查数据库是否已经进行quickIndex改造 241 //如果没有,那么进行下面的步骤 242 //1. 先把hash 都给改成 TX:hash 243 //2. 把所有的 Tx:hash 都加一个 8字节的index 244 //3. 2000个交易处理一次,并且打印进度 245 //4. 全部处理完成了,添加quickIndex 的标记 246 func (bs *BlockStore) initQuickIndex(height int64) { 247 storeLog.Info("quickIndex upgrade start", "current height", height) 248 batch := bs.db.NewBatch(true) 249 var maxsize = 100 * 1024 * 1024 250 var count = 0 251 cfg := bs.client.GetConfig() 252 for i := int64(0); i <= height; i++ { 253 blockdetail, err := bs.LoadBlock(i, nil) 254 if err != nil { 255 panic(err) 256 } 257 for _, tx := range blockdetail.Block.Txs { 258 hash := tx.Hash() 259 txresult, err := bs.db.Get(hash) 260 if err != nil { 261 panic(err) 262 } 263 count += len(txresult) 264 batch.Set(cfg.CalcTxKey(hash), txresult) 265 batch.Set(types.CalcTxShortKey(hash), []byte("1")) 266 } 267 if count > maxsize { 268 storeLog.Info("initQuickIndex", "height", i) 269 err := batch.Write() 270 if err != nil { 271 panic(err) 272 } 273 batch.Reset() 274 count = 0 275 } 276 } 277 if count > 0 { 278 err := batch.Write() 279 if err != nil { 280 panic(err) 281 } 282 storeLog.Info("initQuickIndex", "height", height) 283 batch.Reset() 284 } 285 bs.saveQuickIndexFlag() 286 } 287 288 // store通用接口: 非block相关的保存功能,用通用的接口 289 // 避免store相关的代码膨胀 290 291 // SetSync store通用接口 292 func (bs *BlockStore) SetSync(key, value []byte) error { 293 return bs.db.SetSync(key, value) 294 } 295 296 // Set store通用接口 297 func (bs *BlockStore) Set(key, value []byte) error { 298 return bs.db.Set(key, value) 299 } 300 301 // GetKey store通用接口, Get 已经被使用 302 func (bs *BlockStore) GetKey(key []byte) ([]byte, error) { 303 value, err := bs.db.Get(key) 304 if err != nil && err != dbm.ErrNotFoundInDb { 305 return nil, types.ErrNotFound 306 307 } 308 return value, err 309 } 310 311 // PrefixCount store通用接口 312 func (bs *BlockStore) PrefixCount(prefix []byte) int64 { 313 counts := dbm.NewListHelper(bs.db).PrefixCount(prefix) 314 return counts 315 } 316 317 // List store通用接口 318 func (bs *BlockStore) List(prefix []byte) ([][]byte, error) { 319 values := dbm.NewListHelper(bs.db).PrefixScan(prefix) 320 if values == nil { 321 return nil, types.ErrNotFound 322 } 323 return values, nil 324 } 325 326 func (bs *BlockStore) delAllKeys() { 327 var allkeys [][]byte 328 allkeys = append(allkeys, GetLocalDBKeyList()...) 329 allkeys = append(allkeys, version.GetLocalDBKeyList()...) 330 allkeys = append(allkeys, types.GetLocalDBKeyList()...) 331 var lastkey []byte 332 isvalid := true 333 for isvalid { 334 lastkey, isvalid = bs.delKeys(lastkey, allkeys) 335 } 336 } 337 338 func (bs *BlockStore) delKeys(seek []byte, allkeys [][]byte) ([]byte, bool) { 339 it := bs.db.Iterator(seek, types.EmptyValue, false) 340 defer it.Close() 341 i := 0 342 count := 0 343 var lastkey []byte 344 for it.Rewind(); it.Valid(); it.Next() { 345 key := it.Key() 346 lastkey = key 347 if it.Error() != nil { 348 panic(it.Error()) 349 } 350 has := false 351 for _, prefix := range allkeys { 352 if bytes.HasPrefix(key, prefix) { 353 has = true 354 break 355 } 356 } 357 if !has { 358 i++ 359 if i > 0 && i%10000 == 0 { 360 chainlog.Info("del key count", "count", i) 361 } 362 err := bs.db.Delete(key) 363 if err != nil { 364 panic(err) 365 } 366 } 367 count++ 368 if count == 1000000 { 369 break 370 } 371 } 372 return lastkey, it.Valid() 373 } 374 375 func (bs *BlockStore) saveQuickIndexFlag() { 376 kv := types.FlagKV(types.FlagTxQuickIndex, 1) 377 err := bs.db.Set(kv.Key, kv.Value) 378 if err != nil { 379 panic(err) 380 } 381 } 382 383 func (bs *BlockStore) loadFlag(key []byte) (int64, error) { 384 flag := &types.Int64{} 385 flagBytes, err := bs.db.Get(key) 386 if err == nil { 387 err = types.Decode(flagBytes, flag) 388 if err != nil { 389 return 0, err 390 } 391 return flag.GetData(), nil 392 } else if err == types.ErrNotFound || err == dbm.ErrNotFoundInDb { 393 return 0, nil 394 } 395 return 0, err 396 } 397 398 //HasTx 是否包含该交易 399 func (bs *BlockStore) HasTx(key []byte) (bool, error) { 400 cfg := bs.client.GetConfig() 401 if cfg.IsEnable("quickIndex") { 402 if _, err := bs.db.Get(types.CalcTxShortKey(key)); err != nil { 403 if err == dbm.ErrNotFoundInDb { 404 return false, nil 405 } 406 return false, err 407 } 408 //通过短hash查询交易存在时,需要再通过全hash索引查询一下。 409 //避免短hash重复,而全hash不一样的情况 410 //return true, nil 411 } 412 if _, err := bs.db.Get(cfg.CalcTxKey(key)); err != nil { 413 if err == dbm.ErrNotFoundInDb { 414 return false, nil 415 } 416 return false, err 417 } 418 return true, nil 419 } 420 421 //Height 返回BlockStore保存的当前block高度 422 func (bs *BlockStore) Height() int64 { 423 return atomic.LoadInt64(&bs.height) 424 } 425 426 //UpdateHeight 更新db中的block高度到BlockStore.Height 427 func (bs *BlockStore) UpdateHeight() { 428 height, err := LoadBlockStoreHeight(bs.db) 429 if err != nil && err != types.ErrHeightNotExist { 430 storeLog.Error("UpdateHeight", "LoadBlockStoreHeight err", err) 431 return 432 } 433 atomic.StoreInt64(&bs.height, height) 434 storeLog.Debug("UpdateHeight", "curblockheight", height) 435 } 436 437 //UpdateHeight2 更新指定的block高度到BlockStore.Height TODO:命名不清晰,不能体现和原来函数的区别 438 func (bs *BlockStore) UpdateHeight2(height int64) { 439 atomic.StoreInt64(&bs.height, height) 440 storeLog.Debug("UpdateHeight2", "curblockheight", height) 441 } 442 443 //LastHeader 返回BlockStore保存的当前blockheader 444 func (bs *BlockStore) LastHeader() *types.Header { 445 bs.lastheaderlock.Lock() 446 defer bs.lastheaderlock.Unlock() 447 448 // 通过lastBlock获取lastheader 449 var blockheader = types.Header{} 450 if bs.lastBlock != nil { 451 blockheader.Version = bs.lastBlock.Version 452 blockheader.ParentHash = bs.lastBlock.ParentHash 453 blockheader.TxHash = bs.lastBlock.TxHash 454 blockheader.StateHash = bs.lastBlock.StateHash 455 blockheader.Height = bs.lastBlock.Height 456 blockheader.BlockTime = bs.lastBlock.BlockTime 457 blockheader.Signature = bs.lastBlock.Signature 458 blockheader.Difficulty = bs.lastBlock.Difficulty 459 460 blockheader.Hash = bs.lastBlock.Hash(bs.client.GetConfig()) 461 blockheader.TxCount = int64(len(bs.lastBlock.Txs)) 462 } 463 return &blockheader 464 } 465 466 //UpdateLastBlock 更新LastBlock到缓存中 467 func (bs *BlockStore) UpdateLastBlock(hash []byte) { 468 blockdetail, err := bs.LoadBlockByHash(hash) 469 if err != nil { 470 storeLog.Error("UpdateLastBlock", "hash", common.ToHex(hash), "error", err) 471 return 472 } 473 bs.lastheaderlock.Lock() 474 defer bs.lastheaderlock.Unlock() 475 if blockdetail != nil { 476 bs.lastBlock = blockdetail.Block 477 } 478 storeLog.Debug("UpdateLastBlock", "UpdateLastBlock", blockdetail.Block.Height, "LastHederhash", common.ToHex(blockdetail.Block.Hash(bs.client.GetConfig()))) 479 } 480 481 //UpdateLastBlock2 更新LastBlock到缓存中 TODO:命名不清晰,不能体现和原来函数的区别 482 func (bs *BlockStore) UpdateLastBlock2(block *types.Block) { 483 bs.lastheaderlock.Lock() 484 defer bs.lastheaderlock.Unlock() 485 bs.lastBlock = block 486 storeLog.Debug("UpdateLastBlock", "UpdateLastBlock", block.Height, "LastHederhash", common.ToHex(block.Hash(bs.client.GetConfig()))) 487 } 488 489 //LastBlock 获取最新的block信息 490 func (bs *BlockStore) LastBlock() *types.Block { 491 bs.lastheaderlock.Lock() 492 defer bs.lastheaderlock.Unlock() 493 if bs.lastBlock != nil { 494 return bs.lastBlock 495 } 496 return nil 497 } 498 499 //Get get 500 func (bs *BlockStore) Get(keys *types.LocalDBGet) *types.LocalReplyValue { 501 var reply types.LocalReplyValue 502 for i := 0; i < len(keys.Keys); i++ { 503 key := keys.Keys[i] 504 value, err := bs.db.Get(key) 505 if err != nil && err != types.ErrNotFound { 506 storeLog.Error("Get", "error", err) 507 } 508 reply.Values = append(reply.Values, value) 509 } 510 return &reply 511 } 512 513 //LoadBlock 通过height高度获取BlockDetail信息, hash可为空 514 //首先通过height+hash 主键获取header和body 515 //如果失败使用旧的代码获取block信息 516 //主要考虑到使用新的软件在localdb没有完成升级之前, 517 //启动的过程中通过height获取区块时需要兼容旧的存储格式 518 //升级完成正常启动之后通过loadBlockByIndex获取block不应该有失败 519 //TODO:升级是否是一次性的,升级完成后需要将无效代码移除 520 func (bs *BlockStore) LoadBlock(height int64, hash []byte) (block *types.BlockDetail, err error) { 521 522 if len(hash) == 0 { 523 hash, err = bs.GetBlockHashByHeight(height) 524 if err != nil { 525 return nil, err 526 } 527 } 528 block, err = bs.loadBlockByIndex("", calcHeightHashKey(height, hash), nil) 529 if block == nil && err != nil { 530 return bs.loadBlockByHashOld(hash) 531 } 532 return block, nil 533 } 534 535 //LoadBlockByHash 通过hash获取BlockDetail信息 536 func (bs *BlockStore) LoadBlockByHash(hash []byte) (*types.BlockDetail, error) { 537 block, _, err := bs.loadBlockByHash(hash) 538 return block, err 539 } 540 541 func (bs *BlockStore) loadBlockByHash(hash []byte) (*types.BlockDetail, int, error) { 542 var blockSize int 543 544 //通过hash索引获取blockdetail 545 blockdetail, err := bs.loadBlockByIndex("hash", hash, nil) 546 if err != nil { 547 storeLog.Error("loadBlockByHash:loadBlockByIndex", "hash", common.ToHex(hash), "err", err) 548 return nil, blockSize, err 549 } 550 blockSize = blockdetail.Size() 551 return blockdetail, blockSize, nil 552 } 553 554 //SaveBlock 批量保存blocks信息到db数据库中,并返回最新的sequence值 555 func (bs *BlockStore) SaveBlock(storeBatch dbm.Batch, blockdetail *types.BlockDetail, sequence int64) (int64, error) { 556 cfg := bs.client.GetConfig() 557 var lastSequence int64 = -1 558 height := blockdetail.Block.Height 559 if len(blockdetail.Receipts) == 0 && len(blockdetail.Block.Txs) != 0 { 560 storeLog.Error("SaveBlock Receipts is nil ", "height", height) 561 } 562 hash := blockdetail.Block.Hash(cfg) 563 //存储区块body和header信息 564 err := bs.saveBlockForTable(storeBatch, blockdetail, true, true) 565 if err != nil { 566 storeLog.Error("SaveBlock:saveBlockForTable", "height", height, "hash", common.ToHex(hash), "error", err) 567 return lastSequence, err 568 } 569 //更新最新的block 高度 570 heightbytes := types.Encode(&types.Int64{Data: height}) 571 storeBatch.Set(blockLastHeight, heightbytes) 572 573 //存储block hash和height的对应关系,便于通过hash查询block 574 storeBatch.Set(calcHashToHeightKey(hash), heightbytes) 575 576 //存储block height和block hash的对应关系,便于通过height查询block 577 storeBatch.Set(calcHeightToHashKey(height), hash) 578 579 if bs.saveSequence || bs.isParaChain { 580 //存储记录block序列执行的type add 581 lastSequence, err = bs.saveBlockSequence(storeBatch, hash, height, types.AddBlock, sequence) 582 if err != nil { 583 storeLog.Error("SaveBlock SaveBlockSequence", "height", height, "hash", common.ToHex(hash), "error", err) 584 return lastSequence, err 585 } 586 } 587 storeLog.Debug("SaveBlock success", "blockheight", height, "hash", common.ToHex(hash)) 588 589 return lastSequence, nil 590 } 591 592 //BlockdetailToBlockBody get block detail 593 func (bs *BlockStore) BlockdetailToBlockBody(blockdetail *types.BlockDetail) *types.BlockBody { 594 cfg := bs.client.GetConfig() 595 height := blockdetail.Block.Height 596 hash := blockdetail.Block.Hash(cfg) 597 var blockbody types.BlockBody 598 blockbody.Txs = blockdetail.Block.Txs 599 blockbody.Receipts = blockdetail.Receipts 600 blockbody.MainHash = hash 601 blockbody.MainHeight = height 602 blockbody.Hash = hash 603 blockbody.Height = height 604 if bs.isParaChain { 605 blockbody.MainHash = blockdetail.Block.MainHash 606 blockbody.MainHeight = blockdetail.Block.MainHeight 607 } 608 return &blockbody 609 } 610 611 //DelBlock 删除block信息从db数据库中 612 func (bs *BlockStore) DelBlock(storeBatch dbm.Batch, blockdetail *types.BlockDetail, sequence int64) (int64, error) { 613 var lastSequence int64 = -1 614 height := blockdetail.Block.Height 615 hash := blockdetail.Block.Hash(bs.client.GetConfig()) 616 617 //更新最新的block高度为前一个高度 618 bytes := types.Encode(&types.Int64{Data: height - 1}) 619 storeBatch.Set(blockLastHeight, bytes) 620 621 //删除block hash和height的对应关系 622 storeBatch.Delete(calcHashToHeightKey(hash)) 623 624 //删除block height和block hash的对应关系,便于通过height查询block 625 storeBatch.Delete(calcHeightToHashKey(height)) 626 627 if bs.saveSequence || bs.isParaChain { 628 //存储记录block序列执行的type del 629 lastSequence, err := bs.saveBlockSequence(storeBatch, hash, height, types.DelBlock, sequence) 630 if err != nil { 631 storeLog.Error("DelBlock SaveBlockSequence", "height", height, "hash", common.ToHex(hash), "error", err) 632 return lastSequence, err 633 } 634 } 635 // 删除主链上本区块存储的平行链标识,侧链的不记录 636 if !bs.isParaChain { 637 parakvs, _ := delParaTxTable(bs.db, height) 638 for _, kv := range parakvs { 639 if len(kv.GetKey()) != 0 && kv.GetValue() == nil { 640 storeBatch.Delete(kv.GetKey()) 641 } 642 } 643 } 644 storeLog.Debug("DelBlock success", "blockheight", height, "hash", common.ToHex(hash)) 645 return lastSequence, nil 646 } 647 648 //GetTx 通过tx hash 从db数据库中获取tx交易信息 649 func (bs *BlockStore) GetTx(hash []byte) (*types.TxResult, error) { 650 if len(hash) == 0 { 651 err := errors.New("input hash is null") 652 return nil, err 653 } 654 cfg := bs.client.GetConfig() 655 rawBytes, err := bs.db.Get(cfg.CalcTxKey(hash)) 656 if rawBytes == nil || err != nil { 657 if err != dbm.ErrNotFoundInDb { 658 storeLog.Error("GetTx", "hash", common.ToHex(hash), "err", err) 659 } 660 err = errors.New("tx not exist") 661 return nil, err 662 } 663 664 var txResult types.TxResult 665 err = proto.Unmarshal(rawBytes, &txResult) 666 if err != nil { 667 return nil, err 668 } 669 return bs.getRealTxResult(&txResult), nil 670 } 671 672 func (bs *BlockStore) getRealTxResult(txr *types.TxResult) *types.TxResult { 673 cfg := bs.client.GetConfig() 674 if !cfg.IsEnable("reduceLocaldb") { 675 return txr 676 } 677 678 var blockinfo *types.BlockDetail 679 var err error 680 var exist bool 681 682 //首先从缓存的活跃区块中获取,不存在时再从数据库获取并保存到活跃区块中供下次使用 683 hash, err := bs.GetBlockHashByHeight(txr.Height) 684 if err != nil { 685 chainlog.Error("getRealTxResult GetBlockHashByHeight", "height", txr.Height, "error", err) 686 return txr 687 } 688 689 blockinfo, exist = bs.GetActiveBlock(string(hash)) 690 if !exist { 691 // 如果是精简版的localdb 则需要从block中获取tx交易内容以及receipt 692 blockinfo, err = bs.LoadBlockByHash(hash) 693 if err != nil { 694 chainlog.Error("getRealTxResult LoadBlockByHash", "height", txr.Height, "hash", common.ToHex(hash), "error", err) 695 return txr 696 } 697 698 //添加到活跃区块的缓存中 699 bs.AddActiveBlock(string(hash), blockinfo) 700 } 701 702 if int(txr.Index) < len(blockinfo.Block.Txs) { 703 txr.Tx = blockinfo.Block.Txs[txr.Index] 704 } 705 if int(txr.Index) < len(blockinfo.Receipts) { 706 txr.Receiptdate = blockinfo.Receipts[txr.Index] 707 } 708 709 return txr 710 } 711 712 //AddTxs 通过批量存储tx信息到db中 713 func (bs *BlockStore) AddTxs(storeBatch dbm.Batch, blockDetail *types.BlockDetail) error { 714 kv, err := bs.getLocalKV(blockDetail) 715 if err != nil { 716 storeLog.Error("indexTxs getLocalKV err", "Height", blockDetail.Block.Height, "err", err) 717 return err 718 } 719 //storelog.Info("add txs kv num", "n", len(kv.KV)) 720 for i := 0; i < len(kv.KV); i++ { 721 if kv.KV[i].Value == nil { 722 storeBatch.Delete(kv.KV[i].Key) 723 } else { 724 storeBatch.Set(kv.KV[i].Key, kv.KV[i].Value) 725 } 726 } 727 return nil 728 } 729 730 //DelTxs 通过批量删除tx信息从db中 731 func (bs *BlockStore) DelTxs(storeBatch dbm.Batch, blockDetail *types.BlockDetail) error { 732 //存储key:addr:flag:height ,value:txhash 733 //flag :0-->from,1--> to 734 //height=height*10000+index 存储账户地址相关的交易 735 kv, err := bs.getDelLocalKV(blockDetail) 736 if err != nil { 737 storeLog.Error("indexTxs getLocalKV err", "Height", blockDetail.Block.Height, "err", err) 738 return err 739 } 740 for i := 0; i < len(kv.KV); i++ { 741 if kv.KV[i].Value == nil { 742 storeBatch.Delete(kv.KV[i].Key) 743 } else { 744 storeBatch.Set(kv.KV[i].Key, kv.KV[i].Value) 745 } 746 } 747 748 return nil 749 } 750 751 //GetHeightByBlockHash 从db数据库中获取指定hash对应的block高度 752 func (bs *BlockStore) GetHeightByBlockHash(hash []byte) (int64, error) { 753 754 heightbytes, err := bs.db.Get(calcHashToHeightKey(hash)) 755 if heightbytes == nil || err != nil { 756 if err != dbm.ErrNotFoundInDb { 757 storeLog.Error("GetHeightByBlockHash", "error", err) 758 } 759 return -1, types.ErrHashNotExist 760 } 761 return decodeHeight(heightbytes) 762 } 763 764 func decodeHeight(heightbytes []byte) (int64, error) { 765 var height types.Int64 766 err := types.Decode(heightbytes, &height) 767 if err != nil { 768 //may be old database format json... 769 err = json.Unmarshal(heightbytes, &height.Data) 770 if err != nil { 771 storeLog.Error("GetHeightByBlockHash Could not unmarshal height bytes", "error", err) 772 return -1, types.ErrUnmarshal 773 } 774 } 775 return height.Data, nil 776 } 777 778 //GetBlockHashByHeight 从db数据库中获取指定height对应的blockhash 779 func (bs *BlockStore) GetBlockHashByHeight(height int64) ([]byte, error) { 780 781 if hash := bs.blockCache.GetBlockHash(height); len(hash) > 0 { 782 return hash, nil 783 } 784 hash, err := bs.db.Get(calcHeightToHashKey(height)) 785 if hash == nil || err != nil { 786 if err != dbm.ErrNotFoundInDb { 787 storeLog.Error("GetBlockHashByHeight", "error", err) 788 } 789 return nil, types.ErrHeightNotExist 790 } 791 return hash, nil 792 } 793 794 //GetBlockHeaderByHeight 通过blockheight获取blockheader 795 //为了兼容旧版本的,需要先通过新的方式来获取,获取失败就使用旧的再获取一次 796 func (bs *BlockStore) GetBlockHeaderByHeight(height int64) (*types.Header, error) { 797 return bs.loadHeaderByIndex(height) 798 } 799 800 //GetBlockHeaderByHash 通过blockhash获取blockheader 801 func (bs *BlockStore) GetBlockHeaderByHash(hash []byte) (*types.Header, error) { 802 //使用table的方式获取,hash索引查table表获取 803 header, err := getHeaderByIndex(bs.db, "hash", hash, nil) 804 if header == nil || err != nil { 805 if err != dbm.ErrNotFoundInDb { 806 storeLog.Error("GetBlockHerderByHash:getHeaderByIndex ", "err", err) 807 } 808 return nil, types.ErrHashNotExist 809 } 810 return header, nil 811 } 812 813 func (bs *BlockStore) getLocalKV(detail *types.BlockDetail) (*types.LocalDBSet, error) { 814 if bs.client == nil { 815 panic("client not bind message queue.") 816 } 817 msg := bs.client.NewMessage("execs", types.EventAddBlock, detail) 818 err := bs.client.Send(msg, true) 819 if err != nil { 820 return nil, err 821 } 822 resp, err := bs.client.Wait(msg) 823 if err != nil { 824 return nil, err 825 } 826 kv := resp.GetData().(*types.LocalDBSet) 827 return kv, nil 828 } 829 830 func (bs *BlockStore) getDelLocalKV(detail *types.BlockDetail) (*types.LocalDBSet, error) { 831 if bs.client == nil { 832 panic("client not bind message queue.") 833 } 834 msg := bs.client.NewMessage("execs", types.EventDelBlock, detail) 835 err := bs.client.Send(msg, true) 836 if err != nil { 837 return nil, err 838 } 839 resp, err := bs.client.Wait(msg) 840 if err != nil { 841 return nil, err 842 } 843 localDBSet := resp.GetData().(*types.LocalDBSet) 844 return localDBSet, nil 845 } 846 847 //GetTdByBlockHash 从db数据库中获取指定blockhash对应的block总难度td 848 func (bs *BlockStore) GetTdByBlockHash(hash []byte) (*big.Int, error) { 849 850 blocktd, err := bs.db.Get(calcHashToTdKey(hash)) 851 if blocktd == nil || err != nil { 852 if err != dbm.ErrNotFoundInDb { 853 storeLog.Error("GetTdByBlockHash ", "error", err) 854 } 855 return nil, types.ErrHashNotExist 856 } 857 td := new(big.Int) 858 return td.SetBytes(blocktd), nil 859 } 860 861 //SaveTdByBlockHash 保存block hash对应的总难度到db中 862 func (bs *BlockStore) SaveTdByBlockHash(storeBatch dbm.Batch, hash []byte, td *big.Int) error { 863 if td == nil { 864 return types.ErrInvalidParam 865 } 866 867 storeBatch.Set(calcHashToTdKey(hash), td.Bytes()) 868 return nil 869 } 870 871 //NewBatch new 872 func (bs *BlockStore) NewBatch(sync bool) dbm.Batch { 873 storeBatch := bs.db.NewBatch(sync) 874 return storeBatch 875 } 876 877 //LoadBlockStoreHeight 加载区块高度 878 func LoadBlockStoreHeight(db dbm.DB) (int64, error) { 879 bytes, err := db.Get(blockLastHeight) 880 if bytes == nil || err != nil { 881 if err != dbm.ErrNotFoundInDb { 882 storeLog.Error("LoadBlockStoreHeight", "error", err) 883 } 884 return -1, types.ErrHeightNotExist 885 } 886 return decodeHeight(bytes) 887 } 888 889 // 将收到的block都暂时存储到db中,加入主链之后会重新覆盖。主要是用于chain重组时获取侧链的block使用 890 func (bs *BlockStore) dbMaybeStoreBlock(blockdetail *types.BlockDetail, sync bool) error { 891 if blockdetail == nil { 892 return types.ErrInvalidParam 893 } 894 height := blockdetail.Block.GetHeight() 895 hash := blockdetail.Block.Hash(bs.client.GetConfig()) 896 storeBatch := bs.batch 897 storeBatch.Reset() 898 storeBatch.UpdateWriteSync(sync) 899 //Save block header和body使用table形式存储 900 err := bs.saveBlockForTable(storeBatch, blockdetail, false, true) 901 if err != nil { 902 chainlog.Error("dbMaybeStoreBlock:saveBlockForTable", "height", height, "hash", common.ToHex(hash), "err", err) 903 return err 904 } 905 //保存block的总难度到db中 906 parentHash := blockdetail.Block.ParentHash 907 908 //转换自己的难度成big.int 909 difficulty := difficulty.CalcWork(blockdetail.Block.Difficulty) 910 911 var blocktd *big.Int 912 if height == 0 { 913 blocktd = difficulty 914 } else { 915 parenttd, err := bs.GetTdByBlockHash(parentHash) 916 if err != nil { 917 chainlog.Error("dbMaybeStoreBlock GetTdByBlockHash", "height", height, "parentHash", common.ToHex(parentHash)) 918 return err 919 } 920 blocktd = new(big.Int).Add(difficulty, parenttd) 921 } 922 923 err = bs.SaveTdByBlockHash(storeBatch, blockdetail.Block.Hash(bs.client.GetConfig()), blocktd) 924 if err != nil { 925 chainlog.Error("dbMaybeStoreBlock SaveTdByBlockHash:", "height", height, "hash", common.ToHex(hash), "err", err) 926 return err 927 } 928 929 err = storeBatch.Write() 930 if err != nil { 931 chainlog.Error("dbMaybeStoreBlock storeBatch.Write:", "err", err) 932 panic(err) 933 } 934 return nil 935 } 936 937 //LoadBlockLastSequence 获取当前最新的block操作序列号 938 func (bs *BlockStore) LoadBlockLastSequence() (int64, error) { 939 lastKey := calcLastSeqKey(bs.isParaChain) 940 bytes, err := bs.db.Get(lastKey) 941 if bytes == nil || err != nil { 942 if err != dbm.ErrNotFoundInDb { 943 storeLog.Error("LoadBlockLastSequence", "error", err) 944 } 945 return -1, types.ErrHeightNotExist 946 } 947 return decodeHeight(bytes) 948 } 949 950 //LoadBlockLastMainSequence 获取当前最新的block操作序列号 951 func (bs *BlockStore) LoadBlockLastMainSequence() (int64, error) { 952 bytes, err := bs.db.Get(LastSequence) 953 if bytes == nil || err != nil { 954 if err != dbm.ErrNotFoundInDb { 955 storeLog.Error("LoadBlockLastMainSequence", "error", err) 956 } 957 return -1, types.ErrHeightNotExist 958 } 959 return decodeHeight(bytes) 960 } 961 962 //SaveBlockSequence 存储block 序列执行的类型用于blockchain的恢复 963 //获取当前的序列号,将此序列号加1存储本block的hash ,当使能isRecordBlockSequence 964 //平行链使能isParaChain时,而外保存主链的 sequence 965 // 需要保存 966 // seq->hash, hash->seq, last_seq 967 // 平行链需要主链的对应信息 968 func (bs *BlockStore) saveBlockSequence(storeBatch dbm.Batch, hash []byte, height int64, Type int64, sequence int64) (int64, error) { 969 var newSequence int64 970 if bs.saveSequence { 971 Sequence, err := bs.LoadBlockLastSequence() 972 if err != nil { 973 storeLog.Error("SaveBlockSequence", "LoadBlockLastSequence err", err) 974 if err != types.ErrHeightNotExist { 975 panic(err) 976 } 977 } 978 979 newSequence = Sequence + 1 980 //开启isRecordBlockSequence功能必须从0开始同步数据,不允许从非0高度开启此功能 981 if newSequence == 0 && height != 0 { 982 storeLog.Error("isRecordBlockSequence is true must Synchronizing data from zero block", "height", height, "seq", newSequence) 983 panic(errors.New("isRecordBlockSequence is true must Synchronizing data from zero block")) 984 } 985 986 // seq->hash 987 var blockSequence types.BlockSequence 988 blockSequence.Hash = hash 989 blockSequence.Type = Type 990 BlockSequenceByte, err := proto.Marshal(&blockSequence) 991 if err != nil { 992 storeLog.Error("SaveBlockSequence Marshal BlockSequence", "hash", common.ToHex(hash), "error", err) 993 return newSequence, err 994 } 995 storeBatch.Set(calcSequenceToHashKey(newSequence, bs.isParaChain), BlockSequenceByte) 996 997 sequenceBytes := types.Encode(&types.Int64{Data: newSequence}) 998 // hash->seq 只记录add block时的hash和seq对应关系 999 if Type == types.AddBlock { 1000 storeBatch.Set(calcHashToSequenceKey(hash, bs.isParaChain), sequenceBytes) 1001 } 1002 1003 // 记录last seq 1004 storeBatch.Set(calcLastSeqKey(bs.isParaChain), sequenceBytes) 1005 } 1006 1007 if !bs.isParaChain { 1008 return newSequence, nil 1009 } 1010 1011 mainSeq := sequence 1012 var blockSequence types.BlockSequence 1013 blockSequence.Hash = hash 1014 blockSequence.Type = Type 1015 BlockSequenceByte, err := proto.Marshal(&blockSequence) 1016 if err != nil { 1017 storeLog.Error("SaveBlockSequence Marshal BlockSequence", "hash", common.ToHex(hash), "error", err) 1018 return newSequence, err 1019 } 1020 storeBatch.Set(calcMainSequenceToHashKey(mainSeq), BlockSequenceByte) 1021 1022 // hash->seq 只记录add block时的hash和seq对应关系 1023 sequenceBytes := types.Encode(&types.Int64{Data: mainSeq}) 1024 if Type == types.AddBlock { 1025 storeBatch.Set(calcHashToMainSequenceKey(hash), sequenceBytes) 1026 } 1027 storeBatch.Set(LastSequence, sequenceBytes) 1028 1029 return newSequence, nil 1030 } 1031 1032 //LoadBlockBySequence 通过seq高度获取BlockDetail信息 1033 func (bs *BlockStore) LoadBlockBySequence(Sequence int64) (*types.BlockDetail, int, error) { 1034 //首先通过Sequence序列号获取对应的blockhash和操作类型从db中 1035 BlockSequence, err := bs.GetBlockSequence(Sequence) 1036 if err != nil { 1037 return nil, 0, err 1038 } 1039 return bs.loadBlockByHash(BlockSequence.Hash) 1040 } 1041 1042 //LoadBlockByMainSequence 通过main seq高度获取BlockDetail信息 1043 func (bs *BlockStore) LoadBlockByMainSequence(sequence int64) (*types.BlockDetail, int, error) { 1044 //首先通过Sequence序列号获取对应的blockhash和操作类型从db中 1045 BlockSequence, err := bs.GetBlockByMainSequence(sequence) 1046 if err != nil { 1047 return nil, 0, err 1048 } 1049 return bs.loadBlockByHash(BlockSequence.Hash) 1050 } 1051 1052 //GetBlockSequence 从db数据库中获取指定Sequence对应的block序列操作信息 1053 func (bs *BlockStore) GetBlockSequence(Sequence int64) (*types.BlockSequence, error) { 1054 var blockSeq types.BlockSequence 1055 blockSeqByte, err := bs.db.Get(calcSequenceToHashKey(Sequence, bs.isParaChain)) 1056 if blockSeqByte == nil || err != nil { 1057 if err != dbm.ErrNotFoundInDb { 1058 storeLog.Error("GetBlockSequence", "error", err) 1059 } 1060 return nil, types.ErrHeightNotExist 1061 } 1062 1063 err = proto.Unmarshal(blockSeqByte, &blockSeq) 1064 if err != nil { 1065 storeLog.Error("GetBlockSequence", "err", err) 1066 return nil, err 1067 } 1068 return &blockSeq, nil 1069 } 1070 1071 //GetBlockByMainSequence 从db数据库中获取指定Sequence对应的block序列操作信息 1072 func (bs *BlockStore) GetBlockByMainSequence(sequence int64) (*types.BlockSequence, error) { 1073 var blockSeq types.BlockSequence 1074 blockSeqByte, err := bs.db.Get(calcMainSequenceToHashKey(sequence)) 1075 if blockSeqByte == nil || err != nil { 1076 if err != dbm.ErrNotFoundInDb { 1077 storeLog.Error("GetBlockByMainSequence", "error", err) 1078 } 1079 return nil, types.ErrHeightNotExist 1080 } 1081 1082 err = proto.Unmarshal(blockSeqByte, &blockSeq) 1083 if err != nil { 1084 storeLog.Error("GetBlockByMainSequence", "err", err) 1085 return nil, err 1086 } 1087 return &blockSeq, nil 1088 } 1089 1090 //GetSequenceByHash 通过block还是获取对应的seq 1091 func (bs *BlockStore) GetSequenceByHash(hash []byte) (int64, error) { 1092 var seq types.Int64 1093 seqbytes, err := bs.db.Get(calcHashToSequenceKey(hash, bs.isParaChain)) 1094 if seqbytes == nil || err != nil { 1095 if err != dbm.ErrNotFoundInDb { 1096 storeLog.Error("GetSequenceByHash", "error", err) 1097 } 1098 return -1, types.ErrHashNotExist 1099 } 1100 1101 err = types.Decode(seqbytes, &seq) 1102 if err != nil { 1103 storeLog.Error("GetSequenceByHash types.Decode", "error", err) 1104 return -1, types.ErrUnmarshal 1105 } 1106 return seq.Data, nil 1107 } 1108 1109 //GetMainSequenceByHash 通过block还是获取对应的seq,只提供给parachain使用 1110 func (bs *BlockStore) GetMainSequenceByHash(hash []byte) (int64, error) { 1111 var seq types.Int64 1112 seqbytes, err := bs.db.Get(calcHashToMainSequenceKey(hash)) 1113 if seqbytes == nil || err != nil { 1114 if err != dbm.ErrNotFoundInDb { 1115 storeLog.Error("GetMainSequenceByHash", "error", err) 1116 } 1117 return -1, types.ErrHashNotExist 1118 } 1119 1120 err = types.Decode(seqbytes, &seq) 1121 if err != nil { 1122 storeLog.Error("GetMainSequenceByHash types.Decode", "error", err) 1123 return -1, types.ErrUnmarshal 1124 } 1125 return seq.Data, nil 1126 } 1127 1128 //GetDbVersion 获取blockchain的数据库版本号 1129 func (bs *BlockStore) GetDbVersion() int64 { 1130 ver := types.Int64{} 1131 version, err := bs.db.Get(version.BlockChainVerKey) 1132 if err != nil && err != types.ErrNotFound { 1133 storeLog.Info("GetDbVersion", "err", err) 1134 return 0 1135 } 1136 if len(version) == 0 { 1137 storeLog.Info("GetDbVersion len(version)==0") 1138 return 0 1139 } 1140 err = types.Decode(version, &ver) 1141 if err != nil { 1142 storeLog.Info("GetDbVersion", "types.Decode err", err) 1143 return 0 1144 } 1145 storeLog.Info("GetDbVersion", "blockchain db version", ver.Data) 1146 return ver.Data 1147 } 1148 1149 //SetDbVersion 获取blockchain的数据库版本号 1150 func (bs *BlockStore) SetDbVersion(versionNo int64) error { 1151 ver := types.Int64{Data: versionNo} 1152 verByte := types.Encode(&ver) 1153 1154 storeLog.Info("SetDbVersion", "blcokchain db version", versionNo) 1155 1156 return bs.db.SetSync(version.BlockChainVerKey, verByte) 1157 } 1158 1159 //GetUpgradeMeta 获取blockchain的数据库版本号 1160 func (bs *BlockStore) GetUpgradeMeta() (*types.UpgradeMeta, error) { 1161 ver := types.UpgradeMeta{} 1162 version, err := bs.db.Get(version.LocalDBMeta) 1163 if err != nil && err != dbm.ErrNotFoundInDb { 1164 return nil, err 1165 } 1166 if len(version) == 0 { 1167 return &types.UpgradeMeta{Version: "0.0.0"}, nil 1168 } 1169 err = types.Decode(version, &ver) 1170 if err != nil { 1171 return nil, err 1172 } 1173 storeLog.Info("GetUpgradeMeta", "blockchain db version", ver) 1174 return &ver, nil 1175 } 1176 1177 //SetUpgradeMeta 设置blockchain的数据库版本号 1178 func (bs *BlockStore) SetUpgradeMeta(meta *types.UpgradeMeta) error { 1179 verByte := types.Encode(meta) 1180 storeLog.Info("SetUpgradeMeta", "meta", meta) 1181 return bs.db.SetSync(version.LocalDBMeta, verByte) 1182 } 1183 1184 //GetStoreUpgradeMeta 获取存在blockchain中的Store的数据库版本号 1185 func (bs *BlockStore) GetStoreUpgradeMeta() (*types.UpgradeMeta, error) { 1186 ver := types.UpgradeMeta{} 1187 version, err := bs.db.Get(version.StoreDBMeta) 1188 if err != nil && err != dbm.ErrNotFoundInDb { 1189 return nil, err 1190 } 1191 if len(version) == 0 { 1192 return &types.UpgradeMeta{Version: "0.0.0"}, nil 1193 } 1194 err = types.Decode(version, &ver) 1195 if err != nil { 1196 return nil, err 1197 } 1198 storeLog.Info("GetStoreUpgradeMeta", "blockchain db version", ver) 1199 return &ver, nil 1200 } 1201 1202 //SetStoreUpgradeMeta 设置blockchain中的Store的数据库版本号 1203 func (bs *BlockStore) SetStoreUpgradeMeta(meta *types.UpgradeMeta) error { 1204 verByte := types.Encode(meta) 1205 storeLog.Debug("SetStoreUpgradeMeta", "meta", meta) 1206 return bs.db.SetSync(version.StoreDBMeta, verByte) 1207 } 1208 1209 const ( 1210 seqStatusOk = iota 1211 seqStatusNeedCreate 1212 ) 1213 1214 //CheckSequenceStatus 配置的合法性检测 1215 func (bs *BlockStore) CheckSequenceStatus(recordSequence bool) int { 1216 lastHeight := bs.Height() 1217 lastSequence, err := bs.LoadBlockLastSequence() 1218 if err != nil { 1219 if err != types.ErrHeightNotExist { 1220 storeLog.Error("CheckSequenceStatus", "LoadBlockLastSequence err", err) 1221 panic(err) 1222 } 1223 } 1224 //使能isRecordBlockSequence时的检测 1225 if recordSequence { 1226 //中途开启isRecordBlockSequence报错 1227 if lastSequence == -1 && lastHeight != -1 { 1228 storeLog.Error("CheckSequenceStatus", "lastHeight", lastHeight, "lastSequence", lastSequence) 1229 return seqStatusNeedCreate 1230 } 1231 //lastSequence 必须大于等于lastheight 1232 if lastHeight > lastSequence { 1233 storeLog.Error("CheckSequenceStatus", "lastHeight", lastHeight, "lastSequence", lastSequence) 1234 return seqStatusNeedCreate 1235 } 1236 return seqStatusOk 1237 } 1238 //去使能isRecordBlockSequence时的检测 1239 if lastSequence != -1 { 1240 storeLog.Error("CheckSequenceStatus", "lastSequence", lastSequence) 1241 panic("can not disable isRecordBlockSequence") 1242 } 1243 return seqStatusOk 1244 } 1245 1246 //CreateSequences 根据高度生成sequence记录 1247 func (bs *BlockStore) CreateSequences(batchSize int64) { 1248 lastSeq, err := bs.LoadBlockLastSequence() 1249 if err != nil { 1250 if err != types.ErrHeightNotExist { 1251 storeLog.Error("CreateSequences LoadBlockLastSequence", "error", err) 1252 panic("CreateSequences LoadBlockLastSequence" + err.Error()) 1253 } 1254 } 1255 storeLog.Info("CreateSequences LoadBlockLastSequence", "start", lastSeq) 1256 1257 newBatch := bs.NewBatch(true) 1258 lastHeight := bs.Height() 1259 1260 for i := lastSeq + 1; i <= lastHeight; i++ { 1261 seq := i 1262 header, err := bs.GetBlockHeaderByHeight(i) 1263 if err != nil { 1264 storeLog.Error("CreateSequences GetBlockHeaderByHeight", "height", i, "error", err) 1265 panic("CreateSequences GetBlockHeaderByHeight" + err.Error()) 1266 } 1267 1268 // seq->hash 1269 var blockSequence types.BlockSequence 1270 blockSequence.Hash = header.Hash 1271 blockSequence.Type = types.AddBlock 1272 BlockSequenceByte, err := proto.Marshal(&blockSequence) 1273 if err != nil { 1274 storeLog.Error("CreateSequences Marshal BlockSequence", "height", i, "hash", common.ToHex(header.Hash), "error", err) 1275 panic("CreateSequences Marshal BlockSequence" + err.Error()) 1276 } 1277 newBatch.Set(calcSequenceToHashKey(seq, bs.isParaChain), BlockSequenceByte) 1278 1279 // hash -> seq 1280 sequenceBytes := types.Encode(&types.Int64{Data: seq}) 1281 newBatch.Set(calcHashToSequenceKey(header.Hash, bs.isParaChain), sequenceBytes) 1282 1283 if i-lastSeq == batchSize { 1284 storeLog.Info("CreateSequences ", "height", i) 1285 newBatch.Set(calcLastSeqKey(bs.isParaChain), types.Encode(&types.Int64{Data: i})) 1286 err = newBatch.Write() 1287 if err != nil { 1288 storeLog.Error("CreateSequences newBatch.Write", "error", err) 1289 panic("CreateSequences newBatch.Write" + err.Error()) 1290 } 1291 lastSeq = i 1292 newBatch.Reset() 1293 } 1294 } 1295 // last seq 1296 newBatch.Set(calcLastSeqKey(bs.isParaChain), types.Encode(&types.Int64{Data: lastHeight})) 1297 err = newBatch.Write() 1298 if err != nil { 1299 storeLog.Error("CreateSequences newBatch.Write", "error", err) 1300 panic("CreateSequences newBatch.Write" + err.Error()) 1301 } 1302 storeLog.Info("CreateSequences done") 1303 } 1304 1305 //SetConsensusPara 设置kv到数据库,当value是空时需要delete操作 1306 func (bs *BlockStore) SetConsensusPara(kvs *types.LocalDBSet) error { 1307 var isSync bool 1308 if kvs.GetTxid() != 0 { 1309 isSync = true 1310 } 1311 batch := bs.db.NewBatch(isSync) 1312 for i := 0; i < len(kvs.KV); i++ { 1313 if types.CheckConsensusParaTxsKey(kvs.KV[i].Key) { 1314 if kvs.KV[i].Value == nil { 1315 batch.Delete(kvs.KV[i].Key) 1316 } else { 1317 batch.Set(kvs.KV[i].Key, kvs.KV[i].Value) 1318 } 1319 } else { 1320 storeLog.Error("Set:CheckConsensusParaTxsKey:fail", "key", string(kvs.KV[i].Key)) 1321 } 1322 } 1323 err := batch.Write() 1324 if err != nil { 1325 panic(err) 1326 } 1327 return err 1328 } 1329 1330 //saveBlockForTable 将block的header和body以及paratx保存成table形式,方便快速查询 1331 func (bs *BlockStore) saveBlockForTable(storeBatch dbm.Batch, blockdetail *types.BlockDetail, isBestChain, isSaveReceipt bool) error { 1332 1333 height := blockdetail.Block.Height 1334 cfg := bs.client.GetConfig() 1335 hash := blockdetail.Block.Hash(cfg) 1336 1337 // Save blockbody 1338 blockbody := bs.BlockdetailToBlockBody(blockdetail) 1339 // 这里将blockbody进行中的receipt拆分成独立的一张表, 1340 // 因此body中只保存Receipts的结果,具体内容在ReceiptTable中 1341 blockbody.Receipts = reduceReceipts(blockbody) 1342 bodykvs, err := saveBlockBodyTable(bs.db, blockbody) 1343 if err != nil { 1344 storeLog.Error("SaveBlockForTable:saveBlockBodyTable", "height", height, "hash", common.ToHex(hash), "err", err) 1345 return err 1346 } 1347 for _, kv := range bodykvs { 1348 storeBatch.Set(kv.GetKey(), kv.GetValue()) 1349 } 1350 1351 // Save blockReceipt 1352 if isSaveReceipt { 1353 blockReceipt := &types.BlockReceipt{ 1354 Receipts: blockdetail.Receipts, 1355 Hash: hash, 1356 Height: height, 1357 } 1358 recptkvs, err := saveBlockReceiptTable(bs.db, blockReceipt) 1359 if err != nil { 1360 storeLog.Error("SaveBlockForTable:saveBlockReceiptTable", "height", height, "hash", common.ToHex(hash), "err", err) 1361 return err 1362 } 1363 for _, kv := range recptkvs { 1364 storeBatch.Set(kv.GetKey(), kv.GetValue()) 1365 } 1366 } 1367 1368 // Save blockheader 1369 var blockheader types.Header 1370 blockheader.Version = blockdetail.Block.Version 1371 blockheader.ParentHash = blockdetail.Block.ParentHash 1372 blockheader.TxHash = blockdetail.Block.TxHash 1373 blockheader.StateHash = blockdetail.Block.StateHash 1374 blockheader.Height = blockdetail.Block.Height 1375 blockheader.BlockTime = blockdetail.Block.BlockTime 1376 blockheader.Signature = blockdetail.Block.Signature 1377 blockheader.Difficulty = blockdetail.Block.Difficulty 1378 blockheader.Hash = hash 1379 blockheader.TxCount = int64(len(blockdetail.Block.Txs)) 1380 1381 headerkvs, err := saveHeaderTable(bs.db, &blockheader) 1382 if err != nil { 1383 storeLog.Error("SaveBlock:saveHeaderTable", "height", height, "hash", common.ToHex(hash), "err", err) 1384 return err 1385 } 1386 for _, kv := range headerkvs { 1387 storeBatch.Set(kv.GetKey(), kv.GetValue()) 1388 } 1389 1390 //只过滤主链上的平行链交易 1391 if isBestChain && !bs.isParaChain { 1392 paratxkvs, err := saveParaTxTable(cfg, bs.db, height, hash, blockdetail.Block.Txs) 1393 if err != nil { 1394 storeLog.Error("SaveBlock:saveParaTxTable", "height", height, "hash", common.ToHex(hash), "err", err) 1395 return err 1396 } 1397 for _, kv := range paratxkvs { 1398 storeBatch.Set(kv.GetKey(), kv.GetValue()) 1399 } 1400 } 1401 return nil 1402 } 1403 1404 //loadBlockByIndex 通过索引获取BlockDetail信息 1405 func (bs *BlockStore) loadBlockByIndex(indexName string, prefix []byte, primaryKey []byte) (*types.BlockDetail, error) { 1406 cfg := bs.client.GetConfig() 1407 //获取header 1408 blockheader, err := getHeaderByIndex(bs.db, indexName, prefix, primaryKey) 1409 if blockheader == nil || err != nil { 1410 if err != dbm.ErrNotFoundInDb { 1411 storeLog.Error("loadBlockByIndex:getHeaderByIndex", "indexName", indexName, "prefix", prefix, "primaryKey", primaryKey, "err", err) 1412 } 1413 return nil, types.ErrHashNotExist 1414 } 1415 1416 //获取body 1417 blockbody, err := bs.multiGetBody(blockheader, indexName, prefix, primaryKey) 1418 if blockbody == nil || err != nil { 1419 return nil, err 1420 } 1421 1422 blockreceipt := blockbody.Receipts 1423 // 非精简节点查询时候需要在ReceiptTable中获取详细的receipt信息, 精简情况下可以获取未精简部分receipt 1424 if !cfg.IsEnable("reduceLocaldb") || bs.Height() < blockheader.Height+ReduceHeight { 1425 receipt, err := getReceiptByIndex(bs.db, indexName, prefix, primaryKey) 1426 if receipt != nil { 1427 blockreceipt = receipt.Receipts 1428 } else { 1429 storeLog.Error("loadBlockByIndex:getReceiptByIndex", "indexName", indexName, "prefix", prefix, "primaryKey", primaryKey, "err", err) 1430 if !cfg.IsEnable("reduceLocaldb") { 1431 return nil, types.ErrHashNotExist 1432 } 1433 } 1434 } 1435 1436 var blockdetail types.BlockDetail 1437 var block types.Block 1438 1439 block.Version = blockheader.Version 1440 block.ParentHash = blockheader.ParentHash 1441 block.TxHash = blockheader.TxHash 1442 block.StateHash = blockheader.StateHash 1443 block.Height = blockheader.Height 1444 block.BlockTime = blockheader.BlockTime 1445 block.Signature = blockheader.Signature 1446 block.Difficulty = blockheader.Difficulty 1447 block.Txs = blockbody.Txs 1448 block.MainHeight = blockbody.MainHeight 1449 block.MainHash = blockbody.MainHash 1450 1451 blockdetail.Receipts = blockreceipt 1452 blockdetail.Block = &block 1453 return &blockdetail, nil 1454 } 1455 1456 //loadHeaderByIndex 通过索引获取区块头信息 1457 func (bs *BlockStore) loadHeaderByIndex(height int64) (*types.Header, error) { 1458 1459 hash, err := bs.GetBlockHashByHeight(height) 1460 if err != nil { 1461 return nil, err 1462 } 1463 1464 header, err := getHeaderByIndex(bs.db, "", calcHeightHashKey(height, hash), nil) 1465 if header == nil || err != nil { 1466 if err != dbm.ErrNotFoundInDb { 1467 storeLog.Error("loadHeaderByHeight:getHeaderByIndex", "error", err) 1468 } 1469 return nil, types.ErrHashNotExist 1470 } 1471 return header, nil 1472 } 1473 1474 //loadBlockByHashOld 需要在db升级之前使用旧的key值获取block信息 1475 func (bs *BlockStore) loadBlockByHashOld(hash []byte) (*types.BlockDetail, error) { 1476 var blockdetail types.BlockDetail 1477 var blockheader types.Header 1478 var blockbody types.BlockBody 1479 var block types.Block 1480 1481 //通过hash获取blockheader 1482 header, err := bs.db.Get(calcHashToBlockHeaderKey(hash)) 1483 if header == nil || err != nil { 1484 if err != dbm.ErrNotFoundInDb { 1485 storeLog.Error("loadBlockByHashOld:calcHashToBlockHeaderKey", "hash", common.ToHex(hash), "err", err) 1486 } 1487 return nil, types.ErrHashNotExist 1488 } 1489 err = proto.Unmarshal(header, &blockheader) 1490 if err != nil { 1491 storeLog.Error("loadBlockByHashOld", "err", err) 1492 return nil, err 1493 } 1494 1495 //通过hash获取blockbody 1496 body, err := bs.db.Get(calcHashToBlockBodyKey(hash)) 1497 if body == nil || err != nil { 1498 if err != dbm.ErrNotFoundInDb { 1499 storeLog.Error("loadBlockByHashOld:calcHashToBlockBodyKey ", "err", err) 1500 } 1501 return nil, types.ErrHashNotExist 1502 } 1503 err = proto.Unmarshal(body, &blockbody) 1504 if err != nil { 1505 storeLog.Error("loadBlockByHashOld", "err", err) 1506 return nil, err 1507 } 1508 1509 block.Version = blockheader.Version 1510 block.ParentHash = blockheader.ParentHash 1511 block.TxHash = blockheader.TxHash 1512 block.StateHash = blockheader.StateHash 1513 block.Height = blockheader.Height 1514 block.BlockTime = blockheader.BlockTime 1515 block.Signature = blockheader.Signature 1516 block.Difficulty = blockheader.Difficulty 1517 block.Txs = blockbody.Txs 1518 block.MainHeight = blockbody.MainHeight 1519 block.MainHash = blockbody.MainHash 1520 blockdetail.Receipts = blockbody.Receipts 1521 blockdetail.Block = &block 1522 1523 return &blockdetail, nil 1524 } 1525 1526 //loadBlockByHeightOld 在版本升级到2.0.0时需要使用旧接口获取block信息 1527 func (bs *BlockStore) loadBlockByHeightOld(height int64) (*types.BlockDetail, error) { 1528 hash, err := bs.GetBlockHashByHeight(height) 1529 if err != nil { 1530 return nil, err 1531 } 1532 return bs.loadBlockByHashOld(hash) 1533 } 1534 1535 //getBlockHeaderByHeightOld 需要在db升级之前使用旧的key值获取header信息 1536 func (bs *BlockStore) getBlockHeaderByHeightOld(height int64) (*types.Header, error) { 1537 blockheader, err := bs.db.Get(calcHeightToBlockHeaderKey(height)) 1538 if err != nil { 1539 var hash []byte 1540 hash, err = bs.GetBlockHashByHeight(height) 1541 if err != nil { 1542 return nil, err 1543 } 1544 blockheader, err = bs.db.Get(calcHashToBlockHeaderKey(hash)) 1545 } 1546 if blockheader == nil || err != nil { 1547 if err != dbm.ErrNotFoundInDb { 1548 storeLog.Error("getBlockHeaderByHeightOld:calcHashToBlockHeaderKey", "error", err) 1549 } 1550 return nil, types.ErrHashNotExist 1551 } 1552 var header types.Header 1553 err = proto.Unmarshal(blockheader, &header) 1554 if err != nil { 1555 storeLog.Error("getBlockHeaderByHeightOld", "Could not unmarshal blockheader:", blockheader) 1556 return nil, err 1557 } 1558 return &header, nil 1559 } 1560 1561 //loadBlockBySequenceOld 通过seq高度获取BlockDetail信息,v2版本升级时调用 1562 //可能存在回滚的处理,所以先查旧的,查抄不到就按新的方式再查 1563 func (bs *BlockStore) loadBlockBySequenceOld(Sequence int64) (*types.BlockDetail, int64, error) { 1564 1565 blockSeq, err := bs.GetBlockSequence(Sequence) 1566 if err != nil { 1567 return nil, 0, err 1568 } 1569 1570 block, err := bs.loadBlockByHashOld(blockSeq.Hash) 1571 if err != nil { 1572 block, err = bs.LoadBlockByHash(blockSeq.Hash) 1573 if err != nil { 1574 storeLog.Error("getBlockHeaderByHeightOld", "Sequence", Sequence, "type", blockSeq.Type, "hash", common.ToHex(blockSeq.Hash), "err", err) 1575 panic(err) 1576 } 1577 } 1578 return block, blockSeq.GetType(), nil 1579 } 1580 1581 func (bs *BlockStore) saveReduceLocaldbFlag() { 1582 kv := types.FlagKV(types.FlagReduceLocaldb, 1) 1583 err := bs.db.Set(kv.Key, kv.Value) 1584 if err != nil { 1585 panic(err) 1586 } 1587 } 1588 1589 func (bs *BlockStore) mustSaveKvset(kv *types.LocalDBSet) { 1590 batch := bs.NewBatch(false) 1591 for i := 0; i < len(kv.KV); i++ { 1592 if kv.KV[i].Value == nil { 1593 batch.Delete(kv.KV[i].Key) 1594 } else { 1595 batch.Set(kv.KV[i].Key, kv.KV[i].Value) 1596 } 1597 } 1598 dbm.MustWrite(batch) 1599 } 1600 1601 func (bs *BlockStore) multiGetBody(blockheader *types.Header, indexName string, prefix []byte, primaryKey []byte) (*types.BlockBody, error) { 1602 cfg := bs.client.GetConfig() 1603 chainCfg := cfg.GetModuleConfig().BlockChain 1604 1605 blockbody, err := getBodyByIndex(bs.db, indexName, prefix, primaryKey) 1606 if blockbody == nil || err != nil { 1607 if blockheader.GetHeight() > bs.Height()-MaxRollBlockNum-(chainCfg.ChunkblockNum)*int64(DelRollbackChunkNum) { 1608 // 该高度范围应该保存在本地 1609 return nil, types.ErrHashNotExist 1610 } 1611 if !chainCfg.DisableShard && chainCfg.EnableFetchP2pstore { 1612 bodys, err := bs.getBodyFromP2Pstore(blockheader.Hash, blockheader.Height, blockheader.Height) 1613 if bodys == nil || len(bodys.Items) == 0 || err != nil { 1614 if err != dbm.ErrNotFoundInDb { 1615 storeLog.Error("multiGetBody:getBodyFromP2Pstore", "indexName", indexName, "prefix", prefix, 1616 "primaryKey", primaryKey, "err", err, "hash", common.ToHex(blockheader.Hash)) 1617 } 1618 return nil, types.ErrHashNotExist 1619 } 1620 blockbody = bodys.Items[0] 1621 return blockbody, nil 1622 } 1623 1624 if err != dbm.ErrNotFoundInDb { 1625 storeLog.Error("multiGetBody:getBodyByIndex", "indexName", indexName, "prefix", prefix, "primaryKey", primaryKey, "err", err) 1626 } 1627 return nil, types.ErrHashNotExist 1628 } 1629 return blockbody, nil 1630 } 1631 1632 func (bs *BlockStore) getBodyFromP2Pstore(hash []byte, start, end int64) (*types.BlockBodys, error) { 1633 stime := time.Now() 1634 defer func() { 1635 etime := time.Now() 1636 storeLog.Info("getBodyFromP2Pstore", "start", start, "end", end, "cost time", etime.Sub(stime)) 1637 }() 1638 //value, err := bs.db.Get(calcBlockHashToChunkHash(hash)) 1639 //if value == nil || err != nil { 1640 // if err != dbm.ErrNotFoundInDb { 1641 // storeLog.Error("getBodyFromP2Pstore:calcBlockHashToChunkHash", "hash", common.ToHex(hash), "chunkhash", common.ToHex(value), "err", err) 1642 // } 1643 // return nil, types.ErrHashNotExist 1644 //} 1645 cfg := bs.client.GetConfig() 1646 chainCfg := cfg.GetModuleConfig().BlockChain 1647 chunkNum := start / chainCfg.ChunkblockNum 1648 value, err := bs.db.Get(calcChunkNumToHash(chunkNum)) 1649 if err != nil { 1650 return nil, types.ErrHashNotExist 1651 } 1652 var chunkInfo types.ChunkInfo 1653 if err := types.Decode(value, &chunkInfo); err != nil { 1654 return nil, types.ErrDecode 1655 } 1656 1657 if bs.client == nil { 1658 storeLog.Error("getBodyFromP2Pstore: chain client not bind message queue.") 1659 return nil, types.ErrClientNotBindQueue 1660 } 1661 req := &types.ChunkInfoMsg{ 1662 ChunkHash: chunkInfo.ChunkHash, 1663 Start: start, 1664 End: end, 1665 } 1666 msg := bs.client.NewMessage("p2p", types.EventGetChunkBlockBody, req) 1667 err = bs.client.Send(msg, true) 1668 if err != nil { 1669 storeLog.Error("EventGetChunkBlockBody", "chunk hash", common.ToHex(value), "hash", common.ToHex(hash), "err", err) 1670 return nil, err 1671 } 1672 // 网络查询阻塞最长等待3分钟 1673 resp, err := bs.client.WaitTimeout(msg, time.Minute*3) 1674 if err != nil { 1675 storeLog.Error("EventGetChunkBlockBody", "client.Wait err:", err) 1676 return nil, err 1677 } 1678 bodys, ok := resp.Data.(*types.BlockBodys) 1679 if !ok { 1680 err = types.ErrNotFound 1681 storeLog.Error("EventGetChunkBlockBody", "client.Wait err:", err) 1682 return nil, err 1683 } 1684 return bodys, nil 1685 } 1686 1687 func (bs *BlockStore) getCurChunkNum(prefix []byte) int64 { 1688 it := bs.db.Iterator(prefix, nil, true) 1689 defer it.Close() 1690 height := int64(-1) 1691 var err error 1692 if it.Rewind() && it.Valid() { 1693 height, err = strconv.ParseInt(string(bytes.TrimPrefix(it.Key(), prefix)), 10, 64) 1694 if err != nil { 1695 return -1 1696 } 1697 } 1698 return height 1699 } 1700 1701 func (bs *BlockStore) getRecvChunkHash(chunkNum int64) ([]byte, error) { 1702 value, err := bs.GetKey(calcRecvChunkNumToHash(chunkNum)) 1703 if err != nil { 1704 storeLog.Error("getRecvChunkHash", "chunkNum", chunkNum, "error", err) 1705 return nil, err 1706 } 1707 var chunk types.ChunkInfo 1708 err = types.Decode(value, &chunk) 1709 if err != nil { 1710 storeLog.Error("getRecvChunkHash", "chunkNum", chunkNum, "decode err:", err) 1711 return nil, err 1712 } 1713 return chunk.ChunkHash, err 1714 } 1715 1716 //GetMaxSerialChunkNum get max serial chunk num 1717 func (bs *BlockStore) GetMaxSerialChunkNum() int64 { 1718 value, err := bs.db.Get(MaxSerialChunkNum) 1719 if err != nil { 1720 return -1 1721 } 1722 chunkNum := &types.Int64{} 1723 err = types.Decode(value, chunkNum) 1724 if err != nil { 1725 return -1 1726 } 1727 return chunkNum.Data 1728 } 1729 1730 //SetMaxSerialChunkNum set max serial chunk num 1731 func (bs *BlockStore) SetMaxSerialChunkNum(chunkNum int64) error { 1732 data := &types.Int64{ 1733 Data: chunkNum, 1734 } 1735 return bs.db.Set(MaxSerialChunkNum, types.Encode(data)) 1736 } 1737 1738 // GetMaxDeletedChunkNum gets max chunkNum of deleted chunks. 1739 func (bs *BlockStore) GetMaxDeletedChunkNum() int64 { 1740 value, err := bs.db.Get(MaxDeletedChunkNum) 1741 if err != nil { 1742 return -1 1743 } 1744 chunkNum := &types.Int64{} 1745 err = types.Decode(value, chunkNum) 1746 if err != nil { 1747 return -1 1748 } 1749 return chunkNum.Data 1750 } 1751 1752 // SetMaxDeletedChunkNum sets max chunkNum of deleted chunks. 1753 func (bs *BlockStore) SetMaxDeletedChunkNum(chunkNum int64) error { 1754 data := &types.Int64{ 1755 Data: chunkNum, 1756 } 1757 return bs.db.Set(MaxDeletedChunkNum, types.Encode(data)) 1758 } 1759 1760 // GetActiveBlock :从缓存的活跃区块中获取对应高度的区块 1761 func (bs *BlockStore) GetActiveBlock(hash string) (*types.BlockDetail, bool) { 1762 block := bs.activeBlocks.Get(hash) 1763 if block != nil { 1764 return block.(*types.BlockDetail), true 1765 } 1766 return nil, false 1767 } 1768 1769 // AddActiveBlock :将区块缓存到活跃区块中 1770 func (bs *BlockStore) AddActiveBlock(hash string, block *types.BlockDetail) bool { 1771 return bs.activeBlocks.Add(hash, block, block.Size()) 1772 } 1773 1774 // RemoveActiveBlock :从缓存的活跃区块中删除对应的区块 1775 func (bs *BlockStore) RemoveActiveBlock(hash string) bool { 1776 _, ok := bs.activeBlocks.Remove(hash) 1777 return ok 1778 }