From a4c0a4b74318babf14474e2769791bd3730d50d0 Mon Sep 17 00:00:00 2001 From: ssd04 Date: Tue, 20 May 2025 12:20:42 +0300 Subject: [PATCH 1/3] add unit tests for epoch start trigger with missing prev header --- epochStart/shardchain/trigger_test.go | 100 +++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) diff --git a/epochStart/shardchain/trigger_test.go b/epochStart/shardchain/trigger_test.go index 9a83c666a4b..8b99d5c5522 100644 --- a/epochStart/shardchain/trigger_test.go +++ b/epochStart/shardchain/trigger_test.go @@ -591,7 +591,7 @@ func TestTrigger_RevertStateToBlockBehindEpochStartNoBlockInAnEpoch(t *testing.T assert.Equal(t, et.epochStartShardHeader.GetEpoch(), prevEpochHdr.Epoch) } -func TestTrigger_ReceivedHeaderChangeEpochFinalityAttestingRound(t *testing.T) { +func TestTrigger_ReceivedEpochStartHeaderChangeEpochFinalityAttestingRound(t *testing.T) { t.Parallel() args := createMockShardEpochStartTriggerArguments() @@ -629,6 +629,104 @@ func TestTrigger_ReceivedHeaderChangeEpochFinalityAttestingRound(t *testing.T) { require.Equal(t, uint64(102), epochStartTrigger.EpochFinalityAttestingRound()) } +func TestTrigger_ReceivedHeaderChangeEpochWithoutPrevHeader(t *testing.T) { + t.Parallel() + + args := createMockShardEpochStartTriggerArguments() + args.Validity = 1 + args.Finality = 1 + + oldEpHeader := &block.MetaBlock{Nonce: 99, Round: 99, Epoch: 0} + oldHash, _ := core.CalculateHash(args.Marshalizer, args.Hasher, oldEpHeader) + + hash := []byte("hash") + epochStartHeader := &block.MetaBlock{Nonce: 100, Round: 100, Epoch: 1, PrevHash: oldHash} + epochStartHeader.EpochStart.LastFinalizedHeaders = []block.EpochStartShardData{{ShardID: 0, RootHash: hash, HeaderHash: hash}} + epochStartHash, _ := core.CalculateHash(args.Marshalizer, args.Hasher, epochStartHeader) + + nextHeader := &block.MetaBlock{Nonce: 101, Round: 101, Epoch: 1, PrevHash: epochStartHash} + nextHeaderHash, _ := core.CalculateHash(args.Marshalizer, args.Hasher, nextHeader) + + numGetHeadersFromPoolCalls := 0 + args.DataPool = &dataRetrieverMock.PoolsHolderStub{ + HeadersCalled: func() dataRetriever.HeadersPool { + return &mock.HeadersCacherStub{ + GetHeaderByHashCalled: func(hash []byte) (data.HeaderHandler, error) { + if bytes.Equal(hash, oldHash) { + if numGetHeadersFromPoolCalls == 0 { + numGetHeadersFromPoolCalls++ + return nil, errors.New("not found") + } + + return oldEpHeader, nil + } + + if bytes.Equal(hash, epochStartHash) { + return epochStartHeader, nil + } + if bytes.Equal(hash, nextHeaderHash) { + return nextHeader, nil + } + + return &block.MetaBlock{}, nil + }, + GetHeaderByNonceAndShardIdCalled: func(hdrNonce uint64, shardId uint32) ([]data.HeaderHandler, [][]byte, error) { + if hdrNonce == epochStartHeader.Nonce { + return []data.HeaderHandler{epochStartHeader}, [][]byte{epochStartHash}, nil + } + + if hdrNonce == nextHeader.Nonce { + return []data.HeaderHandler{nextHeader}, [][]byte{nextHeaderHash}, nil + } + + return make([]data.HeaderHandler, 0), make([][]byte, 0), nil + }, + } + }, + MiniBlocksCalled: func() storage.Cacher { + return cache.NewCacherStub() + }, + CurrEpochValidatorInfoCalled: func() dataRetriever.ValidatorInfoCacher { + return &vic.ValidatorInfoCacherStub{} + }, + ProofsCalled: func() dataRetriever.ProofsPool { + return &dataRetrieverMock.ProofsPoolMock{} + }, + } + + args.Storage = &storageStubs.ChainStorerStub{ + GetStorerCalled: func(unitType dataRetriever.UnitType) (storage.Storer, error) { + return &storageStubs.StorerStub{ + GetCalled: func(key []byte) (b []byte, err error) { + if bytes.Equal(key, oldHash) { + return nil, errors.New("failed to get header from storage") + } + + if bytes.Equal(key, nextHeaderHash) { + return nextHeaderHash, nil + } + + return []byte("hash"), nil + }, + PutCalled: func(key, data []byte) error { + return nil + }, + }, nil + }, + } + + epochStartTrigger, err := NewEpochStartTrigger(args) + require.Nil(t, err) + + epochStartTrigger.receivedMetaBlock(epochStartHeader, epochStartHash) + + require.False(t, epochStartTrigger.isEpochStart) + + epochStartTrigger.receivedMetaBlock(epochStartHeader, epochStartHash) + + require.True(t, epochStartTrigger.isEpochStart) +} + func TestTrigger_ClearMissingValidatorsInfoMapShouldWork(t *testing.T) { t.Parallel() From 5e777854867172bf830df2a8a99425fa6231a35f Mon Sep 17 00:00:00 2001 From: ssd04 Date: Tue, 20 May 2025 12:26:42 +0300 Subject: [PATCH 2/3] check epoch start hdr found in finalized --- epochStart/shardchain/trigger.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/epochStart/shardchain/trigger.go b/epochStart/shardchain/trigger.go index 2a569269b66..9af345e61ba 100644 --- a/epochStart/shardchain/trigger.go +++ b/epochStart/shardchain/trigger.go @@ -19,7 +19,7 @@ import ( "github.com/multiversx/mx-chain-core-go/display" "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" - "github.com/multiversx/mx-chain-logger-go" + logger "github.com/multiversx/mx-chain-logger-go" "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/dataRetriever" @@ -655,10 +655,13 @@ func (t *trigger) shouldUpdateTrigger(metaHdr *block.MetaBlock, metaBlockHash [] return false } - if _, ok := t.mapHashHdr[string(metaBlockHash)]; ok { - return false - } - if _, ok := t.mapEpochStartHdrs[string(metaBlockHash)]; ok { + _, foundHdrInMap := t.mapHashHdr[string(metaBlockHash)] + _, foundHdrInEpochStartMap := t.mapEpochStartHdrs[string(metaBlockHash)] + + finalizedMetaBlockHash, ok := t.mapFinalizedEpochs[metaHdr.Epoch] + foundHdrInFinalizedMap := ok && bytes.Equal(metaBlockHash, []byte(finalizedMetaBlockHash)) + + if foundHdrInMap && foundHdrInEpochStartMap && foundHdrInFinalizedMap { return false } From ac17ac08ef95ef5dd8ac02e9c6decefd2cb10d08 Mon Sep 17 00:00:00 2001 From: ssd04 Date: Tue, 20 May 2025 12:27:26 +0300 Subject: [PATCH 3/3] check epoch start hdr for older epochs --- epochStart/shardchain/trigger.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/epochStart/shardchain/trigger.go b/epochStart/shardchain/trigger.go index 9af345e61ba..f3f5262db25 100644 --- a/epochStart/shardchain/trigger.go +++ b/epochStart/shardchain/trigger.go @@ -650,8 +650,8 @@ func (t *trigger) shouldUpdateTrigger(metaHdr *block.MetaBlock, metaBlockHash [] return false } - isMetaStartOfEpochForCurrentEpoch := metaHdr.Epoch == t.epoch && metaHdr.IsStartOfEpochBlock() - if isMetaStartOfEpochForCurrentEpoch { + isMetaStartOfEpochForCurrentOrOlderEpoch := metaHdr.Epoch <= t.epoch && metaHdr.IsStartOfEpochBlock() + if isMetaStartOfEpochForCurrentOrOlderEpoch { return false }