tutus-consensus/check.go

181 lines
4.4 KiB
Go

package dbft
import (
"go.uber.org/zap"
)
func (d *DBFT[H]) checkPrepare() {
if d.lastBlockIndex != d.BlockIndex || d.lastBlockView != d.ViewNumber {
// Notice that lastBlockTimestamp is left unchanged because
// this must be the value from the last header.
d.lastBlockTime = d.Timer.Now()
d.lastBlockIndex = d.BlockIndex
d.lastBlockView = d.ViewNumber
}
if !d.hasAllTransactions() {
d.Logger.Debug("check prepare: some transactions are missing", zap.Any("hashes", d.MissingTransactions))
return
}
count := 0
hasRequest := false
for _, msg := range d.PreparationPayloads {
if msg != nil {
if msg.ViewNumber() == d.ViewNumber {
count++
}
if msg.Type() == PrepareRequestType {
hasRequest = true
}
}
}
d.Logger.Debug("check preparations", zap.Bool("hasReq", hasRequest),
zap.Int("count", count),
zap.Int("M", d.M()))
if hasRequest && count >= d.M() {
if d.isAntiMEVExtensionEnabled() {
d.sendPreCommit()
d.changeTimer(d.timePerBlock)
d.checkPreCommit()
} else {
d.sendCommit()
d.changeTimer(d.timePerBlock)
d.checkCommit()
}
}
}
func (d *DBFT[H]) checkPreCommit() {
if !d.hasAllTransactions() {
d.Logger.Debug("check preCommit: some transactions are missing", zap.Any("hashes", d.MissingTransactions))
return
}
count := 0
for _, msg := range d.PreCommitPayloads {
if msg != nil && msg.ViewNumber() == d.ViewNumber {
count++
}
}
if count < d.M() {
d.Logger.Debug("not enough PreCommits to process PreBlock", zap.Int("count", count))
return
}
d.preBlock = d.CreatePreBlock()
if !d.preBlockProcessed {
d.Logger.Info("processing PreBlock",
zap.Uint32("height", d.BlockIndex),
zap.Uint("view", uint(d.ViewNumber)),
zap.Int("tx_count", len(d.preBlock.Transactions())),
zap.Int("preCommit_count", count))
err := d.ProcessPreBlock(d.preBlock)
if err != nil {
d.Logger.Info("can't process PreBlock, waiting for more PreCommits to be collected",
zap.Error(err),
zap.Int("count", count))
return
}
d.preBlockProcessed = true
}
// Require PreCommit sent by self for reliability. This condition must not be
// removed because:
// 1) we need to filter out WatchOnly nodes;
// 2) CNs that have not sent PreCommit must not skip this stage (although it's OK
// from the DKG/TPKE side to build final Block based only on other CN's data).
if d.PreCommitSent() {
d.verifyCommitPayloadsAgainstHeader()
d.sendCommit()
d.changeTimer(d.timePerBlock)
d.checkCommit()
} else {
if !d.Context.WatchOnly() {
d.Logger.Debug("can't send commit since self preCommit not yet sent")
}
}
}
func (d *DBFT[H]) checkCommit() {
if !d.hasAllTransactions() {
d.Logger.Debug("check commit: some transactions are missing", zap.Any("hashes", d.MissingTransactions))
return
}
// return if we received commits from other nodes
// before receiving PrepareRequest from Speaker
count := 0
for _, msg := range d.CommitPayloads {
if msg != nil && msg.ViewNumber() == d.ViewNumber {
count++
}
}
if count < d.M() {
d.Logger.Debug("not enough to commit", zap.Int("count", count))
return
}
d.block = d.CreateBlock()
hash := d.block.Hash()
d.Logger.Info("approving block",
zap.Uint32("height", d.BlockIndex),
zap.Stringer("hash", hash),
zap.Int("tx_count", len(d.block.Transactions())),
zap.Stringer("merkle", d.block.MerkleRoot()),
zap.Stringer("prev", d.block.PrevHash()))
err := d.ProcessBlock(d.block)
if err != nil {
if d.isAntiMEVExtensionEnabled() {
d.Logger.Info("can't process Block, waiting for more Commits to be collected",
zap.Error(err),
zap.Int("count", count))
return
}
d.Logger.Fatal("block processing failed", zap.Error(err))
}
d.blockProcessed = true
// Do not initialize consensus process immediately. It's the caller's duty to
// start the new block acceptance process and call Reset at the
// new height.
}
func (d *DBFT[H]) checkChangeView(view byte) {
if d.ViewNumber >= view {
return
}
count := 0
for _, msg := range d.ChangeViewPayloads {
if msg != nil && msg.GetChangeView().NewViewNumber() >= view {
count++
}
}
if count < d.M() {
return
}
if !d.Context.WatchOnly() {
msg := d.ChangeViewPayloads[d.MyIndex]
if msg != nil && msg.GetChangeView().NewViewNumber() < view {
d.broadcast(d.makeChangeView(uint64(d.Timer.Now().UnixNano()), CVChangeAgreement))
}
}
d.initializeConsensus(view, d.lastBlockTimestamp)
}