Skip to content

Commit 39ecd4a

Browse files
committed
dbft: specify rejected hashes on CV construction
Ref. nspcc-dev/neo-go#4148. Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
1 parent e044839 commit 39ecd4a

6 files changed

Lines changed: 24 additions & 20 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ This document outlines major changes between releases.
77
New features:
88

99
Behaviour changes:
10+
* specify rejected hashes on ChangeView construction (#158)
1011

1112
Improvements:
1213
* minimum required Go version is 1.25 (#144, #156)

config.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ type Config[H Hash] struct {
5858
GetVerified func() []Transaction[H]
5959
// VerifyPreBlock verifies if preBlock is valid.
6060
VerifyPreBlock func(b PreBlock[H]) bool
61-
// VerifyBlock verifies if block is valid.
62-
VerifyBlock func(b Block[H]) bool
61+
// VerifyBlock verifies if block is valid and optionally returns the hash of invalid transaction.
62+
VerifyBlock func(b Block[H]) (bool, H)
6363
// Broadcast should broadcast payload m to the consensus nodes.
6464
Broadcast func(m ConsensusPayload[H])
6565
// ProcessBlock is called every time new preBlock is accepted.
@@ -86,7 +86,7 @@ type Config[H Hash] struct {
8686
// NewPrepareResponse is a constructor for payload.PrepareResponse.
8787
NewPrepareResponse func(preparationHash H) PrepareResponse[H]
8888
// NewChangeView is a constructor for payload.ChangeView.
89-
NewChangeView func(newViewNumber byte, reason ChangeViewReason, timestamp uint64) ChangeView
89+
NewChangeView func(newViewNumber byte, reason ChangeViewReason, timestamp uint64, rejectedHash ...H) ChangeView
9090
// NewPreCommit is a constructor for payload.PreCommit.
9191
NewPreCommit func(data []byte) PreCommit
9292
// NewCommit is a constructor for payload.Commit.
@@ -124,7 +124,7 @@ func defaultConfig[H Hash]() *Config[H] {
124124
StopTxFlow: func() {},
125125
GetTx: func(H) Transaction[H] { return nil },
126126
GetVerified: func() []Transaction[H] { return make([]Transaction[H], 0) },
127-
VerifyBlock: func(Block[H]) bool { return true },
127+
VerifyBlock: func(Block[H]) (bool, H) { return true, *new(H) },
128128
Broadcast: func(ConsensusPayload[H]) {},
129129
ProcessBlock: func(Block[H]) error { return nil },
130130
GetBlock: func(H) Block[H] { return nil },
@@ -317,7 +317,7 @@ func WithVerifyPreBlock[H Hash](f func(b PreBlock[H]) bool) func(config *Config[
317317
}
318318

319319
// WithVerifyBlock sets VerifyBlock.
320-
func WithVerifyBlock[H Hash](f func(b Block[H]) bool) func(config *Config[H]) {
320+
func WithVerifyBlock[H Hash](f func(b Block[H]) (bool, H)) func(config *Config[H]) {
321321
return func(cfg *Config[H]) {
322322
cfg.VerifyBlock = f
323323
}
@@ -402,7 +402,7 @@ func WithNewPrepareResponse[H Hash](f func(preparationHash H) PrepareResponse[H]
402402
}
403403

404404
// WithNewChangeView sets NewChangeView.
405-
func WithNewChangeView[H Hash](f func(newViewNumber byte, reason ChangeViewReason, ts uint64) ChangeView) func(config *Config[H]) {
405+
func WithNewChangeView[H Hash](f func(newViewNumber byte, reason ChangeViewReason, ts uint64, rejectedHash ...H) ChangeView) func(config *Config[H]) {
406406
return func(cfg *Config[H]) {
407407
cfg.NewChangeView = f
408408
}

dbft.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,10 @@ func (d *DBFT[H]) processMissingTx() {
388388
// with it, it sends a changeView request and returns false. It's only valid to
389389
// call it when all transactions for this block are already collected.
390390
func (d *DBFT[H]) createAndCheckBlock() bool {
391-
var blockOK bool
391+
var (
392+
blockOK bool
393+
invalidH H
394+
)
392395
if d.isAntiMEVExtensionEnabled() {
393396
b := d.CreatePreBlock()
394397
blockOK = d.VerifyPreBlock(b)
@@ -397,13 +400,13 @@ func (d *DBFT[H]) createAndCheckBlock() bool {
397400
}
398401
} else {
399402
b := d.CreateBlock()
400-
blockOK = d.VerifyBlock(b)
403+
blockOK, invalidH = d.VerifyBlock(b)
401404
if !blockOK {
402405
d.Logger.Warn("proposed block fails verification")
403406
}
404407
}
405408
if !blockOK {
406-
d.sendChangeView(CVTxInvalid)
409+
d.sendChangeView(CVTxInvalid, invalidH)
407410
return false
408411
}
409412
return true

dbft_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ type testState struct {
2828
pool *testPool
2929
preBlocks []dbft.PreBlock[crypto.Uint256]
3030
blocks []dbft.Block[crypto.Uint256]
31-
verify func(b dbft.Block[crypto.Uint256]) bool
31+
verify func(b dbft.Block[crypto.Uint256]) (bool, crypto.Uint256)
3232
}
3333

3434
type (
@@ -136,14 +136,14 @@ func TestDBFT_SingleNode(t *testing.T) {
136136

137137
func TestDBFT_OnReceiveRequestSendResponse(t *testing.T) {
138138
s := newTestState(2, 7)
139-
s.verify = func(b dbft.Block[crypto.Uint256]) bool {
139+
s.verify = func(b dbft.Block[crypto.Uint256]) (bool, crypto.Uint256) {
140140
for _, tx := range b.Transactions() {
141141
if tx.(testTx)%10 == 0 {
142-
return false
142+
return false, crypto.Uint256{}
143143
}
144144
}
145145

146-
return true
146+
return true, crypto.Uint256{}
147147
}
148148

149149
t.Run("receive request from primary", func(t *testing.T) {
@@ -551,7 +551,7 @@ func TestDBFT_Invalid(t *testing.T) {
551551
require.Error(t, err)
552552
})
553553

554-
opts = append(opts, dbft.WithNewChangeView[crypto.Uint256](func(byte, dbft.ChangeViewReason, uint64) dbft.ChangeView {
554+
opts = append(opts, dbft.WithNewChangeView[crypto.Uint256](func(byte, dbft.ChangeViewReason, uint64, ...crypto.Uint256) dbft.ChangeView {
555555
return nil
556556
}))
557557
t.Run("without NewCommit", func(t *testing.T) {
@@ -1165,7 +1165,7 @@ func (s *testState) getOptions() []func(*dbft.Config[crypto.Uint256]) {
11651165

11661166
verify := s.verify
11671167
if verify == nil {
1168-
verify = func(dbft.Block[crypto.Uint256]) bool { return true }
1168+
verify = func(dbft.Block[crypto.Uint256]) (bool, crypto.Uint256) { return true, crypto.Uint256{} }
11691169
}
11701170

11711171
opts = append(opts, dbft.WithVerifyBlock(verify))

internal/consensus/constructors.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func NewPrepareResponse(preparationHash crypto.Uint256) dbft.PrepareResponse[cry
3737
}
3838

3939
// NewChangeView returns minimal ChangeView implementation.
40-
func NewChangeView(newViewNumber byte, _ dbft.ChangeViewReason, ts uint64) dbft.ChangeView {
40+
func NewChangeView(newViewNumber byte, _ dbft.ChangeViewReason, ts uint64, rejected ...crypto.Uint256) dbft.ChangeView {
4141
return &changeView{
4242
newViewNumber: newViewNumber,
4343
timestamp: nanoSecToSec(ts),

send.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,16 @@ func (d *DBFT[H]) sendPrepareRequest(force bool) {
5757
d.checkPrepare()
5858
}
5959

60-
func (c *Context[H]) makeChangeView(ts uint64, reason ChangeViewReason) ConsensusPayload[H] {
61-
cv := c.Config.NewChangeView(c.ViewNumber+1, reason, ts)
60+
func (c *Context[H]) makeChangeView(ts uint64, reason ChangeViewReason, invalidH ...H) ConsensusPayload[H] {
61+
cv := c.Config.NewChangeView(c.ViewNumber+1, reason, ts, invalidH...)
6262

6363
msg := c.Config.NewConsensusPayload(c, ChangeViewType, cv)
6464
c.ChangeViewPayloads[c.MyIndex] = msg
6565

6666
return msg
6767
}
6868

69-
func (d *DBFT[H]) sendChangeView(reason ChangeViewReason) {
69+
func (d *DBFT[H]) sendChangeView(reason ChangeViewReason, invalidH ...H) {
7070
if d.Context.WatchOnly() {
7171
return
7272
}
@@ -97,7 +97,7 @@ func (d *DBFT[H]) sendChangeView(reason ChangeViewReason) {
9797
zap.Int("nc", nc),
9898
zap.Int("nf", nf))
9999

100-
msg := d.makeChangeView(uint64(d.Timer.Now().UnixNano()), reason)
100+
msg := d.makeChangeView(uint64(d.Timer.Now().UnixNano()), reason, invalidH...)
101101
d.StopTxFlow()
102102
d.broadcast(msg)
103103
d.checkChangeView(newView)

0 commit comments

Comments
 (0)