Skip to content
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

Stateful property-tests for the error/failure paths in PoX-4 #4842

Merged
merged 73 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from 63 commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
050418c
feat(pox-4-tests): add check function delegate to PoxCommand-derived …
moodmosaic May 21, 2024
6f02aeb
feat(pox-4-tests): add check function delegate to PoxCommand-derived …
moodmosaic May 22, 2024
04e7fe6
Remove command tracking from the command's `run` method
BowTiedRadone May 22, 2024
a243d3b
Pass the incremented burn height when calling `stack-stx`
BowTiedRadone May 22, 2024
7a0c1fd
Add the unhappy path cases for `StackStxXCommand_Err`
BowTiedRadone May 22, 2024
bd159e3
Remove `StackStxXCommand.ts` from statistics
BowTiedRadone May 22, 2024
7405ab0
Add unhappy path for `revoke-delegate-stx`
BowTiedRadone May 24, 2024
10d0b9b
Remove `RevokeDelegateStxCommand_Err` from statistics
BowTiedRadone May 24, 2024
0c83016
Add unhappy path for `delegate-stx`
BowTiedRadone May 24, 2024
48b9032
Remove `DelegateStxCommand_Err` from statistics
BowTiedRadone May 24, 2024
b38c224
Use simnet `mineBlock` inside `StackStxAuthCommand_Err`
BowTiedRadone May 24, 2024
93bfa6c
Add the unhappy path cases for `StackAggCommitSigCommand_Err`
BowTiedRadone May 27, 2024
16311d8
Remove `StackAggregationCommitSigCommand_Err` from statistics
BowTiedRadone May 27, 2024
a8e7ea3
Add the unhappy path cases for `StackAggCommitAuthCommand_Err`
BowTiedRadone May 27, 2024
b592998
Remove `StackAggregationCommitAuthCommand_Err` from statistics
BowTiedRadone May 27, 2024
41c0386
Use strict equality inside generator
BowTiedRadone May 27, 2024
788f986
Order statistics alphabetically
BowTiedRadone May 27, 2024
23e6bc1
Add the unhappy path cases for `StackAggCommitIndexedSigCommand_Err`
BowTiedRadone May 27, 2024
74b4a92
Add the unhappy path cases for `StackAggCommitIndexedAuthCommand_Err`
BowTiedRadone May 28, 2024
91f99db
Remove all files containing `_Err` from command tracking
BowTiedRadone May 28, 2024
48a759a
Add one unhappy path case for `StackAggIncreaseCommand_Err`
BowTiedRadone May 28, 2024
70990a4
Format using `deno` according to the other generators
BowTiedRadone May 28, 2024
c66e679
Add unhappy path cases for `DelegateStackStxCommand_Err`
BowTiedRadone May 29, 2024
17fddaf
Add unhappy path cases for `StackIncreaseSigCommand_Err`
BowTiedRadone May 29, 2024
2a7135f
Add unhappy path cases for `StackIncreaseAuthCommand_Err`
BowTiedRadone May 30, 2024
9a4f775
Add unhappy path cases for `StackExtendSigCommand_Err`
BowTiedRadone May 30, 2024
eaf9274
Add unhappy path cases for `StackExtendAuthCommand_Err`
BowTiedRadone May 30, 2024
be39b1a
Add unhappy path cases for `DelegateStackExtendCommand_Err`
BowTiedRadone May 31, 2024
64e2ece
feat(pox-4-tests): add check function delegate to PoxCommand-derived …
moodmosaic May 21, 2024
7f4b536
feat(pox-4-tests): add check function delegate to PoxCommand-derived …
moodmosaic May 22, 2024
124abd4
Remove command tracking from the command's `run` method
BowTiedRadone May 22, 2024
dfb7230
Pass the incremented burn height when calling `stack-stx`
BowTiedRadone May 22, 2024
1de982d
Add the unhappy path cases for `StackStxXCommand_Err`
BowTiedRadone May 22, 2024
be6966c
Remove `StackStxXCommand.ts` from statistics
BowTiedRadone May 22, 2024
544382c
Add unhappy path for `revoke-delegate-stx`
BowTiedRadone May 24, 2024
3227bc4
Remove `RevokeDelegateStxCommand_Err` from statistics
BowTiedRadone May 24, 2024
e7610e3
Add unhappy path for `delegate-stx`
BowTiedRadone May 24, 2024
232d388
Remove `DelegateStxCommand_Err` from statistics
BowTiedRadone May 24, 2024
bdcee6b
Use simnet `mineBlock` inside `StackStxAuthCommand_Err`
BowTiedRadone May 24, 2024
190d7a5
Add the unhappy path cases for `StackAggCommitSigCommand_Err`
BowTiedRadone May 27, 2024
b0f8464
Remove `StackAggregationCommitSigCommand_Err` from statistics
BowTiedRadone May 27, 2024
367e89a
Add the unhappy path cases for `StackAggCommitAuthCommand_Err`
BowTiedRadone May 27, 2024
abdf8bd
Remove `StackAggregationCommitAuthCommand_Err` from statistics
BowTiedRadone May 27, 2024
3ab6e61
Use strict equality inside generator
BowTiedRadone May 27, 2024
91a7c43
Order statistics alphabetically
BowTiedRadone May 27, 2024
ab686c4
Add the unhappy path cases for `StackAggCommitIndexedSigCommand_Err`
BowTiedRadone May 27, 2024
50475b7
Add the unhappy path cases for `StackAggCommitIndexedAuthCommand_Err`
BowTiedRadone May 28, 2024
7173ad6
Remove all files containing `_Err` from command tracking
BowTiedRadone May 28, 2024
c6ff82d
Add one unhappy path case for `StackAggIncreaseCommand_Err`
BowTiedRadone May 28, 2024
a267a04
Format using `deno` according to the other generators
BowTiedRadone May 28, 2024
1bd9c78
Add unhappy path cases for `DelegateStackStxCommand_Err`
BowTiedRadone May 29, 2024
b66b19c
Add unhappy path cases for `StackIncreaseSigCommand_Err`
BowTiedRadone May 29, 2024
50bd1b5
Add unhappy path cases for `StackIncreaseAuthCommand_Err`
BowTiedRadone May 30, 2024
4c2f3b6
Add unhappy path cases for `StackExtendSigCommand_Err`
BowTiedRadone May 30, 2024
add9d55
Add unhappy path cases for `StackExtendAuthCommand_Err`
BowTiedRadone May 30, 2024
3f3da16
Add unhappy path cases for `DelegateStackExtendCommand_Err`
BowTiedRadone May 31, 2024
8a3dc45
Merge branch 'feat/pox-4-stateful-prop-tests-check-err' of https://gi…
BowTiedRadone May 31, 2024
115a385
Update `err_Commands` to include the `delegatedUntilBurnHt` none branch
BowTiedRadone May 31, 2024
6eb8eec
Add unhappy path cases for `DelegateStackIncreaseCommand_Err`
BowTiedRadone May 31, 2024
da87ec8
Order imports inside `err_Commands`
BowTiedRadone May 31, 2024
9365892
Add unhappy path case for `DisallowContractCallerCommand_Err`
BowTiedRadone May 31, 2024
f03bedf
Add tree logging for test-runs statistics
BowTiedRadone Jun 3, 2024
dc9e019
Fix PoX-4 stateful prop tests comments
BowTiedRadone Jun 10, 2024
f460834
Remove types from `err_Commands` `check` functions
BowTiedRadone Jun 18, 2024
452d7bd
Add an additional condition inside `DelegateStackIncreaseCommand`
BowTiedRadone Jun 20, 2024
90d4a2b
Fix typo in `DelegateStackStxCommand_Err` logging
BowTiedRadone Jun 20, 2024
fa5b78f
Update the err_Commands check functions to return the false first
BowTiedRadone Jun 20, 2024
d10d760
Update the way `firstRewardCycle` is calculated
BowTiedRadone Jun 20, 2024
7c8c540
Remove unused `Stub` import inside `err_Commands`
BowTiedRadone Jun 20, 2024
934d554
Update the way `firstRewardCycle` is calculated all over the stateful…
BowTiedRadone Jun 20, 2024
3057aaa
Add helper functions to use in the commands' check methods
BowTiedRadone Jun 20, 2024
dbaf000
Update `err_Commands` check functions to use suggestive helpers
BowTiedRadone Jun 20, 2024
00c0738
Update happy path commands check functions to use suggestive helpers
BowTiedRadone Jun 20, 2024
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,283 changes: 2,283 additions & 0 deletions contrib/boot-contracts-stateful-prop-tests/tests/pox-4/err_Commands.ts

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { StackingClient } from "@stacks/stacking";

import fc from "fast-check";
import { PoxCommands } from "./pox_Commands.ts";
import { ErrCommands } from "./err_Commands.ts";

import fs from "fs";
import path from "path";
Expand Down Expand Up @@ -108,7 +109,8 @@ it("statefully interacts with PoX-4", async () => {
// commands are run at least once.
const statistics = fs.readdirSync(path.join(__dirname)).filter((file) =>
file.startsWith("pox_") && file.endsWith(".ts") &&
file !== "pox_CommandModel.ts" && file !== "pox_Commands.ts"
file !== "pox_CommandModel.ts" && file !== "pox_Commands.ts" &&
!file.includes("_Err")
).map((file) => file.slice(4, -3)); // Remove "pox_" prefix and ".ts" suffix.

// This is the initial state of the model.
Expand Down Expand Up @@ -143,17 +145,22 @@ it("statefully interacts with PoX-4", async () => {

simnet.setEpoch("3.0");

const successPath = PoxCommands(model.wallets, model.stackers, sut.network);
BowTiedRadone marked this conversation as resolved.
Show resolved Hide resolved
const failurePath = ErrCommands(model.wallets, model.stackers, sut.network);
BowTiedRadone marked this conversation as resolved.
Show resolved Hide resolved

fc.assert(
fc.property(
PoxCommands(model.wallets, model.stackers, sut.network),
// More on size: https://github.com/dubzzz/fast-check/discussions/2978
// More on cmds: https://github.com/dubzzz/fast-check/discussions/3026
fc.commands(successPath.concat(failurePath), { size: "xsmall" }),
(cmds) => {
const initialState = () => ({ model: model, real: sut });
fc.modelRun(initialState, cmds);
},
),
{
// Defines the number of test iterations to run; default is 100.
numRuns: 1000,
numRuns: 20000,
// 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ export class AllowContractCallerCommand implements PoxCommand {

const callerToAllow = model.stackers.get(this.allowanceTo.stxAddress)!;
// Update model so that we know this wallet has authorized a contract-caller.
// If the caller is already allowed, there's no need to add it again.
const callerToAllowIndexInAllowedList = wallet.allowedContractCallers
.indexOf(this.allowanceTo.stxAddress);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,49 @@ export class Stub {

reportCommandRuns() {
console.log("Command run method execution counts:");
this.statistics.forEach((count, commandName) => {
console.log(`${commandName}: ${count}`);
const orderedStatistics = Array.from(this.statistics.entries()).sort(
([keyA], [keyB]) => {
return keyA.localeCompare(keyB);
},
);

this.logAsTree(orderedStatistics);
}

private logAsTree(statistics: [string, number][]) {
const tree: { [key: string]: any } = {};

statistics.forEach(([commandName, count]) => {
const split = commandName.split("_");
let root: string = split[0],
rest: string = "base";

if (split.length > 1) {
rest = split.slice(1).join("_");
}
if (!tree[root]) {
tree[root] = {};
}
tree[root][rest] = count;
});

const printTree = (node: any, indent: string = "") => {
const keys = Object.keys(node);
keys.forEach((key, index) => {
const isLast = index === keys.length - 1;
const boxChar = isLast ? "└─ " : "├─ ";
if (key !== "base") {
if (typeof node[key] === "object") {
console.log(`${indent}${boxChar}${key}: ${node[key]["base"]}`);
printTree(node[key], indent + (isLast ? " " : "│ "));
} else {
console.log(`${indent}${boxChar}${key}: ${node[key]}`);
}
}
});
};

printTree(tree);
}

refreshStateForNextRewardCycle(real: Real) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import fc from "fast-check";
import { Real, Stacker, Stub, StxAddress, Wallet } from "./pox_CommandModel";
import { PoxCommand, Stacker, StxAddress, Wallet } from "./pox_CommandModel";
import { GetStackingMinimumCommand } from "./pox_GetStackingMinimumCommand";
import { GetStxAccountCommand } from "./pox_GetStxAccountCommand";
import { StackStxSigCommand } from "./pox_StackStxSigCommand";
Expand Down Expand Up @@ -27,7 +27,7 @@ export function PoxCommands(
wallets: Map<StxAddress, Wallet>,
stackers: Map<StxAddress, Stacker>,
network: Simnet,
): fc.Arbitrary<Iterable<fc.Command<Stub, Real>>> {
): fc.Arbitrary<PoxCommand>[] {
const cmds = [
// GetStackingMinimumCommand
fc.record({
Expand Down Expand Up @@ -452,9 +452,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: "xsmall" });
return cmds;
}

export const REWARD_CYCLE_LENGTH = 1050;
Expand All @@ -481,7 +479,7 @@ export const currentCycleFirstBlock = (network: Simnet) =>
).result,
));

const nextCycleFirstBlock = (network: Simnet) =>
export const nextCycleFirstBlock = (network: Simnet) =>
Number(cvToValue(
network.callReadOnlyFn(
"ST000000000000000000002AMW42H.pox-4",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ export class DelegateStackExtendCommand implements PoxCommand {
* height as a Pool Operator on behalf of a Stacker.
*
* @param operator - Represents the Pool Operator's wallet.
* @param stacker - Represents the STacker's wallet.
* @param extendCount - Represents the cycles to be expended.
* @param stacker - Represents the Stacker's wallet.
* @param extendCount - Represents the number of cycles to extend
* the stack for.
* @param currentCycle - Represents the current PoX reward cycle.
*/
constructor(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import {
logCommand,
PoxCommand,
Real,
Stub,
Wallet,
} from "./pox_CommandModel.ts";
import { poxAddressToTuple } from "@stacks/stacking";
import { expect } from "vitest";
import { Cl } from "@stacks/transactions";

type CheckFunc = (
this: DelegateStackExtendCommand_Err,
model: Readonly<Stub>,
) => boolean;

export class DelegateStackExtendCommand_Err implements PoxCommand {
readonly operator: Wallet;
readonly stacker: Wallet;
readonly extendCount: number;
readonly currentCycle: number;
readonly checkFunc: CheckFunc;
readonly errorCode: number;

/**
* Constructs a `DelegateStackExtendCommand_Err` to extend the unlock
* height as a Pool Operator on behalf of a Stacker.
*
* @param operator - Represents the Pool Operator's wallet.
* @param stacker - Represents the Stacker's wallet.
* @param extendCount - Represents the number of cycles to extend the stack for.
* @param currentCycle - Represents the current PoX reward cycle.
* @param checkFunc - A function to check constraints for running this command.
* @param errorCode - The expected error code when running this command.
*/
constructor(
operator: Wallet,
stacker: Wallet,
extendCount: number,
currentCycle: number,
checkFunc: CheckFunc,
errorCode: number,
) {
this.operator = operator;
this.stacker = stacker;
this.extendCount = extendCount;
this.currentCycle = currentCycle;
this.checkFunc = checkFunc;
this.errorCode = errorCode;
}

check = (model: Readonly<Stub>): boolean => this.checkFunc.call(this, model);

run(model: Stub, real: Real): void {
const stackerWallet = model.stackers.get(this.stacker.stxAddress)!;

// Act
const delegateStackExtend = real.network.callPublicFn(
"ST000000000000000000002AMW42H.pox-4",
"delegate-stack-extend",
[
// (stacker principal)
Cl.principal(this.stacker.stxAddress),
// (pox-addr { version: (buff 1), hashbytes: (buff 32) })
poxAddressToTuple(this.operator.btcAddress),
// (extend-count uint)
Cl.uint(this.extendCount),
],
this.operator.stxAddress,
);

expect(delegateStackExtend.result).toBeErr(Cl.int(this.errorCode));

// 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(
`₿ ${model.burnBlockHeight}`,
`✗ ${this.operator.label} Ӿ ${this.stacker.label}`,
"delegate-stack-extend",
"extend count",
this.extendCount.toString(),
"new unlock height",
stackerWallet.unlockHeight.toString(),
);

// Refresh the model's state if the network gets to the next reward cycle.
model.refreshStateForNextRewardCycle(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} Ӿ ${this.stacker.label} delegate-stack-extend extend count ${this.extendCount}`;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { expect } from "vitest";
import { Cl } from "@stacks/transactions";

/**
* The DelegateStackIncreaseCommand allows a pool operator to
* The `DelegateStackIncreaseCommand` allows a pool operator to
* increase an active stacking lock, issuing a "partial commitment"
* for the increased cycles.
*
Expand All @@ -33,7 +33,7 @@ export class DelegateStackIncreaseCommand implements PoxCommand {
readonly increaseBy: number;

/**
* Constructs a DelegateStackIncreaseCommand to increase the uSTX amount
* Constructs a `DelegateStackIncreaseCommand` to increase the uSTX amount
* previously locked on behalf of a Stacker.
*
* @param operator - Represents the Pool Operator's wallet.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import {
logCommand,
PoxCommand,
Real,
Stub,
Wallet,
} from "./pox_CommandModel.ts";
import { poxAddressToTuple } from "@stacks/stacking";
import { expect } from "vitest";
import { Cl } from "@stacks/transactions";

type CheckFunc = (
this: DelegateStackIncreaseCommand_Err,
model: Readonly<Stub>,
) => boolean;

export class DelegateStackIncreaseCommand_Err implements PoxCommand {
readonly operator: Wallet;
readonly stacker: Wallet;
readonly increaseBy: number;
readonly checkFunc: CheckFunc;
readonly errorCode: number;

/**
* Constructs a `DelegateStackIncreaseCommand_Err` to increase the uSTX amount
* previously locked on behalf of a Stacker.
*
* @param operator - Represents the Pool Operator's wallet.
* @param stacker - Represents the Stacker's wallet.
* @param increaseBy - Represents the locked amount to be increased by.
* @param checkFunc - A function to check constraints for running this command.
* @param errorCode - The expected error code when running this command.
*/
constructor(
operator: Wallet,
stacker: Wallet,
increaseBy: number,
checkFunc: CheckFunc,
errorCode: number,
) {
this.operator = operator;
this.stacker = stacker;
this.increaseBy = increaseBy;
this.checkFunc = checkFunc;
this.errorCode = errorCode;
}

check = (model: Readonly<Stub>): boolean => this.checkFunc.call(this, model);

run(model: Stub, real: Real): void {
const stackerWallet = model.stackers.get(this.stacker.stxAddress)!;
const prevLocked = stackerWallet.amountLocked;
// Act
const delegateStackIncrease = real.network.callPublicFn(
"ST000000000000000000002AMW42H.pox-4",
"delegate-stack-increase",
[
// (stacker principal)
Cl.principal(this.stacker.stxAddress),
// (pox-addr { version: (buff 1), hashbytes: (buff 32) })
poxAddressToTuple(this.operator.btcAddress),
// (increase-by uint)
Cl.uint(this.increaseBy),
],
this.operator.stxAddress,
);

// Assert
expect(delegateStackIncrease.result).toBeErr(Cl.int(this.errorCode));

// 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(
`₿ ${model.burnBlockHeight}`,
`✗ ${this.operator.label} Ӿ ${this.stacker.label}`,
"delegate-stack-increase",
"increased by",
this.increaseBy.toString(),
"previously locked",
prevLocked.toString(),
"total locked",
stackerWallet.amountLocked.toString(),
);

// Refresh the model's state if the network gets to the next reward cycle.
model.refreshStateForNextRewardCycle(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} delegate-stack-increase by ${this.increaseBy}`;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { currentCycle } from "./pox_Commands.ts";
* `get-stacking-minimum` function at the time of this call.
* - The Stacker cannot currently be engaged in another stacking operation.
* - The Stacker has to currently be delegating to the Operator.
* - The stacked STX amount should be less than or equal to the delegated
* - The stacked uSTX amount should be less than or equal to the delegated
* amount.
* - The stacked uSTX amount should be less than or equal to the Stacker's
* balance.
Expand All @@ -47,7 +47,7 @@ export class DelegateStackStxCommand implements PoxCommand {
* on behalf of a Stacker.
*
* @param operator - Represents the Pool Operator's wallet.
* @param stacker - Represents the STacker's wallet.
* @param stacker - Represents the Stacker's wallet.
* @param period - Number of reward cycles to lock uSTX.
* @param amountUstx - The uSTX amount stacked by the Operator on behalf
* of the Stacker.
Expand Down
Loading