mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-17 20:31:35 +00:00
keep only batch optimization
This commit is contained in:
parent
d9939eb995
commit
f71d097a14
5 changed files with 62 additions and 393 deletions
110
cmd/utils/cmd.go
110
cmd/utils/cmd.go
|
|
@ -249,91 +249,9 @@ func readList(filename string) ([]string, error) {
|
||||||
return strings.Split(string(b), "\n"), nil
|
return strings.Split(string(b), "\n"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type eraReceiptFormat uint8
|
// ImportHistory imports Era1 files containing historical block information,
|
||||||
|
|
||||||
const (
|
|
||||||
eraReceiptFormatConsensus eraReceiptFormat = iota // era1: full receipts
|
|
||||||
eraReceiptFormatSlim // erae: slim receipts
|
|
||||||
)
|
|
||||||
|
|
||||||
func receiptFormat(file string) (eraReceiptFormat, error) {
|
|
||||||
switch filepath.Ext(file) {
|
|
||||||
case ".era1":
|
|
||||||
return eraReceiptFormatConsensus, nil
|
|
||||||
case ".erae":
|
|
||||||
return eraReceiptFormatSlim, nil
|
|
||||||
default:
|
|
||||||
return 0, fmt.Errorf("unsupported era file: %s", file)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// convertSlimReceiptsToStorage converts slim receipt encoding
|
|
||||||
// [tx-type, post-state-or-status, gas-used, logs] into storage encoding
|
|
||||||
// [post-state-or-status, gas-used, logs].
|
|
||||||
func convertSlimReceiptsToStorage(input []byte, expectedTxs int) (rlp.RawValue, error) {
|
|
||||||
var (
|
|
||||||
out bytes.Buffer
|
|
||||||
enc = rlp.NewEncoderBuffer(&out)
|
|
||||||
)
|
|
||||||
blockListIter, err := rlp.NewListIterator(input)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("invalid block receipts list: %w", err)
|
|
||||||
}
|
|
||||||
outerList := enc.List()
|
|
||||||
receipts := 0
|
|
||||||
for ; blockListIter.Next(); receipts++ {
|
|
||||||
dataIter, err := rlp.NewListIterator(blockListIter.Value())
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("slim receipt %d has invalid data: %w", receipts, err)
|
|
||||||
}
|
|
||||||
innerList := enc.List()
|
|
||||||
fields := 0
|
|
||||||
for dataIter.Next() {
|
|
||||||
switch fields {
|
|
||||||
case 0:
|
|
||||||
// Skip tx type.
|
|
||||||
case 1, 2, 3:
|
|
||||||
enc.Write(dataIter.Value())
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("slim receipt %d has too many fields", receipts)
|
|
||||||
}
|
|
||||||
fields++
|
|
||||||
}
|
|
||||||
enc.ListEnd(innerList)
|
|
||||||
if dataIter.Err() != nil {
|
|
||||||
return nil, fmt.Errorf("slim receipt %d iterator error: %w", receipts, dataIter.Err())
|
|
||||||
}
|
|
||||||
if fields != 4 {
|
|
||||||
return nil, fmt.Errorf("slim receipt %d has %d fields, want 4", receipts, fields)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
enc.ListEnd(outerList)
|
|
||||||
if blockListIter.Err() != nil {
|
|
||||||
return nil, fmt.Errorf("block receipt list iterator error: %w", blockListIter.Err())
|
|
||||||
}
|
|
||||||
if expectedTxs >= 0 && receipts != expectedTxs {
|
|
||||||
return nil, fmt.Errorf("tx/receipt count mismatch: %d txs, %d receipts", expectedTxs, receipts)
|
|
||||||
}
|
|
||||||
if err := enc.Flush(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func convertReceiptsToStorage(input []byte, format eraReceiptFormat, expectedTxs int) (rlp.RawValue, error) {
|
|
||||||
switch format {
|
|
||||||
case eraReceiptFormatConsensus:
|
|
||||||
return types.ConvertConsensusReceiptsToStorage(input)
|
|
||||||
case eraReceiptFormatSlim:
|
|
||||||
return convertSlimReceiptsToStorage(input, expectedTxs)
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unsupported receipt format: %d", format)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ImportHistory imports Era files containing historical block information,
|
|
||||||
// starting from genesis. The assumption is held that the provided chain
|
// starting from genesis. The assumption is held that the provided chain
|
||||||
// segment in era file should all be canonical and verified.
|
// segment in Era1 file should all be canonical and verified.
|
||||||
func ImportHistory(chain *core.BlockChain, dir string, network string, from func(f era.ReadAtSeekCloser) (era.Era, error)) 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 {
|
if chain.CurrentSnapBlock().Number.BitLen() != 0 {
|
||||||
return errors.New("history import only supported when starting from genesis")
|
return errors.New("history import only supported when starting from genesis")
|
||||||
|
|
@ -358,10 +276,6 @@ func ImportHistory(chain *core.BlockChain, dir string, network string, from func
|
||||||
)
|
)
|
||||||
|
|
||||||
for i, file := range entries {
|
for i, file := range entries {
|
||||||
format, err := receiptFormat(file)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
path := filepath.Join(dir, file)
|
path := filepath.Join(dir, file)
|
||||||
|
|
||||||
// Validate against checksum file in directory.
|
// Validate against checksum file in directory.
|
||||||
|
|
@ -396,13 +310,14 @@ func ImportHistory(chain *core.BlockChain, dir string, network string, from func
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
blocks = make([]*types.Block, 0, importBatchSize)
|
blocks = make([]*types.Block, 0, importBatchSize)
|
||||||
receipts = make([]rlp.RawValue, 0, importBatchSize)
|
receiptsList = make([]types.Receipts, 0, importBatchSize)
|
||||||
flush = func() error {
|
flush = func() error {
|
||||||
if len(blocks) == 0 {
|
if len(blocks) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if _, err := chain.InsertReceiptChain(blocks, receipts, math.MaxUint64); err != nil {
|
enc := types.EncodeBlockReceiptLists(receiptsList)
|
||||||
|
if _, err := chain.InsertReceiptChain(blocks, enc, math.MaxUint64); err != nil {
|
||||||
return fmt.Errorf("error inserting blocks %d-%d: %w",
|
return fmt.Errorf("error inserting blocks %d-%d: %w",
|
||||||
blocks[0].NumberU64(), blocks[len(blocks)-1].NumberU64(), err)
|
blocks[0].NumberU64(), blocks[len(blocks)-1].NumberU64(), err)
|
||||||
}
|
}
|
||||||
|
|
@ -415,7 +330,7 @@ func ImportHistory(chain *core.BlockChain, dir string, network string, from func
|
||||||
reported = time.Now()
|
reported = time.Now()
|
||||||
}
|
}
|
||||||
blocks = blocks[:0]
|
blocks = blocks[:0]
|
||||||
receipts = receipts[:0]
|
receiptsList = receiptsList[:0]
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -428,18 +343,13 @@ func ImportHistory(chain *core.BlockChain, dir string, network string, from func
|
||||||
if block.Number().BitLen() == 0 {
|
if block.Number().BitLen() == 0 {
|
||||||
continue // skip genesis
|
continue // skip genesis
|
||||||
}
|
}
|
||||||
raw, err := e.GetRawReceiptsByNumber(block.NumberU64())
|
receipts, err := it.Receipts()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.Close()
|
e.Close()
|
||||||
return fmt.Errorf("error reading receipts %d: %w", it.Number(), err)
|
return fmt.Errorf("error reading receipts %d: %w", it.Number(), err)
|
||||||
}
|
}
|
||||||
enc, err := convertReceiptsToStorage(raw, format, len(block.Transactions()))
|
|
||||||
if err != nil {
|
|
||||||
e.Close()
|
|
||||||
return fmt.Errorf("error converting receipts %d: %w", it.Number(), err)
|
|
||||||
}
|
|
||||||
blocks = append(blocks, block)
|
blocks = append(blocks, block)
|
||||||
receipts = append(receipts, enc)
|
receiptsList = append(receiptsList, receipts)
|
||||||
if len(blocks) == importBatchSize {
|
if len(blocks) == importBatchSize {
|
||||||
if err := flush(); err != nil {
|
if err := flush(); err != nil {
|
||||||
e.Close()
|
e.Close()
|
||||||
|
|
|
||||||
|
|
@ -1,131 +0,0 @@
|
||||||
// Copyright 2026 The go-ethereum Authors
|
|
||||||
// This file is part of go-ethereum.
|
|
||||||
//
|
|
||||||
// go-ethereum is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// go-ethereum 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 General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
|
||||||
)
|
|
||||||
|
|
||||||
func makeTestReceipt(typ uint8) *types.Receipt {
|
|
||||||
r := &types.Receipt{
|
|
||||||
Type: typ,
|
|
||||||
Status: types.ReceiptStatusSuccessful,
|
|
||||||
CumulativeGasUsed: 42_000,
|
|
||||||
Logs: []*types.Log{
|
|
||||||
{
|
|
||||||
Address: common.HexToAddress("0x1"),
|
|
||||||
Topics: []common.Hash{common.HexToHash("0x2"), common.HexToHash("0x3")},
|
|
||||||
Data: []byte{0xde, 0xad, 0xbe, 0xef},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
r.Bloom = types.CreateBloom(r)
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestImportHistory_ConvertSlimReceiptsToStorage(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
receipts types.Receipts
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "typed-single",
|
|
||||||
receipts: types.Receipts{makeTestReceipt(types.DynamicFeeTxType)},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "legacy-single",
|
|
||||||
receipts: types.Receipts{makeTestReceipt(types.LegacyTxType)},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "mixed-multiple",
|
|
||||||
receipts: types.Receipts{
|
|
||||||
makeTestReceipt(types.LegacyTxType),
|
|
||||||
makeTestReceipt(types.DynamicFeeTxType),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "empty",
|
|
||||||
receipts: types.Receipts{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tc := range tests {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
rawSlimReceipts := make([]*types.SlimReceipt, len(tc.receipts))
|
|
||||||
for i, receipt := range tc.receipts {
|
|
||||||
rawSlimReceipts[i] = (*types.SlimReceipt)(receipt)
|
|
||||||
}
|
|
||||||
rawSlim, err := rlp.EncodeToBytes(rawSlimReceipts)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to encode slim receipts: %v", err)
|
|
||||||
}
|
|
||||||
got, err := convertReceiptsToStorage(rawSlim, eraReceiptFormatSlim, len(tc.receipts))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("conversion failed: %v", err)
|
|
||||||
}
|
|
||||||
want := types.EncodeBlockReceiptLists([]types.Receipts{tc.receipts})[0]
|
|
||||||
if !bytes.Equal(got, want) {
|
|
||||||
t.Fatalf("converted storage receipts mismatch\ngot: %x\nwant: %x", got, want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestImportHistory_ConvertSlimReceiptsToStorageErrors(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
raw []byte
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "invalid-rlp",
|
|
||||||
raw: []byte{0xff},
|
|
||||||
want: "invalid block receipts list",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "too-few-fields",
|
|
||||||
raw: []byte{0xc4, 0xc3, 0x01, 0x02, 0x03}, // [[1,2,3]]
|
|
||||||
want: "want 4",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "too-many-fields",
|
|
||||||
raw: []byte{0xc6, 0xc5, 0x01, 0x02, 0x03, 0x04, 0x05}, // [[1,2,3,4,5]]
|
|
||||||
want: "too many fields",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "tx-receipt-count-mismatch",
|
|
||||||
raw: []byte{0xc5, 0xc4, 0x01, 0x01, 0x02, 0xc0}, // [[1,1,2,[]]]
|
|
||||||
want: "tx/receipt count mismatch",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tc := range tests {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
_, err := convertReceiptsToStorage(tc.raw, eraReceiptFormatSlim, 2)
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("expected error")
|
|
||||||
}
|
|
||||||
if !strings.Contains(err.Error(), tc.want) {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
package eradb
|
package eradb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
|
|
@ -25,10 +26,10 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common/lru"
|
"github.com/ethereum/go-ethereum/common/lru"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
"github.com/ethereum/go-ethereum/internal/era"
|
"github.com/ethereum/go-ethereum/internal/era"
|
||||||
"github.com/ethereum/go-ethereum/internal/era/onedb"
|
"github.com/ethereum/go-ethereum/internal/era/onedb"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
const openFileLimit = 64
|
const openFileLimit = 64
|
||||||
|
|
@ -137,7 +138,56 @@ func (db *Store) GetRawReceipts(number uint64) ([]byte, error) {
|
||||||
// convertReceipts transforms an encoded block receipts list from the format
|
// convertReceipts transforms an encoded block receipts list from the format
|
||||||
// used by era1 into the 'storage' format used by the go-ethereum ancients database.
|
// used by era1 into the 'storage' format used by the go-ethereum ancients database.
|
||||||
func convertReceipts(input []byte) ([]byte, error) {
|
func convertReceipts(input []byte) ([]byte, error) {
|
||||||
return types.ConvertConsensusReceiptsToStorage(input)
|
var (
|
||||||
|
out bytes.Buffer
|
||||||
|
enc = rlp.NewEncoderBuffer(&out)
|
||||||
|
)
|
||||||
|
blockListIter, err := rlp.NewListIterator(input)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid block receipts list: %v", err)
|
||||||
|
}
|
||||||
|
outerList := enc.List()
|
||||||
|
for i := 0; blockListIter.Next(); i++ {
|
||||||
|
kind, content, _, err := rlp.Split(blockListIter.Value())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("receipt %d invalid: %v", i, err)
|
||||||
|
}
|
||||||
|
var receiptData []byte
|
||||||
|
switch kind {
|
||||||
|
case rlp.Byte:
|
||||||
|
return nil, fmt.Errorf("receipt %d is single byte", i)
|
||||||
|
case rlp.String:
|
||||||
|
// Typed receipt - skip type.
|
||||||
|
receiptData = content[1:]
|
||||||
|
case rlp.List:
|
||||||
|
// Legacy receipt
|
||||||
|
receiptData = blockListIter.Value()
|
||||||
|
}
|
||||||
|
// Convert data list.
|
||||||
|
// Input is [status, gas-used, bloom, logs]
|
||||||
|
// Output is [status, gas-used, logs], i.e. we need to skip the bloom.
|
||||||
|
dataIter, err := rlp.NewListIterator(receiptData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("receipt %d has invalid data: %v", i, err)
|
||||||
|
}
|
||||||
|
innerList := enc.List()
|
||||||
|
for field := 0; dataIter.Next(); field++ {
|
||||||
|
if field == 2 {
|
||||||
|
continue // skip bloom
|
||||||
|
}
|
||||||
|
enc.Write(dataIter.Value())
|
||||||
|
}
|
||||||
|
enc.ListEnd(innerList)
|
||||||
|
if dataIter.Err() != nil {
|
||||||
|
return nil, fmt.Errorf("receipt %d iterator error: %v", i, dataIter.Err())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enc.ListEnd(outerList)
|
||||||
|
if blockListIter.Err() != nil {
|
||||||
|
return nil, fmt.Errorf("block receipt list iterator error: %v", blockListIter.Err())
|
||||||
|
}
|
||||||
|
enc.Flush()
|
||||||
|
return out.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getEraByEpoch opens an era file or gets it from the cache.
|
// getEraByEpoch opens an era file or gets it from the cache.
|
||||||
|
|
|
||||||
|
|
@ -425,70 +425,6 @@ func EncodeBlockReceiptLists(receipts []Receipts) []rlp.RawValue {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConvertConsensusReceiptsToStorage converts canonical receipt encoding
|
|
||||||
// [post-state-or-status, gas-used, bloom, logs] into storage encoding
|
|
||||||
// [post-state-or-status, gas-used, logs].
|
|
||||||
func ConvertConsensusReceiptsToStorage(input []byte) (rlp.RawValue, error) {
|
|
||||||
var (
|
|
||||||
out bytes.Buffer
|
|
||||||
enc = rlp.NewEncoderBuffer(&out)
|
|
||||||
)
|
|
||||||
blockListIter, err := rlp.NewListIterator(input)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("invalid block receipts list: %w", err)
|
|
||||||
}
|
|
||||||
outerList := enc.List()
|
|
||||||
for i := 0; blockListIter.Next(); i++ {
|
|
||||||
kind, content, _, err := rlp.Split(blockListIter.Value())
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("receipt %d invalid: %w", i, err)
|
|
||||||
}
|
|
||||||
var receiptData []byte
|
|
||||||
switch kind {
|
|
||||||
case rlp.Byte:
|
|
||||||
return nil, fmt.Errorf("receipt %d is single byte", i)
|
|
||||||
case rlp.String:
|
|
||||||
if len(content) == 0 {
|
|
||||||
return nil, fmt.Errorf("typed receipt %d has empty payload", i)
|
|
||||||
}
|
|
||||||
receiptData = content[1:] // strip tx type
|
|
||||||
case rlp.List:
|
|
||||||
receiptData = blockListIter.Value()
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("receipt %d has invalid RLP kind", i)
|
|
||||||
}
|
|
||||||
dataIter, err := rlp.NewListIterator(receiptData)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("receipt %d has invalid data: %w", i, err)
|
|
||||||
}
|
|
||||||
innerList := enc.List()
|
|
||||||
fields := 0
|
|
||||||
for dataIter.Next() {
|
|
||||||
if fields == 2 {
|
|
||||||
fields++
|
|
||||||
continue // skip bloom
|
|
||||||
}
|
|
||||||
enc.Write(dataIter.Value())
|
|
||||||
fields++
|
|
||||||
}
|
|
||||||
enc.ListEnd(innerList)
|
|
||||||
if dataIter.Err() != nil {
|
|
||||||
return nil, fmt.Errorf("receipt %d iterator error: %w", i, dataIter.Err())
|
|
||||||
}
|
|
||||||
if fields != 4 {
|
|
||||||
return nil, fmt.Errorf("receipt %d has %d fields, want 4", i, fields)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
enc.ListEnd(outerList)
|
|
||||||
if blockListIter.Err() != nil {
|
|
||||||
return nil, fmt.Errorf("block receipt list iterator error: %w", blockListIter.Err())
|
|
||||||
}
|
|
||||||
if err := enc.Flush(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SlimReceipt is a wrapper around a Receipt with RLP serialization that omits
|
// SlimReceipt is a wrapper around a Receipt with RLP serialization that omits
|
||||||
// the Bloom field and includes the tx type. Used for era files.
|
// the Bloom field and includes the tx type. Used for era files.
|
||||||
type SlimReceipt Receipt
|
type SlimReceipt Receipt
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ import (
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
|
@ -513,101 +512,6 @@ func TestReceiptUnmarshalBinary(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeStorageConversionTestReceipt(typ uint8) *Receipt {
|
|
||||||
r := &Receipt{
|
|
||||||
Type: typ,
|
|
||||||
Status: ReceiptStatusSuccessful,
|
|
||||||
CumulativeGasUsed: 42_000,
|
|
||||||
Logs: []*Log{
|
|
||||||
{
|
|
||||||
Address: common.HexToAddress("0x1"),
|
|
||||||
Topics: []common.Hash{common.HexToHash("0x2"), common.HexToHash("0x3")},
|
|
||||||
Data: []byte{0xde, 0xad, 0xbe, 0xef},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
r.Bloom = CreateBloom(r)
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertConsensusReceiptsToStorage(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
receipts Receipts
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "typed-single",
|
|
||||||
receipts: Receipts{makeStorageConversionTestReceipt(DynamicFeeTxType)},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "legacy-single",
|
|
||||||
receipts: Receipts{makeStorageConversionTestReceipt(LegacyTxType)},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "mixed-multiple",
|
|
||||||
receipts: Receipts{
|
|
||||||
makeStorageConversionTestReceipt(LegacyTxType),
|
|
||||||
makeStorageConversionTestReceipt(DynamicFeeTxType),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "empty",
|
|
||||||
receipts: Receipts{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tc := range tests {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
raw, err := rlp.EncodeToBytes(tc.receipts)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to encode consensus receipts: %v", err)
|
|
||||||
}
|
|
||||||
got, err := ConvertConsensusReceiptsToStorage(raw)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("conversion failed: %v", err)
|
|
||||||
}
|
|
||||||
want := EncodeBlockReceiptLists([]Receipts{tc.receipts})[0]
|
|
||||||
if !bytes.Equal(got, want) {
|
|
||||||
t.Fatalf("converted storage receipts mismatch\ngot: %x\nwant: %x", got, want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvertConsensusReceiptsToStorageErrors(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
raw []byte
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "invalid-rlp",
|
|
||||||
raw: []byte{0xff},
|
|
||||||
want: "invalid block receipts list",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "single-byte-receipt",
|
|
||||||
raw: []byte{0xc1, 0x01}, // list with one single-byte item
|
|
||||||
want: "single byte",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "typed-empty-payload",
|
|
||||||
raw: []byte{0xc1, 0x80}, // list with one empty-string item
|
|
||||||
want: "empty payload",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tc := range tests {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
_, err := ConvertConsensusReceiptsToStorage(tc.raw)
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("expected error")
|
|
||||||
}
|
|
||||||
if !strings.Contains(err.Error(), tc.want) {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSlimReceiptEncodingDecoding(t *testing.T) {
|
func TestSlimReceiptEncodingDecoding(t *testing.T) {
|
||||||
tests := []*Receipt{
|
tests := []*Receipt{
|
||||||
legacyReceipt,
|
legacyReceipt,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue