update_test.go 6.27 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
package fromda

import (
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/ethereum/go-ethereum/common"

	"github.com/ethereum-optimism/optimism/op-supervisor/supervisor/types"
)

type testCase struct {
	name     string
	setupFn  setupFn
	assertFn assertFn
}

func TestBadUpdates(t *testing.T) {
	aDerivedFrom := mockL1(1)
	aDerived := mockL2(201)
	bDerivedFrom := mockL1(2)
	bDerived := mockL2(202)
	cDerivedFrom := mockL1(3)
	cDerived := mockL2(203)
	dDerivedFrom := mockL1(4)
	dDerived := mockL2(204)
	eDerivedFrom := mockL1(5)
	eDerived := mockL2(205)
	fDerivedFrom := mockL1(6)
	fDerived := mockL2(206)

	noChange := assertFn(func(t *testing.T, db *DB, m *stubMetrics) {
		derivedFrom, derived, err := db.Latest()
		require.NoError(t, err)
		require.Equal(t, dDerivedFrom, derivedFrom)
		require.Equal(t, dDerived, derived)
	})

	testCases := []testCase{
		{
			name: "add on old derivedFrom",
			setupFn: func(t *testing.T, db *DB, m *stubMetrics) {
44
				require.ErrorIs(t, db.AddDerived(toRef(bDerivedFrom, aDerivedFrom.Hash), toRef(dDerived, cDerived.Hash)), types.ErrOutOfOrder)
45 46 47 48 49 50
			},
			assertFn: noChange,
		},
		{
			name: "repeat parent derivedFrom",
			setupFn: func(t *testing.T, db *DB, m *stubMetrics) {
51
				require.ErrorIs(t, db.AddDerived(toRef(cDerivedFrom, bDerivedFrom.Hash), toRef(dDerived, cDerived.Hash)), types.ErrOutOfOrder)
52 53 54 55 56 57 58 59 60 61
			},
			assertFn: noChange,
		},
		{
			name: "add on conflicting derivedFrom, same height. And new derived value",
			setupFn: func(t *testing.T, db *DB, m *stubMetrics) {
				require.ErrorIs(t, db.AddDerived(toRef(types.BlockSeal{
					Hash:      common.Hash{0xba, 0xd},
					Number:    dDerivedFrom.Number,
					Timestamp: dDerivedFrom.Timestamp,
62
				}, cDerivedFrom.Hash), toRef(eDerived, dDerived.Hash)), types.ErrConflict)
63 64 65 66
			},
			assertFn: noChange,
		},
		{
67
			name: "CrossDerivedFrom with conflicting parent root, same L1 height, new L2: accepted, L1 parent-hash is used only on L1 increments.",
68
			setupFn: func(t *testing.T, db *DB, m *stubMetrics) {
69
				require.NoError(t, db.AddDerived(toRef(dDerivedFrom, common.Hash{0x42}), toRef(eDerived, dDerived.Hash)), types.ErrConflict)
70 71 72 73 74 75 76 77 78 79 80
			},
			assertFn: func(t *testing.T, db *DB, m *stubMetrics) {
				derivedFrom, derived, err := db.Latest()
				require.NoError(t, err)
				require.Equal(t, dDerivedFrom, derivedFrom)
				require.Equal(t, eDerived, derived)
			},
		},
		{
			name: "Conflicting derivedFrom parent root, new L1 height, same L2",
			setupFn: func(t *testing.T, db *DB, m *stubMetrics) {
81
				require.ErrorIs(t, db.AddDerived(toRef(eDerivedFrom, common.Hash{0x42}), toRef(dDerived, cDerived.Hash)), types.ErrConflict)
82 83 84 85 86 87
			},
			assertFn: noChange,
		},
		{
			name: "add on too new derivedFrom (even if parent-hash looks correct)",
			setupFn: func(t *testing.T, db *DB, m *stubMetrics) {
88
				require.ErrorIs(t, db.AddDerived(toRef(fDerivedFrom, dDerivedFrom.Hash), toRef(eDerived, dDerived.Hash)), types.ErrOutOfOrder)
89 90 91 92 93 94
			},
			assertFn: noChange,
		},
		{
			name: "add on old derivedFrom (even if parent-hash looks correct)",
			setupFn: func(t *testing.T, db *DB, m *stubMetrics) {
95
				require.ErrorIs(t, db.AddDerived(toRef(cDerivedFrom, bDerivedFrom.Hash), toRef(cDerived, dDerived.Hash)), types.ErrOutOfOrder)
96 97 98 99 100 101
			},
			assertFn: noChange,
		},
		{
			name: "add on even older derivedFrom",
			setupFn: func(t *testing.T, db *DB, m *stubMetrics) {
102
				require.ErrorIs(t, db.AddDerived(toRef(bDerivedFrom, aDerivedFrom.Hash), toRef(dDerived, cDerived.Hash)), types.ErrOutOfOrder)
103 104 105 106 107 108 109 110 111 112
			},
			assertFn: noChange,
		},
		{
			name: "add on conflicting derived, same L2 height, new L1 block",
			setupFn: func(t *testing.T, db *DB, m *stubMetrics) {
				require.ErrorIs(t, db.AddDerived(toRef(eDerivedFrom, dDerivedFrom.Hash), toRef(types.BlockSeal{
					Hash:      common.Hash{0x42},
					Number:    dDerived.Number,
					Timestamp: dDerived.Timestamp,
113
				}, cDerived.Hash)), types.ErrConflict)
114 115 116 117 118 119
			},
			assertFn: noChange,
		},
		{
			name: "add derived with conflicting parent hash, new L1 height, same L2 height: accepted, L2 parent-hash is only checked on L2 increments.",
			setupFn: func(t *testing.T, db *DB, m *stubMetrics) {
120
				require.NoError(t, db.AddDerived(toRef(eDerivedFrom, dDerivedFrom.Hash), toRef(dDerived, common.Hash{0x42})), types.ErrConflict)
121 122 123 124 125 126 127 128 129 130 131
			},
			assertFn: func(t *testing.T, db *DB, m *stubMetrics) {
				derivedFrom, derived, err := db.Latest()
				require.NoError(t, err)
				require.Equal(t, eDerivedFrom, derivedFrom)
				require.Equal(t, dDerived, derived)
			},
		},
		{
			name: "add derived with conflicting parent hash, same L1 height, new L2 height",
			setupFn: func(t *testing.T, db *DB, m *stubMetrics) {
132
				require.ErrorIs(t, db.AddDerived(toRef(dDerivedFrom, cDerivedFrom.Hash), toRef(eDerived, common.Hash{0x42})), types.ErrConflict)
133 134 135 136 137 138
			},
			assertFn: noChange,
		},
		{
			name: "add on too new derived (even if parent-hash looks correct)",
			setupFn: func(t *testing.T, db *DB, m *stubMetrics) {
139
				require.ErrorIs(t, db.AddDerived(toRef(dDerivedFrom, cDerivedFrom.Hash), toRef(fDerived, dDerived.Hash)), types.ErrOutOfOrder)
140 141 142 143 144 145
			},
			assertFn: noChange,
		},
		{
			name: "add on old derived (even if parent-hash looks correct)",
			setupFn: func(t *testing.T, db *DB, m *stubMetrics) {
146
				require.ErrorIs(t, db.AddDerived(toRef(dDerivedFrom, cDerivedFrom.Hash), toRef(cDerived, bDerived.Hash)), types.ErrOutOfOrder)
147 148 149 150 151 152
			},
			assertFn: noChange,
		},
		{
			name: "add on even older derived",
			setupFn: func(t *testing.T, db *DB, m *stubMetrics) {
153
				require.ErrorIs(t, db.AddDerived(toRef(dDerivedFrom, cDerivedFrom.Hash), toRef(bDerived, aDerived.Hash)), types.ErrOutOfOrder)
154 155 156 157 158 159 160
			},
			assertFn: noChange,
		},
		{
			name: "repeat self, silent no-op",
			setupFn: func(t *testing.T, db *DB, m *stubMetrics) {
				pre := m.DBDerivedEntryCount
161
				require.NoError(t, db.AddDerived(toRef(dDerivedFrom, cDerivedFrom.Hash), toRef(dDerived, cDerived.Hash)), types.ErrOutOfOrder)
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
				require.Equal(t, pre, m.DBDerivedEntryCount)
			},
			assertFn: noChange,
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			runDBTest(t,
				func(t *testing.T, db *DB, m *stubMetrics) {
					// Good first entry
					require.NoError(t, db.AddDerived(toRef(dDerivedFrom, cDerivedFrom.Hash), toRef(dDerived, cDerived.Hash)))
					// apply the test-case setup
					tc.setupFn(t, db, m)
				},
				tc.assertFn)
		})
	}
}