@@ -73,7 +73,9 @@ contract KlerosCore is IArbitrator {
7373
7474 struct DisputeKitNode {
7575 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.
7677 IDisputeKit disputeKit; // The dispute kit implementation.
78+ uint256 depthLevel; // How far this DK is from the root. 0 for root DK.
7779 }
7880
7981 // ************************************* //
@@ -87,6 +89,7 @@ contract KlerosCore is IArbitrator {
8789 uint256 public constant MIN_JURORS = 3 ; // The global default minimum number of jurors in a dispute.
8890 uint256 public constant ALPHA_DIVISOR = 1e4 ; // The number to divide `Court.alpha` by.
8991 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.
9093
9194 address public governor; // The governor of the contract.
9295 IERC20 public pinakion; // The Pinakion token contract.
@@ -166,7 +169,9 @@ contract KlerosCore is IArbitrator {
166169 jurorProsecutionModule = _jurorProsecutionModule;
167170
168171 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+ );
170175
171176 // Create the Forking court.
172177 Court storage court = courts.push ();
@@ -228,30 +233,28 @@ contract KlerosCore is IArbitrator {
228233 * Note that the root DK must be supported by the forking court.
229234 */
230235 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;
232239
233240 // Create new tree, which root should be supported by Forking court.
234241 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 " );
236247 }
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 " );
249248
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);
255258 }
256259
257260 /** @dev Creates a subcourt under a specified parent court.
@@ -286,7 +289,10 @@ contract KlerosCore is IArbitrator {
286289 Court storage court = courts.push ();
287290
288291 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+ );
290296 court.supportedDisputeKits[_supportedDisputeKits[i]] = true ;
291297 }
292298
@@ -344,6 +350,14 @@ contract KlerosCore is IArbitrator {
344350 courts[_subcourtID].jurorsForCourtJump = _jurorsForCourtJump;
345351 }
346352
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+
347361 /** @dev Changes the `timesPerPeriod` property value of a specified subcourt.
348362 * @param _subcourtID The ID of the subcourt.
349363 * @param _timesPerPeriod The new value for the `timesPerPeriod` property value.
@@ -368,6 +382,7 @@ contract KlerosCore is IArbitrator {
368382 Court storage subcourt = courts[_subcourtID];
369383 for (uint256 i = 0 ; i < _disputeKitIDs.length ; i++ ) {
370384 if (_enable) {
385+ require (_disputeKitIDs[i] > 0 && _disputeKitIDs[i] < disputeKitNodes.length , "Wrong DK index " );
371386 subcourt.supportedDisputeKits[_disputeKitIDs[i]] = true ;
372387 } else {
373388 require (
@@ -527,34 +542,37 @@ contract KlerosCore is IArbitrator {
527542 "Access not allowed: Dispute Kit only. "
528543 );
529544
530- Court storage court = courts[ dispute.subcourtID] ;
545+ uint96 newSubcourtID = dispute.subcourtID;
531546 uint256 newDisputeKitID = round.disputeKitID;
532547
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()
534549 Round storage extraRound = dispute.rounds.push ();
535550
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) {
546559 newDisputeKitID = disputeKitNodes[newDisputeKitID].parent;
547560 } 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;
556565 }
557566 }
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+ }
558576
559577 // Dispute kit was changed, so create a dispute in the new DK contract.
560578 if (newDisputeKitID != round.disputeKitID) {
@@ -563,8 +581,11 @@ contract KlerosCore is IArbitrator {
563581 }
564582 }
565583
584+ dispute.subcourtID = newSubcourtID;
566585 dispute.period = Period.evidence;
567586 dispute.lastPeriodChange = block .timestamp ;
587+
588+ Court storage court = courts[newSubcourtID];
568589 extraRound.nbVotes = msg .value / court.feeForJuror; // As many votes that can be afforded by the provided funds.
569590 extraRound.disputeKitID = newDisputeKitID;
570591 extraRound.tokensAtStakePerJuror = (court.minStake * court.alpha) / ALPHA_DIVISOR;
@@ -801,6 +822,14 @@ contract KlerosCore is IArbitrator {
801822 return courts[_subcourtID].supportedDisputeKits[_disputeKitID];
802823 }
803824
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+
804833 /** @dev Gets the timesPerPeriod array for a given court.
805834 * @param _subcourtID The ID of the court to get the times from.
806835 * @return timesPerPeriod The timesPerPeriod array for the given court.
0 commit comments