engine_test.go 7.94 KB
Newer Older
1 2 3 4 5 6 7
package l2

import (
	"context"
	"math/big"
	"testing"

8 9
	"github.com/ethereum-optimism/optimism/op-node/rollup"
	"github.com/ethereum-optimism/optimism/op-program/client/l2/engineapi"
10 11
	"github.com/stretchr/testify/require"

12 13 14
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/consensus"
	"github.com/ethereum/go-ethereum/core/state"
15
	"github.com/ethereum/go-ethereum/core/stateless"
16 17 18 19
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/core/vm"
	"github.com/ethereum/go-ethereum/params"
	"github.com/ethereum/go-ethereum/trie"
20 21 22 23 24

	"github.com/ethereum-optimism/optimism/op-node/chaincfg"
	"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
	"github.com/ethereum-optimism/optimism/op-node/rollup/engine"
	"github.com/ethereum-optimism/optimism/op-service/eth"
25 26 27
)

// Should implement derive.Engine
28
var _ engine.Engine = (*OracleEngine)(nil)
29 30 31 32 33 34 35 36 37

func TestPayloadByHash(t *testing.T) {
	ctx := context.Background()

	t.Run("KnownBlock", func(t *testing.T) {
		engine, stub := createOracleEngine(t)
		block := stub.head
		payload, err := engine.PayloadByHash(ctx, block.Hash())
		require.NoError(t, err)
38
		expected, err := eth.BlockAsPayload(block, engine.backend.Config().ShanghaiTime)
39
		require.NoError(t, err)
40
		require.Equal(t, &eth.ExecutionPayloadEnvelope{ExecutionPayload: expected}, payload)
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
	})

	t.Run("UnknownBlock", func(t *testing.T) {
		engine, _ := createOracleEngine(t)
		hash := common.HexToHash("0x878899")
		payload, err := engine.PayloadByHash(ctx, hash)
		require.ErrorIs(t, err, ErrNotFound)
		require.Nil(t, payload)
	})
}

func TestPayloadByNumber(t *testing.T) {
	ctx := context.Background()

	t.Run("KnownBlock", func(t *testing.T) {
		engine, stub := createOracleEngine(t)
		block := stub.head
		payload, err := engine.PayloadByNumber(ctx, block.NumberU64())
		require.NoError(t, err)
60
		expected, err := eth.BlockAsPayload(block, engine.backend.Config().ShanghaiTime)
61
		require.NoError(t, err)
62
		require.Equal(t, &eth.ExecutionPayloadEnvelope{ExecutionPayload: expected}, payload)
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
	})

	t.Run("NoCanonicalHash", func(t *testing.T) {
		engine, _ := createOracleEngine(t)
		payload, err := engine.PayloadByNumber(ctx, uint64(700))
		require.ErrorIs(t, err, ErrNotFound)
		require.Nil(t, payload)
	})

	t.Run("UnknownBlock", func(t *testing.T) {
		engine, stub := createOracleEngine(t)
		hash := common.HexToHash("0x878899")
		number := uint64(700)
		stub.canonical[number] = hash
		payload, err := engine.PayloadByNumber(ctx, number)
		require.ErrorIs(t, err, ErrNotFound)
		require.Nil(t, payload)
	})
}

func TestL2BlockRefByLabel(t *testing.T) {
	ctx := context.Background()
	engine, stub := createOracleEngine(t)
	tests := []struct {
		name  eth.BlockLabel
		block *types.Block
	}{
		{eth.Unsafe, stub.head},
		{eth.Safe, stub.safe},
		{eth.Finalized, stub.finalized},
	}
	for _, test := range tests {
		t.Run(string(test.name), func(t *testing.T) {
96
			expected, err := derive.L2BlockToBlockRef(engine.rollupCfg, test.block)
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
			require.NoError(t, err)
			blockRef, err := engine.L2BlockRefByLabel(ctx, test.name)
			require.NoError(t, err)
			require.Equal(t, expected, blockRef)
		})
	}
	t.Run("UnknownLabel", func(t *testing.T) {
		_, err := engine.L2BlockRefByLabel(ctx, "nope")
		require.ErrorContains(t, err, "unknown label")
	})
}

func TestL2BlockRefByHash(t *testing.T) {
	ctx := context.Background()
	engine, stub := createOracleEngine(t)

	t.Run("KnownBlock", func(t *testing.T) {
114
		expected, err := derive.L2BlockToBlockRef(engine.rollupCfg, stub.safe)
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
		require.NoError(t, err)
		ref, err := engine.L2BlockRefByHash(ctx, stub.safe.Hash())
		require.NoError(t, err)
		require.Equal(t, expected, ref)
	})

	t.Run("UnknownBlock", func(t *testing.T) {
		ref, err := engine.L2BlockRefByHash(ctx, common.HexToHash("0x878899"))
		require.ErrorIs(t, err, ErrNotFound)
		require.Equal(t, eth.L2BlockRef{}, ref)
	})
}

func TestSystemConfigByL2Hash(t *testing.T) {
	ctx := context.Background()
	engine, stub := createOracleEngine(t)

	t.Run("KnownBlock", func(t *testing.T) {
133
		payload, err := eth.BlockAsPayload(stub.safe, engine.backend.Config().ShanghaiTime)
134
		require.NoError(t, err)
135
		expected, err := derive.PayloadToSystemConfig(engine.rollupCfg, payload)
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
		require.NoError(t, err)
		cfg, err := engine.SystemConfigByL2Hash(ctx, stub.safe.Hash())
		require.NoError(t, err)
		require.Equal(t, expected, cfg)
	})

	t.Run("UnknownBlock", func(t *testing.T) {
		ref, err := engine.SystemConfigByL2Hash(ctx, common.HexToHash("0x878899"))
		require.ErrorIs(t, err, ErrNotFound)
		require.Equal(t, eth.SystemConfig{}, ref)
	})
}

func createOracleEngine(t *testing.T) (*OracleEngine, *stubEngineBackend) {
	head := createL2Block(t, 4)
	safe := createL2Block(t, 3)
	finalized := createL2Block(t, 2)
153
	rollupCfg := chaincfg.OPSepolia()
154 155 156 157 158 159 160 161 162 163 164 165 166 167
	backend := &stubEngineBackend{
		head:      head,
		safe:      safe,
		finalized: finalized,
		blocks: map[common.Hash]*types.Block{
			head.Hash():      head,
			safe.Hash():      safe,
			finalized.Hash(): finalized,
		},
		canonical: map[uint64]common.Hash{
			head.NumberU64():      head.Hash(),
			safe.NumberU64():      safe.Hash(),
			finalized.NumberU64(): finalized.Hash(),
		},
168
		rollupCfg: rollupCfg,
169 170 171
	}
	engine := OracleEngine{
		backend:   backend,
172
		rollupCfg: rollupCfg,
173 174 175 176 177
	}
	return &engine, backend
}

func createL2Block(t *testing.T, number int) *types.Block {
178
	tx, err := derive.L1InfoDeposit(chaincfg.OPSepolia(), eth.SystemConfig{}, uint64(1), eth.HeaderBlockInfo(&types.Header{
179 180
		Number:  big.NewInt(32),
		BaseFee: big.NewInt(7),
181
	}), 0)
182 183 184 185 186
	require.NoError(t, err)
	header := &types.Header{
		Number:  big.NewInt(int64(number)),
		BaseFee: big.NewInt(7),
	}
187 188 189 190
	body := &types.Body{
		Transactions: []*types.Transaction{types.NewTx(tx)},
	}
	return types.NewBlock(header, body, nil, trie.NewStackTrie(nil))
191 192 193 194 195 196 197 198
}

type stubEngineBackend struct {
	head      *types.Block
	safe      *types.Block
	finalized *types.Block
	blocks    map[common.Hash]*types.Block
	canonical map[uint64]common.Hash
199
	rollupCfg *rollup.Config
200 201
}

202
func (s *stubEngineBackend) CurrentHeader() *types.Header {
203 204 205
	return s.head.Header()
}

206
func (s *stubEngineBackend) CurrentSafeBlock() *types.Header {
207 208 209
	return s.safe.Header()
}

210
func (s *stubEngineBackend) CurrentFinalBlock() *types.Header {
211 212 213
	return s.finalized.Header()
}

214
func (s *stubEngineBackend) GetBlockByHash(hash common.Hash) *types.Block {
215 216 217
	return s.blocks[hash]
}

218
func (s *stubEngineBackend) GetCanonicalHash(n uint64) common.Hash {
219 220 221
	return s.canonical[n]
}

222
func (s *stubEngineBackend) GetBlock(hash common.Hash, number uint64) *types.Block {
223 224 225
	panic("unsupported")
}

226
func (s *stubEngineBackend) HasBlockAndState(hash common.Hash, number uint64) bool {
227 228 229
	panic("unsupported")
}

230
func (s *stubEngineBackend) GetVMConfig() *vm.Config {
231 232 233
	panic("unsupported")
}

234 235 236 237 238 239 240
func (s *stubEngineBackend) Config() *params.ChainConfig {
	return &params.ChainConfig{
		ShanghaiTime: s.rollupCfg.CanyonTime,
	}
}

func (s *stubEngineBackend) Engine() consensus.Engine {
241 242 243
	panic("unsupported")
}

244
func (s *stubEngineBackend) StateAt(root common.Hash) (*state.StateDB, error) {
245 246 247
	panic("unsupported")
}

248
func (s *stubEngineBackend) InsertBlockWithoutSetHead(block *types.Block, makeWitness bool) (*stateless.Witness, error) {
249 250 251
	panic("unsupported")
}

252
func (s stubEngineBackend) AssembleAndInsertBlockWithoutSetHead(_ *engineapi.BlockProcessor) (*types.Block, error) {
253 254 255
	panic("unsupported")
}

256
func (s *stubEngineBackend) SetCanonical(head *types.Block) (common.Hash, error) {
257 258 259
	panic("unsupported")
}

260
func (s *stubEngineBackend) SetFinalized(header *types.Header) {
261 262 263
	panic("unsupported")
}

264
func (s *stubEngineBackend) SetSafe(header *types.Header) {
265 266 267
	panic("unsupported")
}

268
func (s *stubEngineBackend) GetHeader(hash common.Hash, number uint64) *types.Header {
269 270 271
	panic("unsupported")
}

272
func (s *stubEngineBackend) GetHeaderByNumber(number uint64) *types.Header {
273 274 275
	panic("unsupported")
}

276
func (s *stubEngineBackend) GetHeaderByHash(hash common.Hash) *types.Header {
277 278 279
	panic("unsupported")
}

280
func (s *stubEngineBackend) GetTd(hash common.Hash, number uint64) *big.Int {
281 282
	panic("unsupported")
}