Commit ef3b63b3 authored by clabby's avatar clabby

Absolute prestate step fixes + tests

parent cf9c41d7
......@@ -317,7 +317,7 @@ contract OutputBisectionGame is IOutputBisectionGame, Clone, ISemver {
// we add the index at depth + 1 to the genesis block number to get the L2 block number.
uint256 l2Number = Position.unwrap(startingPos) == 0
? GENESIS_BLOCK_NUMBER
: GENESIS_BLOCK_NUMBER + startingPos.indexAtDepth() + 1;
: GENESIS_BLOCK_NUMBER + startingPos.traceIndex(SPLIT_DEPTH) + 1;
oracle.loadLocalData(_ident, Hash.unwrap(uuid), bytes32(l2Number << 0xC0), 8, _partOffset);
} else if (_ident == LocalPreimageKey.CHAIN_ID) {
......
......@@ -834,6 +834,98 @@ contract OutputBisection_1v1_Actors_Test is OutputBisectionGame_Init {
assertEq(uint8(gameProxy.status()), uint8(GameStatus.CHALLENGER_WINS));
}
/// @notice Static unit test for a 1v1 output bisection dispute.
function test_static_1v1correctAbsolutePrestate_succeeds() public {
// Create the dispute game with an honest `ROOT_CLAIM`
bytes memory absolutePrestateData = _setup({ _absolutePrestateData: 0, _rootClaim: 16 });
// The honest l2 outputs are from [1, 16] in this game.
uint256[] memory honestL2Outputs = new uint256[](16);
for (uint256 i; i < honestL2Outputs.length; i++) {
honestL2Outputs[i] = i + 1;
}
// 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 l2 outputs are half correct, half incorrect.
uint256[] memory dishonestL2Outputs = new uint256[](16);
for (uint256 i; i < dishonestL2Outputs.length; i++) {
dishonestL2Outputs[i] = i > 7 ? 0xFF : i + 1;
}
// The dishonest trace is half correct, half (- 1/2 of an exec trace subgame after the midpoint) incorrect.
bytes memory dishonestTrace = new bytes(256);
for (uint256 i; i < dishonestTrace.length; i++) {
dishonestTrace[i] = i > 127 ? bytes1(0xFF) : bytes1(uint8(i));
}
// Create actors
_createActors({
_honestTrace: honestTrace,
_honestPreStateData: absolutePrestateData,
_honestL2Outputs: honestL2Outputs,
_dishonestTrace: dishonestTrace,
_dishonestPreStateData: absolutePrestateData,
_dishonestL2Outputs: dishonestL2Outputs
});
// 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_1v1dishonestAbsolutePrestate_succeeds() public {
// Create the dispute game with an honest `ROOT_CLAIM`
bytes memory absolutePrestateData = _setup({ _absolutePrestateData: 0, _rootClaim: 0xFF });
// The honest l2 outputs are from [1, 16] in this game.
uint256[] memory honestL2Outputs = new uint256[](16);
for (uint256 i; i < honestL2Outputs.length; i++) {
honestL2Outputs[i] = i + 1;
}
// 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 l2 outputs are half correct, half incorrect.
uint256[] memory dishonestL2Outputs = new uint256[](16);
for (uint256 i; i < dishonestL2Outputs.length; i++) {
dishonestL2Outputs[i] = i > 7 ? 0xFF : i + 1;
}
// The dishonest trace is half correct, half (- 1/2 of an exec trace subgame after the midpoint) incorrect.
bytes memory dishonestTrace = new bytes(256);
for (uint256 i; i < dishonestTrace.length; i++) {
dishonestTrace[i] = i > 127 ? bytes1(0xFF) : bytes1(uint8(i));
}
// Create actors
_createActors({
_honestTrace: honestTrace,
_honestPreStateData: absolutePrestateData,
_honestL2Outputs: honestL2Outputs,
_dishonestTrace: dishonestTrace,
_dishonestPreStateData: absolutePrestateData,
_dishonestL2Outputs: dishonestL2Outputs
});
// 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));
}
////////////////////////////////////////////////////////////////
// HELPERS //
////////////////////////////////////////////////////////////////
......
......@@ -2,11 +2,12 @@
pragma solidity ^0.8.15;
import { IBigStepper, IPreimageOracle } from "src/dispute/interfaces/IBigStepper.sol";
import { PreimageOracle } from "src/cannon/PreimageOracle.sol";
import { PreimageOracle, PreimageKeyLib } from "src/cannon/PreimageOracle.sol";
import "src/libraries/DisputeTypes.sol";
/// @title AlphabetVM2
/// @dev A mock VM for the purpose of testing the dispute game infrastructure.
/// @dev A mock VM for the purpose of testing the dispute game infrastructure. Note that this only works
/// for games with an execution trace subgame max depth of 3 (8 instructions per subgame).
contract AlphabetVM2 is IBigStepper {
Claim internal immutable ABSOLUTE_PRESTATE;
IPreimageOracle public oracle;
......@@ -23,17 +24,17 @@ contract AlphabetVM2 is IBigStepper {
bytes32 _localContext
)
external
view
returns (bytes32 postState_)
{
uint256 traceIndex;
uint256 claim;
if ((keccak256(_stateData) << 8) == (Claim.unwrap(ABSOLUTE_PRESTATE) << 8)) {
// If the state data is empty, then the absolute prestate is the claim.
// NOTE: this is wrong, need to fix. Pad to current trace index + claim.
// right now this adds local data into the oracle for whatever reason.
traceIndex = 0;
(claim) = abi.decode(_stateData, (uint256));
claim = claim + uint256(oracle.loadLocalData(4, _localContext, 0, 8, 0));
(bytes32 dat,) = oracle.readPreimage(PreimageKeyLib.localizeIdent(4, _localContext), 0);
uint256 startingL2BlockNumber = (uint256(dat) >> 128) & 0xFFFFFFFF;
traceIndex = (2 ** 4) * startingL2BlockNumber;
claim = traceIndex - 1;
} else {
// Otherwise, decode the state data.
(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