Commit 72cd6482 authored by pcw109550's avatar pcw109550 Committed by protolambda

op-node: Span Batch type/encoding/decoding refactor

Refactor Span batch type

Remove unused methods

Explicit protocol constant

Update type of parentCheck and l1OriginCheck

Use require instead of assert in tests

Refactor RandomTx

Refactor Span batch tx tests

Adjust tnf to fix test

Update comments
Co-authored-by: default avatarpcw109550 <pcw109550@gmail.com>
parent 5b3f8b05
......@@ -759,7 +759,7 @@ func TestFramePublished(t *testing.T) {
}
func ChannelBuilder_PendingFrames_TotalFrames(t *testing.T, batchType uint) {
const tnf = 8
const tnf = 9
rng := rand.New(rand.NewSource(94572314))
require := require.New(t)
cfg := defaultTestChannelConfig
......@@ -828,7 +828,7 @@ func ChannelBuilder_InputBytes(t *testing.T, batchType uint) {
spanBatchBuilder.AppendSingularBatch(singularBatch, l1Info.SequenceNumber)
rawSpanBatch, err := spanBatchBuilder.GetRawSpanBatch()
require.NoError(err)
batch := derive.NewSpanBatchData(*rawSpanBatch)
batch := derive.NewBatchData(rawSpanBatch)
var buf bytes.Buffer
require.NoError(batch.EncodeRLP(&buf))
l = buf.Len()
......@@ -878,7 +878,7 @@ func ChannelBuilder_OutputBytes(t *testing.T, batchType uint) {
func blockBatchRlpSize(t *testing.T, b *types.Block) int {
t.Helper()
singularBatch, _, err := derive.BlockToSingularBatch(b)
batch := derive.NewSingularBatchData(*singularBatch)
batch := derive.NewBatchData(singularBatch)
require.NoError(t, err)
var buf bytes.Buffer
require.NoError(t, batch.EncodeRLP(&buf), "RLP-encoding batch")
......
......@@ -255,13 +255,13 @@ func blockToBatch(block *types.Block) (*derive.BatchData, error) {
return nil, fmt.Errorf("could not parse the L1 Info deposit: %w", err)
}
return &derive.BatchData{
SingularBatch: derive.SingularBatch{
singularBatch := &derive.SingularBatch{
ParentHash: block.ParentHash(),
EpochNum: rollup.Epoch(l1Info.Number),
EpochHash: l1Info.BlockHash,
Timestamp: block.Time(),
Transactions: opaqueTxs,
},
}, nil
}
return derive.NewBatchData(singularBatch), nil
}
......@@ -24,7 +24,7 @@ type ChannelWithMetadata struct {
InvalidFrames bool `json:"invalid_frames"`
InvalidBatches bool `json:"invalid_batches"`
Frames []FrameWithMetadata `json:"frames"`
Batches []derive.SingularBatch `json:"batches"`
Batches []derive.BatchData `json:"batches"`
}
type FrameWithMetadata struct {
......@@ -104,7 +104,7 @@ func processFrames(cfg *rollup.Config, id derive.ChannelID, frames []FrameWithMe
}
}
var batches []derive.SingularBatch
var batches []derive.BatchData
invalidBatches := false
if ch.IsReady() {
br, err := derive.BatchReader(ch.Reader())
......@@ -114,11 +114,7 @@ func processFrames(cfg *rollup.Config, id derive.ChannelID, frames []FrameWithMe
fmt.Printf("Error reading batch for channel %v. Err: %v\n", id.String(), err)
invalidBatches = true
} else {
if batch.BatchType != derive.SingularBatchType {
batches = append(batches, batch.SingularBatch)
} else {
fmt.Printf("batch-type %d is not supported", batch.BatchType)
}
batches = append(batches, *batch)
}
}
} else {
......
......@@ -25,9 +25,9 @@ var encodeBufferPool = sync.Pool{
const (
// SingularBatchType is the first version of Batch format, representing a single L2 block.
SingularBatchType = iota
SingularBatchType = 0
// SpanBatchType is the Batch version used after SpanBatch hard fork, representing a span of L2 blocks.
SpanBatchType
SpanBatchType = 1
)
// Batch contains information to build one or multiple L2 blocks.
......@@ -39,12 +39,22 @@ type Batch interface {
LogContext(log.Logger) log.Logger
}
// BatchData is a composition type that contains raw data of each batch version.
// It has encoding & decoding methods to implement typed encoding.
// BatchData is used to represent the typed encoding & decoding.
// and wraps around a single interface InnerBatchData.
// Further fields such as cache can be added in the future, without embedding each type of InnerBatchData.
// Similar design with op-geth's types.Transaction struct.
type BatchData struct {
BatchType int
SingularBatch
RawSpanBatch
inner InnerBatchData
}
// InnerBatchData is the underlying data of a BatchData.
// This is implemented by SingularBatch and RawSpanBatch.
type InnerBatchData interface {
GetBatchType() int
encode(w io.Writer) error
decode(r *bytes.Reader) error
encodeBytes() ([]byte, error)
decodeBytes(data []byte) error
}
// EncodeRLP implements rlp.Encoder
......@@ -58,6 +68,10 @@ func (b *BatchData) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, buf.Bytes())
}
func (bd *BatchData) GetBatchType() uint8 {
return uint8(bd.inner.GetBatchType())
}
// MarshalBinary returns the canonical encoding of the batch.
func (b *BatchData) MarshalBinary() ([]byte, error) {
var buf bytes.Buffer
......@@ -67,16 +81,10 @@ func (b *BatchData) MarshalBinary() ([]byte, error) {
// encodeTyped encodes batch type and payload for each batch type.
func (b *BatchData) encodeTyped(buf *bytes.Buffer) error {
switch b.BatchType {
case SingularBatchType:
buf.WriteByte(SingularBatchType)
return rlp.Encode(buf, &b.SingularBatch)
case SpanBatchType:
buf.WriteByte(SpanBatchType)
return b.RawSpanBatch.encode(buf)
default:
return fmt.Errorf("unrecognized batch type: %d", b.BatchType)
if err := buf.WriteByte(b.GetBatchType()); err != nil {
return err
}
return b.inner.encode(buf)
}
// DecodeRLP implements rlp.Decoder
......@@ -99,35 +107,28 @@ func (b *BatchData) UnmarshalBinary(data []byte) error {
return b.decodeTyped(data)
}
// decodeTyped decodes batch type and payload for each batch type.
// decodeTyped decodes a typed batchData
func (b *BatchData) decodeTyped(data []byte) error {
if len(data) == 0 {
return fmt.Errorf("batch too short")
return errors.New("batch too short")
}
var inner InnerBatchData
switch data[0] {
case SingularBatchType:
b.BatchType = SingularBatchType
return rlp.DecodeBytes(data[1:], &b.SingularBatch)
inner = new(SingularBatch)
case SpanBatchType:
b.BatchType = int(data[0])
return b.RawSpanBatch.decodeBytes(data[1:])
inner = new(RawSpanBatch)
default:
return fmt.Errorf("unrecognized batch type: %d", data[0])
}
}
// NewSingularBatchData creates new BatchData with SingularBatch
func NewSingularBatchData(singularBatch SingularBatch) *BatchData {
return &BatchData{
BatchType: SingularBatchType,
SingularBatch: singularBatch,
if err := inner.decodeBytes(data[1:]); err != nil {
return err
}
b.inner = inner
return nil
}
// NewSpanBatchData creates new BatchData with SpanBatch
func NewSpanBatchData(spanBatch RawSpanBatch) *BatchData {
return &BatchData{
BatchType: SpanBatchType,
RawSpanBatch: spanBatch,
}
// NewBatchData creates a new BatchData
func NewBatchData(inner InnerBatchData) *BatchData {
return &BatchData{inner: inner}
}
......@@ -6,15 +6,16 @@ import (
"math/rand"
"testing"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum-optimism/optimism/op-service/testutils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum-optimism/optimism/op-service/testutils"
)
func RandomRawSpanBatch(rng *rand.Rand, chainId *big.Int) *RawSpanBatch {
......@@ -52,8 +53,8 @@ func RandomRawSpanBatch(rng *rand.Rand, chainId *big.Int) *RawSpanBatch {
spanBatchPrefix: spanBatchPrefix{
relTimestamp: uint64(rng.Uint32()),
l1OriginNum: rng.Uint64(),
parentCheck: testutils.RandomData(rng, 20),
l1OriginCheck: testutils.RandomData(rng, 20),
parentCheck: [20]byte(testutils.RandomData(rng, 20)),
l1OriginCheck: [20]byte(testutils.RandomData(rng, 20)),
},
spanBatchPayload: spanBatchPayload{
blockCount: blockCount,
......@@ -141,40 +142,42 @@ func TestBatchRoundTrip(t *testing.T) {
chainID := new(big.Int).SetUint64(rng.Uint64())
batches := []*BatchData{
{
SingularBatch: SingularBatch{
NewBatchData(
&SingularBatch{
ParentHash: common.Hash{},
EpochNum: 0,
Timestamp: 0,
Transactions: []hexutil.Bytes{},
},
},
{
SingularBatch: SingularBatch{
),
NewBatchData(
&SingularBatch{
ParentHash: common.Hash{31: 0x42},
EpochNum: 1,
Timestamp: 1647026951,
Transactions: []hexutil.Bytes{[]byte{0, 0, 0}, []byte{0x76, 0xfd, 0x7c}},
},
},
NewSingularBatchData(*RandomSingularBatch(rng, 5, chainID)),
NewSingularBatchData(*RandomSingularBatch(rng, 7, chainID)),
NewSpanBatchData(*RandomRawSpanBatch(rng, chainID)),
NewSpanBatchData(*RandomRawSpanBatch(rng, chainID)),
NewSpanBatchData(*RandomRawSpanBatch(rng, chainID)),
),
NewBatchData(RandomSingularBatch(rng, 5, chainID)),
NewBatchData(RandomSingularBatch(rng, 7, chainID)),
NewBatchData(RandomRawSpanBatch(rng, chainID)),
NewBatchData(RandomRawSpanBatch(rng, chainID)),
NewBatchData(RandomRawSpanBatch(rng, chainID)),
}
for i, batch := range batches {
enc, err := batch.MarshalBinary()
assert.NoError(t, err)
require.NoError(t, err)
var dec BatchData
err = dec.UnmarshalBinary(enc)
assert.NoError(t, err)
if dec.BatchType == SpanBatchType {
_, err := dec.RawSpanBatch.derive(blockTime, genesisTimestamp, chainID)
assert.NoError(t, err)
require.NoError(t, err)
if dec.GetBatchType() == SpanBatchType {
rawSpanBatch, ok := dec.inner.(*RawSpanBatch)
require.True(t, ok)
_, err := rawSpanBatch.derive(blockTime, genesisTimestamp, chainID)
require.NoError(t, err)
}
assert.Equal(t, batch, &dec, "Batch not equal test case %v", i)
require.Equal(t, batch, &dec, "Batch not equal test case %v", i)
}
}
......@@ -185,43 +188,45 @@ func TestBatchRoundTripRLP(t *testing.T) {
chainID := new(big.Int).SetUint64(rng.Uint64())
batches := []*BatchData{
{
SingularBatch: SingularBatch{
NewBatchData(
&SingularBatch{
ParentHash: common.Hash{},
EpochNum: 0,
Timestamp: 0,
Transactions: []hexutil.Bytes{},
},
},
{
SingularBatch: SingularBatch{
),
NewBatchData(
&SingularBatch{
ParentHash: common.Hash{31: 0x42},
EpochNum: 1,
Timestamp: 1647026951,
Transactions: []hexutil.Bytes{[]byte{0, 0, 0}, []byte{0x76, 0xfd, 0x7c}},
},
},
NewSingularBatchData(*RandomSingularBatch(rng, 5, chainID)),
NewSingularBatchData(*RandomSingularBatch(rng, 7, chainID)),
NewSpanBatchData(*RandomRawSpanBatch(rng, chainID)),
NewSpanBatchData(*RandomRawSpanBatch(rng, chainID)),
NewSpanBatchData(*RandomRawSpanBatch(rng, chainID)),
),
NewBatchData(RandomSingularBatch(rng, 5, chainID)),
NewBatchData(RandomSingularBatch(rng, 7, chainID)),
NewBatchData(RandomRawSpanBatch(rng, chainID)),
NewBatchData(RandomRawSpanBatch(rng, chainID)),
NewBatchData(RandomRawSpanBatch(rng, chainID)),
}
for i, batch := range batches {
var buf bytes.Buffer
err := batch.EncodeRLP(&buf)
assert.NoError(t, err)
require.NoError(t, err)
result := buf.Bytes()
var dec BatchData
r := bytes.NewReader(result)
s := rlp.NewStream(r, 0)
err = dec.DecodeRLP(s)
assert.NoError(t, err)
if dec.BatchType == SpanBatchType {
_, err := dec.RawSpanBatch.derive(blockTime, genesisTimestamp, chainID)
assert.NoError(t, err)
}
assert.Equal(t, batch, &dec, "Batch not equal test case %v", i)
require.NoError(t, err)
if dec.GetBatchType() == SpanBatchType {
rawSpanBatch, ok := dec.inner.(*RawSpanBatch)
require.True(t, ok)
_, err := rawSpanBatch.derive(blockTime, genesisTimestamp, chainID)
require.NoError(t, err)
}
require.Equal(t, batch, &dec, "Batch not equal test case %v", i)
}
}
......@@ -17,13 +17,13 @@ func FuzzBatchRoundTrip(f *testing.F) {
typeProvider := fuzz.NewFromGoFuzz(fuzzedData).NilChance(0).MaxDepth(10000).NumElements(0, 0x100).AllowUnexportedFields(true)
fuzzerutils.AddFuzzerFunctions(typeProvider)
var singularBatch SingularBatch
typeProvider.Fuzz(&singularBatch)
// Create our batch data from fuzzed data
var batchData BatchData
typeProvider.Fuzz(&batchData)
// force batchdata to only contain singular batch
batchData.BatchType = SingularBatchType
batchData.RawSpanBatch = RawSpanBatch{}
batchData.inner = &singularBatch
// Encode our batch data
enc, err := batchData.MarshalBinary()
......
......@@ -3,6 +3,7 @@ package derive
import (
"bytes"
"context"
"errors"
"fmt"
"io"
......@@ -89,22 +90,30 @@ func (cr *ChannelInReader) NextBatch(ctx context.Context) (Batch, error) {
cr.NextChannel()
return nil, NotEnoughData
}
switch batchData.BatchType {
switch batchData.GetBatchType() {
case SingularBatchType:
return &batchData.SingularBatch, nil
singularBatch, ok := batchData.inner.(*SingularBatch)
if !ok {
return nil, NewCriticalError(errors.New("failed type assertion to SingularBatch"))
}
return singularBatch, nil
case SpanBatchType:
if origin := cr.Origin(); !cr.cfg.IsSpanBatch(origin.Time) {
return nil, NewTemporaryError(fmt.Errorf("cannot accept span batch in L1 block %s at time %d", origin, origin.Time))
}
rawSpanBatch, ok := batchData.inner.(*RawSpanBatch)
if !ok {
return nil, NewCriticalError(errors.New("failed type assertion to SpanBatch"))
}
// If the batch type is Span batch, derive block inputs from RawSpanBatch.
spanBatch, err := batchData.RawSpanBatch.derive(cr.cfg.BlockTime, cr.cfg.Genesis.L2Time, cr.cfg.L2ChainID)
spanBatch, err := rawSpanBatch.derive(cr.cfg.BlockTime, cr.cfg.Genesis.L2Time, cr.cfg.L2ChainID)
if err != nil {
return nil, err
}
return spanBatch, nil
default:
// error is bubbled up to user, but pipeline can skip the batch and continue after.
return nil, NewTemporaryError(fmt.Errorf("unrecognized batch type: %w", err))
return nil, NewTemporaryError(fmt.Errorf("unrecognized batch type: %d", batchData.GetBatchType()))
}
}
......
......@@ -145,7 +145,7 @@ func (co *SingularChannelOut) AddSingularBatch(batch *SingularBatch, _ uint64) (
// We encode to a temporary buffer to determine the encoded length to
// ensure that the total size of all RLP elements is less than or equal to MAX_RLP_BYTES_PER_CHANNEL
var buf bytes.Buffer
if err := rlp.Encode(&buf, NewSingularBatchData(*batch)); err != nil {
if err := rlp.Encode(&buf, NewBatchData(batch)); err != nil {
return 0, err
}
if co.rlpLength+buf.Len() > MaxRLPBytesPerChannel {
......
package derive
import (
"bytes"
"io"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp"
)
// Batch format
......@@ -51,3 +55,23 @@ func (b *SingularBatch) LogContext(log log.Logger) log.Logger {
func (b *SingularBatch) Epoch() eth.BlockID {
return eth.BlockID{Hash: b.EpochHash, Number: uint64(b.EpochNum)}
}
// encode writes the byte encoding of SingularBatch to Writer stream
func (b *SingularBatch) encode(w io.Writer) error {
return rlp.Encode(w, b)
}
// decode reads the byte encoding of SingularBatch from Reader stream
func (b *SingularBatch) decode(r *bytes.Reader) error {
return rlp.Decode(r, b)
}
// encodeBytes returns the byte encoding of SingularBatch
func (b *SingularBatch) encodeBytes() ([]byte, error) {
return rlp.EncodeToBytes(b)
}
// decodeBytes parses data into b from data
func (b *SingularBatch) decodeBytes(data []byte) error {
return rlp.DecodeBytes(data, b)
}
......@@ -5,7 +5,7 @@ import (
"math/rand"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestSingularBatchForBatchInterface(t *testing.T) {
......@@ -15,7 +15,7 @@ func TestSingularBatchForBatchInterface(t *testing.T) {
singularBatch := RandomSingularBatch(rng, txCount, chainID)
assert.Equal(t, SingularBatchType, singularBatch.GetBatchType())
assert.Equal(t, singularBatch.Timestamp, singularBatch.GetTimestamp())
assert.Equal(t, singularBatch.EpochNum, singularBatch.GetEpochNum())
require.Equal(t, SingularBatchType, singularBatch.GetBatchType())
require.Equal(t, singularBatch.Timestamp, singularBatch.GetTimestamp())
require.Equal(t, singularBatch.EpochNum, singularBatch.GetEpochNum())
}
......@@ -34,8 +34,8 @@ var ErrEmptySpanBatch = errors.New("span-batch must not be empty")
type spanBatchPrefix struct {
relTimestamp uint64 // Relative timestamp of the first block
l1OriginNum uint64 // L1 origin number
parentCheck []byte // First 20 bytes of the first block's parent hash
l1OriginCheck []byte // First 20 bytes of the last block's L1 origin hash
parentCheck [20]byte // First 20 bytes of the first block's parent hash
l1OriginCheck [20]byte // First 20 bytes of the last block's L1 origin hash
}
type spanBatchPayload struct {
......@@ -51,6 +51,11 @@ type RawSpanBatch struct {
spanBatchPayload
}
// GetBatchType returns its batch type (batch_version)
func (b *RawSpanBatch) GetBatchType() int {
return SpanBatchType
}
// decodeOriginBits parses data into bp.originBits
// originBits is bitlist right-padded to a multiple of 8 bits
func (bp *spanBatchPayload) decodeOriginBits(r *bytes.Reader) error {
......@@ -105,8 +110,7 @@ func (bp *spanBatchPrefix) decodeL1OriginNum(r *bytes.Reader) error {
// decodeParentCheck parses data into bp.parentCheck
func (bp *spanBatchPrefix) decodeParentCheck(r *bytes.Reader) error {
bp.parentCheck = make([]byte, 20)
_, err := io.ReadFull(r, bp.parentCheck)
_, err := io.ReadFull(r, bp.parentCheck[:])
if err != nil {
return fmt.Errorf("failed to read parent check: %w", err)
}
......@@ -115,8 +119,7 @@ func (bp *spanBatchPrefix) decodeParentCheck(r *bytes.Reader) error {
// decodeL1OriginCheck parses data into bp.decodeL1OriginCheck
func (bp *spanBatchPrefix) decodeL1OriginCheck(r *bytes.Reader) error {
bp.l1OriginCheck = make([]byte, 20)
_, err := io.ReadFull(r, bp.l1OriginCheck)
_, err := io.ReadFull(r, bp.l1OriginCheck[:])
if err != nil {
return fmt.Errorf("failed to read l1 origin check: %w", err)
}
......@@ -263,7 +266,7 @@ func (bp *spanBatchPrefix) encodeL1OriginNum(w io.Writer) error {
// encodeParentCheck encodes bp.parentCheck
func (bp *spanBatchPrefix) encodeParentCheck(w io.Writer) error {
if _, err := w.Write(bp.parentCheck); err != nil {
if _, err := w.Write(bp.parentCheck[:]); err != nil {
return fmt.Errorf("cannot write parent check: %w", err)
}
return nil
......@@ -271,7 +274,7 @@ func (bp *spanBatchPrefix) encodeParentCheck(w io.Writer) error {
// encodeL1OriginCheck encodes bp.l1OriginCheck
func (bp *spanBatchPrefix) encodeL1OriginCheck(w io.Writer) error {
if _, err := w.Write(bp.l1OriginCheck); err != nil {
if _, err := w.Write(bp.l1OriginCheck[:]); err != nil {
return fmt.Errorf("cannot write l1 origin check: %w", err)
}
return nil
......@@ -451,8 +454,8 @@ func singularBatchToElement(singularBatch *SingularBatch) *spanBatchElement {
// SpanBatch is an implementation of Batch interface,
// containing the input to build a span of L2 blocks in derived form (spanBatchElement)
type SpanBatch struct {
parentCheck []byte // First 20 bytes of the first block's parent hash
l1OriginCheck []byte // First 20 bytes of the last block's L1 origin hash
parentCheck [20]byte // First 20 bytes of the first block's parent hash
l1OriginCheck [20]byte // First 20 bytes of the last block's L1 origin hash
batches []*spanBatchElement // List of block input in derived form
}
......@@ -473,8 +476,8 @@ func (b *SpanBatch) LogContext(log log.Logger) log.Logger {
}
return log.New(
"batch_timestamp", b.batches[0].Timestamp,
"parent_check", hexutil.Encode(b.parentCheck),
"origin_check", hexutil.Encode(b.l1OriginCheck),
"parent_check", hexutil.Encode(b.parentCheck[:]),
"origin_check", hexutil.Encode(b.l1OriginCheck[:]),
"start_epoch_number", b.GetStartEpochNum(),
"end_epoch_number", b.GetBlockEpochNum(len(b.batches)-1),
"block_count", len(b.batches),
......@@ -488,12 +491,12 @@ func (b *SpanBatch) GetStartEpochNum() rollup.Epoch {
// CheckOriginHash checks if the l1OriginCheck matches the first 20 bytes of given hash, probably L1 block hash from the current canonical L1 chain.
func (b *SpanBatch) CheckOriginHash(hash common.Hash) bool {
return bytes.Equal(b.l1OriginCheck, hash.Bytes()[:20])
return bytes.Equal(b.l1OriginCheck[:], hash.Bytes()[:20])
}
// CheckParentHash checks if the parentCheck matches the first 20 bytes of given hash, probably the current L2 safe head.
func (b *SpanBatch) CheckParentHash(hash common.Hash) bool {
return bytes.Equal(b.parentCheck, hash.Bytes()[:20])
return bytes.Equal(b.parentCheck[:], hash.Bytes()[:20])
}
// GetBlockEpochNum returns the epoch number(L1 origin block number) of the block at the given index in the span.
......@@ -520,10 +523,10 @@ func (b *SpanBatch) GetBlockCount() int {
// updates l1OriginCheck or parentCheck if needed.
func (b *SpanBatch) AppendSingularBatch(singularBatch *SingularBatch) {
if len(b.batches) == 0 {
b.parentCheck = singularBatch.ParentHash.Bytes()[:20]
copy(b.parentCheck[:], singularBatch.ParentHash.Bytes()[:20])
}
b.batches = append(b.batches, singularBatchToElement(singularBatch))
b.l1OriginCheck = singularBatch.EpochHash.Bytes()[:20]
copy(b.l1OriginCheck[:], singularBatch.EpochHash.Bytes()[:20])
}
// ToRawSpanBatch merges SingularBatch List and initialize single RawSpanBatch
......@@ -541,10 +544,8 @@ func (b *SpanBatch) ToRawSpanBatch(originChangedBit uint, genesisTimestamp uint6
span_end := b.batches[len(b.batches)-1]
raw.relTimestamp = span_start.Timestamp - genesisTimestamp
raw.l1OriginNum = uint64(span_end.EpochNum)
raw.parentCheck = make([]byte, 20)
copy(raw.parentCheck, b.parentCheck)
raw.l1OriginCheck = make([]byte, 20)
copy(raw.l1OriginCheck, b.l1OriginCheck)
raw.parentCheck = b.parentCheck
raw.l1OriginCheck = b.l1OriginCheck
// spanBatchPayload
raw.blockCount = uint64(len(b.batches))
raw.originBits = new(big.Int)
......@@ -608,17 +609,16 @@ func (b *SpanBatch) GetSingularBatches(l1Origins []eth.L1BlockRef, l2SafeHead et
// NewSpanBatch converts given singularBatches into spanBatchElements, and creates a new SpanBatch.
func NewSpanBatch(singularBatches []*SingularBatch) *SpanBatch {
spanBatch := &SpanBatch{}
if len(singularBatches) == 0 {
return &SpanBatch{}
}
spanBatch := SpanBatch{
parentCheck: singularBatches[0].ParentHash.Bytes()[:20],
l1OriginCheck: singularBatches[len(singularBatches)-1].EpochHash.Bytes()[:20],
return spanBatch
}
copy(spanBatch.parentCheck[:], singularBatches[0].ParentHash.Bytes()[:20])
copy(spanBatch.l1OriginCheck[:], singularBatches[len(singularBatches)-1].EpochHash.Bytes()[:20])
for _, singularBatch := range singularBatches {
spanBatch.batches = append(spanBatch.batches, singularBatchToElement(singularBatch))
}
return &spanBatch
return spanBatch
}
// SpanBatchBuilder is a utility type to build a SpanBatch by adding a SingularBatch one by one.
......
This diff is collapsed.
......@@ -4,7 +4,6 @@ import (
"bytes"
"errors"
"fmt"
"io"
"math/big"
"github.com/ethereum/go-ethereum/common"
......@@ -70,21 +69,6 @@ func (tx *spanBatchTx) MarshalBinary() ([]byte, error) {
return buf.Bytes(), err
}
// EncodeRLP implements rlp.Encoder
func (tx *spanBatchTx) EncodeRLP(w io.Writer) error {
if tx.Type() == types.LegacyTxType {
return rlp.Encode(w, tx.inner)
}
// It's an EIP-2718 typed TX envelope.
buf := encodeBufferPool.Get().(*bytes.Buffer)
defer encodeBufferPool.Put(buf)
buf.Reset()
if err := tx.encodeTyped(buf); err != nil {
return err
}
return rlp.Encode(w, buf.Bytes())
}
// setDecoded sets the inner transaction after decoding.
func (tx *spanBatchTx) setDecoded(inner spanBatchTxData, size uint64) {
tx.inner = inner
......@@ -115,36 +99,6 @@ func (tx *spanBatchTx) decodeTyped(b []byte) (spanBatchTxData, error) {
}
}
// DecodeRLP implements rlp.Decoder
func (tx *spanBatchTx) DecodeRLP(s *rlp.Stream) error {
kind, size, err := s.Kind()
switch {
case err != nil:
return err
case kind == rlp.List:
// It's a legacy transaction.
var inner spanBatchLegacyTxData
err = s.Decode(&inner)
if err != nil {
return fmt.Errorf("failed to decode spanBatchLegacyTxData: %w", err)
}
tx.setDecoded(&inner, rlp.ListSize(size))
return nil
default:
// It's an EIP-2718 typed TX envelope.
var b []byte
if b, err = s.Bytes(); err != nil {
return err
}
inner, err := tx.decodeTyped(b)
if err != nil {
return err
}
tx.setDecoded(inner, uint64(len(b)))
return nil
}
}
// UnmarshalBinary decodes the canonical encoding of transactions.
// It supports legacy RLP transactions and EIP2718 typed transactions.
func (tx *spanBatchTx) UnmarshalBinary(b []byte) error {
......
package derive
import (
"bytes"
"math/big"
"math/rand"
"testing"
"github.com/ethereum-optimism/optimism/op-service/testutils"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type spanBatchTxTest struct {
name string
trials int
mkTx func(rng *rand.Rand, signer types.Signer) *types.Transaction
}
func TestSpanBatchTxConvert(t *testing.T) {
rng := rand.New(rand.NewSource(0x1331))
cases := []spanBatchTxTest{
{"legacy tx", 32, testutils.RandomLegacyTx},
{"access list tx", 32, testutils.RandomAccessListTx},
{"dynamic fee tx", 32, testutils.RandomDynamicFeeTx},
}
for i, testCase := range cases {
t.Run(testCase.name, func(t *testing.T) {
rng := rand.New(rand.NewSource(int64(0x1331 + i)))
chainID := big.NewInt(rng.Int63n(1000))
signer := types.NewLondonSigner(chainID)
m := make(map[byte]int)
for i := 0; i < 32; i++ {
tx := testutils.RandomTx(rng, new(big.Int).SetUint64(rng.Uint64()), signer)
m[tx.Type()] += 1
for txIdx := 0; txIdx < testCase.trials; txIdx++ {
tx := testCase.mkTx(rng, signer)
v, r, s := tx.RawSignatureValues()
sbtx, err := newSpanBatchTx(*tx)
assert.NoError(t, err)
require.NoError(t, err)
tx2, err := sbtx.convertToFullTx(tx.Nonce(), tx.Gas(), tx.To(), chainID, v, r, s)
assert.NoError(t, err)
require.NoError(t, err)
// compare after marshal because we only need inner field of transaction
txEncoded, err := tx.MarshalBinary()
assert.NoError(t, err)
require.NoError(t, err)
tx2Encoded, err := tx2.MarshalBinary()
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, txEncoded, tx2Encoded)
}
// make sure every tx type is tested
assert.Positive(t, m[types.LegacyTxType])
assert.Positive(t, m[types.AccessListTxType])
assert.Positive(t, m[types.DynamicFeeTxType])
})
}
}
func TestSpanBatchTxRoundTrip(t *testing.T) {
rng := rand.New(rand.NewSource(0x1332))
cases := []spanBatchTxTest{
{"legacy tx", 32, testutils.RandomLegacyTx},
{"access list tx", 32, testutils.RandomAccessListTx},
{"dynamic fee tx", 32, testutils.RandomDynamicFeeTx},
}
for i, testCase := range cases {
t.Run(testCase.name, func(t *testing.T) {
rng := rand.New(rand.NewSource(int64(0x1332 + i)))
chainID := big.NewInt(rng.Int63n(1000))
signer := types.NewLondonSigner(chainID)
m := make(map[byte]int)
for i := 0; i < 32; i++ {
tx := testutils.RandomTx(rng, new(big.Int).SetUint64(rng.Uint64()), signer)
m[tx.Type()] += 1
for txIdx := 0; txIdx < testCase.trials; txIdx++ {
tx := testCase.mkTx(rng, signer)
sbtx, err := newSpanBatchTx(*tx)
assert.NoError(t, err)
require.NoError(t, err)
sbtxEncoded, err := sbtx.MarshalBinary()
assert.NoError(t, err)
require.NoError(t, err)
var sbtx2 spanBatchTx
err = sbtx2.UnmarshalBinary(sbtxEncoded)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, sbtx, &sbtx2)
}
// make sure every tx type is tested
assert.Positive(t, m[types.LegacyTxType])
assert.Positive(t, m[types.AccessListTxType])
assert.Positive(t, m[types.DynamicFeeTxType])
}
func TestSpanBatchTxRoundTripRLP(t *testing.T) {
rng := rand.New(rand.NewSource(0x1333))
chainID := big.NewInt(rng.Int63n(1000))
signer := types.NewLondonSigner(chainID)
m := make(map[byte]int)
for i := 0; i < 32; i++ {
tx := testutils.RandomTx(rng, new(big.Int).SetUint64(rng.Uint64()), signer)
m[tx.Type()] += 1
sbtx, err := newSpanBatchTx(*tx)
assert.NoError(t, err)
var buf bytes.Buffer
err = sbtx.EncodeRLP(&buf)
assert.NoError(t, err)
result := buf.Bytes()
var sbtx2 spanBatchTx
r := bytes.NewReader(result)
rlpReader := rlp.NewStream(r, 0)
err = sbtx2.DecodeRLP(rlpReader)
assert.NoError(t, err)
assert.Equal(t, sbtx, &sbtx2)
})
}
// make sure every tx type is tested
assert.Positive(t, m[types.LegacyTxType])
assert.Positive(t, m[types.AccessListTxType])
assert.Positive(t, m[types.DynamicFeeTxType])
}
type spanBatchDummyTxData struct{}
......@@ -107,44 +91,44 @@ func TestSpanBatchTxInvalidTxType(t *testing.T) {
// span batch never contain deposit tx
depositTx := types.NewTx(&types.DepositTx{})
_, err := newSpanBatchTx(*depositTx)
assert.ErrorContains(t, err, "invalid tx type")
require.ErrorContains(t, err, "invalid tx type")
var sbtx spanBatchTx
sbtx.inner = &spanBatchDummyTxData{}
_, err = sbtx.convertToFullTx(0, 0, nil, nil, nil, nil, nil)
assert.ErrorContains(t, err, "invalid tx type")
require.ErrorContains(t, err, "invalid tx type")
}
func TestSpanBatchTxDecodeInvalid(t *testing.T) {
var sbtx spanBatchTx
_, err := sbtx.decodeTyped([]byte{})
assert.EqualError(t, err, "typed transaction too short")
require.EqualError(t, err, "typed transaction too short")
tx := types.NewTx(&types.LegacyTx{})
txEncoded, err := tx.MarshalBinary()
assert.NoError(t, err)
require.NoError(t, err)
// legacy tx is not typed tx
_, err = sbtx.decodeTyped(txEncoded)
assert.EqualError(t, err, types.ErrTxTypeNotSupported.Error())
require.EqualError(t, err, types.ErrTxTypeNotSupported.Error())
tx2 := types.NewTx(&types.AccessListTx{})
tx2Encoded, err := tx2.MarshalBinary()
assert.NoError(t, err)
require.NoError(t, err)
tx2Encoded[0] = types.DynamicFeeTxType
_, err = sbtx.decodeTyped(tx2Encoded)
assert.ErrorContains(t, err, "failed to decode spanBatchDynamicFeeTxData")
require.ErrorContains(t, err, "failed to decode spanBatchDynamicFeeTxData")
tx3 := types.NewTx(&types.DynamicFeeTx{})
tx3Encoded, err := tx3.MarshalBinary()
assert.NoError(t, err)
require.NoError(t, err)
tx3Encoded[0] = types.AccessListTxType
_, err = sbtx.decodeTyped(tx3Encoded)
assert.ErrorContains(t, err, "failed to decode spanBatchAccessListTxData")
require.ErrorContains(t, err, "failed to decode spanBatchAccessListTxData")
invalidLegacyTxDecoded := []byte{0xFF, 0xFF}
err = sbtx.UnmarshalBinary(invalidLegacyTxDecoded)
assert.ErrorContains(t, err, "failed to decode spanBatchLegacyTxData")
require.ErrorContains(t, err, "failed to decode spanBatchLegacyTxData")
}
......@@ -6,11 +6,12 @@ import (
"math/rand"
"testing"
"github.com/ethereum-optimism/optimism/op-service/testutils"
"github.com/ethereum/go-ethereum/core/types"
"github.com/holiman/uint256"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum-optimism/optimism/op-service/testutils"
)
func TestSpanBatchTxsContractCreationBits(t *testing.T) {
......@@ -27,23 +28,23 @@ func TestSpanBatchTxsContractCreationBits(t *testing.T) {
var buf bytes.Buffer
err := sbt.encodeContractCreationBits(&buf)
assert.NoError(t, err)
require.NoError(t, err)
// contractCreationBit field is fixed length: single bit
contractCreationBitBufferLen := totalBlockTxCount / 8
if totalBlockTxCount%8 != 0 {
contractCreationBitBufferLen++
}
assert.Equal(t, buf.Len(), int(contractCreationBitBufferLen))
require.Equal(t, buf.Len(), int(contractCreationBitBufferLen))
result := buf.Bytes()
sbt.contractCreationBits = nil
r := bytes.NewReader(result)
err = sbt.decodeContractCreationBits(r)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, contractCreationBits, sbt.contractCreationBits)
require.Equal(t, contractCreationBits, sbt.contractCreationBits)
}
func TestSpanBatchTxsContractCreationCount(t *testing.T) {
......@@ -62,16 +63,16 @@ func TestSpanBatchTxsContractCreationCount(t *testing.T) {
var buf bytes.Buffer
err := sbt.encodeContractCreationBits(&buf)
assert.NoError(t, err)
require.NoError(t, err)
result := buf.Bytes()
sbt.contractCreationBits = nil
r := bytes.NewReader(result)
err = sbt.decodeContractCreationBits(r)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, contractCreationCount, sbt.contractCreationCount())
require.Equal(t, contractCreationCount, sbt.contractCreationCount())
}
func TestSpanBatchTxsYParityBits(t *testing.T) {
......@@ -88,23 +89,23 @@ func TestSpanBatchTxsYParityBits(t *testing.T) {
var buf bytes.Buffer
err := sbt.encodeYParityBits(&buf)
assert.NoError(t, err)
require.NoError(t, err)
// yParityBit field is fixed length: single bit
yParityBitBufferLen := totalBlockTxCount / 8
if totalBlockTxCount%8 != 0 {
yParityBitBufferLen++
}
assert.Equal(t, buf.Len(), int(yParityBitBufferLen))
require.Equal(t, buf.Len(), int(yParityBitBufferLen))
result := buf.Bytes()
sbt.yParityBits = nil
r := bytes.NewReader(result)
err = sbt.decodeYParityBits(r)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, yParityBits, sbt.yParityBits)
require.Equal(t, yParityBits, sbt.yParityBits)
}
func TestSpanBatchTxsTxSigs(t *testing.T) {
......@@ -121,22 +122,22 @@ func TestSpanBatchTxsTxSigs(t *testing.T) {
var buf bytes.Buffer
err := sbt.encodeTxSigsRS(&buf)
assert.NoError(t, err)
require.NoError(t, err)
// txSig field is fixed length: 32 byte + 32 byte = 64 byte
assert.Equal(t, buf.Len(), 64*int(totalBlockTxCount))
require.Equal(t, buf.Len(), 64*int(totalBlockTxCount))
result := buf.Bytes()
sbt.txSigs = nil
r := bytes.NewReader(result)
err = sbt.decodeTxSigsRS(r)
assert.NoError(t, err)
require.NoError(t, err)
// v field is not set
for i := 0; i < int(totalBlockTxCount); i++ {
assert.Equal(t, txSigs[i].r, sbt.txSigs[i].r)
assert.Equal(t, txSigs[i].s, sbt.txSigs[i].s)
require.Equal(t, txSigs[i].r, sbt.txSigs[i].r)
require.Equal(t, txSigs[i].s, sbt.txSigs[i].s)
}
}
......@@ -154,16 +155,16 @@ func TestSpanBatchTxsTxNonces(t *testing.T) {
var buf bytes.Buffer
err := sbt.encodeTxNonces(&buf)
assert.NoError(t, err)
require.NoError(t, err)
result := buf.Bytes()
sbt.txNonces = nil
r := bytes.NewReader(result)
err = sbt.decodeTxNonces(r)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, txNonces, sbt.txNonces)
require.Equal(t, txNonces, sbt.txNonces)
}
func TestSpanBatchTxsTxGases(t *testing.T) {
......@@ -180,16 +181,16 @@ func TestSpanBatchTxsTxGases(t *testing.T) {
var buf bytes.Buffer
err := sbt.encodeTxGases(&buf)
assert.NoError(t, err)
require.NoError(t, err)
result := buf.Bytes()
sbt.txGases = nil
r := bytes.NewReader(result)
err = sbt.decodeTxGases(r)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, txGases, sbt.txGases)
require.Equal(t, txGases, sbt.txGases)
}
func TestSpanBatchTxsTxTos(t *testing.T) {
......@@ -209,19 +210,19 @@ func TestSpanBatchTxsTxTos(t *testing.T) {
var buf bytes.Buffer
err := sbt.encodeTxTos(&buf)
assert.NoError(t, err)
require.NoError(t, err)
// to field is fixed length: 20 bytes
assert.Equal(t, buf.Len(), 20*len(txTos))
require.Equal(t, buf.Len(), 20*len(txTos))
result := buf.Bytes()
sbt.txTos = nil
r := bytes.NewReader(result)
err = sbt.decodeTxTos(r)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, txTos, sbt.txTos)
require.Equal(t, txTos, sbt.txTos)
}
func TestSpanBatchTxsTxDatas(t *testing.T) {
......@@ -240,7 +241,7 @@ func TestSpanBatchTxsTxDatas(t *testing.T) {
var buf bytes.Buffer
err := sbt.encodeTxDatas(&buf)
assert.NoError(t, err)
require.NoError(t, err)
result := buf.Bytes()
sbt.txDatas = nil
......@@ -248,10 +249,10 @@ func TestSpanBatchTxsTxDatas(t *testing.T) {
r := bytes.NewReader(result)
err = sbt.decodeTxDatas(r)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, txDatas, sbt.txDatas)
assert.Equal(t, txTypes, sbt.txTypes)
require.Equal(t, txDatas, sbt.txDatas)
require.Equal(t, txTypes, sbt.txTypes)
}
func TestSpanBatchTxsRecoverV(t *testing.T) {
......@@ -291,7 +292,7 @@ func TestSpanBatchTxsRecoverV(t *testing.T) {
recoveredVs = append(recoveredVs, txSig.v)
}
assert.Equal(t, originalVs, recoveredVs, "recovered v mismatch")
require.Equal(t, originalVs, recoveredVs, "recovered v mismatch")
}
func TestSpanBatchTxsRoundTrip(t *testing.T) {
......@@ -305,7 +306,7 @@ func TestSpanBatchTxsRoundTrip(t *testing.T) {
var buf bytes.Buffer
err := sbt.encode(&buf)
assert.NoError(t, err)
require.NoError(t, err)
result := buf.Bytes()
r := bytes.NewReader(result)
......@@ -313,10 +314,10 @@ func TestSpanBatchTxsRoundTrip(t *testing.T) {
var sbt2 spanBatchTxs
sbt2.totalBlockTxCount = totalBlockTxCount
err = sbt2.decode(r)
assert.NoError(t, err)
require.NoError(t, err)
sbt2.recoverV(chainID)
assert.Equal(t, sbt, &sbt2)
require.Equal(t, sbt, &sbt2)
}
}
......@@ -331,16 +332,16 @@ func TestSpanBatchTxsRoundTripFullTxs(t *testing.T) {
for i := 0; i < int(totalblockTxCounts); i++ {
tx := testutils.RandomTx(rng, new(big.Int).SetUint64(rng.Uint64()), signer)
rawTx, err := tx.MarshalBinary()
assert.NoError(t, err)
require.NoError(t, err)
txs = append(txs, rawTx)
}
sbt, err := newSpanBatchTxs(txs, chainID)
assert.NoError(t, err)
require.NoError(t, err)
txs2, err := sbt.fullTxs(chainID)
assert.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, txs, txs2)
require.Equal(t, txs, txs2)
}
}
......@@ -373,17 +374,17 @@ func TestSpanBatchTxsFullTxNotEnoughTxTos(t *testing.T) {
for i := 0; i < int(totalblockTxCounts); i++ {
tx := testutils.RandomTx(rng, new(big.Int).SetUint64(rng.Uint64()), signer)
rawTx, err := tx.MarshalBinary()
assert.NoError(t, err)
require.NoError(t, err)
txs = append(txs, rawTx)
}
sbt, err := newSpanBatchTxs(txs, chainID)
assert.NoError(t, err)
require.NoError(t, err)
// drop single to field
sbt.txTos = sbt.txTos[:len(sbt.txTos)-2]
_, err = sbt.fullTxs(chainID)
assert.EqualError(t, err, "tx to not enough")
require.EqualError(t, err, "tx to not enough")
}
func TestSpanBatchTxsMaxContractCreationBitsLength(t *testing.T) {
......
......@@ -106,12 +106,12 @@ func (co *SpanChannelOut) AddSingularBatch(batch *SingularBatch, seqNum uint64)
return 0, fmt.Errorf("failed to convert SpanBatch into RawSpanBatch: %w", err)
}
// Encode RawSpanBatch into bytes
if err = rlp.Encode(&buf, NewSpanBatchData(*rawSpanBatch)); err != nil {
if err = rlp.Encode(&buf, NewBatchData(rawSpanBatch)); err != nil {
return 0, fmt.Errorf("failed to encode RawSpanBatch into bytes: %w", err)
}
// Ensure that the total size of all RLP elements is less than or equal to MAX_RLP_BYTES_PER_CHANNEL
if buf.Len() > MaxRLPBytesPerChannel {
return 0, fmt.Errorf("could not add %d bytes to channel of %d bytes, max is %d. err: %w",
return 0, fmt.Errorf("could not take %d bytes as replacement of channel of %d bytes, max is %d. err: %w",
buf.Len(), co.rlpLength, MaxRLPBytesPerChannel, ErrTooManyRLPBytes)
}
co.rlpLength = buf.Len()
......
......@@ -141,49 +141,72 @@ func RandomTo(rng *rand.Rand) *common.Address {
}
func RandomTx(rng *rand.Rand, baseFee *big.Int, signer types.Signer) *types.Transaction {
gas := params.TxGas + uint64(rng.Int63n(2_000_000))
key := InsecureRandomKey(rng)
tip := big.NewInt(rng.Int63n(10 * params.GWei))
txTypeList := []int{types.LegacyTxType, types.AccessListTxType, types.DynamicFeeTxType}
txType := txTypeList[rng.Intn(len(txTypeList))]
var txData types.TxData
var tx *types.Transaction
switch txType {
case types.LegacyTxType:
txData = &types.LegacyTx{
tx = RandomLegacyTx(rng, signer)
case types.AccessListTxType:
tx = RandomAccessListTx(rng, signer)
case types.DynamicFeeTxType:
tx = RandomDynamicFeeTxWithBaseFee(rng, baseFee, signer)
default:
panic("invalid tx type")
}
return tx
}
func RandomLegacyTx(rng *rand.Rand, signer types.Signer) *types.Transaction {
key := InsecureRandomKey(rng)
txData := &types.LegacyTx{
Nonce: rng.Uint64(),
GasPrice: new(big.Int).SetUint64(rng.Uint64()),
Gas: gas,
Gas: params.TxGas + uint64(rng.Int63n(2_000_000)),
To: RandomTo(rng),
Value: RandomETH(rng, 10),
Data: RandomData(rng, rng.Intn(1000)),
}
case types.AccessListTxType:
txData = &types.AccessListTx{
tx, err := types.SignNewTx(key, signer, txData)
if err != nil {
panic(err)
}
return tx
}
func RandomAccessListTx(rng *rand.Rand, signer types.Signer) *types.Transaction {
key := InsecureRandomKey(rng)
txData := &types.AccessListTx{
ChainID: signer.ChainID(),
Nonce: rng.Uint64(),
GasPrice: new(big.Int).SetUint64(rng.Uint64()),
Gas: gas,
Gas: params.TxGas + uint64(rng.Int63n(2_000_000)),
To: RandomTo(rng),
Value: RandomETH(rng, 10),
Data: RandomData(rng, rng.Intn(1000)),
AccessList: nil,
}
case types.DynamicFeeTxType:
txData = &types.DynamicFeeTx{
tx, err := types.SignNewTx(key, signer, txData)
if err != nil {
panic(err)
}
return tx
}
func RandomDynamicFeeTxWithBaseFee(rng *rand.Rand, baseFee *big.Int, signer types.Signer) *types.Transaction {
key := InsecureRandomKey(rng)
tip := big.NewInt(rng.Int63n(10 * params.GWei))
txData := &types.DynamicFeeTx{
ChainID: signer.ChainID(),
Nonce: rng.Uint64(),
GasTipCap: tip,
GasFeeCap: new(big.Int).Add(baseFee, tip),
Gas: gas,
Gas: params.TxGas + uint64(rng.Int63n(2_000_000)),
To: RandomTo(rng),
Value: RandomETH(rng, 10),
Data: RandomData(rng, rng.Intn(1000)),
AccessList: nil,
}
default:
panic("invalid tx type")
}
tx, err := types.SignNewTx(key, signer, txData)
if err != nil {
panic(err)
......@@ -191,6 +214,11 @@ func RandomTx(rng *rand.Rand, baseFee *big.Int, signer types.Signer) *types.Tran
return tx
}
func RandomDynamicFeeTx(rng *rand.Rand, signer types.Signer) *types.Transaction {
baseFee := new(big.Int).SetUint64(rng.Uint64())
return RandomDynamicFeeTxWithBaseFee(rng, baseFee, signer)
}
func RandomReceipt(rng *rand.Rand, signer types.Signer, tx *types.Transaction, txIndex uint64, cumulativeGasUsed uint64) *types.Receipt {
gasUsed := params.TxGas + uint64(rng.Int63n(int64(tx.Gas()-params.TxGas+1)))
logs := make([]*types.Log, rng.Intn(10))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment