Skip to content
Closed
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
45 changes: 33 additions & 12 deletions utils/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,23 +62,44 @@ export function createOrLoadPool(roundId: string, transcoderAddress: string): Po
pool.delegate = transcoderAddress;
pool.fees = ZERO_BD;

// Propagate cumulative factors from the previous round's pool so every
// pool has valid factors even if the transcoder misses reward() or has
// no fees in a round. This mirrors the contract's latestCumulativeFactorsPool.
let prevRoundNum = integerFromString(roundId).minus(ONE_BI);
let prevPool = Pool.load(
makePoolId(transcoderAddress, prevRoundNum.toString())
);
if (prevPool) {
pool.cumulativeRewardFactor = prevPool.cumulativeRewardFactor;
pool.cumulativeFeeFactor = prevPool.cumulativeFeeFactor;
let transcoder = Transcoder.load(transcoderAddress);

// Propagate cumulative factors from the most recent EXISTING pool so they
// never reset to base across a round gap. Normally that is the previous
// round's pool, but when the transcoder was inactive — or newRound's
// non-deterministic enumeration skipped it (see #249) — the previous
// round's pool can be missing for several rounds. Walk back to the most
// recent pool that exists, bounded below by lastRewardRound (which is
// guaranteed to have a pool with valid factors). This mirrors the
// contract's latestCumulativeFactorsPool.
//
// Only checking round-1 (the previous behavior) left the factors at 0
// whenever that single pool was missing, and reward() then reset the
// cumulative reward factor to base (10^27) — corrupting the stake of every
// delegator whose last claim predated the gap.
let sourcePool: Pool | null = null;
if (transcoder != null && transcoder.lastRewardRound != null) {
let cursor = integerFromString(roundId).minus(ONE_BI);
let floor = integerFromString(transcoder.lastRewardRound!);
while (cursor.ge(floor)) {
let candidate = Pool.load(
makePoolId(transcoderAddress, cursor.toString())
);
if (candidate != null) {
sourcePool = candidate;
break;
}
cursor = cursor.minus(ONE_BI);
}
}
if (sourcePool != null) {
pool.cumulativeRewardFactor = sourcePool.cumulativeRewardFactor;
pool.cumulativeFeeFactor = sourcePool.cumulativeFeeFactor;
} else {
pool.cumulativeRewardFactor = ZERO_BI;
pool.cumulativeFeeFactor = ZERO_BI;
}

let transcoder = Transcoder.load(transcoderAddress);

if (transcoder) {
pool.totalStake = transcoder.totalStake;
pool.rewardCut = transcoder.rewardCut;
Expand Down