From ad007d75a3245ba8c52c05669f1ab94877f3df70 Mon Sep 17 00:00:00 2001 From: Po Date: Sun, 3 Nov 2024 12:18:51 +0800 Subject: [PATCH 01/16] feat(MSFDG): add getSubValues --- op-challenger2/game/fault/agent.go | 3 +- op-challenger2/game/fault/agent_test.go | 8 ++ .../game/fault/contracts/faultdisputegame.go | 97 ++++++++++++++ .../fault/contracts/faultdisputegame_test.go | 125 ++++++++++++++++++ op-challenger2/game/fault/types/position.go | 2 +- op-service/sources/batching/bound.go | 4 + op-service/sources/batching/call.go | 5 + op-service/sources/batching/event_call.go | 37 ++++++ .../sources/batching/event_call_test.go | 75 +++++++++++ op-service/sources/batching/multicall.go | 20 +++ op-service/sources/batching/test/abi_stub.go | 21 +++ .../sources/batching/test/event_stub.go | 66 +++++++++ .../sources/batching/test/generic_stub.go | 8 ++ op-service/sources/batching/test/tx_stub.go | 45 +++++++ op-service/sources/batching/tx_call.go | 64 +++++++++ op-service/sources/batching/tx_call_test.go | 50 +++++++ 16 files changed, 628 insertions(+), 2 deletions(-) create mode 100644 op-service/sources/batching/event_call.go create mode 100644 op-service/sources/batching/event_call_test.go create mode 100644 op-service/sources/batching/test/event_stub.go create mode 100644 op-service/sources/batching/test/tx_stub.go create mode 100644 op-service/sources/batching/tx_call.go create mode 100644 op-service/sources/batching/tx_call_test.go diff --git a/op-challenger2/game/fault/agent.go b/op-challenger2/game/fault/agent.go index b3865dbb2a7f..9a82250f5921 100644 --- a/op-challenger2/game/fault/agent.go +++ b/op-challenger2/game/fault/agent.go @@ -30,6 +30,7 @@ type Responder interface { type ClaimLoader interface { GetAllClaims(ctx context.Context, block rpcblock.Block) ([]types.Claim, error) + GetAllClaimsWithSubValues(ctx context.Context) ([]types.Claim, error) IsL2BlockNumberChallenged(ctx context.Context, block rpcblock.Block) (bool, error) GetMaxGameDepth(ctx context.Context) (types.Depth, error) GetSplitDepth(ctx context.Context) (types.Depth, error) @@ -235,7 +236,7 @@ func (a *Agent) resolveClaims(ctx context.Context) error { // newGameFromContracts initializes a new game state from the state in the contract func (a *Agent) newGameFromContracts(ctx context.Context) (types.Game, error) { - claims, err := a.loader.GetAllClaims(ctx, rpcblock.Latest) + claims, err := a.loader.GetAllClaimsWithSubValues(ctx) if err != nil { return nil, fmt.Errorf("failed to fetch claims: %w", err) } diff --git a/op-challenger2/game/fault/agent_test.go b/op-challenger2/game/fault/agent_test.go index 0acf8ce32d25..f3e9ccccfde2 100644 --- a/op-challenger2/game/fault/agent_test.go +++ b/op-challenger2/game/fault/agent_test.go @@ -221,6 +221,14 @@ func (s *stubClaimLoader) GetAllClaims(_ context.Context, _ rpcblock.Block) ([]t return s.claims, nil } +func (s *stubClaimLoader) GetAllClaimsWithSubValues(_ context.Context) ([]types.Claim, error) { + s.callCount++ + if s.callCount > s.maxLoads && s.maxLoads != 0 { + return []types.Claim{}, nil + } + return s.claims, nil +} + func (s *stubClaimLoader) GetMaxGameDepth(_ context.Context) (types.Depth, error) { return s.maxDepth, nil } diff --git a/op-challenger2/game/fault/contracts/faultdisputegame.go b/op-challenger2/game/fault/contracts/faultdisputegame.go index 28fd34d68269..de945aad5ced 100644 --- a/op-challenger2/game/fault/contracts/faultdisputegame.go +++ b/op-challenger2/game/fault/contracts/faultdisputegame.go @@ -13,12 +13,15 @@ import ( "github.com/ethereum-optimism/optimism/op-challenger2/game/fault/contracts/metrics" "github.com/ethereum-optimism/optimism/op-challenger2/game/fault/types" gameTypes "github.com/ethereum-optimism/optimism/op-challenger2/game/types" + "github.com/ethereum-optimism/optimism/op-e2e/bindings" "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-optimism/optimism/packages/contracts-bedrock/snapshots" "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" ) @@ -58,6 +61,9 @@ var ( methodMaxAttackBranch = "maxAttackBranch" methodAttackV2 = "attackV2" methodStepV2 = "stepV2" + fieldSubValues = "_claims" + fieldAttackBranch = "_attackBranch" + eventMove = "Move" ) var ( @@ -140,6 +146,23 @@ func mustParseAbi(json []byte) *abi.ABI { return &loaded } +func SubValuesHash(values []common.Hash) common.Hash { + nelem := len(values) + hashes := make([]common.Hash, nelem) + copy(hashes, values) + for nelem != 1 { + for i := 0; i < nelem/2; i++ { + hashes[i] = crypto.Keccak256Hash(hashes[i*2][:], hashes[i*2+1][:]) + } + // directly copy the last item + if nelem%2 == 1 { + hashes[nelem/2] = hashes[nelem-1] + } + nelem = (nelem + 1) / 2 + } + return hashes[0] +} + // 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. // Returns the balance and the address of the contract that actually holds the balance. @@ -447,6 +470,79 @@ func (f *FaultDisputeGameContractLatest) GetAllClaims(ctx context.Context, block return claims, nil } +func (f *FaultDisputeGameContractLatest) GetAllClaimsWithSubValues(ctx context.Context) ([]types.Claim, error) { + claims, err := f.GetAllClaims(ctx, rpcblock.Latest) + if err != nil { + return nil, err + } + for idx, claim := range claims { + subValues, attackBranch, err := f.getSubValuesAndAttackBranch(ctx, &claim) + if err != nil { + return nil, fmt.Errorf("failed to load subValues: %w", err) + } + claim.SubValues = &subValues + claim.AttackBranch = attackBranch + claims[idx] = claim + } + return claims, nil +} + +func (f *FaultDisputeGameContractLatest) getSubValuesAndAttackBranch(ctx context.Context, aggClaim *types.Claim) ([]common.Hash, uint64, error) { + defer f.metrics.StartContractRequest("GetSubValues")() + + filter, err := bindings.NewFaultDisputeGameFilterer(f.contract.Addr(), f.multiCaller) + if err != nil { + return nil, 0, err + } + + parentIndex := [...]*big.Int{big.NewInt(int64(aggClaim.ParentContractIndex))} + claim := [...][32]byte{aggClaim.ClaimData.ValueBytes()} + claimant := [...]common.Address{aggClaim.Claimant} + moveIter, err := filter.FilterMove(&bind.FilterOpts{Context: ctx}, parentIndex[:], claim[:], claimant[:]) + if err != nil { + return nil, 0, fmt.Errorf("failed to filter move event log: %w", err) + } + ok := moveIter.Next() + if !ok { + return nil, 0, fmt.Errorf("failed to get move event log: %w", moveIter.Error()) + } + txHash := moveIter.Event.Raw.TxHash + + getTxByHashCall := batching.NewTxGetByHash(f.contract.Abi(), txHash, methodAttackV2) + result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, getTxByHashCall) + if err != nil { + return nil, 0, fmt.Errorf("failed to load attackV2's calldata: %w", err) + } + + txn := result.GetTx() + var subValues []common.Hash + var attackBranch uint64 + if len(txn.BlobHashes()) > 0 { + // todo: fetch Blobs and unpack it into subValues and attackBranch + return nil, 0, fmt.Errorf("blob tx hasn't been supported") + } else { + inputMap, err := getTxByHashCall.UnpackCallData(&txn) + if err != nil { + return nil, 0, fmt.Errorf("failed to unpack tx resp: %w", err) + } + attackBranchU256 := *abi.ConvertType(inputMap[fieldAttackBranch], new(big.Int)).(*big.Int) + attackBranch = attackBranchU256.Uint64() + + maxAttackBranch, err := f.GetMaxAttackBranch(ctx) + if err != nil { + return nil, 0, err + } + valuesBytesLen := uint(32 * maxAttackBranch) + bytes := abi.ConvertType(inputMap[fieldSubValues], make([]byte, valuesBytesLen)).([]byte) + for i := uint64(0); i < maxAttackBranch; i++ { + hash := common.BytesToHash(bytes[i*32 : (i+1)*32]) + subValues = append(subValues, hash) + } + } + + return subValues, attackBranch, nil +} + func (f *FaultDisputeGameContractLatest) IsResolved(ctx context.Context, block rpcblock.Block, claims ...types.Claim) ([]bool, error) { defer f.metrics.StartContractRequest("IsResolved")() calls := make([]batching.Call, 0, len(claims)) @@ -670,4 +766,5 @@ type FaultDisputeGameContract interface { StepV2Tx(claimIdx uint64, attackBranch uint64, stateData []byte, proof types.StepProof) (txmgr.TxCandidate, error) GetNBits(ctx context.Context) (uint64, error) GetMaxAttackBranch(ctx context.Context) (uint64, error) + GetAllClaimsWithSubValues(ctx context.Context) ([]types.Claim, error) } diff --git a/op-challenger2/game/fault/contracts/faultdisputegame_test.go b/op-challenger2/game/fault/contracts/faultdisputegame_test.go index 2c699b27223c..9b8f6019cacb 100644 --- a/op-challenger2/game/fault/contracts/faultdisputegame_test.go +++ b/op-challenger2/game/fault/contracts/faultdisputegame_test.go @@ -23,6 +23,8 @@ import ( "github.com/ethereum-optimism/optimism/packages/contracts-bedrock/snapshots" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" + coreTypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" "github.com/stretchr/testify/require" ) @@ -851,3 +853,126 @@ func TestStepV2Tx(t *testing.T) { }) } } + +func TestGetAllClaimsWithSubValues(t *testing.T) { + for _, version := range versions { + t.Run(version.version, func(t *testing.T) { + stubRpc, game := setupFaultDisputeGameTest(t, version) + block := rpcblock.Latest + + claimant := common.Address{0xbb} + bond := big.NewInt(1044) + nBits := uint64(2) + claimsBytes := make([]byte, ((1< Date: Sun, 3 Nov 2024 19:22:37 +0800 Subject: [PATCH 02/16] op-challenger2 add attackV2 --- op-challenger2/game/fault/agent.go | 2 + .../game/fault/responder/responder.go | 9 +++ .../game/fault/solver/game_solver.go | 40 ++++++---- op-challenger2/game/fault/solver/solver.go | 80 ++++++++++++------- op-challenger2/game/fault/types/actions.go | 6 +- op-challenger2/metrics/metrics.go | 11 +++ op-challenger2/metrics/noop.go | 1 + 7 files changed, 101 insertions(+), 48 deletions(-) diff --git a/op-challenger2/game/fault/agent.go b/op-challenger2/game/fault/agent.go index b3865dbb2a7f..14fca8f60e84 100644 --- a/op-challenger2/game/fault/agent.go +++ b/op-challenger2/game/fault/agent.go @@ -139,6 +139,8 @@ func (a *Agent) performAction(ctx context.Context, wg *sync.WaitGroup, action ty switch action.Type { case types.ActionTypeMove: a.metrics.RecordGameMove() + case types.ActionTypeAttackV2: + a.metrics.RecordGameAttackV2() case types.ActionTypeStep: a.metrics.RecordGameStep() case types.ActionTypeChallengeL2BlockNumber: diff --git a/op-challenger2/game/fault/responder/responder.go b/op-challenger2/game/fault/responder/responder.go index d12a6b9f6558..66b5de7bd5d5 100644 --- a/op-challenger2/game/fault/responder/responder.go +++ b/op-challenger2/game/fault/responder/responder.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "math/big" "github.com/ethereum-optimism/optimism/op-challenger2/game/fault/preimages" "github.com/ethereum-optimism/optimism/op-challenger2/game/fault/types" @@ -19,6 +20,7 @@ type GameContract interface { CallResolveClaim(ctx context.Context, claimIdx uint64) error ResolveClaimTx(claimIdx uint64) (txmgr.TxCandidate, error) AttackTx(ctx context.Context, parent types.Claim, pivot common.Hash) (txmgr.TxCandidate, error) + AttackV2Tx(ctx context.Context, parent types.Claim, attackBranch uint64, daType uint64, claims []byte) (txmgr.TxCandidate, error) DefendTx(ctx context.Context, parent types.Claim, pivot common.Hash) (txmgr.TxCandidate, error) StepTx(claimIdx uint64, isAttack bool, stateData []byte, proof []byte) (txmgr.TxCandidate, error) ChallengeL2BlockNumberTx(challenge *types.InvalidL2BlockNumberChallenge) (txmgr.TxCandidate, error) @@ -117,6 +119,13 @@ func (r *FaultResponder) PerformAction(ctx context.Context, action types.Action) } else { candidate, err = r.contract.DefendTx(ctx, action.ParentClaim, action.Value) } + case types.ActionTypeAttackV2: + subValues := make([]byte, 0, len(*action.SubValues)) + for _, subValue := range *action.SubValues { + subValues = append(subValues, subValue[:]...) + } + daTypeUint64 := (*big.Int)(action.DAType).Uint64() + candidate, err = r.contract.AttackV2Tx(ctx, action.ParentClaim, action.AttackBranch, daTypeUint64, subValues) case types.ActionTypeStep: candidate, err = r.contract.StepTx(uint64(action.ParentClaim.ContractIndex), action.IsAttack, action.PreState, action.ProofData) case types.ActionTypeChallengeL2BlockNumber: diff --git a/op-challenger2/game/fault/solver/game_solver.go b/op-challenger2/game/fault/solver/game_solver.go index 75a9707d6462..c8a0283df606 100644 --- a/op-challenger2/game/fault/solver/game_solver.go +++ b/op-challenger2/game/fault/solver/game_solver.go @@ -95,21 +95,29 @@ func (s *GameSolver) calculateStep(ctx context.Context, game types.Game, claim t } func (s *GameSolver) calculateMove(ctx context.Context, game types.Game, claim types.Claim, honestClaims *honestClaimTracker) (*types.Action, error) { - move, err := s.claimSolver.NextMove(ctx, claim, game, honestClaims) - if err != nil { - return nil, fmt.Errorf("failed to calculate next move for claim index %v: %w", claim.ContractIndex, err) - } - if move == nil { - return nil, nil - } - honestClaims.AddHonestClaim(claim, *move) - if game.IsDuplicate(*move) { - return nil, nil + for branch, _ := range *claim.SubValues { + if claim.Position.Depth() == game.SplitDepth()+types.Depth(game.NBits()) && branch != 0 { + continue + } + move, err := s.claimSolver.NextMove(ctx, claim, game, honestClaims, uint64(branch)) + if err != nil { + return nil, fmt.Errorf("failed to calculate next move for claim index %v: %w", claim.ContractIndex, err) + } + if move == nil { + continue + } + honestClaims.AddHonestClaim(claim, *move) + if game.IsDuplicate(*move) { + continue + } + return &types.Action{ + Type: types.ActionTypeAttackV2, + ParentClaim: game.Claims()[move.ParentContractIndex], + Value: move.Value, + SubValues: move.SubValues, + AttackBranch: uint64(branch), + DAType: s.claimSolver.daType, + }, nil } - return &types.Action{ - Type: types.ActionTypeMove, - IsAttack: !game.DefendsParent(*move), - ParentClaim: game.Claims()[move.ParentContractIndex], - Value: move.Value, - }, nil + return nil, nil } diff --git a/op-challenger2/game/fault/solver/solver.go b/op-challenger2/game/fault/solver/solver.go index a82cc5bb88a0..8c683f80af97 100644 --- a/op-challenger2/game/fault/solver/solver.go +++ b/op-challenger2/game/fault/solver/solver.go @@ -7,6 +7,8 @@ import ( "fmt" "github.com/ethereum-optimism/optimism/op-challenger2/game/fault/types" + "github.com/ethereum-optimism/optimism/op-challenger2/game/keccak/merkle" + "github.com/ethereum/go-ethereum/common" ) var ( @@ -63,7 +65,7 @@ func (s *claimSolver) shouldCounter(game types.Game, claim types.Claim, honestCl } // NextMove returns the next move to make given the current state of the game. -func (s *claimSolver) NextMove(ctx context.Context, claim types.Claim, game types.Game, honestClaims *honestClaimTracker) (*types.Claim, error) { +func (s *claimSolver) NextMove(ctx context.Context, claim types.Claim, game types.Game, honestClaims *honestClaimTracker, branch uint64) (*types.Claim, error) { if claim.Depth() == s.gameDepth { return nil, types.ErrGameDepthReached } @@ -74,12 +76,17 @@ func (s *claimSolver) NextMove(ctx context.Context, claim types.Claim, game type return nil, nil } - if agree, err := s.agreeWithClaim(ctx, game, claim); err != nil { + agree, err := s.agreeWithClaimV2(ctx, game, claim, branch) + if err != nil { return nil, err - } else if agree { - return s.defend(ctx, game, claim) + } + if agree { + if branch < game.MaxAttackBranch()-1 { + return nil, nil + } + return s.attackV2(ctx, game, claim, branch+1) } else { - return s.attack(ctx, game, claim) + return s.attackV2(ctx, game, claim, branch) } } @@ -134,37 +141,48 @@ func (s *claimSolver) AttemptStep(ctx context.Context, game types.Game, claim ty }, nil } -// attack returns a response that attacks the claim. -func (s *claimSolver) attack(ctx context.Context, game types.Game, claim types.Claim) (*types.Claim, error) { - position := claim.Attack() - value, err := s.trace.Get(ctx, game, claim, position) - if err != nil { - return nil, fmt.Errorf("attack claim: %w", err) - } - return &types.Claim{ - ClaimData: types.ClaimData{Value: value, Position: position}, - ParentContractIndex: claim.ContractIndex, - }, nil +// agreeWithClaim returns true if the claim is correct according to the internal [TraceProvider]. +func (s *claimSolver) agreeWithClaim(ctx context.Context, game types.Game, claim types.Claim) (bool, error) { + ourValue, err := s.trace.Get(ctx, game, claim, claim.Position) + return bytes.Equal(ourValue[:], claim.Value[:]), err } -// defend returns a response that defends the claim. -func (s *claimSolver) defend(ctx context.Context, game types.Game, claim types.Claim) (*types.Claim, error) { - if claim.IsRoot() { - return nil, nil - } - position := claim.Defend() - value, err := s.trace.Get(ctx, game, claim, position) - if err != nil { - return nil, fmt.Errorf("defend claim: %w", err) - } +func (s *claimSolver) agreeWithClaimV2(ctx context.Context, game types.Game, claim types.Claim, branch uint64) (bool, error) { + ourValue, err := s.trace.Get(ctx, game, claim, claim.Position.MoveRightN(branch)) + return bytes.Equal(ourValue[:], (*claim.SubValues)[branch][:]), err +} + +func (s *claimSolver) attackV2(ctx context.Context, game types.Game, claim types.Claim, branch uint64) (*types.Claim, error) { + var err error + var value common.Hash + var values []common.Hash + maxAttackBranch := game.MaxAttackBranch() + position := claim.MoveN(game.NBits(), branch) + for i := uint64(0); i < maxAttackBranch; i++ { + tmpPosition := position.MoveRightN(i) + if tmpPosition.Depth() == (game.SplitDepth()+types.Depth(game.NBits())) && i != 0 { + value = common.Hash{} + } else { + value, err = s.trace.Get(ctx, game, claim, tmpPosition) + if err != nil { + return nil, fmt.Errorf("attack claim: %w", err) + } + } + values = append(values, value) + } + hash := getClaimsHash(values) return &types.Claim{ - ClaimData: types.ClaimData{Value: value, Position: position}, + ClaimData: types.ClaimData{Value: hash, Position: position}, ParentContractIndex: claim.ContractIndex, + SubValues: &values, + AttackBranch: branch, }, nil } -// agreeWithClaim returns true if the claim is correct according to the internal [TraceProvider]. -func (s *claimSolver) agreeWithClaim(ctx context.Context, game types.Game, claim types.Claim) (bool, error) { - ourValue, err := s.trace.Get(ctx, game, claim, claim.Position) - return bytes.Equal(ourValue[:], claim.Value[:]), err +func getClaimsHash(values []common.Hash) common.Hash { + tree := merkle.NewBinaryMerkleTree() + for i := 0; i < len(values); i++ { + tree.AddLeaf(values[i]) + } + return tree.RootHash() } diff --git a/op-challenger2/game/fault/types/actions.go b/op-challenger2/game/fault/types/actions.go index e5093d6ac553..d6a22e4463a9 100644 --- a/op-challenger2/game/fault/types/actions.go +++ b/op-challenger2/game/fault/types/actions.go @@ -9,6 +9,7 @@ func (a ActionType) String() string { } const ( + ActionTypeAttackV2 ActionType = "attackV2" ActionTypeMove ActionType = "move" ActionTypeStep ActionType = "step" ActionTypeChallengeL2BlockNumber ActionType = "challenge-l2-block-number" @@ -22,7 +23,10 @@ type Action struct { IsAttack bool // Moves - Value common.Hash + Value common.Hash + SubValues *[]common.Hash + AttackBranch uint64 + DAType DAType // Steps PreState []byte diff --git a/op-challenger2/metrics/metrics.go b/op-challenger2/metrics/metrics.go index adb223c0eac7..3b01fcf603be 100644 --- a/op-challenger2/metrics/metrics.go +++ b/op-challenger2/metrics/metrics.go @@ -36,6 +36,7 @@ type Metricer interface { RecordGameStep() RecordGameMove() + RecordGameAttackV2() RecordGameL2Challenge() RecordCannonExecutionTime(t float64) RecordAsteriscExecutionTime(t float64) @@ -85,6 +86,7 @@ type Metrics struct { highestActedL1Block prometheus.Gauge moves prometheus.Counter + attackV2 prometheus.Counter steps prometheus.Counter l2Challenges prometheus.Counter @@ -142,6 +144,11 @@ func NewMetrics() *Metrics { Name: "moves", Help: "Number of game moves made by the challenge agent", }), + attackV2: factory.NewCounter(prometheus.CounterOpts{ + Namespace: Namespace, + Name: "attackV2", + Help: "Number of game attack v2 moves made by the challenge agent", + }), steps: factory.NewCounter(prometheus.CounterOpts{ Namespace: Namespace, Name: "steps", @@ -254,6 +261,10 @@ func (m *Metrics) RecordGameMove() { m.moves.Add(1) } +func (m *Metrics) RecordGameAttackV2() { + m.attackV2.Add(1) +} + func (m *Metrics) RecordGameStep() { m.steps.Add(1) } diff --git a/op-challenger2/metrics/noop.go b/op-challenger2/metrics/noop.go index 8519d6bab4b6..f53cf9f4c766 100644 --- a/op-challenger2/metrics/noop.go +++ b/op-challenger2/metrics/noop.go @@ -26,6 +26,7 @@ func (*NoopMetricsImpl) RecordInfo(version string) {} func (*NoopMetricsImpl) RecordUp() {} func (*NoopMetricsImpl) RecordGameMove() {} +func (*NoopMetricsImpl) RecordGameAttackV2() {} func (*NoopMetricsImpl) RecordGameStep() {} func (*NoopMetricsImpl) RecordGameL2Challenge() {} From 360b88b62f18b922684fec59cee49e51219fb348 Mon Sep 17 00:00:00 2001 From: Abe Orm Date: Sun, 10 Nov 2024 20:52:39 +0800 Subject: [PATCH 03/16] op-challenger2 add stepV2 --- .../game/fault/responder/responder.go | 8 ++++- .../game/fault/solver/game_solver.go | 33 ++++++++++--------- op-challenger2/game/fault/solver/solver.go | 8 ++--- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/op-challenger2/game/fault/responder/responder.go b/op-challenger2/game/fault/responder/responder.go index 66b5de7bd5d5..5d80bed69b9c 100644 --- a/op-challenger2/game/fault/responder/responder.go +++ b/op-challenger2/game/fault/responder/responder.go @@ -23,6 +23,7 @@ type GameContract interface { AttackV2Tx(ctx context.Context, parent types.Claim, attackBranch uint64, daType uint64, claims []byte) (txmgr.TxCandidate, error) DefendTx(ctx context.Context, parent types.Claim, pivot common.Hash) (txmgr.TxCandidate, error) StepTx(claimIdx uint64, isAttack bool, stateData []byte, proof []byte) (txmgr.TxCandidate, error) + StepV2Tx(claimIdx uint64, attackBranch uint64, stateData []byte, proof types.StepProof) (txmgr.TxCandidate, error) ChallengeL2BlockNumberTx(challenge *types.InvalidL2BlockNumberChallenge) (txmgr.TxCandidate, error) } @@ -127,7 +128,12 @@ func (r *FaultResponder) PerformAction(ctx context.Context, action types.Action) daTypeUint64 := (*big.Int)(action.DAType).Uint64() candidate, err = r.contract.AttackV2Tx(ctx, action.ParentClaim, action.AttackBranch, daTypeUint64, subValues) case types.ActionTypeStep: - candidate, err = r.contract.StepTx(uint64(action.ParentClaim.ContractIndex), action.IsAttack, action.PreState, action.ProofData) + stepProof := types.StepProof{ + PreStateItem: action.OracleData.VMStateDA.PreDA, + PostStateItem: action.OracleData.VMStateDA.PostDA, + VmProof: action.ProofData, + } + candidate, err = r.contract.StepV2Tx(uint64(action.ParentClaim.ContractIndex), action.AttackBranch, action.PreState, stepProof) case types.ActionTypeChallengeL2BlockNumber: candidate, err = r.contract.ChallengeL2BlockNumberTx(action.InvalidL2BlockNumberChallenge) } diff --git a/op-challenger2/game/fault/solver/game_solver.go b/op-challenger2/game/fault/solver/game_solver.go index c8a0283df606..5bdb2dca915b 100644 --- a/op-challenger2/game/fault/solver/game_solver.go +++ b/op-challenger2/game/fault/solver/game_solver.go @@ -77,25 +77,28 @@ func (s *GameSolver) calculateStep(ctx context.Context, game types.Game, claim t if claim.CounteredBy != (common.Address{}) { return nil, nil } - step, err := s.claimSolver.AttemptStep(ctx, game, claim, agreedClaims) - if err != nil { - return nil, err - } - if step == nil { - return nil, nil + for branch := range *claim.SubValues { + step, err := s.claimSolver.AttemptStep(ctx, game, claim, agreedClaims, uint64(branch)) + if err != nil { + return nil, err + } + if step == nil { + continue + } + return &types.Action{ + Type: types.ActionTypeStep, + ParentClaim: step.LeafClaim, + IsAttack: step.IsAttack, + PreState: step.PreState, + ProofData: step.ProofData, + OracleData: step.OracleData, + }, nil } - return &types.Action{ - Type: types.ActionTypeStep, - ParentClaim: step.LeafClaim, - IsAttack: step.IsAttack, - PreState: step.PreState, - ProofData: step.ProofData, - OracleData: step.OracleData, - }, nil + return nil, nil } func (s *GameSolver) calculateMove(ctx context.Context, game types.Game, claim types.Claim, honestClaims *honestClaimTracker) (*types.Action, error) { - for branch, _ := range *claim.SubValues { + for branch := range *claim.SubValues { if claim.Position.Depth() == game.SplitDepth()+types.Depth(game.NBits()) && branch != 0 { continue } diff --git a/op-challenger2/game/fault/solver/solver.go b/op-challenger2/game/fault/solver/solver.go index 8c683f80af97..48c99e69b8d6 100644 --- a/op-challenger2/game/fault/solver/solver.go +++ b/op-challenger2/game/fault/solver/solver.go @@ -101,7 +101,7 @@ type StepData struct { // AttemptStep determines what step, if any, should occur for a given leaf claim. // An error will be returned if the claim is not at the max depth. // Returns nil, nil if no step should be performed. -func (s *claimSolver) AttemptStep(ctx context.Context, game types.Game, claim types.Claim, honestClaims *honestClaimTracker) (*StepData, error) { +func (s *claimSolver) AttemptStep(ctx context.Context, game types.Game, claim types.Claim, honestClaims *honestClaimTracker, branch uint64) (*StepData, error) { if claim.Depth() != s.gameDepth { return nil, ErrStepNonLeafNode } @@ -112,7 +112,7 @@ func (s *claimSolver) AttemptStep(ctx context.Context, game types.Game, claim ty return nil, nil } - claimCorrect, err := s.agreeWithClaim(ctx, game, claim) + claimCorrect, err := s.agreeWithClaimV2(ctx, game, claim, branch) if err != nil { return nil, err } @@ -120,11 +120,11 @@ func (s *claimSolver) AttemptStep(ctx context.Context, game types.Game, claim ty var position types.Position if !claimCorrect { // Attack the claim by executing step index, so we need to get the pre-state of that index - position = claim.Position + position = claim.Position.MoveRightN(branch) } else { // Defend and use this claim as the starting point to execute the step after. // Thus, we need the pre-state of the next step. - position = claim.Position.MoveRight() + position = claim.Position.MoveRightN(branch + 1) } preState, proofData, oracleData, err := s.trace.GetStepData(ctx, game, claim, position) From 42d3a98737d9ec964fbe954266bc0b84c23ff4c8 Mon Sep 17 00:00:00 2001 From: Po Date: Fri, 15 Nov 2024 23:55:42 +0800 Subject: [PATCH 04/16] add getStepData tests for solver_test.go --- op-challenger2/game/fault/agent.go | 4 +- .../game/fault/solver/game_solver.go | 12 +- op-challenger2/game/fault/solver/solver.go | 36 +- .../game/fault/solver/solver_test.go | 420 +++++++++++++++++- op-challenger2/game/fault/test/alphabet.go | 41 +- .../game/fault/test/claim_builder.go | 15 +- op-challenger2/game/fault/trace/access.go | 5 - .../game/fault/trace/access_test.go | 15 - .../game/fault/trace/utils/daproof_test.go | 7 + op-challenger2/game/fault/types/types.go | 2 + 10 files changed, 473 insertions(+), 84 deletions(-) diff --git a/op-challenger2/game/fault/agent.go b/op-challenger2/game/fault/agent.go index 691a3381044d..42d9195e8de8 100644 --- a/op-challenger2/game/fault/agent.go +++ b/op-challenger2/game/fault/agent.go @@ -123,7 +123,7 @@ func (a *Agent) performAction(ctx context.Context, wg *sync.WaitGroup, action ty containsOracleData := action.OracleData != nil isLocal := containsOracleData && action.OracleData.IsLocal actionLog = actionLog.New( - "is_attack", action.IsAttack, + "attackBranch", action.AttackBranch, "parent", action.ParentClaim.ContractIndex, "prestate", common.Bytes2Hex(action.PreState), "proof", common.Bytes2Hex(action.ProofData), @@ -134,7 +134,7 @@ func (a *Agent) performAction(ctx context.Context, wg *sync.WaitGroup, action ty actionLog = actionLog.New("oracleKey", common.Bytes2Hex(action.OracleData.OracleKey)) } } else if action.Type == types.ActionTypeMove { - actionLog = actionLog.New("is_attack", action.IsAttack, "parent", action.ParentClaim.ContractIndex, "value", action.Value) + actionLog = actionLog.New("attackBranch", action.AttackBranch, "parent", action.ParentClaim.ContractIndex, "value", action.Value) } switch action.Type { diff --git a/op-challenger2/game/fault/solver/game_solver.go b/op-challenger2/game/fault/solver/game_solver.go index 5bdb2dca915b..507d9560b843 100644 --- a/op-challenger2/game/fault/solver/game_solver.go +++ b/op-challenger2/game/fault/solver/game_solver.go @@ -86,12 +86,12 @@ func (s *GameSolver) calculateStep(ctx context.Context, game types.Game, claim t continue } return &types.Action{ - Type: types.ActionTypeStep, - ParentClaim: step.LeafClaim, - IsAttack: step.IsAttack, - PreState: step.PreState, - ProofData: step.ProofData, - OracleData: step.OracleData, + Type: types.ActionTypeStep, + ParentClaim: step.LeafClaim, + AttackBranch: step.AttackBranch, + PreState: step.PreState, + ProofData: step.ProofData, + OracleData: step.OracleData, }, nil } return nil, nil diff --git a/op-challenger2/game/fault/solver/solver.go b/op-challenger2/game/fault/solver/solver.go index 48c99e69b8d6..58d4facf01ea 100644 --- a/op-challenger2/game/fault/solver/solver.go +++ b/op-challenger2/game/fault/solver/solver.go @@ -6,8 +6,8 @@ import ( "errors" "fmt" + "github.com/ethereum-optimism/optimism/op-challenger2/game/fault/contracts" "github.com/ethereum-optimism/optimism/op-challenger2/game/fault/types" - "github.com/ethereum-optimism/optimism/op-challenger2/game/keccak/merkle" "github.com/ethereum/go-ethereum/common" ) @@ -91,11 +91,11 @@ func (s *claimSolver) NextMove(ctx context.Context, claim types.Claim, game type } type StepData struct { - LeafClaim types.Claim - IsAttack bool - PreState []byte - ProofData []byte - OracleData *types.PreimageOracleData + LeafClaim types.Claim + AttackBranch uint64 + PreState []byte + ProofData []byte + OracleData *types.PreimageOracleData } // AttemptStep determines what step, if any, should occur for a given leaf claim. @@ -118,6 +118,7 @@ func (s *claimSolver) AttemptStep(ctx context.Context, game types.Game, claim ty } var position types.Position + attackBranch := branch if !claimCorrect { // Attack the claim by executing step index, so we need to get the pre-state of that index position = claim.Position.MoveRightN(branch) @@ -125,19 +126,20 @@ func (s *claimSolver) AttemptStep(ctx context.Context, game types.Game, claim ty // Defend and use this claim as the starting point to execute the step after. // Thus, we need the pre-state of the next step. position = claim.Position.MoveRightN(branch + 1) + attackBranch = branch + 1 } - preState, proofData, oracleData, err := s.trace.GetStepData(ctx, game, claim, position) + preState, proofData, oracleData, err := s.trace.GetStepData2(ctx, game, claim, position) if err != nil { return nil, err } return &StepData{ - LeafClaim: claim, - IsAttack: !claimCorrect, - PreState: preState, - ProofData: proofData, - OracleData: oracleData, + LeafClaim: claim, + AttackBranch: attackBranch, + PreState: preState, + ProofData: proofData, + OracleData: oracleData, }, nil } @@ -170,7 +172,7 @@ func (s *claimSolver) attackV2(ctx context.Context, game types.Game, claim types } values = append(values, value) } - hash := getClaimsHash(values) + hash := contracts.SubValuesHash(values) return &types.Claim{ ClaimData: types.ClaimData{Value: hash, Position: position}, ParentContractIndex: claim.ContractIndex, @@ -178,11 +180,3 @@ func (s *claimSolver) attackV2(ctx context.Context, game types.Game, claim types AttackBranch: branch, }, nil } - -func getClaimsHash(values []common.Hash) common.Hash { - tree := merkle.NewBinaryMerkleTree() - for i := 0; i < len(values); i++ { - tree.AddLeaf(values[i]) - } - return tree.RootHash() -} diff --git a/op-challenger2/game/fault/solver/solver_test.go b/op-challenger2/game/fault/solver/solver_test.go index 4fb5723fde8e..c42b45849fec 100644 --- a/op-challenger2/game/fault/solver/solver_test.go +++ b/op-challenger2/game/fault/solver/solver_test.go @@ -7,82 +7,120 @@ import ( faulttest "github.com/ethereum-optimism/optimism/op-challenger2/game/fault/test" "github.com/ethereum-optimism/optimism/op-challenger2/game/fault/trace" + "github.com/ethereum-optimism/optimism/op-challenger2/game/fault/trace/alphabet" + "github.com/ethereum-optimism/optimism/op-challenger2/game/fault/trace/split" "github.com/ethereum-optimism/optimism/op-challenger2/game/fault/types" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" ) -func TestAttemptStep(t *testing.T) { - maxDepth := types.Depth(3) +func TestAttemptStepNary2(t *testing.T) { + maxDepth := types.Depth(7) startingL2BlockNumber := big.NewInt(0) nbits := uint64(1) splitDepth := types.Depth(3) claimBuilder := faulttest.NewAlphabetClaimBuilder2(t, startingL2BlockNumber, maxDepth, nbits, splitDepth) + traceDepth := maxDepth - splitDepth - types.Depth(nbits) // Last accessible leaf is the second last trace index // The root node is used for the last trace index and can only be attacked. - lastLeafTraceIndex := big.NewInt(1< Date: Sat, 16 Nov 2024 21:06:11 +0800 Subject: [PATCH 05/16] modify test --- .../game/fault/solver/game_solver.go | 3 + .../game/fault/solver/game_solver_test.go | 112 +++++++++++++++++- op-challenger2/game/fault/solver/rules.go | 25 ++-- op-challenger2/game/fault/solver/solver.go | 12 +- .../game/fault/solver/solver_test.go | 3 +- .../game/fault/test/claim_builder.go | 54 +++++++-- .../game/fault/test/game_builder.go | 44 +++++++ 7 files changed, 213 insertions(+), 40 deletions(-) diff --git a/op-challenger2/game/fault/solver/game_solver.go b/op-challenger2/game/fault/solver/game_solver.go index 5bdb2dca915b..51c098010026 100644 --- a/op-challenger2/game/fault/solver/game_solver.go +++ b/op-challenger2/game/fault/solver/game_solver.go @@ -102,6 +102,9 @@ func (s *GameSolver) calculateMove(ctx context.Context, game types.Game, claim t if claim.Position.Depth() == game.SplitDepth()+types.Depth(game.NBits()) && branch != 0 { continue } + if claim.IsRoot() && branch != 0 { + continue + } move, err := s.claimSolver.NextMove(ctx, claim, game, honestClaims, uint64(branch)) if err != nil { return nil, fmt.Errorf("failed to calculate next move for claim index %v: %w", claim.ContractIndex, err) diff --git a/op-challenger2/game/fault/solver/game_solver_test.go b/op-challenger2/game/fault/solver/game_solver_test.go index 9eb9a1a41e50..87930cb0a155 100644 --- a/op-challenger2/game/fault/solver/game_solver_test.go +++ b/op-challenger2/game/fault/solver/game_solver_test.go @@ -45,7 +45,7 @@ func TestCalculateNextActions_ChallengeL2BlockNumber(t *testing.T) { func TestCalculateNextActions(t *testing.T) { maxDepth := types.Depth(6) startingL2BlockNumber := big.NewInt(0) - nbits := uint64(1) + nbits := uint64(2) splitDepth := types.Depth(3) claimBuilder := faulttest.NewAlphabetClaimBuilder2(t, startingL2BlockNumber, maxDepth, nbits, splitDepth) @@ -215,11 +215,13 @@ func TestCalculateNextActions(t *testing.T) { t.Logf("Expect %v: Type: %v, ParentIdx: %v, Attack: %v, Value: %v, PreState: %v, ProofData: %v", i, action.Type, action.ParentClaim.ContractIndex, action.IsAttack, action.Value, hex.EncodeToString(action.PreState), hex.EncodeToString(action.ProofData)) require.Containsf(t, actions, action, "Expected claim %v missing", i) + break } require.Len(t, actions, len(builder.ExpectedActions), "Incorrect number of actions") verifyGameRules(t, postState, test.rootClaimCorrect) }) + break } } @@ -364,3 +366,111 @@ func applyActions(game types.Game, claimant common.Address, actions []types.Acti } return types.NewGameState2(claims, game.MaxDepth(), game.NBits(), game.SplitDepth()) } + +func TestCalculateNextActions2(t *testing.T) { + maxDepth := types.Depth(8) + startingL2BlockNumber := big.NewInt(0) + nbits := uint64(2) + splitDepth := types.Depth(4) + claimBuilder := faulttest.NewAlphabetClaimBuilder2(t, startingL2BlockNumber, maxDepth, nbits, splitDepth) + + tests := []struct { + name string + rootClaimCorrect bool + setupGame func(builder *faulttest.GameBuilder) + }{ + /* + { + name: "AttackRootClaim", + setupGame: func(builder *faulttest.GameBuilder) { + builder.Seq().ExpectAttackV2(0) + }, + }, + { + name: "DoNotAttackCorrectRootClaim_AgreeWithOutputRoot", + rootClaimCorrect: true, + setupGame: func(builder *faulttest.GameBuilder) {}, + }, + { + name: "DoNotPerformDuplicateMoves", + setupGame: func(builder *faulttest.GameBuilder) { + // Expected move has already been made. + builder.Seq().Attack() + }, + }, + */ + { + name: "RespondToAllClaimsAtDisagreeingLevel", + setupGame: func(builder *faulttest.GameBuilder) { + honestClaim := builder.Seq().Attack2(nil, 0) + honestClaim.Attack2(nil, 0).ExpectAttackV2(0) + }, + }, + } + + for _, test := range tests { + test := test + t.Run(test.name, func(t *testing.T) { + builder := claimBuilder.GameBuilder(faulttest.WithInvalidValue(!test.rootClaimCorrect)) + test.setupGame(builder) + game := builder.Game + solver := NewGameSolver(maxDepth, trace.NewSimpleTraceAccessor(claimBuilder.CorrectTraceProvider()), types.CallDataType) + postState, actions := runStep2(t, solver, game, claimBuilder.CorrectTraceProvider()) + for i, action := range builder.ExpectedActions { + t.Logf("Expect %v: Type: %v, ParentIdx: %v, Attack: %v, Value: %v, PreState: %v, ProofData: %v", + i, action.Type, action.ParentClaim.ContractIndex, action.IsAttack, action.Value, hex.EncodeToString(action.PreState), hex.EncodeToString(action.ProofData)) + require.Containsf(t, actions, action, "Expected claim %v missing", i) + break + } + require.Len(t, actions, len(builder.ExpectedActions), "Incorrect number of actions") + + verifyGameRules(t, postState, test.rootClaimCorrect) + }) + } +} + +func runStep2(t *testing.T, solver *GameSolver, game types.Game, correctTraceProvider types.TraceProvider) (types.Game, []types.Action) { + actions, err := solver.CalculateNextActions(context.Background(), game) + t.Logf("runStep2 actions: %v", actions) + require.NoError(t, err) + + postState := applyActions2(game, challengerAddr, actions) + + for i, action := range actions { + t.Logf("Move %v: Type: %v, ParentIdx: %v, Attack: %v, Value: %v, PreState: %v, ProofData: %v", + i, action.Type, action.ParentClaim.ContractIndex, action.IsAttack, action.Value, hex.EncodeToString(action.PreState), hex.EncodeToString(action.ProofData)) + // Check that every move the solver returns meets the generic validation rules + require.NoError(t, checkRules(game, action, correctTraceProvider), "Attempting to perform invalid action") + } + return postState, actions +} + +func applyActions2(game types.Game, claimant common.Address, actions []types.Action) types.Game { + claims := game.Claims() + for _, action := range actions { + switch action.Type { + case types.ActionTypeAttackV2: + newPosition := action.ParentClaim.Position.MoveN(game.NBits(), action.AttackBranch) + claim := types.Claim{ + ClaimData: types.ClaimData{ + Value: action.Value, + Bond: big.NewInt(0), + Position: newPosition, + }, + Claimant: claimant, + ContractIndex: len(claims), + ParentContractIndex: action.ParentClaim.ContractIndex, + SubValues: action.SubValues, + AttackBranch: action.AttackBranch, + } + claims = append(claims, claim) + case types.ActionTypeStep: + counteredClaim := claims[action.ParentClaim.ContractIndex] + counteredClaim.CounteredBy = claimant + claims[action.ParentClaim.ContractIndex] = counteredClaim + default: + panic(fmt.Errorf("unknown move type: %v", action.Type)) + } + } + return types.NewGameState2(claims, game.MaxDepth(), game.NBits(), game.SplitDepth()) +} diff --git a/op-challenger2/game/fault/solver/rules.go b/op-challenger2/game/fault/solver/rules.go index 88d790296a78..8a63d8d3e138 100644 --- a/op-challenger2/game/fault/solver/rules.go +++ b/op-challenger2/game/fault/solver/rules.go @@ -20,10 +20,10 @@ type actionRule func(game types.Game, action types.Action, correctTrace types.Tr var rules = []actionRule{ parentMustExist, onlyStepAtMaxDepth, - onlyMoveBeforeMaxDepth, + onlyAttackBeforeMaxDepth, doNotDuplicateExistingMoves, doNotStepAlreadyCounteredClaims, - doNotDefendRootClaim, + onlyAttackRootClaimZeroBranch, avoidPoisonedPrestate, detectPoisonedStepPrestate, detectFailedStep, @@ -66,15 +66,13 @@ func onlyStepAtMaxDepth(game types.Game, action types.Action, _ types.TraceProvi return nil } -// onlyMoveBeforeMaxDepth verifies that move actions are not performed against leaf claims -// Rationale: The action would be rejected by the contracts -func onlyMoveBeforeMaxDepth(game types.Game, action types.Action, _ types.TraceProvider) error { - if action.Type == types.ActionTypeMove { +func onlyAttackBeforeMaxDepth(game types.Game, action types.Action, _ types.TraceProvider) error { + if action.Type == types.ActionTypeAttackV2 { return nil } parentDepth := game.Claims()[action.ParentClaim.ContractIndex].Position.Depth() if parentDepth < game.MaxDepth() { - return fmt.Errorf("parent (%v) not at max depth (%v) but attempting to perform %v action instead of move", + return fmt.Errorf("parent (%v) not at max depth (%v) but attempting to perform %v action instead of attackV2", parentDepth, game.MaxDepth(), action.Type) } return nil @@ -103,11 +101,9 @@ func doNotStepAlreadyCounteredClaims(game types.Game, action types.Action, _ typ return nil } -// doNotDefendRootClaim checks the challenger doesn't attempt to defend the root claim -// Rationale: The action would be rejected by the contracts -func doNotDefendRootClaim(game types.Game, action types.Action, _ types.TraceProvider) error { - if game.Claims()[action.ParentClaim.ContractIndex].IsRootPosition() && !action.IsAttack { - return fmt.Errorf("defending the root claim at idx %v", action.ParentClaim.ContractIndex) +func onlyAttackRootClaimZeroBranch(game types.Game, action types.Action, _ types.TraceProvider) error { + if game.Claims()[action.ParentClaim.ContractIndex].IsRootPosition() && action.AttackBranch != 0 { + return fmt.Errorf("attacking the root claim at idx %v with branch %v", action.ParentClaim.ContractIndex, action.AttackBranch) } return nil } @@ -272,8 +268,5 @@ func resultingPosition(game types.Game, action types.Action) types.Position { if action.Type == types.ActionTypeStep { return parentPos } - if action.IsAttack { - return parentPos.Attack() - } - return parentPos.Defend() + return parentPos.MoveN(uint64(game.NBits()), action.AttackBranch) } diff --git a/op-challenger2/game/fault/solver/solver.go b/op-challenger2/game/fault/solver/solver.go index 48c99e69b8d6..48920927dd38 100644 --- a/op-challenger2/game/fault/solver/solver.go +++ b/op-challenger2/game/fault/solver/solver.go @@ -6,8 +6,8 @@ import ( "errors" "fmt" + "github.com/ethereum-optimism/optimism/op-challenger2/game/fault/contracts" "github.com/ethereum-optimism/optimism/op-challenger2/game/fault/types" - "github.com/ethereum-optimism/optimism/op-challenger2/game/keccak/merkle" "github.com/ethereum/go-ethereum/common" ) @@ -170,7 +170,7 @@ func (s *claimSolver) attackV2(ctx context.Context, game types.Game, claim types } values = append(values, value) } - hash := getClaimsHash(values) + hash := contracts.SubValuesHash(values) return &types.Claim{ ClaimData: types.ClaimData{Value: hash, Position: position}, ParentContractIndex: claim.ContractIndex, @@ -178,11 +178,3 @@ func (s *claimSolver) attackV2(ctx context.Context, game types.Game, claim types AttackBranch: branch, }, nil } - -func getClaimsHash(values []common.Hash) common.Hash { - tree := merkle.NewBinaryMerkleTree() - for i := 0; i < len(values); i++ { - tree.AddLeaf(values[i]) - } - return tree.RootHash() -} diff --git a/op-challenger2/game/fault/solver/solver_test.go b/op-challenger2/game/fault/solver/solver_test.go index 4fb5723fde8e..1106f73c176b 100644 --- a/op-challenger2/game/fault/solver/solver_test.go +++ b/op-challenger2/game/fault/solver/solver_test.go @@ -179,7 +179,8 @@ func TestAttemptStep(t *testing.T) { grandParentClaim := claims[parentClaim.ParentContractIndex] agreedClaims.AddHonestClaim(grandParentClaim, parentClaim) } - step, err := alphabetSolver.AttemptStep(ctx, game, lastClaim, agreedClaims) + // todo: add test for oracle data + step, err := alphabetSolver.AttemptStep(ctx, game, lastClaim, agreedClaims, 0) require.ErrorIs(t, err, tableTest.expectedErr) if !tableTest.expectNoStep && tableTest.expectedErr == nil { require.NotNil(t, step) diff --git a/op-challenger2/game/fault/test/claim_builder.go b/op-challenger2/game/fault/test/claim_builder.go index 91d07d6d1c0d..8b015a257fe9 100644 --- a/op-challenger2/game/fault/test/claim_builder.go +++ b/op-challenger2/game/fault/test/claim_builder.go @@ -2,6 +2,7 @@ package test import ( "context" + "fmt" "math" "math/big" "testing" @@ -161,22 +162,35 @@ func (c *ClaimBuilder) claim(pos types.Position, opts ...ClaimOpt) types.Claim { }, AttackBranch: cfg.branch, } - if cfg.claimant != (common.Address{}) { - claim.Claimant = cfg.claimant - } - if cfg.value != (common.Hash{}) { - claim.Value = cfg.value - } else if cfg.invalidValue { - claim.Value = c.incorrectClaim(pos) - } else { - claim.Value = c.CorrectClaimAtPosition(pos) - // when nbits is 1, subValues is also filled with claim.Value - claim.SubValues = &[]common.Hash{claim.Value} - } if cfg.subValues != nil { claim.SubValues = cfg.subValues + claim.Value = contracts.SubValuesHash(*claim.SubValues) + } else { + values := []common.Hash{} + if pos.ToGIndex().Cmp(big.NewInt(1)) == 0 { + if cfg.invalidValue { + values = append(values, c.incorrectClaim(pos)) + } else { + values = append(values, c.CorrectClaimAtPosition(pos)) + } + for i := uint64(0); i < c.MaxAttackBranch()-1; i++ { + values = append(values, common.Hash{}) + } + } else { + for i := uint64(0); i < c.MaxAttackBranch(); i++ { + pos := pos.MoveRightN(i) + if cfg.invalidValue { + values = append(values, c.incorrectClaim(pos)) + } else { + values = append(values, c.CorrectClaimAtPosition(pos)) + } + } + } + claim.SubValues = &values + claim.Value = contracts.SubValuesHash(*claim.SubValues) } claim.ParentContractIndex = cfg.parentIdx + fmt.Printf("claim.Value: %v\n", claim.Value) return claim } @@ -205,3 +219,19 @@ func (c *ClaimBuilder) DefendClaim(claim types.Claim, opts ...ClaimOpt) types.Cl pos := claim.Position.Defend() return c.claim(pos, append([]ClaimOpt{WithParent(claim)}, opts...)...) } + +func (c *ClaimBuilder) NBits() uint64 { + return c.nbits +} + +func (c *ClaimBuilder) MaxAttackBranch() uint64 { + return 1< Date: Sat, 16 Nov 2024 23:28:32 +0800 Subject: [PATCH 06/16] fix step maxAttackBranch test case --- op-challenger2/game/fault/solver/solver.go | 3 + .../game/fault/solver/solver_test.go | 74 ++++++++++++------- 2 files changed, 51 insertions(+), 26 deletions(-) diff --git a/op-challenger2/game/fault/solver/solver.go b/op-challenger2/game/fault/solver/solver.go index 58d4facf01ea..f0323db940e7 100644 --- a/op-challenger2/game/fault/solver/solver.go +++ b/op-challenger2/game/fault/solver/solver.go @@ -150,6 +150,9 @@ func (s *claimSolver) agreeWithClaim(ctx context.Context, game types.Game, claim } func (s *claimSolver) agreeWithClaimV2(ctx context.Context, game types.Game, claim types.Claim, branch uint64) (bool, error) { + if branch >= uint64(len(*claim.SubValues)) { + return true, fmt.Errorf("branch must be lesser than maxAttachBranch") + } ourValue, err := s.trace.Get(ctx, game, claim, claim.Position.MoveRightN(branch)) return bytes.Equal(ourValue[:], (*claim.SubValues)[branch][:]), err } diff --git a/op-challenger2/game/fault/solver/solver_test.go b/op-challenger2/game/fault/solver/solver_test.go index c42b45849fec..ce92b62ee9c9 100644 --- a/op-challenger2/game/fault/solver/solver_test.go +++ b/op-challenger2/game/fault/solver/solver_test.go @@ -11,6 +11,7 @@ import ( "github.com/ethereum-optimism/optimism/op-challenger2/game/fault/trace/split" "github.com/ethereum-optimism/optimism/op-challenger2/game/fault/types" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" ) @@ -370,12 +371,7 @@ func TestAttemptStepNary4(t *testing.T) { nbits := uint64(2) splitDepth := types.Depth(2) claimBuilder := faulttest.NewAlphabetClaimBuilder2(t, startingL2BlockNumber, maxDepth, nbits, splitDepth) - // traceDepth := maxDepth - splitDepth - types.Depth(nbits) - // Last accessible leaf is the second last trace index - // The root node is used for the last trace index and can only be attacked. - // lastLeafTraceIndex := big.NewInt(1< Date: Sun, 17 Nov 2024 20:59:51 +0800 Subject: [PATCH 07/16] fix bug by rules --- op-challenger2/game/fault/solver/rules.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/op-challenger2/game/fault/solver/rules.go b/op-challenger2/game/fault/solver/rules.go index 8a63d8d3e138..41c11f10a064 100644 --- a/op-challenger2/game/fault/solver/rules.go +++ b/op-challenger2/game/fault/solver/rules.go @@ -159,7 +159,8 @@ func avoidPoisonedPrestate(game types.Game, action types.Action, correctTrace ty if err != nil { return fmt.Errorf("failed to get correct trace at position %v: %w", preStateClaim.Position, err) } - if correctValue != preStateClaim.Value { + preStateClaimValue := (*preStateClaim.SubValues)[0] + if correctValue != preStateClaimValue { err = fmt.Errorf("prestate poisoned claim %v has invalid prestate and is left of honest claim countering %v at trace index %v", preStateClaim.ContractIndex, action.ParentClaim.ContractIndex, honestTraceIndex) return err } From 0805fd444ad46cef016304e8bee1fdbd77e5938a Mon Sep 17 00:00:00 2001 From: Po Date: Fri, 22 Nov 2024 00:18:46 +0800 Subject: [PATCH 08/16] add getstepData testcase --- op-challenger2/game/fault/solver/solver_test.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/op-challenger2/game/fault/solver/solver_test.go b/op-challenger2/game/fault/solver/solver_test.go index ce92b62ee9c9..10d93a3f08fd 100644 --- a/op-challenger2/game/fault/solver/solver_test.go +++ b/op-challenger2/game/fault/solver/solver_test.go @@ -557,7 +557,8 @@ func TestAttemptStepNary4(t *testing.T) { t.Run(tableTest.name, func(t *testing.T) { builder := claimBuilder.GameBuilder(faulttest.WithInvalidValue(tableTest.agreeWithOutputRoot)) tableTest.setupGame(builder) - alphabetSolver := newClaimSolver(maxDepth, trace.NewSimpleTraceAccessor(claimBuilder.CorrectTraceProvider()), types.CallDataType) + accessor := trace.NewSimpleTraceAccessor(claimBuilder.CorrectTraceProvider()) + alphabetSolver := newClaimSolver(maxDepth, accessor, types.CallDataType) game := builder.Game claims := game.Claims() lastClaim := claims[len(claims)-1] @@ -572,6 +573,8 @@ func TestAttemptStepNary4(t *testing.T) { } step, err := alphabetSolver.AttemptStep(ctx, game, lastClaim, agreedClaims, tableTest.attackBranch) require.ErrorIs(t, err, tableTest.expectedErr) + _, _, preimage, err := accessor.GetStepData2(ctx, game, lastClaim, lastClaim.MoveRightN(tableTest.expectAttackBranch)) + require.NoError(t, err) if !tableTest.expectNoStep && tableTest.expectedErr == nil { require.NotNil(t, step) require.Equal(t, lastClaim, step.LeafClaim) @@ -584,6 +587,8 @@ func TestAttemptStepNary4(t *testing.T) { require.Equal(t, tableTest.expectedOracleData.OracleOffset, step.OracleData.OracleOffset) require.Equal(t, tableTest.expectedVMStateData.PreDA, step.OracleData.VMStateDA.PreDA) require.Equal(t, tableTest.expectedVMStateData.PostDA, step.OracleData.VMStateDA.PostDA) + require.Equal(t, tableTest.expectedVMStateData.PreDA, preimage.VMStateDA.PreDA) + require.Equal(t, tableTest.expectedVMStateData.PostDA, preimage.VMStateDA.PostDA) require.Equal(t, tableTest.expectedLocalData.DaType, step.OracleData.OutputRootDAItem.DaType) require.Equal(t, tableTest.expectedLocalData.DataHash, step.OracleData.OutputRootDAItem.DataHash) require.Equal(t, tableTest.expectedLocalData.Proof, step.OracleData.OutputRootDAItem.Proof) From f65fdc3ca32062ac107287421738a30ca86440c4 Mon Sep 17 00:00:00 2001 From: Abe Orm Date: Sat, 23 Nov 2024 03:36:07 +0800 Subject: [PATCH 09/16] modify unittest TestCalculateNextActions --- .../game/fault/solver/game_solver.go | 6 +- .../game/fault/solver/game_solver_test.go | 528 +++++++++++------- op-challenger2/game/fault/solver/rules.go | 11 +- op-challenger2/game/fault/solver/solver.go | 18 +- .../game/fault/test/claim_builder.go | 57 +- .../game/fault/test/game_builder.go | 19 +- 6 files changed, 386 insertions(+), 253 deletions(-) diff --git a/op-challenger2/game/fault/solver/game_solver.go b/op-challenger2/game/fault/solver/game_solver.go index ac5f95ec0383..5f8ad8c579c1 100644 --- a/op-challenger2/game/fault/solver/game_solver.go +++ b/op-challenger2/game/fault/solver/game_solver.go @@ -20,7 +20,7 @@ func NewGameSolver(gameDepth types.Depth, trace types.TraceAccessor, daType type } func (s *GameSolver) AgreeWithRootClaim(ctx context.Context, game types.Game) (bool, error) { - return s.claimSolver.agreeWithClaim(ctx, game, game.Claims()[0]) + return s.claimSolver.agreeWithClaimV2(ctx, game, game.Claims()[0], 0) } func (s *GameSolver) CalculateNextActions(ctx context.Context, game types.Game) ([]types.Action, error) { @@ -114,14 +114,14 @@ func (s *GameSolver) calculateMove(ctx context.Context, game types.Game, claim t } honestClaims.AddHonestClaim(claim, *move) if game.IsDuplicate(*move) { - continue + break } return &types.Action{ Type: types.ActionTypeAttackV2, ParentClaim: game.Claims()[move.ParentContractIndex], Value: move.Value, SubValues: move.SubValues, - AttackBranch: uint64(branch), + AttackBranch: move.AttackBranch, DAType: s.claimSolver.daType, }, nil } diff --git a/op-challenger2/game/fault/solver/game_solver_test.go b/op-challenger2/game/fault/solver/game_solver_test.go index 87930cb0a155..e36f09da7042 100644 --- a/op-challenger2/game/fault/solver/game_solver_test.go +++ b/op-challenger2/game/fault/solver/game_solver_test.go @@ -17,12 +17,12 @@ import ( func TestCalculateNextActions_ChallengeL2BlockNumber(t *testing.T) { startingBlock := big.NewInt(5) - maxDepth := types.Depth(6) + maxDepth := types.Depth(8) challenge := &types.InvalidL2BlockNumberChallenge{ Output: ð.OutputResponse{OutputRoot: eth.Bytes32{0xbb}}, } - nbits := uint64(1) - splitDepth := types.Depth(3) + nbits := uint64(2) + splitDepth := types.Depth(4) claimBuilder := faulttest.NewAlphabetClaimBuilder2(t, startingBlock, maxDepth, nbits, splitDepth) traceProvider := faulttest.NewAlphabetWithProofProvider(t, startingBlock, maxDepth, nil, 0, faulttest.OracleDefaultKey) solver := NewGameSolver(maxDepth, trace.NewSimpleTraceAccessor(traceProvider), types.CallDataType) @@ -42,189 +42,6 @@ func TestCalculateNextActions_ChallengeL2BlockNumber(t *testing.T) { require.Equal(t, challenge, action.InvalidL2BlockNumberChallenge) } -func TestCalculateNextActions(t *testing.T) { - maxDepth := types.Depth(6) - startingL2BlockNumber := big.NewInt(0) - nbits := uint64(2) - splitDepth := types.Depth(3) - claimBuilder := faulttest.NewAlphabetClaimBuilder2(t, startingL2BlockNumber, maxDepth, nbits, splitDepth) - - tests := []struct { - name string - rootClaimCorrect bool - setupGame func(builder *faulttest.GameBuilder) - }{ - { - name: "AttackRootClaim", - setupGame: func(builder *faulttest.GameBuilder) { - builder.Seq().ExpectAttack() - }, - }, - { - name: "DoNotAttackCorrectRootClaim_AgreeWithOutputRoot", - rootClaimCorrect: true, - setupGame: func(builder *faulttest.GameBuilder) {}, - }, - { - name: "DoNotPerformDuplicateMoves", - setupGame: func(builder *faulttest.GameBuilder) { - // Expected move has already been made. - builder.Seq().Attack() - }, - }, - { - name: "RespondToAllClaimsAtDisagreeingLevel", - setupGame: func(builder *faulttest.GameBuilder) { - honestClaim := builder.Seq().Attack() - honestClaim.Attack().ExpectDefend() - honestClaim.Defend().ExpectDefend() - honestClaim.Attack(faulttest.WithValue(common.Hash{0xaa})).ExpectAttack() - honestClaim.Attack(faulttest.WithValue(common.Hash{0xbb})).ExpectAttack() - honestClaim.Defend(faulttest.WithValue(common.Hash{0xcc})).ExpectAttack() - honestClaim.Defend(faulttest.WithValue(common.Hash{0xdd})).ExpectAttack() - }, - }, - { - name: "StepAtMaxDepth", - setupGame: func(builder *faulttest.GameBuilder) { - lastHonestClaim := builder.Seq(). - Attack(). - Attack(). - Defend(). - Defend(). - Defend() - lastHonestClaim.Attack().ExpectStepDefend() - lastHonestClaim.Attack(faulttest.WithValue(common.Hash{0xdd})).ExpectStepAttack() - }, - }, - { - name: "PoisonedPreState", - setupGame: func(builder *faulttest.GameBuilder) { - // A claim hash that has no pre-image - maliciousStateHash := common.Hash{0x01, 0xaa} - - // Dishonest actor counters their own claims to set up a situation with an invalid prestate - // The honest actor should ignore path created by the dishonest actor, only supporting its own attack on the root claim - honestMove := builder.Seq().Attack() // This expected action is the winning move. - dishonestMove := honestMove.Attack(faulttest.WithValue(maliciousStateHash)) - // The expected action by the honest actor - dishonestMove.ExpectAttack() - // The honest actor will ignore this poisoned path - dishonestMove. - Defend(faulttest.WithValue(maliciousStateHash)). - Attack(faulttest.WithValue(maliciousStateHash)) - }, - }, - { - name: "Freeloader-ValidClaimAtInvalidAttackPosition", - setupGame: func(builder *faulttest.GameBuilder) { - builder.Seq(). - Attack(). // Honest response to invalid root - Defend().ExpectDefend(). // Defender agrees at this point, we should defend - Attack().ExpectDefend() // Freeloader attacks instead of defends - }, - }, - { - name: "Freeloader-InvalidClaimAtInvalidAttackPosition", - setupGame: func(builder *faulttest.GameBuilder) { - builder.Seq(). - Attack(). // Honest response to invalid root - Defend().ExpectDefend(). // Defender agrees at this point, we should defend - Attack(faulttest.WithValue(common.Hash{0xbb})).ExpectAttack() // Freeloader attacks with wrong claim instead of defends - }, - }, - { - name: "Freeloader-InvalidClaimAtValidDefensePosition", - setupGame: func(builder *faulttest.GameBuilder) { - builder.Seq(). - Attack(). // Honest response to invalid root - Defend().ExpectDefend(). // Defender agrees at this point, we should defend - Defend(faulttest.WithValue(common.Hash{0xbb})).ExpectAttack() // Freeloader defends with wrong claim, we should attack - }, - }, - { - name: "Freeloader-InvalidClaimAtValidAttackPosition", - setupGame: func(builder *faulttest.GameBuilder) { - builder.Seq(). - Attack(). // Honest response to invalid root - Defend(faulttest.WithValue(common.Hash{0xaa})).ExpectAttack(). // Defender disagrees at this point, we should attack - Attack(faulttest.WithValue(common.Hash{0xbb})).ExpectAttack() // Freeloader attacks with wrong claim instead of defends - }, - }, - { - name: "Freeloader-InvalidClaimAtInvalidDefensePosition", - setupGame: func(builder *faulttest.GameBuilder) { - builder.Seq(). - Attack(). // Honest response to invalid root - Defend(faulttest.WithValue(common.Hash{0xaa})).ExpectAttack(). // Defender disagrees at this point, we should attack - Defend(faulttest.WithValue(common.Hash{0xbb})) // Freeloader defends with wrong claim but we must not respond to avoid poisoning - }, - }, - { - name: "Freeloader-ValidClaimAtInvalidAttackPosition-RespondingToDishonestButCorrectAttack", - setupGame: func(builder *faulttest.GameBuilder) { - builder.Seq(). - Attack(). // Honest response to invalid root - Attack().ExpectDefend(). // Defender attacks with correct value, we should defend - Attack().ExpectDefend() // Freeloader attacks with wrong claim, we should defend - }, - }, - { - name: "Freeloader-DoNotCounterOwnClaim", - setupGame: func(builder *faulttest.GameBuilder) { - builder.Seq(). - Attack(). // Honest response to invalid root - Attack().ExpectDefend(). // Defender attacks with correct value, we should defend - Attack(). // Freeloader attacks instead, we should defend - Defend() // We do defend and we shouldn't counter our own claim - }, - }, - { - name: "Freeloader-ContinueDefendingAgainstFreeloader", - setupGame: func(builder *faulttest.GameBuilder) { - builder.Seq(). // invalid root - Attack(). // Honest response to invalid root - Attack().ExpectDefend(). // Defender attacks with correct value, we should defend - Attack(). // Freeloader attacks instead, we should defend - Defend(). // We do defend - Attack(faulttest.WithValue(common.Hash{0xaa})). // freeloader attacks our defense, we should attack - ExpectAttack() - }, - }, - { - name: "Freeloader-FreeloaderCountersRootClaim", - setupGame: func(builder *faulttest.GameBuilder) { - builder.Seq(). - ExpectAttack(). // Honest response to invalid root - Attack(faulttest.WithValue(common.Hash{0xaa})). // freeloader - ExpectAttack() // Honest response to freeloader - }, - }, - } - - for _, test := range tests { - test := test - t.Run(test.name, func(t *testing.T) { - builder := claimBuilder.GameBuilder(faulttest.WithInvalidValue(!test.rootClaimCorrect)) - test.setupGame(builder) - game := builder.Game - - solver := NewGameSolver(maxDepth, trace.NewSimpleTraceAccessor(claimBuilder.CorrectTraceProvider()), types.CallDataType) - postState, actions := runStep(t, solver, game, claimBuilder.CorrectTraceProvider()) - for i, action := range builder.ExpectedActions { - t.Logf("Expect %v: Type: %v, ParentIdx: %v, Attack: %v, Value: %v, PreState: %v, ProofData: %v", - i, action.Type, action.ParentClaim.ContractIndex, action.IsAttack, action.Value, hex.EncodeToString(action.PreState), hex.EncodeToString(action.ProofData)) - require.Containsf(t, actions, action, "Expected claim %v missing", i) - break - } - require.Len(t, actions, len(builder.ExpectedActions), "Incorrect number of actions") - - verifyGameRules(t, postState, test.rootClaimCorrect) - }) - break - } -} - func runStep(t *testing.T, solver *GameSolver, game types.Game, correctTraceProvider types.TraceProvider) (types.Game, []types.Action) { actions, err := solver.CalculateNextActions(context.Background(), game) require.NoError(t, err) @@ -367,7 +184,7 @@ func applyActions(game types.Game, claimant common.Address, actions []types.Acti return types.NewGameState2(claims, game.MaxDepth(), game.NBits(), game.SplitDepth()) } -func TestCalculateNextActions2(t *testing.T) { +func TestCalculateNextActions(t *testing.T) { maxDepth := types.Depth(8) startingL2BlockNumber := big.NewInt(0) nbits := uint64(2) @@ -379,31 +196,244 @@ func TestCalculateNextActions2(t *testing.T) { rootClaimCorrect bool setupGame func(builder *faulttest.GameBuilder) }{ - /* - { - name: "AttackRootClaim", - setupGame: func(builder *faulttest.GameBuilder) { - builder.Seq().ExpectAttackV2(0) - }, - }, - { - name: "DoNotAttackCorrectRootClaim_AgreeWithOutputRoot", - rootClaimCorrect: true, - setupGame: func(builder *faulttest.GameBuilder) {}, + { + name: "AttackRootClaim", + setupGame: func(builder *faulttest.GameBuilder) { + builder.Seq().ExpectAttackV2(0) }, - { - name: "DoNotPerformDuplicateMoves", - setupGame: func(builder *faulttest.GameBuilder) { - // Expected move has already been made. - builder.Seq().Attack() - }, + }, + { + name: "DoNotAttackCorrectRootClaim_AgreeWithOutputRoot", + rootClaimCorrect: true, + setupGame: func(builder *faulttest.GameBuilder) {}, + }, + { + name: "DoNotPerformDuplicateMoves", + setupGame: func(builder *faulttest.GameBuilder) { + builder.Seq().Attack2(nil, 0) }, - */ + }, { name: "RespondToAllClaimsAtDisagreeingLevel", setupGame: func(builder *faulttest.GameBuilder) { honestClaim := builder.Seq().Attack2(nil, 0) - honestClaim.Attack2(nil, 0).ExpectAttackV2(0) + honestClaim.Attack2(nil, 0).ExpectAttackV2(3) + }, + }, + { + name: "StepAtMaxDepth", + setupGame: func(builder *faulttest.GameBuilder) { + values := []common.Hash{{0x81}, {0x82}, {0x83}} + lastHonestClaim := builder.Seq(). + Attack2(nil, 0). // honest + Attack2(values, 3). // dishonest + Attack2(nil, 0) // honest + lastHonestClaim.Attack2([]common.Hash{{0x1}, {0x2}, {0x3}}, 0).ExpectStepV2(0) + }, + }, + { + name: "PoisonedPreState", + setupGame: func(builder *faulttest.GameBuilder) { + values := []common.Hash{{0x81}, {0x82}, {0x83}} + honest := builder.Seq().Attack2(nil, 0) + dishonest := honest.Attack2(values, 0) + dishonest.ExpectAttackV2(0) + dishonest.Attack2(values, 0) + dishonest.ExpectAttackV2(0) + }, + }, + { + name: "HonestRoot-OneLevelAttack", + rootClaimCorrect: true, + setupGame: func(builder *faulttest.GameBuilder) { + values := []common.Hash{{0x81}, {0x82}, {0x83}} + honest := builder.Seq() + honest.Attack2(nil, 0).ExpectAttackV2(3) + honest.Attack2(values, 0).ExpectAttackV2(0) + values = claimBuilder.GetClaimsAtPosition(builder.Game.RootClaim().Position.MoveN(nbits, 0), []uint64{1}) + honest.Attack2(values, 0).ExpectAttackV2(1) + values = claimBuilder.GetClaimsAtPosition(builder.Game.RootClaim().Position.MoveN(nbits, 0), []uint64{2}) + honest.Attack2(values, 0).ExpectAttackV2(2) + }, + }, + { + name: "DishonestRoot-OneLevelAttack", + setupGame: func(builder *faulttest.GameBuilder) { + values := []common.Hash{{0x81}, {0x82}, {0x83}} + dishonest := builder.Seq().ExpectAttackV2(0) + dishonest.Attack2(values, 0).ExpectAttackV2(0) + values = claimBuilder.GetClaimsAtPosition(builder.Game.RootClaim().Position.MoveN(nbits, 0), []uint64{1}) + dishonest.Attack2(values, 0).ExpectAttackV2(1) + values = claimBuilder.GetClaimsAtPosition(builder.Game.RootClaim().Position.MoveN(nbits, 0), []uint64{2}) + dishonest.Attack2(values, 0).ExpectAttackV2(2) + }, + }, + { + name: "HonestRoot-TwoLevelAttack-FirstLevelCorrect-SecondLevelCorrect", + rootClaimCorrect: true, + setupGame: func(builder *faulttest.GameBuilder) { + dishonest := builder.Seq().Attack2(nil, 0) + dishonest.Attack2(nil, 0).ExpectAttackV2(3) + dishonest.Attack2(nil, 1).ExpectAttackV2(3) + dishonest.Attack2(nil, 2).ExpectAttackV2(3) + dishonest.Attack2(nil, 3) + }, + }, + { + name: "HonestRoot-TwoLevelAttack-FirstLevelCorrect-SecondLevelIncorrect", + rootClaimCorrect: true, + setupGame: func(builder *faulttest.GameBuilder) { + values := []common.Hash{{0x81}, {0x82}, {0x83}} + dishonest := builder.Seq().Attack2(nil, 0).ExpectAttackV2(3) + lastPosition := builder.Game.Claims()[len(builder.Game.Claims())-1].Position + dishonest.Attack2(values, 0).ExpectAttackV2(0) + dishonest.Attack2(values, 1).ExpectAttackV2(0) + dishonest.Attack2(values, 2).ExpectAttackV2(0) + dishonest.Attack2(values, 3).ExpectAttackV2(0) + + values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 0), []uint64{0}) + dishonest.Attack2(values, 0).ExpectAttackV2(0) + values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 0), []uint64{1}) + dishonest.Attack2(values, 0).ExpectAttackV2(1) + values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 0), []uint64{2}) + dishonest.Attack2(values, 0).ExpectAttackV2(2) + + values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 1), []uint64{0}) + dishonest.Attack2(values, 1).ExpectAttackV2(0) + values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 1), []uint64{1}) + dishonest.Attack2(values, 1).ExpectAttackV2(1) + values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 1), []uint64{2}) + dishonest.Attack2(values, 1).ExpectAttackV2(2) + + values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 2), []uint64{0}) + dishonest.Attack2(values, 2).ExpectAttackV2(0) + values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 2), []uint64{1}) + dishonest.Attack2(values, 2).ExpectAttackV2(1) + values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 2), []uint64{2}) + dishonest.Attack2(values, 2).ExpectAttackV2(2) + + values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 3), []uint64{0}) + dishonest.Attack2(values, 3).ExpectAttackV2(0) + values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 3), []uint64{1}) + dishonest.Attack2(values, 3).ExpectAttackV2(1) + values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 3), []uint64{2}) + dishonest.Attack2(values, 3).ExpectAttackV2(2) + }, + }, + { + name: "HonestRoot-TwoLevelAttack-FirstLevelIncorrect-SecondLevelCorrect", + rootClaimCorrect: true, + setupGame: func(builder *faulttest.GameBuilder) { + values := []common.Hash{{0x81}, {0x82}, {0x83}} + honest := builder.Seq() + lastPosition := builder.Game.Claims()[len(builder.Game.Claims())-1].Position + honest.Attack2(values, 0).Attack2(nil, 0) + values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 0), []uint64{1}) + honest.Attack2(values, 0).ExpectAttackV2(1).Attack2(nil, 0).ExpectAttackV2(3) + values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 0), []uint64{2}) + honest.Attack2(values, 0).ExpectAttackV2(2).Attack2(nil, 0).ExpectAttackV2(3) + values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 0), []uint64{3}) + honest.Attack2(values, 0).ExpectAttackV2(3).Attack2(nil, 0).ExpectAttackV2(3) + }, + }, + { + name: "StepAtMaxDepth-LeftBranch-StepBranch0", + setupGame: func(builder *faulttest.GameBuilder) { + values := []common.Hash{{0x81}, {0x82}, {0x83}} + lastHonestClaim := builder.Seq(). + Attack2(nil, 0). // honest + Attack2(values, 0). // dishonest + Attack2(nil, 0) // honest + lastHonestClaim.Attack2([]common.Hash{{0x1}, {0x2}, {0x3}}, 0).ExpectStepV2(0) + }, + }, + { + name: "StepAtMaxDepth-LeftBranch-StepBranch1", + setupGame: func(builder *faulttest.GameBuilder) { + values := []common.Hash{{0x81}, {0x82}, {0x83}} + lastHonestClaim := builder.Seq(). + Attack2(nil, 0). // honest + Attack2(values, 0). // dishonest + Attack2(nil, 0) // honest + lastPosition := builder.Game.Claims()[len(builder.Game.Claims())-1].Position + values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 0), []uint64{1}) + lastHonestClaim.Attack2(values, 0).ExpectStepV2(1) + }, + }, + { + name: "StepAtMaxDepth-LeftBranch-StepBranch2", + setupGame: func(builder *faulttest.GameBuilder) { + values := []common.Hash{{0x81}, {0x82}, {0x83}} + lastHonestClaim := builder.Seq(). + Attack2(nil, 0). // honest + Attack2(values, 0). // dishonest + Attack2(nil, 0) // honest + lastPosition := builder.Game.Claims()[len(builder.Game.Claims())-1].Position + values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 0), []uint64{2}) + lastHonestClaim.Attack2(values, 0).ExpectStepV2(2) + }, + }, + { + name: "StepAtMaxDepth-LeftBranch-StepBranch3", + setupGame: func(builder *faulttest.GameBuilder) { + values := []common.Hash{{0x81}, {0x82}, {0x83}} + lastHonestClaim := builder.Seq(). + Attack2(nil, 0). // honest + Attack2(values, 0). // dishonest + Attack2(nil, 0) // honest + lastPosition := builder.Game.Claims()[len(builder.Game.Claims())-1].Position + values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 0), []uint64{}) + lastHonestClaim.Attack2(values, 0).ExpectStepV2(3) + }, + }, + { + name: "StepAtMaxDepth-MiddleBranch-StepBranch0", + setupGame: func(builder *faulttest.GameBuilder) { + values := []common.Hash{{0x81}, {0x82}, {0x83}} + lastHonestClaim := builder.Seq(). + Attack2(nil, 0). // honest + Attack2(values, 1). // dishonest + Attack2(nil, 0) // honest + lastHonestClaim.Attack2([]common.Hash{{0x1}, {0x2}, {0x3}}, 0).ExpectStepV2(0) + }, + }, + { + name: "StepAtMaxDepth-MiddleBranch-StepBranch1", + setupGame: func(builder *faulttest.GameBuilder) { + values := []common.Hash{{0x81}, {0x82}, {0x83}} + lastHonestClaim := builder.Seq(). + Attack2(nil, 0). // honest + Attack2(values, 1). // dishonest + Attack2(nil, 0) // honest + lastPosition := builder.Game.Claims()[len(builder.Game.Claims())-1].Position + values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 0), []uint64{1}) + lastHonestClaim.Attack2(values, 0).ExpectStepV2(1) + }, + }, + { + name: "StepAtMaxDepth-MiddleBranch-StepBranch2", + setupGame: func(builder *faulttest.GameBuilder) { + values := []common.Hash{{0x81}, {0x82}, {0x83}} + lastHonestClaim := builder.Seq(). + Attack2(nil, 0). // honest + Attack2(values, 1). // dishonest + Attack2(nil, 0) // honest + lastPosition := builder.Game.Claims()[len(builder.Game.Claims())-1].Position + values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 0), []uint64{2}) + lastHonestClaim.Attack2(values, 0).ExpectStepV2(2) + }, + }, + { + name: "StepAtMaxDepth-MiddleBranch-StepBranch3", + setupGame: func(builder *faulttest.GameBuilder) { + values := []common.Hash{{0x81}, {0x82}, {0x83}} + lastHonestClaim := builder.Seq(). + Attack2(nil, 0). // honest + Attack2(values, 1). // dishonest + Attack2(nil, 0) // honest + lastPosition := builder.Game.Claims()[len(builder.Game.Claims())-1].Position + values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 0), []uint64{}) + lastHonestClaim.Attack2(values, 0).ExpectStepV2(3) }, }, } @@ -414,16 +444,19 @@ func TestCalculateNextActions2(t *testing.T) { builder := claimBuilder.GameBuilder(faulttest.WithInvalidValue(!test.rootClaimCorrect)) test.setupGame(builder) game := builder.Game - solver := NewGameSolver(maxDepth, trace.NewSimpleTraceAccessor(claimBuilder.CorrectTraceProvider()), types.CallDataType) + accessor := trace.NewSimpleTraceAccessor(claimBuilder.CorrectTraceProvider()) + solver := NewGameSolver(maxDepth, accessor, types.CallDataType) postState, actions := runStep2(t, solver, game, claimBuilder.CorrectTraceProvider()) + preimage := getStepPreimage(t, builder, game, accessor) for i, action := range builder.ExpectedActions { - t.Logf("Expect %v: Type: %v, ParentIdx: %v, Attack: %v, Value: %v, PreState: %v, ProofData: %v", - i, action.Type, action.ParentClaim.ContractIndex, action.IsAttack, action.Value, hex.EncodeToString(action.PreState), hex.EncodeToString(action.ProofData)) + if action.Type == types.ActionTypeStep { + action.OracleData = preimage + } + t.Logf("Expect %v: Type: %v, Position: %v, ParentIdx: %v, Branch: %v, Value: %v, SubValues: %v, PreState: %v, ProofData: %v", + i, action.Type, action.ParentClaim.Position, action.ParentClaim.ContractIndex, action.AttackBranch, action.Value, action.SubValues, hex.EncodeToString(action.PreState), hex.EncodeToString(action.ProofData)) require.Containsf(t, actions, action, "Expected claim %v missing", i) - break } require.Len(t, actions, len(builder.ExpectedActions), "Incorrect number of actions") - verifyGameRules(t, postState, test.rootClaimCorrect) }) } @@ -431,14 +464,16 @@ func TestCalculateNextActions2(t *testing.T) { func runStep2(t *testing.T, solver *GameSolver, game types.Game, correctTraceProvider types.TraceProvider) (types.Game, []types.Action) { actions, err := solver.CalculateNextActions(context.Background(), game) - t.Logf("runStep2 actions: %v", actions) require.NoError(t, err) postState := applyActions2(game, challengerAddr, actions) for i, action := range actions { - t.Logf("Move %v: Type: %v, ParentIdx: %v, Attack: %v, Value: %v, PreState: %v, ProofData: %v", - i, action.Type, action.ParentClaim.ContractIndex, action.IsAttack, action.Value, hex.EncodeToString(action.PreState), hex.EncodeToString(action.ProofData)) + t.Logf("Real %v: Type: %v, Position: %v, ParentIdx: %v, Branch: %v, Value: %v, SubValues: %v, PreState: %v, ProofData: %v", + i, action.Type, + action.ParentClaim.Position, + action.ParentClaim.ContractIndex, + action.AttackBranch, action.Value, action.SubValues, hex.EncodeToString(action.PreState), hex.EncodeToString(action.ProofData)) // Check that every move the solver returns meets the generic validation rules require.NoError(t, checkRules(game, action, correctTraceProvider), "Attempting to perform invalid action") } @@ -474,3 +509,68 @@ func applyActions2(game types.Game, claimant common.Address, actions []types.Act } return types.NewGameState2(claims, game.MaxDepth(), game.NBits(), game.SplitDepth()) } + +func getStepPreimage(t *testing.T, builder *faulttest.GameBuilder, game types.Game, accessor types.TraceAccessor) *types.PreimageOracleData { + if len(builder.ExpectedActions) == 0 { + return nil + } + claims := game.Claims() + lastClaim := claims[len(claims)-1] + lastExpectedAction := builder.ExpectedActions[len(builder.ExpectedActions)-1] + if lastExpectedAction.Type != types.ActionTypeStep { + return nil + } + _, _, preimage, err := accessor.GetStepData2(context.Background(), game, lastClaim, lastClaim.MoveRightN(lastExpectedAction.AttackBranch)) + require.NoError(t, err) + return preimage +} + +func TestMultipleRounds2(t *testing.T) { + t.Parallel() + tests := []struct { + name string + actor actor + }{ + /* + { + name: "SingleRoot", + actor: doNothingActor, + }, + */ + { + name: "LinearAttackCorrect", + actor: correctAttackLastClaim, + }, + } + for _, test := range tests { + test := test + for _, rootClaimCorrect := range []bool{true, false} { + rootClaimCorrect := rootClaimCorrect + t.Run(fmt.Sprintf("%v-%v", test.name, rootClaimCorrect), func(t *testing.T) { + t.Parallel() + + maxDepth := types.Depth(8) + startingL2BlockNumber := big.NewInt(50) + nbits := uint64(2) + splitDepth := types.Depth(4) + claimBuilder := faulttest.NewAlphabetClaimBuilder2(t, startingL2BlockNumber, maxDepth, nbits, splitDepth) + builder := claimBuilder.GameBuilder(faulttest.WithInvalidValue(!rootClaimCorrect)) + game := builder.Game + + correctTrace := claimBuilder.CorrectTraceProvider() + solver := NewGameSolver(maxDepth, trace.NewSimpleTraceAccessor(correctTrace), types.CallDataType) + + roundNum := 0 + done := false + for !done { + t.Logf("------ ROUND %v ------", roundNum) + game, _ = runStep2(t, solver, game, correctTrace) + verifyGameRules(t, game, rootClaimCorrect) + + game, done = test.actor.Apply(t, game, correctTrace) + roundNum++ + } + }) + } + } +} diff --git a/op-challenger2/game/fault/solver/rules.go b/op-challenger2/game/fault/solver/rules.go index 41c11f10a064..45ce9af7c5c4 100644 --- a/op-challenger2/game/fault/solver/rules.go +++ b/op-challenger2/game/fault/solver/rules.go @@ -25,8 +25,8 @@ var rules = []actionRule{ doNotStepAlreadyCounteredClaims, onlyAttackRootClaimZeroBranch, avoidPoisonedPrestate, - detectPoisonedStepPrestate, - detectFailedStep, + //detectPoisonedStepPrestate, + //detectFailedStep, doNotCounterSelf, } @@ -191,10 +191,7 @@ func detectFailedStep(game types.Game, action types.Action, correctTrace types.T return nil } honestTraceIndex := position.TraceIndex(game.MaxDepth()) - poststateIndex := honestTraceIndex - if !action.IsAttack { - poststateIndex = new(big.Int).Add(honestTraceIndex, big.NewInt(1)) - } + poststateIndex := new(big.Int).Add(honestTraceIndex, big.NewInt(int64(action.AttackBranch))) // Walk back up the claims and find the claim required post state index claim := game.Claims()[action.ParentClaim.ContractIndex] poststateClaim, ok := game.AncestorWithTraceIndex(claim, poststateIndex) @@ -205,7 +202,7 @@ func detectFailedStep(game types.Game, action types.Action, correctTrace types.T if err != nil { return fmt.Errorf("failed to get correct trace at position %v: %w", poststateClaim.Position, err) } - validStep := correctValue == poststateClaim.Value + validStep := correctValue == (*poststateClaim.SubValues)[0] parentPostAgree := (claim.Depth()-poststateClaim.Depth())%2 == 0 if parentPostAgree == validStep { return fmt.Errorf("failed step against claim at %v using poststate from claim %v post state is correct? %v parentPostAgree? %v", diff --git a/op-challenger2/game/fault/solver/solver.go b/op-challenger2/game/fault/solver/solver.go index f0323db940e7..26095abd5c69 100644 --- a/op-challenger2/game/fault/solver/solver.go +++ b/op-challenger2/game/fault/solver/solver.go @@ -123,17 +123,18 @@ func (s *claimSolver) AttemptStep(ctx context.Context, game types.Game, claim ty // Attack the claim by executing step index, so we need to get the pre-state of that index position = claim.Position.MoveRightN(branch) } else { - // Defend and use this claim as the starting point to execute the step after. - // Thus, we need the pre-state of the next step. - position = claim.Position.MoveRightN(branch + 1) - attackBranch = branch + 1 + if branch == game.MaxAttackBranch()-1 { + // If we are at the max attack branch, we need to step on the next branch + position = claim.Position.MoveRightN(branch + 1) + attackBranch = branch + 1 + } else { + return nil, nil + } } - preState, proofData, oracleData, err := s.trace.GetStepData2(ctx, game, claim, position) if err != nil { return nil, err } - return &StepData{ LeafClaim: claim, AttackBranch: attackBranch, @@ -144,11 +145,6 @@ func (s *claimSolver) AttemptStep(ctx context.Context, game types.Game, claim ty } // agreeWithClaim returns true if the claim is correct according to the internal [TraceProvider]. -func (s *claimSolver) agreeWithClaim(ctx context.Context, game types.Game, claim types.Claim) (bool, error) { - ourValue, err := s.trace.Get(ctx, game, claim, claim.Position) - return bytes.Equal(ourValue[:], claim.Value[:]), err -} - func (s *claimSolver) agreeWithClaimV2(ctx context.Context, game types.Game, claim types.Claim, branch uint64) (bool, error) { if branch >= uint64(len(*claim.SubValues)) { return true, fmt.Errorf("branch must be lesser than maxAttachBranch") diff --git a/op-challenger2/game/fault/test/claim_builder.go b/op-challenger2/game/fault/test/claim_builder.go index 8b015a257fe9..cd2a99f6a6c1 100644 --- a/op-challenger2/game/fault/test/claim_builder.go +++ b/op-challenger2/game/fault/test/claim_builder.go @@ -2,7 +2,6 @@ package test import ( "context" - "fmt" "math" "math/big" "testing" @@ -167,7 +166,7 @@ func (c *ClaimBuilder) claim(pos types.Position, opts ...ClaimOpt) types.Claim { claim.Value = contracts.SubValuesHash(*claim.SubValues) } else { values := []common.Hash{} - if pos.ToGIndex().Cmp(big.NewInt(1)) == 0 { + if pos.IsRootPosition() { if cfg.invalidValue { values = append(values, c.incorrectClaim(pos)) } else { @@ -176,21 +175,21 @@ func (c *ClaimBuilder) claim(pos types.Position, opts ...ClaimOpt) types.Claim { for i := uint64(0); i < c.MaxAttackBranch()-1; i++ { values = append(values, common.Hash{}) } + } else if pos.Depth() == c.splitDepth+types.Depth(c.nbits) { + values = append(values, c.CorrectClaimAtPosition(pos)) + for i := uint64(0); i < c.MaxAttackBranch()-1; i++ { + values = append(values, common.Hash{}) + } } else { for i := uint64(0); i < c.MaxAttackBranch(); i++ { pos := pos.MoveRightN(i) - if cfg.invalidValue { - values = append(values, c.incorrectClaim(pos)) - } else { - values = append(values, c.CorrectClaimAtPosition(pos)) - } + values = append(values, c.CorrectClaimAtPosition(pos)) } } claim.SubValues = &values claim.Value = contracts.SubValuesHash(*claim.SubValues) } claim.ParentContractIndex = cfg.parentIdx - fmt.Printf("claim.Value: %v\n", claim.Value) return claim } @@ -235,3 +234,45 @@ func (c *ClaimBuilder) SplitDepth() types.Depth { func (c *ClaimBuilder) TraceRootDepth() types.Depth { return c.splitDepth + types.Depth(c.nbits) } + +func (c *ClaimBuilder) GetClaimsAtPosition(pos types.Position, invalidBranchList []uint64) []common.Hash { + values := []common.Hash{} + if pos.IsRootPosition() { + if contains(invalidBranchList, uint64(0)) { + values = append(values, c.incorrectClaim(pos)) + } else { + values = append(values, c.CorrectClaimAtPosition(pos)) + } + for i := uint64(0); i < c.MaxAttackBranch()-1; i++ { + values = append(values, common.Hash{}) + } + } else if pos.Depth() == c.splitDepth+types.Depth(c.nbits) { + if contains(invalidBranchList, uint64(0)) { + values = append(values, c.incorrectClaim(pos)) + } else { + values = append(values, c.CorrectClaimAtPosition(pos)) + } + for i := uint64(0); i < c.MaxAttackBranch()-1; i++ { + values = append(values, common.Hash{}) + } + } else { + for i := uint64(0); i < c.MaxAttackBranch(); i++ { + pos := pos.MoveRightN(i) + if contains(invalidBranchList, i) { + values = append(values, c.incorrectClaim(pos)) + } else { + values = append(values, c.CorrectClaimAtPosition(pos)) + } + } + } + return values +} + +func contains(slice []uint64, value uint64) bool { + for _, v := range slice { + if v == value { + return true + } + } + return false +} diff --git a/op-challenger2/game/fault/test/game_builder.go b/op-challenger2/game/fault/test/game_builder.go index 9f6933ec5f2b..5a0e0b18f9c3 100644 --- a/op-challenger2/game/fault/test/game_builder.go +++ b/op-challenger2/game/fault/test/game_builder.go @@ -1,7 +1,6 @@ package test import ( - "fmt" "math/big" "testing" @@ -170,6 +169,7 @@ func (s *GameBuilderSeq) ExpectAttackV2(branch uint64) *GameBuilderSeq { nBits := s.builder.NBits() maxAttackBranch := s.builder.MaxAttackBranch() position := s.lastClaim.Position.MoveN(nBits, branch) + for i := uint64(0); i < maxAttackBranch; i++ { tmpPosition := position.MoveRightN(i) if tmpPosition.Depth() == (s.builder.SplitDepth()+types.Depth(nBits)) && i != 0 { @@ -177,7 +177,6 @@ func (s *GameBuilderSeq) ExpectAttackV2(branch uint64) *GameBuilderSeq { } else { value = s.builder.CorrectClaimAtPosition(tmpPosition) } - fmt.Printf("i: %v, value: %v, position: %v\n", i, value, tmpPosition.ToGIndex()) values = append(values, value) } hash := contracts.SubValuesHash(values) @@ -193,15 +192,15 @@ func (s *GameBuilderSeq) ExpectAttackV2(branch uint64) *GameBuilderSeq { return s } -func (s *GameBuilderSeq) ExpectStepAttackV2(branch uint64) *GameBuilderSeq { - traceIdx := new(big.Int).Add(s.lastClaim.TraceIndex(s.builder.maxDepth), big.NewInt(1)) +func (s *GameBuilderSeq) ExpectStepV2(branch uint64) *GameBuilderSeq { + traceIdx := new(big.Int).Add(s.lastClaim.TraceIndex(s.builder.maxDepth), big.NewInt(int64(branch))) s.gameBuilder.ExpectedActions = append(s.gameBuilder.ExpectedActions, types.Action{ - Type: types.ActionTypeStep, - ParentClaim: s.lastClaim, - IsAttack: true, - PreState: s.builder.CorrectPreState(traceIdx), - ProofData: s.builder.CorrectProofData(traceIdx), - OracleData: s.builder.CorrectOracleData(traceIdx), + Type: types.ActionTypeStep, + ParentClaim: s.lastClaim, + AttackBranch: branch, + PreState: s.builder.CorrectPreState(traceIdx), + ProofData: s.builder.CorrectProofData(traceIdx), + OracleData: s.builder.CorrectOracleData(traceIdx), }) return s } From 32ca079a262fdbda5a7f3cb07e80270f7eb5b841 Mon Sep 17 00:00:00 2001 From: Po Date: Wed, 27 Nov 2024 06:41:39 +0000 Subject: [PATCH 10/16] fix: TestMultipleRoundsWithNbits1/2 --- op-challenger2/game/fault/solver/actors.go | 54 +++++++++++---- .../game/fault/solver/game_rules_test.go | 1 - .../game/fault/solver/game_solver.go | 5 +- .../game/fault/solver/game_solver_test.go | 69 ++++++++++++++++--- op-challenger2/game/fault/solver/solver.go | 8 +++ .../game/fault/solver/solver_test.go | 3 +- .../game/fault/test/claim_builder.go | 8 ++- .../game/fault/test/game_builder.go | 12 ++++ op-challenger2/game/fault/trace/access.go | 2 +- 9 files changed, 133 insertions(+), 29 deletions(-) diff --git a/op-challenger2/game/fault/solver/actors.go b/op-challenger2/game/fault/solver/actors.go index 38ddbbf39b39..aeef491b9493 100644 --- a/op-challenger2/game/fault/solver/actors.go +++ b/op-challenger2/game/fault/solver/actors.go @@ -51,20 +51,28 @@ var correctDefendLastClaim = respondLastClaim(func(seq *test.GameBuilderSeq) { // Must attack the root seq.Attack2(nil, 0) } else { - seq.Attack2(nil, 1) + seq.Attack2(nil, seq.MaxAttackBranch()) } }) var incorrectAttackLastClaim = respondLastClaim(func(seq *test.GameBuilderSeq) { - seq.Attack2(nil, 0, test.WithValue(common.Hash{0xaa})) + incorrectSubValues := []common.Hash{} + for i := uint64(0); i < seq.MaxAttackBranch(); i++ { + incorrectSubValues = append(incorrectSubValues, common.Hash{0xaa}) + } + seq.Attack2(incorrectSubValues, 0) }) var incorrectDefendLastClaim = respondLastClaim(func(seq *test.GameBuilderSeq) { + incorrectSubValues := []common.Hash{} + for i := uint64(0); i < seq.MaxAttackBranch(); i++ { + incorrectSubValues = append(incorrectSubValues, common.Hash{0xdd}) + } if seq.IsRoot() { // Must attack the root - seq.Attack2(nil, 0, test.WithValue(common.Hash{0xdd})) + seq.Attack2(incorrectSubValues, 0) } else { - seq.Attack2(nil, 1, test.WithValue(common.Hash{0xdd})) + seq.Attack2(incorrectSubValues, seq.MaxAttackBranch()) } }) @@ -77,29 +85,51 @@ var defendEverythingCorrect = respondAllClaims(func(seq *test.GameBuilderSeq) { // Must attack root seq.Attack2(nil, 0) } else { - seq.Attack2(nil, 1) + seq.Attack2(nil, seq.MaxAttackBranch()) } }) var attackEverythingIncorrect = respondAllClaims(func(seq *test.GameBuilderSeq) { - seq.Attack2(nil, 0, test.WithValue(common.Hash{0xaa})) + incorrectSubValues := []common.Hash{} + for i := uint64(0); i < seq.MaxAttackBranch(); i++ { + incorrectSubValues = append(incorrectSubValues, common.Hash{0xaa}) + } + seq.Attack2(incorrectSubValues, 0) }) var defendEverythingIncorrect = respondAllClaims(func(seq *test.GameBuilderSeq) { + incorrectSubValues := []common.Hash{} + for i := uint64(0); i < seq.MaxAttackBranch(); i++ { + incorrectSubValues = append(incorrectSubValues, common.Hash{0xbb}) + } if seq.IsRoot() { // Must attack root - seq.Attack2(nil, 0, test.WithValue(common.Hash{0xbb})) + seq.Attack2(incorrectSubValues, 0) } else { - seq.Attack2(nil, 1, test.WithValue(common.Hash{0xbb})) + seq.Attack2(incorrectSubValues, seq.MaxAttackBranch()) } }) var exhaustive = respondAllClaims(func(seq *test.GameBuilderSeq) { seq.Attack2(nil, 0) - seq.Attack2(nil, 0, test.WithValue(common.Hash{0xaa})) - if !seq.IsRoot() { - seq.Attack2(nil, 1) - seq.Attack2(nil, 1, test.WithValue(common.Hash{0xdd})) + incorrectSubValues := []common.Hash{} + for i := uint64(0); i < seq.MaxAttackBranch(); i++ { + incorrectSubValues = append(incorrectSubValues, common.Hash{0xaa}) + if seq.IsSplitDepth() { + // at splitDepth, there is only one subValue + break + } + } + seq.Attack2(incorrectSubValues, 0) + if !seq.IsRoot() && !seq.IsTraceRoot() { + seq.Attack2(nil, seq.MaxAttackBranch()) + for i := uint64(0); i < seq.MaxAttackBranch(); i++ { + incorrectSubValues[i] = common.Hash{0xdd} + if seq.IsSplitDepth() { + break + } + } + seq.Attack2(incorrectSubValues, seq.MaxAttackBranch()) } }) diff --git a/op-challenger2/game/fault/solver/game_rules_test.go b/op-challenger2/game/fault/solver/game_rules_test.go index af6845ccf5eb..0d60476bfb08 100644 --- a/op-challenger2/game/fault/solver/game_rules_test.go +++ b/op-challenger2/game/fault/solver/game_rules_test.go @@ -15,7 +15,6 @@ import ( func verifyGameRules(t *testing.T, game types.Game, rootClaimCorrect bool) { actualResult, claimTree, resolvedGame := gameResult(game) - verifyExpectedGameResult(t, rootClaimCorrect, actualResult) verifyNoChallengerClaimsWereSuccessfullyCountered(t, resolvedGame) diff --git a/op-challenger2/game/fault/solver/game_solver.go b/op-challenger2/game/fault/solver/game_solver.go index 5f8ad8c579c1..d3ebcea0310d 100644 --- a/op-challenger2/game/fault/solver/game_solver.go +++ b/op-challenger2/game/fault/solver/game_solver.go @@ -99,11 +99,12 @@ func (s *GameSolver) calculateStep(ctx context.Context, game types.Game, claim t func (s *GameSolver) calculateMove(ctx context.Context, game types.Game, claim types.Claim, honestClaims *honestClaimTracker) (*types.Action, error) { for branch := range *claim.SubValues { + // attack branch 0 can be attacked at root or splitDepth+nbits if claim.Position.Depth() == game.SplitDepth()+types.Depth(game.NBits()) && branch != 0 { - continue + return nil, nil } if claim.IsRoot() && branch != 0 { - continue + return nil, nil } move, err := s.claimSolver.NextMove(ctx, claim, game, honestClaims, uint64(branch)) if err != nil { diff --git a/op-challenger2/game/fault/solver/game_solver_test.go b/op-challenger2/game/fault/solver/game_solver_test.go index e36f09da7042..58de94bc544b 100644 --- a/op-challenger2/game/fault/solver/game_solver_test.go +++ b/op-challenger2/game/fault/solver/game_solver_test.go @@ -57,7 +57,7 @@ func runStep(t *testing.T, solver *GameSolver, game types.Game, correctTraceProv return postState, actions } -func TestMultipleRounds(t *testing.T) { +func TestMultipleRoundsWithNbits1(t *testing.T) { t.Parallel() tests := []struct { name string @@ -142,7 +142,7 @@ func TestMultipleRounds(t *testing.T) { done := false for !done { t.Logf("------ ROUND %v ------", roundNum) - game, _ = runStep(t, solver, game, correctTrace) + game, _ = runStep2(t, solver, game, correctTrace) verifyGameRules(t, game, rootClaimCorrect) game, done = test.actor.Apply(t, game, correctTrace) @@ -525,33 +525,80 @@ func getStepPreimage(t *testing.T, builder *faulttest.GameBuilder, game types.Ga return preimage } -func TestMultipleRounds2(t *testing.T) { +func TestMultipleRoundsWithNbits2(t *testing.T) { t.Parallel() tests := []struct { name string actor actor }{ - /* - { - name: "SingleRoot", - actor: doNothingActor, - }, - */ + { + name: "SingleRoot", + actor: doNothingActor, + }, { name: "LinearAttackCorrect", actor: correctAttackLastClaim, }, + { + name: "LinearDefendCorrect", + actor: correctDefendLastClaim, + }, + { + name: "LinearAttackIncorrect", + actor: incorrectAttackLastClaim, + }, + { + name: "LinearDefendInorrect", + actor: incorrectDefendLastClaim, + }, + { + name: "LinearDefendIncorrectDefendCorrect", + actor: combineActors(incorrectDefendLastClaim, correctDefendLastClaim), + }, + { + name: "LinearAttackIncorrectDefendCorrect", + actor: combineActors(incorrectAttackLastClaim, correctDefendLastClaim), + }, + { + name: "LinearDefendIncorrectDefendIncorrect", + actor: combineActors(incorrectDefendLastClaim, incorrectDefendLastClaim), + }, + { + name: "LinearAttackIncorrectDefendIncorrect", + actor: combineActors(incorrectAttackLastClaim, incorrectDefendLastClaim), + }, + { + name: "AttackEverythingCorrect", + actor: attackEverythingCorrect, + }, + { + name: "DefendEverythingCorrect", + actor: defendEverythingCorrect, + }, + { + name: "AttackEverythingIncorrect", + actor: attackEverythingIncorrect, + }, + { + name: "DefendEverythingIncorrect", + actor: defendEverythingIncorrect, + }, + { + name: "Exhaustive", + actor: exhaustive, + }, } for _, test := range tests { test := test - for _, rootClaimCorrect := range []bool{true, false} { + for _, rootClaimCorrect := range []bool{false} { rootClaimCorrect := rootClaimCorrect t.Run(fmt.Sprintf("%v-%v", test.name, rootClaimCorrect), func(t *testing.T) { t.Parallel() - maxDepth := types.Depth(8) + maxDepth := types.Depth(10) startingL2BlockNumber := big.NewInt(50) nbits := uint64(2) + // splitDepth can't be 4 when maxDepth=8, because we can only attack branch 0 at claim with depth of splitDepth+nbits splitDepth := types.Depth(4) claimBuilder := faulttest.NewAlphabetClaimBuilder2(t, startingL2BlockNumber, maxDepth, nbits, splitDepth) builder := claimBuilder.GameBuilder(faulttest.WithInvalidValue(!rootClaimCorrect)) diff --git a/op-challenger2/game/fault/solver/solver.go b/op-challenger2/game/fault/solver/solver.go index 26095abd5c69..e702cf25cae6 100644 --- a/op-challenger2/game/fault/solver/solver.go +++ b/op-challenger2/game/fault/solver/solver.go @@ -81,6 +81,14 @@ func (s *claimSolver) NextMove(ctx context.Context, claim types.Claim, game type return nil, err } if agree { + if claim.Depth() == game.TraceRootDepth() && branch == 0 { + // Only useful in alphabet game, because the alphabet game has a constant status byte, and is not safe from someone being dishonest in + // output bisection and then posting a correct execution trace bisection root claim. + // when root claim of output bisection is dishonest, + // root claim of execution trace bisection is made by the dishonest actor but is honest + // we should counter it. + return s.attackV2(ctx, game, claim, branch) + } if branch < game.MaxAttackBranch()-1 { return nil, nil } diff --git a/op-challenger2/game/fault/solver/solver_test.go b/op-challenger2/game/fault/solver/solver_test.go index 10d93a3f08fd..5a0e1f595cc1 100644 --- a/op-challenger2/game/fault/solver/solver_test.go +++ b/op-challenger2/game/fault/solver/solver_test.go @@ -5,6 +5,7 @@ import ( "math/big" "testing" + "github.com/ethereum-optimism/optimism/op-challenger2/game/fault/contracts" faulttest "github.com/ethereum-optimism/optimism/op-challenger2/game/fault/test" "github.com/ethereum-optimism/optimism/op-challenger2/game/fault/trace" "github.com/ethereum-optimism/optimism/op-challenger2/game/fault/trace/alphabet" @@ -534,7 +535,7 @@ func TestAttemptStepNary4(t *testing.T) { ), }, PostDA: types.DAItem{ - DataHash: claimAt(types.NewPosition(types.Depth(4), common.Big0)), + DataHash: contracts.SubValuesHash(append([]common.Hash{}, claimAt(types.NewPosition(types.Depth(4), common.Big0)), common.Hash{}, common.Hash{})), }, }, expectedLocalData: &types.DAItem{}, diff --git a/op-challenger2/game/fault/test/claim_builder.go b/op-challenger2/game/fault/test/claim_builder.go index cd2a99f6a6c1..38cbf021105b 100644 --- a/op-challenger2/game/fault/test/claim_builder.go +++ b/op-challenger2/game/fault/test/claim_builder.go @@ -161,7 +161,13 @@ func (c *ClaimBuilder) claim(pos types.Position, opts ...ClaimOpt) types.Claim { }, AttackBranch: cfg.branch, } - if cfg.subValues != nil { + if cfg.claimant != (common.Address{}) { + claim.Claimant = cfg.claimant + } + if cfg.invalidValue { + claim.Value = c.incorrectClaim(pos) + claim.SubValues = &[]common.Hash{claim.Value} + } else if cfg.subValues != nil { claim.SubValues = cfg.subValues claim.Value = contracts.SubValuesHash(*claim.SubValues) } else { diff --git a/op-challenger2/game/fault/test/game_builder.go b/op-challenger2/game/fault/test/game_builder.go index 5a0e0b18f9c3..e683620563e2 100644 --- a/op-challenger2/game/fault/test/game_builder.go +++ b/op-challenger2/game/fault/test/game_builder.go @@ -56,10 +56,22 @@ func (g *GameBuilderSeq) IsRoot() bool { return g.lastClaim.IsRoot() } +func (g *GameBuilderSeq) IsTraceRoot() bool { + return g.lastClaim.Depth() == g.gameBuilder.Game.SplitDepth()+types.Depth(g.gameBuilder.Game.NBits()) +} + +func (g *GameBuilderSeq) IsSplitDepth() bool { + return g.lastClaim.Depth() == g.gameBuilder.Game.SplitDepth() +} + func (g *GameBuilderSeq) LastClaim() types.Claim { return g.lastClaim } +func (g *GameBuilderSeq) MaxAttackBranch() uint64 { + return g.gameBuilder.builder.MaxAttackBranch() +} + // addClaimToGame replaces the game being built with a new instance that has claim as the latest claim. // The ContractIndex in claim is updated with its position in the game's claim array. // Does nothing if the claim already exists diff --git a/op-challenger2/game/fault/trace/access.go b/op-challenger2/game/fault/trace/access.go index ff610f2f12df..ed00bdbb9072 100644 --- a/op-challenger2/game/fault/trace/access.go +++ b/op-challenger2/game/fault/trace/access.go @@ -152,7 +152,7 @@ func (t *Accessor) GetStepData2(ctx context.Context, game types.Game, ref types. preTraceIdx := new(big.Int).Sub(postTraceIdx, big.NewInt(1)) preStateDaItem, err := findAncestorProofAtDepth2(ctx, provider, game, ref, preTraceIdx) if err != nil { - return nil, nil, nil, fmt.Errorf("failed to get postStateDaItem at trace index %v: %w", preTraceIdx, err) + return nil, nil, nil, fmt.Errorf("failed to get preStateDaItem at trace index %v: %w", preTraceIdx, err) } postStateDaItem, err := findAncestorProofAtDepth2(ctx, provider, game, ref, postTraceIdx) if err != nil { From 0176d08688f8b264e67150e20297d2655eac73aa Mon Sep 17 00:00:00 2001 From: Po Date: Wed, 27 Nov 2024 10:13:29 +0000 Subject: [PATCH 11/16] fix tests: responder_test and TestGetStepDataWithOutputRoot test --- .../game/fault/responder/responder_test.go | 69 ++++++++++++++----- op-challenger2/game/fault/trace/access.go | 21 +++--- 2 files changed, 63 insertions(+), 27 deletions(-) diff --git a/op-challenger2/game/fault/responder/responder_test.go b/op-challenger2/game/fault/responder/responder_test.go index 65517bc188fd..c9dc5b1f7e35 100644 --- a/op-challenger2/game/fault/responder/responder_test.go +++ b/op-challenger2/game/fault/responder/responder_test.go @@ -146,37 +146,54 @@ func TestPerformAction(t *testing.T) { require.Equal(t, ([]byte)("attack"), mockTxMgr.sent[0].TxData) }) - t.Run("defend", func(t *testing.T) { + t.Run("attackV2", func(t *testing.T) { responder, mockTxMgr, contract, _, _ := newTestFaultResponder(t) action := types.Action{ - Type: types.ActionTypeMove, - ParentClaim: types.Claim{ContractIndex: 123}, - IsAttack: false, - Value: common.Hash{0xaa}, + Type: types.ActionTypeAttackV2, + ParentClaim: types.Claim{ContractIndex: 123}, + IsAttack: false, + AttackBranch: 0, + DAType: types.CallDataType, + SubValues: &[]common.Hash{{0xaa}}, } err := responder.PerformAction(context.Background(), action) require.NoError(t, err) require.Len(t, mockTxMgr.sent, 1) - require.EqualValues(t, []interface{}{action.ParentClaim, action.Value}, contract.defendArgs) - require.Equal(t, ([]byte)("defend"), mockTxMgr.sent[0].TxData) + daTypeUint64 := (*big.Int)(action.DAType).Uint64() + subValues := make([]byte, 0, len(*action.SubValues)) + for _, subValue := range *action.SubValues { + subValues = append(subValues, subValue[:]...) + } + require.EqualValues(t, []interface{}{action.ParentClaim, action.AttackBranch, daTypeUint64, subValues}, contract.attackV2Args) + require.Equal(t, ([]byte)("attackV2"), mockTxMgr.sent[0].TxData) }) t.Run("step", func(t *testing.T) { responder, mockTxMgr, contract, _, _ := newTestFaultResponder(t) action := types.Action{ - Type: types.ActionTypeStep, - ParentClaim: types.Claim{ContractIndex: 123}, - IsAttack: true, - PreState: []byte{1, 2, 3}, - ProofData: []byte{4, 5, 6}, + Type: types.ActionTypeStep, + ParentClaim: types.Claim{ContractIndex: 123}, + IsAttack: true, + AttackBranch: 0, + PreState: []byte{1, 2, 3}, + ProofData: []byte{4, 5, 6}, + OracleData: &types.PreimageOracleData{ + VMStateDA: types.DAData{}, + OutputRootDAItem: types.DAItem{}, + }, + } + stepProof := types.StepProof{ + PreStateItem: action.OracleData.VMStateDA.PreDA, + PostStateItem: action.OracleData.VMStateDA.PostDA, + VmProof: action.ProofData, } err := responder.PerformAction(context.Background(), action) require.NoError(t, err) require.Len(t, mockTxMgr.sent, 1) - require.EqualValues(t, []interface{}{uint64(123), action.IsAttack, action.PreState, action.ProofData}, contract.stepArgs) - require.Equal(t, ([]byte)("step"), mockTxMgr.sent[0].TxData) + require.EqualValues(t, []interface{}{uint64(123), action.AttackBranch, action.PreState, stepProof}, contract.stepV2Args) + require.Equal(t, ([]byte)("stepV2"), mockTxMgr.sent[0].TxData) }) t.Run("stepWithLocalOracleData", func(t *testing.T) { @@ -188,7 +205,9 @@ func TestPerformAction(t *testing.T) { PreState: []byte{1, 2, 3}, ProofData: []byte{4, 5, 6}, OracleData: &types.PreimageOracleData{ - IsLocal: true, + IsLocal: true, + VMStateDA: types.DAData{}, + OutputRootDAItem: types.DAItem{}, }, } err := responder.PerformAction(context.Background(), action) @@ -196,7 +215,7 @@ func TestPerformAction(t *testing.T) { require.Len(t, mockTxMgr.sent, 1) require.Nil(t, contract.updateOracleArgs) // mock uploader returns nil - require.Equal(t, ([]byte)("step"), mockTxMgr.sent[0].TxData) + require.Equal(t, ([]byte)("stepV2"), mockTxMgr.sent[0].TxData) require.Equal(t, 1, uploader.updates) require.Equal(t, 0, oracle.existCalls) }) @@ -210,7 +229,9 @@ func TestPerformAction(t *testing.T) { PreState: []byte{1, 2, 3}, ProofData: []byte{4, 5, 6}, OracleData: &types.PreimageOracleData{ - IsLocal: false, + IsLocal: false, + VMStateDA: types.DAData{}, + OutputRootDAItem: types.DAItem{}, }, } err := responder.PerformAction(context.Background(), action) @@ -218,7 +239,7 @@ func TestPerformAction(t *testing.T) { require.Len(t, mockTxMgr.sent, 1) require.Nil(t, contract.updateOracleArgs) // mock uploader returns nil - require.Equal(t, ([]byte)("step"), mockTxMgr.sent[0].TxData) + require.Equal(t, ([]byte)("stepV2"), mockTxMgr.sent[0].TxData) require.Equal(t, 1, uploader.updates) require.Equal(t, 1, oracle.existCalls) }) @@ -370,8 +391,10 @@ type mockContract struct { calls int callFails bool attackArgs []interface{} + attackV2Args []interface{} defendArgs []interface{} stepArgs []interface{} + stepV2Args []interface{} challengeArgs []interface{} updateOracleClaimIdx uint64 updateOracleArgs *types.PreimageOracleData @@ -411,6 +434,11 @@ func (m *mockContract) AttackTx(_ context.Context, parent types.Claim, claim com return txmgr.TxCandidate{TxData: ([]byte)("attack")}, nil } +func (m *mockContract) AttackV2Tx(ctx context.Context, parent types.Claim, attackBranch uint64, daType uint64, claims []byte) (txmgr.TxCandidate, error) { + m.attackV2Args = []interface{}{parent, attackBranch, daType, claims} + return txmgr.TxCandidate{TxData: ([]byte)("attackV2")}, nil +} + func (m *mockContract) DefendTx(_ context.Context, parent types.Claim, claim common.Hash) (txmgr.TxCandidate, error) { m.defendArgs = []interface{}{parent, claim} return txmgr.TxCandidate{TxData: ([]byte)("defend")}, nil @@ -421,6 +449,11 @@ func (m *mockContract) StepTx(claimIdx uint64, isAttack bool, stateData []byte, return txmgr.TxCandidate{TxData: ([]byte)("step")}, nil } +func (m *mockContract) StepV2Tx(claimIdx uint64, attackBranch uint64, stateData []byte, proof types.StepProof) (txmgr.TxCandidate, error) { + m.stepV2Args = []interface{}{claimIdx, attackBranch, stateData, proof} + return txmgr.TxCandidate{TxData: ([]byte)("stepV2")}, nil +} + func (m *mockContract) UpdateOracleTx(_ context.Context, claimIdx uint64, data *types.PreimageOracleData) (txmgr.TxCandidate, error) { m.updateOracleClaimIdx = claimIdx m.updateOracleArgs = data diff --git a/op-challenger2/game/fault/trace/access.go b/op-challenger2/game/fault/trace/access.go index ed00bdbb9072..c8e7841ecc68 100644 --- a/op-challenger2/game/fault/trace/access.go +++ b/op-challenger2/game/fault/trace/access.go @@ -165,17 +165,20 @@ func (t *Accessor) GetStepData2(ctx context.Context, game types.Game, ref types. preimageData.VMStateDA = stateData - keyType := preimage.KeyType(preimageData.OracleKey[0]) - if keyType == preimage.LocalKeyType { - ident := preimageData.GetIdent() - addlocalDataDaItem := types.DAItem{} - if ident.Cmp(big.NewInt(types.LocalPreimageKeyStartingOutputRoot)) == 0 { - addlocalDataDaItem = outputRootDA.PreDA - } else if ident.Cmp(big.NewInt(types.LocalPreimageKeyDisputedOutputRoot)) == 0 { - addlocalDataDaItem = outputRootDA.PostDA + if preimageData.OracleKey != nil { + keyType := preimage.KeyType(preimageData.OracleKey[0]) + if keyType == preimage.LocalKeyType { + ident := preimageData.GetIdent() + addlocalDataDaItem := types.DAItem{} + if ident.Cmp(big.NewInt(types.LocalPreimageKeyStartingOutputRoot)) == 0 { + addlocalDataDaItem = outputRootDA.PreDA + } else if ident.Cmp(big.NewInt(types.LocalPreimageKeyDisputedOutputRoot)) == 0 { + addlocalDataDaItem = outputRootDA.PostDA + } + preimageData.OutputRootDAItem = addlocalDataDaItem } - preimageData.OutputRootDAItem = addlocalDataDaItem } + return prestate, proofData, preimageData, nil } From 670ca682c7e2150dcd371d4b6bb241a1d5ff5901 Mon Sep 17 00:00:00 2001 From: Po Date: Fri, 29 Nov 2024 10:43:41 +0800 Subject: [PATCH 12/16] fix: getTxByHash and filterLog call in devnet env --- .../fault/contracts/faultdisputegame_test.go | 10 ++-- op-service/sources/batching/event_call.go | 58 ++++++++++++++++--- .../sources/batching/event_call_test.go | 2 +- op-service/sources/batching/test/abi_stub.go | 6 +- .../sources/batching/test/event_stub.go | 20 ++++--- .../sources/batching/test/generic_stub.go | 7 ++- op-service/sources/batching/test/tx_stub.go | 6 +- op-service/sources/batching/tx_call.go | 15 ++--- op-service/sources/batching/tx_call_test.go | 4 +- 9 files changed, 83 insertions(+), 45 deletions(-) diff --git a/op-challenger2/game/fault/contracts/faultdisputegame_test.go b/op-challenger2/game/fault/contracts/faultdisputegame_test.go index ced0eb91ee1f..f83517276d88 100644 --- a/op-challenger2/game/fault/contracts/faultdisputegame_test.go +++ b/op-challenger2/game/fault/contracts/faultdisputegame_test.go @@ -794,6 +794,9 @@ func setupFaultDisputeGameTest(t *testing.T, version contractVersion) (*batching caller := batching.NewMultiCaller(stubRpc, batching.DefaultBatchSize) stubRpc.SetResponse(fdgAddr, methodVersion, rpcblock.Latest, nil, []interface{}{version.version}) + nbitOrSplitDepth := big.NewInt(2) + stubRpc.SetResponse(fdgAddr, methodNBits, rpcblock.Latest, nil, []interface{}{nbitOrSplitDepth}) + stubRpc.SetResponse(fdgAddr, methodSplitDepth, rpcblock.Latest, nil, []interface{}{nbitOrSplitDepth}) game, err := NewFaultDisputeGameContract(context.Background(), contractMetrics.NoopContractMetrics, fdgAddr, caller) require.NoError(t, err) return stubRpc, game @@ -874,6 +877,7 @@ func TestGetAllClaimsWithSubValues(t *testing.T) { attackBranch := big.NewInt(0) parent := faultTypes.Claim{ClaimData: faultTypes.ClaimData{Value: common.Hash{0xbb}, Position: parentPos}, ContractIndex: 111} stubRpc.SetResponse(fdgAddr, methodNBits, block, nil, []interface{}{new(big.Int).SetUint64(nBits)}) + stubRpc.SetResponse(fdgAddr, methodSplitDepth, block, nil, []interface{}{new(big.Int).SetUint64(nBits)}) stubRpc.SetResponse(fdgAddr, methodRequiredBond, block, []interface{}{parent.Position.MoveN(nBits, attackBranch.Uint64()).ToGIndex()}, []interface{}{bond}) stubRpc.SetResponse(fdgAddr, methodAttackV2, block, []interface{}{parent.Value, big.NewInt(111), attackBranch, daType, claimsBytes[:]}, nil) txCandidate, err := game.AttackV2Tx(context.Background(), parent, attackBranch.Uint64(), daType.Uint64(), claimsBytes[:]) @@ -886,10 +890,8 @@ func TestGetAllClaimsWithSubValues(t *testing.T) { Value: big.NewInt(111), Data: txCandidate.TxData, }) - packed, err := tx.MarshalBinary() - require.NoError(t, err) txHash := tx.Hash() - stubRpc.SetGetTxByHashResponse(txHash, packed) + stubRpc.SetGetTxByHashResponse(txHash, tx) // mock eventLog eventName := eventMove @@ -915,7 +917,7 @@ func TestGetAllClaimsWithSubValues(t *testing.T) { }, } - stubRpc.SetFilterLogResponse(topics, fdgAddr, block, out) + stubRpc.SetFilterLogResponse(topics, []common.Address{fdgAddr}, block, out) stubRpc.SetResponse(fdgAddr, methodClaimCount, block, nil, []interface{}{big.NewInt(1)}) stubRpc.SetResponse(fdgAddr, methodMaxAttackBranch, block, nil, []interface{}{big.NewInt(1<= 0 { + return hexutil.EncodeBig(number) + } + // It's negative. + if number.IsInt64() { + return rpc.BlockNumber(number.Int64()).String() + } + // It's negative and large, which is invalid. + return fmt.Sprintf("", number) +} diff --git a/op-service/sources/batching/event_call_test.go b/op-service/sources/batching/event_call_test.go index 6144e34bd402..01e41901872b 100644 --- a/op-service/sources/batching/event_call_test.go +++ b/op-service/sources/batching/event_call_test.go @@ -57,7 +57,7 @@ func TestEventLogFilter(t *testing.T) { out[i] = r } - stub.SetFilterLogResponse(topics, addr, block, _out) + stub.SetFilterLogResponse(topics, []common.Address{addr}, block, _out) caller := NewMultiCaller(stub, DefaultBatchSize) filter, err := batchingTest.NewERC20Filterer(addr, caller) diff --git a/op-service/sources/batching/test/abi_stub.go b/op-service/sources/batching/test/abi_stub.go index d29d2f22045b..7fe0635135f1 100644 --- a/op-service/sources/batching/test/abi_stub.go +++ b/op-service/sources/batching/test/abi_stub.go @@ -149,7 +149,7 @@ func (l *AbiBasedRpc) SetResponse(to common.Address, method string, block rpcblo }) } -func (l *AbiBasedRpc) SetFilterLogResponse(topics [][]common.Hash, to common.Address, block rpcblock.Block, output []types.Log) { +func (l *AbiBasedRpc) SetFilterLogResponse(topics [][]common.Hash, to []common.Address, block rpcblock.Block, output []types.Log) { if output == nil { output = []types.Log{} } @@ -162,9 +162,9 @@ func (l *AbiBasedRpc) SetFilterLogResponse(topics [][]common.Hash, to common.Add }) } -func (l *AbiBasedRpc) SetGetTxByHashResponse(txHash common.Hash, output []byte) { +func (l *AbiBasedRpc) SetGetTxByHashResponse(txHash common.Hash, output *types.Transaction) { if output == nil { - output = []byte{} + output = &types.Transaction{} } l.AddExpectedCall(&expectedGetTxByHashCall{txHash: txHash, outputs: output}) } diff --git a/op-service/sources/batching/test/event_stub.go b/op-service/sources/batching/test/event_stub.go index 6b46d385f819..29a00c693214 100644 --- a/op-service/sources/batching/test/event_stub.go +++ b/op-service/sources/batching/test/event_stub.go @@ -14,28 +14,32 @@ import ( type expectedFilterLogsCall struct { topics [][]common.Hash - to common.Address + to []common.Address block rpcblock.Block outputs []types.Log err error } func (c *expectedFilterLogsCall) Matches(rpcMethod string, args ...interface{}) error { - if rpcMethod != "eth_getFilterLogs" { - return fmt.Errorf("expected rpcMethod eth_getFilterLogs but was %v", rpcMethod) + if rpcMethod != "eth_getLogs" { + return fmt.Errorf("expected rpcMethod eth_getLogs but was %v", rpcMethod) } - topics, ok := args[0].([][]common.Hash) + query, ok := args[0].(map[string]interface{}) if !ok { - return fmt.Errorf("arg 0 is not [][]common.Hash") + return fmt.Errorf("arg 0 is not map[string]interface{}") + } + topics := query["topics"].([][]common.Hash) + if !ok { + return fmt.Errorf("topics is not [][]common.Hash") } if !reflect.DeepEqual(topics, c.topics) { return fmt.Errorf("expected topics %v but was %v", c.topics, topics) } - to := args[1].(common.Address) - if to != c.to { + to := query["address"].([]common.Address) + if !reflect.DeepEqual(to, c.to) { return fmt.Errorf("expected contract address %v but was %v", c.to, to) } return c.err @@ -52,7 +56,7 @@ func (c *expectedFilterLogsCall) String() string { return fmt.Sprintf("{to: %v, block: %v, outputs: %v}", c.to, c.block, c.outputs) } -func (l *RpcStub) SetFilterLogResponse(topics [][]common.Hash, to common.Address, block rpcblock.Block, output []types.Log) { +func (l *RpcStub) SetFilterLogResponse(topics [][]common.Hash, to []common.Address, block rpcblock.Block, output []types.Log) { if output == nil { output = []types.Log{} } diff --git a/op-service/sources/batching/test/generic_stub.go b/op-service/sources/batching/test/generic_stub.go index d79d121d4363..ffbc1ac6af5d 100644 --- a/op-service/sources/batching/test/generic_stub.go +++ b/op-service/sources/batching/test/generic_stub.go @@ -11,6 +11,7 @@ import ( "github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -80,11 +81,11 @@ func NewGetBalanceCall(addr common.Address, block rpcblock.Block, balance *big.I } } -func NewGetTxCall(txHash common.Hash, block rpcblock.Block, out *[]byte) ExpectedRpcCall { +func NewGetTxCall(txHash common.Hash, block rpcblock.Block, out *types.Transaction) ExpectedRpcCall { return &GenericExpectedCall{ method: "eth_getTransactionByHash", - args: []interface{}{txHash, block.ArgValue()}, - result: hexutil.Encode(*out), + args: []interface{}{txHash}, + result: out, } } diff --git a/op-service/sources/batching/test/tx_stub.go b/op-service/sources/batching/test/tx_stub.go index 4b14a7592781..562093d3187c 100644 --- a/op-service/sources/batching/test/tx_stub.go +++ b/op-service/sources/batching/test/tx_stub.go @@ -6,13 +6,13 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/types" "github.com/stretchr/testify/require" ) type expectedGetTxByHashCall struct { txHash common.Hash - outputs []byte + outputs *types.Transaction err error } @@ -34,7 +34,7 @@ func (c *expectedGetTxByHashCall) Matches(rpcMethod string, args ...interface{}) } func (c *expectedGetTxByHashCall) Execute(t *testing.T, out interface{}) error { - j, err := json.Marshal(hexutil.Bytes(c.outputs)) + j, err := json.Marshal(c.outputs) require.NoError(t, err) require.NoError(t, json.Unmarshal(j, out)) return c.err diff --git a/op-service/sources/batching/tx_call.go b/op-service/sources/batching/tx_call.go index de3d223e2e5d..e5a0c3b9bf4c 100644 --- a/op-service/sources/batching/tx_call.go +++ b/op-service/sources/batching/tx_call.go @@ -6,7 +6,6 @@ import ( "github.com/ethereum-optimism/optimism/op-service/sources/batching/rpcblock" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" ) @@ -27,25 +26,19 @@ func NewTxGetByHash(abi *abi.ABI, txhash common.Hash, method string) *TxGetByHas func (b *TxGetByHashCall) ToBatchElemCreator() (BatchElementCreator, error) { return func(block rpcblock.Block) (any, rpc.BatchElem) { - out := new(hexutil.Bytes) + out := new(types.Transaction) return out, rpc.BatchElem{ Method: "eth_getTransactionByHash", - Args: []interface{}{b.TxHash, block.ArgValue()}, + Args: []interface{}{b.TxHash}, Result: &out, } }, nil } func (c *TxGetByHashCall) HandleResult(result interface{}) (*CallResult, error) { - res, ok := result.(*hexutil.Bytes) + txn, ok := result.(*types.Transaction) if !ok { - return nil, fmt.Errorf("result is not hexutil.Bytes") - } - - txn := new(types.Transaction) - err := txn.UnmarshalBinary(*res) - if err != nil { - return nil, err + return nil, fmt.Errorf("result is not types.Transaction") } return &CallResult{out: []interface{}{txn}}, nil } diff --git a/op-service/sources/batching/tx_call_test.go b/op-service/sources/batching/tx_call_test.go index 7dfdefb88335..b92d3cd1d880 100644 --- a/op-service/sources/batching/tx_call_test.go +++ b/op-service/sources/batching/tx_call_test.go @@ -31,11 +31,9 @@ func TestUnpackTxCalldata(t *testing.T) { Data: inputData, }) require.NoError(t, err) - packed, err := tx.MarshalBinary() - require.NoError(t, err) stub := test.NewRpcStub(t) - stub.AddExpectedCall(test.NewGetTxCall(txHash, rpcblock.Latest, &packed)) + stub.AddExpectedCall(test.NewGetTxCall(txHash, rpcblock.Latest, tx)) caller := NewMultiCaller(stub, DefaultBatchSize) txCall := NewTxGetByHash(testAbi, txHash, "approve") From 162ec267db9966b0f7c7a4dfc22f22b5f699cc5e Mon Sep 17 00:00:00 2001 From: Po Date: Fri, 29 Nov 2024 10:49:25 +0800 Subject: [PATCH 13/16] contract: 1. rename addLocalData to addLocalData2 to avoid conflicting in tx.Pack 2. fix subValues at splitDepth+nbits must be 1 --- .../game/fault/contracts/faultdisputegame.go | 43 +- op-challenger2/game/fault/solver/solver.go | 7 +- op-e2e2/bindings/faultdiputegameN.go | 2079 ++++++++++++++ .../disputegame/output_game_helper.go | 74 +- .../snapshots/abi/FaultDisputeGameN.json | 2556 ++++++++--------- .../src/dispute/FaultDisputeGameN.sol | 9 +- .../test/actors/FaultDisputeActorsN.sol | 2 +- .../test/dispute/FaultDisputeGameN.t.sol | 70 +- 8 files changed, 3478 insertions(+), 1362 deletions(-) create mode 100644 op-e2e2/bindings/faultdiputegameN.go diff --git a/op-challenger2/game/fault/contracts/faultdisputegame.go b/op-challenger2/game/fault/contracts/faultdisputegame.go index 384bb1065bf8..28aa9f4523df 100644 --- a/op-challenger2/game/fault/contracts/faultdisputegame.go +++ b/op-challenger2/game/fault/contracts/faultdisputegame.go @@ -44,7 +44,7 @@ var ( methodAttack = "attack" methodDefend = "defend" methodStep = "step" - methodAddLocalData = "addLocalData" + methodAddLocalData = "addLocalData2" methodVM = "vm" methodStartingBlockNumber = "startingBlockNumber" methodStartingRootHash = "startingRootHash" @@ -75,6 +75,8 @@ type FaultDisputeGameContractLatest struct { metrics metrics.ContractMetricer multiCaller *batching.MultiCaller contract *batching.BoundContract + nbits uint64 + splitDepth types.Depth } type Proposal struct { @@ -130,11 +132,23 @@ func NewFaultDisputeGameContract(ctx context.Context, metrics metrics.ContractMe }, }, nil } else { - return &FaultDisputeGameContractLatest{ + + contract := &FaultDisputeGameContractLatest{ metrics: metrics, multiCaller: caller, contract: batching.NewBoundContract(contractAbi, addr), - }, nil + } + nbits, err := contract.GetNBits(ctx) + if err != nil { + return nil, err + } + splitDepth, err := contract.GetSplitDepth(ctx) + if err != nil { + return nil, err + } + contract.nbits = nbits + contract.splitDepth = splitDepth + return contract, nil } } @@ -349,6 +363,9 @@ func (f *FaultDisputeGameContractLatest) UpdateOracleTx(ctx context.Context, cla } func (f *FaultDisputeGameContractLatest) addLocalDataTx(claimIdx uint64, data *types.PreimageOracleData) (txmgr.TxCandidate, error) { + if data.OutputRootDAItem.DaType == nil { + return txmgr.TxCandidate{}, fmt.Errorf("DaType isn't set") + } call := f.contract.Call( methodAddLocalData, data.GetIdent(), @@ -479,6 +496,11 @@ func (f *FaultDisputeGameContractLatest) GetAllClaimsWithSubValues(ctx context.C return nil, err } for idx, claim := range claims { + if claim.IsRoot() { // root claim contains no subValues in DA, we create subvalues manually + claim.SubValues = &[]common.Hash{claim.Value} + claims[idx] = claim + continue + } subValues, attackBranch, err := f.getSubValuesAndAttackBranch(ctx, &claim) if err != nil { return nil, fmt.Errorf("failed to load subValues: %w", err) @@ -510,7 +532,6 @@ func (f *FaultDisputeGameContractLatest) getSubValuesAndAttackBranch(ctx context return nil, 0, fmt.Errorf("failed to get move event log: %w", moveIter.Error()) } txHash := moveIter.Event.Raw.TxHash - getTxByHashCall := batching.NewTxGetByHash(f.contract.Abi(), txHash, methodAttackV2) result, err := f.multiCaller.SingleCall(ctx, rpcblock.Latest, getTxByHashCall) if err != nil { @@ -535,9 +556,13 @@ func (f *FaultDisputeGameContractLatest) getSubValuesAndAttackBranch(ctx context if err != nil { return nil, 0, err } - valuesBytesLen := uint(32 * maxAttackBranch) + nelements := maxAttackBranch + if aggClaim.Position.Depth() == types.Depth(f.nbits)+f.splitDepth { + nelements = 1 + } + valuesBytesLen := uint(32 * nelements) bytes := abi.ConvertType(inputMap[fieldSubValues], make([]byte, valuesBytesLen)).([]byte) - for i := uint64(0); i < maxAttackBranch; i++ { + for i := uint64(0); i < nelements; i++ { hash := common.BytesToHash(bytes[i*32 : (i+1)*32]) subValues = append(subValues, hash) } @@ -715,17 +740,13 @@ func (f *FaultDisputeGameContractLatest) GetMaxAttackBranch(ctx context.Context) } func (f *FaultDisputeGameContractLatest) AttackV2Tx(ctx context.Context, parent types.Claim, attackBranch uint64, daType uint64, claims []byte) (txmgr.TxCandidate, error) { - nBits, err := f.GetNBits(ctx) - if err != nil { - return txmgr.TxCandidate{}, fmt.Errorf("failed to retrieve nbits: %w", err) - } call := f.contract.Call(methodAttackV2, parent.Value, big.NewInt(int64(parent.ContractIndex)), new(big.Int).SetUint64(attackBranch), new(big.Int).SetUint64(daType), claims) - return f.txWithBond(ctx, parent.Position.MoveN(nBits, attackBranch), call) + return f.txWithBond(ctx, parent.Position.MoveN(f.nbits, attackBranch), call) } func (f *FaultDisputeGameContractLatest) StepV2Tx(claimIdx uint64, attackBranch uint64, stateData []byte, proof types.StepProof) (txmgr.TxCandidate, error) { diff --git a/op-challenger2/game/fault/solver/solver.go b/op-challenger2/game/fault/solver/solver.go index e702cf25cae6..fcd0843dedf0 100644 --- a/op-challenger2/game/fault/solver/solver.go +++ b/op-challenger2/game/fault/solver/solver.go @@ -143,6 +143,9 @@ func (s *claimSolver) AttemptStep(ctx context.Context, game types.Game, claim ty if err != nil { return nil, err } + oracleData.OutputRootDAItem.DaType = s.daType + oracleData.VMStateDA.PreDA.DaType = s.daType + oracleData.VMStateDA.PostDA.DaType = s.daType return &StepData{ LeafClaim: claim, AttackBranch: attackBranch, @@ -170,14 +173,14 @@ func (s *claimSolver) attackV2(ctx context.Context, game types.Game, claim types for i := uint64(0); i < maxAttackBranch; i++ { tmpPosition := position.MoveRightN(i) if tmpPosition.Depth() == (game.SplitDepth()+types.Depth(game.NBits())) && i != 0 { - value = common.Hash{} + break } else { value, err = s.trace.Get(ctx, game, claim, tmpPosition) if err != nil { return nil, fmt.Errorf("attack claim: %w", err) } + values = append(values, value) } - values = append(values, value) } hash := contracts.SubValuesHash(values) return &types.Claim{ diff --git a/op-e2e2/bindings/faultdiputegameN.go b/op-e2e2/bindings/faultdiputegameN.go new file mode 100644 index 000000000000..e2070a99f5e2 --- /dev/null +++ b/op-e2e2/bindings/faultdiputegameN.go @@ -0,0 +1,2079 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindings + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// FaultDisputeGameStepProof is an auto generated low-level Go binding around an user-defined struct. +type FaultDisputeGameStepProof struct { + PreStateItem LibDADAItem + PostStateItem LibDADAItem + VmProof []byte +} + +// LibDADAItem is an auto generated low-level Go binding around an user-defined struct. +type LibDADAItem struct { + DaType *big.Int + DataHash [32]byte + Proof []byte +} + +// FaultDisputeGameNMetaData contains all meta data concerning the FaultDisputeGameN contract. +var FaultDisputeGameNMetaData = &bind.MetaData{ + ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_gameType\",\"type\":\"uint32\",\"internalType\":\"GameType\"},{\"name\":\"_absolutePrestate\",\"type\":\"bytes32\",\"internalType\":\"Claim\"},{\"name\":\"_maxGameDepth\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_splitDepth\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_clockExtension\",\"type\":\"uint64\",\"internalType\":\"Duration\"},{\"name\":\"_maxClockDuration\",\"type\":\"uint64\",\"internalType\":\"Duration\"},{\"name\":\"_vm\",\"type\":\"address\",\"internalType\":\"contractIBigStepper\"},{\"name\":\"_weth\",\"type\":\"address\",\"internalType\":\"contractIDelayedWETH\"},{\"name\":\"_anchorStateRegistry\",\"type\":\"address\",\"internalType\":\"contractIAnchorStateRegistry\"},{\"name\":\"_l2ChainId\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"MAX_ATTACK_BRANCH\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"N_BITS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"absolutePrestate\",\"inputs\":[],\"outputs\":[{\"name\":\"absolutePrestate_\",\"type\":\"bytes32\",\"internalType\":\"Claim\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"addLocalData\",\"inputs\":[{\"name\":\"_ident\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_execLeafIdx\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_partOffset\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"addLocalData2\",\"inputs\":[{\"name\":\"_ident\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_execLeafIdx\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_partOffset\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_daItem\",\"type\":\"tuple\",\"internalType\":\"structLibDA.DAItem\",\"components\":[{\"name\":\"daType\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"dataHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"outputs\":[{\"name\":\"uuid_\",\"type\":\"bytes32\",\"internalType\":\"Hash\"},{\"name\":\"value_\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"anchorStateRegistry\",\"inputs\":[],\"outputs\":[{\"name\":\"registry_\",\"type\":\"address\",\"internalType\":\"contractIAnchorStateRegistry\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"attack\",\"inputs\":[{\"name\":\"_disputed\",\"type\":\"bytes32\",\"internalType\":\"Claim\"},{\"name\":\"_parentIndex\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_claim\",\"type\":\"bytes32\",\"internalType\":\"Claim\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"attackV2\",\"inputs\":[{\"name\":\"_disputed\",\"type\":\"bytes32\",\"internalType\":\"Claim\"},{\"name\":\"_parentIndex\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_attackBranch\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_daType\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_claims\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"challengeRootL2Block\",\"inputs\":[{\"name\":\"_outputRootProof\",\"type\":\"tuple\",\"internalType\":\"structTypes.OutputRootProof\",\"components\":[{\"name\":\"version\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"stateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"messagePasserStorageRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"latestBlockhash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"_headerRLP\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"claimCredit\",\"inputs\":[{\"name\":\"_recipient\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"claimData\",\"inputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"parentIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"counteredBy\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"claimant\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"bond\",\"type\":\"uint128\",\"internalType\":\"uint128\"},{\"name\":\"claim\",\"type\":\"bytes32\",\"internalType\":\"Claim\"},{\"name\":\"position\",\"type\":\"uint128\",\"internalType\":\"Position\"},{\"name\":\"clock\",\"type\":\"uint128\",\"internalType\":\"Clock\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"claimDataLen\",\"inputs\":[],\"outputs\":[{\"name\":\"len_\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"claims\",\"inputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"Hash\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"clockExtension\",\"inputs\":[],\"outputs\":[{\"name\":\"clockExtension_\",\"type\":\"uint64\",\"internalType\":\"Duration\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"createdAt\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"Timestamp\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"credit\",\"inputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"defend\",\"inputs\":[{\"name\":\"_disputed\",\"type\":\"bytes32\",\"internalType\":\"Claim\"},{\"name\":\"_parentIndex\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_claim\",\"type\":\"bytes32\",\"internalType\":\"Claim\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"extraData\",\"inputs\":[],\"outputs\":[{\"name\":\"extraData_\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"gameCreator\",\"inputs\":[],\"outputs\":[{\"name\":\"creator_\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"gameData\",\"inputs\":[],\"outputs\":[{\"name\":\"gameType_\",\"type\":\"uint32\",\"internalType\":\"GameType\"},{\"name\":\"rootClaim_\",\"type\":\"bytes32\",\"internalType\":\"Claim\"},{\"name\":\"extraData_\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"gameType\",\"inputs\":[],\"outputs\":[{\"name\":\"gameType_\",\"type\":\"uint32\",\"internalType\":\"GameType\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getChallengerDuration\",\"inputs\":[{\"name\":\"_claimIndex\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"duration_\",\"type\":\"uint64\",\"internalType\":\"Duration\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getNumToResolve\",\"inputs\":[{\"name\":\"_claimIndex\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"numRemainingChildren_\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getRequiredBond\",\"inputs\":[{\"name\":\"_position\",\"type\":\"uint128\",\"internalType\":\"Position\"}],\"outputs\":[{\"name\":\"requiredBond_\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"l1Head\",\"inputs\":[],\"outputs\":[{\"name\":\"l1Head_\",\"type\":\"bytes32\",\"internalType\":\"Hash\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"l2BlockNumber\",\"inputs\":[],\"outputs\":[{\"name\":\"l2BlockNumber_\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"l2BlockNumberChallenged\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"l2BlockNumberChallenger\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"l2ChainId\",\"inputs\":[],\"outputs\":[{\"name\":\"l2ChainId_\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"maxAttackBranch\",\"inputs\":[],\"outputs\":[{\"name\":\"maxAttackBranch_\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"maxClockDuration\",\"inputs\":[],\"outputs\":[{\"name\":\"maxClockDuration_\",\"type\":\"uint64\",\"internalType\":\"Duration\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"maxGameDepth\",\"inputs\":[],\"outputs\":[{\"name\":\"maxGameDepth_\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"move\",\"inputs\":[{\"name\":\"_disputed\",\"type\":\"bytes32\",\"internalType\":\"Claim\"},{\"name\":\"_challengeIndex\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_claim\",\"type\":\"bytes32\",\"internalType\":\"Claim\"},{\"name\":\"_isAttack\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"nBits\",\"inputs\":[],\"outputs\":[{\"name\":\"nBits_\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"resolutionCheckpoints\",\"inputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"initialCheckpointComplete\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"subgameIndex\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"leftmostPosition\",\"type\":\"uint128\",\"internalType\":\"Position\"},{\"name\":\"counteredBy\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"resolve\",\"inputs\":[],\"outputs\":[{\"name\":\"status_\",\"type\":\"uint8\",\"internalType\":\"enumGameStatus\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"resolveClaim\",\"inputs\":[{\"name\":\"_claimIndex\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_numToResolve\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"resolvedAt\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"Timestamp\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"resolvedSubgames\",\"inputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"rootClaim\",\"inputs\":[],\"outputs\":[{\"name\":\"rootClaim_\",\"type\":\"bytes32\",\"internalType\":\"Claim\"}],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"splitDepth\",\"inputs\":[],\"outputs\":[{\"name\":\"splitDepth_\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"startingBlockNumber\",\"inputs\":[],\"outputs\":[{\"name\":\"startingBlockNumber_\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"startingOutputRoot\",\"inputs\":[],\"outputs\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"Hash\"},{\"name\":\"l2BlockNumber\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"startingRootHash\",\"inputs\":[],\"outputs\":[{\"name\":\"startingRootHash_\",\"type\":\"bytes32\",\"internalType\":\"Hash\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"status\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumGameStatus\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"step\",\"inputs\":[{\"name\":\"_claimIndex\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_isAttack\",\"type\":\"bool\",\"internalType\":\"bool\"},{\"name\":\"_stateData\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"_proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"stepV2\",\"inputs\":[{\"name\":\"_claimIndex\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_attackBranch\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"_stateData\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"_proof\",\"type\":\"tuple\",\"internalType\":\"structFaultDisputeGame.StepProof\",\"components\":[{\"name\":\"preStateItem\",\"type\":\"tuple\",\"internalType\":\"structLibDA.DAItem\",\"components\":[{\"name\":\"daType\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"dataHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"postStateItem\",\"type\":\"tuple\",\"internalType\":\"structLibDA.DAItem\",\"components\":[{\"name\":\"daType\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"dataHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"vmProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"subgames\",\"inputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"version\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"string\",\"internalType\":\"string\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"vm\",\"inputs\":[],\"outputs\":[{\"name\":\"vm_\",\"type\":\"address\",\"internalType\":\"contractIBigStepper\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"weth\",\"inputs\":[],\"outputs\":[{\"name\":\"weth_\",\"type\":\"address\",\"internalType\":\"contractIDelayedWETH\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"Move\",\"inputs\":[{\"name\":\"parentIndex\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"claim\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"Claim\"},{\"name\":\"claimant\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Resolved\",\"inputs\":[{\"name\":\"status\",\"type\":\"uint8\",\"indexed\":true,\"internalType\":\"enumGameStatus\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"AlreadyInitialized\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"AnchorRootNotFound\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"BlockNumberMatches\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"BondTransferFailed\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"CannotDefendRootClaim\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ClaimAboveSplit\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ClaimAlreadyExists\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ClaimAlreadyResolved\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ClockNotExpired\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ClockTimeExceeded\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ContentLengthMismatch\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"DuplicateStep\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"EmptyItem\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"GameDepthExceeded\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"GameNotInProgress\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"IncorrectBondAmount\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidClockExtension\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidDataRemainder\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidDisputedClaimIndex\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidHeader\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidHeaderRLP\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidLocalIdent\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidOutputRootProof\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidParent\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidPosition\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidPrestate\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidSplitDepth\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"L2BlockNumberChallenged\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"MaxDepthTooLarge\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NoCreditToClaim\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotSupported\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OutOfOrderResolution\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UnexpectedList\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"UnexpectedRootClaim\",\"inputs\":[{\"name\":\"rootClaim\",\"type\":\"bytes32\",\"internalType\":\"Claim\"}]},{\"type\":\"error\",\"name\":\"UnexpectedString\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ValidStep\",\"inputs\":[]}]", +} + +// FaultDisputeGameNABI is the input ABI used to generate the binding from. +// Deprecated: Use FaultDisputeGameNMetaData.ABI instead. +var FaultDisputeGameNABI = FaultDisputeGameNMetaData.ABI + +// FaultDisputeGameN is an auto generated Go binding around an Ethereum contract. +type FaultDisputeGameN struct { + FaultDisputeGameNCaller // Read-only binding to the contract + FaultDisputeGameNTransactor // Write-only binding to the contract + FaultDisputeGameNFilterer // Log filterer for contract events +} + +// FaultDisputeGameNCaller is an auto generated read-only Go binding around an Ethereum contract. +type FaultDisputeGameNCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// FaultDisputeGameNTransactor is an auto generated write-only Go binding around an Ethereum contract. +type FaultDisputeGameNTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// FaultDisputeGameNFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type FaultDisputeGameNFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// FaultDisputeGameNSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type FaultDisputeGameNSession struct { + Contract *FaultDisputeGameN // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// FaultDisputeGameNCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type FaultDisputeGameNCallerSession struct { + Contract *FaultDisputeGameNCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// FaultDisputeGameNTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type FaultDisputeGameNTransactorSession struct { + Contract *FaultDisputeGameNTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// FaultDisputeGameNRaw is an auto generated low-level Go binding around an Ethereum contract. +type FaultDisputeGameNRaw struct { + Contract *FaultDisputeGameN // Generic contract binding to access the raw methods on +} + +// FaultDisputeGameNCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type FaultDisputeGameNCallerRaw struct { + Contract *FaultDisputeGameNCaller // Generic read-only contract binding to access the raw methods on +} + +// FaultDisputeGameNTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type FaultDisputeGameNTransactorRaw struct { + Contract *FaultDisputeGameNTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewFaultDisputeGameN creates a new instance of FaultDisputeGameN, bound to a specific deployed contract. +func NewFaultDisputeGameN(address common.Address, backend bind.ContractBackend) (*FaultDisputeGameN, error) { + contract, err := bindFaultDisputeGameN(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &FaultDisputeGameN{FaultDisputeGameNCaller: FaultDisputeGameNCaller{contract: contract}, FaultDisputeGameNTransactor: FaultDisputeGameNTransactor{contract: contract}, FaultDisputeGameNFilterer: FaultDisputeGameNFilterer{contract: contract}}, nil +} + +// NewFaultDisputeGameNCaller creates a new read-only instance of FaultDisputeGameN, bound to a specific deployed contract. +func NewFaultDisputeGameNCaller(address common.Address, caller bind.ContractCaller) (*FaultDisputeGameNCaller, error) { + contract, err := bindFaultDisputeGameN(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &FaultDisputeGameNCaller{contract: contract}, nil +} + +// NewFaultDisputeGameNTransactor creates a new write-only instance of FaultDisputeGameN, bound to a specific deployed contract. +func NewFaultDisputeGameNTransactor(address common.Address, transactor bind.ContractTransactor) (*FaultDisputeGameNTransactor, error) { + contract, err := bindFaultDisputeGameN(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &FaultDisputeGameNTransactor{contract: contract}, nil +} + +// NewFaultDisputeGameNFilterer creates a new log filterer instance of FaultDisputeGameN, bound to a specific deployed contract. +func NewFaultDisputeGameNFilterer(address common.Address, filterer bind.ContractFilterer) (*FaultDisputeGameNFilterer, error) { + contract, err := bindFaultDisputeGameN(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &FaultDisputeGameNFilterer{contract: contract}, nil +} + +// bindFaultDisputeGameN binds a generic wrapper to an already deployed contract. +func bindFaultDisputeGameN(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := FaultDisputeGameNMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_FaultDisputeGameN *FaultDisputeGameNRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _FaultDisputeGameN.Contract.FaultDisputeGameNCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_FaultDisputeGameN *FaultDisputeGameNRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.FaultDisputeGameNTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_FaultDisputeGameN *FaultDisputeGameNRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.FaultDisputeGameNTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_FaultDisputeGameN *FaultDisputeGameNCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _FaultDisputeGameN.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_FaultDisputeGameN *FaultDisputeGameNTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_FaultDisputeGameN *FaultDisputeGameNTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.contract.Transact(opts, method, params...) +} + +// MAXATTACKBRANCH is a free data retrieval call binding the contract method 0xb76e5932. +// +// Solidity: function MAX_ATTACK_BRANCH() view returns(uint256) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) MAXATTACKBRANCH(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "MAX_ATTACK_BRANCH") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// MAXATTACKBRANCH is a free data retrieval call binding the contract method 0xb76e5932. +// +// Solidity: function MAX_ATTACK_BRANCH() view returns(uint256) +func (_FaultDisputeGameN *FaultDisputeGameNSession) MAXATTACKBRANCH() (*big.Int, error) { + return _FaultDisputeGameN.Contract.MAXATTACKBRANCH(&_FaultDisputeGameN.CallOpts) +} + +// MAXATTACKBRANCH is a free data retrieval call binding the contract method 0xb76e5932. +// +// Solidity: function MAX_ATTACK_BRANCH() view returns(uint256) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) MAXATTACKBRANCH() (*big.Int, error) { + return _FaultDisputeGameN.Contract.MAXATTACKBRANCH(&_FaultDisputeGameN.CallOpts) +} + +// NBITS is a free data retrieval call binding the contract method 0x2a1512ac. +// +// Solidity: function N_BITS() view returns(uint256) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) NBITS(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "N_BITS") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// NBITS is a free data retrieval call binding the contract method 0x2a1512ac. +// +// Solidity: function N_BITS() view returns(uint256) +func (_FaultDisputeGameN *FaultDisputeGameNSession) NBITS() (*big.Int, error) { + return _FaultDisputeGameN.Contract.NBITS(&_FaultDisputeGameN.CallOpts) +} + +// NBITS is a free data retrieval call binding the contract method 0x2a1512ac. +// +// Solidity: function N_BITS() view returns(uint256) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) NBITS() (*big.Int, error) { + return _FaultDisputeGameN.Contract.NBITS(&_FaultDisputeGameN.CallOpts) +} + +// AbsolutePrestate is a free data retrieval call binding the contract method 0x8d450a95. +// +// Solidity: function absolutePrestate() view returns(bytes32 absolutePrestate_) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) AbsolutePrestate(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "absolutePrestate") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// AbsolutePrestate is a free data retrieval call binding the contract method 0x8d450a95. +// +// Solidity: function absolutePrestate() view returns(bytes32 absolutePrestate_) +func (_FaultDisputeGameN *FaultDisputeGameNSession) AbsolutePrestate() ([32]byte, error) { + return _FaultDisputeGameN.Contract.AbsolutePrestate(&_FaultDisputeGameN.CallOpts) +} + +// AbsolutePrestate is a free data retrieval call binding the contract method 0x8d450a95. +// +// Solidity: function absolutePrestate() view returns(bytes32 absolutePrestate_) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) AbsolutePrestate() ([32]byte, error) { + return _FaultDisputeGameN.Contract.AbsolutePrestate(&_FaultDisputeGameN.CallOpts) +} + +// AnchorStateRegistry is a free data retrieval call binding the contract method 0x5c0cba33. +// +// Solidity: function anchorStateRegistry() view returns(address registry_) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) AnchorStateRegistry(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "anchorStateRegistry") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// AnchorStateRegistry is a free data retrieval call binding the contract method 0x5c0cba33. +// +// Solidity: function anchorStateRegistry() view returns(address registry_) +func (_FaultDisputeGameN *FaultDisputeGameNSession) AnchorStateRegistry() (common.Address, error) { + return _FaultDisputeGameN.Contract.AnchorStateRegistry(&_FaultDisputeGameN.CallOpts) +} + +// AnchorStateRegistry is a free data retrieval call binding the contract method 0x5c0cba33. +// +// Solidity: function anchorStateRegistry() view returns(address registry_) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) AnchorStateRegistry() (common.Address, error) { + return _FaultDisputeGameN.Contract.AnchorStateRegistry(&_FaultDisputeGameN.CallOpts) +} + +// ClaimData is a free data retrieval call binding the contract method 0xc6f0308c. +// +// Solidity: function claimData(uint256 ) view returns(uint32 parentIndex, address counteredBy, address claimant, uint128 bond, bytes32 claim, uint128 position, uint128 clock) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) ClaimData(opts *bind.CallOpts, arg0 *big.Int) (struct { + ParentIndex uint32 + CounteredBy common.Address + Claimant common.Address + Bond *big.Int + Claim [32]byte + Position *big.Int + Clock *big.Int +}, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "claimData", arg0) + + outstruct := new(struct { + ParentIndex uint32 + CounteredBy common.Address + Claimant common.Address + Bond *big.Int + Claim [32]byte + Position *big.Int + Clock *big.Int + }) + if err != nil { + return *outstruct, err + } + + outstruct.ParentIndex = *abi.ConvertType(out[0], new(uint32)).(*uint32) + outstruct.CounteredBy = *abi.ConvertType(out[1], new(common.Address)).(*common.Address) + outstruct.Claimant = *abi.ConvertType(out[2], new(common.Address)).(*common.Address) + outstruct.Bond = *abi.ConvertType(out[3], new(*big.Int)).(**big.Int) + outstruct.Claim = *abi.ConvertType(out[4], new([32]byte)).(*[32]byte) + outstruct.Position = *abi.ConvertType(out[5], new(*big.Int)).(**big.Int) + outstruct.Clock = *abi.ConvertType(out[6], new(*big.Int)).(**big.Int) + + return *outstruct, err + +} + +// ClaimData is a free data retrieval call binding the contract method 0xc6f0308c. +// +// Solidity: function claimData(uint256 ) view returns(uint32 parentIndex, address counteredBy, address claimant, uint128 bond, bytes32 claim, uint128 position, uint128 clock) +func (_FaultDisputeGameN *FaultDisputeGameNSession) ClaimData(arg0 *big.Int) (struct { + ParentIndex uint32 + CounteredBy common.Address + Claimant common.Address + Bond *big.Int + Claim [32]byte + Position *big.Int + Clock *big.Int +}, error) { + return _FaultDisputeGameN.Contract.ClaimData(&_FaultDisputeGameN.CallOpts, arg0) +} + +// ClaimData is a free data retrieval call binding the contract method 0xc6f0308c. +// +// Solidity: function claimData(uint256 ) view returns(uint32 parentIndex, address counteredBy, address claimant, uint128 bond, bytes32 claim, uint128 position, uint128 clock) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) ClaimData(arg0 *big.Int) (struct { + ParentIndex uint32 + CounteredBy common.Address + Claimant common.Address + Bond *big.Int + Claim [32]byte + Position *big.Int + Clock *big.Int +}, error) { + return _FaultDisputeGameN.Contract.ClaimData(&_FaultDisputeGameN.CallOpts, arg0) +} + +// ClaimDataLen is a free data retrieval call binding the contract method 0x8980e0cc. +// +// Solidity: function claimDataLen() view returns(uint256 len_) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) ClaimDataLen(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "claimDataLen") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// ClaimDataLen is a free data retrieval call binding the contract method 0x8980e0cc. +// +// Solidity: function claimDataLen() view returns(uint256 len_) +func (_FaultDisputeGameN *FaultDisputeGameNSession) ClaimDataLen() (*big.Int, error) { + return _FaultDisputeGameN.Contract.ClaimDataLen(&_FaultDisputeGameN.CallOpts) +} + +// ClaimDataLen is a free data retrieval call binding the contract method 0x8980e0cc. +// +// Solidity: function claimDataLen() view returns(uint256 len_) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) ClaimDataLen() (*big.Int, error) { + return _FaultDisputeGameN.Contract.ClaimDataLen(&_FaultDisputeGameN.CallOpts) +} + +// Claims is a free data retrieval call binding the contract method 0xeff0f592. +// +// Solidity: function claims(bytes32 ) view returns(bool) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) Claims(opts *bind.CallOpts, arg0 [32]byte) (bool, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "claims", arg0) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// Claims is a free data retrieval call binding the contract method 0xeff0f592. +// +// Solidity: function claims(bytes32 ) view returns(bool) +func (_FaultDisputeGameN *FaultDisputeGameNSession) Claims(arg0 [32]byte) (bool, error) { + return _FaultDisputeGameN.Contract.Claims(&_FaultDisputeGameN.CallOpts, arg0) +} + +// Claims is a free data retrieval call binding the contract method 0xeff0f592. +// +// Solidity: function claims(bytes32 ) view returns(bool) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) Claims(arg0 [32]byte) (bool, error) { + return _FaultDisputeGameN.Contract.Claims(&_FaultDisputeGameN.CallOpts, arg0) +} + +// ClockExtension is a free data retrieval call binding the contract method 0x6b6716c0. +// +// Solidity: function clockExtension() view returns(uint64 clockExtension_) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) ClockExtension(opts *bind.CallOpts) (uint64, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "clockExtension") + + if err != nil { + return *new(uint64), err + } + + out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) + + return out0, err + +} + +// ClockExtension is a free data retrieval call binding the contract method 0x6b6716c0. +// +// Solidity: function clockExtension() view returns(uint64 clockExtension_) +func (_FaultDisputeGameN *FaultDisputeGameNSession) ClockExtension() (uint64, error) { + return _FaultDisputeGameN.Contract.ClockExtension(&_FaultDisputeGameN.CallOpts) +} + +// ClockExtension is a free data retrieval call binding the contract method 0x6b6716c0. +// +// Solidity: function clockExtension() view returns(uint64 clockExtension_) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) ClockExtension() (uint64, error) { + return _FaultDisputeGameN.Contract.ClockExtension(&_FaultDisputeGameN.CallOpts) +} + +// CreatedAt is a free data retrieval call binding the contract method 0xcf09e0d0. +// +// Solidity: function createdAt() view returns(uint64) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) CreatedAt(opts *bind.CallOpts) (uint64, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "createdAt") + + if err != nil { + return *new(uint64), err + } + + out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) + + return out0, err + +} + +// CreatedAt is a free data retrieval call binding the contract method 0xcf09e0d0. +// +// Solidity: function createdAt() view returns(uint64) +func (_FaultDisputeGameN *FaultDisputeGameNSession) CreatedAt() (uint64, error) { + return _FaultDisputeGameN.Contract.CreatedAt(&_FaultDisputeGameN.CallOpts) +} + +// CreatedAt is a free data retrieval call binding the contract method 0xcf09e0d0. +// +// Solidity: function createdAt() view returns(uint64) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) CreatedAt() (uint64, error) { + return _FaultDisputeGameN.Contract.CreatedAt(&_FaultDisputeGameN.CallOpts) +} + +// Credit is a free data retrieval call binding the contract method 0xd5d44d80. +// +// Solidity: function credit(address ) view returns(uint256) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) Credit(opts *bind.CallOpts, arg0 common.Address) (*big.Int, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "credit", arg0) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Credit is a free data retrieval call binding the contract method 0xd5d44d80. +// +// Solidity: function credit(address ) view returns(uint256) +func (_FaultDisputeGameN *FaultDisputeGameNSession) Credit(arg0 common.Address) (*big.Int, error) { + return _FaultDisputeGameN.Contract.Credit(&_FaultDisputeGameN.CallOpts, arg0) +} + +// Credit is a free data retrieval call binding the contract method 0xd5d44d80. +// +// Solidity: function credit(address ) view returns(uint256) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) Credit(arg0 common.Address) (*big.Int, error) { + return _FaultDisputeGameN.Contract.Credit(&_FaultDisputeGameN.CallOpts, arg0) +} + +// ExtraData is a free data retrieval call binding the contract method 0x609d3334. +// +// Solidity: function extraData() pure returns(bytes extraData_) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) ExtraData(opts *bind.CallOpts) ([]byte, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "extraData") + + if err != nil { + return *new([]byte), err + } + + out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + + return out0, err + +} + +// ExtraData is a free data retrieval call binding the contract method 0x609d3334. +// +// Solidity: function extraData() pure returns(bytes extraData_) +func (_FaultDisputeGameN *FaultDisputeGameNSession) ExtraData() ([]byte, error) { + return _FaultDisputeGameN.Contract.ExtraData(&_FaultDisputeGameN.CallOpts) +} + +// ExtraData is a free data retrieval call binding the contract method 0x609d3334. +// +// Solidity: function extraData() pure returns(bytes extraData_) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) ExtraData() ([]byte, error) { + return _FaultDisputeGameN.Contract.ExtraData(&_FaultDisputeGameN.CallOpts) +} + +// GameCreator is a free data retrieval call binding the contract method 0x37b1b229. +// +// Solidity: function gameCreator() pure returns(address creator_) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) GameCreator(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "gameCreator") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// GameCreator is a free data retrieval call binding the contract method 0x37b1b229. +// +// Solidity: function gameCreator() pure returns(address creator_) +func (_FaultDisputeGameN *FaultDisputeGameNSession) GameCreator() (common.Address, error) { + return _FaultDisputeGameN.Contract.GameCreator(&_FaultDisputeGameN.CallOpts) +} + +// GameCreator is a free data retrieval call binding the contract method 0x37b1b229. +// +// Solidity: function gameCreator() pure returns(address creator_) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) GameCreator() (common.Address, error) { + return _FaultDisputeGameN.Contract.GameCreator(&_FaultDisputeGameN.CallOpts) +} + +// GameData is a free data retrieval call binding the contract method 0xfa24f743. +// +// Solidity: function gameData() view returns(uint32 gameType_, bytes32 rootClaim_, bytes extraData_) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) GameData(opts *bind.CallOpts) (struct { + GameType uint32 + RootClaim [32]byte + ExtraData []byte +}, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "gameData") + + outstruct := new(struct { + GameType uint32 + RootClaim [32]byte + ExtraData []byte + }) + if err != nil { + return *outstruct, err + } + + outstruct.GameType = *abi.ConvertType(out[0], new(uint32)).(*uint32) + outstruct.RootClaim = *abi.ConvertType(out[1], new([32]byte)).(*[32]byte) + outstruct.ExtraData = *abi.ConvertType(out[2], new([]byte)).(*[]byte) + + return *outstruct, err + +} + +// GameData is a free data retrieval call binding the contract method 0xfa24f743. +// +// Solidity: function gameData() view returns(uint32 gameType_, bytes32 rootClaim_, bytes extraData_) +func (_FaultDisputeGameN *FaultDisputeGameNSession) GameData() (struct { + GameType uint32 + RootClaim [32]byte + ExtraData []byte +}, error) { + return _FaultDisputeGameN.Contract.GameData(&_FaultDisputeGameN.CallOpts) +} + +// GameData is a free data retrieval call binding the contract method 0xfa24f743. +// +// Solidity: function gameData() view returns(uint32 gameType_, bytes32 rootClaim_, bytes extraData_) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) GameData() (struct { + GameType uint32 + RootClaim [32]byte + ExtraData []byte +}, error) { + return _FaultDisputeGameN.Contract.GameData(&_FaultDisputeGameN.CallOpts) +} + +// GameType is a free data retrieval call binding the contract method 0xbbdc02db. +// +// Solidity: function gameType() view returns(uint32 gameType_) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) GameType(opts *bind.CallOpts) (uint32, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "gameType") + + if err != nil { + return *new(uint32), err + } + + out0 := *abi.ConvertType(out[0], new(uint32)).(*uint32) + + return out0, err + +} + +// GameType is a free data retrieval call binding the contract method 0xbbdc02db. +// +// Solidity: function gameType() view returns(uint32 gameType_) +func (_FaultDisputeGameN *FaultDisputeGameNSession) GameType() (uint32, error) { + return _FaultDisputeGameN.Contract.GameType(&_FaultDisputeGameN.CallOpts) +} + +// GameType is a free data retrieval call binding the contract method 0xbbdc02db. +// +// Solidity: function gameType() view returns(uint32 gameType_) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) GameType() (uint32, error) { + return _FaultDisputeGameN.Contract.GameType(&_FaultDisputeGameN.CallOpts) +} + +// GetChallengerDuration is a free data retrieval call binding the contract method 0xbd8da956. +// +// Solidity: function getChallengerDuration(uint256 _claimIndex) view returns(uint64 duration_) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) GetChallengerDuration(opts *bind.CallOpts, _claimIndex *big.Int) (uint64, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "getChallengerDuration", _claimIndex) + + if err != nil { + return *new(uint64), err + } + + out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) + + return out0, err + +} + +// GetChallengerDuration is a free data retrieval call binding the contract method 0xbd8da956. +// +// Solidity: function getChallengerDuration(uint256 _claimIndex) view returns(uint64 duration_) +func (_FaultDisputeGameN *FaultDisputeGameNSession) GetChallengerDuration(_claimIndex *big.Int) (uint64, error) { + return _FaultDisputeGameN.Contract.GetChallengerDuration(&_FaultDisputeGameN.CallOpts, _claimIndex) +} + +// GetChallengerDuration is a free data retrieval call binding the contract method 0xbd8da956. +// +// Solidity: function getChallengerDuration(uint256 _claimIndex) view returns(uint64 duration_) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) GetChallengerDuration(_claimIndex *big.Int) (uint64, error) { + return _FaultDisputeGameN.Contract.GetChallengerDuration(&_FaultDisputeGameN.CallOpts, _claimIndex) +} + +// GetNumToResolve is a free data retrieval call binding the contract method 0x5a5fa2d9. +// +// Solidity: function getNumToResolve(uint256 _claimIndex) view returns(uint256 numRemainingChildren_) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) GetNumToResolve(opts *bind.CallOpts, _claimIndex *big.Int) (*big.Int, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "getNumToResolve", _claimIndex) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetNumToResolve is a free data retrieval call binding the contract method 0x5a5fa2d9. +// +// Solidity: function getNumToResolve(uint256 _claimIndex) view returns(uint256 numRemainingChildren_) +func (_FaultDisputeGameN *FaultDisputeGameNSession) GetNumToResolve(_claimIndex *big.Int) (*big.Int, error) { + return _FaultDisputeGameN.Contract.GetNumToResolve(&_FaultDisputeGameN.CallOpts, _claimIndex) +} + +// GetNumToResolve is a free data retrieval call binding the contract method 0x5a5fa2d9. +// +// Solidity: function getNumToResolve(uint256 _claimIndex) view returns(uint256 numRemainingChildren_) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) GetNumToResolve(_claimIndex *big.Int) (*big.Int, error) { + return _FaultDisputeGameN.Contract.GetNumToResolve(&_FaultDisputeGameN.CallOpts, _claimIndex) +} + +// GetRequiredBond is a free data retrieval call binding the contract method 0xc395e1ca. +// +// Solidity: function getRequiredBond(uint128 _position) view returns(uint256 requiredBond_) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) GetRequiredBond(opts *bind.CallOpts, _position *big.Int) (*big.Int, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "getRequiredBond", _position) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// GetRequiredBond is a free data retrieval call binding the contract method 0xc395e1ca. +// +// Solidity: function getRequiredBond(uint128 _position) view returns(uint256 requiredBond_) +func (_FaultDisputeGameN *FaultDisputeGameNSession) GetRequiredBond(_position *big.Int) (*big.Int, error) { + return _FaultDisputeGameN.Contract.GetRequiredBond(&_FaultDisputeGameN.CallOpts, _position) +} + +// GetRequiredBond is a free data retrieval call binding the contract method 0xc395e1ca. +// +// Solidity: function getRequiredBond(uint128 _position) view returns(uint256 requiredBond_) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) GetRequiredBond(_position *big.Int) (*big.Int, error) { + return _FaultDisputeGameN.Contract.GetRequiredBond(&_FaultDisputeGameN.CallOpts, _position) +} + +// L1Head is a free data retrieval call binding the contract method 0x6361506d. +// +// Solidity: function l1Head() pure returns(bytes32 l1Head_) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) L1Head(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "l1Head") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// L1Head is a free data retrieval call binding the contract method 0x6361506d. +// +// Solidity: function l1Head() pure returns(bytes32 l1Head_) +func (_FaultDisputeGameN *FaultDisputeGameNSession) L1Head() ([32]byte, error) { + return _FaultDisputeGameN.Contract.L1Head(&_FaultDisputeGameN.CallOpts) +} + +// L1Head is a free data retrieval call binding the contract method 0x6361506d. +// +// Solidity: function l1Head() pure returns(bytes32 l1Head_) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) L1Head() ([32]byte, error) { + return _FaultDisputeGameN.Contract.L1Head(&_FaultDisputeGameN.CallOpts) +} + +// L2BlockNumber is a free data retrieval call binding the contract method 0x8b85902b. +// +// Solidity: function l2BlockNumber() pure returns(uint256 l2BlockNumber_) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) L2BlockNumber(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "l2BlockNumber") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// L2BlockNumber is a free data retrieval call binding the contract method 0x8b85902b. +// +// Solidity: function l2BlockNumber() pure returns(uint256 l2BlockNumber_) +func (_FaultDisputeGameN *FaultDisputeGameNSession) L2BlockNumber() (*big.Int, error) { + return _FaultDisputeGameN.Contract.L2BlockNumber(&_FaultDisputeGameN.CallOpts) +} + +// L2BlockNumber is a free data retrieval call binding the contract method 0x8b85902b. +// +// Solidity: function l2BlockNumber() pure returns(uint256 l2BlockNumber_) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) L2BlockNumber() (*big.Int, error) { + return _FaultDisputeGameN.Contract.L2BlockNumber(&_FaultDisputeGameN.CallOpts) +} + +// L2BlockNumberChallenged is a free data retrieval call binding the contract method 0x3e3ac912. +// +// Solidity: function l2BlockNumberChallenged() view returns(bool) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) L2BlockNumberChallenged(opts *bind.CallOpts) (bool, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "l2BlockNumberChallenged") + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// L2BlockNumberChallenged is a free data retrieval call binding the contract method 0x3e3ac912. +// +// Solidity: function l2BlockNumberChallenged() view returns(bool) +func (_FaultDisputeGameN *FaultDisputeGameNSession) L2BlockNumberChallenged() (bool, error) { + return _FaultDisputeGameN.Contract.L2BlockNumberChallenged(&_FaultDisputeGameN.CallOpts) +} + +// L2BlockNumberChallenged is a free data retrieval call binding the contract method 0x3e3ac912. +// +// Solidity: function l2BlockNumberChallenged() view returns(bool) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) L2BlockNumberChallenged() (bool, error) { + return _FaultDisputeGameN.Contract.L2BlockNumberChallenged(&_FaultDisputeGameN.CallOpts) +} + +// L2BlockNumberChallenger is a free data retrieval call binding the contract method 0x30dbe570. +// +// Solidity: function l2BlockNumberChallenger() view returns(address) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) L2BlockNumberChallenger(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "l2BlockNumberChallenger") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// L2BlockNumberChallenger is a free data retrieval call binding the contract method 0x30dbe570. +// +// Solidity: function l2BlockNumberChallenger() view returns(address) +func (_FaultDisputeGameN *FaultDisputeGameNSession) L2BlockNumberChallenger() (common.Address, error) { + return _FaultDisputeGameN.Contract.L2BlockNumberChallenger(&_FaultDisputeGameN.CallOpts) +} + +// L2BlockNumberChallenger is a free data retrieval call binding the contract method 0x30dbe570. +// +// Solidity: function l2BlockNumberChallenger() view returns(address) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) L2BlockNumberChallenger() (common.Address, error) { + return _FaultDisputeGameN.Contract.L2BlockNumberChallenger(&_FaultDisputeGameN.CallOpts) +} + +// L2ChainId is a free data retrieval call binding the contract method 0xd6ae3cd5. +// +// Solidity: function l2ChainId() view returns(uint256 l2ChainId_) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) L2ChainId(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "l2ChainId") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// L2ChainId is a free data retrieval call binding the contract method 0xd6ae3cd5. +// +// Solidity: function l2ChainId() view returns(uint256 l2ChainId_) +func (_FaultDisputeGameN *FaultDisputeGameNSession) L2ChainId() (*big.Int, error) { + return _FaultDisputeGameN.Contract.L2ChainId(&_FaultDisputeGameN.CallOpts) +} + +// L2ChainId is a free data retrieval call binding the contract method 0xd6ae3cd5. +// +// Solidity: function l2ChainId() view returns(uint256 l2ChainId_) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) L2ChainId() (*big.Int, error) { + return _FaultDisputeGameN.Contract.L2ChainId(&_FaultDisputeGameN.CallOpts) +} + +// MaxAttackBranch is a free data retrieval call binding the contract method 0x70b6bb0d. +// +// Solidity: function maxAttackBranch() view returns(uint256 maxAttackBranch_) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) MaxAttackBranch(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "maxAttackBranch") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// MaxAttackBranch is a free data retrieval call binding the contract method 0x70b6bb0d. +// +// Solidity: function maxAttackBranch() view returns(uint256 maxAttackBranch_) +func (_FaultDisputeGameN *FaultDisputeGameNSession) MaxAttackBranch() (*big.Int, error) { + return _FaultDisputeGameN.Contract.MaxAttackBranch(&_FaultDisputeGameN.CallOpts) +} + +// MaxAttackBranch is a free data retrieval call binding the contract method 0x70b6bb0d. +// +// Solidity: function maxAttackBranch() view returns(uint256 maxAttackBranch_) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) MaxAttackBranch() (*big.Int, error) { + return _FaultDisputeGameN.Contract.MaxAttackBranch(&_FaultDisputeGameN.CallOpts) +} + +// MaxClockDuration is a free data retrieval call binding the contract method 0xdabd396d. +// +// Solidity: function maxClockDuration() view returns(uint64 maxClockDuration_) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) MaxClockDuration(opts *bind.CallOpts) (uint64, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "maxClockDuration") + + if err != nil { + return *new(uint64), err + } + + out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) + + return out0, err + +} + +// MaxClockDuration is a free data retrieval call binding the contract method 0xdabd396d. +// +// Solidity: function maxClockDuration() view returns(uint64 maxClockDuration_) +func (_FaultDisputeGameN *FaultDisputeGameNSession) MaxClockDuration() (uint64, error) { + return _FaultDisputeGameN.Contract.MaxClockDuration(&_FaultDisputeGameN.CallOpts) +} + +// MaxClockDuration is a free data retrieval call binding the contract method 0xdabd396d. +// +// Solidity: function maxClockDuration() view returns(uint64 maxClockDuration_) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) MaxClockDuration() (uint64, error) { + return _FaultDisputeGameN.Contract.MaxClockDuration(&_FaultDisputeGameN.CallOpts) +} + +// MaxGameDepth is a free data retrieval call binding the contract method 0xfa315aa9. +// +// Solidity: function maxGameDepth() view returns(uint256 maxGameDepth_) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) MaxGameDepth(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "maxGameDepth") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// MaxGameDepth is a free data retrieval call binding the contract method 0xfa315aa9. +// +// Solidity: function maxGameDepth() view returns(uint256 maxGameDepth_) +func (_FaultDisputeGameN *FaultDisputeGameNSession) MaxGameDepth() (*big.Int, error) { + return _FaultDisputeGameN.Contract.MaxGameDepth(&_FaultDisputeGameN.CallOpts) +} + +// MaxGameDepth is a free data retrieval call binding the contract method 0xfa315aa9. +// +// Solidity: function maxGameDepth() view returns(uint256 maxGameDepth_) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) MaxGameDepth() (*big.Int, error) { + return _FaultDisputeGameN.Contract.MaxGameDepth(&_FaultDisputeGameN.CallOpts) +} + +// NBits is a free data retrieval call binding the contract method 0x8d0e582e. +// +// Solidity: function nBits() view returns(uint256 nBits_) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) NBits(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "nBits") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// NBits is a free data retrieval call binding the contract method 0x8d0e582e. +// +// Solidity: function nBits() view returns(uint256 nBits_) +func (_FaultDisputeGameN *FaultDisputeGameNSession) NBits() (*big.Int, error) { + return _FaultDisputeGameN.Contract.NBits(&_FaultDisputeGameN.CallOpts) +} + +// NBits is a free data retrieval call binding the contract method 0x8d0e582e. +// +// Solidity: function nBits() view returns(uint256 nBits_) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) NBits() (*big.Int, error) { + return _FaultDisputeGameN.Contract.NBits(&_FaultDisputeGameN.CallOpts) +} + +// ResolutionCheckpoints is a free data retrieval call binding the contract method 0xa445ece6. +// +// Solidity: function resolutionCheckpoints(uint256 ) view returns(bool initialCheckpointComplete, uint32 subgameIndex, uint128 leftmostPosition, address counteredBy) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) ResolutionCheckpoints(opts *bind.CallOpts, arg0 *big.Int) (struct { + InitialCheckpointComplete bool + SubgameIndex uint32 + LeftmostPosition *big.Int + CounteredBy common.Address +}, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "resolutionCheckpoints", arg0) + + outstruct := new(struct { + InitialCheckpointComplete bool + SubgameIndex uint32 + LeftmostPosition *big.Int + CounteredBy common.Address + }) + if err != nil { + return *outstruct, err + } + + outstruct.InitialCheckpointComplete = *abi.ConvertType(out[0], new(bool)).(*bool) + outstruct.SubgameIndex = *abi.ConvertType(out[1], new(uint32)).(*uint32) + outstruct.LeftmostPosition = *abi.ConvertType(out[2], new(*big.Int)).(**big.Int) + outstruct.CounteredBy = *abi.ConvertType(out[3], new(common.Address)).(*common.Address) + + return *outstruct, err + +} + +// ResolutionCheckpoints is a free data retrieval call binding the contract method 0xa445ece6. +// +// Solidity: function resolutionCheckpoints(uint256 ) view returns(bool initialCheckpointComplete, uint32 subgameIndex, uint128 leftmostPosition, address counteredBy) +func (_FaultDisputeGameN *FaultDisputeGameNSession) ResolutionCheckpoints(arg0 *big.Int) (struct { + InitialCheckpointComplete bool + SubgameIndex uint32 + LeftmostPosition *big.Int + CounteredBy common.Address +}, error) { + return _FaultDisputeGameN.Contract.ResolutionCheckpoints(&_FaultDisputeGameN.CallOpts, arg0) +} + +// ResolutionCheckpoints is a free data retrieval call binding the contract method 0xa445ece6. +// +// Solidity: function resolutionCheckpoints(uint256 ) view returns(bool initialCheckpointComplete, uint32 subgameIndex, uint128 leftmostPosition, address counteredBy) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) ResolutionCheckpoints(arg0 *big.Int) (struct { + InitialCheckpointComplete bool + SubgameIndex uint32 + LeftmostPosition *big.Int + CounteredBy common.Address +}, error) { + return _FaultDisputeGameN.Contract.ResolutionCheckpoints(&_FaultDisputeGameN.CallOpts, arg0) +} + +// ResolvedAt is a free data retrieval call binding the contract method 0x19effeb4. +// +// Solidity: function resolvedAt() view returns(uint64) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) ResolvedAt(opts *bind.CallOpts) (uint64, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "resolvedAt") + + if err != nil { + return *new(uint64), err + } + + out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) + + return out0, err + +} + +// ResolvedAt is a free data retrieval call binding the contract method 0x19effeb4. +// +// Solidity: function resolvedAt() view returns(uint64) +func (_FaultDisputeGameN *FaultDisputeGameNSession) ResolvedAt() (uint64, error) { + return _FaultDisputeGameN.Contract.ResolvedAt(&_FaultDisputeGameN.CallOpts) +} + +// ResolvedAt is a free data retrieval call binding the contract method 0x19effeb4. +// +// Solidity: function resolvedAt() view returns(uint64) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) ResolvedAt() (uint64, error) { + return _FaultDisputeGameN.Contract.ResolvedAt(&_FaultDisputeGameN.CallOpts) +} + +// ResolvedSubgames is a free data retrieval call binding the contract method 0xfe2bbeb2. +// +// Solidity: function resolvedSubgames(uint256 ) view returns(bool) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) ResolvedSubgames(opts *bind.CallOpts, arg0 *big.Int) (bool, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "resolvedSubgames", arg0) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// ResolvedSubgames is a free data retrieval call binding the contract method 0xfe2bbeb2. +// +// Solidity: function resolvedSubgames(uint256 ) view returns(bool) +func (_FaultDisputeGameN *FaultDisputeGameNSession) ResolvedSubgames(arg0 *big.Int) (bool, error) { + return _FaultDisputeGameN.Contract.ResolvedSubgames(&_FaultDisputeGameN.CallOpts, arg0) +} + +// ResolvedSubgames is a free data retrieval call binding the contract method 0xfe2bbeb2. +// +// Solidity: function resolvedSubgames(uint256 ) view returns(bool) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) ResolvedSubgames(arg0 *big.Int) (bool, error) { + return _FaultDisputeGameN.Contract.ResolvedSubgames(&_FaultDisputeGameN.CallOpts, arg0) +} + +// RootClaim is a free data retrieval call binding the contract method 0xbcef3b55. +// +// Solidity: function rootClaim() pure returns(bytes32 rootClaim_) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) RootClaim(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "rootClaim") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// RootClaim is a free data retrieval call binding the contract method 0xbcef3b55. +// +// Solidity: function rootClaim() pure returns(bytes32 rootClaim_) +func (_FaultDisputeGameN *FaultDisputeGameNSession) RootClaim() ([32]byte, error) { + return _FaultDisputeGameN.Contract.RootClaim(&_FaultDisputeGameN.CallOpts) +} + +// RootClaim is a free data retrieval call binding the contract method 0xbcef3b55. +// +// Solidity: function rootClaim() pure returns(bytes32 rootClaim_) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) RootClaim() ([32]byte, error) { + return _FaultDisputeGameN.Contract.RootClaim(&_FaultDisputeGameN.CallOpts) +} + +// SplitDepth is a free data retrieval call binding the contract method 0xec5e6308. +// +// Solidity: function splitDepth() view returns(uint256 splitDepth_) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) SplitDepth(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "splitDepth") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// SplitDepth is a free data retrieval call binding the contract method 0xec5e6308. +// +// Solidity: function splitDepth() view returns(uint256 splitDepth_) +func (_FaultDisputeGameN *FaultDisputeGameNSession) SplitDepth() (*big.Int, error) { + return _FaultDisputeGameN.Contract.SplitDepth(&_FaultDisputeGameN.CallOpts) +} + +// SplitDepth is a free data retrieval call binding the contract method 0xec5e6308. +// +// Solidity: function splitDepth() view returns(uint256 splitDepth_) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) SplitDepth() (*big.Int, error) { + return _FaultDisputeGameN.Contract.SplitDepth(&_FaultDisputeGameN.CallOpts) +} + +// StartingBlockNumber is a free data retrieval call binding the contract method 0x70872aa5. +// +// Solidity: function startingBlockNumber() view returns(uint256 startingBlockNumber_) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) StartingBlockNumber(opts *bind.CallOpts) (*big.Int, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "startingBlockNumber") + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// StartingBlockNumber is a free data retrieval call binding the contract method 0x70872aa5. +// +// Solidity: function startingBlockNumber() view returns(uint256 startingBlockNumber_) +func (_FaultDisputeGameN *FaultDisputeGameNSession) StartingBlockNumber() (*big.Int, error) { + return _FaultDisputeGameN.Contract.StartingBlockNumber(&_FaultDisputeGameN.CallOpts) +} + +// StartingBlockNumber is a free data retrieval call binding the contract method 0x70872aa5. +// +// Solidity: function startingBlockNumber() view returns(uint256 startingBlockNumber_) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) StartingBlockNumber() (*big.Int, error) { + return _FaultDisputeGameN.Contract.StartingBlockNumber(&_FaultDisputeGameN.CallOpts) +} + +// StartingOutputRoot is a free data retrieval call binding the contract method 0x57da950e. +// +// Solidity: function startingOutputRoot() view returns(bytes32 root, uint256 l2BlockNumber) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) StartingOutputRoot(opts *bind.CallOpts) (struct { + Root [32]byte + L2BlockNumber *big.Int +}, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "startingOutputRoot") + + outstruct := new(struct { + Root [32]byte + L2BlockNumber *big.Int + }) + if err != nil { + return *outstruct, err + } + + outstruct.Root = *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + outstruct.L2BlockNumber = *abi.ConvertType(out[1], new(*big.Int)).(**big.Int) + + return *outstruct, err + +} + +// StartingOutputRoot is a free data retrieval call binding the contract method 0x57da950e. +// +// Solidity: function startingOutputRoot() view returns(bytes32 root, uint256 l2BlockNumber) +func (_FaultDisputeGameN *FaultDisputeGameNSession) StartingOutputRoot() (struct { + Root [32]byte + L2BlockNumber *big.Int +}, error) { + return _FaultDisputeGameN.Contract.StartingOutputRoot(&_FaultDisputeGameN.CallOpts) +} + +// StartingOutputRoot is a free data retrieval call binding the contract method 0x57da950e. +// +// Solidity: function startingOutputRoot() view returns(bytes32 root, uint256 l2BlockNumber) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) StartingOutputRoot() (struct { + Root [32]byte + L2BlockNumber *big.Int +}, error) { + return _FaultDisputeGameN.Contract.StartingOutputRoot(&_FaultDisputeGameN.CallOpts) +} + +// StartingRootHash is a free data retrieval call binding the contract method 0x25fc2ace. +// +// Solidity: function startingRootHash() view returns(bytes32 startingRootHash_) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) StartingRootHash(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "startingRootHash") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// StartingRootHash is a free data retrieval call binding the contract method 0x25fc2ace. +// +// Solidity: function startingRootHash() view returns(bytes32 startingRootHash_) +func (_FaultDisputeGameN *FaultDisputeGameNSession) StartingRootHash() ([32]byte, error) { + return _FaultDisputeGameN.Contract.StartingRootHash(&_FaultDisputeGameN.CallOpts) +} + +// StartingRootHash is a free data retrieval call binding the contract method 0x25fc2ace. +// +// Solidity: function startingRootHash() view returns(bytes32 startingRootHash_) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) StartingRootHash() ([32]byte, error) { + return _FaultDisputeGameN.Contract.StartingRootHash(&_FaultDisputeGameN.CallOpts) +} + +// Status is a free data retrieval call binding the contract method 0x200d2ed2. +// +// Solidity: function status() view returns(uint8) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) Status(opts *bind.CallOpts) (uint8, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "status") + + if err != nil { + return *new(uint8), err + } + + out0 := *abi.ConvertType(out[0], new(uint8)).(*uint8) + + return out0, err + +} + +// Status is a free data retrieval call binding the contract method 0x200d2ed2. +// +// Solidity: function status() view returns(uint8) +func (_FaultDisputeGameN *FaultDisputeGameNSession) Status() (uint8, error) { + return _FaultDisputeGameN.Contract.Status(&_FaultDisputeGameN.CallOpts) +} + +// Status is a free data retrieval call binding the contract method 0x200d2ed2. +// +// Solidity: function status() view returns(uint8) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) Status() (uint8, error) { + return _FaultDisputeGameN.Contract.Status(&_FaultDisputeGameN.CallOpts) +} + +// Subgames is a free data retrieval call binding the contract method 0x2ad69aeb. +// +// Solidity: function subgames(uint256 , uint256 ) view returns(uint256) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) Subgames(opts *bind.CallOpts, arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "subgames", arg0, arg1) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Subgames is a free data retrieval call binding the contract method 0x2ad69aeb. +// +// Solidity: function subgames(uint256 , uint256 ) view returns(uint256) +func (_FaultDisputeGameN *FaultDisputeGameNSession) Subgames(arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { + return _FaultDisputeGameN.Contract.Subgames(&_FaultDisputeGameN.CallOpts, arg0, arg1) +} + +// Subgames is a free data retrieval call binding the contract method 0x2ad69aeb. +// +// Solidity: function subgames(uint256 , uint256 ) view returns(uint256) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) Subgames(arg0 *big.Int, arg1 *big.Int) (*big.Int, error) { + return _FaultDisputeGameN.Contract.Subgames(&_FaultDisputeGameN.CallOpts, arg0, arg1) +} + +// Version is a free data retrieval call binding the contract method 0x54fd4d50. +// +// Solidity: function version() view returns(string) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) Version(opts *bind.CallOpts) (string, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "version") + + if err != nil { + return *new(string), err + } + + out0 := *abi.ConvertType(out[0], new(string)).(*string) + + return out0, err + +} + +// Version is a free data retrieval call binding the contract method 0x54fd4d50. +// +// Solidity: function version() view returns(string) +func (_FaultDisputeGameN *FaultDisputeGameNSession) Version() (string, error) { + return _FaultDisputeGameN.Contract.Version(&_FaultDisputeGameN.CallOpts) +} + +// Version is a free data retrieval call binding the contract method 0x54fd4d50. +// +// Solidity: function version() view returns(string) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) Version() (string, error) { + return _FaultDisputeGameN.Contract.Version(&_FaultDisputeGameN.CallOpts) +} + +// Vm is a free data retrieval call binding the contract method 0x3a768463. +// +// Solidity: function vm() view returns(address vm_) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) Vm(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "vm") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Vm is a free data retrieval call binding the contract method 0x3a768463. +// +// Solidity: function vm() view returns(address vm_) +func (_FaultDisputeGameN *FaultDisputeGameNSession) Vm() (common.Address, error) { + return _FaultDisputeGameN.Contract.Vm(&_FaultDisputeGameN.CallOpts) +} + +// Vm is a free data retrieval call binding the contract method 0x3a768463. +// +// Solidity: function vm() view returns(address vm_) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) Vm() (common.Address, error) { + return _FaultDisputeGameN.Contract.Vm(&_FaultDisputeGameN.CallOpts) +} + +// Weth is a free data retrieval call binding the contract method 0x3fc8cef3. +// +// Solidity: function weth() view returns(address weth_) +func (_FaultDisputeGameN *FaultDisputeGameNCaller) Weth(opts *bind.CallOpts) (common.Address, error) { + var out []interface{} + err := _FaultDisputeGameN.contract.Call(opts, &out, "weth") + + if err != nil { + return *new(common.Address), err + } + + out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) + + return out0, err + +} + +// Weth is a free data retrieval call binding the contract method 0x3fc8cef3. +// +// Solidity: function weth() view returns(address weth_) +func (_FaultDisputeGameN *FaultDisputeGameNSession) Weth() (common.Address, error) { + return _FaultDisputeGameN.Contract.Weth(&_FaultDisputeGameN.CallOpts) +} + +// Weth is a free data retrieval call binding the contract method 0x3fc8cef3. +// +// Solidity: function weth() view returns(address weth_) +func (_FaultDisputeGameN *FaultDisputeGameNCallerSession) Weth() (common.Address, error) { + return _FaultDisputeGameN.Contract.Weth(&_FaultDisputeGameN.CallOpts) +} + +// AddLocalData is a paid mutator transaction binding the contract method 0xf8f43ff6. +// +// Solidity: function addLocalData(uint256 _ident, uint256 _execLeafIdx, uint256 _partOffset) returns() +func (_FaultDisputeGameN *FaultDisputeGameNTransactor) AddLocalData(opts *bind.TransactOpts, _ident *big.Int, _execLeafIdx *big.Int, _partOffset *big.Int) (*types.Transaction, error) { + return _FaultDisputeGameN.contract.Transact(opts, "addLocalData", _ident, _execLeafIdx, _partOffset) +} + +// AddLocalData is a paid mutator transaction binding the contract method 0xf8f43ff6. +// +// Solidity: function addLocalData(uint256 _ident, uint256 _execLeafIdx, uint256 _partOffset) returns() +func (_FaultDisputeGameN *FaultDisputeGameNSession) AddLocalData(_ident *big.Int, _execLeafIdx *big.Int, _partOffset *big.Int) (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.AddLocalData(&_FaultDisputeGameN.TransactOpts, _ident, _execLeafIdx, _partOffset) +} + +// AddLocalData is a paid mutator transaction binding the contract method 0xf8f43ff6. +// +// Solidity: function addLocalData(uint256 _ident, uint256 _execLeafIdx, uint256 _partOffset) returns() +func (_FaultDisputeGameN *FaultDisputeGameNTransactorSession) AddLocalData(_ident *big.Int, _execLeafIdx *big.Int, _partOffset *big.Int) (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.AddLocalData(&_FaultDisputeGameN.TransactOpts, _ident, _execLeafIdx, _partOffset) +} + +// AddLocalData2 is a paid mutator transaction binding the contract method 0xaf6cc6a7. +// +// Solidity: function addLocalData2(uint256 _ident, uint256 _execLeafIdx, uint256 _partOffset, (uint256,bytes32,bytes) _daItem) returns(bytes32 uuid_, bytes32 value_) +func (_FaultDisputeGameN *FaultDisputeGameNTransactor) AddLocalData2(opts *bind.TransactOpts, _ident *big.Int, _execLeafIdx *big.Int, _partOffset *big.Int, _daItem LibDADAItem) (*types.Transaction, error) { + return _FaultDisputeGameN.contract.Transact(opts, "addLocalData2", _ident, _execLeafIdx, _partOffset, _daItem) +} + +// AddLocalData2 is a paid mutator transaction binding the contract method 0xaf6cc6a7. +// +// Solidity: function addLocalData2(uint256 _ident, uint256 _execLeafIdx, uint256 _partOffset, (uint256,bytes32,bytes) _daItem) returns(bytes32 uuid_, bytes32 value_) +func (_FaultDisputeGameN *FaultDisputeGameNSession) AddLocalData2(_ident *big.Int, _execLeafIdx *big.Int, _partOffset *big.Int, _daItem LibDADAItem) (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.AddLocalData2(&_FaultDisputeGameN.TransactOpts, _ident, _execLeafIdx, _partOffset, _daItem) +} + +// AddLocalData2 is a paid mutator transaction binding the contract method 0xaf6cc6a7. +// +// Solidity: function addLocalData2(uint256 _ident, uint256 _execLeafIdx, uint256 _partOffset, (uint256,bytes32,bytes) _daItem) returns(bytes32 uuid_, bytes32 value_) +func (_FaultDisputeGameN *FaultDisputeGameNTransactorSession) AddLocalData2(_ident *big.Int, _execLeafIdx *big.Int, _partOffset *big.Int, _daItem LibDADAItem) (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.AddLocalData2(&_FaultDisputeGameN.TransactOpts, _ident, _execLeafIdx, _partOffset, _daItem) +} + +// Attack is a paid mutator transaction binding the contract method 0x472777c6. +// +// Solidity: function attack(bytes32 _disputed, uint256 _parentIndex, bytes32 _claim) payable returns() +func (_FaultDisputeGameN *FaultDisputeGameNTransactor) Attack(opts *bind.TransactOpts, _disputed [32]byte, _parentIndex *big.Int, _claim [32]byte) (*types.Transaction, error) { + return _FaultDisputeGameN.contract.Transact(opts, "attack", _disputed, _parentIndex, _claim) +} + +// Attack is a paid mutator transaction binding the contract method 0x472777c6. +// +// Solidity: function attack(bytes32 _disputed, uint256 _parentIndex, bytes32 _claim) payable returns() +func (_FaultDisputeGameN *FaultDisputeGameNSession) Attack(_disputed [32]byte, _parentIndex *big.Int, _claim [32]byte) (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.Attack(&_FaultDisputeGameN.TransactOpts, _disputed, _parentIndex, _claim) +} + +// Attack is a paid mutator transaction binding the contract method 0x472777c6. +// +// Solidity: function attack(bytes32 _disputed, uint256 _parentIndex, bytes32 _claim) payable returns() +func (_FaultDisputeGameN *FaultDisputeGameNTransactorSession) Attack(_disputed [32]byte, _parentIndex *big.Int, _claim [32]byte) (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.Attack(&_FaultDisputeGameN.TransactOpts, _disputed, _parentIndex, _claim) +} + +// AttackV2 is a paid mutator transaction binding the contract method 0x199e300e. +// +// Solidity: function attackV2(bytes32 _disputed, uint256 _parentIndex, uint256 _attackBranch, uint256 _daType, bytes _claims) payable returns() +func (_FaultDisputeGameN *FaultDisputeGameNTransactor) AttackV2(opts *bind.TransactOpts, _disputed [32]byte, _parentIndex *big.Int, _attackBranch *big.Int, _daType *big.Int, _claims []byte) (*types.Transaction, error) { + return _FaultDisputeGameN.contract.Transact(opts, "attackV2", _disputed, _parentIndex, _attackBranch, _daType, _claims) +} + +// AttackV2 is a paid mutator transaction binding the contract method 0x199e300e. +// +// Solidity: function attackV2(bytes32 _disputed, uint256 _parentIndex, uint256 _attackBranch, uint256 _daType, bytes _claims) payable returns() +func (_FaultDisputeGameN *FaultDisputeGameNSession) AttackV2(_disputed [32]byte, _parentIndex *big.Int, _attackBranch *big.Int, _daType *big.Int, _claims []byte) (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.AttackV2(&_FaultDisputeGameN.TransactOpts, _disputed, _parentIndex, _attackBranch, _daType, _claims) +} + +// AttackV2 is a paid mutator transaction binding the contract method 0x199e300e. +// +// Solidity: function attackV2(bytes32 _disputed, uint256 _parentIndex, uint256 _attackBranch, uint256 _daType, bytes _claims) payable returns() +func (_FaultDisputeGameN *FaultDisputeGameNTransactorSession) AttackV2(_disputed [32]byte, _parentIndex *big.Int, _attackBranch *big.Int, _daType *big.Int, _claims []byte) (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.AttackV2(&_FaultDisputeGameN.TransactOpts, _disputed, _parentIndex, _attackBranch, _daType, _claims) +} + +// ChallengeRootL2Block is a paid mutator transaction binding the contract method 0x01935130. +// +// Solidity: function challengeRootL2Block((bytes32,bytes32,bytes32,bytes32) _outputRootProof, bytes _headerRLP) returns() +func (_FaultDisputeGameN *FaultDisputeGameNTransactor) ChallengeRootL2Block(opts *bind.TransactOpts, _outputRootProof TypesOutputRootProof, _headerRLP []byte) (*types.Transaction, error) { + return _FaultDisputeGameN.contract.Transact(opts, "challengeRootL2Block", _outputRootProof, _headerRLP) +} + +// ChallengeRootL2Block is a paid mutator transaction binding the contract method 0x01935130. +// +// Solidity: function challengeRootL2Block((bytes32,bytes32,bytes32,bytes32) _outputRootProof, bytes _headerRLP) returns() +func (_FaultDisputeGameN *FaultDisputeGameNSession) ChallengeRootL2Block(_outputRootProof TypesOutputRootProof, _headerRLP []byte) (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.ChallengeRootL2Block(&_FaultDisputeGameN.TransactOpts, _outputRootProof, _headerRLP) +} + +// ChallengeRootL2Block is a paid mutator transaction binding the contract method 0x01935130. +// +// Solidity: function challengeRootL2Block((bytes32,bytes32,bytes32,bytes32) _outputRootProof, bytes _headerRLP) returns() +func (_FaultDisputeGameN *FaultDisputeGameNTransactorSession) ChallengeRootL2Block(_outputRootProof TypesOutputRootProof, _headerRLP []byte) (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.ChallengeRootL2Block(&_FaultDisputeGameN.TransactOpts, _outputRootProof, _headerRLP) +} + +// ClaimCredit is a paid mutator transaction binding the contract method 0x60e27464. +// +// Solidity: function claimCredit(address _recipient) returns() +func (_FaultDisputeGameN *FaultDisputeGameNTransactor) ClaimCredit(opts *bind.TransactOpts, _recipient common.Address) (*types.Transaction, error) { + return _FaultDisputeGameN.contract.Transact(opts, "claimCredit", _recipient) +} + +// ClaimCredit is a paid mutator transaction binding the contract method 0x60e27464. +// +// Solidity: function claimCredit(address _recipient) returns() +func (_FaultDisputeGameN *FaultDisputeGameNSession) ClaimCredit(_recipient common.Address) (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.ClaimCredit(&_FaultDisputeGameN.TransactOpts, _recipient) +} + +// ClaimCredit is a paid mutator transaction binding the contract method 0x60e27464. +// +// Solidity: function claimCredit(address _recipient) returns() +func (_FaultDisputeGameN *FaultDisputeGameNTransactorSession) ClaimCredit(_recipient common.Address) (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.ClaimCredit(&_FaultDisputeGameN.TransactOpts, _recipient) +} + +// Defend is a paid mutator transaction binding the contract method 0x7b0f0adc. +// +// Solidity: function defend(bytes32 _disputed, uint256 _parentIndex, bytes32 _claim) payable returns() +func (_FaultDisputeGameN *FaultDisputeGameNTransactor) Defend(opts *bind.TransactOpts, _disputed [32]byte, _parentIndex *big.Int, _claim [32]byte) (*types.Transaction, error) { + return _FaultDisputeGameN.contract.Transact(opts, "defend", _disputed, _parentIndex, _claim) +} + +// Defend is a paid mutator transaction binding the contract method 0x7b0f0adc. +// +// Solidity: function defend(bytes32 _disputed, uint256 _parentIndex, bytes32 _claim) payable returns() +func (_FaultDisputeGameN *FaultDisputeGameNSession) Defend(_disputed [32]byte, _parentIndex *big.Int, _claim [32]byte) (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.Defend(&_FaultDisputeGameN.TransactOpts, _disputed, _parentIndex, _claim) +} + +// Defend is a paid mutator transaction binding the contract method 0x7b0f0adc. +// +// Solidity: function defend(bytes32 _disputed, uint256 _parentIndex, bytes32 _claim) payable returns() +func (_FaultDisputeGameN *FaultDisputeGameNTransactorSession) Defend(_disputed [32]byte, _parentIndex *big.Int, _claim [32]byte) (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.Defend(&_FaultDisputeGameN.TransactOpts, _disputed, _parentIndex, _claim) +} + +// Initialize is a paid mutator transaction binding the contract method 0x8129fc1c. +// +// Solidity: function initialize() payable returns() +func (_FaultDisputeGameN *FaultDisputeGameNTransactor) Initialize(opts *bind.TransactOpts) (*types.Transaction, error) { + return _FaultDisputeGameN.contract.Transact(opts, "initialize") +} + +// Initialize is a paid mutator transaction binding the contract method 0x8129fc1c. +// +// Solidity: function initialize() payable returns() +func (_FaultDisputeGameN *FaultDisputeGameNSession) Initialize() (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.Initialize(&_FaultDisputeGameN.TransactOpts) +} + +// Initialize is a paid mutator transaction binding the contract method 0x8129fc1c. +// +// Solidity: function initialize() payable returns() +func (_FaultDisputeGameN *FaultDisputeGameNTransactorSession) Initialize() (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.Initialize(&_FaultDisputeGameN.TransactOpts) +} + +// Move is a paid mutator transaction binding the contract method 0x6f034409. +// +// Solidity: function move(bytes32 _disputed, uint256 _challengeIndex, bytes32 _claim, bool _isAttack) payable returns() +func (_FaultDisputeGameN *FaultDisputeGameNTransactor) Move(opts *bind.TransactOpts, _disputed [32]byte, _challengeIndex *big.Int, _claim [32]byte, _isAttack bool) (*types.Transaction, error) { + return _FaultDisputeGameN.contract.Transact(opts, "move", _disputed, _challengeIndex, _claim, _isAttack) +} + +// Move is a paid mutator transaction binding the contract method 0x6f034409. +// +// Solidity: function move(bytes32 _disputed, uint256 _challengeIndex, bytes32 _claim, bool _isAttack) payable returns() +func (_FaultDisputeGameN *FaultDisputeGameNSession) Move(_disputed [32]byte, _challengeIndex *big.Int, _claim [32]byte, _isAttack bool) (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.Move(&_FaultDisputeGameN.TransactOpts, _disputed, _challengeIndex, _claim, _isAttack) +} + +// Move is a paid mutator transaction binding the contract method 0x6f034409. +// +// Solidity: function move(bytes32 _disputed, uint256 _challengeIndex, bytes32 _claim, bool _isAttack) payable returns() +func (_FaultDisputeGameN *FaultDisputeGameNTransactorSession) Move(_disputed [32]byte, _challengeIndex *big.Int, _claim [32]byte, _isAttack bool) (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.Move(&_FaultDisputeGameN.TransactOpts, _disputed, _challengeIndex, _claim, _isAttack) +} + +// Resolve is a paid mutator transaction binding the contract method 0x2810e1d6. +// +// Solidity: function resolve() returns(uint8 status_) +func (_FaultDisputeGameN *FaultDisputeGameNTransactor) Resolve(opts *bind.TransactOpts) (*types.Transaction, error) { + return _FaultDisputeGameN.contract.Transact(opts, "resolve") +} + +// Resolve is a paid mutator transaction binding the contract method 0x2810e1d6. +// +// Solidity: function resolve() returns(uint8 status_) +func (_FaultDisputeGameN *FaultDisputeGameNSession) Resolve() (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.Resolve(&_FaultDisputeGameN.TransactOpts) +} + +// Resolve is a paid mutator transaction binding the contract method 0x2810e1d6. +// +// Solidity: function resolve() returns(uint8 status_) +func (_FaultDisputeGameN *FaultDisputeGameNTransactorSession) Resolve() (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.Resolve(&_FaultDisputeGameN.TransactOpts) +} + +// ResolveClaim is a paid mutator transaction binding the contract method 0x03c2924d. +// +// Solidity: function resolveClaim(uint256 _claimIndex, uint256 _numToResolve) returns() +func (_FaultDisputeGameN *FaultDisputeGameNTransactor) ResolveClaim(opts *bind.TransactOpts, _claimIndex *big.Int, _numToResolve *big.Int) (*types.Transaction, error) { + return _FaultDisputeGameN.contract.Transact(opts, "resolveClaim", _claimIndex, _numToResolve) +} + +// ResolveClaim is a paid mutator transaction binding the contract method 0x03c2924d. +// +// Solidity: function resolveClaim(uint256 _claimIndex, uint256 _numToResolve) returns() +func (_FaultDisputeGameN *FaultDisputeGameNSession) ResolveClaim(_claimIndex *big.Int, _numToResolve *big.Int) (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.ResolveClaim(&_FaultDisputeGameN.TransactOpts, _claimIndex, _numToResolve) +} + +// ResolveClaim is a paid mutator transaction binding the contract method 0x03c2924d. +// +// Solidity: function resolveClaim(uint256 _claimIndex, uint256 _numToResolve) returns() +func (_FaultDisputeGameN *FaultDisputeGameNTransactorSession) ResolveClaim(_claimIndex *big.Int, _numToResolve *big.Int) (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.ResolveClaim(&_FaultDisputeGameN.TransactOpts, _claimIndex, _numToResolve) +} + +// Step is a paid mutator transaction binding the contract method 0xd8cc1a3c. +// +// Solidity: function step(uint256 _claimIndex, bool _isAttack, bytes _stateData, bytes _proof) returns() +func (_FaultDisputeGameN *FaultDisputeGameNTransactor) Step(opts *bind.TransactOpts, _claimIndex *big.Int, _isAttack bool, _stateData []byte, _proof []byte) (*types.Transaction, error) { + return _FaultDisputeGameN.contract.Transact(opts, "step", _claimIndex, _isAttack, _stateData, _proof) +} + +// Step is a paid mutator transaction binding the contract method 0xd8cc1a3c. +// +// Solidity: function step(uint256 _claimIndex, bool _isAttack, bytes _stateData, bytes _proof) returns() +func (_FaultDisputeGameN *FaultDisputeGameNSession) Step(_claimIndex *big.Int, _isAttack bool, _stateData []byte, _proof []byte) (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.Step(&_FaultDisputeGameN.TransactOpts, _claimIndex, _isAttack, _stateData, _proof) +} + +// Step is a paid mutator transaction binding the contract method 0xd8cc1a3c. +// +// Solidity: function step(uint256 _claimIndex, bool _isAttack, bytes _stateData, bytes _proof) returns() +func (_FaultDisputeGameN *FaultDisputeGameNTransactorSession) Step(_claimIndex *big.Int, _isAttack bool, _stateData []byte, _proof []byte) (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.Step(&_FaultDisputeGameN.TransactOpts, _claimIndex, _isAttack, _stateData, _proof) +} + +// StepV2 is a paid mutator transaction binding the contract method 0x175d249c. +// +// Solidity: function stepV2(uint256 _claimIndex, uint256 _attackBranch, bytes _stateData, ((uint256,bytes32,bytes),(uint256,bytes32,bytes),bytes) _proof) returns() +func (_FaultDisputeGameN *FaultDisputeGameNTransactor) StepV2(opts *bind.TransactOpts, _claimIndex *big.Int, _attackBranch *big.Int, _stateData []byte, _proof FaultDisputeGameStepProof) (*types.Transaction, error) { + return _FaultDisputeGameN.contract.Transact(opts, "stepV2", _claimIndex, _attackBranch, _stateData, _proof) +} + +// StepV2 is a paid mutator transaction binding the contract method 0x175d249c. +// +// Solidity: function stepV2(uint256 _claimIndex, uint256 _attackBranch, bytes _stateData, ((uint256,bytes32,bytes),(uint256,bytes32,bytes),bytes) _proof) returns() +func (_FaultDisputeGameN *FaultDisputeGameNSession) StepV2(_claimIndex *big.Int, _attackBranch *big.Int, _stateData []byte, _proof FaultDisputeGameStepProof) (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.StepV2(&_FaultDisputeGameN.TransactOpts, _claimIndex, _attackBranch, _stateData, _proof) +} + +// StepV2 is a paid mutator transaction binding the contract method 0x175d249c. +// +// Solidity: function stepV2(uint256 _claimIndex, uint256 _attackBranch, bytes _stateData, ((uint256,bytes32,bytes),(uint256,bytes32,bytes),bytes) _proof) returns() +func (_FaultDisputeGameN *FaultDisputeGameNTransactorSession) StepV2(_claimIndex *big.Int, _attackBranch *big.Int, _stateData []byte, _proof FaultDisputeGameStepProof) (*types.Transaction, error) { + return _FaultDisputeGameN.Contract.StepV2(&_FaultDisputeGameN.TransactOpts, _claimIndex, _attackBranch, _stateData, _proof) +} + +// FaultDisputeGameNMoveIterator is returned from FilterMove and is used to iterate over the raw logs and unpacked data for Move events raised by the FaultDisputeGameN contract. +type FaultDisputeGameNMoveIterator struct { + Event *FaultDisputeGameNMove // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FaultDisputeGameNMoveIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FaultDisputeGameNMove) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FaultDisputeGameNMove) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FaultDisputeGameNMoveIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FaultDisputeGameNMoveIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FaultDisputeGameNMove represents a Move event raised by the FaultDisputeGameN contract. +type FaultDisputeGameNMove struct { + ParentIndex *big.Int + Claim [32]byte + Claimant common.Address + Raw types.Log // Blockchain specific contextual infos +} + +// FilterMove is a free log retrieval operation binding the contract event 0x9b3245740ec3b155098a55be84957a4da13eaf7f14a8bc6f53126c0b9350f2be. +// +// Solidity: event Move(uint256 indexed parentIndex, bytes32 indexed claim, address indexed claimant) +func (_FaultDisputeGameN *FaultDisputeGameNFilterer) FilterMove(opts *bind.FilterOpts, parentIndex []*big.Int, claim [][32]byte, claimant []common.Address) (*FaultDisputeGameNMoveIterator, error) { + + var parentIndexRule []interface{} + for _, parentIndexItem := range parentIndex { + parentIndexRule = append(parentIndexRule, parentIndexItem) + } + var claimRule []interface{} + for _, claimItem := range claim { + claimRule = append(claimRule, claimItem) + } + var claimantRule []interface{} + for _, claimantItem := range claimant { + claimantRule = append(claimantRule, claimantItem) + } + + logs, sub, err := _FaultDisputeGameN.contract.FilterLogs(opts, "Move", parentIndexRule, claimRule, claimantRule) + if err != nil { + return nil, err + } + return &FaultDisputeGameNMoveIterator{contract: _FaultDisputeGameN.contract, event: "Move", logs: logs, sub: sub}, nil +} + +// WatchMove is a free log subscription operation binding the contract event 0x9b3245740ec3b155098a55be84957a4da13eaf7f14a8bc6f53126c0b9350f2be. +// +// Solidity: event Move(uint256 indexed parentIndex, bytes32 indexed claim, address indexed claimant) +func (_FaultDisputeGameN *FaultDisputeGameNFilterer) WatchMove(opts *bind.WatchOpts, sink chan<- *FaultDisputeGameNMove, parentIndex []*big.Int, claim [][32]byte, claimant []common.Address) (event.Subscription, error) { + + var parentIndexRule []interface{} + for _, parentIndexItem := range parentIndex { + parentIndexRule = append(parentIndexRule, parentIndexItem) + } + var claimRule []interface{} + for _, claimItem := range claim { + claimRule = append(claimRule, claimItem) + } + var claimantRule []interface{} + for _, claimantItem := range claimant { + claimantRule = append(claimantRule, claimantItem) + } + + logs, sub, err := _FaultDisputeGameN.contract.WatchLogs(opts, "Move", parentIndexRule, claimRule, claimantRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FaultDisputeGameNMove) + if err := _FaultDisputeGameN.contract.UnpackLog(event, "Move", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseMove is a log parse operation binding the contract event 0x9b3245740ec3b155098a55be84957a4da13eaf7f14a8bc6f53126c0b9350f2be. +// +// Solidity: event Move(uint256 indexed parentIndex, bytes32 indexed claim, address indexed claimant) +func (_FaultDisputeGameN *FaultDisputeGameNFilterer) ParseMove(log types.Log) (*FaultDisputeGameNMove, error) { + event := new(FaultDisputeGameNMove) + if err := _FaultDisputeGameN.contract.UnpackLog(event, "Move", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + +// FaultDisputeGameNResolvedIterator is returned from FilterResolved and is used to iterate over the raw logs and unpacked data for Resolved events raised by the FaultDisputeGameN contract. +type FaultDisputeGameNResolvedIterator struct { + Event *FaultDisputeGameNResolved // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *FaultDisputeGameNResolvedIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(FaultDisputeGameNResolved) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(FaultDisputeGameNResolved) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *FaultDisputeGameNResolvedIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *FaultDisputeGameNResolvedIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// FaultDisputeGameNResolved represents a Resolved event raised by the FaultDisputeGameN contract. +type FaultDisputeGameNResolved struct { + Status uint8 + Raw types.Log // Blockchain specific contextual infos +} + +// FilterResolved is a free log retrieval operation binding the contract event 0x5e186f09b9c93491f14e277eea7faa5de6a2d4bda75a79af7a3684fbfb42da60. +// +// Solidity: event Resolved(uint8 indexed status) +func (_FaultDisputeGameN *FaultDisputeGameNFilterer) FilterResolved(opts *bind.FilterOpts, status []uint8) (*FaultDisputeGameNResolvedIterator, error) { + + var statusRule []interface{} + for _, statusItem := range status { + statusRule = append(statusRule, statusItem) + } + + logs, sub, err := _FaultDisputeGameN.contract.FilterLogs(opts, "Resolved", statusRule) + if err != nil { + return nil, err + } + return &FaultDisputeGameNResolvedIterator{contract: _FaultDisputeGameN.contract, event: "Resolved", logs: logs, sub: sub}, nil +} + +// WatchResolved is a free log subscription operation binding the contract event 0x5e186f09b9c93491f14e277eea7faa5de6a2d4bda75a79af7a3684fbfb42da60. +// +// Solidity: event Resolved(uint8 indexed status) +func (_FaultDisputeGameN *FaultDisputeGameNFilterer) WatchResolved(opts *bind.WatchOpts, sink chan<- *FaultDisputeGameNResolved, status []uint8) (event.Subscription, error) { + + var statusRule []interface{} + for _, statusItem := range status { + statusRule = append(statusRule, statusItem) + } + + logs, sub, err := _FaultDisputeGameN.contract.WatchLogs(opts, "Resolved", statusRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(FaultDisputeGameNResolved) + if err := _FaultDisputeGameN.contract.UnpackLog(event, "Resolved", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseResolved is a log parse operation binding the contract event 0x5e186f09b9c93491f14e277eea7faa5de6a2d4bda75a79af7a3684fbfb42da60. +// +// Solidity: event Resolved(uint8 indexed status) +func (_FaultDisputeGameN *FaultDisputeGameNFilterer) ParseResolved(log types.Log) (*FaultDisputeGameNResolved, error) { + event := new(FaultDisputeGameNResolved) + if err := _FaultDisputeGameN.contract.UnpackLog(event, "Resolved", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/op-e2e2/e2eutils/disputegame/output_game_helper.go b/op-e2e2/e2eutils/disputegame/output_game_helper.go index 287fb9b2f06a..aee33917a82f 100644 --- a/op-e2e2/e2eutils/disputegame/output_game_helper.go +++ b/op-e2e2/e2eutils/disputegame/output_game_helper.go @@ -8,12 +8,12 @@ import ( "testing" "time" - "github.com/ethereum-optimism/optimism/op-challenger/game/fault/contracts" - "github.com/ethereum-optimism/optimism/op-challenger/game/fault/preimages" - "github.com/ethereum-optimism/optimism/op-challenger/game/fault/trace/outputs" - "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types" - keccakTypes "github.com/ethereum-optimism/optimism/op-challenger/game/keccak/types" - gameTypes "github.com/ethereum-optimism/optimism/op-challenger/game/types" + "github.com/ethereum-optimism/optimism/op-challenger2/game/fault/contracts" + "github.com/ethereum-optimism/optimism/op-challenger2/game/fault/preimages" + "github.com/ethereum-optimism/optimism/op-challenger2/game/fault/trace/outputs" + "github.com/ethereum-optimism/optimism/op-challenger2/game/fault/types" + keccakTypes "github.com/ethereum-optimism/optimism/op-challenger2/game/keccak/types" + gameTypes "github.com/ethereum-optimism/optimism/op-challenger2/game/types" "github.com/ethereum-optimism/optimism/op-e2e2/bindings" "github.com/ethereum-optimism/optimism/op-e2e2/e2eutils/wait" preimage "github.com/ethereum-optimism/optimism/op-preimage" @@ -34,15 +34,19 @@ type OutputGameHelper struct { Client *ethclient.Client Opts *bind.TransactOpts Game contracts.FaultDisputeGameContract - GameBindings *bindings.FaultDisputeGame + GameBindings *bindings.FaultDisputeGameN FactoryAddr common.Address Addr common.Address CorrectOutputProvider *outputs.OutputTraceProvider System DisputeSystem + DaType *big.Int + Nbits uint64 } func NewOutputGameHelper(t *testing.T, require *require.Assertions, client *ethclient.Client, opts *bind.TransactOpts, - game contracts.FaultDisputeGameContract, gameBindings *bindings.FaultDisputeGame, factoryAddr common.Address, addr common.Address, correctOutputProvider *outputs.OutputTraceProvider, system DisputeSystem) *OutputGameHelper { + game contracts.FaultDisputeGameContract, gameBindings *bindings.FaultDisputeGameN, factoryAddr common.Address, addr common.Address, correctOutputProvider *outputs.OutputTraceProvider, system DisputeSystem, datype int64) *OutputGameHelper { + nbits, err := game.GetNBits(context.Background()) + require.NoError(err, "fail to load nbits from contract") return &OutputGameHelper{ T: t, Require: require, @@ -54,6 +58,8 @@ func NewOutputGameHelper(t *testing.T, require *require.Assertions, client *ethc Addr: addr, CorrectOutputProvider: correctOutputProvider, System: system, + DaType: big.NewInt(datype), + Nbits: nbits, } } @@ -146,7 +152,11 @@ func (g *OutputGameHelper) DisputeBlock(ctx context.Context, disputeBlockNum uin g.Require.NoError(err, "failed to calculate parent claim block number") if parentClaimBlockNum >= disputeBlockNum { pos = pos.Attack() - claim = claim.Attack(ctx, getClaimValue(claim, pos)) + subValues := []common.Hash{} + for i := 0; i < 1< GENESIS + 1` - function test_addLocalDataGenesisTransition_static_succeeds() public { + function test_addLocalData2GenesisTransition_static_succeeds() public { IPreimageOracle oracle = IPreimageOracle(address(gameProxy.vm().oracle())); Claim disputed; Claim[] memory claims = generateClaims(3); @@ -2001,9 +2001,9 @@ contract FaultDisputeGameN_Test is FaultDisputeGame_Init { bytes32 key = _getKey(i, keccak256(abi.encode(disputedClaim.raw(), disputedPos))); if (LocalPreimageKey.DISPUTED_OUTPUT_ROOT == i) { - gameProxy.addLocalData(i, 3, 0, disputedDataItem); + gameProxy.addLocalData2(i, 3, 0, disputedDataItem); } else { - gameProxy.addLocalData(i, 3, 0, startingDataItem); + gameProxy.addLocalData2(i, 3, 0, startingDataItem); } (bytes32 dat, uint256 datLen) = oracle.readPreimage(key, 0); assertEq(dat >> 0xC0, bytes32(expectedLen)); @@ -2015,9 +2015,9 @@ contract FaultDisputeGameN_Test is FaultDisputeGame_Init { assertEq(datLen, expectedLen + (i > 3 ? 8 : 0)); if (LocalPreimageKey.DISPUTED_OUTPUT_ROOT == i) { - gameProxy.addLocalData(i, 3, 8, disputedDataItem); + gameProxy.addLocalData2(i, 3, 8, disputedDataItem); } else { - gameProxy.addLocalData(i, 3, 8, startingDataItem); + gameProxy.addLocalData2(i, 3, 8, startingDataItem); } (dat, datLen) = oracle.readPreimage(key, 8); assertEq(dat, data[i - 1]); @@ -2026,7 +2026,7 @@ contract FaultDisputeGameN_Test is FaultDisputeGame_Init { } /// @dev Tests that local data is loaded into the preimage oracle correctly. - function test_addLocalDataMiddle_static_succeeds() public { + function test_addLocalData2Middle_static_succeeds() public { IPreimageOracle oracle = IPreimageOracle(address(gameProxy.vm().oracle())); Claim[] memory claims = generateClaims(3); Claim root = Claim.wrap( @@ -2073,9 +2073,9 @@ contract FaultDisputeGameN_Test is FaultDisputeGame_Init { bytes32 key = _getKey(i, keccak256(abi.encode(root.raw(), startingPos, root.raw(), disputedPos))); if (LocalPreimageKey.DISPUTED_OUTPUT_ROOT == i) { - gameProxy.addLocalData(i, 3, 0, disputedDataItem); + gameProxy.addLocalData2(i, 3, 0, disputedDataItem); } else { - gameProxy.addLocalData(i, 3, 0, startingDataItem); + gameProxy.addLocalData2(i, 3, 0, startingDataItem); } (bytes32 dat, uint256 datLen) = oracle.readPreimage(key, 0); assertEq(dat >> 0xC0, bytes32(expectedLen)); @@ -2087,9 +2087,9 @@ contract FaultDisputeGameN_Test is FaultDisputeGame_Init { assertEq(datLen, expectedLen + (i > 3 ? 8 : 0)); if (LocalPreimageKey.DISPUTED_OUTPUT_ROOT == i) { - gameProxy.addLocalData(i, 3, 8, disputedDataItem); + gameProxy.addLocalData2(i, 3, 8, disputedDataItem); } else { - gameProxy.addLocalData(i, 3, 8, startingDataItem); + gameProxy.addLocalData2(i, 3, 8, startingDataItem); } (dat, datLen) = oracle.readPreimage(key, 8); assertEq(dat, data[i - 1]); @@ -2262,7 +2262,7 @@ contract FaultDisputeGameN_Test is FaultDisputeGame_Init { LibDA.DAItem memory dummyDataItem = LibDA.DAItem({ daType: LibDA.DA_TYPE_CALLDATA, dataHash: _dummyClaim().raw(), proof: hex"" }); - gameProxy.addLocalData(LocalPreimageKey.DISPUTED_L2_BLOCK_NUMBER, 4, 2, dummyDataItem); + gameProxy.addLocalData2(LocalPreimageKey.DISPUTED_L2_BLOCK_NUMBER, 4, 2, dummyDataItem); LibDA.DAItem memory preStateItem = LibDA.DAItem({ daType: LibDA.DA_TYPE_CALLDATA, @@ -2357,7 +2357,7 @@ contract FaultDisputeGameN_LessSplitDepth_Test is FaultDisputeGame_Init { FaultDisputeGame.StepProof memory stepProof = FaultDisputeGame.StepProof({ preStateItem: preStateItem, postStateItem: postStateItem, vmProof: hex"" }); - gameProxy.addLocalData(LocalPreimageKey.DISPUTED_L2_BLOCK_NUMBER, 4, 3, preStateItem); + gameProxy.addLocalData2(LocalPreimageKey.DISPUTED_L2_BLOCK_NUMBER, 4, 3, preStateItem); gameProxy.stepV2({ _claimIndex: 4, _attackBranch: 3, _stateData: claimData6, _proof: stepProof }); } @@ -2411,7 +2411,7 @@ contract FaultDisputeGameN_LessSplitDepth_Test is FaultDisputeGame_Init { FaultDisputeGame.StepProof memory stepProof = FaultDisputeGame.StepProof({ preStateItem: preStateItem, postStateItem: postStateItem, vmProof: hex"" }); - gameProxy.addLocalData(LocalPreimageKey.DISPUTED_L2_BLOCK_NUMBER, 4, 3, preStateItem); + gameProxy.addLocalData2(LocalPreimageKey.DISPUTED_L2_BLOCK_NUMBER, 4, 3, preStateItem); vm.expectRevert(ValidStep.selector); gameProxy.stepV2({ _claimIndex: 4, _attackBranch: 3, _stateData: claimData6, _proof: stepProof }); } @@ -2464,7 +2464,7 @@ contract FaultDisputeGameN_LessSplitDepth_Test is FaultDisputeGame_Init { FaultDisputeGame.StepProof memory stepProof = FaultDisputeGame.StepProof({ preStateItem: preStateItem, postStateItem: postStateItem, vmProof: hex"" }); - gameProxy.addLocalData(LocalPreimageKey.DISPUTED_L2_BLOCK_NUMBER, 4, 3, preStateItem); + gameProxy.addLocalData2(LocalPreimageKey.DISPUTED_L2_BLOCK_NUMBER, 4, 3, preStateItem); gameProxy.stepV2({ _claimIndex: 4, _attackBranch: 3, _stateData: claimData6, _proof: stepProof }); } From 2716b1ec6a5a83e67d2c51ebdcb7a03fda0cab62 Mon Sep 17 00:00:00 2001 From: Po Date: Sat, 30 Nov 2024 11:33:41 +0800 Subject: [PATCH 14/16] fix: VMStateRoot only has one subValue --- op-challenger2/game/fault/agent.go | 2 +- .../fault/contracts/faultdisputegame_test.go | 14 ----- .../game/fault/solver/game_solver_test.go | 7 +++ .../game/fault/solver/solver_test.go | 55 +++++++++++-------- .../game/fault/test/claim_builder.go | 16 +----- .../game/fault/test/game_builder.go | 2 +- op-challenger2/game/fault/trace/access.go | 4 +- 7 files changed, 46 insertions(+), 54 deletions(-) diff --git a/op-challenger2/game/fault/agent.go b/op-challenger2/game/fault/agent.go index 42d9195e8de8..609e848eb911 100644 --- a/op-challenger2/game/fault/agent.go +++ b/op-challenger2/game/fault/agent.go @@ -133,7 +133,7 @@ func (a *Agent) performAction(ctx context.Context, wg *sync.WaitGroup, action ty if action.OracleData != nil { actionLog = actionLog.New("oracleKey", common.Bytes2Hex(action.OracleData.OracleKey)) } - } else if action.Type == types.ActionTypeMove { + } else if action.Type == types.ActionTypeAttackV2 { actionLog = actionLog.New("attackBranch", action.AttackBranch, "parent", action.ParentClaim.ContractIndex, "value", action.Value) } diff --git a/op-challenger2/game/fault/contracts/faultdisputegame_test.go b/op-challenger2/game/fault/contracts/faultdisputegame_test.go index f83517276d88..e7313bd290cc 100644 --- a/op-challenger2/game/fault/contracts/faultdisputegame_test.go +++ b/op-challenger2/game/fault/contracts/faultdisputegame_test.go @@ -481,20 +481,6 @@ func TestGetBlockRange(t *testing.T) { } } -func TestGetSplitDepth(t *testing.T) { - for _, version := range versions { - version := version - t.Run(version.version, func(t *testing.T) { - stubRpc, contract := setupFaultDisputeGameTest(t, version) - expectedSplitDepth := faultTypes.Depth(15) - 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) { for _, version := range versions { version := version diff --git a/op-challenger2/game/fault/solver/game_solver_test.go b/op-challenger2/game/fault/solver/game_solver_test.go index 58de94bc544b..970a3286497b 100644 --- a/op-challenger2/game/fault/solver/game_solver_test.go +++ b/op-challenger2/game/fault/solver/game_solver_test.go @@ -454,6 +454,13 @@ func TestCalculateNextActions(t *testing.T) { } t.Logf("Expect %v: Type: %v, Position: %v, ParentIdx: %v, Branch: %v, Value: %v, SubValues: %v, PreState: %v, ProofData: %v", i, action.Type, action.ParentClaim.Position, action.ParentClaim.ContractIndex, action.AttackBranch, action.Value, action.SubValues, hex.EncodeToString(action.PreState), hex.EncodeToString(action.ProofData)) + // Datype don't need to be compared, because it's set in solver not in getStepData2. + if action.OracleData != nil { + action.OracleData.VMStateDA.PreDA.DaType = types.CallDataType + action.OracleData.VMStateDA.PostDA.DaType = types.CallDataType + action.OracleData.OutputRootDAItem.DaType = types.CallDataType + + } require.Containsf(t, actions, action, "Expected claim %v missing", i) } require.Len(t, actions, len(builder.ExpectedActions), "Incorrect number of actions") diff --git a/op-challenger2/game/fault/solver/solver_test.go b/op-challenger2/game/fault/solver/solver_test.go index 5a0e1f595cc1..7ce1049419b3 100644 --- a/op-challenger2/game/fault/solver/solver_test.go +++ b/op-challenger2/game/fault/solver/solver_test.go @@ -51,8 +51,8 @@ func TestAttemptStepNary2(t *testing.T) { expectProofData: claimBuilder.CorrectProofData(common.Big0), expectedOracleData: claimBuilder.CorrectOracleData(common.Big0), expectedVMStateData: &types.DAData{ - PreDA: types.DAItem{DataHash: absolutePrestate}, - PostDA: types.DAItem{DataHash: common.Hash{0xbb}}, + PreDA: types.DAItem{DaType: types.CallDataType, DataHash: absolutePrestate}, + PostDA: types.DAItem{DaType: types.CallDataType, DataHash: common.Hash{0xbb}}, }, setupGame: func(builder *faulttest.GameBuilder) { builder.Seq(). @@ -72,8 +72,8 @@ func TestAttemptStepNary2(t *testing.T) { expectProofData: claimBuilder.CorrectProofData(big.NewInt(1)), expectedOracleData: claimBuilder.CorrectOracleData(big.NewInt(1)), expectedVMStateData: &types.DAData{ - PreDA: types.DAItem{DataHash: claimBuilder.CorrectClaimAtPosition(types.NewPosition(types.Depth(7), common.Big0))}, - PostDA: types.DAItem{DataHash: claimBuilder.CorrectClaimAtPosition(types.NewPosition(types.Depth(7), common.Big1))}, + PreDA: types.DAItem{DaType: types.CallDataType, DataHash: claimBuilder.CorrectClaimAtPosition(types.NewPosition(types.Depth(7), common.Big0))}, + PostDA: types.DAItem{DaType: types.CallDataType, DataHash: claimBuilder.CorrectClaimAtPosition(types.NewPosition(types.Depth(7), common.Big1))}, }, setupGame: func(builder *faulttest.GameBuilder) { builder.Seq(). @@ -93,8 +93,8 @@ func TestAttemptStepNary2(t *testing.T) { expectProofData: claimBuilder.CorrectProofData(big.NewInt(4)), expectedOracleData: claimBuilder.CorrectOracleData(big.NewInt(4)), expectedVMStateData: &types.DAData{ - PreDA: types.DAItem{DataHash: claimBuilder.CorrectClaimAtPosition(types.NewPosition(types.Depth(5), big.NewInt(0)))}, - PostDA: types.DAItem{DataHash: common.Hash{0xaa}}, + PreDA: types.DAItem{DaType: types.CallDataType, DataHash: claimBuilder.CorrectClaimAtPosition(types.NewPosition(types.Depth(5), big.NewInt(0)))}, + PostDA: types.DAItem{DaType: types.CallDataType, DataHash: common.Hash{0xaa}}, }, setupGame: func(builder *faulttest.GameBuilder) { builder.Seq(). @@ -114,8 +114,8 @@ func TestAttemptStepNary2(t *testing.T) { expectProofData: claimBuilder.CorrectProofData(big.NewInt(5)), expectedOracleData: claimBuilder.CorrectOracleData(big.NewInt(5)), expectedVMStateData: &types.DAData{ - PreDA: types.DAItem{DataHash: claimBuilder.CorrectClaimAtPosition(types.NewPosition(types.Depth(7), big.NewInt(4)))}, - PostDA: types.DAItem{DataHash: claimBuilder.CorrectClaimAtPosition(types.NewPosition(types.Depth(6), big.NewInt(2)))}, + PreDA: types.DAItem{DaType: types.CallDataType, DataHash: claimBuilder.CorrectClaimAtPosition(types.NewPosition(types.Depth(7), big.NewInt(4)))}, + PostDA: types.DAItem{DaType: types.CallDataType, DataHash: claimBuilder.CorrectClaimAtPosition(types.NewPosition(types.Depth(6), big.NewInt(2)))}, }, setupGame: func(builder *faulttest.GameBuilder) { builder.Seq(). @@ -135,8 +135,8 @@ func TestAttemptStepNary2(t *testing.T) { expectProofData: claimBuilder.CorrectProofData(lastLeafTraceIndex), expectedOracleData: claimBuilder.CorrectOracleData(lastLeafTraceIndex), expectedVMStateData: &types.DAData{ - PreDA: types.DAItem{DataHash: claimBuilder.CorrectClaimAtPosition(types.NewPosition(types.Depth(6), common.Big2))}, - PostDA: types.DAItem{DataHash: common.Hash{0xaa}}, + PreDA: types.DAItem{DaType: types.CallDataType, DataHash: claimBuilder.CorrectClaimAtPosition(types.NewPosition(types.Depth(6), common.Big2))}, + PostDA: types.DAItem{DaType: types.CallDataType, DataHash: common.Hash{0xaa}}, }, setupGame: func(builder *faulttest.GameBuilder) { builder.Seq(). @@ -156,8 +156,8 @@ func TestAttemptStepNary2(t *testing.T) { expectProofData: claimBuilder.CorrectProofData(lastLeafTraceIndexPlusOne), expectedOracleData: claimBuilder.CorrectOracleData(lastLeafTraceIndexPlusOne), expectedVMStateData: &types.DAData{ - PreDA: types.DAItem{DataHash: claimBuilder.CorrectClaimAtPosition(types.NewPosition(types.Depth(7), big.NewInt(6)))}, - PostDA: types.DAItem{DataHash: claimBuilder.CorrectClaimAtPosition(types.NewPosition(types.Depth(4), big.NewInt(0)))}, + PreDA: types.DAItem{DaType: types.CallDataType, DataHash: claimBuilder.CorrectClaimAtPosition(types.NewPosition(types.Depth(7), big.NewInt(6)))}, + PostDA: types.DAItem{DaType: types.CallDataType, DataHash: claimBuilder.CorrectClaimAtPosition(types.NewPosition(types.Depth(4), big.NewInt(0)))}, }, setupGame: func(builder *faulttest.GameBuilder) { builder.Seq(). @@ -310,11 +310,11 @@ func TestAttemptStepNary2WithLocalData(t *testing.T) { name: "DefendFirstTraceIndex", expectedOracleKey: faulttest.LocalDataOracleKeyBytes(oracleKey), expectedVMStateData: &types.DAData{ - PreDA: types.DAItem{DataHash: claimBuilder.CorrectClaimAtPosition(types.NewPosition(types.Depth(7), common.Big0))}, - PostDA: types.DAItem{DataHash: claimBuilder.CorrectClaimAtPosition(types.NewPosition(types.Depth(7), common.Big1))}, + PreDA: types.DAItem{DaType: types.CallDataType, DataHash: claimBuilder.CorrectClaimAtPosition(types.NewPosition(types.Depth(7), common.Big0))}, + PostDA: types.DAItem{DaType: types.CallDataType, DataHash: claimBuilder.CorrectClaimAtPosition(types.NewPosition(types.Depth(7), common.Big1))}, }, expectedLocalData: &types.DAItem{ - DaType: callDataType, + DaType: types.CallDataType, DataHash: claimBuilder.CorrectClaimAtPosition(types.NewPosition(types.Depth(3), common.Big0)), }, setupGame: func(builder *faulttest.GameBuilder) { @@ -402,13 +402,14 @@ func TestAttemptStepNary4(t *testing.T) { expectProofData: claimBuilder.CorrectProofData(common.Big0), expectedOracleData: claimBuilder.CorrectOracleData(common.Big0), expectedVMStateData: &types.DAData{ - PreDA: types.DAItem{DataHash: absolutePrestate}, + PreDA: types.DAItem{DaType: types.CallDataType, DataHash: absolutePrestate}, PostDA: types.DAItem{ + DaType: types.CallDataType, DataHash: common.Hash{0x81}, Proof: append(common.Hash{0x82}.Bytes(), common.Hash{0x83}.Bytes()...), }, }, - expectedLocalData: &types.DAItem{}, + expectedLocalData: &types.DAItem{DaType: types.CallDataType}, setupGame: func(builder *faulttest.GameBuilder) { builder.Seq(). Attack2(nil, 0). // splitDepth @@ -427,6 +428,7 @@ func TestAttemptStepNary4(t *testing.T) { expectedOracleData: claimBuilder.CorrectOracleData(big.NewInt(4)), expectedVMStateData: &types.DAData{ PreDA: types.DAItem{ + DaType: types.CallDataType, DataHash: claimAt(types.NewPosition(types.Depth(6), common.Big0)), Proof: append( claimAt(types.NewPosition(types.Depth(6), common.Big1)).Bytes(), @@ -434,11 +436,12 @@ func TestAttemptStepNary4(t *testing.T) { ), }, PostDA: types.DAItem{ + DaType: types.CallDataType, DataHash: common.Hash{0x81}, Proof: append(common.Hash{0x82}.Bytes(), common.Hash{0x83}.Bytes()...), }, }, - expectedLocalData: &types.DAItem{}, + expectedLocalData: &types.DAItem{DaType: types.CallDataType}, setupGame: func(builder *faulttest.GameBuilder) { builder.Seq(). Attack2(nil, 0). // splitDepth @@ -457,10 +460,12 @@ func TestAttemptStepNary4(t *testing.T) { expectedOracleData: claimBuilder.CorrectOracleData(big.NewInt(6)), expectedVMStateData: &types.DAData{ PreDA: types.DAItem{ + DaType: types.CallDataType, DataHash: claimAt(types.NewPosition(types.Depth(8), big.NewInt(5))), Proof: append(claimAt(types.NewPosition(types.Depth(8), big.NewInt(4))).Bytes(), common.Hash{0x83}.Bytes()...), }, PostDA: types.DAItem{ + DaType: types.CallDataType, DataHash: common.Hash{0x83}, Proof: crypto.Keccak256( claimAt(types.NewPosition(types.Depth(8), big.NewInt(4))).Bytes(), @@ -468,7 +473,7 @@ func TestAttemptStepNary4(t *testing.T) { ), }, }, - expectedLocalData: &types.DAItem{}, + expectedLocalData: &types.DAItem{DaType: types.CallDataType}, setupGame: func(builder *faulttest.GameBuilder) { builder.Seq(). Attack2(nil, 0). // splitDepth @@ -491,6 +496,7 @@ func TestAttemptStepNary4(t *testing.T) { expectedOracleData: claimBuilder.CorrectOracleData(big.NewInt(7)), expectedVMStateData: &types.DAData{ PreDA: types.DAItem{ + DaType: types.CallDataType, DataHash: claimAt(types.NewPosition(types.Depth(8), big.NewInt(6))), Proof: crypto.Keccak256( claimAt(types.NewPosition(types.Depth(8), big.NewInt(4))).Bytes(), @@ -498,6 +504,7 @@ func TestAttemptStepNary4(t *testing.T) { ), }, PostDA: types.DAItem{ + DaType: types.CallDataType, DataHash: claimAt(types.NewPosition(types.Depth(6), common.Big1)), Proof: append( claimAt(types.NewPosition(types.Depth(6), common.Big0)).Bytes(), @@ -505,7 +512,7 @@ func TestAttemptStepNary4(t *testing.T) { ), }, }, - expectedLocalData: &types.DAItem{}, + expectedLocalData: &types.DAItem{DaType: types.CallDataType}, setupGame: func(builder *faulttest.GameBuilder) { builder.Seq(). Attack2(nil, 0). // splitDepth @@ -528,6 +535,7 @@ func TestAttemptStepNary4(t *testing.T) { expectedOracleData: claimBuilder.CorrectOracleData(big.NewInt(15)), expectedVMStateData: &types.DAData{ PreDA: types.DAItem{ + DaType: types.CallDataType, DataHash: claimAt(types.NewPosition(types.Depth(8), big.NewInt(14))), Proof: crypto.Keccak256( claimAt(types.NewPosition(types.Depth(8), big.NewInt(12))).Bytes(), @@ -535,10 +543,11 @@ func TestAttemptStepNary4(t *testing.T) { ), }, PostDA: types.DAItem{ - DataHash: contracts.SubValuesHash(append([]common.Hash{}, claimAt(types.NewPosition(types.Depth(4), common.Big0)), common.Hash{}, common.Hash{})), + DaType: types.CallDataType, + DataHash: contracts.SubValuesHash([]common.Hash{claimAt(types.NewPosition(types.Depth(4), common.Big0))}), }, }, - expectedLocalData: &types.DAItem{}, + expectedLocalData: &types.DAItem{DaType: types.CallDataType}, setupGame: func(builder *faulttest.GameBuilder) { builder.Seq(). Attack2(nil, 0). // splitDepth @@ -576,6 +585,8 @@ func TestAttemptStepNary4(t *testing.T) { require.ErrorIs(t, err, tableTest.expectedErr) _, _, preimage, err := accessor.GetStepData2(ctx, game, lastClaim, lastClaim.MoveRightN(tableTest.expectAttackBranch)) require.NoError(t, err) + preimage.VMStateDA.PreDA.DaType = types.CallDataType + preimage.VMStateDA.PostDA.DaType = types.CallDataType if !tableTest.expectNoStep && tableTest.expectedErr == nil { require.NotNil(t, step) require.Equal(t, lastClaim, step.LeafClaim) diff --git a/op-challenger2/game/fault/test/claim_builder.go b/op-challenger2/game/fault/test/claim_builder.go index 38cbf021105b..c2b27a61d018 100644 --- a/op-challenger2/game/fault/test/claim_builder.go +++ b/op-challenger2/game/fault/test/claim_builder.go @@ -172,20 +172,8 @@ func (c *ClaimBuilder) claim(pos types.Position, opts ...ClaimOpt) types.Claim { claim.Value = contracts.SubValuesHash(*claim.SubValues) } else { values := []common.Hash{} - if pos.IsRootPosition() { - if cfg.invalidValue { - values = append(values, c.incorrectClaim(pos)) - } else { - values = append(values, c.CorrectClaimAtPosition(pos)) - } - for i := uint64(0); i < c.MaxAttackBranch()-1; i++ { - values = append(values, common.Hash{}) - } - } else if pos.Depth() == c.splitDepth+types.Depth(c.nbits) { + if pos.IsRootPosition() || pos.Depth() == c.splitDepth+types.Depth(c.nbits) { values = append(values, c.CorrectClaimAtPosition(pos)) - for i := uint64(0); i < c.MaxAttackBranch()-1; i++ { - values = append(values, common.Hash{}) - } } else { for i := uint64(0); i < c.MaxAttackBranch(); i++ { pos := pos.MoveRightN(i) @@ -193,7 +181,7 @@ func (c *ClaimBuilder) claim(pos types.Position, opts ...ClaimOpt) types.Claim { } } claim.SubValues = &values - claim.Value = contracts.SubValuesHash(*claim.SubValues) + claim.Value = contracts.SubValuesHash(values) } claim.ParentContractIndex = cfg.parentIdx return claim diff --git a/op-challenger2/game/fault/test/game_builder.go b/op-challenger2/game/fault/test/game_builder.go index e683620563e2..9842fb3737d7 100644 --- a/op-challenger2/game/fault/test/game_builder.go +++ b/op-challenger2/game/fault/test/game_builder.go @@ -185,7 +185,7 @@ func (s *GameBuilderSeq) ExpectAttackV2(branch uint64) *GameBuilderSeq { for i := uint64(0); i < maxAttackBranch; i++ { tmpPosition := position.MoveRightN(i) if tmpPosition.Depth() == (s.builder.SplitDepth()+types.Depth(nBits)) && i != 0 { - value = common.Hash{} + break } else { value = s.builder.CorrectClaimAtPosition(tmpPosition) } diff --git a/op-challenger2/game/fault/trace/access.go b/op-challenger2/game/fault/trace/access.go index c8e7841ecc68..72dda0849848 100644 --- a/op-challenger2/game/fault/trace/access.go +++ b/op-challenger2/game/fault/trace/access.go @@ -164,20 +164,20 @@ func (t *Accessor) GetStepData2(ctx context.Context, game types.Game, ref types. } preimageData.VMStateDA = stateData + addlocalDataDaItem := types.DAItem{} if preimageData.OracleKey != nil { keyType := preimage.KeyType(preimageData.OracleKey[0]) if keyType == preimage.LocalKeyType { ident := preimageData.GetIdent() - addlocalDataDaItem := types.DAItem{} if ident.Cmp(big.NewInt(types.LocalPreimageKeyStartingOutputRoot)) == 0 { addlocalDataDaItem = outputRootDA.PreDA } else if ident.Cmp(big.NewInt(types.LocalPreimageKeyDisputedOutputRoot)) == 0 { addlocalDataDaItem = outputRootDA.PostDA } - preimageData.OutputRootDAItem = addlocalDataDaItem } } + preimageData.OutputRootDAItem = addlocalDataDaItem return prestate, proofData, preimageData, nil } From 772c2ac7fe92490eed9c18afcdbb4f929d5f8508 Mon Sep 17 00:00:00 2001 From: Po Date: Sat, 30 Nov 2024 21:49:56 +0800 Subject: [PATCH 15/16] op-challenger2: cosmatic and pass all tests --- .../game/fault/responder/responder_test.go | 2 +- .../game/fault/solver/game_solver_test.go | 50 +++++++++---------- op-challenger2/game/fault/solver/solver.go | 5 +- .../game/fault/test/claim_builder.go | 2 +- 4 files changed, 30 insertions(+), 29 deletions(-) diff --git a/op-challenger2/game/fault/responder/responder_test.go b/op-challenger2/game/fault/responder/responder_test.go index c9dc5b1f7e35..2f8538118774 100644 --- a/op-challenger2/game/fault/responder/responder_test.go +++ b/op-challenger2/game/fault/responder/responder_test.go @@ -169,7 +169,7 @@ func TestPerformAction(t *testing.T) { require.Equal(t, ([]byte)("attackV2"), mockTxMgr.sent[0].TxData) }) - t.Run("step", func(t *testing.T) { + t.Run("stepV2", func(t *testing.T) { responder, mockTxMgr, contract, _, _ := newTestFaultResponder(t) action := types.Action{ Type: types.ActionTypeStep, diff --git a/op-challenger2/game/fault/solver/game_solver_test.go b/op-challenger2/game/fault/solver/game_solver_test.go index 970a3286497b..7d83c31e2f77 100644 --- a/op-challenger2/game/fault/solver/game_solver_test.go +++ b/op-challenger2/game/fault/solver/game_solver_test.go @@ -250,9 +250,9 @@ func TestCalculateNextActions(t *testing.T) { honest := builder.Seq() honest.Attack2(nil, 0).ExpectAttackV2(3) honest.Attack2(values, 0).ExpectAttackV2(0) - values = claimBuilder.GetClaimsAtPosition(builder.Game.RootClaim().Position.MoveN(nbits, 0), []uint64{1}) + values = claimBuilder.GetCorrectClaimsAndInvalidClaimAtIndex(builder.Game.RootClaim().Position.MoveN(nbits, 0), []uint64{1}) honest.Attack2(values, 0).ExpectAttackV2(1) - values = claimBuilder.GetClaimsAtPosition(builder.Game.RootClaim().Position.MoveN(nbits, 0), []uint64{2}) + values = claimBuilder.GetCorrectClaimsAndInvalidClaimAtIndex(builder.Game.RootClaim().Position.MoveN(nbits, 0), []uint64{2}) honest.Attack2(values, 0).ExpectAttackV2(2) }, }, @@ -262,9 +262,9 @@ func TestCalculateNextActions(t *testing.T) { values := []common.Hash{{0x81}, {0x82}, {0x83}} dishonest := builder.Seq().ExpectAttackV2(0) dishonest.Attack2(values, 0).ExpectAttackV2(0) - values = claimBuilder.GetClaimsAtPosition(builder.Game.RootClaim().Position.MoveN(nbits, 0), []uint64{1}) + values = claimBuilder.GetCorrectClaimsAndInvalidClaimAtIndex(builder.Game.RootClaim().Position.MoveN(nbits, 0), []uint64{1}) dishonest.Attack2(values, 0).ExpectAttackV2(1) - values = claimBuilder.GetClaimsAtPosition(builder.Game.RootClaim().Position.MoveN(nbits, 0), []uint64{2}) + values = claimBuilder.GetCorrectClaimsAndInvalidClaimAtIndex(builder.Game.RootClaim().Position.MoveN(nbits, 0), []uint64{2}) dishonest.Attack2(values, 0).ExpectAttackV2(2) }, }, @@ -291,32 +291,32 @@ func TestCalculateNextActions(t *testing.T) { dishonest.Attack2(values, 2).ExpectAttackV2(0) dishonest.Attack2(values, 3).ExpectAttackV2(0) - values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 0), []uint64{0}) + values = claimBuilder.GetCorrectClaimsAndInvalidClaimAtIndex(lastPosition.MoveN(nbits, 0), []uint64{0}) dishonest.Attack2(values, 0).ExpectAttackV2(0) - values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 0), []uint64{1}) + values = claimBuilder.GetCorrectClaimsAndInvalidClaimAtIndex(lastPosition.MoveN(nbits, 0), []uint64{1}) dishonest.Attack2(values, 0).ExpectAttackV2(1) - values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 0), []uint64{2}) + values = claimBuilder.GetCorrectClaimsAndInvalidClaimAtIndex(lastPosition.MoveN(nbits, 0), []uint64{2}) dishonest.Attack2(values, 0).ExpectAttackV2(2) - values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 1), []uint64{0}) + values = claimBuilder.GetCorrectClaimsAndInvalidClaimAtIndex(lastPosition.MoveN(nbits, 1), []uint64{0}) dishonest.Attack2(values, 1).ExpectAttackV2(0) - values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 1), []uint64{1}) + values = claimBuilder.GetCorrectClaimsAndInvalidClaimAtIndex(lastPosition.MoveN(nbits, 1), []uint64{1}) dishonest.Attack2(values, 1).ExpectAttackV2(1) - values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 1), []uint64{2}) + values = claimBuilder.GetCorrectClaimsAndInvalidClaimAtIndex(lastPosition.MoveN(nbits, 1), []uint64{2}) dishonest.Attack2(values, 1).ExpectAttackV2(2) - values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 2), []uint64{0}) + values = claimBuilder.GetCorrectClaimsAndInvalidClaimAtIndex(lastPosition.MoveN(nbits, 2), []uint64{0}) dishonest.Attack2(values, 2).ExpectAttackV2(0) - values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 2), []uint64{1}) + values = claimBuilder.GetCorrectClaimsAndInvalidClaimAtIndex(lastPosition.MoveN(nbits, 2), []uint64{1}) dishonest.Attack2(values, 2).ExpectAttackV2(1) - values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 2), []uint64{2}) + values = claimBuilder.GetCorrectClaimsAndInvalidClaimAtIndex(lastPosition.MoveN(nbits, 2), []uint64{2}) dishonest.Attack2(values, 2).ExpectAttackV2(2) - values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 3), []uint64{0}) + values = claimBuilder.GetCorrectClaimsAndInvalidClaimAtIndex(lastPosition.MoveN(nbits, 3), []uint64{0}) dishonest.Attack2(values, 3).ExpectAttackV2(0) - values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 3), []uint64{1}) + values = claimBuilder.GetCorrectClaimsAndInvalidClaimAtIndex(lastPosition.MoveN(nbits, 3), []uint64{1}) dishonest.Attack2(values, 3).ExpectAttackV2(1) - values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 3), []uint64{2}) + values = claimBuilder.GetCorrectClaimsAndInvalidClaimAtIndex(lastPosition.MoveN(nbits, 3), []uint64{2}) dishonest.Attack2(values, 3).ExpectAttackV2(2) }, }, @@ -328,11 +328,11 @@ func TestCalculateNextActions(t *testing.T) { honest := builder.Seq() lastPosition := builder.Game.Claims()[len(builder.Game.Claims())-1].Position honest.Attack2(values, 0).Attack2(nil, 0) - values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 0), []uint64{1}) + values = claimBuilder.GetCorrectClaimsAndInvalidClaimAtIndex(lastPosition.MoveN(nbits, 0), []uint64{1}) honest.Attack2(values, 0).ExpectAttackV2(1).Attack2(nil, 0).ExpectAttackV2(3) - values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 0), []uint64{2}) + values = claimBuilder.GetCorrectClaimsAndInvalidClaimAtIndex(lastPosition.MoveN(nbits, 0), []uint64{2}) honest.Attack2(values, 0).ExpectAttackV2(2).Attack2(nil, 0).ExpectAttackV2(3) - values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 0), []uint64{3}) + values = claimBuilder.GetCorrectClaimsAndInvalidClaimAtIndex(lastPosition.MoveN(nbits, 0), []uint64{3}) honest.Attack2(values, 0).ExpectAttackV2(3).Attack2(nil, 0).ExpectAttackV2(3) }, }, @@ -356,7 +356,7 @@ func TestCalculateNextActions(t *testing.T) { Attack2(values, 0). // dishonest Attack2(nil, 0) // honest lastPosition := builder.Game.Claims()[len(builder.Game.Claims())-1].Position - values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 0), []uint64{1}) + values = claimBuilder.GetCorrectClaimsAndInvalidClaimAtIndex(lastPosition.MoveN(nbits, 0), []uint64{1}) lastHonestClaim.Attack2(values, 0).ExpectStepV2(1) }, }, @@ -369,7 +369,7 @@ func TestCalculateNextActions(t *testing.T) { Attack2(values, 0). // dishonest Attack2(nil, 0) // honest lastPosition := builder.Game.Claims()[len(builder.Game.Claims())-1].Position - values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 0), []uint64{2}) + values = claimBuilder.GetCorrectClaimsAndInvalidClaimAtIndex(lastPosition.MoveN(nbits, 0), []uint64{2}) lastHonestClaim.Attack2(values, 0).ExpectStepV2(2) }, }, @@ -382,7 +382,7 @@ func TestCalculateNextActions(t *testing.T) { Attack2(values, 0). // dishonest Attack2(nil, 0) // honest lastPosition := builder.Game.Claims()[len(builder.Game.Claims())-1].Position - values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 0), []uint64{}) + values = claimBuilder.GetCorrectClaimsAndInvalidClaimAtIndex(lastPosition.MoveN(nbits, 0), []uint64{}) lastHonestClaim.Attack2(values, 0).ExpectStepV2(3) }, }, @@ -406,7 +406,7 @@ func TestCalculateNextActions(t *testing.T) { Attack2(values, 1). // dishonest Attack2(nil, 0) // honest lastPosition := builder.Game.Claims()[len(builder.Game.Claims())-1].Position - values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 0), []uint64{1}) + values = claimBuilder.GetCorrectClaimsAndInvalidClaimAtIndex(lastPosition.MoveN(nbits, 0), []uint64{1}) lastHonestClaim.Attack2(values, 0).ExpectStepV2(1) }, }, @@ -419,7 +419,7 @@ func TestCalculateNextActions(t *testing.T) { Attack2(values, 1). // dishonest Attack2(nil, 0) // honest lastPosition := builder.Game.Claims()[len(builder.Game.Claims())-1].Position - values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 0), []uint64{2}) + values = claimBuilder.GetCorrectClaimsAndInvalidClaimAtIndex(lastPosition.MoveN(nbits, 0), []uint64{2}) lastHonestClaim.Attack2(values, 0).ExpectStepV2(2) }, }, @@ -432,7 +432,7 @@ func TestCalculateNextActions(t *testing.T) { Attack2(values, 1). // dishonest Attack2(nil, 0) // honest lastPosition := builder.Game.Claims()[len(builder.Game.Claims())-1].Position - values = claimBuilder.GetClaimsAtPosition(lastPosition.MoveN(nbits, 0), []uint64{}) + values = claimBuilder.GetCorrectClaimsAndInvalidClaimAtIndex(lastPosition.MoveN(nbits, 0), []uint64{}) lastHonestClaim.Attack2(values, 0).ExpectStepV2(3) }, }, diff --git a/op-challenger2/game/fault/solver/solver.go b/op-challenger2/game/fault/solver/solver.go index fcd0843dedf0..392fb9b7cd59 100644 --- a/op-challenger2/game/fault/solver/solver.go +++ b/op-challenger2/game/fault/solver/solver.go @@ -92,6 +92,7 @@ func (s *claimSolver) NextMove(ctx context.Context, claim types.Claim, game type if branch < game.MaxAttackBranch()-1 { return nil, nil } + // if we agree with all subValues, we should attack the maxAttackBranch return s.attackV2(ctx, game, claim, branch+1) } else { return s.attackV2(ctx, game, claim, branch) @@ -132,7 +133,7 @@ func (s *claimSolver) AttemptStep(ctx context.Context, game types.Game, claim ty position = claim.Position.MoveRightN(branch) } else { if branch == game.MaxAttackBranch()-1 { - // If we are at the max attack branch, we need to step on the next branch + // If we agree all subValues ,the maxAttackBranch should be stepped position = claim.Position.MoveRightN(branch + 1) attackBranch = branch + 1 } else { @@ -158,7 +159,7 @@ func (s *claimSolver) AttemptStep(ctx context.Context, game types.Game, claim ty // agreeWithClaim returns true if the claim is correct according to the internal [TraceProvider]. func (s *claimSolver) agreeWithClaimV2(ctx context.Context, game types.Game, claim types.Claim, branch uint64) (bool, error) { if branch >= uint64(len(*claim.SubValues)) { - return true, fmt.Errorf("branch must be lesser than maxAttachBranch") + return true, fmt.Errorf("branch must be less than maxAttachBranch") } ourValue, err := s.trace.Get(ctx, game, claim, claim.Position.MoveRightN(branch)) return bytes.Equal(ourValue[:], (*claim.SubValues)[branch][:]), err diff --git a/op-challenger2/game/fault/test/claim_builder.go b/op-challenger2/game/fault/test/claim_builder.go index c2b27a61d018..ad03903ade00 100644 --- a/op-challenger2/game/fault/test/claim_builder.go +++ b/op-challenger2/game/fault/test/claim_builder.go @@ -229,7 +229,7 @@ func (c *ClaimBuilder) TraceRootDepth() types.Depth { return c.splitDepth + types.Depth(c.nbits) } -func (c *ClaimBuilder) GetClaimsAtPosition(pos types.Position, invalidBranchList []uint64) []common.Hash { +func (c *ClaimBuilder) GetCorrectClaimsAndInvalidClaimAtIndex(pos types.Position, invalidBranchList []uint64) []common.Hash { values := []common.Hash{} if pos.IsRootPosition() { if contains(invalidBranchList, uint64(0)) { From c1513a03f2d67a8a626d038de17bf081efd3b19e Mon Sep 17 00:00:00 2001 From: Po Date: Sat, 30 Nov 2024 22:42:08 +0800 Subject: [PATCH 16/16] test: alphabet game e2etest for MSFDG --- op-e2e2/e2eutils/challenger/helper.go | 13 +++- op-e2e2/e2eutils/challenger/metrics.go | 2 +- op-e2e2/e2eutils/disputegame/claim_helper.go | 24 +++++-- .../e2eutils/disputegame/dishonest_helper.go | 21 +++--- op-e2e2/e2eutils/disputegame/helper.go | 18 ++--- .../disputegame/output_alphabet_helper.go | 4 +- .../disputegame/output_cannon_helper.go | 18 ++--- .../disputegame/output_game_helper.go | 12 +++- .../disputegame/output_honest_helper.go | 48 ++++++------- .../disputegame/preimage/preimage_helper.go | 8 +-- .../faultproofs/challenge_preimage_test.go | 6 +- op-e2e2/faultproofs/multi_test.go | 2 +- op-e2e2/faultproofs/output_alphabet_test.go | 67 ++++++++++++------- op-e2e2/faultproofs/output_cannon_test.go | 64 +++++++++--------- op-e2e2/faultproofs/precompile_test.go | 10 +-- op-e2e2/faultproofs/preimages_test.go | 2 +- .../contracts-bedrock/scripts/Deploy.s.sol | 51 +++++++++----- 17 files changed, 218 insertions(+), 152 deletions(-) diff --git a/op-e2e2/e2eutils/challenger/helper.go b/op-e2e2/e2eutils/challenger/helper.go index 7388629cef18..d5df60d57f83 100644 --- a/op-e2e2/e2eutils/challenger/helper.go +++ b/op-e2e2/e2eutils/challenger/helper.go @@ -19,8 +19,8 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/log" - challenger "github.com/ethereum-optimism/optimism/op-challenger" - "github.com/ethereum-optimism/optimism/op-challenger/config" + challenger "github.com/ethereum-optimism/optimism/op-challenger2" + "github.com/ethereum-optimism/optimism/op-challenger2/config" "github.com/ethereum-optimism/optimism/op-e2e2/e2eutils" "github.com/ethereum-optimism/optimism/op-e2e2/e2eutils/wait" "github.com/ethereum-optimism/optimism/op-node/rollup" @@ -80,6 +80,12 @@ func WithPollInterval(pollInterval time.Duration) Option { } } +func WithDaType(datype int64) Option { + return func(c *config.Config) { + c.DAType = datype + } +} + // FindMonorepoRoot finds the relative path to the monorepo root // Different tests might be nested in subdirectories of the op-e2e dir. func FindMonorepoRoot(t *testing.T) string { @@ -150,7 +156,8 @@ func NewChallengerConfig(t *testing.T, sys EndpointProvider, l2NodeName string, // Use the NewConfig method to ensure we pick up any defaults that are set. l1Endpoint := sys.NodeEndpoint("l1") l1Beacon := sys.L1BeaconEndpoint() - cfg := config.NewConfig(common.Address{}, l1Endpoint, l1Beacon, sys.RollupEndpoint(l2NodeName), sys.NodeEndpoint(l2NodeName), t.TempDir()) + datype := config.DACalldata + cfg := config.NewConfig(common.Address{}, l1Endpoint, l1Beacon, sys.RollupEndpoint(l2NodeName), sys.NodeEndpoint(l2NodeName), t.TempDir(), datype) // The devnet can't set the absolute prestate output root because the contracts are deployed in L1 genesis // before the L2 genesis is known. cfg.AllowInvalidPrestate = true diff --git a/op-e2e2/e2eutils/challenger/metrics.go b/op-e2e2/e2eutils/challenger/metrics.go index de95121480f1..25abaa175690 100644 --- a/op-e2e2/e2eutils/challenger/metrics.go +++ b/op-e2e2/e2eutils/challenger/metrics.go @@ -3,7 +3,7 @@ package challenger import ( "sync/atomic" - "github.com/ethereum-optimism/optimism/op-challenger/metrics" + "github.com/ethereum-optimism/optimism/op-challenger2/metrics" ) type CapturingMetrics struct { diff --git a/op-e2e2/e2eutils/disputegame/claim_helper.go b/op-e2e2/e2eutils/disputegame/claim_helper.go index 0effe44ad843..a44ebd72a2b8 100644 --- a/op-e2e2/e2eutils/disputegame/claim_helper.go +++ b/op-e2e2/e2eutils/disputegame/claim_helper.go @@ -6,7 +6,8 @@ import ( "slices" "time" - "github.com/ethereum-optimism/optimism/op-challenger/game/fault/types" + "github.com/ethereum-optimism/optimism/op-challenger2/game/fault/contracts" + "github.com/ethereum-optimism/optimism/op-challenger2/game/fault/types" "github.com/ethereum-optimism/optimism/op-e2e2/e2eutils/wait" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" @@ -33,7 +34,7 @@ func newClaimHelper(game *OutputGameHelper, idx int64, claim types.Claim) *Claim } func (c *ClaimHelper) AgreesWithOutputRoot() bool { - return c.Position.Depth()%2 == 0 + return c.Position.Depth()%(types.Depth(2*c.game.Nbits)) == 0 } func (c *ClaimHelper) IsRootClaim() bool { @@ -52,7 +53,7 @@ func (c *ClaimHelper) IsOutputRootLeaf(ctx context.Context) bool { func (c *ClaimHelper) IsBottomGameRoot(ctx context.Context) bool { splitDepth := c.game.SplitDepth(ctx) - return c.Position.Depth() == splitDepth+1 + return c.Position.Depth() == splitDepth+types.Depth(c.game.Nbits) } func (c *ClaimHelper) IsMaxDepth(ctx context.Context) bool { @@ -93,8 +94,13 @@ func (c *ClaimHelper) WaitForCountered(ctx context.Context) { func (c *ClaimHelper) RequireCorrectOutputRoot(ctx context.Context) { c.require.True(c.IsOutputRoot(ctx), "Should not expect a valid output root in the bottom game") - expected, err := c.game.CorrectOutputProvider.Get(ctx, c.Position) - c.require.NoError(err, "Failed to get correct output root") + subValues := []common.Hash{} + for i := uint64(0); i < (1<= disputeBlockNum { - pos = pos.Attack() + pos = pos.MoveN(nbits, 0) subValues := []common.Hash{} for i := 0; i < 1<