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
ed8c2527
Commit
ed8c2527
authored
Dec 08, 2023
by
clabby
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
:broom:
parent
9ee84e27
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
144 additions
and
112 deletions
+144
-112
OutputBisectionActors.sol
...s/contracts-bedrock/test/actors/OutputBisectionActors.sol
+76
-77
OutputBisectionGame.t.sol
.../contracts-bedrock/test/dispute/OutputBisectionGame.t.sol
+68
-35
No files found.
packages/contracts-bedrock/test/actors/OutputBisectionActors.sol
View file @
ed8c2527
...
@@ -16,16 +16,16 @@ import "src/libraries/DisputeTypes.sol";
...
@@ -16,16 +16,16 @@ import "src/libraries/DisputeTypes.sol";
abstract contract GameSolver is CommonBase {
abstract contract GameSolver is CommonBase {
/// @notice The `OutputBisectionGame` proxy that the `GameSolver` will be solving.
/// @notice The `OutputBisectionGame` proxy that the `GameSolver` will be solving.
OutputBisectionGame public immutable GAME;
OutputBisectionGame public immutable GAME;
/// @notice The maximum length of the execution trace, in bytes. Enforced by the depth of the
/// execution trace bisection game.
uint256 internal immutable MAX_TRACE_LENGTH;
/// @notice The split depth of the game
/// @notice The split depth of the game
uint256 internal immutable SPLIT_DEPTH;
uint256 internal immutable SPLIT_DEPTH;
/// @notice The max depth of the game
/// @notice The max depth of the game
uint256 internal immutable MAX_DEPTH;
uint256 internal immutable MAX_DEPTH;
/// @notice The starting L2 Block Number
/// @notice The maximum L2 block number that the output bisection portion of the position tree
uint256 internal immutable STARTING_L2_BLOCK_NUMBER;
/// can handle.
uint256 internal immutable MAX_L2_BLOCK_NUMBER;
/// @notice The L2 outputs that the `GameSolver` will be representing, keyed by L2 block number - 1.
uint256[] public l2Outputs;
/// @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;
/// @notice The raw absolute prestate data.
/// @notice The raw absolute prestate data.
...
@@ -42,9 +42,7 @@ abstract contract GameSolver is CommonBase {
...
@@ -42,9 +42,7 @@ abstract contract GameSolver is CommonBase {
Attack,
Attack,
Defend,
Defend,
Step,
Step,
AddLocalData,
AddLocalData
ResolveLocal,
ResolveGlobal
}
}
/// @notice The `Move` struct represents a move in the game, and contains information
/// @notice The `Move` struct represents a move in the game, and contains information
...
@@ -57,15 +55,16 @@ abstract contract GameSolver is CommonBase {
...
@@ -57,15 +55,16 @@ abstract contract GameSolver is CommonBase {
constructor(
constructor(
OutputBisectionGame _gameProxy,
OutputBisectionGame _gameProxy,
uint256[] memory _l2Outputs,
bytes memory _trace,
bytes memory _trace,
bytes memory _preStateData,
bytes memory _preStateData
uint256 _startingL2BlockNumber
) {
) {
GAME = _gameProxy;
GAME = _gameProxy;
MAX_TRACE_LENGTH = 2 ** (_gameProxy.MAX_GAME_DEPTH() - _gameProxy.SPLIT_DEPTH());
SPLIT_DEPTH = GAME.SPLIT_DEPTH();
SPLIT_DEPTH = GAME.SPLIT_DEPTH();
MAX_DEPTH = GAME.MAX_GAME_DEPTH();
MAX_DEPTH = GAME.MAX_GAME_DEPTH();
STARTING_L2_BLOCK_NUMBER = _startingL2BlockNumber;
MAX_L2_BLOCK_NUMBER = 2 ** (MAX_DEPTH - SPLIT_DEPTH);
l2Outputs = _l2Outputs;
trace = _trace;
trace = _trace;
absolutePrestateData = _preStateData;
absolutePrestateData = _preStateData;
}
}
...
@@ -90,17 +89,15 @@ contract HonestGameSolver is GameSolver {
...
@@ -90,17 +89,15 @@ contract HonestGameSolver is GameSolver {
constructor(
constructor(
OutputBisectionGame _gameProxy,
OutputBisectionGame _gameProxy,
uint256[] memory _l2Outputs,
bytes memory _trace,
bytes memory _trace,
bytes memory _preStateData,
bytes memory _preStateData
uint256 _startingL2BlockNumber
)
)
GameSolver(_gameProxy, _
trace, _preStateData, _startingL2BlockNumber
)
GameSolver(_gameProxy, _
l2Outputs, _trace, _preStateData
)
{
{
// 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.
if (Claim.unwrap(outputAt(MAX_TRACE_LENGTH)) == Claim.unwrap(_gameProxy.rootClaim())) {
agreeWithRoot = Claim.unwrap(outputAt(MAX_L2_BLOCK_NUMBER)) == Claim.unwrap(_gameProxy.rootClaim());
agreeWithRoot = true;
}
}
}
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
...
@@ -114,9 +111,9 @@ contract HonestGameSolver is GameSolver {
...
@@ -114,9 +111,9 @@ contract HonestGameSolver is GameSolver {
// Pre-allocate the `moves_` array to the maximum possible length. Test environment, so
// Pre-allocate the `moves_` array to the maximum possible length. Test environment, so
// over-allocation is fine, and more easy to read than making a linked list in asm.
// over-allocation is fine, and more easy to read than making a linked list in asm.
uint256 movesLen = 0;
moves_ = new Move[](numClaims - processedBuf);
moves_ = new Move[](numClaims - processedBuf);
uint256 numMoves = 0;
for (uint256 i = processedBuf; i < numClaims; i++) {
for (uint256 i = processedBuf; i < numClaims; i++) {
// Grab the observed claim.
// Grab the observed claim.
IOutputBisectionGame.ClaimData memory observed = getClaimData(i);
IOutputBisectionGame.ClaimData memory observed = getClaimData(i);
...
@@ -127,21 +124,19 @@ contract HonestGameSolver is GameSolver {
...
@@ -127,21 +124,19 @@ 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() <= SPLIT_DEPTH) {
if (movePos.depth() <= MAX_DEPTH) {
// output bisection
// bisection
moves_[movesLen++] = handleOutputBisectionMove(moveDirection, movePos, i);
moves_[numMoves++] = handleBisectionMove(moveDirection, movePos, i);
} else if (movePos.depth() <= MAX_DEPTH) {
// execution trace bisection
moves_[movesLen++] = handleExecutionTraceBisectionMove(moveDirection, movePos, i);
} else {
} else {
// instruction step
// instruction step
moves_[
movesLen
++] = handleStepMove(moveDirection, observed.position, movePos, i);
moves_[
numMoves
++] = handleStepMove(moveDirection, observed.position, movePos, i);
}
}
}
}
// Update the length of the `moves_` array to the number of moves that were added.
// Update the length of the `moves_` array to the number of moves that were added. This is
// always a no-op or a truncation operation.
assembly {
assembly {
mstore(moves_,
movesLen
)
mstore(moves_,
numMoves
)
}
}
// Increment `processedBuf` by the number of claims processed, so that next time around,
// Increment `processedBuf` by the number of claims processed, so that next time around,
...
@@ -170,26 +165,25 @@ contract HonestGameSolver is GameSolver {
...
@@ -170,26 +165,25 @@ contract HonestGameSolver is GameSolver {
direction_ = Direction.Attack;
direction_ = Direction.Attack;
movePos_ = _claimData.position.move(true);
movePos_ = _claimData.position.move(true);
} else {
} else {
// If the parent claim is not the root claim, check if we disagree with it and/or its grandparent
// If the parent claim is not the root claim, first check if the observed claim is on a level that
// to determine our next move.
// agrees with the local view of the root claim. If it is, noop. If it is not, perform an attack or
// defense depending on the local view of the observed claim.
// Fetch the local opinion of the parent claim.
Claim localParent = claimAt(_claimData.position);
bool localAgree = Claim.unwrap(localParent) == Claim.unwrap(_claimData.claim);
if (rightLevel) {
if (rightLevel) {
// Never move against a claim on the right level. Even if it's wrong, if it's uncountered, it furthers
// Never move against a claim on the right level. Even if it's wrong, if it's uncountered, it furthers
// our goals.
// our goals.
return (Direction.Noop, Position.wrap(0));
return (Direction.Noop, Position.wrap(0));
} else {
} else {
// NOTE: Poison not handled yet.
// Fetch the local opinion of the parent claim.
if (!localAgree) {
Claim localParent = claimAt(_claimData.position);
// NOTE: Poison not handled.
if (Claim.unwrap(localParent) != Claim.unwrap(_claimData.claim)) {
// 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 {
} else {
// If we agree with the observed claim, but disagree with the grandparent claim, we must defend
// If we agree with the observed claim, we must defend the observed claim.
// the observed claim.
movePos_ = _claimData.position.move(false);
movePos_ = _claimData.position.move(false);
direction_ = Direction.Defend;
direction_ = Direction.Defend;
}
}
...
@@ -197,31 +191,12 @@ contract HonestGameSolver is GameSolver {
...
@@ -197,31 +191,12 @@ 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 bisection portion
/// portion of the dispute game.
/// of the 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
/// output bisection context. This is enforced by the `solveGame` function.
/// output bisection context. This is enforced by the `solveGame` function.
function handleOutputBisectionMove(
function handleBisectionMove(
Direction _direction,
Position _movePos,
uint256 _challengeIndex
)
internal
view
returns (Move memory move_)
{
bool isAttack = _direction == Direction.Attack;
move_ = Move({
kind: isAttack ? MoveKind.Attack : MoveKind.Defend,
data: abi.encodeCall(OutputBisectionGame.move, (_challengeIndex, claimAt(_movePos), isAttack))
});
}
/// @notice Returns a `Move` struct that represents an attack or defense move in the execution trace
/// bisection portion of the dispute game.
/// @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.
function handleExecutionTraceBisectionMove(
Direction _direction,
Direction _direction,
Position _movePos,
Position _movePos,
uint256 _challengeIndex
uint256 _challengeIndex
...
@@ -255,7 +230,7 @@ contract HonestGameSolver is GameSolver {
...
@@ -255,7 +230,7 @@ contract HonestGameSolver is GameSolver {
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
relative
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 ** (MAX_DEPTH - SPLIT_DEPTH))) > 0) {
if ((_movePos.indexAtDepth() % (2 ** (MAX_DEPTH - SPLIT_DEPTH))) > 0) {
...
@@ -299,13 +274,14 @@ contract HonestGameSolver is GameSolver {
...
@@ -299,13 +274,14 @@ contract HonestGameSolver is GameSolver {
}
}
/// @notice Returns the player's claim that commits to a given position, swapping between
/// @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
/// output bisection claims and execution trace bisection claims depending on the depth.
function claimAt(Position _position) public view returns (Claim claim_) {
/// @dev Prefer this function over `outputAt` or `statehashAt` directly.
function claimAt(Position _position) internal view returns (Claim claim_) {
return _position.depth() > SPLIT_DEPTH ? statehashAt(_position) : outputAt(_position);
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)
internal
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() > SPLIT_DEPTH) {
if (_position.depth() > SPLIT_DEPTH) {
revert("GameSolver: invalid position depth");
revert("GameSolver: invalid position depth");
...
@@ -315,12 +291,12 @@ contract HonestGameSolver is GameSolver {
...
@@ -315,12 +291,12 @@ contract HonestGameSolver is GameSolver {
}
}
/// @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
view returns (Claim claim_) {
function outputAt(uint256 _l2BlockNumber)
internal
view returns (Claim claim_) {
return Claim.wrap(bytes32(
STARTING_L2_BLOCK_NUMBER + _l2BlockNumber
));
return Claim.wrap(bytes32(
l2Outputs[_l2BlockNumber - 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 statehashAt(uint256 _traceIndex)
public
view returns (Claim claim_) {
function statehashAt(uint256 _traceIndex)
internal
view returns (Claim claim_) {
bytes32 hash =
bytes32 hash =
keccak256(abi.encode(_traceIndex >= trace.length ? trace.length - 1 : _traceIndex, stateAt(_traceIndex)));
keccak256(abi.encode(_traceIndex >= trace.length ? trace.length - 1 : _traceIndex, stateAt(_traceIndex)));
assembly {
assembly {
...
@@ -329,23 +305,23 @@ contract HonestGameSolver is GameSolver {
...
@@ -329,23 +305,23 @@ contract HonestGameSolver is GameSolver {
}
}
/// @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 statehashAt(Position _position)
public
view returns (Claim claim_) {
function statehashAt(Position _position)
internal
view returns (Claim claim_) {
return statehashAt(_position.traceIndex(MAX_DEPTH));
return statehashAt(_position.traceIndex(MAX_DEPTH));
}
}
/// @notice Returns the state at the trace index within the player's trace.
/// @notice Returns the state at the trace index within the player's trace.
function stateAt(Position _position)
public
view returns (uint256 state_) {
function stateAt(Position _position)
internal
view returns (uint256 state_) {
return stateAt(_position.traceIndex(MAX_DEPTH));
return stateAt(_position.traceIndex(MAX_DEPTH));
}
}
/// @notice Returns the state at the trace index within the player's trace.
/// @notice Returns the state at the trace index within the player's trace.
function stateAt(uint256 _traceIndex)
public
view returns (uint256 state_) {
function stateAt(uint256 _traceIndex)
internal
view returns (uint256 state_) {
return uint256(uint8(_traceIndex >= trace.length ? trace[trace.length - 1] : trace[_traceIndex]));
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)
internal
view returns (bool isRightLevel_) {
isRightLevel_ = agreeWithRoot == (_position.depth() % 2 == 0);
isRightLevel_ = agreeWithRoot == (_position.depth() % 2 == 0);
}
}
}
}
...
@@ -372,12 +348,12 @@ contract HonestDisputeActor is DisputeActor {
...
@@ -372,12 +348,12 @@ contract HonestDisputeActor is DisputeActor {
constructor(
constructor(
OutputBisectionGame _gameProxy,
OutputBisectionGame _gameProxy,
uint256[] memory _l2Outputs,
bytes memory _trace,
bytes memory _trace,
bytes memory _preStateData,
bytes memory _preStateData
uint256 _startingL2BlockNumber
) {
) {
GAME = _gameProxy;
GAME = _gameProxy;
solver = GameSolver(new HonestGameSolver(_gameProxy, _
trace, _preStateData, _startingL2BlockNumber
));
solver = GameSolver(new HonestGameSolver(_gameProxy, _
l2Outputs, _trace, _preStateData
));
}
}
/// @inheritdoc DisputeActor
/// @inheritdoc DisputeActor
...
@@ -385,10 +361,33 @@ contract HonestDisputeActor is DisputeActor {
...
@@ -385,10 +361,33 @@ contract HonestDisputeActor is DisputeActor {
GameSolver.Move[] memory moves = solver.solveGame();
GameSolver.Move[] memory moves = solver.solveGame();
numMoves_ = moves.length;
numMoves_ = moves.length;
// Optimistically assume success, will be set to false if any move fails.
success_ = true;
success_ = true;
// Perform all available moves given to the actor by the solver.
for (uint256 i = 0; i < moves.length; i++) {
for (uint256 i = 0; i < moves.length; i++) {
(bool innerSuccess,) = address(GAME).call(moves[i].data);
GameSolver.Move memory localMove = moves[i];
success_ = success_ && innerSuccess;
// If the move is a step, we first need to add the starting L2 block number to the `PreimageOracle`
// via the `OutputBisectionGame` contract.
// TODO: This is leaky. Could be another move kind.
if (localMove.kind == GameSolver.MoveKind.Step) {
bytes memory moveData = localMove.data;
uint256 challengeIndex;
assembly {
challengeIndex := mload(add(moveData, 0x24))
}
GAME.addLocalData({
_ident: LocalPreimageKey.STARTING_L2_BLOCK_NUMBER,
_execLeafIdx: challengeIndex,
_partOffset: 0
});
}
(bool innerSuccess,) = address(GAME).call(localMove.data);
assembly {
success_ := and(success_, innerSuccess)
}
}
}
}
}
}
}
packages/contracts-bedrock/test/dispute/OutputBisectionGame.t.sol
View file @
ed8c2527
...
@@ -657,32 +657,37 @@ contract OutputBisection_1v1_Actors_Test is OutputBisectionGame_Init {
...
@@ -657,32 +657,37 @@ contract OutputBisection_1v1_Actors_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_1v1honestRoot_succeeds() public {
function test_static_1v1honestRoot_succeeds() public {
// Create the dispute game with an honest `ROOT_CLAIM`
// Create the dispute game with an honest `ROOT_CLAIM`
bytes memory absolutePrestateData = abi.encode(0);
bytes memory absolutePrestateData = _setup({ _absolutePrestateData: 0, _rootClaim: 16 });
Claim absolutePrestateExec =
_changeClaimStatus(Claim.wrap(keccak256(absolutePrestateData)), VMStatuses.UNFINISHED);
Claim rootClaim = Claim.wrap(bytes32(uint256(0x10)));
super.init({
rootClaim: rootClaim,
absolutePrestate: absolutePrestateExec,
l2BlockNumber: 0x10,
genesisBlockNumber: 0,
genesisOutputRoot: Hash.wrap(bytes32(0))
});
// 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
// The honest trace covers all block -> block + 1 transitions, and is 256 bytes long, consisting
// of bytes [0, 255].
// of bytes [0, 255].
bytes memory honestTrace = new bytes(256);
bytes memory honestTrace = new bytes(256);
for (uint256 i; i < honestTrace.length; i++) {
for (uint256 i; i < honestTrace.length; i++) {
honestTrace[i] = bytes1(uint8(i));
honestTrace[i] = bytes1(uint8(i));
}
}
// The dishonest l2 outputs are from [2, 17] in this game.
uint256[] memory dishonestL2Outputs = new uint256[](16);
for (uint256 i; i < dishonestL2Outputs.length; i++) {
dishonestL2Outputs[i] = i + 2;
}
// 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
// Create actors
_createActors({
_createActors({
_honestTrace: honestTrace,
_honestTrace: honestTrace,
_honestPreStateData: absolutePrestateData,
_honestPreStateData: absolutePrestateData,
_honest
StartingBlock: 0
,
_honest
L2Outputs: honestL2Outputs
,
_dishonestTrace:
new bytes(256)
,
_dishonestTrace:
dishonestTrace
,
_dishonestPreStateData: absolutePrestateData,
_dishonestPreStateData: absolutePrestateData,
_dishonest
StartingBlock: 1
_dishonest
L2Outputs: dishonestL2Outputs
});
});
// Exhaust all moves from both actors
// Exhaust all moves from both actors
...
@@ -696,24 +701,25 @@ contract OutputBisection_1v1_Actors_Test is OutputBisectionGame_Init {
...
@@ -696,24 +701,25 @@ contract OutputBisection_1v1_Actors_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_1v1dishonestRoot_succeeds() public {
function test_static_1v1dishonestRoot_succeeds() public {
// Create the dispute game with an honest `ROOT_CLAIM`
// Create the dispute game with an honest `ROOT_CLAIM`
bytes memory absolutePrestateData = abi.encode(0);
bytes memory absolutePrestateData = _setup({ _absolutePrestateData: 0, _rootClaim: 17 });
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 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
// The honest trace covers all block -> block + 1 transitions, and is 256 bytes long, consisting
// of bytes [0, 255].
// of bytes [0, 255].
bytes memory honestTrace = new bytes(256);
bytes memory honestTrace = new bytes(256);
for (uint256 i; i < honestTrace.length; i++) {
for (uint256 i; i < honestTrace.length; i++) {
honestTrace[i] = bytes1(uint8(i));
honestTrace[i] = bytes1(uint8(i));
}
}
// The dishonest l2 outputs are from [2, 17] in this game.
uint256[] memory dishonestL2Outputs = new uint256[](16);
for (uint256 i; i < dishonestL2Outputs.length; i++) {
dishonestL2Outputs[i] = i + 2;
}
// The dishonest trace covers all block -> block + 1 transitions, and is 256 bytes long, consisting
// The dishonest trace covers all block -> block + 1 transitions, and is 256 bytes long, consisting
// of all zeros.
// of all zeros.
bytes memory dishonestTrace = new bytes(256);
bytes memory dishonestTrace = new bytes(256);
...
@@ -722,40 +728,67 @@ contract OutputBisection_1v1_Actors_Test is OutputBisectionGame_Init {
...
@@ -722,40 +728,67 @@ contract OutputBisection_1v1_Actors_Test is OutputBisectionGame_Init {
_createActors({
_createActors({
_honestTrace: honestTrace,
_honestTrace: honestTrace,
_honestPreStateData: absolutePrestateData,
_honestPreStateData: absolutePrestateData,
_honest
StartingBlock: 0
,
_honest
L2Outputs: honestL2Outputs
,
_dishonestTrace: dishonestTrace,
_dishonestTrace: dishonestTrace,
_dishonestPreStateData: absolutePrestateData,
_dishonestPreStateData: absolutePrestateData,
_dishonest
StartingBlock: 1
_dishonest
L2Outputs: dishonestL2Outputs
});
});
// Exhaust all moves from both actors
// Exhaust all moves from both actors
_exhaustMoves();
_exhaustMoves();
// Resolve the game and assert that the
defend
er won
// Resolve the game and assert that the
challeng
er won
_warpAndResolve();
_warpAndResolve();
assertEq(uint8(gameProxy.status()), uint8(GameStatus.CHALLENGER_WINS));
assertEq(uint8(gameProxy.status()), uint8(GameStatus.CHALLENGER_WINS));
}
}
////////////////////////////////////////////////////////////////
// HELPERS //
////////////////////////////////////////////////////////////////
/// @dev Helper to setup the 1v1 test
function _setup(
uint256 _absolutePrestateData,
uint256 _rootClaim
)
internal
returns (bytes memory absolutePrestateData_)
{
absolutePrestateData_ = abi.encode(_absolutePrestateData);
Claim absolutePrestateExec =
_changeClaimStatus(Claim.wrap(keccak256(absolutePrestateData_)), VMStatuses.UNFINISHED);
Claim rootClaim = Claim.wrap(bytes32(uint256(_rootClaim)));
super.init({
rootClaim: rootClaim,
absolutePrestate: absolutePrestateExec,
l2BlockNumber: _rootClaim,
genesisBlockNumber: 0,
genesisOutputRoot: Hash.wrap(bytes32(0))
});
}
/// @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
,
uint256
[] memory _honestL2Outputs
,
bytes memory _dishonestTrace,
bytes memory _dishonestTrace,
bytes memory _dishonestPreStateData,
bytes memory _dishonestPreStateData,
uint256 _dishonestStartingBlock
uint256[] memory _dishonestL2Outputs
) internal {
)
internal
{
honest = new HonestDisputeActor({
honest = new HonestDisputeActor({
_gameProxy: gameProxy,
_gameProxy: gameProxy,
_l2Outputs: _honestL2Outputs,
_trace: _honestTrace,
_trace: _honestTrace,
_preStateData: _honestPreStateData,
_preStateData: _honestPreStateData
_startingL2BlockNumber: _honestStartingBlock
});
});
dishonest = new HonestDisputeActor({
dishonest = new HonestDisputeActor({
_gameProxy: gameProxy,
_gameProxy: gameProxy,
_l2Outputs: _dishonestL2Outputs,
_trace: _dishonestTrace,
_trace: _dishonestTrace,
_preStateData: _dishonestPreStateData,
_preStateData: _dishonestPreStateData
_startingL2BlockNumber: _dishonestStartingBlock
});
});
vm.label(address(honest), "HonestActor");
vm.label(address(honest), "HonestActor");
...
...
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