Commit 7d090bf9 authored by clabby's avatar clabby

fix: Search for expected status byte

parent c856071b
This diff is collapsed.
...@@ -100,8 +100,8 @@ ...@@ -100,8 +100,8 @@
"sourceCodeHash": "0xa995b54dce03ddf5c9c47451bd7181996b91398ad66b54ab0b8cbf582863a33e" "sourceCodeHash": "0xa995b54dce03ddf5c9c47451bd7181996b91398ad66b54ab0b8cbf582863a33e"
}, },
"src/dispute/OutputBisectionGame.sol": { "src/dispute/OutputBisectionGame.sol": {
"initCodeHash": "0x959d79d64f526fe67a476f876370814fb583bd1674b692f1025632e4f67a8c71", "initCodeHash": "0xd354d78579c42a9f0f8a8c9b5ef04f570fa3bd088f88102b431aca8d48fddaae",
"sourceCodeHash": "0xfdce387743a43e48f6aaa5855de0088d9bbb003d0ce62de465cf151320979a7a" "sourceCodeHash": "0x98f65f2f2f07a525d360eba87e624f1cb44c52326f3b3f2bf7b6ee41a7ec4a2c"
}, },
"src/legacy/DeployerWhitelist.sol": { "src/legacy/DeployerWhitelist.sol": {
"initCodeHash": "0x8de80fb23b26dd9d849f6328e56ea7c173cd9e9ce1f05c9beea559d1720deb3d", "initCodeHash": "0x8de80fb23b26dd9d849f6328e56ea7c173cd9e9ce1f05c9beea559d1720deb3d",
......
...@@ -151,7 +151,7 @@ contract OutputBisectionGame is IOutputBisectionGame, Clone, ISemver { ...@@ -151,7 +151,7 @@ contract OutputBisectionGame is IOutputBisectionGame, Clone, ISemver {
// the remainder of the index at depth divided by 2 ** (MAX_GAME_DEPTH - SPLIT_DEPTH), // the remainder of the index at depth divided by 2 ** (MAX_GAME_DEPTH - SPLIT_DEPTH),
// which is the number of leaves in each execution trace subgame. This is so that we can // which is the number of leaves in each execution trace subgame. This is so that we can
// determine whether or not the step position is represents the `ABSOLUTE_PRESTATE`. // determine whether or not the step position is represents the `ABSOLUTE_PRESTATE`.
preStateClaim = (stepPos.indexAtDepth() % (2 ** (MAX_GAME_DEPTH - SPLIT_DEPTH))) == 0 preStateClaim = (stepPos.indexAtDepth() % (1 << (MAX_GAME_DEPTH - SPLIT_DEPTH))) == 0
? ABSOLUTE_PRESTATE ? ABSOLUTE_PRESTATE
: findTraceAncestor(Position.wrap(Position.unwrap(parentPos) - 1), parent.parentIndex, false).claim; : findTraceAncestor(Position.wrap(Position.unwrap(parentPos) - 1), parent.parentIndex, false).claim;
// For all attacks, the poststate is the parent claim. // For all attacks, the poststate is the parent claim.
...@@ -207,7 +207,8 @@ contract OutputBisectionGame is IOutputBisectionGame, Clone, ISemver { ...@@ -207,7 +207,8 @@ contract OutputBisectionGame is IOutputBisectionGame, Clone, ISemver {
// Compute the position that the claim commits to. Because the parent's position is already // Compute the position that the claim commits to. Because the parent's position is already
// known, we can compute the next position by moving left or right depending on whether // known, we can compute the next position by moving left or right depending on whether
// or not the move is an attack or defense. // or not the move is an attack or defense.
Position nextPosition = parent.position.move(_isAttack); Position parentPos = parent.position;
Position nextPosition = parentPos.move(_isAttack);
uint256 nextPositionDepth = nextPosition.depth(); uint256 nextPositionDepth = nextPosition.depth();
// INVARIANT: A defense can never be made against the root claim of either the output root game or any // INVARIANT: A defense can never be made against the root claim of either the output root game or any
...@@ -225,7 +226,9 @@ contract OutputBisectionGame is IOutputBisectionGame, Clone, ISemver { ...@@ -225,7 +226,9 @@ contract OutputBisectionGame is IOutputBisectionGame, Clone, ISemver {
// When the next position surpasses the split depth (i.e., it is the root claim of an execution // When the next position surpasses the split depth (i.e., it is the root claim of an execution
// trace bisection sub-game), we need to perform some extra verification steps. // trace bisection sub-game), we need to perform some extra verification steps.
if (nextPositionDepth == SPLIT_DEPTH + 1) verifyExecBisectionRoot(_claim); if (nextPositionDepth == SPLIT_DEPTH + 1) {
verifyExecBisectionRoot(_claim, _challengeIndex, parentPos, _isAttack);
}
// Fetch the grandparent clock, if it exists. // Fetch the grandparent clock, if it exists.
// The grandparent clock should always exist unless the parent is the root claim. // The grandparent clock should always exist unless the parent is the root claim.
...@@ -474,11 +477,37 @@ contract OutputBisectionGame is IOutputBisectionGame, Clone, ISemver { ...@@ -474,11 +477,37 @@ contract OutputBisectionGame is IOutputBisectionGame, Clone, ISemver {
/// @notice Verifies the integrity of an execution bisection subgame's root claim. Reverts if the claim /// @notice Verifies the integrity of an execution bisection subgame's root claim. Reverts if the claim
/// is invalid. /// is invalid.
/// @param _rootClaim The root claim of the execution bisection subgame. /// @param _rootClaim The root claim of the execution bisection subgame.
function verifyExecBisectionRoot(Claim _rootClaim) internal pure { function verifyExecBisectionRoot(
// The VMStatus must indicate 'invalid' (1), to argue that disputed thing is invalid. Claim _rootClaim,
// Games that agree with the existing outcome are not allowed. uint256 _parentIdx,
Position _parentPos,
bool _isAttack
)
internal
view
{
// The root claim of an execution trace bisection sub-game must:
// 1. Signal that the VM panicked or resulted in an invalid transition if the disputed output root
// was made by the opposing party.
// 2. Signal that the VM resulted in a valid transition if the disputed output root was made by the same party.
// If the move is a defense, the disputed output could have been made by either party. In this case, we
// need to search for the parent output to determine what the expected status byte should be.
Position disputedLeafPos = Position.wrap(Position.unwrap(_parentPos) + 1);
ClaimData storage disputed = findTraceAncestor({ _pos: disputedLeafPos, _start: _parentIdx, _global: true });
uint8 vmStatus = uint8(Claim.unwrap(_rootClaim)[0]); uint8 vmStatus = uint8(Claim.unwrap(_rootClaim)[0]);
if (!(vmStatus == VMStatus.unwrap(VMStatuses.INVALID) || vmStatus == VMStatus.unwrap(VMStatuses.PANIC))) {
if (_isAttack || disputed.position.depth() % 2 == SPLIT_DEPTH % 2) {
// If the move is an attack, the parent output is always deemed to be disputed. In this case, we only need
// to check that the root claim signals that the VM panicked or resulted in an invalid transition.
// If the move is a defense, and the disputed output and creator of the execution trace subgame disagree,
// the root claim should also signal that the VM panicked or resulted in an invalid transition.
if (!(vmStatus == VMStatus.unwrap(VMStatuses.INVALID) || vmStatus == VMStatus.unwrap(VMStatuses.PANIC))) {
revert UnexpectedRootClaim(_rootClaim);
}
} else if (vmStatus != VMStatus.unwrap(VMStatuses.VALID)) {
// The disputed output and the creator of the execution trace subgame agree. The status byte should
// have signaled that the VM succeeded.
revert UnexpectedRootClaim(_rootClaim); revert UnexpectedRootClaim(_rootClaim);
} }
} }
......
...@@ -593,7 +593,7 @@ contract OutputBisectionGame_Test is OutputBisectionGame_Init { ...@@ -593,7 +593,7 @@ contract OutputBisectionGame_Test is OutputBisectionGame_Init {
for (uint256 i; i < 4; i++) { for (uint256 i; i < 4; i++) {
gameProxy.attack(i, Claim.wrap(bytes32(i))); gameProxy.attack(i, Claim.wrap(bytes32(i)));
} }
gameProxy.defend(4, ROOT_CLAIM); gameProxy.defend(4, _changeClaimStatus(ROOT_CLAIM, VMStatuses.VALID));
// Expected start/disputed claims // Expected start/disputed claims
bytes32 startingClaim = bytes32(uint256(3)); bytes32 startingClaim = bytes32(uint256(3));
......
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