Commit 639363c2 authored by Adrian Sutton's avatar Adrian Sutton

op-challenger: Add BlockNumber method to OutputTraceProvider

Will allow the split provider to convert a claim position to the L2 block number.
Also remove duplication and improve tests.
parent 587999a7
......@@ -2,6 +2,7 @@ package outputs
import (
"context"
"errors"
"fmt"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
......@@ -13,8 +14,8 @@ import (
)
var (
GetStepDataErr = fmt.Errorf("GetStepData not supported")
AbsolutePreStateErr = fmt.Errorf("AbsolutePreState not supported")
ErrGetStepData = errors.New("GetStepData not supported")
ErrIndexTooBig = errors.New("trace index is greater than max uint64")
)
var _ types.TraceProvider = (*OutputTraceProvider)(nil)
......@@ -51,39 +52,40 @@ func NewTraceProviderFromInputs(logger log.Logger, rollupClient OutputRollupClie
}
}
func (o *OutputTraceProvider) Get(ctx context.Context, pos types.Position) (common.Hash, error) {
func (o *OutputTraceProvider) BlockNumber(pos types.Position) (uint64, error) {
traceIndex := pos.TraceIndex(int(o.gameDepth))
if !traceIndex.IsUint64() {
return common.Hash{}, fmt.Errorf("trace index %v is greater than max uint64", traceIndex)
return 0, fmt.Errorf("%w: %v", ErrIndexTooBig, traceIndex)
}
outputBlock := traceIndex.Uint64() + o.prestateBlock + 1
if outputBlock > o.poststateBlock {
outputBlock = o.poststateBlock
}
output, err := o.rollupClient.OutputAtBlock(ctx, outputBlock)
return outputBlock, nil
}
func (o *OutputTraceProvider) Get(ctx context.Context, pos types.Position) (common.Hash, error) {
outputBlock, err := o.BlockNumber(pos)
if err != nil {
o.logger.Error("Failed to fetch output", "blockNumber", outputBlock, "err", err)
return common.Hash{}, err
}
return common.Hash(output.OutputRoot), nil
return o.outputAtBlock(ctx, outputBlock)
}
// AbsolutePreStateCommitment returns the absolute prestate at the configured prestateBlock.
func (o *OutputTraceProvider) AbsolutePreStateCommitment(ctx context.Context) (hash common.Hash, err error) {
output, err := o.rollupClient.OutputAtBlock(ctx, o.prestateBlock)
if err != nil {
o.logger.Error("Failed to fetch output", "blockNumber", o.prestateBlock, "err", err)
return common.Hash{}, err
}
return common.Hash(output.OutputRoot), nil
return o.outputAtBlock(ctx, o.prestateBlock)
}
// AbsolutePreState is not supported in the [OutputTraceProvider].
func (o *OutputTraceProvider) AbsolutePreState(ctx context.Context) (preimage []byte, err error) {
return nil, AbsolutePreStateErr
// GetStepData is not supported in the [OutputTraceProvider].
func (o *OutputTraceProvider) GetStepData(_ context.Context, _ types.Position) (prestate []byte, proofData []byte, preimageData *types.PreimageOracleData, err error) {
return nil, nil, nil, ErrGetStepData
}
// GetStepData is not supported in the [OutputTraceProvider].
func (o *OutputTraceProvider) GetStepData(ctx context.Context, pos types.Position) (prestate []byte, proofData []byte, preimageData *types.PreimageOracleData, err error) {
return nil, nil, nil, GetStepDataErr
func (o *OutputTraceProvider) outputAtBlock(ctx context.Context, block uint64) (common.Hash, error) {
output, err := o.rollupClient.OutputAtBlock(ctx, block)
if err != nil {
return common.Hash{}, fmt.Errorf("failed to fetch output at block %v: %w", o.prestateBlock, err)
}
return common.Hash(output.OutputRoot), nil
}
......@@ -2,6 +2,7 @@ package outputs
import (
"context"
"errors"
"fmt"
"math/big"
"testing"
......@@ -9,7 +10,6 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-service/eth"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/stretchr/testify/require"
......@@ -22,40 +22,29 @@ var (
prestateOutputRoot = common.HexToHash("0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
firstOutputRoot = common.HexToHash("0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")
poststateOutputRoot = common.HexToHash("0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc")
errNoOutputAtBlock = errors.New("no output at block")
)
func TestGet(t *testing.T) {
t.Run("PrePrestateErrors", func(t *testing.T) {
provider, _ := setupWithTestData(t, 0, poststateBlock)
_, err := provider.Get(context.Background(), types.NewPosition(1, common.Big0))
require.ErrorAs(t, fmt.Errorf("no output at block %d", 1), &err)
})
t.Run("ErrorsTraceIndexOutOfBounds", func(t *testing.T) {
deepGame := uint64(64)
deepGame := uint64(164)
provider, _ := setupWithTestData(t, prestateBlock, poststateBlock, deepGame)
pos := types.NewPosition(0, big.NewInt(0))
_, err := provider.Get(context.Background(), pos)
require.ErrorAs(t, fmt.Errorf("trace index %v is greater than max uint64", pos.TraceIndex(int(deepGame))), &err)
})
t.Run("MisconfiguredPoststateErrors", func(t *testing.T) {
provider, _ := setupWithTestData(t, 0, 0)
_, err := provider.Get(context.Background(), types.NewPosition(1, common.Big0))
require.ErrorAs(t, fmt.Errorf("no output at block %d", 0), &err)
require.ErrorIs(t, err, ErrIndexTooBig)
})
t.Run("FirstBlockAfterPrestate", func(t *testing.T) {
provider, _ := setupWithTestData(t, prestateBlock, poststateBlock)
value, err := provider.Get(context.Background(), types.NewPositionFromGIndex(big.NewInt(128)))
value, err := provider.Get(context.Background(), types.NewPosition(int(gameDepth), big.NewInt(0)))
require.NoError(t, err)
require.Equal(t, firstOutputRoot, value)
})
t.Run("MissingOutputAtBlock", func(t *testing.T) {
provider, _ := setupWithTestData(t, prestateBlock, poststateBlock)
_, err := provider.Get(context.Background(), types.NewPositionFromGIndex(big.NewInt(129)))
require.ErrorAs(t, fmt.Errorf("no output at block %d", prestateBlock+2), &err)
_, err := provider.Get(context.Background(), types.NewPosition(int(gameDepth), big.NewInt(1)))
require.ErrorIs(t, err, errNoOutputAtBlock)
})
t.Run("PostStateBlock", func(t *testing.T) {
......@@ -73,12 +62,46 @@ func TestGet(t *testing.T) {
})
}
func TestGetBlockNumber(t *testing.T) {
tests := []struct {
name string
pos types.Position
expected uint64
}{
{"FirstBlockAfterPrestate", types.NewPosition(int(gameDepth), big.NewInt(0)), prestateBlock + 1},
{"PostStateBlock", types.NewPositionFromGIndex(big.NewInt(228)), poststateBlock},
{"AfterPostStateBlock", types.NewPositionFromGIndex(big.NewInt(229)), poststateBlock},
{"Root", types.NewPositionFromGIndex(big.NewInt(1)), poststateBlock},
{"MiddleNode1", types.NewPosition(int(gameDepth-1), big.NewInt(2)), 106},
{"MiddleNode2", types.NewPosition(int(gameDepth-1), big.NewInt(3)), 108},
{"Leaf1", types.NewPosition(int(gameDepth), big.NewInt(1)), prestateBlock + 2},
{"Leaf2", types.NewPosition(int(gameDepth), big.NewInt(2)), prestateBlock + 3},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
provider, _ := setupWithTestData(t, prestateBlock, poststateBlock)
actual, err := provider.BlockNumber(test.pos)
require.NoError(t, err)
require.Equal(t, test.expected, actual)
})
}
t.Run("ErrorsTraceIndexOutOfBounds", func(t *testing.T) {
deepGame := uint64(164)
provider, _ := setupWithTestData(t, prestateBlock, poststateBlock, deepGame)
pos := types.NewPosition(0, big.NewInt(0))
_, err := provider.BlockNumber(pos)
require.ErrorIs(t, err, ErrIndexTooBig)
})
}
func TestAbsolutePreStateCommitment(t *testing.T) {
t.Run("FailedToFetchOutput", func(t *testing.T) {
provider, rollupClient := setupWithTestData(t, prestateBlock, poststateBlock)
rollupClient.errorsOnPrestateFetch = true
_, err := provider.AbsolutePreStateCommitment(context.Background())
require.ErrorAs(t, fmt.Errorf("no output at block %d", prestateBlock), &err)
require.ErrorIs(t, err, errNoOutputAtBlock)
})
t.Run("ReturnsCorrectPrestateOutput", func(t *testing.T) {
......@@ -92,13 +115,7 @@ func TestAbsolutePreStateCommitment(t *testing.T) {
func TestGetStepData(t *testing.T) {
provider, _ := setupWithTestData(t, prestateBlock, poststateBlock)
_, _, _, err := provider.GetStepData(context.Background(), types.NewPosition(1, common.Big0))
require.ErrorIs(t, err, GetStepDataErr)
}
func TestAbsolutePreState(t *testing.T) {
provider, _ := setupWithTestData(t, prestateBlock, poststateBlock)
_, err := provider.AbsolutePreState(context.Background())
require.ErrorIs(t, err, AbsolutePreStateErr)
require.ErrorIs(t, err, ErrGetStepData)
}
func setupWithTestData(t *testing.T, prestateBlock, poststateBlock uint64, customGameDepth ...uint64) (*OutputTraceProvider, *stubRollupClient) {
......@@ -133,10 +150,10 @@ type stubRollupClient struct {
outputs map[uint64]*eth.OutputResponse
}
func (s *stubRollupClient) OutputAtBlock(ctx context.Context, blockNum uint64) (*eth.OutputResponse, error) {
func (s *stubRollupClient) OutputAtBlock(_ context.Context, blockNum uint64) (*eth.OutputResponse, error) {
output, ok := s.outputs[blockNum]
if !ok || s.errorsOnPrestateFetch {
return nil, fmt.Errorf("no output at block %d", blockNum)
return nil, fmt.Errorf("%w: %d", errNoOutputAtBlock, blockNum)
}
return output, nil
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment