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  }