Skip to content

Commit 5ac93ef

Browse files
fix(DisputeKit): check that dispute belongs to DK
1 parent 70e4b7c commit 5ac93ef

File tree

2 files changed

+103
-1
lines changed

2 files changed

+103
-1
lines changed

contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
6464
mapping(uint256 localDisputeID => mapping(uint256 localRoundID => mapping(address drawnAddress => bool)))
6565
public alreadyDrawn; // 'true' if the address has already been drawn, false by default. To be added to the Round struct when fully redeploying rather than upgrading.
6666

67+
mapping(uint256 => uint256) public coreDisputeIDToDisputeLength; // Maps core dispute ID with the current length of disputes array to avoid falling back to 0 index and make sure core dispute is indeed connected to this DK.
68+
6769
// ************************************* //
6870
// * Events * //
6971
// ************************************* //
@@ -204,6 +206,7 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
204206
round.tied = true;
205207

206208
coreDisputeIDToLocal[_coreDisputeID] = localDisputeID;
209+
coreDisputeIDToDisputeLength[_coreDisputeID] = localDisputeID + 1;
207210
emit DisputeCreation(_coreDisputeID, _numberOfChoices, _extraData);
208211
}
209212

@@ -250,6 +253,7 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
250253
(, , KlerosCore.Period period, , ) = core.disputes(_coreDisputeID);
251254
require(period == KlerosCoreBase.Period.commit, "The dispute should be in Commit period.");
252255
require(_commit != bytes32(0), "Empty commit.");
256+
require(coreDisputeIDToDisputeLength[_coreDisputeID] != 0, "No local dispute for core ID");
253257

254258
Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
255259
Round storage round = dispute.rounds[dispute.rounds.length - 1];
@@ -279,6 +283,7 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
279283
(, , KlerosCore.Period period, , ) = core.disputes(_coreDisputeID);
280284
require(period == KlerosCoreBase.Period.vote, "The dispute should be in Vote period.");
281285
require(_voteIDs.length > 0, "No voteID provided");
286+
require(coreDisputeIDToDisputeLength[_coreDisputeID] != 0, "No local dispute for core ID");
282287

283288
Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
284289
require(_choice <= dispute.numberOfChoices, "Choice out of bounds");
@@ -325,6 +330,7 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
325330
function fundAppeal(uint256 _coreDisputeID, uint256 _choice) external payable notJumped(_coreDisputeID) {
326331
Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
327332
require(_choice <= dispute.numberOfChoices, "There is no such ruling to fund.");
333+
require(coreDisputeIDToDisputeLength[_coreDisputeID] != 0, "No local dispute for core ID");
328334

329335
(uint256 appealPeriodStart, uint256 appealPeriodEnd) = core.appealPeriod(_coreDisputeID);
330336
require(block.timestamp >= appealPeriodStart && block.timestamp < appealPeriodEnd, "Appeal period is over.");
@@ -404,6 +410,7 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi
404410
(, , , bool isRuled, ) = core.disputes(_coreDisputeID);
405411
require(isRuled, "Dispute should be resolved.");
406412
require(!core.paused(), "Core is paused");
413+
require(coreDisputeIDToDisputeLength[_coreDisputeID] != 0, "No local dispute for core ID");
407414

408415
Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
409416
Round storage round = dispute.rounds[dispute.coreRoundIDToLocal[_coreRoundID]];

contracts/test/foundry/KlerosCore.t.sol

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1393,6 +1393,7 @@ contract KlerosCoreTest is Test {
13931393
assertEq(jumped, false, "jumped should be false");
13941394
assertEq(extraData, newExtraData, "Wrong extra data");
13951395
assertEq(disputeKit.coreDisputeIDToLocal(0), disputeID, "Wrong local disputeID");
1396+
assertEq(disputeKit.coreDisputeIDToDisputeLength(0), 1, "Wrong disputes length");
13961397

13971398
(
13981399
uint256 winningChoice,
@@ -1783,7 +1784,7 @@ contract KlerosCoreTest is Test {
17831784
(address account, bytes32 commit, uint256 choice, bool voted) = disputeKit.getVoteInfo(0, 0, 0); // Dispute - Round - VoteID
17841785
assertEq(account, staker1, "Wrong drawn account");
17851786
assertEq(commit, bytes32(0), "Commit should be empty");
1786-
assertEq(choice, 2, "Choice should be empty");
1787+
assertEq(choice, 2, "Choice should be 2");
17871788
assertEq(voted, true, "Voted should be true");
17881789

17891790
assertEq(disputeKit.isVoteActive(0, 0, 0), true, "Vote should be active"); // Dispute - Round - VoteID
@@ -2827,4 +2828,98 @@ contract KlerosCoreTest is Test {
28272828
assertEq(crowdfunder2.balance, 10 ether, "Wrong balance of the crowdfunder2");
28282829
assertEq(address(disputeKit).balance, 0, "Wrong balance of the DK");
28292830
}
2831+
2832+
function test_castVote_differentDK() public {
2833+
DisputeKitClassic dkLogic = new DisputeKitClassic();
2834+
// Create a new DK to check castVote.
2835+
bytes memory initDataDk = abi.encodeWithSignature("initialize(address,address)", governor, address(core));
2836+
2837+
UUPSProxy proxyDk = new UUPSProxy(address(dkLogic), initDataDk);
2838+
DisputeKitClassic newDisputeKit = DisputeKitClassic(address(proxyDk));
2839+
2840+
vm.prank(governor);
2841+
core.addNewDisputeKit(newDisputeKit);
2842+
2843+
uint256 newDkID = 2;
2844+
uint256[] memory supportedDK = new uint256[](1);
2845+
bytes memory newExtraData = abi.encodePacked(uint256(GENERAL_COURT), DEFAULT_NB_OF_JURORS, newDkID);
2846+
2847+
vm.prank(governor);
2848+
vm.expectEmit(true, true, true, true);
2849+
emit KlerosCoreBase.DisputeKitEnabled(GENERAL_COURT, newDkID, true);
2850+
supportedDK[0] = newDkID;
2851+
core.enableDisputeKits(GENERAL_COURT, supportedDK, true);
2852+
assertEq(core.isSupported(GENERAL_COURT, newDkID), true, "New DK should be supported by General court");
2853+
2854+
vm.prank(staker1);
2855+
core.setStake(GENERAL_COURT, 20000);
2856+
2857+
// Create one dispute for the old DK and two disputes for the new DK.
2858+
vm.prank(disputer);
2859+
arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
2860+
2861+
arbitrable.changeArbitratorExtraData(newExtraData);
2862+
2863+
vm.prank(disputer);
2864+
arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
2865+
2866+
vm.prank(disputer);
2867+
arbitrable.createDispute{value: feeForJuror * DEFAULT_NB_OF_JURORS}("Action");
2868+
2869+
uint256 disputeID = 2; // Use the latest dispute for reference. This is the ID in the core contract
2870+
2871+
vm.warp(block.timestamp + minStakingTime);
2872+
sortitionModule.passPhase(); // Generating
2873+
vm.roll(block.number + rngLookahead + 1);
2874+
sortitionModule.passPhase(); // Drawing phase
2875+
2876+
KlerosCoreBase.Round memory round = core.getRoundInfo(disputeID, 0);
2877+
assertEq(round.disputeKitID, newDkID, "Wrong DK ID");
2878+
2879+
core.draw(disputeID, DEFAULT_NB_OF_JURORS);
2880+
// Draw jurors for the old DK as well to prepare round.votes array
2881+
core.draw(0, DEFAULT_NB_OF_JURORS);
2882+
2883+
vm.warp(block.timestamp + timesPerPeriod[0]);
2884+
core.passPeriod(disputeID); // Vote
2885+
2886+
// Check that the new DK has the info but not the old one.
2887+
2888+
assertEq(disputeKit.coreDisputeIDToDisputeLength(disputeID), 0, "Should be 0 for old DK");
2889+
2890+
// This is the DK where dispute was created. Core dispute points to index 1 because new DK has two disputes.
2891+
assertEq(newDisputeKit.coreDisputeIDToLocal(disputeID), 1, "Wrong local dispute ID for new DK");
2892+
assertEq(newDisputeKit.coreDisputeIDToDisputeLength(disputeID), 2, "Wrong disputes length for new DK");
2893+
(uint256 numberOfChoices, , bytes memory extraData) = newDisputeKit.disputes(1);
2894+
assertEq(numberOfChoices, 2, "Wrong numberOfChoices in new DK");
2895+
assertEq(extraData, newExtraData, "Wrong extra data");
2896+
2897+
uint256[] memory voteIDs = new uint256[](3);
2898+
voteIDs[0] = 0;
2899+
voteIDs[1] = 1;
2900+
voteIDs[2] = 2;
2901+
2902+
// Deliberately cast votes using the old DK to see if the exception will be caught.
2903+
vm.prank(staker1);
2904+
vm.expectRevert(bytes("No local dispute for core ID"));
2905+
disputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
2906+
2907+
// And check the new DK.
2908+
vm.prank(staker1);
2909+
newDisputeKit.castVote(disputeID, voteIDs, 2, 0, "XYZ");
2910+
2911+
(
2912+
uint256 winningChoice,
2913+
bool tied,
2914+
uint256 totalVoted,
2915+
uint256 totalCommited,
2916+
,
2917+
uint256 choiceCount
2918+
) = newDisputeKit.getRoundInfo(disputeID, 0, 2);
2919+
assertEq(winningChoice, 2, "Wrong winning choice");
2920+
assertEq(tied, false, "tied should be false");
2921+
assertEq(totalVoted, 3, "totalVoted should be 3");
2922+
assertEq(totalCommited, 0, "totalCommited should be 0");
2923+
assertEq(choiceCount, 3, "choiceCount should be 3");
2924+
}
28302925
}

0 commit comments

Comments
 (0)