@@ -73,7 +73,9 @@ contract KlerosCore is IArbitrator {
73
73
74
74
struct DisputeKitNode {
75
75
uint256 parent; // Index of the parent dispute kit. If it's 0 then this DK is a root.
76
+ uint256 [] children; // List of child dispute kits.
76
77
IDisputeKit disputeKit; // The dispute kit implementation.
78
+ uint256 depthLevel; // How far this DK is from the root. 0 for root DK.
77
79
}
78
80
79
81
// ************************************* //
@@ -87,6 +89,7 @@ contract KlerosCore is IArbitrator {
87
89
uint256 public constant MIN_JURORS = 3 ; // The global default minimum number of jurors in a dispute.
88
90
uint256 public constant ALPHA_DIVISOR = 1e4 ; // The number to divide `Court.alpha` by.
89
91
uint256 public constant NON_PAYABLE_AMOUNT = (2 ** 256 - 2 ) / 2 ; // An amount higher than the supply of ETH.
92
+ uint256 public constant SEARCH_ITERATIONS = 10 ; // Number of iterations to search for suitable parent court before jumping to the top court.
90
93
91
94
address public governor; // The governor of the contract.
92
95
IERC20 public pinakion; // The Pinakion token contract.
@@ -166,7 +169,9 @@ contract KlerosCore is IArbitrator {
166
169
jurorProsecutionModule = _jurorProsecutionModule;
167
170
168
171
disputeKitNodes.push (); // NULL_DISPUTE_KIT: an empty element at index 0 to indicate when a node has no parent.
169
- disputeKitNodes.push (DisputeKitNode ({parent: 0 , disputeKit: _disputeKit}));
172
+ disputeKitNodes.push (
173
+ DisputeKitNode ({parent: 0 , children: new uint256 [](0 ), disputeKit: _disputeKit, depthLevel: 0 })
174
+ );
170
175
171
176
// Create the Forking court.
172
177
Court storage court = courts.push ();
@@ -228,30 +233,28 @@ contract KlerosCore is IArbitrator {
228
233
* Note that the root DK must be supported by the forking court.
229
234
*/
230
235
function addNewDisputeKit (IDisputeKit _disputeKitAddress , uint256 _parent ) external onlyByGovernor {
231
- require (_parent < disputeKitNodes.length , "Parent doesn't exist " );
236
+ uint256 disputeKitID = disputeKitNodes.length ;
237
+ require (_parent < disputeKitID, "Parent doesn't exist " );
238
+ uint256 depthLevel;
232
239
233
240
// Create new tree, which root should be supported by Forking court.
234
241
if (_parent == NULL_DISPUTE_KIT) {
235
- courts[FORKING_COURT].supportedDisputeKits[disputeKitNodes.length ] = true ;
242
+ courts[FORKING_COURT].supportedDisputeKits[disputeKitID] = true ;
243
+ } else {
244
+ depthLevel = disputeKitNodes[_parent].depthLevel + 1 ;
245
+ // It should be always possible to reach the root from the leaf with the defined number of search iterations.
246
+ require (depthLevel < SEARCH_ITERATIONS, "Depth level is at max " );
236
247
}
237
- disputeKitNodes.push (DisputeKitNode ({parent: _parent, disputeKit: _disputeKitAddress}));
238
- }
239
-
240
- /** @dev Changes the parent of an existing dispute kit.
241
- * @param _disputeKitID The ID of dispute kit.
242
- * @param _newParent The ID of the new parent dispute kit. It is left empty when root DK is created.
243
- * Note that the root DK must be supported by the forking court.
244
- */
245
- function changeDisputeKitParent (uint256 _disputeKitID , uint256 _newParent ) external onlyByGovernor {
246
- require (_disputeKitID < disputeKitNodes.length , "DisputeKitID doesn't exist " );
247
- require (_newParent < disputeKitNodes.length , "NewParent doesn't exist " );
248
- require (_newParent != _disputeKitID, "Invalid Parent " );
249
248
250
- // Create new tree, which root should be supported by Forking court.
251
- if (_newParent == NULL_DISPUTE_KIT) {
252
- courts[FORKING_COURT].supportedDisputeKits[_disputeKitID] = true ;
253
- }
254
- disputeKitNodes[_disputeKitID].parent = _newParent;
249
+ disputeKitNodes.push (
250
+ DisputeKitNode ({
251
+ parent: _parent,
252
+ children: new uint256 [](0 ),
253
+ disputeKit: _disputeKitAddress,
254
+ depthLevel: depthLevel
255
+ })
256
+ );
257
+ disputeKitNodes[_parent].children.push (disputeKitID);
255
258
}
256
259
257
260
/** @dev Creates a subcourt under a specified parent court.
@@ -286,7 +289,10 @@ contract KlerosCore is IArbitrator {
286
289
Court storage court = courts.push ();
287
290
288
291
for (uint256 i = 0 ; i < _supportedDisputeKits.length ; i++ ) {
289
- require (_supportedDisputeKits[i] < disputeKitNodes.length , "DK doesn't exist " );
292
+ require (
293
+ _supportedDisputeKits[i] > 0 && _supportedDisputeKits[i] < disputeKitNodes.length ,
294
+ "Wrong DK index "
295
+ );
290
296
court.supportedDisputeKits[_supportedDisputeKits[i]] = true ;
291
297
}
292
298
@@ -344,6 +350,14 @@ contract KlerosCore is IArbitrator {
344
350
courts[_subcourtID].jurorsForCourtJump = _jurorsForCourtJump;
345
351
}
346
352
353
+ /** @dev Changes the `hiddenVotes` property value of a specified subcourt.
354
+ * @param _subcourtID The ID of the subcourt.
355
+ * @param _hiddenVotes The new value for the `hiddenVotes` property value.
356
+ */
357
+ function changeHiddenVotes (uint96 _subcourtID , bool _hiddenVotes ) external onlyByGovernor {
358
+ courts[_subcourtID].hiddenVotes = _hiddenVotes;
359
+ }
360
+
347
361
/** @dev Changes the `timesPerPeriod` property value of a specified subcourt.
348
362
* @param _subcourtID The ID of the subcourt.
349
363
* @param _timesPerPeriod The new value for the `timesPerPeriod` property value.
@@ -368,6 +382,7 @@ contract KlerosCore is IArbitrator {
368
382
Court storage subcourt = courts[_subcourtID];
369
383
for (uint256 i = 0 ; i < _disputeKitIDs.length ; i++ ) {
370
384
if (_enable) {
385
+ require (_disputeKitIDs[i] > 0 && _disputeKitIDs[i] < disputeKitNodes.length , "Wrong DK index " );
371
386
subcourt.supportedDisputeKits[_disputeKitIDs[i]] = true ;
372
387
} else {
373
388
require (
@@ -527,34 +542,37 @@ contract KlerosCore is IArbitrator {
527
542
"Access not allowed: Dispute Kit only. "
528
543
);
529
544
530
- Court storage court = courts[ dispute.subcourtID] ;
545
+ uint96 newSubcourtID = dispute.subcourtID;
531
546
uint256 newDisputeKitID = round.disputeKitID;
532
547
533
- // Create a new round beforehand because dispute kit relies on the latest index.
548
+ // Warning: the extra round must be created before calling disputeKit.createDispute()
534
549
Round storage extraRound = dispute.rounds.push ();
535
550
536
- if (round.nbVotes >= court.jurorsForCourtJump) {
537
- {
538
- // Jump to parent subcourt.
539
- emit CourtJump (_disputeID, dispute.rounds.length - 1 , dispute.subcourtID, court.parent);
540
- dispute.subcourtID = court.parent;
541
- court = courts[court.parent];
542
- }
543
- // TODO: Handle court jump in the Forking court.
544
- while (! court.supportedDisputeKits[newDisputeKitID]) {
545
- if (disputeKitNodes[newDisputeKitID].parent != 0 ) {
551
+ if (round.nbVotes >= courts[newDisputeKitID].jurorsForCourtJump) {
552
+ // Jump to parent subcourt.
553
+ newSubcourtID = courts[newSubcourtID].parent;
554
+
555
+ for (uint256 i = 0 ; i < SEARCH_ITERATIONS; i++ ) {
556
+ if (courts[newSubcourtID].supportedDisputeKits[newDisputeKitID]) {
557
+ break ;
558
+ } else if (disputeKitNodes[newDisputeKitID].parent != NULL_DISPUTE_KIT) {
546
559
newDisputeKitID = disputeKitNodes[newDisputeKitID].parent;
547
560
} else {
548
- // If the root still isn't supported by the parent court fallback on the Forking court instead.
549
- // Note that root DK must be supported by Forking court by default but add this require as an extra check.
550
- require (
551
- courts[FORKING_COURT].supportedDisputeKits[newDisputeKitID] = true ,
552
- "DK isn't supported by Forking court "
553
- );
554
- dispute.subcourtID = uint96 (FORKING_COURT);
555
- break ;
561
+ // DK's parent has 0 index, that means we reached the root DK (0 depth level).
562
+ // Jump to the next parent court if the current court doesn't support any DK from this tree.
563
+ // Note that we don't reset newDisputeKitID in this case as, a precaution.
564
+ newSubcourtID = courts[newSubcourtID].parent;
556
565
}
557
566
}
567
+ // We didn't find a court that is compatible with DK from this tree, so we jump directly to the top court.
568
+ // Note that this can only happen when disputeKitID is at its root, and each root DK is supported by the top court by default.
569
+ if (! courts[newSubcourtID].supportedDisputeKits[newDisputeKitID]) {
570
+ newSubcourtID = uint96 (FORKING_COURT);
571
+ }
572
+
573
+ if (newSubcourtID != dispute.subcourtID) {
574
+ emit CourtJump (_disputeID, dispute.rounds.length - 1 , dispute.subcourtID, newSubcourtID);
575
+ }
558
576
559
577
// Dispute kit was changed, so create a dispute in the new DK contract.
560
578
if (newDisputeKitID != round.disputeKitID) {
@@ -563,8 +581,11 @@ contract KlerosCore is IArbitrator {
563
581
}
564
582
}
565
583
584
+ dispute.subcourtID = newSubcourtID;
566
585
dispute.period = Period.evidence;
567
586
dispute.lastPeriodChange = block .timestamp ;
587
+
588
+ Court storage court = courts[newSubcourtID];
568
589
extraRound.nbVotes = msg .value / court.feeForJuror; // As many votes that can be afforded by the provided funds.
569
590
extraRound.disputeKitID = newDisputeKitID;
570
591
extraRound.tokensAtStakePerJuror = (court.minStake * court.alpha) / ALPHA_DIVISOR;
@@ -801,6 +822,14 @@ contract KlerosCore is IArbitrator {
801
822
return courts[_subcourtID].supportedDisputeKits[_disputeKitID];
802
823
}
803
824
825
+ /** @dev Gets non-primitive properties of a specified dispute kit node.
826
+ * @param _disputeKitID The ID of the dispute kit.
827
+ * @return children Indexes of children of this DK.
828
+ */
829
+ function getDisputeKitChildren (uint256 _disputeKitID ) external view returns (uint256 [] memory ) {
830
+ return disputeKitNodes[_disputeKitID].children;
831
+ }
832
+
804
833
/** @dev Gets the timesPerPeriod array for a given court.
805
834
* @param _subcourtID The ID of the court to get the times from.
806
835
* @return timesPerPeriod The timesPerPeriod array for the given court.
0 commit comments