Skip to content

Commit 7eb8634

Browse files
committed
fix: added test coverage to reproduce the drawing bug, contract fix
1 parent 4ee4b72 commit 7eb8634

File tree

5 files changed

+105
-38
lines changed

5 files changed

+105
-38
lines changed

contracts/src/arbitration/SortitionModule.sol

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,11 +289,15 @@ contract SortitionModule is ISortitionModule {
289289
require(phase == Phase.drawing, "Wrong phase.");
290290
SortitionSumTree storage tree = sortitionSumTrees[_key];
291291

292-
uint256 treeIndex = 0;
292+
if (tree.nodes[0] == 0) {
293+
return address(0); // No jurors staked.
294+
}
295+
293296
uint256 currentDrawnNumber = uint256(keccak256(abi.encodePacked(randomNumber, _coreDisputeID, _voteID))) %
294297
tree.nodes[0];
295298

296299
// While it still has children
300+
uint256 treeIndex = 0;
297301
while ((tree.K * treeIndex) + 1 < tree.nodes.length) {
298302
for (uint256 i = 1; i <= tree.K; i++) {
299303
// Loop over children.

contracts/src/arbitration/dispute-kits/DisputeKitClassic.sol

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -557,18 +557,8 @@ contract DisputeKitClassic is BaseDisputeKit, IEvidence {
557557
// * Internal * //
558558
// ************************************* //
559559

560-
/// @dev Checks that the chosen address satisfies certain conditions for being drawn.
561-
/// @param _coreDisputeID ID of the dispute in the core contract.
562-
/// @param _juror Chosen address.
563-
/// @return Whether the address can be drawn or not.
564-
function _postDrawCheck(uint256 _coreDisputeID, address _juror) internal view override returns (bool) {
565-
(uint96 courtID, , , , ) = core.disputes(_coreDisputeID);
566-
(, uint256 lockedAmountPerJuror, , , , , , , , ) = core.getRoundInfo(
567-
_coreDisputeID,
568-
core.getNumberOfRounds(_coreDisputeID) - 1
569-
);
570-
(uint256 staked, uint256 locked, ) = core.getJurorBalance(_juror, courtID);
571-
(, , uint256 minStake, , , , ) = core.courts(courtID);
572-
return staked >= locked + lockedAmountPerJuror && staked >= minStake;
560+
/// @inheritdoc BaseDisputeKit
561+
function _postDrawCheck(uint256 /*_coreDisputeID*/, address /*_juror*/) internal pure override returns (bool) {
562+
return true;
573563
}
574564
}

contracts/test/arbitration/draw.ts

Lines changed: 97 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { anyValue } from "@nomicfoundation/hardhat-chai-matchers/withArgs";
22
import { deployments, ethers, getNamedAccounts, network } from "hardhat";
3-
import { BigNumber } from "ethers";
3+
import { BigNumber, ContractTransaction, Wallet } from "ethers";
44
import {
55
PNK,
66
KlerosCore,
@@ -52,11 +52,7 @@ describe("Draw Benchmark", async () => {
5252
let randomizer;
5353

5454
beforeEach("Setup", async () => {
55-
deployer = (await getNamedAccounts()).deployer;
56-
relayer = (await getNamedAccounts()).relayer;
57-
58-
console.log("deployer:%s", deployer);
59-
console.log("named accounts: %O", await getNamedAccounts());
55+
({ deployer, relayer } = await getNamedAccounts());
6056

6157
await deployments.fixture(["Arbitration", "VeaMock"], {
6258
fallbackToGlobal: true,
@@ -70,9 +66,33 @@ describe("Draw Benchmark", async () => {
7066
rng = (await ethers.getContract("RandomizerRNG")) as RandomizerRNG;
7167
randomizer = (await ethers.getContract("RandomizerMock")) as RandomizerMock;
7268
sortitionModule = (await ethers.getContract("SortitionModule")) as SortitionModule;
69+
70+
// CourtId 2
71+
const minStake = BigNumber.from(10).pow(20).mul(3); // 300 PNK
72+
const alpha = 10000;
73+
const feeForJuror = BigNumber.from(10).pow(17);
74+
await core.createCourt(
75+
1,
76+
false,
77+
minStake,
78+
alpha,
79+
feeForJuror,
80+
256,
81+
[0, 0, 0, 10], // evidencePeriod, commitPeriod, votePeriod, appealPeriod
82+
ethers.utils.hexlify(5), // Extra data for sortition module will return the default value of K)
83+
[1]
84+
);
7385
});
7486

75-
it("Draw Benchmark", async () => {
87+
interface SetStake {
88+
(wallet: Wallet): Promise<void>;
89+
}
90+
91+
interface ExpectFromDraw {
92+
(drawTx: Promise<ContractTransaction>): Promise<void>;
93+
}
94+
95+
const draw = async (setStake: SetStake, createDisputeCourtId: string, expectFromDraw: ExpectFromDraw) => {
7696
const arbitrationCost = ONE_TENTH_ETH.mul(3);
7797
const [bridger] = await ethers.getSigners();
7898

@@ -90,7 +110,8 @@ describe("Draw Benchmark", async () => {
90110
expect(await pnk.balanceOf(wallet.address)).to.equal(ONE_THOUSAND_PNK.mul(10));
91111

92112
await pnk.connect(wallet).approve(core.address, ONE_THOUSAND_PNK.mul(10), { gasLimit: 300000 });
93-
await core.connect(wallet).setStake(1, ONE_THOUSAND_PNK.mul(10), { gasLimit: 5000000 });
113+
114+
await setStake(wallet);
94115
}
95116

96117
// Create a dispute
@@ -114,7 +135,7 @@ describe("Draw Benchmark", async () => {
114135
templateId: 0,
115136
templateUri: "",
116137
choices: 2,
117-
extraData: "0x00",
138+
extraData: `0x000000000000000000000000000000000000000000000000000000000000000${createDisputeCourtId}0000000000000000000000000000000000000000000000000000000000000003`,
118139
},
119140
{ value: arbitrationCost }
120141
);
@@ -131,12 +152,72 @@ describe("Draw Benchmark", async () => {
131152
await randomizer.relay(rng.address, 0, ethers.utils.randomBytes(32));
132153
await sortitionModule.passPhase(); // Generating -> Drawing
133154

134-
await expect(core.draw(0, 1000, { gasLimit: 1000000 }))
135-
.to.emit(core, "Draw")
136-
.withArgs(anyValue, 0, 0, 0)
137-
.to.emit(core, "Draw")
138-
.withArgs(anyValue, 0, 0, 1)
139-
.to.emit(core, "Draw")
140-
.withArgs(anyValue, 0, 0, 2);
155+
await expectFromDraw(core.draw(0, 1000, { gasLimit: 1000000 }));
156+
};
157+
158+
it("Stakes in parent court and should draw jurors in parent court", async () => {
159+
const setStake = async (wallet: Wallet) => {
160+
await core.connect(wallet).setStake(1, ONE_THOUSAND_PNK.mul(5), { gasLimit: 5000000 });
161+
};
162+
163+
const expectFromDraw = async (drawTx: Promise<ContractTransaction>) => {
164+
await expect(drawTx)
165+
.to.emit(core, "Draw")
166+
.withArgs(anyValue, 0, 0, 0)
167+
.to.emit(core, "Draw")
168+
.withArgs(anyValue, 0, 0, 1)
169+
.to.emit(core, "Draw")
170+
.withArgs(anyValue, 0, 0, 2);
171+
};
172+
173+
await draw(setStake, "1", expectFromDraw);
174+
});
175+
176+
it("Stakes in parent court and should draw nobody in subcourt", async () => {
177+
const setStake = async (wallet: Wallet) => {
178+
await core.connect(wallet).setStake(1, ONE_THOUSAND_PNK.mul(5), { gasLimit: 5000000 });
179+
};
180+
181+
const expectFromDraw = async (drawTx: Promise<ContractTransaction>) => {
182+
await expect(drawTx).to.not.emit(core, "Draw");
183+
};
184+
185+
await draw(setStake, "2", expectFromDraw);
186+
});
187+
188+
it("Stakes in subcourt and should draw jurors in parent court", async () => {
189+
const setStake = async (wallet: Wallet) => {
190+
await core.connect(wallet).setStake(2, ONE_THOUSAND_PNK.mul(5), { gasLimit: 5000000 });
191+
};
192+
193+
const expectFromDraw = async (drawTx: Promise<ContractTransaction>) => {
194+
await expect(drawTx)
195+
.to.emit(core, "Draw")
196+
.withArgs(anyValue, 0, 0, 0)
197+
.to.emit(core, "Draw")
198+
.withArgs(anyValue, 0, 0, 1)
199+
.to.emit(core, "Draw")
200+
.withArgs(anyValue, 0, 0, 2);
201+
};
202+
203+
await draw(setStake, "1", expectFromDraw);
204+
});
205+
206+
it("Stakes in subcourt and should draw jurors in subcourt", async () => {
207+
const setStake = async (wallet: Wallet) => {
208+
await core.connect(wallet).setStake(2, ONE_THOUSAND_PNK.mul(5), { gasLimit: 5000000 });
209+
};
210+
211+
const expectFromDraw = async (drawTx: Promise<ContractTransaction>) => {
212+
await expect(drawTx)
213+
.to.emit(core, "Draw")
214+
.withArgs(anyValue, 0, 0, 0)
215+
.to.emit(core, "Draw")
216+
.withArgs(anyValue, 0, 0, 1)
217+
.to.emit(core, "Draw")
218+
.withArgs(anyValue, 0, 0, 2);
219+
};
220+
221+
await draw(setStake, "2", expectFromDraw);
141222
});
142223
});

contracts/test/arbitration/unstake.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,6 @@ describe("Unstake juror", async () => {
3131

3232
beforeEach("Setup", async () => {
3333
({ deployer } = await getNamedAccounts());
34-
35-
console.log("deployer:%s", deployer);
36-
console.log("named accounts: %O", await getNamedAccounts());
37-
3834
await deployments.fixture(["Arbitration"], {
3935
fallbackToGlobal: true,
4036
keepExistingDeployments: false,

contracts/test/integration/index.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,6 @@ describe("Integration tests", async () => {
4343

4444
beforeEach("Setup", async () => {
4545
({ deployer } = await getNamedAccounts());
46-
47-
console.log("deployer:%s", deployer);
48-
console.log("named accounts: %O", await getNamedAccounts());
49-
5046
await deployments.fixture(["Arbitration", "VeaMock"], {
5147
fallbackToGlobal: true,
5248
keepExistingDeployments: false,

0 commit comments

Comments
 (0)