Skip to content

Commit

Permalink
The attack has been modified to support da and the FaultDisputeGameTe…
Browse files Browse the repository at this point in the history
…st contract has been added to minimize changes in the testing code
  • Loading branch information
billxu committed Aug 7, 2024
1 parent 40dfed9 commit 61f97ab
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 26 deletions.
9 changes: 4 additions & 5 deletions packages/contracts-bedrock/src/dispute/FaultDisputeGameN.sol
Original file line number Diff line number Diff line change
Expand Up @@ -367,9 +367,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
Claim _claim,
uint64 _attackBranch
)
public
payable
virtual
internal
{
// For N = 4 (bisec),
// 1. _attackBranch == 0 (attack)
Expand Down Expand Up @@ -1196,8 +1194,9 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
}
}

function attackV2(Claim _disputed, uint256 _parentIndex, Claim _claim, uint64 _attackBranch) public payable {
moveV2(_disputed, _parentIndex, _claim, _attackBranch);
function attackV2(Claim _disputed, uint256 _parentIndex, uint64 _attackBranch, uint256 _daType, bytes memory _claims) public payable {
Claim claim = Claim.wrap(LibDA.getClaimsHash(_daType, MAX_ATTACK_BRANCH, _claims));
moveV2(_disputed, _parentIndex, claim, _attackBranch);
}

function step(
Expand Down
43 changes: 22 additions & 21 deletions packages/contracts-bedrock/test/dispute/FaultDisputeGameN.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Vm } from "forge-std/Vm.sol";
import { DisputeGameFactory_Init } from "test/dispute/DisputeGameFactory.t.sol";
import { DisputeGameFactory } from "src/dispute/DisputeGameFactory.sol";
import { FaultDisputeGame, IDisputeGame } from "src/dispute/FaultDisputeGameN.sol";
import { FaultDisputeGameTest } from "test/dispute/FaultDisputeGameNTest.sol";
import { DelayedWETH } from "src/dispute/weth/DelayedWETH.sol";
import { PreimageOracle } from "src/cannon/PreimageOracle.sol";

Expand All @@ -32,9 +33,9 @@ contract FaultDisputeGame_Init is DisputeGameFactory_Init {
uint256 internal constant MAX_ATTACK_BRANCH = (1 << N_BITS) - 1;

/// @dev The implementation of the game.
FaultDisputeGame internal gameImpl;
FaultDisputeGameTest internal gameImpl;
/// @dev The `Clone` proxy of the game.
FaultDisputeGame internal gameProxy;
FaultDisputeGameTest internal gameProxy;

/// @dev The extra data passed to the game for initialization.
bytes internal extraData;
Expand All @@ -53,7 +54,7 @@ contract FaultDisputeGame_Init is DisputeGameFactory_Init {
AlphabetVM _vm = new AlphabetVM(absolutePrestate, new PreimageOracle(0, 0));

// Deploy an implementation of the fault game
gameImpl = new FaultDisputeGame({
gameImpl = new FaultDisputeGameTest({
_gameType: GAME_TYPE,
_absolutePrestate: absolutePrestate,
_maxGameDepth: 2 ** 3,
Expand All @@ -69,7 +70,7 @@ contract FaultDisputeGame_Init is DisputeGameFactory_Init {
// Register the game implementation with the factory.
disputeGameFactory.setImplementation(GAME_TYPE, gameImpl);
// Create a new game.
gameProxy = FaultDisputeGame(payable(address(disputeGameFactory.create(GAME_TYPE, rootClaim, extraData))));
gameProxy = FaultDisputeGameTest(payable(address(disputeGameFactory.create(GAME_TYPE, rootClaim, extraData))));

// Check immutables
assertEq(gameProxy.gameType().raw(), GAME_TYPE.raw());
Expand Down Expand Up @@ -141,14 +142,14 @@ contract FaultDisputeGameN_Test is FaultDisputeGame_Init {
// `IDisputeGame` Implementation Tests //
////////////////////////////////////////////////////////////////

/// @dev Tests that the constructor of the `FaultDisputeGame` reverts when the `MAX_GAME_DEPTH` parameter is
/// @dev Tests that the constructor of the `FaultDisputeGameTest` reverts when the `MAX_GAME_DEPTH` parameter is
/// greater than `LibPosition.MAX_POSITION_BITLEN - 1`.
function testFuzz_constructor_maxDepthTooLarge_reverts(uint256 _maxGameDepth) public {
AlphabetVM alphabetVM = new AlphabetVM(absolutePrestate, new PreimageOracle(0, 0));

_maxGameDepth = bound(_maxGameDepth, LibPosition.MAX_POSITION_BITLEN, type(uint256).max - 1);
vm.expectRevert(MaxDepthTooLarge.selector);
new FaultDisputeGame({
new FaultDisputeGameTest({
_gameType: GAME_TYPE,
_absolutePrestate: absolutePrestate,
_maxGameDepth: _maxGameDepth,
Expand All @@ -162,14 +163,14 @@ contract FaultDisputeGameN_Test is FaultDisputeGame_Init {
});
}

/// @dev Tests that the constructor of the `FaultDisputeGame` reverts when the `_splitDepth`
/// @dev Tests that the constructor of the `FaultDisputeGameTest` reverts when the `_splitDepth`
/// parameter is greater than or equal to the `MAX_GAME_DEPTH`
function testFuzz_constructor_invalidSplitDepth_reverts(uint256 _splitDepth) public {
AlphabetVM alphabetVM = new AlphabetVM(absolutePrestate, new PreimageOracle(0, 0));

_splitDepth = bound(_splitDepth, 2 ** 3, type(uint256).max);
vm.expectRevert(InvalidSplitDepth.selector);
new FaultDisputeGame({
new FaultDisputeGameTest({
_gameType: GAME_TYPE,
_absolutePrestate: absolutePrestate,
_maxGameDepth: 2 ** 3,
Expand All @@ -183,7 +184,7 @@ contract FaultDisputeGameN_Test is FaultDisputeGame_Init {
});
}

/// @dev Tests that the constructor of the `FaultDisputeGame` reverts when clock extension is greater than the
/// @dev Tests that the constructor of the `FaultDisputeGameTest` reverts when clock extension is greater than the
/// max clock duration.
function testFuzz_constructor_clockExtensionTooLong_reverts(
uint64 _maxClockDuration,
Expand All @@ -196,7 +197,7 @@ contract FaultDisputeGameN_Test is FaultDisputeGame_Init {
_maxClockDuration = uint64(bound(_maxClockDuration, 0, type(uint64).max - 1));
_clockExtension = uint64(bound(_clockExtension, _maxClockDuration + 1, type(uint64).max));
vm.expectRevert(InvalidClockExtension.selector);
new FaultDisputeGame({
new FaultDisputeGameTest({
_gameType: GAME_TYPE,
_absolutePrestate: absolutePrestate,
_maxGameDepth: 16,
Expand Down Expand Up @@ -252,7 +253,7 @@ contract FaultDisputeGameN_Test is FaultDisputeGame_Init {
Claim claim = _dummyClaim();
vm.expectRevert(abi.encodeWithSelector(UnexpectedRootClaim.selector, claim));
gameProxy =
FaultDisputeGame(payable(address(disputeGameFactory.create(GAME_TYPE, claim, abi.encode(_blockNumber)))));
FaultDisputeGameTest(payable(address(disputeGameFactory.create(GAME_TYPE, claim, abi.encode(_blockNumber)))));
}

/// @dev Tests that the proxy receives ETH from the dispute game factory.
Expand All @@ -261,7 +262,7 @@ contract FaultDisputeGameN_Test is FaultDisputeGame_Init {
vm.deal(address(this), _value);

assertEq(address(gameProxy).balance, 0);
gameProxy = FaultDisputeGame(
gameProxy = FaultDisputeGameTest(
payable(address(disputeGameFactory.create{ value: _value }(GAME_TYPE, ROOT_CLAIM, abi.encode(1))))
);
assertEq(address(gameProxy).balance, 0);
Expand Down Expand Up @@ -289,7 +290,7 @@ contract FaultDisputeGameN_Test is FaultDisputeGame_Init {

Claim claim = _dummyClaim();
vm.expectRevert(abi.encodeWithSelector(BadExtraData.selector));
gameProxy = FaultDisputeGame(payable(address(disputeGameFactory.create(GAME_TYPE, claim, _extraData))));
gameProxy = FaultDisputeGameTest(payable(address(disputeGameFactory.create(GAME_TYPE, claim, _extraData))));
}

/// @dev Tests that the game is initialized with the correct data.
Expand Down Expand Up @@ -671,7 +672,7 @@ contract FaultDisputeGameN_Test is FaultDisputeGame_Init {
IDisputeGame game = disputeGameFactory.create(GAME_TYPE, Claim.wrap(outputRoot), abi.encode(_l2BlockNumber + 1));

// Challenge the L2 block number.
FaultDisputeGame fdg = FaultDisputeGame(address(game));
FaultDisputeGameTest fdg = FaultDisputeGameTest(address(game));
fdg.challengeRootL2Block(outputRootProof, headerRLP);

// Ensure that a duplicate challenge reverts.
Expand Down Expand Up @@ -710,7 +711,7 @@ contract FaultDisputeGameN_Test is FaultDisputeGame_Init {
IDisputeGame game = disputeGameFactory.create{ value: 0.1 ether }(
GAME_TYPE, Claim.wrap(outputRoot), abi.encode(_l2BlockNumber + 1)
);
FaultDisputeGame fdg = FaultDisputeGame(address(game));
FaultDisputeGameTest fdg = FaultDisputeGameTest(address(game));

// Attack the root as 0xb0b
uint256 bond = _getRequiredBondV2(0, 0);
Expand Down Expand Up @@ -767,7 +768,7 @@ contract FaultDisputeGameN_Test is FaultDisputeGame_Init {
IDisputeGame game = disputeGameFactory.create(GAME_TYPE, Claim.wrap(outputRoot), abi.encode(_l2BlockNumber));

// Challenge the L2 block number.
FaultDisputeGame fdg = FaultDisputeGame(address(game));
FaultDisputeGameTest fdg = FaultDisputeGameTest(address(game));
vm.expectRevert(BlockNumberMatches.selector);
fdg.challengeRootL2Block(outputRootProof, headerRLP);

Expand Down Expand Up @@ -797,7 +798,7 @@ contract FaultDisputeGameN_Test is FaultDisputeGame_Init {

// Create the dispute game with the output root at the wrong L2 block number.
IDisputeGame game = disputeGameFactory.create(GAME_TYPE, Claim.wrap(outputRoot), abi.encode(1));
FaultDisputeGame fdg = FaultDisputeGame(address(game));
FaultDisputeGameTest fdg = FaultDisputeGameTest(address(game));

vm.expectRevert(InvalidHeaderRLP.selector);
fdg.challengeRootL2Block(outputRootProof, hex"");
Expand All @@ -810,7 +811,7 @@ contract FaultDisputeGameN_Test is FaultDisputeGame_Init {

// Create the dispute game with the output root at the wrong L2 block number.
IDisputeGame game = disputeGameFactory.create(GAME_TYPE, Claim.wrap(outputRoot), abi.encode(1));
FaultDisputeGame fdg = FaultDisputeGame(address(game));
FaultDisputeGameTest fdg = FaultDisputeGameTest(address(game));

vm.expectRevert(InvalidHeaderRLP.selector);
fdg.challengeRootL2Block(outputRootProof, hex"");
Expand Down Expand Up @@ -2416,7 +2417,7 @@ contract FaultDisputeN_1v1_Actors_Test is FaultDisputeGame_Init {
DisputeActor internal dishonest;

function setUp() public override {
// Setup the `FaultDisputeGame`
// Setup the `FaultDisputeGameTest`
super.setUp();
}

Expand Down Expand Up @@ -2952,10 +2953,10 @@ contract FaultDisputeN_1v1_Actors_Test is FaultDisputeGame_Init {

contract ClaimCreditReenter {
Vm internal immutable vm;
FaultDisputeGame internal immutable GAME;
FaultDisputeGameTest internal immutable GAME;
uint256 public numCalls;

constructor(FaultDisputeGame _gameProxy, Vm _vm) {
constructor(FaultDisputeGameTest _gameProxy, Vm _vm) {
GAME = _gameProxy;
vm = _vm;
}
Expand Down
43 changes: 43 additions & 0 deletions packages/contracts-bedrock/test/dispute/FaultDisputeGameNTest.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import { GameType, Claim, Duration } from "src/dispute/lib/LibUDT.sol";
import { FaultDisputeGame } from "src/dispute/FaultDisputeGameN.sol";
import { IAnchorStateRegistry } from "src/dispute/interfaces/IAnchorStateRegistry.sol";
import { IDelayedWETH } from "src/dispute/interfaces/IDelayedWETH.sol";
import { IBigStepper } from "src/dispute/interfaces/IBigStepper.sol";

contract FaultDisputeGameTest is FaultDisputeGame {
constructor(
GameType _gameType,
Claim _absolutePrestate,
uint256 _maxGameDepth,
uint256 _splitDepth,
Duration _clockExtension,
Duration _maxClockDuration,
IBigStepper _vm,
IDelayedWETH _weth,
IAnchorStateRegistry _anchorStateRegistry,
uint256 _l2ChainId
)
FaultDisputeGame(
_gameType,
_absolutePrestate,
_maxGameDepth,
_splitDepth,
_clockExtension,
_maxClockDuration,
_vm,
_weth,
_anchorStateRegistry,
_l2ChainId
)
{ }

// For testing convenience and to minimize changes in the testing code, the submission of the "claims" value is
// omitted during the attack. In contract testing, the value of "claims" is already known and does not need to be
// submitted via calldata or EIP-4844 during the attack.
function attackV2(Claim _disputed, uint256 _parentIndex, Claim _claim, uint64 _attackBranch) public payable {
moveV2(_disputed, _parentIndex, _claim, _attackBranch);
}
}

0 comments on commit 61f97ab

Please sign in to comment.