interna/era,cmd: simplify era interace, fix era.ReadDir, fix lints

This commit is contained in:
lightclient 2025-08-11 14:57:54 -06:00
parent 216409ed06
commit f188ed19e9
No known key found for this signature in database
GPG key ID: 657913021EF45A6A
8 changed files with 55 additions and 49 deletions

View file

@ -20,6 +20,7 @@ import (
"encoding/json"
"errors"
"fmt"
"io"
"os"
"path/filepath"
"regexp"
@ -517,19 +518,21 @@ func importHistory(ctx *cli.Context) error {
network = networks[0]
}
format := ctx.String(utils.EraFormatFlag.Name)
var (
format = ctx.String(utils.EraFormatFlag.Name)
from func(era.ReadAtSeekCloser) (era.Era, error)
)
switch format {
case "era1", "era":
if err := utils.ImportHistory(chain, dir, network, onedb.From, onedb.NewIterator); err != nil {
return err
}
from = onedb.From
case "erae":
if err := utils.ImportHistory(chain, dir, network, execdb.From, execdb.NewIterator); err != nil {
return err
}
from = execdb.From
default:
return fmt.Errorf("unknown --era.format %q (expected 'era1' or 'erae')", format)
}
if err := utils.ImportHistory(chain, dir, network, from); err != nil {
return err
}
fmt.Printf("Import done in %v\n", time.Since(start))
return nil
@ -562,19 +565,24 @@ func exportHistory(ctx *cli.Context) error {
utils.Fatalf("Export error: block number %d larger than head block %d\n", uint64(last), head.Number.Uint64())
}
format := ctx.String(utils.EraFormatFlag.Get(ctx))
var (
format = ctx.String(utils.EraFormatFlag.Get(ctx))
filename func(network string, epoch int, root common.Hash) string
newBuilder func(w io.Writer) era.Builder
)
switch format {
case "era1", "era":
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)
}
newBuilder = func(w io.Writer) era.Builder { return onedb.NewBuilder(w) }
filename = func(network string, epoch int, root common.Hash) string { return onedb.Filename(network, epoch, root) }
case "erae":
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)
}
newBuilder = func(w io.Writer) era.Builder { return execdb.NewBuilder(w) }
filename = func(network string, epoch int, root common.Hash) string { return execdb.Filename(network, epoch, root) }
default:
return fmt.Errorf("unknown archive format %q (use 'era1' or 'erae')", format)
}
if err := utils.ExportHistory(chain, dir, uint64(first), uint64(last), uint64(era.MaxSize), newBuilder, filename); err != nil {
utils.Fatalf("Export error: %v\n", err)
}
fmt.Printf("Export done in %v\n", time.Since(start))
return nil

View file

@ -253,7 +253,7 @@ func readList(filename string) ([]string, error) {
// ImportHistory imports Era1 files containing historical block information,
// starting from genesis. The assumption is held that the provided chain
// segment in Era1 file should all be canonical and verified.
func ImportHistory(chain *core.BlockChain, dir string, network string, from era.FromFn, iterator era.NewIteratorFn) error {
func ImportHistory(chain *core.BlockChain, dir string, network string, from func(f era.ReadAtSeekCloser) (era.Era, error)) error {
if chain.CurrentSnapBlock().Number.BitLen() != 0 {
return errors.New("history import only supported when starting from genesis")
}
@ -305,7 +305,7 @@ func ImportHistory(chain *core.BlockChain, dir string, network string, from era.
if err != nil {
return fmt.Errorf("error opening era: %w", err)
}
it, err := iterator(e)
it, err := e.Iterator()
if err != nil {
return fmt.Errorf("error creating iterator: %w", err)
}
@ -417,7 +417,7 @@ func ExportAppendChain(blockchain *core.BlockChain, fn string, first uint64, las
// ExportHistory exports blockchain history into the specified directory,
// following the Era format.
func ExportHistory(bc *core.BlockChain, dir string, first, last, step uint64, builderfn era.NewBuilderFn, filename era.FilenameFn) error {
func ExportHistory(bc *core.BlockChain, dir string, first, last, step uint64, newBuilder func(io.Writer) era.Builder, filename func(network string, epoch int, root common.Hash) string) error {
log.Info("Exporting blockchain history", "dir", dir)
if head := bc.CurrentBlock().Number.Uint64(); head < last {
log.Warn("Last block beyond head, setting last = head", "head", head, "last", last)
@ -455,7 +455,7 @@ func ExportHistory(bc *core.BlockChain, dir string, first, last, step uint64, bu
}
defer fh.Close()
bldr := builderfn(fh)
bldr := newBuilder(fh)
for j := uint64(0); j < step && batch+j <= last; j++ {
n := batch + j

View file

@ -32,6 +32,7 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/internal/era"
"github.com/ethereum/go-ethereum/internal/era/onedb"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie"
@ -89,7 +90,7 @@ func TestHistoryImportAndExport(t *testing.T) {
dir := t.TempDir()
// Export history to temp directory.
if err := ExportHistory(chain, dir, 0, count, step); err != nil {
if err := ExportHistory(chain, dir, 0, count, step, onedb.NewBuilder, onedb.Filename); err != nil {
t.Fatalf("error exporting history: %v", err)
}
@ -101,7 +102,7 @@ func TestHistoryImportAndExport(t *testing.T) {
checksums := strings.Split(string(b), "\n")
// Verify each Era.
entries, _ := onedb.ReadDir(dir, "mainnet")
entries, _ := era.ReadDir(dir, "mainnet")
for i, filename := range entries {
func() {
f, err := os.Open(filepath.Join(dir, filename))
@ -170,7 +171,7 @@ func TestHistoryImportAndExport(t *testing.T) {
if err != nil {
t.Fatalf("unable to initialize chain: %v", err)
}
if err := ImportHistory(imported, dir, "mainnet"); err != nil {
if err := ImportHistory(imported, dir, "mainnet", onedb.From); err != nil {
t.Fatalf("failed to import chain: %v", err)
}
if have, want := imported.CurrentHeader(), chain.CurrentHeader(); have.Hash() != want.Hash() {

View file

@ -59,45 +59,34 @@ type Era interface {
Close() error
Start() uint64
Count() uint64
Iterator() (Iterator, error)
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
next = uint64(0)
eras []string
dirType 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" {
fmt.Println("entries", entries)
for _, entry := range entries {
ext := path.Ext(entry.Name())
if ext != ".erae" && ext != ".era1" {
continue
}
if dirType == "" {
dirType = ext
}
parts := strings.Split(entry.Name(), "-")
if len(parts) != 3 || parts[0] != network {
// Invalid era1 filename, skip.
@ -108,6 +97,9 @@ func ReadDir(dir, network string) ([]string, error) {
} else if epoch != next {
return nil, fmt.Errorf("missing epoch %d", next)
}
if dirType != ext {
return nil, fmt.Errorf("directory %s contains mixed era file formats: want %s, have %s", dir, dirType, ext)
}
next += 1
eras = append(eras, entry.Name())
}

View file

@ -89,7 +89,6 @@ type Builder struct {
written uint64
expectsProofs bool
isPreMerge bool
numPreMerge int // number of pre-merge blocks
finalTD *big.Int // final total difficulty, used for pre-merge and merge straddling files
}

View file

@ -88,6 +88,11 @@ func (e *Era) Count() uint64 {
return e.m.count
}
// Iterator returns an iterator over the era file.
func (e *Era) Iterator() (era.Iterator, error) {
return NewIterator(e)
}
// GetBlockByNumber retrieves the block if present within the era file.
func (e *Era) GetBlockByNumber(blockNum uint64) (*types.Block, error) {
h, err := e.GetHeader(blockNum)

View file

@ -81,6 +81,11 @@ func (e *Era) Close() error {
return e.f.Close()
}
// Iterator returns an iterator over the era file.
func (e *Era) Iterator() (era.Iterator, error) {
return NewIterator(e)
}
// GetBlockByNumber returns the block for the given block number.
func (e *Era) GetBlockByNumber(num uint64) (*types.Block, error) {
if e.m.start > num || e.m.start+e.m.count <= num {

View file

@ -110,7 +110,3 @@ func (p *BlockProofHistoricalSummariesDeneb) EncodeRLP(w io.Writer) error {
// Variant returns the variant type of the BlockProofHistoricalSummariesDeneb.
func (*BlockProofHistoricalSummariesDeneb) Variant() variant { return proofDeneb }
func variantOf(p Proof) variant {
return p.Variant()
}