driver_test.go 4.49 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
package driver

import (
	"context"
	"errors"
	"fmt"
	"io"
	"testing"

	"github.com/ethereum-optimism/optimism/op-node/rollup/derive"
11
	"github.com/ethereum-optimism/optimism/op-service/eth"
12
	"github.com/ethereum-optimism/optimism/op-service/testlog"
13 14 15 16 17 18 19 20 21 22 23 24 25
	"github.com/ethereum/go-ethereum/log"
	"github.com/stretchr/testify/require"
)

func TestDerivationComplete(t *testing.T) {
	driver := createDriver(t, fmt.Errorf("derivation complete: %w", io.EOF))
	err := driver.Step(context.Background())
	require.ErrorIs(t, err, io.EOF)
}

func TestTemporaryError(t *testing.T) {
	driver := createDriver(t, fmt.Errorf("whoopsie: %w", derive.ErrTemporary))
	err := driver.Step(context.Background())
26
	require.NoError(t, err, "should allow derivation to continue after temporary error")
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
}

func TestNotEnoughDataError(t *testing.T) {
	driver := createDriver(t, fmt.Errorf("idk: %w", derive.NotEnoughData))
	err := driver.Step(context.Background())
	require.NoError(t, err)
}

func TestGenericError(t *testing.T) {
	expected := errors.New("boom")
	driver := createDriver(t, expected)
	err := driver.Step(context.Background())
	require.ErrorIs(t, err, expected)
}

42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
func TestTargetBlock(t *testing.T) {
	t.Run("Reached", func(t *testing.T) {
		driver := createDriverWithNextBlock(t, derive.NotEnoughData, 1000)
		driver.targetBlockNum = 1000
		err := driver.Step(context.Background())
		require.ErrorIs(t, err, io.EOF)
	})

	t.Run("Exceeded", func(t *testing.T) {
		driver := createDriverWithNextBlock(t, derive.NotEnoughData, 1000)
		driver.targetBlockNum = 500
		err := driver.Step(context.Background())
		require.ErrorIs(t, err, io.EOF)
	})

	t.Run("NotYetReached", func(t *testing.T) {
		driver := createDriverWithNextBlock(t, derive.NotEnoughData, 1000)
		driver.targetBlockNum = 1001
		err := driver.Step(context.Background())
		// No error to indicate derivation should continue
		require.NoError(t, err)
	})
}

66 67 68 69 70 71
func TestNoError(t *testing.T) {
	driver := createDriver(t, nil)
	err := driver.Step(context.Background())
	require.NoError(t, err)
}

72 73 74 75
func TestValidateClaim(t *testing.T) {
	t.Run("Valid", func(t *testing.T) {
		driver := createDriver(t, io.EOF)
		expected := eth.Bytes32{0x11}
76
		driver.l2OutputRoot = func(_ uint64) (eth.Bytes32, error) {
77 78
			return expected, nil
		}
79
		err := driver.ValidateClaim(uint64(0), expected)
80
		require.NoError(t, err)
81 82
	})

83 84 85 86 87 88 89 90 91 92 93 94 95
	t.Run("Valid-PriorToSafeHead", func(t *testing.T) {
		driver := createDriverWithNextBlock(t, io.EOF, 10)
		expected := eth.Bytes32{0x11}
		requestedOutputRoot := uint64(0)
		driver.l2OutputRoot = func(blockNum uint64) (eth.Bytes32, error) {
			requestedOutputRoot = blockNum
			return expected, nil
		}
		err := driver.ValidateClaim(uint64(20), expected)
		require.NoError(t, err)
		require.Equal(t, uint64(10), requestedOutputRoot)
	})

96 97
	t.Run("Invalid", func(t *testing.T) {
		driver := createDriver(t, io.EOF)
98
		driver.l2OutputRoot = func(_ uint64) (eth.Bytes32, error) {
99 100
			return eth.Bytes32{0x22}, nil
		}
101
		err := driver.ValidateClaim(uint64(0), eth.Bytes32{0x11})
102
		require.ErrorIs(t, err, ErrClaimNotValid)
103 104
	})

105 106 107 108 109 110 111 112 113 114 115 116 117
	t.Run("Invalid-PriorToSafeHead", func(t *testing.T) {
		driver := createDriverWithNextBlock(t, io.EOF, 10)
		expected := eth.Bytes32{0x11}
		requestedOutputRoot := uint64(0)
		driver.l2OutputRoot = func(blockNum uint64) (eth.Bytes32, error) {
			requestedOutputRoot = blockNum
			return expected, nil
		}
		err := driver.ValidateClaim(uint64(20), eth.Bytes32{0x55})
		require.ErrorIs(t, err, ErrClaimNotValid)
		require.Equal(t, uint64(10), requestedOutputRoot)
	})

118 119
	t.Run("Error", func(t *testing.T) {
		driver := createDriver(t, io.EOF)
120
		expectedErr := errors.New("boom")
121
		driver.l2OutputRoot = func(_ uint64) (eth.Bytes32, error) {
122
			return eth.Bytes32{}, expectedErr
123
		}
124
		err := driver.ValidateClaim(uint64(0), eth.Bytes32{0x11})
125
		require.ErrorIs(t, err, expectedErr)
126 127 128
	})
}

129
func createDriver(t *testing.T, derivationResult error) *Driver {
130 131 132 133 134
	return createDriverWithNextBlock(t, derivationResult, 0)
}

func createDriverWithNextBlock(t *testing.T, derivationResult error, nextBlockNum uint64) *Driver {
	derivation := &stubDerivation{nextErr: derivationResult, nextBlockNum: nextBlockNum}
135
	return &Driver{
136
		logger:         testlog.Logger(t, log.LevelDebug),
137
		pipeline:       derivation,
138
		engine:         derivation,
139
		targetBlockNum: 1_000_000,
140 141 142 143
	}
}

type stubDerivation struct {
144 145
	nextErr      error
	nextBlockNum uint64
146 147 148 149 150 151 152
}

func (s stubDerivation) Step(ctx context.Context) error {
	return s.nextErr
}

func (s stubDerivation) SafeL2Head() eth.L2BlockRef {
153 154 155
	return eth.L2BlockRef{
		Number: s.nextBlockNum,
	}
156
}