internal/era: improve iterator interface

This commit is contained in:
lightclient 2023-06-06 20:43:32 +02:00
parent b8fc70e8f4
commit 67defc417c
No known key found for this signature in database
GPG key ID: 75C916AFEE20183E

View file

@ -17,6 +17,7 @@
package era
import (
"fmt"
"io"
"math/big"
@ -29,7 +30,8 @@ type Iterator struct {
inner *RawIterator
}
// NewIterator returns a new Iterator instance.
// NewRawIterator 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)
if err != nil {
@ -38,7 +40,9 @@ func NewIterator(e *Era) (*Iterator, error) {
return &Iterator{inner}, nil
}
// Next moves the iterator to the next block entry.
// Next moves the iterator to the next block entry. It returns false when all
// items have been read or an error has halted its progress. Block, Receipts,
// and BlockAndReceipts should no longer be called after false is returned.
func (it *Iterator) Next() bool {
return it.inner.Next()
}
@ -48,13 +52,17 @@ func (it *Iterator) Number() uint64 {
return it.inner.next - 1
}
// Error returns the error status of the iterator.
// Error returns the error status of the iterator. It should be called before
// reading from any of the iterator's values.
func (it *Iterator) Error() error {
return it.inner.Error()
}
// Block returns the block for the iterator's current position.
func (it *Iterator) Block() (*types.Block, error) {
if it.inner.Header == nil || it.inner.Body == nil {
return nil, fmt.Errorf("header and body must be non-nil")
}
var (
header types.Header
body types.Body
@ -70,6 +78,9 @@ func (it *Iterator) Block() (*types.Block, error) {
// Receipts returns the receipts for the iterator's current position.
func (it *Iterator) Receipts() (types.Receipts, error) {
if it.inner.Receipts == nil {
return nil, fmt.Errorf("receipts must be non-nil")
}
var receipts types.Receipts
err := rlp.Decode(it.inner.Receipts, &receipts)
return receipts, err
@ -111,7 +122,8 @@ type RawIterator struct {
TotalDifficulty io.Reader
}
// NewRawIterator returns a new Iterator instance.
// NewRawIterator returns a new RawIterator instance. Next must be immediately
// called on new iterators to load the first item.
func NewRawIterator(e *Era) (*RawIterator, error) {
return &RawIterator{
e: e,
@ -119,30 +131,43 @@ func NewRawIterator(e *Era) (*RawIterator, error) {
}, nil
}
// Next moves the iterator to the next block entry.
// Next moves the iterator to the next block entry. It returns false when all
// items have been read or an error has halted its progress. Header, Body,
// Receipts, TotalDifficulty will be set to nil in the case returning false or
// finding an error and should therefore no longer be read from.
func (it *RawIterator) Next() bool {
// Clear old errors.
it.err = nil
if it.e.m.start+it.e.m.count <= it.next {
it.clear()
return false
}
off, err := it.e.readOffset(it.next)
if err == io.EOF {
if err != nil {
// Error here means block index is corrupted, so don't
// continue.
it.clear()
it.err = err
return false
}
var n int64
if it.Header, n, it.err = newSnappyReader(it.e.s, TypeCompressedHeader, off); it.err != nil {
it.clear()
return true
}
off += n
if it.Body, n, it.err = newSnappyReader(it.e.s, TypeCompressedBody, off); it.err != nil {
it.clear()
return true
}
off += n
if it.Receipts, n, it.err = newSnappyReader(it.e.s, TypeCompressedReceipts, off); it.err != nil {
it.clear()
return true
}
off += n
if it.TotalDifficulty, _, it.err = it.e.s.ReaderAt(TypeTotalDifficulty, off); it.err != nil {
it.clear()
return true
}
it.next += 1
@ -154,10 +179,19 @@ func (it *RawIterator) Number() uint64 {
return it.next - 1
}
// Error returns the error status of the iterator.
// Error returns the error status of the iterator. It should be called before
// reading from any of the iterator's values.
func (it *RawIterator) Error() error {
if it.err == io.EOF {
return nil
}
return it.err
}
// clear sets all the outputs to nil.
func (it *RawIterator) clear() {
it.Header = nil
it.Body = nil
it.Receipts = nil
it.TotalDifficulty = nil
}