Skip to content

Commit 876c71a

Browse files
Test finalizing periods
1 parent 42595ef commit 876c71a

3 files changed

Lines changed: 132 additions & 19 deletions

File tree

test/ProverManager/CurrentPeriodHasPublications.t.sol

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,29 +80,31 @@ abstract contract CurrentPeriodHasPublications is UniversalTest {
8080
function test_CurrentPeriodHasPublications_prove_shouldCreditProver() public {
8181
uint256 periodId = proverManager.currentPeriodId();
8282
_proveWholePeriod(periodId);
83-
LibProvingPeriod.Period memory period = proverManager.getPeriod(periodId);
83+
LibProvingPeriod.Period memory periodBefore = proverManager.getPeriod(periodId);
8484

8585
uint256 standardFee =
86-
period.fee * (checkpointTracker.nPublications() - checkpointTracker.nDelayedPublications());
87-
uint256 delayedFee = LibPercentage.scaleByPercentage(period.fee, period.delayedFeePercentage)
86+
periodBefore.fee * (checkpointTracker.nPublications() - checkpointTracker.nDelayedPublications());
87+
uint256 delayedFee = LibPercentage.scaleByPercentage(periodBefore.fee, periodBefore.delayedFeePercentage)
8888
* checkpointTracker.nDelayedPublications();
8989
uint256 reward = standardFee + delayedFee;
9090

91-
bool isDeadlinePassed = period.deadline != 0 && vm.getBlockTimestamp() > period.deadline;
92-
address prover = isDeadlinePassed ? proverB : period.prover;
91+
bool isDeadlinePassed = periodBefore.deadline != 0 && vm.getBlockTimestamp() > periodBefore.deadline;
92+
address newProver = isDeadlinePassed ? proverB : periodBefore.prover;
9393

9494
uint256 escrowedBefore = _currencyBalance(address(proverManager));
95-
uint256 balanceBefore = proverManager.balances(prover);
95+
uint256 balanceBefore = proverManager.balances(newProver);
9696

9797
vm.prank(proverB);
9898
proverManager.prove(start, end, firstPub, lastPub, proof, periodId);
9999

100100
uint256 escrowedAfter = _currencyBalance(address(proverManager));
101-
uint256 balanceAfter = proverManager.balances(prover);
101+
uint256 balanceAfter = proverManager.balances(newProver);
102+
LibProvingPeriod.Period memory periodAfter = proverManager.getPeriod(periodId);
102103

103104
assertEq(escrowedAfter, escrowedBefore, "Value held by ProverManager changed");
104105
assertEq(balanceAfter, balanceBefore + reward, "Balance not updated correctly");
105-
assertEq(proverManager.getPeriod(periodId).pastDeadline, isDeadlinePassed, "PastDeadline flag set incorrectly");
106+
assertEq(periodAfter.pastDeadline, isDeadlinePassed, "PastDeadline flag set incorrectly");
107+
assertEq(periodAfter.prover, newProver, "New prover set incorrectly");
106108
}
107109

108110
// construct a proof consistent with the MockCheckpointTracker and covers publications that span the whole period

test/ProverManager/PeriodScenario.t.sol

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ import {ERC20Currency, ETHCurrency} from "./CurrencyScenario.t.sol";
66
import {CurrentPeriodIsActiveTest} from "./CurrentPeriodIsActiveTest.t.sol";
77

88
import {CurrentPeriodHasPublications} from "./CurrentPeriodHasPublications.t.sol";
9-
import {PreviousPeriodHasPublications} from "./PreviousPeriodHasPublications.t.sol";
9+
1010
import {CurrentPeriodIsOpenTest} from "./CurrentPeriodIsOpenTest.t.sol";
1111
import {CurrentPeriodIsOverTest} from "./CurrentPeriodIsOverTest.t.sol";
1212
import {CurrentPeriodIsVacant} from "./CurrentPeriodIsVacant.t.sol";
1313
import {InitialState} from "./InitialState.t.sol";
1414
import {InitialStateTest} from "./InitialStateTest.t.sol";
1515
import {NextPeriodHasBidTest} from "./NextPeriodHasBidTest.t.sol";
16+
import {PreviousPeriodHasPublications} from "./PreviousPeriodHasPublications.t.sol";
1617
import {LibPercentage} from "src/libs/LibPercentage.sol";
1718

1819
/// Set up various scenarios to cover different period states

test/ProverManager/PreviousPeriodHasPublications.t.sol

Lines changed: 120 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ import {IInbox} from "src/protocol/IInbox.sol";
1212
/// Represents states where the previous period has existing publications (that can be proven).
1313
/// This performs the same tests as CurrentPeriodHasPublications except it applies to proofs for the previous period.
1414
/// We could merge them and check every period but that is probably excessive.
15+
/// This also includes tests to finalize the previous period. For simplicity (since no other tests are affected),
16+
/// we treat the "pastDeadline" options as different tests rather than different states.
1517
abstract contract PreviousPeriodHasPublications is CurrentPeriodHasPublications {
16-
1718
// This is a sanity check to ensure we're in the expected state
1819
function test_PreviousPeriodHasPublications_confirmPreconditions() public view {
1920
uint256 periodId = proverManager.currentPeriodId();
@@ -53,7 +54,7 @@ abstract contract PreviousPeriodHasPublications is CurrentPeriodHasPublications
5354
}
5455

5556
function test_PreviousPeriodHasPublications_prove_shouldRevertIfFirstPublicationInPreviousPeriod() public {
56-
uint256 periodId = proverManager.currentPeriodId() -1;
57+
uint256 periodId = proverManager.currentPeriodId() - 1;
5758
_proveWholePeriod(periodId);
5859
firstPub.timestamp -= 1;
5960
vm.expectRevert(BaseProverManager.FirstPublicationIsBeforePeriod.selector);
@@ -81,28 +82,137 @@ abstract contract PreviousPeriodHasPublications is CurrentPeriodHasPublications
8182
function test_PreviousPeriodHasPublications_prove_shouldCreditProver() public {
8283
uint256 periodId = proverManager.currentPeriodId() - 1;
8384
_proveWholePeriod(periodId);
84-
LibProvingPeriod.Period memory period = proverManager.getPeriod(periodId);
85+
LibProvingPeriod.Period memory periodBefore = proverManager.getPeriod(periodId);
8586

8687
uint256 standardFee =
87-
period.fee * (checkpointTracker.nPublications() - checkpointTracker.nDelayedPublications());
88-
uint256 delayedFee = LibPercentage.scaleByPercentage(period.fee, period.delayedFeePercentage)
88+
periodBefore.fee * (checkpointTracker.nPublications() - checkpointTracker.nDelayedPublications());
89+
uint256 delayedFee = LibPercentage.scaleByPercentage(periodBefore.fee, periodBefore.delayedFeePercentage)
8990
* checkpointTracker.nDelayedPublications();
9091
uint256 reward = standardFee + delayedFee;
9192

92-
bool isDeadlinePassed = period.deadline != 0 && vm.getBlockTimestamp() > period.deadline;
93-
address prover = isDeadlinePassed ? proverB : period.prover;
93+
bool isDeadlinePassed = periodBefore.deadline != 0 && vm.getBlockTimestamp() > periodBefore.deadline;
94+
address newProver = isDeadlinePassed ? proverB : periodBefore.prover;
9495

9596
uint256 escrowedBefore = _currencyBalance(address(proverManager));
96-
uint256 balanceBefore = proverManager.balances(prover);
97+
uint256 balanceBefore = proverManager.balances(newProver);
9798

9899
vm.prank(proverB);
99100
proverManager.prove(start, end, firstPub, lastPub, proof, periodId);
100101

101102
uint256 escrowedAfter = _currencyBalance(address(proverManager));
102-
uint256 balanceAfter = proverManager.balances(prover);
103+
uint256 balanceAfter = proverManager.balances(newProver);
104+
LibProvingPeriod.Period memory periodAfter = proverManager.getPeriod(periodId);
103105

104106
assertEq(escrowedAfter, escrowedBefore, "Value held by ProverManager changed");
105107
assertEq(balanceAfter, balanceBefore + reward, "Balance not updated correctly");
106-
assertEq(proverManager.getPeriod(periodId).pastDeadline, isDeadlinePassed, "PastDeadline flag set incorrectly");
108+
assertEq(periodAfter.pastDeadline, isDeadlinePassed, "PastDeadline flag set incorrectly");
109+
assertEq(periodAfter.prover, newProver, "New prover set incorrectly");
110+
}
111+
112+
function test_PreviousPeriodHasPublications_finalizePastPeriod_shouldRevertWithUnknownPublication() public {
113+
uint256 periodId = proverManager.currentPeriodId() - 1;
114+
IInbox.PublicationHeader memory provenPublication;
115+
inbox.setInvalidHeader(provenPublication);
116+
vm.expectRevert(BaseProverManager.InvalidPublication.selector);
117+
proverManager.finalizePastPeriod(periodId, provenPublication);
118+
}
119+
120+
function test_PreviousPeriodHasPublications_finalizePastPeriod_shouldRevertWithUnprovenPublication() public {
121+
uint256 periodId = proverManager.currentPeriodId() - 1;
122+
IInbox.PublicationHeader memory provenPublication; // despite the name this will be unproven.
123+
provenPublication.id = checkpointTracker.provenPublicationId() + 1;
124+
vm.expectRevert(BaseProverManager.PublicationNotProven.selector);
125+
proverManager.finalizePastPeriod(periodId, provenPublication);
126+
}
127+
128+
function test_PreviousPeriodHasPublications_finalizePastPeriod_cannotFinalizeVacantPeriod() public {
129+
uint256 periodId = proverManager.currentPeriodId() - 1;
130+
IInbox.PublicationHeader memory provenPublication;
131+
provenPublication.id = checkpointTracker.provenPublicationId();
132+
address prover = proverManager.getPeriod(periodId).prover;
133+
vm.expectRevert(BaseProverManager.PeriodNotInitialized.selector, prover == address(0) ? 1 : 0);
134+
proverManager.finalizePastPeriod(periodId, provenPublication);
135+
}
136+
137+
function test_PreviousPeriodHasPublications_finalizePastPeriod_shouldRevertWithEarlyPublication() public {
138+
uint256 periodId = proverManager.currentPeriodId() - 1;
139+
LibProvingPeriod.Period memory period = proverManager.getPeriod(periodId);
140+
if (period.prover == address(0)) return; // skip vacant periods
141+
142+
IInbox.PublicationHeader memory provenPublication;
143+
provenPublication.id = checkpointTracker.provenPublicationId();
144+
provenPublication.timestamp = period.end;
145+
vm.expectRevert(BaseProverManager.PublicationNotAfterPeriod.selector);
146+
proverManager.finalizePastPeriod(periodId, provenPublication);
147+
}
148+
149+
function test_PreviousPeriodHasPublications_finalizePastPeriod_shouldFinalizePeriod() public {
150+
uint256 periodId = proverManager.currentPeriodId() - 1;
151+
LibProvingPeriod.Period memory periodBefore = proverManager.getPeriod(periodId);
152+
if (periodBefore.prover == address(0)) return; // skip vacant periods
153+
154+
IInbox.PublicationHeader memory provenPublication;
155+
provenPublication.id = checkpointTracker.provenPublicationId();
156+
provenPublication.timestamp = periodBefore.end + 1;
157+
proverManager.finalizePastPeriod(periodId, provenPublication);
158+
159+
LibProvingPeriod.Period memory periodAfter = proverManager.getPeriod(periodId);
160+
assertEq(periodAfter.prover, address(0), "Prover not cleared");
161+
assertEq(periodAfter.stake, 0, "Stake not cleared");
162+
}
163+
164+
function test_PreviousPeriodHasPublications_finalizePastPeriod_shouldReturnFullStakeToTimelyProver() public {
165+
uint256 periodId = proverManager.currentPeriodId() - 1;
166+
LibProvingPeriod.Period memory period = proverManager.getPeriod(periodId);
167+
if (period.prover == address(0)) return; // skip vacant periods
168+
169+
// This is the default situation, so this is just a pre-condition check.
170+
assertFalse(period.pastDeadline, "Period had missed deadline");
171+
172+
IInbox.PublicationHeader memory provenPublication;
173+
provenPublication.id = checkpointTracker.provenPublicationId();
174+
provenPublication.timestamp = period.end + 1;
175+
176+
uint256 escrowedBefore = _currencyBalance(address(proverManager));
177+
uint256 balanceBefore = proverManager.balances(period.prover);
178+
179+
proverManager.finalizePastPeriod(periodId, provenPublication);
180+
181+
uint256 escrowedAfter = _currencyBalance(address(proverManager));
182+
uint256 balanceAfter = proverManager.balances(period.prover);
183+
184+
assertEq(escrowedAfter, escrowedBefore, "Value held by ProverManager changed");
185+
assertEq(balanceAfter, balanceBefore + period.stake, "Balance not updated correctly");
186+
}
187+
188+
function test_PreviousPeriodHasPublications_finalizePastPeriod_shouldTransferReducedStakeToNewestProver() public {
189+
uint256 periodId = proverManager.currentPeriodId() - 1;
190+
LibProvingPeriod.Period memory period = proverManager.getPeriod(periodId);
191+
if (period.prover == address(0)) return; // skip vacant periods
192+
if (period.deadline == 0 || vm.getBlockTimestamp() <= period.deadline) return; // skip periods within deadline
193+
194+
// Prove the period now (after the deadline) to set the `pastDeadline` flag
195+
_proveWholePeriod(periodId);
196+
vm.prank(proverB);
197+
proverManager.prove(start, end, firstPub, lastPub, proof, periodId);
198+
LibProvingPeriod.Period memory periodAfterProof = proverManager.getPeriod(periodId);
199+
assertTrue(periodAfterProof.pastDeadline, "Period proven within deadline");
200+
assertEq(periodAfterProof.prover, proverB, "Period not assigned to new prover");
201+
202+
IInbox.PublicationHeader memory provenPublication;
203+
provenPublication.id = checkpointTracker.provenPublicationId();
204+
provenPublication.timestamp = period.end + 1;
205+
206+
uint256 escrowedBefore = _currencyBalance(address(proverManager));
207+
uint256 balanceBefore = proverManager.balances(proverB);
208+
209+
proverManager.finalizePastPeriod(periodId, provenPublication);
210+
211+
uint256 escrowedAfter = _currencyBalance(address(proverManager));
212+
uint256 balanceAfter = proverManager.balances(proverB);
213+
uint256 rewardAmount = LibPercentage.scaleByBPS(period.stake, proverManager.rewardFraction());
214+
215+
assertEq(escrowedAfter, escrowedBefore, "Value held by ProverManager changed");
216+
assertEq(balanceAfter, balanceBefore + rewardAmount, "Balance not updated correctly");
107217
}
108218
}

0 commit comments

Comments
 (0)