diff --git a/cmd/node/factory/interface.go b/cmd/node/factory/interface.go index 4e123d762d6..8f90ce3ee89 100644 --- a/cmd/node/factory/interface.go +++ b/cmd/node/factory/interface.go @@ -5,6 +5,7 @@ import ( "github.com/multiversx/mx-chain-core-go/core" "github.com/multiversx/mx-chain-core-go/data" + "github.com/multiversx/mx-chain-go/p2p" ) @@ -15,7 +16,6 @@ type HeaderSigVerifierHandler interface { VerifyRandSeedAndLeaderSignature(header data.HeaderHandler) error VerifySignature(header data.HeaderHandler) error VerifySignatureForHash(header data.HeaderHandler, hash []byte, pubkeysBitmap []byte, signature []byte) error - VerifyPreviousBlockProof(header data.HeaderHandler) error VerifyHeaderProof(headerProof data.HeaderProofHandler) error IsInterfaceNil() bool } diff --git a/consensus/broadcast/delayedBroadcast.go b/consensus/broadcast/delayedBroadcast.go index f56e65694c7..a1c94cf33d7 100644 --- a/consensus/broadcast/delayedBroadcast.go +++ b/consensus/broadcast/delayedBroadcast.go @@ -699,9 +699,8 @@ func (dbb *delayedBlockBroadcaster) interceptedHeader(_ string, headerHash []byt // TODO: should be handled from interceptor proof := headerHandler.GetPreviousProof() - var aggSig, bitmap []byte - if proof != nil { + if !check.IfNilReflect(proof) { aggSig, bitmap = proof.GetAggregatedSignature(), proof.GetPubKeysBitmap() } diff --git a/consensus/interface.go b/consensus/interface.go index 89e217c3af7..8dfc1018172 100644 --- a/consensus/interface.go +++ b/consensus/interface.go @@ -127,13 +127,13 @@ type HeaderSigVerifier interface { VerifyLeaderSignature(header data.HeaderHandler) error VerifySignature(header data.HeaderHandler) error VerifySignatureForHash(header data.HeaderHandler, hash []byte, pubkeysBitmap []byte, signature []byte) error - VerifyPreviousBlockProof(header data.HeaderHandler) error VerifyHeaderProof(headerProof data.HeaderProofHandler) error IsInterfaceNil() bool } // FallbackHeaderValidator defines the behaviour of a component able to signal when a fallback header validation could be applied type FallbackHeaderValidator interface { + ShouldApplyFallbackValidationForHeaderWith(shardID uint32, startOfEpochBlock bool, round uint64, prevHeaderHash []byte) bool ShouldApplyFallbackValidation(headerHandler data.HeaderHandler) bool IsInterfaceNil() bool } diff --git a/consensus/spos/bls/v1/subroundBlock.go b/consensus/spos/bls/v1/subroundBlock.go index eac4a7c9204..504cb82a180 100644 --- a/consensus/spos/bls/v1/subroundBlock.go +++ b/consensus/spos/bls/v1/subroundBlock.go @@ -415,9 +415,14 @@ func (sr *subroundBlock) receivedBlockBodyAndHeader(ctx context.Context, cnsDta return false } + header := sr.BlockProcessor().DecodeBlockHeader(cnsDta.Header) + if headerHasProof(header) { + return false + } + sr.SetData(cnsDta.BlockHeaderHash) sr.SetBody(sr.BlockProcessor().DecodeBlockBody(cnsDta.Body)) - sr.SetHeader(sr.BlockProcessor().DecodeBlockHeader(cnsDta.Header)) + sr.SetHeader(header) isInvalidData := check.IfNil(sr.GetBody()) || sr.isInvalidHeaderOrData() if isInvalidData { @@ -514,8 +519,13 @@ func (sr *subroundBlock) receivedBlockHeader(ctx context.Context, cnsDta *consen return false } + header := sr.BlockProcessor().DecodeBlockHeader(cnsDta.Header) + if headerHasProof(header) { + return false + } + sr.SetData(cnsDta.BlockHeaderHash) - sr.SetHeader(sr.BlockProcessor().DecodeBlockHeader(cnsDta.Header)) + sr.SetHeader(header) if sr.isInvalidHeaderOrData() { return false @@ -535,6 +545,13 @@ func (sr *subroundBlock) receivedBlockHeader(ctx context.Context, cnsDta *consen return blockProcessedWithSuccess } +func headerHasProof(headerHandler data.HeaderHandler) bool { + if check.IfNil(headerHandler) { + return false + } + return !check.IfNilReflect(headerHandler.GetPreviousProof()) +} + func (sr *subroundBlock) processReceivedBlock(ctx context.Context, cnsDta *consensus.Message) bool { if check.IfNil(sr.GetBody()) { return false diff --git a/consensus/spos/bls/v2/subroundBlock.go b/consensus/spos/bls/v2/subroundBlock.go index 890cf0c5c3c..2454ad3643e 100644 --- a/consensus/spos/bls/v2/subroundBlock.go +++ b/consensus/spos/bls/v2/subroundBlock.go @@ -9,6 +9,7 @@ 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" + "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/consensus" "github.com/multiversx/mx-chain-go/consensus/spos" @@ -110,7 +111,6 @@ func (sr *subroundBlock) doBlockJob(ctx context.Context) bool { return false } - // todo: check again the block proof verification & leader signature verification // block proof verification should be done over the header that contains the leader signature leaderSignature, err := sr.signBlockHeader(header) if err != nil { @@ -177,7 +177,7 @@ func printLogMessage(ctx context.Context, baseMessage string, err error) { log.Debug(baseMessage, "error", err.Error()) } -func (sr *subroundBlock) sendBlock(header data.HeaderHandler, body data.BodyHandler, leader string) bool { +func (sr *subroundBlock) sendBlock(header data.HeaderHandler, body data.BodyHandler, _ string) bool { marshalledBody, err := sr.Marshalizer().Marshal(body) if err != nil { log.Debug("sendBlock.Marshal: body", "error", err.Error()) diff --git a/consensus/spos/errors.go b/consensus/spos/errors.go index abb3c9fb40b..62f9c23ad17 100644 --- a/consensus/spos/errors.go +++ b/consensus/spos/errors.go @@ -253,9 +253,6 @@ var ErrEquivalentMessageAlreadyReceived = errors.New("equivalent message already // ErrNilEnableEpochsHandler signals that a nil enable epochs handler has been provided var ErrNilEnableEpochsHandler = errors.New("nil enable epochs handler") -// ErrMissingProposerSignature signals that proposer signature is missing -var ErrMissingProposerSignature = errors.New("missing proposer signature") - // ErrNilThrottler signals that a nil throttler has been provided var ErrNilThrottler = errors.New("nil throttler") @@ -267,3 +264,9 @@ var ErrNilEquivalentProofPool = errors.New("nil equivalent proof pool") // ErrNilHeaderProof signals that a nil header proof has been provided var ErrNilHeaderProof = errors.New("nil header proof") + +// ErrHeaderProofNotExpected signals that a header proof was not expected +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") diff --git a/consensus/spos/interface.go b/consensus/spos/interface.go index c351cffad54..d85c94f2b7a 100644 --- a/consensus/spos/interface.go +++ b/consensus/spos/interface.go @@ -138,7 +138,7 @@ type HeaderSigVerifier interface { VerifyLeaderSignature(header data.HeaderHandler) error VerifySignature(header data.HeaderHandler) error VerifySignatureForHash(header data.HeaderHandler, hash []byte, pubkeysBitmap []byte, signature []byte) error - VerifyPreviousBlockProof(header data.HeaderHandler) error + VerifyHeaderWithProof(header data.HeaderHandler) error VerifyHeaderProof(headerProof data.HeaderProofHandler) error IsInterfaceNil() bool } diff --git a/consensus/spos/worker.go b/consensus/spos/worker.go index cdec8c35151..62f31dfc8ab 100644 --- a/consensus/spos/worker.go +++ b/consensus/spos/worker.go @@ -525,10 +525,9 @@ func (wrk *Worker) doJobOnMessageWithHeader(cnsMsg *consensus.Message) error { err) } - err = wrk.headerSigVerifier.VerifyPreviousBlockProof(header) + err = wrk.checkHeaderPreviousProof(header) if err != nil { - return fmt.Errorf("%w : verify previous block proof for received header from consensus topic failed", - err) + return err } wrk.processReceivedHeaderMetric(cnsMsg) @@ -544,6 +543,18 @@ func (wrk *Worker) doJobOnMessageWithHeader(cnsMsg *consensus.Message) error { return nil } +func (wrk *Worker) checkHeaderPreviousProof(header data.HeaderHandler) error { + if wrk.enableEpochsHandler.IsFlagEnabledInEpoch(common.EquivalentMessagesFlag, header.GetEpoch()) { + return fmt.Errorf("%w : received header on consensus topic after equivalent messages activation", ErrConsensusMessageNotExpected) + } + + if !check.IfNilReflect(header.GetPreviousProof()) { + return fmt.Errorf("%w : received header from consensus topic has previous proof", ErrHeaderProofNotExpected) + } + + return nil +} + func (wrk *Worker) verifyHeaderHash(hash []byte, marshalledHeader []byte) bool { computedHash := wrk.hasher.Compute(string(marshalledHeader)) return bytes.Equal(hash, computedHash) diff --git a/dataRetriever/dataPool/proofsCache/proofsPool.go b/dataRetriever/dataPool/proofsCache/proofsPool.go index b0de8e005cd..1662f6c5cdc 100644 --- a/dataRetriever/dataPool/proofsCache/proofsPool.go +++ b/dataRetriever/dataPool/proofsCache/proofsPool.go @@ -4,6 +4,7 @@ import ( "fmt" "sync" + "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" ) @@ -26,7 +27,7 @@ func NewProofsPool() *proofsPool { func (pp *proofsPool) AddProof( headerProof data.HeaderProofHandler, ) error { - if headerProof == nil { + if check.IfNilReflect(headerProof) { return ErrNilProof } diff --git a/epochStart/bootstrap/disabled/disabledHeaderSigVerifier.go b/epochStart/bootstrap/disabled/disabledHeaderSigVerifier.go index e23d223c3b9..e4c4bb14a25 100644 --- a/epochStart/bootstrap/disabled/disabledHeaderSigVerifier.go +++ b/epochStart/bootstrap/disabled/disabledHeaderSigVerifier.go @@ -2,6 +2,7 @@ package disabled import ( "github.com/multiversx/mx-chain-core-go/data" + "github.com/multiversx/mx-chain-go/process" ) @@ -40,8 +41,8 @@ func (h *headerSigVerifier) VerifySignatureForHash(_ data.HeaderHandler, _ []byt return nil } -// VerifyPreviousBlockProof returns nil as it is disabled -func (h *headerSigVerifier) VerifyPreviousBlockProof(_ data.HeaderHandler) error { +// VerifyHeaderWithProof returns nil as it is disabled +func (h *headerSigVerifier) VerifyHeaderWithProof(_ data.HeaderHandler) error { return nil } diff --git a/fallback/headerValidator.go b/fallback/headerValidator.go index 8e2d0eda037..4b9110582b0 100644 --- a/fallback/headerValidator.go +++ b/fallback/headerValidator.go @@ -5,10 +5,11 @@ import ( "github.com/multiversx/mx-chain-core-go/core/check" "github.com/multiversx/mx-chain-core-go/data" "github.com/multiversx/mx-chain-core-go/marshal" + "github.com/multiversx/mx-chain-logger-go" + "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/dataRetriever" "github.com/multiversx/mx-chain-go/process" - "github.com/multiversx/mx-chain-logger-go" ) var log = logger.GetOrCreate("fallback") @@ -45,28 +46,34 @@ func NewFallbackHeaderValidator( return hv, nil } -// ShouldApplyFallbackValidation returns if for the given header could be applied fallback validation or not -func (fhv *fallbackHeaderValidator) ShouldApplyFallbackValidation(headerHandler data.HeaderHandler) bool { - if check.IfNil(headerHandler) { - return false - } - if headerHandler.GetShardID() != core.MetachainShardId { +// ShouldApplyFallbackValidationForHeaderWith returns if for the given header data fallback validation could be applied or not +func (fhv *fallbackHeaderValidator) ShouldApplyFallbackValidationForHeaderWith(shardID uint32, startOfEpochBlock bool, round uint64, prevHeaderHash []byte) bool { + if shardID != core.MetachainShardId { return false } - if !headerHandler.IsStartOfEpochBlock() { + if !startOfEpochBlock { return false } - previousHeader, err := process.GetMetaHeader(headerHandler.GetPrevHash(), fhv.headersPool, fhv.marshalizer, fhv.storageService) + previousHeader, err := process.GetMetaHeader(prevHeaderHash, fhv.headersPool, fhv.marshalizer, fhv.storageService) if err != nil { log.Debug("ShouldApplyFallbackValidation", "GetMetaHeader", err.Error()) return false } - isRoundTooOld := int64(headerHandler.GetRound())-int64(previousHeader.GetRound()) >= common.MaxRoundsWithoutCommittedStartInEpochBlock + isRoundTooOld := int64(round)-int64(previousHeader.GetRound()) >= common.MaxRoundsWithoutCommittedStartInEpochBlock return isRoundTooOld } +// ShouldApplyFallbackValidation returns if for the given header could be applied fallback validation or not +func (fhv *fallbackHeaderValidator) ShouldApplyFallbackValidation(headerHandler data.HeaderHandler) bool { + if check.IfNil(headerHandler) { + return false + } + + return fhv.ShouldApplyFallbackValidationForHeaderWith(headerHandler.GetShardID(), headerHandler.IsStartOfEpochBlock(), headerHandler.GetRound(), headerHandler.GetPrevHash()) +} + // IsInterfaceNil returns true if there is no value under the interface func (fhv *fallbackHeaderValidator) IsInterfaceNil() bool { return fhv == nil diff --git a/integrationTests/consensus/consensusSigning_test.go b/integrationTests/consensus/consensusSigning_test.go index ec3fc12292f..dfa6966f1f0 100644 --- a/integrationTests/consensus/consensusSigning_test.go +++ b/integrationTests/consensus/consensusSigning_test.go @@ -8,8 +8,9 @@ import ( "testing" "time" - "github.com/multiversx/mx-chain-go/integrationTests" "github.com/stretchr/testify/assert" + + "github.com/multiversx/mx-chain-go/integrationTests" ) func initNodesWithTestSigner( diff --git a/process/block/baseProcess.go b/process/block/baseProcess.go index 53cfa96e997..4f2a3661ece 100644 --- a/process/block/baseProcess.go +++ b/process/block/baseProcess.go @@ -364,7 +364,7 @@ func displayHeader(headerHandler data.HeaderHandler) []*display.LineData { proof := headerHandler.GetPreviousProof() var prevAggregatedSig, prevBitmap []byte - if proof != nil { + if !check.IfNilReflect(proof) { prevAggregatedSig, prevBitmap = proof.GetAggregatedSignature(), proof.GetPubKeysBitmap() } diff --git a/process/block/baseProcess_test.go b/process/block/baseProcess_test.go index a65369611fa..017f7b3e1d0 100644 --- a/process/block/baseProcess_test.go +++ b/process/block/baseProcess_test.go @@ -3140,7 +3140,10 @@ func TestBaseProcessor_CheckSentSignaturesAtCommitTime(t *testing.T) { arguments.NodesCoordinator = nodesCoordinatorInstance bp, _ := blproc.NewShardProcessor(arguments) - err := bp.CheckSentSignaturesAtCommitTime(&block.Header{}) + err := bp.CheckSentSignaturesAtCommitTime(&block.Header{ + RandSeed: []byte("randSeed"), + PrevRandSeed: []byte("prevRandSeed"), + }) assert.Equal(t, expectedErr, err) }) t.Run("should work with bitmap", func(t *testing.T) { @@ -3164,6 +3167,8 @@ func TestBaseProcessor_CheckSentSignaturesAtCommitTime(t *testing.T) { bp, _ := blproc.NewShardProcessor(arguments) err := bp.CheckSentSignaturesAtCommitTime(&block.Header{ + RandSeed: []byte("randSeed"), + PrevRandSeed: []byte("prevRandSeed"), PubKeysBitmap: []byte{0b00000101}, }) assert.Nil(t, err) diff --git a/process/block/interceptedBlocks/common.go b/process/block/interceptedBlocks/common.go index cece10ee626..90a604dba23 100644 --- a/process/block/interceptedBlocks/common.go +++ b/process/block/interceptedBlocks/common.go @@ -6,6 +6,7 @@ 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" + "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/sharding" @@ -70,14 +71,15 @@ func checkMiniblockArgument(arg *ArgInterceptedMiniblock) error { } func checkHeaderHandler(hdr data.HeaderHandler, enableEpochsHandler common.EnableEpochsHandler) error { - // TODO[cleanup cns finality]: remove these checks - if len(hdr.GetPubKeysBitmap()) == 0 && !enableEpochsHandler.IsFlagEnabledInEpoch(common.EquivalentMessagesFlag, hdr.GetEpoch()) { + equivalentMessagesEnabled := enableEpochsHandler.IsFlagEnabledInEpoch(common.EquivalentMessagesFlag, hdr.GetEpoch()) + + if len(hdr.GetPubKeysBitmap()) == 0 && !equivalentMessagesEnabled { return process.ErrNilPubKeysBitmap } if len(hdr.GetPrevHash()) == 0 { return process.ErrNilPreviousBlockHash } - if len(hdr.GetSignature()) == 0 && !enableEpochsHandler.IsFlagEnabledInEpoch(common.EquivalentMessagesFlag, hdr.GetEpoch()) { + if len(hdr.GetSignature()) == 0 && !equivalentMessagesEnabled { return process.ErrNilSignature } if len(hdr.GetRootHash()) == 0 { @@ -90,16 +92,42 @@ func checkHeaderHandler(hdr data.HeaderHandler, enableEpochsHandler common.Enabl return process.ErrNilPrevRandSeed } + err := checkProofIntegrity(hdr, enableEpochsHandler) + if err != nil { + return err + } + return hdr.CheckFieldsForNil() } +func checkProofIntegrity(hdr data.HeaderHandler, enableEpochsHandler common.EnableEpochsHandler) error { + equivalentMessagesEnabled := enableEpochsHandler.IsFlagEnabledInEpoch(common.EquivalentMessagesFlag, hdr.GetEpoch()) + + prevHeaderProof := hdr.GetPreviousProof() + nilPreviousProof := check.IfNilReflect(prevHeaderProof) + missingProof := nilPreviousProof && equivalentMessagesEnabled + unexpectedProof := !nilPreviousProof && !equivalentMessagesEnabled + hasProof := !nilPreviousProof && equivalentMessagesEnabled + + if missingProof { + return process.ErrMissingHeaderProof + } + if unexpectedProof { + return process.ErrUnexpectedHeaderProof + } + if hasProof && isIncompleteProof(prevHeaderProof) { + return process.ErrInvalidHeaderProof + } + + return nil +} + func checkMetaShardInfo( shardInfo []data.ShardDataHandler, coordinator sharding.Coordinator, headerSigVerifier process.InterceptedHeaderSigVerifier, ) error { wgProofsVerification := sync.WaitGroup{} - wgProofsVerification.Add(len(shardInfo)) errChan := make(chan error, len(shardInfo)) for _, sd := range shardInfo { if sd.GetShardID() >= coordinator.NumberOfShards() && sd.GetShardID() != core.MetachainShardId { @@ -111,6 +139,7 @@ func checkMetaShardInfo( return err } + wgProofsVerification.Add(1) checkProofAsync(sd.GetPreviousProof(), headerSigVerifier, &wgProofsVerification, errChan) } diff --git a/process/block/interceptedBlocks/interceptedBlockHeader.go b/process/block/interceptedBlocks/interceptedBlockHeader.go index 9c009b8bb3f..cde4be46170 100644 --- a/process/block/interceptedBlocks/interceptedBlockHeader.go +++ b/process/block/interceptedBlocks/interceptedBlockHeader.go @@ -78,11 +78,6 @@ func (inHdr *InterceptedHeader) CheckValidity() error { return err } - err = inHdr.sigVerifier.VerifyPreviousBlockProof(inHdr.hdr) - if err != nil { - return err - } - return inHdr.verifySignatures() } diff --git a/process/block/interceptedBlocks/interceptedBlockHeader_test.go b/process/block/interceptedBlocks/interceptedBlockHeader_test.go index 462e040af50..bb58691cd38 100644 --- a/process/block/interceptedBlocks/interceptedBlockHeader_test.go +++ b/process/block/interceptedBlocks/interceptedBlockHeader_test.go @@ -90,7 +90,7 @@ func createMockShardHeader() *dataBlock.Header { } } -//------- TestNewInterceptedHeader +// ------- TestNewInterceptedHeader func TestNewInterceptedHeader_NilArgumentShouldErr(t *testing.T) { t.Parallel() @@ -174,7 +174,7 @@ func TestNewInterceptedHeader_MetachainForThisShardShouldWork(t *testing.T) { assert.True(t, inHdr.IsForCurrentShard()) } -//------- Verify +// ------- Verify func TestInterceptedHeader_CheckValidityNilPubKeyBitmapShouldErr(t *testing.T) { t.Parallel() @@ -236,6 +236,7 @@ func TestInterceptedHeader_CheckValidityLeaderSignatureOkShouldWork(t *testing.T func TestInterceptedHeader_CheckValidityLeaderSignatureOkWithFlagActiveShouldWork(t *testing.T) { t.Parallel() + headerHash := []byte("header hash") arg := createDefaultShardArgumentWithV2Support() arg.EnableEpochsHandler = &enableEpochsHandlerMock.EnableEpochsHandlerStub{ IsFlagEnabledInEpochCalled: func(flag core.EnableEpochFlag, epoch uint32) bool { @@ -264,6 +265,7 @@ func TestInterceptedHeader_CheckValidityLeaderSignatureOkWithFlagActiveShouldWor PreviousHeaderProof: &block.HeaderProof{ PubKeysBitmap: providedPrevBitmap, AggregatedSignature: providedPrevSig, + HeaderHash: headerHash, }, } buff, _ := marshaller.Marshal(hdr) @@ -357,7 +359,7 @@ func TestInterceptedHeader_CheckAgainstFinalHeaderErrorsShouldErr(t *testing.T) assert.Equal(t, expectedErr, err) } -//------- getters +// ------- getters func TestInterceptedHeader_Getters(t *testing.T) { t.Parallel() @@ -370,7 +372,7 @@ func TestInterceptedHeader_Getters(t *testing.T) { assert.Equal(t, hash, inHdr.Hash()) } -//------- IsInterfaceNil +// ------- IsInterfaceNil func TestInterceptedHeader_IsInterfaceNil(t *testing.T) { t.Parallel() diff --git a/process/block/interceptedBlocks/interceptedMetaBlockHeader.go b/process/block/interceptedBlocks/interceptedMetaBlockHeader.go index 52edea546a0..c3f92781e7e 100644 --- a/process/block/interceptedBlocks/interceptedMetaBlockHeader.go +++ b/process/block/interceptedBlocks/interceptedMetaBlockHeader.go @@ -124,11 +124,6 @@ func (imh *InterceptedMetaHeader) CheckValidity() error { return err } - err = imh.sigVerifier.VerifyPreviousBlockProof(imh.hdr) - if err != nil { - return err - } - return imh.integrityVerifier.Verify(imh.hdr) } diff --git a/process/errors.go b/process/errors.go index da775c21ec1..ba66ec2ab93 100644 --- a/process/errors.go +++ b/process/errors.go @@ -1271,3 +1271,6 @@ var ErrMissingHeaderProof = errors.New("missing header proof") // ErrInvalidHeaderProof signals that an invalid equivalent proof has been provided var ErrInvalidHeaderProof = errors.New("invalid equivalent proof") + +// ErrUnexpectedHeaderProof signals that a header proof has been provided unexpectedly +var ErrUnexpectedHeaderProof = errors.New("unexpected header proof") diff --git a/process/headerCheck/common.go b/process/headerCheck/common.go index edd365fa63b..353c112e501 100644 --- a/process/headerCheck/common.go +++ b/process/headerCheck/common.go @@ -18,6 +18,9 @@ func ComputeConsensusGroup(header data.HeaderHandler, nodesCoordinator nodesCoor } prevRandSeed := header.GetPrevRandSeed() + if prevRandSeed == nil { + return nil, nil, process.ErrNilPrevRandSeed + } // TODO: change here with an activation flag if start of epoch block needs to be validated by the new epoch nodes epoch := header.GetEpoch() diff --git a/process/headerCheck/errors.go b/process/headerCheck/errors.go index e0d4123ae2b..b808de98518 100644 --- a/process/headerCheck/errors.go +++ b/process/headerCheck/errors.go @@ -23,3 +23,9 @@ var ErrIndexOutOfBounds = errors.New("index is out of bounds") // ErrIndexNotSelected signals that the given index is not selected var ErrIndexNotSelected = errors.New("index is not selected") + +// ErrProofShardMismatch signals that the proof shard does not match the header shard +var ErrProofShardMismatch = errors.New("proof shard mismatch") + +// ErrProofHeaderHashMismatch signals that the proof header hash does not match the header hash +var ErrProofHeaderHashMismatch = errors.New("proof header hash mismatch") diff --git a/process/headerCheck/headerSignatureVerify.go b/process/headerCheck/headerSignatureVerify.go index 94471949ba0..50bc3ff42ac 100644 --- a/process/headerCheck/headerSignatureVerify.go +++ b/process/headerCheck/headerSignatureVerify.go @@ -1,6 +1,7 @@ package headerCheck import ( + "bytes" "fmt" "math/bits" @@ -125,35 +126,48 @@ func isIndexInBitmap(index uint16, bitmap []byte) error { return nil } -func (hsv *HeaderSigVerifier) getConsensusSigners(header data.HeaderHandler, pubKeysBitmap []byte) ([][]byte, error) { - randSeed := header.GetPrevRandSeed() +func (hsv *HeaderSigVerifier) getConsensusSigners( + randSeed []byte, + shardID uint32, + epoch uint32, + startOfEpochBlock bool, + round uint64, + prevHash []byte, + pubKeysBitmap []byte, +) ([][]byte, error) { if len(pubKeysBitmap) == 0 { return nil, process.ErrNilPubKeysBitmap } - if !hsv.enableEpochsHandler.IsFlagEnabledInEpoch(common.EquivalentMessagesFlag, header.GetEpoch()) { + if !hsv.enableEpochsHandler.IsFlagEnabledInEpoch(common.EquivalentMessagesFlag, epoch) { if pubKeysBitmap[0]&1 == 0 { return nil, process.ErrBlockProposerSignatureMissing } } // TODO: remove if start of epochForConsensus block needs to be validated by the new epochForConsensus nodes - epochForConsensus := header.GetEpoch() - if header.IsStartOfEpochBlock() && epochForConsensus > 0 { + epochForConsensus := epoch + if startOfEpochBlock && epochForConsensus > 0 { epochForConsensus = epochForConsensus - 1 } _, consensusPubKeys, err := hsv.nodesCoordinator.GetConsensusValidatorsPublicKeys( randSeed, - header.GetRound(), - header.GetShardID(), + round, + shardID, epochForConsensus, ) if err != nil { return nil, err } - err = hsv.verifyConsensusSize(consensusPubKeys, header, pubKeysBitmap) + err = hsv.verifyConsensusSize( + consensusPubKeys, + pubKeysBitmap, + shardID, + startOfEpochBlock, + round, + prevHash) if err != nil { return nil, err } @@ -175,8 +189,11 @@ func getPubKeySigners(consensusPubKeys []string, pubKeysBitmap []byte) [][]byte } // VerifySignature will check if signature is correct -// TODO: Adapt header signature verification for the changes related to equivalent proofs func (hsv *HeaderSigVerifier) VerifySignature(header data.HeaderHandler) error { + if hsv.enableEpochsHandler.IsFlagEnabledInEpoch(common.EquivalentMessagesFlag, header.GetEpoch()) { + return hsv.VerifyHeaderWithProof(header) + } + headerCopy, err := hsv.copyHeaderWithoutSig(header) if err != nil { return err @@ -189,14 +206,24 @@ func (hsv *HeaderSigVerifier) VerifySignature(header data.HeaderHandler) error { bitmap := header.GetPubKeysBitmap() sig := header.GetSignature() - if hsv.enableEpochsHandler.IsFlagEnabledInEpoch(common.EquivalentMessagesFlag, headerCopy.GetEpoch()) { - headerCopy, hash, sig, bitmap, err = hsv.getPrevHeaderInfo(headerCopy) - if err != nil { - return err - } + return hsv.VerifySignatureForHash(headerCopy, hash, bitmap, sig) +} + +func verifyPrevProofForHeader(header data.HeaderHandler) error { + prevProof := header.GetPreviousProof() + if check.IfNilReflect(prevProof) { + return process.ErrNilHeaderProof } - return hsv.VerifySignatureForHash(headerCopy, hash, bitmap, sig) + if header.GetShardID() != prevProof.GetHeaderShardId() { + return ErrProofShardMismatch + } + + if !bytes.Equal(header.GetPrevHash(), prevProof.GetHeaderHash()) { + return ErrProofHeaderHashMismatch + } + + return nil } // VerifySignatureForHash will check if signature is correct for the provided hash @@ -206,7 +233,19 @@ func (hsv *HeaderSigVerifier) VerifySignatureForHash(header data.HeaderHandler, return err } - pubKeysSigners, err := hsv.getConsensusSigners(header, pubkeysBitmap) + randSeed := header.GetPrevRandSeed() + if randSeed == nil { + return process.ErrNilPrevRandSeed + } + pubKeysSigners, err := hsv.getConsensusSigners( + randSeed, + header.GetShardID(), + header.GetEpoch(), + header.IsStartOfEpochBlock(), + header.GetRound(), + header.GetPrevHash(), + pubkeysBitmap, + ) if err != nil { return err } @@ -214,17 +253,29 @@ func (hsv *HeaderSigVerifier) VerifySignatureForHash(header data.HeaderHandler, return multiSigVerifier.VerifyAggregatedSig(pubKeysSigners, hash, signature) } +// VerifyHeaderWithProof checks if the proof on the header is correct +func (hsv *HeaderSigVerifier) VerifyHeaderWithProof(header data.HeaderHandler) error { + err := verifyPrevProofForHeader(header) + if err != nil { + return err + } + + prevProof := header.GetPreviousProof() + return hsv.VerifyHeaderProof(prevProof) +} + // VerifyHeaderProof checks if the proof is correct for the header func (hsv *HeaderSigVerifier) VerifyHeaderProof(proofHandler data.HeaderProofHandler) error { if check.IfNilReflect(proofHandler) { return process.ErrNilHeaderProof } - if !hsv.enableEpochsHandler.IsFlagEnabledInEpoch(common.FixedOrderInConsensusFlag, proofHandler.GetHeaderEpoch()) { - return fmt.Errorf("%w for %s", process.ErrFlagNotActive, common.FixedOrderInConsensusFlag) + if !hsv.enableEpochsHandler.IsFlagEnabledInEpoch(common.EquivalentMessagesFlag, proofHandler.GetHeaderEpoch()) { + return fmt.Errorf("%w for flag %s", process.ErrFlagNotActive, common.EquivalentMessagesFlag) } - consensusPubKeys, err := hsv.nodesCoordinator.GetAllEligibleValidatorsPublicKeysForShard(proofHandler.GetHeaderEpoch(), proofHandler.GetHeaderShardId()) + // for the start of epoch block the consensus is taken from the previous epoch + header, err := hsv.headersPool.GetHeaderByHash(proofHandler.GetHeaderHash()) if err != nil { return err } @@ -234,69 +285,32 @@ func (hsv *HeaderSigVerifier) VerifyHeaderProof(proofHandler data.HeaderProofHan return err } - pubKeysSigners := getPubKeySigners(consensusPubKeys, proofHandler.GetPubKeysBitmap()) - - return multiSigVerifier.VerifyAggregatedSig(pubKeysSigners, proofHandler.GetHeaderHash(), proofHandler.GetAggregatedSignature()) -} - -func (hsv *HeaderSigVerifier) getPrevHeaderInfo(currentHeader data.HeaderHandler) (data.HeaderHandler, []byte, []byte, []byte, error) { - previousProof := currentHeader.GetPreviousProof() - - var sig, bitmap []byte - if previousProof != nil { - sig, bitmap = previousProof.GetAggregatedSignature(), previousProof.GetPubKeysBitmap() - } - - hash := currentHeader.GetPrevHash() - prevHeader, err := hsv.headersPool.GetHeaderByHash(hash) - if err != nil { - return nil, nil, nil, nil, err - } - - headerCopy, err := hsv.copyHeaderWithoutSig(prevHeader) - if err != nil { - return nil, nil, nil, nil, err - } - - hash, err = core.CalculateHash(hsv.marshalizer, hsv.hasher, headerCopy) + // round, prevHash and prevRandSeed could be removed when we remove fallback validation and we don't need backwards compatibility + // (e.g new binary from epoch x forward) + consensusPubKeys, err := hsv.getConsensusSigners( + header.GetPrevRandSeed(), + proofHandler.GetHeaderShardId(), + proofHandler.GetHeaderEpoch(), + header.IsStartOfEpochBlock(), + header.GetRound(), + header.GetPrevHash(), + proofHandler.GetPubKeysBitmap(), + ) if err != nil { - return nil, nil, nil, nil, err - } - - return headerCopy, hash, sig, bitmap, nil -} - -// VerifyPreviousBlockProof verifies if the structure of the header matches the expected structure in regards with the consensus flag -func (hsv *HeaderSigVerifier) VerifyPreviousBlockProof(header data.HeaderHandler) error { - previousProof := header.GetPreviousProof() - - hasProof := false - hasLeaderSignature := false - - if previousProof != nil { - previousAggregatedSignature, previousBitmap := previousProof.GetAggregatedSignature(), previousProof.GetPubKeysBitmap() - hasProof = len(previousAggregatedSignature) > 0 && len(previousBitmap) > 0 - - if len(previousBitmap) > 0 { - hasLeaderSignature = previousBitmap[0]&1 != 0 - } - } - - isFlagEnabled := hsv.enableEpochsHandler.IsFlagEnabledInEpoch(common.EquivalentMessagesFlag, header.GetEpoch()) - if isFlagEnabled && !hasProof { - return fmt.Errorf("%w, received header without proof after flag activation", process.ErrInvalidHeader) - } - if !isFlagEnabled && hasProof { - return fmt.Errorf("%w, received header with proof before flag activation", process.ErrInvalidHeader) - } - if isFlagEnabled && !hasLeaderSignature { - return fmt.Errorf("%w, received header without leader signature after flag activation", process.ErrInvalidHeader) + return err } - return nil + return multiSigVerifier.VerifyAggregatedSig(consensusPubKeys, proofHandler.GetHeaderHash(), proofHandler.GetAggregatedSignature()) } -func (hsv *HeaderSigVerifier) verifyConsensusSize(consensusPubKeys []string, header data.HeaderHandler, bitmap []byte) error { +func (hsv *HeaderSigVerifier) verifyConsensusSize( + consensusPubKeys []string, + bitmap []byte, + shardID uint32, + startOfEpochBlock bool, + round uint64, + prevHash []byte, +) error { consensusSize := len(consensusPubKeys) expectedBitmapSize := consensusSize / 8 @@ -316,7 +330,12 @@ func (hsv *HeaderSigVerifier) verifyConsensusSize(consensusPubKeys []string, hea } minNumRequiredSignatures := core.GetPBFTThreshold(consensusSize) - if hsv.fallbackHeaderValidator.ShouldApplyFallbackValidation(header) { + if hsv.fallbackHeaderValidator.ShouldApplyFallbackValidationForHeaderWith( + shardID, + startOfEpochBlock, + round, + prevHash, + ) { minNumRequiredSignatures = core.GetPBFTFallbackThreshold(consensusSize) log.Warn("HeaderSigVerifier.verifyConsensusSize: fallback validation has been applied", "minimum number of signatures required", minNumRequiredSignatures, @@ -400,7 +419,15 @@ func (hsv *HeaderSigVerifier) IsInterfaceNil() bool { func (hsv *HeaderSigVerifier) verifyRandSeed(leaderPubKey crypto.PublicKey, header data.HeaderHandler) error { prevRandSeed := header.GetPrevRandSeed() + if prevRandSeed == nil { + return process.ErrNilPrevRandSeed + } + randSeed := header.GetRandSeed() + if randSeed == nil { + return process.ErrNilRandSeed + } + return hsv.singleSigVerifier.Verify(leaderPubKey, prevRandSeed, randSeed) } diff --git a/process/headerCheck/headerSignatureVerify_test.go b/process/headerCheck/headerSignatureVerify_test.go index dd361ca8f7c..adb372ba15c 100644 --- a/process/headerCheck/headerSignatureVerify_test.go +++ b/process/headerCheck/headerSignatureVerify_test.go @@ -8,10 +8,8 @@ import ( "github.com/multiversx/mx-chain-core-go/core" "github.com/multiversx/mx-chain-core-go/data" - "github.com/multiversx/mx-chain-core-go/data/block" dataBlock "github.com/multiversx/mx-chain-core-go/data/block" crypto "github.com/multiversx/mx-chain-crypto-go" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/multiversx/mx-chain-go/common" @@ -30,16 +28,32 @@ const defaultChancesSelection = 1 var expectedErr = errors.New("expected error") func createHeaderSigVerifierArgs() *ArgsHeaderSigVerifier { + v1, _ := nodesCoordinator.NewValidator([]byte("pubKey1"), 1, defaultChancesSelection) + v2, _ := nodesCoordinator.NewValidator([]byte("pubKey1"), 1, defaultChancesSelection) return &ArgsHeaderSigVerifier{ - Marshalizer: &mock.MarshalizerMock{}, - Hasher: &hashingMocks.HasherMock{}, - NodesCoordinator: &shardingMocks.NodesCoordinatorMock{}, - MultiSigContainer: cryptoMocks.NewMultiSignerContainerMock(cryptoMocks.NewMultiSigner()), - SingleSigVerifier: &mock.SignerMock{}, - KeyGen: &mock.SingleSignKeyGenMock{}, + Marshalizer: &mock.MarshalizerMock{}, + Hasher: &hashingMocks.HasherMock{}, + NodesCoordinator: &shardingMocks.NodesCoordinatorMock{ + ComputeValidatorsGroupCalled: func(randomness []byte, round uint64, shardId uint32, epoch uint32) (leader nodesCoordinator.Validator, validators []nodesCoordinator.Validator, err error) { + return v1, []nodesCoordinator.Validator{v1, v2}, nil + }, + }, + MultiSigContainer: cryptoMocks.NewMultiSignerContainerMock(cryptoMocks.NewMultiSigner()), + SingleSigVerifier: &mock.SignerMock{}, + KeyGen: &mock.SingleSignKeyGenMock{ + PublicKeyFromByteArrayCalled: func(b []byte) (key crypto.PublicKey, err error) { + return &mock.SingleSignPublicKey{}, nil + }, + }, FallbackHeaderValidator: &testscommon.FallBackHeaderValidatorStub{}, EnableEpochsHandler: enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), - HeadersPool: &mock.HeadersCacherStub{}, + HeadersPool: &mock.HeadersCacherStub{ + GetHeaderByHashCalled: func(hash []byte) (data.HeaderHandler, error) { + return &dataBlock.Header{ + PrevRandSeed: []byte("prevRandSeed"), + }, nil + }, + }, } } @@ -145,10 +159,13 @@ func TestHeaderSigVerifier_VerifySignatureNilPrevRandSeedShouldErr(t *testing.T) args := createHeaderSigVerifierArgs() hdrSigVerifier, _ := NewHeaderSigVerifier(args) - header := &dataBlock.Header{} + header := &dataBlock.Header{ + PrevRandSeed: nil, + RandSeed: []byte("rand seed"), + } err := hdrSigVerifier.VerifyRandSeed(header) - require.Equal(t, nodesCoordinator.ErrNilRandomness, err) + require.Equal(t, process.ErrNilPrevRandSeed, err) } func TestHeaderSigVerifier_VerifyRandSeedOk(t *testing.T) { @@ -178,7 +195,10 @@ func TestHeaderSigVerifier_VerifyRandSeedOk(t *testing.T) { } args.NodesCoordinator = nc hdrSigVerifier, _ := NewHeaderSigVerifier(args) - header := &dataBlock.Header{} + header := &dataBlock.Header{ + PrevRandSeed: []byte("prev rand seed"), + RandSeed: []byte("rand seed"), + } err := hdrSigVerifier.VerifyRandSeed(header) require.Nil(t, err) @@ -213,7 +233,10 @@ func TestHeaderSigVerifier_VerifyRandSeedShouldErrWhenVerificationFails(t *testi } args.NodesCoordinator = nc hdrSigVerifier, _ := NewHeaderSigVerifier(args) - header := &dataBlock.Header{} + header := &dataBlock.Header{ + RandSeed: []byte("randSeed"), + PrevRandSeed: []byte("prevRandSeed"), + } err := hdrSigVerifier.VerifyRandSeed(header) require.Equal(t, localError, err) @@ -225,10 +248,13 @@ func TestHeaderSigVerifier_VerifyRandSeedAndLeaderSignatureNilRandomnessShouldEr args := createHeaderSigVerifierArgs() hdrSigVerifier, _ := NewHeaderSigVerifier(args) - header := &dataBlock.Header{} + header := &dataBlock.Header{ + RandSeed: nil, + PrevRandSeed: []byte("prev rand seed"), + } err := hdrSigVerifier.VerifyRandSeedAndLeaderSignature(header) - require.Equal(t, nodesCoordinator.ErrNilRandomness, err) + require.Equal(t, process.ErrNilRandSeed, err) } func TestHeaderSigVerifier_VerifyRandSeedAndLeaderSignatureVerifyShouldErrWhenValidationFails(t *testing.T) { @@ -259,7 +285,10 @@ func TestHeaderSigVerifier_VerifyRandSeedAndLeaderSignatureVerifyShouldErrWhenVa } args.NodesCoordinator = nc hdrSigVerifier, _ := NewHeaderSigVerifier(args) - header := &dataBlock.Header{} + header := &dataBlock.Header{ + RandSeed: []byte("randSeed"), + PrevRandSeed: []byte("prevRandSeed"), + } err := hdrSigVerifier.VerifyRandSeedAndLeaderSignature(header) require.Equal(t, localErr, err) @@ -299,6 +328,8 @@ func TestHeaderSigVerifier_VerifyRandSeedAndLeaderSignatureVerifyLeaderSigShould args.NodesCoordinator = nc hdrSigVerifier, _ := NewHeaderSigVerifier(args) header := &dataBlock.Header{ + RandSeed: []byte("randSeed"), + PrevRandSeed: []byte("prevRandSeed"), LeaderSignature: leaderSig, } @@ -334,22 +365,28 @@ func TestHeaderSigVerifier_VerifyRandSeedAndLeaderSignatureOk(t *testing.T) { } args.NodesCoordinator = nc hdrSigVerifier, _ := NewHeaderSigVerifier(args) - header := &dataBlock.Header{} + header := &dataBlock.Header{ + RandSeed: []byte("randSeed"), + PrevRandSeed: []byte("prevRandSeed"), + } err := hdrSigVerifier.VerifyRandSeedAndLeaderSignature(header) require.Nil(t, err) require.Equal(t, 2, count) } -func TestHeaderSigVerifier_VerifyLeaderSignatureNilRandomnessShouldErr(t *testing.T) { +func TestHeaderSigVerifier_VerifyLeaderSignatureNilPrevRandomnessShouldErr(t *testing.T) { t.Parallel() args := createHeaderSigVerifierArgs() hdrSigVerifier, _ := NewHeaderSigVerifier(args) - header := &dataBlock.Header{} + header := &dataBlock.Header{ + RandSeed: []byte("rand seed "), + PrevRandSeed: nil, + } err := hdrSigVerifier.VerifyLeaderSignature(header) - require.Equal(t, nodesCoordinator.ErrNilRandomness, err) + require.Equal(t, process.ErrNilPrevRandSeed, err) } func TestHeaderSigVerifier_VerifyLeaderSignatureVerifyShouldErrWhenValidationFails(t *testing.T) { @@ -380,7 +417,10 @@ func TestHeaderSigVerifier_VerifyLeaderSignatureVerifyShouldErrWhenValidationFai } args.NodesCoordinator = nc hdrSigVerifier, _ := NewHeaderSigVerifier(args) - header := &dataBlock.Header{} + header := &dataBlock.Header{ + RandSeed: []byte("randSeed"), + PrevRandSeed: []byte("prevRandSeed"), + } err := hdrSigVerifier.VerifyLeaderSignature(header) require.Equal(t, localErr, err) @@ -420,6 +460,8 @@ func TestHeaderSigVerifier_VerifyLeaderSignatureVerifyLeaderSigShouldErr(t *test args.NodesCoordinator = nc hdrSigVerifier, _ := NewHeaderSigVerifier(args) header := &dataBlock.Header{ + RandSeed: []byte("randSeed"), + PrevRandSeed: []byte("prevRandSeed"), LeaderSignature: leaderSig, } @@ -455,7 +497,10 @@ func TestHeaderSigVerifier_VerifyLeaderSignatureOk(t *testing.T) { } args.NodesCoordinator = nc hdrSigVerifier, _ := NewHeaderSigVerifier(args) - header := &dataBlock.Header{} + header := &dataBlock.Header{ + RandSeed: []byte("randSeed"), + PrevRandSeed: []byte("prevRandSeed"), + } err := hdrSigVerifier.VerifyLeaderSignature(header) require.Nil(t, err) @@ -467,7 +512,11 @@ func TestHeaderSigVerifier_VerifySignatureNilBitmapShouldErr(t *testing.T) { args := createHeaderSigVerifierArgs() hdrSigVerifier, _ := NewHeaderSigVerifier(args) - header := &dataBlock.Header{} + header := &dataBlock.Header{ + PubKeysBitmap: nil, + RandSeed: []byte("randSeed"), + PrevRandSeed: []byte("prevRandSeed"), + } err := hdrSigVerifier.VerifySignature(header) require.Equal(t, process.ErrNilPubKeysBitmap, err) @@ -480,6 +529,8 @@ func TestHeaderSigVerifier_VerifySignatureBlockProposerSigMissingShouldErr(t *te hdrSigVerifier, _ := NewHeaderSigVerifier(args) header := &dataBlock.Header{ PubKeysBitmap: []byte("0"), + RandSeed: []byte("randSeed"), + PrevRandSeed: []byte("prevRandSeed"), } err := hdrSigVerifier.VerifySignature(header) @@ -492,11 +543,12 @@ func TestHeaderSigVerifier_VerifySignatureNilRandomnessShouldErr(t *testing.T) { args := createHeaderSigVerifierArgs() hdrSigVerifier, _ := NewHeaderSigVerifier(args) header := &dataBlock.Header{ + PrevRandSeed: nil, PubKeysBitmap: []byte("1"), } err := hdrSigVerifier.VerifySignature(header) - require.Equal(t, nodesCoordinator.ErrNilRandomness, err) + require.Equal(t, process.ErrNilPrevRandSeed, err) } func TestHeaderSigVerifier_VerifySignatureWrongSizeBitmapShouldErr(t *testing.T) { @@ -515,6 +567,8 @@ func TestHeaderSigVerifier_VerifySignatureWrongSizeBitmapShouldErr(t *testing.T) hdrSigVerifier, _ := NewHeaderSigVerifier(args) header := &dataBlock.Header{ PubKeysBitmap: []byte("11"), + RandSeed: []byte("randSeed"), + PrevRandSeed: []byte("prevRandSeed"), } err := hdrSigVerifier.VerifySignature(header) @@ -537,6 +591,8 @@ func TestHeaderSigVerifier_VerifySignatureNotEnoughSigsShouldErr(t *testing.T) { hdrSigVerifier, _ := NewHeaderSigVerifier(args) header := &dataBlock.Header{ PubKeysBitmap: []byte("A"), + RandSeed: []byte("randSeed"), + PrevRandSeed: []byte("prevRandSeed"), } err := hdrSigVerifier.VerifySignature(header) @@ -566,6 +622,7 @@ func TestHeaderSigVerifier_VerifySignatureOk(t *testing.T) { hdrSigVerifier, _ := NewHeaderSigVerifier(args) header := &dataBlock.Header{ PubKeysBitmap: []byte("1"), + PrevRandSeed: []byte("prevRandSeed"), } err := hdrSigVerifier.VerifySignature(header) @@ -604,6 +661,7 @@ func TestHeaderSigVerifier_VerifySignatureNotEnoughSigsShouldErrWhenFallbackThre hdrSigVerifier, _ := NewHeaderSigVerifier(args) header := &dataBlock.MetaBlock{ PubKeysBitmap: []byte("C"), + PrevRandSeed: []byte("prevRandSeed"), } err := hdrSigVerifier.VerifySignature(header) @@ -640,7 +698,8 @@ func TestHeaderSigVerifier_VerifySignatureOkWhenFallbackThresholdCouldBeApplied( hdrSigVerifier, _ := NewHeaderSigVerifier(args) header := &dataBlock.MetaBlock{ - PubKeysBitmap: []byte("C"), + PubKeysBitmap: []byte{15}, + PrevRandSeed: []byte("prevRandSeed"), } err := hdrSigVerifier.VerifySignature(header) @@ -648,97 +707,14 @@ func TestHeaderSigVerifier_VerifySignatureOkWhenFallbackThresholdCouldBeApplied( require.True(t, wasCalled) } -func TestCheckHeaderHandler_VerifyPreviousBlockProof(t *testing.T) { - t.Parallel() - - t.Run("flag enabled and no proof should error", func(t *testing.T) { - t.Parallel() - - args := createHeaderSigVerifierArgs() - args.EnableEpochsHandler = &enableEpochsHandlerMock.EnableEpochsHandlerStub{ - IsFlagEnabledInEpochCalled: func(flag core.EnableEpochFlag, epoch uint32) bool { - return flag == common.EquivalentMessagesFlag - }, - } - - hdrSigVerifier, _ := NewHeaderSigVerifier(args) - - hdr := &testscommon.HeaderHandlerStub{ - GetPreviousProofCalled: func() data.HeaderProofHandler { - return nil - }, - } - err := hdrSigVerifier.VerifyPreviousBlockProof(hdr) - assert.True(t, errors.Is(err, process.ErrInvalidHeader)) - assert.True(t, strings.Contains(err.Error(), "received header without proof after flag activation")) - }) - t.Run("flag not enabled and proof should error", func(t *testing.T) { - t.Parallel() - - args := createHeaderSigVerifierArgs() - args.EnableEpochsHandler = enableEpochsHandlerMock.NewEnableEpochsHandlerStub() - - hdrSigVerifier, _ := NewHeaderSigVerifier(args) - - hdr := &testscommon.HeaderHandlerStub{ - GetPreviousProofCalled: func() data.HeaderProofHandler { - return &block.HeaderProof{ - AggregatedSignature: []byte("sig"), - PubKeysBitmap: []byte("bitmap"), - } - }, - } - err := hdrSigVerifier.VerifyPreviousBlockProof(hdr) - assert.True(t, errors.Is(err, process.ErrInvalidHeader)) - assert.True(t, strings.Contains(err.Error(), "received header with proof before flag activation")) - }) - t.Run("flag enabled and no leader signature should error", func(t *testing.T) { - t.Parallel() - - args := createHeaderSigVerifierArgs() - args.EnableEpochsHandler = &enableEpochsHandlerMock.EnableEpochsHandlerStub{ - IsFlagEnabledInEpochCalled: func(flag core.EnableEpochFlag, epoch uint32) bool { - return flag == common.EquivalentMessagesFlag - }, - } - - hdrSigVerifier, _ := NewHeaderSigVerifier(args) - - hdr := &testscommon.HeaderHandlerStub{ - GetPreviousProofCalled: func() data.HeaderProofHandler { - return &block.HeaderProof{ - AggregatedSignature: []byte("sig"), - PubKeysBitmap: []byte{0, 1, 1, 1}, - } - }, - } - err := hdrSigVerifier.VerifyPreviousBlockProof(hdr) - assert.True(t, errors.Is(err, process.ErrInvalidHeader)) - assert.True(t, strings.Contains(err.Error(), "received header without leader signature after flag activation")) - }) - t.Run("should work, flag enabled with proof", func(t *testing.T) { - t.Parallel() - - args := createHeaderSigVerifierArgs() - args.EnableEpochsHandler = &enableEpochsHandlerMock.EnableEpochsHandlerStub{ - IsFlagEnabledInEpochCalled: func(flag core.EnableEpochFlag, epoch uint32) bool { - return flag == common.EquivalentMessagesFlag - }, - } - - hdrSigVerifier, _ := NewHeaderSigVerifier(args) - - hdr := &testscommon.HeaderHandlerStub{ - GetPreviousProofCalled: func() data.HeaderProofHandler { - return &block.HeaderProof{ - AggregatedSignature: []byte("sig"), - PubKeysBitmap: []byte{1, 1, 1, 1}, - } - }, - } - err := hdrSigVerifier.VerifyPreviousBlockProof(hdr) - assert.Nil(t, err) - }) +func getFilledHeader() data.HeaderHandler { + return &dataBlock.Header{ + PrevHash: []byte("prev hash"), + PrevRandSeed: []byte("prev rand seed"), + RandSeed: []byte("rand seed"), + PubKeysBitmap: []byte{0xFF}, + LeaderSignature: []byte("leader signature"), + } } func TestHeaderSigVerifier_VerifyHeaderProof(t *testing.T) { @@ -761,29 +737,11 @@ func TestHeaderSigVerifier_VerifyHeaderProof(t *testing.T) { hdrSigVerifier, err := NewHeaderSigVerifier(createHeaderSigVerifierArgs()) require.NoError(t, err) - err = hdrSigVerifier.VerifyHeaderProof(&dataBlock.HeaderProof{}) + err = hdrSigVerifier.VerifyHeaderProof(&dataBlock.HeaderProof{ + PubKeysBitmap: []byte{3}, + }) require.True(t, errors.Is(err, process.ErrFlagNotActive)) - require.True(t, strings.Contains(err.Error(), string(common.FixedOrderInConsensusFlag))) - }) - t.Run("GetAllEligibleValidatorsPublicKeysForShard error should error", func(t *testing.T) { - t.Parallel() - - args := createHeaderSigVerifierArgs() - args.EnableEpochsHandler = &enableEpochsHandlerMock.EnableEpochsHandlerStub{ - IsFlagEnabledInEpochCalled: func(flag core.EnableEpochFlag, epoch uint32) bool { - return flag == common.FixedOrderInConsensusFlag - }, - } - args.NodesCoordinator = &shardingMocks.NodesCoordinatorStub{ - GetAllEligibleValidatorsPublicKeysForShardCalled: func(epoch uint32, shardID uint32) ([]string, error) { - return nil, expectedErr - }, - } - hdrSigVerifier, err := NewHeaderSigVerifier(args) - require.NoError(t, err) - - err = hdrSigVerifier.VerifyHeaderProof(&dataBlock.HeaderProof{}) - require.Equal(t, expectedErr, err) + require.True(t, strings.Contains(err.Error(), string(common.EquivalentMessagesFlag))) }) t.Run("GetMultiSigner error should error", func(t *testing.T) { t.Parallel() @@ -792,7 +750,7 @@ func TestHeaderSigVerifier_VerifyHeaderProof(t *testing.T) { args := createHeaderSigVerifierArgs() args.EnableEpochsHandler = &enableEpochsHandlerMock.EnableEpochsHandlerStub{ IsFlagEnabledInEpochCalled: func(flag core.EnableEpochFlag, epoch uint32) bool { - return flag == common.FixedOrderInConsensusFlag + return flag == common.EquivalentMessagesFlag }, } args.MultiSigContainer = &cryptoMocks.MultiSignerContainerStub{ @@ -812,12 +770,17 @@ func TestHeaderSigVerifier_VerifyHeaderProof(t *testing.T) { }) t.Run("should work", func(t *testing.T) { t.Parallel() - + headerHash := []byte("header hash") wasVerifyAggregatedSigCalled := false args := createHeaderSigVerifierArgs() + args.HeadersPool = &mock.HeadersCacherStub{ + GetHeaderByHashCalled: func(hash []byte) (data.HeaderHandler, error) { + return getFilledHeader(), nil + }, + } args.EnableEpochsHandler = &enableEpochsHandlerMock.EnableEpochsHandlerStub{ IsFlagEnabledInEpochCalled: func(flag core.EnableEpochFlag, epoch uint32) bool { - return flag == common.FixedOrderInConsensusFlag + return flag == common.FixedOrderInConsensusFlag || flag == common.EquivalentMessagesFlag }, } args.MultiSigContainer = &cryptoMocks.MultiSignerContainerStub{ @@ -833,7 +796,11 @@ func TestHeaderSigVerifier_VerifyHeaderProof(t *testing.T) { hdrSigVerifier, err := NewHeaderSigVerifier(args) require.NoError(t, err) - err = hdrSigVerifier.VerifyHeaderProof(&dataBlock.HeaderProof{}) + err = hdrSigVerifier.VerifyHeaderProof(&dataBlock.HeaderProof{ + PubKeysBitmap: []byte{0x3}, + AggregatedSignature: make([]byte, 10), + HeaderHash: headerHash, + }) require.NoError(t, err) require.True(t, wasVerifyAggregatedSigCalled) }) diff --git a/process/interface.go b/process/interface.go index 6a410980c35..d7cbe87825b 100644 --- a/process/interface.go +++ b/process/interface.go @@ -850,8 +850,8 @@ type InterceptedHeaderSigVerifier interface { VerifyLeaderSignature(header data.HeaderHandler) error VerifySignature(header data.HeaderHandler) error VerifySignatureForHash(header data.HeaderHandler, hash []byte, pubkeysBitmap []byte, signature []byte) error - VerifyPreviousBlockProof(header data.HeaderHandler) error VerifyHeaderProof(headerProof data.HeaderProofHandler) error + VerifyHeaderWithProof(header data.HeaderHandler) error IsInterfaceNil() bool } @@ -1204,6 +1204,7 @@ type PayableHandler interface { // FallbackHeaderValidator defines the behaviour of a component able to signal when a fallback header validation could be applied type FallbackHeaderValidator interface { + ShouldApplyFallbackValidationForHeaderWith(shardID uint32, startOfEpochBlock bool, round uint64, prevHeaderHash []byte) bool ShouldApplyFallbackValidation(headerHandler data.HeaderHandler) bool IsInterfaceNil() bool } diff --git a/process/peer/process.go b/process/peer/process.go index ccbd46dda83..97ea34fc21a 100644 --- a/process/peer/process.go +++ b/process/peer/process.go @@ -407,7 +407,7 @@ func (vs *validatorStatistics) UpdatePeerState(header data.MetaHeaderHandler, ca bitmap := previousHeader.GetPubKeysBitmap() if vs.enableEpochsHandler.IsFlagEnabledInEpoch(common.EquivalentMessagesFlag, previousHeader.GetEpoch()) { proof := previousHeader.GetPreviousProof() - if proof != nil { + if !check.IfNilReflect(proof) { bitmap = proof.GetPubKeysBitmap() } } diff --git a/testscommon/consensus/headerSigVerifierStub.go b/testscommon/consensus/headerSigVerifierStub.go index 9517d871a6a..d6f1004e9fd 100644 --- a/testscommon/consensus/headerSigVerifierStub.go +++ b/testscommon/consensus/headerSigVerifierStub.go @@ -9,7 +9,7 @@ type HeaderSigVerifierMock struct { VerifyRandSeedCalled func(header data.HeaderHandler) error VerifyLeaderSignatureCalled func(header data.HeaderHandler) error VerifySignatureForHashCalled func(header data.HeaderHandler, hash []byte, pubkeysBitmap []byte, signature []byte) error - VerifyPreviousBlockProofCalled func(header data.HeaderHandler) error + VerifyHeaderWithProofCalled func(header data.HeaderHandler) error VerifyHeaderProofCalled func(proofHandler data.HeaderProofHandler) error } @@ -58,10 +58,10 @@ func (mock *HeaderSigVerifierMock) VerifySignatureForHash(header data.HeaderHand return nil } -// VerifyPreviousBlockProof - -func (mock *HeaderSigVerifierMock) VerifyPreviousBlockProof(header data.HeaderHandler) error { - if mock.VerifyPreviousBlockProofCalled != nil { - return mock.VerifyPreviousBlockProofCalled(header) +// VerifyHeaderWithProof - +func (mock *HeaderSigVerifierMock) VerifyHeaderWithProof(header data.HeaderHandler) error { + if mock.VerifyHeaderWithProofCalled != nil { + return mock.VerifyHeaderWithProofCalled(header) } return nil diff --git a/testscommon/fallbackHeaderValidatorStub.go b/testscommon/fallbackHeaderValidatorStub.go index b769aa94976..2ba582c7118 100644 --- a/testscommon/fallbackHeaderValidatorStub.go +++ b/testscommon/fallbackHeaderValidatorStub.go @@ -6,7 +6,16 @@ import ( // FallBackHeaderValidatorStub - type FallBackHeaderValidatorStub struct { - ShouldApplyFallbackValidationCalled func(headerHandler data.HeaderHandler) bool + ShouldApplyFallbackValidationCalled func(headerHandler data.HeaderHandler) bool + ShouldApplyFallbackValidationForHeaderWithCalled func(shardID uint32, startOfEpochBlock bool, round uint64, prevHeaderHash []byte) bool +} + +// ShouldApplyFallbackValidationForHeaderWith - +func (fhvs *FallBackHeaderValidatorStub) ShouldApplyFallbackValidationForHeaderWith(shardID uint32, startOfEpochBlock bool, round uint64, prevHeaderHash []byte) bool { + if fhvs.ShouldApplyFallbackValidationForHeaderWithCalled != nil { + return fhvs.ShouldApplyFallbackValidationForHeaderWithCalled(shardID, startOfEpochBlock, round, prevHeaderHash) + } + return false } // ShouldApplyFallbackValidation -