state: move pruneBlocks from consensus/state to state/execution (#9443)

This commit is contained in:
JayT106
2022-09-20 05:30:22 -04:00
committed by GitHub
parent a8efef1854
commit db26cff58f
17 changed files with 123 additions and 83 deletions

View File

@@ -25,6 +25,9 @@ type BlockExecutor struct {
// save state, validators, consensus params, abci responses here
store Store
// use blockstore for the pruning functions.
blockStore BlockStore
// execute the app against this
proxyApp proxy.AppConnConsensus
@@ -57,16 +60,18 @@ func NewBlockExecutor(
proxyApp proxy.AppConnConsensus,
mempool mempool.Mempool,
evpool EvidencePool,
blockStore BlockStore,
options ...BlockExecutorOption,
) *BlockExecutor {
res := &BlockExecutor{
store: stateStore,
proxyApp: proxyApp,
eventBus: types.NopEventBus{},
mempool: mempool,
evpool: evpool,
logger: logger,
metrics: NopMetrics(),
store: stateStore,
proxyApp: proxyApp,
eventBus: types.NopEventBus{},
mempool: mempool,
evpool: evpool,
logger: logger,
metrics: NopMetrics(),
blockStore: blockStore,
}
for _, option := range options {
@@ -182,16 +187,16 @@ func (blockExec *BlockExecutor) ValidateBlock(state State, block *types.Block) e
// ApplyBlock validates the block against the state, executes it against the app,
// fires the relevant events, commits the app, and saves the new state and responses.
// It returns the new state and the block height to retain (pruning older blocks).
// It returns the new state.
// It's the only function that needs to be called
// from outside this package to process and commit an entire block.
// It takes a blockID to avoid recomputing the parts hash.
func (blockExec *BlockExecutor) ApplyBlock(
state State, blockID types.BlockID, block *types.Block,
) (State, int64, error) {
) (State, error) {
if err := validateBlock(state, block); err != nil {
return state, 0, ErrInvalidBlock(err)
return state, ErrInvalidBlock(err)
}
startTime := time.Now().UnixNano()
@@ -201,14 +206,14 @@ func (blockExec *BlockExecutor) ApplyBlock(
endTime := time.Now().UnixNano()
blockExec.metrics.BlockProcessingTime.Observe(float64(endTime-startTime) / 1000000)
if err != nil {
return state, 0, ErrProxyAppConn(err)
return state, ErrProxyAppConn(err)
}
fail.Fail() // XXX
// Save the results before we commit.
if err := blockExec.store.SaveABCIResponses(block.Height, abciResponses); err != nil {
return state, 0, err
return state, err
}
fail.Fail() // XXX
@@ -217,12 +222,12 @@ func (blockExec *BlockExecutor) ApplyBlock(
abciValUpdates := abciResponses.EndBlock.ValidatorUpdates
err = validateValidatorUpdates(abciValUpdates, state.ConsensusParams.Validator)
if err != nil {
return state, 0, fmt.Errorf("error in validator updates: %v", err)
return state, fmt.Errorf("error in validator updates: %v", err)
}
validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciValUpdates)
if err != nil {
return state, 0, err
return state, err
}
if len(validatorUpdates) > 0 {
blockExec.logger.Debug("updates to validators", "updates", types.ValidatorListString(validatorUpdates))
@@ -235,13 +240,13 @@ func (blockExec *BlockExecutor) ApplyBlock(
// Update the state with the block and responses.
state, err = updateState(state, blockID, &block.Header, abciResponses, validatorUpdates)
if err != nil {
return state, 0, fmt.Errorf("commit failed for application: %v", err)
return state, fmt.Errorf("commit failed for application: %v", err)
}
// Lock mempool, commit app state, update mempoool.
appHash, retainHeight, err := blockExec.Commit(state, block, abciResponses.DeliverTxs)
if err != nil {
return state, 0, fmt.Errorf("commit failed for application: %v", err)
return state, fmt.Errorf("commit failed for application: %v", err)
}
// Update evpool with the latest state.
@@ -252,16 +257,26 @@ func (blockExec *BlockExecutor) ApplyBlock(
// Update the app hash and save the state.
state.AppHash = appHash
if err := blockExec.store.Save(state); err != nil {
return state, 0, err
return state, err
}
fail.Fail() // XXX
// Prune old heights, if requested by ABCI app.
if retainHeight > 0 {
pruned, err := blockExec.pruneBlocks(retainHeight)
if err != nil {
blockExec.logger.Error("failed to prune blocks", "retain_height", retainHeight, "err", err)
} else {
blockExec.logger.Debug("pruned blocks", "pruned", pruned, "retain_height", retainHeight)
}
}
// Events are fired after everything else.
// NOTE: if we crash between Commit and Save, events wont be fired during replay
fireEvents(blockExec.logger, blockExec.eventBus, block, abciResponses, validatorUpdates)
return state, retainHeight, nil
return state, nil
}
// Commit locks the mempool, runs the ABCI Commit message, and updates the
@@ -626,3 +641,20 @@ func ExecCommitBlock(
// ResponseCommit has no error or log, just data
return res.Data, nil
}
func (blockExec *BlockExecutor) pruneBlocks(retainHeight int64) (uint64, error) {
base := blockExec.blockStore.Base()
if retainHeight <= base {
return 0, nil
}
pruned, err := blockExec.blockStore.PruneBlocks(retainHeight)
if err != nil {
return 0, fmt.Errorf("failed to prune block store: %w", err)
}
err = blockExec.Store().PruneStates(base, retainHeight)
if err != nil {
return 0, fmt.Errorf("failed to prune state store: %w", err)
}
return pruned, nil
}

View File

@@ -25,9 +25,11 @@ import (
pmocks "github.com/tendermint/tendermint/proxy/mocks"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/state/mocks"
"github.com/tendermint/tendermint/store"
"github.com/tendermint/tendermint/types"
tmtime "github.com/tendermint/tendermint/types/time"
"github.com/tendermint/tendermint/version"
dbm "github.com/tendermint/tm-db"
)
var (
@@ -47,6 +49,8 @@ func TestApplyBlock(t *testing.T) {
stateStore := sm.NewStore(stateDB, sm.StoreOptions{
DiscardABCIResponses: false,
})
blockStore := store.NewBlockStore(dbm.NewMemDB())
mp := &mpmocks.Mempool{}
mp.On("Lock").Return()
mp.On("Unlock").Return()
@@ -59,16 +63,15 @@ func TestApplyBlock(t *testing.T) {
mock.Anything,
mock.Anything).Return(nil)
blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(),
mp, sm.EmptyEvidencePool{})
mp, sm.EmptyEvidencePool{}, blockStore)
block := makeBlock(state, 1, new(types.Commit))
bps, err := block.MakePartSet(testPartSize)
require.NoError(t, err)
blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()}
state, retainHeight, err := blockExec.ApplyBlock(state, blockID, block)
state, err = blockExec.ApplyBlock(state, blockID, block)
require.Nil(t, err)
assert.EqualValues(t, retainHeight, 1)
// TODO check state and mempool
assert.EqualValues(t, 1, state.Version.Consensus.App, "App version wasn't updated")
@@ -231,8 +234,10 @@ func TestBeginBlockByzantineValidators(t *testing.T) {
mock.Anything,
mock.Anything).Return(nil)
blockStore := store.NewBlockStore(dbm.NewMemDB())
blockExec := sm.NewBlockExecutor(stateStore, log.TestingLogger(), proxyApp.Consensus(),
mp, evpool)
mp, evpool, blockStore)
block := makeBlock(state, 1, new(types.Commit))
block.Evidence = types.EvidenceData{Evidence: ev}
@@ -242,9 +247,8 @@ func TestBeginBlockByzantineValidators(t *testing.T) {
blockID = types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()}
state, retainHeight, err := blockExec.ApplyBlock(state, blockID, block)
state, err = blockExec.ApplyBlock(state, blockID, block)
require.Nil(t, err)
assert.EqualValues(t, retainHeight, 1)
// TODO check state and mempool
assert.Equal(t, abciMb, app.Misbehavior)
@@ -268,7 +272,7 @@ func TestProcessProposal(t *testing.T) {
stateStore := sm.NewStore(stateDB, sm.StoreOptions{
DiscardABCIResponses: false,
})
blockStore := store.NewBlockStore(dbm.NewMemDB())
eventBus := types.NewEventBus()
err = eventBus.Start()
require.NoError(t, err)
@@ -279,6 +283,7 @@ func TestProcessProposal(t *testing.T) {
proxyApp.Consensus(),
new(mpmocks.Mempool),
sm.EmptyEvidencePool{},
blockStore,
)
block0 := makeBlock(state, height-1, new(types.Commit))
@@ -488,12 +493,14 @@ func TestEndBlockValidatorUpdates(t *testing.T) {
mock.Anything).Return(nil)
mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs{})
blockStore := store.NewBlockStore(dbm.NewMemDB())
blockExec := sm.NewBlockExecutor(
stateStore,
log.TestingLogger(),
proxyApp.Consensus(),
mp,
sm.EmptyEvidencePool{},
blockStore,
)
eventBus := types.NewEventBus()
@@ -522,7 +529,7 @@ func TestEndBlockValidatorUpdates(t *testing.T) {
{PubKey: pk, Power: 10},
}
state, _, err = blockExec.ApplyBlock(state, blockID, block)
state, err = blockExec.ApplyBlock(state, blockID, block)
require.Nil(t, err)
// test new validator was added to NextValidators
if assert.Equal(t, state.Validators.Size()+1, state.NextValidators.Size()) {
@@ -562,12 +569,14 @@ func TestEndBlockValidatorUpdatesResultingInEmptySet(t *testing.T) {
stateStore := sm.NewStore(stateDB, sm.StoreOptions{
DiscardABCIResponses: false,
})
blockStore := store.NewBlockStore(dbm.NewMemDB())
blockExec := sm.NewBlockExecutor(
stateStore,
log.TestingLogger(),
proxyApp.Consensus(),
new(mpmocks.Mempool),
sm.EmptyEvidencePool{},
blockStore,
)
block := makeBlock(state, 1, new(types.Commit))
@@ -582,7 +591,7 @@ func TestEndBlockValidatorUpdatesResultingInEmptySet(t *testing.T) {
{PubKey: vp, Power: 0},
}
assert.NotPanics(t, func() { state, _, err = blockExec.ApplyBlock(state, blockID, block) })
assert.NotPanics(t, func() { state, err = blockExec.ApplyBlock(state, blockID, block) })
assert.NotNil(t, err)
assert.NotEmpty(t, state.NextValidators.Validators)
}
@@ -614,12 +623,14 @@ func TestEmptyPrepareProposal(t *testing.T) {
mock.Anything).Return(nil)
mp.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(types.Txs{})
blockStore := store.NewBlockStore(dbm.NewMemDB())
blockExec := sm.NewBlockExecutor(
stateStore,
log.TestingLogger(),
proxyApp.Consensus(),
mp,
sm.EmptyEvidencePool{},
blockStore,
)
pa, _ := state.Validators.GetByIndex(0)
commit, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals)
@@ -655,12 +666,14 @@ func TestPrepareProposalTxsAllIncluded(t *testing.T) {
require.NoError(t, err)
defer proxyApp.Stop() //nolint:errcheck // ignore for tests
blockStore := store.NewBlockStore(dbm.NewMemDB())
blockExec := sm.NewBlockExecutor(
stateStore,
log.TestingLogger(),
proxyApp.Consensus(),
mp,
evpool,
blockStore,
)
pa, _ := state.Validators.GetByIndex(0)
commit, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals)
@@ -706,12 +719,14 @@ func TestPrepareProposalReorderTxs(t *testing.T) {
require.NoError(t, err)
defer proxyApp.Stop() //nolint:errcheck // ignore for tests
blockStore := store.NewBlockStore(dbm.NewMemDB())
blockExec := sm.NewBlockExecutor(
stateStore,
log.TestingLogger(),
proxyApp.Consensus(),
mp,
evpool,
blockStore,
)
pa, _ := state.Validators.GetByIndex(0)
commit, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals)
@@ -759,12 +774,14 @@ func TestPrepareProposalErrorOnTooManyTxs(t *testing.T) {
require.NoError(t, err)
defer proxyApp.Stop() //nolint:errcheck // ignore for tests
blockStore := store.NewBlockStore(dbm.NewMemDB())
blockExec := sm.NewBlockExecutor(
stateStore,
log.NewNopLogger(),
proxyApp.Consensus(),
mp,
evpool,
blockStore,
)
pa, _ := state.Validators.GetByIndex(0)
commit, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals)
@@ -807,12 +824,14 @@ func TestPrepareProposalErrorOnPrepareProposalError(t *testing.T) {
require.NoError(t, err)
defer proxyApp.Stop() //nolint:errcheck // ignore for tests
blockStore := store.NewBlockStore(dbm.NewMemDB())
blockExec := sm.NewBlockExecutor(
stateStore,
log.NewNopLogger(),
proxyApp.Consensus(),
mp,
evpool,
blockStore,
)
pa, _ := state.Validators.GetByIndex(0)
commit, err := makeValidCommit(height, types.BlockID{}, state.Validators, privVals)

View File

@@ -66,7 +66,7 @@ func makeAndApplyGoodBlock(state sm.State, height int64, lastCommit *types.Commi
}
blockID := types.BlockID{Hash: block.Hash(),
PartSetHeader: partSet.Header()}
state, _, err = blockExec.ApplyBlock(state, blockID, block)
state, err = blockExec.ApplyBlock(state, blockID, block)
if err != nil {
return state, types.BlockID{}, err
}

View File

@@ -17,8 +17,10 @@ import (
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
sm "github.com/tendermint/tendermint/state"
"github.com/tendermint/tendermint/state/mocks"
"github.com/tendermint/tendermint/store"
"github.com/tendermint/tendermint/types"
tmtime "github.com/tendermint/tendermint/types/time"
dbm "github.com/tendermint/tm-db"
)
const validationTestsStopHeight int64 = 10
@@ -44,12 +46,15 @@ func TestValidateBlockHeader(t *testing.T) {
mock.Anything,
mock.Anything).Return(nil)
blockStore := store.NewBlockStore(dbm.NewMemDB())
blockExec := sm.NewBlockExecutor(
stateStore,
log.TestingLogger(),
proxyApp.Consensus(),
mp,
sm.EmptyEvidencePool{},
blockStore,
)
lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil)
@@ -129,12 +134,15 @@ func TestValidateBlockCommit(t *testing.T) {
mock.Anything,
mock.Anything).Return(nil)
blockStore := store.NewBlockStore(dbm.NewMemDB())
blockExec := sm.NewBlockExecutor(
stateStore,
log.TestingLogger(),
proxyApp.Consensus(),
mp,
sm.EmptyEvidencePool{},
blockStore,
)
lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil)
wrongSigsCommit := types.NewCommit(1, 0, types.BlockID{}, nil)
@@ -268,12 +276,15 @@ func TestValidateBlockEvidence(t *testing.T) {
mock.Anything,
mock.Anything).Return(nil)
state.ConsensusParams.Evidence.MaxBytes = 1000
blockStore := store.NewBlockStore(dbm.NewMemDB())
blockExec := sm.NewBlockExecutor(
stateStore,
log.TestingLogger(),
proxyApp.Consensus(),
mp,
evpool,
blockStore,
)
lastCommit := types.NewCommit(0, 0, types.BlockID{}, nil)