mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-20 11:46:44 +00:00
all cmd changes to pass in functions in chaincmd
This commit is contained in:
parent
327655693d
commit
272dcd5c43
13 changed files with 131 additions and 209 deletions
|
|
@ -170,14 +170,15 @@ func open(ctx *cli.Context, epoch uint64) (*onedb.Era, error) {
|
||||||
dir = ctx.String(dirFlag.Name)
|
dir = ctx.String(dirFlag.Name)
|
||||||
network = ctx.String(networkFlag.Name)
|
network = ctx.String(networkFlag.Name)
|
||||||
)
|
)
|
||||||
entries, err := onedb.ReadDir(dir, network)
|
entries, err := era.ReadDir(dir, network)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error reading era dir: %w", err)
|
return nil, fmt.Errorf("error reading era dir: %w", err)
|
||||||
}
|
}
|
||||||
if epoch >= uint64(len(entries)) {
|
if epoch >= uint64(len(entries)) {
|
||||||
return nil, fmt.Errorf("epoch out-of-bounds: last %d, want %d", len(entries)-1, epoch)
|
return nil, fmt.Errorf("epoch out-of-bounds: last %d, want %d", len(entries)-1, epoch)
|
||||||
}
|
}
|
||||||
return onedb.Open(filepath.Join(dir, entries[epoch]))
|
era, err := onedb.Open(filepath.Join(dir, entries[epoch]))
|
||||||
|
return era.(*onedb.Era), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify checks each era1 file in a directory to ensure it is well-formed and
|
// verify checks each era1 file in a directory to ensure it is well-formed and
|
||||||
|
|
@ -199,7 +200,7 @@ func verify(ctx *cli.Context) error {
|
||||||
reported = time.Now()
|
reported = time.Now()
|
||||||
)
|
)
|
||||||
|
|
||||||
entries, err := onedb.ReadDir(dir, network)
|
entries, err := era.ReadDir(dir, network)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error reading %s: %w", dir, err)
|
return fmt.Errorf("error reading %s: %w", dir, err)
|
||||||
}
|
}
|
||||||
|
|
@ -214,18 +215,19 @@ func verify(ctx *cli.Context) error {
|
||||||
err := func() error {
|
err := func() error {
|
||||||
name := entries[i]
|
name := entries[i]
|
||||||
e, err := onedb.Open(filepath.Join(dir, name))
|
e, err := onedb.Open(filepath.Join(dir, name))
|
||||||
|
eraPointer := e.(*onedb.Era)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error opening era1 file %s: %w", name, err)
|
return fmt.Errorf("error opening era1 file %s: %w", name, err)
|
||||||
}
|
}
|
||||||
defer e.Close()
|
defer e.Close()
|
||||||
// Read accumulator and check against expected.
|
// Read accumulator and check against expected.
|
||||||
if got, err := e.Accumulator(); err != nil {
|
if got, err := eraPointer.Accumulator(); err != nil {
|
||||||
return fmt.Errorf("error retrieving accumulator for %s: %w", name, err)
|
return fmt.Errorf("error retrieving accumulator for %s: %w", name, err)
|
||||||
} else if got != want {
|
} else if got != want {
|
||||||
return fmt.Errorf("invalid root %s: got %s, want %s", name, got, want)
|
return fmt.Errorf("invalid root %s: got %s, want %s", name, got, want)
|
||||||
}
|
}
|
||||||
// Recompute accumulator.
|
// Recompute accumulator.
|
||||||
if err := checkAccumulator(e); err != nil {
|
if err := checkAccumulator(eraPointer); err != nil {
|
||||||
return fmt.Errorf("error verify era1 file %s: %w", name, err)
|
return fmt.Errorf("error verify era1 file %s: %w", name, err)
|
||||||
}
|
}
|
||||||
// Give the user some feedback that something is happening.
|
// Give the user some feedback that something is happening.
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,8 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/internal/debug"
|
"github.com/ethereum/go-ethereum/internal/debug"
|
||||||
"github.com/ethereum/go-ethereum/internal/era"
|
"github.com/ethereum/go-ethereum/internal/era"
|
||||||
"github.com/ethereum/go-ethereum/internal/era/eradl"
|
"github.com/ethereum/go-ethereum/internal/era/eradl"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/era/execdb"
|
||||||
|
"github.com/ethereum/go-ethereum/internal/era/onedb"
|
||||||
"github.com/ethereum/go-ethereum/internal/flags"
|
"github.com/ethereum/go-ethereum/internal/flags"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
|
|
@ -518,11 +520,11 @@ func importHistory(ctx *cli.Context) error {
|
||||||
format := ctx.String(utils.EraFormatFlag.Name)
|
format := ctx.String(utils.EraFormatFlag.Name)
|
||||||
switch format {
|
switch format {
|
||||||
case "era1", "era":
|
case "era1", "era":
|
||||||
if err := utils.ImportHistory(chain, dir, network, utils.Era1); err != nil {
|
if err := utils.ImportHistory(chain, dir, network, onedb.From, onedb.NewIterator); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case "erae":
|
case "erae":
|
||||||
if err := utils.ImportHistory(chain, dir, network, utils.EraE); err != nil {
|
if err := utils.ImportHistory(chain, dir, network, execdb.From, execdb.NewIterator); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
@ -563,11 +565,11 @@ func exportHistory(ctx *cli.Context) error {
|
||||||
format := ctx.String(utils.EraFormatFlag.Get(ctx))
|
format := ctx.String(utils.EraFormatFlag.Get(ctx))
|
||||||
switch format {
|
switch format {
|
||||||
case "era1", "era":
|
case "era1", "era":
|
||||||
if err := utils.ExportHistory(chain, dir, uint64(first), uint64(last), uint64(era.MaxEra1Size), utils.Era1); err != nil {
|
if err := utils.ExportHistory(chain, dir, uint64(first), uint64(last), uint64(era.MaxSize), onedb.NewBuilder, onedb.Filename); err != nil {
|
||||||
utils.Fatalf("Export error: %v\n", err)
|
utils.Fatalf("Export error: %v\n", err)
|
||||||
}
|
}
|
||||||
case "erae":
|
case "erae":
|
||||||
if err := utils.ExportHistory(chain, dir, uint64(first), uint64(last), uint64(era2.MaxEraESize), utils.EraE); err != nil {
|
if err := utils.ExportHistory(chain, dir, uint64(first), uint64(last), uint64(era.MaxSize), execdb.NewBuilder, execdb.Filename); err != nil {
|
||||||
utils.Fatalf("Export error: %v\n", err)
|
utils.Fatalf("Export error: %v\n", err)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
115
cmd/utils/cmd.go
115
cmd/utils/cmd.go
|
|
@ -44,7 +44,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/internal/debug"
|
"github.com/ethereum/go-ethereum/internal/debug"
|
||||||
era2 "github.com/ethereum/go-ethereum/internal/era/execdb"
|
"github.com/ethereum/go-ethereum/internal/era"
|
||||||
"github.com/ethereum/go-ethereum/internal/era/onedb"
|
"github.com/ethereum/go-ethereum/internal/era/onedb"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
|
|
@ -253,11 +253,11 @@ func readList(filename string) ([]string, error) {
|
||||||
// ImportHistory imports Era1 files containing historical block information,
|
// ImportHistory imports Era1 files containing historical block information,
|
||||||
// starting from genesis. The assumption is held that the provided chain
|
// starting from genesis. The assumption is held that the provided chain
|
||||||
// segment in Era1 file should all be canonical and verified.
|
// segment in Era1 file should all be canonical and verified.
|
||||||
func ImportHistory(chain *core.BlockChain, dir string, network string) error {
|
func ImportHistory(chain *core.BlockChain, dir string, network string, from era.FromFn, iterator era.NewIteratorFn) error {
|
||||||
if chain.CurrentSnapBlock().Number.BitLen() != 0 {
|
if chain.CurrentSnapBlock().Number.BitLen() != 0 {
|
||||||
return errors.New("history import only supported when starting from genesis")
|
return errors.New("history import only supported when starting from genesis")
|
||||||
}
|
}
|
||||||
entries, err := onedb.ReadDir(dir, network)
|
entries, err := era.ReadDir(dir, network)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error reading %s: %w", dir, err)
|
return fmt.Errorf("error reading %s: %w", dir, err)
|
||||||
}
|
}
|
||||||
|
|
@ -301,11 +301,11 @@ func ImportHistory(chain *core.BlockChain, dir string, network string) error {
|
||||||
return fmt.Errorf("%s checksum mismatch: have %s want %s", file, got, want)
|
return fmt.Errorf("%s checksum mismatch: have %s want %s", file, got, want)
|
||||||
}
|
}
|
||||||
// Import all block data from Era1.
|
// Import all block data from Era1.
|
||||||
e, err := onedb.From(f)
|
e, err := from(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error opening era: %w", err)
|
return fmt.Errorf("error opening era: %w", err)
|
||||||
}
|
}
|
||||||
it, err := onedb.NewIterator(e)
|
it, err := iterator(e)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error creating iterator: %w", err)
|
return fmt.Errorf("error creating iterator: %w", err)
|
||||||
}
|
}
|
||||||
|
|
@ -347,105 +347,6 @@ func ImportHistory(chain *core.BlockChain, dir string, network string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImportHistoryEraE imports Era-E files containing historical block information,
|
|
||||||
// starting from genesis. Currently this function follows the assumptions that the provided chain
|
|
||||||
// segment in Era-E file should all be canonical and verified. In the future, this function will be
|
|
||||||
// extended to support importing Era-E files with proof verification.
|
|
||||||
func ImportHistoryEraE(chain *core.BlockChain, dir, network string) error {
|
|
||||||
if chain.CurrentSnapBlock().Number.Sign() != 0 {
|
|
||||||
return errors.New("history import only supported when starting from genesis")
|
|
||||||
}
|
|
||||||
|
|
||||||
entries, err := era2.ReadDir(dir, network)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("reading %q: %w", dir, err)
|
|
||||||
}
|
|
||||||
checksums, err := readList(filepath.Join(dir, "checksums.txt"))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("reading checksums.txt: %w", err)
|
|
||||||
}
|
|
||||||
if len(entries) != len(checksums) {
|
|
||||||
return fmt.Errorf("mismatch: %d erae files, %d checksums", len(entries), len(checksums))
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
start = time.Now()
|
|
||||||
reported = time.Now()
|
|
||||||
imported int
|
|
||||||
h = sha256.New()
|
|
||||||
scratch bytes.Buffer
|
|
||||||
)
|
|
||||||
|
|
||||||
for i, file := range entries {
|
|
||||||
path := filepath.Join(dir, file)
|
|
||||||
|
|
||||||
// validate against checksum file in directory
|
|
||||||
f, err := os.Open(path)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("open %s: %w", path, err)
|
|
||||||
}
|
|
||||||
if _, err := io.Copy(h, f); err != nil {
|
|
||||||
f.Close()
|
|
||||||
return fmt.Errorf("checksum %s: %w", path, err)
|
|
||||||
}
|
|
||||||
got := common.BytesToHash(h.Sum(scratch.Bytes()[:])).Hex()
|
|
||||||
want := checksums[i]
|
|
||||||
h.Reset()
|
|
||||||
scratch.Reset()
|
|
||||||
if got != want {
|
|
||||||
f.Close()
|
|
||||||
return fmt.Errorf("%s checksum mismatch: have %s want %s", file, got, want)
|
|
||||||
}
|
|
||||||
// rewind for reading
|
|
||||||
if _, err := f.Seek(0, io.SeekStart); err != nil {
|
|
||||||
f.Close()
|
|
||||||
return fmt.Errorf("rewind %s: %w", file, err)
|
|
||||||
}
|
|
||||||
// import archive
|
|
||||||
e, err := era2.From(f)
|
|
||||||
if err != nil {
|
|
||||||
f.Close()
|
|
||||||
return fmt.Errorf("open erae %s: %w", file, err)
|
|
||||||
}
|
|
||||||
blockCount := e.Count()
|
|
||||||
|
|
||||||
for j := uint64(0); j < blockCount; j++ {
|
|
||||||
hdr, err := e.GetHeader(e.Start() + j)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("header #%d: %w", hdr.Number.Uint64(), err)
|
|
||||||
}
|
|
||||||
if hdr.Number.Sign() == 0 { // skip genesis
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
body, err := e.GetBody(hdr.Number.Uint64())
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("body #%d: %w", hdr.Number.Uint64(), err)
|
|
||||||
}
|
|
||||||
rcpts, err := e.GetReceipts(hdr.Number.Uint64(), 1)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("receipts #%d: %w", hdr.Number.Uint64(), err)
|
|
||||||
}
|
|
||||||
blk := types.NewBlockWithHeader(hdr).WithBody(*body)
|
|
||||||
|
|
||||||
enc := types.EncodeBlockReceiptLists(rcpts)
|
|
||||||
if _, err := chain.InsertReceiptChain([]*types.Block{blk}, enc, ^uint64(0)); err != nil {
|
|
||||||
return fmt.Errorf("insert #%d: %w", hdr.Number.Uint64(), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
imported++
|
|
||||||
if time.Since(reported) >= 8*time.Second {
|
|
||||||
log.Info("Importing Era‑E", "head", hdr.Number, "imported", imported, "elapsed", common.PrettyDuration(time.Since(start)))
|
|
||||||
reported = time.Now()
|
|
||||||
imported = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info("Era‑E import complete", "duration", common.PrettyDuration(time.Since(start)))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func missingBlocks(chain *core.BlockChain, blocks []*types.Block) []*types.Block {
|
func missingBlocks(chain *core.BlockChain, blocks []*types.Block) []*types.Block {
|
||||||
head := chain.CurrentBlock()
|
head := chain.CurrentBlock()
|
||||||
for i, block := range blocks {
|
for i, block := range blocks {
|
||||||
|
|
@ -516,7 +417,7 @@ func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, las
|
||||||
|
|
||||||
// ExportHistory exports blockchain history into the specified directory,
|
// ExportHistory exports blockchain history into the specified directory,
|
||||||
// following the Era format.
|
// following the Era format.
|
||||||
func ExportHistory(bc *core.BlockChain, dir string, first, last, step uint64) error {
|
func ExportHistory(bc *core.BlockChain, dir string, first, last, step uint64, builderfn era.NewBuilderFn, filename era.FilenameFn) error {
|
||||||
log.Info("Exporting blockchain history", "dir", dir)
|
log.Info("Exporting blockchain history", "dir", dir)
|
||||||
if head := bc.CurrentBlock().Number.Uint64(); head < last {
|
if head := bc.CurrentBlock().Number.Uint64(); head < last {
|
||||||
log.Warn("Last block beyond head, setting last = head", "head", head, "last", last)
|
log.Warn("Last block beyond head, setting last = head", "head", head, "last", last)
|
||||||
|
|
@ -545,7 +446,7 @@ func ExportHistory(bc *core.BlockChain, dir string, first, last, step uint64) er
|
||||||
|
|
||||||
for batch := first; batch <= last; batch += step {
|
for batch := first; batch <= last; batch += step {
|
||||||
idx := int(batch / step)
|
idx := int(batch / step)
|
||||||
tmpPath := filepath.Join(dir, onedb.Filename(network, idx, common.Hash{}))
|
tmpPath := filepath.Join(dir, filename(network, idx, common.Hash{}))
|
||||||
|
|
||||||
if err := func() error {
|
if err := func() error {
|
||||||
fh, err := os.Create(tmpPath)
|
fh, err := os.Create(tmpPath)
|
||||||
|
|
@ -554,7 +455,7 @@ func ExportHistory(bc *core.BlockChain, dir string, first, last, step uint64) er
|
||||||
}
|
}
|
||||||
defer fh.Close()
|
defer fh.Close()
|
||||||
|
|
||||||
bldr := onedb.NewBuilder(fh)
|
bldr := builderfn(fh)
|
||||||
|
|
||||||
for j := uint64(0); j < step && batch+j <= last; j++ {
|
for j := uint64(0); j < step && batch+j <= last; j++ {
|
||||||
n := batch + j
|
n := batch + j
|
||||||
|
|
|
||||||
|
|
@ -308,7 +308,7 @@ func (db *Store) openEraFile(epoch uint64) (*onedb.Era, error) {
|
||||||
return nil, fmt.Errorf("pre-merge era1 file has invalid boundary. %d %% %d != 0", e.Start(), era.MaxSize)
|
return nil, fmt.Errorf("pre-merge era1 file has invalid boundary. %d %% %d != 0", e.Start(), era.MaxSize)
|
||||||
}
|
}
|
||||||
log.Debug("Opened era1 file", "epoch", epoch)
|
log.Debug("Opened era1 file", "epoch", epoch)
|
||||||
return e, nil
|
return e.(*onedb.Era), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// doneWithFile signals that the caller has finished using a file.
|
// doneWithFile signals that the caller has finished using a file.
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,17 @@
|
||||||
package era
|
package era
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
// Removed import of internal/era to avoid import cycle and missing metadata error
|
||||||
)
|
)
|
||||||
|
|
||||||
// Type constants for the e2store entries in the Era1 and EraE formats.
|
// Type constants for the e2store entries in the Era1 and EraE formats.
|
||||||
|
|
@ -36,12 +42,74 @@ type Iterator interface {
|
||||||
Next() bool
|
Next() bool
|
||||||
Number() uint64
|
Number() uint64
|
||||||
Block() (*types.Block, error)
|
Block() (*types.Block, error)
|
||||||
|
BlockAndReceipts() (*types.Block, types.Receipts, error)
|
||||||
Receipts() (types.Receipts, error)
|
Receipts() (types.Receipts, error)
|
||||||
Error() error
|
Error() error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Builder represents the interface for various types of era formats.
|
// Builder represents the interface for various types of era formats.
|
||||||
type Builder interface {
|
type Builder interface {
|
||||||
Add(block *types.Block, receipts types.Receipts, td *big.Int, proof []byte) error
|
Add(block *types.Block, receipts types.Receipts, td *big.Int, proof Proof) error
|
||||||
|
AddRLP(header, body, receipts, proof []byte, number uint64, hash common.Hash, td, difficulty *big.Int) error
|
||||||
Finalize() (common.Hash, error)
|
Finalize() (common.Hash, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Era represents the interface for reading era data.
|
||||||
|
type Era interface {
|
||||||
|
Close() error
|
||||||
|
Start() uint64
|
||||||
|
Count() uint64
|
||||||
|
GetBlockByNumber(num uint64) (*types.Block, error)
|
||||||
|
GetRawBodyByNumber(num uint64) ([]byte, error)
|
||||||
|
GetRawReceiptsByNumber(num uint64) ([]byte, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBuilderFn defines a function type for creating a new Builder.
|
||||||
|
type NewBuilderFn func(w io.Writer) Builder
|
||||||
|
|
||||||
|
// FilenameFn defines a function type for generating a filename based on network, epoch, and root hash.
|
||||||
|
type FilenameFn func(network string, epoch int, root common.Hash) string
|
||||||
|
|
||||||
|
// FromFn defines a function type for creating an Era from a ReadAtSeekCloser.
|
||||||
|
type FromFn func(f ReadAtSeekCloser) (Era, error)
|
||||||
|
|
||||||
|
// NewIteratorFn defines a function type for creating a new Iterator from an Era.
|
||||||
|
type NewIteratorFn func(e Era) (Iterator, error)
|
||||||
|
|
||||||
|
// ReadDir reads all the era1 files in a directory for a given network.
|
||||||
|
// Format: <network>-<epoch>-<hexroot>.erae or <network>-<epoch>-<hexroot>.era1
|
||||||
|
func ReadDir(dir, network string) ([]string, error) {
|
||||||
|
entries, err := os.ReadDir(dir)
|
||||||
|
var directoryExtension string
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error reading directory %s: %w", dir, err)
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
next = uint64(0)
|
||||||
|
eras []string
|
||||||
|
)
|
||||||
|
for i, entry := range entries {
|
||||||
|
fileExtension := path.Ext(entry.Name())
|
||||||
|
if i == 0 {
|
||||||
|
directoryExtension = fileExtension
|
||||||
|
} else if directoryExtension != fileExtension {
|
||||||
|
return nil, fmt.Errorf("directory %s contains mixed era file formats", dir)
|
||||||
|
}
|
||||||
|
if fileExtension != ".erae" || fileExtension != ".era1" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
parts := strings.Split(entry.Name(), "-")
|
||||||
|
if len(parts) != 3 || parts[0] != network {
|
||||||
|
// Invalid era1 filename, skip.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if epoch, err := strconv.ParseUint(parts[1], 10, 64); err != nil {
|
||||||
|
return nil, fmt.Errorf("malformed era filenames: %s", entry.Name())
|
||||||
|
} else if epoch != next {
|
||||||
|
return nil, fmt.Errorf("missing epoch %d", next)
|
||||||
|
}
|
||||||
|
next += 1
|
||||||
|
eras = append(eras, entry.Name())
|
||||||
|
}
|
||||||
|
return eras, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,9 +51,11 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/history"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/internal/era"
|
"github.com/ethereum/go-ethereum/internal/era"
|
||||||
"github.com/ethereum/go-ethereum/internal/era/e2store"
|
"github.com/ethereum/go-ethereum/internal/era/e2store"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/golang/snappy"
|
"github.com/golang/snappy"
|
||||||
)
|
)
|
||||||
|
|
@ -91,7 +93,7 @@ type Builder struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBuilder returns a new Builder instance.
|
// NewBuilder returns a new Builder instance.
|
||||||
func NewBuilder(w io.Writer) *Builder {
|
func NewBuilder(w io.Writer) era.Builder {
|
||||||
tmp := bytes.NewBuffer(nil)
|
tmp := bytes.NewBuffer(nil)
|
||||||
return &Builder{
|
return &Builder{
|
||||||
w: e2store.NewWriter(w),
|
w: e2store.NewWriter(w),
|
||||||
|
|
@ -137,12 +139,15 @@ func (b *Builder) Add(block *types.Block, receipts types.Receipts, td *big.Int,
|
||||||
return b.AddRLP(
|
return b.AddRLP(
|
||||||
eh, eb, er, ep,
|
eh, eb, er, ep,
|
||||||
header.Number.Uint64(),
|
header.Number.Uint64(),
|
||||||
header.Hash(), td,
|
header.Hash(), td, nil,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddRLP takes the RLP encoded block components and writes them to the underlying e2store file.
|
// AddRLP takes the RLP encoded block components and writes them to the underlying e2store file.
|
||||||
func (b *Builder) AddRLP(headerRLP []byte, bodyRLP []byte, receipts []byte, proof []byte, blockNum uint64, blockHash common.Hash, td *big.Int) error {
|
func (b *Builder) AddRLP(headerRLP []byte, bodyRLP []byte, receipts []byte, proof []byte, blockNum uint64, blockHash common.Hash, td, difficulty *big.Int) error {
|
||||||
|
if difficulty != nil {
|
||||||
|
return fmt.Errorf("block difficulty not allowed in erae format")
|
||||||
|
}
|
||||||
if len(b.buff.headers) >= era.MaxSize {
|
if len(b.buff.headers) >= era.MaxSize {
|
||||||
return fmt.Errorf("exceeds max size %d", era.MaxSize)
|
return fmt.Errorf("exceeds max size %d", era.MaxSize)
|
||||||
}
|
}
|
||||||
|
|
@ -156,6 +161,11 @@ func (b *Builder) AddRLP(headerRLP []byte, bodyRLP []byte, receipts []byte, proo
|
||||||
b.buff.proofs = append(b.buff.proofs, proof)
|
b.buff.proofs = append(b.buff.proofs, proof)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mergeblock := history.PrunePoints[params.MainnetGenesisHash]
|
||||||
|
if mergeblock != nil && blockNum <= mergeblock.BlockNumber {
|
||||||
|
b.buff.tds = append(b.buff.tds, new(big.Int).Set(td))
|
||||||
|
}
|
||||||
|
|
||||||
// Write Era2 version before writing any blocks.
|
// Write Era2 version before writing any blocks.
|
||||||
if b.startNum == nil {
|
if b.startNum == nil {
|
||||||
b.startNum = new(uint64)
|
b.startNum = new(uint64)
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,7 @@ func TestEra2Builder(t *testing.T) {
|
||||||
t.Fatalf("body %d mismatch", i)
|
t.Fatalf("body %d mismatch", i)
|
||||||
}
|
}
|
||||||
|
|
||||||
rawBody, err := era.GetRawBodyFrameByNumber(bn)
|
rawBody, err := era.GetRawBodyByNumber(bn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("raw body %d: %v", i, err)
|
t.Fatalf("raw body %d: %v", i, err)
|
||||||
}
|
}
|
||||||
|
|
@ -153,7 +153,7 @@ func TestEra2Builder(t *testing.T) {
|
||||||
t.Fatalf("body frame %d mismatch", i)
|
t.Fatalf("body frame %d mismatch", i)
|
||||||
}
|
}
|
||||||
|
|
||||||
rawRcpt, err := era.GetRawReceiptsFrameByNumber(bn)
|
rawRcpt, err := era.GetRawReceiptsByNumber(bn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("raw receipts %d: %v", i, err)
|
t.Fatalf("raw receipts %d: %v", i, err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,8 @@ type Iterator struct {
|
||||||
|
|
||||||
// NewIterator returns a header/body/receipt iterator over the archive.
|
// NewIterator returns a header/body/receipt iterator over the archive.
|
||||||
// Call Next immediately to position on the first block.
|
// Call Next immediately to position on the first block.
|
||||||
func NewIterator(e *Era) (*Iterator, error) {
|
func NewIterator(e era.Era) (era.Iterator, error) {
|
||||||
inner, err := NewRawIterator(e)
|
inner, err := NewRawIterator(e.(*Era))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"slices"
|
"slices"
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
|
@ -72,7 +69,7 @@ func (e *Era) Close() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// From returns an Era backed by f.
|
// From returns an Era backed by f.
|
||||||
func From(f era.ReadAtSeekCloser) (*Era, error) {
|
func From(f era.ReadAtSeekCloser) (era.Era, error) {
|
||||||
e := &Era{f: f, s: e2store.NewReader(f)}
|
e := &Era{f: f, s: e2store.NewReader(f)}
|
||||||
if err := e.loadIndex(); err != nil {
|
if err := e.loadIndex(); err != nil {
|
||||||
f.Close()
|
f.Close()
|
||||||
|
|
@ -81,37 +78,6 @@ func From(f era.ReadAtSeekCloser) (*Era, error) {
|
||||||
return e, nil
|
return e, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadDir reads all the era1 files in a directory for a given network.
|
|
||||||
// Format: <network>-<epoch>-<hexroot>.erae
|
|
||||||
func ReadDir(dir, network string) ([]string, error) {
|
|
||||||
entries, err := os.ReadDir(dir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error reading directory %s: %w", dir, err)
|
|
||||||
}
|
|
||||||
var (
|
|
||||||
next = uint64(0)
|
|
||||||
eras []string
|
|
||||||
)
|
|
||||||
for _, entry := range entries {
|
|
||||||
if path.Ext(entry.Name()) != ".erae" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
parts := strings.Split(entry.Name(), "-")
|
|
||||||
if len(parts) != 3 || parts[0] != network {
|
|
||||||
// Invalid era1 filename, skip.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if epoch, err := strconv.ParseUint(parts[1], 10, 64); err != nil {
|
|
||||||
return nil, fmt.Errorf("malformed era1 filename: %s", entry.Name())
|
|
||||||
} else if epoch != next {
|
|
||||||
return nil, fmt.Errorf("missing epoch %d", next)
|
|
||||||
}
|
|
||||||
next += 1
|
|
||||||
eras = append(eras, entry.Name())
|
|
||||||
}
|
|
||||||
return eras, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start retrieves the starting block number.
|
// Start retrieves the starting block number.
|
||||||
func (e *Era) Start() uint64 {
|
func (e *Era) Start() uint64 {
|
||||||
return e.m.start
|
return e.m.start
|
||||||
|
|
@ -185,8 +151,8 @@ func (e *Era) getTD(blockNum uint64) (*big.Int, error) {
|
||||||
return td, nil
|
return td, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRawBodyFrameByNumber retrieves the raw body frame in bytes of a specific block.
|
// GetRawBodyByNumber returns the RLP-encoded body for the given block number.
|
||||||
func (e *Era) GetRawBodyFrameByNumber(blockNum uint64) ([]byte, error) {
|
func (e *Era) GetRawBodyByNumber(blockNum uint64) ([]byte, error) {
|
||||||
off, err := e.bodyOff(blockNum)
|
off, err := e.bodyOff(blockNum)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -198,8 +164,8 @@ func (e *Era) GetRawBodyFrameByNumber(blockNum uint64) ([]byte, error) {
|
||||||
return io.ReadAll(r)
|
return io.ReadAll(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRawReceiptsFrameByNumber retrieves the raw receipts frame in bytes of a specific block.
|
// GetRawReceiptsByNumber returns the RLP-encoded receipts for the given block number.
|
||||||
func (e *Era) GetRawReceiptsFrameByNumber(blockNum uint64) ([]byte, error) {
|
func (e *Era) GetRawReceiptsByNumber(blockNum uint64) ([]byte, error) {
|
||||||
off, err := e.receiptOff(blockNum)
|
off, err := e.receiptOff(blockNum)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -211,7 +177,7 @@ func (e *Era) GetRawReceiptsFrameByNumber(blockNum uint64) ([]byte, error) {
|
||||||
return io.ReadAll(r)
|
return io.ReadAll(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRawProofFrameByNumber retrieves the raw proof frame in bytes of a specific block proof.
|
// GetRawProofFrameByNumber returns the RLP-encoded receipts for the given block number.
|
||||||
func (e *Era) GetRawProofFrameByNumber(blockNum uint64) ([]byte, error) {
|
func (e *Era) GetRawProofFrameByNumber(blockNum uint64) ([]byte, error) {
|
||||||
off, err := e.proofOff(blockNum)
|
off, err := e.proofOff(blockNum)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ type Builder struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBuilder returns a new Builder instance.
|
// NewBuilder returns a new Builder instance.
|
||||||
func NewBuilder(w io.Writer) *Builder {
|
func NewBuilder(w io.Writer) era.Builder {
|
||||||
buf := bytes.NewBuffer(nil)
|
buf := bytes.NewBuffer(nil)
|
||||||
return &Builder{
|
return &Builder{
|
||||||
w: e2store.NewWriter(w),
|
w: e2store.NewWriter(w),
|
||||||
|
|
@ -113,12 +113,15 @@ func (b *Builder) Add(block *types.Block, receipts types.Receipts, td *big.Int,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return b.AddRLP(eh, eb, er, block.NumberU64(), block.Hash(), td, block.Difficulty())
|
return b.AddRLP(eh, eb, er, nil, block.NumberU64(), block.Hash(), td, block.Difficulty())
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddRLP writes a compressed block entry and compressed receipts entry to the
|
// AddRLP writes a compressed block entry and compressed receipts entry to the
|
||||||
// underlying e2store file.
|
// underlying e2store file.
|
||||||
func (b *Builder) AddRLP(header, body, receipts []byte, number uint64, hash common.Hash, td, difficulty *big.Int) error {
|
func (b *Builder) AddRLP(header, body, receipts, proof []byte, number uint64, hash common.Hash, td, difficulty *big.Int) error {
|
||||||
|
if proof != nil {
|
||||||
|
return fmt.Errorf("proof not allowed in era1 format")
|
||||||
|
}
|
||||||
// Write Era1 version entry before first block.
|
// Write Era1 version entry before first block.
|
||||||
if b.startNum == nil {
|
if b.startNum == nil {
|
||||||
n, err := b.w.Write(era.TypeVersion, nil)
|
n, err := b.w.Write(era.TypeVersion, nil)
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ func TestEra1Builder(t *testing.T) {
|
||||||
hash = common.Hash{byte(i)}
|
hash = common.Hash{byte(i)}
|
||||||
td = chain.tds[i]
|
td = chain.tds[i]
|
||||||
)
|
)
|
||||||
if err = builder.AddRLP(header, body, receipts, uint64(i), hash, td, big.NewInt(1)); err != nil {
|
if err = builder.AddRLP(header, body, receipts, nil, uint64(i), hash, td, big.NewInt(1)); err != nil {
|
||||||
t.Fatalf("error adding entry: %v", err)
|
t.Fatalf("error adding entry: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -83,7 +83,11 @@ func TestEra1Builder(t *testing.T) {
|
||||||
t.Fatalf("failed to open era: %v", err)
|
t.Fatalf("failed to open era: %v", err)
|
||||||
}
|
}
|
||||||
defer e.Close()
|
defer e.Close()
|
||||||
it, err := NewRawIterator(e)
|
eraPtr, ok := e.(*Era)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("failed to assert *Era type")
|
||||||
|
}
|
||||||
|
it, err := NewRawIterator(eraPtr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to make iterator: %s", err)
|
t.Fatalf("failed to make iterator: %s", err)
|
||||||
}
|
}
|
||||||
|
|
@ -120,7 +124,7 @@ func TestEra1Builder(t *testing.T) {
|
||||||
if !bytes.Equal(rawReceipts, chain.receipts[i]) {
|
if !bytes.Equal(rawReceipts, chain.receipts[i]) {
|
||||||
t.Fatalf("mismatched receipts: want %s, got %s", chain.receipts[i], rawReceipts)
|
t.Fatalf("mismatched receipts: want %s, got %s", chain.receipts[i], rawReceipts)
|
||||||
}
|
}
|
||||||
receipts, err := getReceiptsByNumber(e, i)
|
receipts, err := getReceiptsByNumber(eraPtr, i)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error reading receipts: %v", err)
|
t.Fatalf("error reading receipts: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,8 @@ type Iterator struct {
|
||||||
|
|
||||||
// NewIterator returns a new Iterator instance. Next must be immediately
|
// NewIterator returns a new Iterator instance. Next must be immediately
|
||||||
// called on new iterators to load the first item.
|
// called on new iterators to load the first item.
|
||||||
func NewIterator(e *Era) (*Iterator, error) {
|
func NewIterator(e era.Era) (era.Iterator, error) {
|
||||||
inner, err := NewRawIterator(e)
|
inner, err := NewRawIterator(e.(*Era))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"slices"
|
"slices"
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -42,37 +39,6 @@ func Filename(network string, epoch int, root common.Hash) string {
|
||||||
return fmt.Sprintf("%s-%05d-%s.era1", network, epoch, root.Hex()[2:10])
|
return fmt.Sprintf("%s-%05d-%s.era1", network, epoch, root.Hex()[2:10])
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadDir reads all the era1 files in a directory for a given network.
|
|
||||||
// Format: <network>-<epoch>-<hexroot>.era1
|
|
||||||
func ReadDir(dir, network string) ([]string, error) {
|
|
||||||
entries, err := os.ReadDir(dir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error reading directory %s: %w", dir, err)
|
|
||||||
}
|
|
||||||
var (
|
|
||||||
next = uint64(0)
|
|
||||||
eras []string
|
|
||||||
)
|
|
||||||
for _, entry := range entries {
|
|
||||||
if path.Ext(entry.Name()) != ".era1" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
parts := strings.Split(entry.Name(), "-")
|
|
||||||
if len(parts) != 3 || parts[0] != network {
|
|
||||||
// Invalid era1 filename, skip.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if epoch, err := strconv.ParseUint(parts[1], 10, 64); err != nil {
|
|
||||||
return nil, fmt.Errorf("malformed era1 filename: %s", entry.Name())
|
|
||||||
} else if epoch != next {
|
|
||||||
return nil, fmt.Errorf("missing epoch %d", next)
|
|
||||||
}
|
|
||||||
next += 1
|
|
||||||
eras = append(eras, entry.Name())
|
|
||||||
}
|
|
||||||
return eras, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type ReadAtSeekCloser interface {
|
type ReadAtSeekCloser interface {
|
||||||
io.ReaderAt
|
io.ReaderAt
|
||||||
io.Seeker
|
io.Seeker
|
||||||
|
|
@ -89,7 +55,7 @@ type Era struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// From returns an Era backed by f.
|
// From returns an Era backed by f.
|
||||||
func From(f ReadAtSeekCloser) (*Era, error) {
|
func From(f era.ReadAtSeekCloser) (era.Era, error) {
|
||||||
m, err := readMetadata(f)
|
m, err := readMetadata(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -103,7 +69,7 @@ func From(f ReadAtSeekCloser) (*Era, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open returns an Era backed by the given filename.
|
// Open returns an Era backed by the given filename.
|
||||||
func Open(filename string) (*Era, error) {
|
func Open(filename string) (era.Era, error) {
|
||||||
f, err := os.Open(filename)
|
f, err := os.Open(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue