Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: ancient blockchain pruner #751

Closed
wants to merge 40 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
c9ef24f
core/state: typo
jsvisa Feb 10, 2023
a4b592c
core/rawdb: backport from https://github.com/bnb-chain/bsc/pull/543
jsvisa Feb 17, 2023
8c35ece
eth,ethdb,node,core/state: backport from https://github.com/bnb-chain…
jsvisa Feb 17, 2023
2b8ca73
eth,core: backport from https://github.com/bnb-chain/bsc/pull/543
jsvisa Feb 17, 2023
4b96e5c
cmd: open db with freeze disabled
jsvisa Feb 17, 2023
4e25407
cli: snapshot prune-block
jsvisa Feb 17, 2023
8bd357f
fix typo
jsvisa Feb 20, 2023
b34d1a5
cli/snapshot: fix the issue of dup open db error
jsvisa Feb 20, 2023
b5f9741
cli/snapshot: resolve datadir and ancient before backup
jsvisa Feb 20, 2023
b4ad6c0
core: more prune-block log
jsvisa Feb 20, 2023
cf25261
core: truncatetail missing f.offset
jsvisa Feb 20, 2023
7397e5a
core/rawdb: indextx adjust offset of pruned block
jsvisa Feb 20, 2023
f7833b7
core/rawdb: freezer batch should implement the offset commit, ref htt…
jsvisa Feb 21, 2023
786c95c
core: check of ancientdb, backport https://github.com/bnb-chain/bsc/p…
jsvisa Feb 21, 2023
ec275a9
core/state: read raw borReceipt to backup
jsvisa Feb 23, 2023
afdeeec
core/rawdb: bor receipt maybe in []Receipt or Receipt RLP format
jsvisa Mar 1, 2023
f91030b
core/state: typo and error msg
jsvisa Mar 1, 2023
727656c
core/rawdb: offSet -> offset
jsvisa Mar 1, 2023
13292b0
cli/snapshot: comment
jsvisa Mar 1, 2023
59e6752
cli/snapshot: add prune-block doc
jsvisa Mar 1, 2023
1b0abf0
docs: add prune-block document
jsvisa Mar 1, 2023
f9ae714
core/rawdb: print wrong bor-receipt length
jsvisa Mar 1, 2023
a3ed4ea
internal/cli: add snapshot prune block tests (referenced from bsc's PR)
manav2401 May 13, 2023
c314ed8
improve errors
manav2401 May 15, 2023
383508a
Merge branch 'develop' into block-pruner
manav2401 May 15, 2023
98c020c
cmd, core, eth, internal: fix lint
manav2401 May 15, 2023
3d71ce5
internal/cli: refactor snapshot prune block test
manav2401 May 16, 2023
f195feb
fix linters in tests
manav2401 May 16, 2023
7104f95
internal/cli: add inspect-ancient-db command, update docs
manav2401 May 17, 2023
54d5a5e
pruner: use a generic function for simplification
manav2401 May 19, 2023
98149be
internal/cli: fixes for inspect-db command
manav2401 May 19, 2023
7c0baba
internal/cli: improve pruning tests
manav2401 May 19, 2023
6276de6
core/rawdb: update end block calculation logic in inspect command
manav2401 May 21, 2023
e21c500
core/rawdb: improve checks db initialisation
manav2401 May 21, 2023
35a95b2
core/rawdb: remove offset check
manav2401 May 21, 2023
495e5cc
update mocks for span, ethdb and add command in makefile
manav2401 May 22, 2023
eda6bac
Merge branch 'develop' into block-pruner
manav2401 May 23, 2023
25a775b
docs/cli: update docs with inspect command
manav2401 May 23, 2023
8cc56a4
Merge branch 'develop' into block-pruner
manav2401 Jun 8, 2023
e813a95
Merge branch 'develop' into block-pruner
manav2401 Jun 20, 2023
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
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ protoc:

generate-mocks:
go generate mockgen -destination=./tests/bor/mocks/IHeimdallClient.go -package=mocks ./consensus/bor IHeimdallClient
go generate mockgen -destination=./eth/filters/IDatabase.go -package=filters ./ethdb Database
go generate mockgen -destination=./eth/filters/IBackend.go -package=filters ./eth/filters Backend

geth:
Expand Down
6 changes: 3 additions & 3 deletions cmd/geth/chaincmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ func importPreimages(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()

db := utils.MakeChainDatabase(ctx, stack, false)
db := utils.MakeChainDatabase(ctx, stack, false, false)
start := time.Now()

if err := utils.ImportPreimages(db, ctx.Args().First()); err != nil {
Expand All @@ -387,7 +387,7 @@ func exportPreimages(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()

db := utils.MakeChainDatabase(ctx, stack, true)
db := utils.MakeChainDatabase(ctx, stack, true, false)
start := time.Now()

if err := utils.ExportPreimages(db, ctx.Args().First()); err != nil {
Expand All @@ -398,7 +398,7 @@ func exportPreimages(ctx *cli.Context) error {
}

func parseDumpConfig(ctx *cli.Context, stack *node.Node) (*state.DumpConfig, ethdb.Database, common.Hash, error) {
db := utils.MakeChainDatabase(ctx, stack, true)
db := utils.MakeChainDatabase(ctx, stack, true, false)
var header *types.Header
if ctx.NArg() > 1 {
return nil, nil, common.Hash{}, fmt.Errorf("expected 1 argument (number or hash), got %d", ctx.NArg())
Expand Down
30 changes: 16 additions & 14 deletions cmd/geth/dbcmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ Remove blockchain and state databases`,
utils.CacheFlag,
utils.CacheDatabaseFlag,
},
Description: `This command performs a database compaction.
Description: `This command performs a database compaction.
WARNING: This operation may take a very long time to finish, and may cause database
corruption if it is aborted during execution'!`,
}
Expand Down Expand Up @@ -166,7 +166,7 @@ corruption if it is aborted during execution'!`,
utils.MumbaiFlag,
utils.BorMainnetFlag,
},
Description: `This command deletes the specified database key from the database.
Description: `This command deletes the specified database key from the database.
WARNING: This is a low-level operation which may cause database corruption!`,
}
dbPutCmd = cli.Command{
Expand All @@ -185,7 +185,7 @@ WARNING: This is a low-level operation which may cause database corruption!`,
utils.MumbaiFlag,
utils.BorMainnetFlag,
},
Description: `This command sets a given database key to the given value.
Description: `This command sets a given database key to the given value.
WARNING: This is a low-level operation which may cause database corruption!`,
}
dbGetSlotsCmd = cli.Command{
Expand Down Expand Up @@ -373,7 +373,7 @@ func inspect(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()

db := utils.MakeChainDatabase(ctx, stack, true)
db := utils.MakeChainDatabase(ctx, stack, true, false)
defer db.Close()

return rawdb.InspectDatabase(db, prefix, start)
Expand All @@ -396,7 +396,7 @@ func dbStats(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()

db := utils.MakeChainDatabase(ctx, stack, true)
db := utils.MakeChainDatabase(ctx, stack, true, false)
defer db.Close()

showLeveldbStats(db)
Expand All @@ -407,7 +407,7 @@ func dbCompact(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()

db := utils.MakeChainDatabase(ctx, stack, false)
db := utils.MakeChainDatabase(ctx, stack, false, false)
defer db.Close()

log.Info("Stats before compaction")
Expand All @@ -431,7 +431,7 @@ func dbGet(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()

db := utils.MakeChainDatabase(ctx, stack, true)
db := utils.MakeChainDatabase(ctx, stack, true, false)
defer db.Close()

key, err := parseHexOrString(ctx.Args().Get(0))
Expand All @@ -457,7 +457,7 @@ func dbDelete(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()

db := utils.MakeChainDatabase(ctx, stack, false)
db := utils.MakeChainDatabase(ctx, stack, false, false)
defer db.Close()

key, err := parseHexOrString(ctx.Args().Get(0))
Expand All @@ -484,7 +484,7 @@ func dbPut(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()

db := utils.MakeChainDatabase(ctx, stack, false)
db := utils.MakeChainDatabase(ctx, stack, false, false)
defer db.Close()

var (
Expand Down Expand Up @@ -518,7 +518,7 @@ func dbDumpTrie(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()

db := utils.MakeChainDatabase(ctx, stack, true)
db := utils.MakeChainDatabase(ctx, stack, true, false)
defer db.Close()
var (
root []byte
Expand Down Expand Up @@ -639,7 +639,8 @@ func importLDBdata(ctx *cli.Context) error {
}
close(stop)
}()
db := utils.MakeChainDatabase(ctx, stack, false)

db := utils.MakeChainDatabase(ctx, stack, false, false)
return utils.ImportLDBData(db, fName, int64(start), stop)
}

Expand Down Expand Up @@ -735,14 +736,15 @@ func exportChaindata(ctx *cli.Context) error {
}
close(stop)
}()
db := utils.MakeChainDatabase(ctx, stack, true)

db := utils.MakeChainDatabase(ctx, stack, true, false)
return utils.ExportChaindata(ctx.Args().Get(1), kind, exporter(db), stop)
}

func showMetaData(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack, true)
db := utils.MakeChainDatabase(ctx, stack, true, false)
ancients, err := db.Ancients()
if err != nil {
fmt.Fprintf(os.Stderr, "Error accessing ancients: %v", err)
Expand Down Expand Up @@ -793,7 +795,7 @@ func freezerMigrate(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()

db := utils.MakeChainDatabase(ctx, stack, false)
db := utils.MakeChainDatabase(ctx, stack, false, false)
defer db.Close()

// Check first block for legacy receipt format
Expand Down
12 changes: 6 additions & 6 deletions cmd/geth/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ geth snapshot traverse-rawstate <state-root>
will traverse the whole state from the given root and will abort if any referenced
trie node or contract code is missing. This command can be used for state integrity
verification. The default checking target is the HEAD state. It's basically identical
to traverse-state, but the check granularity is smaller.
to traverse-state, but the check granularity is smaller.

It's also usable without snapshot enabled.
`,
Expand All @@ -181,7 +181,7 @@ It's also usable without snapshot enabled.
},
Description: `
This command is semantically equivalent to 'geth dump', but uses the snapshots
as the backend data source, making this command a lot faster.
as the backend data source, making this command a lot faster.

The argument is interpreted as block number or hash. If none is provided, the latest
block is used.
Expand All @@ -195,7 +195,7 @@ func pruneState(ctx *cli.Context) error {
stack, config := makeConfigNode(ctx)
defer stack.Close()

chaindb := utils.MakeChainDatabase(ctx, stack, false)
chaindb := utils.MakeChainDatabase(ctx, stack, false, false)
pruner, err := pruner.NewPruner(chaindb, stack.ResolvePath(""), stack.ResolvePath(config.Eth.TrieCleanCacheJournal), ctx.GlobalUint64(utils.BloomFilterSizeFlag.Name))
if err != nil {
log.Error("Failed to open snapshot tree", "err", err)
Expand Down Expand Up @@ -224,7 +224,7 @@ func verifyState(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()

chaindb := utils.MakeChainDatabase(ctx, stack, true)
chaindb := utils.MakeChainDatabase(ctx, stack, true, false)
headBlock := rawdb.ReadHeadBlock(chaindb)
if headBlock == nil {
log.Error("Failed to load head block")
Expand Down Expand Up @@ -262,7 +262,7 @@ func traverseState(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()

chaindb := utils.MakeChainDatabase(ctx, stack, true)
chaindb := utils.MakeChainDatabase(ctx, stack, true, false)
headBlock := rawdb.ReadHeadBlock(chaindb)
if headBlock == nil {
log.Error("Failed to load head block")
Expand Down Expand Up @@ -351,7 +351,7 @@ func traverseRawState(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
defer stack.Close()

chaindb := utils.MakeChainDatabase(ctx, stack, true)
chaindb := utils.MakeChainDatabase(ctx, stack, true, false)
headBlock := rawdb.ReadHeadBlock(chaindb)
if headBlock == nil {
log.Error("Failed to load head block")
Expand Down
8 changes: 4 additions & 4 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -1817,7 +1817,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
}
// Check if we have an already initialized chain and fall back to
// that if so. Otherwise we need to generate a new genesis spec.
chaindb := MakeChainDatabase(ctx, stack, readonly)
chaindb := MakeChainDatabase(ctx, stack, readonly, false)
if rawdb.ReadCanonicalHash(chaindb, 0) != (common.Hash{}) {
cfg.Genesis = nil // fallback to db content
}
Expand Down Expand Up @@ -1977,7 +1977,7 @@ func SplitTagsFlag(tagsFlag string) map[string]string {
}

// MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails.
func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly bool) ethdb.Database {
func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly, disableFreeze bool) ethdb.Database {
var (
cache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
handles = MakeDatabaseHandles(ctx.GlobalInt(FDLimitFlag.Name))
Expand All @@ -1990,7 +1990,7 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly bool) ethdb.
chainDb, err = stack.OpenDatabase(name, cache, handles, "", readonly)
} else {
name := "chaindata"
chainDb, err = stack.OpenDatabaseWithFreezer(name, cache, handles, ctx.GlobalString(AncientFlag.Name), "", readonly)
chainDb, err = stack.OpenDatabaseWithFreezer(name, cache, handles, ctx.GlobalString(AncientFlag.Name), "", readonly, disableFreeze, false)
}
if err != nil {
Fatalf("Could not open database: %v", err)
Expand Down Expand Up @@ -2031,7 +2031,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai
Fatalf("Valid genesis file is required as argument: {}", err)
}

chainDb = MakeChainDatabase(ctx, stack, false) // TODO(rjl493456442) support read-only database
chainDb = MakeChainDatabase(ctx, stack, false, false) // TODO(rjl493456442) support read-only database
config, _, err := core.SetupGenesisBlock(chainDb, genesis)
if err != nil {
Fatalf("%v", err)
Expand Down
11 changes: 8 additions & 3 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,9 +305,9 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
rawdb.InitDatabaseFromFreezer(bc.db)
// If ancient database is not empty, reconstruct all missing
// indices in the background.
frozen, _ := bc.db.Ancients()
frozen, _ := bc.db.ItemAmountInAncient()
if frozen > 0 {
txIndexBlock = frozen
txIndexBlock, _ = bc.db.Ancients()
}
}
if err := bc.loadLastState(); err != nil {
Expand Down Expand Up @@ -344,7 +344,12 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
}

// Ensure that a previous crash in SetHead doesn't leave extra ancients
if frozen, err := bc.db.Ancients(); err == nil && frozen > 0 {
//nolint:nestif
if frozen, err := bc.db.ItemAmountInAncient(); err == nil && frozen > 0 {
frozen, err = bc.db.Ancients()
if err != nil {
return nil, err
}
var (
needRewind bool
low uint64
Expand Down
20 changes: 10 additions & 10 deletions core/blockchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -814,7 +814,7 @@ func TestFastVsFullChains(t *testing.T) {
t.Fatalf("failed to create temp freezer dir: %v", err)
}
defer os.Remove(frdir)
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false)
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false)
if err != nil {
t.Fatalf("failed to create temp freezer db: %v", err)
}
Expand Down Expand Up @@ -910,7 +910,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
t.Fatalf("failed to create temp freezer dir: %v", err)
}
defer os.Remove(dir)
db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), dir, "", false)
db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), dir, "", false, false, false)
if err != nil {
t.Fatalf("failed to create temp freezer db: %v", err)
}
Expand Down Expand Up @@ -1782,7 +1782,7 @@ func TestBlockchainRecovery(t *testing.T) {
}
defer os.Remove(frdir)

ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false)
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false)
if err != nil {
t.Fatalf("failed to create temp freezer db: %v", err)
}
Expand Down Expand Up @@ -1853,7 +1853,7 @@ func TestInsertReceiptChainRollback(t *testing.T) {
t.Fatalf("failed to create temp freezer dir: %v", err)
}
defer os.Remove(frdir)
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false)
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false)
if err != nil {
t.Fatalf("failed to create temp freezer db: %v", err)
}
Expand Down Expand Up @@ -2120,7 +2120,7 @@ func testInsertKnownChainData(t *testing.T, typ string) {
t.Fatalf("failed to create temp freezer dir: %v", err)
}
defer os.Remove(dir)
chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), dir, "", false)
chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), dir, "", false, false, false)
if err != nil {
t.Fatalf("failed to create temp freezer db: %v", err)
}
Expand Down Expand Up @@ -2284,7 +2284,7 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i
t.Fatalf("failed to create temp freezer dir: %v", err)
}
defer os.Remove(dir)
chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), dir, "", false)
chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), dir, "", false, false, false)
if err != nil {
t.Fatalf("failed to create temp freezer db: %v", err)
}
Expand Down Expand Up @@ -2594,7 +2594,7 @@ func TestTransactionIndices(t *testing.T) {
t.Fatalf("failed to create temp freezer dir: %v", err)
}
defer os.Remove(frdir)
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false)
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false)
if err != nil {
t.Fatalf("failed to create temp freezer db: %v", err)
}
Expand Down Expand Up @@ -2622,7 +2622,7 @@ func TestTransactionIndices(t *testing.T) {
// Init block chain with external ancients, check all needed indices has been indexed.
limit := []uint64{0, 32, 64, 128}
for _, l := range limit {
ancientDb, err = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false)
ancientDb, err = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false)
if err != nil {
t.Fatalf("failed to create temp freezer db: %v", err)
}
Expand All @@ -2642,7 +2642,7 @@ func TestTransactionIndices(t *testing.T) {
}

// Reconstruct a block chain which only reserves HEAD-64 tx indices
ancientDb, err = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false)
ancientDb, err = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false)
if err != nil {
t.Fatalf("failed to create temp freezer db: %v", err)
}
Expand Down Expand Up @@ -2721,7 +2721,7 @@ func TestSkipStaleTxIndicesInSnapSync(t *testing.T) {
t.Fatalf("failed to create temp freezer dir: %v", err)
}
defer os.Remove(frdir)
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false)
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false)
if err != nil {
t.Fatalf("failed to create temp freezer db: %v", err)
}
Expand Down
3 changes: 3 additions & 0 deletions core/headerchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ func (hc *HeaderChain) Reorg(headers []*types.Header) error {
headHash = header.Hash()
)
for rawdb.ReadCanonicalHash(hc.chainDb, headNumber) != headHash {
if frozen, _ := hc.chainDb.Ancients(); frozen == headNumber {
break
}
rawdb.WriteCanonicalHash(batch, headHash, headNumber)
if headNumber == 0 {
break // It shouldn't be reached
Expand Down
Loading
Loading