github.com/turingchain2020/turingchain@v1.1.21/blockchain/rollback.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 "syscall" 10 11 "github.com/turingchain2020/turingchain/common" 12 "github.com/turingchain2020/turingchain/common/db" 13 "github.com/turingchain2020/turingchain/types" 14 ) 15 16 // Rollbackblock chain Rollbackblock 17 func (chain *BlockChain) Rollbackblock() { 18 tipnode := chain.bestChain.Tip() 19 if chain.cfg.RollbackBlock > 0 { 20 if chain.NeedRollback(tipnode.height, chain.cfg.RollbackBlock) { 21 chainlog.Info("chain rollback start") 22 chain.Rollback() 23 chainlog.Info("chain rollback end") 24 } 25 syscall.Exit(0) 26 } 27 } 28 29 // NeedRollback need Rollback 30 func (chain *BlockChain) NeedRollback(curHeight, rollHeight int64) bool { 31 if curHeight <= rollHeight { 32 chainlog.Info("curHeight is small than rollback height, no need rollback") 33 return false 34 } 35 cfg := chain.client.GetConfig() 36 kvmvccMavlFork := cfg.GetDappFork("store-kvmvccmavl", "ForkKvmvccmavl") 37 if curHeight >= kvmvccMavlFork+10000 && rollHeight <= kvmvccMavlFork { 38 chainlog.Info("because ForkKvmvccmavl", "current height", curHeight, "not support rollback to", rollHeight) 39 return false 40 } 41 return true 42 } 43 44 // Rollback chain Rollback 45 func (chain *BlockChain) Rollback() { 46 cfg := chain.client.GetConfig() 47 //获取当前的tip节点 48 tipnode := chain.bestChain.Tip() 49 startHeight := tipnode.height 50 for i := startHeight; i > chain.cfg.RollbackBlock; i-- { 51 blockdetail, err := chain.blockStore.LoadBlock(i, nil) 52 if err != nil { 53 panic(fmt.Sprintln("rollback LoadBlock err :", err)) 54 } 55 if chain.cfg.RollbackSave { //本地保存临时区块 56 lastHeightSave := false 57 if i == startHeight { 58 lastHeightSave = true 59 } 60 err = chain.WriteBlockToDbTemp(blockdetail.Block, lastHeightSave) 61 if err != nil { 62 panic(fmt.Sprintln("rollback WriteBlockToDbTemp fail", "height", blockdetail.Block.Height, "error ", err)) 63 } 64 } 65 sequence := int64(-1) 66 if chain.isParaChain { 67 // 获取平行链的seq 68 sequence, err = chain.ProcGetMainSeqByHash(blockdetail.Block.Hash(cfg)) 69 if err != nil { 70 chainlog.Error("chain rollback get main seq fail", "height: ", i, "err", err, "hash", common.ToHex(blockdetail.Block.Hash(cfg))) 71 } 72 } 73 err = chain.disBlock(blockdetail, sequence) 74 if err != nil { 75 panic(fmt.Sprintln("rollback block fail ", "height", blockdetail.Block.Height, "blockHash:", common.ToHex(blockdetail.Block.Hash(cfg)))) 76 } 77 // 删除storedb中的状态高度 78 chain.sendDelStore(blockdetail.Block.StateHash, blockdetail.Block.Height) 79 chainlog.Info("chain rollback ", "height: ", i, "blockheight", blockdetail.Block.Height, "hash", common.ToHex(blockdetail.Block.Hash(cfg)), "state hash", common.ToHex(blockdetail.Block.StateHash)) 80 } 81 } 82 83 // 删除blocks 84 func (chain *BlockChain) disBlock(blockdetail *types.BlockDetail, sequence int64) error { 85 var lastSequence int64 86 cfg := chain.client.GetConfig() 87 88 //批量删除block的信息从磁盘中 89 newbatch := chain.blockStore.NewBatch(true) 90 91 //从db中删除tx相关的信息 92 err := chain.blockStore.DelTxs(newbatch, blockdetail) 93 if err != nil { 94 chainlog.Error("disBlock DelTxs:", "height", blockdetail.Block.Height, "err", err) 95 return err 96 } 97 98 //优先删除缓存中的block信息 99 chain.DelCacheBlock(blockdetail.Block.Height, blockdetail.Block.Hash(cfg)) 100 101 //从db中删除block相关的信息 102 lastSequence, err = chain.blockStore.DelBlock(newbatch, blockdetail, sequence) 103 if err != nil { 104 chainlog.Error("disBlock DelBlock:", "height", blockdetail.Block.Height, "err", err) 105 return err 106 } 107 db.MustWrite(newbatch) 108 109 //更新最新的高度和header为上一个块 110 chain.blockStore.UpdateHeight() 111 chain.blockStore.UpdateLastBlock(blockdetail.Block.ParentHash) 112 113 //通知共识,mempool和钱包删除block 114 err = chain.SendDelBlockEvent(blockdetail) 115 if err != nil { 116 chainlog.Error("disBlock SendDelBlockEvent", "err", err) 117 } 118 119 //目前非平行链并开启isRecordBlockSequence功能和enablePushSubscribe 120 if chain.isRecordBlockSequence && chain.enablePushSubscribe { 121 chain.push.UpdateSeq(lastSequence) 122 chainlog.Debug("isRecordBlockSequence", "lastSequence", lastSequence, "height", blockdetail.Block.Height) 123 } 124 125 return nil 126 } 127 128 // 通知store删除区块,主要针对kvmvcc 129 func (chain *BlockChain) sendDelStore(hash []byte, height int64) { 130 storeDel := &types.StoreDel{StateHash: hash, Height: height} 131 msg := chain.client.NewMessage("store", types.EventStoreDel, storeDel) 132 err := chain.client.Send(msg, true) 133 if err != nil { 134 chainlog.Debug("sendDelStoreEvent -->>store", "err", err) 135 } 136 _, err = chain.client.Wait(msg) 137 if err != nil { 138 panic(fmt.Sprintln("sendDelStore", err)) 139 } 140 }