Skip to content
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

*: support extra dBFT stage #118

Merged
merged 16 commits into from
Aug 1, 2024
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
7 changes: 6 additions & 1 deletion block.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ type Block[H Hash] interface {

// Transactions returns block's transaction list.
Transactions() []Transaction[H]
// SetTransactions sets block's transaction list.
// SetTransactions sets block's transaction list. For anti-MEV extension
// transactions provided via this call are taken directly from PreBlock level
// and thus, may be out-of-date. Thus, with anti-MEV extension enabled it's
// suggested to use this method as a Block finalizer since it will be called
// right before the block approval. Do not rely on this with anti-MEV extension
// disabled.
SetTransactions([]Transaction[H])
}
48 changes: 48 additions & 0 deletions check.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,57 @@
zap.Int("M", d.M()))

if hasRequest && count >= d.M() {
if d.isAntiMEVExtensionEnabled() {
d.sendPreCommit()
d.changeTimer(d.SecondsPerBlock)
d.checkPreCommit()
} else {
d.sendCommit()
d.changeTimer(d.SecondsPerBlock)
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

Check warning on line 48 in check.go

View check run for this annotation

Codecov / codecov/patch

check.go#L47-L48

Added lines #L47 - L48 were not covered by tests
}

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 create PreBlock", zap.Int("count", count))
return
}

d.preBlock = d.CreatePreBlock()

d.Logger.Info("processing PreBlock",
zap.Uint32("height", d.BlockIndex),
zap.Uint("view", uint(d.ViewNumber)),
zap.Int("tx_count", len(d.preBlock.Transactions())))

if !d.preBlockProcessed {
d.preBlockProcessed = true
d.ProcessPreBlock(d.preBlock)
}

// Require PreCommit sent by self for reliability. This condition may be removed
// in the future.
if d.PreCommitSent() {
d.verifyCommitPayloadsAgainstHeader()
d.sendCommit()
d.changeTimer(d.SecondsPerBlock)
d.checkCommit()
} else {
d.Logger.Debug("can't send commit since self preCommit not yet sent")

Check warning on line 83 in check.go

View check run for this annotation

Codecov / codecov/patch

check.go#L83

Added line #L83 was not covered by tests
}
}

Expand Down
3 changes: 2 additions & 1 deletion commit.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package dbft
// Commit is an interface for dBFT Commit message.
type Commit interface {
// Signature returns commit's signature field
// which is a block signature for the current epoch.
// which is a final block signature for the current epoch for both dBFT 2.0 and
// for anti-MEV extension.
Signature() []byte
roman-khimov marked this conversation as resolved.
Show resolved Hide resolved
}
75 changes: 75 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,14 @@
// if current time is less than that of previous context.
// By default use millisecond precision.
TimestampIncrement uint64
// AntiMEVExtensionEnablingHeight denotes the height starting from which dBFT
// Anti-MEV extensions should be enabled. -1 means no extension is enabled.
AntiMEVExtensionEnablingHeight int64
// GetKeyPair returns an index of the node in the list of validators
// together with it's key pair.
GetKeyPair func([]PublicKey) (int, PrivateKey, PublicKey)
// NewPreBlockFromContext should allocate, fill from Context and return new block.PreBlock.
NewPreBlockFromContext func(ctx *Context[H]) PreBlock[H]
// NewBlockFromContext should allocate, fill from Context and return new block.Block.
NewBlockFromContext func(ctx *Context[H]) Block[H]
// RequestTx is a callback which is called when transaction contained
Expand All @@ -36,10 +41,14 @@
// GetVerified returns a slice of verified transactions
// to be proposed in a new block.
GetVerified func() []Transaction[H]
// VerifyPreBlock verifies if preBlock is valid.
VerifyPreBlock func(b PreBlock[H]) bool
// VerifyBlock verifies if block is valid.
VerifyBlock func(b Block[H]) bool
// Broadcast should broadcast payload m to the consensus nodes.
Broadcast func(m ConsensusPayload[H])
// ProcessBlock is called every time new preBlock is accepted.
ProcessPreBlock func(b PreBlock[H])
// ProcessBlock is called every time new block is accepted.
ProcessBlock func(b Block[H])
// GetBlock should return block with hash.
Expand All @@ -63,6 +72,8 @@
NewPrepareResponse func(preparationHash H) PrepareResponse[H]
// NewChangeView is a constructor for payload.ChangeView.
NewChangeView func(newViewNumber byte, reason ChangeViewReason, timestamp uint64) ChangeView
// NewPreCommit is a constructor for payload.PreCommit.
NewPreCommit func(data []byte) PreCommit
// NewCommit is a constructor for payload.Commit.
NewCommit func(signature []byte) Commit
// NewRecoveryRequest is a constructor for payload.RecoveryRequest.
Expand All @@ -73,6 +84,10 @@
VerifyPrepareRequest func(p ConsensusPayload[H]) error
// VerifyPrepareResponse performs external PrepareResponse verification and returns nil if it's successful.
VerifyPrepareResponse func(p ConsensusPayload[H]) error
// VerifyPreCommit performs external PreCommit verification and returns nil if it's successful.
// Note that PreBlock-dependent PreCommit verification should be performed inside PreBlock.Verify
// callback.
VerifyPreCommit func(p ConsensusPayload[H]) error
}

const defaultSecondsPerBlock = time.Second * 15
Expand Down Expand Up @@ -101,6 +116,10 @@

VerifyPrepareRequest: func(ConsensusPayload[H]) error { return nil },
VerifyPrepareResponse: func(ConsensusPayload[H]) error { return nil },

AntiMEVExtensionEnablingHeight: -1,
VerifyPreBlock: func(PreBlock[H]) bool { return true },
VerifyPreCommit: func(ConsensusPayload[H]) error { return nil },
}
}

Expand Down Expand Up @@ -131,6 +150,20 @@
return errors.New("NewRecoveryRequest is nil")
} else if cfg.NewRecoveryMessage == nil {
return errors.New("NewRecoveryMessage is nil")
} else if cfg.AntiMEVExtensionEnablingHeight >= 0 {
if cfg.NewPreBlockFromContext == nil {
return errors.New("NewPreBlockFromContext is nil")

Check warning on line 155 in config.go

View check run for this annotation

Codecov / codecov/patch

config.go#L155

Added line #L155 was not covered by tests
} else if cfg.ProcessPreBlock == nil {
return errors.New("ProcessPreBlock is nil")

Check warning on line 157 in config.go

View check run for this annotation

Codecov / codecov/patch

config.go#L157

Added line #L157 was not covered by tests
} else if cfg.NewPreCommit == nil {
return errors.New("NewPreCommit is nil")

Check warning on line 159 in config.go

View check run for this annotation

Codecov / codecov/patch

config.go#L159

Added line #L159 was not covered by tests
}
} else if cfg.NewPreBlockFromContext != nil {
return errors.New("NewPreBlockFromContext is set, but AntiMEVExtensionEnablingHeight is not specified")

Check warning on line 162 in config.go

View check run for this annotation

Codecov / codecov/patch

config.go#L162

Added line #L162 was not covered by tests
} else if cfg.ProcessPreBlock != nil {
return errors.New("ProcessPreBlock is set, but AntiMEVExtensionEnablingHeight is not specified")

Check warning on line 164 in config.go

View check run for this annotation

Codecov / codecov/patch

config.go#L164

Added line #L164 was not covered by tests
} else if cfg.NewPreCommit != nil {
return errors.New("NewPreCommit is set, but AntiMEVExtensionEnablingHeight is not specified")

Check warning on line 166 in config.go

View check run for this annotation

Codecov / codecov/patch

config.go#L166

Added line #L166 was not covered by tests
}

return nil
Expand Down Expand Up @@ -164,13 +197,27 @@
}
}

// WithAntiMEVExtensionEnablingHeight sets AntiMEVExtensionEnablingHeight.
func WithAntiMEVExtensionEnablingHeight[H Hash](h int64) func(config *Config[H]) {
return func(cfg *Config[H]) {
cfg.AntiMEVExtensionEnablingHeight = h
}
}

// WithTimestampIncrement sets TimestampIncrement.
func WithTimestampIncrement[H Hash](u uint64) func(config *Config[H]) {
return func(cfg *Config[H]) {
cfg.TimestampIncrement = u
}
}

// WithNewPreBlockFromContext sets NewPreBlockFromContext.
func WithNewPreBlockFromContext[H Hash](f func(ctx *Context[H]) PreBlock[H]) func(config *Config[H]) {
return func(cfg *Config[H]) {
cfg.NewPreBlockFromContext = f
}
}

// WithNewBlockFromContext sets NewBlockFromContext.
func WithNewBlockFromContext[H Hash](f func(ctx *Context[H]) Block[H]) func(config *Config[H]) {
return func(cfg *Config[H]) {
Expand Down Expand Up @@ -206,6 +253,13 @@
}
}

// WithVerifyPreBlock sets VerifyPreBlock.
func WithVerifyPreBlock[H Hash](f func(b PreBlock[H]) bool) func(config *Config[H]) {
return func(cfg *Config[H]) {
cfg.VerifyPreBlock = f

Check warning on line 259 in config.go

View check run for this annotation

Codecov / codecov/patch

config.go#L257-L259

Added lines #L257 - L259 were not covered by tests
}
}

// WithVerifyBlock sets VerifyBlock.
func WithVerifyBlock[H Hash](f func(b Block[H]) bool) func(config *Config[H]) {
return func(cfg *Config[H]) {
Expand All @@ -227,6 +281,13 @@
}
}

// WithProcessPreBlock sets ProcessPreBlock.
func WithProcessPreBlock[H Hash](f func(b PreBlock[H])) func(config *Config[H]) {
return func(cfg *Config[H]) {
cfg.ProcessPreBlock = f
}
}

// WithGetBlock sets GetBlock.
func WithGetBlock[H Hash](f func(h H) Block[H]) func(config *Config[H]) {
return func(cfg *Config[H]) {
Expand Down Expand Up @@ -297,6 +358,13 @@
}
}

// WithNewPreCommit sets NewPreCommit.
func WithNewPreCommit[H Hash](f func(signature []byte) PreCommit) func(config *Config[H]) {
return func(cfg *Config[H]) {
cfg.NewPreCommit = f
}
}

// WithNewRecoveryRequest sets NewRecoveryRequest.
func WithNewRecoveryRequest[H Hash](f func(ts uint64) RecoveryRequest) func(config *Config[H]) {
return func(cfg *Config[H]) {
Expand Down Expand Up @@ -324,3 +392,10 @@
cfg.VerifyPrepareResponse = f
}
}

// WithVerifyPreCommit sets VerifyPreCommit.
func WithVerifyPreCommit[H Hash](f func(preCommit ConsensusPayload[H]) error) func(config *Config[H]) {
return func(cfg *Config[H]) {
cfg.VerifyPreCommit = f

Check warning on line 399 in config.go

View check run for this annotation

Codecov / codecov/patch

config.go#L397-L399

Added lines #L397 - L399 were not covered by tests
}
}
2 changes: 2 additions & 0 deletions consensus_message.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ type ConsensusMessage[H Hash] interface {
GetPrepareRequest() PrepareRequest[H]
// GetPrepareResponse returns payload as if it was PrepareResponse.
GetPrepareResponse() PrepareResponse[H]
// GetPreCommit returns payload as if it was PreCommit.
GetPreCommit() PreCommit
// GetCommit returns payload as if it was Commit.
GetCommit() Commit
// GetRecoveryRequest returns payload as if it was RecoveryRequest.
Expand Down
5 changes: 4 additions & 1 deletion consensus_message_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
// MessageType is a type for dBFT consensus messages.
type MessageType byte

// 6 following constants enumerate all possible type of consensus message.
// 7 following constants enumerate all possible type of consensus message.
const (
ChangeViewType MessageType = 0x00
PrepareRequestType MessageType = 0x20
PrepareResponseType MessageType = 0x21
PreCommitType MessageType = 0x31
CommitType MessageType = 0x30
RecoveryRequestType MessageType = 0x40
RecoveryMessageType MessageType = 0x41
Expand All @@ -26,6 +27,8 @@
return "PrepareResponse"
case CommitType:
return "Commit"
case PreCommitType:
return "PreCommit"

Check warning on line 31 in consensus_message_type.go

View check run for this annotation

Codecov / codecov/patch

consensus_message_type.go#L30-L31

Added lines #L30 - L31 were not covered by tests
case RecoveryRequestType:
return "RecoveryRequest"
case RecoveryMessageType:
Expand Down
Loading
Loading