From b6d5a609505e9a7d0c4a2bb9252022aaa9f7c522 Mon Sep 17 00:00:00 2001 From: jules01 <iulian.pascalau@gmail.com> Date: Mon, 20 Feb 2023 14:29:12 +0200 Subject: [PATCH] - fixed self-blacklisted event in consensus due to edge case when setting the current epoch --- process/block/shardblock.go | 10 +++ process/block/shardblock_test.go | 145 +++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+) diff --git a/process/block/shardblock.go b/process/block/shardblock.go index 16b88d5bf9d..a43a98111b2 100644 --- a/process/block/shardblock.go +++ b/process/block/shardblock.go @@ -807,6 +807,16 @@ func (sp *shardProcessor) CreateBlock( if err != nil { return nil, nil, err } + + epoch := sp.epochStartTrigger.MetaEpoch() + if initialHdr.GetEpoch() != epoch { + log.Debug("shardProcessor.CreateBlock: epoch from header is not the same as epoch from epoch start trigger, overwriting", + "epoch from header", initialHdr.GetEpoch(), "epoch from epoch start trigger", epoch) + err = shardHdr.SetEpoch(epoch) + if err != nil { + return nil, nil, err + } + } } sp.epochNotifier.CheckEpoch(shardHdr) diff --git a/process/block/shardblock_test.go b/process/block/shardblock_test.go index d20d4a9ca84..0f79df9c47a 100644 --- a/process/block/shardblock_test.go +++ b/process/block/shardblock_test.go @@ -15,6 +15,7 @@ import ( "github.com/multiversx/mx-chain-core-go/core" atomicCore "github.com/multiversx/mx-chain-core-go/core/atomic" + "github.com/multiversx/mx-chain-core-go/core/check" "github.com/multiversx/mx-chain-core-go/data" "github.com/multiversx/mx-chain-core-go/data/block" outportcore "github.com/multiversx/mx-chain-core-go/data/outport" @@ -5241,3 +5242,147 @@ func TestShardProcessor_RollBackProcessedMiniBlocksInfo(t *testing.T) { assert.False(t, processedMbInfo.FullyProcessed) assert.Equal(t, indexOfFirstTxProcessed-1, processedMbInfo.IndexOfLastTxProcessed) } + +func TestShardProcessor_CreateBlock(t *testing.T) { + t.Parallel() + + arguments := CreateMockArguments(createComponentHolderMocks()) + processHandler := arguments.CoreComponents.ProcessStatusHandler() + mockProcessHandler := processHandler.(*testscommon.ProcessStatusHandlerStub) + busyIdleCalled := make([]string, 0) + mockProcessHandler.SetIdleCalled = func() { + busyIdleCalled = append(busyIdleCalled, idleIdentifier) + } + mockProcessHandler.SetBusyCalled = func(reason string) { + busyIdleCalled = append(busyIdleCalled, busyIdentifier) + } + + expectedBusyIdleSequencePerCall := []string{busyIdentifier, idleIdentifier} + sp, errConstructor := blproc.NewShardProcessor(arguments) + assert.Nil(t, errConstructor) + + doesHaveTime := func() bool { + return true + } + t.Run("nil block should error", func(t *testing.T) { + hdr, body, err := sp.CreateBlock(nil, doesHaveTime) + assert.True(t, check.IfNil(body)) + assert.True(t, check.IfNil(hdr)) + assert.Equal(t, process.ErrNilBlockHeader, err) + assert.Zero(t, len(busyIdleCalled)) + }) + t.Run("wrong block type should error", func(t *testing.T) { + meta := &block.MetaBlock{} + + hdr, body, err := sp.CreateBlock(meta, doesHaveTime) + assert.True(t, check.IfNil(body)) + assert.True(t, check.IfNil(hdr)) + assert.Equal(t, process.ErrWrongTypeAssertion, err) + assert.Zero(t, len(busyIdleCalled)) + }) + t.Run("should work with empty header v1", func(t *testing.T) { + header := &block.Header{ + Nonce: 37, + Round: 38, + Epoch: 1, + } + + expectedHeader := &block.Header{ + Nonce: 37, + Round: 38, + Epoch: 1, + ReceiptsHash: []byte("receiptHash"), + DeveloperFees: big.NewInt(0), + AccumulatedFees: big.NewInt(0), + } + + // reset the slice, do not call these tests in parallel + busyIdleCalled = make([]string, 0) + hdr, bodyHandler, err := sp.CreateBlock(header, doesHaveTime) + assert.False(t, check.IfNil(bodyHandler)) + body, ok := bodyHandler.(*block.Body) + assert.True(t, ok) + + assert.Zero(t, len(body.MiniBlocks)) + assert.False(t, check.IfNil(hdr)) + assert.Equal(t, expectedHeader, header) + assert.Nil(t, err) + assert.Equal(t, expectedBusyIdleSequencePerCall, busyIdleCalled) + }) + t.Run("should work with empty header v2", func(t *testing.T) { + header := &block.HeaderV2{ + Header: &block.Header{ + Nonce: 37, + Round: 38, + Epoch: 1, + }, + } + + expectedHeader := &block.HeaderV2{ + Header: &block.Header{ + Nonce: 37, + Round: 38, + Epoch: 1, + ReceiptsHash: []byte("receiptHash"), + DeveloperFees: big.NewInt(0), + AccumulatedFees: big.NewInt(0), + }, + } + + // reset the slice, do not call these tests in parallel + busyIdleCalled = make([]string, 0) + hdr, bodyHandler, err := sp.CreateBlock(header, doesHaveTime) + assert.False(t, check.IfNil(bodyHandler)) + body, ok := bodyHandler.(*block.Body) + assert.True(t, ok) + + assert.Zero(t, len(body.MiniBlocks)) + assert.False(t, check.IfNil(hdr)) + assert.Equal(t, expectedHeader, header) + assert.Nil(t, err) + assert.Equal(t, expectedBusyIdleSequencePerCall, busyIdleCalled) + }) + t.Run("should work with empty header v2 and epoch start rewriting the epoch value", func(t *testing.T) { + argumentsLocal := CreateMockArguments(createComponentHolderMocks()) + argumentsLocal.EpochStartTrigger = &mock.EpochStartTriggerStub{ + IsEpochStartCalled: func() bool { + return true + }, + MetaEpochCalled: func() uint32 { + return 2 + }, + } + + spLocal, err := blproc.NewShardProcessor(argumentsLocal) + assert.Nil(t, err) + + header := &block.HeaderV2{ + Header: &block.Header{ + Nonce: 37, + Round: 38, + Epoch: 1, + }, + } + + expectedHeader := &block.HeaderV2{ + Header: &block.Header{ + Nonce: 37, + Round: 38, + Epoch: 2, // epoch should be re-written + ReceiptsHash: []byte("receiptHash"), + DeveloperFees: big.NewInt(0), + AccumulatedFees: big.NewInt(0), + }, + } + + hdr, bodyHandler, err := spLocal.CreateBlock(header, doesHaveTime) + assert.False(t, check.IfNil(bodyHandler)) + body, ok := bodyHandler.(*block.Body) + assert.True(t, ok) + + assert.Zero(t, len(body.MiniBlocks)) + assert.False(t, check.IfNil(hdr)) + assert.Equal(t, expectedHeader, header) + assert.Nil(t, err) + }) +}