github.com/turingchain2020/turingchain@v1.1.21/system/consensus/base.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 consensus
     6  
     7  import (
     8  	"bytes"
     9  	"errors"
    10  	"math/rand"
    11  	"sync"
    12  	"sync/atomic"
    13  
    14  	"github.com/turingchain2020/turingchain/client"
    15  	"github.com/turingchain2020/turingchain/common"
    16  	log "github.com/turingchain2020/turingchain/common/log/log15"
    17  	"github.com/turingchain2020/turingchain/common/merkle"
    18  	"github.com/turingchain2020/turingchain/queue"
    19  	"github.com/turingchain2020/turingchain/types"
    20  	"github.com/turingchain2020/turingchain/util"
    21  )
    22  
    23  var tlog = log.New("module", "consensus")
    24  
    25  var (
    26  	zeroHash [32]byte
    27  )
    28  
    29  var randgen *rand.Rand
    30  
    31  func init() {
    32  	randgen = rand.New(rand.NewSource(types.Now().UnixNano()))
    33  	QueryData.Register("base", &BaseClient{})
    34  }
    35  
    36  //Miner 矿工
    37  type Miner interface {
    38  	CreateGenesisTx() []*types.Transaction
    39  	GetGenesisBlockTime() int64
    40  	CreateBlock()
    41  	AddBlock(b *types.Block) error
    42  	CheckBlock(parent *types.Block, current *types.BlockDetail) error
    43  	ProcEvent(msg *queue.Message) bool
    44  	CmpBestBlock(newBlock *types.Block, cmpBlock *types.Block) bool
    45  }
    46  
    47  //BaseClient ...
    48  type BaseClient struct {
    49  	client       queue.Client
    50  	api          client.QueueProtocolAPI
    51  	minerStart   int32
    52  	isclosed     int32
    53  	once         sync.Once
    54  	Cfg          *types.Consensus
    55  	currentBlock *types.Block
    56  	mulock       sync.Mutex
    57  	child        Miner
    58  	minerstartCB func()
    59  	isCaughtUp   int32
    60  }
    61  
    62  //NewBaseClient ...
    63  func NewBaseClient(cfg *types.Consensus) *BaseClient {
    64  	var flag int32
    65  	if cfg.Minerstart {
    66  		flag = 1
    67  	}
    68  	client := &BaseClient{minerStart: flag, isCaughtUp: 0}
    69  	client.Cfg = cfg
    70  	log.Info("Enter consensus " + cfg.Name)
    71  	return client
    72  }
    73  
    74  //GetGenesisBlockTime 获取创世区块时间
    75  func (bc *BaseClient) GetGenesisBlockTime() int64 {
    76  	return bc.Cfg.GenesisBlockTime
    77  }
    78  
    79  //SetChild ...
    80  func (bc *BaseClient) SetChild(c Miner) {
    81  	bc.child = c
    82  }
    83  
    84  //GetAPI 获取api
    85  func (bc *BaseClient) GetAPI() client.QueueProtocolAPI {
    86  	return bc.api
    87  }
    88  
    89  //SetAPI ...
    90  func (bc *BaseClient) SetAPI(api client.QueueProtocolAPI) {
    91  	bc.api = api
    92  }
    93  
    94  //AddBlock 添加区块的时候,通知系统做处理
    95  func (bc *BaseClient) AddBlock(b *types.Block) error {
    96  	return nil
    97  }
    98  
    99  //InitClient 初始化
   100  func (bc *BaseClient) InitClient(c queue.Client, minerstartCB func()) {
   101  	log.Info("Enter SetQueueClient method of consensus")
   102  	bc.client = c
   103  	bc.minerstartCB = minerstartCB
   104  	var err error
   105  	bc.api, err = client.New(c, nil)
   106  	if err != nil {
   107  		panic(err)
   108  	}
   109  	bc.InitMiner()
   110  }
   111  
   112  //GetQueueClient 获取客户端队列
   113  func (bc *BaseClient) GetQueueClient() queue.Client {
   114  	return bc.client
   115  }
   116  
   117  //RandInt64 随机数
   118  func (bc *BaseClient) RandInt64() int64 {
   119  	return randgen.Int63()
   120  }
   121  
   122  //InitMiner 初始化矿工
   123  func (bc *BaseClient) InitMiner() {
   124  	bc.once.Do(bc.minerstartCB)
   125  }
   126  
   127  //Wait wait for ready
   128  func (bc *BaseClient) Wait() {}
   129  
   130  //SetQueueClient 设置客户端队列
   131  func (bc *BaseClient) SetQueueClient(c queue.Client) {
   132  	bc.InitClient(c, func() {
   133  		//call init block
   134  		bc.InitBlock()
   135  	})
   136  	go bc.EventLoop()
   137  	go bc.child.CreateBlock()
   138  }
   139  
   140  //InitBlock change init block
   141  func (bc *BaseClient) InitBlock() {
   142  	cfg := bc.client.GetConfig()
   143  	block, err := bc.RequestLastBlock()
   144  	if err != nil {
   145  		panic(err)
   146  	}
   147  	if block == nil {
   148  		// 创世区块
   149  		newblock := &types.Block{}
   150  		newblock.Height = 0
   151  		newblock.BlockTime = bc.child.GetGenesisBlockTime()
   152  		// TODO: 下面这些值在创世区块中赋值nil,是否合理?
   153  		newblock.ParentHash = zeroHash[:]
   154  		tx := bc.child.CreateGenesisTx()
   155  		newblock.Txs = tx
   156  		newblock.TxHash = merkle.CalcMerkleRoot(cfg, newblock.Height, newblock.Txs)
   157  		if newblock.Height == 0 {
   158  			types.AssertConfig(bc.client)
   159  			newblock.Difficulty = cfg.GetP(0).PowLimitBits
   160  		}
   161  		err := bc.WriteBlock(zeroHash[:], newblock)
   162  		if err != nil {
   163  			panic(err)
   164  		}
   165  	} else {
   166  		bc.SetCurrentBlock(block)
   167  	}
   168  }
   169  
   170  //Close 关闭
   171  func (bc *BaseClient) Close() {
   172  	atomic.StoreInt32(&bc.minerStart, 0)
   173  	atomic.StoreInt32(&bc.isclosed, 1)
   174  	bc.client.Close()
   175  	log.Info("consensus base closed")
   176  }
   177  
   178  //IsClosed 是否已经关闭
   179  func (bc *BaseClient) IsClosed() bool {
   180  	return atomic.LoadInt32(&bc.isclosed) == 1
   181  }
   182  
   183  //CheckTxDup 为了不引起交易检查时候产生的无序
   184  func (bc *BaseClient) CheckTxDup(txs []*types.Transaction) (transactions []*types.Transaction) {
   185  	cacheTxs := types.TxsToCache(txs)
   186  	var err error
   187  	cacheTxs, err = util.CheckTxDup(bc.client, cacheTxs, 0)
   188  	if err != nil {
   189  		return txs
   190  	}
   191  	return types.CacheToTxs(cacheTxs)
   192  }
   193  
   194  //IsMining 是否在挖矿
   195  func (bc *BaseClient) IsMining() bool {
   196  	return atomic.LoadInt32(&bc.minerStart) == 1
   197  }
   198  
   199  //IsCaughtUp 是否追上最新高度
   200  func (bc *BaseClient) IsCaughtUp() bool {
   201  	if bc.client == nil {
   202  		panic("bc not bind message queue.")
   203  	}
   204  	msg := bc.client.NewMessage("blockchain", types.EventIsSync, nil)
   205  	err := bc.client.Send(msg, true)
   206  	if err != nil {
   207  		return false
   208  	}
   209  	resp, err := bc.client.Wait(msg)
   210  	if err != nil {
   211  		return false
   212  	}
   213  	return resp.GetData().(*types.IsCaughtUp).GetIscaughtup()
   214  }
   215  
   216  //ExecConsensus 执行共识
   217  func (bc *BaseClient) ExecConsensus(data *types.ChainExecutor) (types.Message, error) {
   218  	param, err := QueryData.Decode(data.Driver, data.FuncName, data.Param)
   219  	if err != nil {
   220  		return nil, err
   221  	}
   222  	return QueryData.Call(data.Driver, data.FuncName, param)
   223  }
   224  
   225  //EventLoop 准备新区块
   226  func (bc *BaseClient) EventLoop() {
   227  	// 监听blockchain模块,获取当前最高区块
   228  	bc.client.Sub("consensus")
   229  	go func() {
   230  		for msg := range bc.client.Recv() {
   231  			tlog.Debug("consensus recv", "msg", msg)
   232  			if msg.Ty == types.EventConsensusQuery {
   233  				exec := msg.GetData().(*types.ChainExecutor)
   234  				param, err := QueryData.Decode(exec.Driver, exec.FuncName, exec.Param)
   235  				if err != nil {
   236  					msg.Reply(bc.api.NewMessage("", 0, err))
   237  					continue
   238  				}
   239  				reply, err := QueryData.Call(exec.Driver, exec.FuncName, param)
   240  				if err != nil {
   241  					msg.Reply(bc.api.NewMessage("", 0, err))
   242  				} else {
   243  					msg.Reply(bc.api.NewMessage("", 0, reply))
   244  				}
   245  			} else if msg.Ty == types.EventAddBlock {
   246  				block := msg.GetData().(*types.BlockDetail).Block
   247  				bc.SetCurrentBlock(block)
   248  				bc.child.AddBlock(block)
   249  			} else if msg.Ty == types.EventCheckBlock {
   250  				block := msg.GetData().(*types.BlockDetail)
   251  				err := bc.CheckBlock(block)
   252  				msg.ReplyErr("EventCheckBlock", err)
   253  			} else if msg.Ty == types.EventMinerStart {
   254  				if !atomic.CompareAndSwapInt32(&bc.minerStart, 0, 1) {
   255  					msg.ReplyErr("EventMinerStart", types.ErrMinerIsStared)
   256  				} else {
   257  					bc.InitMiner()
   258  					msg.ReplyErr("EventMinerStart", nil)
   259  				}
   260  			} else if msg.Ty == types.EventMinerStop {
   261  				if !atomic.CompareAndSwapInt32(&bc.minerStart, 1, 0) {
   262  					msg.ReplyErr("EventMinerStop", types.ErrMinerNotStared)
   263  				} else {
   264  					msg.ReplyErr("EventMinerStop", nil)
   265  				}
   266  			} else if msg.Ty == types.EventDelBlock {
   267  				block := msg.GetData().(*types.BlockDetail).Block
   268  				bc.UpdateCurrentBlock(block)
   269  			} else if msg.Ty == types.EventCmpBestBlock {
   270  				var reply types.Reply
   271  				cmpBlock := msg.GetData().(*types.CmpBlock)
   272  				reply.IsOk = bc.CmpBestBlock(cmpBlock.Block, cmpBlock.CmpHash)
   273  				msg.Reply(bc.api.NewMessage("", 0, &reply))
   274  			} else {
   275  				if !bc.child.ProcEvent(msg) {
   276  					msg.ReplyErr("BaseClient.EventLoop() ", types.ErrActionNotSupport)
   277  				}
   278  			}
   279  		}
   280  	}()
   281  }
   282  
   283  //CheckBlock 检查区块
   284  func (bc *BaseClient) CheckBlock(block *types.BlockDetail) error {
   285  	//check parent
   286  	if block.Block.Height <= 0 { //genesis block not check
   287  		return nil
   288  	}
   289  	parent, err := bc.RequestBlock(block.Block.Height - 1)
   290  	if err != nil {
   291  		return err
   292  	}
   293  	//check base info
   294  	if parent.Height+1 != block.Block.Height {
   295  		return types.ErrBlockHeight
   296  	}
   297  	types.AssertConfig(bc.client)
   298  	cfg := bc.client.GetConfig()
   299  	if cfg.IsFork(block.Block.Height, "ForkCheckBlockTime") && parent.BlockTime > block.Block.BlockTime {
   300  		return types.ErrBlockTime
   301  	}
   302  	//check parent hash
   303  	if string(block.Block.GetParentHash()) != string(parent.Hash(cfg)) {
   304  		return types.ErrParentHash
   305  	}
   306  	//check block size and tx count
   307  	if cfg.IsFork(block.Block.Height, "ForkBlockCheck") {
   308  		if block.Block.Size() > types.MaxBlockSize {
   309  			return types.ErrBlockSize
   310  		}
   311  		if int64(len(block.Block.Txs)) > cfg.GetP(block.Block.Height).MaxTxNumber {
   312  			return types.ErrManyTx
   313  		}
   314  	}
   315  	//check by drivers
   316  	err = bc.child.CheckBlock(parent, block)
   317  	return err
   318  }
   319  
   320  //RequestTx Mempool中取交易列表
   321  func (bc *BaseClient) RequestTx(listSize int, txHashList [][]byte) []*types.Transaction {
   322  	if bc.client == nil {
   323  		panic("bc not bind message queue.")
   324  	}
   325  	msg := bc.client.NewMessage("mempool", types.EventTxList, &types.TxHashList{Hashes: txHashList, Count: int64(listSize)})
   326  	err := bc.client.Send(msg, true)
   327  	if err != nil {
   328  		return nil
   329  	}
   330  	resp, err := bc.client.Wait(msg)
   331  	if err != nil {
   332  		return nil
   333  	}
   334  	return resp.GetData().(*types.ReplyTxList).GetTxs()
   335  }
   336  
   337  //RequestBlock 请求区块
   338  func (bc *BaseClient) RequestBlock(start int64) (*types.Block, error) {
   339  	if bc.client == nil {
   340  		panic("bc not bind message queue.")
   341  	}
   342  	reqblock := &types.ReqBlocks{Start: start, End: start, IsDetail: false, Pid: []string{""}}
   343  	msg := bc.client.NewMessage("blockchain", types.EventGetBlocks, reqblock)
   344  	err := bc.client.Send(msg, true)
   345  	if err != nil {
   346  		return nil, err
   347  	}
   348  	resp, err := bc.client.Wait(msg)
   349  	if err != nil {
   350  		return nil, err
   351  	}
   352  	blocks := resp.GetData().(*types.BlockDetails)
   353  	return blocks.Items[0].Block, nil
   354  }
   355  
   356  //RequestLastBlock 获取最新的block从blockchain模块
   357  func (bc *BaseClient) RequestLastBlock() (*types.Block, error) {
   358  	if bc.client == nil {
   359  		panic("client not bind message queue.")
   360  	}
   361  	msg := bc.client.NewMessage("blockchain", types.EventGetLastBlock, nil)
   362  	err := bc.client.Send(msg, true)
   363  	if err != nil {
   364  		return nil, err
   365  	}
   366  	resp, err := bc.client.Wait(msg)
   367  	if err != nil {
   368  		return nil, err
   369  	}
   370  	block := resp.GetData().(*types.Block)
   371  	return block, nil
   372  }
   373  
   374  //del mempool
   375  func (bc *BaseClient) delMempoolTx(deltx []*types.Transaction) error {
   376  	hashList := buildHashList(deltx)
   377  	msg := bc.client.NewMessage("mempool", types.EventDelTxList, hashList)
   378  	err := bc.client.Send(msg, true)
   379  	if err != nil {
   380  		return err
   381  	}
   382  	resp, err := bc.client.Wait(msg)
   383  	if err != nil {
   384  		return err
   385  	}
   386  	if resp.GetData().(*types.Reply).GetIsOk() {
   387  		return nil
   388  	}
   389  	return errors.New(string(resp.GetData().(*types.Reply).GetMsg()))
   390  }
   391  
   392  func buildHashList(deltx []*types.Transaction) *types.TxHashList {
   393  	list := &types.TxHashList{}
   394  	for i := 0; i < len(deltx); i++ {
   395  		list.Hashes = append(list.Hashes, deltx[i].Hash())
   396  	}
   397  	return list
   398  }
   399  
   400  //WriteBlock 向blockchain写区块
   401  func (bc *BaseClient) WriteBlock(prev []byte, block *types.Block) error {
   402  	//保存block的原始信息用于删除mempool中的错误交易
   403  	rawtxs := make([]*types.Transaction, len(block.Txs))
   404  	copy(rawtxs, block.Txs)
   405  
   406  	blockdetail := &types.BlockDetail{Block: block}
   407  	msg := bc.client.NewMessage("blockchain", types.EventAddBlockDetail, blockdetail)
   408  	err := bc.client.Send(msg, true)
   409  	if err != nil {
   410  		return err
   411  	}
   412  	resp, err := bc.client.Wait(msg)
   413  	if err != nil {
   414  		return err
   415  	}
   416  	blockdetail = resp.GetData().(*types.BlockDetail)
   417  	//从mempool 中删除错误的交易
   418  	deltx := diffTx(rawtxs, blockdetail.Block.Txs)
   419  	if len(deltx) > 0 {
   420  		err := bc.delMempoolTx(deltx)
   421  		if err != nil {
   422  			return err
   423  		}
   424  	}
   425  	if blockdetail != nil {
   426  		bc.SetCurrentBlock(blockdetail.Block)
   427  	} else {
   428  		return errors.New("block detail is nil")
   429  	}
   430  	return nil
   431  }
   432  
   433  // PreExecBlock 预执行区块, 用于raft, tendermint等共识, errReturn表示区块来源于自己还是别人
   434  func (bc *BaseClient) PreExecBlock(block *types.Block, errReturn bool) *types.Block {
   435  	lastBlock, err := bc.RequestBlock(block.Height - 1)
   436  	if err != nil {
   437  		log.Error("PreExecBlock RequestBlock fail", "err", err)
   438  		return nil
   439  	}
   440  	blockdetail, deltx, err := util.PreExecBlock(bc.client, lastBlock.StateHash, block, errReturn, false, true)
   441  	if err != nil {
   442  		log.Error("util.PreExecBlock fail", "err", err)
   443  		return nil
   444  	}
   445  	if len(deltx) > 0 {
   446  		err := bc.delMempoolTx(deltx)
   447  		if err != nil {
   448  			log.Error("PreExecBlock delMempoolTx fail", "err", err)
   449  			return nil
   450  		}
   451  	}
   452  	return blockdetail.Block
   453  }
   454  
   455  func diffTx(tx1, tx2 []*types.Transaction) (deltx []*types.Transaction) {
   456  	txlist2 := make(map[string]bool)
   457  	for _, tx := range tx2 {
   458  		txlist2[string(tx.Hash())] = true
   459  	}
   460  	for _, tx := range tx1 {
   461  		hash := string(tx.Hash())
   462  		if _, ok := txlist2[hash]; !ok {
   463  			deltx = append(deltx, tx)
   464  		}
   465  	}
   466  	return deltx
   467  }
   468  
   469  //SetCurrentBlock 设置当前区块
   470  func (bc *BaseClient) SetCurrentBlock(b *types.Block) {
   471  	bc.mulock.Lock()
   472  	bc.currentBlock = b
   473  	bc.mulock.Unlock()
   474  }
   475  
   476  //UpdateCurrentBlock 更新当前区块
   477  func (bc *BaseClient) UpdateCurrentBlock(b *types.Block) {
   478  	bc.mulock.Lock()
   479  	defer bc.mulock.Unlock()
   480  	block, err := bc.RequestLastBlock()
   481  	if err != nil {
   482  		log.Error("UpdateCurrentBlock", "RequestLastBlock", err)
   483  		return
   484  	}
   485  	bc.currentBlock = block
   486  }
   487  
   488  //GetCurrentBlock 获取当前区块
   489  func (bc *BaseClient) GetCurrentBlock() (b *types.Block) {
   490  	bc.mulock.Lock()
   491  	defer bc.mulock.Unlock()
   492  	return bc.currentBlock
   493  }
   494  
   495  //GetCurrentHeight 获取当前高度
   496  func (bc *BaseClient) GetCurrentHeight() int64 {
   497  	bc.mulock.Lock()
   498  	start := bc.currentBlock.Height
   499  	bc.mulock.Unlock()
   500  	return start
   501  }
   502  
   503  //Lock 上锁
   504  func (bc *BaseClient) Lock() {
   505  	bc.mulock.Lock()
   506  }
   507  
   508  //Unlock 解锁
   509  func (bc *BaseClient) Unlock() {
   510  	bc.mulock.Unlock()
   511  }
   512  
   513  //ConsensusTicketMiner ...
   514  func (bc *BaseClient) ConsensusTicketMiner(iscaughtup *types.IsCaughtUp) {
   515  	if !atomic.CompareAndSwapInt32(&bc.isCaughtUp, 0, 1) {
   516  		log.Info("ConsensusTicketMiner", "isCaughtUp", bc.isCaughtUp)
   517  	} else {
   518  		log.Info("ConsensusTicketMiner", "isCaughtUp", bc.isCaughtUp)
   519  	}
   520  }
   521  
   522  //AddTxsToBlock 添加交易到区块中
   523  func (bc *BaseClient) AddTxsToBlock(block *types.Block, txs []*types.Transaction) []*types.Transaction {
   524  	size := block.Size()
   525  	max := types.MaxBlockSize - 100000 //留下100K空间,添加其他的交易
   526  	currentCount := int64(len(block.Txs))
   527  	types.AssertConfig(bc.client)
   528  	cfg := bc.client.GetConfig()
   529  	maxTx := cfg.GetP(block.Height).MaxTxNumber
   530  	addedTx := make([]*types.Transaction, 0, len(txs))
   531  	for i := 0; i < len(txs); i++ {
   532  		txGroup, err := txs[i].GetTxGroup()
   533  		if err != nil {
   534  			continue
   535  		}
   536  		if txGroup == nil {
   537  			currentCount++
   538  			if currentCount > maxTx {
   539  				return addedTx
   540  			}
   541  			size += txs[i].Size()
   542  			if size > max {
   543  				return addedTx
   544  			}
   545  			addedTx = append(addedTx, txs[i])
   546  			block.Txs = append(block.Txs, txs[i])
   547  		} else {
   548  			currentCount += int64(len(txGroup.Txs))
   549  			if currentCount > maxTx {
   550  				return addedTx
   551  			}
   552  			for i := 0; i < len(txGroup.Txs); i++ {
   553  				size += txGroup.Txs[i].Size()
   554  			}
   555  			if size > max {
   556  				return addedTx
   557  			}
   558  			addedTx = append(addedTx, txGroup.Txs...)
   559  			block.Txs = append(block.Txs, txGroup.Txs...)
   560  		}
   561  	}
   562  	return addedTx
   563  }
   564  
   565  //CheckTxExpire 此时的tx交易组都是展开的,过滤掉已经过期的tx交易,目前只有ticket共识需要在updateBlock时调用
   566  func (bc *BaseClient) CheckTxExpire(txs []*types.Transaction, height int64, blocktime int64) (transactions []*types.Transaction) {
   567  	var txlist types.Transactions
   568  	var hasTxExpire bool
   569  
   570  	types.AssertConfig(bc.client)
   571  	cfg := bc.client.GetConfig()
   572  	for i := 0; i < len(txs); i++ {
   573  
   574  		groupCount := txs[i].GroupCount
   575  		if groupCount == 0 {
   576  			if isExpire(cfg, txs[i:i+1], height, blocktime) {
   577  				txs[i] = nil
   578  				hasTxExpire = true
   579  			}
   580  			continue
   581  		}
   582  
   583  		//判断GroupCount 是否会产生越界
   584  		if i+int(groupCount) > len(txs) {
   585  			continue
   586  		}
   587  
   588  		//交易组有过期交易时需要将整个交易组都删除
   589  		grouptxs := txs[i : i+int(groupCount)]
   590  		if isExpire(cfg, grouptxs, height, blocktime) {
   591  			for j := i; j < i+int(groupCount); j++ {
   592  				txs[j] = nil
   593  				hasTxExpire = true
   594  			}
   595  		}
   596  		i = i + int(groupCount) - 1
   597  	}
   598  
   599  	//有过期交易时需要重新组装交易
   600  	if hasTxExpire {
   601  		for _, tx := range txs {
   602  			if tx != nil {
   603  				txlist.Txs = append(txlist.Txs, tx)
   604  			}
   605  		}
   606  		return txlist.GetTxs()
   607  	}
   608  
   609  	return txs
   610  }
   611  
   612  //检测交易数组是否过期,只要有一个过期就认为整个交易组过期
   613  func isExpire(cfg *types.TuringchainConfig, txs []*types.Transaction, height int64, blocktime int64) bool {
   614  	for _, tx := range txs {
   615  		if height > 0 && blocktime > 0 && tx.IsExpire(cfg, height, blocktime) {
   616  			log.Debug("isExpire", "height", height, "blocktime", blocktime, "hash", common.ToHex(tx.Hash()), "Expire", tx.Expire)
   617  			return true
   618  		}
   619  	}
   620  	return false
   621  }
   622  
   623  //CmpBestBlock 最优区块的比较
   624  //height,BlockTime,ParentHash必须一致才可以继续比较
   625  //通过比较newBlock是最优区块就返回true,否则返回false
   626  func (bc *BaseClient) CmpBestBlock(newBlock *types.Block, cmpHash []byte) bool {
   627  
   628  	cfg := bc.client.GetConfig()
   629  	curBlock := bc.GetCurrentBlock()
   630  
   631  	//需要比较的区块就是当前区块,
   632  	if bytes.Equal(cmpHash, curBlock.Hash(cfg)) {
   633  		if curBlock.GetHeight() == newBlock.GetHeight() && curBlock.BlockTime == newBlock.BlockTime && bytes.Equal(newBlock.GetParentHash(), curBlock.GetParentHash()) {
   634  			return bc.child.CmpBestBlock(newBlock, curBlock)
   635  		}
   636  		return false
   637  	}
   638  	//需要比较的区块不是当前区块,需要从blockchain模块获取cmpHash对应的block信息
   639  	block, err := bc.ReqBlockByHash(cmpHash)
   640  	if err != nil {
   641  		log.Error("CmpBestBlock:RequestBlockByHash", "Hash", common.ToHex(cmpHash), "err", err)
   642  		return false
   643  	}
   644  
   645  	if block.GetHeight() == newBlock.GetHeight() && block.BlockTime == newBlock.BlockTime && bytes.Equal(block.GetParentHash(), newBlock.GetParentHash()) {
   646  		return bc.child.CmpBestBlock(newBlock, block)
   647  	}
   648  	return false
   649  }
   650  
   651  //ReqBlockByHash 通过区块hash获取区块信息
   652  func (bc *BaseClient) ReqBlockByHash(hash []byte) (*types.Block, error) {
   653  	if bc.client == nil {
   654  		panic("bc not bind message queue.")
   655  	}
   656  	hashes := types.ReqHashes{}
   657  	hashes.Hashes = append(hashes.Hashes, hash)
   658  	msg := bc.client.NewMessage("blockchain", types.EventGetBlockByHashes, &hashes)
   659  	err := bc.client.Send(msg, true)
   660  	if err != nil {
   661  		return nil, err
   662  	}
   663  	resp, err := bc.client.Wait(msg)
   664  	if err != nil {
   665  		return nil, err
   666  	}
   667  	blocks := resp.GetData().(*types.BlockDetails)
   668  	if len(blocks.Items) == 1 && blocks.Items[0] != nil {
   669  		return blocks.Items[0].Block, nil
   670  	}
   671  	return nil, types.ErrHashNotExist
   672  }