Skip to content

fix(DK): appeal override #426

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 4 additions & 21 deletions contracts/src/arbitration/IDisputeKit.sol
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,10 @@ interface IDisputeKit {
/** @dev Gets the current ruling of a specified dispute.
* @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.
* @return ruling The current ruling.
*/
function currentRuling(uint256 _coreDisputeID) external view returns (uint256 ruling);

/** @dev Returns the voting data from the most relevant round.
* @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.
* @return winningChoice The winning choice of this round.
* @return tied Whether it's a tie or not.
* @return overridden Whether the ruling was overridden by appeal funding or not.
*/
function getLastRoundResult(uint256 _coreDisputeID) external view returns (uint256 winningChoice, bool tied);
function currentRuling(uint256 _coreDisputeID) external view returns (uint256 ruling, bool tied, bool overridden);

/** @dev Gets the degree of coherence of a particular voter. This function is called by Kleros Core in order to determine the amount of the reward.
* @param _coreDisputeID The ID of the dispute in Kleros Core, not in the Dispute Kit.
Expand Down Expand Up @@ -118,11 +113,7 @@ interface IDisputeKit {
* @param _voteID The ID of the voter.
* @return Whether the voter was active or not.
*/
function isVoteActive(
uint256 _coreDisputeID,
uint256 _coreRoundID,
uint256 _voteID
) external view returns (bool);
function isVoteActive(uint256 _coreDisputeID, uint256 _coreRoundID, uint256 _voteID) external view returns (bool);

function getRoundInfo(
uint256 _coreDisputeID,
Expand All @@ -144,15 +135,7 @@ interface IDisputeKit {
uint256 _coreDisputeID,
uint256 _coreRoundID,
uint256 _voteID
)
external
view
returns (
address account,
bytes32 commit,
uint256 choice,
bool voted
);
) external view returns (address account, bytes32 commit, uint256 choice, bool voted);

/** @dev Returns the number of disputes without jurors in the dispute kit.
* @return The number of disputes without jurors in the dispute kit.
Expand Down
106 changes: 37 additions & 69 deletions contracts/src/arbitration/KlerosCore.sol
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ contract KlerosCore is IArbitrator {
uint256 public constant MAX_STAKE_PATHS = 4; // The maximum number of stake paths a juror can have.
uint256 public constant MIN_JURORS = 3; // The global default minimum number of jurors in a dispute.
uint256 public constant ALPHA_DIVISOR = 1e4; // The number to divide `Court.alpha` by.
uint256 public constant NON_PAYABLE_AMOUNT = (2**256 - 2) / 2; // An amount higher than the supply of ETH.
uint256 public constant NON_PAYABLE_AMOUNT = (2 ** 256 - 2) / 2; // An amount higher than the supply of ETH.
uint256 public constant SEARCH_ITERATIONS = 10; // Number of iterations to search for suitable parent court before jumping to the top court.

address public governor; // The governor of the contract.
Expand Down Expand Up @@ -462,10 +462,10 @@ contract KlerosCore is IArbitrator {
* @param _subcourtID The ID of the subcourt.
* @param _timesPerPeriod The new value for the `timesPerPeriod` property value.
*/
function changeSubcourtTimesPerPeriod(uint96 _subcourtID, uint256[4] memory _timesPerPeriod)
external
onlyByGovernor
{
function changeSubcourtTimesPerPeriod(
uint96 _subcourtID,
uint256[4] memory _timesPerPeriod
) external onlyByGovernor {
courts[_subcourtID].timesPerPeriod = _timesPerPeriod;
emit SubcourtModified(_subcourtID, "timesPerPeriod");
}
Expand Down Expand Up @@ -532,12 +532,10 @@ contract KlerosCore is IArbitrator {
* the minimum number of jurors required (next 32 bytes) and the ID of the specific dispute kit (last 32 bytes).
* @return disputeID The ID of the created dispute.
*/
function createDispute(uint256 _numberOfChoices, bytes memory _extraData)
external
payable
override
returns (uint256 disputeID)
{
function createDispute(
uint256 _numberOfChoices,
bytes memory _extraData
) external payable override returns (uint256 disputeID) {
require(msg.value >= arbitrationCost(_extraData), "ETH too low for arbitration cost");

(uint96 subcourtID, , uint256 disputeKitID) = extraDataToSubcourtIDMinJurorsDisputeKit(_extraData);
Expand Down Expand Up @@ -687,11 +685,7 @@ contract KlerosCore is IArbitrator {
* @param _numberOfChoices Number of choices for the dispute. Can be required during court jump.
* @param _extraData Extradata for the dispute. Can be required during court jump.
*/
function appeal(
uint256 _disputeID,
uint256 _numberOfChoices,
bytes memory _extraData
) external payable {
function appeal(uint256 _disputeID, uint256 _numberOfChoices, bytes memory _extraData) external payable {
require(msg.value >= appealCost(_disputeID), "ETH too low for appeal cost");

Dispute storage dispute = disputes[_disputeID];
Expand Down Expand Up @@ -769,11 +763,7 @@ contract KlerosCore is IArbitrator {
* @param _round The appeal round.
* @param _iterations The number of iterations to run.
*/
function execute(
uint256 _disputeID,
uint256 _round,
uint256 _iterations
) external {
function execute(uint256 _disputeID, uint256 _round, uint256 _iterations) external {
Dispute storage dispute = disputes[_disputeID];
require(dispute.period == Period.execution, "!Execution period");

Expand Down Expand Up @@ -881,7 +871,7 @@ contract KlerosCore is IArbitrator {
require(dispute.period == Period.execution, "!Execution period");
require(!dispute.ruled, "Ruling already executed");

uint256 winningChoice = currentRuling(_disputeID);
(uint256 winningChoice, , ) = currentRuling(_disputeID);
dispute.ruled = true;
dispute.arbitrated.rule(_disputeID, winningChoice);
}
Expand Down Expand Up @@ -941,15 +931,20 @@ contract KlerosCore is IArbitrator {
/** @dev Gets the current ruling of a specified dispute.
* @param _disputeID The ID of the dispute.
* @return ruling The current ruling.
* @return tied Whether it's a tie or not.
* @return overridden Whether the ruling was overridden by appeal funding or not.
*/
function currentRuling(uint256 _disputeID) public view returns (uint256 ruling) {
function currentRuling(uint256 _disputeID) public view returns (uint256 ruling, bool tied, bool overridden) {
Dispute storage dispute = disputes[_disputeID];
Round storage round = dispute.rounds[dispute.rounds.length - 1];
IDisputeKit disputeKit = disputeKitNodes[round.disputeKitID].disputeKit;
return disputeKit.currentRuling(_disputeID);
(ruling, tied, overridden) = disputeKit.currentRuling(_disputeID);
}

function getRoundInfo(uint256 _disputeID, uint256 _round)
function getRoundInfo(
uint256 _disputeID,
uint256 _round
)
external
view
returns (
Expand All @@ -976,11 +971,10 @@ contract KlerosCore is IArbitrator {
return disputes[_disputeID].rounds.length;
}

function getJurorBalance(address _juror, uint96 _subcourtID)
external
view
returns (uint256 staked, uint256 locked)
{
function getJurorBalance(
address _juror,
uint96 _subcourtID
) external view returns (uint256 staked, uint256 locked) {
staked = jurors[_juror].stakedTokens[_subcourtID];
locked = jurors[_juror].lockedTokens[_subcourtID];
}
Expand Down Expand Up @@ -1014,15 +1008,10 @@ contract KlerosCore is IArbitrator {
return sortitionSumTrees.sortitionSumTrees[_key].nodes[_index];
}

function getSortitionSumTree(bytes32 _key, uint256 _nodeIndex)
public
view
returns (
uint256 K,
uint256 length,
bytes32 ID
)
{
function getSortitionSumTree(
bytes32 _key,
uint256 _nodeIndex
) public view returns (uint256 K, uint256 length, bytes32 ID) {
SortitionSumTreeFactory.SortitionSumTree storage tree = sortitionSumTrees.sortitionSumTrees[_key];
K = tree.K;
length = tree.nodes.length;
Expand Down Expand Up @@ -1055,12 +1044,6 @@ contract KlerosCore is IArbitrator {
return !courts[court.parent].supportedDisputeKits[round.disputeKitID];
}

function getLastRoundResult(uint256 _disputeID) external view returns (uint256 winningChoice, bool tied) {
Dispute storage dispute = disputes[_disputeID];
Round storage round = dispute.rounds[dispute.rounds.length - 1];
(winningChoice, tied) = disputeKitNodes[round.disputeKitID].disputeKit.getLastRoundResult(_disputeID);
}

function getDisputesKitIDsThatNeedFreezing() external view returns (uint256[] memory) {
return disputesKitIDsThatNeedFreezing;
}
Expand All @@ -1073,11 +1056,7 @@ contract KlerosCore is IArbitrator {
// * Internal * //
// ************************************* //

function enableDisputeKit(
uint96 _subcourtID,
uint256 _disputeKitID,
bool _enable
) internal {
function enableDisputeKit(uint96 _subcourtID, uint256 _disputeKitID, bool _enable) internal {
courts[_subcourtID].supportedDisputeKits[_disputeKitID] = _enable;
emit DisputeKitEnabled(_subcourtID, _disputeKitID, _enable);
}
Expand Down Expand Up @@ -1185,15 +1164,9 @@ contract KlerosCore is IArbitrator {
* @return minJurors The minimum number of jurors required.
* @return disputeKitID The ID of the dispute kit.
*/
function extraDataToSubcourtIDMinJurorsDisputeKit(bytes memory _extraData)
internal
view
returns (
uint96 subcourtID,
uint256 minJurors,
uint256 disputeKitID
)
{
function extraDataToSubcourtIDMinJurorsDisputeKit(
bytes memory _extraData
) internal view returns (uint96 subcourtID, uint256 minJurors, uint256 disputeKitID) {
// Note that if the extradata doesn't contain 32 bytes for the dispute kit ID it'll return the default 0 index.
if (_extraData.length >= 64) {
assembly {
Expand Down Expand Up @@ -1223,11 +1196,10 @@ contract KlerosCore is IArbitrator {
* @param _subcourtID The subcourt ID to pack.
* @return stakePathID The stake path ID.
*/
function accountAndSubcourtIDToStakePathID(address _account, uint96 _subcourtID)
internal
pure
returns (bytes32 stakePathID)
{
function accountAndSubcourtIDToStakePathID(
address _account,
uint96 _subcourtID
) internal pure returns (bytes32 stakePathID) {
assembly {
// solium-disable-line security/no-inline-assembly
let ptr := mload(0x40)
Expand Down Expand Up @@ -1267,11 +1239,7 @@ contract KlerosCore is IArbitrator {
* @param _value Amount transferred.
* @return Whether transfer succeeded or not.
*/
function safeTransferFrom(
address _from,
address _to,
uint256 _value
) internal returns (bool) {
function safeTransferFrom(address _from, address _to, uint256 _value) internal returns (bool) {
(bool success, bytes memory data) = address(pinakion).call(
abi.encodeWithSelector(IERC20.transferFrom.selector, _from, _to, _value)
);
Expand Down
73 changes: 33 additions & 40 deletions contracts/src/arbitration/dispute-kits/DisputeKitClassic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,7 @@ contract DisputeKitClassic is BaseDisputeKit, IEvidence {
* @param _core The KlerosCore arbitrator.
* @param _rng The random number generator.
*/
constructor(
address _governor,
KlerosCore _core,
RNG _rng
) BaseDisputeKit(_governor, _core) {
constructor(address _governor, KlerosCore _core, RNG _rng) BaseDisputeKit(_governor, _core) {
rng = _rng;
}

Expand Down Expand Up @@ -218,13 +214,9 @@ contract DisputeKitClassic is BaseDisputeKit, IEvidence {
* @param _coreDisputeID The ID of the dispute in Kleros Core.
* @return drawnAddress The drawn address.
*/
function draw(uint256 _coreDisputeID)
external
override
onlyByCore
notJumped(_coreDisputeID)
returns (address drawnAddress)
{
function draw(
uint256 _coreDisputeID
) external override onlyByCore notJumped(_coreDisputeID) returns (address drawnAddress) {
require(phase == Phase.drawing, "Should be in drawing phase");

Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
Expand Down Expand Up @@ -371,7 +363,8 @@ contract DisputeKitClassic is BaseDisputeKit, IEvidence {
require(block.timestamp >= appealPeriodStart && block.timestamp < appealPeriodEnd, "Appeal period is over.");

uint256 multiplier;
if (this.currentRuling(_coreDisputeID) == _choice) {
(uint256 ruling, , ) = this.currentRuling(_coreDisputeID);
if (ruling == _choice) {
multiplier = WINNER_STAKE_MULTIPLIER;
} else {
require(
Expand Down Expand Up @@ -447,7 +440,7 @@ contract DisputeKitClassic is BaseDisputeKit, IEvidence {

Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
Round storage round = dispute.rounds[dispute.coreRoundIDToLocal[_coreRoundID]];
uint256 finalRuling = core.currentRuling(_coreDisputeID);
(uint256 finalRuling, , ) = core.currentRuling(_coreDisputeID);

if (!round.hasPaid[_choice]) {
// Allow to reimburse if funding was unsuccessful for this ruling option.
Expand Down Expand Up @@ -486,25 +479,35 @@ contract DisputeKitClassic is BaseDisputeKit, IEvidence {
// * Public Views * //
// ************************************* //

function getFundedChoices(uint256 _coreDisputeID) public view returns (uint256[] memory fundedChoices) {
Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
Round storage lastRound = dispute.rounds[dispute.rounds.length - 1];
return lastRound.fundedChoices;
}

/** @dev Gets the current ruling of a specified dispute.
* @param _coreDisputeID The ID of the dispute in Kleros Core.
* @return ruling The current ruling.
* @return tied Whether it's a tie or not.
* @return overridden Whether the ruling was overridden by appeal funding or not.
*/
function currentRuling(uint256 _coreDisputeID) external view override returns (uint256 ruling) {
function currentRuling(
uint256 _coreDisputeID
) external view override returns (uint256 ruling, bool tied, bool overridden) {
Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
Round storage round = dispute.rounds[dispute.rounds.length - 1];
ruling = round.tied ? 0 : round.winningChoice;
}

function getLastRoundResult(uint256 _coreDisputeID)
external
view
override
returns (uint256 winningChoice, bool tied)
{
Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
Round storage lastRound = dispute.rounds[dispute.rounds.length - 1];
return (lastRound.winningChoice, lastRound.tied);
tied = round.tied;
ruling = tied ? 0 : round.winningChoice;
(, , KlerosCore.Period period, , ) = core.disputes(_coreDisputeID);
// Override the final ruling if only one side funded the appeals.
if (period == KlerosCore.Period.execution) {
uint256[] memory fundedChoices = getFundedChoices(_coreDisputeID);
if (fundedChoices.length == 1) {
ruling = fundedChoices[0];
tied = false;
overridden = true;
}
}
}

/** @dev Gets the degree of coherence of a particular voter. This function is called by Kleros Core in order to determine the amount of the reward.
Expand All @@ -521,7 +524,7 @@ contract DisputeKitClassic is BaseDisputeKit, IEvidence {
// In this contract this degree can be either 0 or 1, but in other dispute kits this value can be something in between.
Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
Vote storage vote = dispute.rounds[dispute.coreRoundIDToLocal[_coreRoundID]].votes[_voteID];
(uint256 winningChoice, bool tied) = core.getLastRoundResult(_coreDisputeID);
(uint256 winningChoice, bool tied, ) = core.currentRuling(_coreDisputeID);

if (vote.voted && (vote.choice == winningChoice || tied)) {
return ONE_BASIS_POINT;
Expand All @@ -538,7 +541,7 @@ contract DisputeKitClassic is BaseDisputeKit, IEvidence {
function getCoherentCount(uint256 _coreDisputeID, uint256 _coreRoundID) external view override returns (uint256) {
Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
Round storage currentRound = dispute.rounds[dispute.coreRoundIDToLocal[_coreRoundID]];
(uint256 winningChoice, bool tied) = core.getLastRoundResult(_coreDisputeID);
(uint256 winningChoice, bool tied, ) = core.currentRuling(_coreDisputeID);

if (currentRound.totalVoted == 0 || (!tied && currentRound.counts[winningChoice] == 0)) {
return 0;
Expand Down Expand Up @@ -618,17 +621,7 @@ contract DisputeKitClassic is BaseDisputeKit, IEvidence {
uint256 _coreDisputeID,
uint256 _coreRoundID,
uint256 _voteID
)
external
view
override
returns (
address account,
bytes32 commit,
uint256 choice,
bool voted
)
{
) external view override returns (address account, bytes32 commit, uint256 choice, bool voted) {
Dispute storage dispute = disputes[coreDisputeIDToLocal[_coreDisputeID]];
Vote storage vote = dispute.rounds[dispute.coreRoundIDToLocal[_coreRoundID]].votes[_voteID];
return (vote.account, vote.commit, vote.choice, vote.voted);
Expand Down
Loading