github.com/ethereum-optimism/optimism@v1.7.2/op-node/rollup/derive/channel_out_test.go (about)

     1  package derive
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"math/big"
     7  	"math/rand"
     8  	"testing"
     9  
    10  	"github.com/ethereum/go-ethereum/common"
    11  	"github.com/ethereum/go-ethereum/core/types"
    12  	"github.com/ethereum/go-ethereum/rlp"
    13  	"github.com/stretchr/testify/require"
    14  
    15  	"github.com/ethereum-optimism/optimism/op-node/rollup"
    16  )
    17  
    18  var (
    19  	rollupCfg rollup.Config
    20  )
    21  
    22  // basic implementation of the Compressor interface that does no compression
    23  type nonCompressor struct {
    24  	bytes.Buffer
    25  }
    26  
    27  func (s *nonCompressor) Flush() error {
    28  	return nil
    29  }
    30  
    31  func (s *nonCompressor) Close() error {
    32  	return nil
    33  }
    34  
    35  func (s *nonCompressor) FullErr() error {
    36  	return nil
    37  }
    38  
    39  func TestChannelOutAddBlock(t *testing.T) {
    40  	cout, err := NewChannelOut(SingularBatchType, &nonCompressor{}, nil)
    41  	require.NoError(t, err)
    42  
    43  	t.Run("returns err if first tx is not an l1info tx", func(t *testing.T) {
    44  		header := &types.Header{Number: big.NewInt(1), Difficulty: big.NewInt(100)}
    45  		block := types.NewBlockWithHeader(header).WithBody(
    46  			[]*types.Transaction{
    47  				types.NewTx(&types.DynamicFeeTx{}),
    48  			},
    49  			nil,
    50  		)
    51  		_, err := cout.AddBlock(&rollupCfg, block)
    52  		require.Error(t, err)
    53  		require.Equal(t, ErrNotDepositTx, err)
    54  	})
    55  }
    56  
    57  // TestOutputFrameSmallMaxSize tests that calling [OutputFrame] with a small
    58  // max size that is below the fixed frame size overhead of 23, will return
    59  // an error.
    60  func TestOutputFrameSmallMaxSize(t *testing.T) {
    61  	cout, err := NewChannelOut(SingularBatchType, &nonCompressor{}, nil)
    62  	require.NoError(t, err)
    63  
    64  	// Call OutputFrame with the range of small max size values that err
    65  	var w bytes.Buffer
    66  	for i := 0; i < 23; i++ {
    67  		fid, err := cout.OutputFrame(&w, uint64(i))
    68  		require.ErrorIs(t, err, ErrMaxFrameSizeTooSmall)
    69  		require.Zero(t, fid)
    70  	}
    71  }
    72  
    73  func TestOutputFrameNoEmptyLastFrame(t *testing.T) {
    74  	cout, err := NewChannelOut(SingularBatchType, &nonCompressor{}, nil)
    75  	require.NoError(t, err)
    76  
    77  	rng := rand.New(rand.NewSource(0x543331))
    78  	chainID := big.NewInt(rng.Int63n(1000))
    79  	txCount := 1
    80  	singularBatch := RandomSingularBatch(rng, txCount, chainID)
    81  
    82  	written, err := cout.AddSingularBatch(singularBatch, 0)
    83  	require.NoError(t, err)
    84  
    85  	require.NoError(t, cout.Close())
    86  
    87  	var buf bytes.Buffer
    88  	// Output a frame which needs exactly `written` bytes. This frame is expected to be the last frame.
    89  	_, err = cout.OutputFrame(&buf, written+FrameV0OverHeadSize)
    90  	require.ErrorIs(t, err, io.EOF)
    91  
    92  }
    93  
    94  // TestRLPByteLimit ensures that stream encoder is properly limiting the length.
    95  // It will decode the input if `len(input) <= inputLimit`.
    96  func TestRLPByteLimit(t *testing.T) {
    97  	// Should succeed if `len(input) == inputLimit`
    98  	enc := []byte("\x8bhello world") // RLP encoding of the string "hello world"
    99  	in := bytes.NewBuffer(enc)
   100  	var out string
   101  	stream := rlp.NewStream(in, 12)
   102  	err := stream.Decode(&out)
   103  	require.Nil(t, err)
   104  	require.Equal(t, out, "hello world")
   105  
   106  	// Should fail if the `inputLimit = len(input) - 1`
   107  	enc = []byte("\x8bhello world") // RLP encoding of the string "hello world"
   108  	in = bytes.NewBuffer(enc)
   109  	var out2 string
   110  	stream = rlp.NewStream(in, 11)
   111  	err = stream.Decode(&out2)
   112  	require.Equal(t, err, rlp.ErrValueTooLarge)
   113  	require.Equal(t, out2, "")
   114  }
   115  
   116  func TestForceCloseTxData(t *testing.T) {
   117  	id := [16]byte{0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef}
   118  	tests := []struct {
   119  		frames []Frame
   120  		errors bool
   121  		output string
   122  	}{
   123  		{
   124  			frames: []Frame{},
   125  			errors: true,
   126  			output: "",
   127  		},
   128  		{
   129  			frames: []Frame{{FrameNumber: 0, IsLast: false}, {ID: id, FrameNumber: 1, IsLast: true}},
   130  			errors: true,
   131  			output: "",
   132  		},
   133  		{
   134  			frames: []Frame{{ID: id, FrameNumber: 0, IsLast: false}},
   135  			errors: false,
   136  			output: "00deadbeefdeadbeefdeadbeefdeadbeef00000000000001",
   137  		},
   138  		{
   139  			frames: []Frame{{ID: id, FrameNumber: 0, IsLast: true}},
   140  			errors: false,
   141  			output: "00",
   142  		},
   143  		{
   144  			frames: []Frame{{ID: id, FrameNumber: 1, IsLast: false}},
   145  			errors: false,
   146  			output: "00deadbeefdeadbeefdeadbeefdeadbeef00000000000001",
   147  		},
   148  		{
   149  			frames: []Frame{{ID: id, FrameNumber: 1, IsLast: true}},
   150  			errors: false,
   151  			output: "00deadbeefdeadbeefdeadbeefdeadbeef00000000000000",
   152  		},
   153  		{
   154  			frames: []Frame{{ID: id, FrameNumber: 2, IsLast: true}},
   155  			errors: false,
   156  			output: "00deadbeefdeadbeefdeadbeefdeadbeef00000000000000deadbeefdeadbeefdeadbeefdeadbeef00010000000000",
   157  		},
   158  		{
   159  			frames: []Frame{{ID: id, FrameNumber: 1, IsLast: false}, {ID: id, FrameNumber: 3, IsLast: true}},
   160  			errors: false,
   161  			output: "00deadbeefdeadbeefdeadbeefdeadbeef00000000000000deadbeefdeadbeefdeadbeefdeadbeef00020000000000",
   162  		},
   163  		{
   164  			frames: []Frame{{ID: id, FrameNumber: 1, IsLast: false}, {ID: id, FrameNumber: 3, IsLast: true}, {ID: id, FrameNumber: 5, IsLast: true}},
   165  			errors: false,
   166  			output: "00deadbeefdeadbeefdeadbeefdeadbeef00000000000000deadbeefdeadbeefdeadbeefdeadbeef00020000000000",
   167  		},
   168  	}
   169  
   170  	for i, test := range tests {
   171  		out, err := ForceCloseTxData(test.frames)
   172  		if test.errors {
   173  			require.NotNil(t, err, "Should error on tc %v", i)
   174  			require.Nil(t, out, "Should return no value in tc %v", i)
   175  		} else {
   176  			require.NoError(t, err, "Should not error on tc %v", i)
   177  			require.Equal(t, common.FromHex(test.output), out, "Should match output tc %v", i)
   178  		}
   179  	}
   180  }
   181  
   182  func TestBlockToBatchValidity(t *testing.T) {
   183  	block := new(types.Block)
   184  	_, _, err := BlockToSingularBatch(&rollupCfg, block)
   185  	require.ErrorContains(t, err, "has no transactions")
   186  }