diff --git a/internal/era2/builder.go b/internal/era2/builder.go index 79370e4336..6e57e8a195 100644 --- a/internal/era2/builder.go +++ b/internal/era2/builder.go @@ -70,16 +70,16 @@ const ( headerSize uint64 = 8 ) -type variant uint16 - +// temporary buffer for writing blocks until Finalize is called type buffer struct { headers [][]byte bodies [][]byte receipts [][]byte proofs [][]byte - tds [][]byte + tds []*big.Int } +// offsets holds the offsets of the different block components in the e2store file type offsets struct { headers []uint64 bodys []uint64 @@ -89,50 +89,30 @@ type offsets struct { } type Builder struct { - w *e2store.Writer - buf *bytes.Buffer - sn *snappy.Writer + w *e2store.Writer + buf *bytes.Buffer + snappy *snappy.Writer buff buffer off offsets - prooftype variant - tdsint []*big.Int - hashes []common.Hash - startNum *uint64 - writtenBytes uint64 + hashes []common.Hash + startNum *uint64 + written uint64 } // NewBuilder returns a new Builder instance. func NewBuilder(w io.Writer) *Builder { buf := bytes.NewBuffer(nil) return &Builder{ - w: e2store.NewWriter(w), - buf: buf, - sn: snappy.NewBufferedWriter(buf), + w: e2store.NewWriter(w), + buf: buf, + snappy: snappy.NewBufferedWriter(buf), } } // Add writes a block entry, its reciepts, and optionally its proofs as well into the e2store file. func (b *Builder) Add(header types.Header, body types.Body, receipts types.Receipts, td *big.Int, proof Proof) error { - pv := variantOf(proof) // variant code (or proofNone) - var ep []byte // encoded proof payload - - if proof != nil { - var buf bytes.Buffer - if err := proof.EncodeRLP(&buf); err != nil { - return fmt.Errorf("encode proof: %w", err) - } - ep = buf.Bytes() - } - - if len(b.buff.headers) == 0 { - b.prooftype = pv - } else if pv != b.prooftype { - return fmt.Errorf("cannot mix proof variants: first=%d now=%d", - b.prooftype, pv) - } - eh, err := rlp.EncodeToBytes(&header) if err != nil { return fmt.Errorf("encode header: %w", err) @@ -146,6 +126,22 @@ func (b *Builder) Add(header types.Header, body types.Body, receipts types.Recei return fmt.Errorf("encode receipts: %w", err) } + var ep []byte + var buffer bytes.Buffer + + if proof != nil { + if err := proof.EncodeRLP(&buffer); err != nil { + return fmt.Errorf("encode proof: %w", err) + } + ep = buffer.Bytes() + } else { + noProof := &NoProof{} + if err := noProof.EncodeRLP(&buffer); err != nil { + return fmt.Errorf("encode no proof: %w", err) + } + ep = buffer.Bytes() + } + return b.AddRLP( eh, eb, er, ep, header.Number.Uint64(), @@ -162,27 +158,26 @@ func (b *Builder) AddRLP(headerRLP []byte, bodyRLP []byte, receipts []byte, proo b.buff.headers = append(b.buff.headers, headerRLP) b.buff.bodies = append(b.buff.bodies, bodyRLP) b.buff.receipts = append(b.buff.receipts, receipts) - b.buff.tds = append(b.buff.tds, uint256LE(td)) - b.tdsint = append(b.tdsint, new(big.Int).Set(td)) + b.buff.tds = append(b.buff.tds, new(big.Int).Set(td)) b.hashes = append(b.hashes, blockHash) if proof != nil { b.buff.proofs = append(b.buff.proofs, proof) } - //Write Era2 version before writing any blocks. + // Write Era2 version before writing any blocks. if b.startNum == nil { b.startNum = new(uint64) *b.startNum = blockNum if n, err := b.w.Write(TypeVersion, nil); err != nil { return fmt.Errorf("write version entry: %w", err) } else { - b.writtenBytes += uint64(n) + b.written += uint64(n) } } return nil } -// Finalize flushes all entries present in cache to the underlying e2store file. +// Finalize writes all header entries, followed by all body entries, followed by all receipt entries. func (b *Builder) Finalize() (common.Hash, error) { if b.startNum == nil { return common.Hash{}, errors.New("no blocks added, cannot finalize") @@ -213,7 +208,8 @@ func (b *Builder) Finalize() (common.Hash, error) { if len(b.buff.tds) > 0 { for _, data := range b.buff.tds { - off, err := b.addEntry(TypeTotalDifficulty, data, false) + littleEndian := uint256LE(data) + off, err := b.addEntry(TypeTotalDifficulty, littleEndian, false) if err != nil { return common.Hash{}, fmt.Errorf("total-difficulty: %w", err) } @@ -221,7 +217,7 @@ func (b *Builder) Finalize() (common.Hash, error) { } } - if b.prooftype != ProofNone { + if len(b.buff.proofs) > 0 { for _, data := range b.buff.proofs { off, err := b.addEntry(TypeProof, data, true) if err != nil { @@ -234,14 +230,14 @@ func (b *Builder) Finalize() (common.Hash, error) { var accRoot common.Hash if len(b.hashes) > 0 { var err error - accRoot, err = ComputeAccumulator(b.hashes, b.tdsint) + accRoot, err = ComputeAccumulator(b.hashes, b.buff.tds) if err != nil { return common.Hash{}, fmt.Errorf("compute accumulator: %w", err) } if n, err := b.w.Write(TypeAccumulatorRoot, accRoot[:]); err != nil { return common.Hash{}, fmt.Errorf("write accumulator: %w", err) } else { - b.writtenBytes += uint64(n) + b.written += uint64(n) } } @@ -261,18 +257,18 @@ func uint256LE(v *big.Int) []byte { func (b *Builder) snappyWrite(typ uint16, in []byte) error { var ( buf = b.buf - s = b.sn + s = b.snappy ) buf.Reset() s.Reset(buf) - if _, err := b.sn.Write(in); err != nil { + if _, err := b.snappy.Write(in); err != nil { return fmt.Errorf("error snappy encoding: %w", err) } if err := s.Flush(); err != nil { return fmt.Errorf("error flushing snappy encoding: %w", err) } n, err := b.w.Write(typ, b.buf.Bytes()) - b.writtenBytes += uint64(n) + b.written += uint64(n) if err != nil { return fmt.Errorf("error writing e2store entry: %w", err) } @@ -280,10 +276,10 @@ func (b *Builder) snappyWrite(typ uint16, in []byte) error { } // Add entry takes the e2store object and writes it into the file -func (b *Builder) addEntry(typ uint16, payload []byte, snappyIt bool) (uint64, error) { - offset := b.writtenBytes +func (b *Builder) addEntry(typ uint16, payload []byte, compressed bool) (uint64, error) { + offset := b.written var err error - if snappyIt { + if compressed { if err = b.snappyWrite(typ, payload); err != nil { return 0, err } @@ -292,12 +288,12 @@ func (b *Builder) addEntry(typ uint16, payload []byte, snappyIt bool) (uint64, e if n, err = b.w.Write(typ, payload); err != nil { return 0, err } - b.writtenBytes += uint64(n) + b.written += uint64(n) } return offset, nil } -// write index takes all the offset table and writes it to the file +// writeIndex takes all the offset table and writes it to the file // the index table contains all offsets to specific block entries func (b *Builder) writeIndex() error { count := uint64(len(b.off.headers)) @@ -309,9 +305,9 @@ func (b *Builder) writeIndex() error { componentCount++ } - index := make([]byte, 8+count*8*componentCount+16) //8 for start block, 8 per property per block, 16 for the number of properties and the number of blocks + index := make([]byte, 8+count*8*componentCount+16) // 8 for start block, 8 per property per block, 16 for the number of properties and the number of blocks binary.LittleEndian.PutUint64(index, *b.startNum) - base := int64(b.writtenBytes) + base := int64(b.written) rel := func(abs uint64) uint64 { return uint64(int64(abs) - base) } for i := uint64(0); i < count; i++ { basePosition := 8 + i*componentCount*8 @@ -329,14 +325,14 @@ func (b *Builder) writeIndex() error { binary.LittleEndian.PutUint64(index[basePosition+pos:], rel(b.off.proofoffsets[i])) } } - indexEnd := 8 + count*componentCount*8 + end := 8 + count*componentCount*8 - binary.LittleEndian.PutUint64(index[indexEnd+0:], componentCount) - binary.LittleEndian.PutUint64(index[indexEnd+8:], count) + binary.LittleEndian.PutUint64(index[end+0:], componentCount) + binary.LittleEndian.PutUint64(index[end+8:], count) if n, err := b.w.Write(TypeBlockIndex, index); err != nil { return err } else { - b.writtenBytes += uint64(n) + b.written += uint64(n) } return nil } diff --git a/internal/era2/era.go b/internal/era2/era.go index 35d514a3e1..67848cb2b9 100644 --- a/internal/era2/era.go +++ b/internal/era2/era.go @@ -30,6 +30,7 @@ import ( "github.com/klauspost/compress/snappy" ) +// metadata contains the information about the era file that is written into the file. type metadata struct { start uint64 // start block number count uint64 // number of blocks in the era @@ -37,97 +38,17 @@ type metadata struct { length int64 // length of the file in bytes } -const ( - ProofNone variant = iota - proofHHA - proofRoots - proofCapella - proofDeneb -) +// the types of components that can be present in the era file. +type componentType int const ( - compHeader = 0 - compBody = 1 - compReceipts = 2 - compTD = 3 - compProof = 4 + componentHeader componentType = iota + componentBody + componentReceipts + componentTD + componentProof ) -type BlockProofHistoricalHashesAccumulator [15]common.Hash // 15 * 32 = 480 bytes - -// BlockProofHistoricalRoots – Altair / Bellatrix historical_roots branch. -type BlockProofHistoricalRoots struct { - BeaconBlockProof [14]common.Hash // 448 - BeaconBlockRoot common.Hash // 32 - ExecutionBlockProof [11]common.Hash // 352 - Slot uint64 // 8 => 840 bytes -} - -// BlockProofHistoricalSummariesCapella – Capella historical_summaries branch. -type BlockProofHistoricalSummariesCapella struct { - BeaconBlockProof [13]common.Hash // 416 - BeaconBlockRoot common.Hash // 32 - ExecutionBlockProof [11]common.Hash // 352 - Slot uint64 // 8 => 808 bytes -} - -// BlockProofHistoricalSummariesDeneb – Deneb historical_summaries branch. -type BlockProofHistoricalSummariesDeneb struct { - BeaconBlockProof [13]common.Hash // 416 - BeaconBlockRoot common.Hash // 32 - ExecutionBlockProof [12]common.Hash // 384 - Slot uint64 // 8 => 840 bytes -} - -type Proof interface { - EncodeRLP(w io.Writer) error - DecodeRlP(s *rlp.Stream) error - Variant() variant -} - -type hhaAlias BlockProofHistoricalHashesAccumulator // alias ⇒ no EncodeRLP method - -func (p *BlockProofHistoricalHashesAccumulator) EncodeRLP(w io.Writer) error { - payload := []interface{}{uint16(proofHHA), hhaAlias(*p)} - return rlp.Encode(w, payload) -} - -func (p *BlockProofHistoricalHashesAccumulator) Variant() variant { return proofHHA } - -type rootsAlias BlockProofHistoricalRoots - -func (p *BlockProofHistoricalRoots) EncodeRLP(w io.Writer) error { - payload := []interface{}{uint16(proofRoots), rootsAlias(*p)} - return rlp.Encode(w, payload) -} - -func (*BlockProofHistoricalRoots) Variant() variant { return proofRoots } - -type capellaAlias BlockProofHistoricalSummariesCapella - -func (p *BlockProofHistoricalSummariesCapella) EncodeRLP(w io.Writer) error { - payload := []interface{}{uint16(proofCapella), capellaAlias(*p)} - return rlp.Encode(w, payload) -} - -func (*BlockProofHistoricalSummariesCapella) Variant() variant { return proofCapella } - -type denebAlias BlockProofHistoricalSummariesDeneb - -func (p *BlockProofHistoricalSummariesDeneb) EncodeRLP(w io.Writer) error { - payload := []interface{}{uint16(proofDeneb), denebAlias(*p)} - return rlp.Encode(w, payload) -} - -func (*BlockProofHistoricalSummariesDeneb) Variant() variant { return proofDeneb } - -func variantOf(p Proof) variant { - if p == nil { - return ProofNone - } - return p.Variant() -} - type ReadAtSeekCloser interface { io.ReaderAt io.Seeker @@ -135,19 +56,17 @@ type ReadAtSeekCloser interface { } type Era struct { - f ReadAtSeekCloser - s *e2store.Reader - m metadata // metadata for the Era file - indstart int64 - rootheader uint64 // offset of the root header in the file if present + f ReadAtSeekCloser + s *e2store.Reader + m metadata // metadata for the Era file } -// Returns a recognizable filename for erae file +// Filename returns a recognizable filename for erae file func Filename(network string, epoch int, root common.Hash) string { return fmt.Sprintf("%s-%05d-%s.erae", network, epoch, root.Hex()[2:10]) } -// Opens era file +// Open opens the era file func Open(path string) (*Era, error) { f, err := os.Open(path) if err != nil { @@ -161,7 +80,7 @@ func Open(path string) (*Era, error) { return e, nil } -// Closes era file +// Close closes the era file func (e *Era) Close() error { if e.f == nil { return nil @@ -171,17 +90,17 @@ func (e *Era) Close() error { return err } -// retrieves starting block number +// Start retrieves the starting block number func (e *Era) Start() uint64 { return e.m.start } -// retrieves count of blocks present +// Count retrieves the count of blocks present func (e *Era) Count() uint64 { return e.m.count } -// retrieves the block if present within the era file +// GetBlockByNumber retrieves the block if present within the era file func (e *Era) GetBlockByNumber(blockNum uint64) (*types.Block, error) { h, err := e.GetHeader(blockNum) if err != nil { @@ -194,7 +113,7 @@ func (e *Era) GetBlockByNumber(blockNum uint64) (*types.Block, error) { return types.NewBlockWithHeader(h).WithBody(*b), nil } -// retrieves header from era file through the cached offset table +// GetHeader retrieves the header from the era file through the cached offset table func (e *Era) GetHeader(num uint64) (*types.Header, error) { off, err := e.headerOff(num) if err != nil { @@ -211,7 +130,7 @@ func (e *Era) GetHeader(num uint64) (*types.Header, error) { return &h, rlp.Decode(r, &h) } -// retrieves body from era file through cached offset table +// GetBody retrieves the body from the era file through cached offset table func (e *Era) GetBody(num uint64) (*types.Body, error) { off, err := e.bodyOff(num) if err != nil { @@ -228,7 +147,7 @@ func (e *Era) GetBody(num uint64) (*types.Body, error) { return &b, rlp.Decode(r, &b) } -// retrieves td from era file through cached offset table +// getTD retrieves the td from the era file through cached offset table func (e *Era) getTD(blockNum uint64) (*big.Int, error) { off, err := e.tdOff(blockNum) if err != nil { @@ -243,7 +162,7 @@ func (e *Era) getTD(blockNum uint64) (*big.Int, error) { return td, nil } -// retrieves the raw body frame in bytes of a specific block +// GetRawBodyFrameByNumber retrieves the raw body frame in bytes of a specific block func (e *Era) GetRawBodyFrameByNumber(blockNum uint64) ([]byte, error) { off, err := e.bodyOff(blockNum) if err != nil { @@ -256,9 +175,9 @@ func (e *Era) GetRawBodyFrameByNumber(blockNum uint64) ([]byte, error) { return io.ReadAll(r) } -// retrieves the raw receipts frame in bytes of a specific block +// GetRawReceiptsFrameByNumber retrieves the raw receipts frame in bytes of a specific block. func (e *Era) GetRawReceiptsFrameByNumber(blockNum uint64) ([]byte, error) { - off, err := e.rcptOff(blockNum) + off, err := e.receiptOff(blockNum) if err != nil { return nil, err } @@ -269,7 +188,7 @@ func (e *Era) GetRawReceiptsFrameByNumber(blockNum uint64) ([]byte, error) { return io.ReadAll(r) } -// retrieves the raw proof frame in bytes of a specific block proof +// GetRawProofFrameByNumber retrieves the raw proof frame in bytes of a specific block proof func (e *Era) GetRawProofFrameByNumber(blockNum uint64) ([]byte, error) { off, err := e.proofOff(blockNum) if err != nil { @@ -282,7 +201,7 @@ func (e *Era) GetRawProofFrameByNumber(blockNum uint64) ([]byte, error) { return io.ReadAll(r) } -// loads in the index table containing all offsets and caches it +// loadIndex loads in the index table containing all offsets and caches it func (e *Era) loadIndex() error { var err error e.m.length, err = e.f.Seek(0, io.SeekEnd) @@ -299,65 +218,43 @@ func (e *Era) loadIndex() error { payloadlen := 8 + 8*e.m.count*e.m.components + 16 // 8 for start block, 8 per property per block, 16 for the number of properties and the number of blocks tlvstart := e.m.length - int64(payloadlen) - 8 - e.indstart = tlvstart - _, err = e.f.ReadAt(b[:8], tlvstart+8) if err != nil { return err } e.m.start = binary.LittleEndian.Uint64(b[:8]) - num := int(e.m.components) - - totaloffsets := num * int(e.m.count) - offBytes := make([]byte, totaloffsets*8) - offsetArea := tlvstart + 8 + 8 // 8 for the header size, 8 for the start number - _, err = e.f.ReadAt(offBytes, offsetArea) - if err != nil { - return err - } - - var off int64 = 0 // start at byte-0 of file - - for off < e.indstart { // never enter the Block-Index TLV - typ, length, err := e.s.ReadMetadataAt(off) - if err != nil { - return fmt.Errorf("error reading TLV at offset %d: %w", off, err) - } - if typ == TypeAccumulatorRoot { - e.rootheader = uint64(off) // remember absolute header offset - break // found - } - off += 8 + int64(length) // headersize plus length to jump to next TLV header - } return nil } // Getter methods to calculate offset of a specific component in the file. -func (e *Era) headerOff(num uint64) (uint64, error) { return e.indexOffset(num, compHeader) } -func (e *Era) bodyOff(num uint64) (uint64, error) { return e.indexOffset(num, compBody) } -func (e *Era) rcptOff(num uint64) (uint64, error) { return e.indexOffset(num, compReceipts) } -func (e *Era) tdOff(num uint64) (uint64, error) { return e.indexOffset(num, compTD) } -func (e *Era) proofOff(num uint64) (uint64, error) { return e.indexOffset(num, compProof) } +func (e *Era) headerOff(num uint64) (uint64, error) { return e.indexOffset(num, componentHeader) } +func (e *Era) bodyOff(num uint64) (uint64, error) { return e.indexOffset(num, componentBody) } +func (e *Era) receiptOff(num uint64) (uint64, error) { return e.indexOffset(num, componentReceipts) } +func (e *Era) tdOff(num uint64) (uint64, error) { return e.indexOffset(num, componentTD) } +func (e *Era) proofOff(num uint64) (uint64, error) { return e.indexOffset(num, componentProof) } -// calculates offset to a certain component for a block number within a file. -func (e *Era) indexOffset(n uint64, comp int) (uint64, error) { +// indexOffset calculates offset to a certain component for a block number within a file. +func (e *Era) indexOffset(n uint64, component componentType) (uint64, error) { if n < e.m.start || n >= e.m.start+e.m.count { return 0, fmt.Errorf("block %d out of range [%d,%d)", n, e.m.start, e.m.start+e.m.count) } - if comp >= int(e.m.components) { - return 0, fmt.Errorf("component %d not present", comp) + if int(component) >= int(e.m.components) { + return 0, fmt.Errorf("component %d not present", component) } - rec := (n-e.m.start)*e.m.components + uint64(comp) - pos := e.indstart + 8 + 8 + int64(rec*8) + payloadlen := 8 + 8*e.m.count*e.m.components + 16 // 8 for start block, 8 per property per block, 16 for the number of properties and the number of blocks + indstart := e.m.length - int64(payloadlen) - 8 + + rec := (n-e.m.start)*e.m.components + uint64(component) + pos := indstart + 8 + 8 + int64(rec*8) var buf [8]byte if _, err := e.f.ReadAt(buf[:], pos); err != nil { return 0, err } rel := binary.LittleEndian.Uint64(buf[:]) - return uint64(int64(rel) + e.indstart), nil + return uint64(int64(rel) + indstart), nil } // GetHeaders returns RLP-decoded headers. @@ -430,7 +327,7 @@ func (e *Era) GetReceipts(first, count uint64) ([]types.Receipts, error) { out := make([]types.Receipts, count) for i := uint64(0); i < count; i++ { n := first + i - off, err := e.rcptOff(n) + off, err := e.receiptOff(n) if err != nil { return nil, err } diff --git a/internal/era2/proof.go b/internal/era2/proof.go new file mode 100644 index 0000000000..f52f1db5bc --- /dev/null +++ b/internal/era2/proof.go @@ -0,0 +1,118 @@ +// Copyright 2025 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 ( + "io" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/rlp" +) + +type variant uint16 + +const ( + proofNone variant = iota + proofHistoricalHashesAccumulator + proofHistoricalRoots + proofCapella + proofDeneb +) + +type BlockProofHistoricalHashesAccumulator [15]common.Hash // 15 * 32 = 480 bytes + +// BlockProofHistoricalRoots – Altair / Bellatrix historical_roots branch. +type BlockProofHistoricalRoots struct { + BeaconBlockProof [14]common.Hash // 448 + BeaconBlockRoot common.Hash // 32 + ExecutionBlockProof [11]common.Hash // 352 + Slot uint64 // 8 => 840 bytes +} + +// BlockProofHistoricalSummariesCapella – Capella historical_summaries branch. +type BlockProofHistoricalSummariesCapella struct { + BeaconBlockProof [13]common.Hash // 416 + BeaconBlockRoot common.Hash // 32 + ExecutionBlockProof [11]common.Hash // 352 + Slot uint64 // 8 => 808 bytes +} + +// BlockProofHistoricalSummariesDeneb – Deneb historical_summaries branch. +type BlockProofHistoricalSummariesDeneb struct { + BeaconBlockProof [13]common.Hash // 416 + BeaconBlockRoot common.Hash // 32 + ExecutionBlockProof [12]common.Hash // 384 + Slot uint64 // 8 => 840 bytes +} + +type NoProof struct{} + +type Proof interface { + EncodeRLP(w io.Writer) error + DecodeRlP(s *rlp.Stream) error + Variant() variant +} + +type hhaAlias BlockProofHistoricalHashesAccumulator // alias ⇒ no EncodeRLP method + +func (p *BlockProofHistoricalHashesAccumulator) EncodeRLP(w io.Writer) error { + payload := []interface{}{uint16(proofHistoricalHashesAccumulator), hhaAlias(*p)} + return rlp.Encode(w, payload) +} + +func (p *BlockProofHistoricalHashesAccumulator) Variant() variant { + return proofHistoricalHashesAccumulator +} + +type rootsAlias BlockProofHistoricalRoots + +func (p *BlockProofHistoricalRoots) EncodeRLP(w io.Writer) error { + payload := []interface{}{uint16(proofHistoricalRoots), rootsAlias(*p)} + return rlp.Encode(w, payload) +} + +func (*BlockProofHistoricalRoots) Variant() variant { return proofHistoricalRoots } + +type capellaAlias BlockProofHistoricalSummariesCapella + +func (p *BlockProofHistoricalSummariesCapella) EncodeRLP(w io.Writer) error { + payload := []interface{}{uint16(proofCapella), capellaAlias(*p)} + return rlp.Encode(w, payload) +} + +func (*BlockProofHistoricalSummariesCapella) Variant() variant { return proofCapella } + +type denebAlias BlockProofHistoricalSummariesDeneb + +func (p *BlockProofHistoricalSummariesDeneb) EncodeRLP(w io.Writer) error { + payload := []interface{}{uint16(proofDeneb), denebAlias(*p)} + return rlp.Encode(w, payload) +} + +type NoProofAlias NoProof // alias ⇒ no EncodeRLP method + +func (p *NoProof) EncodeRLP(w io.Writer) error { + payload := []interface{}{uint16(proofNone), NoProofAlias(*p)} + return rlp.Encode(w, payload) +} + +func (*NoProof) Variant() variant { return proofNone } + +func (*BlockProofHistoricalSummariesDeneb) Variant() variant { return proofDeneb } + +func variantOf(p Proof) variant { + return p.Variant() +}