diff --git a/consensus/spos/bls/proxy/subroundsHandler_test.go b/consensus/spos/bls/proxy/subroundsHandler_test.go index 80ee81e0829..52523aca7c9 100644 --- a/consensus/spos/bls/proxy/subroundsHandler_test.go +++ b/consensus/spos/bls/proxy/subroundsHandler_test.go @@ -81,6 +81,7 @@ func getDefaultArgumentsSubroundHandler() (*SubroundsHandlerArgs, *spos.Consensu consensusCore.SetScheduledProcessor(&consensus.ScheduledProcessorStub{}) consensusCore.SetMessageSigningHandler(&mock2.MessageSigningHandlerStub{}) consensusCore.SetPeerBlacklistHandler(&mock2.PeerBlacklistHandlerStub{}) + consensusCore.SetPeerSignatureHandler(&cryptoMocks.PeerSignatureHandlerStub{}) consensusCore.SetSigningHandler(&consensus.SigningHandlerStub{}) consensusCore.SetEnableEpochsHandler(epochsEnable) consensusCore.SetEnableRoundsHandler(&testscommon.EnableRoundsHandlerStub{}) diff --git a/consensus/spos/bls/v2/common.go b/consensus/spos/bls/v2/common.go new file mode 100644 index 00000000000..41f04a2e610 --- /dev/null +++ b/consensus/spos/bls/v2/common.go @@ -0,0 +1,27 @@ +package v2 + +import ( + "context" + "fmt" + "time" + + "github.com/multiversx/mx-chain-core-go/core" + + "github.com/multiversx/mx-chain-go/consensus/spos" +) + +func checkGoRoutinesThrottler(ctx context.Context, throttler core.Throttler) error { + for { + if throttler.CanProcess() { + break + } + + select { + case <-time.After(time.Millisecond): + continue + case <-ctx.Done(): + return fmt.Errorf("%w while checking the throttler", spos.ErrTimeIsOut) + } + } + return nil +} diff --git a/consensus/spos/bls/v2/common_test.go b/consensus/spos/bls/v2/common_test.go new file mode 100644 index 00000000000..40cd0b190b3 --- /dev/null +++ b/consensus/spos/bls/v2/common_test.go @@ -0,0 +1,90 @@ +package v2 + +import ( + "context" + "sync/atomic" + "testing" + "time" + + "github.com/stretchr/testify/assert" + + dataRetrieverMock "github.com/multiversx/mx-chain-go/dataRetriever/mock" +) + +func TestCheckGoRoutinesThrottler(t *testing.T) { + t.Parallel() + + t.Run("throttler can process should return nil immediately", func(t *testing.T) { + t.Parallel() + + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + throttler := &dataRetrieverMock.ThrottlerStub{ + CanProcessCalled: func() bool { + return true + }, + } + + err := checkGoRoutinesThrottler(ctx, throttler) + assert.Nil(t, err) + }) + + t.Run("throttler cannot process for a period of time, then can process, should return nil", func(t *testing.T) { + t.Parallel() + + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + var numCalls int32 + throttler := &dataRetrieverMock.ThrottlerStub{ + CanProcessCalled: func() bool { + return atomic.AddInt32(&numCalls, 1) >= 5 + }, + } + + err := checkGoRoutinesThrottler(ctx, throttler) + assert.Nil(t, err) + assert.GreaterOrEqual(t, atomic.LoadInt32(&numCalls), int32(5)) + }) + + t.Run("throttler cannot process should return error when context is done", func(t *testing.T) { + t.Parallel() + + ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) + defer cancel() + + var numCalls int32 + throttler := &dataRetrieverMock.ThrottlerStub{ + CanProcessCalled: func() bool { + atomic.AddInt32(&numCalls, 1) + return false + }, + } + + err := checkGoRoutinesThrottler(ctx, throttler) + assert.NotNil(t, err) + assert.ErrorContains(t, err, "time is out") + assert.ErrorContains(t, err, "while checking the throttler") + assert.Greater(t, atomic.LoadInt32(&numCalls), int32(1)) + }) + + t.Run("context already canceled and throttler cannot process should return error without retrying", func(t *testing.T) { + t.Parallel() + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + var numCalls int32 + throttler := &dataRetrieverMock.ThrottlerStub{ + CanProcessCalled: func() bool { + atomic.AddInt32(&numCalls, 1) + return false + }, + } + + err := checkGoRoutinesThrottler(ctx, throttler) + assert.NotNil(t, err) + assert.ErrorContains(t, err, "time is out") + }) +} diff --git a/consensus/spos/bls/v2/errors.go b/consensus/spos/bls/v2/errors.go index 52fadbe9ef7..d1c32ca83d2 100644 --- a/consensus/spos/bls/v2/errors.go +++ b/consensus/spos/bls/v2/errors.go @@ -22,3 +22,9 @@ var ErrNilRoundSyncController = errors.New("nil round sync controller") // ErrTooManyInvalidSigners signals that too many invalid signers were received var ErrTooManyInvalidSigners = errors.New("too many invalid signers") + +// ErrPublicKeyMismatch signals that the BLS public key in the message does not belong to the transport sender +var ErrPublicKeyMismatch = errors.New("public key does not match the message sender") + +// ErrSignerNotInConsensusGroup signals that the signer is not part of the current consensus group +var ErrSignerNotInConsensusGroup = errors.New("signer is not part of the consensus group") diff --git a/consensus/spos/bls/v2/subroundEndRound.go b/consensus/spos/bls/v2/subroundEndRound.go index 0dd66439c7d..89c65a27af0 100644 --- a/consensus/spos/bls/v2/subroundEndRound.go +++ b/consensus/spos/bls/v2/subroundEndRound.go @@ -224,11 +224,20 @@ func (sr *subroundEndRound) verifyInvalidSigner( return "", spos.ErrInvalidMessageType } + if !sr.IsNodeInConsensusGroup(string(cnsMsg.PubKey)) { + return "", ErrSignerNotInConsensusGroup + } + err = sr.MessageSigningHandler().Verify(msg) if err != nil { return "", err } + err = sr.PeerSignatureHandler().VerifyPeerSignature(cnsMsg.PubKey, msg.Peer(), cnsMsg.Signature) + if err != nil { + return "", ErrPublicKeyMismatch + } + if !bytes.Equal(headerHash, cnsMsg.BlockHeaderHash) { return "", ErrHeaderHashMismatch } diff --git a/consensus/spos/bls/v2/subroundEndRound_test.go b/consensus/spos/bls/v2/subroundEndRound_test.go index fe75cd03828..7f409d644e0 100644 --- a/consensus/spos/bls/v2/subroundEndRound_test.go +++ b/consensus/spos/bls/v2/subroundEndRound_test.go @@ -34,6 +34,7 @@ import ( "github.com/multiversx/mx-chain-go/testscommon" consensusMocks "github.com/multiversx/mx-chain-go/testscommon/consensus" "github.com/multiversx/mx-chain-go/testscommon/consensus/initializers" + "github.com/multiversx/mx-chain-go/testscommon/cryptoMocks" "github.com/multiversx/mx-chain-go/testscommon/dataRetriever" "github.com/multiversx/mx-chain-go/testscommon/enableEpochsHandlerMock" "github.com/multiversx/mx-chain-go/testscommon/p2pmocks" @@ -1898,6 +1899,43 @@ func TestVerifyInvalidSigners(t *testing.T) { require.Equal(t, expectedErr, err) }) + t.Run("peer signature binding fails should error", func(t *testing.T) { + t.Parallel() + + container := consensusMocks.InitConsensusCore() + + consensusMsg := &consensus.Message{ + BlockHeaderHash: headerHash, + PubKey: pubKey, + MsgType: int64(bls.MtSignature), + } + consensusMsgBytes, _ := container.Marshalizer().Marshal(consensusMsg) + + invalidSigners := []p2p.MessageP2P{&factory.Message{ + FromField: []byte("attackerPid"), + DataField: consensusMsgBytes, + }} + invalidSignersBytes, _ := container.Marshalizer().Marshal(invalidSigners) + + messageSigningHandler := &mock.MessageSigningHandlerStub{ + DeserializeCalled: func(messagesBytes []byte) ([]p2p.MessageP2P, error) { + return invalidSigners, nil + }, + } + container.SetMessageSigningHandler(messageSigningHandler) + + container.SetPeerSignatureHandler(&cryptoMocks.PeerSignatureHandlerStub{ + VerifyPeerSignatureCalled: func(pk []byte, pid core.PeerID, signature []byte) error { + return expectedErr + }, + }) + + sr := initSubroundEndRoundWithContainer(container, &statusHandler.AppStatusHandlerStub{}) + + _, err := sr.VerifyInvalidSigners(headerHash, invalidSignersBytes) + require.Equal(t, v2.ErrPublicKeyMismatch, err) + }) + t.Run("invalid message type should err", func(t *testing.T) { t.Parallel() @@ -1940,6 +1978,37 @@ func TestVerifyInvalidSigners(t *testing.T) { require.False(t, wasCalled) }) + t.Run("signer not in consensus group should err", func(t *testing.T) { + t.Parallel() + + container := consensusMocks.InitConsensusCore() + + unknownPubKey := []byte("unknownKey") + consensusMsg := &consensus.Message{ + PubKey: unknownPubKey, + MsgType: int64(bls.MtSignature), + } + consensusMsgBytes, _ := container.Marshalizer().Marshal(consensusMsg) + + invalidSigners := []p2p.MessageP2P{&factory.Message{ + FromField: []byte("from"), + DataField: consensusMsgBytes, + }} + invalidSignersBytes, _ := container.Marshalizer().Marshal(invalidSigners) + + messageSigningHandler := &mock.MessageSigningHandlerStub{ + DeserializeCalled: func(messagesBytes []byte) ([]p2p.MessageP2P, error) { + return invalidSigners, nil + }, + } + container.SetMessageSigningHandler(messageSigningHandler) + + sr := initSubroundEndRoundWithContainer(container, &statusHandler.AppStatusHandlerStub{}) + + _, err := sr.VerifyInvalidSigners(headerHash, invalidSignersBytes) + require.Equal(t, v2.ErrSignerNotInConsensusGroup, err) + }) + t.Run("failed to verify signature share", func(t *testing.T) { t.Parallel() diff --git a/consensus/spos/bls/v2/subroundSignature.go b/consensus/spos/bls/v2/subroundSignature.go index 4f7b864d687..76b9566c131 100644 --- a/consensus/spos/bls/v2/subroundSignature.go +++ b/consensus/spos/bls/v2/subroundSignature.go @@ -3,7 +3,6 @@ package v2 import ( "bytes" "context" - "fmt" "sync" "sync/atomic" "time" @@ -290,18 +289,7 @@ func (sr *subroundSignature) sendSignatureForManagedKey(_ context.Context, idx i } func (sr *subroundSignature) checkGoRoutinesThrottler(ctx context.Context) error { - for { - if sr.signatureThrottler.CanProcess() { - break - } - select { - case <-time.After(timeSpentBetweenChecks): - continue - case <-ctx.Done(): - return fmt.Errorf("%w while checking the throttler", spos.ErrTimeIsOut) - } - } - return nil + return checkGoRoutinesThrottler(ctx, sr.signatureThrottler) } func (sr *subroundSignature) doSignatureJobForSingleKey(_ context.Context) bool { diff --git a/consensus/spos/consensusCore.go b/consensus/spos/consensusCore.go index bcd91011125..208c8d97322 100644 --- a/consensus/spos/consensusCore.go +++ b/consensus/spos/consensusCore.go @@ -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" + crypto "github.com/multiversx/mx-chain-crypto-go" "github.com/multiversx/mx-chain-go/common" cryptoCommon "github.com/multiversx/mx-chain-go/common/crypto" @@ -40,6 +41,7 @@ type ConsensusCore struct { scheduledProcessor consensus.ScheduledProcessor messageSigningHandler consensus.P2PSigningHandler peerBlacklistHandler consensus.PeerBlacklistHandler + peerSignatureHandler crypto.PeerSignatureHandler signingHandler consensus.SigningHandler enableEpochsHandler common.EnableEpochsHandler enableRoundsHandler common.EnableRoundsHandler @@ -74,6 +76,7 @@ type ConsensusCoreArgs struct { ScheduledProcessor consensus.ScheduledProcessor MessageSigningHandler consensus.P2PSigningHandler PeerBlacklistHandler consensus.PeerBlacklistHandler + PeerSignatureHandler crypto.PeerSignatureHandler SigningHandler consensus.SigningHandler EnableEpochsHandler common.EnableEpochsHandler EnableRoundsHandler common.EnableRoundsHandler @@ -111,6 +114,7 @@ func NewConsensusCore( scheduledProcessor: args.ScheduledProcessor, messageSigningHandler: args.MessageSigningHandler, peerBlacklistHandler: args.PeerBlacklistHandler, + peerSignatureHandler: args.PeerSignatureHandler, signingHandler: args.SigningHandler, enableEpochsHandler: args.EnableEpochsHandler, enableRoundsHandler: args.EnableRoundsHandler, @@ -244,6 +248,11 @@ func (cc *ConsensusCore) PeerBlacklistHandler() consensus.PeerBlacklistHandler { return cc.peerBlacklistHandler } +// PeerSignatureHandler will return the peer signature handler +func (cc *ConsensusCore) PeerSignatureHandler() crypto.PeerSignatureHandler { + return cc.peerSignatureHandler +} + // SigningHandler will return the signing handler component func (cc *ConsensusCore) SigningHandler() consensus.SigningHandler { return cc.signingHandler @@ -364,6 +373,11 @@ func (cc *ConsensusCore) SetPeerBlacklistHandler(peerBlacklistHandler consensus. cc.peerBlacklistHandler = peerBlacklistHandler } +// SetPeerSignatureHandler sets peer signature handler +func (cc *ConsensusCore) SetPeerSignatureHandler(peerSignatureHandler crypto.PeerSignatureHandler) { + cc.peerSignatureHandler = peerSignatureHandler +} + // SetHeaderSigVerifier sets header sig verifier func (cc *ConsensusCore) SetHeaderSigVerifier(headerSigVerifier consensus.HeaderSigVerifier) { cc.headerSigVerifier = headerSigVerifier diff --git a/consensus/spos/consensusCoreValidator.go b/consensus/spos/consensusCoreValidator.go index d6c6b0997a5..6f098fdb721 100644 --- a/consensus/spos/consensusCoreValidator.go +++ b/consensus/spos/consensusCoreValidator.go @@ -76,6 +76,9 @@ func ValidateConsensusCore(container ConsensusCoreHandler) error { if check.IfNil(container.PeerBlacklistHandler()) { return ErrNilPeerBlacklistHandler } + if check.IfNil(container.PeerSignatureHandler()) { + return ErrNilPeerSignatureHandler + } if check.IfNil(container.SigningHandler()) { return ErrNilSigningHandler } diff --git a/consensus/spos/consensusCoreValidator_test.go b/consensus/spos/consensusCoreValidator_test.go index 4f34107f1cb..9089d2181c7 100644 --- a/consensus/spos/consensusCoreValidator_test.go +++ b/consensus/spos/consensusCoreValidator_test.go @@ -45,6 +45,7 @@ func initConsensusDataContainer() *spos.ConsensusCore { scheduledProcessor := &consensusMocks.ScheduledProcessorStub{} messageSigningHandler := &mock.MessageSigningHandlerStub{} peerBlacklistHandler := &mock.PeerBlacklistHandlerStub{} + peerSignatureHandler := &cryptoMocks.PeerSignatureHandlerStub{} multiSignerContainer := cryptoMocks.NewMultiSignerContainerMock(multiSignerMock) signingHandler := &consensusMocks.SigningHandlerStub{} enableEpochsHandler := &enableEpochsHandlerMock.EnableEpochsHandlerStub{} @@ -77,6 +78,7 @@ func initConsensusDataContainer() *spos.ConsensusCore { ScheduledProcessor: scheduledProcessor, MessageSigningHandler: messageSigningHandler, PeerBlacklistHandler: peerBlacklistHandler, + PeerSignatureHandler: peerSignatureHandler, SigningHandler: signingHandler, EnableEpochsHandler: enableEpochsHandler, EnableRoundsHandler: enableRoundsHandler, @@ -372,6 +374,17 @@ func TestConsensusContainerValidator_ValidateNilPeerBlacklistHandlerShouldFail(t assert.Equal(t, spos.ErrNilPeerBlacklistHandler, err) } +func TestConsensusContainerValidator_ValidateNilPeerSignatureHandlerShouldFail(t *testing.T) { + t.Parallel() + + container := initConsensusDataContainer() + container.SetPeerSignatureHandler(nil) + + err := spos.ValidateConsensusCore(container) + + assert.Equal(t, spos.ErrNilPeerSignatureHandler, err) +} + func TestConsensusContainerValidator_ValidateNilEquivalentProofPoolShouldFail(t *testing.T) { t.Parallel() diff --git a/consensus/spos/consensusCore_test.go b/consensus/spos/consensusCore_test.go index 12857b067bf..5801aff5024 100644 --- a/consensus/spos/consensusCore_test.go +++ b/consensus/spos/consensusCore_test.go @@ -40,6 +40,7 @@ func createDefaultConsensusCoreArgs() *spos.ConsensusCoreArgs { ScheduledProcessor: scheduledProcessor, MessageSigningHandler: consensusCoreMock.MessageSigningHandler(), PeerBlacklistHandler: consensusCoreMock.PeerBlacklistHandler(), + PeerSignatureHandler: consensusCoreMock.PeerSignatureHandler(), SigningHandler: consensusCoreMock.SigningHandler(), EnableEpochsHandler: consensusCoreMock.EnableEpochsHandler(), EnableRoundsHandler: consensusCoreMock.EnableRoundsHandler(), @@ -357,6 +358,20 @@ func TestConsensusCore_WithNilPeerBlacklistHandlerShouldFail(t *testing.T) { assert.Equal(t, spos.ErrNilPeerBlacklistHandler, err) } +func TestConsensusCore_WithNilPeerSignatureHandlerShouldFail(t *testing.T) { + t.Parallel() + + args := createDefaultConsensusCoreArgs() + args.PeerSignatureHandler = nil + + consensusCore, err := spos.NewConsensusCore( + args, + ) + + assert.Nil(t, consensusCore) + assert.Equal(t, spos.ErrNilPeerSignatureHandler, err) +} + func TestConsensusCore_WithNilEnableEpochsHandlerShouldFail(t *testing.T) { t.Parallel() diff --git a/consensus/spos/interface.go b/consensus/spos/interface.go index 5ffaa51198a..3cb33cc7ac5 100644 --- a/consensus/spos/interface.go +++ b/consensus/spos/interface.go @@ -9,6 +9,7 @@ import ( "github.com/multiversx/mx-chain-core-go/data/outport" "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" + crypto "github.com/multiversx/mx-chain-crypto-go" "github.com/multiversx/mx-chain-go/common" cryptoCommon "github.com/multiversx/mx-chain-go/common/crypto" @@ -45,6 +46,7 @@ type ConsensusCoreHandler interface { ScheduledProcessor() consensus.ScheduledProcessor MessageSigningHandler() consensus.P2PSigningHandler PeerBlacklistHandler() consensus.PeerBlacklistHandler + PeerSignatureHandler() crypto.PeerSignatureHandler SigningHandler() consensus.SigningHandler EnableEpochsHandler() common.EnableEpochsHandler EnableRoundsHandler() common.EnableRoundsHandler diff --git a/dataRetriever/txpool/memorytests/memory_test.go b/dataRetriever/txpool/memorytests/memory_test.go index 1a899f742ab..4980929c57d 100644 --- a/dataRetriever/txpool/memorytests/memory_test.go +++ b/dataRetriever/txpool/memorytests/memory_test.go @@ -48,7 +48,7 @@ func TestShardedTxPool_MemoryFootprint(t *testing.T) { // With larger memory footprint journals = append(journals, runScenario(t, newScenario(100000, 3, 650, "0"), memoryAssertion{290, 340}, memoryAssertion{80, 148})) - journals = append(journals, runScenario(t, newScenario(150000, 2, 650, "0"), memoryAssertion{290, 340}, memoryAssertion{90, 160})) + journals = append(journals, runScenario(t, newScenario(150000, 2, 650, "0"), memoryAssertion{290, 340}, memoryAssertion{90, 163})) journals = append(journals, runScenario(t, newScenario(300000, 1, 650, "0"), memoryAssertion{290, 340}, memoryAssertion{100, 190})) journals = append(journals, runScenario(t, newScenario(30, 10000, 650, "0"), memoryAssertion{290, 340}, memoryAssertion{60, 132})) journals = append(journals, runScenario(t, newScenario(300, 1000, 650, "0"), memoryAssertion{290, 340}, memoryAssertion{60, 148})) diff --git a/factory/consensus/consensusComponents.go b/factory/consensus/consensusComponents.go index 20be5c45b50..3bd2205ce86 100644 --- a/factory/consensus/consensusComponents.go +++ b/factory/consensus/consensusComponents.go @@ -269,6 +269,7 @@ func (ccf *consensusComponentsFactory) Create() (*consensusComponents, error) { ScheduledProcessor: ccf.scheduledProcessor, MessageSigningHandler: p2pSigningHandler, PeerBlacklistHandler: cc.peerBlacklistHandler, + PeerSignatureHandler: ccf.cryptoComponents.PeerSignatureHandler(), SigningHandler: ccf.cryptoComponents.ConsensusSigningHandler(), EnableEpochsHandler: ccf.coreComponents.EnableEpochsHandler(), EnableRoundsHandler: ccf.coreComponents.EnableRoundsHandler(), diff --git a/go.mod b/go.mod index 8ca0e6c5c89..46a90221854 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/multiversx/mx-chain-scenario-go v1.6.0 github.com/multiversx/mx-chain-storage-go v1.1.2-0.20260608080818-1fde35395146 github.com/multiversx/mx-chain-vm-common-go v1.6.7 - github.com/multiversx/mx-chain-vm-go v1.5.45 + github.com/multiversx/mx-chain-vm-go v1.6.1-0.20260709131117-b8afa5c1796f github.com/multiversx/mx-chain-vm-v1_2-go v1.2.69 github.com/multiversx/mx-chain-vm-v1_3-go v1.3.70 github.com/multiversx/mx-chain-vm-v1_4-go v1.4.99 diff --git a/go.sum b/go.sum index 28a0b77d4a0..33eafaf0605 100644 --- a/go.sum +++ b/go.sum @@ -415,8 +415,8 @@ github.com/multiversx/mx-chain-storage-go v1.1.2-0.20260608080818-1fde35395146 h github.com/multiversx/mx-chain-storage-go v1.1.2-0.20260608080818-1fde35395146/go.mod h1:o6Jm7cjfPmcc6XpyihYWrd6sx3sgqwurrunw3ZrfyxI= github.com/multiversx/mx-chain-vm-common-go v1.6.7 h1:oX2/RMXdhqUkJSebK+cosknBjNBX0DFAEDR6ZqNTN80= github.com/multiversx/mx-chain-vm-common-go v1.6.7/go.mod h1:Lc7r4VDPYRDS0CVIaWAoLtf3YQn6PZEYHv4QtaOE2Z0= -github.com/multiversx/mx-chain-vm-go v1.5.45 h1:0JBB/imgI8wa6muXtdGMDrW685sdsRwH/+gMPuX96OU= -github.com/multiversx/mx-chain-vm-go v1.5.45/go.mod h1:Qc2Sckw+EfQwnapkzghFfhuUAOGv29oSZgvj8LJ+xWQ= +github.com/multiversx/mx-chain-vm-go v1.6.1-0.20260709131117-b8afa5c1796f h1:de4qEkVPj2efb4tprAN+rG03eUUmhPFdTJMZpRnxVLg= +github.com/multiversx/mx-chain-vm-go v1.6.1-0.20260709131117-b8afa5c1796f/go.mod h1:Qc2Sckw+EfQwnapkzghFfhuUAOGv29oSZgvj8LJ+xWQ= github.com/multiversx/mx-chain-vm-v1_2-go v1.2.69 h1:5gSR3IMw1mcp/v5oO+vZ5YOyWO8w7O2qKhCKNPwsWNE= github.com/multiversx/mx-chain-vm-v1_2-go v1.2.69/go.mod h1:Qqn+B6IBlOi5huybKlvqNYDMsAHognVI6a6uiSZvaj0= github.com/multiversx/mx-chain-vm-v1_3-go v1.3.70 h1:UnTw+KJcLLqkqTR6EoZksqiM8PP4/BI6RcJlx25H9hc= diff --git a/process/block/headerForBlock/headersForBlock.go b/process/block/headerForBlock/headersForBlock.go index f3f3a3863a6..4a5d147ab91 100644 --- a/process/block/headerForBlock/headersForBlock.go +++ b/process/block/headerForBlock/headersForBlock.go @@ -581,7 +581,14 @@ func (hfb *headersForBlock) requestMissingFinalityAttestingHeaders( false, ) - hfb.requestProofIfNeeded(headersHashes[index], headers[index]) + if !hfb.enableEpochsHandler.IsFlagEnabledInEpoch(common.AndromedaFlag, headers[index].GetEpoch()) { + continue + } + + _, err = hfb.dataPool.Proofs().GetProofByNonce(i, shardID) + if err != nil { + hfb.requestProofIfNeeded(headersHashes[index], headers[index]) + } } } diff --git a/process/block/headerForBlock/headersForBlock_test.go b/process/block/headerForBlock/headersForBlock_test.go index 9abb4912ab6..da6b718179a 100644 --- a/process/block/headerForBlock/headersForBlock_test.go +++ b/process/block/headerForBlock/headersForBlock_test.go @@ -973,6 +973,9 @@ func TestHeadersForBlock_RequestMissingFinalityAttestingShardHeaders(t *testing. HasProofCalled: func(shardID uint32, headerHash []byte) bool { return false // no proof available for the attestation header }, + GetProofByNonceCalled: func(headerNonce uint64, shardID uint32) (data.HeaderProofHandler, error) { + return nil, errors.New("GetProofByNonce error") + }, }) args.BlockTracker = &mock.BlockTrackerStub{ diff --git a/testscommon/consensus/mockTestInitializer.go b/testscommon/consensus/mockTestInitializer.go index ccf3d403c5f..618ca01f8d4 100644 --- a/testscommon/consensus/mockTestInitializer.go +++ b/testscommon/consensus/mockTestInitializer.go @@ -229,6 +229,7 @@ func InitConsensusCoreWithMultiSigner(multiSigner crypto.MultiSignerV2) *spos.Co scheduledProcessor := &ScheduledProcessorStub{} messageSigningHandler := &mock.MessageSigningHandlerStub{} peerBlacklistHandler := &mock.PeerBlacklistHandlerStub{} + peerSignatureHandler := &cryptoMocks.PeerSignatureHandlerStub{} multiSignerContainer := cryptoMocks.NewMultiSignerContainerMock(multiSigner) signingHandler := &SigningHandlerStub{} enableEpochsHandler := &enableEpochsHandlerMock.EnableEpochsHandlerStub{} @@ -260,6 +261,7 @@ func InitConsensusCoreWithMultiSigner(multiSigner crypto.MultiSignerV2) *spos.Co ScheduledProcessor: scheduledProcessor, MessageSigningHandler: messageSigningHandler, PeerBlacklistHandler: peerBlacklistHandler, + PeerSignatureHandler: peerSignatureHandler, SigningHandler: signingHandler, EnableEpochsHandler: enableEpochsHandler, EnableRoundsHandler: enableRoundsHandler, diff --git a/trie/extensionNode.go b/trie/extensionNode.go index 0c1a657665b..1467251541b 100644 --- a/trie/extensionNode.go +++ b/trie/extensionNode.go @@ -695,6 +695,10 @@ func (en *extensionNode) getNextHashAndKey(key []byte) (bool, []byte, []byte) { return false, nil, nil } + if len(en.Key) > len(key) || !bytes.HasPrefix(key, en.Key) { + return false, nil, nil + } + nextKey := key[len(en.Key):] wantHash := en.EncodedChild diff --git a/trie/extensionNode_test.go b/trie/extensionNode_test.go index b68d9f14d79..1c79a81e9fc 100644 --- a/trie/extensionNode_test.go +++ b/trie/extensionNode_test.go @@ -987,6 +987,26 @@ func TestExtensionNode_getNextHashAndKeyNilNode(t *testing.T) { assert.Nil(t, nextKey) } +func TestExtensionNode_getNextHashAndKeyInvalidKeyShouldNotAdvance(t *testing.T) { + t.Parallel() + + _, collapsedEn := getEnAndCollapsedEn() + + collapsedEn.Key = []byte("dog") + proofVerified, nextHash, nextKey := collapsedEn.getNextHashAndKey([]byte("do")) + + assert.False(t, proofVerified) + assert.Nil(t, nextHash) + assert.Nil(t, nextKey) + + collapsedEn.Key = []byte("dog") + proofVerified, nextHash, nextKey = collapsedEn.getNextHashAndKey([]byte("cat")) + + assert.False(t, proofVerified) + assert.Nil(t, nextHash) + assert.Nil(t, nextKey) +} + func TestExtensionNode_SizeInBytes(t *testing.T) { t.Parallel() diff --git a/trie/node.go b/trie/node.go index f15f182c1cb..caf3227b186 100644 --- a/trie/node.go +++ b/trie/node.go @@ -3,6 +3,7 @@ package trie import ( "context" + "fmt" "runtime/debug" "time" @@ -197,12 +198,34 @@ func decodeNode(encNode []byte, marshalizer marshal.Marshalizer, hasher hashing. return nil, err } + err = validateDecodedNode(newNode) + if err != nil { + return nil, err + } + newNode.setMarshalizer(marshalizer) newNode.setHasher(hasher) return newNode, nil } +func validateDecodedNode(n node) error { + bn, ok := n.(*branchNode) + if !ok { + return nil + } + + if len(bn.EncodedChildren) != nrOfChildren { + return fmt.Errorf("%w for EncodedChildren, len is %d", ErrInvalidEncoding, len(bn.EncodedChildren)) + } + + if len(bn.ChildrenVersion) != 0 && len(bn.ChildrenVersion) != nrOfChildren { + return fmt.Errorf("%w for ChildrenVersion, len is %d", ErrInvalidEncoding, len(bn.ChildrenVersion)) + } + + return nil +} + func getEmptyNodeOfType(t byte) (node, error) { switch t { case extension: