From 6b74ebcb87373d00758d00f91a8d3db7cce58958 Mon Sep 17 00:00:00 2001 From: unknownunknown1 Date: Thu, 25 Sep 2025 05:24:29 +1000 Subject: [PATCH 1/2] fix(DK): multiple commit fix --- .../src/arbitration/dispute-kits/DisputeKitClassicBase.sol | 2 ++ contracts/test/foundry/KlerosCore_Voting.t.sol | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol b/contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol index 912155986..6168c7b43 100644 --- a/contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol +++ b/contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol @@ -275,6 +275,7 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]]; Round storage round = dispute.rounds[dispute.rounds.length - 1]; for (uint256 i = 0; i < _voteIDs.length; i++) { + if (round.votes[_voteIDs[i]].commit != bytes32(0)) revert AlreadyCommittedThisVote(); if (round.votes[_voteIDs[i]].account != msg.sender) revert JurorHasToOwnTheVote(); round.votes[_voteIDs[i]].commit = _commit; } @@ -759,4 +760,5 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi error AppealFeeIsAlreadyPaid(); error DisputeNotResolved(); error CoreIsPaused(); + error AlreadyCommittedThisVote(); } diff --git a/contracts/test/foundry/KlerosCore_Voting.t.sol b/contracts/test/foundry/KlerosCore_Voting.t.sol index 504c9c644..50bd00d03 100644 --- a/contracts/test/foundry/KlerosCore_Voting.t.sol +++ b/contracts/test/foundry/KlerosCore_Voting.t.sol @@ -97,6 +97,10 @@ contract KlerosCore_VotingTest is KlerosCore_TestBase { assertEq(commitStored, keccak256(abi.encodePacked(YES, salt)), "Incorrect commit"); } + vm.prank(staker1); + vm.expectRevert(DisputeKitClassicBase.AlreadyCommittedThisVote.selector); + disputeKit.castCommit(disputeID, voteIDs, commit); + // Check reveal in the next period vm.warp(block.timestamp + timesPerPeriod[1]); core.passPeriod(disputeID); From df07fbb11099bf823c97c866bc359cc678d2eb6d Mon Sep 17 00:00:00 2001 From: unknownunknown1 Date: Wed, 1 Oct 2025 03:09:20 +1000 Subject: [PATCH 2/2] fix(DK): allow recommits without changing counter --- .../dispute-kits/DisputeKitClassicBase.sol | 9 ++++++--- contracts/test/foundry/KlerosCore_Voting.t.sol | 15 +++++++++++---- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol b/contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol index 6168c7b43..464e848d6 100644 --- a/contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol +++ b/contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol @@ -274,12 +274,16 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]]; Round storage round = dispute.rounds[dispute.rounds.length - 1]; + // Introduce a counter so we don't count a re-commited votes. + uint256 commitCount; for (uint256 i = 0; i < _voteIDs.length; i++) { - if (round.votes[_voteIDs[i]].commit != bytes32(0)) revert AlreadyCommittedThisVote(); if (round.votes[_voteIDs[i]].account != msg.sender) revert JurorHasToOwnTheVote(); + if (round.votes[_voteIDs[i]].commit == bytes32(0)) { + commitCount++; + } round.votes[_voteIDs[i]].commit = _commit; } - round.totalCommitted += _voteIDs.length; + round.totalCommitted += commitCount; emit CommitCast(_coreDisputeID, msg.sender, _voteIDs, _commit); } @@ -760,5 +764,4 @@ abstract contract DisputeKitClassicBase is IDisputeKit, Initializable, UUPSProxi error AppealFeeIsAlreadyPaid(); error DisputeNotResolved(); error CoreIsPaused(); - error AlreadyCommittedThisVote(); } diff --git a/contracts/test/foundry/KlerosCore_Voting.t.sol b/contracts/test/foundry/KlerosCore_Voting.t.sol index 50bd00d03..f09ee903f 100644 --- a/contracts/test/foundry/KlerosCore_Voting.t.sol +++ b/contracts/test/foundry/KlerosCore_Voting.t.sol @@ -35,6 +35,7 @@ contract KlerosCore_VotingTest is KlerosCore_TestBase { sortitionModule.passPhase(); // Drawing phase core.draw(disputeID, DEFAULT_NB_OF_JURORS); + uint256 NO = 0; uint256 YES = 1; uint256 salt = 123455678; uint256[] memory voteIDs = new uint256[](1); @@ -79,6 +80,16 @@ contract KlerosCore_VotingTest is KlerosCore_TestBase { (, bytes32 commitStored, , ) = disputeKit.getVoteInfo(0, 0, 0); assertEq(commitStored, keccak256(abi.encodePacked(YES, salt)), "Incorrect commit"); + // Cast again with the same voteID to check that the count doesn't increase. + bytes32 newCommit = keccak256(abi.encodePacked(NO, salt)); + vm.prank(staker1); + disputeKit.castCommit(disputeID, voteIDs, newCommit); + + (, , , totalCommited, , ) = disputeKit.getRoundInfo(disputeID, 0, 0); + assertEq(totalCommited, 1, "totalCommited should still be 1"); + (, commitStored, , ) = disputeKit.getVoteInfo(0, 0, 0); + assertEq(commitStored, keccak256(abi.encodePacked(NO, salt)), "Incorrect commit after recommitting"); + voteIDs = new uint256[](2); // Create the leftover votes subset voteIDs[0] = 1; voteIDs[1] = 2; @@ -97,10 +108,6 @@ contract KlerosCore_VotingTest is KlerosCore_TestBase { assertEq(commitStored, keccak256(abi.encodePacked(YES, salt)), "Incorrect commit"); } - vm.prank(staker1); - vm.expectRevert(DisputeKitClassicBase.AlreadyCommittedThisVote.selector); - disputeKit.castCommit(disputeID, voteIDs, commit); - // Check reveal in the next period vm.warp(block.timestamp + timesPerPeriod[1]); core.passPeriod(disputeID);