Commit 5e23d3a7 authored by Adrian Sutton's avatar Adrian Sutton Committed by GitHub

e2e: Convert more fault proof tests to use the custom contract bindings. (#10716)

parent f638bfa2
...@@ -355,7 +355,7 @@ func (f *FaultDisputeGameContractLatest) getDelayedWETH(ctx context.Context, blo ...@@ -355,7 +355,7 @@ func (f *FaultDisputeGameContractLatest) getDelayedWETH(ctx context.Context, blo
func (f *FaultDisputeGameContractLatest) 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 {
return nil, err return nil, err
} }
...@@ -458,7 +458,7 @@ func (f *FaultDisputeGameContractLatest) IsResolved(ctx context.Context, block r ...@@ -458,7 +458,7 @@ func (f *FaultDisputeGameContractLatest) IsResolved(ctx context.Context, block r
return resolved, nil return resolved, nil
} }
func (f *FaultDisputeGameContractLatest) 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)
...@@ -623,4 +623,5 @@ type FaultDisputeGameContract interface { ...@@ -623,4 +623,5 @@ type FaultDisputeGameContract interface {
ResolveClaimTx(claimIdx uint64) (txmgr.TxCandidate, error) ResolveClaimTx(claimIdx uint64) (txmgr.TxCandidate, error)
CallResolve(ctx context.Context) (gameTypes.GameStatus, error) CallResolve(ctx context.Context) (gameTypes.GameStatus, error)
ResolveTx() (txmgr.TxCandidate, error) ResolveTx() (txmgr.TxCandidate, error)
Vm(ctx context.Context) (*VMContract, error)
} }
...@@ -29,6 +29,10 @@ func NewVMContract(addr common.Address, caller *batching.MultiCaller) *VMContrac ...@@ -29,6 +29,10 @@ func NewVMContract(addr common.Address, caller *batching.MultiCaller) *VMContrac
} }
} }
func (c *VMContract) Addr() common.Address {
return c.contract.Addr()
}
func (c *VMContract) Oracle(ctx context.Context) (*PreimageOracleContract, error) { func (c *VMContract) Oracle(ctx context.Context) (*PreimageOracleContract, error) {
results, err := c.multiCaller.SingleCall(ctx, rpcblock.Latest, c.contract.Call(methodOracle)) results, err := c.multiCaller.SingleCall(ctx, rpcblock.Latest, c.contract.Call(methodOracle))
if err != nil { if err != nil {
......
...@@ -2,6 +2,7 @@ package disputegame ...@@ -2,6 +2,7 @@ package disputegame
import ( import (
"context" "context"
"crypto/ecdsa"
"encoding/binary" "encoding/binary"
"math/big" "math/big"
"testing" "testing"
...@@ -88,6 +89,7 @@ type FactoryHelper struct { ...@@ -88,6 +89,7 @@ type FactoryHelper struct {
System DisputeSystem System DisputeSystem
Client *ethclient.Client Client *ethclient.Client
Opts *bind.TransactOpts Opts *bind.TransactOpts
PrivKey *ecdsa.PrivateKey
FactoryAddr common.Address FactoryAddr common.Address
Factory *bindings.DisputeGameFactory Factory *bindings.DisputeGameFactory
} }
...@@ -97,7 +99,8 @@ func NewFactoryHelper(t *testing.T, ctx context.Context, system DisputeSystem) * ...@@ -97,7 +99,8 @@ func NewFactoryHelper(t *testing.T, ctx context.Context, system DisputeSystem) *
client := system.NodeClient("l1") client := system.NodeClient("l1")
chainID, err := client.ChainID(ctx) chainID, err := client.ChainID(ctx)
require.NoError(err) require.NoError(err)
opts, err := bind.NewKeyedTransactorWithChainID(TestKey, chainID) privKey := TestKey
opts, err := bind.NewKeyedTransactorWithChainID(privKey, chainID)
require.NoError(err) require.NoError(err)
l1Deployments := system.L1Deployments() l1Deployments := system.L1Deployments()
...@@ -111,6 +114,7 @@ func NewFactoryHelper(t *testing.T, ctx context.Context, system DisputeSystem) * ...@@ -111,6 +114,7 @@ func NewFactoryHelper(t *testing.T, ctx context.Context, system DisputeSystem) *
System: system, System: system,
Client: client, Client: client,
Opts: opts, Opts: opts,
PrivKey: privKey,
Factory: factory, Factory: factory,
FactoryAddr: factoryAddr, FactoryAddr: factoryAddr,
} }
...@@ -167,8 +171,6 @@ func (h *FactoryHelper) StartOutputCannonGame(ctx context.Context, l2Node string ...@@ -167,8 +171,6 @@ func (h *FactoryHelper) StartOutputCannonGame(ctx context.Context, l2Node string
h.Require.Len(rcpt.Logs, 2, "should have emitted a single DisputeGameCreated event") h.Require.Len(rcpt.Logs, 2, "should have emitted a single DisputeGameCreated event")
createdEvent, err := h.Factory.ParseDisputeGameCreated(*rcpt.Logs[1]) createdEvent, err := h.Factory.ParseDisputeGameCreated(*rcpt.Logs[1])
h.Require.NoError(err) h.Require.NoError(err)
gameBindings, err := bindings.NewFaultDisputeGame(createdEvent.DisputeProxy, h.Client)
h.Require.NoError(err)
game, err := contracts.NewFaultDisputeGameContract(ctx, metrics.NoopContractMetrics, createdEvent.DisputeProxy, batching.NewMultiCaller(h.Client.Client(), batching.DefaultBatchSize)) game, err := contracts.NewFaultDisputeGameContract(ctx, metrics.NoopContractMetrics, createdEvent.DisputeProxy, batching.NewMultiCaller(h.Client.Client(), batching.DefaultBatchSize))
h.Require.NoError(err) h.Require.NoError(err)
...@@ -182,7 +184,7 @@ func (h *FactoryHelper) StartOutputCannonGame(ctx context.Context, l2Node string ...@@ -182,7 +184,7 @@ func (h *FactoryHelper) StartOutputCannonGame(ctx context.Context, l2Node string
provider := outputs.NewTraceProvider(logger, prestateProvider, rollupClient, l2Client, l1Head, splitDepth, prestateBlock, poststateBlock) provider := outputs.NewTraceProvider(logger, prestateProvider, rollupClient, l2Client, l1Head, splitDepth, prestateBlock, poststateBlock)
return &OutputCannonGameHelper{ return &OutputCannonGameHelper{
OutputGameHelper: *NewOutputGameHelper(h.T, h.Require, h.Client, h.Opts, game, gameBindings, h.FactoryAddr, createdEvent.DisputeProxy, provider, h.System), OutputGameHelper: *NewOutputGameHelper(h.T, h.Require, h.Client, h.Opts, h.PrivKey, game, h.FactoryAddr, createdEvent.DisputeProxy, provider, h.System),
} }
} }
...@@ -223,8 +225,6 @@ func (h *FactoryHelper) StartOutputAlphabetGame(ctx context.Context, l2Node stri ...@@ -223,8 +225,6 @@ func (h *FactoryHelper) StartOutputAlphabetGame(ctx context.Context, l2Node stri
h.Require.Len(rcpt.Logs, 2, "should have emitted a single DisputeGameCreated event") h.Require.Len(rcpt.Logs, 2, "should have emitted a single DisputeGameCreated event")
createdEvent, err := h.Factory.ParseDisputeGameCreated(*rcpt.Logs[1]) createdEvent, err := h.Factory.ParseDisputeGameCreated(*rcpt.Logs[1])
h.Require.NoError(err) h.Require.NoError(err)
gameBindings, err := bindings.NewFaultDisputeGame(createdEvent.DisputeProxy, h.Client)
h.Require.NoError(err)
game, err := contracts.NewFaultDisputeGameContract(ctx, metrics.NoopContractMetrics, createdEvent.DisputeProxy, batching.NewMultiCaller(h.Client.Client(), batching.DefaultBatchSize)) game, err := contracts.NewFaultDisputeGameContract(ctx, metrics.NoopContractMetrics, createdEvent.DisputeProxy, batching.NewMultiCaller(h.Client.Client(), batching.DefaultBatchSize))
h.Require.NoError(err) h.Require.NoError(err)
...@@ -238,7 +238,7 @@ func (h *FactoryHelper) StartOutputAlphabetGame(ctx context.Context, l2Node stri ...@@ -238,7 +238,7 @@ func (h *FactoryHelper) StartOutputAlphabetGame(ctx context.Context, l2Node stri
provider := outputs.NewTraceProvider(logger, prestateProvider, rollupClient, l2Client, l1Head, splitDepth, prestateBlock, poststateBlock) provider := outputs.NewTraceProvider(logger, prestateProvider, rollupClient, l2Client, l1Head, splitDepth, prestateBlock, poststateBlock)
return &OutputAlphabetGameHelper{ return &OutputAlphabetGameHelper{
OutputGameHelper: *NewOutputGameHelper(h.T, h.Require, h.Client, h.Opts, game, gameBindings, h.FactoryAddr, createdEvent.DisputeProxy, provider, h.System), OutputGameHelper: *NewOutputGameHelper(h.T, h.Require, h.Client, h.Opts, h.PrivKey, game, h.FactoryAddr, createdEvent.DisputeProxy, provider, h.System),
} }
} }
......
...@@ -18,12 +18,12 @@ import ( ...@@ -18,12 +18,12 @@ import (
"github.com/ethereum-optimism/optimism/op-challenger/metrics" "github.com/ethereum-optimism/optimism/op-challenger/metrics"
"github.com/ethereum-optimism/optimism/op-e2e/bindings" "github.com/ethereum-optimism/optimism/op-e2e/bindings"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/challenger"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/transactions"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
preimage "github.com/ethereum-optimism/optimism/op-preimage" preimage "github.com/ethereum-optimism/optimism/op-preimage"
"github.com/ethereum-optimism/optimism/op-service/sources/batching" "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/sources/batching/rpcblock"
"github.com/ethereum-optimism/optimism/op-service/testlog" "github.com/ethereum-optimism/optimism/op-service/testlog"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
...@@ -233,19 +233,14 @@ func (g *OutputCannonGameHelper) VerifyPreimage(ctx context.Context, outputRootC ...@@ -233,19 +233,14 @@ func (g *OutputCannonGameHelper) VerifyPreimage(ctx context.Context, outputRootC
g.Require.NotNil(oracleData, "Should have had required preimage oracle data") g.Require.NotNil(oracleData, "Should have had required preimage oracle data")
g.Require.Equal(common.Hash(preimageKey.PreimageKey()).Bytes(), oracleData.OracleKey, "Must have correct preimage key") g.Require.Equal(common.Hash(preimageKey.PreimageKey()).Bytes(), oracleData.OracleKey, "Must have correct preimage key")
tx, err := g.GameBindings.AddLocalData(g.Opts, candidate, err := g.Game.UpdateOracleTx(ctx, uint64(outputRootClaim.Index), oracleData)
oracleData.GetIdent(), g.Require.NoError(err, "failed to get oracle")
big.NewInt(outputRootClaim.Index), transactions.RequireSendTx(g.T, ctx, g.Client, candidate, g.PrivKey)
new(big.Int).SetUint64(uint64(oracleData.OracleOffset)))
g.Require.NoError(err)
_, err = wait.ForReceiptOK(ctx, g.Client, tx.Hash())
g.Require.NoError(err)
expectedPostState, err := provider.Get(ctx, pos) expectedPostState, err := provider.Get(ctx, pos)
g.Require.NoError(err, "Failed to get expected post state") g.Require.NoError(err, "Failed to get expected post state")
callOpts := &bind.CallOpts{Context: ctx} vm, err := g.Game.Vm(ctx)
vmAddr, err := g.GameBindings.Vm(callOpts)
g.Require.NoError(err, "Failed to get VM address") g.Require.NoError(err, "Failed to get VM address")
abi, err := bindings.MIPSMetaData.GetAbi() abi, err := bindings.MIPSMetaData.GetAbi()
...@@ -253,7 +248,7 @@ func (g *OutputCannonGameHelper) VerifyPreimage(ctx context.Context, outputRootC ...@@ -253,7 +248,7 @@ func (g *OutputCannonGameHelper) VerifyPreimage(ctx context.Context, outputRootC
caller := batching.NewMultiCaller(g.Client.Client(), batching.DefaultBatchSize) caller := batching.NewMultiCaller(g.Client.Client(), batching.DefaultBatchSize)
result, err := caller.SingleCall(ctx, rpcblock.Latest, &batching.ContractCall{ result, err := caller.SingleCall(ctx, rpcblock.Latest, &batching.ContractCall{
Abi: abi, Abi: abi,
Addr: vmAddr, Addr: vm.Addr(),
Method: "step", Method: "step",
Args: []interface{}{ Args: []interface{}{
prestate, proof, localContext, prestate, proof, localContext,
......
...@@ -3,6 +3,7 @@ package disputegame ...@@ -3,6 +3,7 @@ package disputegame
import ( import (
"context" "context"
"crypto/ecdsa" "crypto/ecdsa"
"errors"
"fmt" "fmt"
"math/big" "math/big"
"testing" "testing"
...@@ -15,6 +16,7 @@ import ( ...@@ -15,6 +16,7 @@ import (
keccakTypes "github.com/ethereum-optimism/optimism/op-challenger/game/keccak/types" keccakTypes "github.com/ethereum-optimism/optimism/op-challenger/game/keccak/types"
gameTypes "github.com/ethereum-optimism/optimism/op-challenger/game/types" gameTypes "github.com/ethereum-optimism/optimism/op-challenger/game/types"
"github.com/ethereum-optimism/optimism/op-e2e/bindings" "github.com/ethereum-optimism/optimism/op-e2e/bindings"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/transactions"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait" "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
preimage "github.com/ethereum-optimism/optimism/op-preimage" preimage "github.com/ethereum-optimism/optimism/op-preimage"
"github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum-optimism/optimism/op-service/eth"
...@@ -33,23 +35,23 @@ type OutputGameHelper struct { ...@@ -33,23 +35,23 @@ type OutputGameHelper struct {
Require *require.Assertions Require *require.Assertions
Client *ethclient.Client Client *ethclient.Client
Opts *bind.TransactOpts Opts *bind.TransactOpts
PrivKey *ecdsa.PrivateKey
Game contracts.FaultDisputeGameContract Game contracts.FaultDisputeGameContract
GameBindings *bindings.FaultDisputeGame
FactoryAddr common.Address FactoryAddr common.Address
Addr common.Address Addr common.Address
CorrectOutputProvider *outputs.OutputTraceProvider CorrectOutputProvider *outputs.OutputTraceProvider
System DisputeSystem System DisputeSystem
} }
func NewOutputGameHelper(t *testing.T, require *require.Assertions, client *ethclient.Client, opts *bind.TransactOpts, func NewOutputGameHelper(t *testing.T, require *require.Assertions, client *ethclient.Client, opts *bind.TransactOpts, privKey *ecdsa.PrivateKey,
game contracts.FaultDisputeGameContract, gameBindings *bindings.FaultDisputeGame, factoryAddr common.Address, addr common.Address, correctOutputProvider *outputs.OutputTraceProvider, system DisputeSystem) *OutputGameHelper { game contracts.FaultDisputeGameContract, factoryAddr common.Address, addr common.Address, correctOutputProvider *outputs.OutputTraceProvider, system DisputeSystem) *OutputGameHelper {
return &OutputGameHelper{ return &OutputGameHelper{
T: t, T: t,
Require: require, Require: require,
Client: client, Client: client,
Opts: opts, Opts: opts,
PrivKey: privKey,
Game: game, Game: game,
GameBindings: gameBindings,
FactoryAddr: factoryAddr, FactoryAddr: factoryAddr,
Addr: addr, Addr: addr,
CorrectOutputProvider: correctOutputProvider, CorrectOutputProvider: correctOutputProvider,
...@@ -203,22 +205,13 @@ func (g *OutputGameHelper) AvailableCredit(ctx context.Context, addr common.Addr ...@@ -203,22 +205,13 @@ func (g *OutputGameHelper) AvailableCredit(ctx context.Context, addr common.Addr
} }
func (g *OutputGameHelper) CreditUnlockDuration(ctx context.Context) time.Duration { func (g *OutputGameHelper) CreditUnlockDuration(ctx context.Context) time.Duration {
weth, err := g.GameBindings.Weth(&bind.CallOpts{Context: ctx}) _, delay, _, err := g.Game.GetBalanceAndDelay(ctx, rpcblock.Latest)
g.Require.NoError(err, "Failed to get WETH contract") g.Require.NoError(err, "Failed to get withdrawal delay")
contract, err := bindings.NewDelayedWETH(weth, g.Client) return delay
g.Require.NoError(err)
period, err := contract.Delay(&bind.CallOpts{Context: ctx})
g.Require.NoError(err, "Failed to get WETH unlock period")
float, _ := period.Float64()
return time.Duration(float) * time.Second
} }
func (g *OutputGameHelper) WethBalance(ctx context.Context, addr common.Address) *big.Int { func (g *OutputGameHelper) WethBalance(ctx context.Context, addr common.Address) *big.Int {
weth, err := g.GameBindings.Weth(&bind.CallOpts{Context: ctx}) balance, _, _, err := g.Game.GetBalanceAndDelay(ctx, rpcblock.Latest)
g.Require.NoError(err, "Failed to get WETH contract")
contract, err := bindings.NewDelayedWETH(weth, g.Client)
g.Require.NoError(err)
balance, err := contract.BalanceOf(&bind.CallOpts{Context: ctx}, addr)
g.Require.NoError(err, "Failed to get WETH balance") g.Require.NoError(err, "Failed to get WETH balance")
return balance return balance
} }
...@@ -363,10 +356,9 @@ func (g *OutputGameHelper) WaitForAllClaimsCountered(ctx context.Context) { ...@@ -363,10 +356,9 @@ func (g *OutputGameHelper) WaitForAllClaimsCountered(ctx context.Context) {
func (g *OutputGameHelper) Resolve(ctx context.Context) { func (g *OutputGameHelper) Resolve(ctx context.Context) {
ctx, cancel := context.WithTimeout(ctx, time.Minute) ctx, cancel := context.WithTimeout(ctx, time.Minute)
defer cancel() defer cancel()
tx, err := g.GameBindings.Resolve(g.Opts) candidate, err := g.Game.ResolveTx()
g.Require.NoError(err)
_, err = wait.ForReceiptOK(ctx, g.Client, tx.Hash())
g.Require.NoError(err) g.Require.NoError(err)
transactions.RequireSendTx(g.T, ctx, g.Client, candidate, g.PrivKey)
} }
func (g *OutputGameHelper) Status(ctx context.Context) gameTypes.GameStatus { func (g *OutputGameHelper) Status(ctx context.Context) gameTypes.GameStatus {
...@@ -545,11 +537,10 @@ func (g *OutputGameHelper) Attack(ctx context.Context, claimIdx int64, claim com ...@@ -545,11 +537,10 @@ func (g *OutputGameHelper) Attack(ctx context.Context, claimIdx int64, claim com
claimData, err := g.Game.GetClaim(ctx, uint64(claimIdx)) claimData, err := g.Game.GetClaim(ctx, uint64(claimIdx))
g.Require.NoError(err, "Failed to get claim data") g.Require.NoError(err, "Failed to get claim data")
attackPos := claimData.Position.Attack() attackPos := claimData.Position.Attack()
transactOpts := g.makeBondedTransactOpts(ctx, claimData.Position.Attack().ToGIndex(), cfg.Opts)
err = g.sendMove(ctx, func() (*gethtypes.Transaction, error) { candidate, err := g.Game.AttackTx(ctx, claimData, claim)
return g.GameBindings.Attack(transactOpts, claimData.Value, big.NewInt(claimIdx), claim) g.Require.NoError(err, "Failed to create tx candidate")
}) _, _, err = transactions.SendTx(ctx, g.Client, candidate, g.PrivKey)
if err != nil { if err != nil {
if cfg.ignoreDupes && g.hasClaim(ctx, claimIdx, attackPos, claim) { if cfg.ignoreDupes && g.hasClaim(ctx, claimIdx, attackPos, claim) {
return return
...@@ -565,11 +556,10 @@ func (g *OutputGameHelper) Defend(ctx context.Context, claimIdx int64, claim com ...@@ -565,11 +556,10 @@ func (g *OutputGameHelper) Defend(ctx context.Context, claimIdx int64, claim com
claimData, err := g.Game.GetClaim(ctx, uint64(claimIdx)) claimData, err := g.Game.GetClaim(ctx, uint64(claimIdx))
g.Require.NoError(err, "Failed to get claim data") g.Require.NoError(err, "Failed to get claim data")
defendPos := claimData.Position.Defend() defendPos := claimData.Position.Defend()
transactOpts := g.makeBondedTransactOpts(ctx, defendPos.ToGIndex(), cfg.Opts)
err = g.sendMove(ctx, func() (*gethtypes.Transaction, error) { candidate, err := g.Game.DefendTx(ctx, claimData, claim)
return g.GameBindings.Defend(transactOpts, claimData.Value, big.NewInt(claimIdx), claim) g.Require.NoError(err, "Failed to create tx candidate")
}) _, _, err = transactions.SendTx(ctx, g.Client, candidate, g.PrivKey)
if err != nil { if err != nil {
if cfg.ignoreDupes && g.hasClaim(ctx, claimIdx, defendPos, claim) { if cfg.ignoreDupes && g.hasClaim(ctx, claimIdx, defendPos, claim) {
return return
...@@ -588,45 +578,27 @@ func (g *OutputGameHelper) hasClaim(ctx context.Context, parentIdx int64, pos ty ...@@ -588,45 +578,27 @@ func (g *OutputGameHelper) hasClaim(ctx context.Context, parentIdx int64, pos ty
return false return false
} }
func (g *OutputGameHelper) sendMove(ctx context.Context, send func() (*gethtypes.Transaction, error)) error {
tx, err := send()
if err != nil {
return fmt.Errorf("transaction did not send: %w", err)
}
_, err = wait.ForReceiptOK(ctx, g.Client, tx.Hash())
if err != nil {
return fmt.Errorf("transaction was not ok: %w", err)
}
return nil
}
func (g *OutputGameHelper) makeBondedTransactOpts(ctx context.Context, pos *big.Int, Opts *bind.TransactOpts) *bind.TransactOpts {
bOpts := *Opts
bond, err := g.GameBindings.GetRequiredBond(&bind.CallOpts{Context: ctx}, pos)
g.Require.NoError(err, "Failed to get required bond")
bOpts.Value = bond
return &bOpts
}
type ErrWithData interface { type ErrWithData interface {
ErrorData() interface{} ErrorData() interface{}
} }
// StepFails attempts to call step and verifies that it fails with ValidStep() // StepFails attempts to call step and verifies that it fails with ValidStep()
func (g *OutputGameHelper) StepFails(claimIdx int64, isAttack bool, stateData []byte, proof []byte) { func (g *OutputGameHelper) StepFails(ctx context.Context, claimIdx int64, isAttack bool, stateData []byte, proof []byte) {
g.T.Logf("Attempting step against claim %v isAttack: %v", claimIdx, isAttack) g.T.Logf("Attempting step against claim %v isAttack: %v", claimIdx, isAttack)
_, err := g.GameBindings.Step(g.Opts, big.NewInt(claimIdx), isAttack, stateData, proof) candidate, err := g.Game.StepTx(uint64(claimIdx), isAttack, stateData, proof)
errData, ok := err.(ErrWithData) g.Require.NoError(err, "Failed to create tx candidate")
_, _, err = transactions.SendTx(ctx, g.Client, candidate, g.PrivKey, transactions.WithReceiptFail())
var errData ErrWithData
ok := errors.As(err, &errData)
g.Require.Truef(ok, "Error should provide ErrorData method: %v", err) g.Require.Truef(ok, "Error should provide ErrorData method: %v", err)
g.Require.Equal("0xfb4e40dd", errData.ErrorData(), "Revert reason should be abi encoded ValidStep()") g.Require.Equal("0xfb4e40dd", errData.ErrorData(), "Revert reason should be abi encoded ValidStep()")
} }
// ResolveClaim resolves a single subgame // ResolveClaim resolves a single subgame
func (g *OutputGameHelper) ResolveClaim(ctx context.Context, claimIdx int64) { func (g *OutputGameHelper) ResolveClaim(ctx context.Context, claimIdx int64) {
tx, err := g.GameBindings.ResolveClaim(g.Opts, big.NewInt(claimIdx), common.Big0) candidate, err := g.Game.ResolveClaimTx(uint64(claimIdx))
g.Require.NoError(err, "ResolveClaim transaction did not send") g.Require.NoError(err, "Failed to create resolve claim candidate tx")
_, err = wait.ForReceiptOK(ctx, g.Client, tx.Hash()) transactions.RequireSendTx(g.T, ctx, g.Client, candidate, g.PrivKey)
g.Require.NoError(err, "ResolveClaim transaction was not OK")
} }
// ChallengePeriod returns the challenge period fetched from the PreimageOracle contract. // ChallengePeriod returns the challenge period fetched from the PreimageOracle contract.
......
...@@ -101,7 +101,7 @@ func (h *OutputHonestHelper) StepFails(ctx context.Context, claimIdx int64, isAt ...@@ -101,7 +101,7 @@ func (h *OutputHonestHelper) StepFails(ctx context.Context, claimIdx int64, isAt
} }
prestate, proofData, _, err := h.correctTrace.GetStepData(ctx, game, claim, pos) prestate, proofData, _, err := h.correctTrace.GetStepData(ctx, game, claim, pos)
h.require.NoError(err, "Get step data") h.require.NoError(err, "Get step data")
h.game.StepFails(claimIdx, isAttack, prestate, proofData) h.game.StepFails(ctx, claimIdx, isAttack, prestate, proofData)
} }
func (h *OutputHonestHelper) loadState(ctx context.Context, claimIdx int64) (types.Game, types.Claim) { func (h *OutputHonestHelper) loadState(ctx context.Context, claimIdx int64) (types.Game, types.Claim) {
......
package transactions
import (
"context"
"crypto/ecdsa"
"errors"
"fmt"
"math/big"
"testing"
"github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/params"
"github.com/stretchr/testify/require"
)
type SendTxOpt func(cfg *sendTxCfg)
type ErrWithData interface {
ErrorData() interface{}
}
type sendTxCfg struct {
receiptStatus uint64
}
func makeSendTxCfg(opts ...SendTxOpt) *sendTxCfg {
cfg := &sendTxCfg{
receiptStatus: types.ReceiptStatusSuccessful,
}
for _, opt := range opts {
opt(cfg)
}
return cfg
}
func WithReceiptFail() SendTxOpt {
return func(cfg *sendTxCfg) {
cfg.receiptStatus = types.ReceiptStatusFailed
}
}
func RequireSendTx(t *testing.T, ctx context.Context, client *ethclient.Client, candidate txmgr.TxCandidate, privKey *ecdsa.PrivateKey, opts ...SendTxOpt) {
_, _, err := SendTx(ctx, client, candidate, privKey, opts...)
require.NoError(t, err, "Failed to send transaction")
}
func SendTx(ctx context.Context, client *ethclient.Client, candidate txmgr.TxCandidate, privKey *ecdsa.PrivateKey, opts ...SendTxOpt) (*types.Transaction, *types.Receipt, error) {
cfg := makeSendTxCfg(opts...)
from := crypto.PubkeyToAddress(privKey.PublicKey)
chainID, err := client.ChainID(ctx)
if err != nil {
return nil, nil, fmt.Errorf("failed to get chain ID: %w", err)
}
nonce, err := client.PendingNonceAt(ctx, from)
if err != nil {
return nil, nil, fmt.Errorf("failed to get next nonce: %w", err)
}
latestBlock, err := client.HeaderByNumber(ctx, nil)
if err != nil {
return nil, nil, fmt.Errorf("failed to get latest block: %w", err)
}
gasFeeCap := new(big.Int).Mul(latestBlock.BaseFee, big.NewInt(3))
gasTipCap := big.NewInt(1 * params.GWei)
if gasFeeCap.Cmp(gasTipCap) < 0 {
// gasTipCap can't be higher than gasFeeCap
// Since there's a minimum gasTipCap to be accepted, increase the gasFeeCap. Extra will be refunded anyway.
gasFeeCap = gasTipCap
}
msg := ethereum.CallMsg{
From: from,
To: candidate.To,
Value: candidate.Value,
GasTipCap: gasTipCap,
GasFeeCap: gasFeeCap,
Data: candidate.TxData,
}
gas, err := client.EstimateGas(ctx, msg)
if err != nil {
var errWithData ErrWithData
if errors.As(err, &errWithData) {
return nil, nil, fmt.Errorf("failed to estimate gas. errdata: %v err: %w", errWithData.ErrorData(), err)
}
return nil, nil, fmt.Errorf("failed to estimate gas: %w", err)
}
tx := types.MustSignNewTx(privKey, types.LatestSignerForChainID(chainID), &types.DynamicFeeTx{
ChainID: chainID,
Nonce: nonce,
To: candidate.To,
Value: candidate.Value,
GasTipCap: gasTipCap,
GasFeeCap: gasFeeCap,
Data: candidate.TxData,
Gas: gas,
})
err = client.SendTransaction(ctx, tx)
if err != nil {
return nil, nil, fmt.Errorf("failed to send transaction: %w", err)
}
receipt, err := wait.ForReceipt(ctx, client, tx.Hash(), cfg.receiptStatus)
if err != nil {
return nil, nil, fmt.Errorf("failed to find OK receipt: %w", err)
}
return tx, receipt, nil
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment