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 }