diff --git a/internal/mempool/reactor_test.go b/internal/mempool/reactor_test.go index dab63af73..64a8adca1 100644 --- a/internal/mempool/reactor_test.go +++ b/internal/mempool/reactor_test.go @@ -139,14 +139,14 @@ func (rts *reactorTestSuite) waitForTxns(t *testing.T, txs []types.Tx, ids ...ty } wg.Add(1) - go func(pool *TxMempool) { + go func(name types.NodeID, pool *TxMempool) { defer wg.Done() require.Eventually(t, func() bool { return len(txs) == pool.Size() }, time.Minute, 250*time.Millisecond, - "ntx=%d, size=%d", len(txs), pool.Size(), + "node=%q, ntx=%d, size=%d", name, len(txs), pool.Size(), ) - }(pool) + }(name, pool) } wg.Wait() } @@ -196,8 +196,8 @@ func TestReactorBroadcastDoesNotPanic(t *testing.T) { } func TestReactorBroadcastTxs(t *testing.T) { - numTxs := 1000 - numNodes := 10 + numTxs := 512 + numNodes := 4 ctx, cancel := context.WithCancel(context.Background()) defer cancel() diff --git a/internal/state/execution.go b/internal/state/execution.go index 3423b00f6..e8c8c0f58 100644 --- a/internal/state/execution.go +++ b/internal/state/execution.go @@ -147,7 +147,7 @@ func (blockExec *BlockExecutor) CreateProposalBlock( txrSet := types.NewTxRecordSet(rpp.TxRecords) if err := txrSet.Validate(maxDataBytes, block.Txs); err != nil { - return nil, err + panic(fmt.Errorf("ResponsePrepareProposal validation: %w", err)) } for _, rtx := range txrSet.RemovedTxs() { diff --git a/internal/state/execution_test.go b/internal/state/execution_test.go index dfba6b6b5..3d637422f 100644 --- a/internal/state/execution_test.go +++ b/internal/state/execution_test.go @@ -650,6 +650,64 @@ func TestEmptyPrepareProposal(t *testing.T) { require.NoError(t, err) } +// TestPrepareProposalPanicOnInvalid tests that the block creation logic panics +// if the ResponsePrepareProposal returned from the application is invalid. +func TestPrepareProposalPanicOnInvalid(t *testing.T) { + const height = 2 + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + logger := log.TestingLogger() + eventBus := eventbus.NewDefault(logger) + require.NoError(t, eventBus.Start(ctx)) + + state, stateDB, privVals := makeState(t, 1, height) + stateStore := sm.NewStore(stateDB) + + evpool := &mocks.EvidencePool{} + evpool.On("PendingEvidence", mock.Anything).Return([]types.Evidence{}, int64(0)) + + mp := &mpmocks.Mempool{} + mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs{}) + + app := abcimocks.NewBaseMock() + + // create an invalid ResponsePrepareProposal + rpp := abci.ResponsePrepareProposal{ + ModifiedTx: true, + TxRecords: []*abci.TxRecord{ + { + Action: abci.TxRecord_REMOVED, + Tx: []byte("new tx"), + }, + }, + } + app.On("PrepareProposal", mock.Anything).Return(rpp, nil) + + cc := abciclient.NewLocalClient(logger, app) + proxyApp := proxy.New(cc, logger, proxy.NopMetrics()) + err := proxyApp.Start(ctx) + require.NoError(t, err) + + blockExec := sm.NewBlockExecutor( + stateStore, + logger, + proxyApp, + mp, + evpool, + nil, + eventBus, + ) + pa, _ := state.Validators.GetByIndex(0) + commit := makeValidCommit(ctx, t, height, types.BlockID{}, state.Validators, privVals) + require.Panics(t, + func() { + blockExec.CreateProposalBlock(ctx, height, state, commit, pa, nil) //nolint:errcheck + }) + + mp.AssertExpectations(t) +} + // TestPrepareProposalRemoveTxs tests that any transactions marked as REMOVED // are not included in the block produced by CreateProposalBlock. The test also // ensures that any transactions removed are also removed from the mempool.