Skip to content

Prepare next proposal #4594

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion consensus/consensusfsm/fsm.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
39 changes: 39 additions & 0 deletions consensus/scheme/rolldpos/rolldposctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why use go func() here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor:
if fork.MintNewBlock() errs out, the error won't be captured and handled

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MintNewBlock keep mint result in memory, and will return it if mint same block. Here is to just to start the next proposal mint in advance, which can be run in background.

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()
Expand Down Expand Up @@ -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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why now need to prepareNextProposal() in this case?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

msg == nil means that the proposal for this round was not received in time; in this case, it's possible to mint the proposal for round +1 in advance.

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

Expand Down