Commit b1a1a154 authored by clabby's avatar clabby

some actor tests

parent 0a9d6b10
...@@ -19,6 +19,12 @@ abstract contract GameSolver is CommonBase { ...@@ -19,6 +19,12 @@ abstract contract GameSolver is CommonBase {
/// @notice The maximum length of the execution trace, in bytes. Enforced by the depth of the /// @notice The maximum length of the execution trace, in bytes. Enforced by the depth of the
/// execution trace bisection game. /// execution trace bisection game.
uint256 internal immutable MAX_TRACE_LENGTH; uint256 internal immutable MAX_TRACE_LENGTH;
/// @notice The split depth of the game
uint256 internal immutable SPLIT_DEPTH;
/// @notice The max depth of the game
uint256 internal immutable MAX_DEPTH;
/// @notice The starting L2 Block Number
uint256 internal immutable STARTING_L2_BLOCK_NUMBER;
/// @notice The execution trace that the `GameSolver` will be representing. /// @notice The execution trace that the `GameSolver` will be representing.
bytes public trace; bytes public trace;
...@@ -49,9 +55,17 @@ abstract contract GameSolver is CommonBase { ...@@ -49,9 +55,17 @@ abstract contract GameSolver is CommonBase {
bytes data; bytes data;
} }
constructor(OutputBisectionGame _gameProxy, bytes memory _trace, bytes memory _preStateData) { constructor(
OutputBisectionGame _gameProxy,
bytes memory _trace,
bytes memory _preStateData,
uint256 _startingL2BlockNumber
) {
GAME = _gameProxy; GAME = _gameProxy;
MAX_TRACE_LENGTH = 2 ** (_gameProxy.MAX_GAME_DEPTH() - _gameProxy.SPLIT_DEPTH()); MAX_TRACE_LENGTH = 2 ** (_gameProxy.MAX_GAME_DEPTH() - _gameProxy.SPLIT_DEPTH());
SPLIT_DEPTH = GAME.SPLIT_DEPTH();
MAX_DEPTH = GAME.MAX_GAME_DEPTH();
STARTING_L2_BLOCK_NUMBER = _startingL2BlockNumber;
trace = _trace; trace = _trace;
absolutePrestateData = _preStateData; absolutePrestateData = _preStateData;
} }
...@@ -77,9 +91,10 @@ contract HonestGameSolver is GameSolver { ...@@ -77,9 +91,10 @@ contract HonestGameSolver is GameSolver {
constructor( constructor(
OutputBisectionGame _gameProxy, OutputBisectionGame _gameProxy,
bytes memory _trace, bytes memory _trace,
bytes memory _preStateData bytes memory _preStateData,
uint256 _startingL2BlockNumber
) )
GameSolver(_gameProxy, _trace, _preStateData) GameSolver(_gameProxy, _trace, _preStateData, _startingL2BlockNumber)
{ {
// Mark agreement with the root claim if the local opinion of the root claim is the same as the // Mark agreement with the root claim if the local opinion of the root claim is the same as the
// observed root claim. // observed root claim.
...@@ -112,15 +127,15 @@ contract HonestGameSolver is GameSolver { ...@@ -112,15 +127,15 @@ contract HonestGameSolver is GameSolver {
// Continue if there is no move to be taken against the observed claim. // Continue if there is no move to be taken against the observed claim.
if (moveDirection == Direction.Noop) continue; if (moveDirection == Direction.Noop) continue;
if (movePos.depth() <= GAME.SPLIT_DEPTH()) { if (movePos.depth() <= SPLIT_DEPTH) {
// output bisection // output bisection
moves_[movesLen++] = handleOutputBisectionMove(moveDirection, movePos, i); moves_[movesLen++] = handleOutputBisectionMove(moveDirection, movePos, i);
} else if (movePos.depth() <= GAME.MAX_GAME_DEPTH()) { } else if (movePos.depth() <= MAX_DEPTH) {
// execution trace bisection // execution trace bisection
moves_[movesLen++] = handleExecutionTraceBisectionMove(moveDirection, movePos, i); moves_[movesLen++] = handleExecutionTraceBisectionMove(moveDirection, movePos, i);
} else { } else {
// instruction step // instruction step
moves_[movesLen++] = handleStepMove(moveDirection, movePos, i); moves_[movesLen++] = handleStepMove(moveDirection, observed.position, movePos, i);
} }
} }
...@@ -144,9 +159,10 @@ contract HonestGameSolver is GameSolver { ...@@ -144,9 +159,10 @@ contract HonestGameSolver is GameSolver {
view view
returns (Direction direction_, Position movePos_) returns (Direction direction_, Position movePos_)
{ {
bool rightLevel = isRightLevel(_claimData.position);
if (_claimData.parentIndex == type(uint32).max) { if (_claimData.parentIndex == type(uint32).max) {
// If we agree with the parent claim and it is on a level we agree with, ignore it. // If we agree with the parent claim and it is on a level we agree with, ignore it.
if (Claim.unwrap(claimAt(_claimData.position)) == Claim.unwrap(_claimData.claim)) { if (Claim.unwrap(claimAt(_claimData.position)) == Claim.unwrap(_claimData.claim) && rightLevel) {
return (Direction.Noop, Position.wrap(0)); return (Direction.Noop, Position.wrap(0));
} }
...@@ -160,23 +176,18 @@ contract HonestGameSolver is GameSolver { ...@@ -160,23 +176,18 @@ contract HonestGameSolver is GameSolver {
// Fetch the local opinion of the parent claim. // Fetch the local opinion of the parent claim.
Claim localParent = claimAt(_claimData.position); Claim localParent = claimAt(_claimData.position);
// Fetch the local opinion of the grandparent claim and the grandparent claim's metadata. bool localAgree = Claim.unwrap(localParent) == Claim.unwrap(_claimData.claim);
IOutputBisectionGame.ClaimData memory grandparentClaimData = getClaimData(_claimData.parentIndex); if (rightLevel) {
Claim localGrandparent = claimAt(grandparentClaimData.position); // Never move against a claim on the right level. Even if it's wrong, if it's uncountered, it furthers
// our goals.
if (Claim.unwrap(localParent) != Claim.unwrap(_claimData.claim)) { return (Direction.Noop, Position.wrap(0));
} else {
// NOTE: Poison not handled yet.
if (!localAgree) {
// If we disagree with the observed claim, we must attack it. // If we disagree with the observed claim, we must attack it.
movePos_ = _claimData.position.move(true); movePos_ = _claimData.position.move(true);
direction_ = Direction.Attack; direction_ = Direction.Attack;
} else if ( } else {
Claim.unwrap(localParent) == Claim.unwrap(_claimData.claim)
&& Claim.unwrap(localGrandparent) != Claim.unwrap(grandparentClaimData.claim)
) {
// Never defend a claim that the solver would have made.
if (isRightLevel(_claimData.position)) {
return (Direction.Noop, Position.wrap(0));
}
// If we agree with the observed claim, but disagree with the grandparent claim, we must defend // If we agree with the observed claim, but disagree with the grandparent claim, we must defend
// the observed claim. // the observed claim.
movePos_ = _claimData.position.move(false); movePos_ = _claimData.position.move(false);
...@@ -184,6 +195,7 @@ contract HonestGameSolver is GameSolver { ...@@ -184,6 +195,7 @@ contract HonestGameSolver is GameSolver {
} }
} }
} }
}
/// @notice Returns a `Move` struct that represents an attack or defense move in the output bisection /// @notice Returns a `Move` struct that represents an attack or defense move in the output bisection
/// portion of the dispute game. /// portion of the dispute game.
...@@ -201,7 +213,7 @@ contract HonestGameSolver is GameSolver { ...@@ -201,7 +213,7 @@ contract HonestGameSolver is GameSolver {
bool isAttack = _direction == Direction.Attack; bool isAttack = _direction == Direction.Attack;
move_ = Move({ move_ = Move({
kind: isAttack ? MoveKind.Attack : MoveKind.Defend, kind: isAttack ? MoveKind.Attack : MoveKind.Defend,
data: abi.encodeCall(OutputBisectionGame.move, (_challengeIndex, outputAt(_movePos), isAttack)) data: abi.encodeCall(OutputBisectionGame.move, (_challengeIndex, claimAt(_movePos), isAttack))
}); });
} }
...@@ -229,9 +241,9 @@ contract HonestGameSolver is GameSolver { ...@@ -229,9 +241,9 @@ contract HonestGameSolver is GameSolver {
/// bisection portion of the dispute game. /// bisection portion of the dispute game.
/// @dev Note: This function assumes that the `movePos` and `challengeIndex` are valid within the /// @dev Note: This function assumes that the `movePos` and `challengeIndex` are valid within the
/// execution trace bisection context. This is enforced by the `solveGame` function. /// execution trace bisection context. This is enforced by the `solveGame` function.
/// @dev TODO: Handle new format for `AlphabetVM` once it's been refactored for Output Bisection.
function handleStepMove( function handleStepMove(
Direction _direction, Direction _direction,
Position _parentPos,
Position _movePos, Position _movePos,
uint256 _challengeIndex uint256 _challengeIndex
) )
...@@ -240,23 +252,19 @@ contract HonestGameSolver is GameSolver { ...@@ -240,23 +252,19 @@ contract HonestGameSolver is GameSolver {
returns (Move memory move_) returns (Move memory move_)
{ {
bool isAttack = _direction == Direction.Attack; bool isAttack = _direction == Direction.Attack;
Position parentPos = _movePos.parent();
bytes memory preStateTrace; bytes memory preStateTrace;
// First, we need to find the pre/post state index depending on whether we // First, we need to find the pre/post state index depending on whether we
// are making an attack step or a defense step. If the index at depth of the // are making an attack step or a defense step. If the index at depth of the
// move position is 0, the prestate is the absolute prestate and we need to // move position is 0, the prestate is the absolute prestate and we need to
// do nothing. // do nothing.
if ((_movePos.indexAtDepth() % (2 ** (GAME.MAX_GAME_DEPTH() - GAME.SPLIT_DEPTH()))) > 0) { if ((_movePos.indexAtDepth() % (2 ** (MAX_DEPTH - SPLIT_DEPTH))) > 0) {
Position leafPos =
isAttack ? Position.wrap(Position.unwrap(parentPos) - 1) : Position.wrap(Position.unwrap(parentPos) + 1);
Position statePos = leafPos.traceAncestor();
// Grab the trace up to the prestate's trace index. // Grab the trace up to the prestate's trace index.
if (isAttack) { if (isAttack) {
preStateTrace = abi.encode(statePos.traceIndex(GAME.MAX_GAME_DEPTH()), traceAt(statePos)); Position leafPos = Position.wrap(Position.unwrap(_parentPos) - 1);
preStateTrace = abi.encode(leafPos.traceIndex(MAX_DEPTH), stateAt(leafPos));
} else { } else {
preStateTrace = abi.encode(parentPos.traceIndex(GAME.MAX_GAME_DEPTH()), traceAt(parentPos)); preStateTrace = abi.encode(_parentPos.traceIndex(MAX_DEPTH), stateAt(_parentPos));
} }
} else { } else {
preStateTrace = absolutePrestateData; preStateTrace = absolutePrestateData;
...@@ -290,49 +298,55 @@ contract HonestGameSolver is GameSolver { ...@@ -290,49 +298,55 @@ contract HonestGameSolver is GameSolver {
}); });
} }
/// @notice Returns the player's claim that commits to a given position, swapping between
/// output bisection claims and execution trace bisection claims depending on the depth
function claimAt(Position _position) public view returns (Claim claim_) {
return _position.depth() > SPLIT_DEPTH ? statehashAt(_position) : outputAt(_position);
}
/// @notice Returns the mock output at the given position. /// @notice Returns the mock output at the given position.
function outputAt(Position _position) public view returns (Claim claim_) { function outputAt(Position _position) public view returns (Claim claim_) {
// Don't allow for positions that are deeper than the split depth. // Don't allow for positions that are deeper than the split depth.
if (_position.depth() > GAME.SPLIT_DEPTH()) { if (_position.depth() > SPLIT_DEPTH) {
revert("GameSolver: invalid position depth"); revert("GameSolver: invalid position depth");
} }
return outputAt(_position.traceIndex(GAME.SPLIT_DEPTH()) + 1); return outputAt(_position.traceIndex(SPLIT_DEPTH) + 1);
} }
/// @notice Returns the mock output at the given L2 block number. /// @notice Returns the mock output at the given L2 block number.
function outputAt(uint256 _l2BlockNumber) public pure returns (Claim claim_) { function outputAt(uint256 _l2BlockNumber) public view returns (Claim claim_) {
return Claim.wrap(bytes32(_l2BlockNumber)); return Claim.wrap(bytes32(STARTING_L2_BLOCK_NUMBER + _l2BlockNumber));
}
/// @notice Returns the state at the trace index within the player's trace.
function traceAt(Position _position) public view returns (uint256 state_) {
return traceAt(_position.traceIndex(GAME.MAX_GAME_DEPTH()));
}
/// @notice Returns the state at the trace index within the player's trace.
function traceAt(uint256 _traceIndex) public view returns (uint256 state_) {
return uint256(uint8(_traceIndex >= trace.length ? trace[trace.length - 1] : trace[_traceIndex]));
} }
/// @notice Returns the player's claim that commits to a given trace index. /// @notice Returns the player's claim that commits to a given trace index.
function claimAt(uint256 _traceIndex) public view returns (Claim claim_) { function statehashAt(uint256 _traceIndex) public view returns (Claim claim_) {
bytes32 hash = bytes32 hash =
keccak256(abi.encode(_traceIndex >= trace.length ? trace.length - 1 : _traceIndex, traceAt(_traceIndex))); keccak256(abi.encode(_traceIndex >= trace.length ? trace.length - 1 : _traceIndex, stateAt(_traceIndex)));
assembly { assembly {
claim_ := or(and(hash, not(shl(248, 0xFF))), shl(248, 1)) claim_ := or(and(hash, not(shl(248, 0xFF))), shl(248, 1))
} }
} }
/// @notice Returns the player's claim that commits to a given trace index. /// @notice Returns the player's claim that commits to a given trace index.
function claimAt(Position _position) public view returns (Claim claim_) { function statehashAt(Position _position) public view returns (Claim claim_) {
return claimAt(_position.traceIndex(GAME.MAX_GAME_DEPTH())); return statehashAt(_position.traceIndex(MAX_DEPTH));
}
/// @notice Returns the state at the trace index within the player's trace.
function stateAt(Position _position) public view returns (uint256 state_) {
return stateAt(_position.traceIndex(MAX_DEPTH));
}
/// @notice Returns the state at the trace index within the player's trace.
function stateAt(uint256 _traceIndex) public view returns (uint256 state_) {
return uint256(uint8(_traceIndex >= trace.length ? trace[trace.length - 1] : trace[_traceIndex]));
} }
/// @notice Returns whether or not the position is on a level which opposes the local opinion of the /// @notice Returns whether or not the position is on a level which opposes the local opinion of the
/// root claim. /// root claim.
function isRightLevel(Position _position) public view returns (bool isRightLevel_) { function isRightLevel(Position _position) public view returns (bool isRightLevel_) {
return _position.depth() % 2 == 0 && agreeWithRoot; isRightLevel_ = agreeWithRoot == (_position.depth() % 2 == 0);
} }
} }
...@@ -344,8 +358,9 @@ abstract contract DisputeActor { ...@@ -344,8 +358,9 @@ abstract contract DisputeActor {
GameSolver public solver; GameSolver public solver;
/// @notice Performs all available moves deemed by the attached solver. /// @notice Performs all available moves deemed by the attached solver.
/// @return numMoves_ The number of moves that the actor took.
/// @return success_ True if all moves were successful, false otherwise. /// @return success_ True if all moves were successful, false otherwise.
function move() external virtual returns (bool success_); function move() external virtual returns (uint256 numMoves_, bool success_);
} }
/// @title HonestDisputeActor /// @title HonestDisputeActor
...@@ -355,16 +370,25 @@ abstract contract DisputeActor { ...@@ -355,16 +370,25 @@ abstract contract DisputeActor {
contract HonestDisputeActor is DisputeActor { contract HonestDisputeActor is DisputeActor {
OutputBisectionGame public immutable GAME; OutputBisectionGame public immutable GAME;
constructor(OutputBisectionGame _gameProxy, bytes memory _trace, bytes memory _preStateData) { constructor(
OutputBisectionGame _gameProxy,
bytes memory _trace,
bytes memory _preStateData,
uint256 _startingL2BlockNumber
) {
GAME = _gameProxy; GAME = _gameProxy;
solver = GameSolver(new HonestGameSolver(_gameProxy, _trace, _preStateData)); solver = GameSolver(new HonestGameSolver(_gameProxy, _trace, _preStateData, _startingL2BlockNumber));
} }
/// @inheritdoc DisputeActor /// @inheritdoc DisputeActor
function move() external override returns (bool success_) { function move() external override returns (uint256 numMoves_, bool success_) {
GameSolver.Move[] memory moves = solver.solveGame(); GameSolver.Move[] memory moves = solver.solveGame();
numMoves_ = moves.length;
success_ = true;
for (uint256 i = 0; i < moves.length; i++) { for (uint256 i = 0; i < moves.length; i++) {
(success_,) = address(GAME).call(moves[i].data); (bool innerSuccess,) = address(GAME).call(moves[i].data);
success_ = success_ && innerSuccess;
} }
} }
} }
...@@ -641,28 +641,13 @@ contract OutputBisectionGame_Test is OutputBisectionGame_Init { ...@@ -641,28 +641,13 @@ contract OutputBisectionGame_Test is OutputBisectionGame_Init {
bytes32 h = keccak256(abi.encode(_ident | (1 << 248), address(gameProxy), _localContext)); bytes32 h = keccak256(abi.encode(_ident | (1 << 248), address(gameProxy), _localContext));
return bytes32((uint256(h) & ~uint256(0xFF << 248)) | (1 << 248)); return bytes32((uint256(h) & ~uint256(0xFF << 248)) | (1 << 248));
} }
/// @dev Helper to change the VM status byte of a claim.
function _changeClaimStatus(Claim _claim, VMStatus _status) public pure returns (Claim out_) {
assembly {
out_ := or(and(not(shl(248, 0xFF)), _claim), shl(248, _status))
}
}
} }
contract ThunderDome_1v1_Test is OutputBisectionGame_Init { contract OutputBisection_1v1_Actors_Test is OutputBisectionGame_Init {
/// @dev The root claim of the game. This is the output root at block # 2 ** SPLIT_DEPTH /// @dev The honest actor
/// in the alphabet game. DisputeActor internal honest;
Claim internal immutable ROOT_CLAIM; /// @dev The dishonest actor
/// @dev The absolute prestate of the trace. DisputeActor internal dishonest;
Claim internal immutable ABSOLUTE_PRESTATE;
/// @dev The state data (preimage) of the absolute prestate hash.
bytes internal absolutePrestateData;
constructor() {
ROOT_CLAIM = Claim.wrap(bytes32((uint256(1) << 248) | uint256(10)));
ABSOLUTE_PRESTATE = Claim.wrap(bytes32((uint256(3) << 248) | uint256(0)));
}
function setUp() public override { function setUp() public override {
// Setup the `OutputBisectionGame` // Setup the `OutputBisectionGame`
...@@ -670,37 +655,145 @@ contract ThunderDome_1v1_Test is OutputBisectionGame_Init { ...@@ -670,37 +655,145 @@ contract ThunderDome_1v1_Test is OutputBisectionGame_Init {
} }
/// @notice Static unit test for a 1v1 output bisection dispute. /// @notice Static unit test for a 1v1 output bisection dispute.
function test_static_1v1_succeeds() public { function test_static_1v1honestRoot_succeeds() public {
// Create the dispute game. // Create the dispute game with an honest `ROOT_CLAIM`
bytes memory absolutePrestateData = abi.encode(0);
Claim absolutePrestateExec =
_changeClaimStatus(Claim.wrap(keccak256(absolutePrestateData)), VMStatuses.UNFINISHED);
Claim rootClaim = Claim.wrap(bytes32(uint256(0x10)));
super.init({ super.init({
rootClaim: ROOT_CLAIM, rootClaim: rootClaim,
absolutePrestate: ABSOLUTE_PRESTATE, absolutePrestate: absolutePrestateExec,
l2BlockNumber: 0x10, l2BlockNumber: 0x10,
genesisBlockNumber: 0, genesisBlockNumber: 0,
genesisOutputRoot: Hash.wrap(bytes32(0)) genesisOutputRoot: Hash.wrap(bytes32(0))
}); });
bytes memory honestPreStateData = abi.encode(0); // The honest trace covers all block -> block + 1 transitions, and is 256 bytes long, consisting
bytes memory honestTrace = hex""; // of bytes [0, 255].
bytes memory honestTrace = new bytes(256);
for (uint256 i; i < honestTrace.length; i++) {
honestTrace[i] = bytes1(uint8(i));
}
// Create actors
_createActors({
_honestTrace: honestTrace,
_honestPreStateData: absolutePrestateData,
_honestStartingBlock: 0,
_dishonestTrace: new bytes(256),
_dishonestPreStateData: absolutePrestateData,
_dishonestStartingBlock: 1
});
// Exhaust all moves from both actors
_exhaustMoves();
// Resolve the game and assert that the defender won
_warpAndResolve();
assertEq(uint8(gameProxy.status()), uint8(GameStatus.DEFENDER_WINS));
}
/// @notice Static unit test for a 1v1 output bisection dispute.
function test_static_1v1dishonestRoot_succeeds() public {
// Create the dispute game with an honest `ROOT_CLAIM`
bytes memory absolutePrestateData = abi.encode(0);
Claim absolutePrestateExec =
_changeClaimStatus(Claim.wrap(keccak256(absolutePrestateData)), VMStatuses.UNFINISHED);
Claim rootClaim = Claim.wrap(bytes32(uint256(0x11)));
super.init({
rootClaim: rootClaim,
absolutePrestate: absolutePrestateExec,
l2BlockNumber: 0x11,
genesisBlockNumber: 0,
genesisOutputRoot: Hash.wrap(bytes32(0))
});
// The honest trace covers all block -> block + 1 transitions, and is 256 bytes long, consisting
// of bytes [0, 255].
bytes memory honestTrace = new bytes(256);
for (uint256 i; i < honestTrace.length; i++) {
honestTrace[i] = bytes1(uint8(i));
}
// The dishonest trace covers all block -> block + 1 transitions, and is 256 bytes long, consisting
// of all zeros.
bytes memory dishonestTrace = new bytes(256);
// Create actors
_createActors({
_honestTrace: honestTrace,
_honestPreStateData: absolutePrestateData,
_honestStartingBlock: 0,
_dishonestTrace: dishonestTrace,
_dishonestPreStateData: absolutePrestateData,
_dishonestStartingBlock: 1
});
// Exhaust all moves from both actors
_exhaustMoves();
// Resolve the game and assert that the defender won
_warpAndResolve();
assertEq(uint8(gameProxy.status()), uint8(GameStatus.CHALLENGER_WINS));
} }
/// @dev Helper to create actors for the 1v1 dispute. /// @dev Helper to create actors for the 1v1 dispute.
function _createActors( function _createActors(
bytes memory _honestTrace, bytes memory _honestTrace,
bytes memory _honestPreStateData, bytes memory _honestPreStateData,
uint256 _honestStartingBlock,
bytes memory _dishonestTrace, bytes memory _dishonestTrace,
bytes memory _dishonestPreStateData bytes memory _dishonestPreStateData,
) uint256 _dishonestStartingBlock
internal ) internal {
returns (DisputeActor honest_, DisputeActor dishonest_) honest = new HonestDisputeActor({
{ _gameProxy: gameProxy,
// Setup the honest and dishonest actors (todo) _trace: _honestTrace,
honest_ = _preStateData: _honestPreStateData,
new HonestDisputeActor({ _gameProxy: gameProxy, _trace: _honestTrace, _preStateData: _honestPreStateData }); _startingL2BlockNumber: _honestStartingBlock
dishonest_ = new HonestDisputeActor({ });
dishonest = new HonestDisputeActor({
_gameProxy: gameProxy, _gameProxy: gameProxy,
_trace: _dishonestTrace, _trace: _dishonestTrace,
_preStateData: _dishonestPreStateData _preStateData: _dishonestPreStateData,
_startingL2BlockNumber: _dishonestStartingBlock
}); });
vm.label(address(honest), "HonestActor");
vm.label(address(dishonest), "DishonestActor");
}
/// @dev Helper to exhaust all moves from both actors.
function _exhaustMoves() internal {
while (true) {
// Allow the dishonest actor to make their moves, and then the honest actor.
(uint256 numMovesA,) = dishonest.move();
(uint256 numMovesB,) = honest.move();
// If both actors have run out of moves, we're done.
if (numMovesA == 0 && numMovesB == 0) break;
}
}
/// @dev Helper to warp past the chess clock and resolve all claims within the dispute game.
function _warpAndResolve() internal {
// Warp past the chess clock
vm.warp(block.timestamp + 3 days + 12 hours + 1 seconds);
// Resolve all claims in reverse order. We allow `resolveClaim` calls to fail due to
// the check that prevents claims with no subgames attached from being passed to
// `resolveClaim`. There's also a check in `resolve` to ensure all children have been
// resolved before global resolution, which catches any unresolved subgames here.
for (uint256 i = gameProxy.claimDataLen(); i > 0; i--) {
(bool success,) = address(gameProxy).call(abi.encodeCall(gameProxy.resolveClaim, (i - 1)));
success;
}
gameProxy.resolve();
}
}
/// @dev Helper to change the VM status byte of a claim.
function _changeClaimStatus(Claim _claim, VMStatus _status) pure returns (Claim out_) {
assembly {
out_ := or(and(not(shl(248, 0xFF)), _claim), shl(248, _status))
} }
} }
...@@ -31,7 +31,7 @@ contract AlphabetVM2 is IBigStepper { ...@@ -31,7 +31,7 @@ contract AlphabetVM2 is IBigStepper {
// If the state data is empty, then the absolute prestate is the claim. // If the state data is empty, then the absolute prestate is the claim.
traceIndex = 0; traceIndex = 0;
(claim) = abi.decode(_stateData, (uint256)); (claim) = abi.decode(_stateData, (uint256));
claim = claim + uint256(oracle.loadLocalData(4, _localContext, 0, 32, 0)); claim = claim + uint256(oracle.loadLocalData(4, _localContext, 0, 8, 0));
} else { } else {
// Otherwise, decode the state data. // Otherwise, decode the state data.
(traceIndex, claim) = abi.decode(_stateData, (uint256, uint256)); (traceIndex, claim) = abi.decode(_stateData, (uint256, uint256));
......
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