github.com/aergoio/aergo@v1.3.1/consensus/impl/raftv2/blockfactory.go (about)

     1  package raftv2
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"encoding/json"
     7  	"errors"
     8  	"fmt"
     9  	"github.com/aergoio/aergo/p2p/p2pcommon"
    10  	"github.com/aergoio/aergo/p2p/p2pkey"
    11  	"runtime"
    12  	"strings"
    13  	"sync"
    14  	"time"
    15  
    16  	"github.com/aergoio/aergo/internal/enc"
    17  	"github.com/libp2p/go-libp2p-core/crypto"
    18  
    19  	"github.com/aergoio/aergo-lib/log"
    20  	bc "github.com/aergoio/aergo/chain"
    21  	"github.com/aergoio/aergo/config"
    22  	"github.com/aergoio/aergo/consensus"
    23  	"github.com/aergoio/aergo/consensus/chain"
    24  	"github.com/aergoio/aergo/contract"
    25  	"github.com/aergoio/aergo/pkg/component"
    26  	"github.com/aergoio/aergo/state"
    27  	"github.com/aergoio/aergo/types"
    28  )
    29  
    30  var (
    31  	logger     *log.Logger
    32  	httpLogger *log.Logger
    33  )
    34  
    35  var (
    36  	ErrClusterNotReady      = errors.New("cluster is not ready")
    37  	ErrNotRaftLeader        = errors.New("this node is not leader")
    38  	ErrInvalidConsensusName = errors.New("invalid consensus name")
    39  	ErrCancelGenerate       = errors.New("cancel generating block because work becomes stale")
    40  )
    41  
    42  func init() {
    43  	logger = log.NewLogger("raft")
    44  	httpLogger = log.NewLogger("rafthttp")
    45  }
    46  
    47  type txExec struct {
    48  	execTx bc.TxExecFn
    49  }
    50  
    51  func newTxExec(ccc consensus.ChainConsensusCluster, cdb consensus.ChainDB, blockNo types.BlockNo, ts int64, prevHash []byte, chainID []byte) chain.TxOp {
    52  	// Block hash not determined yet
    53  	return &txExec{
    54  		execTx: bc.NewTxExecutor(ccc, contract.ChainAccessor(cdb), blockNo, ts, prevHash, contract.BlockFactory, chainID),
    55  	}
    56  }
    57  
    58  func (te *txExec) Apply(bState *state.BlockState, tx types.Transaction) error {
    59  	err := te.execTx(bState, tx)
    60  	return err
    61  }
    62  
    63  type Work struct {
    64  	*types.Block
    65  	term uint64
    66  }
    67  
    68  func (work *Work) GetTimeout() time.Duration {
    69  	return BlockIntervalMs
    70  }
    71  
    72  func (work *Work) ToString() string {
    73  	return fmt.Sprintf("bestblock=%s, no=%d, term=%d", work.BlockID(), work.BlockNo(), work.term)
    74  }
    75  
    76  type leaderReady struct {
    77  	sync.RWMutex
    78  
    79  	ce *commitEntry
    80  }
    81  
    82  func (ready *leaderReady) set(ce *commitEntry) {
    83  	logger.Debug().Uint64("term", ce.term).Msg("set ready marker")
    84  
    85  	ready.Lock()
    86  	defer ready.Unlock()
    87  
    88  	ready.ce = ce
    89  }
    90  
    91  func (ready *leaderReady) isReady(curTerm uint64) bool {
    92  	ready.RLock()
    93  	defer ready.RUnlock()
    94  
    95  	if curTerm <= 0 {
    96  		logger.Fatal().Msg("failed to get status of raft")
    97  		return false
    98  	}
    99  
   100  	if ready.ce == nil {
   101  		logger.Debug().Msg("not exist ready marker")
   102  		return false
   103  	}
   104  
   105  	if ready.ce.term != curTerm {
   106  		logger.Debug().Uint64("ready-term", ready.ce.term).Uint64("cur-term", curTerm).Msg("not ready for producing")
   107  		return false
   108  	}
   109  
   110  	return true
   111  }
   112  
   113  // BlockFactory implments a raft block factory which generate block each cfg.Consensus.BlockIntervalMs if this node is leader of raft
   114  //
   115  // This can be used for testing purpose.
   116  type BlockFactory struct {
   117  	*component.ComponentHub
   118  	consensus.ChainWAL
   119  
   120  	bpc *Cluster
   121  	rhw consensus.AergoRaftAccessor
   122  
   123  	workerQueue chan *Work
   124  	jobQueue    chan interface{}
   125  	bpTimeoutC  chan interface{}
   126  	quit        chan interface{}
   127  
   128  	ready leaderReady
   129  
   130  	maxBlockBodySize uint32
   131  	ID               string
   132  	privKey          crypto.PrivKey
   133  	txOp             chain.TxOp
   134  	sdb              *state.ChainStateDB
   135  	prevBlock        *types.Block // best block of last job
   136  	jobLock          sync.RWMutex
   137  
   138  	raftOp     *RaftOperator
   139  	raftServer *raftServer
   140  }
   141  
   142  // GetName returns the name of the consensus.
   143  func GetName() string {
   144  	return consensus.ConsensusName[consensus.ConsensusRAFT]
   145  }
   146  
   147  // GetConstructor build and returns consensus.Constructor from New function.
   148  func GetConstructor(cfg *config.Config, hub *component.ComponentHub, cdb consensus.ChainWAL,
   149  	sdb *state.ChainStateDB, pa p2pcommon.PeerAccessor) consensus.Constructor {
   150  	return func() (consensus.Consensus, error) {
   151  		return New(cfg, hub, cdb, sdb, pa)
   152  	}
   153  }
   154  
   155  // New returns a BlockFactory.
   156  func New(cfg *config.Config, hub *component.ComponentHub, cdb consensus.ChainWAL,
   157  	sdb *state.ChainStateDB, pa p2pcommon.PeerAccessor) (*BlockFactory, error) {
   158  
   159  	bf := &BlockFactory{
   160  		ComponentHub:     hub,
   161  		ChainWAL:         cdb,
   162  		jobQueue:         make(chan interface{}),
   163  		workerQueue:      make(chan *Work),
   164  		bpTimeoutC:       make(chan interface{}, 1),
   165  		quit:             make(chan interface{}),
   166  		maxBlockBodySize: chain.MaxBlockBodySize(),
   167  		ID:               p2pkey.NodeSID(),
   168  		privKey:          p2pkey.NodePrivKey(),
   169  		sdb:              sdb,
   170  	}
   171  
   172  	if cfg.Consensus.EnableBp {
   173  		Init(cfg.Consensus.Raft)
   174  
   175  		if err := bf.newRaftServer(cfg); err != nil {
   176  			logger.Error().Err(err).Msg("failed to init raft server")
   177  			return bf, err
   178  		}
   179  
   180  		bf.raftServer.SetPeerAccessor(pa)
   181  		bf.rhw = &raftHttpWrapper{raftServer: bf.raftServer}
   182  	} else {
   183  		bf.rhw = &consensus.DummyRaftAccessor{}
   184  	}
   185  
   186  	bf.txOp = chain.NewCompTxOp(
   187  		// timeout check
   188  		chain.TxOpFn(func(bState *state.BlockState, txIn types.Transaction) error {
   189  			return bf.checkBpTimeout()
   190  		}),
   191  	)
   192  
   193  	return bf, nil
   194  }
   195  
   196  func (bf *BlockFactory) newRaftServer(cfg *config.Config) error {
   197  	if err := bf.InitCluster(cfg); err != nil {
   198  		return err
   199  	}
   200  
   201  	bf.raftOp = newRaftOperator(bf.raftServer, bf.bpc)
   202  
   203  	logger.Info().Str("name", bf.bpc.NodeName()).Msg("create raft server")
   204  
   205  	bf.raftServer = newRaftServer(bf.ComponentHub, bf.bpc,
   206  		!cfg.Consensus.Raft.NewCluster, cfg.Consensus.Raft.UseBackup, nil,
   207  		RaftTick, bf.bpc.confChangeC, bf.raftOp.commitC, false, bf.ChainWAL)
   208  
   209  	bf.bpc.rs = bf.raftServer
   210  	bf.raftOp.rs = bf.raftServer
   211  
   212  	return nil
   213  }
   214  
   215  // Ticker returns a time.Ticker for the main consensus loop.
   216  func (bf *BlockFactory) Ticker() *time.Ticker {
   217  	return time.NewTicker(BlockFactoryTickMs)
   218  }
   219  
   220  // QueueJob send a block triggering information to jq.
   221  func (bf *BlockFactory) QueueJob(now time.Time, jq chan<- interface{}) {
   222  	bf.jobLock.Lock()
   223  	defer bf.jobLock.Unlock()
   224  
   225  	var (
   226  		isReady bool
   227  		term    uint64
   228  	)
   229  
   230  	if isReady, term = bf.isLeaderReady(); !isReady {
   231  		//logger.Debug().Msg("skip producing block because this bp is leader but it's not ready to produce new block")
   232  		return
   233  	}
   234  
   235  	prevToString := func(prevBlock *types.Block) string {
   236  		if prevBlock == nil {
   237  			return "empty"
   238  		} else {
   239  			return prevBlock.ID()
   240  		}
   241  	}
   242  
   243  	if b, _ := bf.GetBestBlock(); b != nil {
   244  		if bf.prevBlock != nil && bf.prevBlock.BlockNo() == b.BlockNo() {
   245  			//logger.Debug().Uint64("bestno", b.BlockNo()).Msg("previous block not connected. skip to generate block")
   246  			return
   247  		}
   248  
   249  		// If requested block remains in commit channel, block factory must wait until all requests are completed.
   250  		// otherwise block of same height will be created and a fork will occur.
   251  		if !bf.raftServer.commitProgress.IsReadyToPropose() {
   252  			logger.Debug().Uint64("bestno", b.BlockNo()).Msg("pending request block not connected. skip to generate block")
   253  			return
   254  		}
   255  
   256  		prev := bf.prevBlock
   257  		bf.prevBlock = b
   258  		work := &Work{Block: b, term: term}
   259  
   260  		logger.Debug().Str("work", work.ToString()).Str("prev", prevToString(prev)).Msg("new work generated")
   261  		jq <- work
   262  	}
   263  }
   264  
   265  // isLeaderReady must be called after bf.jobLock
   266  // check if block factory has finished all blocks of previous term. it can be checked that it has received raft marker of this term.
   267  // TODO) term may be set when raft leader is changed from hardstate
   268  func (bf *BlockFactory) isLeaderReady() (bool, uint64) {
   269  	var (
   270  		status LeaderStatus
   271  	)
   272  
   273  	if status = bf.raftServer.GetLeaderStatus(); !status.IsLeader {
   274  		return false, 0
   275  	}
   276  
   277  	return bf.ready.isReady(status.Term), status.Term
   278  }
   279  
   280  func (bf *BlockFactory) GetType() consensus.ConsensusType {
   281  	return consensus.ConsensusRAFT
   282  }
   283  
   284  // IsTransactionValid checks the onsensus level validity of a transaction
   285  func (bf *BlockFactory) IsTransactionValid(tx *types.Tx) bool {
   286  	// BlockFactory has no tx valid check.
   287  	return true
   288  }
   289  
   290  // VerifyTimestamp checks the validity of the block timestamp.
   291  func (bf *BlockFactory) VerifyTimestamp(*types.Block) bool {
   292  	// BlockFactory don't need to check timestamp.
   293  	return true
   294  }
   295  
   296  // VerifySign checks the consensus level validity of a block.
   297  func (bf *BlockFactory) VerifySign(block *types.Block) error {
   298  	valid, err := block.VerifySign()
   299  	if !valid || err != nil {
   300  		return &consensus.ErrorConsensus{Msg: "bad block signature", Err: err}
   301  	}
   302  	return nil
   303  }
   304  
   305  // IsBlockValid checks the consensus level validity of a block.
   306  func (bf *BlockFactory) IsBlockValid(block *types.Block, bestBlock *types.Block) error {
   307  	// BlockFactory has no block valid check.
   308  	_, err := block.BPID()
   309  	if err != nil {
   310  		return &consensus.ErrorConsensus{Msg: "bad public key in block", Err: err}
   311  	}
   312  	return nil
   313  }
   314  
   315  // QuitChan returns the channel from which consensus-related goroutines check
   316  // when shutdown is initiated.
   317  func (bf *BlockFactory) QuitChan() chan interface{} {
   318  	return bf.quit
   319  }
   320  
   321  // Update has nothging to do.
   322  func (bf *BlockFactory) Update(block *types.Block) {
   323  }
   324  
   325  // Save has nothging to do.
   326  func (bf *BlockFactory) Save(tx consensus.TxWriter) error {
   327  	return nil
   328  }
   329  
   330  // BlockFactory returns r itself.
   331  func (bf *BlockFactory) BlockFactory() consensus.BlockFactory {
   332  	return bf
   333  }
   334  
   335  // NeedReorganization has nothing to do.
   336  func (bf *BlockFactory) NeedReorganization(rootNo types.BlockNo) bool {
   337  	return true
   338  }
   339  
   340  // Start run a raft block factory service.
   341  func (bf *BlockFactory) Start() {
   342  	bf.raftServer.Start()
   343  
   344  	go bf.worker()
   345  	go bf.controller()
   346  }
   347  
   348  func (bf *BlockFactory) controller() {
   349  	defer shutdownMsg("block factory controller")
   350  
   351  	beginBlock := func(work *Work) error {
   352  		// This is only for draining an unconsumed message, which means
   353  		// the previous block is generated within timeout. This code
   354  		// is needed since an empty block will be generated without it.
   355  		if err := bf.checkBpTimeout(); err == chain.ErrQuit {
   356  			return err
   357  		}
   358  
   359  		select {
   360  		case bf.workerQueue <- work:
   361  		default:
   362  			logger.Error().Msgf(
   363  				"skip block production for %s due to a pending job", work.ToString())
   364  		}
   365  		return nil
   366  	}
   367  
   368  	notifyBpTimeout := func(work *Work) {
   369  		timeout := work.GetTimeout()
   370  		time.Sleep(timeout)
   371  		bf.bpTimeoutC <- struct{}{}
   372  		logger.Debug().Int64("timeout(ms)", timeout.Nanoseconds()/int64(time.Millisecond)).Msg("block production timeout signaled")
   373  	}
   374  
   375  	for {
   376  		select {
   377  		case info := <-bf.jobQueue:
   378  			work := info.(*Work)
   379  
   380  			logger.Debug().Msgf("received work: %s",
   381  				log.DoLazyEval(func() string { return work.ToString() }))
   382  
   383  			err := beginBlock(work)
   384  			if err == chain.ErrQuit {
   385  				return
   386  			} else if err != nil {
   387  				logger.Debug().Err(err).Msg("skip block production")
   388  				continue
   389  			}
   390  
   391  			notifyBpTimeout(work)
   392  
   393  		case <-bf.quit:
   394  			return
   395  		}
   396  	}
   397  }
   398  
   399  // worker() is different for each consensus
   400  func (bf *BlockFactory) worker() {
   401  	defer logger.Info().Msg("shutdown initiated. stop the service")
   402  
   403  	runtime.LockOSThread()
   404  
   405  	for {
   406  		select {
   407  		case work := <-bf.workerQueue:
   408  			var (
   409  				block      *types.Block
   410  				blockState *state.BlockState
   411  				err        error
   412  			)
   413  
   414  			if block, blockState, err = bf.generateBlock(work); err != nil {
   415  				logger.Error().Err(err).Msg("failed to generate block")
   416  				if err == chain.ErrQuit {
   417  					logger.Info().Msg("quit worker of block factory")
   418  					return
   419  				}
   420  
   421  				bf.reset()
   422  				continue
   423  			}
   424  
   425  			if err = bf.raftOp.propose(block, blockState, work.term); err != nil {
   426  				logger.Error().Err(err).Msg("failed to propose block")
   427  				bf.reset()
   428  			}
   429  
   430  		case cEntry, ok := <-bf.commitC():
   431  			logger.Debug().Msg("received block to connect from raft")
   432  
   433  			if !ok {
   434  				logger.Fatal().Msg("commit channel for raft is closed")
   435  				return
   436  			}
   437  
   438  			// RaftEmptyBlockLog: When the leader changes, the new raft leader creates an empty data log with a new term and index.
   439  			// When block factory receives empty block log, the blockfactory that is running as the leader should reset the proposal in progress.
   440  			// since it may have been dropped on the raft. Block factory must produce new block after all blocks of previous term are connected. Empty log can be a marker for that.
   441  			if cEntry.IsReadyMarker() {
   442  				bf.handleReadyMarker(cEntry)
   443  				continue
   444  			}
   445  
   446  			// add block that has produced by remote BP
   447  			if err := bf.connect(cEntry.block); err != nil {
   448  				logger.Error().Err(err).Msg("failed to connect block")
   449  				return
   450  			}
   451  
   452  			bf.raftServer.commitProgress.UpdateConnect(cEntry)
   453  		case <-bf.quit:
   454  			return
   455  		}
   456  	}
   457  }
   458  
   459  // @ReadyMarker: leader can make new block after receiving empty commit entry. It is ready marker.
   460  //               Receiving a marker ensures that all the blocks of previous term has been connected in chain
   461  func (bf *BlockFactory) handleReadyMarker(ce *commitEntry) {
   462  	logger.Debug().Uint64("index", ce.index).Uint64("term", ce.term).Msg("set raft marker(empty block)")
   463  
   464  	// set ready to produce block for this term
   465  	bf.ready.set(ce)
   466  	bf.reset()
   467  }
   468  
   469  func (bf *BlockFactory) generateBlock(work *Work) (*types.Block, *state.BlockState, error) {
   470  	var (
   471  		bestBlock *types.Block
   472  		err       error
   473  	)
   474  
   475  	bestBlock = work.Block
   476  
   477  	defer func() {
   478  		if panicMsg := recover(); panicMsg != nil {
   479  			err = fmt.Errorf("panic ocurred during block generation - %v", panicMsg)
   480  		}
   481  	}()
   482  
   483  	checkCancel := func() bool {
   484  		if !bf.raftServer.IsLeaderOfTerm(work.term) {
   485  			logger.Debug().Msg("cancel because blockfactory is not leader of term")
   486  			return true
   487  		}
   488  
   489  		if b, _ := bf.GetBestBlock(); b != nil && bestBlock.BlockNo() != b.BlockNo() {
   490  			logger.Debug().Uint64("best", b.BlockNo()).Msg("cancel because best block changed")
   491  			if StopDupCommit {
   492  				logger.Fatal().Str("work", work.ToString()).Msg("work duplicate")
   493  			}
   494  			return true
   495  		}
   496  
   497  		return false
   498  	}
   499  
   500  	if checkCancel() {
   501  		return nil, nil, ErrCancelGenerate
   502  	}
   503  
   504  	blockState := bf.sdb.NewBlockState(bestBlock.GetHeader().GetBlocksRootHash())
   505  
   506  	ts := time.Now().UnixNano()
   507  
   508  	txOp := chain.NewCompTxOp(
   509  		bf.txOp,
   510  		newTxExec(bf, bf.ChainWAL, bestBlock.GetHeader().GetBlockNo()+1, ts, bestBlock.GetHash(), bestBlock.GetHeader().GetChainID()),
   511  	)
   512  
   513  	block, err := chain.GenerateBlock(bf, bestBlock, blockState, txOp, ts, RaftSkipEmptyBlock)
   514  	if err == chain.ErrBlockEmpty {
   515  		//need reset previous work
   516  		return nil, nil, chain.ErrBlockEmpty
   517  	} else if err != nil {
   518  		logger.Info().Err(err).Msg("failed to generate block")
   519  		return nil, nil, err
   520  	}
   521  
   522  	if err = block.Sign(bf.privKey); err != nil {
   523  		logger.Error().Err(err).Msg("failed to sign in block")
   524  		return nil, nil, err
   525  	}
   526  
   527  	logger.Info().Str("blockProducer", bf.ID).Str("raftID", EtcdIDToString(bf.bpc.NodeID())).
   528  		Str("sroot", enc.ToString(block.GetHeader().GetBlocksRootHash())).
   529  		Uint64("no", block.GetHeader().GetBlockNo()).
   530  		Str("hash", block.ID()).
   531  		Msg("block produced")
   532  
   533  	return block, blockState, nil
   534  }
   535  
   536  func (bf *BlockFactory) commitC() chan *commitEntry {
   537  	return bf.raftOp.commitC
   538  }
   539  
   540  func (bf *BlockFactory) reset() {
   541  	bf.jobLock.Lock()
   542  	defer bf.jobLock.Unlock()
   543  
   544  	// empty jobQueue. Pushed works in job queue should be removed before resetting prev work of block factory. Otherwise, it can be possible to make same job since prev work is nil.
   545  	for len(bf.jobQueue) > 0 {
   546  		info := <-bf.jobQueue
   547  		drop := info.(*Work)
   548  		logger.Debug().Str("work", drop.ToString()).Msg("drop work for reset")
   549  	}
   550  
   551  	if bf.prevBlock != nil {
   552  		logger.Info().Str("prev proposed", bf.raftOp.toString()).Msg("reset previous work of block factory")
   553  		bf.prevBlock = nil
   554  	}
   555  	bf.bpc.resetSavedConfChangePropose()
   556  }
   557  
   558  // save block/block state to connect after commit
   559  func (bf *BlockFactory) connect(block *types.Block) error {
   560  	proposed := bf.raftOp.proposed
   561  	var blockState *state.BlockState
   562  
   563  	if proposed != nil {
   564  		if !bytes.Equal(block.BlockHash(), proposed.block.BlockHash()) {
   565  			logger.Warn().Uint64("prop-no", proposed.block.GetHeader().GetBlockNo()).Str("prop", proposed.block.ID()).Uint64("commit-no", block.GetHeader().GetBlockNo()).Str("commit", block.ID()).Msg("commited block is not proposed by me. this node is probably not leader")
   566  			bf.raftOp.resetPropose()
   567  		} else {
   568  			blockState = proposed.blockState
   569  		}
   570  	}
   571  
   572  	logger.Info().Uint64("no", block.BlockNo()).
   573  		Str("hash", block.ID()).
   574  		Str("prev", block.PrevID()).
   575  		Bool("proposed", blockState != nil).
   576  		Msg("connect block")
   577  
   578  	// if bestblock is changed, connecting block failed. new block is generated in next tick
   579  	// On a slow server, chain service takes too long to add block in blockchain. In this case, raft server waits to send new block to commit channel.
   580  	if err := chain.ConnectBlock(bf, block, blockState, time.Second*300); err != nil {
   581  		logger.Fatal().Msg(err.Error())
   582  		return err
   583  	}
   584  
   585  	return nil
   586  }
   587  
   588  /*
   589  // waitUntilStartable wait until this chain synchronizes with more than half of all peers
   590  func (bf *BlockFactory) waitSyncWithMajority() error {
   591  	ticker := time.NewTicker(peerCheckInterval)
   592  
   593  	for {
   594  		select {
   595  		case <-ticker.C:
   596  			if synced, err := bf.cl.hasSynced(); err != nil {
   597  				logger.Error().Err(err).Msg("failed to check sync with a majority of peers")
   598  				return err
   599  			} else if synced {
   600  				return nil
   601  			}
   602  
   603  		case <-bf.QuitChan():
   604  			logger.Info().Msg("quit while wait sync")
   605  			return ErrBFQuit
   606  		default:
   607  		}
   608  	}
   609  }
   610  */
   611  // JobQueue returns the queue for block production triggering.
   612  func (bf *BlockFactory) JobQueue() chan<- interface{} {
   613  	return bf.jobQueue
   614  }
   615  
   616  // Info retuns an empty string.
   617  func (bf *BlockFactory) Info() string {
   618  	// TODO: Returns a appropriate information inx json format like current
   619  	// leader, etc.
   620  	info := consensus.NewInfo(GetName())
   621  	if bf.raftServer == nil {
   622  		return info.AsJSON()
   623  	}
   624  
   625  	b, err := json.Marshal(bf.bpc.getRaftInfo(false))
   626  	if err != nil {
   627  		logger.Error().Err(err).Msg("failed to marshalEntryData raft consensus")
   628  	} else {
   629  		m := json.RawMessage(b)
   630  		info.Status = &m
   631  	}
   632  
   633  	return info.AsJSON()
   634  }
   635  
   636  func (bf *BlockFactory) ConsensusInfo() *types.ConsensusInfo {
   637  	if bf.bpc == nil {
   638  		return &types.ConsensusInfo{Type: GetName()}
   639  	}
   640  	return bf.bpc.toConsensusInfo()
   641  }
   642  
   643  func (bf *BlockFactory) NeedNotify() bool {
   644  	return false
   645  }
   646  
   647  func (bf *BlockFactory) HasWAL() bool {
   648  	return true
   649  }
   650  
   651  func (bf *BlockFactory) IsForkEnable() bool {
   652  	return false
   653  }
   654  
   655  // check already connect block
   656  // In raft, block hash may already have been writtern when writing log entry.
   657  func (bf *BlockFactory) IsConnectedBlock(block *types.Block) bool {
   658  	savedBlk, err := bf.GetBlockByNo(block.GetHeader().GetBlockNo())
   659  	if err == nil {
   660  		if bytes.Equal([]byte(savedBlk.BlockHash()), []byte(block.BlockHash())) {
   661  			return true
   662  		}
   663  	}
   664  	return false
   665  }
   666  
   667  type ErrorMembershipChange struct {
   668  	Err error
   669  }
   670  
   671  func (e ErrorMembershipChange) Error() string {
   672  	return fmt.Sprintf("failed to change membership: %s", e.Err.Error())
   673  }
   674  
   675  // ConfChange change membership of raft cluster and returns new membership
   676  func (bf *BlockFactory) ConfChange(req *types.MembershipChange) (*consensus.Member, error) {
   677  	if bf.bpc == nil {
   678  		return nil, ErrorMembershipChange{ErrClusterNotReady}
   679  	}
   680  
   681  	if !bf.raftServer.IsLeader() {
   682  		return nil, ErrorMembershipChange{ErrNotRaftLeader}
   683  	}
   684  
   685  	var member *consensus.Member
   686  	var err error
   687  
   688  	// set reqID by blockHash
   689  	var best *types.Block
   690  	if best, err = bf.GetBestBlock(); err != nil {
   691  		return nil, err
   692  	}
   693  
   694  	req.RequestID = binary.LittleEndian.Uint64(best.GetHash()[0:8])
   695  
   696  	if member, err = bf.bpc.ChangeMembership(req, false); err != nil {
   697  		return nil, ErrorMembershipChange{err}
   698  	}
   699  
   700  	return member, nil
   701  }
   702  
   703  func (bf *BlockFactory) RaftAccessor() consensus.AergoRaftAccessor {
   704  	return bf.rhw
   705  }
   706  
   707  func (bf *BlockFactory) MakeConfChangeProposal(req *types.MembershipChange) (*consensus.ConfChangePropose, error) {
   708  	var (
   709  		proposal *consensus.ConfChangePropose
   710  		err      error
   711  	)
   712  
   713  	if bf.bpc == nil {
   714  		return nil, ErrorMembershipChange{ErrClusterNotReady}
   715  	}
   716  
   717  	cl := bf.bpc
   718  
   719  	cl.Lock()
   720  	defer cl.Unlock()
   721  
   722  	if !bf.raftServer.IsLeader() {
   723  		logger.Info().Msg("skipped conf change request since node is not leader")
   724  		return nil, consensus.ErrorMembershipChangeSkip
   725  	}
   726  
   727  	logger.Info().Str("request", req.ToString()).Msg("make proposal of cluster conf change")
   728  
   729  	if proposal, err = cl.makeProposal(req, true); err != nil {
   730  		logger.Error().Uint64("requestID", req.GetRequestID()).Msg("failed to make proposal for conf change")
   731  		return nil, err
   732  	}
   733  
   734  	// To make cluster_test easier, this check called not in makeProposal() but here
   735  	if err = cl.isEnableChangeMembership(proposal.Cc); err != nil {
   736  		logger.Error().Err(err).Msg("failed cluster availability check to change membership")
   737  		return nil, err
   738  	}
   739  
   740  	return proposal, nil
   741  }
   742  
   743  // getHardStateOfBlock returns (term/commit) corresponding to best block hash.
   744  // To get hardstateinfo, it needs to search all raft indexes.
   745  func (bf *BlockFactory) getHardStateOfBlock(bestBlockHash []byte) (*types.HardStateInfo, error) {
   746  	var (
   747  		bestBlock *types.Block
   748  		err       error
   749  		hash      []byte
   750  	)
   751  	if bestBlock, err = bf.GetBlock(bestBlockHash); err != nil {
   752  		return nil, fmt.Errorf("block does not exist in chain")
   753  	}
   754  
   755  	entry, err := bf.ChainWAL.GetRaftEntryOfBlock(bestBlockHash)
   756  	if err == nil {
   757  		logger.Debug().Uint64("term", entry.Term).Uint64("comit", entry.Index).Msg("get hardstate of block")
   758  
   759  		return &types.HardStateInfo{Term: entry.Term, Commit: entry.Index}, nil
   760  	}
   761  
   762  	logger.Warn().Uint64("request no", bestBlock.BlockNo()).Msg("can't find raft entry for requested hash. so try to find closest raft entry.")
   763  
   764  	// find best hash mapping (no < bestBlock no)
   765  	for i := bestBlock.BlockNo() - 1; i >= 1; i-- {
   766  		if hash, err = bf.GetHashByNo(i); err == nil {
   767  			if entry, err = bf.ChainWAL.GetRaftEntryOfBlock(hash); err == nil {
   768  				logger.Debug().Str("entry", entry.ToString()).Msg("find best closest entry")
   769  				return &types.HardStateInfo{Term: entry.Term, Commit: entry.Index}, nil
   770  			}
   771  		}
   772  	}
   773  
   774  	return nil, fmt.Errorf("not exist proper raft entry for requested hash")
   775  }
   776  
   777  // ClusterInfo returns members of cluster and hardstate info corresponding to best block hash
   778  func (bf *BlockFactory) ClusterInfo(bestBlockHash []byte) *types.GetClusterInfoResponse {
   779  	var (
   780  		hardStateInfo *types.HardStateInfo
   781  		mbrAttrs      []*types.MemberAttr
   782  		bestBlock     *types.Block
   783  		err           error
   784  	)
   785  
   786  	if bf.bpc.ClusterID() == InvalidClusterID {
   787  		return &types.GetClusterInfoResponse{Error: ErrClusterNotReady.Error()}
   788  	}
   789  
   790  	if bestBlockHash != nil {
   791  		if hardStateInfo, err = bf.getHardStateOfBlock(bestBlockHash); err != nil {
   792  			return &types.GetClusterInfoResponse{Error: err.Error()}
   793  		}
   794  	}
   795  
   796  	if mbrAttrs, err = bf.bpc.getMemberAttrs(); err != nil {
   797  		return &types.GetClusterInfoResponse{Error: err.Error()}
   798  	}
   799  
   800  	if bestBlock, err = bf.GetBestBlock(); err != nil {
   801  		return &types.GetClusterInfoResponse{Error: err.Error()}
   802  	}
   803  
   804  	return &types.GetClusterInfoResponse{ChainID: bf.bpc.chainID, ClusterID: bf.bpc.ClusterID(), MbrAttrs: mbrAttrs, BestBlockNo: bestBlock.BlockNo(), HardStateInfo: hardStateInfo}
   805  }
   806  
   807  // ConfChangeInfo returns ConfChangeProgress queries by request ID of ConfChange
   808  func (bf *BlockFactory) ConfChangeInfo(requestID uint64) (*types.ConfChangeProgress, error) {
   809  	return bf.GetConfChangeProgress(requestID)
   810  }
   811  
   812  func (bf *BlockFactory) checkBpTimeout() error {
   813  	select {
   814  	case <-bf.bpTimeoutC:
   815  		return chain.ErrTimeout{Kind: "block"}
   816  	case <-bf.quit:
   817  		return chain.ErrQuit
   818  	default:
   819  		return nil
   820  	}
   821  }
   822  
   823  type Proposed struct {
   824  	block      *types.Block
   825  	blockState *state.BlockState
   826  }
   827  
   828  type RaftOperator struct {
   829  	commitC chan *commitEntry
   830  
   831  	cl *Cluster
   832  	rs *raftServer
   833  
   834  	proposed *Proposed
   835  }
   836  
   837  func newRaftOperator(rs *raftServer, cl *Cluster) *RaftOperator {
   838  	//commitC := make(chan *commitEntry, MaxCommitQueueLen)
   839  	commitC := make(chan *commitEntry)
   840  
   841  	return &RaftOperator{commitC: commitC, rs: rs, cl: cl}
   842  }
   843  
   844  func (rop *RaftOperator) propose(block *types.Block, blockState *state.BlockState, term uint64) error {
   845  	if !rop.rs.IsLeaderOfTerm(term) {
   846  		logger.Info().Msg("dropped produced block because this bp became no longer leader")
   847  		return ErrNotRaftLeader
   848  	}
   849  
   850  	debugRaftProposeSleep()
   851  
   852  	rop.proposed = &Proposed{block: block, blockState: blockState}
   853  
   854  	if err := rop.rs.Propose(block); err != nil {
   855  		return err
   856  	}
   857  
   858  	logger.Info().Msg("block proposed by blockfactory")
   859  
   860  	if blockState.CCProposal != nil {
   861  		if err := rop.ProposeConfChange(blockState.CCProposal); err != nil {
   862  			logger.Error().Err(err).Msg("failed to change membership")
   863  			return ErrorMembershipChange{err}
   864  		}
   865  	}
   866  
   867  	return nil
   868  }
   869  
   870  func (rop *RaftOperator) ProposeConfChange(proposal *consensus.ConfChangePropose) error {
   871  	var err error
   872  
   873  	if rop.cl == nil {
   874  		return ErrClusterNotReady
   875  	}
   876  
   877  	if err = rop.cl.submitProposal(proposal, true); err != nil {
   878  		return err
   879  	}
   880  
   881  	return nil
   882  }
   883  
   884  func (rop *RaftOperator) resetPropose() {
   885  	rop.proposed = nil
   886  	logger.Debug().Msg("reset proposed block")
   887  }
   888  
   889  func (rop *RaftOperator) toString() string {
   890  	buf := "proposed:"
   891  	if rop.proposed != nil && rop.proposed.block != nil {
   892  		buf = buf + fmt.Sprintf("[no=%d, hash=%s]", rop.proposed.block.BlockNo(), rop.proposed.block.BlockID().String())
   893  	} else {
   894  		buf = buf + "empty"
   895  	}
   896  	return buf
   897  }
   898  
   899  func shutdownMsg(m string) {
   900  	logger.Info().Msgf("shutdown initiated. stop the %s", m)
   901  }
   902  
   903  func ValidateGenesis(genesis *types.Genesis) error {
   904  	if strings.ToLower(genesis.ID.Consensus) != consensus.ConsensusName[consensus.ConsensusRAFT] {
   905  		return ErrInvalidConsensusName
   906  	}
   907  
   908  	// validate BPS
   909  	if _, err := parseBpsToMembers(genesis.EnterpriseBPs); err != nil {
   910  		logger.Error().Err(err).Msg("failed to parse bp list of Genesis block")
   911  		return err
   912  	}
   913  
   914  	return nil
   915  }