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

stabilization-equivalent-proofs #6686

Draft
wants to merge 11 commits into
base: feat/equivalent-messages
Choose a base branch
from
5 changes: 5 additions & 0 deletions common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,8 @@ func IsFlagEnabledAfterEpochsStartBlock(header data.HeaderHandler, enableEpochsH
isEpochStartBlock := IsEpochChangeBlockForFlagActivation(header, enableEpochsHandler, flag)
return isFlagEnabled && !isEpochStartBlock
}

// ShouldBlockHavePrevProof returns true if the block should have a proof
func ShouldBlockHavePrevProof(header data.HeaderHandler, enableEpochsHandler EnableEpochsHandler, flag core.EnableEpochFlag) bool {
return IsFlagEnabledAfterEpochsStartBlock(header, enableEpochsHandler, flag) && header.GetNonce() > 1
}
32 changes: 8 additions & 24 deletions consensus/spos/bls/proxy/subroundsHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package proxy
import (
"github.com/multiversx/mx-chain-core-go/core"
"github.com/multiversx/mx-chain-core-go/core/check"
"github.com/multiversx/mx-chain-core-go/data"
logger "github.com/multiversx/mx-chain-logger-go"

"github.com/multiversx/mx-chain-go/common"
Expand Down Expand Up @@ -57,6 +56,13 @@ type SubroundsHandler struct {
currentConsensusType consensusStateMachineType
}

func (s *SubroundsHandler) EpochConfirmed(epoch uint32, _ uint64) {
err := s.initSubroundsForEpoch(epoch)
if err != nil {
log.Error("SubroundsHandler.EpochStartAction: cannot initialize subrounds", "error", err)
}
}

const (
consensusNone consensusStateMachineType = iota
consensusV1
Expand Down Expand Up @@ -85,7 +91,7 @@ func NewSubroundsHandler(args *SubroundsHandlerArgs) (*SubroundsHandler, error)
currentConsensusType: consensusNone,
}

subroundHandler.consensusCoreHandler.EpochStartRegistrationHandler().RegisterHandler(subroundHandler)
subroundHandler.consensusCoreHandler.EpochNotifier().RegisterNotifyHandler(subroundHandler)

return subroundHandler, nil
}
Expand Down Expand Up @@ -189,28 +195,6 @@ func (s *SubroundsHandler) initSubroundsForEpoch(epoch uint32) error {
return nil
}

// EpochStartAction is called when the epoch starts
func (s *SubroundsHandler) EpochStartAction(hdr data.HeaderHandler) {
if check.IfNil(hdr) {
log.Error("SubroundsHandler.EpochStartAction: nil header")
return
}

err := s.initSubroundsForEpoch(hdr.GetEpoch())
if err != nil {
log.Error("SubroundsHandler.EpochStartAction: cannot initialize subrounds", "error", err)
}
}

// EpochStartPrepare prepares the subrounds handler for the epoch start
func (s *SubroundsHandler) EpochStartPrepare(_ data.HeaderHandler, _ data.BodyHandler) {
}

// NotifyOrder returns the order of the subrounds handler
func (s *SubroundsHandler) NotifyOrder() uint32 {
return common.ConsensusHandlerOrder
}

// IsInterfaceNil returns true if there is no value under the interface
func (s *SubroundsHandler) IsInterfaceNil() bool {
return s == nil
Expand Down
51 changes: 28 additions & 23 deletions consensus/spos/bls/proxy/subroundsHandler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
crypto "github.com/multiversx/mx-chain-crypto-go"
"github.com/stretchr/testify/require"

chainCommon "github.com/multiversx/mx-chain-go/common"
mock2 "github.com/multiversx/mx-chain-go/consensus/mock"
"github.com/multiversx/mx-chain-go/testscommon"
"github.com/multiversx/mx-chain-go/testscommon/bootstrapperStubs"
Expand All @@ -17,6 +16,7 @@ import (
"github.com/multiversx/mx-chain-go/testscommon/cryptoMocks"
"github.com/multiversx/mx-chain-go/testscommon/dataRetriever"
"github.com/multiversx/mx-chain-go/testscommon/enableEpochsHandlerMock"
epochNotifierMock "github.com/multiversx/mx-chain-go/testscommon/epochNotifier"
mock "github.com/multiversx/mx-chain-go/testscommon/epochstartmock"
outportStub "github.com/multiversx/mx-chain-go/testscommon/outport"
"github.com/multiversx/mx-chain-go/testscommon/shardingMocks"
Expand All @@ -29,6 +29,7 @@ func getDefaultArgumentsSubroundHandler() (*SubroundsHandlerArgs, *consensus.Con
epochsEnable := &enableEpochsHandlerMock.EnableEpochsHandlerStub{}
epochStartNotifier := &mock.EpochStartNotifierStub{}
consensusState := &consensus.ConsensusStateMock{}
epochNotifier := &epochNotifierMock.EpochNotifierStub{}
worker := &consensus.SposWorkerMock{
RemoveAllReceivedMessagesCallsCalled: func() {},
GetConsensusStateChangedChannelsCalled: func() chan bool {
Expand Down Expand Up @@ -78,6 +79,7 @@ func getDefaultArgumentsSubroundHandler() (*SubroundsHandlerArgs, *consensus.Con
consensusCore.SetSigningHandler(&consensus.SigningHandlerStub{})
consensusCore.SetEnableEpochsHandler(epochsEnable)
consensusCore.SetEquivalentProofsPool(&dataRetriever.ProofsPoolMock{})
consensusCore.SetEpochNotifier(epochNotifier)
handlerArgs.ConsensusCoreHandler = consensusCore

return handlerArgs, consensusCore
Expand Down Expand Up @@ -221,12 +223,14 @@ func TestSubroundsHandler_initSubroundsForEpoch(t *testing.T) {
sh, err := NewSubroundsHandler(handlerArgs)
require.Nil(t, err)
require.NotNil(t, sh)
// first call on register to EpochNotifier
require.Equal(t, int32(1), startCalled.Load())
sh.currentConsensusType = consensusNone

err = sh.initSubroundsForEpoch(0)
require.Nil(t, err)
require.Equal(t, consensusV1, sh.currentConsensusType)
require.Equal(t, int32(1), startCalled.Load())
require.Equal(t, int32(2), startCalled.Load())
})
t.Run("equivalent messages not enabled, with previous consensus type consensusV1", func(t *testing.T) {
t.Parallel()
Expand All @@ -251,12 +255,15 @@ func TestSubroundsHandler_initSubroundsForEpoch(t *testing.T) {
sh, err := NewSubroundsHandler(handlerArgs)
require.Nil(t, err)
require.NotNil(t, sh)
// first call on register to EpochNotifier
require.Equal(t, int32(1), startCalled.Load())
sh.currentConsensusType = consensusV1

err = sh.initSubroundsForEpoch(0)
require.Nil(t, err)
require.Equal(t, consensusV1, sh.currentConsensusType)
require.Equal(t, int32(0), startCalled.Load())
require.Equal(t, int32(1), startCalled.Load())

})
t.Run("equivalent messages enabled, with previous consensus type consensusNone", func(t *testing.T) {
t.Parallel()
Expand All @@ -280,12 +287,14 @@ func TestSubroundsHandler_initSubroundsForEpoch(t *testing.T) {
sh, err := NewSubroundsHandler(handlerArgs)
require.Nil(t, err)
require.NotNil(t, sh)
// first call on register to EpochNotifier
require.Equal(t, int32(1), startCalled.Load())
sh.currentConsensusType = consensusNone

err = sh.initSubroundsForEpoch(0)
require.Nil(t, err)
require.Equal(t, consensusV2, sh.currentConsensusType)
require.Equal(t, int32(1), startCalled.Load())
require.Equal(t, int32(2), startCalled.Load())
})
t.Run("equivalent messages enabled, with previous consensus type consensusV1", func(t *testing.T) {
t.Parallel()
Expand All @@ -309,12 +318,14 @@ func TestSubroundsHandler_initSubroundsForEpoch(t *testing.T) {
sh, err := NewSubroundsHandler(handlerArgs)
require.Nil(t, err)
require.NotNil(t, sh)
// first call on register to EpochNotifier
require.Equal(t, int32(1), startCalled.Load())
sh.currentConsensusType = consensusV1

err = sh.initSubroundsForEpoch(0)
require.Nil(t, err)
require.Equal(t, consensusV2, sh.currentConsensusType)
require.Equal(t, int32(1), startCalled.Load())
require.Equal(t, int32(2), startCalled.Load())
})
t.Run("equivalent messages enabled, with previous consensus type consensusV2", func(t *testing.T) {
t.Parallel()
Expand All @@ -339,12 +350,14 @@ func TestSubroundsHandler_initSubroundsForEpoch(t *testing.T) {
sh, err := NewSubroundsHandler(handlerArgs)
require.Nil(t, err)
require.NotNil(t, sh)
// first call on register to EpochNotifier
require.Equal(t, int32(1), startCalled.Load())
sh.currentConsensusType = consensusV2

err = sh.initSubroundsForEpoch(0)
require.Nil(t, err)
require.Equal(t, consensusV2, sh.currentConsensusType)
require.Equal(t, int32(0), startCalled.Load())
require.Equal(t, int32(1), startCalled.Load())
})
}

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

err = sh.Start(0)
require.Nil(t, err)
require.Equal(t, consensusV1, sh.currentConsensusType)
require.Equal(t, int32(1), startCalled.Load())
require.Equal(t, int32(2), startCalled.Load())
})
}

func TestSubroundsHandler_NotifyOrder(t *testing.T) {
t.Parallel()

handlerArgs, _ := getDefaultArgumentsSubroundHandler()
sh, err := NewSubroundsHandler(handlerArgs)
require.Nil(t, err)
require.NotNil(t, sh)

order := sh.NotifyOrder()
require.Equal(t, uint32(chainCommon.ConsensusHandlerOrder), order)
}

func TestSubroundsHandler_IsInterfaceNil(t *testing.T) {
t.Parallel()

Expand All @@ -417,7 +420,7 @@ func TestSubroundsHandler_IsInterfaceNil(t *testing.T) {
})
}

func TestSubroundsHandler_EpochStartAction(t *testing.T) {
func TestSubroundsHandler_EpochConfirmed(t *testing.T) {
t.Parallel()

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

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

sh.currentConsensusType = consensusNone
sh.EpochStartAction(&testscommon.HeaderHandlerStub{})
sh.EpochConfirmed(0, 0)
require.Nil(t, err)
require.Equal(t, consensusV1, sh.currentConsensusType)
require.Equal(t, int32(1), startCalled.Load())
require.Equal(t, int32(2), startCalled.Load())
})
}
1 change: 1 addition & 0 deletions consensus/spos/bls/v1/blsSubroundsFactory.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ func (fct *factory) generateBlockSubround() error {
fct.worker.AddReceivedMessageCall(bls.MtBlockBodyAndHeader, subroundBlockInstance.receivedBlockBodyAndHeader)
fct.worker.AddReceivedMessageCall(bls.MtBlockBody, subroundBlockInstance.receivedBlockBody)
fct.worker.AddReceivedMessageCall(bls.MtBlockHeader, subroundBlockInstance.receivedBlockHeader)
fct.worker.AddReceivedHeaderHandler(subroundBlockInstance.receivedFullHeader)
fct.consensusCore.Chronology().AddSubround(subroundBlockInstance)

return nil
Expand Down
3 changes: 3 additions & 0 deletions consensus/spos/bls/v1/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ import "errors"

// ErrNilSentSignatureTracker defines the error for setting a nil SentSignatureTracker
var ErrNilSentSignatureTracker = errors.New("nil sent signature tracker")

// ErrEquivalentMessagesFlagEnabledWithConsensusV1 defines the error for running with the equivalent messages flag enabled under v1 consensus
var ErrEquivalentMessagesFlagEnabledWithConsensusV1 = errors.New("equivalent messages flag enabled with consensus v1")
23 changes: 23 additions & 0 deletions consensus/spos/bls/v1/subroundBlock.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package v1

import (
"bytes"
"context"
"time"

Expand Down Expand Up @@ -334,6 +335,10 @@ func (sr *subroundBlock) createHeader() (data.HeaderHandler, error) {
return nil, err
}

if sr.EnableEpochsHandler().IsFlagEnabledInEpoch(common.EquivalentMessagesFlag, hdr.GetEpoch()) {
return nil, ErrEquivalentMessagesFlagEnabledWithConsensusV1
}

err = hdr.SetPrevHash(prevHash)
if err != nil {
return nil, err
Expand Down Expand Up @@ -491,6 +496,24 @@ func (sr *subroundBlock) receivedBlockBody(ctx context.Context, cnsDta *consensu
return blockProcessedWithSuccess
}

func (sr *subroundBlock) receivedFullHeader(headerHandler data.HeaderHandler) {
if sr.ShardCoordinator().SelfId() != headerHandler.GetShardID() {
return
}

if !sr.EnableEpochsHandler().IsFlagEnabledInEpoch(common.EquivalentMessagesFlag, headerHandler.GetEpoch()) {
return
}

log.Debug("subroundBlock.ReceivedFullHeader", "nonce", headerHandler.GetNonce(), "epoch", headerHandler.GetEpoch())

lastCommittedBlockHash := sr.Blockchain().GetCurrentBlockHeaderHash()
if bytes.Equal(lastCommittedBlockHash, headerHandler.GetPrevHash()) {
// Need to switch to consensus v2
sr.EpochNotifier().CheckEpoch(headerHandler)
}
}

// receivedBlockHeader method is called when a block header is received through the block header channel.
// If the block header is valid, then the validatorRoundStates map corresponding to the node which sent it,
// is set on true for the subround Block
Expand Down
9 changes: 9 additions & 0 deletions consensus/spos/consensusCore.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"github.com/multiversx/mx-chain-core-go/data"
"github.com/multiversx/mx-chain-core-go/hashing"
"github.com/multiversx/mx-chain-core-go/marshal"

"github.com/multiversx/mx-chain-go/common"
cryptoCommon "github.com/multiversx/mx-chain-go/common/crypto"
"github.com/multiversx/mx-chain-go/consensus"
Expand Down Expand Up @@ -41,6 +42,7 @@ type ConsensusCore struct {
signingHandler consensus.SigningHandler
enableEpochsHandler common.EnableEpochsHandler
equivalentProofsPool consensus.EquivalentProofsPool
epochNotifier process.EpochNotifier
}

// ConsensusCoreArgs store all arguments that are needed to create a ConsensusCore object
Expand Down Expand Up @@ -69,6 +71,7 @@ type ConsensusCoreArgs struct {
SigningHandler consensus.SigningHandler
EnableEpochsHandler common.EnableEpochsHandler
EquivalentProofsPool consensus.EquivalentProofsPool
EpochNotifier process.EpochNotifier
}

// NewConsensusCore creates a new ConsensusCore instance
Expand Down Expand Up @@ -100,6 +103,7 @@ func NewConsensusCore(
signingHandler: args.SigningHandler,
enableEpochsHandler: args.EnableEpochsHandler,
equivalentProofsPool: args.EquivalentProofsPool,
epochNotifier: args.EpochNotifier,
}

err := ValidateConsensusCore(consensusCore)
Expand Down Expand Up @@ -180,6 +184,11 @@ func (cc *ConsensusCore) EpochStartRegistrationHandler() epochStart.Registration
return cc.epochStartRegistrationHandler
}

// EpochNotifier returns the epoch notifier
func (cc *ConsensusCore) EpochNotifier() process.EpochNotifier {
return cc.epochNotifier
}

// PeerHonestyHandler will return the peer honesty handler which will be used in subrounds
func (cc *ConsensusCore) PeerHonestyHandler() consensus.PeerHonestyHandler {
return cc.peerHonestyHandler
Expand Down
3 changes: 3 additions & 0 deletions consensus/spos/consensusCoreValidator.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ func ValidateConsensusCore(container ConsensusCoreHandler) error {
if check.IfNil(container.EquivalentProofsPool()) {
return ErrNilEquivalentProofPool
}
if check.IfNil(container.EpochNotifier()) {
return ErrNilEpochNotifier
}

return nil
}
3 changes: 3 additions & 0 deletions consensus/spos/consensusCoreValidator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/multiversx/mx-chain-go/testscommon/cryptoMocks"
"github.com/multiversx/mx-chain-go/testscommon/dataRetriever"
"github.com/multiversx/mx-chain-go/testscommon/enableEpochsHandlerMock"
epochNotifierMock "github.com/multiversx/mx-chain-go/testscommon/epochNotifier"
"github.com/multiversx/mx-chain-go/testscommon/hashingMocks"
"github.com/multiversx/mx-chain-go/testscommon/shardingMocks"
)
Expand Down Expand Up @@ -41,6 +42,7 @@ func initConsensusDataContainer() *ConsensusCore {
signingHandler := &consensusMocks.SigningHandlerStub{}
enableEpochsHandler := &enableEpochsHandlerMock.EnableEpochsHandlerStub{}
proofsPool := &dataRetriever.ProofsPoolMock{}
epochNotifier := &epochNotifierMock.EpochNotifierStub{}

return &ConsensusCore{
blockChain: blockChain,
Expand All @@ -66,6 +68,7 @@ func initConsensusDataContainer() *ConsensusCore {
signingHandler: signingHandler,
enableEpochsHandler: enableEpochsHandler,
equivalentProofsPool: proofsPool,
epochNotifier: epochNotifier,
}
}

Expand Down
1 change: 1 addition & 0 deletions consensus/spos/consensusCore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ func createDefaultConsensusCoreArgs() *spos.ConsensusCoreArgs {
SigningHandler: consensusCoreMock.SigningHandler(),
EnableEpochsHandler: consensusCoreMock.EnableEpochsHandler(),
EquivalentProofsPool: consensusCoreMock.EquivalentProofsPool(),
EpochNotifier: consensusCoreMock.EpochNotifier(),
}
return args
}
Expand Down
3 changes: 3 additions & 0 deletions consensus/spos/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,3 +270,6 @@ var ErrHeaderProofNotExpected = errors.New("header proof not expected")

// ErrConsensusMessageNotExpected signals that a consensus message was not expected
var ErrConsensusMessageNotExpected = errors.New("consensus message not expected")

// ErrNilEpochNotifier signals that a nil epoch notifier has been provided
var ErrNilEpochNotifier = errors.New("nil epoch notifier")
Loading
Loading