Skip to content

Commit fd92b5a

Browse files
authored
Merge pull request #6686 from multiversx/equivalent-proofs-feat-stabilization
stabilization-equivalent-proofs
2 parents 7e35a87 + 3bd8598 commit fd92b5a

File tree

102 files changed

+1836
-449
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

102 files changed

+1836
-449
lines changed

cmd/node/config/enableEpochs.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -319,10 +319,10 @@
319319
CryptoOpcodesV2EnableEpoch = 4
320320

321321
# EquivalentMessagesEnableEpoch represents the epoch when the equivalent messages are enabled
322-
EquivalentMessagesEnableEpoch = 4
322+
EquivalentMessagesEnableEpoch = 8 # the chain simulator tests for staking v4 fail if this is set earlier, as they test the transition in epochs 4-7
323323

324324
# FixedOrderInConsensusEnableEpoch represents the epoch when the fixed order in consensus is enabled
325-
FixedOrderInConsensusEnableEpoch = 4
325+
FixedOrderInConsensusEnableEpoch = 8 # the chain simulator tests for staking v4 fail if this is set earlier, as they test the transition in epochs 4-7
326326

327327
# BLSMultiSignerEnableEpoch represents the activation epoch for different types of BLS multi-signers
328328
BLSMultiSignerEnableEpoch = [

common/common.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
package common
22

33
import (
4+
"fmt"
5+
46
"github.com/multiversx/mx-chain-core-go/core"
7+
"github.com/multiversx/mx-chain-core-go/core/check"
58
"github.com/multiversx/mx-chain-core-go/data"
9+
"github.com/multiversx/mx-chain-go/storage"
10+
"github.com/multiversx/mx-chain-vm-v1_2-go/ipc/marshaling"
611
)
712

813
// IsEpochChangeBlockForFlagActivation returns true if the provided header is the first one after the specified flag's activation
@@ -19,3 +24,55 @@ func IsFlagEnabledAfterEpochsStartBlock(header data.HeaderHandler, enableEpochsH
1924
isEpochStartBlock := IsEpochChangeBlockForFlagActivation(header, enableEpochsHandler, flag)
2025
return isFlagEnabled && !isEpochStartBlock
2126
}
27+
28+
// ShouldBlockHavePrevProof returns true if the block should have a proof
29+
func ShouldBlockHavePrevProof(header data.HeaderHandler, enableEpochsHandler EnableEpochsHandler, flag core.EnableEpochFlag) bool {
30+
return IsFlagEnabledAfterEpochsStartBlock(header, enableEpochsHandler, flag) && header.GetNonce() > 1
31+
}
32+
33+
// VerifyProofAgainstHeader verifies the fields on the proof match the ones on the header
34+
func VerifyProofAgainstHeader(proof data.HeaderProofHandler, header data.HeaderHandler) error {
35+
if check.IfNilReflect(proof) {
36+
return ErrInvalidHeaderProof
37+
}
38+
39+
if proof.GetHeaderNonce() != header.GetNonce() {
40+
return fmt.Errorf("%w, nonce mismatch", ErrInvalidHeaderProof)
41+
}
42+
if proof.GetHeaderShardId() != header.GetShardID() {
43+
return fmt.Errorf("%w, shard id mismatch", ErrInvalidHeaderProof)
44+
}
45+
if proof.GetHeaderEpoch() != header.GetEpoch() {
46+
return fmt.Errorf("%w, epoch mismatch", ErrInvalidHeaderProof)
47+
}
48+
if proof.GetHeaderRound() != header.GetRound() {
49+
return fmt.Errorf("%w, round mismatch", ErrInvalidHeaderProof)
50+
}
51+
52+
return nil
53+
}
54+
55+
// GetHeader tries to get the header from pool first and if not found, searches for it through storer
56+
func GetHeader(
57+
headerHash []byte,
58+
headersPool HeadersPool,
59+
headersStorer storage.Storer,
60+
marshaller marshaling.Marshalizer,
61+
) (data.HeaderHandler, error) {
62+
header, err := headersPool.GetHeaderByHash(headerHash)
63+
if err == nil {
64+
return header, nil
65+
}
66+
67+
headerBytes, err := headersStorer.SearchFirst(headerHash)
68+
if err != nil {
69+
return nil, err
70+
}
71+
72+
err = marshaller.Unmarshal(header, headerBytes)
73+
if err != nil {
74+
return nil, err
75+
}
76+
77+
return header, nil
78+
}

common/errors.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,6 @@ var ErrNilWasmChangeLocker = errors.New("nil wasm change locker")
1010

1111
// ErrNilStateSyncNotifierSubscriber signals that a nil state sync notifier subscriber has been provided
1212
var ErrNilStateSyncNotifierSubscriber = errors.New("nil state sync notifier subscriber")
13+
14+
// ErrInvalidHeaderProof signals that an invalid equivalent proof has been provided
15+
var ErrInvalidHeaderProof = errors.New("invalid equivalent proof")

common/interface.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,3 +379,8 @@ type ChainParametersSubscriptionHandler interface {
379379
ChainParametersChanged(chainParameters config.ChainParametersByEpochConfig)
380380
IsInterfaceNil() bool
381381
}
382+
383+
// HeadersPool defines what a headers pool structure can perform
384+
type HeadersPool interface {
385+
GetHeaderByHash(hash []byte) (data.HeaderHandler, error)
386+
}

consensus/spos/bls/proxy/subroundsHandler.go

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package proxy
33
import (
44
"github.com/multiversx/mx-chain-core-go/core"
55
"github.com/multiversx/mx-chain-core-go/core/check"
6-
"github.com/multiversx/mx-chain-core-go/data"
76
logger "github.com/multiversx/mx-chain-logger-go"
87

98
"github.com/multiversx/mx-chain-go/common"
@@ -57,6 +56,14 @@ type SubroundsHandler struct {
5756
currentConsensusType consensusStateMachineType
5857
}
5958

59+
// EpochConfirmed is called when the epoch is confirmed (this is registered as callback)
60+
func (s *SubroundsHandler) EpochConfirmed(epoch uint32, _ uint64) {
61+
err := s.initSubroundsForEpoch(epoch)
62+
if err != nil {
63+
log.Error("SubroundsHandler.EpochConfirmed: cannot initialize subrounds", "error", err)
64+
}
65+
}
66+
6067
const (
6168
consensusNone consensusStateMachineType = iota
6269
consensusV1
@@ -85,7 +92,7 @@ func NewSubroundsHandler(args *SubroundsHandlerArgs) (*SubroundsHandler, error)
8592
currentConsensusType: consensusNone,
8693
}
8794

88-
subroundHandler.consensusCoreHandler.EpochStartRegistrationHandler().RegisterHandler(subroundHandler)
95+
subroundHandler.consensusCoreHandler.EpochNotifier().RegisterNotifyHandler(subroundHandler)
8996

9097
return subroundHandler, nil
9198
}
@@ -189,28 +196,6 @@ func (s *SubroundsHandler) initSubroundsForEpoch(epoch uint32) error {
189196
return nil
190197
}
191198

192-
// EpochStartAction is called when the epoch starts
193-
func (s *SubroundsHandler) EpochStartAction(hdr data.HeaderHandler) {
194-
if check.IfNil(hdr) {
195-
log.Error("SubroundsHandler.EpochStartAction: nil header")
196-
return
197-
}
198-
199-
err := s.initSubroundsForEpoch(hdr.GetEpoch())
200-
if err != nil {
201-
log.Error("SubroundsHandler.EpochStartAction: cannot initialize subrounds", "error", err)
202-
}
203-
}
204-
205-
// EpochStartPrepare prepares the subrounds handler for the epoch start
206-
func (s *SubroundsHandler) EpochStartPrepare(_ data.HeaderHandler, _ data.BodyHandler) {
207-
}
208-
209-
// NotifyOrder returns the order of the subrounds handler
210-
func (s *SubroundsHandler) NotifyOrder() uint32 {
211-
return common.ConsensusHandlerOrder
212-
}
213-
214199
// IsInterfaceNil returns true if there is no value under the interface
215200
func (s *SubroundsHandler) IsInterfaceNil() bool {
216201
return s == nil

consensus/spos/bls/proxy/subroundsHandler_test.go

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
crypto "github.com/multiversx/mx-chain-crypto-go"
99
"github.com/stretchr/testify/require"
1010

11-
chainCommon "github.com/multiversx/mx-chain-go/common"
1211
mock2 "github.com/multiversx/mx-chain-go/consensus/mock"
1312
"github.com/multiversx/mx-chain-go/testscommon"
1413
"github.com/multiversx/mx-chain-go/testscommon/bootstrapperStubs"
@@ -17,6 +16,7 @@ import (
1716
"github.com/multiversx/mx-chain-go/testscommon/cryptoMocks"
1817
"github.com/multiversx/mx-chain-go/testscommon/dataRetriever"
1918
"github.com/multiversx/mx-chain-go/testscommon/enableEpochsHandlerMock"
19+
epochNotifierMock "github.com/multiversx/mx-chain-go/testscommon/epochNotifier"
2020
mock "github.com/multiversx/mx-chain-go/testscommon/epochstartmock"
2121
outportStub "github.com/multiversx/mx-chain-go/testscommon/outport"
2222
"github.com/multiversx/mx-chain-go/testscommon/shardingMocks"
@@ -29,6 +29,7 @@ func getDefaultArgumentsSubroundHandler() (*SubroundsHandlerArgs, *consensus.Con
2929
epochsEnable := &enableEpochsHandlerMock.EnableEpochsHandlerStub{}
3030
epochStartNotifier := &mock.EpochStartNotifierStub{}
3131
consensusState := &consensus.ConsensusStateMock{}
32+
epochNotifier := &epochNotifierMock.EpochNotifierStub{}
3233
worker := &consensus.SposWorkerMock{
3334
RemoveAllReceivedMessagesCallsCalled: func() {},
3435
GetConsensusStateChangedChannelsCalled: func() chan bool {
@@ -78,6 +79,7 @@ func getDefaultArgumentsSubroundHandler() (*SubroundsHandlerArgs, *consensus.Con
7879
consensusCore.SetSigningHandler(&consensus.SigningHandlerStub{})
7980
consensusCore.SetEnableEpochsHandler(epochsEnable)
8081
consensusCore.SetEquivalentProofsPool(&dataRetriever.ProofsPoolMock{})
82+
consensusCore.SetEpochNotifier(epochNotifier)
8183
handlerArgs.ConsensusCoreHandler = consensusCore
8284

8385
return handlerArgs, consensusCore
@@ -221,12 +223,14 @@ func TestSubroundsHandler_initSubroundsForEpoch(t *testing.T) {
221223
sh, err := NewSubroundsHandler(handlerArgs)
222224
require.Nil(t, err)
223225
require.NotNil(t, sh)
226+
// first call on register to EpochNotifier
227+
require.Equal(t, int32(1), startCalled.Load())
224228
sh.currentConsensusType = consensusNone
225229

226230
err = sh.initSubroundsForEpoch(0)
227231
require.Nil(t, err)
228232
require.Equal(t, consensusV1, sh.currentConsensusType)
229-
require.Equal(t, int32(1), startCalled.Load())
233+
require.Equal(t, int32(2), startCalled.Load())
230234
})
231235
t.Run("equivalent messages not enabled, with previous consensus type consensusV1", func(t *testing.T) {
232236
t.Parallel()
@@ -251,12 +255,15 @@ func TestSubroundsHandler_initSubroundsForEpoch(t *testing.T) {
251255
sh, err := NewSubroundsHandler(handlerArgs)
252256
require.Nil(t, err)
253257
require.NotNil(t, sh)
258+
// first call on register to EpochNotifier
259+
require.Equal(t, int32(1), startCalled.Load())
254260
sh.currentConsensusType = consensusV1
255261

256262
err = sh.initSubroundsForEpoch(0)
257263
require.Nil(t, err)
258264
require.Equal(t, consensusV1, sh.currentConsensusType)
259-
require.Equal(t, int32(0), startCalled.Load())
265+
require.Equal(t, int32(1), startCalled.Load())
266+
260267
})
261268
t.Run("equivalent messages enabled, with previous consensus type consensusNone", func(t *testing.T) {
262269
t.Parallel()
@@ -280,12 +287,14 @@ func TestSubroundsHandler_initSubroundsForEpoch(t *testing.T) {
280287
sh, err := NewSubroundsHandler(handlerArgs)
281288
require.Nil(t, err)
282289
require.NotNil(t, sh)
290+
// first call on register to EpochNotifier
291+
require.Equal(t, int32(1), startCalled.Load())
283292
sh.currentConsensusType = consensusNone
284293

285294
err = sh.initSubroundsForEpoch(0)
286295
require.Nil(t, err)
287296
require.Equal(t, consensusV2, sh.currentConsensusType)
288-
require.Equal(t, int32(1), startCalled.Load())
297+
require.Equal(t, int32(2), startCalled.Load())
289298
})
290299
t.Run("equivalent messages enabled, with previous consensus type consensusV1", func(t *testing.T) {
291300
t.Parallel()
@@ -309,12 +318,14 @@ func TestSubroundsHandler_initSubroundsForEpoch(t *testing.T) {
309318
sh, err := NewSubroundsHandler(handlerArgs)
310319
require.Nil(t, err)
311320
require.NotNil(t, sh)
321+
// first call on register to EpochNotifier
322+
require.Equal(t, int32(1), startCalled.Load())
312323
sh.currentConsensusType = consensusV1
313324

314325
err = sh.initSubroundsForEpoch(0)
315326
require.Nil(t, err)
316327
require.Equal(t, consensusV2, sh.currentConsensusType)
317-
require.Equal(t, int32(1), startCalled.Load())
328+
require.Equal(t, int32(2), startCalled.Load())
318329
})
319330
t.Run("equivalent messages enabled, with previous consensus type consensusV2", func(t *testing.T) {
320331
t.Parallel()
@@ -339,12 +350,14 @@ func TestSubroundsHandler_initSubroundsForEpoch(t *testing.T) {
339350
sh, err := NewSubroundsHandler(handlerArgs)
340351
require.Nil(t, err)
341352
require.NotNil(t, sh)
353+
// first call on register to EpochNotifier
354+
require.Equal(t, int32(1), startCalled.Load())
342355
sh.currentConsensusType = consensusV2
343356

344357
err = sh.initSubroundsForEpoch(0)
345358
require.Nil(t, err)
346359
require.Equal(t, consensusV2, sh.currentConsensusType)
347-
require.Equal(t, int32(0), startCalled.Load())
360+
require.Equal(t, int32(1), startCalled.Load())
348361
})
349362
}
350363

@@ -375,27 +388,17 @@ func TestSubroundsHandler_Start(t *testing.T) {
375388
sh, err := NewSubroundsHandler(handlerArgs)
376389
require.Nil(t, err)
377390
require.NotNil(t, sh)
391+
// first call on init of EpochNotifier
392+
require.Equal(t, int32(1), startCalled.Load())
378393
sh.currentConsensusType = consensusNone
379394

380395
err = sh.Start(0)
381396
require.Nil(t, err)
382397
require.Equal(t, consensusV1, sh.currentConsensusType)
383-
require.Equal(t, int32(1), startCalled.Load())
398+
require.Equal(t, int32(2), startCalled.Load())
384399
})
385400
}
386401

387-
func TestSubroundsHandler_NotifyOrder(t *testing.T) {
388-
t.Parallel()
389-
390-
handlerArgs, _ := getDefaultArgumentsSubroundHandler()
391-
sh, err := NewSubroundsHandler(handlerArgs)
392-
require.Nil(t, err)
393-
require.NotNil(t, sh)
394-
395-
order := sh.NotifyOrder()
396-
require.Equal(t, uint32(chainCommon.ConsensusHandlerOrder), order)
397-
}
398-
399402
func TestSubroundsHandler_IsInterfaceNil(t *testing.T) {
400403
t.Parallel()
401404

@@ -417,7 +420,7 @@ func TestSubroundsHandler_IsInterfaceNil(t *testing.T) {
417420
})
418421
}
419422

420-
func TestSubroundsHandler_EpochStartAction(t *testing.T) {
423+
func TestSubroundsHandler_EpochConfirmed(t *testing.T) {
421424
t.Parallel()
422425

423426
t.Run("nil handler does not panic", func(t *testing.T) {
@@ -431,7 +434,7 @@ func TestSubroundsHandler_EpochStartAction(t *testing.T) {
431434
handlerArgs, _ := getDefaultArgumentsSubroundHandler()
432435
sh, err := NewSubroundsHandler(handlerArgs)
433436
require.Nil(t, err)
434-
sh.EpochStartAction(&testscommon.HeaderHandlerStub{})
437+
sh.EpochConfirmed(0, 0)
435438
})
436439

437440
// tested through initSubroundsForEpoch
@@ -458,11 +461,13 @@ func TestSubroundsHandler_EpochStartAction(t *testing.T) {
458461
sh, err := NewSubroundsHandler(handlerArgs)
459462
require.Nil(t, err)
460463
require.NotNil(t, sh)
464+
// first call on register to EpochNotifier
465+
require.Equal(t, int32(1), startCalled.Load())
461466

462467
sh.currentConsensusType = consensusNone
463-
sh.EpochStartAction(&testscommon.HeaderHandlerStub{})
468+
sh.EpochConfirmed(0, 0)
464469
require.Nil(t, err)
465470
require.Equal(t, consensusV1, sh.currentConsensusType)
466-
require.Equal(t, int32(1), startCalled.Load())
471+
require.Equal(t, int32(2), startCalled.Load())
467472
})
468473
}

consensus/spos/bls/v1/blsSubroundsFactory.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ func (fct *factory) GenerateSubrounds() error {
104104
fct.initConsensusThreshold()
105105
fct.consensusCore.Chronology().RemoveAllSubrounds()
106106
fct.worker.RemoveAllReceivedMessagesCalls()
107+
fct.worker.RemoveAllReceivedHeaderHandlers()
107108

108109
err := fct.generateStartRoundSubround()
109110
if err != nil {
@@ -206,6 +207,7 @@ func (fct *factory) generateBlockSubround() error {
206207
fct.worker.AddReceivedMessageCall(bls.MtBlockBodyAndHeader, subroundBlockInstance.receivedBlockBodyAndHeader)
207208
fct.worker.AddReceivedMessageCall(bls.MtBlockBody, subroundBlockInstance.receivedBlockBody)
208209
fct.worker.AddReceivedMessageCall(bls.MtBlockHeader, subroundBlockInstance.receivedBlockHeader)
210+
fct.worker.AddReceivedHeaderHandler(subroundBlockInstance.receivedFullHeader)
209211
fct.consensusCore.Chronology().AddSubround(subroundBlockInstance)
210212

211213
return nil

consensus/spos/bls/v1/errors.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@ import "errors"
44

55
// ErrNilSentSignatureTracker defines the error for setting a nil SentSignatureTracker
66
var ErrNilSentSignatureTracker = errors.New("nil sent signature tracker")
7+
8+
// ErrEquivalentMessagesFlagEnabledWithConsensusV1 defines the error for running with the equivalent messages flag enabled under v1 consensus
9+
var ErrEquivalentMessagesFlagEnabledWithConsensusV1 = errors.New("equivalent messages flag enabled with consensus v1")

0 commit comments

Comments
 (0)