Skip to content

Commit 57d5261

Browse files
committed
feat: no more SortitionSumTree.setStake() failure to handle
1 parent 3d4832a commit 57d5261

File tree

3 files changed

+34
-103
lines changed

3 files changed

+34
-103
lines changed

contracts/src/arbitration/SortitionSumTreeBase.sol

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -97,35 +97,27 @@ abstract contract SortitionSumTreeBase is ISortitionSumTree, Initializable, UUPS
9797
address _account,
9898
uint96 _courtID,
9999
uint256 _newStake
100-
) external virtual override onlyByStakeController returns (StakingResult stakingResult) {
101-
uint256 currentStake = this.stakeOf(_account, _courtID);
102-
103-
if (currentStake == 0 && _newStake == 0) {
104-
return StakingResult.CannotStakeZeroWhenNoStake; // No change needed
105-
}
106-
107-
// Update the sortition sum tree in court hierarchy
100+
) external virtual override onlyByStakeController {
108101
bytes32 stakePathID = _accountAndCourtIDToStakePathID(_account, _courtID);
109102
bool finished = false;
110-
uint96 currentCourtIDForHierarchy = _courtID;
103+
uint96 currentCourtID = _courtID;
111104
KlerosCoreXBase core = stakeController.core();
112105

113106
while (!finished) {
114-
_set(bytes32(uint256(currentCourtIDForHierarchy)), _newStake, stakePathID);
115-
if (currentCourtIDForHierarchy == GENERAL_COURT) {
107+
_set(bytes32(uint256(currentCourtID)), _newStake, stakePathID);
108+
if (currentCourtID == GENERAL_COURT) {
116109
finished = true;
117110
} else {
118111
// Fetch parent court ID. Ensure core.courts() is accessible and correct.
119-
(uint96 parentCourtID, , , , , , ) = core.courts(currentCourtIDForHierarchy);
120-
if (parentCourtID == currentCourtIDForHierarchy) {
112+
(uint96 parentCourtID, , , , , , ) = core.courts(currentCourtID);
113+
if (parentCourtID == currentCourtID) {
121114
// Avoid infinite loop if parent is self (e.g. for general court already handled or misconfiguration)
122115
finished = true;
123116
} else {
124-
currentCourtIDForHierarchy = parentCourtID;
117+
currentCourtID = parentCourtID;
125118
}
126119
}
127120
}
128-
return StakingResult.Successful;
129121
}
130122

131123
// ************************************* //

contracts/src/arbitration/StakeControllerBase.sol

Lines changed: 26 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -344,48 +344,33 @@ abstract contract StakeControllerBase is IStakeController, Initializable, UUPSPr
344344
JurorStake storage currentJurorStake = jurorStakes[_account];
345345
uint256 currentStakeInCourt = currentJurorStake.stakes[_courtID];
346346

347-
// Check for MAX_STAKE_PATHS before calculating deposit/withdrawal if it's a new court stake
348-
if (currentStakeInCourt == 0 && _newStake > 0) {
349-
if (currentJurorStake.stakedCourtIDs.length >= MAX_STAKE_PATHS) {
347+
if (currentStakeInCourt == 0) {
348+
if (_newStake == 0)
349+
// No change needed
350+
return (0, 0, StakingResult.CannotStakeZeroWhenNoStake);
351+
else if (_newStake > 0 && currentJurorStake.stakedCourtIDs.length >= MAX_STAKE_PATHS)
352+
// Cannot stake in more courts
350353
return (0, 0, StakingResult.CannotStakeInMoreCourts);
351-
}
352354
}
353355

354-
uint256 previousTotalStake = currentJurorStake.totalStake; // Keep track for potential revert
356+
currentJurorStake.stakes[_courtID] = _newStake;
357+
355358
if (_newStake > currentStakeInCourt) {
356359
pnkDeposit = _newStake - currentStakeInCourt;
357-
currentJurorStake.totalStake = previousTotalStake + pnkDeposit;
360+
currentJurorStake.totalStake += pnkDeposit;
358361
} else if (_newStake < currentStakeInCourt) {
359362
pnkWithdrawal = currentStakeInCourt - _newStake;
360-
currentJurorStake.totalStake = previousTotalStake - pnkWithdrawal;
363+
currentJurorStake.totalStake -= pnkWithdrawal;
361364
}
362365

363-
currentJurorStake.stakes[_courtID] = _newStake;
364-
365366
// Manage stakedCourtIDs
366367
if (currentStakeInCourt == 0 && _newStake > 0) {
367368
currentJurorStake.stakedCourtIDs.push(_courtID);
368369
} else if (currentStakeInCourt > 0 && _newStake == 0) {
369370
_removeCourt(currentJurorStake.stakedCourtIDs, _courtID);
370371
}
371372

372-
stakingResult = sortitionModule.setStake(_account, _courtID, _newStake);
373-
if (stakingResult != StakingResult.Successful) {
374-
// Revert local changes if sortitionModule update fails
375-
currentJurorStake.stakes[_courtID] = currentStakeInCourt;
376-
currentJurorStake.totalStake = previousTotalStake;
377-
if (currentStakeInCourt == 0 && _newStake > 0) {
378-
// revert insertion: was a push, so pop
379-
uint96[] storage stakedCourtsRevert = currentJurorStake.stakedCourtIDs;
380-
if (stakedCourtsRevert.length > 0 && stakedCourtsRevert[stakedCourtsRevert.length - 1] == _courtID) {
381-
stakedCourtsRevert.pop();
382-
}
383-
} else if (currentStakeInCourt > 0 && _newStake == 0) {
384-
// revert removal: was a remove, so add it back (order might not be preserved by simple push)
385-
currentJurorStake.stakedCourtIDs.push(_courtID);
386-
}
387-
return (0, 0, stakingResult);
388-
}
373+
sortitionModule.setStake(_account, _courtID, _newStake);
389374

390375
emit StakeSet(_account, _courtID, _newStake, currentJurorStake.totalStake);
391376
}
@@ -402,6 +387,10 @@ abstract contract StakeControllerBase is IStakeController, Initializable, UUPSPr
402387
uint96 _courtID,
403388
uint256 _newStake
404389
) internal virtual returns (uint256 pnkDeposit, uint256 pnkWithdrawal, StakingResult stakingResult) {
390+
if (phase == Phase.staking) {
391+
return _setStakeBySystem(_account, _courtID, _newStake);
392+
}
393+
405394
JurorStake storage currentJurorStake = jurorStakes[_account];
406395
uint256 currentStakeInCourt = currentJurorStake.stakes[_courtID];
407396

@@ -411,70 +400,25 @@ abstract contract StakeControllerBase is IStakeController, Initializable, UUPSPr
411400
pnkWithdrawal = currentStakeInCourt - _newStake;
412401
}
413402

414-
if (phase != Phase.staking) {
415-
// MAX_STAKE_PATHS is checked when _setStakeBySystem() is called during executeDelayedStakes().
416-
DelayedStake storage delayedStake = delayedStakes[++delayedStakeWriteIndex];
417-
delayedStake.account = _account;
418-
delayedStake.courtID = _courtID;
419-
delayedStake.stake = _newStake;
420-
return (pnkDeposit, pnkWithdrawal, StakingResult.Delayed);
421-
}
422-
423-
// Check for MAX_STAKE_PATHS if it's a new court stake
424-
if (currentStakeInCourt == 0 && _newStake > 0) {
425-
if (currentJurorStake.stakedCourtIDs.length >= MAX_STAKE_PATHS) {
426-
return (0, 0, StakingResult.CannotStakeInMoreCourts);
427-
}
428-
}
429-
430-
// Update local stake records first
431-
uint256 previousTotalStake = currentJurorStake.totalStake; // Keep track for potential revert
432-
if (_newStake > currentStakeInCourt) {
433-
currentJurorStake.totalStake = previousTotalStake + pnkDeposit;
434-
} else if (_newStake < currentStakeInCourt) {
435-
currentJurorStake.totalStake = previousTotalStake - pnkWithdrawal;
436-
}
437-
currentJurorStake.stakes[_courtID] = _newStake;
438-
439-
// Manage stakedCourtIDs
440-
if (currentStakeInCourt == 0 && _newStake > 0) {
441-
currentJurorStake.stakedCourtIDs.push(_courtID);
442-
} else if (currentStakeInCourt > 0 && _newStake == 0) {
443-
_removeCourt(currentJurorStake.stakedCourtIDs, _courtID);
444-
}
445-
446-
stakingResult = sortitionModule.setStake(_account, _courtID, _newStake);
447-
if (stakingResult != StakingResult.Successful) {
448-
// Revert local changes if sortitionModule update fails
449-
currentJurorStake.stakes[_courtID] = currentStakeInCourt;
450-
currentJurorStake.totalStake = previousTotalStake;
451-
if (currentStakeInCourt == 0 && _newStake > 0) {
452-
// revert insertion: was a push, so pop
453-
uint96[] storage stakedCourtsRevert = currentJurorStake.stakedCourtIDs;
454-
if (stakedCourtsRevert.length > 0 && stakedCourtsRevert[stakedCourtsRevert.length - 1] == _courtID) {
455-
stakedCourtsRevert.pop();
456-
}
457-
} else if (currentStakeInCourt > 0 && _newStake == 0) {
458-
// revert removal: was a remove, so add it back (order might not be preserved by simple push)
459-
currentJurorStake.stakedCourtIDs.push(_courtID);
460-
}
461-
return (0, 0, stakingResult);
462-
}
463-
464-
emit StakeSet(_account, _courtID, _newStake, currentJurorStake.totalStake);
403+
// MAX_STAKE_PATHS is checked by _setStakeBySystem() called during executeDelayedStakes().
404+
DelayedStake storage delayedStake = delayedStakes[++delayedStakeWriteIndex];
405+
delayedStake.account = _account;
406+
delayedStake.courtID = _courtID;
407+
delayedStake.stake = _newStake;
408+
return (pnkDeposit, pnkWithdrawal, StakingResult.Delayed);
465409
}
466410

467411
/// @dev Removes a court from a juror's list of staked courts.
468412
/// @param _stakedCourts Storage pointer to the juror's array of staked court IDs.
469413
/// @param _courtID The ID of the court to remove.
470414
function _removeCourt(uint96[] storage _stakedCourts, uint96 _courtID) internal {
471-
uint256 len = _stakedCourts.length;
472-
if (len == 0) {
415+
uint256 length = _stakedCourts.length;
416+
if (length == 0) {
473417
return; // Nothing to remove
474418
}
475419

476420
uint256 courtIndexToRemove = type(uint256).max; // Sentinel value indicates not found
477-
for (uint256 i = 0; i < len; i++) {
421+
for (uint256 i = 0; i < length; i++) {
478422
if (_stakedCourts[i] == _courtID) {
479423
courtIndexToRemove = i;
480424
break;
@@ -484,8 +428,8 @@ abstract contract StakeControllerBase is IStakeController, Initializable, UUPSPr
484428
if (courtIndexToRemove != type(uint256).max) {
485429
// If the courtID was found in the array
486430
// If it's not the last element, swap the last element into its place
487-
if (courtIndexToRemove != len - 1) {
488-
_stakedCourts[courtIndexToRemove] = _stakedCourts[len - 1];
431+
if (courtIndexToRemove != length - 1) {
432+
_stakedCourts[courtIndexToRemove] = _stakedCourts[length - 1];
489433
}
490434
// Remove the last element (either the original last, or the one that was swapped)
491435
_stakedCourts.pop();

contracts/src/arbitration/interfaces/ISortitionSumTree.sol

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,7 @@ interface ISortitionSumTree {
2121
/// @param _account The address of the juror
2222
/// @param _courtID The ID of the court
2323
/// @param _newStake The new stake amount
24-
/// @return stakingResult The result of the staking operation
25-
function setStake(
26-
address _account,
27-
uint96 _courtID,
28-
uint256 _newStake
29-
) external returns (StakingResult stakingResult);
24+
function setStake(address _account, uint96 _courtID, uint256 _newStake) external;
3025

3126
// ************************************* //
3227
// * Drawing * //

0 commit comments

Comments
 (0)