From fd11aa11e4df739e54aa3e91efd94592f8933d32 Mon Sep 17 00:00:00 2001 From: shantichanal <158101918+shantichanal@users.noreply.github.com> Date: Tue, 8 Jul 2025 14:10:22 +0200 Subject: [PATCH] adding testing and refining functions --- internal/era2/builder2.go | 41 ++++++------ internal/era2/era2.go | 2 +- internal/era2/era_test.go | 130 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 154 insertions(+), 19 deletions(-) create mode 100644 internal/era2/era_test.go diff --git a/internal/era2/builder2.go b/internal/era2/builder2.go index a94f0ae7cd..6fcfdfa5b4 100644 --- a/internal/era2/builder2.go +++ b/internal/era2/builder2.go @@ -112,7 +112,7 @@ func NewBuilder(w io.Writer) *Builder { } } -func (b *Builder) Add(block *types.Block, receipts types.Receipts, td *big.Int, proof *Proof) error { +func (b *Builder) Add(header types.Header, body types.Body, receipts types.Receipts, blockhash common.Hash, blocknum uint64, td *big.Int, proof *Proof) error { if len(b.headersRLP) >= MaxEraESize { return fmt.Errorf("exceeds MaxEraESize %d", MaxEraESize) } @@ -124,16 +124,20 @@ func (b *Builder) Add(block *types.Block, receipts types.Receipts, td *big.Int, } if len(b.headersRLP) == 0 { - b.prooftype = proof.Variant + if proof == nil { + b.prooftype = ProofNone + } else { + b.prooftype = proof.Variant + } } else if proof.Variant != b.prooftype { return fmt.Errorf("cannot mix proof variants: have %d want %d", b.prooftype, proof.Variant) } - hdr, err := rlp.EncodeToBytes(block.Header()) + hdr, err := rlp.EncodeToBytes(header) if err != nil { return fmt.Errorf("error encoding block header: %w", err) } - bod, err := rlp.EncodeToBytes(block.Body()) + bod, err := rlp.EncodeToBytes(body) if err != nil { return fmt.Errorf("error encoding block header: %w", err) } @@ -147,14 +151,14 @@ func (b *Builder) Add(block *types.Block, receipts types.Receipts, td *big.Int, b.receiptsRLP = append(b.receiptsRLP, rct) b.tds = append(b.tds, uint256LE(td)) b.tdsint = append(b.tdsint, new(big.Int).Set(td)) - b.hashes = append(b.hashes, block.Hash()) + b.hashes = append(b.hashes, blockhash) - if proof.Variant != ProofNone { + if b.prooftype != ProofNone { b.proofsRLP = append(b.proofsRLP, proof.Data) } if b.startNum == nil { - sn := block.NumberU64() + sn := blocknum b.startNum = &sn if n, err := b.w.Write(TypeVersion, nil); err != nil { return fmt.Errorf("error writing version entry: %w", err) @@ -165,50 +169,51 @@ func (b *Builder) Add(block *types.Block, receipts types.Receipts, td *big.Int, return nil } -func (b *Builder) Finalize() error { +func (b *Builder) Finalize() (common.Hash, error) { if b.startNum == nil { - return errors.New("no blocks added, cannot finalize") + return common.Hash{}, errors.New("no blocks added, cannot finalize") } var err error b.headeroffsets, err = b.writeSection(TypeCompressedHeader, b.headersRLP, true) if err != nil { - return fmt.Errorf("error writing compressed headers: %w", err) + return common.Hash{}, fmt.Errorf("error writing compressed headers: %w", err) } b.bodyoffsets, err = b.writeSection(TypeCompressedBody, b.bodiesRLP, true) if err != nil { - return fmt.Errorf("error writing compressed bodies: %w", err) + return common.Hash{}, fmt.Errorf("error writing compressed bodies: %w", err) } b.receiptoffsets, err = b.writeSection(TypeCompressedReceipts, b.receiptsRLP, true) if err != nil { - return fmt.Errorf("error writing compressed receipts: %w", err) + return common.Hash{}, fmt.Errorf("error writing compressed receipts: %w", err) } if len(b.tds) > 0 { b.tdoff, err = b.writeSection(TypeTotalDifficulty, b.tds, false) if err != nil { - return fmt.Errorf("error writing total difficulties: %w", err) + return common.Hash{}, fmt.Errorf("error writing total difficulties: %w", err) } } if b.prooftype != 0 { b.proofoffsets, err = b.writeSection(uint16(b.prooftype), b.proofsRLP, true) if err != nil { - return fmt.Errorf("error writing proofs: %w", err) + return common.Hash{}, fmt.Errorf("error writing proofs: %w", err) } } + var accRoot common.Hash if len(b.hashes) > 0 { - accRoot, err := ComputeAccumulator(b.hashes, b.tdsint) + accRoot, err = ComputeAccumulator(b.hashes, b.tdsint) if err != nil { - return fmt.Errorf("error calculating accumulator root: %w", err) + return common.Hash{}, fmt.Errorf("error calculating accumulator root: %w", err) } if n, err := b.w.Write(TypeAccumulatorRoot, accRoot[:]); err != nil { - return fmt.Errorf("error writing accumulator root: %w", err) + return common.Hash{}, fmt.Errorf("error writing accumulator root: %w", err) } else { b.writtenBytes += uint64(n) } } - return b.writeIndex() + return accRoot, b.writeIndex() } func uint256LE(v *big.Int) []byte { diff --git a/internal/era2/era2.go b/internal/era2/era2.go index a6c47d6912..e01fd0980c 100644 --- a/internal/era2/era2.go +++ b/internal/era2/era2.go @@ -68,7 +68,7 @@ type Era2 struct { indstart int64 } -func OpenEra(filename string) (*Era2, error) { +func Open(filename string) (*Era2, error) { f, err := os.Open(filename) if err != nil { return nil, err diff --git a/internal/era2/era_test.go b/internal/era2/era_test.go new file mode 100644 index 0000000000..6978c02ba3 --- /dev/null +++ b/internal/era2/era_test.go @@ -0,0 +1,130 @@ +// Copyright 2024 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package era2 + +import ( + "bytes" + "fmt" + "math/big" + "os" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rlp" +) + +type testchain struct { + headers []types.Header + bodies []types.Body + receipts []types.Receipts + tds []*big.Int +} + +func TestEra2Builder(t *testing.T) { + t.Parallel() + + // Get temp directory. + f, err := os.CreateTemp(t.TempDir(), "era2-test") + if err != nil { + t.Fatalf("error creating temp file: %v", err) + } + defer f.Close() + + var ( + builder = NewBuilder(f) + chain = testchain{} + ) + for i := 0; i < 128; i++ { + chain.headers = append(chain.headers, types.Header{Number: big.NewInt(int64(i))}) + chain.bodies = append(chain.bodies, types.Body{Transactions: []*types.Transaction{types.NewTransaction(0, common.Address{byte(i)}, nil, 0, nil, nil)}}) + chain.receipts = append(chain.receipts, types.Receipts{{CumulativeGasUsed: uint64(i)}}) + chain.tds = append(chain.tds, big.NewInt(int64(i))) + } + + // Write blocks to Era1. + for i := 0; i < len(chain.headers); i++ { + var ( + header = chain.headers[i] + body = chain.bodies[i] + receipts = chain.receipts[i] + hash = common.Hash{byte(i)} + td = chain.tds[i] + ) + if err = builder.Add(header, body, receipts, hash, uint64(i), td, nil); err != nil { + t.Fatalf("error adding entry: %v", err) + } + } + + // Finalize Era1. + if _, err := builder.Finalize(); err != nil { + t.Fatalf("error finalizing era1: %v", err) + } + + // 3. open reader + era, err := Open(f.Name()) + if err != nil { + t.Fatalf("open era: %v", err) + } + defer era.Close() + + // 4. verify every block + for i := 0; i < 128; i++ { + bn := uint64(i) + + // -- header + body via GetBlockByNumber ------------------------------ + gotBlock, err := era.GetBlockByNumber(bn) + if err != nil { + t.Fatalf("get block %d: %v", i, err) + } + + if chain.headers[i].Hash() != gotBlock.Header().Hash() { + t.Fatalf("header %d mismatch", i) + } + if !bytes.Equal(mustEncode(chain.bodies[i]), mustEncode(gotBlock.Body())) { + t.Fatalf("body %d mismatch", i) + } + + // -- raw body frame -------------------------------------------------- + rawBody, err := era.GetRawBodyFrameByNumber(bn) + if err != nil { + t.Fatalf("raw body %d: %v", i, err) + } + expectBody := mustEncode(chain.bodies[i]) + if !bytes.Contains(rawBody, expectBody) { // frame may include next + t.Fatalf("body frame %d mismatch", i) + } + + // -- raw receipts frame --------------------------------------------- + rawRcpt, err := era.GetRawReceiptsFrameByNumber(bn) + if err != nil { + t.Fatalf("raw receipts %d: %v", i, err) + } + expectRcpt := mustEncode(chain.receipts[i]) + if !bytes.Contains(rawRcpt, expectRcpt) { + t.Fatalf("receipts frame %d mismatch", i) + } + } +} + +func mustEncode(obj any) []byte { + b, err := rlp.EncodeToBytes(obj) + if err != nil { + panic(fmt.Sprintf("failed in encode obj: %v", err)) + } + return b +}