Commit 0d221da6 authored by clabby's avatar clabby Committed by GitHub

feat(ctb): Allow for checkpointing in claim resolution (#10248)

* feat(ctb): Allow for checkpointing in claim resolution

Introduces checkpointing to the `resolveClaim` function in the
`FaultDisputeGame`, allowing for the pagination of subgame resolution.

fix

* review

* feat(challenger): Resolution checkpointing support (#10253)

* feat(challenger): Resolution checkpointing support

Adds support for resolution checkpointing

* op-challenger: Use a simple maximum number of child claims to resolve per call.

---------
Co-authored-by: default avatarAdrian Sutton <adrian@oplabs.co>

---------
Co-authored-by: default avatarAdrian Sutton <adrian@oplabs.co>
parent caf41c55
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -18,6 +18,9 @@ import ( ...@@ -18,6 +18,9 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
) )
// The maximum number of children that will be processed during a call to `resolveClaim`
var maxChildChecks = big.NewInt(512)
var ( var (
methodMaxClockDuration = "maxClockDuration" methodMaxClockDuration = "maxClockDuration"
methodMaxGameDepth = "maxGameDepth" methodMaxGameDepth = "maxGameDepth"
...@@ -408,7 +411,7 @@ func (f *FaultDisputeGameContract) ResolveClaimTx(claimIdx uint64) (txmgr.TxCand ...@@ -408,7 +411,7 @@ func (f *FaultDisputeGameContract) ResolveClaimTx(claimIdx uint64) (txmgr.TxCand
} }
func (f *FaultDisputeGameContract) resolveClaimCall(claimIdx uint64) *batching.ContractCall { func (f *FaultDisputeGameContract) resolveClaimCall(claimIdx uint64) *batching.ContractCall {
return f.contract.Call(methodResolveClaim, new(big.Int).SetUint64(claimIdx)) return f.contract.Call(methodResolveClaim, new(big.Int).SetUint64(claimIdx), maxChildChecks)
} }
func (f *FaultDisputeGameContract) CallResolve(ctx context.Context) (gameTypes.GameStatus, error) { func (f *FaultDisputeGameContract) CallResolve(ctx context.Context) (gameTypes.GameStatus, error) {
......
...@@ -250,14 +250,14 @@ func TestGetBalance(t *testing.T) { ...@@ -250,14 +250,14 @@ func TestGetBalance(t *testing.T) {
func TestCallResolveClaim(t *testing.T) { func TestCallResolveClaim(t *testing.T) {
stubRpc, game := setupFaultDisputeGameTest(t) stubRpc, game := setupFaultDisputeGameTest(t)
stubRpc.SetResponse(fdgAddr, methodResolveClaim, rpcblock.Latest, []interface{}{big.NewInt(123)}, nil) stubRpc.SetResponse(fdgAddr, methodResolveClaim, rpcblock.Latest, []interface{}{big.NewInt(123), maxChildChecks}, nil)
err := game.CallResolveClaim(context.Background(), 123) err := game.CallResolveClaim(context.Background(), 123)
require.NoError(t, err) require.NoError(t, err)
} }
func TestResolveClaimTxTest(t *testing.T) { func TestResolveClaimTxTest(t *testing.T) {
stubRpc, game := setupFaultDisputeGameTest(t) stubRpc, game := setupFaultDisputeGameTest(t)
stubRpc.SetResponse(fdgAddr, methodResolveClaim, rpcblock.Latest, []interface{}{big.NewInt(123)}, nil) stubRpc.SetResponse(fdgAddr, methodResolveClaim, rpcblock.Latest, []interface{}{big.NewInt(123), maxChildChecks}, nil)
tx, err := game.ResolveClaimTx(123) tx, err := game.ResolveClaimTx(123)
require.NoError(t, err) require.NoError(t, err)
stubRpc.VerifyTxCandidate(tx) stubRpc.VerifyTxCandidate(tx)
......
...@@ -569,7 +569,7 @@ func (s *CrossLayerUser) ResolveClaim(t Testing, l2TxHash common.Hash) common.Ha ...@@ -569,7 +569,7 @@ func (s *CrossLayerUser) ResolveClaim(t Testing, l2TxHash common.Hash) common.Ha
require.Nil(t, err) require.Nil(t, err)
time.Sleep(time.Duration(expiry) * time.Second) time.Sleep(time.Duration(expiry) * time.Second)
resolveClaimTx, err := game.ResolveClaim(&s.L1.txOpts, common.Big0) resolveClaimTx, err := game.ResolveClaim(&s.L1.txOpts, common.Big0, common.Big0)
require.Nil(t, err) require.Nil(t, err)
err = s.L1.env.EthCl.SendTransaction(t.Ctx(), resolveClaimTx) err = s.L1.env.EthCl.SendTransaction(t.Ctx(), resolveClaimTx)
......
...@@ -334,7 +334,7 @@ func (g *FaultGameHelper) StepFails(claimIdx int64, isAttack bool, stateData []b ...@@ -334,7 +334,7 @@ func (g *FaultGameHelper) StepFails(claimIdx int64, isAttack bool, stateData []b
// ResolveClaim resolves a single subgame // ResolveClaim resolves a single subgame
func (g *FaultGameHelper) ResolveClaim(ctx context.Context, claimIdx int64) { func (g *FaultGameHelper) ResolveClaim(ctx context.Context, claimIdx int64) {
tx, err := g.game.ResolveClaim(g.opts, big.NewInt(claimIdx)) tx, err := g.game.ResolveClaim(g.opts, big.NewInt(claimIdx), common.Big0)
g.require.NoError(err, "ResolveClaim transaction did not send") g.require.NoError(err, "ResolveClaim transaction did not send")
_, err = wait.ForReceiptOK(ctx, g.client, tx.Hash()) _, err = wait.ForReceiptOK(ctx, g.client, tx.Hash())
g.require.NoError(err, "ResolveClaim transaction was not OK") g.require.NoError(err, "ResolveClaim transaction was not OK")
......
...@@ -620,7 +620,7 @@ func (g *OutputGameHelper) StepFails(claimIdx int64, isAttack bool, stateData [] ...@@ -620,7 +620,7 @@ func (g *OutputGameHelper) StepFails(claimIdx int64, isAttack bool, stateData []
// ResolveClaim resolves a single subgame // ResolveClaim resolves a single subgame
func (g *OutputGameHelper) ResolveClaim(ctx context.Context, claimIdx int64) { func (g *OutputGameHelper) ResolveClaim(ctx context.Context, claimIdx int64) {
tx, err := g.game.ResolveClaim(g.opts, big.NewInt(claimIdx)) tx, err := g.game.ResolveClaim(g.opts, big.NewInt(claimIdx), common.Big0)
g.require.NoError(err, "ResolveClaim transaction did not send") g.require.NoError(err, "ResolveClaim transaction did not send")
_, err = wait.ForReceiptOK(ctx, g.client, tx.Hash()) _, err = wait.ForReceiptOK(ctx, g.client, tx.Hash())
g.require.NoError(err, "ResolveClaim transaction was not OK") g.require.NoError(err, "ResolveClaim transaction was not OK")
......
...@@ -205,7 +205,7 @@ func FinalizeWithdrawal(t *testing.T, cfg SystemConfig, l1Client *ethclient.Clie ...@@ -205,7 +205,7 @@ func FinalizeWithdrawal(t *testing.T, cfg SystemConfig, l1Client *ethclient.Clie
require.Nil(t, err) require.Nil(t, err)
time.Sleep(time.Duration(expiry) * time.Second) time.Sleep(time.Duration(expiry) * time.Second)
resolveClaimTx, err := proxy.ResolveClaim(opts, common.Big0) resolveClaimTx, err := proxy.ResolveClaim(opts, common.Big0, common.Big0)
require.Nil(t, err) require.Nil(t, err)
resolveClaimReceipt, err = wait.ForReceiptOK(ctx, l1Client, resolveClaimTx.Hash()) resolveClaimReceipt, err = wait.ForReceiptOK(ctx, l1Client, resolveClaimTx.Hash())
......
...@@ -116,8 +116,8 @@ ...@@ -116,8 +116,8 @@
"sourceCodeHash": "0xc4dbd17217b63f8117f56f78c213e57dda304fee7577fe296e1d804ebe049542" "sourceCodeHash": "0xc4dbd17217b63f8117f56f78c213e57dda304fee7577fe296e1d804ebe049542"
}, },
"src/dispute/FaultDisputeGame.sol": { "src/dispute/FaultDisputeGame.sol": {
"initCodeHash": "0x8b8be450739ffdc236e5cbad7d59140d5c1f80cfc096c75260fb7224701fa3f3", "initCodeHash": "0x614fc47be249e9e2278acfff13f4167c48db77bee9dd188e0514f67fbe6d2cd2",
"sourceCodeHash": "0xe5bcdc2d310c46445a1f420db76225e0b5446671ba1c9a2f0b73e2a522faf967" "sourceCodeHash": "0xf7d3b1188f08c0bcb089db41f45622a08d71bccdcaf0479ebc71f65178f75c21"
}, },
"src/dispute/weth/DelayedWETH.sol": { "src/dispute/weth/DelayedWETH.sol": {
"initCodeHash": "0x7b6ec89eaec09e369426e73161a9c6932223bb1f974377190c3f6f552995da35", "initCodeHash": "0x7b6ec89eaec09e369426e73161a9c6932223bb1f974377190c3f6f552995da35",
......
...@@ -360,6 +360,25 @@ ...@@ -360,6 +360,25 @@
"stateMutability": "view", "stateMutability": "view",
"type": "function" "type": "function"
}, },
{
"inputs": [
{
"internalType": "uint256",
"name": "_claimIndex",
"type": "uint256"
}
],
"name": "getNumToResolve",
"outputs": [
{
"internalType": "uint256",
"name": "numRemainingChildren_",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{ {
"inputs": [ "inputs": [
{ {
...@@ -474,6 +493,40 @@ ...@@ -474,6 +493,40 @@
"stateMutability": "payable", "stateMutability": "payable",
"type": "function" "type": "function"
}, },
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "resolutionCheckpoints",
"outputs": [
{
"internalType": "bool",
"name": "initialCheckpointComplete",
"type": "bool"
},
{
"internalType": "uint32",
"name": "subgameIndex",
"type": "uint32"
},
{
"internalType": "Position",
"name": "leftmostPosition",
"type": "uint128"
},
{
"internalType": "address",
"name": "counteredBy",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{ {
"inputs": [], "inputs": [],
"name": "resolve", "name": "resolve",
...@@ -493,6 +546,11 @@ ...@@ -493,6 +546,11 @@
"internalType": "uint256", "internalType": "uint256",
"name": "_claimIndex", "name": "_claimIndex",
"type": "uint256" "type": "uint256"
},
{
"internalType": "uint256",
"name": "_numToResolve",
"type": "uint256"
} }
], ],
"name": "resolveClaim", "name": "resolveClaim",
......
...@@ -383,6 +383,25 @@ ...@@ -383,6 +383,25 @@
"stateMutability": "view", "stateMutability": "view",
"type": "function" "type": "function"
}, },
{
"inputs": [
{
"internalType": "uint256",
"name": "_claimIndex",
"type": "uint256"
}
],
"name": "getNumToResolve",
"outputs": [
{
"internalType": "uint256",
"name": "numRemainingChildren_",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{ {
"inputs": [ "inputs": [
{ {
...@@ -510,6 +529,40 @@ ...@@ -510,6 +529,40 @@
"stateMutability": "view", "stateMutability": "view",
"type": "function" "type": "function"
}, },
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "resolutionCheckpoints",
"outputs": [
{
"internalType": "bool",
"name": "initialCheckpointComplete",
"type": "bool"
},
{
"internalType": "uint32",
"name": "subgameIndex",
"type": "uint32"
},
{
"internalType": "Position",
"name": "leftmostPosition",
"type": "uint128"
},
{
"internalType": "address",
"name": "counteredBy",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{ {
"inputs": [], "inputs": [],
"name": "resolve", "name": "resolve",
...@@ -529,6 +582,11 @@ ...@@ -529,6 +582,11 @@
"internalType": "uint256", "internalType": "uint256",
"name": "_claimIndex", "name": "_claimIndex",
"type": "uint256" "type": "uint256"
},
{
"internalType": "uint256",
"name": "_numToResolve",
"type": "uint256"
} }
], ],
"name": "resolveClaim", "name": "resolveClaim",
......
...@@ -62,11 +62,18 @@ ...@@ -62,11 +62,18 @@
"slot": "5", "slot": "5",
"type": "mapping(uint256 => bool)" "type": "mapping(uint256 => bool)"
}, },
{
"bytes": "32",
"label": "resolutionCheckpoints",
"offset": 0,
"slot": "6",
"type": "mapping(uint256 => struct IFaultDisputeGame.ResolutionCheckpoint)"
},
{ {
"bytes": "64", "bytes": "64",
"label": "startingOutputRoot", "label": "startingOutputRoot",
"offset": 0, "offset": 0,
"slot": "6", "slot": "7",
"type": "struct OutputRoot" "type": "struct OutputRoot"
} }
] ]
\ No newline at end of file
...@@ -62,11 +62,18 @@ ...@@ -62,11 +62,18 @@
"slot": "5", "slot": "5",
"type": "mapping(uint256 => bool)" "type": "mapping(uint256 => bool)"
}, },
{
"bytes": "32",
"label": "resolutionCheckpoints",
"offset": 0,
"slot": "6",
"type": "mapping(uint256 => struct IFaultDisputeGame.ResolutionCheckpoint)"
},
{ {
"bytes": "64", "bytes": "64",
"label": "startingOutputRoot", "label": "startingOutputRoot",
"offset": 0, "offset": 0,
"slot": "6", "slot": "7",
"type": "struct OutputRoot" "type": "struct OutputRoot"
} }
] ]
\ No newline at end of file
...@@ -62,8 +62,8 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver { ...@@ -62,8 +62,8 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
Position internal constant ROOT_POSITION = Position.wrap(1); Position internal constant ROOT_POSITION = Position.wrap(1);
/// @notice Semantic version. /// @notice Semantic version.
/// @custom:semver 0.17.0 /// @custom:semver 0.18.0
string public constant version = "0.17.0"; string public constant version = "0.18.0";
/// @notice The starting timestamp of the game /// @notice The starting timestamp of the game
Timestamp public createdAt; Timestamp public createdAt;
...@@ -89,9 +89,12 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver { ...@@ -89,9 +89,12 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
/// @notice A mapping of subgames rooted at a claim index to other claim indices in the subgame. /// @notice A mapping of subgames rooted at a claim index to other claim indices in the subgame.
mapping(uint256 => uint256[]) public subgames; mapping(uint256 => uint256[]) public subgames;
/// @notice An interneal mapping of resolved subgames rooted at a claim index. /// @notice A mapping of resolved subgames rooted at a claim index.
mapping(uint256 => bool) public resolvedSubgames; mapping(uint256 => bool) public resolvedSubgames;
/// @notice A mapping of claim indices to resolution checkpoints.
mapping(uint256 => ResolutionCheckpoint) public resolutionCheckpoints;
/// @notice The latest finalized output root, serving as the anchor for output bisection. /// @notice The latest finalized output root, serving as the anchor for output bisection.
OutputRoot public startingOutputRoot; OutputRoot public startingOutputRoot;
...@@ -436,6 +439,15 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver { ...@@ -436,6 +439,15 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
} }
} }
/// @inheritdoc IFaultDisputeGame
function getNumToResolve(uint256 _claimIndex) public view returns (uint256 numRemainingChildren_) {
ResolutionCheckpoint storage checkpoint = resolutionCheckpoints[_claimIndex];
uint256[] storage challengeIndices = subgames[_claimIndex];
uint256 challengeIndicesLen = challengeIndices.length;
numRemainingChildren_ = challengeIndicesLen - checkpoint.subgameIndex;
}
/// @inheritdoc IFaultDisputeGame /// @inheritdoc IFaultDisputeGame
function l2BlockNumber() public pure returns (uint256 l2BlockNumber_) { function l2BlockNumber() public pure returns (uint256 l2BlockNumber_) {
l2BlockNumber_ = _getArgUint256(0x54); l2BlockNumber_ = _getArgUint256(0x54);
...@@ -475,7 +487,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver { ...@@ -475,7 +487,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
} }
/// @inheritdoc IFaultDisputeGame /// @inheritdoc IFaultDisputeGame
function resolveClaim(uint256 _claimIndex) external { function resolveClaim(uint256 _claimIndex, uint256 _numToResolve) external {
// INVARIANT: Resolution cannot occur unless the game is currently in progress. // INVARIANT: Resolution cannot occur unless the game is currently in progress.
if (status != GameStatus.IN_PROGRESS) revert GameNotInProgress(); if (status != GameStatus.IN_PROGRESS) revert GameNotInProgress();
...@@ -507,10 +519,22 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver { ...@@ -507,10 +519,22 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
return; return;
} }
// Fetch the resolution checkpoint from storage.
ResolutionCheckpoint memory checkpoint = resolutionCheckpoints[_claimIndex];
// If the checkpoint does not currently exist, initialize the current left most position as max u128.
if (!checkpoint.initialCheckpointComplete) {
checkpoint.leftmostPosition = Position.wrap(type(uint128).max);
checkpoint.initialCheckpointComplete = true;
// If `_numToResolve == 0`, assume that we can check all child subgames in this one callframe.
if (_numToResolve == 0) _numToResolve = challengeIndicesLen;
}
// Assume parent is honest until proven otherwise // Assume parent is honest until proven otherwise
address countered = address(0); uint256 lastToResolve = checkpoint.subgameIndex + _numToResolve;
Position leftmostCounter = Position.wrap(type(uint128).max); uint256 finalCursor = lastToResolve > challengeIndicesLen ? challengeIndicesLen : lastToResolve;
for (uint256 i = 0; i < challengeIndicesLen; ++i) { for (uint256 i = checkpoint.subgameIndex; i < finalCursor; i++) {
uint256 challengeIndex = challengeIndices[i]; uint256 challengeIndex = challengeIndices[i];
// INVARIANT: Cannot resolve a subgame containing an unresolved claim // INVARIANT: Cannot resolve a subgame containing an unresolved claim
...@@ -524,22 +548,35 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver { ...@@ -524,22 +548,35 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
// from countering invalid subgame roots via an invalid defense position. As such positions // from countering invalid subgame roots via an invalid defense position. As such positions
// cannot be correctly countered. // cannot be correctly countered.
// Note that correctly positioned defense, but invalid claimes can still be successfully countered. // Note that correctly positioned defense, but invalid claimes can still be successfully countered.
if (claim.counteredBy == address(0) && leftmostCounter.raw() > claim.position.raw()) { if (claim.counteredBy == address(0) && checkpoint.leftmostPosition.raw() > claim.position.raw()) {
countered = claim.claimant; checkpoint.counteredBy = claim.claimant;
leftmostCounter = claim.position; checkpoint.leftmostPosition = claim.position;
} }
} }
// If the parent was not successfully countered, pay out the parent's bond to the claimant. // Increase the checkpoint's cursor position by the number of children that were checked.
// If the parent was successfully countered, pay out the parent's bond to the challenger. checkpoint.subgameIndex = uint32(finalCursor);
_distributeBond(countered == address(0) ? subgameRootClaim.claimant : countered, subgameRootClaim);
// Persist the checkpoint and allow for continuing in a separate transaction, if resolution is not already
// complete.
resolutionCheckpoints[_claimIndex] = checkpoint;
// Once a subgame is resolved, we percolate the result up the DAG so subsequent calls to // If all children have been traversed in the above loop, the subgame may be resolved. Otherwise, persist the
// resolveClaim will not need to traverse this subgame. // checkpoint and allow for continuation in a separate transaction.
subgameRootClaim.counteredBy = countered; if (checkpoint.subgameIndex == challengeIndicesLen) {
address countered = checkpoint.counteredBy;
// Mark the subgame as resolved. // Once a subgame is resolved, we percolate the result up the DAG so subsequent calls to
resolvedSubgames[_claimIndex] = true; // resolveClaim will not need to traverse this subgame.
subgameRootClaim.counteredBy = countered;
// Mark the subgame as resolved.
resolvedSubgames[_claimIndex] = true;
// If the parent was not successfully countered, pay out the parent's bond to the claimant.
// If the parent was successfully countered, pay out the parent's bond to the challenger.
_distributeBond(countered == address(0) ? subgameRootClaim.claimant : countered, subgameRootClaim);
}
} }
/// @inheritdoc IDisputeGame /// @inheritdoc IDisputeGame
......
...@@ -19,6 +19,14 @@ interface IFaultDisputeGame is IDisputeGame { ...@@ -19,6 +19,14 @@ interface IFaultDisputeGame is IDisputeGame {
Clock clock; Clock clock;
} }
/// @notice The `ResolutionCheckpoint` struct represents the data associated with an in-progress claim resolution.
struct ResolutionCheckpoint {
bool initialCheckpointComplete;
uint32 subgameIndex;
Position leftmostPosition;
address counteredBy;
}
/// @notice Emitted when a new claim is added to the DAG by `claimant` /// @notice Emitted when a new claim is added to the DAG by `claimant`
/// @param parentIndex The index within the `claimData` array of the parent claim /// @param parentIndex The index within the `claimData` array of the parent claim
/// @param claim The claim being added /// @param claim The claim being added
...@@ -54,13 +62,24 @@ interface IFaultDisputeGame is IDisputeGame { ...@@ -54,13 +62,24 @@ interface IFaultDisputeGame is IDisputeGame {
/// @param _partOffset The offset of the data to post. /// @param _partOffset The offset of the data to post.
function addLocalData(uint256 _ident, uint256 _execLeafIdx, uint256 _partOffset) external; function addLocalData(uint256 _ident, uint256 _execLeafIdx, uint256 _partOffset) external;
/// @notice Resolves the subgame rooted at the given claim index. /// @notice Resolves the subgame rooted at the given claim index. `_numToResolve` specifies how many children of
/// the subgame will be checked in this call. If `_numToResolve` is less than the number of children, an
/// internal cursor will be updated and this function may be called again to complete resolution of the
/// subgame.
/// @dev This function must be called bottom-up in the DAG /// @dev This function must be called bottom-up in the DAG
/// A subgame is a tree of claims that has a maximum depth of 1. /// A subgame is a tree of claims that has a maximum depth of 1.
/// A subgame root claims is valid if, and only if, all of its child claims are invalid. /// A subgame root claims is valid if, and only if, all of its child claims are invalid.
/// At the deepest level in the DAG, a claim is invalid if there's a successful step against it. /// At the deepest level in the DAG, a claim is invalid if there's a successful step against it.
/// @param _claimIndex The index of the subgame root claim to resolve. /// @param _claimIndex The index of the subgame root claim to resolve.
function resolveClaim(uint256 _claimIndex) external; /// @param _numToResolve The number of subgames to resolve in this call. If the input is `0`, and this is the first
/// page, this function will attempt to check all of the subgame's children at once.
function resolveClaim(uint256 _claimIndex, uint256 _numToResolve) external;
/// @notice Returns the number of children that still need to be resolved in order to fully resolve a subgame rooted
/// at `_claimIndex`.
/// @param _claimIndex The subgame root claim's index within `claimData`.
/// @return numRemainingChildren_ The number of children that still need to be checked to resolve the subgame.
function getNumToResolve(uint256 _claimIndex) external view returns (uint256 numRemainingChildren_);
/// @notice The l2BlockNumber of the disputed output root in the `L2OutputOracle`. /// @notice The l2BlockNumber of the disputed output root in the `L2OutputOracle`.
function l2BlockNumber() external view returns (uint256 l2BlockNumber_); function l2BlockNumber() external view returns (uint256 l2BlockNumber_);
......
...@@ -631,7 +631,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest { ...@@ -631,7 +631,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest {
}); });
// Warp and resolve the dispute game. // Warp and resolve the dispute game.
game.resolveClaim(0); game.resolveClaim(0, 0);
game.resolve(); game.resolve();
vm.warp(block.timestamp + optimismPortal2.proofMaturityDelaySeconds() + 1 seconds); vm.warp(block.timestamp + optimismPortal2.proofMaturityDelaySeconds() + 1 seconds);
...@@ -659,7 +659,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest { ...@@ -659,7 +659,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest {
}); });
// Warp and resolve the dispute game. // Warp and resolve the dispute game.
game.resolveClaim(0); game.resolveClaim(0, 0);
game.resolve(); game.resolve();
vm.warp(block.timestamp + optimismPortal2.proofMaturityDelaySeconds() + 1 seconds); vm.warp(block.timestamp + optimismPortal2.proofMaturityDelaySeconds() + 1 seconds);
...@@ -709,7 +709,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest { ...@@ -709,7 +709,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest {
}); });
// Warp and resolve the original dispute game. // Warp and resolve the original dispute game.
game.resolveClaim(0); game.resolveClaim(0, 0);
game.resolve(); game.resolve();
vm.warp(block.timestamp + optimismPortal2.proofMaturityDelaySeconds() + 1 seconds); vm.warp(block.timestamp + optimismPortal2.proofMaturityDelaySeconds() + 1 seconds);
...@@ -836,7 +836,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest { ...@@ -836,7 +836,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest {
}); });
// Resolve the dispute game. // Resolve the dispute game.
game.resolveClaim(0); game.resolveClaim(0, 0);
game.resolve(); game.resolve();
vm.warp(block.timestamp + optimismPortal2.proofMaturityDelaySeconds() + 1); vm.warp(block.timestamp + optimismPortal2.proofMaturityDelaySeconds() + 1);
...@@ -860,7 +860,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest { ...@@ -860,7 +860,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest {
}); });
// Resolve the dispute game. // Resolve the dispute game.
game.resolveClaim(0); game.resolveClaim(0, 0);
game.resolve(); game.resolve();
vm.warp(block.timestamp + optimismPortal2.proofMaturityDelaySeconds() + 1); vm.warp(block.timestamp + optimismPortal2.proofMaturityDelaySeconds() + 1);
...@@ -908,7 +908,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest { ...@@ -908,7 +908,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest {
}); });
// Resolve the dispute game. // Resolve the dispute game.
game.resolveClaim(0); game.resolveClaim(0, 0);
game.resolve(); game.resolve();
vm.warp(block.timestamp + optimismPortal2.proofMaturityDelaySeconds() + 1); vm.warp(block.timestamp + optimismPortal2.proofMaturityDelaySeconds() + 1);
...@@ -950,7 +950,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest { ...@@ -950,7 +950,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest {
optimismPortal2.proveWithdrawalTransaction(_testTx, _proposedGameIndex, outputRootProof, withdrawalProof); optimismPortal2.proveWithdrawalTransaction(_testTx, _proposedGameIndex, outputRootProof, withdrawalProof);
// Resolve the dispute game. // Resolve the dispute game.
game.resolveClaim(0); game.resolveClaim(0, 0);
game.resolve(); game.resolve();
vm.warp(block.timestamp + optimismPortal2.proofMaturityDelaySeconds() + 1); vm.warp(block.timestamp + optimismPortal2.proofMaturityDelaySeconds() + 1);
...@@ -1025,7 +1025,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest { ...@@ -1025,7 +1025,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest {
assertTrue(_game.rootClaim().raw() != bytes32(0)); assertTrue(_game.rootClaim().raw() != bytes32(0));
// Resolve the dispute game // Resolve the dispute game
game.resolveClaim(0); game.resolveClaim(0, 0);
game.resolve(); game.resolve();
// Warp past the finalization period // Warp past the finalization period
...@@ -1049,7 +1049,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest { ...@@ -1049,7 +1049,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest {
}); });
// Resolve the dispute game. // Resolve the dispute game.
game.resolveClaim(0); game.resolveClaim(0, 0);
game.resolve(); game.resolve();
vm.prank(optimismPortal2.guardian()); vm.prank(optimismPortal2.guardian());
...@@ -1077,7 +1077,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest { ...@@ -1077,7 +1077,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest {
vm.warp(block.timestamp + optimismPortal2.proofMaturityDelaySeconds() + 1); vm.warp(block.timestamp + optimismPortal2.proofMaturityDelaySeconds() + 1);
// Resolve the dispute game. // Resolve the dispute game.
game.resolveClaim(0); game.resolveClaim(0, 0);
game.resolve(); game.resolve();
// Attempt to finalize the withdrawal directly after the game resolves. This should fail. // Attempt to finalize the withdrawal directly after the game resolves. This should fail.
...@@ -1106,7 +1106,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest { ...@@ -1106,7 +1106,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest {
vm.warp(block.timestamp + optimismPortal2.proofMaturityDelaySeconds() + 1); vm.warp(block.timestamp + optimismPortal2.proofMaturityDelaySeconds() + 1);
// Resolve the dispute game. // Resolve the dispute game.
game.resolveClaim(0); game.resolveClaim(0, 0);
game.resolve(); game.resolve();
// Change the respected game type in the portal. // Change the respected game type in the portal.
...@@ -1133,7 +1133,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest { ...@@ -1133,7 +1133,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest {
vm.warp(block.timestamp + optimismPortal2.proofMaturityDelaySeconds() + 1); vm.warp(block.timestamp + optimismPortal2.proofMaturityDelaySeconds() + 1);
// Resolve the dispute game. // Resolve the dispute game.
game.resolveClaim(0); game.resolveClaim(0, 0);
game.resolve(); game.resolve();
// Change the respected game type in the portal. // Change the respected game type in the portal.
...@@ -1172,7 +1172,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest { ...@@ -1172,7 +1172,7 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest {
// Finalize the dispute game and attempt to finalize the withdrawal again. This should also fail, since the // Finalize the dispute game and attempt to finalize the withdrawal again. This should also fail, since the
// air gap dispute game delay has not elapsed. // air gap dispute game delay has not elapsed.
game.resolveClaim(0); game.resolveClaim(0, 0);
game.resolve(); game.resolve();
vm.warp(block.timestamp + optimismPortal2.disputeGameFinalityDelaySeconds()); vm.warp(block.timestamp + optimismPortal2.disputeGameFinalityDelaySeconds());
vm.expectRevert("OptimismPortal: output proposal in air-gap"); vm.expectRevert("OptimismPortal: output proposal in air-gap");
......
...@@ -536,7 +536,8 @@ contract Specification_Test is CommonTest { ...@@ -536,7 +536,8 @@ contract Specification_Test is CommonTest {
_addSpec({ _name: "FaultDisputeGame", _sel: _getSel("move(uint256,bytes32,bool)") }); _addSpec({ _name: "FaultDisputeGame", _sel: _getSel("move(uint256,bytes32,bool)") });
_addSpec({ _name: "FaultDisputeGame", _sel: _getSel("proposer()") }); _addSpec({ _name: "FaultDisputeGame", _sel: _getSel("proposer()") });
_addSpec({ _name: "FaultDisputeGame", _sel: _getSel("resolve()") }); _addSpec({ _name: "FaultDisputeGame", _sel: _getSel("resolve()") });
_addSpec({ _name: "FaultDisputeGame", _sel: _getSel("resolveClaim(uint256)") }); _addSpec({ _name: "FaultDisputeGame", _sel: _getSel("getNumToResolve(uint256)") });
_addSpec({ _name: "FaultDisputeGame", _sel: _getSel("resolveClaim(uint256,uint256)") });
_addSpec({ _name: "FaultDisputeGame", _sel: _getSel("resolvedAt()") }); _addSpec({ _name: "FaultDisputeGame", _sel: _getSel("resolvedAt()") });
_addSpec({ _name: "FaultDisputeGame", _sel: _getSel("resolvedSubgames(uint256)") }); _addSpec({ _name: "FaultDisputeGame", _sel: _getSel("resolvedSubgames(uint256)") });
_addSpec({ _name: "FaultDisputeGame", _sel: _getSel("rootClaim()") }); _addSpec({ _name: "FaultDisputeGame", _sel: _getSel("rootClaim()") });
......
...@@ -36,7 +36,7 @@ contract FaultDisputeGame_Solvency_Invariant is FaultDisputeGame_Init { ...@@ -36,7 +36,7 @@ contract FaultDisputeGame_Solvency_Invariant is FaultDisputeGame_Init {
(,,, uint256 rootBond,,,) = gameProxy.claimData(0); (,,, uint256 rootBond,,,) = gameProxy.claimData(0);
for (uint256 i = gameProxy.claimDataLen(); i > 0; i--) { for (uint256 i = gameProxy.claimDataLen(); i > 0; i--) {
(bool success,) = address(gameProxy).call(abi.encodeCall(gameProxy.resolveClaim, (i - 1))); (bool success,) = address(gameProxy).call(abi.encodeCall(gameProxy.resolveClaim, (i - 1, 0)));
assertTrue(success); assertTrue(success);
} }
gameProxy.resolve(); gameProxy.resolve();
......
...@@ -128,7 +128,7 @@ contract OptimismPortal2_Invariant_Harness is CommonTest { ...@@ -128,7 +128,7 @@ contract OptimismPortal2_Invariant_Harness is CommonTest {
// Warp beyond the finalization period for the dispute game and resolve it. // Warp beyond the finalization period for the dispute game and resolve it.
vm.warp(block.timestamp + (game.maxClockDuration().raw() * 2) + 1 seconds); vm.warp(block.timestamp + (game.maxClockDuration().raw() * 2) + 1 seconds);
game.resolveClaim(0); game.resolveClaim(0, 0);
game.resolve(); game.resolve();
// Fund the portal so that we can withdraw ETH. // Fund the portal so that we can withdraw ETH.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment