mirror of
https://github.com/tendermint/tendermint.git
synced 2026-09-21 07:24:36 +00:00
Use evidence period when pruning (#9505)
* Added logic so when pruning, the evidence period is taken into consideration and only deletes unecessary data
This commit is contained in:
+6
-5
@@ -264,7 +264,7 @@ func (blockExec *BlockExecutor) ApplyBlock(
|
||||
|
||||
// Prune old heights, if requested by ABCI app.
|
||||
if retainHeight > 0 {
|
||||
pruned, err := blockExec.pruneBlocks(retainHeight)
|
||||
pruned, err := blockExec.pruneBlocks(retainHeight, state)
|
||||
if err != nil {
|
||||
blockExec.logger.Error("failed to prune blocks", "retain_height", retainHeight, "err", err)
|
||||
} else {
|
||||
@@ -642,19 +642,20 @@ func ExecCommitBlock(
|
||||
return res.Data, nil
|
||||
}
|
||||
|
||||
func (blockExec *BlockExecutor) pruneBlocks(retainHeight int64) (uint64, error) {
|
||||
func (blockExec *BlockExecutor) pruneBlocks(retainHeight int64, state State) (uint64, error) {
|
||||
base := blockExec.blockStore.Base()
|
||||
if retainHeight <= base {
|
||||
return 0, nil
|
||||
}
|
||||
pruned, err := blockExec.blockStore.PruneBlocks(retainHeight)
|
||||
|
||||
amountPruned, prunedHeaderHeight, err := blockExec.blockStore.PruneBlocks(retainHeight, state)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to prune block store: %w", err)
|
||||
}
|
||||
|
||||
err = blockExec.Store().PruneStates(base, retainHeight)
|
||||
err = blockExec.Store().PruneStates(base, retainHeight, prunedHeaderHeight)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to prune state store: %w", err)
|
||||
}
|
||||
return pruned, nil
|
||||
return amountPruned, nil
|
||||
}
|
||||
|
||||
+18
-10
@@ -4,6 +4,7 @@ package mocks
|
||||
|
||||
import (
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
state "github.com/tendermint/tendermint/state"
|
||||
|
||||
types "github.com/tendermint/tendermint/types"
|
||||
)
|
||||
@@ -183,25 +184,32 @@ func (_m *BlockStore) LoadSeenCommit(height int64) *types.Commit {
|
||||
return r0
|
||||
}
|
||||
|
||||
// PruneBlocks provides a mock function with given fields: height
|
||||
func (_m *BlockStore) PruneBlocks(height int64) (uint64, error) {
|
||||
ret := _m.Called(height)
|
||||
// PruneBlocks provides a mock function with given fields: height, _a1
|
||||
func (_m *BlockStore) PruneBlocks(height int64, _a1 state.State) (uint64, int64, error) {
|
||||
ret := _m.Called(height, _a1)
|
||||
|
||||
var r0 uint64
|
||||
if rf, ok := ret.Get(0).(func(int64) uint64); ok {
|
||||
r0 = rf(height)
|
||||
if rf, ok := ret.Get(0).(func(int64, state.State) uint64); ok {
|
||||
r0 = rf(height, _a1)
|
||||
} else {
|
||||
r0 = ret.Get(0).(uint64)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(int64) error); ok {
|
||||
r1 = rf(height)
|
||||
var r1 int64
|
||||
if rf, ok := ret.Get(1).(func(int64, state.State) int64); ok {
|
||||
r1 = rf(height, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
r1 = ret.Get(1).(int64)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(int64, state.State) error); ok {
|
||||
r2 = rf(height, _a1)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// SaveBlock provides a mock function with given fields: block, blockParts, seenCommit
|
||||
|
||||
@@ -197,13 +197,13 @@ func (_m *Store) LoadValidators(_a0 int64) (*types.ValidatorSet, error) {
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// PruneStates provides a mock function with given fields: _a0, _a1
|
||||
func (_m *Store) PruneStates(_a0 int64, _a1 int64) error {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
// PruneStates provides a mock function with given fields: _a0, _a1, _a2
|
||||
func (_m *Store) PruneStates(_a0 int64, _a1 int64, _a2 int64) error {
|
||||
ret := _m.Called(_a0, _a1, _a2)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(int64, int64) error); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
if rf, ok := ret.Get(0).(func(int64, int64, int64) error); ok {
|
||||
r0 = rf(_a0, _a1, _a2)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ type BlockStore interface {
|
||||
|
||||
SaveBlock(block *types.Block, blockParts *types.PartSet, seenCommit *types.Commit)
|
||||
|
||||
PruneBlocks(height int64) (uint64, error)
|
||||
PruneBlocks(height int64, state State) (uint64, int64, error)
|
||||
|
||||
LoadBlockByHash(hash []byte) *types.Block
|
||||
LoadBlockMetaByHash(hash []byte) *types.BlockMeta
|
||||
|
||||
+16
-6
@@ -68,10 +68,10 @@ type Store interface {
|
||||
Save(State) error
|
||||
// SaveABCIResponses saves ABCIResponses for a given height
|
||||
SaveABCIResponses(int64, *tmstate.ABCIResponses) error
|
||||
// Bootstrap is used for bootstrapping state when not starting from a initial height.
|
||||
// Bootstrap is used for bootstrapping state when not starting from a initial height
|
||||
Bootstrap(State) error
|
||||
// PruneStates takes the height from which to start prning and which height stop at
|
||||
PruneStates(int64, int64) error
|
||||
// PruneStates takes the height from which to start pruning and which height stop at
|
||||
PruneStates(int64, int64, int64) error
|
||||
// Close closes the connection with the database
|
||||
Close() error
|
||||
}
|
||||
@@ -237,14 +237,15 @@ func (store dbStore) Bootstrap(state State) error {
|
||||
// encoding not preserving ordering: https://github.com/tendermint/tendermint/issues/4567
|
||||
// This will cause some old states to be left behind when doing incremental partial prunes,
|
||||
// specifically older checkpoints and LastHeightChanged targets.
|
||||
func (store dbStore) PruneStates(from int64, to int64) error {
|
||||
func (store dbStore) PruneStates(from int64, to int64, evidenceThresholdHeight int64) error {
|
||||
if from <= 0 || to <= 0 {
|
||||
return fmt.Errorf("from height %v and to height %v must be greater than 0", from, to)
|
||||
}
|
||||
if from >= to {
|
||||
return fmt.Errorf("from height %v must be lower than to height %v", from, to)
|
||||
}
|
||||
valInfo, err := loadValidatorsInfo(store.db, to)
|
||||
|
||||
valInfo, err := loadValidatorsInfo(store.db, min(to, evidenceThresholdHeight))
|
||||
if err != nil {
|
||||
return fmt.Errorf("validators at height %v not found: %w", to, err)
|
||||
}
|
||||
@@ -298,12 +299,14 @@ func (store dbStore) PruneStates(from int64, to int64) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else if h < evidenceThresholdHeight {
|
||||
err = batch.Delete(calcValidatorsKey(h))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// else we keep the validator set because we might need
|
||||
// it later on for evidence verification
|
||||
|
||||
if keepParams[h] {
|
||||
p, err := store.loadConsensusParamsInfo(h)
|
||||
@@ -661,3 +664,10 @@ func (store dbStore) saveConsensusParamsInfo(nextHeight, changeHeight int64, par
|
||||
func (store dbStore) Close() error {
|
||||
return store.db.Close()
|
||||
}
|
||||
|
||||
func min(a int64, b int64) int64 {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
+17
-15
@@ -88,23 +88,25 @@ func BenchmarkLoadValidators(b *testing.B) {
|
||||
|
||||
func TestPruneStates(t *testing.T) {
|
||||
testcases := map[string]struct {
|
||||
makeHeights int64
|
||||
pruneFrom int64
|
||||
pruneTo int64
|
||||
expectErr bool
|
||||
expectVals []int64
|
||||
expectParams []int64
|
||||
expectABCI []int64
|
||||
makeHeights int64
|
||||
pruneFrom int64
|
||||
pruneTo int64
|
||||
evidenceThresholdHeight int64
|
||||
expectErr bool
|
||||
expectVals []int64
|
||||
expectParams []int64
|
||||
expectABCI []int64
|
||||
}{
|
||||
"error on pruning from 0": {100, 0, 5, true, nil, nil, nil},
|
||||
"error when from > to": {100, 3, 2, true, nil, nil, nil},
|
||||
"error when from == to": {100, 3, 3, true, nil, nil, nil},
|
||||
"error when to does not exist": {100, 1, 101, true, nil, nil, nil},
|
||||
"prune all": {100, 1, 100, false, []int64{93, 100}, []int64{95, 100}, []int64{100}},
|
||||
"prune some": {10, 2, 8, false, []int64{1, 3, 8, 9, 10},
|
||||
"error on pruning from 0": {100, 0, 5, 100, true, nil, nil, nil},
|
||||
"error when from > to": {100, 3, 2, 2, true, nil, nil, nil},
|
||||
"error when from == to": {100, 3, 3, 3, true, nil, nil, nil},
|
||||
"error when to does not exist": {100, 1, 101, 101, true, nil, nil, nil},
|
||||
"prune all": {100, 1, 100, 100, false, []int64{93, 100}, []int64{95, 100}, []int64{100}},
|
||||
"prune some": {10, 2, 8, 8, false, []int64{1, 3, 8, 9, 10},
|
||||
[]int64{1, 5, 8, 9, 10}, []int64{1, 8, 9, 10}},
|
||||
"prune across checkpoint": {100001, 1, 100001, false, []int64{99993, 100000, 100001},
|
||||
"prune across checkpoint": {100001, 1, 100001, 100001, false, []int64{99993, 100000, 100001},
|
||||
[]int64{99995, 100001}, []int64{100001}},
|
||||
"prune when evidence height < height": {20, 1, 18, 17, false, []int64{13, 17, 18, 19, 20}, []int64{15, 18, 19, 20}, []int64{18, 19, 20}},
|
||||
}
|
||||
for name, tc := range testcases {
|
||||
tc := tc
|
||||
@@ -163,7 +165,7 @@ func TestPruneStates(t *testing.T) {
|
||||
}
|
||||
|
||||
// Test assertions
|
||||
err := stateStore.PruneStates(tc.pruneFrom, tc.pruneTo)
|
||||
err := stateStore.PruneStates(tc.pruneFrom, tc.pruneTo, tc.evidenceThresholdHeight)
|
||||
if tc.expectErr {
|
||||
require.Error(t, err)
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user