fix(pox-4-tests): Refresh the model's state if the network gets to the next reward cycle

This commit is contained in:
BowTiedRadone
2024-04-10 18:24:47 +03:00
committed by Nikos Baxevanis
parent e0493305c4
commit b75cb1e93b
18 changed files with 133 additions and 24 deletions

View File

@@ -119,24 +119,27 @@ it("statefully interacts with PoX-4", async () => {
simnet.setEpoch("3.0");
fc.assert(
fc.property(
PoxCommands(model.wallets, sut.network),
(cmds) => {
const initialState = () => ({ model: model, real: sut });
fc.modelRun(initialState, cmds);
// The testing suite will run for 5000 times.
for (let i = 0; i < 5000; i++) {
fc.assert(
fc.property(
PoxCommands(model.wallets, sut.network),
(cmds) => {
const initialState = () => ({ model: model, real: sut });
fc.modelRun(initialState, cmds);
},
),
{
// Defines the number of test iterations to run; default is 100.
numRuns: 10,
// Adjusts the level of detail in test reports. Default is 0 (minimal).
// At level 2, reports include extensive details, helpful for deep
// debugging. This includes not just the failing case and its seed, but
// also a comprehensive log of all executed steps and their outcomes.
verbose: 2,
},
),
{
// Defines the number of test iterations to run; default is 100.
numRuns: 10,
// Adjusts the level of detail in test reports. Default is 0 (minimal).
// At level 2, reports include extensive details, helpful for deep
// debugging. This includes not just the failing case and its seed, but
// also a comprehensive log of all executed steps and their outcomes.
verbose: 2,
},
);
);
}
model.reportCommandRuns();
});

View File

@@ -85,6 +85,9 @@ export class AllowContractCallerCommand implements PoxCommand {
"until",
optionalCVToString(this.allowUntilBurnHt),
);
// Refresh the model's state if the network gets to the next reward cycle.
model.stateRefresh(real);
}
toString() {

View File

@@ -1,7 +1,11 @@
import fc from "fast-check";
import { Simnet } from "@hirosystems/clarinet-sdk";
import { StacksPrivateKey } from "@stacks/transactions";
import {
ClarityValue,
cvToValue,
StacksPrivateKey,
} from "@stacks/transactions";
import { StackingClient } from "@stacks/stacking";
export type StxAddress = string;
@@ -12,7 +16,8 @@ export class Stub {
readonly wallets: Map<StxAddress, Wallet>;
readonly statistics: Map<string, number>;
stackingMinimum: number;
nextRewardSetIndex: number
nextRewardSetIndex: number;
lastRefreshedCycle: number;
constructor(
wallets: Map<StxAddress, Wallet>,
@@ -22,6 +27,7 @@ export class Stub {
this.statistics = statistics;
this.stackingMinimum = 0;
this.nextRewardSetIndex = 0;
this.lastRefreshedCycle = 0;
}
trackCommandRun(commandName: string) {
@@ -35,6 +41,53 @@ export class Stub {
console.log(`${commandName}: ${count}`);
});
}
stateRefresh(real: Real) {
const burnBlockHeightResult = real.network.runSnippet("burn-block-height");
const burnBlockHeight = cvToValue(burnBlockHeightResult as ClarityValue);
const lastRefreshedCycle = this.lastRefreshedCycle;
const currentRewCycle = Math.floor((Number(burnBlockHeight) - 0) / 1050);
if (lastRefreshedCycle < currentRewCycle) {
this.nextRewardSetIndex = 0;
this.wallets.forEach((wallet) => {
const expiredDelegators = wallet.poolMembers.filter((stackerAddress) =>
this.wallets.get(stackerAddress)!.delegatedUntilBurnHt + 1 <
burnBlockHeight
);
const expiredStackers = wallet.lockedAddresses.filter(
(stackerAddress) =>
this.wallets.get(stackerAddress)!.unlockHeight + 1 <=
burnBlockHeight,
);
expiredDelegators.forEach((expDelegator) => {
const expDelegatorIndex = wallet.poolMembers.indexOf(expDelegator);
wallet.poolMembers.splice(expDelegatorIndex, 1);
});
expiredStackers.forEach((expStacker) => {
const expStackerWallet = this.wallets.get(expStacker)!;
const expStackerIndex = wallet.lockedAddresses.indexOf(expStacker);
wallet.lockedAddresses.splice(expStackerIndex, 1);
wallet.amountToCommit -= expStackerWallet.amountLocked;
});
if (
wallet.unlockHeight > 0 && wallet.unlockHeight + 1 <= burnBlockHeight
) {
wallet.isStacking = false;
wallet.amountUnlocked += wallet.amountLocked;
wallet.amountLocked = 0;
wallet.unlockHeight = 0;
wallet.firstLockedRewardCycle = 0;
}
wallet.committedRewCycleIndexes = [];
});
}
this.lastRefreshedCycle = currentRewCycle;
}
}
export type Real = {

View File

@@ -357,7 +357,7 @@ export function PoxCommands(
// More on size: https://github.com/dubzzz/fast-check/discussions/2978
// More on cmds: https://github.com/dubzzz/fast-check/discussions/3026
return fc.commands(cmds, { size: "large" });
return fc.commands(cmds, { size: "xsmall" });
}
export const REWARD_CYCLE_LENGTH = 1050;

View File

@@ -149,6 +149,9 @@ export class DelegateStackExtendCommand implements PoxCommand {
"new unlock height",
this.stacker.unlockHeight.toString(),
);
// Refresh the model's state if the network gets to the next reward cycle.
model.stateRefresh(real);
}
toString() {

View File

@@ -123,6 +123,9 @@ export class DelegateStackIncreaseCommand implements PoxCommand {
"total locked",
stackerWallet.amountLocked.toString(),
);
// Refresh the model's state if the network gets to the next reward cycle.
model.stateRefresh(real);
}
toString() {

View File

@@ -169,6 +169,9 @@ export class DelegateStackStxCommand implements PoxCommand {
"until",
this.stacker.unlockHeight.toString()
);
// Refresh the model's state if the network gets to the next reward cycle.
model.stateRefresh(real);
}
toString() {

View File

@@ -106,6 +106,9 @@ export class DelegateStxCommand implements PoxCommand {
"until",
this.untilBurnHt.toString()
);
// Refresh the model's state if the network gets to the next reward cycle.
model.stateRefresh(real);
}
toString() {

View File

@@ -87,6 +87,9 @@ export class DisallowContractCallerCommand implements PoxCommand {
"disallow-contract-caller",
this.callerToDisallow.label,
);
// Refresh the model's state if the network gets to the next reward cycle.
model.stateRefresh(real);
}
toString() {

View File

@@ -55,6 +55,9 @@ export class GetStackingMinimumCommand implements PoxCommand {
"pox-4",
stackingMinimum.value.toString(),
);
// Refresh the model's state if the network gets to the next reward cycle.
model.stateRefresh(real);
}
toString() {

View File

@@ -54,6 +54,9 @@ export class GetStxAccountCommand implements PoxCommand {
"unlocked-height",
actual.unlockHeight.toString(),
);
// Refresh the model's state if the network gets to the next reward cycle.
model.stateRefresh(real);
}
toString() {

View File

@@ -85,6 +85,9 @@ export class RevokeDelegateStxCommand implements PoxCommand {
// Log to console for debugging purposes. This is not necessary for the
// test to pass but it is useful for debugging and eyeballing the test.
logCommand(`${this.wallet.label}`, "revoke-delegate-stx");
// Refresh the model's state if the network gets to the next reward cycle.
model.stateRefresh(real);
}
toString() {

View File

@@ -124,12 +124,17 @@ export class StackAggregationCommitAuthCommand implements PoxCommand {
committedAmount.toString(),
"authorization",
);
// Refresh the model's state if the network gets to the next reward cycle.
model.stateRefresh(real);
}
toString() {
// fast-check will call toString() in case of errors, e.g. property failed.
// It will then make a minimal counterexample, a process called 'shrinking'
// https://github.com/dubzzz/fast-check/issues/2864#issuecomment-1098002642
return `${this.operator.label} stack-aggregation-commit auth-id ${this.authId} for reward cycle ${this.currentCycle}`;
return `${this.operator.label} stack-aggregation-commit auth-id ${this.authId} for reward cycle ${
this.currentCycle + 1
}`;
}
}

View File

@@ -128,12 +128,17 @@ export class StackAggregationCommitIndexedAuthCommand implements PoxCommand {
committedAmount.toString(),
"authorization",
);
// Refresh the model's state if the network gets to the next reward cycle.
model.stateRefresh(real);
}
toString() {
// fast-check will call toString() in case of errors, e.g. property failed.
// It will then make a minimal counterexample, a process called 'shrinking'
// https://github.com/dubzzz/fast-check/issues/2864#issuecomment-1098002642
return `${this.operator.label} stack-aggregation-commit-indexed auth-id ${this.authId} for reward cycle ${this.currentCycle}`;
return `${this.operator.label} stack-aggregation-commit-indexed auth-id ${this.authId} for reward cycle ${
this.currentCycle + 1
}`;
}
}

View File

@@ -128,12 +128,17 @@ export class StackAggregationCommitIndexedSigCommand implements PoxCommand {
committedAmount.toString(),
"signature",
);
// Refresh the model's state if the network gets to the next reward cycle.
model.stateRefresh(real);
}
toString() {
// fast-check will call toString() in case of errors, e.g. property failed.
// It will then make a minimal counterexample, a process called 'shrinking'
// https://github.com/dubzzz/fast-check/issues/2864#issuecomment-1098002642
return `${this.operator.label} stack-aggregation-commit-indexed auth-id ${this.authId} for reward cycle ${this.currentCycle}`;
return `${this.operator.label} stack-aggregation-commit-indexed auth-id ${this.authId} for reward cycle ${
this.currentCycle + 1
}`;
}
}

View File

@@ -124,12 +124,17 @@ export class StackAggregationCommitSigCommand implements PoxCommand {
committedAmount.toString(),
"signature",
);
// Refresh the model's state if the network gets to the next reward cycle.
model.stateRefresh(real);
}
toString() {
// fast-check will call toString() in case of errors, e.g. property failed.
// It will then make a minimal counterexample, a process called 'shrinking'
// https://github.com/dubzzz/fast-check/issues/2864#issuecomment-1098002642
return `${this.operator.label} stack-aggregation-commit auth-id ${this.authId} for reward cycle ${this.currentCycle}`;
return `${this.operator.label} stack-aggregation-commit auth-id ${this.authId} for reward cycle ${
this.currentCycle + 1
}`;
}
}

View File

@@ -96,6 +96,9 @@ export class StackAggregationIncreaseCommand implements PoxCommand {
"cycle index",
this.rewardCycleIndex.toString(),
);
// Refresh the model's state if the network gets to the next reward cycle.
model.stateRefresh(real);
}
toString() {

View File

@@ -172,6 +172,9 @@ export class StackStxCommand implements PoxCommand {
"lock-amount",
amountUstx.toString(),
);
// Refresh the model's state if the network gets to the next reward cycle.
model.stateRefresh(real);
}
toString() {