2022-01-20 07:34:50 +00:00
|
|
|
package app
|
2021-12-27 07:59:29 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/binary"
|
|
|
|
"fmt"
|
|
|
|
"path"
|
2022-02-12 13:33:09 +00:00
|
|
|
"path/filepath"
|
2022-01-06 07:13:09 +00:00
|
|
|
"runtime"
|
2021-12-27 07:59:29 +00:00
|
|
|
|
|
|
|
"github.com/holiman/uint256"
|
2022-01-19 03:49:07 +00:00
|
|
|
"github.com/ledgerwatch/erigon-lib/common"
|
2022-02-18 02:24:17 +00:00
|
|
|
"github.com/ledgerwatch/erigon-lib/common/dir"
|
2022-01-06 11:22:59 +00:00
|
|
|
"github.com/ledgerwatch/erigon-lib/etl"
|
2021-12-27 07:59:29 +00:00
|
|
|
"github.com/ledgerwatch/erigon-lib/kv"
|
|
|
|
"github.com/ledgerwatch/erigon-lib/kv/mdbx"
|
|
|
|
"github.com/ledgerwatch/erigon/cmd/hack/tool"
|
|
|
|
"github.com/ledgerwatch/erigon/cmd/utils"
|
|
|
|
"github.com/ledgerwatch/erigon/core/rawdb"
|
2022-01-20 05:01:02 +00:00
|
|
|
"github.com/ledgerwatch/erigon/eth/ethconfig"
|
2022-01-09 07:43:58 +00:00
|
|
|
"github.com/ledgerwatch/erigon/internal/debug"
|
2022-01-03 04:39:20 +00:00
|
|
|
"github.com/ledgerwatch/erigon/params"
|
2021-12-27 07:59:29 +00:00
|
|
|
"github.com/ledgerwatch/erigon/turbo/snapshotsync"
|
|
|
|
"github.com/ledgerwatch/log/v3"
|
|
|
|
"github.com/urfave/cli"
|
|
|
|
)
|
|
|
|
|
|
|
|
const ASSERT = false
|
|
|
|
|
|
|
|
var snapshotCommand = cli.Command{
|
2021-12-31 04:53:15 +00:00
|
|
|
Name: "snapshots",
|
2022-01-05 10:14:37 +00:00
|
|
|
Description: `Managing snapshots (historical data partitions)`,
|
2021-12-27 07:59:29 +00:00
|
|
|
Subcommands: []cli.Command{
|
|
|
|
{
|
|
|
|
Name: "create",
|
|
|
|
Action: doSnapshotCommand,
|
2022-01-05 10:14:37 +00:00
|
|
|
Usage: "Create snapshots for given range of blocks",
|
2022-01-09 08:30:26 +00:00
|
|
|
Before: func(ctx *cli.Context) error { return debug.Setup(ctx) },
|
2022-01-09 07:43:58 +00:00
|
|
|
Flags: append([]cli.Flag{
|
2021-12-27 07:59:29 +00:00
|
|
|
utils.DataDirFlag,
|
|
|
|
SnapshotFromFlag,
|
2022-01-03 04:39:20 +00:00
|
|
|
SnapshotToFlag,
|
2021-12-27 07:59:29 +00:00
|
|
|
SnapshotSegmentSizeFlag,
|
2022-01-09 07:43:58 +00:00
|
|
|
}, debug.Flags...),
|
2021-12-27 07:59:29 +00:00
|
|
|
},
|
2022-02-22 08:35:04 +00:00
|
|
|
{
|
|
|
|
Name: "recompress",
|
|
|
|
Action: doRecompressCommand,
|
|
|
|
Usage: "Recompress existing .seg files to apply new compression rules",
|
|
|
|
Before: func(ctx *cli.Context) error { return debug.Setup(ctx) },
|
|
|
|
Flags: append([]cli.Flag{
|
|
|
|
utils.DataDirFlag,
|
|
|
|
}, debug.Flags...),
|
|
|
|
},
|
2022-01-06 11:22:59 +00:00
|
|
|
{
|
|
|
|
Name: "index",
|
|
|
|
Action: doIndicesCommand,
|
|
|
|
Usage: "Create all indices for snapshots",
|
2022-01-09 08:30:26 +00:00
|
|
|
Before: func(ctx *cli.Context) error { return debug.Setup(ctx) },
|
2022-01-09 07:43:58 +00:00
|
|
|
Flags: append([]cli.Flag{
|
2022-01-06 11:22:59 +00:00
|
|
|
utils.DataDirFlag,
|
2022-02-10 07:40:29 +00:00
|
|
|
SnapshotFromFlag,
|
2022-01-09 07:43:58 +00:00
|
|
|
SnapshotRebuildFlag,
|
|
|
|
}, debug.Flags...),
|
2022-01-06 11:22:59 +00:00
|
|
|
},
|
2022-02-24 04:30:34 +00:00
|
|
|
{
|
|
|
|
Name: "retire",
|
|
|
|
Action: doRetireCommand,
|
|
|
|
Usage: "Build snapshots for some recent blocks",
|
|
|
|
Before: func(ctx *cli.Context) error { return debug.Setup(ctx) },
|
|
|
|
Flags: append([]cli.Flag{
|
|
|
|
utils.DataDirFlag,
|
|
|
|
SnapshotFromFlag,
|
|
|
|
SnapshotToFlag,
|
2022-03-12 10:26:11 +00:00
|
|
|
SnapshotEveryFlag,
|
2022-02-24 04:30:34 +00:00
|
|
|
}, debug.Flags...),
|
|
|
|
},
|
2021-12-27 07:59:29 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
SnapshotFromFlag = cli.Uint64Flag{
|
2022-01-05 10:14:37 +00:00
|
|
|
Name: "from",
|
|
|
|
Usage: "From block number",
|
|
|
|
Value: 0,
|
2021-12-27 07:59:29 +00:00
|
|
|
}
|
2022-01-03 04:39:20 +00:00
|
|
|
SnapshotToFlag = cli.Uint64Flag{
|
2022-01-05 10:14:37 +00:00
|
|
|
Name: "to",
|
|
|
|
Usage: "To block number. Zero - means unlimited.",
|
|
|
|
Value: 0,
|
2022-01-03 04:39:20 +00:00
|
|
|
}
|
2022-03-12 10:26:11 +00:00
|
|
|
SnapshotEveryFlag = cli.Uint64Flag{
|
|
|
|
Name: "every",
|
|
|
|
Usage: "Do operation every N blocks",
|
|
|
|
Value: 1_000,
|
|
|
|
}
|
2021-12-27 07:59:29 +00:00
|
|
|
SnapshotSegmentSizeFlag = cli.Uint64Flag{
|
2022-01-05 10:14:37 +00:00
|
|
|
Name: "segment.size",
|
|
|
|
Usage: "Amount of blocks in each segment",
|
2022-01-20 05:01:02 +00:00
|
|
|
Value: snapshotsync.DEFAULT_SEGMENT_SIZE,
|
2021-12-27 07:59:29 +00:00
|
|
|
}
|
2022-01-09 07:43:58 +00:00
|
|
|
SnapshotRebuildFlag = cli.BoolFlag{
|
|
|
|
Name: "rebuild",
|
|
|
|
Usage: "Force rebuild",
|
|
|
|
}
|
2021-12-27 07:59:29 +00:00
|
|
|
)
|
|
|
|
|
2022-01-06 11:22:59 +00:00
|
|
|
func doIndicesCommand(cliCtx *cli.Context) error {
|
2022-01-19 03:49:07 +00:00
|
|
|
ctx, cancel := common.RootContext()
|
2022-01-06 11:22:59 +00:00
|
|
|
defer cancel()
|
|
|
|
|
2022-02-22 17:39:48 +00:00
|
|
|
datadir := cliCtx.String(utils.DataDirFlag.Name)
|
|
|
|
snapshotDir := filepath.Join(datadir, "snapshots")
|
|
|
|
tmpDir := filepath.Join(datadir, etl.TmpDirName)
|
2022-01-09 07:43:58 +00:00
|
|
|
rebuild := cliCtx.Bool(SnapshotRebuildFlag.Name)
|
2022-02-10 07:40:29 +00:00
|
|
|
from := cliCtx.Uint64(SnapshotFromFlag.Name)
|
2022-01-06 11:22:59 +00:00
|
|
|
|
2022-02-22 17:39:48 +00:00
|
|
|
chainDB := mdbx.NewMDBX(log.New()).Path(path.Join(datadir, "chaindata")).Readonly().MustOpen()
|
2022-01-06 11:22:59 +00:00
|
|
|
defer chainDB.Close()
|
|
|
|
|
2022-01-09 07:43:58 +00:00
|
|
|
if rebuild {
|
2022-01-22 04:18:24 +00:00
|
|
|
cfg := ethconfig.NewSnapshotCfg(true, true)
|
2022-02-18 02:24:17 +00:00
|
|
|
rwSnapshotDir, err := dir.OpenRw(snapshotDir)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer rwSnapshotDir.Close()
|
|
|
|
if err := rebuildIndices(ctx, chainDB, cfg, rwSnapshotDir, tmpDir, from); err != nil {
|
2022-01-09 07:43:58 +00:00
|
|
|
log.Error("Error", "err", err)
|
|
|
|
}
|
2022-01-06 11:22:59 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2022-02-04 05:42:55 +00:00
|
|
|
|
2022-02-24 04:30:34 +00:00
|
|
|
func doRetireCommand(cliCtx *cli.Context) error {
|
|
|
|
ctx, cancel := common.RootContext()
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
datadir := cliCtx.String(utils.DataDirFlag.Name)
|
|
|
|
snapshotDir := filepath.Join(datadir, "snapshots")
|
|
|
|
tmpDir := filepath.Join(datadir, etl.TmpDirName)
|
|
|
|
from := cliCtx.Uint64(SnapshotFromFlag.Name)
|
|
|
|
to := cliCtx.Uint64(SnapshotToFlag.Name)
|
2022-03-12 10:26:11 +00:00
|
|
|
every := cliCtx.Uint64(SnapshotEveryFlag.Name)
|
2022-02-24 04:30:34 +00:00
|
|
|
|
2022-03-12 10:26:11 +00:00
|
|
|
chainDB := mdbx.NewMDBX(log.New()).Label(kv.ChainDB).Path(path.Join(datadir, "chaindata")).Readonly().MustOpen()
|
2022-02-24 04:30:34 +00:00
|
|
|
defer chainDB.Close()
|
|
|
|
|
|
|
|
cfg := ethconfig.NewSnapshotCfg(true, true)
|
|
|
|
rwSnapshotDir, err := dir.OpenRw(snapshotDir)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer rwSnapshotDir.Close()
|
|
|
|
chainConfig := tool.ChainConfigFromDB(chainDB)
|
|
|
|
chainID, _ := uint256.FromBig(chainConfig.ChainID)
|
|
|
|
snapshots := snapshotsync.NewRoSnapshots(cfg, snapshotDir)
|
2022-03-12 10:26:11 +00:00
|
|
|
snapshots.ReopenSegments()
|
2022-02-24 04:30:34 +00:00
|
|
|
|
2022-03-24 02:25:38 +00:00
|
|
|
br := snapshotsync.NewBlockRetire(runtime.NumCPU()/2, tmpDir, snapshots, chainDB, nil, nil)
|
2022-03-16 02:57:48 +00:00
|
|
|
|
2022-03-12 10:26:11 +00:00
|
|
|
for i := from; i < to; i += every {
|
2022-03-16 02:57:48 +00:00
|
|
|
br.RetireBlocksInBackground(ctx, i, i+every, *chainID, log.LvlInfo)
|
|
|
|
br.Wait()
|
|
|
|
res := br.Result()
|
|
|
|
if res.Err != nil {
|
|
|
|
panic(res.Err)
|
2022-03-12 10:26:11 +00:00
|
|
|
}
|
2022-02-24 04:30:34 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-01-09 07:43:58 +00:00
|
|
|
func doSnapshotCommand(cliCtx *cli.Context) error {
|
2022-01-19 03:49:07 +00:00
|
|
|
ctx, cancel := common.RootContext()
|
2022-01-09 07:43:58 +00:00
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
fromBlock := cliCtx.Uint64(SnapshotFromFlag.Name)
|
|
|
|
toBlock := cliCtx.Uint64(SnapshotToFlag.Name)
|
|
|
|
segmentSize := cliCtx.Uint64(SnapshotSegmentSizeFlag.Name)
|
2021-12-27 07:59:29 +00:00
|
|
|
if segmentSize < 1000 {
|
|
|
|
return fmt.Errorf("too small --segment.size %d", segmentSize)
|
|
|
|
}
|
2022-02-22 17:39:48 +00:00
|
|
|
datadir := cliCtx.String(utils.DataDirFlag.Name)
|
|
|
|
snapshotDir := filepath.Join(datadir, "snapshots")
|
|
|
|
tmpDir := filepath.Join(datadir, etl.TmpDirName)
|
2022-02-18 02:24:17 +00:00
|
|
|
dir.MustExist(tmpDir)
|
2021-12-27 07:59:29 +00:00
|
|
|
|
2022-03-12 10:26:11 +00:00
|
|
|
chainDB := mdbx.NewMDBX(log.New()).Label(kv.ChainDB).Path(filepath.Join(datadir, "chaindata")).Readonly().MustOpen()
|
2021-12-27 07:59:29 +00:00
|
|
|
defer chainDB.Close()
|
|
|
|
|
2022-01-09 07:43:58 +00:00
|
|
|
if err := snapshotBlocks(ctx, chainDB, fromBlock, toBlock, segmentSize, snapshotDir, tmpDir); err != nil {
|
2021-12-27 07:59:29 +00:00
|
|
|
log.Error("Error", "err", err)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2022-02-22 08:35:04 +00:00
|
|
|
func doRecompressCommand(cliCtx *cli.Context) error {
|
|
|
|
ctx, cancel := common.RootContext()
|
|
|
|
defer cancel()
|
|
|
|
|
2022-02-22 17:39:48 +00:00
|
|
|
datadir := cliCtx.String(utils.DataDirFlag.Name)
|
|
|
|
snapshotDir, err := dir.OpenRw(filepath.Join(datadir, "snapshots"))
|
2022-02-22 08:35:04 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-02-22 17:39:48 +00:00
|
|
|
tmpDir := filepath.Join(datadir, etl.TmpDirName)
|
2022-02-22 08:35:04 +00:00
|
|
|
dir.MustExist(tmpDir)
|
|
|
|
|
2022-02-22 09:02:09 +00:00
|
|
|
if err := snapshotsync.RecompressSegments(ctx, snapshotDir, tmpDir); err != nil {
|
2022-02-22 08:35:04 +00:00
|
|
|
log.Error("Error", "err", err)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2022-02-18 02:24:17 +00:00
|
|
|
func rebuildIndices(ctx context.Context, chainDB kv.RoDB, cfg ethconfig.Snapshot, snapshotDir *dir.Rw, tmpDir string, from uint64) error {
|
2022-01-06 11:22:59 +00:00
|
|
|
chainConfig := tool.ChainConfigFromDB(chainDB)
|
|
|
|
chainID, _ := uint256.FromBig(chainConfig.ChainID)
|
|
|
|
|
2022-02-18 02:24:17 +00:00
|
|
|
allSnapshots := snapshotsync.NewRoSnapshots(cfg, snapshotDir.Path)
|
2022-01-06 11:22:59 +00:00
|
|
|
if err := allSnapshots.ReopenSegments(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-02-24 09:28:46 +00:00
|
|
|
if err := snapshotsync.BuildIndices(ctx, allSnapshots, snapshotDir, *chainID, tmpDir, from, log.LvlInfo); err != nil {
|
2022-01-06 11:22:59 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-01-09 07:43:58 +00:00
|
|
|
func snapshotBlocks(ctx context.Context, chainDB kv.RoDB, fromBlock, toBlock, blocksPerFile uint64, snapshotDir, tmpDir string) error {
|
2022-01-03 04:39:20 +00:00
|
|
|
var last uint64
|
|
|
|
|
|
|
|
if toBlock > 0 {
|
|
|
|
last = toBlock
|
|
|
|
} else {
|
|
|
|
lastChunk := func(tx kv.Tx, blocksPerFile uint64) (uint64, error) {
|
|
|
|
c, err := tx.Cursor(kv.BlockBody)
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
k, _, err := c.Last()
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
last := binary.BigEndian.Uint64(k)
|
|
|
|
if last > params.FullImmutabilityThreshold {
|
|
|
|
last -= params.FullImmutabilityThreshold
|
|
|
|
} else {
|
|
|
|
last = 0
|
|
|
|
}
|
|
|
|
last = last - last%blocksPerFile
|
|
|
|
return last, nil
|
2021-12-27 07:59:29 +00:00
|
|
|
}
|
2022-01-03 04:39:20 +00:00
|
|
|
|
|
|
|
if err := chainDB.View(context.Background(), func(tx kv.Tx) (err error) {
|
|
|
|
last, err = lastChunk(tx, blocksPerFile)
|
|
|
|
return err
|
|
|
|
}); err != nil {
|
|
|
|
return err
|
2021-12-27 07:59:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-18 02:24:17 +00:00
|
|
|
dir.MustExist(snapshotDir)
|
2021-12-27 07:59:29 +00:00
|
|
|
|
|
|
|
log.Info("Last body number", "last", last)
|
2022-01-06 07:13:09 +00:00
|
|
|
workers := runtime.NumCPU() - 1
|
|
|
|
if workers < 1 {
|
|
|
|
workers = 1
|
|
|
|
}
|
2022-02-24 09:28:46 +00:00
|
|
|
if err := snapshotsync.DumpBlocks(ctx, fromBlock, last, blocksPerFile, tmpDir, snapshotDir, chainDB, workers, log.LvlInfo); err != nil {
|
2022-03-10 07:48:58 +00:00
|
|
|
return fmt.Errorf("DumpBlocks: %w", err)
|
2021-12-27 07:59:29 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
//nolint
|
|
|
|
func checkBlockSnapshot(chaindata string) error {
|
|
|
|
database := mdbx.MustOpen(chaindata)
|
|
|
|
defer database.Close()
|
2022-02-22 17:39:48 +00:00
|
|
|
datadir := path.Dir(chaindata)
|
2021-12-27 07:59:29 +00:00
|
|
|
chainConfig := tool.ChainConfigFromDB(database)
|
|
|
|
chainID, _ := uint256.FromBig(chainConfig.ChainID)
|
|
|
|
_ = chainID
|
|
|
|
|
2022-01-22 04:18:24 +00:00
|
|
|
cfg := ethconfig.NewSnapshotCfg(true, true)
|
2022-02-22 17:39:48 +00:00
|
|
|
snapshots := snapshotsync.NewRoSnapshots(cfg, filepath.Join(datadir, "snapshots"))
|
2021-12-27 07:59:29 +00:00
|
|
|
snapshots.ReopenSegments()
|
|
|
|
snapshots.ReopenIndices()
|
|
|
|
//if err := snapshots.BuildIndices(context.Background(), *chainID); err != nil {
|
|
|
|
// panic(err)
|
|
|
|
//}
|
|
|
|
|
|
|
|
snBlockReader := snapshotsync.NewBlockReaderWithSnapshots(snapshots)
|
|
|
|
tx, err := database.BeginRo(context.Background())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer tx.Rollback()
|
|
|
|
|
|
|
|
for i := uint64(0); i < snapshots.BlocksAvailable(); i++ {
|
|
|
|
hash, err := rawdb.ReadCanonicalHash(tx, i)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
blockFromDB := rawdb.ReadBlock(tx, hash, i)
|
|
|
|
blockFromSnapshot, _, err := snBlockReader.BlockWithSenders(context.Background(), tx, hash, i)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if blockFromSnapshot.Hash() != blockFromDB.Hash() {
|
|
|
|
panic(i)
|
|
|
|
}
|
|
|
|
if i%1_000 == 0 {
|
|
|
|
log.Info(fmt.Sprintf("Block Num: %dK", i/1_000))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|