Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
590d2b79
Unverified
Commit
590d2b79
authored
Jun 23, 2023
by
clabby
Committed by
GitHub
Jun 23, 2023
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #6112 from ethereum-optimism/clabby/dispute/hotswap-vm
feat(ctb): Modular VM for `FaultDisputeGame`
parents
e4985632
9d68af5b
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
198 additions
and
108 deletions
+198
-108
.gas-snapshot
packages/contracts-bedrock/.gas-snapshot
+8
-8
FaultDisputeGame.sol
.../contracts-bedrock/contracts/dispute/FaultDisputeGame.sol
+22
-13
IBigStepper.sol
...acts-bedrock/contracts/dispute/interfaces/IBigStepper.sol
+34
-0
LibPosition.sol
...s/contracts-bedrock/contracts/dispute/lib/LibPosition.sol
+20
-0
FaultDisputeGame.t.sol
...s/contracts-bedrock/contracts/test/FaultDisputeGame.t.sol
+114
-87
No files found.
packages/contracts-bedrock/.gas-snapshot
View file @
590d2b79
...
...
@@ -32,12 +32,12 @@ DisputeGameFactory_SetImplementation_Test:test_setImplementation_notOwner_revert
DisputeGameFactory_SetImplementation_Test:test_setImplementation_succeeds() (gas: 44243)
DisputeGameFactory_TransferOwnership_Test:test_transferOwnership_notOwner_reverts() (gas: 15950)
DisputeGameFactory_TransferOwnership_Test:test_transferOwnership_succeeds() (gas: 18642)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot2:test_resolvesCorrectly_succeeds() (gas:
497198
)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot
4:test_resolvesCorrectly_succeeds() (gas: 499064
)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot:test_resolvesCorrectly_succeeds() (gas: 4
89092
)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot2:test_resolvesCorrectly_succeeds() (gas:
49406
7)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot3:test_resolvesCorrectly_succeeds() (gas:
495933
)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot:test_resolvesCorrectly_succeeds() (gas: 4
8596
1)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot2:test_resolvesCorrectly_succeeds() (gas:
502842
)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot
3:test_resolvesCorrectly_succeeds() (gas: 504699
)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot:test_resolvesCorrectly_succeeds() (gas: 4
92706
)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot2:test_resolvesCorrectly_succeeds() (gas:
50171
7)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot3:test_resolvesCorrectly_succeeds() (gas:
503574
)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot:test_resolvesCorrectly_succeeds() (gas: 4
9158
1)
FaultDisputeGame_Test:test_defendRoot_invalidMove_reverts() (gas: 13250)
FaultDisputeGame_Test:test_extraData_succeeds() (gas: 17409)
FaultDisputeGame_Test:test_gameData_succeeds() (gas: 17834)
...
...
@@ -49,10 +49,10 @@ FaultDisputeGame_Test:test_move_duplicateClaim_reverts() (gas: 103231)
FaultDisputeGame_Test:test_move_gameDepthExceeded_reverts() (gas: 407967)
FaultDisputeGame_Test:test_move_gameNotInProgress_reverts() (gas: 10923)
FaultDisputeGame_Test:test_move_nonExistentParent_reverts() (gas: 24632)
FaultDisputeGame_Test:test_resolve_challengeContested() (gas: 2210
74
)
FaultDisputeGame_Test:test_resolve_challengeContested() (gas: 2210
68
)
FaultDisputeGame_Test:test_resolve_notInProgress_reverts() (gas: 9657)
FaultDisputeGame_Test:test_resolve_rootContested() (gas: 106120)
FaultDisputeGame_Test:test_resolve_rootUncontested() (gas: 236
30
)
FaultDisputeGame_Test:test_resolve_rootUncontested() (gas: 236
24
)
FaultDisputeGame_Test:test_resolve_teamDeathmatch() (gas: 391731)
FaultDisputeGame_Test:test_rootClaim_succeeds() (gas: 8203)
FaultDisputeGame_Test:test_simpleAttack_succeeds() (gas: 107322)
...
...
packages/contracts-bedrock/contracts/dispute/FaultDisputeGame.sol
View file @
590d2b79
...
...
@@ -6,6 +6,7 @@ import { IVersioned } from "./interfaces/IVersioned.sol";
import { IFaultDisputeGame } from "./interfaces/IFaultDisputeGame.sol";
import { IInitializable } from "./interfaces/IInitializable.sol";
import { IBondManager } from "./interfaces/IBondManager.sol";
import { IBigStepper } from "./interfaces/IBigStepper.sol";
import { Clone } from "../libraries/Clone.sol";
import { LibHashing } from "./lib/LibHashing.sol";
...
...
@@ -29,6 +30,9 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
/// @notice The max depth of the game.
uint256 public immutable MAX_GAME_DEPTH;
/// @notice A hypervisor that performs single instruction steps on a fault proof program trace.
IBigStepper public immutable VM;
/// @notice The duration of the game.
/// @dev TODO: Account for resolution buffer. (?)
Duration internal constant GAME_DURATION = Duration.wrap(7 days);
...
...
@@ -55,9 +59,14 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
mapping(ClaimHash => bool) internal claims;
/// @param _absolutePrestate The absolute prestate of the instruction trace.
constructor(Claim _absolutePrestate, uint256 _maxGameDepth) {
constructor(
Claim _absolutePrestate,
uint256 _maxGameDepth,
IBigStepper _vm
) {
ABSOLUTE_PRESTATE = _absolutePrestate;
MAX_GAME_DEPTH = _maxGameDepth;
VM = _vm;
}
////////////////////////////////////////////////////////////////
...
...
@@ -79,8 +88,8 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
uint256 _stateIndex,
uint256 _claimIndex,
bool _isAttack,
bytes calldata,
bytes calldata
bytes calldata
_stateData
,
bytes calldata
_proof
) external {
// Steps cannot be made unless the game is currently in progress.
if (status != GameStatus.IN_PROGRESS) {
...
...
@@ -127,19 +136,19 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
postStateClaim = claimData[_stateIndex].claim;
}
// Assert that the given prestate commits to the instruction at `gindex - 1`.
// Assert that the given prestate commits to the instruction at `gindex - 1` and
// that the `_stateData` is the preimage for the prestate claim digest.
if (
Position.unwrap(preStatePos.rightIndex(MAX_GAME_DEPTH)) !=
Position.unwrap(postStatePos.rightIndex(MAX_GAME_DEPTH)) - 1
Position.unwrap(postStatePos.rightIndex(MAX_GAME_DEPTH)) - 1 ||
keccak256(_stateData) != Claim.unwrap(preStateClaim)
) {
revert InvalidPrestate();
}
}
// TODO: Call `MIPS.sol#step` to verify the step.
// For now, we just use a simple state transition function that increments the prestate,
// `s_p`, by 1.
if (uint256(Claim.unwrap(preStateClaim)) + 1 == uint256(Claim.unwrap(postStateClaim))) {
// Perform the VM step and check to see if it is valid.
if (VM.step(_stateData, _proof) == Claim.unwrap(postStateClaim)) {
revert ValidStep();
}
...
...
@@ -274,7 +283,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
// Search for the left-most dangling non-bottom node
// The most recent claim is always a dangling, non-bottom node so we start with that
uint256 leftMostIndex = claimData.length - 1;
Position leftMostTraceIndex = Position.wrap(type(uint128).max)
;
uint256 leftMostTraceIndex = type(uint128).max
;
for (uint256 i = leftMostIndex; i < type(uint64).max; ) {
// Fetch the claim at the current index.
ClaimData storage claim = claimData[i];
...
...
@@ -295,8 +304,8 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
// If the claim is a dangling node, we can check if it is the left-most
// dangling node we've come across so far. If it is, we can update the
// left-most trace index.
Position traceIndex = claimPos.right
Index(MAX_GAME_DEPTH);
if (
Position.unwrap(traceIndex) < Position.unwrap(leftMostTraceIndex)
) {
uint256 traceIndex = claimPos.trace
Index(MAX_GAME_DEPTH);
if (
traceIndex < leftMostTraceIndex
) {
leftMostTraceIndex = traceIndex;
unchecked {
leftMostIndex = i + 1;
...
...
@@ -309,7 +318,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
if (
// slither-disable-next-line weak-prng
claimData[leftMostIndex].position.depth() % 2 == 0 &&
Position.unwrap(leftMostTraceIndex)
!= type(uint128).max
leftMostTraceIndex
!= type(uint128).max
) {
status_ = GameStatus.DEFENDER_WINS;
} else {
...
...
packages/contracts-bedrock/contracts/dispute/interfaces/IBigStepper.sol
0 → 100644
View file @
590d2b79
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
/// @title IBigStepper
/// @notice An interface for a contract with a state transition function that
/// will accept a pre state and return a post state.
/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣼⠶⢅⠒⢄⢔⣶⡦⣤⡤⠄⣀⠀⠀⠀⠀⠀⠀⠀
/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠨⡏⠀⠀⠈⠢⣙⢯⣄⠀⢨⠯⡺⡘⢄⠀⠀⠀⠀⠀
/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣶⡆⠀⠀⠀⠀⠈⠓⠬⡒⠡⣀⢙⡜⡀⠓⠄⠀⠀⠀
/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⡷⠿⣧⣀⡀⠀⠀⠀⠀⠀⠀⠉⠣⣞⠩⠥⠀⠼⢄⠀⠀
/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⡇⠀⠀⠀⠉⢹⣶⠒⠒⠂⠈⠉⠁⠘⡆⠀⣿⣿⠫⡄⠀
/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⢶⣤⣀⡀⠀⠀⢸⡿⠀⠀⠀⠀⠀⢀⠞⠀⠀⢡⢨⢀⡄⠀
/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⡒⣿⢿⡤⠝⡣⠉⠁⠚⠛⠀⠤⠤⣄⡰⠁⠀⠀⠀⠉⠙⢸⠀⠀
/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡤⢯⡌⡿⡇⠘⡷⠀⠁⠀⠀⢀⣰⠢⠲⠛⣈⣸⠦⠤⠶⠴⢬⣐⣊⡂⠀
/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣤⡪⡗⢫⠞⠀⠆⣀⠻⠤⠴⠐⠚⣉⢀⠦⠂⠋⠁⠀⠁⠀⠀⠀⠀⢋⠉⠇⠀
/// ⠀⠀⠀⠀⣀⡤⠐⠒⠘⡹⠉⢸⠇⠸⠀⠀⠀⠀⣀⣤⠴⠚⠉⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠼⠀⣾⠀
/// ⠀⠀⠀⡰⠀⠉⠉⠀⠁⠀⠀⠈⢇⠈⠒⠒⠘⠈⢀⢡⡂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⠀⢸⡄
/// ⠀⠀⠸⣿⣆⠤⢀⡀⠀⠀⠀⠀⢘⡌⠀⠀⣀⣀⣀⡈⣤⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⢸⡇
/// ⠀⠀⢸⣀⠀⠉⠒⠐⠛⠋⠭⠭⠍⠉⠛⠒⠒⠒⠀⠒⠚⠛⠛⠛⠩⠭⠭⠭⠭⠤⠤⠤⠤⠤⠭⠭⠉⠓⡆
/// ⠀⠀⠘⠿⣷⣶⣤⣤⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣤⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇
/// ⠀⠀⠀⠀⠀⠉⠙⠛⠛⠻⠿⢿⣿⣿⣷⣶⣶⣶⣤⣤⣀⣁⣛⣃⣒⠿⠿⠿⠤⠠⠄⠤⠤⢤⣛⣓⣂⣻⡇
/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠉⠉⠙⠛⠻⠿⠿⠿⢿⣿⣿⣿⣷⣶⣶⣾⣿⣿⣿⣿⠿⠟⠁
/// ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠈⠉⠉⠉⠉⠁⠀⠀⠀⠀⠀
interface IBigStepper {
/// @notice Performs a single instruction step from a given prestate and returns the poststate
/// hash.
/// @param _stateData The preimage of the prestate hash.
/// @param _proof A proof for the inclusion of the prestate's memory in the merkle tree.
/// @return postState_ The poststate hash after the instruction step.
function step(bytes calldata _stateData, bytes calldata _proof)
external
returns (bytes32 postState_);
}
packages/contracts-bedrock/contracts/dispute/lib/LibPosition.sol
View file @
590d2b79
...
...
@@ -104,6 +104,26 @@ library LibPosition {
}
}
/// @notice Get the deepest, right most trace index relative to the `position`. This is
/// equivalent to calling `right` on a position until the maximum depth is reached and
/// then finding its index at depth.
/// @param _position The position to get the relative trace index of.
/// @param _maxDepth The maximum depth of the game.
/// @return traceIndex_ The trace index relative to the `position`.
function traceIndex(
Position _position,
uint256 _maxDepth
) internal pure returns (uint256 traceIndex_) {
uint256 msb = depth(_position);
assembly {
let remaining := sub(_maxDepth, msb)
traceIndex_ := sub(
or(shl(remaining, _position), sub(shl(remaining, 1), 1)),
shl(_maxDepth, 1)
)
}
}
/// @notice Get the move position of `_position`, which is the left child of:
/// 1. `_position + 1` if `_isAttack` is true.
/// 1. `_position` if `_isAttack` is false.
...
...
packages/contracts-bedrock/contracts/test/FaultDisputeGame.t.sol
View file @
590d2b79
...
...
@@ -11,6 +11,7 @@ import "../libraries/DisputeTypes.sol";
import "../libraries/DisputeErrors.sol";
import { LibClock } from "../dispute/lib/LibClock.sol";
import { LibPosition } from "../dispute/lib/LibPosition.sol";
import { IBigStepper } from "../dispute/interfaces/IBigStepper.sol";
contract FaultDisputeGame_Init is DisputeGameFactory_Init {
/// @dev The extra data passed to the game for initialization.
...
...
@@ -28,7 +29,7 @@ contract FaultDisputeGame_Init is DisputeGameFactory_Init {
function init(Claim rootClaim, Claim absolutePrestate) public {
super.setUp();
// Deploy an implementation of the fault game
gameImpl = new FaultDisputeGame(absolutePrestate, 4);
gameImpl = new FaultDisputeGame(absolutePrestate, 4
, new AlphabetVM(absolutePrestate)
);
// Register the game implementation with the factory.
factory.setImplementation(GAME_TYPE, gameImpl);
// Create a new game.
...
...
@@ -296,10 +297,10 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init {
contract GamePlayer {
bool public failedToStep;
FaultDisputeGame public gameProxy;
bytes public trace;
GamePlayer internal counterParty;
Vm internal vm;
bytes internal trace;
uint256 internal maxDepth;
/// @notice Initializes the player
...
...
@@ -307,7 +308,7 @@ contract GamePlayer {
FaultDisputeGame _gameProxy,
GamePlayer _counterParty,
Vm _vm
) public
virtual
{
) public {
gameProxy = _gameProxy;
counterParty = _counterParty;
vm = _vm;
...
...
@@ -366,8 +367,9 @@ contract GamePlayer {
// If we are past the maximum depth, break the recursion and step.
if (movePos.depth() > maxDepth) {
// Perform a step.
uint256 stateIndex;
bytes memory preStateTrace;
// 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
// move position is 0, the prestate is the absolute prestate and we need to
...
...
@@ -397,17 +399,24 @@ contract GamePlayer {
break;
}
}
// Grab the trace up to the prestate's trace index.
if (isAttack) {
preStateTrace = abi.encode(statePos.traceIndex(maxDepth), traceAt(statePos));
} else {
preStateTrace = abi.encode(parentPos.traceIndex(maxDepth), traceAt(parentPos));
}
}
// Perform the step and halt recursion.
try gameProxy.step(stateIndex, _parentIndex, isAttack,
hex""
, hex"") {
try gameProxy.step(stateIndex, _parentIndex, isAttack,
preStateTrace
, hex"") {
// Do nothing, step succeeded.
} catch {
failedToStep = true;
}
} else {
// Find the trace index that our next claim must commit to.
uint256 traceIndex = movePos.
rightIndex(maxDepth).indexAtDepth(
);
uint256 traceIndex = movePos.
traceIndex(maxDepth
);
// Grab the claim that we need to make from the helper.
Claim ourClaim = claimAt(traceIndex);
...
...
@@ -439,151 +448,156 @@ contract GamePlayer {
return uint256(vm.load(address(gameProxy), bytes32(uint256(1))));
}
/// @notice Returns the player's claim that commits to a given gindex.
function claimAt(Position _position) internal view returns (Claim claim_) {
return claimAt(_position.rightIndex(maxDepth).indexAtDepth());
/// @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(maxDepth));
}
/// @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(trace[_traceIndex]));
}
/// @notice Returns the player's claim that commits to a given trace index.
function claimAt(uint256 _traceIndex) public view returns (Claim claim_) {
return Claim.wrap(bytes32(uint256(bytes32(trace[_traceIndex]) >> 248)));
return Claim.wrap(keccak256(abi.encode(_traceIndex, traceAt(_traceIndex))));
}
/// @notice Returns the player's claim that commits to a given trace index.
function claimAt(Position _position) public view returns (Claim claim_) {
return claimAt(_position.traceIndex(maxDepth));
}
}
contract OneVsOne_Arena is FaultDisputeGame_Init {
/// @dev The absolute prestate of the trace.
Claim internal constant ABSOLUTE_PRESTATE = Claim.wrap(bytes32(uint256(15)));
/// @dev The
honest participant
.
GamePlayer internal
honest
;
/// @dev The
dishonest participant
.
GamePlayer internal
dishonest
;
/// @dev The
defender
.
GamePlayer internal
defender
;
/// @dev The
challenger
.
GamePlayer internal
challenger
;
function init(
GamePlayer _honest,
GamePlayer _dishonest,
Claim _rootClaim
) public {
super.init(_rootClaim, ABSOLUTE_PRESTATE);
// Deploy a new honest player.
honest = _honest;
// Deploy a new dishonest player.
dishonest = _dishonest;
function init(GamePlayer _defender, GamePlayer _challenger) public {
Claim rootClaim = Claim.wrap(keccak256(abi.encode(15, _defender.traceAt(15))));
super.init(rootClaim, ABSOLUTE_PRESTATE);
defender = _defender;
challenger = _challenger;
// Set the counterparties.
honest.init(gameProxy, dishonest
, vm);
dishonest.init(gameProxy, honest
, vm);
defender.init(gameProxy, challenger
, vm);
challenger.init(gameProxy, defender
, vm);
// Label actors for trace.
vm.label(address(
honest), "HonestPlay
er");
vm.label(address(d
ishonest), "DishonestPlay
er");
vm.label(address(
challenger), "Challeng
er");
vm.label(address(d
efender), "Defend
er");
}
}
contract FaultDisputeGame_ResolvesCorrectly_IncorrectRoot is OneVsOne_Arena {
function setUp() public override {
GamePlayer honest = new HonestPlayer();
GamePlayer dishonest = new FullyDivergentPlayer();
super.init(
honest, dishonest, Claim.wrap(bytes32(uint256(30)))
);
GamePlayer honest = new HonestPlayer(
ABSOLUTE_PRESTATE
);
GamePlayer dishonest = new FullyDivergentPlayer(
ABSOLUTE_PRESTATE
);
super.init(
dishonest, honest
);
}
function test_resolvesCorrectly_succeeds() public {
// Play the game until a step is forced.
honest
.play(0);
challenger
.play(0);
// Resolve the game and assert that the honest player challenged the root
// claim successfully.
assertEq(uint8(gameProxy.resolve()), uint8(GameStatus.CHALLENGER_WINS));
assertFalse(
honest
.failedToStep());
assertFalse(
defender
.failedToStep());
}
}
contract FaultDisputeGame_ResolvesCorrectly_CorrectRoot is OneVsOne_Arena {
function setUp() public override {
GamePlayer honest = new HonestPlayer();
GamePlayer dishonest = new FullyDivergentPlayer();
super.init(honest, dishonest
, Claim.wrap(bytes32(uint256(31)))
);
GamePlayer honest = new HonestPlayer(
ABSOLUTE_PRESTATE
);
GamePlayer dishonest = new FullyDivergentPlayer(
ABSOLUTE_PRESTATE
);
super.init(honest, dishonest);
}
function test_resolvesCorrectly_succeeds() public {
// Play the game until a step is forced.
dishonest
.play(0);
challenger
.play(0);
// Resolve the game and assert that the dishonest player challenged the root
// claim unsuccessfully.
assertEq(uint8(gameProxy.resolve()), uint8(GameStatus.DEFENDER_WINS));
assertTrue(
dishonest
.failedToStep());
assertTrue(
challenger
.failedToStep());
}
}
contract FaultDisputeGame_ResolvesCorrectly_IncorrectRoot2 is OneVsOne_Arena {
function setUp() public override {
GamePlayer honest = new HonestPlayer();
GamePlayer dishonest = new HalfDivergentPlayer();
super.init(
honest, dishonest, Claim.wrap(bytes32(uint256(15)))
);
GamePlayer honest = new HonestPlayer(
ABSOLUTE_PRESTATE
);
GamePlayer dishonest = new HalfDivergentPlayer(
ABSOLUTE_PRESTATE
);
super.init(
dishonest, honest
);
}
function test_resolvesCorrectly_succeeds() public {
// Play the game until a step is forced.
honest
.play(0);
challenger
.play(0);
// Resolve the game and assert that the honest player challenged the root
// claim successfully.
assertEq(uint8(gameProxy.resolve()), uint8(GameStatus.CHALLENGER_WINS));
assertFalse(
honest
.failedToStep());
assertFalse(
defender
.failedToStep());
}
}
contract FaultDisputeGame_ResolvesCorrectly_CorrectRoot2 is OneVsOne_Arena {
function setUp() public override {
GamePlayer honest = new HonestPlayer();
GamePlayer dishonest = new HalfDivergentPlayer();
super.init(honest, dishonest
, Claim.wrap(bytes32(uint256(31)))
);
GamePlayer honest = new HonestPlayer(
ABSOLUTE_PRESTATE
);
GamePlayer dishonest = new HalfDivergentPlayer(
ABSOLUTE_PRESTATE
);
super.init(honest, dishonest);
}
function test_resolvesCorrectly_succeeds() public {
// Play the game until a step is forced.
dishonest
.play(0);
challenger
.play(0);
// Resolve the game and assert that the dishonest player challenged the root
// claim unsuccessfully.
assertEq(uint8(gameProxy.resolve()), uint8(GameStatus.DEFENDER_WINS));
assertTrue(
dishonest
.failedToStep());
assertTrue(
challenger
.failedToStep());
}
}
contract FaultDisputeGame_ResolvesCorrectly_IncorrectRoot3 is OneVsOne_Arena {
function setUp() public override {
GamePlayer honest = new HonestPlayer();
GamePlayer dishonest = new EarlyDivergentPlayer();
super.init(
honest, dishonest, Claim.wrap(bytes32(uint256(15)))
);
GamePlayer honest = new HonestPlayer(
ABSOLUTE_PRESTATE
);
GamePlayer dishonest = new EarlyDivergentPlayer(
ABSOLUTE_PRESTATE
);
super.init(
dishonest, honest
);
}
function test_resolvesCorrectly_succeeds() public {
// Play the game until a step is forced.
honest
.play(0);
challenger
.play(0);
// Resolve the game and assert that the honest player challenged the root
// claim successfully.
assertEq(uint8(gameProxy.resolve()), uint8(GameStatus.CHALLENGER_WINS));
assertFalse(
honest
.failedToStep());
assertFalse(
defender
.failedToStep());
}
}
contract FaultDisputeGame_ResolvesCorrectly_CorrectRoot
4
is OneVsOne_Arena {
contract FaultDisputeGame_ResolvesCorrectly_CorrectRoot
3
is OneVsOne_Arena {
function setUp() public override {
GamePlayer honest = new HonestPlayer();
GamePlayer dishonest = new EarlyDivergentPlayer();
super.init(honest, dishonest
, Claim.wrap(bytes32(uint256(31)))
);
GamePlayer honest = new HonestPlayer(
ABSOLUTE_PRESTATE
);
GamePlayer dishonest = new EarlyDivergentPlayer(
ABSOLUTE_PRESTATE
);
super.init(honest, dishonest);
}
function test_resolvesCorrectly_succeeds() public {
// Play the game until a step is forced.
dishonest
.play(0);
challenger
.play(0);
// Resolve the game and assert that the dishonest player challenged the root
// claim unsuccessfully.
assertEq(uint8(gameProxy.resolve()), uint8(GameStatus.DEFENDER_WINS));
assertTrue(
dishonest
.failedToStep());
assertTrue(
challenger
.failedToStep());
}
}
...
...
@@ -592,13 +606,8 @@ contract FaultDisputeGame_ResolvesCorrectly_CorrectRoot4 is OneVsOne_Arena {
////////////////////////////////////////////////////////////////
contract HonestPlayer is GamePlayer {
function init(
FaultDisputeGame _gameProxy,
GamePlayer _counterParty,
Vm _vm
) public virtual override {
super.init(_gameProxy, _counterParty, _vm);
uint8 absolutePrestate = uint8(uint256(Claim.unwrap(_gameProxy.ABSOLUTE_PRESTATE())));
constructor(Claim _absolutePrestate) {
uint8 absolutePrestate = uint8(uint256(Claim.unwrap(_absolutePrestate)));
bytes memory honestTrace = new bytes(16);
for (uint8 i = 0; i < honestTrace.length; i++) {
honestTrace[i] = bytes1(absolutePrestate + i + 1);
...
...
@@ -608,13 +617,8 @@ contract HonestPlayer is GamePlayer {
}
contract FullyDivergentPlayer is GamePlayer {
function init(
FaultDisputeGame _gameProxy,
GamePlayer _counterParty,
Vm _vm
) public virtual override {
super.init(_gameProxy, _counterParty, _vm);
uint8 absolutePrestate = uint8(uint256(Claim.unwrap(_gameProxy.ABSOLUTE_PRESTATE())));
constructor(Claim _absolutePrestate) {
uint8 absolutePrestate = uint8(uint256(Claim.unwrap(_absolutePrestate)));
bytes memory dishonestTrace = new bytes(16);
for (uint8 i = 0; i < dishonestTrace.length; i++) {
// Offset the honest trace by 1.
...
...
@@ -625,13 +629,8 @@ contract FullyDivergentPlayer is GamePlayer {
}
contract HalfDivergentPlayer is GamePlayer {
function init(
FaultDisputeGame _gameProxy,
GamePlayer _counterParty,
Vm _vm
) public virtual override {
super.init(_gameProxy, _counterParty, _vm);
uint8 absolutePrestate = uint8(uint256(Claim.unwrap(_gameProxy.ABSOLUTE_PRESTATE())));
constructor(Claim _absolutePrestate) {
uint8 absolutePrestate = uint8(uint256(Claim.unwrap(_absolutePrestate)));
bytes memory dishonestTrace = new bytes(16);
for (uint8 i = 0; i < dishonestTrace.length; i++) {
// Offset the trace after the first half.
...
...
@@ -642,13 +641,8 @@ contract HalfDivergentPlayer is GamePlayer {
}
contract EarlyDivergentPlayer is GamePlayer {
function init(
FaultDisputeGame _gameProxy,
GamePlayer _counterParty,
Vm _vm
) public virtual override {
super.init(_gameProxy, _counterParty, _vm);
uint8 absolutePrestate = uint8(uint256(Claim.unwrap(_gameProxy.ABSOLUTE_PRESTATE())));
constructor(Claim _absolutePrestate) {
uint8 absolutePrestate = uint8(uint256(Claim.unwrap(_absolutePrestate)));
bytes memory dishonestTrace = new bytes(16);
for (uint8 i = 0; i < dishonestTrace.length; i++) {
// Offset the trace after the first half.
...
...
@@ -657,3 +651,36 @@ contract EarlyDivergentPlayer is GamePlayer {
trace = dishonestTrace;
}
}
////////////////////////////////////////////////////////////////
// MOCK VMS //
////////////////////////////////////////////////////////////////
contract AlphabetVM is IBigStepper {
Claim internal immutable ABSOLUTE_PRESTATE;
constructor(Claim _absolutePrestate) {
ABSOLUTE_PRESTATE = _absolutePrestate;
}
/// @inheritdoc IBigStepper
function step(bytes calldata _stateData, bytes calldata)
external
view
returns (bytes32 postState_)
{
uint256 traceIndex;
uint256 claim;
if (_stateData.length == 0) {
// If the state data is empty, then the absolute prestate is the claim.
traceIndex = 0;
claim = uint256(Claim.unwrap(ABSOLUTE_PRESTATE));
} else {
// Otherwise, decode the state data.
(traceIndex, claim) = abi.decode(_stateData, (uint256, uint256));
traceIndex++;
}
// STF: n -> n + 1
postState_ = keccak256(abi.encode(traceIndex, claim + 1));
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment