Commit b4d628a1 authored by clabby's avatar clabby

Account for `ABSOLUTE_PRESTATE` in `step`

parent 1ca4741f
...@@ -111,11 +111,6 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone { ...@@ -111,11 +111,6 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
bytes calldata, bytes calldata,
bytes calldata bytes calldata
) external { ) external {
// TODO: Determine where the prestate for the full trace comes from
// (i.e. instruction 0 -> 1) This will likely be in the preimage oracle, but this
// function currently does not support an attack step against the first trace
// instruction.
// Steps cannot be made unless the game is currently in progress. // Steps cannot be made unless the game is currently in progress.
if (status != GameStatus.IN_PROGRESS) { if (status != GameStatus.IN_PROGRESS) {
revert GameNotInProgress(); revert GameNotInProgress();
...@@ -123,8 +118,6 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone { ...@@ -123,8 +118,6 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
// Get the parent. If it does not exist, the call will revert with OOB. // Get the parent. If it does not exist, the call will revert with OOB.
ClaimData storage parent = claimData[_parentIndex]; ClaimData storage parent = claimData[_parentIndex];
// Get the pre/post state. If it does not exist, the call will revert with OOB.
ClaimData storage state = claimData[_stateIndex];
// Pull the parent position out of storage. // Pull the parent position out of storage.
Position parentPos = parent.position; Position parentPos = parent.position;
...@@ -137,30 +130,40 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone { ...@@ -137,30 +130,40 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
} }
// Determine the expected pre & post states of the step. // Determine the expected pre & post states of the step.
ClaimData storage preState; Claim preStateClaim;
Claim postStateClaim; Claim postStateClaim;
if (_isAttack) { if (stepPos.indexAtDepth() == 0) {
// If the step is an attack, the prestate exists elsewhere in the game state, // If the step position's index at depth is 0, the prestate is the absolute prestate
// and the parent claim is the expected post-state. // and the post state is the parent claim.
preState = state; preStateClaim = ABSOLUTE_PRESTATE;
postStateClaim = parent.claim; postStateClaim = claimData[_stateIndex].claim;
} else { } else {
// If the step is a defense, the poststate exists elsewhere in the game state, Position preStatePos;
// and the parent claim is the expected pre-state. if (_isAttack) {
preState = parent; // If the step is an attack, the prestate exists elsewhere in the game state,
postStateClaim = state.claim; // and the parent claim is the expected post-state.
} preStatePos = claimData[_stateIndex].position;
preStateClaim = claimData[_parentIndex].claim;
postStateClaim = parent.claim;
} else {
// If the step is a defense, the poststate exists elsewhere in the game state,
// and the parent claim is the expected pre-state.
preStatePos = parent.position;
preStateClaim = parent.claim;
postStateClaim = claimData[_stateIndex].claim;
}
// Assert that the prestate commits to the instruction at `gindex - 1` // Assert that the given prestate commits to the instruction at `gindex - 1`.
if (preState.position.rightIndex(MAX_GAME_DEPTH) != Position.unwrap(stepPos) - 1) { if (preStatePos.rightIndex(MAX_GAME_DEPTH) != Position.unwrap(stepPos) - 1) {
revert InvalidStep(); revert InvalidPrestate();
}
} }
// TODO: Call `MIPS.sol#step` to verify the step. // TODO: Call `MIPS.sol#step` to verify the step.
// For now, we just use a simple state transition function that increments the prestate, // For now, we just use a simple state transition function that increments the prestate,
// `s_p`, by 1. // `s_p`, by 1.
if (uint256(Claim.unwrap(preState.claim)) + 1 != uint256(Claim.unwrap(postStateClaim))) { if (uint256(Claim.unwrap(preStateClaim)) + 1 == uint256(Claim.unwrap(postStateClaim))) {
revert InvalidStep(); revert ValidStep();
} }
// Set the parent claim as countered. We do not need to append a new claim to the game; // Set the parent claim as countered. We do not need to append a new claim to the game;
...@@ -315,7 +318,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone { ...@@ -315,7 +318,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
// If the claim is not a dangling node above the bottom of the tree, // If the claim is not a dangling node above the bottom of the tree,
// we can skip over it. These nodes are not relevant to the game resolution. // we can skip over it. These nodes are not relevant to the game resolution.
Position claimPos = claim.position; Position claimPos = claim.position;
if (claimPos.depth() == MAX_GAME_DEPTH || claim.countered) { if (claim.countered) {
continue; continue;
} }
......
...@@ -110,7 +110,6 @@ library LibPosition { ...@@ -110,7 +110,6 @@ library LibPosition {
let remaining := sub(_maxDepth, msb) let remaining := sub(_maxDepth, msb)
rightIndex_ := or(shl(remaining, _position), sub(shl(remaining, 1), 1)) rightIndex_ := or(shl(remaining, _position), sub(shl(remaining, 1), 1))
} }
rightIndex_ := sub(rightIndex_, shl(_maxDepth, 1))
} }
} }
......
...@@ -71,10 +71,9 @@ error InvalidParent(); ...@@ -71,10 +71,9 @@ error InvalidParent();
error InvalidPrestate(); error InvalidPrestate();
/** /**
* @notice Thrown when a step is attempted to be made where the post state does not match * @notice Thrown when a step is made that computes the expected post state correctly.
* what was expected.
*/ */
error InvalidStep(); error ValidStep();
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// `AttestationDisputeGame` Errors // // `AttestationDisputeGame` Errors //
......
...@@ -323,6 +323,26 @@ contract FaultDisputeGame_Test is DisputeGameFactory_Init { ...@@ -323,6 +323,26 @@ contract FaultDisputeGame_Test is DisputeGameFactory_Init {
assertEq(uint8(status), uint8(GameStatus.CHALLENGER_WINS)); assertEq(uint8(status), uint8(GameStatus.CHALLENGER_WINS));
assertEq(uint8(gameProxy.status()), uint8(GameStatus.CHALLENGER_WINS)); assertEq(uint8(gameProxy.status()), uint8(GameStatus.CHALLENGER_WINS));
} }
/**
* @notice Tests that the `step` function works from the absolute prestate -> instruction 1.
*/
function test_step_absolute_succeeds() public {
Claim claim = Claim.wrap(bytes32(uint256(5)));
for (uint256 i = 0; i < 62; i++) {
gameProxy.attack(i, claim);
}
// This step should succeed, since it proves the above claim as invalid relative
// to the absolute prestate.
gameProxy.step(0, 62, true, hex"", hex"");
(,bool countered,,,) = gameProxy.claimData(62);
assertTrue(countered);
GameStatus status = gameProxy.resolve();
assertEq(uint8(status), uint8(GameStatus.DEFENDER_WINS));
}
} }
/** /**
......
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