text: // Copyright 2018-2019 The PlatON Network Authors
  // This file is part of the PlatON-Go library.
  //
  // The PlatON-Go library is free software: you can redistribute it and/or modify
  // it under the terms of the GNU Lesser General Public License as published by
  // the Free Software Foundation, either version 3 of the License, or
  // (at your option) any later version.
  //
  // The PlatON-Go library is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  // GNU Lesser General Public License for more details.
  //
  // You should have received a copy of the GNU Lesser General Public License
  // along with the PlatON-Go library. If not, see <http://www.gnu.org/licenses/>.
  
  package protocols
  
  import (
  	"fmt"
  	"math/big"
  	"reflect"
  	"sync/atomic"
  
  	"github.com/PlatONnetwork/PlatON-Go/common"
  	ctypes "github.com/PlatONnetwork/PlatON-Go/consensus/cbft/types"
  	"github.com/PlatONnetwork/PlatON-Go/consensus/cbft/utils"
  	"github.com/PlatONnetwork/PlatON-Go/core/types"
  	"github.com/PlatONnetwork/PlatON-Go/crypto"
  	"github.com/PlatONnetwork/PlatON-Go/rlp"
  )
  
  // Maximum cap on the size of a cbft protocol message
  const CbftProtocolMaxMsgSize = 10 * 1024 * 1024
  
  // Default average delay time (in milliseconds).
  const DefaultAvgLatency = 100
  
  const (
  	CBFTStatusMsg           = 0x00 // Protocol messages belonging to cbft
  	PrepareBlockMsg         = 0x01
  	PrepareVoteMsg          = 0x02
  	ViewChangeMsg           = 0x03
  	GetPrepareBlockMsg      = 0x04
  	GetBlockQuorumCertMsg   = 0x05
  	BlockQuorumCertMsg      = 0x06
  	GetPrepareVoteMsg       = 0x07
  	PrepareVotesMsg         = 0x08
  	GetQCBlockListMsg       = 0x09
  	QCBlockListMsg          = 0x0a
  	GetLatestStatusMsg      = 0x0b
  	LatestStatusMsg         = 0x0c
  	PrepareBlockHashMsg     = 0x0d
  	GetViewChangeMsg        = 0x0e
  	PingMsg                 = 0x0f
  	PongMsg                 = 0x10
  	ViewChangeQuorumCertMsg = 0x11
  	ViewChangesMsg          = 0x12
  )
  
  // A is used to convert specific message types according to the message body.
  // The program is forcibly terminated if there is an unmatched message type and
  // all types must exist in the match list.
  func MessageType(msg interface{}) uint64 {
  	switch msg.(type) {
  	case *CbftStatusData:
  		return CBFTStatusMsg
  	case *PrepareBlock:
  		return PrepareBlockMsg
  	case *PrepareVote:
  		return PrepareVoteMsg
  	case *ViewChange:
  		return ViewChangeMsg
  	case *GetPrepareBlock:
  		return GetPrepareBlockMsg
  	case *GetBlockQuorumCert:
  		return GetBlockQuorumCertMsg
  	case *BlockQuorumCert:
  		return BlockQuorumCertMsg
  	case *GetQCBlockList:
  		return GetQCBlockListMsg
  	case *GetPrepareVote:
  		return GetPrepareVoteMsg
  	case *PrepareBlockHash:
  		return PrepareBlockHashMsg
  	case *PrepareVotes:
  		return PrepareVotesMsg
  	case *QCBlockList:
  		return QCBlockListMsg
  	case *GetLatestStatus:
  		return GetLatestStatusMsg
  	case *LatestStatus:
  		return LatestStatusMsg
  	case *GetViewChange:
  		return GetViewChangeMsg
  	case *Ping:
  		return PingMsg
  	case *Pong:
  		return PongMsg
  	case *ViewChangeQuorumCert:
  		return ViewChangeQuorumCertMsg
  	case *ViewChanges:
  		return ViewChangesMsg
  	default:
  	}
  	panic(fmt.Sprintf("unknown message type [%v}", reflect.TypeOf(msg)))
  }
  
  // Proposed block carrier.
  type PrepareBlock struct {
  	Epoch         uint64               `json:"epoch"`
  	ViewNumber    uint64               `json:"viewNumber"`
  	Block         *types.Block         `json:"blockHash"`
  	BlockIndex    uint32               `json:"blockIndex"`             // The block number of the current ViewNumber proposal, 0....10
  	ProposalIndex uint32               `json:"proposalIndex"`          // Proposer's index.
  	PrepareQC     *ctypes.QuorumCert   `json:"prepareQC" rlp:"nil"`    // N-f aggregate signature
  	ViewChangeQC  *ctypes.ViewChangeQC `json:"viewchangeQC" rlp:"nil"` // viewChange aggregate signature
  	Signature     ctypes.Signature     `json:"signature"`              // PrepareBlock signature information
  	messageHash   atomic.Value         `rlp:"-"`
  }
  
  func (pb *PrepareBlock) String() string {
  	return fmt.Sprintf("{Epoch:%d,ViewNumber:%d,Hash:%s,Number:%d,BlockIndex:%d,ProposalIndex:%d,ParentHash:%s}",
  		pb.Epoch, pb.ViewNumber, pb.Block.Hash().TerminalString(), pb.Block.NumberU64(), pb.BlockIndex, pb.ProposalIndex, pb.Block.ParentHash().TerminalString())
  }
  
  func (pb *PrepareBlock) MsgHash() common.Hash {
  	if mhash := pb.messageHash.Load(); mhash != nil {
  		return mhash.(common.Hash)
  	}
  	v := utils.BuildHash(PrepareBlockMsg,
  		utils.MergeBytes(common.Uint64ToBytes(pb.ViewNumber), pb.Block.Hash().Bytes(), pb.Signature.Bytes()))
  	pb.messageHash.Store(v)
  	return v
  }
  
  func (pb *PrepareBlock) BHash() common.Hash {
  	return pb.Block.Hash()
  }
  func (pb *PrepareBlock) EpochNum() uint64 {
  	return pb.Epoch
  }
  func (pb *PrepareBlock) ViewNum() uint64 {
  	return pb.ViewNumber
  }
  func (pb *PrepareBlock) BlockNum() uint64 {
  	return pb.Block.NumberU64()
  }
  
  func (pb *PrepareBlock) NodeIndex() uint32 {
  	return pb.ProposalIndex
  }
  
  func (pb *PrepareBlock) CannibalizeBytes() ([]byte, error) {
  	blockData, err := rlp.EncodeToBytes(pb.Block)
  	if err != nil {
  		return nil, err
  	}
  	buf, err := rlp.EncodeToBytes([]interface{}{
  		pb.Epoch,
  		pb.ViewNumber,
  		pb.Block.Hash(),
  		pb.Block.NumberU64(),
  		crypto.Keccak256(blockData),
  		pb.BlockIndex,
  		pb.ProposalIndex,
  	})
  	if err != nil {
  		return nil, err
  	}
  	return crypto.Keccak256(buf), nil
  }
  
  func (pb *PrepareBlock) Sign() []byte {
  	return pb.Signature.Bytes()
  }
  
  func (pb *PrepareBlock) SetSign(sign []byte) {
  	pb.Signature.SetBytes(sign)
  }
  
  // Removed the validator address, index. Mainly to ensure
  // that the signature hash of the aggregate signature is consistent.
  type PrepareVote struct {
  	Epoch          uint64             `json:"epoch"`
  	ViewNumber     uint64             `json:"viewNumber"`
  	BlockHash      common.Hash        `json:"blockHash"`
  	BlockNumber    uint64             `json:"blockNumber"`
  	BlockIndex     uint32             `json:"blockIndex"` // The block number of the current ViewNumber proposal, 0....10
  	ValidatorIndex uint32             `json:"validatorIndex"`
  	ParentQC       *ctypes.QuorumCert `json:"parentQC" rlp:"nil"`
  	Signature      ctypes.Signature   `json:"signature"`
  	messageHash    atomic.Value       `rlp:"-"`
  }
  
  func (pv *PrepareVote) String() string {
  	return fmt.Sprintf("{Epoch:%d,ViewNumber:%d,Hash:%s,Number:%d,BlockIndex:%d,ValidatorIndex:%d}",
  		pv.Epoch, pv.ViewNumber, pv.BlockHash.TerminalString(), pv.BlockNumber, pv.BlockIndex, pv.ValidatorIndex)
  }
  
  func (pv *PrepareVote) MsgHash() common.Hash {
  	if mhash := pv.messageHash.Load(); mhash != nil {
  		return mhash.(common.Hash)
  	}
  	v := utils.BuildHash(PrepareVoteMsg,
  		utils.MergeBytes(common.Uint64ToBytes(pv.ViewNumber), pv.BlockHash.Bytes(), common.Uint32ToBytes(pv.BlockIndex), pv.Signature.Bytes()))
  	pv.messageHash.Store(v)
  	return v
  }
  
  func (pv *PrepareVote) BHash() common.Hash {
  	return pv.BlockHash
  }
  func (pv *PrepareVote) EpochNum() uint64 {
  	return pv.Epoch
  }
  func (pv *PrepareVote) ViewNum() uint64 {
  	return pv.ViewNumber
  }
  
  func (pv *PrepareVote) BlockNum() uint64 {
  	return pv.BlockNumber
  }
  
  func (pv *PrepareVote) NodeIndex() uint32 {
  	return pv.ValidatorIndex
  }
  
  func (pv *PrepareVote) CannibalizeBytes() ([]byte, error) {
  	buf, err := rlp.EncodeToBytes([]interface{}{
  		pv.Epoch,
  		pv.ViewNumber,
  		pv.BlockHash,
  		pv.BlockNumber,
  		pv.BlockIndex,
  	})
  
  	if err != nil {
  		return nil, err
  	}
  	return crypto.Keccak256(buf), nil
  }
  
  func (pv *PrepareVote) Sign() []byte {
  	return pv.Signature.Bytes()
  }
  
  func (pv *PrepareVote) SetSign(sign []byte) {
  	pv.Signature.SetBytes(sign)
  }
  
  func (pv *PrepareVote) EqualState(vote *PrepareVote) bool {
  	return pv.Epoch == vote.Epoch &&
  		pv.ViewNumber == vote.ViewNumber &&
  		pv.BlockHash == vote.BlockHash &&
  		pv.BlockNumber == vote.BlockNumber &&
  		pv.BlockIndex == vote.BlockIndex
  }
  
  // ViewChange is message structure for view switching.
  type ViewChange struct {
  	Epoch          uint64             `json:"epoch"`
  	ViewNumber     uint64             `json:"viewNumber"`
  	BlockHash      common.Hash        `json:"blockHash"`
  	BlockNumber    uint64             `json:"blockNumber"`
  	ValidatorIndex uint32             `json:"validatorIndex"`
  	PrepareQC      *ctypes.QuorumCert `json:"prepareQC" rlp:"nil"`
  	Signature      ctypes.Signature   `json:"signature"`
  	messageHash    atomic.Value       `rlp:"-"`
  }
  
  func (vc *ViewChange) String() string {
  	return fmt.Sprintf("{Epoch:%d,ViewNumber:%d,BlockHash:%s,BlockNumber:%d,ValidatorIndex:%d}",
  		vc.Epoch, vc.ViewNumber, vc.BlockHash.TerminalString(), vc.BlockNumber, vc.ValidatorIndex)
  }
  
  func (vc *ViewChange) MsgHash() common.Hash {
  	if mhash := vc.messageHash.Load(); mhash != nil {
  		return mhash.(common.Hash)
  	}
  	v := utils.BuildHash(ViewChangeMsg, utils.MergeBytes(common.Uint64ToBytes(vc.ViewNumber),
  		vc.BlockHash.Bytes(), common.Uint64ToBytes(vc.BlockNumber), common.Uint32ToBytes(vc.ValidatorIndex),
  		vc.Signature.Bytes()))
  	vc.messageHash.Store(v)
  	return v
  }
  
  func (vc *ViewChange) BHash() common.Hash {
  	return vc.BlockHash
  }
  
  func (vc *ViewChange) EpochNum() uint64 {
  	return vc.Epoch
  }
  
  func (vc *ViewChange) ViewNum() uint64 {
  	return vc.ViewNumber
  }
  
  func (vc *ViewChange) BlockNum() uint64 {
  	return vc.BlockNumber
  }
  
  func (vc *ViewChange) NodeIndex() uint32 {
  	return vc.ValidatorIndex
  }
  
  func (vc *ViewChange) CannibalizeBytes() ([]byte, error) {
  	blockEpoch, blockView := uint64(0), uint64(0)
  	if vc.PrepareQC != nil {
  		blockEpoch, blockView = vc.PrepareQC.Epoch, vc.PrepareQC.ViewNumber
  	}
  	buf, err := rlp.EncodeToBytes([]interface{}{
  		vc.Epoch,
  		vc.ViewNumber,
  		vc.BlockHash,
  		vc.BlockNumber,
  		blockEpoch,
  		blockView,
  	})
  
  	if err != nil {
  		return nil, err
  	}
  	return crypto.Keccak256(buf), nil
  }
  
  func (vc *ViewChange) Sign() []byte {
  	return vc.Signature.Bytes()
  }
  
  func (vc *ViewChange) SetSign(sign []byte) {
  	vc.Signature.SetBytes(sign)
  }
  
  type ViewChanges struct {
  	VCs         []*ViewChange
  	messageHash atomic.Value `rlp:"-"`
  }
  
  func (v ViewChanges) String() string {
  	if len(v.VCs) != 0 {
  		epoch, viewNumber := v.VCs[0].Epoch, v.VCs[0].ViewNumber
  		return fmt.Sprintf("{Epoch:%d,ViewNumber:%d,Len:%d}", epoch, viewNumber, len(v.VCs))
  	}
  	return fmt.Sprintf("{Len:%d}", len(v.VCs))
  }
  
  func (v ViewChanges) MsgHash() common.Hash {
  	if mhash := v.messageHash.Load(); mhash != nil {
  		return mhash.(common.Hash)
  	}
  	var mv common.Hash
  	if len(v.VCs) != 0 {
  		epoch, viewNumber := v.VCs[0].Epoch, v.VCs[0].ViewNumber
  		mv = utils.BuildHash(ViewChangesMsg, utils.MergeBytes(common.Uint64ToBytes(epoch),
  			common.Uint64ToBytes(viewNumber)))
  	} else {
  		mv = utils.BuildHash(ViewChangesMsg, common.Hash{}.Bytes())
  	}
  	v.messageHash.Store(mv)
  	return mv
  }
  
  func (ViewChanges) BHash() common.Hash {
  	return common.Hash{}
  }
  
  // CbftStatusData implement Message and including status information about peer.
  type CbftStatusData struct {
  	ProtocolVersion uint32       `json:"protocolVersion"` // CBFT protocol version number.
  	QCBn            *big.Int     `json:"qcBn"`            // The highest local block number for collecting block signatures.
  	QCBlock         common.Hash  `json:"qcBlock"`         // The highest local block hash for collecting block signatures.
  	LockBn          *big.Int     `json:"lockBn"`          // Locally locked block number.
  	LockBlock       common.Hash  `json:"lockBlock"`       // Locally locked block hash.
  	CmtBn           *big.Int     `json:"cmtBn"`           // Locally submitted block number.
  	CmtBlock        common.Hash  `json:"cmtBlock"`        // Locally submitted block hash.
  	messageHash     atomic.Value `rlp:"-"`
  }
  
  func (s *CbftStatusData) String() string {
  	return fmt.Sprintf("{ProtocolVersion:%d,QCBn:%d,LockBn:%d,CmtBn:%d}",
  		s.ProtocolVersion, s.QCBn.Uint64(), s.LockBn.Uint64(), s.CmtBn.Uint64())
  }
  
  func (s *CbftStatusData) MsgHash() common.Hash {
  	if mhash := s.messageHash.Load(); mhash != nil {
  		return mhash.(common.Hash)
  	}
  	v := utils.BuildHash(CBFTStatusMsg, utils.MergeBytes(s.QCBlock.Bytes(),
  		s.LockBlock.Bytes(), s.CmtBlock.Bytes()))
  	s.messageHash.Store(v)
  	return v
  }
  
  func (s *CbftStatusData) BHash() common.Hash {
  	return s.QCBlock
  }
  
  // GetPrepareBlock is used to get the
  // proposed block information.
  type GetPrepareBlock struct {
  	Epoch       uint64
  	ViewNumber  uint64
  	BlockIndex  uint32
  	messageHash atomic.Value `rlp:"-"`
  }
  
  func (s *GetPrepareBlock) String() string {
  	return fmt.Sprintf("{Epoch:%d,ViewNumber:%d,BlockIndex:%d}", s.Epoch, s.ViewNumber, s.BlockIndex)
  }
  
  func (s *GetPrepareBlock) MsgHash() common.Hash {
  	if mhash := s.messageHash.Load(); mhash != nil {
  		return mhash.(common.Hash)
  	}
  	v := utils.BuildHash(GetPrepareBlockMsg, utils.MergeBytes(common.Uint64ToBytes(s.Epoch), common.Uint64ToBytes(s.ViewNumber), common.Uint32ToBytes(s.BlockIndex)))
  	s.messageHash.Store(v)
  	return v
  }
  
  func (s *GetPrepareBlock) BHash() common.Hash {
  	return common.Hash{}
  }
  
  // GetBlockQuorumCert is the protocol message for obtaining an aggregated signature.
  // todo: Need to determine the attribute field - ParentQC.
  type GetBlockQuorumCert struct {
  	BlockHash   common.Hash  `json:"blockHash"`   // The hash of the block to be acquired.
  	BlockNumber uint64       `json:"blockNumber"` // The number of the block to be acquired.
  	messageHash atomic.Value `json:"-" rlp:"-"`
  }
  
  func (s *GetBlockQuorumCert) String() string {
  	return fmt.Sprintf("{Hash:%s,Number:%d}", s.BlockHash.TerminalString(), s.BlockNumber)
  }
  
  func (s *GetBlockQuorumCert) MsgHash() common.Hash {
  	if mhash := s.messageHash.Load(); mhash != nil {
  		return mhash.(common.Hash)
  	}
  	v := utils.BuildHash(GetBlockQuorumCertMsg, utils.MergeBytes(s.BlockHash.Bytes(), common.Uint64ToBytes(s.BlockNumber)))
  	s.messageHash.Store(v)
  	return v
  }
  
  func (s *GetBlockQuorumCert) BHash() common.Hash {
  	return s.BlockHash
  }
  
  // Aggregate signature response message, representing
  // aggregated signature information for a block.
  type BlockQuorumCert struct {
  	BlockQC     *ctypes.QuorumCert `json:"qc"`        // Block aggregation signature information.
  	messageHash atomic.Value       `json:"-" rlp:"-"` // BlockQuorumCert hash value.
  }
  
  func (s *BlockQuorumCert) String() string {
  	return fmt.Sprintf("{Epoch:%d,ViewNumber:%d,BlockIndex:%d,Hash:%s,Number:%d}",
  		s.BlockQC.Epoch, s.BlockQC.ViewNumber, s.BlockQC.BlockIndex, s.BlockQC.BlockHash.TerminalString(), s.BlockQC.BlockNumber)
  }
  
  func (s *BlockQuorumCert) MsgHash() common.Hash {
  	if mhash := s.messageHash.Load(); mhash != nil {
  		return mhash.(common.Hash)
  	}
  	v := utils.BuildHash(BlockQuorumCertMsg, utils.MergeBytes(
  		s.BlockQC.BlockHash.Bytes(),
  		common.Uint64ToBytes(s.BlockQC.BlockNumber), s.BlockQC.Signature.Bytes()))
  	s.messageHash.Store(v)
  	return v
  }
  
  func (s *BlockQuorumCert) BHash() common.Hash {
  	return s.BlockQC.BlockHash
  }
  
  // Used to get block information that has reached QC.
  // Note: Get up to 3 blocks of data at a time.
  type GetQCBlockList struct {
  	BlockHash   common.Hash  `json:"blockHash"`   // The hash to the block.
  	BlockNumber uint64       `json:"blockNumber"` // The number corresponding to the block.
  	messageHash atomic.Value `json:"-" rlp:"-"`
  }
  
  func (s *GetQCBlockList) String() string {
  	return fmt.Sprintf("{BlockkNumber:%d,BlockHash:%s}", s.BlockNumber, s.BlockHash.TerminalString())
  }
  
  func (s *GetQCBlockList) MsgHash() common.Hash {
  	if mhash := s.messageHash.Load(); mhash != nil {
  		return mhash.(common.Hash)
  	}
  	v := utils.BuildHash(GetQCBlockListMsg, utils.MergeBytes(
  		common.Uint64ToBytes(s.BlockNumber)))
  	s.messageHash.Store(v)
  	return v
  }
  
  func (s *GetQCBlockList) BHash() common.Hash {
  	return common.Hash{}
  }
  
  // Message used to get block voting.
  type GetPrepareVote struct {
  	Epoch       uint64
  	ViewNumber  uint64
  	BlockIndex  uint32
  	UnKnownSet  *utils.BitArray
  	messageHash atomic.Value `json:"-" rlp:"-"`
  }
  
  func (s *GetPrepareVote) String() string {
  	return fmt.Sprintf("{Epoch:%d,ViewNumber:%d,BlockIndex:%d,UnKnownSet:%s}", s.Epoch, s.ViewNumber, s.BlockIndex, s.UnKnownSet.String())
  }
  
  func (s *GetPrepareVote) MsgHash() common.Hash {
  	if mhash := s.messageHash.Load(); mhash != nil {
  		return mhash.(common.Hash)
  	}
  	v := utils.BuildHash(GetPrepareVoteMsg, utils.MergeBytes(common.Uint64ToBytes(s.Epoch), common.Uint64ToBytes(s.ViewNumber),
  		common.Uint32ToBytes(s.BlockIndex)))
  	s.messageHash.Store(v)
  	return v
  }
  
  func (s *GetPrepareVote) BHash() common.Hash {
  	return common.Hash{}
  }
  
  // Message used to respond to the number of block votes.
  type PrepareVotes struct {
  	Epoch       uint64
  	ViewNumber  uint64
  	BlockIndex  uint32
  	Votes       []*PrepareVote // Block voting set.
  	messageHash atomic.Value   `json:"-" rlp:"-"`
  }
  
  func (s *PrepareVotes) String() string {
  	return fmt.Sprintf("{Epoch:%d,ViewNumber:%d,BlockIndex:%d}", s.Epoch, s.ViewNumber, s.BlockIndex)
  }
  
  func (s *PrepareVotes) MsgHash() common.Hash {
  	if mhash := s.messageHash.Load(); mhash != nil {
  		return mhash.(common.Hash)
  	}
  	v := utils.BuildHash(PrepareVotesMsg, utils.MergeBytes(common.Uint64ToBytes(s.Epoch), common.Uint64ToBytes(s.ViewNumber), common.Uint32ToBytes(s.BlockIndex)))
  	s.messageHash.Store(v)
  	return v
  }
  
  func (s *PrepareVotes) BHash() common.Hash {
  	return common.Hash{}
  }
  
  // Represents the hash of the proposed block for secondary propagation.
  type PrepareBlockHash struct {
  	Epoch       uint64
  	ViewNumber  uint64
  	BlockIndex  uint32
  	BlockHash   common.Hash
  	BlockNumber uint64
  	messageHash atomic.Value `json:"-" rlp:"-"`
  }
  
  func (s *PrepareBlockHash) String() string {
  	return fmt.Sprintf("{Epoch:%d,ViewNumber:%d,BlockIndex:%d,Hash:%s,Number:%d}", s.Epoch, s.ViewNumber, s.BlockIndex, s.BlockHash.TerminalString(), s.BlockNumber)
  }
  
  func (s *PrepareBlockHash) MsgHash() common.Hash {
  	if mhash := s.messageHash.Load(); mhash != nil {
  		return mhash.(common.Hash)
  	}
  	v := utils.BuildHash(PrepareBlockHashMsg, utils.MergeBytes(s.BlockHash.Bytes(), common.Uint64ToBytes(s.BlockNumber),
  		common.Uint32ToBytes(s.BlockIndex), common.Uint64ToBytes(s.ViewNumber)))
  	s.messageHash.Store(v)
  	return v
  
  }
  
  func (s *PrepareBlockHash) BHash() common.Hash {
  	return s.BlockHash
  }
  
  // For time detection.
  type Ping [1]string
  
  func (s *Ping) String() string {
  	return fmt.Sprintf("{pingTime:%s}", s[0])
  }
  
  func (s *Ping) MsgHash() common.Hash {
  	return utils.BuildHash(PingMsg, utils.MergeBytes([]byte(s[0])))
  }
  
  func (s *Ping) BHash() common.Hash {
  	return common.Hash{}
  }
  
  // Response to ping.
  type Pong [1]string
  
  func (s *Pong) String() string {
  	return fmt.Sprintf("{pongTime:%s}", s[0])
  }
  
  func (s *Pong) MsgHash() common.Hash {
  	return utils.BuildHash(PongMsg, utils.MergeBytes([]byte(s[0])))
  }
  
  func (s *Pong) BHash() common.Hash {
  	return common.Hash{}
  }
  
  // CBFT synchronize blocks that have reached qc.
  type QCBlockList struct {
  	QC           []*ctypes.QuorumCert
  	Blocks       []*types.Block
  	ForkedQC     []*ctypes.QuorumCert
  	ForkedBlocks []*types.Block
  	messageHash  atomic.Value `rlp:"-"`
  }
  
  func (s *QCBlockList) String() string {
  	return fmt.Sprintf("{QC.Len:%d,Blocks.Len:%d,ForkedQC.Len:%d,ForkedBlocks.Len:%d}", len(s.QC), len(s.Blocks), len(s.ForkedQC), len(s.ForkedBlocks))
  }
  
  func (s *QCBlockList) MsgHash() common.Hash {
  	if mhash := s.messageHash.Load(); mhash != nil {
  		return mhash.(common.Hash)
  	}
  	v := common.Hash{}
  	if len(s.QC) != 0 {
  		v = utils.BuildHash(QCBlockListMsg, utils.MergeBytes(s.QC[0].BlockHash.Bytes(),
  			s.QC[0].Signature.Bytes()))
  	}
  	if len(s.Blocks) != 0 {
  		v = utils.BuildHash(QCBlockListMsg, utils.MergeBytes(s.Blocks[0].Hash().Bytes(),
  			s.Blocks[0].Number().Bytes()))
  	}
  	s.messageHash.Store(v)
  	return v
  }
  
  func (s *QCBlockList) BHash() common.Hash {
  	// No explicit hash value and return empty hash.
  	return common.Hash{}
  }
  
  // State synchronization for nodes.
  type GetLatestStatus struct {
  	BlockNumber  uint64             `json:"blockNumber"`           // QC Block height
  	BlockHash    common.Hash        `json:"blockHash"`             // QC block hash
  	QuorumCert   *ctypes.QuorumCert `json:"quorumCert" rlp:"nil"`  // QC quorumCert
  	LBlockNumber uint64             `json:"lBlockNumber"`          // Locked block height
  	LBlockHash   common.Hash        `json:"lBlockHash"`            // Locked block hash
  	LQuorumCert  *ctypes.QuorumCert `json:"lQuorumCert" rlp:"nil"` // Locked quorumCert
  	LogicType    uint64             `json:"logicType"`             // LogicType: 1 QCBn, 2 LockedBn, 3 CommitBn
  	messageHash  atomic.Value       `rlp:"-"`
  }
  
  func (s *GetLatestStatus) String() string {
  	return fmt.Sprintf("{BlockNumber:%d,BlockHash:%s,QuorumCert:%s,LBlockNumber:%d,LBlockHash:%s,LQuorumCert:%s,LogicType:%d}",
  		s.BlockNumber, s.BlockHash.String(), s.QuorumCert.String(), s.LBlockNumber, s.LBlockHash.String(), s.LQuorumCert.String(), s.LogicType)
  }
  
  func (s *GetLatestStatus) MsgHash() common.Hash {
  	if mhash := s.messageHash.Load(); mhash != nil {
  		return mhash.(common.Hash)
  	}
  	v := utils.BuildHash(GetLatestStatusMsg,
  		utils.MergeBytes(common.Uint64ToBytes(s.BlockNumber), common.Uint64ToBytes(s.LogicType),
  			common.Uint64ToBytes(s.LBlockNumber), s.BlockHash.Bytes(), s.LBlockHash.Bytes()))
  	s.messageHash.Store(v)
  	return v
  
  }
  
  func (s *GetLatestStatus) BHash() common.Hash {
  	return s.BlockHash
  }
  
  // Response message to GetLatestStatus request.
  type LatestStatus struct {
  	BlockNumber  uint64             `json:"blockNumber"`           // QC Block height
  	BlockHash    common.Hash        `json:"blockHash"`             // QC block hash
  	QuorumCert   *ctypes.QuorumCert `json:"quorumCert" rlp:"nil"`  // QC quorumCert
  	LBlockNumber uint64             `json:"lBlockNumber"`          // Locked block height
  	LBlockHash   common.Hash        `json:"lBlockHash"`            // Locked block hash
  	LQuorumCert  *ctypes.QuorumCert `json:"lQuorumCert" rlp:"nil"` // Locked quorumCert
  	LogicType    uint64             `json:"logicType"`             // LogicType: 1 QCBn, 2 LockedBn, 3 CommitBn
  	messageHash  atomic.Value       `rlp:"-"`
  }
  
  func (s *LatestStatus) String() string {
  	return fmt.Sprintf("{BlockNumber:%d,BlockHash:%s,QuorumCert:%s,LBlockNumber:%d,LBlockHash:%s,LQuorumCert:%s,LogicType:%d}",
  		s.BlockNumber, s.BlockHash.String(), s.QuorumCert.String(), s.LBlockNumber, s.LBlockHash.String(), s.LQuorumCert.String(), s.LogicType)
  }
  
  func (s *LatestStatus) MsgHash() common.Hash {
  	if mhash := s.messageHash.Load(); mhash != nil {
  		return mhash.(common.Hash)
  	}
  	v := utils.BuildHash(LatestStatusMsg,
  		utils.MergeBytes(common.Uint64ToBytes(s.BlockNumber), common.Uint64ToBytes(s.LogicType),
  			common.Uint64ToBytes(s.LBlockNumber), s.BlockHash.Bytes(), s.LBlockHash.Bytes()))
  	s.messageHash.Store(v)
  	return v
  }
  
  func (s *LatestStatus) BHash() common.Hash {
  	return s.BlockHash
  }
  
  // Used to actively request to get viewChange.
  type GetViewChange struct {
  	Epoch          uint64          `json:"epoch"`
  	ViewNumber     uint64          `json:"viewNumber"`
  	ViewChangeBits *utils.BitArray `json:"nodeIndexes"`
  	messageHash    atomic.Value    `rlp:"-"`
  }
  
  func (s *GetViewChange) String() string {
  	return fmt.Sprintf("{Epoch:%d,ViewNumber:%d,NodeIndexesLen:%s}", s.Epoch, s.ViewNumber, s.ViewChangeBits.String())
  }
  
  func (s *GetViewChange) MsgHash() common.Hash {
  	if mhash := s.messageHash.Load(); mhash != nil {
  		return mhash.(common.Hash)
  	}
  	v := utils.BuildHash(GetViewChangeMsg,
  		utils.MergeBytes(common.Uint64ToBytes(s.Epoch), common.Uint64ToBytes(s.ViewNumber)))
  	s.messageHash.Store(v)
  	return v
  }
  
  func (s *GetViewChange) BHash() common.Hash {
  	return common.Hash{}
  }
  
  type ViewChangeQuorumCert struct {
  	ViewChangeQC *ctypes.ViewChangeQC `json:"viewchangeQC"` // viewChange aggregate signature
  	messageHash  atomic.Value         `rlp:"-"`
  }
  
  func (v *ViewChangeQuorumCert) String() string {
  	epoch, viewNumber, blockEpoch, blockViewNumber, hash, number := v.ViewChangeQC.MaxBlock()
  	return fmt.Sprintf("{Epoch:%d,ViewNumber:%d,BlockEpoch:%d,BlockViewNumber:%d,Hash:%s,Number:%d}",
  		epoch, viewNumber, blockEpoch, blockViewNumber, hash.TerminalString(), number)
  }
  
  func (v *ViewChangeQuorumCert) MsgHash() common.Hash {
  	if mhash := v.messageHash.Load(); mhash != nil {
  		return mhash.(common.Hash)
  	}
  	epoch, viewNumber, blockEpoch, blockViewNumber, hash, number := v.ViewChangeQC.MaxBlock()
  	mv := utils.BuildHash(ViewChangeQuorumCertMsg, utils.MergeBytes(
  		common.Uint64ToBytes(epoch),
  		common.Uint64ToBytes(viewNumber),
  		common.Uint64ToBytes(blockEpoch),
  		common.Uint64ToBytes(blockViewNumber),
  		hash.Bytes(),
  		common.Uint64ToBytes(number)))
  	v.messageHash.Store(mv)
  	return mv
  }
  
  func (v *ViewChangeQuorumCert) BHash() common.Hash {
  	_, _, _, _, hash, _ := v.ViewChangeQC.MaxBlock()
  	return hash
  }
  