• protolambda's avatar
    op-node: SystemConfig in derivation (#3787) · 0b40e612
    protolambda authored
    * op-node: SystemConfig in derivation
    
    * op-node: reduce sys config test boilerplate
    
    * op-node: more readable loop to find L2 block with L1 origin we look for
    
    * op-node: change test addresses to not confuse with predeploys
    
    * op-node: system config field doc comments
    
    * op-node: fix lint
    
    * contracts-bedrock: Sys config contract and L2 contract updates (#3788)
    
    * contracts-bedrock: SystemConfig contract and L2 contract updates
    Co-authored-by: default avatarMark Tyneway <mark.tyneway@gmail.com>
    
    * contracts-bedrock: SystemConfig/L1Block batcherHash typing
    
    * contracts-bedrock: test updates for SystemConfig/L1Block type changes
    
    * contracts-bedrock: initialize SystemConfig
    
    * contracts-bedrock: batcher hash initialize arg
    
    * contracts-bedrock: all mutable sys config fields now initialize
    
    * contracts-bedrock: update gas-snapshot
    
    * contracts-bedrock: rename deployment system config
    
    Prevent name collisions between contracts
    
    * contracts-bedrock: regenerate storage layout
    
    * contracts-bedrock: lint
    
    * op-bindings: regenerate
    
    * op-node: fix test build
    
    * op-chain-ops: remove dead storage config
    
    * tests: fixup
    
    * tests: fix build
    
    * op-bindings,op-chain-ops,op-node: System config bindings and integration (#3789)
    
    * op-chain-ops,op-bindings,op-node: integrate system config
    
    * op-e2e: system config action tests (#3790)
    
    * op-e2e: system config action tests
    
    * op-e2e: decimals separator formatting fix
    Co-authored-by: default avatarMark Tyneway <mark.tyneway@gmail.com>
    
    * bindings
    
    * contracts-bedrock: update gas snapshot
    
    * contracts-bedrock: sys config owner address in hardhat
    
    * op-e2e: remove temporary function usage stubs
    
    * op-e2e: add action test descriptions for batcher key and gpo updates
    
    * op-node: fix fuzzing test, batcher hash must be padded
    
    * reset go.work
    
    * update go mod/sum
    
    * remove dead import
    
    * remove more dead config
    Co-authored-by: default avatarMark Tyneway <mark.tyneway@gmail.com>
    Co-authored-by: default avatarMatthew Slipper <me@matthewslipper.com>
    0b40e612
l1_traversal_test.go 4.3 KB
package derive

import (
	"context"
	"errors"
	"io"
	"math/rand"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/ethereum/go-ethereum"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/log"

	"github.com/ethereum-optimism/optimism/op-node/eth"
	"github.com/ethereum-optimism/optimism/op-node/rollup"
	"github.com/ethereum-optimism/optimism/op-node/testlog"
	"github.com/ethereum-optimism/optimism/op-node/testutils"
)

// TestL1TraversalNext tests that the `Next` function only returns
// a block reference once and then properly returns io.EOF afterwards
func TestL1TraversalNext(t *testing.T) {
	rng := rand.New(rand.NewSource(1234))
	a := testutils.RandomBlockRef(rng)
	// Load up the initial state with a reset
	l1Cfg := eth.SystemConfig{
		BatcherAddr: testutils.RandomAddress(rng),
		Overhead:    [32]byte{42},
		Scalar:      [32]byte{69},
	}
	sysCfgAddr := testutils.RandomAddress(rng)
	cfg := &rollup.Config{
		Genesis:               rollup.Genesis{SystemConfig: l1Cfg},
		L1SystemConfigAddress: sysCfgAddr,
	}
	tr := NewL1Traversal(testlog.Logger(t, log.LvlError), cfg, nil)

	_ = tr.Reset(context.Background(), a, l1Cfg)

	// First call should always succeed
	ref, err := tr.NextL1Block(context.Background())
	require.Nil(t, err)
	require.Equal(t, a, ref)

	// Subsequent calls should return io.EOF
	ref, err = tr.NextL1Block(context.Background())
	require.Equal(t, eth.L1BlockRef{}, ref)
	require.Equal(t, io.EOF, err)

	ref, err = tr.NextL1Block(context.Background())
	require.Equal(t, eth.L1BlockRef{}, ref)
	require.Equal(t, io.EOF, err)
}

// TestL1TraversalAdvance tests that the `Advance` function properly
// handles different error cases and returns the expected block ref
// if there is no error.
func TestL1TraversalAdvance(t *testing.T) {
	rng := rand.New(rand.NewSource(1234))
	a := testutils.RandomBlockRef(rng)
	b := testutils.NextRandomRef(rng, a)
	// x is at the same height as b but does not extend `a`
	x := testutils.RandomBlockRef(rng)
	x.Number = b.Number
	sysCfgAddr := testutils.RandomAddress(rng)

	tests := []struct {
		name         string
		startBlock   eth.L1BlockRef
		nextBlock    eth.L1BlockRef
		initialL1Cfg eth.SystemConfig
		l1Receipts   []*types.Receipt
		fetcherErr   error
		expectedErr  error
	}{
		{
			name:       "simple extension",
			startBlock: a,
			nextBlock:  b,
			initialL1Cfg: eth.SystemConfig{
				BatcherAddr: common.Address{11},
				Overhead:    [32]byte{22},
				Scalar:      [32]byte{33},
			},
			l1Receipts:  []*types.Receipt{},
			fetcherErr:  nil,
			expectedErr: nil,
		},
		{
			name:        "reorg",
			startBlock:  a,
			nextBlock:   x,
			fetcherErr:  nil,
			expectedErr: ErrReset,
		},
		{
			name:        "not found",
			startBlock:  a,
			nextBlock:   eth.L1BlockRef{},
			fetcherErr:  ethereum.NotFound,
			expectedErr: io.EOF,
		},
		{
			name:        "temporary error",
			startBlock:  a,
			nextBlock:   eth.L1BlockRef{},
			fetcherErr:  errors.New("interrupted connection"),
			expectedErr: ErrTemporary,
		},
		// TODO: add tests that cover the receipts to config data updates
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			src := &testutils.MockL1Source{}
			src.ExpectL1BlockRefByNumber(test.startBlock.Number+1, test.nextBlock, test.fetcherErr)
			info := &testutils.MockBlockInfo{
				InfoHash:       test.nextBlock.Hash,
				InfoParentHash: test.nextBlock.ParentHash,
				InfoNum:        test.nextBlock.Number,
				InfoTime:       test.nextBlock.Time,
				// TODO: don't need full L1 info in receipts fetching API maybe?
			}
			if test.l1Receipts != nil {
				src.ExpectFetchReceipts(test.nextBlock.Hash, info, test.l1Receipts, nil)
			}

			cfg := &rollup.Config{
				Genesis:               rollup.Genesis{SystemConfig: test.initialL1Cfg},
				L1SystemConfigAddress: sysCfgAddr,
			}
			tr := NewL1Traversal(testlog.Logger(t, log.LvlError), cfg, src)
			// Load up the initial state with a reset
			_ = tr.Reset(context.Background(), test.startBlock, test.initialL1Cfg)

			// Advance it + assert output
			err := tr.AdvanceL1Block(context.Background())
			require.ErrorIs(t, err, test.expectedErr)

			if test.expectedErr == nil {
				ref, err := tr.NextL1Block(context.Background())
				require.Nil(t, err)
				require.Equal(t, test.nextBlock, ref)
			}

			src.AssertExpectations(t)
		})
	}

}