Skip to content

fix: Don't distribute reward for non-finalized pricing chunk #50

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
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
2 changes: 1 addition & 1 deletion contracts/reward/ChunkLinearReward.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ contract ChunkLinearReward is ChunkRewardBase {
}

function _baseReward(uint, Reward memory reward, uint) internal view override returns (uint) {
if (reward.startTime + releaseSeconds > block.timestamp) {
if (reward.startTime != 0 && reward.startTime + releaseSeconds > block.timestamp) {
return baseReward;
} else {
return 0;
Expand Down
4 changes: 2 additions & 2 deletions contracts/reward/ChunkRewardBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ abstract contract ChunkRewardBase is IReward, PullPayment, ZgInitializable, Acce
uint rewardAmount = reward.claimReward();
rewards[pricingIndex] = reward;

uint approvedReward = _baseReward(pricingIndex, reward, rewardAmount);
uint actualBaseReward = totalBaseReward > approvedReward ? approvedReward : totalBaseReward;
uint approvedBaseReward = _baseReward(pricingIndex, reward, rewardAmount);
uint actualBaseReward = totalBaseReward > approvedBaseReward ? approvedBaseReward : totalBaseReward;
rewardAmount += actualBaseReward;
totalBaseReward -= actualBaseReward;

Expand Down
5 changes: 4 additions & 1 deletion contracts/reward/Reward.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ library RewardLibrary {
}

function linearDecayReward(Reward memory reward, uint releaseSeconds) internal view returns (uint) {
if (reward.lastUpdate == 0) {
if (reward.startTime == 0) {
return 0;
}

Expand All @@ -65,6 +65,9 @@ library RewardLibrary {
}

function claimReward(Reward memory reward) internal pure returns (uint amount) {
if (reward.startTime == 0) {
return 0;
}
uint128 claimedReward = reward.claimableReward / 2;
reward.claimableReward -= claimedReward;
reward.distributedReward += claimedReward;
Expand Down
48 changes: 46 additions & 2 deletions src/dev/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ async function printStatus(flow: FixedPriceFlow, mine: PoraMine) {

const context = await flow.makeContextWithResult.staticCall();
console.log("\n============= Flow information =============");
console.log("current length: %d", context.flowLength);
console.log("current length: %d (%d pricing chunks)", context.flowLength, context.flowLength / 33554432n);
console.log("current flow root: %s", context.flowRoot);
console.log("current context digest: %s", context.digest);

Expand Down Expand Up @@ -198,15 +198,57 @@ async function printMineSubmissions(mine: PoraMine, blocks: number = 1000) {
console.log("====== Mine Submission Events (last %d blocks) ======", blocks);
await queryEvents<TypedNewSubmissionEvent>(blocks, mine, mine.filters.NewSubmission(), async function (event) {
console.log(
"Mine submission, epoch: %d\tindex: %d,\ttx hash: %s",
"Mine submission, epoch: %d\tindex: %d,\tposition: %d - %d\ttx hash: %s",
event.args.epoch,
event.args.epochIndex,
event.args.recallPosition / 33554432n,
event.args.recallPosition % 33554432n,
event.transactionHash
);
});
console.log("<<<<<<<< Done <<<<<<<<<<\n");
}

async function printRewardPool(reward: ChunkLinearReward, chunks: number) {
const toDate = function (timestamp) {
const date = new Date(Number(timestamp * 1000n));
return date.toISOString();
};
const base = 1000000000000000n;
console.log("====== Reward pool ======");

const [releaseSeconds, baseReward, totalBaseReward, firstRewardableChunk] = await Promise.all([
reward.releaseSeconds(),
reward.baseReward(),
reward.totalBaseReward(),
reward.firstRewardableChunk(),
]);

console.log("Note: 1000 mZG = 1 ZG");
console.log(`release days: ${releaseSeconds / 86400n}`);
console.log(`base reward: ${baseReward / base} mZG`);
console.log(`total base reward: ${totalBaseReward / base} mZG`);
console.log(`first rewardable chunk: ${firstRewardableChunk}`);

for (let i = firstRewardableChunk; i < chunks; i++) {
const res = await reward.rewards(i);
console.log(
`[Pool ${i}]\tlocked: ${res.lockedReward / base} mZG,\tclaimable: ${
res.claimableReward / base
} mZG,\tdistributed: ${res.distributedReward / base} mZG,\tstart time: ${toDate(
res.startTime
)},\tlast update: ${toDate(res.lastUpdate)}`
);
}
const res = await reward.rewards(chunks);
console.log(
`[Pool next]\treward: ${res.lockedReward / base},\tclaimable: ${res.claimableReward / base},\tdistributed: ${
res.distributedReward / base
},\tstart time: ${toDate(res.startTime)},\tlast update: ${toDate(res.lastUpdate)}`
);
console.log("<<<<<<<< Done <<<<<<<<<<\n");
}

async function updateContext(flow: FixedPriceFlow) {
const tx = await flow.makeContext();
const receipt = await tx.wait();
Expand All @@ -221,6 +263,8 @@ async function main() {
await printContext(flow);
await printReward(reward);
await printMineSubmissions(mine);
const pricingChunks = Number((await flow.makeContextWithResult.staticCall()).flowLength / 33554432n);
await printRewardPool(reward, pricingChunks);
// await updateContext(flow);
}

Expand Down
24 changes: 13 additions & 11 deletions test/mine.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ describe("Miner", function () {
nonceSeed?: number;
shardMask?: bigint;
shardId?: bigint;
subtaskBlockDigest?: Buffer,
subtaskBlockDigest?: Buffer;
}) {
const nonce = await keccak256(nonceSeed?.toString() || "nonce");

Expand All @@ -122,7 +122,9 @@ describe("Miner", function () {
)
);
const context: MineContextStruct = await makeContextDigest(tree);
const subtaskDigest: Buffer = await keccak256(Buffer.concat([context.digest, subtaskBlockDigest || context.blockDigest]));
const subtaskDigest: Buffer = await keccak256(
Buffer.concat([context.digest, subtaskBlockDigest || context.blockDigest])
);
const { scratchPad, chunkOffset, padSeed } = await makeScratchPad(
minerId,
nonce,
Expand Down Expand Up @@ -184,7 +186,9 @@ describe("Miner", function () {

expect(hexToBuffer(await mineContract.recoverMerkleRoot(answer, unsealedData))).to.deep.equal(tree.root());

expect(hexToBuffer(await mineContract.pora(answer, subtaskDigest))).to.deep.equal(hexToBuffer(quality.slice(0, 64)));
expect(hexToBuffer(await mineContract.pora(answer, subtaskDigest))).to.deep.equal(
hexToBuffer(quality.slice(0, 64))
);

await mockFlow.mock.getEpochRange
.withArgs(answer.sealedContextDigest)
Expand Down Expand Up @@ -213,7 +217,9 @@ describe("Miner", function () {

expect(hexToBuffer(await mineContract.recoverMerkleRoot(answer, unsealedData))).to.deep.equal(tree.root());

expect(hexToBuffer(await mineContract.pora(answer, subtaskDigest))).to.deep.equal(hexToBuffer(quality.slice(0, 64)));
expect(hexToBuffer(await mineContract.pora(answer, subtaskDigest))).to.deep.equal(
hexToBuffer(quality.slice(0, 64))
);

await mockFlow.mock.getEpochRange
.withArgs(answer.sealedContextDigest)
Expand Down Expand Up @@ -400,11 +406,7 @@ async function seal(
return sealedData;
}

async function makeContextDigest(
tree: MockMerkle,
epoch?: number,
mineStart?: number,
): Promise<MineContextStruct> {
async function makeContextDigest(tree: MockMerkle, epoch?: number, mineStart?: number): Promise<MineContextStruct> {
const KeccakEmpty: Buffer = hexToBuffer("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470");

if (epoch === undefined) {
Expand All @@ -415,8 +417,8 @@ async function makeContextDigest(
mineStart = await ethers.provider.getBlockNumber();
}

const startBlock = (await ethers.provider.getBlock(mineStart)) !;
const blockDigest = hexToBuffer(startBlock.hash !);
const startBlock = (await ethers.provider.getBlock(mineStart))!;
const blockDigest = hexToBuffer(startBlock.hash!);

const context: MineContextStruct = {
epoch,
Expand Down