github.com/turingchain2020/turingchain@v1.1.21/blockchain/chain.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  /*
     6  Package blockchain 实现区块链模块,包含区块链存储
     7  */
     8  package blockchain
     9  
    10  import (
    11  	"fmt"
    12  	"sync"
    13  	"sync/atomic"
    14  	"time"
    15  
    16  	"github.com/turingchain2020/turingchain/common"
    17  	dbm "github.com/turingchain2020/turingchain/common/db"
    18  	log "github.com/turingchain2020/turingchain/common/log/log15"
    19  	"github.com/turingchain2020/turingchain/queue"
    20  	"github.com/turingchain2020/turingchain/types"
    21  	lru "github.com/hashicorp/golang-lru"
    22  )
    23  
    24  //var
    25  var (
    26  	//cache 存贮的block个数
    27  	zeroHash             [32]byte
    28  	InitBlockNum         int64 = 10240 //节点刚启动时从db向index和bestchain缓存中添加的blocknode数,和blockNodeCacheLimit保持一致
    29  	chainlog                   = log.New("module", "blockchain")
    30  	FutureBlockDelayTime int64 = 1
    31  )
    32  
    33  const (
    34  	maxFutureBlocks = 256
    35  
    36  	maxActiveBlocks = 1024
    37  
    38  	// 默认轻广播组装临时区块缓存, 100M
    39  	maxActiveBlocksCacheSize = 100
    40  
    41  	defaultChunkBlockNum = 1
    42  )
    43  
    44  //BlockChain 区块链结构体
    45  type BlockChain struct {
    46  	client        queue.Client
    47  	blockCache    *BlockCache
    48  	txHeightCache txHeightCacheType
    49  
    50  	// 永久存储数据到db中
    51  	blockStore *BlockStore
    52  	push       *Push
    53  	//cache  缓存block方便快速查询
    54  	cfg             *types.BlockChain
    55  	syncTask        *Task
    56  	downLoadTask    *Task
    57  	chunkRecordTask *Task
    58  
    59  	query *Query
    60  
    61  	//记录收到的最新广播的block高度,用于节点追赶active链
    62  	rcvLastBlockHeight int64
    63  
    64  	//记录本节点已经同步的block高度,用于节点追赶active链,处理节点分叉不同步的场景
    65  	synBlockHeight int64
    66  
    67  	//记录peer的最新block高度,用于节点追赶active链
    68  	peerList PeerInfoList
    69  	recvwg   *sync.WaitGroup
    70  	tickerwg *sync.WaitGroup
    71  	reducewg *sync.WaitGroup
    72  
    73  	synblock            chan struct{}
    74  	quit                chan struct{}
    75  	isclosed            int32
    76  	runcount            int32
    77  	isbatchsync         int32
    78  	firstcheckbestchain int32 //节点启动之后首次检测最优链的标志
    79  
    80  	// 孤儿链
    81  	orphanPool *OrphanPool
    82  	// 主链或者侧链的blocknode信息
    83  	index *blockIndex
    84  	//当前主链
    85  	bestChain *chainView
    86  
    87  	chainLock sync.RWMutex
    88  	//blockchain的启动时间
    89  	startTime time.Time
    90  
    91  	//标记本节点是否已经追赶上主链
    92  	isCaughtUp bool
    93  
    94  	//同步block批量写数据库时,是否需要刷盘的标志。
    95  	//非固态硬盘的电脑可以关闭刷盘,提高同步性能.
    96  	cfgBatchSync bool
    97  
    98  	//记录可疑故障节点peer信息
    99  	//在ExecBlock执行失败时记录对应的peerid以及故障区块的高度和hash
   100  	faultPeerList map[string]*FaultPeerInfo
   101  
   102  	bestChainPeerList map[string]*BestPeerInfo
   103  
   104  	//记录futureblocks
   105  	futureBlocks *lru.Cache // future blocks are broadcast later processing
   106  
   107  	//downLoad block info
   108  	downLoadInfo *DownLoadInfo
   109  	downloadMode int //当本节点落后很多时,可以先下载区块到db,启动单独的goroutine去执行block
   110  
   111  	isRecordBlockSequence bool //是否记录add或者del block的序列,方便blcokchain的恢复通过记录的序列表
   112  	enablePushSubscribe   bool //是否允许推送订阅
   113  	isParaChain           bool //是否是平行链。平行链需要记录Sequence信息
   114  	isStrongConsistency   bool
   115  	//lock
   116  	synBlocklock     sync.Mutex
   117  	peerMaxBlklock   sync.Mutex
   118  	castlock         sync.Mutex
   119  	ntpClockSynclock sync.Mutex
   120  	faultpeerlock    sync.Mutex
   121  	bestpeerlock     sync.Mutex
   122  	downLoadlock     sync.Mutex
   123  	downLoadModeLock sync.Mutex
   124  	isNtpClockSync   bool //ntp时间是否同步
   125  
   126  	//cfg
   127  	MaxFetchBlockNum int64 //一次最多申请获取block个数
   128  	TimeoutSeconds   int64
   129  	blockSynInterVal time.Duration
   130  
   131  	failed int32
   132  
   133  	blockOnChain   *BlockOnChain
   134  	onChainTimeout int64
   135  
   136  	//记录当前已经连续的最高高度
   137  	maxSerialChunkNum     int64
   138  	processingGenChunk    int32
   139  	processingDeleteChunk int32
   140  	deleteChunkCount      int64
   141  }
   142  
   143  //New new
   144  func New(cfg *types.TuringchainConfig) *BlockChain {
   145  	mcfg := cfg.GetModuleConfig().BlockChain
   146  	futureBlocks, err := lru.New(maxFutureBlocks)
   147  	if err != nil {
   148  		panic("when New BlockChain lru.New return err")
   149  	}
   150  
   151  	if atomic.LoadInt64(&mcfg.ChunkblockNum) == 0 {
   152  		atomic.StoreInt64(&mcfg.ChunkblockNum, defaultChunkBlockNum)
   153  	}
   154  
   155  	blockchain := &BlockChain{
   156  		rcvLastBlockHeight: -1,
   157  		synBlockHeight:     -1,
   158  		maxSerialChunkNum:  -1,
   159  		peerList:           nil,
   160  		cfg:                mcfg,
   161  		recvwg:             &sync.WaitGroup{},
   162  		tickerwg:           &sync.WaitGroup{},
   163  		reducewg:           &sync.WaitGroup{},
   164  
   165  		syncTask:        newTask(300 * time.Second), //考虑到区块交易多时执行耗时,需要延长task任务的超时时间
   166  		downLoadTask:    newTask(300 * time.Second),
   167  		chunkRecordTask: newTask(120 * time.Second),
   168  
   169  		quit:                make(chan struct{}),
   170  		synblock:            make(chan struct{}, 1),
   171  		orphanPool:          NewOrphanPool(cfg),
   172  		index:               newBlockIndex(),
   173  		isCaughtUp:          false,
   174  		isbatchsync:         1,
   175  		firstcheckbestchain: 0,
   176  		cfgBatchSync:        mcfg.Batchsync,
   177  		faultPeerList:       make(map[string]*FaultPeerInfo),
   178  		bestChainPeerList:   make(map[string]*BestPeerInfo),
   179  		futureBlocks:        futureBlocks,
   180  		downLoadInfo:        &DownLoadInfo{},
   181  		isNtpClockSync:      true,
   182  		MaxFetchBlockNum:    128 * 6, //一次最多申请获取block个数
   183  		TimeoutSeconds:      2,
   184  		downloadMode:        fastDownLoadMode,
   185  		blockOnChain:        &BlockOnChain{},
   186  		onChainTimeout:      0,
   187  	}
   188  	blockchain.initConfig(cfg)
   189  	blockchain.blockCache = newBlockCache(cfg, defaultBlockHashCacheSize)
   190  	return blockchain
   191  }
   192  
   193  func (chain *BlockChain) initConfig(cfg *types.TuringchainConfig) {
   194  	mcfg := cfg.GetModuleConfig().BlockChain
   195  
   196  	if mcfg.MaxFetchBlockNum > 0 {
   197  		chain.MaxFetchBlockNum = mcfg.MaxFetchBlockNum
   198  	}
   199  
   200  	if mcfg.TimeoutSeconds > 0 {
   201  		chain.TimeoutSeconds = mcfg.TimeoutSeconds
   202  	}
   203  
   204  	if mcfg.DefCacheSize <= 0 {
   205  		mcfg.DefCacheSize = 128
   206  	}
   207  
   208  	chain.blockSynInterVal = time.Duration(chain.TimeoutSeconds)
   209  	chain.isStrongConsistency = mcfg.IsStrongConsistency
   210  	chain.isRecordBlockSequence = mcfg.IsRecordBlockSequence
   211  	chain.enablePushSubscribe = mcfg.EnablePushSubscribe
   212  	chain.isParaChain = mcfg.IsParaChain
   213  	cfg.S("quickIndex", mcfg.EnableTxQuickIndex)
   214  	cfg.S("reduceLocaldb", mcfg.EnableReduceLocaldb)
   215  
   216  	if mcfg.OnChainTimeout > 0 {
   217  		chain.onChainTimeout = mcfg.OnChainTimeout
   218  	}
   219  	chain.initOnChainTimeout()
   220  	// 	初始化AllowPackHeight
   221  	initAllowPackHeight(chain.cfg)
   222  }
   223  
   224  //Close 关闭区块链
   225  func (chain *BlockChain) Close() {
   226  	//等待所有的写线程退出,防止数据库写到一半被暂停
   227  	atomic.StoreInt32(&chain.isclosed, 1)
   228  
   229  	//退出线程
   230  	close(chain.quit)
   231  
   232  	//等待执行完成
   233  	for atomic.LoadInt32(&chain.runcount) > 0 {
   234  		time.Sleep(time.Microsecond)
   235  	}
   236  	chain.client.Close()
   237  	//wait for recvwg quit:
   238  	chainlog.Info("blockchain wait for recvwg quit")
   239  	chain.recvwg.Wait()
   240  
   241  	//wait for tickerwg quit:
   242  	chainlog.Info("blockchain wait for tickerwg quit")
   243  	chain.tickerwg.Wait()
   244  
   245  	//wait for reducewg quit:
   246  	chainlog.Info("blockchain wait for reducewg quit")
   247  	chain.reducewg.Wait()
   248  
   249  	if chain.push != nil {
   250  		chainlog.Info("blockchain wait for push quit")
   251  		chain.push.Close()
   252  	}
   253  
   254  	//关闭数据库
   255  	chain.blockStore.db.Close()
   256  	chainlog.Info("blockchain module closed")
   257  }
   258  
   259  //SetQueueClient 设置队列
   260  func (chain *BlockChain) SetQueueClient(client queue.Client) {
   261  	chain.client = client
   262  	chain.client.Sub("blockchain")
   263  
   264  	blockStoreDB := dbm.NewDB("blockchain", chain.cfg.Driver, chain.cfg.DbPath, chain.cfg.DbCache)
   265  	chain.blockStore = NewBlockStore(chain, blockStoreDB, client)
   266  	stateHash := chain.getStateHash()
   267  	chain.query = NewQuery(blockStoreDB, chain.client, stateHash)
   268  	if chain.enablePushSubscribe && chain.isRecordBlockSequence {
   269  		chain.push = newpush(chain.blockStore, chain.blockStore, chain.client.GetConfig())
   270  		chainlog.Info("chain push is setup")
   271  	}
   272  
   273  	//startTime
   274  	chain.startTime = types.Now()
   275  	// 获取当前最大chunk连续高度
   276  	chain.maxSerialChunkNum = chain.blockStore.GetMaxSerialChunkNum()
   277  
   278  	//recv 消息的处理,共识模块需要获取lastblock从数据库中
   279  	chain.recvwg.Add(1)
   280  	//初始化blockchian模块
   281  	chain.InitBlockChain()
   282  	go chain.ProcRecvMsg()
   283  }
   284  
   285  //Wait for ready
   286  func (chain *BlockChain) Wait() {}
   287  
   288  //GetStore only used for test
   289  func (chain *BlockChain) GetStore() *BlockStore {
   290  	return chain.blockStore
   291  }
   292  
   293  //GetOrphanPool 获取孤儿链
   294  func (chain *BlockChain) GetOrphanPool() *OrphanPool {
   295  	return chain.orphanPool
   296  }
   297  
   298  //InitBlockChain 区块链初始化
   299  func (chain *BlockChain) InitBlockChain() {
   300  	//isRecordBlockSequence配置的合法性检测
   301  	seqStatus := chain.blockStore.CheckSequenceStatus(chain.isRecordBlockSequence)
   302  	if seqStatus == seqStatusNeedCreate {
   303  		chain.blockStore.CreateSequences(100000)
   304  	}
   305  
   306  	//先缓存最新的128个block信息到cache中
   307  	curheight := chain.GetBlockHeight()
   308  	chain.InitCache(curheight)
   309  
   310  	//获取数据库中最新的10240个区块加载到index和bestview链中
   311  	beg := types.Now()
   312  	chain.InitIndexAndBestView()
   313  	chainlog.Info("InitIndexAndBestView", "cost", types.Since(beg))
   314  
   315  	//获取数据库中最新的区块高度,以及blockchain的数据库版本号
   316  	curdbver := chain.blockStore.GetDbVersion()
   317  	if curdbver == 0 && curheight == -1 {
   318  		curdbver = 1
   319  		err := chain.blockStore.SetDbVersion(curdbver)
   320  		//设置失败后恢复成原来的值保持和types.S("dbversion", curdbver)设置的版本一致
   321  		if err != nil {
   322  			curdbver = 0
   323  			chainlog.Error("InitIndexAndBestView SetDbVersion ", "err", err)
   324  		}
   325  	}
   326  	cfg := chain.client.GetConfig()
   327  	cfg.S("dbversion", curdbver)
   328  	if !chain.cfg.IsParaChain && chain.cfg.RollbackBlock <= 0 {
   329  		// 定时检测/同步block
   330  		go chain.SynRoutine()
   331  
   332  		// 定时处理futureblock
   333  		go chain.UpdateRoutine()
   334  	}
   335  
   336  	if !chain.cfg.DisableShard {
   337  		chain.tickerwg.Add(1)
   338  		go chain.chunkProcessRoutine()
   339  	}
   340  
   341  	//初始化默认DownLoadInfo
   342  	chain.DefaultDownLoadInfo()
   343  }
   344  
   345  func (chain *BlockChain) getStateHash() []byte {
   346  	blockhight := chain.GetBlockHeight()
   347  	blockdetail, err := chain.GetBlock(blockhight)
   348  	if err != nil {
   349  		return zeroHash[:]
   350  	}
   351  	if blockdetail != nil {
   352  		return blockdetail.GetBlock().GetStateHash()
   353  	}
   354  	return zeroHash[:]
   355  }
   356  
   357  //SendAddBlockEvent blockchain 模块add block到db之后通知mempool 和consense模块做相应的更新
   358  func (chain *BlockChain) SendAddBlockEvent(block *types.BlockDetail) (err error) {
   359  	if chain.client == nil {
   360  		chainlog.Error("SendAddBlockEvent: chain client not bind message queue.")
   361  		return types.ErrClientNotBindQueue
   362  	}
   363  	if block == nil {
   364  		chainlog.Error("SendAddBlockEvent block is null")
   365  		return types.ErrInvalidParam
   366  	}
   367  	chainlog.Debug("SendAddBlockEvent", "Height", block.Block.Height)
   368  
   369  	chainlog.Debug("SendAddBlockEvent -->>mempool")
   370  	msg := chain.client.NewMessage("mempool", types.EventAddBlock, block)
   371  	//此处采用同步发送模式,主要是为了消息在消息队列内部走高速通道,尽快被mempool模块处理
   372  	Err := chain.client.Send(msg, true)
   373  	if Err != nil {
   374  		chainlog.Error("SendAddBlockEvent -->>mempool", "err", Err)
   375  	}
   376  	chainlog.Debug("SendAddBlockEvent -->>consensus")
   377  
   378  	msg = chain.client.NewMessage("consensus", types.EventAddBlock, block)
   379  	Err = chain.client.Send(msg, false)
   380  	if Err != nil {
   381  		chainlog.Error("SendAddBlockEvent -->>consensus", "err", Err)
   382  	}
   383  	chainlog.Debug("SendAddBlockEvent -->>wallet", "height", block.GetBlock().GetHeight())
   384  	msg = chain.client.NewMessage("wallet", types.EventAddBlock, block)
   385  	Err = chain.client.Send(msg, false)
   386  	if Err != nil {
   387  		chainlog.Error("SendAddBlockEvent -->>wallet", "err", Err)
   388  	}
   389  	return nil
   390  }
   391  
   392  //SendBlockBroadcast blockchain模块广播此block到网络中
   393  func (chain *BlockChain) SendBlockBroadcast(block *types.BlockDetail) {
   394  	cfg := chain.client.GetConfig()
   395  	if chain.client == nil {
   396  		chainlog.Error("SendBlockBroadcast: chain client not bind message queue.")
   397  		return
   398  	}
   399  	if block == nil {
   400  		chainlog.Error("SendBlockBroadcast block is null")
   401  		return
   402  	}
   403  	chainlog.Debug("SendBlockBroadcast", "Height", block.Block.Height, "hash", common.ToHex(block.Block.Hash(cfg)))
   404  
   405  	msg := chain.client.NewMessage("p2p", types.EventBlockBroadcast, block.Block)
   406  	err := chain.client.Send(msg, false)
   407  	if err != nil {
   408  		chainlog.Error("SendBlockBroadcast", "Height", block.Block.Height, "hash", common.ToHex(block.Block.Hash(cfg)), "err", err)
   409  	}
   410  }
   411  
   412  //GetBlockHeight 获取区块高度
   413  func (chain *BlockChain) GetBlockHeight() int64 {
   414  	return chain.blockStore.Height()
   415  }
   416  
   417  //GetBlock 用于获取指定高度的block,首先在缓存中获取,如果不存在就从db中获取
   418  func (chain *BlockChain) GetBlock(height int64) (detail *types.BlockDetail, err error) {
   419  
   420  	cfg := chain.client.GetConfig()
   421  
   422  	var hash []byte
   423  	if hash, err = chain.blockStore.GetBlockHashByHeight(height); err != nil {
   424  		return nil, err
   425  	}
   426  
   427  	//从缓存的最新区块中尝试获取,最新区块的add是在执行block流程中处理
   428  	if detail = chain.blockCache.GetBlockByHash(hash); detail != nil {
   429  		if len(detail.Receipts) == 0 && len(detail.Block.Txs) != 0 {
   430  			chainlog.Debug("GetBlockByHash  GetBlockByHeight Receipts ==0", "height", height)
   431  		}
   432  		return detail, nil
   433  	}
   434  
   435  	if detail, exist := chain.blockStore.GetActiveBlock(string(hash)); exist {
   436  		return detail, nil
   437  	}
   438  
   439  	//从blockstore db中通过block height获取block
   440  	detail, err = chain.blockStore.LoadBlock(height, hash)
   441  	if err != nil {
   442  		chainlog.Error("GetBlock", "height", height, "LoadBlock err", err)
   443  		return nil, err
   444  	}
   445  	if len(detail.Receipts) == 0 && len(detail.Block.Txs) != 0 {
   446  		chainlog.Debug("GetBlock  LoadBlock Receipts ==0", "height", height)
   447  	}
   448  	//缓存到活跃区块中
   449  	chain.blockStore.AddActiveBlock(string(detail.Block.Hash(cfg)), detail)
   450  	return detail, nil
   451  
   452  }
   453  
   454  //SendDelBlockEvent blockchain 模块 del block从db之后通知mempool 和consense以及wallet模块做相应的更新
   455  func (chain *BlockChain) SendDelBlockEvent(block *types.BlockDetail) (err error) {
   456  	if chain.client == nil {
   457  		chainlog.Error("SendDelBlockEvent: chain client not bind message queue.")
   458  		err := types.ErrClientNotBindQueue
   459  		return err
   460  	}
   461  	if block == nil {
   462  		chainlog.Error("SendDelBlockEvent block is null")
   463  		return nil
   464  	}
   465  
   466  	chainlog.Debug("SendDelBlockEvent -->>mempool&consensus&wallet", "height", block.GetBlock().GetHeight())
   467  
   468  	msg := chain.client.NewMessage("consensus", types.EventDelBlock, block)
   469  	Err := chain.client.Send(msg, false)
   470  	if Err != nil {
   471  		chainlog.Debug("SendDelBlockEvent -->>consensus", "err", err)
   472  	}
   473  	msg = chain.client.NewMessage("mempool", types.EventDelBlock, block)
   474  	Err = chain.client.Send(msg, false)
   475  	if Err != nil {
   476  		chainlog.Debug("SendDelBlockEvent -->>mempool", "err", err)
   477  	}
   478  	msg = chain.client.NewMessage("wallet", types.EventDelBlock, block)
   479  	Err = chain.client.Send(msg, false)
   480  	if Err != nil {
   481  		chainlog.Debug("SendDelBlockEvent -->>wallet", "err", err)
   482  	}
   483  	return nil
   484  }
   485  
   486  //GetDB 获取DB
   487  func (chain *BlockChain) GetDB() dbm.DB {
   488  	return chain.blockStore.db
   489  }
   490  
   491  //InitCache 初始化缓存
   492  func (chain *BlockChain) InitCache(currHeight int64) {
   493  
   494  	if !chain.client.GetConfig().IsEnable("TxHeight") {
   495  		chain.txHeightCache = &noneCache{}
   496  		return
   497  	}
   498  	chain.txHeightCache = newTxHashCache(chain, types.HighAllowPackHeight, types.LowAllowPackHeight)
   499  	// cache history block if exist
   500  	if currHeight < 0 {
   501  		return
   502  	}
   503  
   504  	for i := currHeight - chain.cfg.DefCacheSize; i <= currHeight; i++ {
   505  		if i < 0 {
   506  			i = 0
   507  		}
   508  		block, err := chain.GetBlock(i)
   509  		if err != nil {
   510  			panic(fmt.Sprintf("getBlock err=%s, height=%d", err.Error(), i))
   511  		}
   512  		chain.blockCache.AddBlock(block)
   513  	}
   514  
   515  	for i := currHeight - types.HighAllowPackHeight - types.LowAllowPackHeight + 1; i <= currHeight; i++ {
   516  		if i < 0 {
   517  			i = 0
   518  		}
   519  		block, err := chain.GetBlock(i)
   520  		if err != nil {
   521  			panic(err)
   522  		}
   523  		chain.txHeightCache.Add(block.GetBlock())
   524  	}
   525  }
   526  
   527  //InitIndexAndBestView 第一次启动之后需要将数据库中最新的128个block的node添加到index和bestchain中
   528  // 主要是为了接下来分叉时的block处理,.........todo
   529  func (chain *BlockChain) InitIndexAndBestView() {
   530  	//获取lastblocks从数据库,创建bestviewtip节点
   531  	var node *blockNode
   532  	var prevNode *blockNode
   533  	var height int64
   534  	var initflag = false
   535  	curheight := chain.blockStore.height
   536  	if curheight == -1 {
   537  		node = newPreGenBlockNode()
   538  		node.parent = nil
   539  		chain.bestChain = newChainView(node)
   540  		chain.index.AddNode(node)
   541  		return
   542  	}
   543  	if curheight >= InitBlockNum {
   544  		height = curheight - InitBlockNum
   545  	} else {
   546  		height = 0
   547  	}
   548  	for ; height <= curheight; height++ {
   549  		header, err := chain.blockStore.GetBlockHeaderByHeight(height)
   550  		if header == nil {
   551  			chainlog.Error("InitIndexAndBestView GetBlockHeaderByHeight", "height", height, "err", err)
   552  			//开始升级localdb到2.0.0版本时需要兼容旧的存储方式
   553  			header, err = chain.blockStore.getBlockHeaderByHeightOld(height)
   554  			if header == nil {
   555  				chainlog.Error("InitIndexAndBestView getBlockHeaderByHeightOld", "height", height, "err", err)
   556  				panic("InitIndexAndBestView fail!")
   557  			}
   558  		}
   559  
   560  		newNode := newBlockNodeByHeader(false, header, "self", -1)
   561  		newNode.parent = prevNode
   562  		prevNode = newNode
   563  
   564  		chain.index.AddNode(newNode)
   565  		if !initflag {
   566  			chain.bestChain = newChainView(newNode)
   567  			initflag = true
   568  		} else {
   569  			chain.bestChain.SetTip(newNode)
   570  		}
   571  	}
   572  
   573  }
   574  
   575  //UpdateRoutine 定时延时广播futureblock
   576  func (chain *BlockChain) UpdateRoutine() {
   577  	//1秒尝试检测一次futureblock,futureblock的time小于当前系统时间就广播此block
   578  	futureblockTicker := time.NewTicker(1 * time.Second)
   579  
   580  	for {
   581  		select {
   582  		case <-chain.quit:
   583  			//chainlog.Info("UpdateRoutine quit")
   584  			return
   585  		case <-futureblockTicker.C:
   586  			chain.ProcFutureBlocks()
   587  		}
   588  	}
   589  }
   590  
   591  //ProcFutureBlocks 循环遍历所有futureblocks,当futureblock的block生成time小于当前系统时间就将此block广播出去
   592  func (chain *BlockChain) ProcFutureBlocks() {
   593  	cfg := chain.client.GetConfig()
   594  	for _, hash := range chain.futureBlocks.Keys() {
   595  		if block, exist := chain.futureBlocks.Peek(hash); exist {
   596  			if block != nil {
   597  				blockdetail := block.(*types.BlockDetail)
   598  				//block产生的时间小于当前时间,广播此block,然后将此block从futureblocks中移除
   599  				if types.Now().Unix() > blockdetail.Block.BlockTime {
   600  					chain.SendBlockBroadcast(blockdetail)
   601  					chain.futureBlocks.Remove(hash)
   602  					chainlog.Debug("ProcFutureBlocks Remove", "height", blockdetail.Block.Height, "hash", common.ToHex(blockdetail.Block.Hash(cfg)), "blocktime", blockdetail.Block.BlockTime, "curtime", types.Now().Unix())
   603  				}
   604  			}
   605  		}
   606  	}
   607  }
   608  
   609  //SetValueByKey 设置kv对到blockchain数据库
   610  func (chain *BlockChain) SetValueByKey(kvs *types.LocalDBSet) error {
   611  	return chain.blockStore.SetConsensusPara(kvs)
   612  }
   613  
   614  //GetValueByKey 通过key值从blockchain数据库中获取value值
   615  func (chain *BlockChain) GetValueByKey(keys *types.LocalDBGet) *types.LocalReplyValue {
   616  	return chain.blockStore.Get(keys)
   617  }
   618  
   619  // AddCacheBlock 添加区块相关缓存
   620  func (chain *BlockChain) AddCacheBlock(detail *types.BlockDetail) {
   621  	//txHeight缓存先增加
   622  	chain.txHeightCache.Add(detail.Block)
   623  	chain.blockCache.AddBlock(detail)
   624  }
   625  
   626  //DelCacheBlock 删除缓存的中对应的区块
   627  func (chain *BlockChain) DelCacheBlock(height int64, hash []byte) {
   628  	//txHeight缓存先删除
   629  	chain.txHeightCache.Del(height)
   630  	chain.blockCache.DelBlock(height)
   631  	chain.blockStore.RemoveActiveBlock(string(hash))
   632  }
   633  
   634  //initAllowPackHeight 根据配置修改LowAllowPackHeight和值HighAllowPackHeight
   635  func initAllowPackHeight(mcfg *types.BlockChain) {
   636  	if mcfg.HighAllowPackHeight > 0 && mcfg.LowAllowPackHeight > 0 {
   637  		if mcfg.HighAllowPackHeight+mcfg.LowAllowPackHeight > types.MaxAllowPackInterval {
   638  			panic("when Enable TxHeight HighAllowPackHeight + LowAllowPackHeight must less than types.MaxAllowPackInterval")
   639  		}
   640  		types.HighAllowPackHeight = mcfg.HighAllowPackHeight
   641  		types.LowAllowPackHeight = mcfg.LowAllowPackHeight
   642  	}
   643  	chainlog.Debug("initAllowPackHeight", "types.HighAllowPackHeight", types.HighAllowPackHeight, "types.LowAllowPackHeight", types.LowAllowPackHeight)
   644  }