diff --git a/consensus/consensusfsm/fsm.go b/consensus/consensusfsm/fsm.go index 694c763f4d..c31db07675 100644 --- a/consensus/consensusfsm/fsm.go +++ b/consensus/consensusfsm/fsm.go @@ -466,7 +466,6 @@ func (m *ConsensusFSM) onReceiveBlock(evt fsm.Event) (fsm.State, error) { m.ctx.Logger().Debug("Failed to generate proposal endorsement", zap.Error(err)) return sAcceptBlockProposal, nil } - return sAcceptProposalEndorsement, nil } diff --git a/consensus/scheme/rolldpos/rolldposctx.go b/consensus/scheme/rolldpos/rolldposctx.go index 8cf0eb60c7..0902648540 100644 --- a/consensus/scheme/rolldpos/rolldposctx.go +++ b/consensus/scheme/rolldpos/rolldposctx.go @@ -13,6 +13,7 @@ import ( "github.com/facebookgo/clock" fsm "github.com/iotexproject/go-fsm" "github.com/iotexproject/go-pkgs/crypto" + "github.com/iotexproject/go-pkgs/hash" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "go.uber.org/zap" @@ -405,6 +406,37 @@ func (ctx *rollDPoSCtx) Proposal() (interface{}, error) { return ctx.mintNewBlock(privateKey) } +func (ctx *rollDPoSCtx) prepareNextProposal(prevHeight uint64, prevHash hash.Hash256) error { + var ( + height = prevHeight + 1 + interval = ctx.BlockInterval(height) + startTime = ctx.round.StartTime().Add(interval) + err error + ) + fork, err := ctx.chain.Fork(prevHash) + if err != nil { + return errors.Wrapf(err, "failed to check fork at block %d, hash %x", prevHeight, prevHash[:]) + } + roundCalc := ctx.roundCalc.Fork(fork) + // check if the current node is the next proposer + nextProposer := roundCalc.Proposer(height, interval, startTime) + idx := slices.Index(ctx.encodedAddrs, nextProposer) + if idx < 0 { + return nil + } + privateKey := ctx.priKeys[idx] + ctx.logger().Debug("prepare next proposal", log.Hex("prevHash", prevHash[:]), zap.Uint64("height", ctx.round.height+1), zap.Time("timestamp", startTime), zap.String("nextproposer", nextProposer)) + go func() { + blk, err := fork.MintNewBlock(startTime, privateKey, prevHash) + if err != nil { + ctx.logger().Error("failed to mint new block", zap.Error(err)) + return + } + ctx.logger().Debug("prepared a new block", zap.Uint64("height", blk.Height()), zap.Time("timestamp", blk.Timestamp())) + }() + return nil +} + func (ctx *rollDPoSCtx) WaitUntilRoundStart() time.Duration { ctx.mutex.RLock() defer ctx.mutex.RUnlock() @@ -454,9 +486,16 @@ func (ctx *rollDPoSCtx) NewProposalEndorsement(msg interface{}) (interface{}, er if err := ctx.round.AddBlock(proposal.block); err != nil { return nil, err } + if err := ctx.prepareNextProposal(proposal.block.Height(), blkHash); err != nil { + ctx.loggerWithStats().Warn("failed to prepare next proposal", zap.Error(err), zap.Uint64("prevHeight", proposal.block.Height())) + } ctx.loggerWithStats().Debug("accept block proposal", log.Hex("block", blockHash)) } else if ctx.round.IsLocked() { blockHash = ctx.round.HashOfBlockInLock() + } else { + if err := ctx.prepareNextProposal(ctx.round.Height()-1, ctx.round.PrevHash()); err != nil { + ctx.loggerWithStats().Warn("failed to prepare next proposal", zap.Error(err), zap.Uint64("prevHeight", ctx.round.Height()-1)) + } } // TODO: prepare next block if the current node will be a proposer