Skip to content
Merged
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
27 changes: 27 additions & 0 deletions process/coordinator/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,11 @@ func (tc *transactionCoordinator) ProcessBlockTransaction(
}

miniBlocksFromMe := body.MiniBlocks[mbIndex:]
if !header.IsHeaderV3() &&
shouldDisableOutgoingTxs(tc.enableEpochsHandler, tc.enableRoundsHandler, header) &&
hasForbiddenOutgoingTxMiniBlocks(tc.shardCoordinator.SelfId(), miniBlocksFromMe) {
return process.ErrOutgoingTxsDisabled
}
startTime = time.Now()
err = tc.processMiniBlocksFromMe(header, &block.Body{MiniBlocks: miniBlocksFromMe}, haveTime)
elapsedTime = time.Since(startTime)
Expand All @@ -381,6 +386,28 @@ func (tc *transactionCoordinator) ProcessBlockTransaction(
return nil
}

func shouldDisableOutgoingTxs(
enableEpochsHandler common.EnableEpochsHandler,
enableRoundsHandler common.EnableRoundsHandler,
header data.HeaderHandler,
) bool {
isSupernovaEnabled := enableEpochsHandler.IsFlagEnabledInEpoch(common.SupernovaFlag, header.GetEpoch())
supernovaRoundEnabled := enableRoundsHandler.IsFlagEnabledInRound(common.SupernovaRoundFlag, header.GetRound())
return isSupernovaEnabled && !supernovaRoundEnabled
}

func hasForbiddenOutgoingTxMiniBlocks(selfShardID uint32, miniBlocks block.MiniBlockSlice) bool {
for _, mb := range miniBlocks {
if mb.SenderShardID != selfShardID {
continue
}
if mb.Type == block.TxBlock || mb.Type == block.InvalidBlock {
return true
}
}
return false
}
Comment thread
Copilot marked this conversation as resolved.

// GetCreatedMiniBlocksFromMe returns the created mini blocks from me
func (tc *transactionCoordinator) GetCreatedMiniBlocksFromMe() block.MiniBlockSlice {
miniBlocks := make(block.MiniBlockSlice, 0)
Expand Down
118 changes: 118 additions & 0 deletions process/coordinator/process_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2048,6 +2048,124 @@ func TestTransactionCoordinator_ProcessBlockTransaction(t *testing.T) {
assert.Equal(t, process.ErrMissingTransaction, err)
}

func TestTransactionCoordinator_ProcessBlockTransactionRejectsForbiddenOutgoingTxMiniBlocksDuringSupernovaTransition(t *testing.T) {
t.Parallel()

argsTransactionCoordinator := createMockTransactionCoordinatorArguments()
argsTransactionCoordinator.EnableEpochsHandler = &enableEpochsHandlerMock.EnableEpochsHandlerStub{
IsFlagEnabledInEpochCalled: func(flag core.EnableEpochFlag, epoch uint32) bool {
return flag == common.SupernovaFlag && epoch == 7
},
}
argsTransactionCoordinator.EnableRoundsHandler = &testscommon.EnableRoundsHandlerStub{
IsFlagEnabledInRoundCalled: func(flag common.EnableRoundFlag, round uint64) bool {
return false
},
}

tc, err := NewTransactionCoordinator(argsTransactionCoordinator)
require.NoError(t, err)

haveTime := func() time.Duration {
return time.Second
}

receiverShardID := (tc.shardCoordinator.SelfId() + 1) % tc.shardCoordinator.NumberOfShards()
header, body := getBodyAndHeader(t, tc, block.TxBlock, receiverShardID)
err = tc.ProcessBlockTransaction(header, body, haveTime)
require.ErrorIs(t, err, process.ErrOutgoingTxsDisabled)

header, body = getBodyAndHeader(t, tc, block.InvalidBlock, tc.shardCoordinator.SelfId())
err = tc.ProcessBlockTransaction(header, body, haveTime)
require.ErrorIs(t, err, process.ErrOutgoingTxsDisabled)
}

func getBodyAndHeader(t *testing.T, tc *transactionCoordinator, blockType block.Type, receiverShardID uint32) (data.HeaderHandler, *block.Body) {
miniBlock := &block.MiniBlock{
SenderShardID: tc.shardCoordinator.SelfId(),
ReceiverShardID: receiverShardID,
Type: blockType,
TxHashes: [][]byte{txHash},
}
miniBlockHash, err := core.CalculateHash(tc.marshalizer, tc.hasher, miniBlock)
require.NoError(t, err)

body := &block.Body{MiniBlocks: []*block.MiniBlock{miniBlock}}
header := &block.Header{
Epoch: 7,
Round: 41,
MiniBlockHeaders: []block.MiniBlockHeader{
{Hash: miniBlockHash, TxCount: 1, ReceiverShardID: receiverShardID},
},
}

return header, body
}
Comment on lines +2051 to +2103

@BeniaminDrasovean BeniaminDrasovean Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.


func TestTransactionCoordinator_ProcessBlockTransactionAllowsPostProcessMiniBlocksDuringSupernovaTransition(t *testing.T) {
t.Parallel()

processCalled := false
preProcessor := &preprocMocks.PreProcessorMock{
ProcessBlockTransactionsCalled: func(header data.HeaderHandler, body *block.Body, haveTime func() bool) error {
processCalled = true
require.Len(t, body.MiniBlocks, 1)
require.Equal(t, block.SmartContractResultBlock, body.MiniBlocks[0].Type)
return nil
},
}

argsTransactionCoordinator := createMockTransactionCoordinatorArguments()
argsTransactionCoordinator.PreProcessors = &preprocMocks.PreProcessorContainerMock{
KeysCalled: func() []block.Type {
return []block.Type{block.SmartContractResultBlock}
},
GetCalled: func(key block.Type) (process.PreProcessor, error) {
require.Equal(t, block.SmartContractResultBlock, key)
return preProcessor, nil
},
}
argsTransactionCoordinator.EnableEpochsHandler = &enableEpochsHandlerMock.EnableEpochsHandlerStub{
IsFlagEnabledInEpochCalled: func(flag core.EnableEpochFlag, epoch uint32) bool {
return flag == common.SupernovaFlag && epoch == 7
},
}
argsTransactionCoordinator.EnableRoundsHandler = &testscommon.EnableRoundsHandlerStub{
IsFlagEnabledInRoundCalled: func(flag common.EnableRoundFlag, round uint64) bool {
return false
},
}

tc, err := NewTransactionCoordinator(argsTransactionCoordinator)
require.NoError(t, err)

haveTime := func() time.Duration {
return time.Second
}

selfShardID := tc.shardCoordinator.SelfId()
miniBlock := &block.MiniBlock{
SenderShardID: selfShardID,
ReceiverShardID: selfShardID,
Type: block.SmartContractResultBlock,
}
miniBlockHash, err := core.CalculateHash(tc.marshalizer, tc.hasher, miniBlock)
require.NoError(t, err)

body := &block.Body{MiniBlocks: []*block.MiniBlock{miniBlock}}
header := &block.Header{
Epoch: 7,
Round: 41,
MiniBlockHeaders: []block.MiniBlockHeader{
{Hash: miniBlockHash, TxCount: 0, ReceiverShardID: selfShardID},
},
}

err = tc.ProcessBlockTransaction(header, body, haveTime)
require.NoError(t, err)
require.True(t, processCalled)
}

func TestTransactionCoordinator_ProcessBlockTransaction_DoubleTxs(t *testing.T) {
t.Parallel()

Expand Down
3 changes: 3 additions & 0 deletions process/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -1541,3 +1541,6 @@ 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")

// ErrOutgoingTxsDisabled signals that the outgoing transactions are disabled
var ErrOutgoingTxsDisabled = errors.New("outgoing transactions are disabled")
Loading