Commit b36be771 authored by inphi's avatar inphi

feat(ctb): Implement fault dispute game resolution

parent 48acb226
...@@ -219,8 +219,38 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone { ...@@ -219,8 +219,38 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
* @inheritdoc IDisputeGame * @inheritdoc IDisputeGame
*/ */
function resolve() external returns (GameStatus status_) { function resolve() external returns (GameStatus status_) {
// TODO - Resolve the game if (status != GameStatus.IN_PROGRESS) {
status = GameStatus.IN_PROGRESS; revert GameNotInProgress();
}
// 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;
uint256 leftMostTraceIndex = LibPosition.rightIndex(
claimData[leftMostIndex].position,
MAX_GAME_DEPTH
);
int256 length = int256(claimData.length);
for (int256 i = length - 1; i >= 0; i--) {
ClaimData memory claim = claimData[uint256(i)];
if (LibPosition.depth(claim.position) >= MAX_GAME_DEPTH) {
continue;
}
if (claim.countered) {
continue;
}
uint256 traceIndex = LibPosition.rightIndex(claim.position, MAX_GAME_DEPTH);
if (traceIndex < leftMostTraceIndex) {
leftMostTraceIndex = traceIndex;
}
}
ClaimData memory winner = claimData[leftMostIndex];
if (LibPosition.depth(winner.position) % 2 == 0) {
status = GameStatus.DEFENDER_WINS;
} else {
status = GameStatus.CHALLENGER_WINS;
}
status_ = status; status_ = status;
} }
......
...@@ -268,6 +268,61 @@ contract FaultDisputeGame_Test is DisputeGameFactory_Init { ...@@ -268,6 +268,61 @@ contract FaultDisputeGame_Test is DisputeGameFactory_Init {
) )
); );
} }
/**
* @dev Static unit test for the correctness of resolution.
*/
function test_resolve_root_uncontested() public {
GameStatus status = gameProxy.resolve();
assertEq(uint(status), uint(GameStatus.DEFENDER_WINS));
assertEq(uint(gameProxy.status()), uint(GameStatus.DEFENDER_WINS));
}
/**
* @dev Static unit test for the correctness of resolution.
*/
function test_resolve_reverts() public {
gameProxy.resolve();
vm.expectRevert(GameNotInProgress.selector);
gameProxy.resolve();
}
/**
* @dev Static unit test for the correctness of resolution.
*/
function test_resolve_root_contested() public {
gameProxy.attack(0, Claim.wrap(bytes32(uint256(5))));
GameStatus status = gameProxy.resolve();
assertEq(uint(status), uint(GameStatus.CHALLENGER_WINS));
assertEq(uint(gameProxy.status()), uint(GameStatus.CHALLENGER_WINS));
}
/**
* @dev Static unit test for the correctness of resolution.
*/
function test_resolve_challenge_contested() public {
gameProxy.attack(0, Claim.wrap(bytes32(uint256(5))));
gameProxy.defend(1, Claim.wrap(bytes32(uint256(6))));
GameStatus status = gameProxy.resolve();
assertEq(uint(status), uint(GameStatus.DEFENDER_WINS));
assertEq(uint(gameProxy.status()), uint(GameStatus.DEFENDER_WINS));
}
/**
* @dev Static unit test for the correctness of resolution.
*/
function test_resolve_team_deathmatch() public {
gameProxy.attack(0, Claim.wrap(bytes32(uint256(5))));
gameProxy.attack(0, Claim.wrap(bytes32(uint256(4))));
gameProxy.defend(1, Claim.wrap(bytes32(uint256(6))));
gameProxy.defend(1, Claim.wrap(bytes32(uint256(7))));
GameStatus status = gameProxy.resolve();
assertEq(uint(status), uint(GameStatus.DEFENDER_WINS));
assertEq(uint(gameProxy.status()), uint(GameStatus.DEFENDER_WINS));
}
} }
/** /**
......
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