diff --git a/consensus/interface.go b/consensus/interface.go index 7c6c4ad5714..0ea983af1d9 100644 --- a/consensus/interface.go +++ b/consensus/interface.go @@ -24,6 +24,7 @@ type RoundHandler interface { TimeDuration() time.Duration RemainingTime(startTime time.Time, maxTime time.Duration) time.Duration GetTimeStampForRound(round uint64) uint64 + ComputeCurrentRound() int64 IsInterfaceNil() bool } diff --git a/consensus/round/round.go b/consensus/round/round.go index e8dfe6f6d7e..9b889b3ef46 100644 --- a/consensus/round/round.go +++ b/consensus/round/round.go @@ -83,6 +83,14 @@ func NewRound(args ArgsRound) (*round, error) { // UpdateRound updates the index and the time stamp of the round depending on the genesis time and the current time given func (rnd *round) UpdateRound(genesisTimeStamp time.Time, currentTimeStamp time.Time) { + baseTimeStamp, roundDuration, startRound := rnd.getBaseInfo(genesisTimeStamp, currentTimeStamp) + rnd.updateRound(baseTimeStamp, currentTimeStamp, startRound, roundDuration) +} + +func (rnd *round) getBaseInfo( + genesisTimeStamp time.Time, + currentTimeStamp time.Time, +) (time.Time, time.Duration, int64) { baseTimeStamp := rnd.supernovaGenesisTimeStamp roundDuration := rnd.supernovaTimeDuration startRound := rnd.supernovaStartRound @@ -95,7 +103,20 @@ func (rnd *round) UpdateRound(genesisTimeStamp time.Time, currentTimeStamp time. startRound = rnd.startRound } - rnd.updateRound(baseTimeStamp, currentTimeStamp, startRound, roundDuration) + return baseTimeStamp, roundDuration, startRound +} + +func getIndex( + genesisTimeStamp time.Time, + currentTimeStamp time.Time, + roundDuration time.Duration, + startRound int64, +) (int64, int64) { + delta := currentTimeStamp.Sub(genesisTimeStamp).Nanoseconds() + + index := int64(math.Floor(float64(delta)/float64(roundDuration.Nanoseconds()))) + startRound + + return index, delta } func (rnd *round) isSupernovaRoundActivated() bool { @@ -134,9 +155,7 @@ func (rnd *round) updateRound( startRound int64, roundDuration time.Duration, ) { - delta := currentTimeStamp.Sub(genesisTimeStamp).Nanoseconds() - - index := int64(math.Floor(float64(delta)/float64(roundDuration.Nanoseconds()))) + startRound + index, delta := getIndex(genesisTimeStamp, currentTimeStamp, roundDuration, startRound) rnd.Lock() if rnd.index != index { @@ -226,6 +245,16 @@ func (rnd *round) GetTimeStampForRound(round uint64) uint64 { return uint64(roundTimeStampMs) } +// ComputeCurrentRound computes the round that should match the current timestamp +func (rnd *round) ComputeCurrentRound() int64 { + genesisTimeStamp := rnd.genesisTimeStamp + currentTimeStamp := rnd.syncTimer.CurrentTime() + timeStamp, roundDuration, startRound := rnd.getBaseInfo(genesisTimeStamp, currentTimeStamp) + index, _ := getIndex(timeStamp, currentTimeStamp, roundDuration, startRound) + + return index +} + // IsInterfaceNil returns true if there is no value under the interface func (rnd *round) IsInterfaceNil() bool { return rnd == nil diff --git a/consensus/round/round_test.go b/consensus/round/round_test.go index 3aa2611e515..de26a0f98a2 100644 --- a/consensus/round/round_test.go +++ b/consensus/round/round_test.go @@ -697,6 +697,74 @@ func TestRound_Concurrency(t *testing.T) { }) } +func TestRound_ComputeCurrentRound(t *testing.T) { + t.Parallel() + + t.Run("before supernova should return correct round", func(t *testing.T) { + t.Parallel() + + genesisTime := time.Now() + currentTime := genesisTime.Add(3 * roundTimeDuration) + + syncTimerMock := &consensusMocks.SyncTimerMock{ + CurrentTimeCalled: func() time.Time { + return currentTime + }, + } + + args := createDefaultRoundArgs() + args.GenesisTimeStamp = genesisTime + args.SupernovaGenesisTimeStamp = genesisTime.Add(10 * roundTimeDuration) + args.SyncTimer = syncTimerMock + + rnd, err := round.NewRound(args) + require.Nil(t, err) + + computedRound := rnd.ComputeCurrentRound() + assert.Equal(t, int64(3), computedRound) + }) + + t.Run("after supernova should return correct round", func(t *testing.T) { + t.Parallel() + + genesisTime := time.Now() + roundDuration := 10 * time.Millisecond + supernovaRoundDuration := 5 * time.Millisecond + supernovaStartRound := int64(5) + supernovaGenesisTime := genesisTime.Add(time.Duration(supernovaStartRound) * roundDuration) + + // current time is 3 supernova rounds after supernova genesis + currentTime := supernovaGenesisTime.Add(3 * supernovaRoundDuration) + + syncTimerMock := &consensusMocks.SyncTimerMock{ + CurrentTimeCalled: func() time.Time { + return currentTime + }, + } + + args := createDefaultRoundArgs() + args.GenesisTimeStamp = genesisTime + args.SupernovaGenesisTimeStamp = supernovaGenesisTime + args.RoundTimeDuration = roundDuration + args.SupernovaTimeDuration = supernovaRoundDuration + args.SupernovaStartRound = supernovaStartRound + args.CurrentTimeStamp = currentTime + args.SyncTimer = syncTimerMock + args.EnableRoundsHandler = &testscommon.EnableRoundsHandlerStub{ + IsFlagEnabledInRoundCalled: func(flag common.EnableRoundFlag, round uint64) bool { + return flag == common.SupernovaRoundFlag && round >= uint64(supernovaStartRound) + }, + } + + rnd, err := round.NewRound(args) + require.Nil(t, err) + + // delta from supernovaGenesis = 3*5ms = 15ms, index = floor(15ms/5ms) + 5 = 3 + 5 = 8 + computedRound := rnd.ComputeCurrentRound() + assert.Equal(t, int64(8), computedRound) + }) +} + func TestRound_GetTimeStampForRound(t *testing.T) { t.Parallel() diff --git a/consensus/spos/worker.go b/consensus/spos/worker.go index 87588618611..68478463604 100644 --- a/consensus/spos/worker.go +++ b/consensus/spos/worker.go @@ -37,7 +37,7 @@ const sleepTime = 5 * time.Millisecond const redundancySingleKeySteppedIn = "single-key node stepped in" type blockProcessorWithPool interface { - RemoveHeaderFromPool(headerHash []byte) + RemoveHeaderFromPool(headerNonce uint64) } // Worker defines the data needed by spos to communicate between nodes which are in the validators group @@ -960,7 +960,7 @@ func (wrk *Worker) removeConsensusHeaderFromPool() { return } - blockProcessorWithPoolAccess.RemoveHeaderFromPool(headerHash) + blockProcessorWithPoolAccess.RemoveHeaderFromPool(header.GetNonce()) wrk.forkDetector.RemoveHeader(header.GetNonce(), headerHash) } diff --git a/consensus/spos/worker_test.go b/consensus/spos/worker_test.go index 819a4dacc2f..a4b7f379a4e 100644 --- a/consensus/spos/worker_test.go +++ b/consensus/spos/worker_test.go @@ -2208,7 +2208,7 @@ func TestWorker_ExtendShouldNotRemoveConsensusHeaderFromPoolsWhenAsyncExecutionI RevertCurrentBlockCalled: func() { revertCalled = true }, - RemoveHeaderFromPoolCalled: func(headerHash []byte) { + RemoveHeaderFromPoolCalled: func(_ uint64) { removeHeaderFromPoolCalled = true }, } @@ -2251,9 +2251,9 @@ func TestWorker_ExtendShouldRemoveConsensusHeaderFromPoolsWhenAsyncExecutionIsDi RevertCurrentBlockCalled: func() { revertCalled = true }, - RemoveHeaderFromPoolCalled: func(hash []byte) { + RemoveHeaderFromPoolCalled: func(nonce uint64) { removeHeaderFromPoolCalled = true - require.Equal(t, headerHash, hash) + require.Equal(t, header.GetNonce(), nonce) }, } wrk.SetBlockProcessor(blockProcessor) diff --git a/epochStart/mock/rounderStub.go b/epochStart/mock/rounderStub.go index c1d6b86675a..a67288b9041 100644 --- a/epochStart/mock/rounderStub.go +++ b/epochStart/mock/rounderStub.go @@ -8,11 +8,13 @@ import ( type RoundHandlerStub struct { RoundIndex int64 - IndexCalled func() int64 - TimeDurationCalled func() time.Duration - TimeStampCalled func() time.Time - UpdateRoundCalled func(time.Time, time.Time) - RemainingTimeCalled func(startTime time.Time, maxTime time.Duration) time.Duration + IndexCalled func() int64 + TimeDurationCalled func() time.Duration + TimeStampCalled func() time.Time + UpdateRoundCalled func(time.Time, time.Time) + RemainingTimeCalled func(startTime time.Time, maxTime time.Duration) time.Duration + GetTimeStampForRoundCalled func(round uint64) uint64 + ComputeCurrentRoundCalled func() int64 } // Index - @@ -61,6 +63,24 @@ func (rndm *RoundHandlerStub) RemainingTime(startTime time.Time, maxTime time.Du return 4000 * time.Millisecond } +// GetTimeStampForRound - +func (rndm *RoundHandlerStub) GetTimeStampForRound(round uint64) uint64 { + if rndm.GetTimeStampForRoundCalled != nil { + return rndm.GetTimeStampForRoundCalled(round) + } + + return uint64(time.Unix(0, 0).UnixMilli()) +} + +// ComputeCurrentRound - +func (rndm *RoundHandlerStub) ComputeCurrentRound() int64 { + if rndm.ComputeCurrentRoundCalled != nil { + return rndm.ComputeCurrentRoundCalled() + } + + return rndm.RoundIndex +} + // IsInterfaceNil returns true if there is no value under the interface func (rndm *RoundHandlerStub) IsInterfaceNil() bool { return rndm == nil diff --git a/integrationTests/mock/roundHandlerMock.go b/integrationTests/mock/roundHandlerMock.go index 8051a909e01..5a42cb6a16d 100644 --- a/integrationTests/mock/roundHandlerMock.go +++ b/integrationTests/mock/roundHandlerMock.go @@ -4,11 +4,12 @@ import "time" // RoundHandlerMock - type RoundHandlerMock struct { - IndexField int64 - TimeStampField time.Time - TimeDurationField time.Duration - RemainingTimeField time.Duration - BeforeGenesisCalled func() bool + IndexField int64 + TimeStampField time.Time + TimeDurationField time.Duration + RemainingTimeField time.Duration + BeforeGenesisCalled func() bool + ComputeCurrentRoundCalled func() int64 } // BeforeGenesis - @@ -58,6 +59,15 @@ func (mock *RoundHandlerMock) GetTimeStampForRound(round uint64) uint64 { return round * uint64(mock.TimeDuration().Milliseconds()) } +// ComputeCurrentRound - +func (mock *RoundHandlerMock) ComputeCurrentRound() int64 { + if mock.ComputeCurrentRoundCalled != nil { + return mock.ComputeCurrentRoundCalled() + } + + return mock.IndexField +} + // IsInterfaceNil - func (mock *RoundHandlerMock) IsInterfaceNil() bool { return mock == nil diff --git a/integrationTests/testProcessorNode.go b/integrationTests/testProcessorNode.go index 4db620e0d6e..6bfe1363f19 100644 --- a/integrationTests/testProcessorNode.go +++ b/integrationTests/testProcessorNode.go @@ -3556,7 +3556,10 @@ func (tpn *TestProcessorNode) MiniBlocksPresent(hashes [][]byte) bool { } func (tpn *TestProcessorNode) initRoundHandler(roundTime time.Duration) { - tpn.RoundHandler = &mock.RoundHandlerMock{TimeDurationField: roundTime} + tpn.RoundHandler = &mock.RoundHandlerMock{ + TimeDurationField: roundTime, + RemainingTimeField: roundTime, + } } func (tpn *TestProcessorNode) initRequestedItemsHandler() { diff --git a/node/chainSimulator/components/manualRoundHandler.go b/node/chainSimulator/components/manualRoundHandler.go index f5a3accd792..b7453f08ffb 100644 --- a/node/chainSimulator/components/manualRoundHandler.go +++ b/node/chainSimulator/components/manualRoundHandler.go @@ -124,6 +124,11 @@ func (handler *manualRoundHandler) GetTimeStampForRound(round uint64) uint64 { } +// ComputeCurrentRound returns the current index +func (handler *manualRoundHandler) ComputeCurrentRound() int64 { + return handler.index +} + // IsInterfaceNil returns true if there is no value under the interface func (handler *manualRoundHandler) IsInterfaceNil() bool { return handler == nil diff --git a/node/mock/rounderMock.go b/node/mock/rounderMock.go index 9cf1f1a4f42..06b173d0fea 100644 --- a/node/mock/rounderMock.go +++ b/node/mock/rounderMock.go @@ -15,6 +15,15 @@ type RoundHandlerMock struct { RemainingTimeCalled func(startTime time.Time, maxTime time.Duration) time.Duration BeforeGenesisCalled func() bool GetTimeStampForRoundCalled func(round uint64) uint64 + ComputeCurrentRoundCalled func() int64 +} + +// ComputeCurrentRound - +func (rndm *RoundHandlerMock) ComputeCurrentRound() int64 { + if rndm.ComputeCurrentRoundCalled != nil { + return rndm.ComputeCurrentRoundCalled() + } + return 0 } // BeforeGenesis - diff --git a/process/block/baseProcess.go b/process/block/baseProcess.go index 993c6bde9f5..180060a2df3 100644 --- a/process/block/baseProcess.go +++ b/process/block/baseProcess.go @@ -2543,9 +2543,9 @@ func (bp *baseProcessor) restoreBlockBody(headerHandler data.HeaderHandler, body } // RemoveHeaderFromPool removes the header from the pool -func (bp *baseProcessor) RemoveHeaderFromPool(headerHash []byte) { +func (bp *baseProcessor) RemoveHeaderFromPool(headerNonce uint64) { headersPool := bp.dataPool.Headers() - headersPool.RemoveHeaderByHash(headerHash) + headersPool.RemoveHeaderByNonceAndShardId(headerNonce, bp.shardCoordinator.SelfId()) } // RestoreBlockBodyIntoPools restores the block body into associated pools diff --git a/process/block/interceptedBlocks/argInterceptedBlockHeader.go b/process/block/interceptedBlocks/argInterceptedBlockHeader.go index 3e763e64ce4..119a92e1958 100644 --- a/process/block/interceptedBlocks/argInterceptedBlockHeader.go +++ b/process/block/interceptedBlocks/argInterceptedBlockHeader.go @@ -3,6 +3,7 @@ package interceptedBlocks import ( "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" + "github.com/multiversx/mx-chain-go/p2p" "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/process" @@ -21,4 +22,5 @@ type ArgInterceptedBlockHeader struct { EpochStartTrigger process.EpochStartTriggerHandler EnableEpochsHandler common.EnableEpochsHandler EpochChangeGracePeriodHandler common.EpochChangeGracePeriodHandler + BroadcastMethod p2p.BroadcastMethod } diff --git a/process/block/interceptedBlocks/interceptedBlockHeader.go b/process/block/interceptedBlocks/interceptedBlockHeader.go index 255e32ef5df..0d7224f76fe 100644 --- a/process/block/interceptedBlocks/interceptedBlockHeader.go +++ b/process/block/interceptedBlocks/interceptedBlockHeader.go @@ -7,6 +7,7 @@ import ( "github.com/multiversx/mx-chain-core-go/data" "github.com/multiversx/mx-chain-core-go/data/block" "github.com/multiversx/mx-chain-core-go/hashing" + "github.com/multiversx/mx-chain-go/p2p" logger "github.com/multiversx/mx-chain-logger-go" "github.com/multiversx/mx-chain-go/common" @@ -31,6 +32,7 @@ type InterceptedHeader struct { epochStartTrigger process.EpochStartTriggerHandler enableEpochsHandler common.EnableEpochsHandler epochChangeGracePeriodHandler common.EpochChangeGracePeriodHandler + broadcastMethod p2p.BroadcastMethod } // NewInterceptedHeader creates a new instance of InterceptedHeader struct @@ -55,6 +57,7 @@ func NewInterceptedHeader(arg *ArgInterceptedBlockHeader) (*InterceptedHeader, e epochStartTrigger: arg.EpochStartTrigger, enableEpochsHandler: arg.EnableEpochsHandler, epochChangeGracePeriodHandler: arg.EpochChangeGracePeriodHandler, + broadcastMethod: arg.BroadcastMethod, } inHdr.processFields(arg.HdrBuff) @@ -154,9 +157,11 @@ func (inHdr *InterceptedHeader) integrity() error { } } - err = inHdr.validityAttester.CheckBlockAgainstRoundHandler(inHdr.HeaderHandler()) - if err != nil { - return err + if inHdr.broadcastMethod == p2p.Broadcast { + err = inHdr.validityAttester.CheckBlockAgainstRoundHandler(inHdr.HeaderHandler()) + if err != nil { + return err + } } err = checkMiniBlocksHeaders(inHdr.hdr.GetMiniBlockHeaderHandlers(), inHdr.shardCoordinator) diff --git a/process/block/interceptedBlocks/interceptedBlockHeader_test.go b/process/block/interceptedBlocks/interceptedBlockHeader_test.go index 24ce863d610..cec8e821d04 100644 --- a/process/block/interceptedBlocks/interceptedBlockHeader_test.go +++ b/process/block/interceptedBlocks/interceptedBlockHeader_test.go @@ -10,6 +10,7 @@ import ( "github.com/multiversx/mx-chain-core-go/data" dataBlock "github.com/multiversx/mx-chain-core-go/data/block" "github.com/multiversx/mx-chain-core-go/marshal" + "github.com/multiversx/mx-chain-go/p2p" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -45,6 +46,7 @@ func createDefaultShardArgument() *interceptedBlocks.ArgInterceptedBlockHeader { EpochStartTrigger: &mock.EpochStartTriggerStub{}, EnableEpochsHandler: &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, EpochChangeGracePeriodHandler: gracePeriod, + BroadcastMethod: p2p.Broadcast, } hdr := createMockShardHeader() @@ -65,6 +67,7 @@ func createDefaultShardArgumentWithV2Support() *interceptedBlocks.ArgIntercepted EpochStartTrigger: &mock.EpochStartTriggerStub{}, EnableEpochsHandler: &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, EpochChangeGracePeriodHandler: gracePeriod, + BroadcastMethod: p2p.Broadcast, } hdr := createMockShardHeader() arg.HdrBuff, _ = arg.Marshalizer.Marshal(hdr) @@ -113,6 +116,7 @@ func createDefaultShardArgumentWithV3Support() *interceptedBlocks.ArgIntercepted }, }, EpochChangeGracePeriodHandler: gracePeriod, + BroadcastMethod: p2p.Broadcast, } hdr := createMockShardHeaderV3() arg.HdrBuff, _ = arg.Marshalizer.Marshal(hdr) @@ -639,6 +643,13 @@ func TestInterceptedHeader_CheckValidityShouldWorkHeaderV3(t *testing.T) { t.Parallel() arg := createDefaultShardArgumentWithV3Support() + arg.BroadcastMethod = p2p.Direct + arg.ValidityAttester = &mock.ValidityAttesterStub{ + CheckBlockAgainstRoundHandlerCalled: func(headerHandler data.HeaderHandler) error { + require.Fail(t, "should not be called") + return nil + }, + } inHdr, err := interceptedBlocks.NewInterceptedHeader(arg) assert.Nil(t, err) assert.NotNil(t, inHdr) diff --git a/process/block/interceptedBlocks/interceptedEquivalentProof.go b/process/block/interceptedBlocks/interceptedEquivalentProof.go index 3ab90be39c1..903f2fba70d 100644 --- a/process/block/interceptedBlocks/interceptedEquivalentProof.go +++ b/process/block/interceptedBlocks/interceptedEquivalentProof.go @@ -10,6 +10,7 @@ import ( "github.com/multiversx/mx-chain-core-go/data/block" "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" + "github.com/multiversx/mx-chain-go/p2p" logger "github.com/multiversx/mx-chain-logger-go" "github.com/multiversx/mx-chain-go/common" @@ -34,6 +35,7 @@ type ArgInterceptedEquivalentProof struct { ProofSizeChecker common.FieldsSizeChecker KeyRWMutexHandler sync.KeyRWMutexHandler ValidityAttester process.ValidityAttester + BroadcastMethod p2p.BroadcastMethod } type interceptedEquivalentProof struct { @@ -48,6 +50,7 @@ type interceptedEquivalentProof struct { proofSizeChecker common.FieldsSizeChecker km sync.KeyRWMutexHandler validityAttester process.ValidityAttester + broadcastMethod p2p.BroadcastMethod } // NewInterceptedEquivalentProof returns a new instance of interceptedEquivalentProof @@ -57,7 +60,7 @@ func NewInterceptedEquivalentProof(args ArgInterceptedEquivalentProof) (*interce return nil, err } - equivalentProof, err := createEquivalentProof(args.Marshaller, args.DataBuff) + equivalentProof, err := createEquivalentProof(args.Marshaller, args.DataBuff, args.BroadcastMethod) if err != nil { return nil, err } @@ -76,6 +79,7 @@ func NewInterceptedEquivalentProof(args ArgInterceptedEquivalentProof) (*interce hash: hash, km: args.KeyRWMutexHandler, validityAttester: args.ValidityAttester, + broadcastMethod: args.BroadcastMethod, }, nil } @@ -114,7 +118,7 @@ func checkArgInterceptedEquivalentProof(args ArgInterceptedEquivalentProof) erro return nil } -func createEquivalentProof(marshaller marshal.Marshalizer, buff []byte) (*block.HeaderProof, error) { +func createEquivalentProof(marshaller marshal.Marshalizer, buff []byte, broadcastMethod p2p.BroadcastMethod) (*block.HeaderProof, error) { headerProof := &block.HeaderProof{} err := marshaller.Unmarshal(headerProof, buff) if err != nil { @@ -130,6 +134,7 @@ func createEquivalentProof(marshaller marshal.Marshalizer, buff []byte) (*block. "bitmap", logger.DisplayByteSlice(headerProof.PubKeysBitmap), "signature", logger.DisplayByteSlice(headerProof.AggregatedSignature), "isEpochStart", headerProof.IsStartOfEpoch, + "broadcastMethod", broadcastMethod, ) return headerProof, nil @@ -164,9 +169,11 @@ func (iep *interceptedEquivalentProof) CheckValidity() error { } } - err = iep.validityAttester.CheckProofAgainstRoundHandler(iep.proof) - if err != nil { - return err + if iep.broadcastMethod == p2p.Broadcast { + err = iep.validityAttester.CheckProofAgainstRoundHandler(iep.proof) + if err != nil { + return err + } } headerHash := string(iep.proof.GetHeaderHash()) diff --git a/process/block/interceptedBlocks/interceptedEquivalentProof_test.go b/process/block/interceptedBlocks/interceptedEquivalentProof_test.go index 5c9674688f8..43d36bab6bf 100644 --- a/process/block/interceptedBlocks/interceptedEquivalentProof_test.go +++ b/process/block/interceptedBlocks/interceptedEquivalentProof_test.go @@ -11,6 +11,7 @@ import ( "github.com/multiversx/mx-chain-core-go/data" "github.com/multiversx/mx-chain-core-go/data/block" errErd "github.com/multiversx/mx-chain-go/errors" + "github.com/multiversx/mx-chain-go/p2p" "github.com/multiversx/mx-chain-go/testscommon/pool" logger "github.com/multiversx/mx-chain-logger-go" "github.com/stretchr/testify/require" @@ -90,6 +91,7 @@ func createMockArgInterceptedEquivalentProof() ArgInterceptedEquivalentProof { ProofSizeChecker: &testscommon.FieldsSizeCheckerMock{}, KeyRWMutexHandler: coreSync.NewKeyRWMutex(), ValidityAttester: &processMock.ValidityAttesterStub{}, + BroadcastMethod: p2p.Broadcast, } } @@ -362,6 +364,19 @@ func TestInterceptedEquivalentProof_CheckValidity(t *testing.T) { t.Parallel() args := createMockArgInterceptedEquivalentProof() + args.BroadcastMethod = p2p.Direct // should skip round check + args.ValidityAttester = &processMock.ValidityAttesterStub{ + CheckAgainstWhitelistCalled: func(interceptedData process.InterceptedData) bool { + return true + }, + CheckProofAgainstFinalCalled: func(proof data.HeaderProofHandler) error { + return nil + }, + CheckProofAgainstRoundHandlerCalled: func(proof data.HeaderProofHandler) error { + require.Fail(t, "should not be called") + return nil + }, + } args.HeadersPool = &pool.HeadersPoolStub{ GetHeaderByHashCalled: func(hash []byte) (data.HeaderHandler, error) { return &testscommon.HeaderHandlerStub{ diff --git a/process/block/interceptedBlocks/interceptedMetaBlockHeader.go b/process/block/interceptedBlocks/interceptedMetaBlockHeader.go index db4256f7428..84c808239c3 100644 --- a/process/block/interceptedBlocks/interceptedMetaBlockHeader.go +++ b/process/block/interceptedBlocks/interceptedMetaBlockHeader.go @@ -7,6 +7,7 @@ import ( "github.com/multiversx/mx-chain-core-go/data" "github.com/multiversx/mx-chain-core-go/data/block" "github.com/multiversx/mx-chain-core-go/hashing" + "github.com/multiversx/mx-chain-go/p2p" logger "github.com/multiversx/mx-chain-logger-go" "github.com/multiversx/mx-chain-go/common" @@ -30,6 +31,7 @@ type InterceptedMetaHeader struct { validityAttester process.ValidityAttester epochStartTrigger process.EpochStartTriggerHandler enableEpochsHandler common.EnableEpochsHandler + broadcastMethod p2p.BroadcastMethod } // NewInterceptedMetaHeader creates a new instance of InterceptedMetaHeader struct @@ -53,6 +55,7 @@ func NewInterceptedMetaHeader(arg *ArgInterceptedBlockHeader) (*InterceptedMetaH validityAttester: arg.ValidityAttester, epochStartTrigger: arg.EpochStartTrigger, enableEpochsHandler: arg.EnableEpochsHandler, + broadcastMethod: arg.BroadcastMethod, } inHdr.processFields(arg.HdrBuff) @@ -98,9 +101,11 @@ func (imh *InterceptedMetaHeader) CheckValidity() error { } } - err = imh.validityAttester.CheckBlockAgainstRoundHandler(imh.HeaderHandler()) - if err != nil { - return err + if imh.broadcastMethod == p2p.Broadcast { + err = imh.validityAttester.CheckBlockAgainstRoundHandler(imh.HeaderHandler()) + if err != nil { + return err + } } err = imh.sigVerifier.VerifyRandSeedAndLeaderSignature(imh.hdr) diff --git a/process/block/interceptedBlocks/interceptedMetaBlockHeader_test.go b/process/block/interceptedBlocks/interceptedMetaBlockHeader_test.go index 5bfaec4869d..28699086aa5 100644 --- a/process/block/interceptedBlocks/interceptedMetaBlockHeader_test.go +++ b/process/block/interceptedBlocks/interceptedMetaBlockHeader_test.go @@ -9,6 +9,7 @@ import ( "github.com/multiversx/mx-chain-core-go/core/check" "github.com/multiversx/mx-chain-core-go/data" dataBlock "github.com/multiversx/mx-chain-core-go/data/block" + "github.com/multiversx/mx-chain-go/p2p" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -54,6 +55,7 @@ func createMetaArgumentWithShardCoordinatorAndHeader(shardCoordinator sharding.C }, EnableEpochsHandler: &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, EpochChangeGracePeriodHandler: gracePeriod, + BroadcastMethod: p2p.Broadcast, } arg.HdrBuff, _ = testMarshalizer.Marshal(hdr) diff --git a/process/errors.go b/process/errors.go index 2aef2176c5c..e4166c5e6ee 100644 --- a/process/errors.go +++ b/process/errors.go @@ -1545,5 +1545,8 @@ var ErrInvalidShardInfo = errors.New("invalid shard info") // ErrNilClosingNodeStartedFlag signals that the closing node started flag is nil var ErrNilClosingNodeStartedFlag = errors.New("closing node started flag is nil") +// ErrInvalidRound signals that an invalid round has been provided +var ErrInvalidRound = errors.New("invalid round") + // ErrOutgoingTxsDisabled signals that the outgoing transactions are disabled var ErrOutgoingTxsDisabled = errors.New("outgoing transactions are disabled") diff --git a/process/interceptors/factory/interceptedEquivalentProofsFactory.go b/process/interceptors/factory/interceptedEquivalentProofsFactory.go index b0d412589ea..076d981eacf 100644 --- a/process/interceptors/factory/interceptedEquivalentProofsFactory.go +++ b/process/interceptors/factory/interceptedEquivalentProofsFactory.go @@ -5,6 +5,7 @@ import ( "github.com/multiversx/mx-chain-core-go/core/sync" "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" + "github.com/multiversx/mx-chain-go/p2p" "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/consensus" @@ -49,7 +50,7 @@ func NewInterceptedEquivalentProofsFactory(args ArgInterceptedEquivalentProofsFa } // Create creates instances of InterceptedData by unmarshalling provided buffer -func (factory *interceptedEquivalentProofsFactory) Create(buff []byte, _ core.PeerID) (process.InterceptedData, error) { +func (factory *interceptedEquivalentProofsFactory) Create(buff []byte, _ core.PeerID, broadcastMethod p2p.BroadcastMethod) (process.InterceptedData, error) { args := interceptedBlocks.ArgInterceptedEquivalentProof{ DataBuff: buff, Marshaller: factory.marshaller, diff --git a/process/interceptors/factory/interceptedEquivalentProofsFactory_test.go b/process/interceptors/factory/interceptedEquivalentProofsFactory_test.go index f848d209ec9..17e91e01d0b 100644 --- a/process/interceptors/factory/interceptedEquivalentProofsFactory_test.go +++ b/process/interceptors/factory/interceptedEquivalentProofsFactory_test.go @@ -74,7 +74,7 @@ func TestInterceptedEquivalentProofsFactory_Create(t *testing.T) { HeaderShardId: 0, } providedDataBuff, _ := args.CoreComponents.InternalMarshalizer().Marshal(providedProof) - interceptedData, err := factory.Create(providedDataBuff, "") + interceptedData, err := factory.Create(providedDataBuff, "", "") require.NoError(t, err) require.NotNil(t, interceptedData) diff --git a/process/interceptors/factory/interceptedHeartbeatDataFactory.go b/process/interceptors/factory/interceptedHeartbeatDataFactory.go index 5d5c3fed2e6..03069e836db 100644 --- a/process/interceptors/factory/interceptedHeartbeatDataFactory.go +++ b/process/interceptors/factory/interceptedHeartbeatDataFactory.go @@ -4,6 +4,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/marshal" + "github.com/multiversx/mx-chain-go/p2p" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/process/heartbeat" ) @@ -29,7 +30,7 @@ func NewInterceptedHeartbeatDataFactory(arg ArgInterceptedDataFactory) (*interce } // Create creates instances of InterceptedData by unmarshalling provided buffer -func (ihdf *interceptedHeartbeatDataFactory) Create(buff []byte, _ core.PeerID) (process.InterceptedData, error) { +func (ihdf *interceptedHeartbeatDataFactory) Create(buff []byte, _ core.PeerID, _ p2p.BroadcastMethod) (process.InterceptedData, error) { arg := heartbeat.ArgBaseInterceptedHeartbeat{ DataBuff: buff, Marshaller: ihdf.marshalizer, diff --git a/process/interceptors/factory/interceptedHeartbeatDataFactory_test.go b/process/interceptors/factory/interceptedHeartbeatDataFactory_test.go index 055830b685d..1c4297675ed 100644 --- a/process/interceptors/factory/interceptedHeartbeatDataFactory_test.go +++ b/process/interceptors/factory/interceptedHeartbeatDataFactory_test.go @@ -67,7 +67,7 @@ func TestNewInterceptedHeartbeatDataFactory(t *testing.T) { marshaledHeartbeat, err := marshaller.Marshal(hb) assert.Nil(t, err) - interceptedData, err := ihdf.Create(marshaledHeartbeat, "") + interceptedData, err := ihdf.Create(marshaledHeartbeat, "", "") assert.NotNil(t, interceptedData) assert.Nil(t, err) assert.True(t, strings.Contains(fmt.Sprintf("%T", interceptedData), "*heartbeat.interceptedHeartbeat")) diff --git a/process/interceptors/factory/interceptedMetaHeaderDataFactory.go b/process/interceptors/factory/interceptedMetaHeaderDataFactory.go index 9678ad725b8..914333bf2e9 100644 --- a/process/interceptors/factory/interceptedMetaHeaderDataFactory.go +++ b/process/interceptors/factory/interceptedMetaHeaderDataFactory.go @@ -5,6 +5,8 @@ import ( "github.com/multiversx/mx-chain-core-go/core/check" "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" + "github.com/multiversx/mx-chain-go/p2p" + "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/process/block/interceptedBlocks" @@ -80,7 +82,7 @@ func NewInterceptedMetaHeaderDataFactory(argument *ArgInterceptedMetaHeaderFacto } // Create creates instances of InterceptedData by unmarshalling provided buffer -func (imhdf *interceptedMetaHeaderDataFactory) Create(buff []byte, _ core.PeerID) (process.InterceptedData, error) { +func (imhdf *interceptedMetaHeaderDataFactory) Create(buff []byte, _ core.PeerID, broadcastMethod p2p.BroadcastMethod) (process.InterceptedData, error) { arg := &interceptedBlocks.ArgInterceptedBlockHeader{ HdrBuff: buff, Marshalizer: imhdf.marshalizer, @@ -92,6 +94,7 @@ func (imhdf *interceptedMetaHeaderDataFactory) Create(buff []byte, _ core.PeerID EpochStartTrigger: imhdf.epochStartTrigger, EnableEpochsHandler: imhdf.enableEpochsHandler, EpochChangeGracePeriodHandler: imhdf.epochChangeGracePeriodHandler, + BroadcastMethod: broadcastMethod, } return interceptedBlocks.NewInterceptedMetaHeader(arg) diff --git a/process/interceptors/factory/interceptedMetaHeaderDataFactory_test.go b/process/interceptors/factory/interceptedMetaHeaderDataFactory_test.go index d2724b38782..de33989a62a 100644 --- a/process/interceptors/factory/interceptedMetaHeaderDataFactory_test.go +++ b/process/interceptors/factory/interceptedMetaHeaderDataFactory_test.go @@ -268,7 +268,7 @@ func TestNewInterceptedMetaHeaderDataFactory_ShouldWorkAndCreate(t *testing.T) { marshalizer := &processMocks.MarshalizerMock{} emptyMetaHeader := &block.Header{} emptyMetaHeaderBuff, _ := marshalizer.Marshal(emptyMetaHeader) - interceptedData, err := imh.Create(emptyMetaHeaderBuff, "") + interceptedData, err := imh.Create(emptyMetaHeaderBuff, "", "") assert.Nil(t, err) _, ok := interceptedData.(*interceptedBlocks.InterceptedMetaHeader) diff --git a/process/interceptors/factory/interceptedMiniblockDataFactory.go b/process/interceptors/factory/interceptedMiniblockDataFactory.go index c51c78dac16..977d335e664 100644 --- a/process/interceptors/factory/interceptedMiniblockDataFactory.go +++ b/process/interceptors/factory/interceptedMiniblockDataFactory.go @@ -5,6 +5,7 @@ import ( "github.com/multiversx/mx-chain-core-go/core/check" "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" + "github.com/multiversx/mx-chain-go/p2p" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/process/block/interceptedBlocks" "github.com/multiversx/mx-chain-go/sharding" @@ -44,7 +45,7 @@ func NewInterceptedMiniblockDataFactory(argument *ArgInterceptedDataFactory) (*i } // Create creates instances of InterceptedData by unmarshalling provided buffer -func (imfd *interceptedMiniblockDataFactory) Create(buff []byte, _ core.PeerID) (process.InterceptedData, error) { +func (imfd *interceptedMiniblockDataFactory) Create(buff []byte, _ core.PeerID, _ p2p.BroadcastMethod) (process.InterceptedData, error) { arg := &interceptedBlocks.ArgInterceptedMiniblock{ MiniblockBuff: buff, Marshalizer: imfd.marshalizer, diff --git a/process/interceptors/factory/interceptedMiniblockDataFactory_test.go b/process/interceptors/factory/interceptedMiniblockDataFactory_test.go index 3a15d006751..8cbef5e6f08 100644 --- a/process/interceptors/factory/interceptedMiniblockDataFactory_test.go +++ b/process/interceptors/factory/interceptedMiniblockDataFactory_test.go @@ -69,7 +69,7 @@ func TestInterceptedMiniblockDataFactory_ShouldWorkAndCreate(t *testing.T) { marshalizer := &mock.MarshalizerMock{} emptyBlockBody := &block.Body{} emptyBlockBodyBuff, _ := marshalizer.Marshal(emptyBlockBody) - interceptedData, err := imdf.Create(emptyBlockBodyBuff, "") + interceptedData, err := imdf.Create(emptyBlockBodyBuff, "", "") assert.Nil(t, err) _, ok := interceptedData.(*interceptedBlocks.InterceptedMiniblock) diff --git a/process/interceptors/factory/interceptedPeerAuthenticationDataFactory.go b/process/interceptors/factory/interceptedPeerAuthenticationDataFactory.go index bd7ef59ec3e..a11df626a3c 100644 --- a/process/interceptors/factory/interceptedPeerAuthenticationDataFactory.go +++ b/process/interceptors/factory/interceptedPeerAuthenticationDataFactory.go @@ -8,6 +8,7 @@ import ( "github.com/multiversx/mx-chain-core-go/marshal" crypto "github.com/multiversx/mx-chain-crypto-go" "github.com/multiversx/mx-chain-go/common" + "github.com/multiversx/mx-chain-go/p2p" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/process/heartbeat" "github.com/multiversx/mx-chain-go/process/heartbeat/validator" @@ -87,7 +88,7 @@ func checkArgInterceptedDataFactory(args ArgInterceptedDataFactory) error { } // Create creates instances of InterceptedData by unmarshalling provided buffer -func (ipadf *interceptedPeerAuthenticationDataFactory) Create(buff []byte, messageOriginator core.PeerID) (process.InterceptedData, error) { +func (ipadf *interceptedPeerAuthenticationDataFactory) Create(buff []byte, messageOriginator core.PeerID, _ p2p.BroadcastMethod) (process.InterceptedData, error) { arg := heartbeat.ArgInterceptedPeerAuthentication{ ArgBaseInterceptedHeartbeat: heartbeat.ArgBaseInterceptedHeartbeat{ DataBuff: buff, diff --git a/process/interceptors/factory/interceptedPeerAuthenticationDataFactory_test.go b/process/interceptors/factory/interceptedPeerAuthenticationDataFactory_test.go index ad83aaea5fd..77556a6165e 100644 --- a/process/interceptors/factory/interceptedPeerAuthenticationDataFactory_test.go +++ b/process/interceptors/factory/interceptedPeerAuthenticationDataFactory_test.go @@ -132,7 +132,7 @@ func TestNewInterceptedPeerAuthenticationDataFactory(t *testing.T) { marshaledPeerAuthentication, err := marshaller.Marshal(peerAuthentication) assert.Nil(t, err) - interceptedData, err := ipadf.Create(marshaledPeerAuthentication, "") + interceptedData, err := ipadf.Create(marshaledPeerAuthentication, "", "") assert.NotNil(t, interceptedData) assert.Nil(t, err) assert.True(t, strings.Contains(fmt.Sprintf("%T", interceptedData), "*heartbeat.interceptedPeerAuthentication")) diff --git a/process/interceptors/factory/interceptedPeerShardFactory.go b/process/interceptors/factory/interceptedPeerShardFactory.go index 3234bb89681..9876d37ea53 100644 --- a/process/interceptors/factory/interceptedPeerShardFactory.go +++ b/process/interceptors/factory/interceptedPeerShardFactory.go @@ -4,6 +4,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/marshal" + p "github.com/multiversx/mx-chain-go/p2p" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/process/p2p" "github.com/multiversx/mx-chain-go/sharding" @@ -42,7 +43,7 @@ func checkInterceptedDirectConnectionInfoFactoryArgs(args ArgInterceptedDataFact } // Create creates instances of InterceptedData by unmarshalling provided buffer -func (ipsf *interceptedPeerShardFactory) Create(buff []byte, _ core.PeerID) (process.InterceptedData, error) { +func (ipsf *interceptedPeerShardFactory) Create(buff []byte, _ core.PeerID, _ p.BroadcastMethod) (process.InterceptedData, error) { args := p2p.ArgInterceptedPeerShard{ Marshaller: ipsf.marshaller, DataBuff: buff, diff --git a/process/interceptors/factory/interceptedPeerShardFactory_test.go b/process/interceptors/factory/interceptedPeerShardFactory_test.go index 797a5109113..1d014e0d41b 100644 --- a/process/interceptors/factory/interceptedPeerShardFactory_test.go +++ b/process/interceptors/factory/interceptedPeerShardFactory_test.go @@ -60,7 +60,7 @@ func TestNewInterceptedPeerShardFactory(t *testing.T) { ShardId: "5", } msgBuff, _ := arg.CoreComponents.InternalMarshalizer().Marshal(msg) - interceptedData, err := idcif.Create(msgBuff, "") + interceptedData, err := idcif.Create(msgBuff, "", "") assert.Nil(t, err) assert.False(t, check.IfNil(interceptedData)) assert.True(t, strings.Contains(fmt.Sprintf("%T", interceptedData), "*p2p.interceptedPeerShard")) diff --git a/process/interceptors/factory/interceptedRewardTxDataFactory.go b/process/interceptors/factory/interceptedRewardTxDataFactory.go index 1ceec65e05f..ad99eac9ec3 100644 --- a/process/interceptors/factory/interceptedRewardTxDataFactory.go +++ b/process/interceptors/factory/interceptedRewardTxDataFactory.go @@ -5,6 +5,7 @@ import ( "github.com/multiversx/mx-chain-core-go/core/check" "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" + "github.com/multiversx/mx-chain-go/p2p" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/process/rewardTransaction" "github.com/multiversx/mx-chain-go/sharding" @@ -52,7 +53,7 @@ func NewInterceptedRewardTxDataFactory(argument *ArgInterceptedDataFactory) (*in } // Create creates instances of InterceptedData by unmarshalling provided buffer -func (irtdf *interceptedRewardTxDataFactory) Create(buff []byte, _ core.PeerID) (process.InterceptedData, error) { +func (irtdf *interceptedRewardTxDataFactory) Create(buff []byte, _ core.PeerID, _ p2p.BroadcastMethod) (process.InterceptedData, error) { return rewardTransaction.NewInterceptedRewardTransaction( buff, irtdf.protoMarshalizer, diff --git a/process/interceptors/factory/interceptedRewardTxDataFactory_test.go b/process/interceptors/factory/interceptedRewardTxDataFactory_test.go index da7971d86b2..76493ed7920 100644 --- a/process/interceptors/factory/interceptedRewardTxDataFactory_test.go +++ b/process/interceptors/factory/interceptedRewardTxDataFactory_test.go @@ -93,7 +93,7 @@ func TestInterceptedRewardTxDataFactory_ShouldWorkAndCreate(t *testing.T) { marshalizer := &mock.MarshalizerMock{} emptyRewardTx := &rewardTx.RewardTx{} emptyRewardTxBuff, _ := marshalizer.Marshal(emptyRewardTx) - interceptedData, err := imh.Create(emptyRewardTxBuff, "") + interceptedData, err := imh.Create(emptyRewardTxBuff, "", "") assert.Nil(t, err) _, ok := interceptedData.(*rewardTransaction.InterceptedRewardTransaction) diff --git a/process/interceptors/factory/interceptedShardHeaderDataFactory.go b/process/interceptors/factory/interceptedShardHeaderDataFactory.go index 8d9018a8b0e..581efcdc56b 100644 --- a/process/interceptors/factory/interceptedShardHeaderDataFactory.go +++ b/process/interceptors/factory/interceptedShardHeaderDataFactory.go @@ -5,6 +5,8 @@ import ( "github.com/multiversx/mx-chain-core-go/core/check" "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" + "github.com/multiversx/mx-chain-go/p2p" + "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/process/block/interceptedBlocks" @@ -75,7 +77,7 @@ func NewInterceptedShardHeaderDataFactory(argument *ArgInterceptedDataFactory) ( } // Create creates instances of InterceptedData by unmarshalling provided buffer -func (ishdf *interceptedShardHeaderDataFactory) Create(buff []byte, _ core.PeerID) (process.InterceptedData, error) { +func (ishdf *interceptedShardHeaderDataFactory) Create(buff []byte, _ core.PeerID, broadcastMethod p2p.BroadcastMethod) (process.InterceptedData, error) { arg := &interceptedBlocks.ArgInterceptedBlockHeader{ HdrBuff: buff, Marshalizer: ishdf.marshalizer, @@ -87,6 +89,7 @@ func (ishdf *interceptedShardHeaderDataFactory) Create(buff []byte, _ core.PeerI EpochStartTrigger: ishdf.epochStartTrigger, EnableEpochsHandler: ishdf.enableEpochsHandler, EpochChangeGracePeriodHandler: ishdf.epochChangeGracePeriodHandler, + BroadcastMethod: broadcastMethod, } return interceptedBlocks.NewInterceptedHeader(arg) diff --git a/process/interceptors/factory/interceptedShardHeaderDataFactory_test.go b/process/interceptors/factory/interceptedShardHeaderDataFactory_test.go index 31adf2802a1..8f7d0ca0755 100644 --- a/process/interceptors/factory/interceptedShardHeaderDataFactory_test.go +++ b/process/interceptors/factory/interceptedShardHeaderDataFactory_test.go @@ -106,7 +106,7 @@ func TestInterceptedShardHeaderDataFactory_ShouldWorkAndCreate(t *testing.T) { marshalizer := &mock.MarshalizerMock{} emptyBlockHeader := &block.Header{} emptyBlockHeaderBuff, _ := marshalizer.Marshal(emptyBlockHeader) - interceptedData, err := imh.Create(emptyBlockHeaderBuff, "") + interceptedData, err := imh.Create(emptyBlockHeaderBuff, "", "") assert.Nil(t, err) _, ok := interceptedData.(*interceptedBlocks.InterceptedHeader) diff --git a/process/interceptors/factory/interceptedTrieNodeDataFactory.go b/process/interceptors/factory/interceptedTrieNodeDataFactory.go index 33e09286487..d96d69a1894 100644 --- a/process/interceptors/factory/interceptedTrieNodeDataFactory.go +++ b/process/interceptors/factory/interceptedTrieNodeDataFactory.go @@ -4,6 +4,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/hashing" + "github.com/multiversx/mx-chain-go/p2p" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/trie" ) @@ -35,7 +36,7 @@ func NewInterceptedTrieNodeDataFactory( } // Create creates instances of InterceptedData by unmarshalling provided buffer -func (sidf *interceptedTrieNodeDataFactory) Create(buff []byte, _ core.PeerID) (process.InterceptedData, error) { +func (sidf *interceptedTrieNodeDataFactory) Create(buff []byte, _ core.PeerID, _ p2p.BroadcastMethod) (process.InterceptedData, error) { return trie.NewInterceptedTrieNode(buff, sidf.hasher) } diff --git a/process/interceptors/factory/interceptedTxDataFactory.go b/process/interceptors/factory/interceptedTxDataFactory.go index 65fe2f69e7c..bc33bfa23d3 100644 --- a/process/interceptors/factory/interceptedTxDataFactory.go +++ b/process/interceptors/factory/interceptedTxDataFactory.go @@ -7,6 +7,7 @@ import ( "github.com/multiversx/mx-chain-core-go/marshal" "github.com/multiversx/mx-chain-crypto-go" "github.com/multiversx/mx-chain-go/common" + "github.com/multiversx/mx-chain-go/p2p" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/process/transaction" "github.com/multiversx/mx-chain-go/sharding" @@ -113,7 +114,7 @@ func NewInterceptedTxDataFactory(argument *ArgInterceptedDataFactory) (*intercep } // Create creates instances of InterceptedData by unmarshalling provided buffer -func (itdf *interceptedTxDataFactory) Create(buff []byte, _ core.PeerID) (process.InterceptedData, error) { +func (itdf *interceptedTxDataFactory) Create(buff []byte, _ core.PeerID, _ p2p.BroadcastMethod) (process.InterceptedData, error) { return transaction.NewInterceptedTransaction( buff, itdf.protoMarshalizer, diff --git a/process/interceptors/factory/interceptedTxDataFactory_test.go b/process/interceptors/factory/interceptedTxDataFactory_test.go index 56efc31b681..414a9eb0ddc 100644 --- a/process/interceptors/factory/interceptedTxDataFactory_test.go +++ b/process/interceptors/factory/interceptedTxDataFactory_test.go @@ -196,7 +196,7 @@ func TestInterceptedTxDataFactory_ShouldWorkAndCreate(t *testing.T) { Value: big.NewInt(0), } emptyTxBuff, _ := marshalizer.Marshal(emptyTx) - interceptedData, err := imh.Create(emptyTxBuff, "") + interceptedData, err := imh.Create(emptyTxBuff, "", "") assert.Nil(t, err) _, ok := interceptedData.(*transaction.InterceptedTransaction) diff --git a/process/interceptors/factory/interceptedUnsignedTxDataFactory.go b/process/interceptors/factory/interceptedUnsignedTxDataFactory.go index 44233ae1ef6..8bf508f295d 100644 --- a/process/interceptors/factory/interceptedUnsignedTxDataFactory.go +++ b/process/interceptors/factory/interceptedUnsignedTxDataFactory.go @@ -5,6 +5,7 @@ import ( "github.com/multiversx/mx-chain-core-go/core/check" "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" + "github.com/multiversx/mx-chain-go/p2p" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/process/unsigned" "github.com/multiversx/mx-chain-go/sharding" @@ -52,7 +53,7 @@ func NewInterceptedUnsignedTxDataFactory(argument *ArgInterceptedDataFactory) (* } // Create creates instances of InterceptedData by unmarshalling provided buffer -func (iutdf *interceptedUnsignedTxDataFactory) Create(buff []byte, _ core.PeerID) (process.InterceptedData, error) { +func (iutdf *interceptedUnsignedTxDataFactory) Create(buff []byte, _ core.PeerID, _ p2p.BroadcastMethod) (process.InterceptedData, error) { return unsigned.NewInterceptedUnsignedTransaction( buff, iutdf.protoMarshalizer, diff --git a/process/interceptors/factory/interceptedUnsignedTxDataFactory_test.go b/process/interceptors/factory/interceptedUnsignedTxDataFactory_test.go index 41ab63596b1..439f76b60ae 100644 --- a/process/interceptors/factory/interceptedUnsignedTxDataFactory_test.go +++ b/process/interceptors/factory/interceptedUnsignedTxDataFactory_test.go @@ -93,7 +93,7 @@ func TestInterceptedUnsignedTxDataFactory_ShouldWorkAndCreate(t *testing.T) { marshalizer := &mock.MarshalizerMock{} emptyTx := &smartContractResult.SmartContractResult{} emptyTxBuff, _ := marshalizer.Marshal(emptyTx) - interceptedData, err := imh.Create(emptyTxBuff, "") + interceptedData, err := imh.Create(emptyTxBuff, "", "") assert.Nil(t, err) _, ok := interceptedData.(*unsigned.InterceptedUnsignedTransaction) diff --git a/process/interceptors/factory/interceptedValidatorInfoDataFactory.go b/process/interceptors/factory/interceptedValidatorInfoDataFactory.go index 0ae55db3767..a1429350831 100644 --- a/process/interceptors/factory/interceptedValidatorInfoDataFactory.go +++ b/process/interceptors/factory/interceptedValidatorInfoDataFactory.go @@ -5,6 +5,7 @@ import ( "github.com/multiversx/mx-chain-core-go/core/check" "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" + "github.com/multiversx/mx-chain-go/p2p" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/process/peer" ) @@ -42,7 +43,7 @@ func checkInterceptedValidatorInfoDataFactoryArgs(args ArgInterceptedDataFactory } // Create creates instances of InterceptedData by unmarshalling provided buffer -func (ividf *interceptedValidatorInfoDataFactory) Create(buff []byte, _ core.PeerID) (process.InterceptedData, error) { +func (ividf *interceptedValidatorInfoDataFactory) Create(buff []byte, _ core.PeerID, _ p2p.BroadcastMethod) (process.InterceptedData, error) { args := peer.ArgInterceptedValidatorInfo{ DataBuff: buff, Marshalizer: ividf.marshaller, diff --git a/process/interceptors/factory/interceptedValidatorInfoDataFactory_test.go b/process/interceptors/factory/interceptedValidatorInfoDataFactory_test.go index a6f1d9772d6..e15b8fb48b5 100644 --- a/process/interceptors/factory/interceptedValidatorInfoDataFactory_test.go +++ b/process/interceptors/factory/interceptedValidatorInfoDataFactory_test.go @@ -79,7 +79,7 @@ func TestInterceptedValidatorInfoDataFactory_Create(t *testing.T) { ividf, _ := NewInterceptedValidatorInfoDataFactory(*createMockArgument(createMockComponentHolders())) require.False(t, check.IfNil(ividf)) - ivi, err := ividf.Create(nil, "") + ivi, err := ividf.Create(nil, "", "") assert.NotNil(t, err) assert.True(t, check.IfNil(ivi)) }) @@ -88,7 +88,7 @@ func TestInterceptedValidatorInfoDataFactory_Create(t *testing.T) { ividf, _ := NewInterceptedValidatorInfoDataFactory(*createMockArgument(createMockComponentHolders())) require.False(t, check.IfNil(ividf)) - ivi, err := ividf.Create(createMockValidatorInfoBuff(), "") + ivi, err := ividf.Create(createMockValidatorInfoBuff(), "", "") assert.Nil(t, err) assert.False(t, check.IfNil(ivi)) }) diff --git a/process/interceptors/multiDataInterceptor.go b/process/interceptors/multiDataInterceptor.go index 6db9ed69b61..3b048aa22c2 100644 --- a/process/interceptors/multiDataInterceptor.go +++ b/process/interceptors/multiDataInterceptor.go @@ -236,7 +236,7 @@ func (mdi *MultiDataInterceptor) interceptedData( errOriginator error, ) (process.InterceptedData, bool, error) { originator := message.Peer() - interceptedData, err := mdi.factory.Create(dataBuff, originator) + interceptedData, err := mdi.factory.Create(dataBuff, originator, message.BroadcastMethod()) if err != nil { // this situation is so severe that we need to black list de peers reason := "can not create object from received bytes, topic " + mdi.topic + ", error " + err.Error() diff --git a/process/interceptors/singleDataInterceptor.go b/process/interceptors/singleDataInterceptor.go index 6ce80edce3f..7613e30f63e 100644 --- a/process/interceptors/singleDataInterceptor.go +++ b/process/interceptors/singleDataInterceptor.go @@ -94,7 +94,7 @@ func (sdi *SingleDataInterceptor) ProcessReceivedMessage(message p2p.MessageP2P, return nil, err } - interceptedData, err := sdi.factory.Create(message.Data(), message.Peer()) + interceptedData, err := sdi.factory.Create(message.Data(), message.Peer(), message.BroadcastMethod()) if err != nil { sdi.throttler.EndProcessing() diff --git a/process/interface.go b/process/interface.go index 7d74c54c1a8..ecd706b2d01 100644 --- a/process/interface.go +++ b/process/interface.go @@ -133,7 +133,7 @@ type HdrValidatorHandler interface { // InterceptedDataFactory can create new instances of InterceptedData type InterceptedDataFactory interface { - Create(buff []byte, messageOriginator core.PeerID) (InterceptedData, error) + Create(buff []byte, messageOriginator core.PeerID, broadcastMethod p2p.BroadcastMethod) (InterceptedData, error) IsInterfaceNil() bool } @@ -1212,6 +1212,9 @@ type RoundTimeDurationHandler interface { type RoundHandler interface { Index() int64 TimeDuration() time.Duration + RemainingTime(startTime time.Time, maxTime time.Duration) time.Duration + GetTimeStampForRound(round uint64) uint64 + ComputeCurrentRound() int64 IsInterfaceNil() bool } diff --git a/process/mock/interceptedDataFactoryStub.go b/process/mock/interceptedDataFactoryStub.go index 3481f42e5b7..0c493f0cc60 100644 --- a/process/mock/interceptedDataFactoryStub.go +++ b/process/mock/interceptedDataFactoryStub.go @@ -2,6 +2,7 @@ package mock import ( "github.com/multiversx/mx-chain-core-go/core" + "github.com/multiversx/mx-chain-go/p2p" "github.com/multiversx/mx-chain-go/process" ) @@ -11,7 +12,7 @@ type InterceptedDataFactoryStub struct { } // Create - -func (idfs *InterceptedDataFactoryStub) Create(buff []byte, _ core.PeerID) (process.InterceptedData, error) { +func (idfs *InterceptedDataFactoryStub) Create(buff []byte, messageOriginator core.PeerID, broadcastMethod p2p.BroadcastMethod) (process.InterceptedData, error) { return idfs.CreateCalled(buff) } diff --git a/process/mock/roundStub.go b/process/mock/roundStub.go index 8b99f5d256d..b7c440f6855 100644 --- a/process/mock/roundStub.go +++ b/process/mock/roundStub.go @@ -6,11 +6,13 @@ import ( // RoundStub - type RoundStub struct { - IndexCalled func() int64 - TimeDurationCalled func() time.Duration - TimeStampCalled func() time.Time - UpdateRoundCalled func(time.Time, time.Time) - RemainingTimeCalled func(time.Time, time.Duration) time.Duration + IndexCalled func() int64 + TimeDurationCalled func() time.Duration + TimeStampCalled func() time.Time + UpdateRoundCalled func(time.Time, time.Time) + RemainingTimeCalled func(time.Time, time.Duration) time.Duration + GetTimeStampForRoundCalled func(round uint64) uint64 + ComputeCurrentRoundCalled func() int64 } // Index - @@ -38,6 +40,24 @@ func (rnds *RoundStub) RemainingTime(startTime time.Time, maxTime time.Duration) return rnds.RemainingTimeCalled(startTime, maxTime) } +// GetTimeStampForRound - +func (rnds *RoundStub) GetTimeStampForRound(round uint64) uint64 { + if rnds.GetTimeStampForRoundCalled != nil { + return rnds.GetTimeStampForRoundCalled(round) + } + + return uint64(time.Unix(0, 0).UnixMilli()) +} + +// ComputeCurrentRound - +func (rnds *RoundStub) ComputeCurrentRound() int64 { + if rnds.ComputeCurrentRoundCalled != nil { + return rnds.ComputeCurrentRoundCalled() + } + + return 0 +} + // IsInterfaceNil -- func (rnds *RoundStub) IsInterfaceNil() bool { return rnds == nil diff --git a/process/mock/rounderMock.go b/process/mock/rounderMock.go index 5f1234c3aa6..522f06e47c0 100644 --- a/process/mock/rounderMock.go +++ b/process/mock/rounderMock.go @@ -7,10 +7,12 @@ import ( // RoundHandlerMock - type RoundHandlerMock struct { - RoundIndex int64 - RoundTimeStamp time.Time - RoundTimeDuration time.Duration - BeforeGenesisCalled func() bool + RoundIndex int64 + RoundTimeStamp time.Time + RoundTimeDuration time.Duration + BeforeGenesisCalled func() bool + RemainingTimeCalled func(startTime time.Time, maxTime time.Duration) time.Duration + ComputeCurrentRoundCalled func() int64 } // BeforeGenesis - @@ -55,7 +57,10 @@ func (rndm *RoundHandlerMock) UpdateRound(genesisRoundTimeStamp time.Time, timeS } // RemainingTime - -func (rndm *RoundHandlerMock) RemainingTime(_ time.Time, _ time.Duration) time.Duration { +func (rndm *RoundHandlerMock) RemainingTime(startTime time.Time, maxTime time.Duration) time.Duration { + if rndm.RemainingTimeCalled != nil { + return rndm.RemainingTimeCalled(startTime, maxTime) + } return rndm.RoundTimeDuration } @@ -64,6 +69,15 @@ func (rndm *RoundHandlerMock) GetTimeStampForRound(round uint64) uint64 { return 0 } +// ComputeCurrentRound - +func (rndm *RoundHandlerMock) ComputeCurrentRound() int64 { + if rndm.ComputeCurrentRoundCalled != nil { + return rndm.ComputeCurrentRoundCalled() + } + + return rndm.RoundIndex +} + // IsInterfaceNil returns true if there is no value under the interface func (rndm *RoundHandlerMock) IsInterfaceNil() bool { return rndm == nil diff --git a/process/track/baseBlockTrack.go b/process/track/baseBlockTrack.go index f50de157328..4bed371a43b 100644 --- a/process/track/baseBlockTrack.go +++ b/process/track/baseBlockTrack.go @@ -5,6 +5,7 @@ import ( "fmt" "sort" "sync" + "time" "github.com/multiversx/mx-chain-core-go/core" "github.com/multiversx/mx-chain-core-go/core/check" @@ -25,6 +26,10 @@ var log = logger.GetOrCreate("process/track") const maxNonceDifference = 3 // TODO move this to a config file +// receivedProofDelay is the extra fraction of one full round time during which +// a proof is still accepted, i.e. total allowed time = roundDuration * (1 + receivedProofDelay) +const receivedProofDelay = 0.5 + // HeaderInfo holds the information about a header type HeaderInfo struct { Hash []byte @@ -486,7 +491,7 @@ func (bbt *baseBlockTrack) CheckProofAgainstRoundHandler(proof data.HeaderProofH } func (bbt *baseBlockTrack) checkAgainstRoundHandler(round uint64) error { - nextRound := bbt.roundHandler.Index() + 1 + nextRound := bbt.roundHandler.ComputeCurrentRound() + 1 if int64(round) > nextRound { return fmt.Errorf("%w header round: %d, next chronology round: %d", process.ErrHigherRoundInBlock, @@ -494,6 +499,18 @@ func (bbt *baseBlockTrack) checkAgainstRoundHandler(round uint64) error { nextRound) } + roundTimestamp := time.UnixMilli(int64(bbt.roundHandler.GetTimeStampForRound(round))) + roundDuration := float64(bbt.roundHandler.TimeDuration()) + maxTimeToAccept := time.Duration(roundDuration + roundDuration*receivedProofDelay) + timeLeftToAccept := bbt.roundHandler.RemainingTime(roundTimestamp, maxTimeToAccept) + if timeLeftToAccept <= 0 { + return fmt.Errorf("%w header round: %d, current round timestamp: %d, time left to accept proof: %d", + process.ErrInvalidRound, + round, + roundTimestamp.UnixMilli(), + timeLeftToAccept.Milliseconds()) + } + return nil } diff --git a/process/track/baseBlockTrack_test.go b/process/track/baseBlockTrack_test.go index b57f322ddc5..914abfb0080 100644 --- a/process/track/baseBlockTrack_test.go +++ b/process/track/baseBlockTrack_test.go @@ -5,6 +5,7 @@ import ( "fmt" "sync" "testing" + "time" "github.com/multiversx/mx-chain-core-go/core" "github.com/multiversx/mx-chain-core-go/core/check" @@ -2406,7 +2407,12 @@ func TestBaseBlockTrack_CheckBlockAgainstRoundHandlerShouldWork(t *testing.T) { currentRound := int64(50) bbt.SetRoundHandler( &mock.RoundHandlerMock{ - RoundIndex: currentRound, + RoundIndex: currentRound, + RoundTimeStamp: time.Now(), + RoundTimeDuration: time.Second, + ComputeCurrentRoundCalled: func() int64 { + return currentRound + }, }, ) @@ -2418,6 +2424,42 @@ func TestBaseBlockTrack_CheckBlockAgainstRoundHandlerShouldWork(t *testing.T) { assert.Nil(t, err) } +func TestBaseBlockTrack_CheckBlockAgainstRoundHandlerShouldFailOnInvalidWindow(t *testing.T) { + t.Parallel() + + bbt := track.NewBaseBlockTrack() + currentRound := int64(50) + roundDuration := time.Millisecond * 200 + bbt.SetRoundHandler( + &mock.RoundHandlerMock{ + RoundIndex: currentRound, + RoundTimeStamp: time.Now(), + RoundTimeDuration: roundDuration, + RemainingTimeCalled: func(startTime time.Time, maxTime time.Duration) time.Duration { + currentTime := time.Now() + elapsedTime := currentTime.Sub(startTime) + remainingTime := maxTime - elapsedTime + + return remainingTime + }, + ComputeCurrentRoundCalled: func() int64 { + return currentRound + }, + }, + ) + + hdr := &block.Header{ + Round: uint64(currentRound + 1), // proper round but received too late + } + + // wait until after half of the next round passed + timeToSleep := roundDuration + time.Duration(float64(roundDuration)*0.6) + time.Sleep(timeToSleep) + err := bbt.CheckBlockAgainstRoundHandler(hdr) + require.ErrorIs(t, err, process.ErrInvalidRound) + require.Contains(t, err.Error(), "current round timestamp") +} + // ------- CheckBlockAgainstFinal func TestBaseBlockTrack_CheckBlockAgainstFinalNilHeaderShouldErr(t *testing.T) { diff --git a/testscommon/blockProcessorStub.go b/testscommon/blockProcessorStub.go index 2b06d3015b7..66f977481e3 100644 --- a/testscommon/blockProcessorStub.go +++ b/testscommon/blockProcessorStub.go @@ -46,7 +46,7 @@ type BlockProcessorStub struct { _ []byte, ) error OnExecutedBlockCalled func(header data.HeaderHandler, rootHash []byte) error - RemoveHeaderFromPoolCalled func(headerHash []byte) + RemoveHeaderFromPoolCalled func(headerNonce uint64) ProposedDirectSentTransactionsToBroadcastCalled func(proposedBody data.BodyHandler) map[string][][]byte PruneTrieAsyncHeaderCalled func() } @@ -280,9 +280,9 @@ func (bps *BlockProcessorStub) OnExecutedBlock(header data.HeaderHandler, rootHa } // RemoveHeaderFromPool - -func (bps *BlockProcessorStub) RemoveHeaderFromPool(headerHash []byte) { +func (bps *BlockProcessorStub) RemoveHeaderFromPool(headerNonce uint64) { if bps.RemoveHeaderFromPoolCalled != nil { - bps.RemoveHeaderFromPoolCalled(headerHash) + bps.RemoveHeaderFromPoolCalled(headerNonce) } } diff --git a/testscommon/round/rounderMock.go b/testscommon/round/rounderMock.go index 21488b048f5..9411fa3a3cf 100644 --- a/testscommon/round/rounderMock.go +++ b/testscommon/round/rounderMock.go @@ -15,6 +15,7 @@ type RoundHandlerMock struct { RemainingTimeCalled func(startTime time.Time, maxTime time.Duration) time.Duration GetTimeStampForRoundCalled func(round uint64) uint64 BeforeGenesisCalled func() bool + ComputeCurrentRoundCalled func() int64 } // BeforeGenesis - @@ -83,6 +84,15 @@ func (rndm *RoundHandlerMock) GetTimeStampForRound(round uint64) uint64 { return 0 } +// ComputeCurrentRound - +func (rndm *RoundHandlerMock) ComputeCurrentRound() int64 { + if rndm.ComputeCurrentRoundCalled != nil { + return rndm.ComputeCurrentRoundCalled() + } + + return rndm.RoundIndex +} + // IsInterfaceNil returns true if there is no value under the interface func (rndm *RoundHandlerMock) IsInterfaceNil() bool { return rndm == nil diff --git a/testscommon/roundHandlerMock.go b/testscommon/roundHandlerMock.go index 7f5451ac9e9..077ef99fed8 100644 --- a/testscommon/roundHandlerMock.go +++ b/testscommon/roundHandlerMock.go @@ -18,6 +18,7 @@ type RoundHandlerMock struct { BeforeGenesisCalled func() bool IncrementIndexCalled func() GetTimeStampForRoundCalled func(round uint64) uint64 + ComputeCurrentRoundCalled func() int64 } // BeforeGenesis - @@ -98,6 +99,19 @@ func (rndm *RoundHandlerMock) GetTimeStampForRound(round uint64) uint64 { return 0 } +// ComputeCurrentRound - +func (rndm *RoundHandlerMock) ComputeCurrentRound() int64 { + if rndm.ComputeCurrentRoundCalled != nil { + return rndm.ComputeCurrentRoundCalled() + } + + rndm.indexMut.RLock() + idx := rndm.index + rndm.indexMut.RUnlock() + + return idx +} + // IsInterfaceNil returns true if there is no value under the interface func (rndm *RoundHandlerMock) IsInterfaceNil() bool { return rndm == nil