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

     1  package derive
     2  
     3  import (
     4  	"context"
     5  	"io"
     6  	"math/rand"
     7  	"testing"
     8  
     9  	"github.com/stretchr/testify/mock"
    10  	"github.com/stretchr/testify/require"
    11  
    12  	"github.com/ethereum/go-ethereum"
    13  	"github.com/ethereum/go-ethereum/common"
    14  	"github.com/ethereum/go-ethereum/common/hexutil"
    15  	"github.com/ethereum/go-ethereum/log"
    16  
    17  	"github.com/ethereum-optimism/optimism/op-service/eth"
    18  	"github.com/ethereum-optimism/optimism/op-service/testlog"
    19  	"github.com/ethereum-optimism/optimism/op-service/testutils"
    20  )
    21  
    22  type fakeDataIter struct {
    23  	idx  int
    24  	data []eth.Data
    25  	errs []error
    26  }
    27  
    28  func (cs *fakeDataIter) Next(ctx context.Context) (eth.Data, error) {
    29  	i := cs.idx
    30  	cs.idx += 1
    31  	return cs.data[i], cs.errs[i]
    32  }
    33  
    34  type MockDataSource struct {
    35  	mock.Mock
    36  }
    37  
    38  func (m *MockDataSource) OpenData(ctx context.Context, ref eth.L1BlockRef, batcherAddr common.Address) (DataIter, error) {
    39  	out := m.Mock.MethodCalled("OpenData", ref, batcherAddr)
    40  	return out[0].(DataIter), nil
    41  }
    42  
    43  func (m *MockDataSource) ExpectOpenData(ref eth.L1BlockRef, iter DataIter, batcherAddr common.Address) {
    44  	m.Mock.On("OpenData", ref, batcherAddr).Return(iter)
    45  }
    46  
    47  var _ DataAvailabilitySource = (*MockDataSource)(nil)
    48  
    49  type MockL1Traversal struct {
    50  	mock.Mock
    51  }
    52  
    53  func (m *MockL1Traversal) ExpectSystemConfig(sysCfg eth.SystemConfig) {
    54  	m.Mock.On("SystemConfig").Return(sysCfg)
    55  }
    56  
    57  func (m *MockL1Traversal) SystemConfig() eth.SystemConfig {
    58  	out := m.Mock.MethodCalled("SystemConfig")
    59  	return out[0].(eth.SystemConfig)
    60  }
    61  
    62  func (m *MockL1Traversal) Origin() eth.L1BlockRef {
    63  	out := m.Mock.MethodCalled("Origin")
    64  	return out[0].(eth.L1BlockRef)
    65  }
    66  
    67  func (m *MockL1Traversal) ExpectOrigin(block eth.L1BlockRef) {
    68  	m.Mock.On("Origin").Return(block)
    69  }
    70  
    71  func (m *MockL1Traversal) NextL1Block(_ context.Context) (eth.L1BlockRef, error) {
    72  	out := m.Mock.MethodCalled("NextL1Block")
    73  	return out[0].(eth.L1BlockRef), *out[1].(*error)
    74  }
    75  
    76  func (m *MockL1Traversal) ExpectNextL1Block(block eth.L1BlockRef, err error) {
    77  	m.Mock.On("NextL1Block").Return(block, &err)
    78  }
    79  
    80  var _ NextBlockProvider = (*MockL1Traversal)(nil)
    81  
    82  // TestL1RetrievalReset tests the reset. The reset just opens up a new
    83  // data for the specified block.
    84  func TestL1RetrievalReset(t *testing.T) {
    85  	rng := rand.New(rand.NewSource(1234))
    86  	dataSrc := &MockDataSource{}
    87  	a := testutils.RandomBlockRef(rng)
    88  	l1Cfg := eth.SystemConfig{
    89  		BatcherAddr: common.Address{42},
    90  	}
    91  
    92  	dataSrc.ExpectOpenData(a, &fakeDataIter{}, l1Cfg.BatcherAddr)
    93  	defer dataSrc.AssertExpectations(t)
    94  
    95  	l1r := NewL1Retrieval(testlog.Logger(t, log.LevelError), dataSrc, nil)
    96  
    97  	// We assert that it opens up the correct data on a reset
    98  	_ = l1r.Reset(context.Background(), a, l1Cfg)
    99  }
   100  
   101  // TestL1RetrievalNextData tests that the `NextData` function properly
   102  // handles different error cases and returns the expected data
   103  // if there is no error.
   104  func TestL1RetrievalNextData(t *testing.T) {
   105  	rng := rand.New(rand.NewSource(1234))
   106  	a := testutils.RandomBlockRef(rng)
   107  
   108  	tests := []struct {
   109  		name         string
   110  		prevBlock    eth.L1BlockRef
   111  		sysCfg       eth.SystemConfig
   112  		prevErr      error // error returned by prev.NextL1Block
   113  		openErr      error // error returned by NextData if prev.NextL1Block fails
   114  		datas        []eth.Data
   115  		datasErrs    []error
   116  		expectedErrs []error
   117  	}{
   118  		{
   119  			name:         "simple retrieval",
   120  			prevBlock:    a,
   121  			sysCfg:       eth.SystemConfig{BatcherAddr: common.Address{0x55}},
   122  			prevErr:      nil,
   123  			openErr:      nil,
   124  			datas:        []eth.Data{testutils.RandomData(rng, 10), testutils.RandomData(rng, 10), testutils.RandomData(rng, 10), nil},
   125  			datasErrs:    []error{nil, nil, nil, io.EOF},
   126  			expectedErrs: []error{nil, nil, nil, io.EOF},
   127  		},
   128  		{
   129  			name:    "out of data",
   130  			prevErr: io.EOF,
   131  			openErr: io.EOF,
   132  		},
   133  		{
   134  			name:         "fail to open data",
   135  			prevBlock:    a,
   136  			sysCfg:       eth.SystemConfig{BatcherAddr: common.Address{0x55}},
   137  			prevErr:      nil,
   138  			openErr:      nil,
   139  			datas:        []eth.Data{nil},
   140  			datasErrs:    []error{NewCriticalError(ethereum.NotFound)},
   141  			expectedErrs: []error{ErrCritical},
   142  		},
   143  	}
   144  
   145  	for _, test := range tests {
   146  		t.Run(test.name, func(t *testing.T) {
   147  			l1t := &MockL1Traversal{}
   148  			l1t.ExpectNextL1Block(test.prevBlock, test.prevErr)
   149  			dataSrc := &MockDataSource{}
   150  			dataSrc.ExpectOpenData(test.prevBlock, &fakeDataIter{data: test.datas, errs: test.datasErrs}, test.sysCfg.BatcherAddr)
   151  
   152  			ret := NewL1Retrieval(testlog.Logger(t, log.LevelCrit), dataSrc, l1t)
   153  
   154  			// If prevErr != nil we forced an error while getting data from the previous stage
   155  			if test.openErr != nil {
   156  				data, err := ret.NextData(context.Background())
   157  				require.Nil(t, data)
   158  				require.ErrorIs(t, err, test.openErr)
   159  			}
   160  
   161  			// Go through the fake data an assert that data is passed through and the correct
   162  			// errors are returned.
   163  			for i := range test.expectedErrs {
   164  				l1t.ExpectSystemConfig(test.sysCfg)
   165  				data, err := ret.NextData(context.Background())
   166  				require.Equal(t, test.datas[i], hexutil.Bytes(data))
   167  				require.ErrorIs(t, err, test.expectedErrs[i])
   168  			}
   169  
   170  			l1t.AssertExpectations(t)
   171  		})
   172  	}
   173  
   174  }