mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-19 11:20:45 +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)
|
||||
network = ctx.String(networkFlag.Name)
|
||||
)
|
||||
entries, err := onedb.ReadDir(dir, network)
|
||||
entries, err := era.ReadDir(dir, network)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading era dir: %w", err)
|
||||
}
|
||||
if epoch >= uint64(len(entries)) {
|
||||
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
|
||||
|
|
@ -199,7 +200,7 @@ func verify(ctx *cli.Context) error {
|
|||
reported = time.Now()
|
||||
)
|
||||
|
||||
entries, err := onedb.ReadDir(dir, network)
|
||||
entries, err := era.ReadDir(dir, network)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error reading %s: %w", dir, err)
|
||||
}
|
||||
|
|
@ -214,18 +215,19 @@ func verify(ctx *cli.Context) error {
|
|||
err := func() error {
|
||||
name := entries[i]
|
||||
e, err := onedb.Open(filepath.Join(dir, name))
|
||||
eraPointer := e.(*onedb.Era)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error opening era1 file %s: %w", name, err)
|
||||
}
|
||||
defer e.Close()
|
||||
// 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)
|
||||
} else if got != want {
|
||||
return fmt.Errorf("invalid root %s: got %s, want %s", name, got, want)
|
||||
}
|
||||
// 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)
|
||||
}
|
||||
// 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/era"
|
||||
"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/log"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
|
|
@ -518,11 +520,11 @@ func importHistory(ctx *cli.Context) error {
|
|||
format := ctx.String(utils.EraFormatFlag.Name)
|
||||
switch format {
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
default:
|
||||
|
|
@ -563,11 +565,11 @@ func exportHistory(ctx *cli.Context) error {
|
|||
format := ctx.String(utils.EraFormatFlag.Get(ctx))
|
||||
switch format {
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
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/ethdb"
|
||||
"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/log"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
|
|
@ -253,11 +253,11 @@ 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) error {
|
||||
func ImportHistory(chain *core.BlockChain, dir string, network string, from era.FromFn, iterator era.NewIteratorFn) error {
|
||||
if chain.CurrentSnapBlock().Number.BitLen() != 0 {
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
// Import all block data from Era1.
|
||||
e, err := onedb.From(f)
|
||||
e, err := from(f)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error opening era: %w", err)
|
||||
}
|
||||
it, err := onedb.NewIterator(e)
|
||||
it, err := iterator(e)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating iterator: %w", err)
|
||||
}
|
||||
|
|
@ -347,105 +347,6 @@ func ImportHistory(chain *core.BlockChain, dir string, network string) error {
|
|||
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 {
|
||||
head := chain.CurrentBlock()
|
||||
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,
|
||||
// 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)
|
||||
if head := bc.CurrentBlock().Number.Uint64(); head < 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 {
|
||||
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 {
|
||||
fh, err := os.Create(tmpPath)
|
||||
|
|
@ -554,7 +455,7 @@ func ExportHistory(bc *core.BlockChain, dir string, first, last, step uint64) er
|
|||
}
|
||||
defer fh.Close()
|
||||
|
||||
bldr := onedb.NewBuilder(fh)
|
||||
bldr := builderfn(fh)
|
||||
|
||||
for j := uint64(0); j < step && batch+j <= last; 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)
|
||||
}
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -1,11 +1,17 @@
|
|||
package era
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"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.
|
||||
|
|
@ -36,12 +42,74 @@ type Iterator interface {
|
|||
Next() bool
|
||||
Number() uint64
|
||||
Block() (*types.Block, error)
|
||||
BlockAndReceipts() (*types.Block, types.Receipts, error)
|
||||
Receipts() (types.Receipts, error)
|
||||
Error() error
|
||||
}
|
||||
|
||||
// Builder represents the interface for various types of era formats.
|
||||
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)
|
||||
}
|
||||
|
||||
// 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"
|
||||
|
||||
"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/internal/era"
|
||||
"github.com/ethereum/go-ethereum/internal/era/e2store"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/golang/snappy"
|
||||
)
|
||||
|
|
@ -91,7 +93,7 @@ type Builder struct {
|
|||
}
|
||||
|
||||
// NewBuilder returns a new Builder instance.
|
||||
func NewBuilder(w io.Writer) *Builder {
|
||||
func NewBuilder(w io.Writer) era.Builder {
|
||||
tmp := bytes.NewBuffer(nil)
|
||||
return &Builder{
|
||||
w: e2store.NewWriter(w),
|
||||
|
|
@ -137,12 +139,15 @@ func (b *Builder) Add(block *types.Block, receipts types.Receipts, td *big.Int,
|
|||
return b.AddRLP(
|
||||
eh, eb, er, ep,
|
||||
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.
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
|
||||
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.
|
||||
if b.startNum == nil {
|
||||
b.startNum = new(uint64)
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ func TestEra2Builder(t *testing.T) {
|
|||
t.Fatalf("body %d mismatch", i)
|
||||
}
|
||||
|
||||
rawBody, err := era.GetRawBodyFrameByNumber(bn)
|
||||
rawBody, err := era.GetRawBodyByNumber(bn)
|
||||
if err != nil {
|
||||
t.Fatalf("raw body %d: %v", i, err)
|
||||
}
|
||||
|
|
@ -153,7 +153,7 @@ func TestEra2Builder(t *testing.T) {
|
|||
t.Fatalf("body frame %d mismatch", i)
|
||||
}
|
||||
|
||||
rawRcpt, err := era.GetRawReceiptsFrameByNumber(bn)
|
||||
rawRcpt, err := era.GetRawReceiptsByNumber(bn)
|
||||
if err != nil {
|
||||
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.
|
||||
// Call Next immediately to position on the first block.
|
||||
func NewIterator(e *Era) (*Iterator, error) {
|
||||
inner, err := NewRawIterator(e)
|
||||
func NewIterator(e era.Era) (era.Iterator, error) {
|
||||
inner, err := NewRawIterator(e.(*Era))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,10 +22,7 @@ import (
|
|||
"io"
|
||||
"math/big"
|
||||
"os"
|
||||
"path"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
|
|
@ -72,7 +69,7 @@ func (e *Era) Close() error {
|
|||
}
|
||||
|
||||
// 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)}
|
||||
if err := e.loadIndex(); err != nil {
|
||||
f.Close()
|
||||
|
|
@ -81,37 +78,6 @@ func From(f era.ReadAtSeekCloser) (*Era, error) {
|
|||
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.
|
||||
func (e *Era) Start() uint64 {
|
||||
return e.m.start
|
||||
|
|
@ -185,8 +151,8 @@ func (e *Era) getTD(blockNum uint64) (*big.Int, error) {
|
|||
return td, nil
|
||||
}
|
||||
|
||||
// GetRawBodyFrameByNumber retrieves the raw body frame in bytes of a specific block.
|
||||
func (e *Era) GetRawBodyFrameByNumber(blockNum uint64) ([]byte, error) {
|
||||
// GetRawBodyByNumber returns the RLP-encoded body for the given block number.
|
||||
func (e *Era) GetRawBodyByNumber(blockNum uint64) ([]byte, error) {
|
||||
off, err := e.bodyOff(blockNum)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -198,8 +164,8 @@ func (e *Era) GetRawBodyFrameByNumber(blockNum uint64) ([]byte, error) {
|
|||
return io.ReadAll(r)
|
||||
}
|
||||
|
||||
// GetRawReceiptsFrameByNumber retrieves the raw receipts frame in bytes of a specific block.
|
||||
func (e *Era) GetRawReceiptsFrameByNumber(blockNum uint64) ([]byte, error) {
|
||||
// GetRawReceiptsByNumber returns the RLP-encoded receipts for the given block number.
|
||||
func (e *Era) GetRawReceiptsByNumber(blockNum uint64) ([]byte, error) {
|
||||
off, err := e.receiptOff(blockNum)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -211,7 +177,7 @@ func (e *Era) GetRawReceiptsFrameByNumber(blockNum uint64) ([]byte, error) {
|
|||
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) {
|
||||
off, err := e.proofOff(blockNum)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ type Builder struct {
|
|||
}
|
||||
|
||||
// NewBuilder returns a new Builder instance.
|
||||
func NewBuilder(w io.Writer) *Builder {
|
||||
func NewBuilder(w io.Writer) era.Builder {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
return &Builder{
|
||||
w: e2store.NewWriter(w),
|
||||
|
|
@ -113,12 +113,15 @@ func (b *Builder) Add(block *types.Block, receipts types.Receipts, td *big.Int,
|
|||
if err != nil {
|
||||
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
|
||||
// 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.
|
||||
if b.startNum == nil {
|
||||
n, err := b.w.Write(era.TypeVersion, nil)
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ func TestEra1Builder(t *testing.T) {
|
|||
hash = common.Hash{byte(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)
|
||||
}
|
||||
}
|
||||
|
|
@ -83,7 +83,11 @@ func TestEra1Builder(t *testing.T) {
|
|||
t.Fatalf("failed to open era: %v", err)
|
||||
}
|
||||
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 {
|
||||
t.Fatalf("failed to make iterator: %s", err)
|
||||
}
|
||||
|
|
@ -120,7 +124,7 @@ func TestEra1Builder(t *testing.T) {
|
|||
if !bytes.Equal(rawReceipts, chain.receipts[i]) {
|
||||
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 {
|
||||
t.Fatalf("error reading receipts: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ type Iterator struct {
|
|||
|
||||
// NewIterator returns a new Iterator instance. Next must be immediately
|
||||
// called on new iterators to load the first item.
|
||||
func NewIterator(e *Era) (*Iterator, error) {
|
||||
inner, err := NewRawIterator(e)
|
||||
func NewIterator(e era.Era) (era.Iterator, error) {
|
||||
inner, err := NewRawIterator(e.(*Era))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,10 +22,7 @@ import (
|
|||
"io"
|
||||
"math/big"
|
||||
"os"
|
||||
"path"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"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])
|
||||
}
|
||||
|
||||
// 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 {
|
||||
io.ReaderAt
|
||||
io.Seeker
|
||||
|
|
@ -89,7 +55,7 @@ type Era struct {
|
|||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -103,7 +69,7 @@ func From(f ReadAtSeekCloser) (*Era, error) {
|
|||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
Loading…
Reference in a new issue