Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 10 additions & 20 deletions process/block/pendingMb/pendingMiniBlocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/multiversx/mx-chain-core-go/data"
logger "github.com/multiversx/mx-chain-logger-go"

"github.com/multiversx/mx-chain-go/common"
"github.com/multiversx/mx-chain-go/process"
)

Expand Down Expand Up @@ -52,7 +53,12 @@ func (p *pendingMiniBlocks) getMiniBlocksHashesReadyForCrossShardExecution(metaB
crossShardMiniBlocks[string(mbHeader.GetHash())] = mbHeader.GetReceiverShardID()
}

for _, mbHeader := range metaBlock.GetMiniBlockHeaderHandlers() {
metaMiniBlockHeaders, err := common.GetMiniBlockHeadersFromExecResult(metaBlock)
if err != nil {
return nil, err
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getMiniBlocksHashesReadyForCrossShardExecution now propagates errors from common.GetMiniBlockHeadersFromExecResult (new behavior vs. calling GetMiniBlockHeaderHandlers() directly). There should be a unit test exercising this error path (e.g., a v3 meta header whose execution result handler is nil or a wrong type) to ensure AddProcessedHeader returns the wrapped error as expected.

Suggested change
return nil, err
return nil, fmt.Errorf("pendingMiniBlocks: get meta miniblock headers from exec result: %w", err)

Copilot uses AI. Check for mistakes.
}

for _, mbHeader := range metaMiniBlockHeaders {
if !shouldConsiderCrossShardMiniBlock(mbHeader.GetSenderShardID(), mbHeader.GetReceiverShardID()) {
continue
}
Expand All @@ -65,26 +71,10 @@ func (p *pendingMiniBlocks) getMiniBlocksHashesReadyForCrossShardExecution(metaB

func (p *pendingMiniBlocks) getMiniBlockHandlersFromShardData(metaBlock data.MetaHeaderHandler) ([]data.MiniBlockHeaderHandler, error) {
miniBlocks := make([]data.MiniBlockHeaderHandler, 0)
if !metaBlock.IsHeaderV3() {
for _, shardData := range metaBlock.GetShardInfoHandlers() {
miniblockHandlers := shardData.GetShardMiniBlockHeaderHandlers()
miniBlocks = append(miniBlocks, miniblockHandlers...)
}

return miniBlocks, nil
}

for _, shardData := range metaBlock.GetShardInfoProposalHandlers() {
shardHeader, err := p.headersPool.GetHeaderByHash(shardData.GetHeaderHash())
if err != nil {
log.Debug("getMiniBlockHandlersFromShardData: failed to get from pool",
"hash", shardData.GetHeaderHash(),
"error", err,
)
return nil, err
}

miniBlocks = append(miniBlocks, shardHeader.GetMiniBlockHeaderHandlers()...)
for _, shardData := range metaBlock.GetShardInfoHandlers() {
miniblockHandlers := shardData.GetShardMiniBlockHeaderHandlers()
miniBlocks = append(miniBlocks, miniblockHandlers...)
}

return miniBlocks, nil
Expand Down
99 changes: 86 additions & 13 deletions process/block/pendingMb/pendingMiniBlocks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,11 @@ func createMockHeader(
func TestPendingMiniBlockHeaders_AddProcessedHeader(t *testing.T) {
t.Parallel()

pmb, _ := pendingMb.NewPendingMiniBlocks(&pool.HeadersPoolStub{})
t.Run("same sender and receiver shard, empty pendingMb", func(t *testing.T) {
t.Parallel()

pmb, _ := pendingMb.NewPendingMiniBlocks(&pool.HeadersPoolStub{})

miniBlockHeaders := []block.MiniBlockHeader{
{
Hash: []byte("mb header hash"),
Expand All @@ -92,6 +95,9 @@ func TestPendingMiniBlockHeaders_AddProcessedHeader(t *testing.T) {
assert.Equal(t, 0, len(pendingMiniblocks))
})
t.Run("metachain receiver shard, empty pendingMb", func(t *testing.T) {
t.Parallel()

pmb, _ := pendingMb.NewPendingMiniBlocks(&pool.HeadersPoolStub{})
receivedShardId := core.MetachainShardId
miniBlockHeaders := []block.MiniBlockHeader{
{
Expand All @@ -115,6 +121,9 @@ func TestPendingMiniBlockHeaders_AddProcessedHeader(t *testing.T) {
assert.Equal(t, 0, len(pendingMiniblocks))
})
t.Run("metachain sender shard, empty pendingMb", func(t *testing.T) {
t.Parallel()

pmb, _ := pendingMb.NewPendingMiniBlocks(&pool.HeadersPoolStub{})
miniBlockHeaders := []block.MiniBlockHeader{
{
Hash: []byte("mb header hash"),
Expand All @@ -137,6 +146,9 @@ func TestPendingMiniBlockHeaders_AddProcessedHeader(t *testing.T) {
assert.Equal(t, 0, len(pendingMiniblocks))
})
t.Run("different sender and receiver shard, non empty pendingMb", func(t *testing.T) {
t.Parallel()

pmb, _ := pendingMb.NewPendingMiniBlocks(&pool.HeadersPoolStub{})
receivedShardId := uint32(1)
miniBlockHeaders := []block.MiniBlockHeader{
{
Expand All @@ -159,7 +171,11 @@ func TestPendingMiniBlockHeaders_AddProcessedHeader(t *testing.T) {
pendingMiniblocks := pmb.GetPendingMiniBlocks(receivedShardId)
assert.Equal(t, 2, len(pendingMiniblocks))
})

t.Run("different sender and receiver shard, delete already added, non empty pendingMb", func(t *testing.T) {
t.Parallel()

pmb, _ := pendingMb.NewPendingMiniBlocks(&pool.HeadersPoolStub{})
receivedShardId := uint32(1)
miniBlockHeaders := []block.MiniBlockHeader{
{
Expand Down Expand Up @@ -187,8 +203,15 @@ func TestPendingMiniBlockHeaders_AddProcessedHeader(t *testing.T) {
assert.Nil(t, err)

pendingMiniblocks := pmb.GetPendingMiniBlocks(receivedShardId)
assert.Equal(t, 2, len(pendingMiniblocks))
assert.Equal(t, 4, len(pendingMiniblocks))

err = pmb.AddProcessedHeader(header)
assert.Nil(t, err)

pendingMiniblocks = pmb.GetPendingMiniBlocks(receivedShardId)
assert.Equal(t, 2, len(pendingMiniblocks)) // removed duplicated mbs
})

t.Run("epoch start should reprocess everything", func(t *testing.T) {
t.Parallel()

Expand Down Expand Up @@ -269,6 +292,7 @@ func TestPendingMiniBlockHeaders_AddProcessedHeader(t *testing.T) {
assert.Equal(t, expectedMap, pendingMiniblocks.GetMapPendingMbShard())
assert.Equal(t, expectedBefore, pendingMiniblocks.GetBeforeRevertPendingMbShard())
})

t.Run("MetaBlockV3 with shard data proposals", func(t *testing.T) {
t.Parallel()

Expand Down Expand Up @@ -328,36 +352,85 @@ func TestPendingMiniBlockHeaders_AddProcessedHeader(t *testing.T) {

// Only valid cross-shard miniblocks should be added
pendingMiniblocks := pmbLocal.GetPendingMiniBlocks(1)
assert.Equal(t, 0, len(pendingMiniblocks))
assert.Equal(t, 1, len(pendingMiniblocks)) // shard data mb header is included here
assert.Equal(t, []byte("cross shard 0-1"), pendingMiniblocks[0])

pendingMiniblocks = pmbLocal.GetPendingMiniBlocks(2)
assert.Equal(t, 1, len(pendingMiniblocks))
assert.Equal(t, []byte("cross shard 0-2"), pendingMiniblocks[0])
assert.Equal(t, 0, len(pendingMiniblocks)) // do not consider proposed shard data info

// Invalid miniblocks should not be present
pendingMiniblocks = pmbLocal.GetPendingMiniBlocks(core.MetachainShardId)
assert.Nil(t, pendingMiniblocks)
})
t.Run("MetaBlockV3 with missing header from pool should error", func(t *testing.T) {

t.Run("MetaBlockV3 with execution result miniblocks", func(t *testing.T) {
t.Parallel()

dataPool := &pool.HeadersPoolStub{
GetHeaderByHashCalled: func(hash []byte) (data.HeaderHandler, error) {
return nil, errExpected
},
}
pmbLocal, _ := pendingMb.NewPendingMiniBlocks(dataPool)
pmbLocal, _ := pendingMb.NewPendingMiniBlocks(&pool.HeadersPoolStub{})

header := &block.MetaBlockV3{
Nonce: 1,
ShardInfo: []block.ShardData{
{
ShardMiniBlockHeaders: []block.MiniBlockHeader{
{
Hash: []byte("cross shard 0-1"),
SenderShardID: 0,
ReceiverShardID: 1,
},
},
},
},
ShardInfoProposal: []block.ShardDataProposal{
{
HeaderHash: []byte("proposed header"),
},
},
ExecutionResults: []*block.MetaExecutionResult{
{
ExecutionResult: &block.BaseMetaExecutionResult{},
MiniBlockHeaders: []block.MiniBlockHeader{
{
Hash: []byte("same shard"),
SenderShardID: 1,
ReceiverShardID: 1,
},
{
Hash: []byte("shard to meta"),
SenderShardID: 1,
ReceiverShardID: core.MetachainShardId,
},
{
Hash: []byte("meta to all"),
SenderShardID: core.MetachainShardId,
ReceiverShardID: core.AllShardId,
},
{
Hash: []byte("cross shard 0-2"),
SenderShardID: 0,
ReceiverShardID: 2,
},
},
},
},
}

Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

errExpected is now declared but never used (the previous assertion that referenced it was removed). This will fail go test due to an unused global variable—please remove errExpected or reintroduce a usage where appropriate.

Suggested change
_ = errExpected

Copilot uses AI. Check for mistakes.
err := pmbLocal.AddProcessedHeader(header)
require.Equal(t, errExpected, err)
require.Nil(t, err)

// Only valid cross-shard miniblocks should be added
// added from execution results data from meta
pendingMiniblocks := pmbLocal.GetPendingMiniBlocks(1)
assert.Equal(t, 1, len(pendingMiniblocks))
assert.Equal(t, []byte("cross shard 0-1"), pendingMiniblocks[0])

pendingMiniblocks = pmbLocal.GetPendingMiniBlocks(2)
assert.Equal(t, 1, len(pendingMiniblocks))
assert.Equal(t, []byte("cross shard 0-2"), pendingMiniblocks[0])

// Invalid miniblocks should not be present
pendingMiniblocks = pmbLocal.GetPendingMiniBlocks(core.MetachainShardId)
assert.Nil(t, pendingMiniblocks)
})
}

Expand Down
Loading