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
b1a1a154
Commit
b1a1a154
authored
Dec 08, 2023
by
clabby
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
some actor tests
parent
0a9d6b10
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
215 additions
and
98 deletions
+215
-98
OutputBisectionActors.sol
...s/contracts-bedrock/test/actors/OutputBisectionActors.sol
+85
-61
OutputBisectionGame.t.sol
.../contracts-bedrock/test/dispute/OutputBisectionGame.t.sol
+129
-36
AlphabetVM2.sol
packages/contracts-bedrock/test/mocks/AlphabetVM2.sol
+1
-1
No files found.
packages/contracts-bedrock/test/actors/OutputBisectionActors.sol
View file @
b1a1a154
...
@@ -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,
output
At(_movePos), isAttack))
data: abi.encodeCall(OutputBisectionGame.move, (_challengeIndex,
claim
At(_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
claim
At(uint256 _traceIndex) public view returns (Claim claim_) {
function
statehash
At(uint256 _traceIndex) public view returns (Claim claim_) {
bytes32 hash =
bytes32 hash =
keccak256(abi.encode(_traceIndex >= trace.length ? trace.length - 1 : _traceIndex,
trac
eAt(_traceIndex)));
keccak256(abi.encode(_traceIndex >= trace.length ? trace.length - 1 : _traceIndex,
stat
eAt(_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;
}
}
}
}
}
}
packages/contracts-bedrock/test/dispute/OutputBisectionGame.t.sol
View file @
b1a1a154
...
@@ -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))
}
}
}
}
packages/contracts-bedrock/test/mocks/AlphabetVM2.sol
View file @
b1a1a154
...
@@ -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));
...
...
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