Commit 113e2744 authored by Adrian Sutton's avatar Adrian Sutton Committed by GitHub

op-challenger, op-dispute-mon: Support both old and new versions of the...

op-challenger, op-dispute-mon: Support both old and new versions of the dispute game contracts (#10302)

* op-challenger, op-dispute-mon: Support both old and new versions of the dispute game contracts.

* op-challenger: Update fault dispute game contract tests to cover multiple versions.
parent ba174f4d
package main package main
import ( import (
"context"
"fmt" "fmt"
"github.com/ethereum-optimism/optimism/op-challenger/config" "github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-challenger/flags" "github.com/ethereum-optimism/optimism/op-challenger/flags"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts"
contractMetrics "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics"
"github.com/ethereum-optimism/optimism/op-challenger/tools" "github.com/ethereum-optimism/optimism/op-challenger/tools"
opservice "github.com/ethereum-optimism/optimism/op-service" opservice "github.com/ethereum-optimism/optimism/op-service"
oplog "github.com/ethereum-optimism/optimism/op-service/log" oplog "github.com/ethereum-optimism/optimism/op-service/log"
"github.com/ethereum-optimism/optimism/op-service/sources/batching"
"github.com/ethereum-optimism/optimism/op-service/txmgr" "github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
...@@ -38,7 +41,10 @@ func CreateGame(ctx *cli.Context) error { ...@@ -38,7 +41,10 @@ func CreateGame(ctx *cli.Context) error {
traceType := ctx.Uint64(TraceTypeFlag.Name) traceType := ctx.Uint64(TraceTypeFlag.Name)
l2BlockNum := ctx.Uint64(L2BlockNumFlag.Name) l2BlockNum := ctx.Uint64(L2BlockNumFlag.Name)
contract, txMgr, err := NewContractWithTxMgr[*contracts.DisputeGameFactoryContract](ctx, flags.FactoryAddressFlag.Name, contracts.NewDisputeGameFactoryContract) contract, txMgr, err := NewContractWithTxMgr[*contracts.DisputeGameFactoryContract](ctx, flags.FactoryAddressFlag.Name,
func(ctx context.Context, metricer contractMetrics.ContractMetricer, address common.Address, caller *batching.MultiCaller) (*contracts.DisputeGameFactoryContract, error) {
return contracts.NewDisputeGameFactoryContract(metricer, address, caller), nil
})
if err != nil { if err != nil {
return fmt.Errorf("failed to create dispute game factory bindings: %w", err) return fmt.Errorf("failed to create dispute game factory bindings: %w", err)
} }
......
...@@ -48,11 +48,14 @@ func ListClaims(ctx *cli.Context) error { ...@@ -48,11 +48,14 @@ func ListClaims(ctx *cli.Context) error {
defer l1Client.Close() defer l1Client.Close()
caller := batching.NewMultiCaller(l1Client.Client(), batching.DefaultBatchSize) caller := batching.NewMultiCaller(l1Client.Client(), batching.DefaultBatchSize)
contract := contracts.NewFaultDisputeGameContract(metrics.NoopContractMetrics, gameAddr, caller) contract, err := contracts.NewFaultDisputeGameContract(ctx.Context, metrics.NoopContractMetrics, gameAddr, caller)
if err != nil {
return err
}
return listClaims(ctx.Context, contract) return listClaims(ctx.Context, contract)
} }
func listClaims(ctx context.Context, game *contracts.FaultDisputeGameContract) error { func listClaims(ctx context.Context, game contracts.FaultDisputeGameContract) error {
maxDepth, err := game.GetMaxGameDepth(ctx) maxDepth, err := game.GetMaxGameDepth(ctx)
if err != nil { if err != nil {
return fmt.Errorf("failed to retrieve max depth: %w", err) return fmt.Errorf("failed to retrieve max depth: %w", err)
......
...@@ -66,7 +66,10 @@ func listGames(ctx context.Context, caller *batching.MultiCaller, factory *contr ...@@ -66,7 +66,10 @@ func listGames(ctx context.Context, caller *batching.MultiCaller, factory *contr
infos := make([]*gameInfo, len(games)) infos := make([]*gameInfo, len(games))
var wg sync.WaitGroup var wg sync.WaitGroup
for idx, game := range games { for idx, game := range games {
gameContract := contracts.NewFaultDisputeGameContract(metrics.NoopContractMetrics, game.Proxy, caller) gameContract, err := contracts.NewFaultDisputeGameContract(ctx, metrics.NoopContractMetrics, game.Proxy, caller)
if err != nil {
return fmt.Errorf("failed to create dispute game contract: %w", err)
}
info := gameInfo{GameMetadata: game} info := gameInfo{GameMetadata: game}
infos[idx] = &info infos[idx] = &info
gameProxy := game.Proxy gameProxy := game.Proxy
......
...@@ -46,7 +46,7 @@ func Move(ctx *cli.Context) error { ...@@ -46,7 +46,7 @@ func Move(ctx *cli.Context) error {
return fmt.Errorf("both attack and defense flags cannot be set") return fmt.Errorf("both attack and defense flags cannot be set")
} }
contract, txMgr, err := NewContractWithTxMgr[*contracts.FaultDisputeGameContract](ctx, GameAddressFlag.Name, contracts.NewFaultDisputeGameContract) contract, txMgr, err := NewContractWithTxMgr[contracts.FaultDisputeGameContract](ctx, GameAddressFlag.Name, contracts.NewFaultDisputeGameContract)
if err != nil { if err != nil {
return fmt.Errorf("failed to create dispute game bindings: %w", err) return fmt.Errorf("failed to create dispute game bindings: %w", err)
} }
......
...@@ -12,7 +12,7 @@ import ( ...@@ -12,7 +12,7 @@ import (
) )
func Resolve(ctx *cli.Context) error { func Resolve(ctx *cli.Context) error {
contract, txMgr, err := NewContractWithTxMgr[*contracts.FaultDisputeGameContract](ctx, GameAddressFlag.Name, contracts.NewFaultDisputeGameContract) contract, txMgr, err := NewContractWithTxMgr[contracts.FaultDisputeGameContract](ctx, GameAddressFlag.Name, contracts.NewFaultDisputeGameContract)
if err != nil { if err != nil {
return fmt.Errorf("failed to create dispute game bindings: %w", err) return fmt.Errorf("failed to create dispute game bindings: %w", err)
} }
......
package main package main
import ( import (
"context"
"fmt" "fmt"
"github.com/ethereum-optimism/optimism/op-challenger/flags" "github.com/ethereum-optimism/optimism/op-challenger/flags"
...@@ -14,7 +15,7 @@ import ( ...@@ -14,7 +15,7 @@ import (
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
type ContractCreator[T any] func(contractMetrics.ContractMetricer, common.Address, *batching.MultiCaller) T type ContractCreator[T any] func(context.Context, contractMetrics.ContractMetricer, common.Address, *batching.MultiCaller) (T, error)
// NewContractWithTxMgr creates a new contract and a transaction manager. // NewContractWithTxMgr creates a new contract and a transaction manager.
func NewContractWithTxMgr[T any](ctx *cli.Context, flagName string, creator ContractCreator[T]) (T, txmgr.TxManager, error) { func NewContractWithTxMgr[T any](ctx *cli.Context, flagName string, creator ContractCreator[T]) (T, txmgr.TxManager, error) {
...@@ -40,7 +41,10 @@ func newContractFromCLI[T any](ctx *cli.Context, flagName string, caller *batchi ...@@ -40,7 +41,10 @@ func newContractFromCLI[T any](ctx *cli.Context, flagName string, caller *batchi
return contract, err return contract, err
} }
created := creator(contractMetrics.NoopContractMetrics, gameAddr, caller) created, err := creator(ctx.Context, contractMetrics.NoopContractMetrics, gameAddr, caller)
if err != nil {
return contract, fmt.Errorf("failed to create contract bindings: %w", err)
}
return created, nil return created, nil
} }
......
[
{
"inputs": [
{
"internalType": "GameType",
"name": "_gameType",
"type": "uint32"
},
{
"internalType": "Claim",
"name": "_absolutePrestate",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "_maxGameDepth",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_splitDepth",
"type": "uint256"
},
{
"internalType": "Duration",
"name": "_gameDuration",
"type": "uint64"
},
{
"internalType": "contract IBigStepper",
"name": "_vm",
"type": "address"
},
{
"internalType": "contract IDelayedWETH",
"name": "_weth",
"type": "address"
},
{
"internalType": "contract IAnchorStateRegistry",
"name": "_anchorStateRegistry",
"type": "address"
},
{
"internalType": "uint256",
"name": "_l2ChainId",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"stateMutability": "payable",
"type": "fallback"
},
{
"stateMutability": "payable",
"type": "receive"
},
{
"inputs": [],
"name": "absolutePrestate",
"outputs": [
{
"internalType": "Claim",
"name": "absolutePrestate_",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_ident",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_execLeafIdx",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_partOffset",
"type": "uint256"
}
],
"name": "addLocalData",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_parentIndex",
"type": "uint256"
},
{
"internalType": "Claim",
"name": "_claim",
"type": "bytes32"
}
],
"name": "attack",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_recipient",
"type": "address"
}
],
"name": "claimCredit",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "claimData",
"outputs": [
{
"internalType": "uint32",
"name": "parentIndex",
"type": "uint32"
},
{
"internalType": "address",
"name": "counteredBy",
"type": "address"
},
{
"internalType": "address",
"name": "claimant",
"type": "address"
},
{
"internalType": "uint128",
"name": "bond",
"type": "uint128"
},
{
"internalType": "Claim",
"name": "claim",
"type": "bytes32"
},
{
"internalType": "Position",
"name": "position",
"type": "uint128"
},
{
"internalType": "Clock",
"name": "clock",
"type": "uint128"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "claimDataLen",
"outputs": [
{
"internalType": "uint256",
"name": "len_",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "createdAt",
"outputs": [
{
"internalType": "Timestamp",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "credit",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_parentIndex",
"type": "uint256"
},
{
"internalType": "Claim",
"name": "_claim",
"type": "bytes32"
}
],
"name": "defend",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "extraData",
"outputs": [
{
"internalType": "bytes",
"name": "extraData_",
"type": "bytes"
}
],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [],
"name": "gameData",
"outputs": [
{
"internalType": "GameType",
"name": "gameType_",
"type": "uint32"
},
{
"internalType": "Claim",
"name": "rootClaim_",
"type": "bytes32"
},
{
"internalType": "bytes",
"name": "extraData_",
"type": "bytes"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "gameDuration",
"outputs": [
{
"internalType": "Duration",
"name": "gameDuration_",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "gameType",
"outputs": [
{
"internalType": "GameType",
"name": "gameType_",
"type": "uint32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "Position",
"name": "_position",
"type": "uint128"
}
],
"name": "getRequiredBond",
"outputs": [
{
"internalType": "uint256",
"name": "requiredBond_",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "initialize",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "l1Head",
"outputs": [
{
"internalType": "Hash",
"name": "l1Head_",
"type": "bytes32"
}
],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [],
"name": "l2BlockNumber",
"outputs": [
{
"internalType": "uint256",
"name": "l2BlockNumber_",
"type": "uint256"
}
],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [],
"name": "l2ChainId",
"outputs": [
{
"internalType": "uint256",
"name": "l2ChainId_",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "maxGameDepth",
"outputs": [
{
"internalType": "uint256",
"name": "maxGameDepth_",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_challengeIndex",
"type": "uint256"
},
{
"internalType": "Claim",
"name": "_claim",
"type": "bytes32"
},
{
"internalType": "bool",
"name": "_isAttack",
"type": "bool"
}
],
"name": "move",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "resolve",
"outputs": [
{
"internalType": "enum GameStatus",
"name": "status_",
"type": "uint8"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_claimIndex",
"type": "uint256"
}
],
"name": "resolveClaim",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "resolvedAt",
"outputs": [
{
"internalType": "Timestamp",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "rootClaim",
"outputs": [
{
"internalType": "Claim",
"name": "rootClaim_",
"type": "bytes32"
}
],
"stateMutability": "pure",
"type": "function"
},
{
"inputs": [],
"name": "splitDepth",
"outputs": [
{
"internalType": "uint256",
"name": "splitDepth_",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "startingBlockNumber",
"outputs": [
{
"internalType": "uint256",
"name": "startingBlockNumber_",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "startingOutputRoot",
"outputs": [
{
"internalType": "Hash",
"name": "root",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "l2BlockNumber",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "startingRootHash",
"outputs": [
{
"internalType": "Hash",
"name": "startingRootHash_",
"type": "bytes32"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "status",
"outputs": [
{
"internalType": "enum GameStatus",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_claimIndex",
"type": "uint256"
},
{
"internalType": "bool",
"name": "_isAttack",
"type": "bool"
},
{
"internalType": "bytes",
"name": "_stateData",
"type": "bytes"
},
{
"internalType": "bytes",
"name": "_proof",
"type": "bytes"
}
],
"name": "step",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "version",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "vm",
"outputs": [
{
"internalType": "contract IBigStepper",
"name": "vm_",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "weth",
"outputs": [
{
"internalType": "contract IDelayedWETH",
"name": "weth_",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "uint256",
"name": "parentIndex",
"type": "uint256"
},
{
"indexed": true,
"internalType": "Claim",
"name": "claim",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "claimant",
"type": "address"
}
],
"name": "Move",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "enum GameStatus",
"name": "status",
"type": "uint8"
}
],
"name": "Resolved",
"type": "event"
},
{
"inputs": [],
"name": "AlreadyInitialized",
"type": "error"
},
{
"inputs": [],
"name": "AnchorRootNotFound",
"type": "error"
},
{
"inputs": [],
"name": "BondTransferFailed",
"type": "error"
},
{
"inputs": [],
"name": "CannotDefendRootClaim",
"type": "error"
},
{
"inputs": [],
"name": "ClaimAboveSplit",
"type": "error"
},
{
"inputs": [],
"name": "ClaimAlreadyExists",
"type": "error"
},
{
"inputs": [],
"name": "ClaimAlreadyResolved",
"type": "error"
},
{
"inputs": [],
"name": "ClockNotExpired",
"type": "error"
},
{
"inputs": [],
"name": "ClockTimeExceeded",
"type": "error"
},
{
"inputs": [],
"name": "DuplicateStep",
"type": "error"
},
{
"inputs": [],
"name": "GameDepthExceeded",
"type": "error"
},
{
"inputs": [],
"name": "GameNotInProgress",
"type": "error"
},
{
"inputs": [],
"name": "IncorrectBondAmount",
"type": "error"
},
{
"inputs": [],
"name": "InvalidLocalIdent",
"type": "error"
},
{
"inputs": [],
"name": "InvalidParent",
"type": "error"
},
{
"inputs": [],
"name": "InvalidPrestate",
"type": "error"
},
{
"inputs": [],
"name": "InvalidSplitDepth",
"type": "error"
},
{
"inputs": [],
"name": "NoCreditToClaim",
"type": "error"
},
{
"inputs": [],
"name": "OutOfOrderResolution",
"type": "error"
},
{
"inputs": [
{
"internalType": "Claim",
"name": "rootClaim",
"type": "bytes32"
}
],
"name": "UnexpectedRootClaim",
"type": "error"
},
{
"inputs": [],
"name": "ValidStep",
"type": "error"
}
]
\ No newline at end of file
package contracts package contracts
import ( import (
"bytes"
"context" "context"
"errors" "errors"
"fmt" "fmt"
"math" "math"
"math/big" "math/big"
"strings"
"time" "time"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics" "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics"
...@@ -15,6 +17,7 @@ import ( ...@@ -15,6 +17,7 @@ import (
"github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock" "github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock"
"github.com/ethereum-optimism/optimism/op-service/txmgr" "github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum-optimism/optimism/packages/contracts-bedrock/snapshots" "github.com/ethereum-optimism/optimism/packages/contracts-bedrock/snapshots"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
) )
...@@ -22,6 +25,7 @@ import ( ...@@ -22,6 +25,7 @@ import (
var maxChildChecks = big.NewInt(512) var maxChildChecks = big.NewInt(512)
var ( var (
methodVersion = "version"
methodMaxClockDuration = "maxClockDuration" methodMaxClockDuration = "maxClockDuration"
methodMaxGameDepth = "maxGameDepth" methodMaxGameDepth = "maxGameDepth"
methodAbsolutePrestate = "absolutePrestate" methodAbsolutePrestate = "absolutePrestate"
...@@ -50,7 +54,7 @@ var ( ...@@ -50,7 +54,7 @@ var (
var ErrSimulationFailed = errors.New("tx simulation failed") var ErrSimulationFailed = errors.New("tx simulation failed")
type FaultDisputeGameContract struct { type FaultDisputeGameContractLatest struct {
metrics metrics.ContractMetricer metrics metrics.ContractMetricer
multiCaller *batching.MultiCaller multiCaller *batching.MultiCaller
contract *batching.BoundContract contract *batching.BoundContract
...@@ -61,20 +65,46 @@ type Proposal struct { ...@@ -61,20 +65,46 @@ type Proposal struct {
OutputRoot common.Hash OutputRoot common.Hash
} }
func NewFaultDisputeGameContract(metrics metrics.ContractMetricer, addr common.Address, caller *batching.MultiCaller) *FaultDisputeGameContract { func NewFaultDisputeGameContract(ctx context.Context, metrics metrics.ContractMetricer, addr common.Address, caller *batching.MultiCaller) (FaultDisputeGameContract, error) {
contractAbi := snapshots.LoadFaultDisputeGameABI() contractAbi := snapshots.LoadFaultDisputeGameABI()
return &FaultDisputeGameContract{ result, err := caller.SingleCall(ctx, rpcblock.Latest, batching.NewContractCall(contractAbi, addr, methodVersion))
metrics: metrics, if err != nil {
multiCaller: caller, return nil, fmt.Errorf("failed to retrieve version of dispute game %v: %w", addr, err)
contract: batching.NewBoundContract(contractAbi, addr), }
version := result.GetString(0)
if strings.HasPrefix(version, "0.8.") {
// Detected an older version of contracts, use a compatibility shim.
legacyAbi := mustParseAbi(faultDisputeGameAbi020)
return &FaultDisputeGameContract080{
FaultDisputeGameContractLatest: FaultDisputeGameContractLatest{
metrics: metrics,
multiCaller: caller,
contract: batching.NewBoundContract(legacyAbi, addr),
},
}, nil
} else {
return &FaultDisputeGameContractLatest{
metrics: metrics,
multiCaller: caller,
contract: batching.NewBoundContract(contractAbi, addr),
}, nil
}
}
func mustParseAbi(json []byte) *abi.ABI {
loaded, err := abi.JSON(bytes.NewReader(json))
if err != nil {
panic(err)
} }
return &loaded
} }
// GetBalance returns the total amount of ETH controlled by this contract. // GetBalance returns the total amount of ETH controlled by this contract.
// Note that the ETH is actually held by the DelayedWETH contract which may be shared by multiple games. // Note that the ETH is actually held by the DelayedWETH contract which may be shared by multiple games.
// Returns the balance and the address of the contract that actually holds the balance. // Returns the balance and the address of the contract that actually holds the balance.
func (f *FaultDisputeGameContract) GetBalance(ctx context.Context, block rpcblock.Block) (*big.Int, common.Address, error) { func (f *FaultDisputeGameContractLatest) GetBalance(ctx context.Context, block rpcblock.Block) (*big.Int, common.Address, error) {
defer f.metrics.StartContractRequest("GetBalance")() defer f.metrics.StartContractRequest("GetBalance")()
result, err := f.multiCaller.SingleCall(ctx, block, f.contract.Call(methodWETH)) result, err := f.multiCaller.SingleCall(ctx, block, f.contract.Call(methodWETH))
if err != nil { if err != nil {
...@@ -90,7 +120,7 @@ func (f *FaultDisputeGameContract) GetBalance(ctx context.Context, block rpcbloc ...@@ -90,7 +120,7 @@ func (f *FaultDisputeGameContract) GetBalance(ctx context.Context, block rpcbloc
// GetBlockRange returns the block numbers of the absolute pre-state block (typically genesis or the bedrock activation block) // GetBlockRange returns the block numbers of the absolute pre-state block (typically genesis or the bedrock activation block)
// and the post-state block (that the proposed output root is for). // and the post-state block (that the proposed output root is for).
func (f *FaultDisputeGameContract) GetBlockRange(ctx context.Context) (prestateBlock uint64, poststateBlock uint64, retErr error) { func (f *FaultDisputeGameContractLatest) GetBlockRange(ctx context.Context) (prestateBlock uint64, poststateBlock uint64, retErr error) {
defer f.metrics.StartContractRequest("GetBlockRange")() defer f.metrics.StartContractRequest("GetBlockRange")()
results, err := f.multiCaller.Call(ctx, rpcblock.Latest, results, err := f.multiCaller.Call(ctx, rpcblock.Latest,
f.contract.Call(methodStartingBlockNumber), f.contract.Call(methodStartingBlockNumber),
...@@ -109,7 +139,7 @@ func (f *FaultDisputeGameContract) GetBlockRange(ctx context.Context) (prestateB ...@@ -109,7 +139,7 @@ func (f *FaultDisputeGameContract) GetBlockRange(ctx context.Context) (prestateB
} }
// GetGameMetadata returns the game's L1 head, L2 block number, root claim, status, and max clock duration. // GetGameMetadata returns the game's L1 head, L2 block number, root claim, status, and max clock duration.
func (f *FaultDisputeGameContract) GetGameMetadata(ctx context.Context, block rpcblock.Block) (common.Hash, uint64, common.Hash, gameTypes.GameStatus, uint64, error) { func (f *FaultDisputeGameContractLatest) GetGameMetadata(ctx context.Context, block rpcblock.Block) (common.Hash, uint64, common.Hash, gameTypes.GameStatus, uint64, error) {
defer f.metrics.StartContractRequest("GetGameMetadata")() defer f.metrics.StartContractRequest("GetGameMetadata")()
results, err := f.multiCaller.Call(ctx, block, results, err := f.multiCaller.Call(ctx, block,
f.contract.Call(methodL1Head), f.contract.Call(methodL1Head),
...@@ -134,7 +164,7 @@ func (f *FaultDisputeGameContract) GetGameMetadata(ctx context.Context, block rp ...@@ -134,7 +164,7 @@ func (f *FaultDisputeGameContract) GetGameMetadata(ctx context.Context, block rp
return l1Head, l2BlockNumber, rootClaim, status, duration, nil return l1Head, l2BlockNumber, rootClaim, status, duration, nil
} }
func (f *FaultDisputeGameContract) GetStartingRootHash(ctx context.Context) (common.Hash, error) { func (f *FaultDisputeGameContractLatest) GetStartingRootHash(ctx context.Context) (common.Hash, error) {
defer f.metrics.StartContractRequest("GetStartingRootHash")() defer f.metrics.StartContractRequest("GetStartingRootHash")()
startingRootHash, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodStartingRootHash)) startingRootHash, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodStartingRootHash))
if err != nil { if err != nil {
...@@ -143,7 +173,7 @@ func (f *FaultDisputeGameContract) GetStartingRootHash(ctx context.Context) (com ...@@ -143,7 +173,7 @@ func (f *FaultDisputeGameContract) GetStartingRootHash(ctx context.Context) (com
return startingRootHash.GetHash(0), nil return startingRootHash.GetHash(0), nil
} }
func (f *FaultDisputeGameContract) GetSplitDepth(ctx context.Context) (types.Depth, error) { func (f *FaultDisputeGameContractLatest) GetSplitDepth(ctx context.Context) (types.Depth, error) {
defer f.metrics.StartContractRequest("GetSplitDepth")() defer f.metrics.StartContractRequest("GetSplitDepth")()
splitDepth, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodSplitDepth)) splitDepth, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodSplitDepth))
if err != nil { if err != nil {
...@@ -152,7 +182,7 @@ func (f *FaultDisputeGameContract) GetSplitDepth(ctx context.Context) (types.Dep ...@@ -152,7 +182,7 @@ func (f *FaultDisputeGameContract) GetSplitDepth(ctx context.Context) (types.Dep
return types.Depth(splitDepth.GetBigInt(0).Uint64()), nil return types.Depth(splitDepth.GetBigInt(0).Uint64()), nil
} }
func (f *FaultDisputeGameContract) GetCredit(ctx context.Context, recipient common.Address) (*big.Int, gameTypes.GameStatus, error) { func (f *FaultDisputeGameContractLatest) GetCredit(ctx context.Context, recipient common.Address) (*big.Int, gameTypes.GameStatus, error) {
defer f.metrics.StartContractRequest("GetCredit")() defer f.metrics.StartContractRequest("GetCredit")()
results, err := f.multiCaller.Call(ctx, rpcblock.Latest, results, err := f.multiCaller.Call(ctx, rpcblock.Latest,
f.contract.Call(methodCredit, recipient), f.contract.Call(methodCredit, recipient),
...@@ -171,7 +201,7 @@ func (f *FaultDisputeGameContract) GetCredit(ctx context.Context, recipient comm ...@@ -171,7 +201,7 @@ func (f *FaultDisputeGameContract) GetCredit(ctx context.Context, recipient comm
return credit, status, nil return credit, status, nil
} }
func (f *FaultDisputeGameContract) GetRequiredBonds(ctx context.Context, block rpcblock.Block, positions ...*big.Int) ([]*big.Int, error) { func (f *FaultDisputeGameContractLatest) GetRequiredBonds(ctx context.Context, block rpcblock.Block, positions ...*big.Int) ([]*big.Int, error) {
calls := make([]batching.Call, 0, len(positions)) calls := make([]batching.Call, 0, len(positions))
for _, position := range positions { for _, position := range positions {
calls = append(calls, f.contract.Call(methodRequiredBond, position)) calls = append(calls, f.contract.Call(methodRequiredBond, position))
...@@ -187,7 +217,7 @@ func (f *FaultDisputeGameContract) GetRequiredBonds(ctx context.Context, block r ...@@ -187,7 +217,7 @@ func (f *FaultDisputeGameContract) GetRequiredBonds(ctx context.Context, block r
return requiredBonds, nil return requiredBonds, nil
} }
func (f *FaultDisputeGameContract) GetCredits(ctx context.Context, block rpcblock.Block, recipients ...common.Address) ([]*big.Int, error) { func (f *FaultDisputeGameContractLatest) GetCredits(ctx context.Context, block rpcblock.Block, recipients ...common.Address) ([]*big.Int, error) {
defer f.metrics.StartContractRequest("GetCredits")() defer f.metrics.StartContractRequest("GetCredits")()
calls := make([]batching.Call, 0, len(recipients)) calls := make([]batching.Call, 0, len(recipients))
for _, recipient := range recipients { for _, recipient := range recipients {
...@@ -204,7 +234,7 @@ func (f *FaultDisputeGameContract) GetCredits(ctx context.Context, block rpcbloc ...@@ -204,7 +234,7 @@ func (f *FaultDisputeGameContract) GetCredits(ctx context.Context, block rpcbloc
return credits, nil return credits, nil
} }
func (f *FaultDisputeGameContract) ClaimCreditTx(ctx context.Context, recipient common.Address) (txmgr.TxCandidate, error) { func (f *FaultDisputeGameContractLatest) ClaimCreditTx(ctx context.Context, recipient common.Address) (txmgr.TxCandidate, error) {
defer f.metrics.StartContractRequest("ClaimCredit")() defer f.metrics.StartContractRequest("ClaimCredit")()
call := f.contract.Call(methodClaimCredit, recipient) call := f.contract.Call(methodClaimCredit, recipient)
_, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, call) _, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, call)
...@@ -214,7 +244,7 @@ func (f *FaultDisputeGameContract) ClaimCreditTx(ctx context.Context, recipient ...@@ -214,7 +244,7 @@ func (f *FaultDisputeGameContract) ClaimCreditTx(ctx context.Context, recipient
return call.ToTxCandidate() return call.ToTxCandidate()
} }
func (f *FaultDisputeGameContract) GetRequiredBond(ctx context.Context, position types.Position) (*big.Int, error) { func (f *FaultDisputeGameContractLatest) GetRequiredBond(ctx context.Context, position types.Position) (*big.Int, error) {
defer f.metrics.StartContractRequest("GetRequiredBond")() defer f.metrics.StartContractRequest("GetRequiredBond")()
bond, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodRequiredBond, position.ToGIndex())) bond, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodRequiredBond, position.ToGIndex()))
if err != nil { if err != nil {
...@@ -223,14 +253,14 @@ func (f *FaultDisputeGameContract) GetRequiredBond(ctx context.Context, position ...@@ -223,14 +253,14 @@ func (f *FaultDisputeGameContract) GetRequiredBond(ctx context.Context, position
return bond.GetBigInt(0), nil return bond.GetBigInt(0), nil
} }
func (f *FaultDisputeGameContract) UpdateOracleTx(ctx context.Context, claimIdx uint64, data *types.PreimageOracleData) (txmgr.TxCandidate, error) { func (f *FaultDisputeGameContractLatest) UpdateOracleTx(ctx context.Context, claimIdx uint64, data *types.PreimageOracleData) (txmgr.TxCandidate, error) {
if data.IsLocal { if data.IsLocal {
return f.addLocalDataTx(claimIdx, data) return f.addLocalDataTx(claimIdx, data)
} }
return f.addGlobalDataTx(ctx, data) return f.addGlobalDataTx(ctx, data)
} }
func (f *FaultDisputeGameContract) addLocalDataTx(claimIdx uint64, data *types.PreimageOracleData) (txmgr.TxCandidate, error) { func (f *FaultDisputeGameContractLatest) addLocalDataTx(claimIdx uint64, data *types.PreimageOracleData) (txmgr.TxCandidate, error) {
call := f.contract.Call( call := f.contract.Call(
methodAddLocalData, methodAddLocalData,
data.GetIdent(), data.GetIdent(),
...@@ -240,7 +270,7 @@ func (f *FaultDisputeGameContract) addLocalDataTx(claimIdx uint64, data *types.P ...@@ -240,7 +270,7 @@ func (f *FaultDisputeGameContract) addLocalDataTx(claimIdx uint64, data *types.P
return call.ToTxCandidate() return call.ToTxCandidate()
} }
func (f *FaultDisputeGameContract) addGlobalDataTx(ctx context.Context, data *types.PreimageOracleData) (txmgr.TxCandidate, error) { func (f *FaultDisputeGameContractLatest) addGlobalDataTx(ctx context.Context, data *types.PreimageOracleData) (txmgr.TxCandidate, error) {
oracle, err := f.GetOracle(ctx) oracle, err := f.GetOracle(ctx)
if err != nil { if err != nil {
return txmgr.TxCandidate{}, err return txmgr.TxCandidate{}, err
...@@ -248,7 +278,7 @@ func (f *FaultDisputeGameContract) addGlobalDataTx(ctx context.Context, data *ty ...@@ -248,7 +278,7 @@ func (f *FaultDisputeGameContract) addGlobalDataTx(ctx context.Context, data *ty
return oracle.AddGlobalDataTx(data) return oracle.AddGlobalDataTx(data)
} }
func (f *FaultDisputeGameContract) GetWithdrawals(ctx context.Context, block rpcblock.Block, gameAddr common.Address, recipients ...common.Address) ([]*WithdrawalRequest, error) { func (f *FaultDisputeGameContractLatest) GetWithdrawals(ctx context.Context, block rpcblock.Block, gameAddr common.Address, recipients ...common.Address) ([]*WithdrawalRequest, error) {
defer f.metrics.StartContractRequest("GetWithdrawals")() defer f.metrics.StartContractRequest("GetWithdrawals")()
delayedWETH, err := f.getDelayedWETH(ctx) delayedWETH, err := f.getDelayedWETH(ctx)
if err != nil { if err != nil {
...@@ -257,7 +287,7 @@ func (f *FaultDisputeGameContract) GetWithdrawals(ctx context.Context, block rpc ...@@ -257,7 +287,7 @@ func (f *FaultDisputeGameContract) GetWithdrawals(ctx context.Context, block rpc
return delayedWETH.GetWithdrawals(ctx, block, gameAddr, recipients...) return delayedWETH.GetWithdrawals(ctx, block, gameAddr, recipients...)
} }
func (f *FaultDisputeGameContract) getDelayedWETH(ctx context.Context) (*DelayedWETHContract, error) { func (f *FaultDisputeGameContractLatest) getDelayedWETH(ctx context.Context) (*DelayedWETHContract, error) {
defer f.metrics.StartContractRequest("GetDelayedWETH")() defer f.metrics.StartContractRequest("GetDelayedWETH")()
result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodWETH)) result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodWETH))
if err != nil { if err != nil {
...@@ -266,7 +296,7 @@ func (f *FaultDisputeGameContract) getDelayedWETH(ctx context.Context) (*Delayed ...@@ -266,7 +296,7 @@ func (f *FaultDisputeGameContract) getDelayedWETH(ctx context.Context) (*Delayed
return NewDelayedWETHContract(f.metrics, result.GetAddress(0), f.multiCaller), nil return NewDelayedWETHContract(f.metrics, result.GetAddress(0), f.multiCaller), nil
} }
func (f *FaultDisputeGameContract) GetOracle(ctx context.Context) (*PreimageOracleContract, error) { func (f *FaultDisputeGameContractLatest) GetOracle(ctx context.Context) (*PreimageOracleContract, error) {
defer f.metrics.StartContractRequest("GetOracle")() defer f.metrics.StartContractRequest("GetOracle")()
vm, err := f.vm(ctx) vm, err := f.vm(ctx)
if err != nil { if err != nil {
...@@ -275,7 +305,7 @@ func (f *FaultDisputeGameContract) GetOracle(ctx context.Context) (*PreimageOrac ...@@ -275,7 +305,7 @@ func (f *FaultDisputeGameContract) GetOracle(ctx context.Context) (*PreimageOrac
return vm.Oracle(ctx) return vm.Oracle(ctx)
} }
func (f *FaultDisputeGameContract) GetMaxClockDuration(ctx context.Context) (time.Duration, error) { func (f *FaultDisputeGameContractLatest) GetMaxClockDuration(ctx context.Context) (time.Duration, error) {
defer f.metrics.StartContractRequest("GetMaxClockDuration")() defer f.metrics.StartContractRequest("GetMaxClockDuration")()
result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodMaxClockDuration)) result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodMaxClockDuration))
if err != nil { if err != nil {
...@@ -284,7 +314,7 @@ func (f *FaultDisputeGameContract) GetMaxClockDuration(ctx context.Context) (tim ...@@ -284,7 +314,7 @@ func (f *FaultDisputeGameContract) GetMaxClockDuration(ctx context.Context) (tim
return time.Duration(result.GetUint64(0)) * time.Second, nil return time.Duration(result.GetUint64(0)) * time.Second, nil
} }
func (f *FaultDisputeGameContract) GetMaxGameDepth(ctx context.Context) (types.Depth, error) { func (f *FaultDisputeGameContractLatest) GetMaxGameDepth(ctx context.Context) (types.Depth, error) {
defer f.metrics.StartContractRequest("GetMaxGameDepth")() defer f.metrics.StartContractRequest("GetMaxGameDepth")()
result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodMaxGameDepth)) result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodMaxGameDepth))
if err != nil { if err != nil {
...@@ -293,7 +323,7 @@ func (f *FaultDisputeGameContract) GetMaxGameDepth(ctx context.Context) (types.D ...@@ -293,7 +323,7 @@ func (f *FaultDisputeGameContract) GetMaxGameDepth(ctx context.Context) (types.D
return types.Depth(result.GetBigInt(0).Uint64()), nil return types.Depth(result.GetBigInt(0).Uint64()), nil
} }
func (f *FaultDisputeGameContract) GetAbsolutePrestateHash(ctx context.Context) (common.Hash, error) { func (f *FaultDisputeGameContractLatest) GetAbsolutePrestateHash(ctx context.Context) (common.Hash, error) {
defer f.metrics.StartContractRequest("GetAbsolutePrestateHash")() defer f.metrics.StartContractRequest("GetAbsolutePrestateHash")()
result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodAbsolutePrestate)) result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodAbsolutePrestate))
if err != nil { if err != nil {
...@@ -302,7 +332,7 @@ func (f *FaultDisputeGameContract) GetAbsolutePrestateHash(ctx context.Context) ...@@ -302,7 +332,7 @@ func (f *FaultDisputeGameContract) GetAbsolutePrestateHash(ctx context.Context)
return result.GetHash(0), nil return result.GetHash(0), nil
} }
func (f *FaultDisputeGameContract) GetL1Head(ctx context.Context) (common.Hash, error) { func (f *FaultDisputeGameContractLatest) GetL1Head(ctx context.Context) (common.Hash, error) {
defer f.metrics.StartContractRequest("GetL1Head")() defer f.metrics.StartContractRequest("GetL1Head")()
result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodL1Head)) result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodL1Head))
if err != nil { if err != nil {
...@@ -311,7 +341,7 @@ func (f *FaultDisputeGameContract) GetL1Head(ctx context.Context) (common.Hash, ...@@ -311,7 +341,7 @@ func (f *FaultDisputeGameContract) GetL1Head(ctx context.Context) (common.Hash,
return result.GetHash(0), nil return result.GetHash(0), nil
} }
func (f *FaultDisputeGameContract) GetStatus(ctx context.Context) (gameTypes.GameStatus, error) { func (f *FaultDisputeGameContractLatest) GetStatus(ctx context.Context) (gameTypes.GameStatus, error) {
defer f.metrics.StartContractRequest("GetStatus")() defer f.metrics.StartContractRequest("GetStatus")()
result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodStatus)) result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodStatus))
if err != nil { if err != nil {
...@@ -320,7 +350,7 @@ func (f *FaultDisputeGameContract) GetStatus(ctx context.Context) (gameTypes.Gam ...@@ -320,7 +350,7 @@ func (f *FaultDisputeGameContract) GetStatus(ctx context.Context) (gameTypes.Gam
return gameTypes.GameStatusFromUint8(result.GetUint8(0)) return gameTypes.GameStatusFromUint8(result.GetUint8(0))
} }
func (f *FaultDisputeGameContract) GetClaimCount(ctx context.Context) (uint64, error) { func (f *FaultDisputeGameContractLatest) GetClaimCount(ctx context.Context) (uint64, error) {
defer f.metrics.StartContractRequest("GetClaimCount")() defer f.metrics.StartContractRequest("GetClaimCount")()
result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodClaimCount)) result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodClaimCount))
if err != nil { if err != nil {
...@@ -329,7 +359,7 @@ func (f *FaultDisputeGameContract) GetClaimCount(ctx context.Context) (uint64, e ...@@ -329,7 +359,7 @@ func (f *FaultDisputeGameContract) GetClaimCount(ctx context.Context) (uint64, e
return result.GetBigInt(0).Uint64(), nil return result.GetBigInt(0).Uint64(), nil
} }
func (f *FaultDisputeGameContract) GetClaim(ctx context.Context, idx uint64) (types.Claim, error) { func (f *FaultDisputeGameContractLatest) GetClaim(ctx context.Context, idx uint64) (types.Claim, error) {
defer f.metrics.StartContractRequest("GetClaim")() defer f.metrics.StartContractRequest("GetClaim")()
result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodClaim, new(big.Int).SetUint64(idx))) result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodClaim, new(big.Int).SetUint64(idx)))
if err != nil { if err != nil {
...@@ -338,7 +368,7 @@ func (f *FaultDisputeGameContract) GetClaim(ctx context.Context, idx uint64) (ty ...@@ -338,7 +368,7 @@ func (f *FaultDisputeGameContract) GetClaim(ctx context.Context, idx uint64) (ty
return f.decodeClaim(result, int(idx)), nil return f.decodeClaim(result, int(idx)), nil
} }
func (f *FaultDisputeGameContract) GetAllClaims(ctx context.Context, block rpcblock.Block) ([]types.Claim, error) { func (f *FaultDisputeGameContractLatest) GetAllClaims(ctx context.Context, block rpcblock.Block) ([]types.Claim, error) {
defer f.metrics.StartContractRequest("GetAllClaims")() defer f.metrics.StartContractRequest("GetAllClaims")()
results, err := batching.ReadArray(ctx, f.multiCaller, block, f.contract.Call(methodClaimCount), func(i *big.Int) *batching.ContractCall { results, err := batching.ReadArray(ctx, f.multiCaller, block, f.contract.Call(methodClaimCount), func(i *big.Int) *batching.ContractCall {
return f.contract.Call(methodClaim, i) return f.contract.Call(methodClaim, i)
...@@ -354,7 +384,7 @@ func (f *FaultDisputeGameContract) GetAllClaims(ctx context.Context, block rpcbl ...@@ -354,7 +384,7 @@ func (f *FaultDisputeGameContract) GetAllClaims(ctx context.Context, block rpcbl
return claims, nil return claims, nil
} }
func (f *FaultDisputeGameContract) IsResolved(ctx context.Context, block rpcblock.Block, claims ...types.Claim) ([]bool, error) { func (f *FaultDisputeGameContractLatest) IsResolved(ctx context.Context, block rpcblock.Block, claims ...types.Claim) ([]bool, error) {
defer f.metrics.StartContractRequest("IsResolved")() defer f.metrics.StartContractRequest("IsResolved")()
calls := make([]batching.Call, 0, len(claims)) calls := make([]batching.Call, 0, len(claims))
for _, claim := range claims { for _, claim := range claims {
...@@ -371,7 +401,7 @@ func (f *FaultDisputeGameContract) IsResolved(ctx context.Context, block rpcbloc ...@@ -371,7 +401,7 @@ func (f *FaultDisputeGameContract) IsResolved(ctx context.Context, block rpcbloc
return resolved, nil return resolved, nil
} }
func (f *FaultDisputeGameContract) vm(ctx context.Context) (*VMContract, error) { func (f *FaultDisputeGameContractLatest) vm(ctx context.Context) (*VMContract, error) {
result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodVM)) result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodVM))
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to fetch VM addr: %w", err) return nil, fmt.Errorf("failed to fetch VM addr: %w", err)
...@@ -380,22 +410,22 @@ func (f *FaultDisputeGameContract) vm(ctx context.Context) (*VMContract, error) ...@@ -380,22 +410,22 @@ func (f *FaultDisputeGameContract) vm(ctx context.Context) (*VMContract, error)
return NewVMContract(vmAddr, f.multiCaller), nil return NewVMContract(vmAddr, f.multiCaller), nil
} }
func (f *FaultDisputeGameContract) AttackTx(parentContractIndex uint64, pivot common.Hash) (txmgr.TxCandidate, error) { func (f *FaultDisputeGameContractLatest) AttackTx(parentContractIndex uint64, pivot common.Hash) (txmgr.TxCandidate, error) {
call := f.contract.Call(methodAttack, new(big.Int).SetUint64(parentContractIndex), pivot) call := f.contract.Call(methodAttack, new(big.Int).SetUint64(parentContractIndex), pivot)
return call.ToTxCandidate() return call.ToTxCandidate()
} }
func (f *FaultDisputeGameContract) DefendTx(parentContractIndex uint64, pivot common.Hash) (txmgr.TxCandidate, error) { func (f *FaultDisputeGameContractLatest) DefendTx(parentContractIndex uint64, pivot common.Hash) (txmgr.TxCandidate, error) {
call := f.contract.Call(methodDefend, new(big.Int).SetUint64(parentContractIndex), pivot) call := f.contract.Call(methodDefend, new(big.Int).SetUint64(parentContractIndex), pivot)
return call.ToTxCandidate() return call.ToTxCandidate()
} }
func (f *FaultDisputeGameContract) StepTx(claimIdx uint64, isAttack bool, stateData []byte, proof []byte) (txmgr.TxCandidate, error) { func (f *FaultDisputeGameContractLatest) StepTx(claimIdx uint64, isAttack bool, stateData []byte, proof []byte) (txmgr.TxCandidate, error) {
call := f.contract.Call(methodStep, new(big.Int).SetUint64(claimIdx), isAttack, stateData, proof) call := f.contract.Call(methodStep, new(big.Int).SetUint64(claimIdx), isAttack, stateData, proof)
return call.ToTxCandidate() return call.ToTxCandidate()
} }
func (f *FaultDisputeGameContract) CallResolveClaim(ctx context.Context, claimIdx uint64) error { func (f *FaultDisputeGameContractLatest) CallResolveClaim(ctx context.Context, claimIdx uint64) error {
defer f.metrics.StartContractRequest("CallResolveClaim")() defer f.metrics.StartContractRequest("CallResolveClaim")()
call := f.resolveClaimCall(claimIdx) call := f.resolveClaimCall(claimIdx)
_, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, call) _, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, call)
...@@ -405,16 +435,16 @@ func (f *FaultDisputeGameContract) CallResolveClaim(ctx context.Context, claimId ...@@ -405,16 +435,16 @@ func (f *FaultDisputeGameContract) CallResolveClaim(ctx context.Context, claimId
return nil return nil
} }
func (f *FaultDisputeGameContract) ResolveClaimTx(claimIdx uint64) (txmgr.TxCandidate, error) { func (f *FaultDisputeGameContractLatest) ResolveClaimTx(claimIdx uint64) (txmgr.TxCandidate, error) {
call := f.resolveClaimCall(claimIdx) call := f.resolveClaimCall(claimIdx)
return call.ToTxCandidate() return call.ToTxCandidate()
} }
func (f *FaultDisputeGameContract) resolveClaimCall(claimIdx uint64) *batching.ContractCall { func (f *FaultDisputeGameContractLatest) resolveClaimCall(claimIdx uint64) *batching.ContractCall {
return f.contract.Call(methodResolveClaim, new(big.Int).SetUint64(claimIdx), maxChildChecks) return f.contract.Call(methodResolveClaim, new(big.Int).SetUint64(claimIdx), maxChildChecks)
} }
func (f *FaultDisputeGameContract) CallResolve(ctx context.Context) (gameTypes.GameStatus, error) { func (f *FaultDisputeGameContractLatest) CallResolve(ctx context.Context) (gameTypes.GameStatus, error) {
defer f.metrics.StartContractRequest("CallResolve")() defer f.metrics.StartContractRequest("CallResolve")()
call := f.resolveCall() call := f.resolveCall()
result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, call) result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, call)
...@@ -424,12 +454,12 @@ func (f *FaultDisputeGameContract) CallResolve(ctx context.Context) (gameTypes.G ...@@ -424,12 +454,12 @@ func (f *FaultDisputeGameContract) CallResolve(ctx context.Context) (gameTypes.G
return gameTypes.GameStatusFromUint8(result.GetUint8(0)) return gameTypes.GameStatusFromUint8(result.GetUint8(0))
} }
func (f *FaultDisputeGameContract) ResolveTx() (txmgr.TxCandidate, error) { func (f *FaultDisputeGameContractLatest) ResolveTx() (txmgr.TxCandidate, error) {
call := f.resolveCall() call := f.resolveCall()
return call.ToTxCandidate() return call.ToTxCandidate()
} }
func (f *FaultDisputeGameContract) resolveCall() *batching.ContractCall { func (f *FaultDisputeGameContractLatest) resolveCall() *batching.ContractCall {
return f.contract.Call(methodResolve) return f.contract.Call(methodResolve)
} }
...@@ -448,7 +478,7 @@ func packClock(c types.Clock) *big.Int { ...@@ -448,7 +478,7 @@ func packClock(c types.Clock) *big.Int {
return new(big.Int).Or(encoded, big.NewInt(c.Timestamp.Unix())) return new(big.Int).Or(encoded, big.NewInt(c.Timestamp.Unix()))
} }
func (f *FaultDisputeGameContract) decodeClaim(result *batching.CallResult, contractIndex int) types.Claim { func (f *FaultDisputeGameContractLatest) decodeClaim(result *batching.CallResult, contractIndex int) types.Claim {
parentIndex := result.GetUint32(0) parentIndex := result.GetUint32(0)
counteredBy := result.GetAddress(1) counteredBy := result.GetAddress(1)
claimant := result.GetAddress(2) claimant := result.GetAddress(2)
...@@ -469,3 +499,35 @@ func (f *FaultDisputeGameContract) decodeClaim(result *batching.CallResult, cont ...@@ -469,3 +499,35 @@ func (f *FaultDisputeGameContract) decodeClaim(result *batching.CallResult, cont
ParentContractIndex: int(parentIndex), ParentContractIndex: int(parentIndex),
} }
} }
type FaultDisputeGameContract interface {
GetBalance(ctx context.Context, block rpcblock.Block) (*big.Int, common.Address, error)
GetBlockRange(ctx context.Context) (prestateBlock uint64, poststateBlock uint64, retErr error)
GetGameMetadata(ctx context.Context, block rpcblock.Block) (common.Hash, uint64, common.Hash, gameTypes.GameStatus, uint64, error)
GetStartingRootHash(ctx context.Context) (common.Hash, error)
GetSplitDepth(ctx context.Context) (types.Depth, error)
GetCredit(ctx context.Context, recipient common.Address) (*big.Int, gameTypes.GameStatus, error)
GetRequiredBonds(ctx context.Context, block rpcblock.Block, positions ...*big.Int) ([]*big.Int, error)
GetCredits(ctx context.Context, block rpcblock.Block, recipients ...common.Address) ([]*big.Int, error)
ClaimCreditTx(ctx context.Context, recipient common.Address) (txmgr.TxCandidate, error)
GetRequiredBond(ctx context.Context, position types.Position) (*big.Int, error)
UpdateOracleTx(ctx context.Context, claimIdx uint64, data *types.PreimageOracleData) (txmgr.TxCandidate, error)
GetWithdrawals(ctx context.Context, block rpcblock.Block, gameAddr common.Address, recipients ...common.Address) ([]*WithdrawalRequest, error)
GetOracle(ctx context.Context) (*PreimageOracleContract, error)
GetMaxClockDuration(ctx context.Context) (time.Duration, error)
GetMaxGameDepth(ctx context.Context) (types.Depth, error)
GetAbsolutePrestateHash(ctx context.Context) (common.Hash, error)
GetL1Head(ctx context.Context) (common.Hash, error)
GetStatus(ctx context.Context) (gameTypes.GameStatus, error)
GetClaimCount(ctx context.Context) (uint64, error)
GetClaim(ctx context.Context, idx uint64) (types.Claim, error)
GetAllClaims(ctx context.Context, block rpcblock.Block) ([]types.Claim, error)
IsResolved(ctx context.Context, block rpcblock.Block, claims ...types.Claim) ([]bool, error)
AttackTx(parentContractIndex uint64, pivot common.Hash) (txmgr.TxCandidate, error)
DefendTx(parentContractIndex uint64, pivot common.Hash) (txmgr.TxCandidate, error)
StepTx(claimIdx uint64, isAttack bool, stateData []byte, proof []byte) (txmgr.TxCandidate, error)
CallResolveClaim(ctx context.Context, claimIdx uint64) error
ResolveClaimTx(claimIdx uint64) (txmgr.TxCandidate, error)
CallResolve(ctx context.Context) (gameTypes.GameStatus, error)
ResolveTx() (txmgr.TxCandidate, error)
}
package contracts
import (
"context"
_ "embed"
"fmt"
"math/big"
"time"
"github.com/ethereum-optimism/optimism/op-challenger/game/fault/types"
gameTypes "github.com/ethereum-optimism/optimism/op-challenger/game/types"
"github.com/ethereum-optimism/optimism/op-service/sources/batching"
"github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum/common"
)
//go:embed abis/FaultDisputeGame-0.8.0.json
var faultDisputeGameAbi020 []byte
var resolvedBondAmount = new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 128), big.NewInt(1))
var (
methodGameDuration = "gameDuration"
)
type FaultDisputeGameContract080 struct {
FaultDisputeGameContractLatest
}
// GetGameMetadata returns the game's L1 head, L2 block number, root claim, status, and max clock duration.
func (f *FaultDisputeGameContract080) GetGameMetadata(ctx context.Context, block rpcblock.Block) (common.Hash, uint64, common.Hash, gameTypes.GameStatus, uint64, error) {
defer f.metrics.StartContractRequest("GetGameMetadata")()
results, err := f.multiCaller.Call(ctx, block,
f.contract.Call(methodL1Head),
f.contract.Call(methodL2BlockNumber),
f.contract.Call(methodRootClaim),
f.contract.Call(methodStatus),
f.contract.Call(methodGameDuration))
if err != nil {
return common.Hash{}, 0, common.Hash{}, 0, 0, fmt.Errorf("failed to retrieve game metadata: %w", err)
}
if len(results) != 5 {
return common.Hash{}, 0, common.Hash{}, 0, 0, fmt.Errorf("expected 3 results but got %v", len(results))
}
l1Head := results[0].GetHash(0)
l2BlockNumber := results[1].GetBigInt(0).Uint64()
rootClaim := results[2].GetHash(0)
status, err := gameTypes.GameStatusFromUint8(results[3].GetUint8(0))
if err != nil {
return common.Hash{}, 0, common.Hash{}, 0, 0, fmt.Errorf("failed to convert game status: %w", err)
}
duration := results[4].GetUint64(0)
return l1Head, l2BlockNumber, rootClaim, status, duration / 2, nil
}
func (f *FaultDisputeGameContract080) GetMaxClockDuration(ctx context.Context) (time.Duration, error) {
defer f.metrics.StartContractRequest("GetMaxClockDuration")()
result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, f.contract.Call(methodGameDuration))
if err != nil {
return 0, fmt.Errorf("failed to fetch game duration: %w", err)
}
return time.Duration(result.GetUint64(0)) * time.Second / 2, nil
}
func (f *FaultDisputeGameContract080) GetClaim(ctx context.Context, idx uint64) (types.Claim, error) {
claim, err := f.FaultDisputeGameContractLatest.GetClaim(ctx, idx)
if err != nil {
return types.Claim{}, err
}
// Replace the resolved sentinel with what the bond would have been
if claim.Bond.Cmp(resolvedBondAmount) == 0 {
bond, err := f.GetRequiredBond(ctx, claim.Position)
if err != nil {
return types.Claim{}, err
}
claim.Bond = bond
}
return claim, nil
}
func (f *FaultDisputeGameContract080) GetAllClaims(ctx context.Context, block rpcblock.Block) ([]types.Claim, error) {
claims, err := f.FaultDisputeGameContractLatest.GetAllClaims(ctx, block)
if err != nil {
return nil, err
}
resolvedClaims := make([]*types.Claim, 0, len(claims))
positions := make([]*big.Int, 0, len(claims))
for i, claim := range claims {
if claim.Bond.Cmp(resolvedBondAmount) == 0 {
resolvedClaims = append(resolvedClaims, &claims[i])
positions = append(positions, claim.Position.ToGIndex())
}
}
bonds, err := f.GetRequiredBonds(ctx, block, positions...)
if err != nil {
return nil, fmt.Errorf("failed to get required bonds for resolved claims: %w", err)
}
for i, bond := range bonds {
resolvedClaims[i].Bond = bond
}
return claims, nil
}
func (f *FaultDisputeGameContract080) IsResolved(ctx context.Context, block rpcblock.Block, claims ...types.Claim) ([]bool, error) {
rawClaims, err := f.FaultDisputeGameContractLatest.GetAllClaims(ctx, block)
if err != nil {
return nil, fmt.Errorf("failed to get raw claim data: %w", err)
}
results := make([]bool, len(claims))
for i, claim := range claims {
results[i] = rawClaims[claim.ContractIndex].Bond.Cmp(resolvedBondAmount) == 0
}
return results, nil
}
func (f *FaultDisputeGameContract080) CallResolveClaim(ctx context.Context, claimIdx uint64) error {
defer f.metrics.StartContractRequest("CallResolveClaim")()
call := f.resolveClaimCall(claimIdx)
_, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, call)
if err != nil {
return fmt.Errorf("failed to call resolve claim: %w", err)
}
return nil
}
func (f *FaultDisputeGameContract080) ResolveClaimTx(claimIdx uint64) (txmgr.TxCandidate, error) {
call := f.resolveClaimCall(claimIdx)
return call.ToTxCandidate()
}
func (f *FaultDisputeGameContract080) resolveClaimCall(claimIdx uint64) *batching.ContractCall {
return f.contract.Call(methodResolveClaim, new(big.Int).SetUint64(claimIdx))
}
...@@ -16,6 +16,7 @@ import ( ...@@ -16,6 +16,7 @@ import (
batchingTest "github.com/ethereum-optimism/optimism/op-service/sources/batching/test" batchingTest "github.com/ethereum-optimism/optimism/op-service/sources/batching/test"
"github.com/ethereum-optimism/optimism/op-service/txmgr" "github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum-optimism/optimism/packages/contracts-bedrock/snapshots" "github.com/ethereum-optimism/optimism/packages/contracts-bedrock/snapshots"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
...@@ -26,6 +27,29 @@ var ( ...@@ -26,6 +27,29 @@ var (
oracleAddr = common.HexToAddress("0x44442842371dFC380576ebb09Ae16Cb6B6ca4444") oracleAddr = common.HexToAddress("0x44442842371dFC380576ebb09Ae16Cb6B6ca4444")
) )
type contractVersion struct {
version string
loadAbi func() *abi.ABI
}
const (
vers080 = "0.8.0"
versLatest = "0.18.0"
)
var versions = []contractVersion{
{
version: vers080,
loadAbi: func() *abi.ABI {
return mustParseAbi(faultDisputeGameAbi020)
},
},
{
version: versLatest,
loadAbi: snapshots.LoadFaultDisputeGameABI,
},
}
func TestSimpleGetters(t *testing.T) { func TestSimpleGetters(t *testing.T) {
tests := []struct { tests := []struct {
methodAlias string methodAlias string
...@@ -33,13 +57,14 @@ func TestSimpleGetters(t *testing.T) { ...@@ -33,13 +57,14 @@ func TestSimpleGetters(t *testing.T) {
args []interface{} args []interface{}
result interface{} result interface{}
expected interface{} // Defaults to expecting the same as result expected interface{} // Defaults to expecting the same as result
call func(game *FaultDisputeGameContract) (any, error) call func(game FaultDisputeGameContract) (any, error)
applies func(version contractVersion) bool
}{ }{
{ {
methodAlias: "status", methodAlias: "status",
method: methodStatus, method: methodStatus,
result: types.GameStatusChallengerWon, result: types.GameStatusChallengerWon,
call: func(game *FaultDisputeGameContract) (any, error) { call: func(game FaultDisputeGameContract) (any, error) {
return game.GetStatus(context.Background()) return game.GetStatus(context.Background())
}, },
}, },
...@@ -48,16 +73,31 @@ func TestSimpleGetters(t *testing.T) { ...@@ -48,16 +73,31 @@ func TestSimpleGetters(t *testing.T) {
method: methodMaxClockDuration, method: methodMaxClockDuration,
result: uint64(5566), result: uint64(5566),
expected: 5566 * time.Second, expected: 5566 * time.Second,
call: func(game *FaultDisputeGameContract) (any, error) { call: func(game FaultDisputeGameContract) (any, error) {
return game.GetMaxClockDuration(context.Background()) return game.GetMaxClockDuration(context.Background())
}, },
applies: func(version contractVersion) bool {
return version.version != vers080
},
},
{
methodAlias: "gameDuration",
method: methodGameDuration,
result: uint64(5566) * 2,
expected: 5566 * time.Second,
call: func(game FaultDisputeGameContract) (any, error) {
return game.GetMaxClockDuration(context.Background())
},
applies: func(version contractVersion) bool {
return version.version == vers080
},
}, },
{ {
methodAlias: "maxGameDepth", methodAlias: "maxGameDepth",
method: methodMaxGameDepth, method: methodMaxGameDepth,
result: big.NewInt(128), result: big.NewInt(128),
expected: faultTypes.Depth(128), expected: faultTypes.Depth(128),
call: func(game *FaultDisputeGameContract) (any, error) { call: func(game FaultDisputeGameContract) (any, error) {
return game.GetMaxGameDepth(context.Background()) return game.GetMaxGameDepth(context.Background())
}, },
}, },
...@@ -65,7 +105,7 @@ func TestSimpleGetters(t *testing.T) { ...@@ -65,7 +105,7 @@ func TestSimpleGetters(t *testing.T) {
methodAlias: "absolutePrestate", methodAlias: "absolutePrestate",
method: methodAbsolutePrestate, method: methodAbsolutePrestate,
result: common.Hash{0xab}, result: common.Hash{0xab},
call: func(game *FaultDisputeGameContract) (any, error) { call: func(game FaultDisputeGameContract) (any, error) {
return game.GetAbsolutePrestateHash(context.Background()) return game.GetAbsolutePrestateHash(context.Background())
}, },
}, },
...@@ -74,7 +114,7 @@ func TestSimpleGetters(t *testing.T) { ...@@ -74,7 +114,7 @@ func TestSimpleGetters(t *testing.T) {
method: methodClaimCount, method: methodClaimCount,
result: big.NewInt(9876), result: big.NewInt(9876),
expected: uint64(9876), expected: uint64(9876),
call: func(game *FaultDisputeGameContract) (any, error) { call: func(game FaultDisputeGameContract) (any, error) {
return game.GetClaimCount(context.Background()) return game.GetClaimCount(context.Background())
}, },
}, },
...@@ -82,7 +122,7 @@ func TestSimpleGetters(t *testing.T) { ...@@ -82,7 +122,7 @@ func TestSimpleGetters(t *testing.T) {
methodAlias: "l1Head", methodAlias: "l1Head",
method: methodL1Head, method: methodL1Head,
result: common.Hash{0xdd, 0xbb}, result: common.Hash{0xdd, 0xbb},
call: func(game *FaultDisputeGameContract) (any, error) { call: func(game FaultDisputeGameContract) (any, error) {
return game.GetL1Head(context.Background()) return game.GetL1Head(context.Background())
}, },
}, },
...@@ -90,23 +130,31 @@ func TestSimpleGetters(t *testing.T) { ...@@ -90,23 +130,31 @@ func TestSimpleGetters(t *testing.T) {
methodAlias: "resolve", methodAlias: "resolve",
method: methodResolve, method: methodResolve,
result: types.GameStatusInProgress, result: types.GameStatusInProgress,
call: func(game *FaultDisputeGameContract) (any, error) { call: func(game FaultDisputeGameContract) (any, error) {
return game.CallResolve(context.Background()) return game.CallResolve(context.Background())
}, },
}, },
} }
for _, test := range tests { for _, version := range versions {
test := test version := version
t.Run(test.methodAlias, func(t *testing.T) { t.Run(version.version, func(t *testing.T) {
stubRpc, game := setupFaultDisputeGameTest(t) for _, test := range tests {
stubRpc.SetResponse(fdgAddr, test.method, rpcblock.Latest, nil, []interface{}{test.result}) test := test
status, err := test.call(game) t.Run(test.methodAlias, func(t *testing.T) {
require.NoError(t, err) if test.applies != nil && !test.applies(version) {
expected := test.expected t.Skip("Skipping for this version")
if expected == nil { }
expected = test.result stubRpc, game := setupFaultDisputeGameTest(t, version)
stubRpc.SetResponse(fdgAddr, test.method, rpcblock.Latest, nil, []interface{}{test.result})
status, err := test.call(game)
require.NoError(t, err)
expected := test.expected
if expected == nil {
expected = test.result
}
require.Equal(t, expected, status)
})
} }
require.Equal(t, expected, status)
}) })
} }
} }
...@@ -150,153 +198,211 @@ func TestClock_EncodingDecoding(t *testing.T) { ...@@ -150,153 +198,211 @@ func TestClock_EncodingDecoding(t *testing.T) {
} }
func TestGetOracleAddr(t *testing.T) { func TestGetOracleAddr(t *testing.T) {
stubRpc, game := setupFaultDisputeGameTest(t) for _, version := range versions {
stubRpc.SetResponse(fdgAddr, methodVM, rpcblock.Latest, nil, []interface{}{vmAddr}) version := version
stubRpc.SetResponse(vmAddr, methodOracle, rpcblock.Latest, nil, []interface{}{oracleAddr}) t.Run(version.version, func(t *testing.T) {
stubRpc, game := setupFaultDisputeGameTest(t, version)
actual, err := game.GetOracle(context.Background()) stubRpc.SetResponse(fdgAddr, methodVM, rpcblock.Latest, nil, []interface{}{vmAddr})
require.NoError(t, err) stubRpc.SetResponse(vmAddr, methodOracle, rpcblock.Latest, nil, []interface{}{oracleAddr})
require.Equal(t, oracleAddr, actual.Addr())
actual, err := game.GetOracle(context.Background())
require.NoError(t, err)
require.Equal(t, oracleAddr, actual.Addr())
})
}
} }
func TestGetClaim(t *testing.T) { func TestGetClaim(t *testing.T) {
stubRpc, game := setupFaultDisputeGameTest(t) for _, version := range versions {
idx := big.NewInt(2) version := version
parentIndex := uint32(1) t.Run(version.version, func(t *testing.T) {
counteredBy := common.Address{0x01} stubRpc, game := setupFaultDisputeGameTest(t, version)
claimant := common.Address{0x02} idx := big.NewInt(2)
bond := big.NewInt(5) parentIndex := uint32(1)
value := common.Hash{0xab} counteredBy := common.Address{0x01}
position := big.NewInt(2) claimant := common.Address{0x02}
clock := big.NewInt(1234) bond := big.NewInt(5)
stubRpc.SetResponse(fdgAddr, methodClaim, rpcblock.Latest, []interface{}{idx}, []interface{}{parentIndex, counteredBy, claimant, bond, value, position, clock}) value := common.Hash{0xab}
status, err := game.GetClaim(context.Background(), idx.Uint64()) position := big.NewInt(2)
require.NoError(t, err) clock := big.NewInt(1234)
require.Equal(t, faultTypes.Claim{ stubRpc.SetResponse(fdgAddr, methodClaim, rpcblock.Latest, []interface{}{idx}, []interface{}{parentIndex, counteredBy, claimant, bond, value, position, clock})
ClaimData: faultTypes.ClaimData{ status, err := game.GetClaim(context.Background(), idx.Uint64())
Value: value, require.NoError(t, err)
Position: faultTypes.NewPositionFromGIndex(position), require.Equal(t, faultTypes.Claim{
Bond: bond, ClaimData: faultTypes.ClaimData{
}, Value: value,
CounteredBy: counteredBy, Position: faultTypes.NewPositionFromGIndex(position),
Claimant: claimant, Bond: bond,
Clock: decodeClock(big.NewInt(1234)), },
ContractIndex: int(idx.Uint64()), CounteredBy: counteredBy,
ParentContractIndex: 1, Claimant: claimant,
}, status) Clock: decodeClock(big.NewInt(1234)),
ContractIndex: int(idx.Uint64()),
ParentContractIndex: 1,
}, status)
})
}
} }
func TestGetAllClaims(t *testing.T) { func TestGetAllClaims(t *testing.T) {
stubRpc, game := setupFaultDisputeGameTest(t) for _, version := range versions {
claim0 := faultTypes.Claim{ version := version
ClaimData: faultTypes.ClaimData{ t.Run(version.version, func(t *testing.T) {
Value: common.Hash{0xaa}, stubRpc, game := setupFaultDisputeGameTest(t, version)
Position: faultTypes.NewPositionFromGIndex(big.NewInt(1)), claim0 := faultTypes.Claim{
Bond: big.NewInt(5), ClaimData: faultTypes.ClaimData{
}, Value: common.Hash{0xaa},
CounteredBy: common.Address{0x01}, Position: faultTypes.NewPositionFromGIndex(big.NewInt(1)),
Claimant: common.Address{0x02}, Bond: big.NewInt(5),
Clock: decodeClock(big.NewInt(1234)), },
ContractIndex: 0, CounteredBy: common.Address{0x01},
ParentContractIndex: math.MaxUint32, Claimant: common.Address{0x02},
} Clock: decodeClock(big.NewInt(1234)),
claim1 := faultTypes.Claim{ ContractIndex: 0,
ClaimData: faultTypes.ClaimData{ ParentContractIndex: math.MaxUint32,
Value: common.Hash{0xab}, }
Position: faultTypes.NewPositionFromGIndex(big.NewInt(2)), claim1 := faultTypes.Claim{
Bond: big.NewInt(5), ClaimData: faultTypes.ClaimData{
}, Value: common.Hash{0xab},
CounteredBy: common.Address{0x02}, Position: faultTypes.NewPositionFromGIndex(big.NewInt(2)),
Claimant: common.Address{0x01}, Bond: big.NewInt(5),
Clock: decodeClock(big.NewInt(4455)), },
ContractIndex: 1, CounteredBy: common.Address{0x02},
ParentContractIndex: 0, Claimant: common.Address{0x01},
} Clock: decodeClock(big.NewInt(4455)),
claim2 := faultTypes.Claim{ ContractIndex: 1,
ClaimData: faultTypes.ClaimData{ ParentContractIndex: 0,
Value: common.Hash{0xbb}, }
Position: faultTypes.NewPositionFromGIndex(big.NewInt(6)), claim2 := faultTypes.Claim{
Bond: big.NewInt(5), ClaimData: faultTypes.ClaimData{
}, Value: common.Hash{0xbb},
Claimant: common.Address{0x02}, Position: faultTypes.NewPositionFromGIndex(big.NewInt(6)),
Clock: decodeClock(big.NewInt(7777)), Bond: big.NewInt(5),
ContractIndex: 2, },
ParentContractIndex: 1, Claimant: common.Address{0x02},
} Clock: decodeClock(big.NewInt(7777)),
expectedClaims := []faultTypes.Claim{claim0, claim1, claim2} ContractIndex: 2,
block := rpcblock.ByNumber(42) ParentContractIndex: 1,
stubRpc.SetResponse(fdgAddr, methodClaimCount, block, nil, []interface{}{big.NewInt(int64(len(expectedClaims)))}) }
for _, claim := range expectedClaims { expectedClaims := []faultTypes.Claim{claim0, claim1, claim2}
expectGetClaim(stubRpc, block, claim) block := rpcblock.ByNumber(42)
stubRpc.SetResponse(fdgAddr, methodClaimCount, block, nil, []interface{}{big.NewInt(int64(len(expectedClaims)))})
for _, claim := range expectedClaims {
expectGetClaim(stubRpc, block, claim)
}
claims, err := game.GetAllClaims(context.Background(), block)
require.NoError(t, err)
require.Equal(t, expectedClaims, claims)
})
} }
claims, err := game.GetAllClaims(context.Background(), block)
require.NoError(t, err)
require.Equal(t, expectedClaims, claims)
} }
func TestGetBalance(t *testing.T) { func TestGetBalance(t *testing.T) {
wethAddr := common.Address{0x11, 0x55, 0x66} for _, version := range versions {
balance := big.NewInt(9995877) version := version
block := rpcblock.ByNumber(424) t.Run(version.version, func(t *testing.T) {
stubRpc, game := setupFaultDisputeGameTest(t) wethAddr := common.Address{0x11, 0x55, 0x66}
stubRpc.SetResponse(fdgAddr, methodWETH, block, nil, []interface{}{wethAddr}) balance := big.NewInt(9995877)
stubRpc.AddExpectedCall(batchingTest.NewGetBalanceCall(wethAddr, block, balance)) block := rpcblock.ByNumber(424)
stubRpc, game := setupFaultDisputeGameTest(t, version)
actualBalance, actualAddr, err := game.GetBalance(context.Background(), block) stubRpc.SetResponse(fdgAddr, methodWETH, block, nil, []interface{}{wethAddr})
require.NoError(t, err) stubRpc.AddExpectedCall(batchingTest.NewGetBalanceCall(wethAddr, block, balance))
require.Equal(t, wethAddr, actualAddr)
require.Truef(t, balance.Cmp(actualBalance) == 0, "Expected balance %v but was %v", balance, actualBalance) actualBalance, actualAddr, err := game.GetBalance(context.Background(), block)
require.NoError(t, err)
require.Equal(t, wethAddr, actualAddr)
require.Truef(t, balance.Cmp(actualBalance) == 0, "Expected balance %v but was %v", balance, actualBalance)
})
}
} }
func TestCallResolveClaim(t *testing.T) { func TestCallResolveClaim(t *testing.T) {
stubRpc, game := setupFaultDisputeGameTest(t) for _, version := range versions {
stubRpc.SetResponse(fdgAddr, methodResolveClaim, rpcblock.Latest, []interface{}{big.NewInt(123), maxChildChecks}, nil) version := version
err := game.CallResolveClaim(context.Background(), 123) t.Run(version.version, func(t *testing.T) {
require.NoError(t, err) stubRpc, game := setupFaultDisputeGameTest(t, version)
if version.version == vers080 {
stubRpc.SetResponse(fdgAddr, methodResolveClaim, rpcblock.Latest, []interface{}{big.NewInt(123)}, nil)
} else {
stubRpc.SetResponse(fdgAddr, methodResolveClaim, rpcblock.Latest, []interface{}{big.NewInt(123), maxChildChecks}, nil)
}
err := game.CallResolveClaim(context.Background(), 123)
require.NoError(t, err)
})
}
} }
func TestResolveClaimTxTest(t *testing.T) { func TestResolveClaimTxTest(t *testing.T) {
stubRpc, game := setupFaultDisputeGameTest(t) for _, version := range versions {
stubRpc.SetResponse(fdgAddr, methodResolveClaim, rpcblock.Latest, []interface{}{big.NewInt(123), maxChildChecks}, nil) version := version
tx, err := game.ResolveClaimTx(123) t.Run(version.version, func(t *testing.T) {
require.NoError(t, err) stubRpc, game := setupFaultDisputeGameTest(t, version)
stubRpc.VerifyTxCandidate(tx) if version.version == vers080 {
stubRpc.SetResponse(fdgAddr, methodResolveClaim, rpcblock.Latest, []interface{}{big.NewInt(123)}, nil)
} else {
stubRpc.SetResponse(fdgAddr, methodResolveClaim, rpcblock.Latest, []interface{}{big.NewInt(123), maxChildChecks}, nil)
}
tx, err := game.ResolveClaimTx(123)
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx)
})
}
} }
func TestResolveTx(t *testing.T) { func TestResolveTx(t *testing.T) {
stubRpc, game := setupFaultDisputeGameTest(t) for _, version := range versions {
stubRpc.SetResponse(fdgAddr, methodResolve, rpcblock.Latest, nil, nil) version := version
tx, err := game.ResolveTx() t.Run(version.version, func(t *testing.T) {
require.NoError(t, err) stubRpc, game := setupFaultDisputeGameTest(t, version)
stubRpc.VerifyTxCandidate(tx) stubRpc.SetResponse(fdgAddr, methodResolve, rpcblock.Latest, nil, nil)
tx, err := game.ResolveTx()
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx)
})
}
} }
func TestAttackTx(t *testing.T) { func TestAttackTx(t *testing.T) {
stubRpc, game := setupFaultDisputeGameTest(t) for _, version := range versions {
value := common.Hash{0xaa} version := version
stubRpc.SetResponse(fdgAddr, methodAttack, rpcblock.Latest, []interface{}{big.NewInt(111), value}, nil) t.Run(version.version, func(t *testing.T) {
tx, err := game.AttackTx(111, value) stubRpc, game := setupFaultDisputeGameTest(t, version)
require.NoError(t, err) value := common.Hash{0xaa}
stubRpc.VerifyTxCandidate(tx) stubRpc.SetResponse(fdgAddr, methodAttack, rpcblock.Latest, []interface{}{big.NewInt(111), value}, nil)
tx, err := game.AttackTx(111, value)
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx)
})
}
} }
func TestDefendTx(t *testing.T) { func TestDefendTx(t *testing.T) {
stubRpc, game := setupFaultDisputeGameTest(t) for _, version := range versions {
value := common.Hash{0xaa} version := version
stubRpc.SetResponse(fdgAddr, methodDefend, rpcblock.Latest, []interface{}{big.NewInt(111), value}, nil) t.Run(version.version, func(t *testing.T) {
tx, err := game.DefendTx(111, value) stubRpc, game := setupFaultDisputeGameTest(t, version)
require.NoError(t, err) value := common.Hash{0xaa}
stubRpc.VerifyTxCandidate(tx) stubRpc.SetResponse(fdgAddr, methodDefend, rpcblock.Latest, []interface{}{big.NewInt(111), value}, nil)
tx, err := game.DefendTx(111, value)
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx)
})
}
} }
func TestStepTx(t *testing.T) { func TestStepTx(t *testing.T) {
stubRpc, game := setupFaultDisputeGameTest(t) for _, version := range versions {
stateData := []byte{1, 2, 3} version := version
proofData := []byte{4, 5, 6, 7, 8, 9} t.Run(version.version, func(t *testing.T) {
stubRpc.SetResponse(fdgAddr, methodStep, rpcblock.Latest, []interface{}{big.NewInt(111), true, stateData, proofData}, nil) stubRpc, game := setupFaultDisputeGameTest(t, version)
tx, err := game.StepTx(111, true, stateData, proofData) stateData := []byte{1, 2, 3}
require.NoError(t, err) proofData := []byte{4, 5, 6, 7, 8, 9}
stubRpc.VerifyTxCandidate(tx) stubRpc.SetResponse(fdgAddr, methodStep, rpcblock.Latest, []interface{}{big.NewInt(111), true, stateData, proofData}, nil)
tx, err := game.StepTx(111, true, stateData, proofData)
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx)
})
}
} }
func expectGetClaim(stubRpc *batchingTest.AbiBasedRpc, block rpcblock.Block, claim faultTypes.Claim) { func expectGetClaim(stubRpc *batchingTest.AbiBasedRpc, block rpcblock.Block, claim faultTypes.Claim) {
...@@ -317,171 +423,237 @@ func expectGetClaim(stubRpc *batchingTest.AbiBasedRpc, block rpcblock.Block, cla ...@@ -317,171 +423,237 @@ func expectGetClaim(stubRpc *batchingTest.AbiBasedRpc, block rpcblock.Block, cla
} }
func TestGetBlockRange(t *testing.T) { func TestGetBlockRange(t *testing.T) {
stubRpc, contract := setupFaultDisputeGameTest(t) for _, version := range versions {
expectedStart := uint64(65) version := version
expectedEnd := uint64(102) t.Run(version.version, func(t *testing.T) {
stubRpc.SetResponse(fdgAddr, methodStartingBlockNumber, rpcblock.Latest, nil, []interface{}{new(big.Int).SetUint64(expectedStart)}) stubRpc, contract := setupFaultDisputeGameTest(t, version)
stubRpc.SetResponse(fdgAddr, methodL2BlockNumber, rpcblock.Latest, nil, []interface{}{new(big.Int).SetUint64(expectedEnd)}) expectedStart := uint64(65)
start, end, err := contract.GetBlockRange(context.Background()) expectedEnd := uint64(102)
require.NoError(t, err) stubRpc.SetResponse(fdgAddr, methodStartingBlockNumber, rpcblock.Latest, nil, []interface{}{new(big.Int).SetUint64(expectedStart)})
require.Equal(t, expectedStart, start) stubRpc.SetResponse(fdgAddr, methodL2BlockNumber, rpcblock.Latest, nil, []interface{}{new(big.Int).SetUint64(expectedEnd)})
require.Equal(t, expectedEnd, end) start, end, err := contract.GetBlockRange(context.Background())
require.NoError(t, err)
require.Equal(t, expectedStart, start)
require.Equal(t, expectedEnd, end)
})
}
} }
func TestGetSplitDepth(t *testing.T) { func TestGetSplitDepth(t *testing.T) {
stubRpc, contract := setupFaultDisputeGameTest(t) for _, version := range versions {
expectedSplitDepth := faultTypes.Depth(15) version := version
stubRpc.SetResponse(fdgAddr, methodSplitDepth, rpcblock.Latest, nil, []interface{}{new(big.Int).SetUint64(uint64(expectedSplitDepth))}) t.Run(version.version, func(t *testing.T) {
splitDepth, err := contract.GetSplitDepth(context.Background()) stubRpc, contract := setupFaultDisputeGameTest(t, version)
require.NoError(t, err) expectedSplitDepth := faultTypes.Depth(15)
require.Equal(t, expectedSplitDepth, splitDepth) stubRpc.SetResponse(fdgAddr, methodSplitDepth, rpcblock.Latest, nil, []interface{}{new(big.Int).SetUint64(uint64(expectedSplitDepth))})
splitDepth, err := contract.GetSplitDepth(context.Background())
require.NoError(t, err)
require.Equal(t, expectedSplitDepth, splitDepth)
})
}
} }
func TestGetGameMetadata(t *testing.T) { func TestGetGameMetadata(t *testing.T) {
stubRpc, contract := setupFaultDisputeGameTest(t) for _, version := range versions {
expectedL1Head := common.Hash{0x0a, 0x0b} version := version
expectedL2BlockNumber := uint64(123) t.Run(version.version, func(t *testing.T) {
expectedMaxClockDuration := uint64(456) stubRpc, contract := setupFaultDisputeGameTest(t, version)
expectedRootClaim := common.Hash{0x01, 0x02} expectedL1Head := common.Hash{0x0a, 0x0b}
expectedStatus := types.GameStatusChallengerWon expectedL2BlockNumber := uint64(123)
block := rpcblock.ByNumber(889) expectedMaxClockDuration := uint64(456)
stubRpc.SetResponse(fdgAddr, methodL1Head, block, nil, []interface{}{expectedL1Head}) expectedRootClaim := common.Hash{0x01, 0x02}
stubRpc.SetResponse(fdgAddr, methodL2BlockNumber, block, nil, []interface{}{new(big.Int).SetUint64(expectedL2BlockNumber)}) expectedStatus := types.GameStatusChallengerWon
stubRpc.SetResponse(fdgAddr, methodRootClaim, block, nil, []interface{}{expectedRootClaim}) block := rpcblock.ByNumber(889)
stubRpc.SetResponse(fdgAddr, methodStatus, block, nil, []interface{}{expectedStatus}) stubRpc.SetResponse(fdgAddr, methodL1Head, block, nil, []interface{}{expectedL1Head})
stubRpc.SetResponse(fdgAddr, methodMaxClockDuration, block, nil, []interface{}{expectedMaxClockDuration}) stubRpc.SetResponse(fdgAddr, methodL2BlockNumber, block, nil, []interface{}{new(big.Int).SetUint64(expectedL2BlockNumber)})
l1Head, l2BlockNumber, rootClaim, status, duration, err := contract.GetGameMetadata(context.Background(), block) stubRpc.SetResponse(fdgAddr, methodRootClaim, block, nil, []interface{}{expectedRootClaim})
require.NoError(t, err) stubRpc.SetResponse(fdgAddr, methodStatus, block, nil, []interface{}{expectedStatus})
require.Equal(t, expectedL1Head, l1Head) if version.version == vers080 {
require.Equal(t, expectedL2BlockNumber, l2BlockNumber) stubRpc.SetResponse(fdgAddr, methodGameDuration, block, nil, []interface{}{expectedMaxClockDuration * 2})
require.Equal(t, expectedRootClaim, rootClaim) } else {
require.Equal(t, expectedStatus, status) stubRpc.SetResponse(fdgAddr, methodMaxClockDuration, block, nil, []interface{}{expectedMaxClockDuration})
require.Equal(t, expectedMaxClockDuration, duration) }
l1Head, l2BlockNumber, rootClaim, status, duration, err := contract.GetGameMetadata(context.Background(), block)
require.NoError(t, err)
require.Equal(t, expectedL1Head, l1Head)
require.Equal(t, expectedL2BlockNumber, l2BlockNumber)
require.Equal(t, expectedRootClaim, rootClaim)
require.Equal(t, expectedStatus, status)
require.Equal(t, expectedMaxClockDuration, duration)
})
}
} }
func TestGetStartingRootHash(t *testing.T) { func TestGetStartingRootHash(t *testing.T) {
stubRpc, contract := setupFaultDisputeGameTest(t) for _, version := range versions {
expectedOutputRoot := common.HexToHash("0x1234") version := version
stubRpc.SetResponse(fdgAddr, methodStartingRootHash, rpcblock.Latest, nil, []interface{}{expectedOutputRoot}) t.Run(version.version, func(t *testing.T) {
startingOutputRoot, err := contract.GetStartingRootHash(context.Background()) stubRpc, contract := setupFaultDisputeGameTest(t, version)
require.NoError(t, err) expectedOutputRoot := common.HexToHash("0x1234")
require.Equal(t, expectedOutputRoot, startingOutputRoot) stubRpc.SetResponse(fdgAddr, methodStartingRootHash, rpcblock.Latest, nil, []interface{}{expectedOutputRoot})
startingOutputRoot, err := contract.GetStartingRootHash(context.Background())
require.NoError(t, err)
require.Equal(t, expectedOutputRoot, startingOutputRoot)
})
}
} }
func TestFaultDisputeGame_UpdateOracleTx(t *testing.T) { func TestFaultDisputeGame_UpdateOracleTx(t *testing.T) {
t.Run("Local", func(t *testing.T) { for _, version := range versions {
stubRpc, game := setupFaultDisputeGameTest(t) version := version
data := faultTypes.NewPreimageOracleData(common.Hash{0x01, 0xbc}.Bytes(), []byte{1, 2, 3, 4, 5, 6, 7}, 16) t.Run(version.version, func(t *testing.T) {
claimIdx := uint64(6) t.Run("Local", func(t *testing.T) {
stubRpc.SetResponse(fdgAddr, methodAddLocalData, rpcblock.Latest, []interface{}{ stubRpc, game := setupFaultDisputeGameTest(t, version)
data.GetIdent(), data := faultTypes.NewPreimageOracleData(common.Hash{0x01, 0xbc}.Bytes(), []byte{1, 2, 3, 4, 5, 6, 7}, 16)
new(big.Int).SetUint64(claimIdx), claimIdx := uint64(6)
new(big.Int).SetUint64(uint64(data.OracleOffset)), stubRpc.SetResponse(fdgAddr, methodAddLocalData, rpcblock.Latest, []interface{}{
}, nil) data.GetIdent(),
tx, err := game.UpdateOracleTx(context.Background(), claimIdx, data) new(big.Int).SetUint64(claimIdx),
require.NoError(t, err) new(big.Int).SetUint64(uint64(data.OracleOffset)),
stubRpc.VerifyTxCandidate(tx) }, nil)
}) tx, err := game.UpdateOracleTx(context.Background(), claimIdx, data)
require.NoError(t, err)
t.Run("Global", func(t *testing.T) { stubRpc.VerifyTxCandidate(tx)
stubRpc, game := setupFaultDisputeGameTest(t) })
data := faultTypes.NewPreimageOracleData(common.Hash{0x02, 0xbc}.Bytes(), []byte{1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15}, 16)
claimIdx := uint64(6) t.Run("Global", func(t *testing.T) {
stubRpc.SetResponse(fdgAddr, methodVM, rpcblock.Latest, nil, []interface{}{vmAddr}) stubRpc, game := setupFaultDisputeGameTest(t, version)
stubRpc.SetResponse(vmAddr, methodOracle, rpcblock.Latest, nil, []interface{}{oracleAddr}) data := faultTypes.NewPreimageOracleData(common.Hash{0x02, 0xbc}.Bytes(), []byte{1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15}, 16)
stubRpc.SetResponse(oracleAddr, methodLoadKeccak256PreimagePart, rpcblock.Latest, []interface{}{ claimIdx := uint64(6)
new(big.Int).SetUint64(uint64(data.OracleOffset)), stubRpc.SetResponse(fdgAddr, methodVM, rpcblock.Latest, nil, []interface{}{vmAddr})
data.GetPreimageWithoutSize(), stubRpc.SetResponse(vmAddr, methodOracle, rpcblock.Latest, nil, []interface{}{oracleAddr})
}, nil) stubRpc.SetResponse(oracleAddr, methodLoadKeccak256PreimagePart, rpcblock.Latest, []interface{}{
tx, err := game.UpdateOracleTx(context.Background(), claimIdx, data) new(big.Int).SetUint64(uint64(data.OracleOffset)),
require.NoError(t, err) data.GetPreimageWithoutSize(),
stubRpc.VerifyTxCandidate(tx) }, nil)
}) tx, err := game.UpdateOracleTx(context.Background(), claimIdx, data)
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx)
})
})
}
} }
func TestFaultDisputeGame_GetCredit(t *testing.T) { func TestFaultDisputeGame_GetCredit(t *testing.T) {
stubRpc, game := setupFaultDisputeGameTest(t) for _, version := range versions {
addr := common.Address{0x01} version := version
expectedCredit := big.NewInt(4284) t.Run(version.version, func(t *testing.T) {
expectedStatus := types.GameStatusChallengerWon stubRpc, game := setupFaultDisputeGameTest(t, version)
stubRpc.SetResponse(fdgAddr, methodCredit, rpcblock.Latest, []interface{}{addr}, []interface{}{expectedCredit}) addr := common.Address{0x01}
stubRpc.SetResponse(fdgAddr, methodStatus, rpcblock.Latest, nil, []interface{}{expectedStatus}) expectedCredit := big.NewInt(4284)
expectedStatus := types.GameStatusChallengerWon
actualCredit, actualStatus, err := game.GetCredit(context.Background(), addr) stubRpc.SetResponse(fdgAddr, methodCredit, rpcblock.Latest, []interface{}{addr}, []interface{}{expectedCredit})
require.NoError(t, err) stubRpc.SetResponse(fdgAddr, methodStatus, rpcblock.Latest, nil, []interface{}{expectedStatus})
require.Equal(t, expectedCredit, actualCredit)
require.Equal(t, expectedStatus, actualStatus) actualCredit, actualStatus, err := game.GetCredit(context.Background(), addr)
require.NoError(t, err)
require.Equal(t, expectedCredit, actualCredit)
require.Equal(t, expectedStatus, actualStatus)
})
}
} }
func TestFaultDisputeGame_GetCredits(t *testing.T) { func TestFaultDisputeGame_GetCredits(t *testing.T) {
stubRpc, game := setupFaultDisputeGameTest(t) for _, version := range versions {
version := version
t.Run(version.version, func(t *testing.T) {
stubRpc, game := setupFaultDisputeGameTest(t, version)
block := rpcblock.ByNumber(482) block := rpcblock.ByNumber(482)
addrs := []common.Address{{0x01}, {0x02}, {0x03}} addrs := []common.Address{{0x01}, {0x02}, {0x03}}
expected := []*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(0)} expected := []*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(0)}
for i, addr := range addrs { for i, addr := range addrs {
stubRpc.SetResponse(fdgAddr, methodCredit, block, []interface{}{addr}, []interface{}{expected[i]}) stubRpc.SetResponse(fdgAddr, methodCredit, block, []interface{}{addr}, []interface{}{expected[i]})
} }
actual, err := game.GetCredits(context.Background(), block, addrs...) actual, err := game.GetCredits(context.Background(), block, addrs...)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, len(expected), len(actual)) require.Equal(t, len(expected), len(actual))
for i := range expected { for i := range expected {
require.Zerof(t, expected[i].Cmp(actual[i]), "expected: %v actual: %v", expected[i], actual[i]) require.Zerof(t, expected[i].Cmp(actual[i]), "expected: %v actual: %v", expected[i], actual[i])
}
})
} }
} }
func TestFaultDisputeGame_ClaimCreditTx(t *testing.T) { func TestFaultDisputeGame_ClaimCreditTx(t *testing.T) {
t.Run("Success", func(t *testing.T) { for _, version := range versions {
stubRpc, game := setupFaultDisputeGameTest(t) version := version
addr := common.Address{0xaa} t.Run(version.version, func(t *testing.T) {
t.Run("Success", func(t *testing.T) {
stubRpc.SetResponse(fdgAddr, methodClaimCredit, rpcblock.Latest, []interface{}{addr}, nil) stubRpc, game := setupFaultDisputeGameTest(t, version)
tx, err := game.ClaimCreditTx(context.Background(), addr) addr := common.Address{0xaa}
require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx) stubRpc.SetResponse(fdgAddr, methodClaimCredit, rpcblock.Latest, []interface{}{addr}, nil)
}) tx, err := game.ClaimCreditTx(context.Background(), addr)
require.NoError(t, err)
t.Run("SimulationFails", func(t *testing.T) { stubRpc.VerifyTxCandidate(tx)
stubRpc, game := setupFaultDisputeGameTest(t) })
addr := common.Address{0xaa}
t.Run("SimulationFails", func(t *testing.T) {
stubRpc.SetError(fdgAddr, methodClaimCredit, rpcblock.Latest, []interface{}{addr}, errors.New("still locked")) stubRpc, game := setupFaultDisputeGameTest(t, version)
tx, err := game.ClaimCreditTx(context.Background(), addr) addr := common.Address{0xaa}
require.ErrorIs(t, err, ErrSimulationFailed)
require.Equal(t, txmgr.TxCandidate{}, tx) stubRpc.SetError(fdgAddr, methodClaimCredit, rpcblock.Latest, []interface{}{addr}, errors.New("still locked"))
}) tx, err := game.ClaimCreditTx(context.Background(), addr)
require.ErrorIs(t, err, ErrSimulationFailed)
require.Equal(t, txmgr.TxCandidate{}, tx)
})
})
}
} }
func TestFaultDisputeGame_IsResolved(t *testing.T) { func TestFaultDisputeGame_IsResolved(t *testing.T) {
stubRpc, game := setupFaultDisputeGameTest(t) for _, version := range versions {
version := version
t.Run(version.version, func(t *testing.T) {
stubRpc, game := setupFaultDisputeGameTest(t, version)
block := rpcblock.ByNumber(482) block := rpcblock.ByNumber(482)
claims := []faultTypes.Claim{ claims := []faultTypes.Claim{
{ContractIndex: 1}, {ContractIndex: 1},
{ContractIndex: 5}, {ContractIndex: 5},
{ContractIndex: 13}, {ContractIndex: 13},
} }
claimIdxs := []*big.Int{big.NewInt(1), big.NewInt(5), big.NewInt(13)} claimIdxs := []*big.Int{big.NewInt(1), big.NewInt(5), big.NewInt(13)}
expected := []bool{false, true, true} expected := []bool{false, true, true}
for i, idx := range claimIdxs { if version.version == vers080 {
stubRpc.SetResponse(fdgAddr, methodResolvedSubgames, block, []interface{}{idx}, []interface{}{expected[i]}) claimCount := 14
} stubRpc.SetResponse(fdgAddr, methodClaimCount, block, nil, []interface{}{big.NewInt(int64(claimCount))})
for idx := 0; idx < claimCount; idx++ {
bond := big.NewInt(42)
if idx == 5 || idx == 13 { // The two claims expected to be resolved
bond = resolvedBondAmount
}
expectGetClaim(stubRpc, block, faultTypes.Claim{
ContractIndex: idx,
ClaimData: faultTypes.ClaimData{
Bond: bond,
},
})
}
} else {
for i, idx := range claimIdxs {
stubRpc.SetResponse(fdgAddr, methodResolvedSubgames, block, []interface{}{idx}, []interface{}{expected[i]})
}
}
actual, err := game.IsResolved(context.Background(), block, claims...) actual, err := game.IsResolved(context.Background(), block, claims...)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, len(expected), len(actual)) require.Equal(t, len(expected), len(actual))
for i := range expected { for i := range expected {
require.Equal(t, expected[i], actual[i]) require.Equal(t, expected[i], actual[i])
}
})
} }
} }
func setupFaultDisputeGameTest(t *testing.T) (*batchingTest.AbiBasedRpc, *FaultDisputeGameContract) { func setupFaultDisputeGameTest(t *testing.T, version contractVersion) (*batchingTest.AbiBasedRpc, FaultDisputeGameContract) {
fdgAbi := snapshots.LoadFaultDisputeGameABI() fdgAbi := version.loadAbi()
vmAbi := snapshots.LoadMIPSABI() vmAbi := snapshots.LoadMIPSABI()
oracleAbi := snapshots.LoadPreimageOracleABI() oracleAbi := snapshots.LoadPreimageOracleABI()
...@@ -490,6 +662,9 @@ func setupFaultDisputeGameTest(t *testing.T) (*batchingTest.AbiBasedRpc, *FaultD ...@@ -490,6 +662,9 @@ func setupFaultDisputeGameTest(t *testing.T) (*batchingTest.AbiBasedRpc, *FaultD
stubRpc.AddContract(vmAddr, vmAbi) stubRpc.AddContract(vmAddr, vmAbi)
stubRpc.AddContract(oracleAddr, oracleAbi) stubRpc.AddContract(oracleAddr, oracleAbi)
caller := batching.NewMultiCaller(stubRpc, batching.DefaultBatchSize) caller := batching.NewMultiCaller(stubRpc, batching.DefaultBatchSize)
game := NewFaultDisputeGameContract(contractMetrics.NoopContractMetrics, fdgAddr, caller)
stubRpc.SetResponse(fdgAddr, methodVersion, rpcblock.Latest, nil, []interface{}{version.version})
game, err := NewFaultDisputeGameContract(context.Background(), contractMetrics.NoopContractMetrics, fdgAddr, caller)
require.NoError(t, err)
return stubRpc, game return stubRpc, game
} }
...@@ -120,7 +120,10 @@ func registerAlphabet( ...@@ -120,7 +120,10 @@ func registerAlphabet(
claimants []common.Address, claimants []common.Address,
) error { ) error {
playerCreator := func(game types.GameMetadata, dir string) (scheduler.GamePlayer, error) { playerCreator := func(game types.GameMetadata, dir string) (scheduler.GamePlayer, error) {
contract := contracts.NewFaultDisputeGameContract(m, game.Proxy, caller) contract, err := contracts.NewFaultDisputeGameContract(ctx, m, game.Proxy, caller)
if err != nil {
return nil, fmt.Errorf("failed to create fault dispute game contract: %w", err)
}
oracle, err := contract.GetOracle(ctx) oracle, err := contract.GetOracle(ctx)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to load oracle for game %v: %w", game.Proxy, err) return nil, fmt.Errorf("failed to load oracle for game %v: %w", game.Proxy, err)
...@@ -157,7 +160,7 @@ func registerAlphabet( ...@@ -157,7 +160,7 @@ func registerAlphabet(
registry.RegisterGameType(faultTypes.AlphabetGameType, playerCreator) registry.RegisterGameType(faultTypes.AlphabetGameType, playerCreator)
contractCreator := func(game types.GameMetadata) (claims.BondContract, error) { contractCreator := func(game types.GameMetadata) (claims.BondContract, error) {
return contracts.NewFaultDisputeGameContract(m, game.Proxy, caller), nil return contracts.NewFaultDisputeGameContract(ctx, m, game.Proxy, caller)
} }
registry.RegisterBondContract(faultTypes.AlphabetGameType, contractCreator) registry.RegisterBondContract(faultTypes.AlphabetGameType, contractCreator)
return nil return nil
...@@ -168,7 +171,10 @@ func registerOracle(ctx context.Context, m metrics.Metricer, oracles OracleRegis ...@@ -168,7 +171,10 @@ func registerOracle(ctx context.Context, m metrics.Metricer, oracles OracleRegis
if err != nil { if err != nil {
return fmt.Errorf("failed to load implementation for game type %v: %w", gameType, err) return fmt.Errorf("failed to load implementation for game type %v: %w", gameType, err)
} }
contract := contracts.NewFaultDisputeGameContract(m, implAddr, caller) contract, err := contracts.NewFaultDisputeGameContract(ctx, m, implAddr, caller)
if err != nil {
return fmt.Errorf("failed to create fault dispute game contracts: %w", err)
}
oracle, err := contract.GetOracle(ctx) oracle, err := contract.GetOracle(ctx)
if err != nil { if err != nil {
return fmt.Errorf("failed to load oracle address: %w", err) return fmt.Errorf("failed to load oracle address: %w", err)
...@@ -199,7 +205,10 @@ func registerAsterisc( ...@@ -199,7 +205,10 @@ func registerAsterisc(
) error { ) error {
asteriscPrestateProvider := asterisc.NewPrestateProvider(cfg.AsteriscAbsolutePreState) asteriscPrestateProvider := asterisc.NewPrestateProvider(cfg.AsteriscAbsolutePreState)
playerCreator := func(game types.GameMetadata, dir string) (scheduler.GamePlayer, error) { playerCreator := func(game types.GameMetadata, dir string) (scheduler.GamePlayer, error) {
contract := contracts.NewFaultDisputeGameContract(m, game.Proxy, caller) contract, err := contracts.NewFaultDisputeGameContract(ctx, m, game.Proxy, caller)
if err != nil {
return nil, fmt.Errorf("failed to create fault dispute game contracts: %w", err)
}
oracle, err := contract.GetOracle(ctx) oracle, err := contract.GetOracle(ctx)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to load oracle for game %v: %w", game.Proxy, err) return nil, fmt.Errorf("failed to load oracle for game %v: %w", game.Proxy, err)
...@@ -236,7 +245,7 @@ func registerAsterisc( ...@@ -236,7 +245,7 @@ func registerAsterisc(
registry.RegisterGameType(gameType, playerCreator) registry.RegisterGameType(gameType, playerCreator)
contractCreator := func(game types.GameMetadata) (claims.BondContract, error) { contractCreator := func(game types.GameMetadata) (claims.BondContract, error) {
return contracts.NewFaultDisputeGameContract(m, game.Proxy, caller), nil return contracts.NewFaultDisputeGameContract(ctx, m, game.Proxy, caller)
} }
registry.RegisterBondContract(gameType, contractCreator) registry.RegisterBondContract(gameType, contractCreator)
return nil return nil
...@@ -276,7 +285,10 @@ func registerCannon( ...@@ -276,7 +285,10 @@ func registerCannon(
return cannon.NewPrestateProvider(prestatePath), nil return cannon.NewPrestateProvider(prestatePath), nil
}) })
playerCreator := func(game types.GameMetadata, dir string) (scheduler.GamePlayer, error) { playerCreator := func(game types.GameMetadata, dir string) (scheduler.GamePlayer, error) {
contract := contracts.NewFaultDisputeGameContract(m, game.Proxy, caller) contract, err := contracts.NewFaultDisputeGameContract(ctx, m, game.Proxy, caller)
if err != nil {
return nil, fmt.Errorf("failed to create fault dispute game contracts: %w", err)
}
requiredPrestatehash, err := contract.GetAbsolutePrestateHash(ctx) requiredPrestatehash, err := contract.GetAbsolutePrestateHash(ctx)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to load prestate hash for game %v: %w", game.Proxy, err) return nil, fmt.Errorf("failed to load prestate hash for game %v: %w", game.Proxy, err)
...@@ -324,13 +336,13 @@ func registerCannon( ...@@ -324,13 +336,13 @@ func registerCannon(
registry.RegisterGameType(gameType, playerCreator) registry.RegisterGameType(gameType, playerCreator)
contractCreator := func(game types.GameMetadata) (claims.BondContract, error) { contractCreator := func(game types.GameMetadata) (claims.BondContract, error) {
return contracts.NewFaultDisputeGameContract(m, game.Proxy, caller), nil return contracts.NewFaultDisputeGameContract(ctx, m, game.Proxy, caller)
} }
registry.RegisterBondContract(gameType, contractCreator) registry.RegisterBondContract(gameType, contractCreator)
return nil return nil
} }
func loadL1Head(contract *contracts.FaultDisputeGameContract, ctx context.Context, l1HeaderSource L1HeaderSource) (eth.BlockID, error) { func loadL1Head(contract contracts.FaultDisputeGameContract, ctx context.Context, l1HeaderSource L1HeaderSource) (eth.BlockID, error) {
l1Head, err := contract.GetL1Head(ctx) l1Head, err := contract.GetL1Head(ctx)
if err != nil { if err != nil {
return eth.BlockID{}, fmt.Errorf("failed to load L1 head: %w", err) return eth.BlockID{}, fmt.Errorf("failed to load L1 head: %w", err)
......
...@@ -34,7 +34,7 @@ type GameCaller interface { ...@@ -34,7 +34,7 @@ type GameCaller interface {
type GameCallerCreator struct { type GameCallerCreator struct {
m GameCallerMetrics m GameCallerMetrics
cache *caching.LRUCache[common.Address, *contracts.FaultDisputeGameContract] cache *caching.LRUCache[common.Address, contracts.FaultDisputeGameContract]
caller *batching.MultiCaller caller *batching.MultiCaller
} }
...@@ -42,17 +42,20 @@ func NewGameCallerCreator(m GameCallerMetrics, caller *batching.MultiCaller) *Ga ...@@ -42,17 +42,20 @@ func NewGameCallerCreator(m GameCallerMetrics, caller *batching.MultiCaller) *Ga
return &GameCallerCreator{ return &GameCallerCreator{
m: m, m: m,
caller: caller, caller: caller,
cache: caching.NewLRUCache[common.Address, *contracts.FaultDisputeGameContract](m, metricsLabel, 100), cache: caching.NewLRUCache[common.Address, contracts.FaultDisputeGameContract](m, metricsLabel, 100),
} }
} }
func (g *GameCallerCreator) CreateContract(game gameTypes.GameMetadata) (GameCaller, error) { func (g *GameCallerCreator) CreateContract(ctx context.Context, game gameTypes.GameMetadata) (GameCaller, error) {
if fdg, ok := g.cache.Get(game.Proxy); ok { if fdg, ok := g.cache.Get(game.Proxy); ok {
return fdg, nil return fdg, nil
} }
switch game.GameType { switch game.GameType {
case faultTypes.CannonGameType, faultTypes.AsteriscGameType, faultTypes.AlphabetGameType: case faultTypes.CannonGameType, faultTypes.AsteriscGameType, faultTypes.AlphabetGameType:
fdg := contracts.NewFaultDisputeGameContract(g.m, game.Proxy, g.caller) fdg, err := contracts.NewFaultDisputeGameContract(ctx, g.m, game.Proxy, g.caller)
if err != nil {
return nil, fmt.Errorf("failed to create fault dispute game contract: %w", err)
}
g.cache.Add(game.Proxy, fdg) g.cache.Add(game.Proxy, fdg)
return fdg, nil return fdg, nil
default: default:
......
package extract package extract
import ( import (
"context"
"fmt" "fmt"
"testing" "testing"
contractMetrics "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics" contractMetrics "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts/metrics"
"github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum-optimism/optimism/op-bindings/bindings"
...@@ -49,13 +51,13 @@ func TestMetadataCreator_CreateContract(t *testing.T) { ...@@ -49,13 +51,13 @@ func TestMetadataCreator_CreateContract(t *testing.T) {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
caller, metrics := setupMetadataLoaderTest(t) caller, metrics := setupMetadataLoaderTest(t)
creator := NewGameCallerCreator(metrics, caller) creator := NewGameCallerCreator(metrics, caller)
_, err := creator.CreateContract(test.game) _, err := creator.CreateContract(context.Background(), test.game)
require.Equal(t, test.expectedErr, err) require.Equal(t, test.expectedErr, err)
if test.expectedErr == nil { if test.expectedErr == nil {
require.Equal(t, 1, metrics.cacheAddCalls) require.Equal(t, 1, metrics.cacheAddCalls)
require.Equal(t, 1, metrics.cacheGetCalls) require.Equal(t, 1, metrics.cacheGetCalls)
} }
_, err = creator.CreateContract(test.game) _, err = creator.CreateContract(context.Background(), test.game)
require.Equal(t, test.expectedErr, err) require.Equal(t, test.expectedErr, err)
if test.expectedErr == nil { if test.expectedErr == nil {
require.Equal(t, 1, metrics.cacheAddCalls) require.Equal(t, 1, metrics.cacheAddCalls)
...@@ -70,6 +72,7 @@ func setupMetadataLoaderTest(t *testing.T) (*batching.MultiCaller, *mockCacheMet ...@@ -70,6 +72,7 @@ func setupMetadataLoaderTest(t *testing.T) (*batching.MultiCaller, *mockCacheMet
require.NoError(t, err) require.NoError(t, err)
stubRpc := batchingTest.NewAbiBasedRpc(t, fdgAddr, fdgAbi) stubRpc := batchingTest.NewAbiBasedRpc(t, fdgAddr, fdgAbi)
caller := batching.NewMultiCaller(stubRpc, batching.DefaultBatchSize) caller := batching.NewMultiCaller(stubRpc, batching.DefaultBatchSize)
stubRpc.SetResponse(fdgAddr, "version", rpcblock.Latest, nil, []interface{}{"0.18.0"})
return caller, &mockCacheMetrics{} return caller, &mockCacheMetrics{}
} }
......
...@@ -13,7 +13,7 @@ import ( ...@@ -13,7 +13,7 @@ import (
) )
type ( type (
CreateGameCaller func(game gameTypes.GameMetadata) (GameCaller, error) CreateGameCaller func(ctx context.Context, game gameTypes.GameMetadata) (GameCaller, error)
FactoryGameFetcher func(ctx context.Context, blockHash common.Hash, earliestTimestamp uint64) ([]gameTypes.GameMetadata, error) FactoryGameFetcher func(ctx context.Context, blockHash common.Hash, earliestTimestamp uint64) ([]gameTypes.GameMetadata, error)
) )
...@@ -48,7 +48,7 @@ func (e *Extractor) Extract(ctx context.Context, blockHash common.Hash, minTimes ...@@ -48,7 +48,7 @@ func (e *Extractor) Extract(ctx context.Context, blockHash common.Hash, minTimes
func (e *Extractor) enrichGames(ctx context.Context, blockHash common.Hash, games []gameTypes.GameMetadata) []*monTypes.EnrichedGameData { func (e *Extractor) enrichGames(ctx context.Context, blockHash common.Hash, games []gameTypes.GameMetadata) []*monTypes.EnrichedGameData {
var enrichedGames []*monTypes.EnrichedGameData var enrichedGames []*monTypes.EnrichedGameData
for _, game := range games { for _, game := range games {
caller, err := e.createContract(game) caller, err := e.createContract(ctx, game)
if err != nil { if err != nil {
e.logger.Error("Failed to create game caller", "err", err) e.logger.Error("Failed to create game caller", "err", err)
continue continue
......
...@@ -167,7 +167,7 @@ type mockGameCallerCreator struct { ...@@ -167,7 +167,7 @@ type mockGameCallerCreator struct {
caller *mockGameCaller caller *mockGameCaller
} }
func (m *mockGameCallerCreator) CreateGameCaller(_ gameTypes.GameMetadata) (GameCaller, error) { func (m *mockGameCallerCreator) CreateGameCaller(_ context.Context, _ gameTypes.GameMetadata) (GameCaller, error) {
m.calls++ m.calls++
if m.err != nil { if m.err != nil {
return nil, m.err return nil, m.err
......
...@@ -39,7 +39,8 @@ func (g *OutputAlphabetGameHelper) StartChallenger( ...@@ -39,7 +39,8 @@ func (g *OutputAlphabetGameHelper) StartChallenger(
func (g *OutputAlphabetGameHelper) CreateHonestActor(ctx context.Context, l2Node string) *OutputHonestHelper { func (g *OutputAlphabetGameHelper) CreateHonestActor(ctx context.Context, l2Node string) *OutputHonestHelper {
logger := testlog.Logger(g.T, log.LevelInfo).New("role", "HonestHelper", "game", g.Addr) logger := testlog.Logger(g.T, log.LevelInfo).New("role", "HonestHelper", "game", g.Addr)
caller := batching.NewMultiCaller(g.System.NodeClient("l1").Client(), batching.DefaultBatchSize) caller := batching.NewMultiCaller(g.System.NodeClient("l1").Client(), batching.DefaultBatchSize)
contract := contracts.NewFaultDisputeGameContract(contractMetrics.NoopContractMetrics, g.Addr, caller) contract, err := contracts.NewFaultDisputeGameContract(ctx, contractMetrics.NoopContractMetrics, g.Addr, caller)
g.Require.NoError(err)
prestateBlock, poststateBlock, err := contract.GetBlockRange(ctx) prestateBlock, poststateBlock, err := contract.GetBlockRange(ctx)
g.Require.NoError(err, "Get block range") g.Require.NoError(err, "Get block range")
splitDepth := g.SplitDepth(ctx) splitDepth := g.SplitDepth(ctx)
......
...@@ -63,7 +63,8 @@ func (g *OutputCannonGameHelper) CreateHonestActor(ctx context.Context, l2Node s ...@@ -63,7 +63,8 @@ func (g *OutputCannonGameHelper) CreateHonestActor(ctx context.Context, l2Node s
logger := testlog.Logger(g.T, log.LevelInfo).New("role", "HonestHelper", "game", g.Addr) logger := testlog.Logger(g.T, log.LevelInfo).New("role", "HonestHelper", "game", g.Addr)
l2Client := g.System.NodeClient(l2Node) l2Client := g.System.NodeClient(l2Node)
caller := batching.NewMultiCaller(g.System.NodeClient("l1").Client(), batching.DefaultBatchSize) caller := batching.NewMultiCaller(g.System.NodeClient("l1").Client(), batching.DefaultBatchSize)
contract := contracts.NewFaultDisputeGameContract(contractMetrics.NoopContractMetrics, g.Addr, caller) contract, err := contracts.NewFaultDisputeGameContract(ctx, contractMetrics.NoopContractMetrics, g.Addr, caller)
g.Require.NoError(err)
prestateBlock, poststateBlock, err := contract.GetBlockRange(ctx) prestateBlock, poststateBlock, err := contract.GetBlockRange(ctx)
g.Require.NoError(err, "Failed to load block range") g.Require.NoError(err, "Failed to load block range")
...@@ -288,7 +289,8 @@ func (g *OutputCannonGameHelper) createCannonTraceProvider(ctx context.Context, ...@@ -288,7 +289,8 @@ func (g *OutputCannonGameHelper) createCannonTraceProvider(ctx context.Context,
caller := batching.NewMultiCaller(g.System.NodeClient("l1").Client(), batching.DefaultBatchSize) caller := batching.NewMultiCaller(g.System.NodeClient("l1").Client(), batching.DefaultBatchSize)
l2Client := g.System.NodeClient(l2Node) l2Client := g.System.NodeClient(l2Node)
contract := contracts.NewFaultDisputeGameContract(contractMetrics.NoopContractMetrics, g.Addr, caller) contract, err := contracts.NewFaultDisputeGameContract(ctx, contractMetrics.NoopContractMetrics, g.Addr, caller)
g.Require.NoError(err)
prestateBlock, poststateBlock, err := contract.GetBlockRange(ctx) prestateBlock, poststateBlock, err := contract.GetBlockRange(ctx)
g.Require.NoError(err, "Failed to load block range") g.Require.NoError(err, "Failed to load block range")
......
...@@ -713,7 +713,8 @@ func (g *OutputGameHelper) UploadPreimage(ctx context.Context, data *types.Preim ...@@ -713,7 +713,8 @@ func (g *OutputGameHelper) UploadPreimage(ctx context.Context, data *types.Preim
func (g *OutputGameHelper) oracle(ctx context.Context) *contracts.PreimageOracleContract { func (g *OutputGameHelper) oracle(ctx context.Context) *contracts.PreimageOracleContract {
caller := batching.NewMultiCaller(g.System.NodeClient("l1").Client(), batching.DefaultBatchSize) caller := batching.NewMultiCaller(g.System.NodeClient("l1").Client(), batching.DefaultBatchSize)
contract := contracts.NewFaultDisputeGameContract(contractMetrics.NoopContractMetrics, g.Addr, caller) contract, err := contracts.NewFaultDisputeGameContract(ctx, contractMetrics.NoopContractMetrics, g.Addr, caller)
g.Require.NoError(err)
oracle, err := contract.GetOracle(ctx) oracle, err := contract.GetOracle(ctx)
g.Require.NoError(err, "Failed to create oracle contract") g.Require.NoError(err, "Failed to create oracle contract")
return oracle return oracle
......
...@@ -17,11 +17,11 @@ type OutputHonestHelper struct { ...@@ -17,11 +17,11 @@ type OutputHonestHelper struct {
t *testing.T t *testing.T
require *require.Assertions require *require.Assertions
game *OutputGameHelper game *OutputGameHelper
contract *contracts.FaultDisputeGameContract contract contracts.FaultDisputeGameContract
correctTrace types.TraceAccessor correctTrace types.TraceAccessor
} }
func NewOutputHonestHelper(t *testing.T, require *require.Assertions, game *OutputGameHelper, contract *contracts.FaultDisputeGameContract, correctTrace types.TraceAccessor) *OutputHonestHelper { func NewOutputHonestHelper(t *testing.T, require *require.Assertions, game *OutputGameHelper, contract contracts.FaultDisputeGameContract, correctTrace types.TraceAccessor) *OutputHonestHelper {
return &OutputHonestHelper{ return &OutputHonestHelper{
t: t, t: t,
require: require, require: require,
......
...@@ -63,3 +63,7 @@ func (c *CallResult) GetBytes32(i int) [32]byte { ...@@ -63,3 +63,7 @@ func (c *CallResult) GetBytes32(i int) [32]byte {
func (c *CallResult) GetBytes32Slice(i int) [][32]byte { func (c *CallResult) GetBytes32Slice(i int) [][32]byte {
return *abi.ConvertType(c.out[i], new([][32]byte)).(*[][32]byte) return *abi.ConvertType(c.out[i], new([][32]byte)).(*[][32]byte)
} }
func (c *CallResult) GetString(i int) string {
return *abi.ConvertType(c.out[i], new(string)).(*string)
}
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