add support for block pruning via ABCI Commit response (#4588)

* Added BlockStore.DeleteBlock()

* Added initial block pruner prototype

* wip

* Added BlockStore.PruneBlocks()

* Added consensus setting for block pruning

* Added BlockStore base

* Error on replay if base does not have blocks

* Handle missing blocks when sending VoteSetMaj23Message

* Error message tweak

* Properly update blockstore state

* Error message fix again

* blockchain: ignore peer missing blocks

* Added FIXME

* Added test for block replay with truncated history

* Handle peer base in blockchain reactor

* Improved replay error handling

* Added tests for Store.PruneBlocks()

* Fix non-RPC handling of truncated block history

* Panic on missing block meta in needProofBlock()

* Updated changelog

* Handle truncated block history in RPC layer

* Added info about earliest block in /status RPC

* Reorder height and base in blockchain reactor messages

* Updated changelog

* Fix tests

* Appease linter

* Minor review fixes

* Non-empty BlockStores should always have base > 0

* Update code to assume base > 0 invariant

* Added blockstore tests for pruning to 0

* Make sure we don't prune below the current base

* Added BlockStore.Size()

* config: added retain_blocks recommendations

* Update v1 blockchain reactor to handle blockstore base

* Added state database pruning

* Propagate errors on missing validator sets

* Comment tweaks

* Improved error message

Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com>

* use ABCI field ResponseCommit.retain_height instead of retain-blocks config option

* remove State.RetainHeight, return value instead

* fix minor issues

* rename pruneHeights() to pruneBlocks()

* noop to fix GitHub borkage

Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
This commit is contained in:
Erik Grinaker
2020-04-03 10:38:32 +02:00
committed by GitHub
parent ce50dda66c
commit 4298bbcc4e
42 changed files with 1208 additions and 393 deletions

View File

@@ -19,42 +19,46 @@ import (
func TestBlockchainInfo(t *testing.T) {
cases := []struct {
min, max int64
height int64
base, height int64
limit int64
resultLength int64
wantErr bool
}{
// min > max
{0, 0, 0, 10, 0, true}, // min set to 1
{0, 1, 0, 10, 0, true}, // max set to height (0)
{0, 0, 1, 10, 1, false}, // max set to height (1)
{2, 0, 1, 10, 0, true}, // max set to height (1)
{2, 1, 5, 10, 0, true},
{0, 0, 0, 0, 10, 0, true}, // min set to 1
{0, 1, 0, 0, 10, 0, true}, // max set to height (0)
{0, 0, 0, 1, 10, 1, false}, // max set to height (1)
{2, 0, 0, 1, 10, 0, true}, // max set to height (1)
{2, 1, 0, 5, 10, 0, true},
// negative
{1, 10, 14, 10, 10, false}, // control
{-1, 10, 14, 10, 0, true},
{1, -10, 14, 10, 0, true},
{-9223372036854775808, -9223372036854775788, 100, 20, 0, true},
{1, 10, 0, 14, 10, 10, false}, // control
{-1, 10, 0, 14, 10, 0, true},
{1, -10, 0, 14, 10, 0, true},
{-9223372036854775808, -9223372036854775788, 0, 100, 20, 0, true},
// check base
{1, 1, 1, 1, 1, 1, false},
{2, 5, 3, 5, 5, 3, false},
// check limit and height
{1, 1, 1, 10, 1, false},
{1, 1, 5, 10, 1, false},
{2, 2, 5, 10, 1, false},
{1, 2, 5, 10, 2, false},
{1, 5, 1, 10, 1, false},
{1, 5, 10, 10, 5, false},
{1, 15, 10, 10, 10, false},
{1, 15, 15, 10, 10, false},
{1, 15, 15, 20, 15, false},
{1, 20, 15, 20, 15, false},
{1, 20, 20, 20, 20, false},
{1, 1, 0, 1, 10, 1, false},
{1, 1, 0, 5, 10, 1, false},
{2, 2, 0, 5, 10, 1, false},
{1, 2, 0, 5, 10, 2, false},
{1, 5, 0, 1, 10, 1, false},
{1, 5, 0, 10, 10, 5, false},
{1, 15, 0, 10, 10, 10, false},
{1, 15, 0, 15, 10, 10, false},
{1, 15, 0, 15, 20, 15, false},
{1, 20, 0, 15, 20, 15, false},
{1, 20, 0, 20, 20, 20, false},
}
for i, c := range cases {
caseString := fmt.Sprintf("test %d failed", i)
min, max, err := filterMinMax(c.height, c.min, c.max, c.limit)
min, max, err := filterMinMax(c.base, c.height, c.min, c.max, c.limit)
if c.wantErr {
require.Error(t, err, caseString)
} else {
@@ -112,12 +116,15 @@ type mockBlockStore struct {
height int64
}
func (mockBlockStore) Base() int64 { return 1 }
func (store mockBlockStore) Height() int64 { return store.height }
func (store mockBlockStore) Size() int64 { return store.height }
func (mockBlockStore) LoadBlockMeta(height int64) *types.BlockMeta { return nil }
func (mockBlockStore) LoadBlock(height int64) *types.Block { return nil }
func (mockBlockStore) LoadBlockByHash(hash []byte) *types.Block { return nil }
func (mockBlockStore) LoadBlockPart(height int64, index int) *types.Part { return nil }
func (mockBlockStore) LoadBlockCommit(height int64) *types.Commit { return nil }
func (mockBlockStore) LoadSeenCommit(height int64) *types.Commit { return nil }
func (mockBlockStore) PruneBlocks(height int64) (uint64, error) { return 0, nil }
func (mockBlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, seenCommit *types.Commit) {
}