Skip to content

Commit 838e7bf

Browse files
unknownunknown1jaybuidl
authored andcommitted
fix(KlerosCore): dispute kit structure fix
1 parent 4c4a17e commit 838e7bf

File tree

2 files changed

+37
-106
lines changed

2 files changed

+37
-106
lines changed

contracts/src/arbitration/KlerosCore.sol

Lines changed: 37 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ contract KlerosCore is IArbitratorV2, UUPSProxiable, Initializable {
4343
uint256 feeForJuror; // Arbitration fee paid per juror.
4444
uint256 jurorsForCourtJump; // The appeal after the one that reaches this number of jurors will go to the parent court if any.
4545
uint256[4] timesPerPeriod; // The time allotted to each dispute period in the form `timesPerPeriod[period]`.
46-
mapping(uint256 => bool) supportedDisputeKits; // True if DK with this ID is supported by the court.
46+
mapping(uint256 => bool) supportedDisputeKits; // True if DK with this ID is supported by the court. Note that each court must support classic dispute kit.
4747
bool disabled; // True if the court is disabled. Unused for now, will be implemented later.
4848
}
4949

@@ -77,14 +77,6 @@ contract KlerosCore is IArbitratorV2, UUPSProxiable, Initializable {
7777
mapping(uint96 => uint256) stakedPnkByCourt; // The amount of PNKs the juror has staked in the court in the form `stakedPnkByCourt[courtID]`.
7878
}
7979

80-
struct DisputeKitNode {
81-
uint256 parent; // Index of the parent dispute kit. If it's 0 then this DK is a root.
82-
uint256[] children; // List of child dispute kits.
83-
IDisputeKit disputeKit; // The dispute kit implementation.
84-
uint256 depthLevel; // How far this DK is from the root. 0 for root DK.
85-
bool disabled; // True if the dispute kit is disabled and can't be used. This parameter is added preemptively to avoid storage changes in the future.
86-
}
87-
8880
// Workaround "stack too deep" errors
8981
struct ExecuteParams {
9082
uint256 disputeID; // The ID of the dispute to execute.
@@ -107,14 +99,13 @@ contract KlerosCore is IArbitratorV2, UUPSProxiable, Initializable {
10799

108100
uint256 private constant ALPHA_DIVISOR = 1e4; // The number to divide `Court.alpha` by.
109101
uint256 private constant NON_PAYABLE_AMOUNT = (2 ** 256 - 2) / 2; // An amount higher than the supply of ETH.
110-
uint256 private constant SEARCH_ITERATIONS = 10; // Number of iterations to search for suitable parent court before jumping to the top court.
111102

112103
address public governor; // The governor of the contract.
113104
IERC20 public pinakion; // The Pinakion token contract.
114105
address public jurorProsecutionModule; // The module for juror's prosecution.
115106
ISortitionModule public sortitionModule; // Sortition module for drawing.
116107
Court[] public courts; // The courts.
117-
DisputeKitNode[] public disputeKitNodes; // The list of DisputeKitNode, indexed by DisputeKitID.
108+
IDisputeKit[] public disputeKits; // Array of dispute kits.
118109
Dispute[] public disputes; // The disputes.
119110
mapping(address => Juror) internal jurors; // The jurors.
120111
mapping(IERC20 => CurrencyRate) public currencyRates; // The price of each token in ETH.
@@ -149,11 +140,7 @@ contract KlerosCore is IArbitratorV2, UUPSProxiable, Initializable {
149140
uint256 _jurorsForCourtJump,
150141
uint256[4] _timesPerPeriod
151142
);
152-
event DisputeKitCreated(
153-
uint256 indexed _disputeKitID,
154-
IDisputeKit indexed _disputeKitAddress,
155-
uint256 indexed _parent
156-
);
143+
event DisputeKitCreated(uint256 indexed _disputeKitID, IDisputeKit indexed _disputeKitAddress);
157144
event DisputeKitEnabled(uint96 indexed _courtID, uint256 indexed _disputeKitID, bool indexed _enable);
158145
event CourtJump(
159146
uint256 indexed _disputeID,
@@ -228,20 +215,13 @@ contract KlerosCore is IArbitratorV2, UUPSProxiable, Initializable {
228215
jurorProsecutionModule = _jurorProsecutionModule;
229216
sortitionModule = _sortitionModuleAddress;
230217

231-
// NULL_DISPUTE_KIT: an empty element at index 0 to indicate when a node has no parent.
232-
disputeKitNodes.push();
218+
// NULL_DISPUTE_KIT: an empty element at index 0 to indicate when a dispute kit is not supported.
219+
disputeKits.push();
233220

234221
// DISPUTE_KIT_CLASSIC
235-
disputeKitNodes.push(
236-
DisputeKitNode({
237-
parent: Constants.NULL_DISPUTE_KIT,
238-
children: new uint256[](0),
239-
disputeKit: _disputeKit,
240-
depthLevel: 0,
241-
disabled: false
242-
})
243-
);
244-
emit DisputeKitCreated(Constants.DISPUTE_KIT_CLASSIC, _disputeKit, Constants.NULL_DISPUTE_KIT);
222+
disputeKits.push(_disputeKit);
223+
224+
emit DisputeKitCreated(Constants.DISPUTE_KIT_CLASSIC, _disputeKit);
245225

246226
// FORKING_COURT
247227
// TODO: Fill the properties for the Forking court, emit CourtCreated.
@@ -326,33 +306,10 @@ contract KlerosCore is IArbitratorV2, UUPSProxiable, Initializable {
326306

327307
/// @dev Add a new supported dispute kit module to the court.
328308
/// @param _disputeKitAddress The address of the dispute kit contract.
329-
/// @param _parent The ID of the parent dispute kit. It is left empty when root DK is created.
330-
/// Note that the root DK must be supported by the general court.
331-
function addNewDisputeKit(IDisputeKit _disputeKitAddress, uint256 _parent) external onlyByGovernor {
332-
uint256 disputeKitID = disputeKitNodes.length;
333-
if (_parent >= disputeKitID) revert InvalidDisputKitParent();
334-
uint256 depthLevel;
335-
if (_parent != Constants.NULL_DISPUTE_KIT) {
336-
depthLevel = disputeKitNodes[_parent].depthLevel + 1;
337-
// It should be always possible to reach the root from the leaf with the defined number of search iterations.
338-
if (depthLevel >= SEARCH_ITERATIONS) revert DepthLevelMax();
339-
}
340-
disputeKitNodes.push(
341-
DisputeKitNode({
342-
parent: _parent,
343-
children: new uint256[](0),
344-
disputeKit: _disputeKitAddress,
345-
depthLevel: depthLevel,
346-
disabled: false
347-
})
348-
);
349-
350-
disputeKitNodes[_parent].children.push(disputeKitID);
351-
emit DisputeKitCreated(disputeKitID, _disputeKitAddress, _parent);
352-
if (_parent == Constants.NULL_DISPUTE_KIT) {
353-
// A new dispute kit tree root should always be supported by the General court.
354-
_enableDisputeKit(Constants.GENERAL_COURT, disputeKitID, true);
355-
}
309+
function addNewDisputeKit(IDisputeKit _disputeKitAddress) external onlyByGovernor {
310+
uint256 disputeKitID = disputeKits.length;
311+
disputeKits.push(_disputeKitAddress);
312+
emit DisputeKitCreated(disputeKitID, _disputeKitAddress);
356313
}
357314

358315
/// @dev Creates a court under a specified parent court.
@@ -384,11 +341,13 @@ contract KlerosCore is IArbitratorV2, UUPSProxiable, Initializable {
384341
Court storage court = courts.push();
385342

386343
for (uint256 i = 0; i < _supportedDisputeKits.length; i++) {
387-
if (_supportedDisputeKits[i] == 0 || _supportedDisputeKits[i] >= disputeKitNodes.length) {
344+
if (_supportedDisputeKits[i] == 0 || _supportedDisputeKits[i] >= disputeKits.length) {
388345
revert WrongDisputeKitIndex();
389346
}
390347
court.supportedDisputeKits[_supportedDisputeKits[i]] = true;
391348
}
349+
// Check that Classic DK support was added.
350+
if (!court.supportedDisputeKits[Constants.DISPUTE_KIT_CLASSIC]) revert MustSupportDisputeKitClassic();
392351

393352
court.parent = _parent;
394353
court.children = new uint256[](0);
@@ -458,16 +417,14 @@ contract KlerosCore is IArbitratorV2, UUPSProxiable, Initializable {
458417
function enableDisputeKits(uint96 _courtID, uint256[] memory _disputeKitIDs, bool _enable) external onlyByGovernor {
459418
for (uint256 i = 0; i < _disputeKitIDs.length; i++) {
460419
if (_enable) {
461-
if (_disputeKitIDs[i] == 0 || _disputeKitIDs[i] >= disputeKitNodes.length) {
420+
if (_disputeKitIDs[i] == 0 || _disputeKitIDs[i] >= disputeKits.length) {
462421
revert WrongDisputeKitIndex();
463422
}
464423
_enableDisputeKit(_courtID, _disputeKitIDs[i], true);
465424
} else {
466-
if (
467-
_courtID == Constants.GENERAL_COURT &&
468-
disputeKitNodes[_disputeKitIDs[i]].parent == Constants.NULL_DISPUTE_KIT
469-
) {
470-
revert CannotDisableRootDKInGeneral();
425+
// Classic dispute kit must be supported by all courts.
426+
if (_disputeKitIDs[i] == Constants.DISPUTE_KIT_CLASSIC) {
427+
revert CannotDisableClassicDK();
471428
}
472429
_enableDisputeKit(_courtID, _disputeKitIDs[i], false);
473430
}
@@ -547,7 +504,7 @@ contract KlerosCore is IArbitratorV2, UUPSProxiable, Initializable {
547504
dispute.arbitrated = IArbitrableV2(msg.sender);
548505
dispute.lastPeriodChange = block.timestamp;
549506

550-
IDisputeKit disputeKit = disputeKitNodes[disputeKitID].disputeKit;
507+
IDisputeKit disputeKit = disputeKits[disputeKitID];
551508
Court storage court = courts[dispute.courtID];
552509
Round storage round = dispute.rounds.push();
553510

@@ -587,15 +544,15 @@ contract KlerosCore is IArbitratorV2, UUPSProxiable, Initializable {
587544
} else if (dispute.period == Period.commit) {
588545
if (
589546
block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)] &&
590-
!disputeKitNodes[round.disputeKitID].disputeKit.areCommitsAllCast(_disputeID)
547+
!disputeKits[round.disputeKitID].areCommitsAllCast(_disputeID)
591548
) {
592549
revert CommitPeriodNotPassed();
593550
}
594551
dispute.period = Period.vote;
595552
} else if (dispute.period == Period.vote) {
596553
if (
597554
block.timestamp - dispute.lastPeriodChange < court.timesPerPeriod[uint256(dispute.period)] &&
598-
!disputeKitNodes[round.disputeKitID].disputeKit.areVotesAllCast(_disputeID)
555+
!disputeKits[round.disputeKitID].areVotesAllCast(_disputeID)
599556
) {
600557
revert VotePeriodNotPassed();
601558
}
@@ -623,7 +580,7 @@ contract KlerosCore is IArbitratorV2, UUPSProxiable, Initializable {
623580
Round storage round = dispute.rounds[currentRound];
624581
if (dispute.period != Period.evidence) revert NotEvidencePeriod();
625582

626-
IDisputeKit disputeKit = disputeKitNodes[round.disputeKitID].disputeKit;
583+
IDisputeKit disputeKit = disputeKits[round.disputeKitID];
627584

628585
uint256 startIndex = round.drawIterations; // for gas: less storage reads
629586
uint256 i;
@@ -654,7 +611,7 @@ contract KlerosCore is IArbitratorV2, UUPSProxiable, Initializable {
654611
if (dispute.period != Period.appeal) revert DisputeNotAppealable();
655612

656613
Round storage round = dispute.rounds[dispute.rounds.length - 1];
657-
if (msg.sender != address(disputeKitNodes[round.disputeKitID].disputeKit)) revert DisputeKitOnly();
614+
if (msg.sender != address(disputeKits[round.disputeKitID])) revert DisputeKitOnly();
658615

659616
uint96 newCourtID = dispute.courtID;
660617
uint256 newDisputeKitID = round.disputeKitID;
@@ -666,22 +623,9 @@ contract KlerosCore is IArbitratorV2, UUPSProxiable, Initializable {
666623
// Jump to parent court.
667624
newCourtID = courts[newCourtID].parent;
668625

669-
for (uint256 i = 0; i < SEARCH_ITERATIONS; i++) {
670-
if (courts[newCourtID].supportedDisputeKits[newDisputeKitID]) {
671-
break;
672-
} else if (disputeKitNodes[newDisputeKitID].parent != Constants.NULL_DISPUTE_KIT) {
673-
newDisputeKitID = disputeKitNodes[newDisputeKitID].parent;
674-
} else {
675-
// DK's parent has 0 index, that means we reached the root DK (0 depth level).
676-
// Jump to the next parent court if the current court doesn't support any DK from this tree.
677-
// Note that we don't reset newDisputeKitID in this case as, a precaution.
678-
newCourtID = courts[newCourtID].parent;
679-
}
680-
}
681-
// We didn't find a court that is compatible with DK from this tree, so we jump directly to the top court.
682-
// Note that this can only happen when disputeKitID is at its root, and each root DK is supported by the top court by default.
683626
if (!courts[newCourtID].supportedDisputeKits[newDisputeKitID]) {
684-
newCourtID = Constants.GENERAL_COURT;
627+
// Switch to classic dispute kit if parent court doesn't support the current one.
628+
newDisputeKitID = Constants.DISPUTE_KIT_CLASSIC;
685629
}
686630

687631
if (newCourtID != dispute.courtID) {
@@ -704,7 +648,7 @@ contract KlerosCore is IArbitratorV2, UUPSProxiable, Initializable {
704648
// Dispute kit was changed, so create a dispute in the new DK contract.
705649
if (extraRound.disputeKitID != round.disputeKitID) {
706650
emit DisputeKitJump(_disputeID, dispute.rounds.length - 1, round.disputeKitID, extraRound.disputeKitID);
707-
disputeKitNodes[extraRound.disputeKitID].disputeKit.createDispute(
651+
disputeKits[extraRound.disputeKitID].createDispute(
708652
_disputeID,
709653
_numberOfChoices,
710654
_extraData,
@@ -725,7 +669,7 @@ contract KlerosCore is IArbitratorV2, UUPSProxiable, Initializable {
725669
if (dispute.period != Period.execution) revert NotExecutionPeriod();
726670

727671
Round storage round = dispute.rounds[_round];
728-
IDisputeKit disputeKit = disputeKitNodes[round.disputeKitID].disputeKit;
672+
IDisputeKit disputeKit = disputeKits[round.disputeKitID];
729673

730674
uint256 start = round.repartitions;
731675
uint256 end = round.repartitions + _iterations;
@@ -765,7 +709,7 @@ contract KlerosCore is IArbitratorV2, UUPSProxiable, Initializable {
765709
function _executePenalties(ExecuteParams memory _params) internal returns (uint256) {
766710
Dispute storage dispute = disputes[_params.disputeID];
767711
Round storage round = dispute.rounds[_params.round];
768-
IDisputeKit disputeKit = disputeKitNodes[round.disputeKitID].disputeKit;
712+
IDisputeKit disputeKit = disputeKits[round.disputeKitID];
769713

770714
// [0, 1] value that determines how coherent the juror was in this round, in basis points.
771715
uint256 degreeOfCoherence = disputeKit.getDegreeOfCoherence(
@@ -833,7 +777,7 @@ contract KlerosCore is IArbitratorV2, UUPSProxiable, Initializable {
833777
function _executeRewards(ExecuteParams memory _params) internal {
834778
Dispute storage dispute = disputes[_params.disputeID];
835779
Round storage round = dispute.rounds[_params.round];
836-
IDisputeKit disputeKit = disputeKitNodes[round.disputeKitID].disputeKit;
780+
IDisputeKit disputeKit = disputeKits[round.disputeKitID];
837781

838782
// [0, 1] value that determines how coherent the juror was in this round, in basis points.
839783
uint256 degreeOfCoherence = disputeKit.getDegreeOfCoherence(
@@ -988,7 +932,7 @@ contract KlerosCore is IArbitratorV2, UUPSProxiable, Initializable {
988932
function currentRuling(uint256 _disputeID) public view returns (uint256 ruling, bool tied, bool overridden) {
989933
Dispute storage dispute = disputes[_disputeID];
990934
Round storage round = dispute.rounds[dispute.rounds.length - 1];
991-
IDisputeKit disputeKit = disputeKitNodes[round.disputeKitID].disputeKit;
935+
IDisputeKit disputeKit = disputeKits[round.disputeKitID];
992936
(ruling, tied, overridden) = disputeKit.currentRuling(_disputeID);
993937
}
994938

@@ -1015,13 +959,6 @@ contract KlerosCore is IArbitratorV2, UUPSProxiable, Initializable {
1015959
return courts[_courtID].supportedDisputeKits[_disputeKitID];
1016960
}
1017961

1018-
/// @dev Gets non-primitive properties of a specified dispute kit node.
1019-
/// @param _disputeKitID The ID of the dispute kit.
1020-
/// @return children Indexes of children of this DK.
1021-
function getDisputeKitChildren(uint256 _disputeKitID) external view returns (uint256[] memory) {
1022-
return disputeKitNodes[_disputeKitID].children;
1023-
}
1024-
1025962
/// @dev Gets the timesPerPeriod array for a given court.
1026963
/// @param _courtID The ID of the court to get the times from.
1027964
/// @return timesPerPeriod The timesPerPeriod array for the given court.
@@ -1056,14 +993,8 @@ contract KlerosCore is IArbitratorV2, UUPSProxiable, Initializable {
1056993
return !courts[court.parent].supportedDisputeKits[round.disputeKitID];
1057994
}
1058995

1059-
function getDisputeKitNodesLength() external view returns (uint256) {
1060-
return disputeKitNodes.length;
1061-
}
1062-
1063-
/// @dev Gets the dispute kit for a specific `_disputeKitID`.
1064-
/// @param _disputeKitID The ID of the dispute kit.
1065-
function getDisputeKit(uint256 _disputeKitID) external view returns (IDisputeKit) {
1066-
return disputeKitNodes[_disputeKitID].disputeKit;
996+
function getDisputeKitsLength() external view returns (uint256) {
997+
return disputeKits.length;
1067998
}
1068999

10691000
/// @dev Gets the court identifiers where a specific `_juror` has staked.
@@ -1083,7 +1014,7 @@ contract KlerosCore is IArbitratorV2, UUPSProxiable, Initializable {
10831014
/// @dev Toggles the dispute kit support for a given court.
10841015
/// @param _courtID The ID of the court to toggle the support for.
10851016
/// @param _disputeKitID The ID of the dispute kit to toggle the support for.
1086-
/// @param _enable Whether to enable or disable the support.
1017+
/// @param _enable Whether to enable or disable the support. Note that classic dispute kit should always be enabled.
10871018
function _enableDisputeKit(uint96 _courtID, uint256 _disputeKitID, bool _enable) internal {
10881019
courts[_courtID].supportedDisputeKits[_disputeKitID] = _enable;
10891020
emit DisputeKitEnabled(_courtID, _disputeKitID, _enable);
@@ -1197,7 +1128,7 @@ contract KlerosCore is IArbitratorV2, UUPSProxiable, Initializable {
11971128
if (minJurors == 0) {
11981129
minJurors = Constants.DEFAULT_NB_OF_JURORS;
11991130
}
1200-
if (disputeKitID == Constants.NULL_DISPUTE_KIT || disputeKitID >= disputeKitNodes.length) {
1131+
if (disputeKitID == Constants.NULL_DISPUTE_KIT || disputeKitID >= disputeKits.length) {
12011132
disputeKitID = Constants.DISPUTE_KIT_CLASSIC; // 0 index is not used.
12021133
}
12031134
} else {
@@ -1219,12 +1150,13 @@ contract KlerosCore is IArbitratorV2, UUPSProxiable, Initializable {
12191150
error UnsupportedDisputeKit();
12201151
error InvalidForkingCourtAsParent();
12211152
error WrongDisputeKitIndex();
1222-
error CannotDisableRootDKInGeneral();
1153+
error CannotDisableClassicDK();
12231154
error ArraysLengthMismatch();
12241155
error StakingFailed();
12251156
error WrongCaller();
12261157
error ArbitrationFeesNotEnough();
12271158
error DisputeKitNotSupportedByCourt();
1159+
error MustSupportDisputeKitClassic();
12281160
error TokenNotAccepted();
12291161
error EvidenceNotPassedAndNotAppeal();
12301162
error DisputeStillDrawing();

contracts/test/arbitration/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ describe("DisputeKitClassic", async () => {
1818
expect(events.length).to.equal(1);
1919
expect(events[0].args._disputeKitID).to.equal(1);
2020
expect(events[0].args._disputeKitAddress).to.equal(disputeKit.address);
21-
expect(events[0].args._parent).to.equal(0);
2221

2322
// Reminder: the Forking court will be added which will break these expectations.
2423
events = await core.queryFilter(core.filters.CourtCreated());

0 commit comments

Comments
 (0)