Commit ab402c42 authored by Adrian Sutton's avatar Adrian Sutton Committed by GitHub

Merge pull request #8045 from ethereum-optimism/aj/remove-more-bindings

op-challenger: Use FaultDisputeGameContract to retrieve cannon local inputs
parents b36aae92 a3672dd4
......@@ -19,6 +19,8 @@ const (
methodStatus = "status"
methodClaimCount = "claimDataLen"
methodClaim = "claimData"
methodL1Head = "l1Head"
methodProposals = "proposals"
)
type FaultDisputeGameContract struct {
......@@ -26,6 +28,12 @@ type FaultDisputeGameContract struct {
contract *batching.BoundContract
}
type Proposal struct {
Index *big.Int
L2BlockNumber *big.Int
OutputRoot common.Hash
}
func NewFaultDisputeGameContract(addr common.Address, caller *batching.MultiCaller) (*FaultDisputeGameContract, error) {
fdgAbi, err := bindings.FaultDisputeGameMetaData.GetAbi()
if err != nil {
......@@ -62,6 +70,27 @@ func (f *FaultDisputeGameContract) GetAbsolutePrestateHash(ctx context.Context)
return result.GetHash(0), nil
}
func (f *FaultDisputeGameContract) GetL1Head(ctx context.Context) (common.Hash, error) {
result, err := f.multiCaller.SingleCall(ctx, batching.BlockLatest, f.contract.Call(methodL1Head))
if err != nil {
return common.Hash{}, fmt.Errorf("failed to fetch L1 head: %w", err)
}
return result.GetHash(0), nil
}
// GetProposals returns the agreed and disputed proposals
func (f *FaultDisputeGameContract) GetProposals(ctx context.Context) (Proposal, Proposal, error) {
result, err := f.multiCaller.SingleCall(ctx, batching.BlockLatest, f.contract.Call(methodProposals))
if err != nil {
return Proposal{}, Proposal{}, fmt.Errorf("failed to fetch proposals: %w", err)
}
var agreed, disputed Proposal
result.GetStruct(0, &agreed)
result.GetStruct(1, &disputed)
return agreed, disputed, nil
}
func (f *FaultDisputeGameContract) GetStatus(ctx context.Context) (gameTypes.GameStatus, error) {
result, err := f.multiCaller.SingleCall(ctx, batching.BlockLatest, f.contract.Call(methodStatus))
if err != nil {
......
......@@ -60,6 +60,13 @@ func TestSimpleGetters(t *testing.T) {
return game.GetClaimCount(context.Background())
},
},
{
method: methodL1Head,
result: common.Hash{0xdd, 0xbb},
call: func(game *FaultDisputeGameContract) (any, error) {
return game.GetL1Head(context.Background())
},
},
}
for _, test := range tests {
test := test
......@@ -77,6 +84,33 @@ func TestSimpleGetters(t *testing.T) {
}
}
func TestGetProposals(t *testing.T) {
stubRpc, game := setup(t)
agreedIndex := big.NewInt(5)
agreedBlockNum := big.NewInt(6)
agreedRoot := common.Hash{0xaa}
disputedIndex := big.NewInt(7)
disputedBlockNum := big.NewInt(8)
disputedRoot := common.Hash{0xdd}
agreed := Proposal{
Index: agreedIndex,
L2BlockNumber: agreedBlockNum,
OutputRoot: agreedRoot,
}
disputed := Proposal{
Index: disputedIndex,
L2BlockNumber: disputedBlockNum,
OutputRoot: disputedRoot,
}
stubRpc.SetResponse(methodProposals, batching.BlockLatest, []interface{}{}, []interface{}{
agreed, disputed,
})
actualAgreed, actualDisputed, err := game.GetProposals(context.Background())
require.NoError(t, err)
require.Equal(t, agreed, actualAgreed)
require.Equal(t, disputed, actualDisputed)
}
func TestGetClaim(t *testing.T) {
stubRpc, game := setup(t)
idx := big.NewInt(2)
......
......@@ -34,7 +34,7 @@ type GamePlayer struct {
status gameTypes.GameStatus
}
type resourceCreator func(addr common.Address, gameDepth uint64, dir string) (types.TraceProvider, types.OracleUpdater, error)
type resourceCreator func(addr common.Address, contract *contracts.FaultDisputeGameContract, gameDepth uint64, dir string) (types.TraceProvider, types.OracleUpdater, error)
func NewGamePlayer(
ctx context.Context,
......@@ -77,7 +77,7 @@ func NewGamePlayer(
return nil, fmt.Errorf("failed to fetch the game depth: %w", err)
}
provider, updater, err := creator(addr, gameDepth, dir)
provider, updater, err := creator(addr, loader, gameDepth, dir)
if err != nil {
return nil, fmt.Errorf("failed to create trace provider: %w", err)
}
......
......@@ -5,6 +5,7 @@ import (
"fmt"
"github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/alphabet"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/cannon"
faultTypes "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
......@@ -36,8 +37,8 @@ func RegisterGameTypes(
client *ethclient.Client,
) {
if cfg.TraceTypeEnabled(config.TraceTypeCannon) {
resourceCreator := func(addr common.Address, gameDepth uint64, dir string) (faultTypes.TraceProvider, faultTypes.OracleUpdater, error) {
provider, err := cannon.NewTraceProvider(ctx, logger, m, cfg, client, dir, addr, gameDepth)
resourceCreator := func(addr common.Address, contract *contracts.FaultDisputeGameContract, gameDepth uint64, dir string) (faultTypes.TraceProvider, faultTypes.OracleUpdater, error) {
provider, err := cannon.NewTraceProvider(ctx, logger, m, cfg, contract, dir, gameDepth)
if err != nil {
return nil, nil, fmt.Errorf("create cannon trace provider: %w", err)
}
......@@ -53,7 +54,7 @@ func RegisterGameTypes(
registry.RegisterGameType(cannonGameType, playerCreator)
}
if cfg.TraceTypeEnabled(config.TraceTypeAlphabet) {
resourceCreator := func(addr common.Address, gameDepth uint64, dir string) (faultTypes.TraceProvider, faultTypes.OracleUpdater, error) {
resourceCreator := func(addr common.Address, contract *contracts.FaultDisputeGameContract, gameDepth uint64, dir string) (faultTypes.TraceProvider, faultTypes.OracleUpdater, error) {
provider := alphabet.NewTraceProvider(cfg.AlphabetTrace, gameDepth)
updater := alphabet.NewOracleUpdater(logger)
return provider, updater, nil
......
......@@ -5,8 +5,7 @@ import (
"fmt"
"math/big"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts"
"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
)
......@@ -25,26 +24,20 @@ type L2DataSource interface {
}
type GameInputsSource interface {
L1Head(opts *bind.CallOpts) ([32]byte, error)
Proposals(opts *bind.CallOpts) (struct {
Starting bindings.IFaultDisputeGameOutputProposal
Disputed bindings.IFaultDisputeGameOutputProposal
}, error)
GetL1Head(ctx context.Context) (common.Hash, error)
GetProposals(ctx context.Context) (agreed contracts.Proposal, disputed contracts.Proposal, err error)
}
func fetchLocalInputs(ctx context.Context, gameAddr common.Address, caller GameInputsSource, l2Client L2DataSource) (LocalGameInputs, error) {
opts := &bind.CallOpts{Context: ctx}
l1Head, err := caller.L1Head(opts)
func fetchLocalInputs(ctx context.Context, caller GameInputsSource, l2Client L2DataSource) (LocalGameInputs, error) {
l1Head, err := caller.GetL1Head(ctx)
if err != nil {
return LocalGameInputs{}, fmt.Errorf("fetch L1 head for game %v: %w", gameAddr, err)
return LocalGameInputs{}, fmt.Errorf("fetch L1 head: %w", err)
}
proposals, err := caller.Proposals(opts)
agreedOutput, claimedOutput, err := caller.GetProposals(ctx)
if err != nil {
return LocalGameInputs{}, fmt.Errorf("fetch proposals: %w", err)
}
claimedOutput := proposals.Disputed
agreedOutput := proposals.Starting
agreedHeader, err := l2Client.HeaderByNumber(ctx, agreedOutput.L2BlockNumber)
if err != nil {
return LocalGameInputs{}, fmt.Errorf("fetch L2 block header %v: %w", agreedOutput.L2BlockNumber, err)
......
......@@ -5,9 +5,8 @@ import (
"math/big"
"testing"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/stretchr/testify/require"
......@@ -15,15 +14,14 @@ import (
func TestFetchLocalInputs(t *testing.T) {
ctx := context.Background()
gameAddr := common.Address{0xab}
l1Client := &mockGameInputsSource{
contract := &mockGameInputsSource{
l1Head: common.Hash{0xcc},
starting: bindings.IFaultDisputeGameOutputProposal{
starting: contracts.Proposal{
Index: big.NewInt(6),
L2BlockNumber: big.NewInt(2222),
OutputRoot: common.Hash{0xdd},
},
disputed: bindings.IFaultDisputeGameOutputProposal{
disputed: contracts.Proposal{
Index: big.NewInt(7),
L2BlockNumber: big.NewInt(3333),
OutputRoot: common.Hash{0xee},
......@@ -32,41 +30,32 @@ func TestFetchLocalInputs(t *testing.T) {
l2Client := &mockL2DataSource{
chainID: big.NewInt(88422),
header: ethtypes.Header{
Number: l1Client.starting.L2BlockNumber,
Number: contract.starting.L2BlockNumber,
},
}
inputs, err := fetchLocalInputs(ctx, gameAddr, l1Client, l2Client)
inputs, err := fetchLocalInputs(ctx, contract, l2Client)
require.NoError(t, err)
require.Equal(t, l1Client.l1Head, inputs.L1Head)
require.Equal(t, contract.l1Head, inputs.L1Head)
require.Equal(t, l2Client.header.Hash(), inputs.L2Head)
require.EqualValues(t, l1Client.starting.OutputRoot, inputs.L2OutputRoot)
require.EqualValues(t, l1Client.disputed.OutputRoot, inputs.L2Claim)
require.Equal(t, l1Client.disputed.L2BlockNumber, inputs.L2BlockNumber)
require.EqualValues(t, contract.starting.OutputRoot, inputs.L2OutputRoot)
require.EqualValues(t, contract.disputed.OutputRoot, inputs.L2Claim)
require.Equal(t, contract.disputed.L2BlockNumber, inputs.L2BlockNumber)
}
type mockGameInputsSource struct {
l1Head common.Hash
starting bindings.IFaultDisputeGameOutputProposal
disputed bindings.IFaultDisputeGameOutputProposal
starting contracts.Proposal
disputed contracts.Proposal
}
func (s *mockGameInputsSource) L1Head(opts *bind.CallOpts) ([32]byte, error) {
func (s *mockGameInputsSource) GetL1Head(_ context.Context) (common.Hash, error) {
return s.l1Head, nil
}
func (s *mockGameInputsSource) Proposals(opts *bind.CallOpts) (struct {
Starting bindings.IFaultDisputeGameOutputProposal
Disputed bindings.IFaultDisputeGameOutputProposal
}, error) {
return struct {
Starting bindings.IFaultDisputeGameOutputProposal
Disputed bindings.IFaultDisputeGameOutputProposal
}{
Starting: s.starting,
Disputed: s.disputed,
}, nil
func (s *mockGameInputsSource) GetProposals(_ context.Context) (contracts.Proposal, contracts.Proposal, error) {
return s.starting, s.disputed, nil
}
type mockL2DataSource struct {
......
......@@ -8,11 +8,10 @@ import (
"os"
"path/filepath"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
"github.com/ethereum-optimism/optimism/op-service/ioutil"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/ethclient"
......@@ -56,17 +55,13 @@ type CannonTraceProvider struct {
lastStep uint64
}
func NewTraceProvider(ctx context.Context, logger log.Logger, m CannonMetricer, cfg *config.Config, l1Client bind.ContractCaller, dir string, gameAddr common.Address, gameDepth uint64) (*CannonTraceProvider, error) {
func NewTraceProvider(ctx context.Context, logger log.Logger, m CannonMetricer, cfg *config.Config, gameContract *contracts.FaultDisputeGameContract, dir string, gameDepth uint64) (*CannonTraceProvider, error) {
l2Client, err := ethclient.DialContext(ctx, cfg.CannonL2)
if err != nil {
return nil, fmt.Errorf("dial l2 client %v: %w", cfg.CannonL2, err)
}
defer l2Client.Close() // Not needed after fetching the inputs
gameCaller, err := bindings.NewFaultDisputeGameCaller(gameAddr, l1Client)
if err != nil {
return nil, fmt.Errorf("create caller for game %v: %w", gameAddr, err)
}
localInputs, err := fetchLocalInputs(ctx, gameAddr, gameCaller, l2Client)
localInputs, err := fetchLocalInputs(ctx, gameContract, l2Client)
if err != nil {
return nil, fmt.Errorf("fetch local game inputs: %w", err)
}
......
......@@ -4,13 +4,15 @@ import (
"context"
"path/filepath"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/cannon"
"github.com/ethereum-optimism/optimism/op-challenger/metrics"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger"
"github.com/ethereum-optimism/optimism/op-node/rollup"
"github.com/ethereum-optimism/optimism/op-service/sources/batching"
"github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
)
......@@ -32,7 +34,7 @@ func (g *CannonGameHelper) StartChallenger(ctx context.Context, rollupCfg *rollu
return c
}
func (g *CannonGameHelper) CreateHonestActor(ctx context.Context, rollupCfg *rollup.Config, l2Genesis *core.Genesis, l1Client bind.ContractCaller, l1Endpoint string, l2Endpoint string, options ...challenger.Option) *HonestHelper {
func (g *CannonGameHelper) CreateHonestActor(ctx context.Context, rollupCfg *rollup.Config, l2Genesis *core.Genesis, l1Client *ethclient.Client, l1Endpoint string, l2Endpoint string, options ...challenger.Option) *HonestHelper {
opts := []challenger.Option{
challenger.WithCannon(g.t, rollupCfg, l2Genesis, l2Endpoint),
challenger.WithFactoryAddress(g.factoryAddr),
......@@ -42,7 +44,9 @@ func (g *CannonGameHelper) CreateHonestActor(ctx context.Context, rollupCfg *rol
cfg := challenger.NewChallengerConfig(g.t, l1Endpoint, opts...)
logger := testlog.Logger(g.t, log.LvlInfo).New("role", "CorrectTrace")
maxDepth := g.MaxDepth(ctx)
provider, err := cannon.NewTraceProvider(ctx, logger, metrics.NoopMetrics, cfg, l1Client, filepath.Join(cfg.Datadir, "honest"), g.addr, uint64(maxDepth))
gameContract, err := contracts.NewFaultDisputeGameContract(g.addr, batching.NewMultiCaller(l1Client.Client(), batching.DefaultBatchSize))
g.require.NoError(err, "Create game contract bindings")
provider, err := cannon.NewTraceProvider(ctx, logger, metrics.NoopMetrics, cfg, gameContract, filepath.Join(cfg.Datadir, "honest"), uint64(maxDepth))
g.require.NoError(err, "create cannon trace provider")
return &HonestHelper{
......
......@@ -117,3 +117,7 @@ func (c *CallResult) GetAddress(i int) common.Address {
func (c *CallResult) GetBigInt(i int) *big.Int {
return *abi.ConvertType(c.out[i], new(*big.Int)).(**big.Int)
}
func (c *CallResult) GetStruct(i int, target interface{}) {
abi.ConvertType(c.out[i], target)
}
......@@ -139,6 +139,24 @@ func TestCallResult_GetValues(t *testing.T) {
},
expected: big.NewInt(2398423),
},
{
name: "GetStruct",
getter: func(result *CallResult, i int) interface{} {
out := struct {
a *big.Int
b common.Hash
}{}
result.GetStruct(i, &out)
return out
},
expected: struct {
a *big.Int
b common.Hash
}{
a: big.NewInt(6),
b: common.Hash{0xee},
},
},
}
for _, test := range tests {
......
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