Commit 22cf0c23 authored by Inphi's avatar Inphi Committed by GitHub

ctb: Add leftmost bond payout rule to FDG (#9300)

* ctb: Add leftmost bond payout rule to FDG

* Update packages/contracts-bedrock/test/dispute/FaultDisputeGame.t.sol
Co-authored-by: default avatarclabby <ben@clab.by>

* address @clabby's review

---------
Co-authored-by: default avatarclabby <ben@clab.by>
Co-authored-by: default avatarMatthew Slipper <me@matthewslipper.com>
parent 88586b75
This diff is collapsed.
...@@ -96,8 +96,8 @@ ...@@ -96,8 +96,8 @@
"sourceCodeHash": "0x78a030cd808a997f4b82c4fa284d6c394dae9d1fafeccb8783059a3b60bfb0ce" "sourceCodeHash": "0x78a030cd808a997f4b82c4fa284d6c394dae9d1fafeccb8783059a3b60bfb0ce"
}, },
"src/dispute/FaultDisputeGame.sol": { "src/dispute/FaultDisputeGame.sol": {
"initCodeHash": "0xccfcffe9a293c76f8e395677501b85bbc45854ea9235ec1b54ef8c78c672a87f", "initCodeHash": "0x471c66c96f233d0d1589c18efada49e14bf52e22e1bafc6d7768ee10b5b4f1de",
"sourceCodeHash": "0x7c582f30c639bdc687bec06a8faf517a2b8338edefc02f8703b8c41e7f09c8af" "sourceCodeHash": "0x34d7af1f21b12900721a11eabb4131b99920047830c6784d06aacf648156d993"
}, },
"src/legacy/DeployerWhitelist.sol": { "src/legacy/DeployerWhitelist.sol": {
"initCodeHash": "0x8de80fb23b26dd9d849f6328e56ea7c173cd9e9ce1f05c9beea559d1720deb3d", "initCodeHash": "0x8de80fb23b26dd9d849f6328e56ea7c173cd9e9ce1f05c9beea559d1720deb3d",
......
...@@ -81,8 +81,8 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver { ...@@ -81,8 +81,8 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
bool internal initialized; bool internal initialized;
/// @notice Semantic version. /// @notice Semantic version.
/// @custom:semver 0.0.25 /// @custom:semver 0.0.26
string public constant version = "0.0.25"; string public constant version = "0.0.26";
/// @param _gameType The type ID of the game. /// @param _gameType The type ID of the game.
/// @param _absolutePrestate The absolute prestate of the instruction trace. /// @param _absolutePrestate The absolute prestate of the instruction trace.
...@@ -401,6 +401,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver { ...@@ -401,6 +401,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
// Assume parent is honest until proven otherwise // Assume parent is honest until proven otherwise
address countered = address(0); address countered = address(0);
Position leftmostCounter = Position.wrap(type(uint128).max);
for (uint256 i = 0; i < challengeIndicesLen; ++i) { for (uint256 i = 0; i < challengeIndicesLen; ++i) {
uint256 challengeIndex = challengeIndices[i]; uint256 challengeIndex = challengeIndices[i];
...@@ -409,10 +410,15 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver { ...@@ -409,10 +410,15 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, ISemver {
ClaimData storage claim = claimData[challengeIndex]; ClaimData storage claim = claimData[challengeIndex];
// Ignore false claims // If the child subgame is uncountered and further left than the current left-most counter,
if (claim.counteredBy == address(0)) { // update the parent subgame's `countered` address and the current `leftmostCounter`.
// The left-most correct counter is preferred in bond payouts in order to discourage attackers
// from countering invalid subgame roots via an invalid defense position. As such positions
// cannot be correctly countered.
// Note that correctly positioned defense, but invalid claimes can still be successfully countered.
if (claim.counteredBy == address(0) && leftmostCounter.raw() > claim.position.raw()) {
countered = claim.claimant; countered = claim.claimant;
break; leftmostCounter = claim.position;
} }
} }
......
...@@ -694,6 +694,58 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init { ...@@ -694,6 +694,58 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init {
assertEq(factory.initBonds(GAME_TYPE), 0); assertEq(factory.initBonds(GAME_TYPE), 0);
} }
/// @dev Static unit test asserting that resolve pays out bonds on moves to the leftmost actor
/// in subgames containing successful counters.
function test_resolve_leftmostBondPayout_succeeds() public {
address alice = address(0xa11ce);
address bob = address(0xb0b);
address charlie = address(0xc0c);
vm.deal(address(this), 100 ether);
vm.deal(alice, 100 ether);
vm.deal(bob, 100 ether);
vm.deal(charlie, 100 ether);
// Make claims with bob, charlie and the test contract on defense, and alice as the challenger
// charlie is successfully countered by alice
// alice is successfully countered by both bob and the test coontract
vm.prank(alice);
gameProxy.attack{ value: 1 ether }(0, _dummyClaim());
vm.prank(bob);
gameProxy.defend{ value: 1 ether }(1, _dummyClaim());
vm.prank(charlie);
gameProxy.attack{ value: 1 ether }(1, _dummyClaim());
gameProxy.attack{ value: 1 ether }(1, _dummyClaim());
vm.prank(alice);
gameProxy.attack{ value: 1 ether }(3, _dummyClaim());
// Resolve all claims
vm.warp(block.timestamp + 3 days + 12 hours + 1 seconds);
for (uint256 i = gameProxy.claimDataLen(); i > 0; i--) {
(bool success,) = address(gameProxy).call(abi.encodeCall(gameProxy.resolveClaim, (i - 1)));
success;
}
gameProxy.resolve();
gameProxy.claimCredit(address(this));
gameProxy.claimCredit(alice);
gameProxy.claimCredit(bob);
gameProxy.claimCredit(charlie);
// Ensure that bonds were paid out correctly.
uint256 aliceLosses = 1 ether;
uint256 charlieLosses = 1 ether;
assertEq(address(this).balance, 100 ether + aliceLosses, "incorrect this balance");
assertEq(alice.balance, 100 ether - aliceLosses + charlieLosses, "incorrect alice balance");
assertEq(bob.balance, 100 ether, "incorrect bob balance");
assertEq(charlie.balance, 100 ether - charlieLosses, "incorrect charlie balance");
assertEq(address(gameProxy).balance, 0);
// Ensure that the init bond for the game is 0, in case we change it in the test suite in the future.
assertEq(factory.initBonds(GAME_TYPE), 0);
}
/// @dev Static unit test asserting that credit may not be drained past allowance through reentrancy. /// @dev Static unit test asserting that credit may not be drained past allowance through reentrancy.
function test_claimCredit_claimAlreadyResolved_reverts() public { function test_claimCredit_claimAlreadyResolved_reverts() public {
ClaimCreditReenter reenter = new ClaimCreditReenter(gameProxy); ClaimCreditReenter reenter = new ClaimCreditReenter(gameProxy);
......
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