Skip to content

Conversation

@unknownunknown1
Copy link
Contributor

@unknownunknown1 unknownunknown1 commented Sep 24, 2025

PR-Codex overview

This PR focuses on improving the voting mechanism in the DisputeKitClassicBase contract by introducing a counter to prevent double counting of committed votes. It also includes tests to verify that re-committing a vote does not increase the total committed count.

Detailed summary

  • Added a commitCount variable to track unique committed votes in DisputeKitClassicBase.
  • Updated the logic to increment round.totalCommitted by commitCount instead of the length of _voteIDs.
  • Added tests in KlerosCore_VotingTest to ensure re-committing a vote does not increase the total committed count.

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

Summary by CodeRabbit

  • Bug Fixes

    • Prevents double-counting when recommitting votes: recommitting previously committed vote IDs no longer increases the total committed count.
    • Ensures recommits correctly update the stored commit value without affecting totals.
  • Tests

    • Added test coverage to validate recommit behavior, including unchanged totals and updated commit hashes.
@netlify
Copy link

netlify bot commented Sep 24, 2025

Deploy Preview for kleros-v2-testnet ready!

Name Link
🔨 Latest commit 5b35be9
🔍 Latest deploy log https://app.netlify.com/projects/kleros-v2-testnet/deploys/68dc10cc6c58100008d27088
😎 Deploy Preview https://deploy-preview-2145--kleros-v2-testnet.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link

netlify bot commented Sep 24, 2025

Deploy Preview for kleros-v2-testnet-devtools failed. Why did it fail? →

Name Link
🔨 Latest commit 5b35be9
🔍 Latest deploy log https://app.netlify.com/projects/kleros-v2-testnet-devtools/deploys/68dc10ccf69d6e00086cf456
@netlify
Copy link

netlify bot commented Sep 24, 2025

Deploy Preview for kleros-v2-neo ready!

Name Link
🔨 Latest commit 5b35be9
🔍 Latest deploy log https://app.netlify.com/projects/kleros-v2-neo/deploys/68dc10cca527a300082d0dba
😎 Deploy Preview https://deploy-preview-2145--kleros-v2-neo.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 24, 2025

Walkthrough

Adjusts commit accounting in DisputeKitClassicBase.castCommit to increment totals only for previously uncommitted voteIDs and adds tests validating recommit behavior without inflating totalCommitted while updating stored commit hashes.

Changes

Cohort / File(s) Summary
DisputeKit commit accounting
contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol
Introduces local commitCount to count only newly committed votes; updates totalCommitted by commitCount; preserves existing validations; allows recommit without increasing totals while updating stored commit.
Voting tests
contracts/test/foundry/KlerosCore_Voting.t.sol
Adds test: draw, commit once, recommit same voteIDs with new commit; asserts totalCommitted remains 1 and stored commit updated to keccak256(NO, salt).

Sequence Diagram(s)

sequenceDiagram autonumber actor Juror participant DK as DisputeKitClassicBase participant Storage as Vote Storage Note over Juror,DK: castCommit(voteIDs[], commit) Juror->>DK: castCommit(voteIDs, commit) activate DK DK->>DK: commitCount = 0 loop For each voteID DK->>Storage: read commit[voteID] alt not previously committed (commit == 0) DK->>Storage: set commit[voteID] = newCommit DK->>DK: commitCount++ else already committed DK->>Storage: update commit[voteID] = newCommit end end DK->>Storage: totalCommitted += commitCount deactivate DK DK-->>Juror: return Note over DK: Recommit updates hash but not totalCommitted 
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Suggested labels

Type: Bug :bug:, Package: Contracts

Suggested reviewers

  • kemuru

Poem

A rabbit taps the chain with gentle wit,
“Count once, commit—recommit won’t overfit.”
Hashes hop anew, tallies stay still,
Burrows of bytes obey the bill.
With tidy paws and salted cheer,
The ledger’s clear—no double-count here. 🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title “fix(DK): multiple commit fix” follows the conventional commit format, clearly indicates that this is a fix in the DisputeKit component (DK) addressing multiple commits, and concisely summarizes the main functional change of preventing re-committed votes from being counted. It directly relates to the core update of tracking commitCount and adjusting totalCommitted to exclude already-committed votes. As such, the title is focused, specific, and informative for team members scanning the PR history.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/dk-multiple-commits

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between df07fbb and 5b35be9.

📒 Files selected for processing (1)
  • contracts/test/foundry/KlerosCore_Voting.t.sol (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • contracts/test/foundry/KlerosCore_Voting.t.sol
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Analyze (javascript)
  • GitHub Check: hardhat-tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol (1)

253-257: Update NatSpec to reflect new single-commit semantics

Doc says commits can be overridden, but code now reverts on re-commit. Align the comment with behavior.

Apply:

- /// @dev It can be called multiple times during the commit period, each call overrides the commits of the previous one. + /// @dev Each vote can be committed at most once per round. Attempts to re-commit an already committed vote revert with AlreadyCommittedThisVote().
🧹 Nitpick comments (1)
contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol (1)

277-281: Keep revert semantics predictable and save an sload per iteration

Check ownership before the “already committed” guard to avoid revealing commit status to non-owners and use a local Vote storage reference.

Apply:

- 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; - } + for (uint256 i = 0; i < _voteIDs.length; i++) { + Vote storage v = round.votes[_voteIDs[i]]; + if (v.account != msg.sender) revert JurorHasToOwnTheVote(); + if (v.commit != bytes32(0)) revert AlreadyCommittedThisVote(); + v.commit = _commit; + }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e827f63 and 6b74ebc.

📒 Files selected for processing (2)
  • contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol (2 hunks)
  • contracts/test/foundry/KlerosCore_Voting.t.sol (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: Redirect rules - kleros-v2-neo
  • GitHub Check: Header rules - kleros-v2-neo
  • GitHub Check: Redirect rules - kleros-v2-testnet-devtools
  • GitHub Check: Redirect rules - kleros-v2-testnet
  • GitHub Check: Redirect rules - kleros-v2-testnet
  • GitHub Check: Pages changed - kleros-v2-neo
  • GitHub Check: Header rules - kleros-v2-testnet-devtools
  • GitHub Check: Header rules - kleros-v2-testnet
  • GitHub Check: Header rules - kleros-v2-testnet
  • GitHub Check: Analyze (javascript)
  • GitHub Check: hardhat-tests
  • GitHub Check: Pages changed - kleros-v2-testnet-devtools
  • GitHub Check: Pages changed - kleros-v2-testnet
  • GitHub Check: Pages changed - kleros-v2-testnet
🔇 Additional comments (2)
contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol (1)

763-764: LGTM: new error improves clarity

Error declaration is appropriate and non-breaking for storage.

contracts/test/foundry/KlerosCore_Voting.t.sol (1)

100-103: LGTM: asserts double-commit reverts as intended

Test correctly guards against re-commit attempts.

Consider adding one more check to ensure atomicity on mixed arrays (one already committed, one fresh) reverts and does not partially commit the fresh vote ID.

coderabbitai[bot]
coderabbitai bot previously approved these changes Sep 24, 2025
@jaybuidl
Copy link
Member

@coderabbitai create an issue for this

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 30, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash # Create a GitHub issue for tracking the multiple commit fix gh issue create \ --title "Fix: Prevent multiple commits for the same vote in DisputeKit" \ --body "This issue tracks the fix for allowing multiple commits for the same vote in DisputeKitClassicBase. **Background:** The DisputeKit was allowing jurors to submit multiple commits for the same vote IDs, which could lead to unexpected behavior. **Solution:** Added a guard in \`castCommit\` function to revert with \`AlreadyCommittedThisVote()\` error if a vote's commit is already set. **Related PR:** #2145 **Requested by:** @jaybuidl" \ --assignee jaybuidl 

Length of output: 47


@jaybuidl I've created issue #2151 to track this fix: #2151

The issue documents the bug where multiple commits could be submitted for the same vote and the solution implemented in this PR.

@jaybuidl jaybuidl linked an issue Sep 30, 2025 that may be closed by this pull request
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol (2)

281-283: Potential logic issue: Re-commit with same hash not properly handled.

The current logic only increments commitCount if commit == bytes32(0). However, if a juror calls castCommit twice with the same commit hash, the second call will:

  1. Not increment commitCount (correct)
  2. Overwrite commit with the same value (redundant but harmless)
  3. Emit CommitCast event again (potentially confusing)

While this doesn't break functionality, it allows redundant operations. Consider whether this is the desired behavior or if you should add an early check to prevent calling castCommit with an identical hash.

If you want to optimize, you could add:

 for (uint256 i = 0; i < _voteIDs.length; i++) { if (round.votes[_voteIDs[i]].account != msg.sender) revert JurorHasToOwnTheVote(); + if (round.votes[_voteIDs[i]].commit == _commit) continue; // Skip if committing the same value if (round.votes[_voteIDs[i]].commit == bytes32(0)) { commitCount++; } round.votes[_voteIDs[i]].commit = _commit; }

277-278: Consider adding inline documentation.

The comment "Introduce a counter so we don't count a re-commited votes" is helpful. Consider expanding it to explain the invariant being maintained: totalCommitted represents the number of unique jurors who have committed at least once, not the total number of castCommit calls.

- // Introduce a counter so we don't count a re-commited votes. + // Track how many votes are being committed for the first time in this call. + // totalCommitted represents unique votes committed, not total castCommit calls. uint256 commitCount;
contracts/test/foundry/KlerosCore_Voting.t.sol (1)

83-92: Consider adding edge case test coverage.

While the current test validates the core re-commit behavior, consider adding test cases for:

  1. Re-committing multiple voteIDs where some are new and some are re-commits
  2. Re-committing with the same hash (to verify idempotency)
  3. Verifying that CommitCast event is emitted correctly on re-commit

Example test for mixed scenario:

// Test re-committing with a mix of new and already-committed voteIDs voteIDs = new uint256[](2); voteIDs[0] = 0; // Already committed voteIDs[1] = 1; // Not yet committed vm.prank(staker1); disputeKit.castCommit(disputeID, voteIDs, newCommit); (, , , totalCommited, , ) = disputeKit.getRoundInfo(disputeID, 0, 0); assertEq(totalCommited, 2, "totalCommited should be 2 (1 existing + 1 new)");
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6b74ebc and df07fbb.

📒 Files selected for processing (2)
  • contracts/src/arbitration/dispute-kits/DisputeKitClassicBase.sol (1 hunks)
  • contracts/test/foundry/KlerosCore_Voting.t.sol (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
  • GitHub Check: Redirect rules - kleros-v2-neo
  • GitHub Check: Redirect rules - kleros-v2-testnet
  • GitHub Check: Redirect rules - kleros-v2-testnet
  • GitHub Check: Redirect rules - kleros-v2-testnet-devtools
  • GitHub Check: Header rules - kleros-v2-testnet
  • GitHub Check: Header rules - kleros-v2-neo
  • GitHub Check: Header rules - kleros-v2-testnet
  • GitHub Check: Header rules - kleros-v2-testnet-devtools
  • GitHub Check: Pages changed - kleros-v2-testnet
  • GitHub Check: Pages changed - kleros-v2-testnet
  • GitHub Check: Pages changed - kleros-v2-neo
  • GitHub Check: Pages changed - kleros-v2-testnet-devtools
  • GitHub Check: Analyze (javascript)
  • GitHub Check: hardhat-tests
  • GitHub Check: SonarCloud
🔇 Additional comments (2)
contracts/test/foundry/KlerosCore_Voting.t.sol (2)

38-38: LGTM: NO constant improves test readability.

The introduction of the NO constant (value 0) alongside the existing YES constant makes the test more readable and semantically clear, especially in the re-commit test scenario.


83-92: LGTM: Test correctly validates re-commit behavior.

This test segment properly verifies the fix:

  1. ✓ Confirms totalCommitted remains 1 after re-committing the same voteID
  2. ✓ Validates that the stored commit value is updated to the new hash
  3. ✓ Demonstrates that jurors can change their commit during the commit period

The test aligns with the implementation in DisputeKitClassicBase.sol and provides good coverage for the re-commit scenario.

@jaybuidl jaybuidl merged commit 06db2d0 into dev Sep 30, 2025
13 of 20 checks passed
@jaybuidl jaybuidl deleted the fix/dk-multiple-commits branch September 30, 2025 18:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

3 participants