From 9905e7e59835b80b0fdc39f51993fa827310a867 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Sat, 16 Mar 2024 10:01:26 +0100 Subject: [PATCH 001/129] wip(pox-4-tests): StackStxCommand & stateful property tests planning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit lays the groundwork for the StackStxCommand and GetStackingMinimumCommand classes for PoX-4. It also proposes the introduction of fast-check based stateful tests, similar to the efforts for sBTC (https://github.com/stacks-network/sbtc/pull/152). As highlighted in https://github.com/stacks-network/stacks-core/issues/4548, this initiative is part of an ongoing effort to embrace a more rigorous, property-based testing strategy for PoX-4 interactions. The planned stateful tests aim to simulate various stacking scenarios, ensuring compliance with PoX-4 protocols and robust error handling. This strategy is expected to greatly enhance test coverage and the reliability of PoX-4 stacking operations, bolstering confidence in the protocol’s robustness and correctness. Note: This is an early-stage WIP commit. Implementation details and testing strategies are subject to substantial development and refinement. --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 92 ++++++++++ .../tests/pox-4/pox_CommandModel.ts | 32 ++++ .../tests/pox-4/pox_Commands.ts | 48 +++++ .../pox-4/pox_GetStackingMinimumCommand.ts | 60 +++++++ .../tests/pox-4/pox_StackStxCommand.ts | 169 ++++++++++++++++++ 5 files changed, 401 insertions(+) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_Commands.ts create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts new file mode 100644 index 0000000000..cdd26d843f --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -0,0 +1,92 @@ +import { describe, it } from "vitest"; + +import { initSimnet } from "@hirosystems/clarinet-sdk"; +import { Real, Stub, StxAddress, Wallet } from "./pox_CommandModel.ts"; + +import { + getPublicKeyFromPrivate, + publicKeyToBtcAddress, +} from "@stacks/encryption"; +import { StacksDevnet } from "@stacks/network"; +import { + createStacksPrivateKey, + getAddressFromPrivateKey, + TransactionVersion, +} from "@stacks/transactions"; +import { StackingClient } from "@stacks/stacking"; + +import fc from "fast-check"; +import { PoxCommands } from "./pox_Commands.ts"; + +describe("PoX-4 invariant tests", () => { + it("statefully does solo stacking with a signature", async () => { + // SUT stands for "System Under Test". + const sut: Real = { + network: await initSimnet(), + }; + + // This is the initial state of the model. + const model: Stub = { + stackingMinimum: 0, + wallets: new Map(), + }; + + const wallets = [ + "7287ba251d44a4d3fd9276c88ce34c5c52a038955511cccaf77e61068649c17801", + "d655b2523bcd65e34889725c73064feb17ceb796831c0e111ba1a552b0f31b3901", + "3eccc5dac8056590432db6a35d52b9896876a3d5cbdea53b72400bc9c2099fe801", + "7036b29cb5e235e5fd9b09ae3e8eec4404e44906814d5d01cbca968a60ed4bfb01", + "b463f0df6c05d2f156393eee73f8016c5372caa0e9e29a901bb7171d90dc4f1401", + ].map((prvKey) => { + const pubKey = getPublicKeyFromPrivate(prvKey); + const devnet = new StacksDevnet(); + const signerPrvKey = createStacksPrivateKey(prvKey); + const signerPubKey = getPublicKeyFromPrivate(signerPrvKey.data); + const btcAddress = publicKeyToBtcAddress(pubKey); + const stxAddress = getAddressFromPrivateKey( + prvKey, + TransactionVersion.Testnet, + ); + + return { + prvKey, + pubKey, + stxAddress, + btcAddress, + signerPrvKey, + signerPubKey, + client: new StackingClient(stxAddress, devnet), + ustxBalance: 100_000_000_000_000, + isStacking: false, + amountLocked: 0, + unlockHeight: 0, + }; + }); + + // Add the wallets to the model. + wallets.forEach((wallet) => { + model.wallets.set(wallet.stxAddress, wallet); + }); + + simnet.setEpoch("3.0"); + + fc.assert( + fc.property( + PoxCommands(model.wallets), + (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, + }, + ); + }); +}); diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts new file mode 100644 index 0000000000..b0ce6e5156 --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -0,0 +1,32 @@ +import fc from "fast-check"; + +import { Simnet } from "@hirosystems/clarinet-sdk"; +import { StacksPrivateKey } from "@stacks/transactions"; +import { StackingClient } from "@stacks/stacking"; + +export type StxAddress = string; + +export type Stub = { + stackingMinimum: number; + wallets: Map; +}; + +export type Real = { + network: Simnet; +}; + +export type Wallet = { + prvKey: string; + pubKey: string; + stxAddress: string; + btcAddress: string; + signerPrvKey: StacksPrivateKey; + signerPubKey: string; + client: StackingClient; + ustxBalance: number; + isStacking: boolean; + amountLocked: number; + unlockHeight: number; +}; + +export type PoxCommand = fc.Command; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts new file mode 100644 index 0000000000..397b8e88b3 --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -0,0 +1,48 @@ +import fc from "fast-check"; +import { Real, Stub, StxAddress, Wallet } from "./pox_CommandModel"; +import { GetStackingMinimumCommand } from "./pox_GetStackingMinimumCommand"; +import { StackStxCommand } from "./pox_StackStxCommand"; + +export function PoxCommands( + wallets: Map, +): fc.Arbitrary>> { + const cmds = [ + // GetStackingMinimumCommand + fc.record({ + wallet: fc.constantFrom(...wallets.values()), + }).map(( + r: { + wallet: Wallet; + }, + ) => + new GetStackingMinimumCommand( + r.wallet, + ) + ), + // StackStxCommand + fc.record({ + wallet: fc.constantFrom(...wallets.values()), + authId: fc.nat(), + period: fc.integer({ min: 1, max: 12 }), + margin: fc.integer({ min: 1, max: 9 }), + }).map(( + r: { + wallet: Wallet; + authId: number; + period: number; + margin: number; + }, + ) => + new StackStxCommand( + r.wallet, + r.authId, + r.period, + r.margin, + ) + ), + ]; + + // 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" }); +} diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts new file mode 100644 index 0000000000..14ba177c4d --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts @@ -0,0 +1,60 @@ +import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { assert } from "vitest"; +import { ClarityType, isClarityType } from "@stacks/transactions"; + +/** + * Implements the `PoxCommand` interface to get the minimum stacking amount + * required for a given reward cycle. + */ +export class GetStackingMinimumCommand implements PoxCommand { + readonly wallet: Wallet; + + /** + * Constructs a new `GetStackingMinimumCommand`. + * + * @param wallet The wallet information, including the STX address used to + * query the stacking minimum requirement. + */ + constructor(wallet: Wallet) { + this.wallet = wallet; + } + + check(_model: Readonly): boolean { + // Can always check the minimum number of uSTX to be stacked in the given + // reward cycle. + return true; + } + + run(model: Stub, real: Real): void { + // Act + const { result: stackingMinimum } = real.network.callReadOnlyFn( + "ST000000000000000000002AMW42H.pox-4", + "get-stacking-minimum", + [], + this.wallet.stxAddress, + ); + assert(isClarityType(stackingMinimum, ClarityType.UInt)); + + // Update the model with the new stacking minimum. This is important for + // the `check` method of the `StackStxCommand` class to work correctly, as + // we as other tests that may depend on the stacking minimum. + model.stackingMinimum = Number(stackingMinimum.value); + + // 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. + console.info( + `✓ ${this.wallet.stxAddress.padStart(8, " ")} ${ + "get-stacking-minimum".padStart(34, " ") + } ${"pox-4".padStart(12, " ")} ${ + stackingMinimum.value.toString().padStart(13, " ") + }`, + ); + } + + 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.wallet.stxAddress} get-stacking-minimum`; + } +} diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts new file mode 100644 index 0000000000..087331387c --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -0,0 +1,169 @@ +import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { Pox4SignatureTopic, poxAddressToTuple } from "@stacks/stacking"; +import { assert, expect } from "vitest"; +import { Cl, ClarityType, isClarityType } from "@stacks/transactions"; + +/** + * The `StackStxCommand` locks STX for stacking within PoX-4. This self-service + * operation allows the `tx-sender` (the `wallet` in this case) to participate + * as a Stacker. + * + * Constraints for running this command include: + * - The Stacker cannot currently be engaged in another stacking operation. + * - A minimum threshold of uSTX must be met, determined by the + * `get-stacking-minimum` function at the time of this call. + * - The amount of uSTX locked may need to be increased in future reward cycles + * if the minimum threshold rises. + */ +export class StackStxCommand implements PoxCommand { + readonly wallet: Wallet; + readonly authId: number; + readonly period: number; + readonly margin: number; + + /** + * Constructs a `StackStxCommand` to lock uSTX for stacking. + * + * @param wallet - Represents the Stacker's wallet. + * @param authId - Unique auth-id for the authorization. + * @param period - Number of reward cycles to lock uSTX. + * @param margin - Multiplier for minimum required uSTX to stack so that each + * Stacker locks a different amount of uSTX across test runs. + */ + constructor( + wallet: Wallet, + authId: number, + period: number, + margin: number, + ) { + this.wallet = wallet; + this.authId = authId; + this.period = period; + this.margin = margin; + } + + check(model: Readonly): boolean { + // Constraints for running this command include: + // - A minimum threshold of uSTX must be met, determined by the + // `get-stacking-minimum` function at the time of this call. + // - The Stacker cannot currently be engaged in another stacking operation. + return model.stackingMinimum > 0 && + !model.wallets.get(this.wallet.stxAddress)?.isStacking; + } + + run(model: Stub, real: Real): void { + // The maximum amount of uSTX that can be used (per tx) with this signer + // key. For our tests, we will use the minimum amount of uSTX to be stacked + // in the given reward cycle multiplied by the margin, which is a randomly + // generated number passed to the constructor of this class. + const maxAmount = model.stackingMinimum * this.margin; + + const signerSig = this.wallet.client.signPoxSignature({ + // The signer key being authorized. + signerPrivateKey: this.wallet.signerPrvKey, + // The reward cycle for which the authorization is valid. + // For `stack-stx` and `stack-extend`, this refers to the reward cycle + // where the transaction is confirmed. For `stack-aggregation-commit`, + // this refers to the reward cycle argument in that function. + rewardCycle: 0, + // For `stack-stx`, this refers to `lock-period`. For `stack-extend`, + // this refers to `extend-count`. For `stack-aggregation-commit`, this is + // `u1`. + period: this.period, + // A string representing the function where this authorization is valid. + // Either `stack-stx`, `stack-extend`, `stack-increase` or `agg-commit`. + topic: Pox4SignatureTopic.StackStx, + // The PoX address that can be used with this signer key. + poxAddress: this.wallet.btcAddress, + // The unique auth-id for this authorization. + authId: this.authId, + // The maximum amount of uSTX that can be used (per tx) with this signer + // key. + maxAmount: maxAmount, + }); + + // The amount of uSTX to be locked in the reward cycle. For this test, we + // will use the maximum amount of uSTX that can be used (per tx) with this + // signer key. + const amountUstx = maxAmount; + + // Act + const stackStx = real.network.callPublicFn( + "ST000000000000000000002AMW42H.pox-4", + "stack-stx", + [ + // (amount-ustx uint) + Cl.uint(amountUstx), + // (pox-addr (tuple (version (buff 1)) (hashbytes (buff 32)))) + poxAddressToTuple(this.wallet.btcAddress), + // (start-burn-ht uint) + Cl.uint(real.network.blockHeight), + // (lock-period uint) + Cl.uint(this.period), + // (signer-sig (optional (buff 65))) + Cl.some(Cl.bufferFromHex(signerSig)), + // (signer-key (buff 33)) + Cl.bufferFromHex(this.wallet.signerPubKey), + // (max-amount uint) + Cl.uint(maxAmount), + // (auth-id uint) + Cl.uint(this.authId), + ], + this.wallet.stxAddress, + ); + + const { result: rewardCycle } = real.network.callReadOnlyFn( + "ST000000000000000000002AMW42H.pox-4", + "burn-height-to-reward-cycle", + [Cl.uint(real.network.blockHeight)], + this.wallet.stxAddress, + ); + assert(isClarityType(rewardCycle, ClarityType.UInt)); + + const { result: unlockBurnHeight } = real.network.callReadOnlyFn( + "ST000000000000000000002AMW42H.pox-4", + "reward-cycle-to-burn-height", + [Cl.uint(Number(rewardCycle.value) + this.period + 1)], + this.wallet.stxAddress, + ); + assert(isClarityType(unlockBurnHeight, ClarityType.UInt)); + + // Assert + expect(stackStx.result).toBeOk( + Cl.tuple({ + "lock-amount": Cl.uint(amountUstx), + "signer-key": Cl.bufferFromHex(this.wallet.signerPubKey), + "stacker": Cl.principal(this.wallet.stxAddress), + "unlock-burn-height": Cl.uint(Number(unlockBurnHeight.value)), + }), + ); + + // Get the wallet from the model and update it with the new state. + const wallet = model.wallets.get(this.wallet.stxAddress)!; + // Update model so that we know this wallet is stacking. This is important + // in order to prevent the test from stacking multiple times with the same + // address. + wallet.isStacking = true; + // Update locked, unlocked, and unlock-height fields in the model. + wallet.amountLocked = amountUstx; + wallet.unlockHeight = Number(unlockBurnHeight.value); + wallet.ustxBalance -= amountUstx; + + // 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. + console.info( + `✓ ${this.wallet.stxAddress.padStart(8, " ")} ${ + "stack-stx".padStart(34, " ") + } ${"lock-amount".padStart(12, " ")} ${ + amountUstx.toString().padStart(13, " ") + }`, + ); + } + + 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.wallet.stxAddress} stack-stx auth-id ${this.authId} and period ${this.period}`; + } +} From 57cc223077f42ca8e3728de2bbf898dd36100cd1 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Mon, 18 Mar 2024 01:24:26 +0100 Subject: [PATCH 002/129] test(pox-4-tests): Add GetStxAccountCommand --- .../tests/pox-4/pox_Commands.ts | 13 +++++ .../tests/pox-4/pox_GetStxAccountCommand.ts | 57 +++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 397b8e88b3..e2e71fe479 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -1,6 +1,7 @@ import fc from "fast-check"; import { Real, Stub, StxAddress, Wallet } from "./pox_CommandModel"; import { GetStackingMinimumCommand } from "./pox_GetStackingMinimumCommand"; +import { GetStxAccountCommand } from "./pox_GetStxAccountCommand"; import { StackStxCommand } from "./pox_StackStxCommand"; export function PoxCommands( @@ -40,6 +41,18 @@ export function PoxCommands( r.margin, ) ), + // GetStxAccountCommand + fc.record({ + wallet: fc.constantFrom(...wallets.values()), + }).map(( + r: { + wallet: Wallet; + }, + ) => + new GetStxAccountCommand( + r.wallet, + ) + ), ]; // More on size: https://github.com/dubzzz/fast-check/discussions/2978 diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts new file mode 100644 index 0000000000..780f363417 --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts @@ -0,0 +1,57 @@ +import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { expect } from "vitest"; +import { Cl } from "@stacks/transactions"; + +/** + * Implements the `PoxCommand` interface to get the info returned from the + * `stx-account`. + */ +export class GetStxAccountCommand implements PoxCommand { + readonly wallet: Wallet; + + /** + * Constructs a new `GetStxAccountCommand`. + * + * @param wallet The wallet information, including the STX address used to + * query the `stx-account`. + */ + constructor(wallet: Wallet) { + this.wallet = wallet; + } + + check(_model: Readonly): boolean { + // Can always check the `stx-account` info. + return true; + } + + run(model: Stub, real: Real): void { + const actual = model.wallets.get(this.wallet.stxAddress)!; + expect(real.network.runSnippet(`(stx-account '${actual.stxAddress})`)) + .toBeTuple({ + "locked": Cl.uint(actual.amountLocked), + "unlocked": Cl.uint(actual.ustxBalance), + "unlock-height": Cl.uint(actual.unlockHeight), + }); + + // 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. + console.info( + `✓ ${this.wallet.stxAddress.padStart(8, " ")} ${ + "stx-account".padStart(34, " ") + } ${"lock-amount".padStart(12, " ")} ${ + actual.amountLocked.toString().padStart(13, " ") + } ${"unlocked-amount".padStart(12, " ")} ${ + actual.ustxBalance.toString().padStart(15, " ") + } ${"unlocked-height".padStart(12, " ")} ${ + actual.unlockHeight.toString().padStart(7, " ") + }`, + ); + } + + 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.wallet.stxAddress} stx-account`; + } +} From b047b943602575f23425d853b3d89396d9677a0b Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Mon, 18 Mar 2024 14:42:43 +0200 Subject: [PATCH 003/129] test(pox-4-tests): Add DelegateStxCommand --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 2 + .../tests/pox-4/pox_CommandModel.ts | 2 + .../tests/pox-4/pox_Commands.ts | 22 ++++ .../tests/pox-4/pox_DelegateStxCommand.ts | 119 ++++++++++++++++++ .../tests/pox-4/pox_StackStxCommand.ts | 8 +- 5 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index cdd26d843f..009d70bbf3 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -58,6 +58,8 @@ describe("PoX-4 invariant tests", () => { client: new StackingClient(stxAddress, devnet), ustxBalance: 100_000_000_000_000, isStacking: false, + hasDelegated: false, + delegatedTo: "", amountLocked: 0, unlockHeight: 0, }; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index b0ce6e5156..39d08c6b79 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -25,6 +25,8 @@ export type Wallet = { client: StackingClient; ustxBalance: number; isStacking: boolean; + hasDelegated: boolean; + delegatedTo: string; amountLocked: number; unlockHeight: number; }; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index e2e71fe479..1e45237a94 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -3,6 +3,7 @@ import { Real, Stub, StxAddress, Wallet } from "./pox_CommandModel"; import { GetStackingMinimumCommand } from "./pox_GetStackingMinimumCommand"; import { GetStxAccountCommand } from "./pox_GetStxAccountCommand"; import { StackStxCommand } from "./pox_StackStxCommand"; +import { DelegateStxCommand } from "./pox_DelegateStxCommand"; export function PoxCommands( wallets: Map, @@ -41,6 +42,27 @@ export function PoxCommands( r.margin, ) ), + // DelegateStxCommand + fc.record({ + wallet: fc.constantFrom(...wallets.values()), + delegateTo: fc.constantFrom(...wallets.values()), + untilBurnHt: fc.integer({ min: 1 }), + margin: fc.integer({ min: 1, max: 9 }), + }).map(( + r: { + wallet: Wallet; + delegateTo: Wallet; + untilBurnHt: number; + margin: number; + }, + ) => + new DelegateStxCommand( + r.wallet, + r.delegateTo, + r.untilBurnHt, + r.margin, + ) + ), // GetStxAccountCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts new file mode 100644 index 0000000000..395a775175 --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts @@ -0,0 +1,119 @@ +import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { poxAddressToTuple } from "@stacks/stacking"; +import { expect } from "vitest"; +import { boolCV, Cl } from "@stacks/transactions"; + +/** + * The `DelegateStxCommand` delegates STX for stacking within PoX-4. This self-service + * operation allows the `tx-sender` (the `wallet` in this case) to delegate stacking + * participation to a `delegatee`. + * + * Constraints for running this command include: + * - The Stacker cannot currently be a delegator in another delegation. + * - The PoX address provided should have a valid version (between 0 and 6 inclusive). + */ +export class DelegateStxCommand implements PoxCommand { + readonly wallet: Wallet; + readonly delegateTo: Wallet; + readonly untilBurnHt: number; + readonly margin: number; + + /** + * Constructs a `DelegateStxCommand` to delegate uSTX for stacking. + * + * @param wallet - Represents the Stacker's wallet. + * @param delegateTo - Represents the Delegatee's STX address. + * @param untilBurnHt - The burn block height until the delegation is valid. + * @param margin - Multiplier for minimum required uSTX to stack so that each + * Stacker locks a different amount of uSTX across test runs. + */ + constructor( + wallet: Wallet, + delegateTo: Wallet, + untilBurnHt: number, + margin: number, + ) { + this.wallet = wallet; + this.delegateTo = delegateTo; + this.untilBurnHt = untilBurnHt; + this.margin = margin; + } + + check(model: Readonly): boolean { + // Constraints for running this command include: + // - The Stacker cannot currently be a delegator in another delegation. + return ( + model.stackingMinimum > 0 && + !model.wallets.get(this.wallet.stxAddress)?.hasDelegated + ); + } + + run(model: Stub, real: Real): void { + // The amount of uSTX delegated by the Stacker to the Delegatee. + // For our tests, we will use the minimum amount of uSTX to be stacked + // in the given reward cycle multiplied by the margin, which is a randomly + // generated number passed to the constructor of this class. Even if there + // are no constraints about the delegated amount, it will be checked in the + // future, when calling delegate-stack-stx. + const delegatedAmount = model.stackingMinimum * this.margin; + + // The amount of uSTX to be delegated. For this test, we will use the + // delegated amount calculated before. + const amountUstx = delegatedAmount; + + // Act + const delegateStx = real.network.callPublicFn( + "ST000000000000000000002AMW42H.pox-4", + "delegate-stx", + [ + // (amount-ustx uint) + Cl.uint(amountUstx), + // (delegate-to principal) + Cl.principal(this.delegateTo.stxAddress), + // (until-burn-ht (optional uint)) + Cl.some(Cl.uint(this.untilBurnHt)), + // (pox-addr (optional { version: (buff 1), hashbytes: (buff 32) })) + Cl.some(poxAddressToTuple(this.delegateTo.btcAddress)), + ], + this.wallet.stxAddress, + ); + + // Assert + expect(delegateStx.result).toBeOk(boolCV(true)); + + // Get the wallet from the model and update it with the new state. + const wallet = model.wallets.get(this.wallet.stxAddress)!; + // Update model so that we know this wallet has delegated. This is important + // in order to prevent the test from delegating multiple times with the same + // address. + wallet.hasDelegated = true; + wallet.delegatedTo = this.delegateTo.stxAddress; + + // 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. + console.info( + `✓ ${this.wallet.stxAddress.padStart(8, " ")} ${ + "delegate-stx".padStart( + 34, + " ", + ) + } ${"amount".padStart(12, " ")} ${ + amountUstx + .toString() + .padStart(13, " ") + } delegated to ${ + this.delegateTo.stxAddress.padStart( + 42, + " ", + ) + }`, + ); + } + + 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.wallet.stxAddress} delegate-stx to ${this.delegateTo.stxAddress} until burn ht ${this.untilBurnHt}`; + } +} diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index 087331387c..2a6de9e893 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -47,8 +47,12 @@ export class StackStxCommand implements PoxCommand { // - A minimum threshold of uSTX must be met, determined by the // `get-stacking-minimum` function at the time of this call. // - The Stacker cannot currently be engaged in another stacking operation. - return model.stackingMinimum > 0 && - !model.wallets.get(this.wallet.stxAddress)?.isStacking; + // - The Stacker cannot currently be delegating STX to a delegatee. + return ( + model.stackingMinimum > 0 && + !model.wallets.get(this.wallet.stxAddress)?.isStacking && + !model.wallets.get(this.wallet.stxAddress)?.hasDelegated + ); } run(model: Stub, real: Real): void { From c7dd8f4d390345356fafc80a0a4af363e243de13 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Tue, 19 Mar 2024 10:00:50 +0100 Subject: [PATCH 004/129] test(pox-4-tests): Incorporate wallet labels for clearer test logging Revamps the PoX-4 testing suite by introducing wallet labels, aiming for more intelligible logging and easier identification of wallets in tests. This enhancement affects various commands and test setups, making debugging and test verification processes more straightforward. Includes updates to wallet structures and all related command implementations to utilize these labels in their logging outputs. --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 19 +++++++++++++------ .../tests/pox-4/pox_CommandModel.ts | 1 + .../tests/pox-4/pox_DelegateStxCommand.ts | 6 +++--- .../pox-4/pox_GetStackingMinimumCommand.ts | 4 ++-- .../tests/pox-4/pox_GetStxAccountCommand.ts | 4 ++-- .../tests/pox-4/pox_StackStxCommand.ts | 4 ++-- 6 files changed, 23 insertions(+), 15 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index 009d70bbf3..f768c2bad6 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -32,12 +32,18 @@ describe("PoX-4 invariant tests", () => { }; const wallets = [ - "7287ba251d44a4d3fd9276c88ce34c5c52a038955511cccaf77e61068649c17801", - "d655b2523bcd65e34889725c73064feb17ceb796831c0e111ba1a552b0f31b3901", - "3eccc5dac8056590432db6a35d52b9896876a3d5cbdea53b72400bc9c2099fe801", - "7036b29cb5e235e5fd9b09ae3e8eec4404e44906814d5d01cbca968a60ed4bfb01", - "b463f0df6c05d2f156393eee73f8016c5372caa0e9e29a901bb7171d90dc4f1401", - ].map((prvKey) => { + ["wallet_1", "7287ba251d44a4d3fd9276c88ce34c5c52a038955511cccaf77e61068649c17801"], + ["wallet_2", "530d9f61984c888536871c6573073bdfc0058896dc1adfe9a6a10dfacadc209101"], + ["wallet_3", "d655b2523bcd65e34889725c73064feb17ceb796831c0e111ba1a552b0f31b3901"], + ["wallet_4", "f9d7206a47f14d2870c163ebab4bf3e70d18f5d14ce1031f3902fbbc894fe4c701"], + ["wallet_5", "3eccc5dac8056590432db6a35d52b9896876a3d5cbdea53b72400bc9c2099fe801"], + ["wallet_6", "7036b29cb5e235e5fd9b09ae3e8eec4404e44906814d5d01cbca968a60ed4bfb01"], + ["wallet_7", "b463f0df6c05d2f156393eee73f8016c5372caa0e9e29a901bb7171d90dc4f1401"], + ["wallet_8", "6a1a754ba863d7bab14adbbc3f8ebb090af9e871ace621d3e5ab634e1422885e01"], + ["wallet_9", "de433bdfa14ec43aa1098d5be594c8ffb20a31485ff9de2923b2689471c401b801"], + ].map((wallet) => { + const label = wallet[0]; + const prvKey = wallet[1]; const pubKey = getPublicKeyFromPrivate(prvKey); const devnet = new StacksDevnet(); const signerPrvKey = createStacksPrivateKey(prvKey); @@ -49,6 +55,7 @@ describe("PoX-4 invariant tests", () => { ); return { + label, prvKey, pubKey, stxAddress, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 39d08c6b79..acaf90658a 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -16,6 +16,7 @@ export type Real = { }; export type Wallet = { + label: string; prvKey: string; pubKey: string; stxAddress: string; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts index 395a775175..426d55f980 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts @@ -92,7 +92,7 @@ export class DelegateStxCommand 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. console.info( - `✓ ${this.wallet.stxAddress.padStart(8, " ")} ${ + `✓ ${this.wallet.label.padStart(8, " ")} ${ "delegate-stx".padStart( 34, " ", @@ -102,7 +102,7 @@ export class DelegateStxCommand implements PoxCommand { .toString() .padStart(13, " ") } delegated to ${ - this.delegateTo.stxAddress.padStart( + this.delegateTo.label.padStart( 42, " ", ) @@ -114,6 +114,6 @@ export class DelegateStxCommand implements PoxCommand { // 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.wallet.stxAddress} delegate-stx to ${this.delegateTo.stxAddress} until burn ht ${this.untilBurnHt}`; + return `${this.wallet.label} delegate-stx to ${this.delegateTo.label} until burn ht ${this.untilBurnHt}`; } } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts index 14ba177c4d..e9968e7060 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts @@ -43,7 +43,7 @@ export class GetStackingMinimumCommand 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. console.info( - `✓ ${this.wallet.stxAddress.padStart(8, " ")} ${ + `✓ ${this.wallet.label.padStart(8, " ")} ${ "get-stacking-minimum".padStart(34, " ") } ${"pox-4".padStart(12, " ")} ${ stackingMinimum.value.toString().padStart(13, " ") @@ -55,6 +55,6 @@ export class GetStackingMinimumCommand implements PoxCommand { // 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.wallet.stxAddress} get-stacking-minimum`; + return `${this.wallet.label} get-stacking-minimum`; } } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts index 780f363417..0d415f6a29 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts @@ -36,7 +36,7 @@ export class GetStxAccountCommand 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. console.info( - `✓ ${this.wallet.stxAddress.padStart(8, " ")} ${ + `✓ ${this.wallet.label.padStart(8, " ")} ${ "stx-account".padStart(34, " ") } ${"lock-amount".padStart(12, " ")} ${ actual.amountLocked.toString().padStart(13, " ") @@ -52,6 +52,6 @@ export class GetStxAccountCommand implements PoxCommand { // 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.wallet.stxAddress} stx-account`; + return `${this.wallet.label} stx-account`; } } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index 2a6de9e893..b0fa999280 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -156,7 +156,7 @@ export class StackStxCommand 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. console.info( - `✓ ${this.wallet.stxAddress.padStart(8, " ")} ${ + `✓ ${this.wallet.label.padStart(8, " ")} ${ "stack-stx".padStart(34, " ") } ${"lock-amount".padStart(12, " ")} ${ amountUstx.toString().padStart(13, " ") @@ -168,6 +168,6 @@ export class StackStxCommand implements PoxCommand { // 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.wallet.stxAddress} stack-stx auth-id ${this.authId} and period ${this.period}`; + return `${this.wallet.label} stack-stx auth-id ${this.authId} and period ${this.period}`; } } From 8d886f59e2182743a59afa6a70dea7547575f643 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Tue, 19 Mar 2024 15:01:30 +0100 Subject: [PATCH 005/129] refactor(pox-4-tests): Remove unused prvKey and pubKey from Wallet Simplifies the Wallet type and its usage in PoX-4 tests by removing the prvKey and pubKey fields. This change reflects an effort to simplify the data structures and focus on the essential elements needed for testing. The reduction in fields contributes to cleaner code and minimizes unnecessary data handling in the test setup and execution. --- .../core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts | 2 -- contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts | 2 -- 2 files changed, 4 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index f768c2bad6..809280b2aa 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -56,8 +56,6 @@ describe("PoX-4 invariant tests", () => { return { label, - prvKey, - pubKey, stxAddress, btcAddress, signerPrvKey, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index acaf90658a..0eb9a98e44 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -17,8 +17,6 @@ export type Real = { export type Wallet = { label: string; - prvKey: string; - pubKey: string; stxAddress: string; btcAddress: string; signerPrvKey: StacksPrivateKey; From d6536c38fdf9774cd58cc86cc370c28643072b20 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Tue, 19 Mar 2024 15:03:14 +0100 Subject: [PATCH 006/129] refactor(pox-4-tests): Rename Wallet 'client' to 'stackingClient' Improves code clarity by renaming the 'client' field in the Wallet type to 'stackingClient'. This change better specifies the purpose of the client as specifically for stacking operations within the PoX-4 testing framework. The update is applied across all instances where the field is referenced, ensuring consistency and enhancing readability. --- .../core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts | 2 +- contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts | 2 +- contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index 809280b2aa..ab7dea06ae 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -60,7 +60,7 @@ describe("PoX-4 invariant tests", () => { btcAddress, signerPrvKey, signerPubKey, - client: new StackingClient(stxAddress, devnet), + stackingClient: new StackingClient(stxAddress, devnet), ustxBalance: 100_000_000_000_000, isStacking: false, hasDelegated: false, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 0eb9a98e44..b823248e58 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -21,7 +21,7 @@ export type Wallet = { btcAddress: string; signerPrvKey: StacksPrivateKey; signerPubKey: string; - client: StackingClient; + stackingClient: StackingClient; ustxBalance: number; isStacking: boolean; hasDelegated: boolean; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index b0fa999280..63ae48bbd2 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -62,7 +62,7 @@ export class StackStxCommand implements PoxCommand { // generated number passed to the constructor of this class. const maxAmount = model.stackingMinimum * this.margin; - const signerSig = this.wallet.client.signPoxSignature({ + const signerSig = this.wallet.stackingClient.signPoxSignature({ // The signer key being authorized. signerPrivateKey: this.wallet.signerPrvKey, // The reward cycle for which the authorization is valid. From d50a40217ba7560bda788cde42da4ce9510fcff6 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Tue, 19 Mar 2024 15:04:23 +0100 Subject: [PATCH 007/129] refactor(pox-4-tests): Typify 'delegatedTo' field in Wallet Enhances type safety by changing the 'delegatedTo' field in the Wallet type from a generic string to a more specific StxAddress type. This modification aids in preventing potential bugs by ensuring the field is used consistently as an STX address across the PoX-4 testing suite. The adjustment promotes clearer code, and better alignment with the domain model. --- contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index b823248e58..174ad1c805 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -25,7 +25,7 @@ export type Wallet = { ustxBalance: number; isStacking: boolean; hasDelegated: boolean; - delegatedTo: string; + delegatedTo: StxAddress; amountLocked: number; unlockHeight: number; }; From e8e2b5db1f2c2caa25bd865d41e43c7e4bc98931 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Tue, 19 Mar 2024 16:07:26 +0100 Subject: [PATCH 008/129] feat(pox-4-tests): Add amountUnlocked to Wallet for staking Introduces `amountUnlocked` to the Wallet model in PoX-4 tests to clearly differentiate between locked and available balances. This addition complements the existing balance field, enhancing understanding of staking dynamics without renaming or removing existing structures. Adjustments made in related commands and tests ensure accuracy and consistency. --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 4 +++- contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts | 1 + .../tests/pox-4/pox_GetStxAccountCommand.ts | 4 ++-- .../core-contract-tests/tests/pox-4/pox_StackStxCommand.ts | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index ab7dea06ae..f2e943bb32 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -46,6 +46,7 @@ describe("PoX-4 invariant tests", () => { const prvKey = wallet[1]; const pubKey = getPublicKeyFromPrivate(prvKey); const devnet = new StacksDevnet(); + const initialUstxBalance = 100_000_000_000_000; const signerPrvKey = createStacksPrivateKey(prvKey); const signerPubKey = getPublicKeyFromPrivate(signerPrvKey.data); const btcAddress = publicKeyToBtcAddress(pubKey); @@ -61,11 +62,12 @@ describe("PoX-4 invariant tests", () => { signerPrvKey, signerPubKey, stackingClient: new StackingClient(stxAddress, devnet), - ustxBalance: 100_000_000_000_000, + ustxBalance: initialUstxBalance, isStacking: false, hasDelegated: false, delegatedTo: "", amountLocked: 0, + amountUnlocked: initialUstxBalance, unlockHeight: 0, }; }); diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 174ad1c805..2f19482f39 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -27,6 +27,7 @@ export type Wallet = { hasDelegated: boolean; delegatedTo: StxAddress; amountLocked: number; + amountUnlocked: number; unlockHeight: number; }; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts index 0d415f6a29..0a902f0366 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts @@ -29,7 +29,7 @@ export class GetStxAccountCommand implements PoxCommand { expect(real.network.runSnippet(`(stx-account '${actual.stxAddress})`)) .toBeTuple({ "locked": Cl.uint(actual.amountLocked), - "unlocked": Cl.uint(actual.ustxBalance), + "unlocked": Cl.uint(actual.amountUnlocked), "unlock-height": Cl.uint(actual.unlockHeight), }); @@ -41,7 +41,7 @@ export class GetStxAccountCommand implements PoxCommand { } ${"lock-amount".padStart(12, " ")} ${ actual.amountLocked.toString().padStart(13, " ") } ${"unlocked-amount".padStart(12, " ")} ${ - actual.ustxBalance.toString().padStart(15, " ") + actual.amountUnlocked.toString().padStart(15, " ") } ${"unlocked-height".padStart(12, " ")} ${ actual.unlockHeight.toString().padStart(7, " ") }`, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index 63ae48bbd2..68aa2f1992 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -151,7 +151,7 @@ export class StackStxCommand implements PoxCommand { // Update locked, unlocked, and unlock-height fields in the model. wallet.amountLocked = amountUstx; wallet.unlockHeight = Number(unlockBurnHeight.value); - wallet.ustxBalance -= amountUstx; + wallet.amountUnlocked -= amountUstx; // 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. From 71306da1bdd244d9b6261c5d9a5ac837834cd261 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Tue, 19 Mar 2024 23:16:34 +0200 Subject: [PATCH 009/129] test(pox-4-tests): Add DelegateStackStxCommand --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 39 ++++- .../tests/pox-4/pox_CommandModel.ts | 2 + .../tests/pox-4/pox_Commands.ts | 38 ++++- .../pox-4/pox_DelegateStackStxCommand.ts | 156 ++++++++++++++++++ .../tests/pox-4/pox_DelegateStxCommand.ts | 34 ++-- .../pox-4/pox_GetStackingMinimumCommand.ts | 2 +- .../tests/pox-4/pox_GetStxAccountCommand.ts | 2 +- .../tests/pox-4/pox_StackStxCommand.ts | 2 +- 8 files changed, 246 insertions(+), 29 deletions(-) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index f2e943bb32..d02101bb37 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -1,6 +1,5 @@ import { describe, it } from "vitest"; - -import { initSimnet } from "@hirosystems/clarinet-sdk"; +import { initSimnet, Simnet } from "@hirosystems/clarinet-sdk"; import { Real, Stub, StxAddress, Wallet } from "./pox_CommandModel.ts"; import { @@ -9,7 +8,9 @@ import { } from "@stacks/encryption"; import { StacksDevnet } from "@stacks/network"; import { + Cl, createStacksPrivateKey, + cvToValue, getAddressFromPrivateKey, TransactionVersion, } from "@stacks/transactions"; @@ -18,6 +19,36 @@ import { StackingClient } from "@stacks/stacking"; import fc from "fast-check"; import { PoxCommands } from "./pox_Commands.ts"; +export const currentCycle = (network: Simnet) => + Number(cvToValue( + network.callReadOnlyFn( + "ST000000000000000000002AMW42H.pox-4", + "current-pox-reward-cycle", + [], + "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM", + ).result, + )); + +export const currentCycleFirstBlock = (network: Simnet) => + Number(cvToValue( + network.callReadOnlyFn( + "ST000000000000000000002AMW42H.pox-4", + "reward-cycle-to-burn-height", + [Cl.uint(currentCycle(network))], + "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM", + ).result, + )); + +export const nextCycleFirstBlock = (network: Simnet) => + Number(cvToValue( + network.callReadOnlyFn( + "ST000000000000000000002AMW42H.pox-4", + "reward-cycle-to-burn-height", + [Cl.uint(currentCycle(network) + 1)], + "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM", + ).result, + )); + describe("PoX-4 invariant tests", () => { it("statefully does solo stacking with a signature", async () => { // SUT stands for "System Under Test". @@ -65,7 +96,9 @@ describe("PoX-4 invariant tests", () => { ustxBalance: initialUstxBalance, isStacking: false, hasDelegated: false, + hasPoolMembers: [], delegatedTo: "", + delegatedMaxAmount: 0, amountLocked: 0, amountUnlocked: initialUstxBalance, unlockHeight: 0, @@ -81,7 +114,7 @@ describe("PoX-4 invariant tests", () => { fc.assert( fc.property( - PoxCommands(model.wallets), + PoxCommands(model.wallets, sut.network), (cmds) => { const initialState = () => ({ model: model, real: sut }); fc.modelRun(initialState, cmds); diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 2f19482f39..f88d64ccd4 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -25,7 +25,9 @@ export type Wallet = { ustxBalance: number; isStacking: boolean; hasDelegated: boolean; + hasPoolMembers: StxAddress[]; delegatedTo: StxAddress; + delegatedMaxAmount: number; amountLocked: number; amountUnlocked: number; unlockHeight: number; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 1e45237a94..bea8907412 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -4,9 +4,12 @@ import { GetStackingMinimumCommand } from "./pox_GetStackingMinimumCommand"; import { GetStxAccountCommand } from "./pox_GetStxAccountCommand"; import { StackStxCommand } from "./pox_StackStxCommand"; import { DelegateStxCommand } from "./pox_DelegateStxCommand"; +import { DelegateStackStxCommand } from "./pox_DelegateStackStxCommand"; +import { Simnet } from "@hirosystems/clarinet-sdk"; +import { currentCycleFirstBlock, nextCycleFirstBlock } from "./pox-4.stateful-prop.test"; export function PoxCommands( - wallets: Map, + wallets: Map, network: Simnet, ): fc.Arbitrary>> { const cmds = [ // GetStackingMinimumCommand @@ -47,20 +50,47 @@ export function PoxCommands( wallet: fc.constantFrom(...wallets.values()), delegateTo: fc.constantFrom(...wallets.values()), untilBurnHt: fc.integer({ min: 1 }), - margin: fc.integer({ min: 1, max: 9 }), + amount: fc.bigInt({ min:0n, max: 100_000_000_000_000n }), }).map(( r: { wallet: Wallet; delegateTo: Wallet; untilBurnHt: number; - margin: number; + amount: bigint; }, ) => new DelegateStxCommand( r.wallet, r.delegateTo, r.untilBurnHt, - r.margin, + r.amount, + ) + ), + // DelegateStackStxCommand + fc.record({ + operator: fc.constantFrom(...wallets.values()), + stacker: fc.constantFrom(...wallets.values()), + startBurnHt: fc.integer({ + min: currentCycleFirstBlock(network), + max: nextCycleFirstBlock(network), + }), + period: fc.integer({ min: 1, max: 12 }), + amount: fc.bigInt({ min:0n, max: 100_000_000_000_000n }), + }).map(( + r: { + operator: Wallet; + stacker: Wallet; + startBurnHt: number; + period: number; + amount: bigint; + }, + ) => + new DelegateStackStxCommand( + r.operator, + r.stacker, + r.startBurnHt, + r.period, + r.amount ) ), // GetStxAccountCommand diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts new file mode 100644 index 0000000000..4fb9ed09a4 --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -0,0 +1,156 @@ +import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { poxAddressToTuple } from "@stacks/stacking"; +import { assert, expect } from "vitest"; +import { Cl, ClarityType, isClarityType } from "@stacks/transactions"; + +/** + * The `DelegateStackStxCommand` locks STX for stacking within PoX-4 on behalf of a delegator. + * This operation allows the `operator` to stack the `stacker`'s STX. + * + * Constraints for running this command include: + * - A minimum threshold of uSTX must be met, determined by the + * `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 amount. + * - The stacked uSTX amount should be less than or equal to the + * Stacker's balance + * - The stacked uSTX amount should be greater than or equal to the + * minimum threshold of uSTX + * - The Operator has to currently be delegated by the Stacker. + */ +export class DelegateStackStxCommand implements PoxCommand { + readonly operator: Wallet; + readonly stacker: Wallet; + readonly startBurnHt: number; + readonly period: number; + readonly amountUstx: bigint; + + /** + * Constructs a `DelegateStackStxCommand` to lock uSTX 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 startBurnHt - A burn height inside the current reward cycle. + * @param period - Number of reward cycles to lock uSTX. + * @param amountUstx - The uSTX amount stacked by the Operator on behalf + * of the Stacker + */ + constructor( + operator: Wallet, + stacker: Wallet, + startBurnHt: number, + period: number, + amountUstx: bigint, + ) { + this.operator = operator; + this.stacker = stacker; + this.startBurnHt = startBurnHt; + this.period = period; + this.amountUstx = amountUstx; + } + + check(model: Readonly): boolean { + // Constraints for running this command include: + // - A minimum threshold of uSTX must be met, determined by the + // `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 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 + // - The stacked uSTX amount should be greater than or equal to the + // minimum threshold of uSTX + // - The Operator has to currently be delegated by the Stacker + + const operatorWallet = model.wallets.get(this.operator.stxAddress)!; + const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; + return ( + model.stackingMinimum > 0 && + !stackerWallet.isStacking && + stackerWallet.hasDelegated && + stackerWallet.delegatedMaxAmount >= Number(this.amountUstx) && + Number(this.amountUstx) <= stackerWallet.ustxBalance && + Number(this.amountUstx) >= model.stackingMinimum && + operatorWallet.hasPoolMembers.includes(stackerWallet.stxAddress) + ); + } + + run(model: Stub, real: Real): void { + // Act + const delegateStackStx = real.network.callPublicFn( + "ST000000000000000000002AMW42H.pox-4", + "delegate-stack-stx", + [ + // (stacker principal) + Cl.principal(this.stacker.stxAddress), + // (amount-ustx uint) + Cl.uint(this.amountUstx), + // (pox-addr { version: (buff 1), hashbytes: (buff 32) }) + poxAddressToTuple(this.operator.btcAddress), + // (start-burn-ht uint) + Cl.uint(this.startBurnHt), + // (lock-period uint) + Cl.uint(this.period) + ], + this.operator.stxAddress, + ); + const { result: rewardCycle } = real.network.callReadOnlyFn( + "ST000000000000000000002AMW42H.pox-4", + "burn-height-to-reward-cycle", + [Cl.uint(real.network.blockHeight)], + this.operator.stxAddress, + ); + assert(isClarityType(rewardCycle, ClarityType.UInt)); + + const { result: unlockBurnHeight } = real.network.callReadOnlyFn( + "ST000000000000000000002AMW42H.pox-4", + "reward-cycle-to-burn-height", + [Cl.uint(Number(rewardCycle.value) + this.period + 1)], + this.operator.stxAddress, + ); + assert(isClarityType(unlockBurnHeight, ClarityType.UInt)); + + // Assert + expect(delegateStackStx.result).toBeOk( + Cl.tuple({ + stacker: Cl.principal(this.stacker.stxAddress), + "lock-amount": Cl.uint(this.amountUstx), + "unlock-burn-height": Cl.uint(Number(unlockBurnHeight.value)), + }), + ); + + // Get the Stacker's wallet from the model and update it with the new state. + const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; + // Update model so that we know this wallet is stacking. This is important + // in order to prevent the test from stacking multiple times with the same + // address. + stackerWallet.isStacking = true; + // Update locked, unlocked, and unlock-height fields in the model. + stackerWallet.amountLocked = Number(this.amountUstx); + stackerWallet.unlockHeight = Number(unlockBurnHeight.value); + stackerWallet.amountUnlocked -= Number(this.amountUstx); + + // 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. + console.info( + `✓ ${this.operator.label.padStart(8, " ")} Ӿ ${this.stacker.label.padStart(8, " ")} ${ + "delegate-stack-stx".padStart(23, " ") + } ${"lock-amount".padStart(12, " ")} ${ + this.amountUstx.toString().padStart(15, " ") + } ${"until".padStart(37)} ${this.stacker.unlockHeight.toString().padStart(17)}`, + ); + } + + 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-stx period ${this.period}`; + } +} diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts index 426d55f980..08d2988293 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts @@ -4,9 +4,9 @@ import { expect } from "vitest"; import { boolCV, Cl } from "@stacks/transactions"; /** - * The `DelegateStxCommand` delegates STX for stacking within PoX-4. This self-service - * operation allows the `tx-sender` (the `wallet` in this case) to delegate stacking - * participation to a `delegatee`. + * The `DelegateStxCommand` delegates STX for stacking within PoX-4. This operation + * allows the `tx-sender` (the `wallet` in this case) to delegate stacking participation + * to a `delegatee`. * * Constraints for running this command include: * - The Stacker cannot currently be a delegator in another delegation. @@ -16,7 +16,7 @@ export class DelegateStxCommand implements PoxCommand { readonly wallet: Wallet; readonly delegateTo: Wallet; readonly untilBurnHt: number; - readonly margin: number; + readonly amount: bigint; /** * Constructs a `DelegateStxCommand` to delegate uSTX for stacking. @@ -24,19 +24,19 @@ export class DelegateStxCommand implements PoxCommand { * @param wallet - Represents the Stacker's wallet. * @param delegateTo - Represents the Delegatee's STX address. * @param untilBurnHt - The burn block height until the delegation is valid. - * @param margin - Multiplier for minimum required uSTX to stack so that each - * Stacker locks a different amount of uSTX across test runs. + * @param amount - The maximum amount the `Stacker` delegates the `Delegatee` to + * stack on his behalf */ constructor( wallet: Wallet, delegateTo: Wallet, untilBurnHt: number, - margin: number, + amount: bigint, ) { this.wallet = wallet; this.delegateTo = delegateTo; this.untilBurnHt = untilBurnHt; - this.margin = margin; + this.amount = amount; } check(model: Readonly): boolean { @@ -50,16 +50,9 @@ export class DelegateStxCommand implements PoxCommand { run(model: Stub, real: Real): void { // The amount of uSTX delegated by the Stacker to the Delegatee. - // For our tests, we will use the minimum amount of uSTX to be stacked - // in the given reward cycle multiplied by the margin, which is a randomly - // generated number passed to the constructor of this class. Even if there - // are no constraints about the delegated amount, it will be checked in the - // future, when calling delegate-stack-stx. - const delegatedAmount = model.stackingMinimum * this.margin; - - // The amount of uSTX to be delegated. For this test, we will use the - // delegated amount calculated before. - const amountUstx = delegatedAmount; + // Even if there are no constraints about the delegated amount, + // it will be checked in the future, when calling delegate-stack-stx. + const amountUstx = Number(this.amount); // Act const delegateStx = real.network.callPublicFn( @@ -83,12 +76,15 @@ export class DelegateStxCommand implements PoxCommand { // Get the wallet from the model and update it with the new state. const wallet = model.wallets.get(this.wallet.stxAddress)!; + const delegatedWallet = model.wallets.get(this.delegateTo.stxAddress)!; // Update model so that we know this wallet has delegated. This is important // in order to prevent the test from delegating multiple times with the same // address. wallet.hasDelegated = true; wallet.delegatedTo = this.delegateTo.stxAddress; + wallet.delegatedMaxAmount = amountUstx; + delegatedWallet.hasPoolMembers.push(wallet.stxAddress); // 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. console.info( @@ -100,7 +96,7 @@ export class DelegateStxCommand implements PoxCommand { } ${"amount".padStart(12, " ")} ${ amountUstx .toString() - .padStart(13, " ") + .padStart(15, " ") } delegated to ${ this.delegateTo.label.padStart( 42, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts index e9968e7060..3f573f4d99 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts @@ -46,7 +46,7 @@ export class GetStackingMinimumCommand implements PoxCommand { `✓ ${this.wallet.label.padStart(8, " ")} ${ "get-stacking-minimum".padStart(34, " ") } ${"pox-4".padStart(12, " ")} ${ - stackingMinimum.value.toString().padStart(13, " ") + stackingMinimum.value.toString().padStart(15, " ") }`, ); } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts index 0a902f0366..58257cf529 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts @@ -39,7 +39,7 @@ export class GetStxAccountCommand implements PoxCommand { `✓ ${this.wallet.label.padStart(8, " ")} ${ "stx-account".padStart(34, " ") } ${"lock-amount".padStart(12, " ")} ${ - actual.amountLocked.toString().padStart(13, " ") + actual.amountLocked.toString().padStart(15, " ") } ${"unlocked-amount".padStart(12, " ")} ${ actual.amountUnlocked.toString().padStart(15, " ") } ${"unlocked-height".padStart(12, " ")} ${ diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index 68aa2f1992..c77fe9e206 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -159,7 +159,7 @@ export class StackStxCommand implements PoxCommand { `✓ ${this.wallet.label.padStart(8, " ")} ${ "stack-stx".padStart(34, " ") } ${"lock-amount".padStart(12, " ")} ${ - amountUstx.toString().padStart(13, " ") + amountUstx.toString().padStart(15, " ") }`, ); } From 70b6c44981a6a751747bf7e68ead16898f90941b Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Fri, 22 Mar 2024 16:32:29 +0100 Subject: [PATCH 010/129] refactor(pox-4-tests): Relocate cycle utility functions to PoxCommands - Removes `Cl` and `cvToValue` imports and cycle utility functions from `pox-4.stateful-prop.test.ts`, streamlining its focus on tests. - Adds these imports and functions to `pox_Commands.ts`, centralizing cycle-related logic within command utilities for better cohesion and reusability. This shift enhances modularity and clarity in handling reward cycle calculations across PoX-4 tests. --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 34 +------------------ .../tests/pox-4/pox_Commands.ts | 32 ++++++++++++++++- 2 files changed, 32 insertions(+), 34 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index d02101bb37..c18c11e6c9 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -1,5 +1,5 @@ import { describe, it } from "vitest"; -import { initSimnet, Simnet } from "@hirosystems/clarinet-sdk"; +import { initSimnet } from "@hirosystems/clarinet-sdk"; import { Real, Stub, StxAddress, Wallet } from "./pox_CommandModel.ts"; import { @@ -8,9 +8,7 @@ import { } from "@stacks/encryption"; import { StacksDevnet } from "@stacks/network"; import { - Cl, createStacksPrivateKey, - cvToValue, getAddressFromPrivateKey, TransactionVersion, } from "@stacks/transactions"; @@ -19,36 +17,6 @@ import { StackingClient } from "@stacks/stacking"; import fc from "fast-check"; import { PoxCommands } from "./pox_Commands.ts"; -export const currentCycle = (network: Simnet) => - Number(cvToValue( - network.callReadOnlyFn( - "ST000000000000000000002AMW42H.pox-4", - "current-pox-reward-cycle", - [], - "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM", - ).result, - )); - -export const currentCycleFirstBlock = (network: Simnet) => - Number(cvToValue( - network.callReadOnlyFn( - "ST000000000000000000002AMW42H.pox-4", - "reward-cycle-to-burn-height", - [Cl.uint(currentCycle(network))], - "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM", - ).result, - )); - -export const nextCycleFirstBlock = (network: Simnet) => - Number(cvToValue( - network.callReadOnlyFn( - "ST000000000000000000002AMW42H.pox-4", - "reward-cycle-to-burn-height", - [Cl.uint(currentCycle(network) + 1)], - "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM", - ).result, - )); - describe("PoX-4 invariant tests", () => { it("statefully does solo stacking with a signature", async () => { // SUT stands for "System Under Test". diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index bea8907412..88fbea9a6b 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -6,7 +6,7 @@ import { StackStxCommand } from "./pox_StackStxCommand"; import { DelegateStxCommand } from "./pox_DelegateStxCommand"; import { DelegateStackStxCommand } from "./pox_DelegateStackStxCommand"; import { Simnet } from "@hirosystems/clarinet-sdk"; -import { currentCycleFirstBlock, nextCycleFirstBlock } from "./pox-4.stateful-prop.test"; +import { Cl, cvToValue } from "@stacks/transactions"; export function PoxCommands( wallets: Map, network: Simnet, @@ -111,3 +111,33 @@ export function PoxCommands( // More on cmds: https://github.com/dubzzz/fast-check/discussions/3026 return fc.commands(cmds, { size: "large" }); } + +const currentCycle = (network: Simnet) => + Number(cvToValue( + network.callReadOnlyFn( + "ST000000000000000000002AMW42H.pox-4", + "current-pox-reward-cycle", + [], + "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM", + ).result, + )); + +const currentCycleFirstBlock = (network: Simnet) => + Number(cvToValue( + network.callReadOnlyFn( + "ST000000000000000000002AMW42H.pox-4", + "reward-cycle-to-burn-height", + [Cl.uint(currentCycle(network))], + "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM", + ).result, + )); + +const nextCycleFirstBlock = (network: Simnet) => + Number(cvToValue( + network.callReadOnlyFn( + "ST000000000000000000002AMW42H.pox-4", + "reward-cycle-to-burn-height", + [Cl.uint(currentCycle(network) + 1)], + "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM", + ).result, + )); From 48490e6b94441bf6060cb31ef4b536b44d1ca0ea Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Fri, 22 Mar 2024 23:04:13 +0200 Subject: [PATCH 011/129] test(pox-4-tests): Add RevokeDelegateStxCommand --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 1 + .../tests/pox-4/pox_CommandModel.ts | 1 + .../tests/pox-4/pox_Commands.ts | 19 ++++ .../tests/pox-4/pox_DelegateStxCommand.ts | 1 + .../pox-4/pox_RevokeDelegateStxCommand.ts | 96 +++++++++++++++++++ 5 files changed, 118 insertions(+) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index c18c11e6c9..805ea2f53a 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -67,6 +67,7 @@ describe("PoX-4 invariant tests", () => { hasPoolMembers: [], delegatedTo: "", delegatedMaxAmount: 0, + delegatedUntilBurnHt: 0, amountLocked: 0, amountUnlocked: initialUstxBalance, unlockHeight: 0, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index f88d64ccd4..138027d5d5 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -28,6 +28,7 @@ export type Wallet = { hasPoolMembers: StxAddress[]; delegatedTo: StxAddress; delegatedMaxAmount: number; + delegatedUntilBurnHt: number; amountLocked: number; amountUnlocked: number; unlockHeight: number; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 88fbea9a6b..92d2b87ae5 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -7,6 +7,7 @@ import { DelegateStxCommand } from "./pox_DelegateStxCommand"; import { DelegateStackStxCommand } from "./pox_DelegateStackStxCommand"; import { Simnet } from "@hirosystems/clarinet-sdk"; import { Cl, cvToValue } from "@stacks/transactions"; +import { RevokeDelegateStxCommand } from "./pox_RevokeDelegateStxCommand"; export function PoxCommands( wallets: Map, network: Simnet, @@ -66,6 +67,24 @@ export function PoxCommands( r.amount, ) ), + // RevokeDelegateStxCommand + fc.record({ + wallet: fc.constantFrom(...wallets.values()), + delegateTo: fc.constantFrom(...wallets.values()), + untilBurnHt: fc.integer({ min: 1 }), + amount: fc.bigInt({ min:0n, max: 100_000_000_000_000n }), + }).map(( + r: { + wallet: Wallet; + delegateTo: Wallet; + untilBurnHt: number; + amount: bigint; + }, + ) => + new RevokeDelegateStxCommand( + r.wallet + ) + ), // DelegateStackStxCommand fc.record({ operator: fc.constantFrom(...wallets.values()), diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts index 08d2988293..28fd596643 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts @@ -83,6 +83,7 @@ export class DelegateStxCommand implements PoxCommand { wallet.hasDelegated = true; wallet.delegatedTo = this.delegateTo.stxAddress; wallet.delegatedMaxAmount = amountUstx; + wallet.delegatedUntilBurnHt = this.untilBurnHt delegatedWallet.hasPoolMembers.push(wallet.stxAddress); // Log to console for debugging purposes. This is not necessary for the diff --git a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts new file mode 100644 index 0000000000..5882402e7e --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts @@ -0,0 +1,96 @@ +import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { poxAddressToTuple } from "@stacks/stacking"; +import { expect } from "vitest"; +import { Cl, someCV, tupleCV } from "@stacks/transactions"; + +/** + * The `RevokeDelegateStxCommand` revokes the delegation for stacking within PoX-4. + * + * Constraints for running this command include: + * - The `Stacker` has to currently be delegating. + */ +export class RevokeDelegateStxCommand implements PoxCommand { + readonly wallet: Wallet; + + /** + * Constructs a RevokeDelegateStxCommand to revoke delegate uSTX for stacking. + * + * @param wallet - Represents the Stacker's wallet. + */ + constructor(wallet: Wallet) { + this.wallet = wallet; + } + + check(model: Readonly): boolean { + // Constraints for running this command include: + // - The Stacker has to currently be delegating. + return ( + model.stackingMinimum > 0 && + model.wallets.get(this.wallet.stxAddress)!.hasDelegated === true + ); + } + + run(model: Stub, real: Real): void { + // Get the Operator's wallet + const operatorWallet = model.wallets.get(this.wallet.delegatedTo)!; + + // Act + const revokeDelegateStx = real.network.callPublicFn( + "ST000000000000000000002AMW42H.pox-4", + "revoke-delegate-stx", + [], + this.wallet.stxAddress, + ); + + // Assert + expect(revokeDelegateStx.result).toBeOk( + someCV( + tupleCV({ + "amount-ustx": Cl.uint(this.wallet.delegatedMaxAmount), + "delegated-to": Cl.principal( + operatorWallet.stxAddress || "", + ), + "pox-addr": Cl.some( + poxAddressToTuple(operatorWallet.btcAddress || ""), + ), + "until-burn-ht": Cl.some(Cl.uint(this.wallet.delegatedUntilBurnHt)), + }), + ), + ); + + // Get the Stacker's wallet from the model and update the two wallets involved with the new state. + const wallet = model.wallets.get(this.wallet.stxAddress)!; + // Update model so that we know this wallet is not delegating anymore. + // This is important in order to prevent the test from revoking the delegation + // multiple times with the same address. + wallet.hasDelegated = false; + wallet.delegatedTo = ""; + wallet.delegatedUntilBurnHt = 0; + wallet.delegatedMaxAmount = 0; + + // Remove the Stacker from the Pool Operator's pool members list + let walletIndexInDelegatorsList = operatorWallet.hasPoolMembers.indexOf( + wallet.stxAddress, + ); + expect(walletIndexInDelegatorsList).toBeGreaterThan(-1); + operatorWallet.hasPoolMembers.splice(walletIndexInDelegatorsList, 1); + + // 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. + console.info( + `✓ ${ + this.wallet.label.padStart( + 8, + " ", + ) + } ${"revoke-delegate-stx".padStart(34, " ")}`, + ); + } + + 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.wallet.stxAddress} revoke-delegate-stx`; + } +} From 48cdebf37008f2f0f79d248fa5f88a368c3e6676 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Mon, 25 Mar 2024 15:46:26 +0200 Subject: [PATCH 012/129] test(pox-4-tests): Add AllowContractCallerCommand --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 2 + .../pox-4/pox_AllowContractCallerCommand.ts | 97 +++++++++++++++++++ .../tests/pox-4/pox_CommandModel.ts | 2 + .../tests/pox-4/pox_Commands.ts | 19 ++++ 4 files changed, 120 insertions(+) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index 805ea2f53a..4331f434a2 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -71,6 +71,8 @@ describe("PoX-4 invariant tests", () => { amountLocked: 0, amountUnlocked: initialUstxBalance, unlockHeight: 0, + allowedContractCaller: '', + callerAllowedBy: [] }; }); diff --git a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts new file mode 100644 index 0000000000..48dc8a6eb1 --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts @@ -0,0 +1,97 @@ +import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { expect } from "vitest"; +import { boolCV, Cl } from "@stacks/transactions"; + +/** + * The `AllowContractCallerComand` gives a `contract-caller` authorization to call stacking methods. + * Normally, stacking methods may only be invoked by direct transactions (i.e., the tx-sender + * issues a direct contract-call to the stacking methods). + * By issuing an allowance, the tx-sender may call stacking methods through the allowed contract. + * + * There are no constraints for running this command. + */ +export class AllowContractCallerCommand implements PoxCommand { + readonly wallet: Wallet; + readonly allowanceTo: Wallet; + readonly allowUntilBurnHt: number | undefined; + + /** + * Constructs an `AllowContractCallerComand` that authorizes a `contract-caller` to call + * stacking methods. + * + * @param wallet - Represents the Stacker's wallet. + * @param allowanceTo - Represents the authorized `contract-caller` (i.e. a stacking pool) + * @param alllowUntilBurnHt - The burn block height until the authorization is valid. + */ + + constructor( + wallet: Wallet, + allowanceTo: Wallet, + allowUntilBurnHt: number | undefined, + ) { + this.wallet = wallet; + this.allowanceTo = allowanceTo; + this.allowUntilBurnHt = allowUntilBurnHt; + } + + check(): boolean { + // There are no constraints for running this command. + return true; + } + + run(model: Stub, real: Real): void { + // Arrange + const untilBurnHtOptionalCv = this.allowUntilBurnHt === undefined + ? Cl.none() + : Cl.some(Cl.uint(this.allowUntilBurnHt)); + + // Act + const allowContractCaller = real.network.callPublicFn( + "ST000000000000000000002AMW42H.pox-4", + "allow-contract-caller", + [ + // (caller principal) + Cl.principal(this.allowanceTo.stxAddress), + // (until-burn-ht (optional uint)) + untilBurnHtOptionalCv, + ], + this.wallet.stxAddress, + ); + + // Assert + expect(allowContractCaller.result).toBeOk(boolCV(true)); + + // Get the wallets involved from the model and update it with the new state. + const wallet = model.wallets.get(this.wallet.stxAddress)!; + const callerToAllow = model.wallets.get(this.allowanceTo.stxAddress)!; + // Update model so that we know this wallet has authorized a contract-caller. + + wallet.allowedContractCaller = this.allowanceTo.stxAddress; + callerToAllow.callerAllowedBy.push(wallet.stxAddress); + + // 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. + console.info( + `✓ ${ + this.wallet.label.padStart( + 8, + " ", + ) + } ${ + "allow-contract-caller".padStart( + 34, + " ", + ) + } ${this.allowanceTo.label.padStart(12, " ")} ${"until".padStart(53)} ${ + (this.allowUntilBurnHt || "none").toString().padStart(17) + }`, + ); + } + + 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.wallet.stxAddress} allow-contract-caller ${this.allowanceTo.stxAddress} until burn ht ${this.allowUntilBurnHt}`; + } +} diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 138027d5d5..ad5b3dd2fa 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -32,6 +32,8 @@ export type Wallet = { amountLocked: number; amountUnlocked: number; unlockHeight: number; + allowedContractCaller: StxAddress; + callerAllowedBy: StxAddress[]; }; export type PoxCommand = fc.Command; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 92d2b87ae5..85a6777d3a 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -8,6 +8,7 @@ import { DelegateStackStxCommand } from "./pox_DelegateStackStxCommand"; import { Simnet } from "@hirosystems/clarinet-sdk"; import { Cl, cvToValue } from "@stacks/transactions"; import { RevokeDelegateStxCommand } from "./pox_RevokeDelegateStxCommand"; +import { AllowContractCallerCommand } from "./pox_AllowContractCallerCommand"; export function PoxCommands( wallets: Map, network: Simnet, @@ -112,6 +113,24 @@ export function PoxCommands( r.amount ) ), + // AllowContractCallerCommand + fc.record({ + wallet: fc.constantFrom(...wallets.values()), + allowanceTo: fc.constantFrom(...wallets.values()), + alllowUntilBurnHt: fc.option(fc.integer({ min: 1 }), {nil: undefined}), + }) + .map( + (r: { + wallet: Wallet; + allowanceTo: Wallet; + alllowUntilBurnHt: number | undefined; + }) => + new AllowContractCallerCommand( + r.wallet, + r.allowanceTo, + r.alllowUntilBurnHt, + ), + ), // GetStxAccountCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), From da4d6583ef244ba4f1e8673be0b5bf54e250305d Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Mon, 25 Mar 2024 15:49:34 +0200 Subject: [PATCH 013/129] refactor(pox-4-tests): Remove unused generators from RevokeDelegateStxCommand --- contrib/core-contract-tests/tests/pox-4/pox_Commands.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 85a6777d3a..062afd2e59 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -71,15 +71,9 @@ export function PoxCommands( // RevokeDelegateStxCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), - delegateTo: fc.constantFrom(...wallets.values()), - untilBurnHt: fc.integer({ min: 1 }), - amount: fc.bigInt({ min:0n, max: 100_000_000_000_000n }), }).map(( r: { wallet: Wallet; - delegateTo: Wallet; - untilBurnHt: number; - amount: bigint; }, ) => new RevokeDelegateStxCommand( From fe81e9d46bd8bdcc6818e78da8bcff5c5699d287 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Mon, 25 Mar 2024 17:31:58 +0200 Subject: [PATCH 014/129] wip(pox-4-tests): Add check for DelegateStackStx period --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 1 + .../tests/pox-4/pox_CommandModel.ts | 1 + .../tests/pox-4/pox_Commands.ts | 2 +- .../pox-4/pox_DelegateStackStxCommand.ts | 24 ++++++++++++------- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index 4331f434a2..bd01ccce7c 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -28,6 +28,7 @@ describe("PoX-4 invariant tests", () => { const model: Stub = { stackingMinimum: 0, wallets: new Map(), + network: sut.network }; const wallets = [ diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index ad5b3dd2fa..73ed4f9588 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -9,6 +9,7 @@ export type StxAddress = string; export type Stub = { stackingMinimum: number; wallets: Map; + network: Simnet; }; export type Real = { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 062afd2e59..a6de622eaf 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -154,7 +154,7 @@ const currentCycle = (network: Simnet) => ).result, )); -const currentCycleFirstBlock = (network: Simnet) => +export const currentCycleFirstBlock = (network: Simnet) => Number(cvToValue( network.callReadOnlyFn( "ST000000000000000000002AMW42H.pox-4", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index 4fb9ed09a4..4d6aafd095 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -2,6 +2,7 @@ import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; import { poxAddressToTuple } from "@stacks/stacking"; import { assert, expect } from "vitest"; import { Cl, ClarityType, isClarityType } from "@stacks/transactions"; +import { currentCycleFirstBlock } from "./pox_Commands.ts"; /** * The `DelegateStackStxCommand` locks STX for stacking within PoX-4 on behalf of a delegator. @@ -16,10 +17,11 @@ import { Cl, ClarityType, isClarityType } from "@stacks/transactions"; * - The stacked STX 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 + * Stacker's balance. * - The stacked uSTX amount should be greater than or equal to the - * minimum threshold of uSTX + * minimum threshold of uSTX. * - The Operator has to currently be delegated by the Stacker. + * - The Period has to fit the last delegation burn block height. */ export class DelegateStackStxCommand implements PoxCommand { readonly operator: Wallet; @@ -58,18 +60,21 @@ export class DelegateStackStxCommand implements PoxCommand { // - A minimum threshold of uSTX must be met, determined by the // `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 + // operation. + // - The Stacker has to currently be delegating to the Operator. // - The stacked uSTX amount should be less than or equal to the - // delegated amount + // delegated amount. // - The stacked uSTX amount should be less than or equal to the - // Stacker's balance + // Stacker's balance. // - The stacked uSTX amount should be greater than or equal to the - // minimum threshold of uSTX - // - The Operator has to currently be delegated by the Stacker + // minimum threshold of uSTX. + // - The Operator has to currently be delegated by the Stacker. + // - The Period has to fit the last delegation burn block height. const operatorWallet = model.wallets.get(this.operator.stxAddress)!; const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; + const unlockBurnHt = currentCycleFirstBlock(model.network) + 1050 * (this.period + 1) + return ( model.stackingMinimum > 0 && !stackerWallet.isStacking && @@ -77,7 +82,8 @@ export class DelegateStackStxCommand implements PoxCommand { stackerWallet.delegatedMaxAmount >= Number(this.amountUstx) && Number(this.amountUstx) <= stackerWallet.ustxBalance && Number(this.amountUstx) >= model.stackingMinimum && - operatorWallet.hasPoolMembers.includes(stackerWallet.stxAddress) + operatorWallet.hasPoolMembers.includes(stackerWallet.stxAddress) && + unlockBurnHt <= stackerWallet.delegatedUntilBurnHt ); } From 306c9d7e1eb00a0ad3f8cc9720f13b0dc5533fde Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Mon, 25 Mar 2024 18:57:40 +0100 Subject: [PATCH 015/129] refactor(pox-4-tests): Integrate Clarity value generation This change optimizes the generation of Clarity values for the allowUntilBurnHt property in the AllowContractCallerCommand tests. By directly creating Clarity optional values (none or some(uint)) within the fast-check generator, we remove the need for conditional post-processing. This approach simplifies the test setup and aligns more closely with the intended usage patterns of the Clarity and fast-check libraries. --- .../pox-4/pox_AllowContractCallerCommand.ts | 24 ++++++++++--------- .../tests/pox-4/pox_Commands.ts | 9 ++++--- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts index 48dc8a6eb1..d8988e1309 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts @@ -1,6 +1,6 @@ import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; import { expect } from "vitest"; -import { boolCV, Cl } from "@stacks/transactions"; +import { boolCV, Cl, ClarityType, OptionalCV, UIntCV } from "@stacks/transactions"; /** * The `AllowContractCallerComand` gives a `contract-caller` authorization to call stacking methods. @@ -13,7 +13,7 @@ import { boolCV, Cl } from "@stacks/transactions"; export class AllowContractCallerCommand implements PoxCommand { readonly wallet: Wallet; readonly allowanceTo: Wallet; - readonly allowUntilBurnHt: number | undefined; + readonly allowUntilBurnHt: OptionalCV; /** * Constructs an `AllowContractCallerComand` that authorizes a `contract-caller` to call @@ -27,7 +27,7 @@ export class AllowContractCallerCommand implements PoxCommand { constructor( wallet: Wallet, allowanceTo: Wallet, - allowUntilBurnHt: number | undefined, + allowUntilBurnHt: OptionalCV, ) { this.wallet = wallet; this.allowanceTo = allowanceTo; @@ -40,11 +40,6 @@ export class AllowContractCallerCommand implements PoxCommand { } run(model: Stub, real: Real): void { - // Arrange - const untilBurnHtOptionalCv = this.allowUntilBurnHt === undefined - ? Cl.none() - : Cl.some(Cl.uint(this.allowUntilBurnHt)); - // Act const allowContractCaller = real.network.callPublicFn( "ST000000000000000000002AMW42H.pox-4", @@ -53,7 +48,7 @@ export class AllowContractCallerCommand implements PoxCommand { // (caller principal) Cl.principal(this.allowanceTo.stxAddress), // (until-burn-ht (optional uint)) - untilBurnHtOptionalCv, + this.allowUntilBurnHt, ], this.wallet.stxAddress, ); @@ -83,7 +78,7 @@ export class AllowContractCallerCommand implements PoxCommand { " ", ) } ${this.allowanceTo.label.padStart(12, " ")} ${"until".padStart(53)} ${ - (this.allowUntilBurnHt || "none").toString().padStart(17) + optionalCVToString(this.allowUntilBurnHt).padStart(17) }`, ); } @@ -92,6 +87,13 @@ export class AllowContractCallerCommand implements PoxCommand { // 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.wallet.stxAddress} allow-contract-caller ${this.allowanceTo.stxAddress} until burn ht ${this.allowUntilBurnHt}`; + return `${this.wallet.stxAddress} allow-contract-caller ${this.allowanceTo.stxAddress} until burn ht ${ + optionalCVToString(this.allowUntilBurnHt) + }`; } } + +const optionalCVToString = (optional: OptionalCV): string => + optional.type === ClarityType.OptionalSome + ? (optional.value as UIntCV).value.toString() + : "none"; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index a6de622eaf..4ab67a63f9 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -6,7 +6,7 @@ import { StackStxCommand } from "./pox_StackStxCommand"; import { DelegateStxCommand } from "./pox_DelegateStxCommand"; import { DelegateStackStxCommand } from "./pox_DelegateStackStxCommand"; import { Simnet } from "@hirosystems/clarinet-sdk"; -import { Cl, cvToValue } from "@stacks/transactions"; +import { Cl, cvToValue, OptionalCV, UIntCV } from "@stacks/transactions"; import { RevokeDelegateStxCommand } from "./pox_RevokeDelegateStxCommand"; import { AllowContractCallerCommand } from "./pox_AllowContractCallerCommand"; @@ -111,13 +111,16 @@ export function PoxCommands( fc.record({ wallet: fc.constantFrom(...wallets.values()), allowanceTo: fc.constantFrom(...wallets.values()), - alllowUntilBurnHt: fc.option(fc.integer({ min: 1 }), {nil: undefined}), + alllowUntilBurnHt: fc.oneof( + fc.constant(Cl.none()), + fc.integer({ min: 1 }).map((value) => Cl.some(Cl.uint(value))), + ), }) .map( (r: { wallet: Wallet; allowanceTo: Wallet; - alllowUntilBurnHt: number | undefined; + alllowUntilBurnHt: OptionalCV; }) => new AllowContractCallerCommand( r.wallet, From d318addb033d92b0ae95a4a13134d0ef0d7dfdc5 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Mon, 25 Mar 2024 23:41:11 +0100 Subject: [PATCH 016/129] refactor(pox-4-tests): Dynamic `unlockBurnHt` and cleaner state - Moved `network` from `Stub` (Model) to `Real`, streamlining state management. - `unlockBurnHt` now dynamically calculated, passed via constructor, ensuring alignment with generated `period`. - Utilized `fast-check`'s `chain` for dynamic `unlockBurnHt` calculation, improving test accuracy. - Enforces discipline in constructor use and `check` method validation, highlighting the importance of explicit state and parameter handling for reliable testing. --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 1 - .../tests/pox-4/pox_CommandModel.ts | 1 - .../tests/pox-4/pox_Commands.ts | 22 ++++++++++--------- .../pox-4/pox_DelegateStackStxCommand.ts | 8 ++++--- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index bd01ccce7c..4331f434a2 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -28,7 +28,6 @@ describe("PoX-4 invariant tests", () => { const model: Stub = { stackingMinimum: 0, wallets: new Map(), - network: sut.network }; const wallets = [ diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 73ed4f9588..ad5b3dd2fa 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -9,7 +9,6 @@ export type StxAddress = string; export type Stub = { stackingMinimum: number; wallets: Map; - network: Simnet; }; export type Real = { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 4ab67a63f9..859316451c 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -90,21 +90,23 @@ export function PoxCommands( }), period: fc.integer({ min: 1, max: 12 }), amount: fc.bigInt({ min:0n, max: 100_000_000_000_000n }), - }).map(( - r: { - operator: Wallet; - stacker: Wallet; - startBurnHt: number; - period: number; - amount: bigint; - }, - ) => + }).chain((r) => + fc.record({ + unlockBurnHt: fc.constant( + currentCycleFirstBlock(network) + 1050 * (r.period + 1), + ), + }).map((unlockBurnHtRecord) => ({ + ...r, + ...unlockBurnHtRecord, + })) + ).map((r) => new DelegateStackStxCommand( r.operator, r.stacker, r.startBurnHt, r.period, - r.amount + r.amount, + r.unlockBurnHt, ) ), // AllowContractCallerCommand diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index 4d6aafd095..f23b4817a5 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -2,7 +2,6 @@ import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; import { poxAddressToTuple } from "@stacks/stacking"; import { assert, expect } from "vitest"; import { Cl, ClarityType, isClarityType } from "@stacks/transactions"; -import { currentCycleFirstBlock } from "./pox_Commands.ts"; /** * The `DelegateStackStxCommand` locks STX for stacking within PoX-4 on behalf of a delegator. @@ -29,6 +28,7 @@ export class DelegateStackStxCommand implements PoxCommand { readonly startBurnHt: number; readonly period: number; readonly amountUstx: bigint; + readonly unlockBurnHt: number; /** * Constructs a `DelegateStackStxCommand` to lock uSTX as a Pool Operator @@ -40,6 +40,7 @@ export class DelegateStackStxCommand implements PoxCommand { * @param period - Number of reward cycles to lock uSTX. * @param amountUstx - The uSTX amount stacked by the Operator on behalf * of the Stacker + * @param unlockBurnHt - The burn height at which the uSTX is unlocked. */ constructor( operator: Wallet, @@ -47,12 +48,14 @@ export class DelegateStackStxCommand implements PoxCommand { startBurnHt: number, period: number, amountUstx: bigint, + unlockBurnHt: number, ) { this.operator = operator; this.stacker = stacker; this.startBurnHt = startBurnHt; this.period = period; this.amountUstx = amountUstx; + this.unlockBurnHt = unlockBurnHt; } check(model: Readonly): boolean { @@ -73,7 +76,6 @@ export class DelegateStackStxCommand implements PoxCommand { const operatorWallet = model.wallets.get(this.operator.stxAddress)!; const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; - const unlockBurnHt = currentCycleFirstBlock(model.network) + 1050 * (this.period + 1) return ( model.stackingMinimum > 0 && @@ -83,7 +85,7 @@ export class DelegateStackStxCommand implements PoxCommand { Number(this.amountUstx) <= stackerWallet.ustxBalance && Number(this.amountUstx) >= model.stackingMinimum && operatorWallet.hasPoolMembers.includes(stackerWallet.stxAddress) && - unlockBurnHt <= stackerWallet.delegatedUntilBurnHt + this.unlockBurnHt <= stackerWallet.delegatedUntilBurnHt ); } From ddc7c4dab8846c7fa3f811f49ad508d84f75094d Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Tue, 26 Mar 2024 23:36:14 +0100 Subject: [PATCH 017/129] feat(dependencies): Update stacks.js packages for PoX-4 stacking client --- contrib/core-contract-tests/package-lock.json | 50 ++++++++++--------- contrib/core-contract-tests/package.json | 3 +- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/contrib/core-contract-tests/package-lock.json b/contrib/core-contract-tests/package-lock.json index 50ded82d38..5fd11568ce 100644 --- a/contrib/core-contract-tests/package-lock.json +++ b/contrib/core-contract-tests/package-lock.json @@ -11,7 +11,8 @@ "dependencies": { "@hirosystems/clarinet-sdk": "^2.4.1", "@stacks/clarunit": "0.0.1", - "@stacks/transactions": "^6.12.0", + "@stacks/stacking": "^6.13.0", + "@stacks/transactions": "^6.13.0", "chokidar-cli": "^3.0.0", "fast-check": "^3.15.1", "typescript": "^5.4.2", @@ -1219,23 +1220,23 @@ } }, "node_modules/@stacks/common": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/@stacks/common/-/common-6.10.0.tgz", - "integrity": "sha512-6x5Z7AKd9/kj3+DYE9xIDIkFLHihBH614i2wqrZIjN02WxVo063hWSjIlUxlx8P4gl6olVzlOy5LzhLJD9OP0A==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@stacks/common/-/common-6.13.0.tgz", + "integrity": "sha512-wwzyihjaSdmL6NxKvDeayy3dqM0L0Q2sawmdNtzJDi0FnXuJGm5PeapJj7bEfcI9XwI7Bw5jZoC6mCn9nc5YIw==", "dependencies": { "@types/bn.js": "^5.1.0", "@types/node": "^18.0.4" } }, "node_modules/@stacks/encryption": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@stacks/encryption/-/encryption-6.12.0.tgz", - "integrity": "sha512-CubE51pHrcxx3yA+xapevPgA9UDleIoEaUZ06/9uD91B42yvTg37HyS8t06rzukU9q+X7Cv2I/+vbuf4nJIo8g==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@stacks/encryption/-/encryption-6.13.0.tgz", + "integrity": "sha512-CsacBxY1XBVXBuJ5erJPjB5FmQ8KGJ/ft02/pIM6WrJ31ZcBdkn2BPV1AsPSD5qsIkiMdHAe14WKIwm8M2SWtQ==", "dependencies": { "@noble/hashes": "1.1.5", "@noble/secp256k1": "1.7.1", "@scure/bip39": "1.1.0", - "@stacks/common": "^6.10.0", + "@stacks/common": "^6.13.0", "@types/node": "^18.0.4", "base64-js": "^1.5.1", "bs58": "^5.0.0", @@ -1244,25 +1245,26 @@ } }, "node_modules/@stacks/network": { - "version": "6.11.3", - "resolved": "https://registry.npmjs.org/@stacks/network/-/network-6.11.3.tgz", - "integrity": "sha512-c4ClCU/QUwuu8NbHtDKPJNa0M5YxauLN3vYaR0+S4awbhVIKFQSxirm9Q9ckV1WBh7FtD6u2S0x+tDQGAODjNg==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@stacks/network/-/network-6.13.0.tgz", + "integrity": "sha512-Ss/Da4BNyPBBj1OieM981fJ7SkevKqLPkzoI1+Yo7cYR2df+0FipIN++Z4RfpJpc8ne60vgcx7nJZXQsiGhKBQ==", "dependencies": { - "@stacks/common": "^6.10.0", + "@stacks/common": "^6.13.0", "cross-fetch": "^3.1.5" } }, "node_modules/@stacks/stacking": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@stacks/stacking/-/stacking-6.12.0.tgz", - "integrity": "sha512-XBxwbaCGRPnjpjspb3CBXrlZl6xR+gghLMz9PQNPdpuIbBDFa0SGeHgqjtpVU+2DVL4UyBx8PVsAWtlssyVGng==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@stacks/stacking/-/stacking-6.13.0.tgz", + "integrity": "sha512-ivzFZkVpqzneJ71T1eZTW8Rr5oVYrs4HkwZqGHxDEySb1I6p96hojH5gEguj9g7szQiyeYLj1dreCvhLh6ET6A==", "dependencies": { + "@noble/hashes": "1.1.5", "@scure/base": "1.1.1", - "@stacks/common": "^6.10.0", - "@stacks/encryption": "^6.12.0", - "@stacks/network": "^6.11.3", + "@stacks/common": "^6.13.0", + "@stacks/encryption": "^6.13.0", + "@stacks/network": "^6.13.0", "@stacks/stacks-blockchain-api-types": "^0.61.0", - "@stacks/transactions": "^6.12.0", + "@stacks/transactions": "^6.13.0", "bs58": "^5.0.0" } }, @@ -1283,14 +1285,14 @@ "integrity": "sha512-yPOfTUboo5eA9BZL/hqMcM71GstrFs9YWzOrJFPeP4cOO1wgYvAcckgBRbgiE3NqeX0A7SLZLDAXLZbATuRq9w==" }, "node_modules/@stacks/transactions": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@stacks/transactions/-/transactions-6.12.0.tgz", - "integrity": "sha512-gRP3SfTaAIoTdjMvOiLrMZb/senqB8JQlT5Y4C3/CiHhiprYwTx7TbOCSa7WsNOU99H4aNfHvatmymuggXQVkA==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@stacks/transactions/-/transactions-6.13.0.tgz", + "integrity": "sha512-xrx09qsXL/tWCkvAArzsFQqtZKDXyedjdVB9uX8xw+cQCi3xZ7r5MHMKzvEsTgJz3EO+MkQBXcvI1uzfuoqhcA==", "dependencies": { "@noble/hashes": "1.1.5", "@noble/secp256k1": "1.7.1", - "@stacks/common": "^6.10.0", - "@stacks/network": "^6.11.3", + "@stacks/common": "^6.13.0", + "@stacks/network": "^6.13.0", "c32check": "^2.0.0", "lodash.clonedeep": "^4.5.0" } diff --git a/contrib/core-contract-tests/package.json b/contrib/core-contract-tests/package.json index 7ba3ba62e2..0d80a4e570 100644 --- a/contrib/core-contract-tests/package.json +++ b/contrib/core-contract-tests/package.json @@ -13,7 +13,8 @@ "dependencies": { "@hirosystems/clarinet-sdk": "^2.4.1", "@stacks/clarunit": "0.0.1", - "@stacks/transactions": "^6.12.0", + "@stacks/stacking": "^6.13.0", + "@stacks/transactions": "^6.13.0", "chokidar-cli": "^3.0.0", "fast-check": "^3.15.1", "typescript": "^5.4.2", From a6c965700193fee533282a5007f8322f9f2910f7 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Wed, 27 Mar 2024 00:53:54 +0100 Subject: [PATCH 018/129] feat(pox-4-tests): Add `logCommand` for structured output using `ololog` Replace direct `console.log` and manual padding with `logCommand`, enhancing readability and simplifying logging. --- contrib/core-contract-tests/package-lock.json | 85 +++++++++++++++++++ contrib/core-contract-tests/package.json | 1 + .../pox-4/pox_AllowContractCallerCommand.ts | 18 +--- .../tests/pox-4/pox_CommandModel.ts | 13 +++ .../pox-4/pox_DelegateStackStxCommand.ts | 10 +-- .../tests/pox-4/pox_DelegateStxCommand.ts | 20 +---- .../pox-4/pox_GetStackingMinimumCommand.ts | 10 +-- .../tests/pox-4/pox_GetStxAccountCommand.ts | 14 +-- .../pox-4/pox_RevokeDelegateStxCommand.ts | 11 +-- .../tests/pox-4/pox_StackStxCommand.ts | 10 +-- 10 files changed, 113 insertions(+), 79 deletions(-) diff --git a/contrib/core-contract-tests/package-lock.json b/contrib/core-contract-tests/package-lock.json index 5fd11568ce..f636a0d085 100644 --- a/contrib/core-contract-tests/package-lock.json +++ b/contrib/core-contract-tests/package-lock.json @@ -15,6 +15,7 @@ "@stacks/transactions": "^6.13.0", "chokidar-cli": "^3.0.0", "fast-check": "^3.15.1", + "ololog": "^1.1.175", "typescript": "^5.4.2", "vite": "^5.1.6", "vitest": "^1.3.1", @@ -1476,6 +1477,11 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/ansicolor": { + "version": "1.1.100", + "resolved": "https://registry.npmjs.org/ansicolor/-/ansicolor-1.1.100.tgz", + "integrity": "sha512-Jl0pxRfa9WaQVUX57AB8/V2my6FJxrOR1Pp2qqFbig20QB4HzUoQ48THTKAgHlUCJeQm/s2WoOPcoIDhyCL/kw==" + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -1493,6 +1499,14 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, + "node_modules/as-table": { + "version": "1.0.55", + "resolved": "https://registry.npmjs.org/as-table/-/as-table-1.0.55.tgz", + "integrity": "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==", + "dependencies": { + "printable-characters": "^1.0.42" + } + }, "node_modules/assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -1919,6 +1933,11 @@ "node": ">= 8" } }, + "node_modules/data-uri-to-buffer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-2.0.2.tgz", + "integrity": "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==" + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -2347,6 +2366,15 @@ "node": "*" } }, + "node_modules/get-source": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/get-source/-/get-source-2.0.12.tgz", + "integrity": "sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==", + "dependencies": { + "data-uri-to-buffer": "^2.0.0", + "source-map": "^0.6.1" + } + }, "node_modules/get-stream": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", @@ -2792,6 +2820,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ololog": { + "version": "1.1.175", + "resolved": "https://registry.npmjs.org/ololog/-/ololog-1.1.175.tgz", + "integrity": "sha512-DSPbsvZzLshFiPI1ul7iJDn6wI75goOLyrn8uRB92sPon5LS8J2KlAIkSoHXtRztb2idPjuzq3R1J58hN2qOEA==", + "dependencies": { + "ansicolor": "^1.1.84", + "pipez": "^1.1.12", + "printable-characters": "^1.0.42", + "stacktracey": "^2.1.6", + "string.bullet": "^1.0.12", + "string.ify": "^1.0.64" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -2939,6 +2980,11 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pipez": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/pipez/-/pipez-1.1.12.tgz", + "integrity": "sha512-VuJ+c44f3s/4cirqtBI3wa0LscCo1IG9sQH2DnClJWEMkGylE52mDjLLHR5QyLjij1EiGocMEIAJsmpyXczXJQ==" + }, "node_modules/pkg-types": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", @@ -3008,6 +3054,11 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/printable-characters": { + "version": "1.0.42", + "resolved": "https://registry.npmjs.org/printable-characters/-/printable-characters-1.0.42.tgz", + "integrity": "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==" + }, "node_modules/process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -3255,6 +3306,14 @@ "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", @@ -3268,6 +3327,15 @@ "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==" }, + "node_modules/stacktracey": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/stacktracey/-/stacktracey-2.1.8.tgz", + "integrity": "sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==", + "dependencies": { + "as-table": "^1.0.36", + "get-source": "^2.0.12" + } + }, "node_modules/std-env": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", @@ -3286,6 +3354,23 @@ "node": ">=8" } }, + "node_modules/string.bullet": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/string.bullet/-/string.bullet-1.0.12.tgz", + "integrity": "sha512-6+tQyad/ux52N+7wUcjmxeK5TfdeykBBLHQPk8MxUVrk9JwHzJnuxsJzjjpWAuz0x3EmnVGCg0ibMHqez1l/qQ==", + "dependencies": { + "printable-characters": "^1.0.26" + } + }, + "node_modules/string.ify": { + "version": "1.0.64", + "resolved": "https://registry.npmjs.org/string.ify/-/string.ify-1.0.64.tgz", + "integrity": "sha512-4Aa5yndnuOhE1GV2W3ht4rQ08XHq46JLXmSOv0jeUWEzqliBvm8lAXvt+66np+J9DkoCZikFzTzjXVLRR0F/Xw==", + "dependencies": { + "printable-characters": "^1.0.42", + "string.bullet": "^1.0.12" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", diff --git a/contrib/core-contract-tests/package.json b/contrib/core-contract-tests/package.json index 0d80a4e570..a6c8b23262 100644 --- a/contrib/core-contract-tests/package.json +++ b/contrib/core-contract-tests/package.json @@ -17,6 +17,7 @@ "@stacks/transactions": "^6.13.0", "chokidar-cli": "^3.0.0", "fast-check": "^3.15.1", + "ololog": "^1.1.175", "typescript": "^5.4.2", "vite": "^5.1.6", "vitest": "^1.3.1", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts index d8988e1309..64f4a32142 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts @@ -1,4 +1,4 @@ -import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; import { expect } from "vitest"; import { boolCV, Cl, ClarityType, OptionalCV, UIntCV } from "@stacks/transactions"; @@ -66,21 +66,7 @@ export class AllowContractCallerCommand 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. - console.info( - `✓ ${ - this.wallet.label.padStart( - 8, - " ", - ) - } ${ - "allow-contract-caller".padStart( - 34, - " ", - ) - } ${this.allowanceTo.label.padStart(12, " ")} ${"until".padStart(53)} ${ - optionalCVToString(this.allowUntilBurnHt).padStart(17) - }`, - ); + logCommand(`✓ ${this.wallet.label}`, "allow-contract-caller", this.allowanceTo.label, "until", optionalCVToString(this.allowUntilBurnHt)); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index ad5b3dd2fa..449ef3b672 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -1,4 +1,5 @@ import fc from "fast-check"; +import ololog from "ololog"; import { Simnet } from "@hirosystems/clarinet-sdk"; import { StacksPrivateKey } from "@stacks/transactions"; @@ -37,3 +38,15 @@ export type Wallet = { }; export type PoxCommand = fc.Command; + +export const logCommand = (...items: (string | undefined)[]) => { + // Ensure we only render up to the first 10 items for brevity. + const renderItems = items.slice(0, 10); + const columnWidth = 23; + // Pad each column to the same width. + const prettyPrint = renderItems.map((content) => + content ? content.padEnd(columnWidth) : "".padEnd(columnWidth) + ); + + ololog.configure({ locate: false })(prettyPrint.join("")); +}; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index f23b4817a5..ae4d61cc7b 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -1,4 +1,4 @@ -import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; import { poxAddressToTuple } from "@stacks/stacking"; import { assert, expect } from "vitest"; import { Cl, ClarityType, isClarityType } from "@stacks/transactions"; @@ -146,13 +146,7 @@ export class DelegateStackStxCommand 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. - console.info( - `✓ ${this.operator.label.padStart(8, " ")} Ӿ ${this.stacker.label.padStart(8, " ")} ${ - "delegate-stack-stx".padStart(23, " ") - } ${"lock-amount".padStart(12, " ")} ${ - this.amountUstx.toString().padStart(15, " ") - } ${"until".padStart(37)} ${this.stacker.unlockHeight.toString().padStart(17)}`, - ); + logCommand(`✓ ${this.operator.label} Ӿ ${this.stacker.label}`, "delegate-stack-stx", "lock-amount", this.amountUstx.toString(), "until", this.stacker.unlockHeight.toString()); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts index 28fd596643..bc638719fd 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts @@ -1,4 +1,4 @@ -import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; import { poxAddressToTuple } from "@stacks/stacking"; import { expect } from "vitest"; import { boolCV, Cl } from "@stacks/transactions"; @@ -88,23 +88,7 @@ export class DelegateStxCommand implements PoxCommand { delegatedWallet.hasPoolMembers.push(wallet.stxAddress); // 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. - console.info( - `✓ ${this.wallet.label.padStart(8, " ")} ${ - "delegate-stx".padStart( - 34, - " ", - ) - } ${"amount".padStart(12, " ")} ${ - amountUstx - .toString() - .padStart(15, " ") - } delegated to ${ - this.delegateTo.label.padStart( - 42, - " ", - ) - }`, - ); + logCommand(`✓ ${this.wallet.label}`, "delegate-stx", "amount", amountUstx.toString(), "delegated to", this.delegateTo.label); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts index 3f573f4d99..78b084f910 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts @@ -1,4 +1,4 @@ -import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; import { assert } from "vitest"; import { ClarityType, isClarityType } from "@stacks/transactions"; @@ -42,13 +42,7 @@ export class GetStackingMinimumCommand 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. - console.info( - `✓ ${this.wallet.label.padStart(8, " ")} ${ - "get-stacking-minimum".padStart(34, " ") - } ${"pox-4".padStart(12, " ")} ${ - stackingMinimum.value.toString().padStart(15, " ") - }`, - ); + logCommand(`✓ ${this.wallet.label}`, "get-stacking-minimum", "pox-4", stackingMinimum.value.toString()); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts index 58257cf529..b67079f404 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts @@ -1,4 +1,4 @@ -import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; import { expect } from "vitest"; import { Cl } from "@stacks/transactions"; @@ -35,17 +35,7 @@ export class GetStxAccountCommand 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. - console.info( - `✓ ${this.wallet.label.padStart(8, " ")} ${ - "stx-account".padStart(34, " ") - } ${"lock-amount".padStart(12, " ")} ${ - actual.amountLocked.toString().padStart(15, " ") - } ${"unlocked-amount".padStart(12, " ")} ${ - actual.amountUnlocked.toString().padStart(15, " ") - } ${"unlocked-height".padStart(12, " ")} ${ - actual.unlockHeight.toString().padStart(7, " ") - }`, - ); + logCommand(`✓ ${this.wallet.label}`, "stx-account", "lock-amount", actual.amountLocked.toString(), "unlocked-amount", actual.amountUnlocked.toString(), "unlocked-height", actual.unlockHeight.toString()); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts index 5882402e7e..c121146130 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts @@ -1,4 +1,4 @@ -import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; import { poxAddressToTuple } from "@stacks/stacking"; import { expect } from "vitest"; import { Cl, someCV, tupleCV } from "@stacks/transactions"; @@ -77,14 +77,7 @@ 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. - console.info( - `✓ ${ - this.wallet.label.padStart( - 8, - " ", - ) - } ${"revoke-delegate-stx".padStart(34, " ")}`, - ); + logCommand(`✓ ${this.wallet.label}`, "revoke-delegate-stx"); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index c77fe9e206..765441a68f 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -1,4 +1,4 @@ -import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; import { Pox4SignatureTopic, poxAddressToTuple } from "@stacks/stacking"; import { assert, expect } from "vitest"; import { Cl, ClarityType, isClarityType } from "@stacks/transactions"; @@ -155,13 +155,7 @@ export class StackStxCommand 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. - console.info( - `✓ ${this.wallet.label.padStart(8, " ")} ${ - "stack-stx".padStart(34, " ") - } ${"lock-amount".padStart(12, " ")} ${ - amountUstx.toString().padStart(15, " ") - }`, - ); + logCommand(`✓ ${this.wallet.label}`, "stack-stx", "lock-amount", amountUstx.toString()); } toString() { From 4704f7b059a51bbd234bad5f775ff2272ae609d9 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Wed, 27 Mar 2024 01:03:09 +0100 Subject: [PATCH 019/129] style(pox-4-tests): Run formatter on tests/pox-4/*.ts --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 49 ++++++++++++++----- .../pox-4/pox_AllowContractCallerCommand.ts | 27 ++++++++-- .../tests/pox-4/pox_Commands.ts | 9 ++-- .../pox-4/pox_DelegateStackStxCommand.ts | 19 +++++-- .../tests/pox-4/pox_DelegateStxCommand.ts | 25 +++++++--- .../pox-4/pox_GetStackingMinimumCommand.ts | 15 +++++- .../tests/pox-4/pox_GetStxAccountCommand.ts | 19 ++++++- .../pox-4/pox_RevokeDelegateStxCommand.ts | 8 ++- .../tests/pox-4/pox_StackStxCommand.ts | 15 +++++- 9 files changed, 150 insertions(+), 36 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index 4331f434a2..6c3df5fa0b 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -31,15 +31,42 @@ describe("PoX-4 invariant tests", () => { }; const wallets = [ - ["wallet_1", "7287ba251d44a4d3fd9276c88ce34c5c52a038955511cccaf77e61068649c17801"], - ["wallet_2", "530d9f61984c888536871c6573073bdfc0058896dc1adfe9a6a10dfacadc209101"], - ["wallet_3", "d655b2523bcd65e34889725c73064feb17ceb796831c0e111ba1a552b0f31b3901"], - ["wallet_4", "f9d7206a47f14d2870c163ebab4bf3e70d18f5d14ce1031f3902fbbc894fe4c701"], - ["wallet_5", "3eccc5dac8056590432db6a35d52b9896876a3d5cbdea53b72400bc9c2099fe801"], - ["wallet_6", "7036b29cb5e235e5fd9b09ae3e8eec4404e44906814d5d01cbca968a60ed4bfb01"], - ["wallet_7", "b463f0df6c05d2f156393eee73f8016c5372caa0e9e29a901bb7171d90dc4f1401"], - ["wallet_8", "6a1a754ba863d7bab14adbbc3f8ebb090af9e871ace621d3e5ab634e1422885e01"], - ["wallet_9", "de433bdfa14ec43aa1098d5be594c8ffb20a31485ff9de2923b2689471c401b801"], + [ + "wallet_1", + "7287ba251d44a4d3fd9276c88ce34c5c52a038955511cccaf77e61068649c17801", + ], + [ + "wallet_2", + "530d9f61984c888536871c6573073bdfc0058896dc1adfe9a6a10dfacadc209101", + ], + [ + "wallet_3", + "d655b2523bcd65e34889725c73064feb17ceb796831c0e111ba1a552b0f31b3901", + ], + [ + "wallet_4", + "f9d7206a47f14d2870c163ebab4bf3e70d18f5d14ce1031f3902fbbc894fe4c701", + ], + [ + "wallet_5", + "3eccc5dac8056590432db6a35d52b9896876a3d5cbdea53b72400bc9c2099fe801", + ], + [ + "wallet_6", + "7036b29cb5e235e5fd9b09ae3e8eec4404e44906814d5d01cbca968a60ed4bfb01", + ], + [ + "wallet_7", + "b463f0df6c05d2f156393eee73f8016c5372caa0e9e29a901bb7171d90dc4f1401", + ], + [ + "wallet_8", + "6a1a754ba863d7bab14adbbc3f8ebb090af9e871ace621d3e5ab634e1422885e01", + ], + [ + "wallet_9", + "de433bdfa14ec43aa1098d5be594c8ffb20a31485ff9de2923b2689471c401b801", + ], ].map((wallet) => { const label = wallet[0]; const prvKey = wallet[1]; @@ -71,8 +98,8 @@ describe("PoX-4 invariant tests", () => { amountLocked: 0, amountUnlocked: initialUstxBalance, unlockHeight: 0, - allowedContractCaller: '', - callerAllowedBy: [] + allowedContractCaller: "", + callerAllowedBy: [], }; }); diff --git a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts index 64f4a32142..591568a17c 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts @@ -1,6 +1,18 @@ -import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; import { expect } from "vitest"; -import { boolCV, Cl, ClarityType, OptionalCV, UIntCV } from "@stacks/transactions"; +import { + boolCV, + Cl, + ClarityType, + OptionalCV, + UIntCV, +} from "@stacks/transactions"; /** * The `AllowContractCallerComand` gives a `contract-caller` authorization to call stacking methods. @@ -23,7 +35,6 @@ export class AllowContractCallerCommand implements PoxCommand { * @param allowanceTo - Represents the authorized `contract-caller` (i.e. a stacking pool) * @param alllowUntilBurnHt - The burn block height until the authorization is valid. */ - constructor( wallet: Wallet, allowanceTo: Wallet, @@ -59,14 +70,20 @@ export class AllowContractCallerCommand implements PoxCommand { // Get the wallets involved from the model and update it with the new state. const wallet = model.wallets.get(this.wallet.stxAddress)!; const callerToAllow = model.wallets.get(this.allowanceTo.stxAddress)!; - // Update model so that we know this wallet has authorized a contract-caller. + // Update model so that we know this wallet has authorized a contract-caller. wallet.allowedContractCaller = this.allowanceTo.stxAddress; callerToAllow.callerAllowedBy.push(wallet.stxAddress); // 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}`, "allow-contract-caller", this.allowanceTo.label, "until", optionalCVToString(this.allowUntilBurnHt)); + logCommand( + `✓ ${this.wallet.label}`, + "allow-contract-caller", + this.allowanceTo.label, + "until", + optionalCVToString(this.allowUntilBurnHt), + ); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 859316451c..e0024ffbeb 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -11,7 +11,8 @@ import { RevokeDelegateStxCommand } from "./pox_RevokeDelegateStxCommand"; import { AllowContractCallerCommand } from "./pox_AllowContractCallerCommand"; export function PoxCommands( - wallets: Map, network: Simnet, + wallets: Map, + network: Simnet, ): fc.Arbitrary>> { const cmds = [ // GetStackingMinimumCommand @@ -52,7 +53,7 @@ export function PoxCommands( wallet: fc.constantFrom(...wallets.values()), delegateTo: fc.constantFrom(...wallets.values()), untilBurnHt: fc.integer({ min: 1 }), - amount: fc.bigInt({ min:0n, max: 100_000_000_000_000n }), + amount: fc.bigInt({ min: 0n, max: 100_000_000_000_000n }), }).map(( r: { wallet: Wallet; @@ -77,7 +78,7 @@ export function PoxCommands( }, ) => new RevokeDelegateStxCommand( - r.wallet + r.wallet, ) ), // DelegateStackStxCommand @@ -89,7 +90,7 @@ export function PoxCommands( max: nextCycleFirstBlock(network), }), period: fc.integer({ min: 1, max: 12 }), - amount: fc.bigInt({ min:0n, max: 100_000_000_000_000n }), + amount: fc.bigInt({ min: 0n, max: 100_000_000_000_000n }), }).chain((r) => fc.record({ unlockBurnHt: fc.constant( diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index ae4d61cc7b..23e1892a39 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -1,4 +1,10 @@ -import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; import { poxAddressToTuple } from "@stacks/stacking"; import { assert, expect } from "vitest"; import { Cl, ClarityType, isClarityType } from "@stacks/transactions"; @@ -104,7 +110,7 @@ export class DelegateStackStxCommand implements PoxCommand { // (start-burn-ht uint) Cl.uint(this.startBurnHt), // (lock-period uint) - Cl.uint(this.period) + Cl.uint(this.period), ], this.operator.stxAddress, ); @@ -146,7 +152,14 @@ export class DelegateStackStxCommand 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.operator.label} Ӿ ${this.stacker.label}`, "delegate-stack-stx", "lock-amount", this.amountUstx.toString(), "until", this.stacker.unlockHeight.toString()); + logCommand( + `✓ ${this.operator.label} Ӿ ${this.stacker.label}`, + "delegate-stack-stx", + "lock-amount", + this.amountUstx.toString(), + "until", + this.stacker.unlockHeight.toString(), + ); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts index bc638719fd..3fbf131a62 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts @@ -1,11 +1,17 @@ -import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; import { poxAddressToTuple } from "@stacks/stacking"; import { expect } from "vitest"; import { boolCV, Cl } from "@stacks/transactions"; /** - * The `DelegateStxCommand` delegates STX for stacking within PoX-4. This operation - * allows the `tx-sender` (the `wallet` in this case) to delegate stacking participation + * The `DelegateStxCommand` delegates STX for stacking within PoX-4. This operation + * allows the `tx-sender` (the `wallet` in this case) to delegate stacking participation * to a `delegatee`. * * Constraints for running this command include: @@ -50,7 +56,7 @@ export class DelegateStxCommand implements PoxCommand { run(model: Stub, real: Real): void { // The amount of uSTX delegated by the Stacker to the Delegatee. - // Even if there are no constraints about the delegated amount, + // Even if there are no constraints about the delegated amount, // it will be checked in the future, when calling delegate-stack-stx. const amountUstx = Number(this.amount); @@ -83,12 +89,19 @@ export class DelegateStxCommand implements PoxCommand { wallet.hasDelegated = true; wallet.delegatedTo = this.delegateTo.stxAddress; wallet.delegatedMaxAmount = amountUstx; - wallet.delegatedUntilBurnHt = this.untilBurnHt + wallet.delegatedUntilBurnHt = this.untilBurnHt; delegatedWallet.hasPoolMembers.push(wallet.stxAddress); // 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}`, "delegate-stx", "amount", amountUstx.toString(), "delegated to", this.delegateTo.label); + logCommand( + `✓ ${this.wallet.label}`, + "delegate-stx", + "amount", + amountUstx.toString(), + "delegated to", + this.delegateTo.label, + ); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts index 78b084f910..6e3ca20b43 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts @@ -1,4 +1,10 @@ -import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; import { assert } from "vitest"; import { ClarityType, isClarityType } from "@stacks/transactions"; @@ -42,7 +48,12 @@ export class GetStackingMinimumCommand 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}`, "get-stacking-minimum", "pox-4", stackingMinimum.value.toString()); + logCommand( + `✓ ${this.wallet.label}`, + "get-stacking-minimum", + "pox-4", + stackingMinimum.value.toString(), + ); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts index b67079f404..ac5a482b85 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts @@ -1,4 +1,10 @@ -import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; import { expect } from "vitest"; import { Cl } from "@stacks/transactions"; @@ -35,7 +41,16 @@ export class GetStxAccountCommand 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}`, "stx-account", "lock-amount", actual.amountLocked.toString(), "unlocked-amount", actual.amountUnlocked.toString(), "unlocked-height", actual.unlockHeight.toString()); + logCommand( + `✓ ${this.wallet.label}`, + "stx-account", + "lock-amount", + actual.amountLocked.toString(), + "unlocked-amount", + actual.amountUnlocked.toString(), + "unlocked-height", + actual.unlockHeight.toString(), + ); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts index c121146130..ecd9ddfec6 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts @@ -1,4 +1,10 @@ -import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; import { poxAddressToTuple } from "@stacks/stacking"; import { expect } from "vitest"; import { Cl, someCV, tupleCV } from "@stacks/transactions"; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index 765441a68f..66557bd473 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -1,4 +1,10 @@ -import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; import { Pox4SignatureTopic, poxAddressToTuple } from "@stacks/stacking"; import { assert, expect } from "vitest"; import { Cl, ClarityType, isClarityType } from "@stacks/transactions"; @@ -155,7 +161,12 @@ export class StackStxCommand 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}`, "stack-stx", "lock-amount", amountUstx.toString()); + logCommand( + `✓ ${this.wallet.label}`, + "stack-stx", + "lock-amount", + amountUstx.toString(), + ); } toString() { From dae4ebd35dac138d453308ad1032c003a94a950b Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Wed, 27 Mar 2024 14:28:17 +0200 Subject: [PATCH 020/129] fix(pox-4-tests): Address delegated PoX address comment https://github.com/stacks-network/stacks-core/pull/4550#discussion_r1537538470 --- .../core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts | 1 + contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts | 2 ++ .../core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts | 1 + .../tests/pox-4/pox_RevokeDelegateStxCommand.ts | 2 +- 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index 6c3df5fa0b..ab6ed61d56 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -95,6 +95,7 @@ describe("PoX-4 invariant tests", () => { delegatedTo: "", delegatedMaxAmount: 0, delegatedUntilBurnHt: 0, + delegatedPoxAddress: "", amountLocked: 0, amountUnlocked: initialUstxBalance, unlockHeight: 0, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 449ef3b672..94d3739d46 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -6,6 +6,7 @@ import { StacksPrivateKey } from "@stacks/transactions"; import { StackingClient } from "@stacks/stacking"; export type StxAddress = string; +export type BtcAddress = string; export type Stub = { stackingMinimum: number; @@ -30,6 +31,7 @@ export type Wallet = { delegatedTo: StxAddress; delegatedMaxAmount: number; delegatedUntilBurnHt: number; + delegatedPoxAddress: BtcAddress; amountLocked: number; amountUnlocked: number; unlockHeight: number; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts index 3fbf131a62..f59131ce95 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts @@ -90,6 +90,7 @@ export class DelegateStxCommand implements PoxCommand { wallet.delegatedTo = this.delegateTo.stxAddress; wallet.delegatedMaxAmount = amountUstx; wallet.delegatedUntilBurnHt = this.untilBurnHt; + wallet.delegatedPoxAddress = this.delegateTo.btcAddress; delegatedWallet.hasPoolMembers.push(wallet.stxAddress); // Log to console for debugging purposes. This is not necessary for the diff --git a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts index ecd9ddfec6..dbd7ee6b74 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts @@ -57,7 +57,7 @@ export class RevokeDelegateStxCommand implements PoxCommand { operatorWallet.stxAddress || "", ), "pox-addr": Cl.some( - poxAddressToTuple(operatorWallet.btcAddress || ""), + poxAddressToTuple(this.wallet.delegatedPoxAddress || ""), ), "until-burn-ht": Cl.some(Cl.uint(this.wallet.delegatedUntilBurnHt)), }), From f0c7bf093b07489e8bf30be3025f4c955848cbca Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Wed, 27 Mar 2024 14:43:39 +0200 Subject: [PATCH 021/129] fix(pox-4-tests): Address current reward cycle comment https://github.com/stacks-network/stacks-core/pull/4550#discussion_r1537520283 --- contrib/core-contract-tests/tests/pox-4/pox_Commands.ts | 3 +++ .../core-contract-tests/tests/pox-4/pox_StackStxCommand.ts | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index e0024ffbeb..f2b08ce53f 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -33,12 +33,14 @@ export function PoxCommands( authId: fc.nat(), period: fc.integer({ min: 1, max: 12 }), margin: fc.integer({ min: 1, max: 9 }), + currentCycle: fc.constant(currentCycle(network)), }).map(( r: { wallet: Wallet; authId: number; period: number; margin: number; + currentCycle: number; }, ) => new StackStxCommand( @@ -46,6 +48,7 @@ export function PoxCommands( r.authId, r.period, r.margin, + r.currentCycle, ) ), // DelegateStxCommand diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index 66557bd473..da8a295bd5 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -26,6 +26,7 @@ export class StackStxCommand implements PoxCommand { readonly authId: number; readonly period: number; readonly margin: number; + readonly currentCycle: number; /** * Constructs a `StackStxCommand` to lock uSTX for stacking. @@ -41,11 +42,13 @@ export class StackStxCommand implements PoxCommand { authId: number, period: number, margin: number, + currentCycle: number, ) { this.wallet = wallet; this.authId = authId; this.period = period; this.margin = margin; + this.currentCycle = currentCycle; } check(model: Readonly): boolean { @@ -75,7 +78,7 @@ export class StackStxCommand implements PoxCommand { // For `stack-stx` and `stack-extend`, this refers to the reward cycle // where the transaction is confirmed. For `stack-aggregation-commit`, // this refers to the reward cycle argument in that function. - rewardCycle: 0, + rewardCycle: this.currentCycle, // For `stack-stx`, this refers to `lock-period`. For `stack-extend`, // this refers to `extend-count`. For `stack-aggregation-commit`, this is // `u1`. @@ -173,6 +176,6 @@ export class StackStxCommand implements PoxCommand { // 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.wallet.label} stack-stx auth-id ${this.authId} and period ${this.period}`; + return `${this.wallet.label} stack-stx auth-id ${this.authId} and period ${this.period} during reward cycle ${this.currentCycle}`; } } From b77c81bd904a421e89e1ad909ba60fc1adb29c46 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Wed, 27 Mar 2024 15:37:31 +0200 Subject: [PATCH 022/129] fix(pox-4-tests): Address check balance command comment https://github.com/stacks-network/stacks-core/pull/4550#discussion_r1530409991 --- .../tests/pox-4/pox_CheckBalanceCommand.ts | 66 +++++++++++++++++++ .../tests/pox-4/pox_Commands.ts | 13 ++++ 2 files changed, 79 insertions(+) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_CheckBalanceCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CheckBalanceCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_CheckBalanceCommand.ts new file mode 100644 index 0000000000..d28613a226 --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_CheckBalanceCommand.ts @@ -0,0 +1,66 @@ +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; +import { expect } from "vitest"; +import { ClarityValue, cvToValue } from "@stacks/transactions"; + +/** + * Implements the `PoxCommand` interface to check a wallet's balance. + */ +export class CheckBalanceCommand implements PoxCommand { + readonly wallet: Wallet; + + /** + * Constructs a new `CheckBalanceCommand`. + * + * @param wallet The wallet information, including the STX address used to + * query the `stx-account`. + */ + constructor(wallet: Wallet) { + this.wallet = wallet; + } + + check(_model: Readonly): boolean { + // Can always check user's balance. + return true; + } + + run(model: Stub, real: Real): void { + const actual = model.wallets.get(this.wallet.stxAddress)!; + + // Get the real balance + const stxAccount = cvToValue( + real.network.runSnippet( + `(stx-account '${actual.stxAddress})`, + ) as ClarityValue, + ); + const lockedBalance = parseInt(stxAccount.locked.value); + const unlockedBalance = parseInt(stxAccount.unlocked.value); + const realBalance = lockedBalance + unlockedBalance; + + // Check the real balance to equal wallet's ustxBalance + expect(realBalance).toBe(this.wallet.ustxBalance); + + // 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}`, + "check-balance", + "real-balance", + realBalance.toString(), + "wallet-balance", + this.wallet.ustxBalance.toString(), + ); + } + + 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.wallet.label} check-balance`; + } +} diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index f2b08ce53f..c87c50e7d4 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -9,6 +9,7 @@ import { Simnet } from "@hirosystems/clarinet-sdk"; import { Cl, cvToValue, OptionalCV, UIntCV } from "@stacks/transactions"; import { RevokeDelegateStxCommand } from "./pox_RevokeDelegateStxCommand"; import { AllowContractCallerCommand } from "./pox_AllowContractCallerCommand"; +import { CheckBalanceCommand } from "./pox_CheckBalanceCommand"; export function PoxCommands( wallets: Map, @@ -146,6 +147,18 @@ export function PoxCommands( r.wallet, ) ), + // CheckBalanceCommand + fc.record({ + wallet: fc.constantFrom(...wallets.values()), + }).map(( + r: { + wallet: Wallet; + }, + ) => + new CheckBalanceCommand( + r.wallet, + ) + ), ]; // More on size: https://github.com/dubzzz/fast-check/discussions/2978 From 35df5a2cbe179deeb763fe81509a45d40b757e50 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Wed, 27 Mar 2024 19:08:56 +0200 Subject: [PATCH 023/129] fix(pox-4-tests): Address stacker generation comment https://github.com/stacks-network/stacks-core/pull/4550#discussion_r1537470910 --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 2 +- .../tests/pox-4/pox_CommandModel.ts | 2 +- .../tests/pox-4/pox_Commands.ts | 61 +++++++++++++------ .../pox-4/pox_DelegateStackStxCommand.ts | 3 +- .../tests/pox-4/pox_DelegateStxCommand.ts | 4 +- .../pox-4/pox_RevokeDelegateStxCommand.ts | 4 +- 6 files changed, 50 insertions(+), 26 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index ab6ed61d56..d9e2f4a21e 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -91,7 +91,7 @@ describe("PoX-4 invariant tests", () => { ustxBalance: initialUstxBalance, isStacking: false, hasDelegated: false, - hasPoolMembers: [], + poolMembers: [], delegatedTo: "", delegatedMaxAmount: 0, delegatedUntilBurnHt: 0, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 94d3739d46..32971bc854 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -27,7 +27,7 @@ export type Wallet = { ustxBalance: number; isStacking: boolean; hasDelegated: boolean; - hasPoolMembers: StxAddress[]; + poolMembers: StxAddress[]; delegatedTo: StxAddress; delegatedMaxAmount: number; delegatedUntilBurnHt: number; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index c87c50e7d4..838b4d2a22 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -88,32 +88,53 @@ export function PoxCommands( // DelegateStackStxCommand fc.record({ operator: fc.constantFrom(...wallets.values()), - stacker: fc.constantFrom(...wallets.values()), startBurnHt: fc.integer({ min: currentCycleFirstBlock(network), max: nextCycleFirstBlock(network), }), period: fc.integer({ min: 1, max: 12 }), - amount: fc.bigInt({ min: 0n, max: 100_000_000_000_000n }), - }).chain((r) => - fc.record({ - unlockBurnHt: fc.constant( - currentCycleFirstBlock(network) + 1050 * (r.period + 1), - ), - }).map((unlockBurnHtRecord) => ({ + }).chain((r) => { + // Determine available stackers based on the operator + const availableStackers = r.operator.poolMembers.length > 0 + ? r.operator.poolMembers + : [r.operator.stxAddress]; + + return fc.record({ + stacker: fc.constantFrom(...availableStackers), + }).map((stacker) => ({ ...r, - ...unlockBurnHtRecord, - })) - ).map((r) => - new DelegateStackStxCommand( - r.operator, - r.stacker, - r.startBurnHt, - r.period, - r.amount, - r.unlockBurnHt, - ) - ), + stacker: wallets.get(stacker.stacker)!, + })).chain((resultWithStacker) => { + return fc.record({ + unlockBurnHt: fc.constant( + currentCycleFirstBlock(network) + + 1050 * (resultWithStacker.period + 1), + ), + }).map((additionalProps) => ({ + ...resultWithStacker, + ...additionalProps, + })); + }).chain((resultWithUnlockHeight) => { + return fc.record({ + amount: fc.bigInt({ + min: 0n, + max: BigInt(resultWithUnlockHeight.stacker.delegatedMaxAmount), + }), + }).map((amountProps) => ({ + ...resultWithUnlockHeight, + ...amountProps, + })); + }); + }).map((finalResult) => { + return new DelegateStackStxCommand( + finalResult.operator, + finalResult.stacker, + finalResult.startBurnHt, + finalResult.period, + finalResult.amount, + finalResult.unlockBurnHt, + ); + }), // AllowContractCallerCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index 23e1892a39..baa5b16abd 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -90,7 +90,8 @@ export class DelegateStackStxCommand implements PoxCommand { stackerWallet.delegatedMaxAmount >= Number(this.amountUstx) && Number(this.amountUstx) <= stackerWallet.ustxBalance && Number(this.amountUstx) >= model.stackingMinimum && - operatorWallet.hasPoolMembers.includes(stackerWallet.stxAddress) && + operatorWallet.poolMembers.length > 0 && + operatorWallet.poolMembers.includes(stackerWallet.stxAddress) && this.unlockBurnHt <= stackerWallet.delegatedUntilBurnHt ); } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts index f59131ce95..59a0b9cba4 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts @@ -92,7 +92,7 @@ export class DelegateStxCommand implements PoxCommand { wallet.delegatedUntilBurnHt = this.untilBurnHt; wallet.delegatedPoxAddress = this.delegateTo.btcAddress; - delegatedWallet.hasPoolMembers.push(wallet.stxAddress); + delegatedWallet.poolMembers.push(wallet.stxAddress); // 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( @@ -102,6 +102,8 @@ export class DelegateStxCommand implements PoxCommand { amountUstx.toString(), "delegated to", this.delegateTo.label, + "until", + this.untilBurnHt.toString() ); } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts index dbd7ee6b74..4e7f16e620 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts @@ -75,11 +75,11 @@ export class RevokeDelegateStxCommand implements PoxCommand { wallet.delegatedMaxAmount = 0; // Remove the Stacker from the Pool Operator's pool members list - let walletIndexInDelegatorsList = operatorWallet.hasPoolMembers.indexOf( + let walletIndexInDelegatorsList = operatorWallet.poolMembers.indexOf( wallet.stxAddress, ); expect(walletIndexInDelegatorsList).toBeGreaterThan(-1); - operatorWallet.hasPoolMembers.splice(walletIndexInDelegatorsList, 1); + operatorWallet.poolMembers.splice(walletIndexInDelegatorsList, 1); // 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. From ebb17e3b65b5626babf9809ee912887b59dba389 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Thu, 28 Mar 2024 12:37:23 +0100 Subject: [PATCH 024/129] feat(pox-4-tests): Print command output in real-time Thanks to @hugocaillard for swiftly implementing this feature. --- contrib/core-contract-tests/noopReporter.ts | 26 +++ contrib/core-contract-tests/package-lock.json | 85 ------- contrib/core-contract-tests/package.json | 1 - .../tests/pox-4/pox-4.stateful-prop.test.ts | 212 +++++++++--------- .../tests/pox-4/pox_CommandModel.ts | 4 +- contrib/core-contract-tests/vitest.config.js | 1 + 6 files changed, 134 insertions(+), 195 deletions(-) create mode 100644 contrib/core-contract-tests/noopReporter.ts diff --git a/contrib/core-contract-tests/noopReporter.ts b/contrib/core-contract-tests/noopReporter.ts new file mode 100644 index 0000000000..c97206f5f1 --- /dev/null +++ b/contrib/core-contract-tests/noopReporter.ts @@ -0,0 +1,26 @@ +import type { UserConsoleLog } from "vitest"; + +import { DefaultReporter } from "vitest/reporters"; + +export default class LoggerReporter extends DefaultReporter { + onInit() {} + onPathsCollected() {} + onCollected() {} + onFinished() { + return Promise.resolve(); + } + onTaskUpdate() {} + + onWatcherStart() { + return Promise.resolve(); + } + onWatcherRerun() { + return Promise.resolve(); + } + + onServerRestart() {} + + onProcessTimeou() {} + + onUserConsoleLog(log: UserConsoleLog) {} +} diff --git a/contrib/core-contract-tests/package-lock.json b/contrib/core-contract-tests/package-lock.json index f636a0d085..5fd11568ce 100644 --- a/contrib/core-contract-tests/package-lock.json +++ b/contrib/core-contract-tests/package-lock.json @@ -15,7 +15,6 @@ "@stacks/transactions": "^6.13.0", "chokidar-cli": "^3.0.0", "fast-check": "^3.15.1", - "ololog": "^1.1.175", "typescript": "^5.4.2", "vite": "^5.1.6", "vitest": "^1.3.1", @@ -1477,11 +1476,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/ansicolor": { - "version": "1.1.100", - "resolved": "https://registry.npmjs.org/ansicolor/-/ansicolor-1.1.100.tgz", - "integrity": "sha512-Jl0pxRfa9WaQVUX57AB8/V2my6FJxrOR1Pp2qqFbig20QB4HzUoQ48THTKAgHlUCJeQm/s2WoOPcoIDhyCL/kw==" - }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -1499,14 +1493,6 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, - "node_modules/as-table": { - "version": "1.0.55", - "resolved": "https://registry.npmjs.org/as-table/-/as-table-1.0.55.tgz", - "integrity": "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==", - "dependencies": { - "printable-characters": "^1.0.42" - } - }, "node_modules/assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -1933,11 +1919,6 @@ "node": ">= 8" } }, - "node_modules/data-uri-to-buffer": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-2.0.2.tgz", - "integrity": "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==" - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -2366,15 +2347,6 @@ "node": "*" } }, - "node_modules/get-source": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/get-source/-/get-source-2.0.12.tgz", - "integrity": "sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==", - "dependencies": { - "data-uri-to-buffer": "^2.0.0", - "source-map": "^0.6.1" - } - }, "node_modules/get-stream": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", @@ -2820,19 +2792,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ololog": { - "version": "1.1.175", - "resolved": "https://registry.npmjs.org/ololog/-/ololog-1.1.175.tgz", - "integrity": "sha512-DSPbsvZzLshFiPI1ul7iJDn6wI75goOLyrn8uRB92sPon5LS8J2KlAIkSoHXtRztb2idPjuzq3R1J58hN2qOEA==", - "dependencies": { - "ansicolor": "^1.1.84", - "pipez": "^1.1.12", - "printable-characters": "^1.0.42", - "stacktracey": "^2.1.6", - "string.bullet": "^1.0.12", - "string.ify": "^1.0.64" - } - }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -2980,11 +2939,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pipez": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/pipez/-/pipez-1.1.12.tgz", - "integrity": "sha512-VuJ+c44f3s/4cirqtBI3wa0LscCo1IG9sQH2DnClJWEMkGylE52mDjLLHR5QyLjij1EiGocMEIAJsmpyXczXJQ==" - }, "node_modules/pkg-types": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", @@ -3054,11 +3008,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/printable-characters": { - "version": "1.0.42", - "resolved": "https://registry.npmjs.org/printable-characters/-/printable-characters-1.0.42.tgz", - "integrity": "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==" - }, "node_modules/process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -3306,14 +3255,6 @@ "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", @@ -3327,15 +3268,6 @@ "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==" }, - "node_modules/stacktracey": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/stacktracey/-/stacktracey-2.1.8.tgz", - "integrity": "sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==", - "dependencies": { - "as-table": "^1.0.36", - "get-source": "^2.0.12" - } - }, "node_modules/std-env": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", @@ -3354,23 +3286,6 @@ "node": ">=8" } }, - "node_modules/string.bullet": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/string.bullet/-/string.bullet-1.0.12.tgz", - "integrity": "sha512-6+tQyad/ux52N+7wUcjmxeK5TfdeykBBLHQPk8MxUVrk9JwHzJnuxsJzjjpWAuz0x3EmnVGCg0ibMHqez1l/qQ==", - "dependencies": { - "printable-characters": "^1.0.26" - } - }, - "node_modules/string.ify": { - "version": "1.0.64", - "resolved": "https://registry.npmjs.org/string.ify/-/string.ify-1.0.64.tgz", - "integrity": "sha512-4Aa5yndnuOhE1GV2W3ht4rQ08XHq46JLXmSOv0jeUWEzqliBvm8lAXvt+66np+J9DkoCZikFzTzjXVLRR0F/Xw==", - "dependencies": { - "printable-characters": "^1.0.42", - "string.bullet": "^1.0.12" - } - }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", diff --git a/contrib/core-contract-tests/package.json b/contrib/core-contract-tests/package.json index a6c8b23262..0d80a4e570 100644 --- a/contrib/core-contract-tests/package.json +++ b/contrib/core-contract-tests/package.json @@ -17,7 +17,6 @@ "@stacks/transactions": "^6.13.0", "chokidar-cli": "^3.0.0", "fast-check": "^3.15.1", - "ololog": "^1.1.175", "typescript": "^5.4.2", "vite": "^5.1.6", "vitest": "^1.3.1", diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index d9e2f4a21e..70533ce605 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -1,4 +1,4 @@ -import { describe, it } from "vitest"; +import { it } from "vitest"; import { initSimnet } from "@hirosystems/clarinet-sdk"; import { Real, Stub, StxAddress, Wallet } from "./pox_CommandModel.ts"; @@ -17,117 +17,115 @@ import { StackingClient } from "@stacks/stacking"; import fc from "fast-check"; import { PoxCommands } from "./pox_Commands.ts"; -describe("PoX-4 invariant tests", () => { - it("statefully does solo stacking with a signature", async () => { - // SUT stands for "System Under Test". - const sut: Real = { - network: await initSimnet(), - }; +it("statefully interacts with PoX-4", async () => { + // SUT stands for "System Under Test". + const sut: Real = { + network: await initSimnet(), + }; - // This is the initial state of the model. - const model: Stub = { - stackingMinimum: 0, - wallets: new Map(), - }; + // This is the initial state of the model. + const model: Stub = { + stackingMinimum: 0, + wallets: new Map(), + }; - const wallets = [ - [ - "wallet_1", - "7287ba251d44a4d3fd9276c88ce34c5c52a038955511cccaf77e61068649c17801", - ], - [ - "wallet_2", - "530d9f61984c888536871c6573073bdfc0058896dc1adfe9a6a10dfacadc209101", - ], - [ - "wallet_3", - "d655b2523bcd65e34889725c73064feb17ceb796831c0e111ba1a552b0f31b3901", - ], - [ - "wallet_4", - "f9d7206a47f14d2870c163ebab4bf3e70d18f5d14ce1031f3902fbbc894fe4c701", - ], - [ - "wallet_5", - "3eccc5dac8056590432db6a35d52b9896876a3d5cbdea53b72400bc9c2099fe801", - ], - [ - "wallet_6", - "7036b29cb5e235e5fd9b09ae3e8eec4404e44906814d5d01cbca968a60ed4bfb01", - ], - [ - "wallet_7", - "b463f0df6c05d2f156393eee73f8016c5372caa0e9e29a901bb7171d90dc4f1401", - ], - [ - "wallet_8", - "6a1a754ba863d7bab14adbbc3f8ebb090af9e871ace621d3e5ab634e1422885e01", - ], - [ - "wallet_9", - "de433bdfa14ec43aa1098d5be594c8ffb20a31485ff9de2923b2689471c401b801", - ], - ].map((wallet) => { - const label = wallet[0]; - const prvKey = wallet[1]; - const pubKey = getPublicKeyFromPrivate(prvKey); - const devnet = new StacksDevnet(); - const initialUstxBalance = 100_000_000_000_000; - const signerPrvKey = createStacksPrivateKey(prvKey); - const signerPubKey = getPublicKeyFromPrivate(signerPrvKey.data); - const btcAddress = publicKeyToBtcAddress(pubKey); - const stxAddress = getAddressFromPrivateKey( - prvKey, - TransactionVersion.Testnet, - ); + const wallets = [ + [ + "wallet_1", + "7287ba251d44a4d3fd9276c88ce34c5c52a038955511cccaf77e61068649c17801", + ], + [ + "wallet_2", + "530d9f61984c888536871c6573073bdfc0058896dc1adfe9a6a10dfacadc209101", + ], + [ + "wallet_3", + "d655b2523bcd65e34889725c73064feb17ceb796831c0e111ba1a552b0f31b3901", + ], + [ + "wallet_4", + "f9d7206a47f14d2870c163ebab4bf3e70d18f5d14ce1031f3902fbbc894fe4c701", + ], + [ + "wallet_5", + "3eccc5dac8056590432db6a35d52b9896876a3d5cbdea53b72400bc9c2099fe801", + ], + [ + "wallet_6", + "7036b29cb5e235e5fd9b09ae3e8eec4404e44906814d5d01cbca968a60ed4bfb01", + ], + [ + "wallet_7", + "b463f0df6c05d2f156393eee73f8016c5372caa0e9e29a901bb7171d90dc4f1401", + ], + [ + "wallet_8", + "6a1a754ba863d7bab14adbbc3f8ebb090af9e871ace621d3e5ab634e1422885e01", + ], + [ + "wallet_9", + "de433bdfa14ec43aa1098d5be594c8ffb20a31485ff9de2923b2689471c401b801", + ], + ].map((wallet) => { + const label = wallet[0]; + const prvKey = wallet[1]; + const pubKey = getPublicKeyFromPrivate(prvKey); + const devnet = new StacksDevnet(); + const initialUstxBalance = 100_000_000_000_000; + const signerPrvKey = createStacksPrivateKey(prvKey); + const signerPubKey = getPublicKeyFromPrivate(signerPrvKey.data); + const btcAddress = publicKeyToBtcAddress(pubKey); + const stxAddress = getAddressFromPrivateKey( + prvKey, + TransactionVersion.Testnet, + ); - return { - label, - stxAddress, - btcAddress, - signerPrvKey, - signerPubKey, - stackingClient: new StackingClient(stxAddress, devnet), - ustxBalance: initialUstxBalance, - isStacking: false, - hasDelegated: false, - poolMembers: [], - delegatedTo: "", - delegatedMaxAmount: 0, - delegatedUntilBurnHt: 0, - delegatedPoxAddress: "", - amountLocked: 0, - amountUnlocked: initialUstxBalance, - unlockHeight: 0, - allowedContractCaller: "", - callerAllowedBy: [], - }; - }); + return { + label, + stxAddress, + btcAddress, + signerPrvKey, + signerPubKey, + stackingClient: new StackingClient(stxAddress, devnet), + ustxBalance: initialUstxBalance, + isStacking: false, + hasDelegated: false, + poolMembers: [], + delegatedTo: "", + delegatedMaxAmount: 0, + delegatedUntilBurnHt: 0, + delegatedPoxAddress: "", + amountLocked: 0, + amountUnlocked: initialUstxBalance, + unlockHeight: 0, + allowedContractCaller: "", + callerAllowedBy: [], + }; + }); - // Add the wallets to the model. - wallets.forEach((wallet) => { - model.wallets.set(wallet.stxAddress, wallet); - }); + // Add the wallets to the model. + wallets.forEach((wallet) => { + model.wallets.set(wallet.stxAddress, wallet); + }); - simnet.setEpoch("3.0"); + simnet.setEpoch("3.0"); - 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, + 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, + }, + ); }); diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 32971bc854..d31e11a426 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -1,5 +1,4 @@ import fc from "fast-check"; -import ololog from "ololog"; import { Simnet } from "@hirosystems/clarinet-sdk"; import { StacksPrivateKey } from "@stacks/transactions"; @@ -49,6 +48,7 @@ export const logCommand = (...items: (string | undefined)[]) => { const prettyPrint = renderItems.map((content) => content ? content.padEnd(columnWidth) : "".padEnd(columnWidth) ); + prettyPrint.push("\n"); - ololog.configure({ locate: false })(prettyPrint.join("")); + process.stdout.write(prettyPrint.join("")); }; diff --git a/contrib/core-contract-tests/vitest.config.js b/contrib/core-contract-tests/vitest.config.js index 364c55f735..3059a20050 100644 --- a/contrib/core-contract-tests/vitest.config.js +++ b/contrib/core-contract-tests/vitest.config.js @@ -29,6 +29,7 @@ export default defineConfig({ threads: { singleThread: true }, forks: { singleFork: true }, }, + reporters: ["./noopReporter.ts"], setupFiles: [ vitestSetupFilePath, // custom setup files can be added here From 64857fd6f0726341a19fbca352b66f0a2221fcee Mon Sep 17 00:00:00 2001 From: BowTiedRadone <92028479+BowTiedRadone@users.noreply.github.com> Date: Thu, 28 Mar 2024 13:42:16 +0200 Subject: [PATCH 025/129] fix(pox-4-tests): Update let to const RevokeDelegateStx Co-authored-by: Nikos Baxevanis --- .../tests/pox-4/pox_RevokeDelegateStxCommand.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts index 4e7f16e620..93c3844d92 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts @@ -75,7 +75,7 @@ export class RevokeDelegateStxCommand implements PoxCommand { wallet.delegatedMaxAmount = 0; // Remove the Stacker from the Pool Operator's pool members list - let walletIndexInDelegatorsList = operatorWallet.poolMembers.indexOf( + const walletIndexInDelegatorsList = operatorWallet.poolMembers.indexOf( wallet.stxAddress, ); expect(walletIndexInDelegatorsList).toBeGreaterThan(-1); From 7ff85f583244f6bade4a6031bfaf33d38c71c7ae Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Thu, 28 Mar 2024 13:53:36 +0200 Subject: [PATCH 026/129] fix(pox-4-tests): Move balance check inside GetStxAccountCommand --- .../tests/pox-4/pox_CheckBalanceCommand.ts | 66 ------------------- .../tests/pox-4/pox_Commands.ts | 13 ---- .../tests/pox-4/pox_GetStxAccountCommand.ts | 2 + 3 files changed, 2 insertions(+), 79 deletions(-) delete mode 100644 contrib/core-contract-tests/tests/pox-4/pox_CheckBalanceCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CheckBalanceCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_CheckBalanceCommand.ts deleted file mode 100644 index d28613a226..0000000000 --- a/contrib/core-contract-tests/tests/pox-4/pox_CheckBalanceCommand.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { - logCommand, - PoxCommand, - Real, - Stub, - Wallet, -} from "./pox_CommandModel.ts"; -import { expect } from "vitest"; -import { ClarityValue, cvToValue } from "@stacks/transactions"; - -/** - * Implements the `PoxCommand` interface to check a wallet's balance. - */ -export class CheckBalanceCommand implements PoxCommand { - readonly wallet: Wallet; - - /** - * Constructs a new `CheckBalanceCommand`. - * - * @param wallet The wallet information, including the STX address used to - * query the `stx-account`. - */ - constructor(wallet: Wallet) { - this.wallet = wallet; - } - - check(_model: Readonly): boolean { - // Can always check user's balance. - return true; - } - - run(model: Stub, real: Real): void { - const actual = model.wallets.get(this.wallet.stxAddress)!; - - // Get the real balance - const stxAccount = cvToValue( - real.network.runSnippet( - `(stx-account '${actual.stxAddress})`, - ) as ClarityValue, - ); - const lockedBalance = parseInt(stxAccount.locked.value); - const unlockedBalance = parseInt(stxAccount.unlocked.value); - const realBalance = lockedBalance + unlockedBalance; - - // Check the real balance to equal wallet's ustxBalance - expect(realBalance).toBe(this.wallet.ustxBalance); - - // 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}`, - "check-balance", - "real-balance", - realBalance.toString(), - "wallet-balance", - this.wallet.ustxBalance.toString(), - ); - } - - 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.wallet.label} check-balance`; - } -} diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 838b4d2a22..62db94efab 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -9,7 +9,6 @@ import { Simnet } from "@hirosystems/clarinet-sdk"; import { Cl, cvToValue, OptionalCV, UIntCV } from "@stacks/transactions"; import { RevokeDelegateStxCommand } from "./pox_RevokeDelegateStxCommand"; import { AllowContractCallerCommand } from "./pox_AllowContractCallerCommand"; -import { CheckBalanceCommand } from "./pox_CheckBalanceCommand"; export function PoxCommands( wallets: Map, @@ -168,18 +167,6 @@ export function PoxCommands( r.wallet, ) ), - // CheckBalanceCommand - fc.record({ - wallet: fc.constantFrom(...wallets.values()), - }).map(( - r: { - wallet: Wallet; - }, - ) => - new CheckBalanceCommand( - r.wallet, - ) - ), ]; // More on size: https://github.com/dubzzz/fast-check/discussions/2978 diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts index ac5a482b85..7f6ddf6ca8 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts @@ -39,6 +39,8 @@ export class GetStxAccountCommand implements PoxCommand { "unlock-height": Cl.uint(actual.unlockHeight), }); + expect(actual.amountLocked + actual.amountUnlocked).toBe(actual.ustxBalance); + // 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( From 6254bac7c7afbce67665795acd1bb9efa9c4bdbe Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Fri, 29 Mar 2024 07:22:00 +0100 Subject: [PATCH 027/129] fix(test-output): Remove global noopReporter to restore test visibility Removed the "./noopReporter.ts" from the global Vitest reporters configuration to ensure test outputs are visible by default. This change addresses an issue where the output from all tests was being hidden, making it difficult to observe test results directly. The noopReporter can still be used selectively for specific tests via: npx vitest --reporter=./noopReporter.ts run tests/pox-4/pox-4.stateful-prop.test.ts --- contrib/core-contract-tests/vitest.config.js | 1 - 1 file changed, 1 deletion(-) diff --git a/contrib/core-contract-tests/vitest.config.js b/contrib/core-contract-tests/vitest.config.js index 3059a20050..364c55f735 100644 --- a/contrib/core-contract-tests/vitest.config.js +++ b/contrib/core-contract-tests/vitest.config.js @@ -29,7 +29,6 @@ export default defineConfig({ threads: { singleThread: true }, forks: { singleFork: true }, }, - reporters: ["./noopReporter.ts"], setupFiles: [ vitestSetupFilePath, // custom setup files can be added here From 848e0a8d4211ab8794ca61d12381512afe5dfe58 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Fri, 29 Mar 2024 08:09:38 +0100 Subject: [PATCH 028/129] feat(pox-4-tests): Track command execution in PoxCommand implementations Each `run` method now calls `model.trackCommandRun(this.constructor.name)`, enhancing observability and aiding in debugging by systematically tracking command executions. Example output: Command run method execution counts: AllowContractCallerCommand: 491 DelegateStackStxCommand: 1 DelegateStxCommand: 285 GetStackingMinimumCommand: 536 GetStxAccountCommand: 503 RevokeDelegateStxCommand: 281 StackStxCommand: 8 --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 29 ++++++++++++------- .../pox-4/pox_AllowContractCallerCommand.ts | 1 + .../tests/pox-4/pox_CommandModel.ts | 29 +++++++++++++++++-- .../pox-4/pox_DelegateStackStxCommand.ts | 1 + .../tests/pox-4/pox_DelegateStxCommand.ts | 1 + .../pox-4/pox_GetStackingMinimumCommand.ts | 1 + .../tests/pox-4/pox_GetStxAccountCommand.ts | 1 + .../pox-4/pox_RevokeDelegateStxCommand.ts | 1 + .../tests/pox-4/pox_StackStxCommand.ts | 1 + 9 files changed, 51 insertions(+), 14 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index 70533ce605..6c64d93c29 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -1,6 +1,6 @@ import { it } from "vitest"; import { initSimnet } from "@hirosystems/clarinet-sdk"; -import { Real, Stub, StxAddress, Wallet } from "./pox_CommandModel.ts"; +import { Real, Stub } from "./pox_CommandModel.ts"; import { getPublicKeyFromPrivate, @@ -17,18 +17,15 @@ import { StackingClient } from "@stacks/stacking"; import fc from "fast-check"; import { PoxCommands } from "./pox_Commands.ts"; +import fs from "fs"; +import path from "path"; + it("statefully interacts with PoX-4", async () => { // SUT stands for "System Under Test". const sut: Real = { network: await initSimnet(), }; - // This is the initial state of the model. - const model: Stub = { - stackingMinimum: 0, - wallets: new Map(), - }; - const wallets = [ [ "wallet_1", @@ -103,10 +100,18 @@ it("statefully interacts with PoX-4", async () => { }; }); - // Add the wallets to the model. - wallets.forEach((wallet) => { - model.wallets.set(wallet.stxAddress, wallet); - }); + // Track the number of times each command is run, so we can see if all the + // 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" + ).map((file) => file.slice(4, -3)); // Remove "pox_" prefix and ".ts" suffix. + + // This is the initial state of the model. + const model = new Stub( + new Map(wallets.map((wallet) => [wallet.stxAddress, wallet])), + new Map(statistics.map((commandName) => [commandName, 0])), + ); simnet.setEpoch("3.0"); @@ -128,4 +133,6 @@ it("statefully interacts with PoX-4", async () => { verbose: 2, }, ); + + model.reportCommandRuns(); }); diff --git a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts index 591568a17c..13283af8a9 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts @@ -51,6 +51,7 @@ export class AllowContractCallerCommand implements PoxCommand { } run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); // Act const allowContractCaller = real.network.callPublicFn( "ST000000000000000000002AMW42H.pox-4", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index d31e11a426..10dbbeaedc 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -6,11 +6,34 @@ import { StackingClient } from "@stacks/stacking"; export type StxAddress = string; export type BtcAddress = string; +export type CommandTag = string; -export type Stub = { +export class Stub { + readonly wallets: Map; + readonly statistics: Map; stackingMinimum: number; - wallets: Map; -}; + + constructor( + wallets: Map, + statistics: Map, + ) { + this.wallets = wallets; + this.statistics = statistics; + this.stackingMinimum = 0; + } + + trackCommandRun(commandName: string) { + const count = this.statistics.get(commandName) || 0; + this.statistics.set(commandName, count + 1); + } + + reportCommandRuns() { + process.stdout.write("Command run method execution counts:"); + this.statistics.forEach((count, commandName) => { + process.stdout.write(`\n${commandName}: ${count}`); + }); + } +} export type Real = { network: Simnet; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index baa5b16abd..5eeb43372e 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -97,6 +97,7 @@ export class DelegateStackStxCommand implements PoxCommand { } run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); // Act const delegateStackStx = real.network.callPublicFn( "ST000000000000000000002AMW42H.pox-4", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts index 59a0b9cba4..6de496d375 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts @@ -55,6 +55,7 @@ export class DelegateStxCommand implements PoxCommand { } run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); // The amount of uSTX delegated by the Stacker to the Delegatee. // Even if there are no constraints about the delegated amount, // it will be checked in the future, when calling delegate-stack-stx. diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts index 6e3ca20b43..c5a84e6a3d 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts @@ -32,6 +32,7 @@ export class GetStackingMinimumCommand implements PoxCommand { } run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); // Act const { result: stackingMinimum } = real.network.callReadOnlyFn( "ST000000000000000000002AMW42H.pox-4", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts index 7f6ddf6ca8..71cf99207c 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts @@ -31,6 +31,7 @@ export class GetStxAccountCommand implements PoxCommand { } run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); const actual = model.wallets.get(this.wallet.stxAddress)!; expect(real.network.runSnippet(`(stx-account '${actual.stxAddress})`)) .toBeTuple({ diff --git a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts index 93c3844d92..5ada55932d 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts @@ -37,6 +37,7 @@ export class RevokeDelegateStxCommand implements PoxCommand { } run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); // Get the Operator's wallet const operatorWallet = model.wallets.get(this.wallet.delegatedTo)!; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index da8a295bd5..cbdb782dc9 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -65,6 +65,7 @@ export class StackStxCommand implements PoxCommand { } run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); // The maximum amount of uSTX that can be used (per tx) with this signer // key. For our tests, we will use the minimum amount of uSTX to be stacked // in the given reward cycle multiplied by the margin, which is a randomly From 3b857f9b35eda11162e13a7aa1ab518d044a08f8 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Fri, 29 Mar 2024 12:11:59 +0200 Subject: [PATCH 029/129] fix(pox-4-tests): Remove unnecessary check https://github.com/stacks-network/stacks-core/pull/4597/files/32e64e8ce33e440b5ddf9b3d804ce42e66e760ff#r1542690008 --- .../tests/pox-4/pox_DelegateStackStxCommand.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index 5eeb43372e..4da9cc6980 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -54,7 +54,7 @@ export class DelegateStackStxCommand implements PoxCommand { startBurnHt: number, period: number, amountUstx: bigint, - unlockBurnHt: number, + unlockBurnHt: number ) { this.operator = operator; this.stacker = stacker; @@ -90,7 +90,6 @@ export class DelegateStackStxCommand implements PoxCommand { stackerWallet.delegatedMaxAmount >= Number(this.amountUstx) && Number(this.amountUstx) <= stackerWallet.ustxBalance && Number(this.amountUstx) >= model.stackingMinimum && - operatorWallet.poolMembers.length > 0 && operatorWallet.poolMembers.includes(stackerWallet.stxAddress) && this.unlockBurnHt <= stackerWallet.delegatedUntilBurnHt ); @@ -114,13 +113,13 @@ export class DelegateStackStxCommand implements PoxCommand { // (lock-period uint) Cl.uint(this.period), ], - this.operator.stxAddress, + this.operator.stxAddress ); const { result: rewardCycle } = real.network.callReadOnlyFn( "ST000000000000000000002AMW42H.pox-4", "burn-height-to-reward-cycle", [Cl.uint(real.network.blockHeight)], - this.operator.stxAddress, + this.operator.stxAddress ); assert(isClarityType(rewardCycle, ClarityType.UInt)); @@ -128,7 +127,7 @@ export class DelegateStackStxCommand implements PoxCommand { "ST000000000000000000002AMW42H.pox-4", "reward-cycle-to-burn-height", [Cl.uint(Number(rewardCycle.value) + this.period + 1)], - this.operator.stxAddress, + this.operator.stxAddress ); assert(isClarityType(unlockBurnHeight, ClarityType.UInt)); @@ -138,7 +137,7 @@ export class DelegateStackStxCommand implements PoxCommand { stacker: Cl.principal(this.stacker.stxAddress), "lock-amount": Cl.uint(this.amountUstx), "unlock-burn-height": Cl.uint(Number(unlockBurnHeight.value)), - }), + }) ); // Get the Stacker's wallet from the model and update it with the new state. @@ -160,7 +159,7 @@ export class DelegateStackStxCommand implements PoxCommand { "lock-amount", this.amountUstx.toString(), "until", - this.stacker.unlockHeight.toString(), + this.stacker.unlockHeight.toString() ); } From 5afc571ec0cac1251f53fea41c886fa7a2f45317 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Fri, 29 Mar 2024 17:02:35 +0200 Subject: [PATCH 030/129] test(pox-4-tests): Add DelegateStackIncreaseCommand --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 1 + .../tests/pox-4/pox_CommandModel.ts | 1 + .../tests/pox-4/pox_Commands.ts | 24 ++++ .../pox-4/pox_DelegateStackIncreaseCommand.ts | 132 ++++++++++++++++++ .../pox-4/pox_DelegateStackStxCommand.ts | 5 + 5 files changed, 163 insertions(+) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index 6c64d93c29..f44a255351 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -87,6 +87,7 @@ it("statefully interacts with PoX-4", async () => { ustxBalance: initialUstxBalance, isStacking: false, hasDelegated: false, + hasLocked: [], poolMembers: [], delegatedTo: "", delegatedMaxAmount: 0, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 10dbbeaedc..de01266838 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -49,6 +49,7 @@ export type Wallet = { ustxBalance: number; isStacking: boolean; hasDelegated: boolean; + hasLocked: StxAddress[]; poolMembers: StxAddress[]; delegatedTo: StxAddress; delegatedMaxAmount: number; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 62db94efab..2abfd762be 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -9,6 +9,7 @@ import { Simnet } from "@hirosystems/clarinet-sdk"; import { Cl, cvToValue, OptionalCV, UIntCV } from "@stacks/transactions"; import { RevokeDelegateStxCommand } from "./pox_RevokeDelegateStxCommand"; import { AllowContractCallerCommand } from "./pox_AllowContractCallerCommand"; +import { DelegateStackIncreaseCommand } from "./pox_DelegateStackIncreaseCommand"; export function PoxCommands( wallets: Map, @@ -134,6 +135,29 @@ export function PoxCommands( finalResult.unlockBurnHt, ); }), + // DelegateStackIncreaseCommand + fc.record({ + operator: fc.constantFrom(...wallets.values()), + stacker: fc.constantFrom(...wallets.values()), + increaseBy: fc.bigInt({ min: 0n, max: 100_000_000_000_000n }), + }).chain((r) => { + const availableStackers = r.operator.poolMembers.length > 0 + ? r.operator.poolMembers + : [r.operator.stxAddress]; + + return fc.record({ + stacker: fc.constantFrom(...availableStackers), + }).map((stacker) => ({ + ...r, + stacker: wallets.get(stacker.stacker)!, + })); + }).map((final) => { + return new DelegateStackIncreaseCommand( + final.operator, + final.stacker, + final.increaseBy, + ); + }), // AllowContractCallerCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts new file mode 100644 index 0000000000..4df9f5f752 --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts @@ -0,0 +1,132 @@ +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; +import { poxAddressToTuple } from "@stacks/stacking"; +import { expect } from "vitest"; +import { Cl } from "@stacks/transactions"; + +/** + * The DelegateStackIncreaseCommand allows a pool operator to + * increase an active stacking lock, issuing a "partial commitment" + * for the increased cycles. + * + * This method increases stacker's current lockup and partially + * commits the additional STX to pox-addr + * + * Constraints for running this command include: + * - The Stacker must have locked uSTX. + * - The Operator has to currently be delegated by the Stacker. + * - The increase amount must be greater than 0. + * - Stacker's unlocked uSTX amount must be greater than or equal + * to the value of the increase amount. + * - Stacker's maximum delegated amount must be greater than or equal + * to the final locked amount. + * - The Operator must have locked the Stacker's previously locked funds. + */ +export class DelegateStackIncreaseCommand implements PoxCommand { + readonly operator: Wallet; + readonly stacker: Wallet; + readonly increaseBy: bigint; + + /** + * Constructs a DelegateStackIncreaseCommand 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 + */ + constructor(operator: Wallet, stacker: Wallet, increaseBy: bigint) { + this.operator = operator; + this.stacker = stacker; + this.increaseBy = increaseBy; + } + + check(model: Readonly): boolean { + // Constraints for running this command include: + // - The Stacker must have locked uSTX. + // - The Operator has to currently be delegated by the Stacker. + // - The increase amount must be greater than 0. + // - Stacker's unlocked uSTX amount must be greater than or equal + // to the value of the increase amount. + // - Stacker's maximum delegated amount must be greater than or equal + // to the final locked amount. + // - The Operator must have locked the Stacker's previously locked funds. + + const operatorWallet = model.wallets.get(this.operator.stxAddress)!; + const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; + + return ( + stackerWallet.amountLocked > 0 && + stackerWallet.hasDelegated === true && + stackerWallet.isStacking === true && + this.increaseBy > 0 && + operatorWallet.poolMembers.includes(stackerWallet.stxAddress) && + stackerWallet.amountUnlocked >= this.increaseBy && + stackerWallet.delegatedMaxAmount >= + Number(this.increaseBy) + stackerWallet.amountLocked && + operatorWallet.hasLocked.indexOf(stackerWallet.stxAddress) > -1 + ); + } + + run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); + + const prevLocked = this.stacker.amountLocked; + const newTotalLocked = prevLocked + Number(this.increaseBy); + // 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.stacker.delegatedPoxAddress), + // (increase-by uint) + Cl.uint(this.increaseBy), + ], + this.operator.stxAddress, + ); + + // Assert + expect(delegateStackIncrease.result).toBeOk( + Cl.tuple({ + stacker: Cl.principal(this.stacker.stxAddress), + "total-locked": Cl.uint(newTotalLocked), + }), + ); + + // Get the Stacker's wallet from the model and update it with the new state. + const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; + // Update model so that we know this stacker has increased the stacked amount. + // Update locked and unlocked fields in the model. + stackerWallet.amountLocked = newTotalLocked; + stackerWallet.amountUnlocked = stackerWallet.amountUnlocked - + Number(this.increaseBy); + + // 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.operator.label} Ӿ ${this.stacker.label}`, + "delegate-stack-increase", + "increased by", + this.increaseBy.toString(), + "previously locked", + prevLocked.toString(), + "total locked", + stackerWallet.amountLocked.toString(), + ); + } + + 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}`; + } +} diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index 4da9cc6980..73096a4d42 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -142,6 +142,7 @@ export class DelegateStackStxCommand implements PoxCommand { // Get the Stacker's wallet from the model and update it with the new state. const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; + const operatorWallet = model.wallets.get(this.operator.stxAddress)!; // Update model so that we know this wallet is stacking. This is important // in order to prevent the test from stacking multiple times with the same // address. @@ -150,6 +151,10 @@ export class DelegateStackStxCommand implements PoxCommand { stackerWallet.amountLocked = Number(this.amountUstx); stackerWallet.unlockHeight = Number(unlockBurnHeight.value); stackerWallet.amountUnlocked -= Number(this.amountUstx); + // Add stacker to the operators lock list. This will help knowing that + // the stacker's funds are locked when calling delegate-stack-extend, + // delegate-stack-increase + operatorWallet.hasLocked.push(stackerWallet.stxAddress); // 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. From 8f59b980c7fcfc449fcb693199fce8a8acfee2e9 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Fri, 29 Mar 2024 17:03:02 +0200 Subject: [PATCH 031/129] fix(pox-4-tests): Remove noopReporter file --- contrib/core-contract-tests/noopReporter.ts | 26 --------------------- 1 file changed, 26 deletions(-) delete mode 100644 contrib/core-contract-tests/noopReporter.ts diff --git a/contrib/core-contract-tests/noopReporter.ts b/contrib/core-contract-tests/noopReporter.ts deleted file mode 100644 index c97206f5f1..0000000000 --- a/contrib/core-contract-tests/noopReporter.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { UserConsoleLog } from "vitest"; - -import { DefaultReporter } from "vitest/reporters"; - -export default class LoggerReporter extends DefaultReporter { - onInit() {} - onPathsCollected() {} - onCollected() {} - onFinished() { - return Promise.resolve(); - } - onTaskUpdate() {} - - onWatcherStart() { - return Promise.resolve(); - } - onWatcherRerun() { - return Promise.resolve(); - } - - onServerRestart() {} - - onProcessTimeou() {} - - onUserConsoleLog(log: UserConsoleLog) {} -} From 91d54112721671b82d318a17f7a868e0a5b0965a Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Mon, 1 Apr 2024 13:34:34 +0300 Subject: [PATCH 032/129] fix(pox-4-tests): Adjust delegate-stack-increase generator to address lock period comment https://github.com/stacks-network/stacks-core/pull/4607#discussion_r1544640858 --- .../tests/pox-4/pox_Commands.ts | 46 +++++++++++-------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 2abfd762be..0d672d9f67 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -138,26 +138,36 @@ export function PoxCommands( // DelegateStackIncreaseCommand fc.record({ operator: fc.constantFrom(...wallets.values()), - stacker: fc.constantFrom(...wallets.values()), increaseBy: fc.bigInt({ min: 0n, max: 100_000_000_000_000n }), - }).chain((r) => { - const availableStackers = r.operator.poolMembers.length > 0 - ? r.operator.poolMembers - : [r.operator.stxAddress]; + }) + .chain((r) => { + const delegatorsList = r.operator.poolMembers; - return fc.record({ - stacker: fc.constantFrom(...availableStackers), - }).map((stacker) => ({ - ...r, - stacker: wallets.get(stacker.stacker)!, - })); - }).map((final) => { - return new DelegateStackIncreaseCommand( - final.operator, - final.stacker, - final.increaseBy, - ); - }), + const availableStackers = delegatorsList.filter((delegator) => { + const delegatorWallet = wallets.get(delegator)!; + return delegatorWallet.unlockHeight > nextCycleFirstBlock(network); + }); + + const availableStackersOrFallback = availableStackers.length === 0 + ? [r.operator.stxAddress] + : availableStackers; + + return fc + .record({ + stacker: fc.constantFrom(...availableStackersOrFallback), + }) + .map((stacker) => ({ + ...r, + stacker: wallets.get(stacker.stacker)!, + })); + }) + .map((final) => { + return new DelegateStackIncreaseCommand( + final.operator, + final.stacker, + final.increaseBy, + ); + }), // AllowContractCallerCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), From 0657943439a45d6177e7210178c543cb4dc9d21c Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Mon, 1 Apr 2024 13:48:54 +0300 Subject: [PATCH 033/129] fix(pox-4-tests): Rename `haslocked` to `lockedAddresses` --- .../core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts | 2 +- contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts | 2 +- .../tests/pox-4/pox_DelegateStackIncreaseCommand.ts | 2 +- .../tests/pox-4/pox_DelegateStackStxCommand.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index f44a255351..51553de06a 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -87,7 +87,7 @@ it("statefully interacts with PoX-4", async () => { ustxBalance: initialUstxBalance, isStacking: false, hasDelegated: false, - hasLocked: [], + lockedAddresses: [], poolMembers: [], delegatedTo: "", delegatedMaxAmount: 0, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index de01266838..ef7740cff0 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -49,7 +49,7 @@ export type Wallet = { ustxBalance: number; isStacking: boolean; hasDelegated: boolean; - hasLocked: StxAddress[]; + lockedAddresses: StxAddress[]; poolMembers: StxAddress[]; delegatedTo: StxAddress; delegatedMaxAmount: number; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts index 4df9f5f752..dee49e8199 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts @@ -69,7 +69,7 @@ export class DelegateStackIncreaseCommand implements PoxCommand { stackerWallet.amountUnlocked >= this.increaseBy && stackerWallet.delegatedMaxAmount >= Number(this.increaseBy) + stackerWallet.amountLocked && - operatorWallet.hasLocked.indexOf(stackerWallet.stxAddress) > -1 + operatorWallet.lockedAddresses.indexOf(stackerWallet.stxAddress) > -1 ); } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index 73096a4d42..15eda03b31 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -154,7 +154,7 @@ export class DelegateStackStxCommand implements PoxCommand { // Add stacker to the operators lock list. This will help knowing that // the stacker's funds are locked when calling delegate-stack-extend, // delegate-stack-increase - operatorWallet.hasLocked.push(stackerWallet.stxAddress); + operatorWallet.lockedAddresses.push(stackerWallet.stxAddress); // 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. From a2f87b9b903cc374196292e0c0e65eb8a122ef3a Mon Sep 17 00:00:00 2001 From: BowTiedRadone <92028479+BowTiedRadone@users.noreply.github.com> Date: Mon, 1 Apr 2024 13:51:04 +0300 Subject: [PATCH 034/129] chore(pox-4-tests): Update `DelegateStackIncreaseCommand` documentation https://github.com/stacks-network/stacks-core/pull/4607#discussion_r1545250631 Co-authored-by: Nikos Baxevanis --- .../tests/pox-4/pox_DelegateStackIncreaseCommand.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts index dee49e8199..89ea9afbc3 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts @@ -15,7 +15,7 @@ import { Cl } from "@stacks/transactions"; * for the increased cycles. * * This method increases stacker's current lockup and partially - * commits the additional STX to pox-addr + * commits the additional STX to `pox-addr`. * * Constraints for running this command include: * - The Stacker must have locked uSTX. From 853209809ad142181b0b89ca9dd84e7b21f2f315 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Mon, 1 Apr 2024 14:15:24 +0300 Subject: [PATCH 035/129] fix(pox-4-tests): Update `increaseBy` generator from bigint to number https://github.com/stacks-network/stacks-core/pull/4607#discussion_r1545253300 --- .../core-contract-tests/tests/pox-4/pox_Commands.ts | 2 +- .../tests/pox-4/pox_DelegateStackIncreaseCommand.ts | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 0d672d9f67..9603496273 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -138,7 +138,7 @@ export function PoxCommands( // DelegateStackIncreaseCommand fc.record({ operator: fc.constantFrom(...wallets.values()), - increaseBy: fc.bigInt({ min: 0n, max: 100_000_000_000_000n }), + increaseBy: fc.nat(), }) .chain((r) => { const delegatorsList = r.operator.poolMembers; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts index 89ea9afbc3..ff8ecfb98a 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts @@ -30,7 +30,7 @@ import { Cl } from "@stacks/transactions"; export class DelegateStackIncreaseCommand implements PoxCommand { readonly operator: Wallet; readonly stacker: Wallet; - readonly increaseBy: bigint; + readonly increaseBy: number; /** * Constructs a DelegateStackIncreaseCommand to increase the uSTX amount @@ -40,7 +40,7 @@ export class DelegateStackIncreaseCommand implements PoxCommand { * @param stacker - Represents the Stacker's wallet. * @param increaseBy - Represents the locked amount to be increased by */ - constructor(operator: Wallet, stacker: Wallet, increaseBy: bigint) { + constructor(operator: Wallet, stacker: Wallet, increaseBy: number) { this.operator = operator; this.stacker = stacker; this.increaseBy = increaseBy; @@ -68,7 +68,7 @@ export class DelegateStackIncreaseCommand implements PoxCommand { operatorWallet.poolMembers.includes(stackerWallet.stxAddress) && stackerWallet.amountUnlocked >= this.increaseBy && stackerWallet.delegatedMaxAmount >= - Number(this.increaseBy) + stackerWallet.amountLocked && + this.increaseBy + stackerWallet.amountLocked && operatorWallet.lockedAddresses.indexOf(stackerWallet.stxAddress) > -1 ); } @@ -77,7 +77,7 @@ export class DelegateStackIncreaseCommand implements PoxCommand { model.trackCommandRun(this.constructor.name); const prevLocked = this.stacker.amountLocked; - const newTotalLocked = prevLocked + Number(this.increaseBy); + const newTotalLocked = prevLocked + this.increaseBy; // Act const delegateStackIncrease = real.network.callPublicFn( "ST000000000000000000002AMW42H.pox-4", @@ -107,7 +107,7 @@ export class DelegateStackIncreaseCommand implements PoxCommand { // Update locked and unlocked fields in the model. stackerWallet.amountLocked = newTotalLocked; stackerWallet.amountUnlocked = stackerWallet.amountUnlocked - - Number(this.increaseBy); + this.increaseBy; // 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. From ed447864b789381d557d875b70a2343f054ccf05 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Mon, 1 Apr 2024 19:44:33 +0300 Subject: [PATCH 036/129] test(pox-4-tests): Add DelegateStackExtendCommand --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 1 + .../tests/pox-4/pox_CommandModel.ts | 1 + .../tests/pox-4/pox_Commands.ts | 39 ++++- .../pox-4/pox_DelegateStackExtendCommand.ts | 160 ++++++++++++++++++ .../pox-4/pox_DelegateStackStxCommand.ts | 2 + 5 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index 51553de06a..4c60af0dca 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -96,6 +96,7 @@ it("statefully interacts with PoX-4", async () => { amountLocked: 0, amountUnlocked: initialUstxBalance, unlockHeight: 0, + firstLockedRewardCycle: 0, allowedContractCaller: "", callerAllowedBy: [], }; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index ef7740cff0..668de39fc3 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -58,6 +58,7 @@ export type Wallet = { amountLocked: number; amountUnlocked: number; unlockHeight: number; + firstLockedRewardCycle: number; allowedContractCaller: StxAddress; callerAllowedBy: StxAddress[]; }; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 9603496273..79a54808c6 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -10,6 +10,7 @@ import { Cl, cvToValue, OptionalCV, UIntCV } from "@stacks/transactions"; import { RevokeDelegateStxCommand } from "./pox_RevokeDelegateStxCommand"; import { AllowContractCallerCommand } from "./pox_AllowContractCallerCommand"; import { DelegateStackIncreaseCommand } from "./pox_DelegateStackIncreaseCommand"; +import { DelegateStackExtendCommand } from "./pox_DelegateStackExtendCommand"; export function PoxCommands( wallets: Map, @@ -168,6 +169,38 @@ export function PoxCommands( final.increaseBy, ); }), + // DelegateStackExtendCommand + fc.record({ + operator: fc.constantFrom(...wallets.values()), + extendCount: fc.integer({ min: 1, max: 11 }), + }).chain((r) => { + const delegatorsList = r.operator.poolMembers; + const availableStackers = delegatorsList.filter((delegator) => { + const delegatorWallet = wallets.get(delegator)!; + return delegatorWallet.unlockHeight > nextCycleFirstBlock(network); + }); + + const availableStackersOrFallback = availableStackers.length === 0 + ? [r.operator.stxAddress] + : availableStackers; + + return fc.record({ + stacker: fc.constantFrom(...availableStackersOrFallback), + currentCycle: fc.constant(currentCycle(network)), + }) + .map((additionalProps) => ({ + ...r, + stacker: wallets.get(additionalProps.stacker)!, + currentCycle: additionalProps.currentCycle, + })); + }).map((final) => + new DelegateStackExtendCommand( + final.operator, + final.stacker, + final.extendCount, + final.currentCycle, + ) + ), // AllowContractCallerCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), @@ -208,7 +241,11 @@ export function PoxCommands( return fc.commands(cmds, { size: "large" }); } -const currentCycle = (network: Simnet) => +export const REWARD_CYCLE_LENGTH = 1050; + +export const FIRST_BURNCHAIN_BLOCK_HEIGHT = 0; + +export const currentCycle = (network: Simnet) => Number(cvToValue( network.callReadOnlyFn( "ST000000000000000000002AMW42H.pox-4", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts new file mode 100644 index 0000000000..f66b42ddb4 --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts @@ -0,0 +1,160 @@ +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; +import { poxAddressToTuple } from "@stacks/stacking"; +import { assert, expect } from "vitest"; +import { + Cl, + ClarityType, + isClarityType, +} from "@stacks/transactions"; +import { + FIRST_BURNCHAIN_BLOCK_HEIGHT, + REWARD_CYCLE_LENGTH, +} from "./pox_Commands.ts"; + +/** + * The `DelegateStackExtendCommand` allows a pool operator to + * extend an active stacking lock, issuing a "partial commitment" + * for the extended-to cycles. + * + * This method extends stacker's current lockup for an additional + * extend-count and partially commits those new cycles to `pox-addr`. + * + * Constraints for running this command include: + * - Stacker must have locked uSTX. + * - The Operator has to currently be delegated by the Stacker. + * - The new lock period must be less than or equal to 12. + */ +export class DelegateStackExtendCommand implements PoxCommand { + readonly operator: Wallet; + readonly stacker: Wallet; + readonly extendCount: number; + readonly currentCycle: number; + + /** + * Constructs a `DelegateStackExtendCommand` 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 cycles to be expended. + * @param currentCycle - Represents the current PoX reward cycle. + */ + constructor( + operator: Wallet, + stacker: Wallet, + extendCount: number, + currentCycle: number, + ) { + this.operator = operator; + this.stacker = stacker; + this.extendCount = extendCount; + this.currentCycle = currentCycle; + } + + check(model: Readonly): boolean { + // Constraints for running this command include: + // - Stacker must have locked uSTX. + // - The Stacker's uSTX must have been locked by the Operator. + // - The Operator has to currently be delegated by the Stacker. + // - The new lock period must be less than or equal to 12. + + const operatorWallet = model.wallets.get(this.operator.stxAddress)!; + const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; + + const firstRewardCycle = + this.currentCycle > this.stacker.firstLockedRewardCycle + ? this.currentCycle + : this.stacker.firstLockedRewardCycle; + const firstExtendCycle = Math.floor( + (this.stacker.unlockHeight - FIRST_BURNCHAIN_BLOCK_HEIGHT) / + REWARD_CYCLE_LENGTH, + ); + const lastExtendCycle = firstExtendCycle + this.extendCount - 1; + const totalPeriod = lastExtendCycle - firstRewardCycle + 1; + + return ( + stackerWallet.amountLocked > 0 && + stackerWallet.hasDelegated === true && + stackerWallet.isStacking === true && + operatorWallet.poolMembers.includes(stackerWallet.stxAddress) && + operatorWallet.lockedAddresses.includes(stackerWallet.stxAddress) && + totalPeriod <= 12 + ); + } + + run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); + + // 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.stacker.delegatedPoxAddress), + // (extend-count uint) + Cl.uint(this.extendCount), + ], + this.operator.stxAddress, + ); + + const { result: firstExtendCycle } = real.network.callReadOnlyFn( + "ST000000000000000000002AMW42H.pox-4", + "burn-height-to-reward-cycle", + [Cl.uint(this.stacker.unlockHeight)], + this.operator.stxAddress, + ); + assert(isClarityType(firstExtendCycle, ClarityType.UInt)); + + const lastExtendCycle = Number(firstExtendCycle.value) + this.extendCount - + 1; + + const { result: extendedUnlockHeight } = real.network.callReadOnlyFn( + "ST000000000000000000002AMW42H.pox-4", + "reward-cycle-to-burn-height", + [Cl.uint(lastExtendCycle + 1)], + this.operator.stxAddress, + ); + assert(isClarityType(extendedUnlockHeight, ClarityType.UInt)); + const newUnlockHeight = extendedUnlockHeight.value; + + // Assert + expect(delegateStackExtend.result).toBeOk( + Cl.tuple({ + stacker: Cl.principal(this.stacker.stxAddress), + "unlock-burn-height": Cl.uint(newUnlockHeight), + }), + ); + + // Get the Stacker's wallet from the model and update it with the new state. + const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; + // Update model so that we know this wallet's unlock height was extended. + stackerWallet.unlockHeight = Number(newUnlockHeight); + + // 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.operator.label} Ӿ ${this.stacker.label}`, + "delegate-stack-extend", + "extend count", + this.extendCount.toString(), + "new unlock height", + this.stacker.unlockHeight.toString(), + ); + } + + 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-extend extend count ${this.extendCount} previous unlock height ${this.stacker.unlockHeight}`; + } +} diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index 15eda03b31..1005765c54 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -8,6 +8,7 @@ import { import { poxAddressToTuple } from "@stacks/stacking"; import { assert, expect } from "vitest"; import { Cl, ClarityType, isClarityType } from "@stacks/transactions"; +import { currentCycle } from "./pox_Commands.ts"; /** * The `DelegateStackStxCommand` locks STX for stacking within PoX-4 on behalf of a delegator. @@ -151,6 +152,7 @@ export class DelegateStackStxCommand implements PoxCommand { stackerWallet.amountLocked = Number(this.amountUstx); stackerWallet.unlockHeight = Number(unlockBurnHeight.value); stackerWallet.amountUnlocked -= Number(this.amountUstx); + stackerWallet.firstLockedRewardCycle = currentCycle(real.network) + 1; // Add stacker to the operators lock list. This will help knowing that // the stacker's funds are locked when calling delegate-stack-extend, // delegate-stack-increase From 43c39605f514ce72e632807918930426cd1bd1c2 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Wed, 3 Apr 2024 00:34:11 +0300 Subject: [PATCH 037/129] test(pox-4-tests): Add StackAggregationCommitCommand authorization-based --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 1 + .../tests/pox-4/pox_CommandModel.ts | 1 + .../tests/pox-4/pox_Commands.ts | 19 +++ .../pox-4/pox_DelegateStackIncreaseCommand.ts | 2 + .../pox-4/pox_DelegateStackStxCommand.ts | 1 + .../pox_StackAggregationCommitCommand.ts | 140 ++++++++++++++++++ 6 files changed, 164 insertions(+) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index 4c60af0dca..6153640165 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -88,6 +88,7 @@ it("statefully interacts with PoX-4", async () => { isStacking: false, hasDelegated: false, lockedAddresses: [], + amountToCommit: 0, poolMembers: [], delegatedTo: "", delegatedMaxAmount: 0, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 668de39fc3..ea8fcbdad0 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -50,6 +50,7 @@ export type Wallet = { isStacking: boolean; hasDelegated: boolean; lockedAddresses: StxAddress[]; + amountToCommit: number; poolMembers: StxAddress[]; delegatedTo: StxAddress; delegatedMaxAmount: number; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 79a54808c6..2dcd804012 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -11,6 +11,7 @@ import { RevokeDelegateStxCommand } from "./pox_RevokeDelegateStxCommand"; import { AllowContractCallerCommand } from "./pox_AllowContractCallerCommand"; import { DelegateStackIncreaseCommand } from "./pox_DelegateStackIncreaseCommand"; import { DelegateStackExtendCommand } from "./pox_DelegateStackExtendCommand"; +import { StackAggregationCommitCommand } from "./pox_StackAggregationCommitCommand"; export function PoxCommands( wallets: Map, @@ -74,6 +75,24 @@ export function PoxCommands( r.amount, ) ), + // StackAggregationCommitCommand + fc.record({ + wallet: fc.constantFrom(...wallets.values()), + authId: fc.nat(), + currentCycle: fc.constant(currentCycle(network)), + }).map(( + r: { + wallet: Wallet; + authId: number; + currentCycle: number; + }, + ) => + new StackAggregationCommitCommand( + r.wallet, + r.authId, + r.currentCycle, + ) + ), // RevokeDelegateStxCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts index ff8ecfb98a..23cfd63413 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts @@ -103,11 +103,13 @@ export class DelegateStackIncreaseCommand implements PoxCommand { // Get the Stacker's wallet from the model and update it with the new state. const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; + const operatorWallet = model.wallets.get(this.operator.stxAddress)! // Update model so that we know this stacker has increased the stacked amount. // Update locked and unlocked fields in the model. stackerWallet.amountLocked = newTotalLocked; stackerWallet.amountUnlocked = stackerWallet.amountUnlocked - this.increaseBy; + operatorWallet.amountToCommit += this.increaseBy // 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. diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index 1005765c54..544c869f40 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -157,6 +157,7 @@ export class DelegateStackStxCommand implements PoxCommand { // the stacker's funds are locked when calling delegate-stack-extend, // delegate-stack-increase operatorWallet.lockedAddresses.push(stackerWallet.stxAddress); + operatorWallet.amountToCommit += Number(this.amountUstx) // 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. diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitCommand.ts new file mode 100644 index 0000000000..dfa5b971fd --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitCommand.ts @@ -0,0 +1,140 @@ +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; +import { poxAddressToTuple } from "@stacks/stacking"; +import { expect } from "vitest"; +import { Cl } from "@stacks/transactions"; + +/** + * The `StackAggregationCommitCommand` allows an operator commits partially + * stacked STX and allocate a new PoX reward address slot. This allows a + * stacker to lock fewer STX than the minimal threshold in multiple transactions, + * so long as: + * 1. The pox-addr is the same. + * 2. This "commit" transaction is called _before_ the PoX anchor block. + * + * Constraints for running this command include: + * - The Operator must have locked STX on behalf of at least one stacker. + * - The total amount previously locked by the Operator on behalf of the + * stackers has to be greater than the uSTX threshold. + * - All of the Stackers must have delegated to the same pox address. + */ +export class StackAggregationCommitCommand implements PoxCommand { + readonly operator: Wallet; + readonly authId: number; + readonly currentCycle: number; + + /** + * Constructs a `StackAggregationCommitCommand` to lock uSTX for stacking. + * + * @param operator - Represents the `Operator`'s wallet. + * @param authId - Unique `auth-id` for the authorization. + * @param currentCycle - The current reward cycle. + */ + constructor( + operator: Wallet, + authId: number, + currentCycle: number, + ) { + this.operator = operator; + this.authId = authId; + this.currentCycle = currentCycle; + } + + check(model: Readonly): boolean { + // Constraints for running this command include: + // - The Operator must have locked STX on behalf of at least one stacker. + // - The total amount previously locked by the Operator on behalf of the + // stackers has to be greater than the uSTX threshold. + // - All of the Stackers must have delegated to the same pox address. + let sameDelegatedPoxAddrAllStackers = true; + const firstDelegatedPoxAddress = this.operator.lockedAddresses.length > 0 + ? model.wallets.get(this.operator.lockedAddresses[0])!.delegatedPoxAddress + : this.operator.btcAddress; + + this.operator.lockedAddresses.forEach((stacker) => { + if ( + model.wallets.get(stacker)!.delegatedPoxAddress !== + firstDelegatedPoxAddress + ) sameDelegatedPoxAddrAllStackers = false; + }); + + return this.operator.lockedAddresses.length > 0 && + this.operator.amountToCommit >= model.stackingMinimum && + sameDelegatedPoxAddrAllStackers; + } + + run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); + + const committedAmount = this.operator.amountToCommit; + + const { result: setSignature } = real.network.callPublicFn( + "ST000000000000000000002AMW42H.pox-4", + "set-signer-key-authorization", + [ + // (pox-addr (tuple (version (buff 1)) (hashbytes (buff 32)))) + poxAddressToTuple(this.operator.btcAddress), + // (period uint) + Cl.uint(1), + // (reward-cycle uint) + Cl.uint(this.currentCycle + 1), + // (topic (string-ascii 14)) + Cl.stringAscii("agg-commit"), + // (signer-key (buff 33)) + Cl.bufferFromHex(this.operator.signerPubKey), + // (allowed bool) + Cl.bool(true), + // (max-amount uint) + Cl.uint(this.operator.amountToCommit), + // (auth-id uint) + Cl.uint(this.authId), + ], + this.operator.stxAddress, + ); + expect(setSignature).toBeOk(Cl.bool(true)); + + // Act + const stackAggregationCommit = real.network.callPublicFn( + "ST000000000000000000002AMW42H.pox-4", + "stack-aggregation-commit", + [ + // (pox-addr (tuple (version (buff 1)) (hashbytes (buff 32)))) + poxAddressToTuple(this.operator.btcAddress), + // (reward-cycle uint) + Cl.uint(this.currentCycle + 1), + // (signer-sig (optional (buff 65))) + Cl.none(), + // (signer-key (buff 33)) + Cl.bufferFromHex(this.operator.signerPubKey), + // (max-amount uint) + Cl.uint(committedAmount), + // (auth-id uint) + Cl.uint(this.authId), + ], + this.operator.stxAddress, + ); + + // Assert + expect(stackAggregationCommit.result).toBeOk(Cl.bool(true)); + + const operatorWallet = model.wallets.get(this.operator.stxAddress)!; + + operatorWallet.amountToCommit -= committedAmount; + + // 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.operator.label}`, "stack-aggregation-commit", 'amount committed', committedAmount.toString()); + } + + 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}`; + } +} From f12bcc062a5f90f63c3deeacc64e011d4a9074a6 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Wed, 3 Apr 2024 13:49:26 +0300 Subject: [PATCH 038/129] test(pox-4-tests): Rename `StackAggregationCommit` to `StackAggregationCommitAuth` --- contrib/core-contract-tests/tests/pox-4/pox_Commands.ts | 6 +++--- ...tCommand.ts => pox_StackAggregationCommitAuthCommand.ts} | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) rename contrib/core-contract-tests/tests/pox-4/{pox_StackAggregationCommitCommand.ts => pox_StackAggregationCommitAuthCommand.ts} (95%) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 2dcd804012..27a644aa07 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -11,7 +11,7 @@ import { RevokeDelegateStxCommand } from "./pox_RevokeDelegateStxCommand"; import { AllowContractCallerCommand } from "./pox_AllowContractCallerCommand"; import { DelegateStackIncreaseCommand } from "./pox_DelegateStackIncreaseCommand"; import { DelegateStackExtendCommand } from "./pox_DelegateStackExtendCommand"; -import { StackAggregationCommitCommand } from "./pox_StackAggregationCommitCommand"; +import { StackAggregationCommitAuthCommand } from "./pox_StackAggregationCommitAuthCommand"; export function PoxCommands( wallets: Map, @@ -75,7 +75,7 @@ export function PoxCommands( r.amount, ) ), - // StackAggregationCommitCommand + // StackAggregationCommitAuthCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), authId: fc.nat(), @@ -87,7 +87,7 @@ export function PoxCommands( currentCycle: number; }, ) => - new StackAggregationCommitCommand( + new StackAggregationCommitAuthCommand( r.wallet, r.authId, r.currentCycle, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts similarity index 95% rename from contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitCommand.ts rename to contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts index dfa5b971fd..1b8795ca00 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts @@ -10,7 +10,7 @@ import { expect } from "vitest"; import { Cl } from "@stacks/transactions"; /** - * The `StackAggregationCommitCommand` allows an operator commits partially + * The `StackAggregationCommitAuthCommand` allows an operator commits partially * stacked STX and allocate a new PoX reward address slot. This allows a * stacker to lock fewer STX than the minimal threshold in multiple transactions, * so long as: @@ -23,13 +23,13 @@ import { Cl } from "@stacks/transactions"; * stackers has to be greater than the uSTX threshold. * - All of the Stackers must have delegated to the same pox address. */ -export class StackAggregationCommitCommand implements PoxCommand { +export class StackAggregationCommitAuthCommand implements PoxCommand { readonly operator: Wallet; readonly authId: number; readonly currentCycle: number; /** - * Constructs a `StackAggregationCommitCommand` to lock uSTX for stacking. + * Constructs a `StackAggregationCommitAuthCommand` to lock uSTX for stacking. * * @param operator - Represents the `Operator`'s wallet. * @param authId - Unique `auth-id` for the authorization. From caf62d68c8f93e03a3552885e711beb849105c4c Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Wed, 3 Apr 2024 14:18:27 +0300 Subject: [PATCH 039/129] Add StackAggregationCommitCommand signature-based --- .../tests/pox-4/pox_Commands.ts | 19 +++ .../pox_StackAggregationCommitAuthCommand.ts | 10 +- .../pox_StackAggregationCommitSigCommand.ts | 148 ++++++++++++++++++ 3 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 27a644aa07..93b6dc3c89 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -12,6 +12,7 @@ import { AllowContractCallerCommand } from "./pox_AllowContractCallerCommand"; import { DelegateStackIncreaseCommand } from "./pox_DelegateStackIncreaseCommand"; import { DelegateStackExtendCommand } from "./pox_DelegateStackExtendCommand"; import { StackAggregationCommitAuthCommand } from "./pox_StackAggregationCommitAuthCommand"; +import { StackAggregationCommitSigCommand } from "./pox_StackAggregationCommitSigCommand"; export function PoxCommands( wallets: Map, @@ -93,6 +94,24 @@ export function PoxCommands( r.currentCycle, ) ), + // StackAggregationCommitSigCommand + fc.record({ + wallet: fc.constantFrom(...wallets.values()), + authId: fc.nat(), + currentCycle: fc.constant(currentCycle(network)), + }).map(( + r: { + wallet: Wallet; + authId: number; + currentCycle: number; + }, + ) => + new StackAggregationCommitSigCommand( + r.wallet, + r.authId, + r.currentCycle, + ) + ), // RevokeDelegateStxCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts index 1b8795ca00..24bb540e23 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts @@ -17,6 +17,8 @@ import { Cl } from "@stacks/transactions"; * 1. The pox-addr is the same. * 2. This "commit" transaction is called _before_ the PoX anchor block. * + * This command calls stack-aggregation-commit using an `authorization`. + * * Constraints for running this command include: * - The Operator must have locked STX on behalf of at least one stacker. * - The total amount previously locked by the Operator on behalf of the @@ -128,7 +130,13 @@ export class StackAggregationCommitAuthCommand 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.operator.label}`, "stack-aggregation-commit", 'amount committed', committedAmount.toString()); + logCommand( + `✓ ${this.operator.label}`, + "stack-agg-commit", + "amount committed", + committedAmount.toString(), + "authorization", + ); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts new file mode 100644 index 0000000000..bf8b2e61be --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts @@ -0,0 +1,148 @@ +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; +import { Pox4SignatureTopic, poxAddressToTuple } from "@stacks/stacking"; +import { expect } from "vitest"; +import { Cl } from "@stacks/transactions"; +import { bufferFromHex } from "@stacks/transactions/dist/cl"; + +/** + * The `StackAggregationCommitSigCommand` allows an operator commits partially + * stacked STX and allocate a new PoX reward address slot. This allows a + * stacker to lock fewer STX than the minimal threshold in multiple transactions, + * so long as: + * 1. The pox-addr is the same. + * 2. This "commit" transaction is called _before_ the PoX anchor block. + * + * This command calls `stack-aggregation-commit` using an `signature`. + * + * Constraints for running this command include: + * - The Operator must have locked STX on behalf of at least one stacker. + * - The total amount previously locked by the Operator on behalf of the + * stackers has to be greater than the uSTX threshold. + * - All of the Stackers must have delegated to the same pox address. + */ +export class StackAggregationCommitSigCommand implements PoxCommand { + readonly operator: Wallet; + readonly authId: number; + readonly currentCycle: number; + + /** + * Constructs a `StackAggregationCommitSigCommand` to lock uSTX for stacking. + * + * @param operator - Represents the `Operator`'s wallet. + * @param authId - Unique `auth-id` for the authorization. + * @param currentCycle - The current reward cycle. + */ + constructor( + operator: Wallet, + authId: number, + currentCycle: number, + ) { + this.operator = operator; + this.authId = authId; + this.currentCycle = currentCycle; + } + + check(model: Readonly): boolean { + // Constraints for running this command include: + // - The Operator must have locked STX on behalf of at least one stacker. + // - The total amount previously locked by the Operator on behalf of the + // stackers has to be greater than the uSTX threshold. + // - All of the Stackers must have delegated to the same pox address. + let sameDelegatedPoxAddrAllStackers = true; + const firstDelegatedPoxAddress = this.operator.lockedAddresses.length > 0 + ? model.wallets.get(this.operator.lockedAddresses[0])!.delegatedPoxAddress + : this.operator.btcAddress; + + this.operator.lockedAddresses.forEach((stacker) => { + if ( + model.wallets.get(stacker)!.delegatedPoxAddress !== + firstDelegatedPoxAddress + ) sameDelegatedPoxAddrAllStackers = false; + }); + + return this.operator.lockedAddresses.length > 0 && + this.operator.amountToCommit >= model.stackingMinimum && + sameDelegatedPoxAddrAllStackers; + } + + run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); + + const committedAmount = this.operator.amountToCommit; + + const signerSig = this.operator.stackingClient.signPoxSignature({ + // The signer key being authorized. + signerPrivateKey: this.operator.signerPrvKey, + // The reward cycle for which the authorization is valid. + // For stack-stx and stack-extend, this refers to the reward cycle + // where the transaction is confirmed. For stack-aggregation-commit, + // this refers to the reward cycle argument in that function. + rewardCycle: this.currentCycle + 1, + // For stack-stx, this refers to lock-period. For stack-extend, + // this refers to extend-count. For stack-aggregation-commit, this is + // u1. + period: 1, + // A string representing the function where this authorization is valid. + // Either stack-stx, stack-extend, stack-increase or agg-commit. + topic: Pox4SignatureTopic.AggregateCommit, + // The PoX address that can be used with this signer key. + poxAddress: this.operator.btcAddress, + // The unique auth-id for this authorization. + authId: this.authId, + // The maximum amount of uSTX that can be used (per tx) with this signer + // key. + maxAmount: committedAmount, + }); + + // Act + const stackAggregationCommit = real.network.callPublicFn( + "ST000000000000000000002AMW42H.pox-4", + "stack-aggregation-commit", + [ + // (pox-addr (tuple (version (buff 1)) (hashbytes (buff 32)))) + poxAddressToTuple(this.operator.btcAddress), + // (reward-cycle uint) + Cl.uint(this.currentCycle + 1), + // (signer-sig (optional (buff 65))) + Cl.some(bufferFromHex(signerSig)), + // (signer-key (buff 33)) + Cl.bufferFromHex(this.operator.signerPubKey), + // (max-amount uint) + Cl.uint(committedAmount), + // (auth-id uint) + Cl.uint(this.authId), + ], + this.operator.stxAddress, + ); + + // Assert + expect(stackAggregationCommit.result).toBeOk(Cl.bool(true)); + + const operatorWallet = model.wallets.get(this.operator.stxAddress)!; + + operatorWallet.amountToCommit -= committedAmount; + + // 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.operator.label}`, + "stack-agg-commit", + "amount committed", + committedAmount.toString(), + "signature", + ); + } + + 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}`; + } +} From fdf188077d9e8a073c89343c17d11202431396ea Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Wed, 3 Apr 2024 15:18:04 +0300 Subject: [PATCH 040/129] fix(pox-4-tests): Address commands documentation comment https://github.com/stacks-network/stacks-core/pull/4628/files/852b0c5ca8b3dd7c6f91a55e464b9095fa8776d5#r1549587969 --- .../pox-4/pox_StackAggregationCommitAuthCommand.ts | 8 ++++---- .../pox-4/pox_StackAggregationCommitSigCommand.ts | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts index 24bb540e23..98c06c5bd1 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts @@ -10,10 +10,10 @@ import { expect } from "vitest"; import { Cl } from "@stacks/transactions"; /** - * The `StackAggregationCommitAuthCommand` allows an operator commits partially - * stacked STX and allocate a new PoX reward address slot. This allows a - * stacker to lock fewer STX than the minimal threshold in multiple transactions, - * so long as: + * The `StackAggregationCommitAuthCommand` allows an operator to commit + * partially stacked STX & to allocate a new PoX reward address slot. + * This allows a stacker to lock fewer STX than the minimal threshold + * in multiple transactions, so long as: * 1. The pox-addr is the same. * 2. This "commit" transaction is called _before_ the PoX anchor block. * diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts index bf8b2e61be..1fb93fa97e 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts @@ -11,14 +11,14 @@ import { Cl } from "@stacks/transactions"; import { bufferFromHex } from "@stacks/transactions/dist/cl"; /** - * The `StackAggregationCommitSigCommand` allows an operator commits partially - * stacked STX and allocate a new PoX reward address slot. This allows a - * stacker to lock fewer STX than the minimal threshold in multiple transactions, - * so long as: + * The `StackAggregationCommitSigCommand` allows an operator to commit + * partially stacked STX & to allocate a new PoX reward address slot. + * This allows a stacker to lock fewer STX than the minimal threshold + * in multiple transactions, so long as: * 1. The pox-addr is the same. * 2. This "commit" transaction is called _before_ the PoX anchor block. * - * This command calls `stack-aggregation-commit` using an `signature`. + * This command calls `stack-aggregation-commit` using a `signature`. * * Constraints for running this command include: * - The Operator must have locked STX on behalf of at least one stacker. From bb5bb99ddb637007163204cf93848c12f5600f73 Mon Sep 17 00:00:00 2001 From: BowTiedRadone <92028479+BowTiedRadone@users.noreply.github.com> Date: Wed, 3 Apr 2024 15:19:38 +0300 Subject: [PATCH 041/129] fix(pox-4-tests): Address format comment https://github.com/stacks-network/stacks-core/pull/4628/files#r1549544398 Co-authored-by: Nikos Baxevanis --- .../tests/pox-4/pox_DelegateStackIncreaseCommand.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts index 23cfd63413..eb1ee6bfe4 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts @@ -109,7 +109,7 @@ export class DelegateStackIncreaseCommand implements PoxCommand { stackerWallet.amountLocked = newTotalLocked; stackerWallet.amountUnlocked = stackerWallet.amountUnlocked - this.increaseBy; - operatorWallet.amountToCommit += this.increaseBy + operatorWallet.amountToCommit += this.increaseBy; // 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. From ed6e4fd6800850cdc63075067dc4f95aa3ec3554 Mon Sep 17 00:00:00 2001 From: BowTiedRadone <92028479+BowTiedRadone@users.noreply.github.com> Date: Wed, 3 Apr 2024 15:20:11 +0300 Subject: [PATCH 042/129] fix(pox-4-tests): Address format comment https://github.com/stacks-network/stacks-core/pull/4628/files#r1549544650 Co-authored-by: Nikos Baxevanis --- .../tests/pox-4/pox_DelegateStackStxCommand.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index 544c869f40..5b46c5443d 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -157,7 +157,7 @@ export class DelegateStackStxCommand implements PoxCommand { // the stacker's funds are locked when calling delegate-stack-extend, // delegate-stack-increase operatorWallet.lockedAddresses.push(stackerWallet.stxAddress); - operatorWallet.amountToCommit += Number(this.amountUstx) + operatorWallet.amountToCommit += Number(this.amountUstx); // 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. From 664668811417da4a2022dd20dc5e1369f99ed4f3 Mon Sep 17 00:00:00 2001 From: BowTiedRadone <92028479+BowTiedRadone@users.noreply.github.com> Date: Wed, 3 Apr 2024 15:20:33 +0300 Subject: [PATCH 043/129] fix(pox-4-tests): Address documentation comment https://github.com/stacks-network/stacks-core/pull/4628/files#r1549546009 Co-authored-by: Nikos Baxevanis --- .../tests/pox-4/pox_StackAggregationCommitAuthCommand.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts index 98c06c5bd1..8c8e85cf32 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts @@ -15,7 +15,7 @@ import { Cl } from "@stacks/transactions"; * This allows a stacker to lock fewer STX than the minimal threshold * in multiple transactions, so long as: * 1. The pox-addr is the same. - * 2. This "commit" transaction is called _before_ the PoX anchor block. + * 2. The "commit" transaction is called _before_ the PoX anchor block. * * This command calls stack-aggregation-commit using an `authorization`. * From 03e415826ef712451a3a654061f6f7ff670c321b Mon Sep 17 00:00:00 2001 From: BowTiedRadone <92028479+BowTiedRadone@users.noreply.github.com> Date: Wed, 3 Apr 2024 15:26:52 +0300 Subject: [PATCH 044/129] fix(pox-4-tests): Addres not needed new line comment https://github.com/stacks-network/stacks-core/pull/4628/files#r1549557014 Co-authored-by: Nikos Baxevanis --- .../tests/pox-4/pox_StackAggregationCommitSigCommand.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts index 1fb93fa97e..55ec09ca0d 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts @@ -125,7 +125,6 @@ export class StackAggregationCommitSigCommand implements PoxCommand { expect(stackAggregationCommit.result).toBeOk(Cl.bool(true)); const operatorWallet = model.wallets.get(this.operator.stxAddress)!; - operatorWallet.amountToCommit -= committedAmount; // Log to console for debugging purposes. This is not necessary for the From ba564dcba4e0095078f25988fde9b1a80cb11456 Mon Sep 17 00:00:00 2001 From: BowTiedRadone <92028479+BowTiedRadone@users.noreply.github.com> Date: Wed, 3 Apr 2024 15:27:31 +0300 Subject: [PATCH 045/129] fix(pox-4-tests): Address not needed new line comment https://github.com/stacks-network/stacks-core/pull/4628/files#r1549556367 Co-authored-by: Nikos Baxevanis --- .../tests/pox-4/pox_StackAggregationCommitAuthCommand.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts index 8c8e85cf32..20887862ba 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts @@ -125,7 +125,6 @@ export class StackAggregationCommitAuthCommand implements PoxCommand { expect(stackAggregationCommit.result).toBeOk(Cl.bool(true)); const operatorWallet = model.wallets.get(this.operator.stxAddress)!; - operatorWallet.amountToCommit -= committedAmount; // Log to console for debugging purposes. This is not necessary for the From fe10e3d6b49ea73a1b3ac5b37be4033a00af8937 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Wed, 3 Apr 2024 15:44:33 +0300 Subject: [PATCH 046/129] fix(pox-4-tests): Address committedAmount variable comment https://github.com/stacks-network/stacks-core/pull/4628/files#r1549622406 --- .../tests/pox-4/pox_StackAggregationCommitAuthCommand.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts index 20887862ba..76d6959499 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts @@ -92,7 +92,7 @@ export class StackAggregationCommitAuthCommand implements PoxCommand { // (allowed bool) Cl.bool(true), // (max-amount uint) - Cl.uint(this.operator.amountToCommit), + Cl.uint(committedAmount), // (auth-id uint) Cl.uint(this.authId), ], From b23cd8d2d0a4155eb196291625d83777aa42d954 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Wed, 3 Apr 2024 19:21:05 +0300 Subject: [PATCH 047/129] fix(pox-4-tests): Address same pool pox address comment - removed check that verifies all the stackers have delegated to the same PoX address - addressed comments: - https://github.com/stacks-network/stacks-core/pull/4628#discussion_r1549535566 - https://github.com/stacks-network/stacks-core/pull/4628#discussion_r1549559748 - https://github.com/stacks-network/stacks-core/pull/4628#discussion_r1549631930 --- .../pox_StackAggregationCommitAuthCommand.ts | 22 ++++--------------- .../pox_StackAggregationCommitSigCommand.ts | 22 ++++--------------- 2 files changed, 8 insertions(+), 36 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts index 76d6959499..dc80fb4270 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts @@ -10,9 +10,9 @@ import { expect } from "vitest"; import { Cl } from "@stacks/transactions"; /** - * The `StackAggregationCommitAuthCommand` allows an operator to commit - * partially stacked STX & to allocate a new PoX reward address slot. - * This allows a stacker to lock fewer STX than the minimal threshold + * The `StackAggregationCommitAuthCommand` allows an operator to commit + * partially stacked STX & to allocate a new PoX reward address slot. + * This allows a stacker to lock fewer STX than the minimal threshold * in multiple transactions, so long as: * 1. The pox-addr is the same. * 2. The "commit" transaction is called _before_ the PoX anchor block. @@ -23,7 +23,6 @@ import { Cl } from "@stacks/transactions"; * - The Operator must have locked STX on behalf of at least one stacker. * - The total amount previously locked by the Operator on behalf of the * stackers has to be greater than the uSTX threshold. - * - All of the Stackers must have delegated to the same pox address. */ export class StackAggregationCommitAuthCommand implements PoxCommand { readonly operator: Wallet; @@ -52,22 +51,9 @@ export class StackAggregationCommitAuthCommand implements PoxCommand { // - The Operator must have locked STX on behalf of at least one stacker. // - The total amount previously locked by the Operator on behalf of the // stackers has to be greater than the uSTX threshold. - // - All of the Stackers must have delegated to the same pox address. - let sameDelegatedPoxAddrAllStackers = true; - const firstDelegatedPoxAddress = this.operator.lockedAddresses.length > 0 - ? model.wallets.get(this.operator.lockedAddresses[0])!.delegatedPoxAddress - : this.operator.btcAddress; - - this.operator.lockedAddresses.forEach((stacker) => { - if ( - model.wallets.get(stacker)!.delegatedPoxAddress !== - firstDelegatedPoxAddress - ) sameDelegatedPoxAddrAllStackers = false; - }); return this.operator.lockedAddresses.length > 0 && - this.operator.amountToCommit >= model.stackingMinimum && - sameDelegatedPoxAddrAllStackers; + this.operator.amountToCommit >= model.stackingMinimum; } run(model: Stub, real: Real): void { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts index 55ec09ca0d..677b7f052e 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts @@ -11,9 +11,9 @@ import { Cl } from "@stacks/transactions"; import { bufferFromHex } from "@stacks/transactions/dist/cl"; /** - * The `StackAggregationCommitSigCommand` allows an operator to commit - * partially stacked STX & to allocate a new PoX reward address slot. - * This allows a stacker to lock fewer STX than the minimal threshold + * The `StackAggregationCommitSigCommand` allows an operator to commit + * partially stacked STX & to allocate a new PoX reward address slot. + * This allows a stacker to lock fewer STX than the minimal threshold * in multiple transactions, so long as: * 1. The pox-addr is the same. * 2. This "commit" transaction is called _before_ the PoX anchor block. @@ -24,7 +24,6 @@ import { bufferFromHex } from "@stacks/transactions/dist/cl"; * - The Operator must have locked STX on behalf of at least one stacker. * - The total amount previously locked by the Operator on behalf of the * stackers has to be greater than the uSTX threshold. - * - All of the Stackers must have delegated to the same pox address. */ export class StackAggregationCommitSigCommand implements PoxCommand { readonly operator: Wallet; @@ -53,22 +52,9 @@ export class StackAggregationCommitSigCommand implements PoxCommand { // - The Operator must have locked STX on behalf of at least one stacker. // - The total amount previously locked by the Operator on behalf of the // stackers has to be greater than the uSTX threshold. - // - All of the Stackers must have delegated to the same pox address. - let sameDelegatedPoxAddrAllStackers = true; - const firstDelegatedPoxAddress = this.operator.lockedAddresses.length > 0 - ? model.wallets.get(this.operator.lockedAddresses[0])!.delegatedPoxAddress - : this.operator.btcAddress; - - this.operator.lockedAddresses.forEach((stacker) => { - if ( - model.wallets.get(stacker)!.delegatedPoxAddress !== - firstDelegatedPoxAddress - ) sameDelegatedPoxAddrAllStackers = false; - }); return this.operator.lockedAddresses.length > 0 && - this.operator.amountToCommit >= model.stackingMinimum && - sameDelegatedPoxAddrAllStackers; + this.operator.amountToCommit >= model.stackingMinimum; } run(model: Stub, real: Real): void { From 79893f504d6ea1e6db98b6fbd338e1935512f37d Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Thu, 4 Apr 2024 18:21:58 +0300 Subject: [PATCH 048/129] test(pox-4-tests): Add `StackAggregationCommitIndexedCommand` signature-based --- .../tests/pox-4/pox_CommandModel.ts | 2 + .../tests/pox-4/pox_Commands.ts | 19 +++ .../pox_StackAggregationCommitAuthCommand.ts | 1 + ...StackAggregationCommitIndexedSigCommand.ts | 138 ++++++++++++++++++ .../pox_StackAggregationCommitSigCommand.ts | 1 + .../tests/pox-4/pox_StackStxCommand.ts | 1 + 6 files changed, 162 insertions(+) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index ea8fcbdad0..aed279dba4 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -12,6 +12,7 @@ export class Stub { readonly wallets: Map; readonly statistics: Map; stackingMinimum: number; + nextRewardSetIndex: number constructor( wallets: Map, @@ -20,6 +21,7 @@ export class Stub { this.wallets = wallets; this.statistics = statistics; this.stackingMinimum = 0; + this.nextRewardSetIndex = 0; } trackCommandRun(commandName: string) { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 93b6dc3c89..2c6385f7f2 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -13,6 +13,7 @@ import { DelegateStackIncreaseCommand } from "./pox_DelegateStackIncreaseCommand import { DelegateStackExtendCommand } from "./pox_DelegateStackExtendCommand"; import { StackAggregationCommitAuthCommand } from "./pox_StackAggregationCommitAuthCommand"; import { StackAggregationCommitSigCommand } from "./pox_StackAggregationCommitSigCommand"; +import { StackAggregationCommitIndexedSigCommand } from "./pox_StackAggregationCommitIndexedSigCommand"; export function PoxCommands( wallets: Map, @@ -112,6 +113,24 @@ export function PoxCommands( r.currentCycle, ) ), + // StackAggregationCommitIndexedSigCommand + fc.record({ + wallet: fc.constantFrom(...wallets.values()), + authId: fc.nat(), + currentCycle: fc.constant(currentCycle(network)), + }).map(( + r: { + wallet: Wallet; + authId: number; + currentCycle: number; + }, + ) => + new StackAggregationCommitIndexedSigCommand( + r.wallet, + r.authId, + r.currentCycle, + ) + ), // RevokeDelegateStxCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts index dc80fb4270..289b6c03ca 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts @@ -112,6 +112,7 @@ export class StackAggregationCommitAuthCommand implements PoxCommand { const operatorWallet = model.wallets.get(this.operator.stxAddress)!; operatorWallet.amountToCommit -= committedAmount; + model.nextRewardSetIndex++; // 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. diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts new file mode 100644 index 0000000000..673625f301 --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts @@ -0,0 +1,138 @@ +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; +import { Pox4SignatureTopic, poxAddressToTuple } from "@stacks/stacking"; +import { expect } from "vitest"; +import { Cl } from "@stacks/transactions"; +import { bufferFromHex } from "@stacks/transactions/dist/cl"; + +/** + * The `StackAggregationCommitIndexedSigCommand` allows an operator to + * commit partially stacked STX & to allocate a new PoX reward address + * slot. + * This allows a stacker to lock fewer STX than the minimal threshold + * in multiple transactions, so long as: + * 1. The pox-addr is the same. + * 2. The "commit" transaction is called _before_ the PoX anchor block. + * + * This command calls `stack-aggregation-commit-indexed` using a + * `signature`. + * + * Constraints for running this command include: + * - The Operator must have locked STX on behalf of at least one stacker. + * - The total amount previously locked by the Operator on behalf of the + * stackers has to be greater than the uSTX threshold. + */ +export class StackAggregationCommitIndexedSigCommand implements PoxCommand { + readonly operator: Wallet; + readonly authId: number; + readonly currentCycle: number; + + /** + * Constructs a `StackAggregationCommitIndexedSigCommand` to lock uSTX + * for stacking. + * + * @param operator - Represents the `Operator`'s wallet. + * @param authId - Unique `auth-id` for the authorization. + * @param currentCycle - The current reward cycle. + */ + constructor(operator: Wallet, authId: number, currentCycle: number) { + this.operator = operator; + this.authId = authId; + this.currentCycle = currentCycle; + } + + check(model: Readonly): boolean { + // Constraints for running this command include: + // - The Operator must have locked STX on behalf of at least one stacker. + // - The total amount previously locked by the Operator on behalf of the + // stackers has to be greater than the uSTX threshold. + + return ( + this.operator.lockedAddresses.length > 0 && + this.operator.amountToCommit >= model.stackingMinimum + ); + } + + run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); + + const committedAmount = this.operator.amountToCommit; + + const signerSig = this.operator.stackingClient.signPoxSignature({ + // The signer key being authorized. + signerPrivateKey: this.operator.signerPrvKey, + // The reward cycle for which the authorization is valid. + // For stack-stx and stack-extend, this refers to the reward cycle + // where the transaction is confirmed. For stack-aggregation-commit, + // this refers to the reward cycle argument in that function. + rewardCycle: this.currentCycle + 1, + // For stack-stx, this refers to lock-period. For stack-extend, + // this refers to extend-count. For stack-aggregation-commit, this is + // u1. + period: 1, + // A string representing the function where this authorization is valid. + // Either stack-stx, stack-extend, stack-increase or agg-commit. + topic: Pox4SignatureTopic.AggregateCommit, + // The PoX address that can be used with this signer key. + poxAddress: this.operator.btcAddress, + // The unique auth-id for this authorization. + authId: this.authId, + // The maximum amount of uSTX that can be used (per tx) with this signer + // key. + maxAmount: committedAmount, + }); + + // Act + const stackAggregationCommitIndexed = real.network.callPublicFn( + "ST000000000000000000002AMW42H.pox-4", + "stack-aggregation-commit-indexed", + [ + // (pox-addr (tuple (version (buff 1)) (hashbytes (buff 32)))) + poxAddressToTuple(this.operator.btcAddress), + // (reward-cycle uint) + Cl.uint(this.currentCycle + 1), + // (signer-sig (optional (buff 65))) + Cl.some(bufferFromHex(signerSig)), + // (signer-key (buff 33)) + Cl.bufferFromHex(this.operator.signerPubKey), + // (max-amount uint) + Cl.uint(committedAmount), + // (auth-id uint) + Cl.uint(this.authId), + ], + this.operator.stxAddress, + ); + + // Assert + expect(stackAggregationCommitIndexed.result).toBeOk( + Cl.uint(model.nextRewardSetIndex), + ); + + // Update the model + const operatorWallet = model.wallets.get(this.operator.stxAddress)!; + operatorWallet.amountToCommit -= committedAmount; + model.nextRewardSetIndex++; + + // 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.operator.label}`, + "stack-agg-commit-indexed", + "amount committed", + committedAmount.toString(), + "signature", + ); + } + + 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}`; + } +} diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts index 677b7f052e..ed7b99447d 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts @@ -112,6 +112,7 @@ export class StackAggregationCommitSigCommand implements PoxCommand { const operatorWallet = model.wallets.get(this.operator.stxAddress)!; operatorWallet.amountToCommit -= committedAmount; + model.nextRewardSetIndex++; // 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. diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index cbdb782dc9..205704f978 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -162,6 +162,7 @@ export class StackStxCommand implements PoxCommand { wallet.amountLocked = amountUstx; wallet.unlockHeight = Number(unlockBurnHeight.value); wallet.amountUnlocked -= amountUstx; + model.nextRewardSetIndex++; // 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. From b726a24ff9499e836f04546b9598d92fdca5a74f Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Thu, 4 Apr 2024 18:36:04 +0300 Subject: [PATCH 049/129] test(pox-4-tests): Add `StackAggregationCommitIndexedCommand` authorization-based --- .../tests/pox-4/pox_Commands.ts | 19 +++ ...tackAggregationCommitIndexedAuthCommand.ts | 138 ++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 2c6385f7f2..238538f08c 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -14,6 +14,7 @@ import { DelegateStackExtendCommand } from "./pox_DelegateStackExtendCommand"; import { StackAggregationCommitAuthCommand } from "./pox_StackAggregationCommitAuthCommand"; import { StackAggregationCommitSigCommand } from "./pox_StackAggregationCommitSigCommand"; import { StackAggregationCommitIndexedSigCommand } from "./pox_StackAggregationCommitIndexedSigCommand"; +import { StackAggregationCommitIndexedAuthCommand } from "./pox_StackAggregationCommitIndexedAuthCommand"; export function PoxCommands( wallets: Map, @@ -113,6 +114,24 @@ export function PoxCommands( r.currentCycle, ) ), + // StackAggregationCommitIndexedAuthCommand + fc.record({ + wallet: fc.constantFrom(...wallets.values()), + authId: fc.nat(), + currentCycle: fc.constant(currentCycle(network)), + }).map(( + r: { + wallet: Wallet; + authId: number; + currentCycle: number; + }, + ) => + new StackAggregationCommitIndexedAuthCommand( + r.wallet, + r.authId, + r.currentCycle, + ) + ), // StackAggregationCommitIndexedSigCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts new file mode 100644 index 0000000000..f33b509fcd --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts @@ -0,0 +1,138 @@ +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; +import { poxAddressToTuple } from "@stacks/stacking"; +import { expect } from "vitest"; +import { Cl } from "@stacks/transactions"; + +/** + * The `StackAggregationCommitIndexedAuthCommand` allows an operator to + * commit partially stacked STX & to allocate a new PoX reward address + * slot. + * This allows a stacker to lock fewer STX than the minimal threshold + * in multiple transactions, so long as: + * 1. The pox-addr is the same. + * 2. The "commit" transaction is called _before_ the PoX anchor block. + * + * This command calls `stack-aggregation-commit-indexed` using an + * `authorization`. + * + * Constraints for running this command include: + * - The Operator must have locked STX on behalf of at least one stacker. + * - The total amount previously locked by the Operator on behalf of the + * stackers has to be greater than the uSTX threshold. + */ +export class StackAggregationCommitIndexedAuthCommand implements PoxCommand { + readonly operator: Wallet; + readonly authId: number; + readonly currentCycle: number; + + /** + * Constructs a `StackAggregationCommitIndexedAuthCommand` to lock uSTX + * for stacking. + * + * @param operator - Represents the `Operator`'s wallet. + * @param authId - Unique `auth-id` for the authorization. + * @param currentCycle - The current reward cycle. + */ + constructor(operator: Wallet, authId: number, currentCycle: number) { + this.operator = operator; + this.authId = authId; + this.currentCycle = currentCycle; + } + + check(model: Readonly): boolean { + // Constraints for running this command include: + // - The Operator must have locked STX on behalf of at least one stacker. + // - The total amount previously locked by the Operator on behalf of the + // stackers has to be greater than the uSTX threshold. + + return ( + this.operator.lockedAddresses.length > 0 && + this.operator.amountToCommit >= model.stackingMinimum + ); + } + + run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); + + const committedAmount = this.operator.amountToCommit; + + const { result: setSignature } = real.network.callPublicFn( + "ST000000000000000000002AMW42H.pox-4", + "set-signer-key-authorization", + [ + // (pox-addr (tuple (version (buff 1)) (hashbytes (buff 32)))) + poxAddressToTuple(this.operator.btcAddress), + // (period uint) + Cl.uint(1), + // (reward-cycle uint) + Cl.uint(this.currentCycle + 1), + // (topic (string-ascii 14)) + Cl.stringAscii("agg-commit"), + // (signer-key (buff 33)) + Cl.bufferFromHex(this.operator.signerPubKey), + // (allowed bool) + Cl.bool(true), + // (max-amount uint) + Cl.uint(committedAmount), + // (auth-id uint) + Cl.uint(this.authId), + ], + this.operator.stxAddress, + ); + expect(setSignature).toBeOk(Cl.bool(true)); + + // Act + const stackAggregationCommitIndexed = real.network.callPublicFn( + "ST000000000000000000002AMW42H.pox-4", + "stack-aggregation-commit-indexed", + [ + // (pox-addr (tuple (version (buff 1)) (hashbytes (buff 32)))) + poxAddressToTuple(this.operator.btcAddress), + // (reward-cycle uint) + Cl.uint(this.currentCycle + 1), + // (signer-sig (optional (buff 65))) + Cl.none(), + // (signer-key (buff 33)) + Cl.bufferFromHex(this.operator.signerPubKey), + // (max-amount uint) + Cl.uint(committedAmount), + // (auth-id uint) + Cl.uint(this.authId), + ], + this.operator.stxAddress, + ); + + // Assert + expect(stackAggregationCommitIndexed.result).toBeOk( + Cl.uint(model.nextRewardSetIndex), + ); + + // Update the model + const operatorWallet = model.wallets.get(this.operator.stxAddress)!; + operatorWallet.amountToCommit -= committedAmount; + model.nextRewardSetIndex++; + + // 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.operator.label}`, + "stack-agg-commit-indexed", + "amount committed", + committedAmount.toString(), + "authorization", + ); + } + + 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}`; + } +} From 04be682c9bfb6dbb1f16064a334e6a40628d87b5 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Thu, 4 Apr 2024 18:39:18 +0300 Subject: [PATCH 050/129] chore(pox-4-tests): Update stdout logging to console.log --- contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index aed279dba4..1630f3e617 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -30,9 +30,9 @@ export class Stub { } reportCommandRuns() { - process.stdout.write("Command run method execution counts:"); + console.log("Command run method execution counts:"); this.statistics.forEach((count, commandName) => { - process.stdout.write(`\n${commandName}: ${count}`); + console.log(`${commandName}: ${count}`); }); } } From fb48e073e3b5a44aabe32d42f92320e54c19e335 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Sun, 7 Apr 2024 16:25:22 +0300 Subject: [PATCH 051/129] test(pox-4-tests): Add `StackAggregationIncreaseCommand` Adding the `StackAggregationIncreaseCommand` is currently causing the tests to fail. To investigate: - this may be a PoX-4 bug - this may be a command implementation issue --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 1 + .../tests/pox-4/pox_CommandModel.ts | 1 + .../tests/pox-4/pox_Commands.ts | 28 +++++ .../pox_StackAggregationCommitAuthCommand.ts | 1 + ...tackAggregationCommitIndexedAuthCommand.ts | 1 + ...StackAggregationCommitIndexedSigCommand.ts | 1 + .../pox_StackAggregationCommitSigCommand.ts | 1 + .../pox_StackAggregationIncreaseCommand.ts | 109 ++++++++++++++++++ 8 files changed, 143 insertions(+) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index 6153640165..6935d35cf6 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -100,6 +100,7 @@ it("statefully interacts with PoX-4", async () => { firstLockedRewardCycle: 0, allowedContractCaller: "", callerAllowedBy: [], + committedRewCycleIndexes: [], }; }); diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 1630f3e617..91f68e68b0 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -64,6 +64,7 @@ export type Wallet = { firstLockedRewardCycle: number; allowedContractCaller: StxAddress; callerAllowedBy: StxAddress[]; + committedRewCycleIndexes: number[]; }; export type PoxCommand = fc.Command; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 238538f08c..81f3967b24 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -15,6 +15,7 @@ import { StackAggregationCommitAuthCommand } from "./pox_StackAggregationCommitA import { StackAggregationCommitSigCommand } from "./pox_StackAggregationCommitSigCommand"; import { StackAggregationCommitIndexedSigCommand } from "./pox_StackAggregationCommitIndexedSigCommand"; import { StackAggregationCommitIndexedAuthCommand } from "./pox_StackAggregationCommitIndexedAuthCommand"; +import { StackAggregationIncreaseCommand } from "./pox_StackAggregationIncreaseCommand"; export function PoxCommands( wallets: Map, @@ -150,6 +151,33 @@ export function PoxCommands( r.currentCycle, ) ), + // StackAggregationIncreaseCommand + fc.record({ + wallet: fc.constantFrom(...wallets.values()), + currentCycle: fc.constant(currentCycle(network)), + }).chain((r) => { + const committedRewCycleIndexesOrFallback = + r.wallet.committedRewCycleIndexes.length > 0 + ? r.wallet.committedRewCycleIndexes + : [-1]; + return fc.record({ + rewardCycleIndex: fc.constantFrom( + ...committedRewCycleIndexesOrFallback, + ), + }).map((cycleIndex) => ({ ...r, ...cycleIndex })); + }).map(( + r: { + wallet: Wallet; + currentCycle: number; + rewardCycleIndex: number; + }, + ) => + new StackAggregationIncreaseCommand( + r.wallet, + r.currentCycle, + r.rewardCycleIndex, + ) + ), // RevokeDelegateStxCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts index 289b6c03ca..22544274cb 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts @@ -112,6 +112,7 @@ export class StackAggregationCommitAuthCommand implements PoxCommand { const operatorWallet = model.wallets.get(this.operator.stxAddress)!; operatorWallet.amountToCommit -= committedAmount; + operatorWallet.committedRewCycleIndexes.push(model.nextRewardSetIndex); model.nextRewardSetIndex++; // Log to console for debugging purposes. This is not necessary for the diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts index f33b509fcd..54e4639d7e 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts @@ -116,6 +116,7 @@ export class StackAggregationCommitIndexedAuthCommand implements PoxCommand { // Update the model const operatorWallet = model.wallets.get(this.operator.stxAddress)!; operatorWallet.amountToCommit -= committedAmount; + operatorWallet.committedRewCycleIndexes.push(model.nextRewardSetIndex); model.nextRewardSetIndex++; // Log to console for debugging purposes. This is not necessary for the diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts index 673625f301..3ee837852f 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts @@ -116,6 +116,7 @@ export class StackAggregationCommitIndexedSigCommand implements PoxCommand { // Update the model const operatorWallet = model.wallets.get(this.operator.stxAddress)!; operatorWallet.amountToCommit -= committedAmount; + operatorWallet.committedRewCycleIndexes.push(model.nextRewardSetIndex); model.nextRewardSetIndex++; // Log to console for debugging purposes. This is not necessary for the diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts index ed7b99447d..e1bf233644 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts @@ -112,6 +112,7 @@ export class StackAggregationCommitSigCommand implements PoxCommand { const operatorWallet = model.wallets.get(this.operator.stxAddress)!; operatorWallet.amountToCommit -= committedAmount; + operatorWallet.committedRewCycleIndexes.push(model.nextRewardSetIndex); model.nextRewardSetIndex++; // Log to console for debugging purposes. This is not necessary for the diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts new file mode 100644 index 0000000000..e15ac26c5d --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts @@ -0,0 +1,109 @@ +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; +import { poxAddressToTuple } from "@stacks/stacking"; +import { expect } from "vitest"; +import { Cl } from "@stacks/transactions"; + +/** + * The `StackAggregationIncreaseCommand` allows an operator to commit + * partially stacked STX to a PoX address which has already received + * some STX (more than the `stacking minimum`). + * This allows a delegator to lock up marginally more STX from new + * delegates, even if they collectively do not exceed the Stacking + * minimum, so long as the target PoX address already represents at + * least as many STX as the `stacking minimum`. + * This command calls stack-aggregation-increase. + * + * Constraints for running this command include: + * - The Operator must have locked STX on behalf of at least one stacker. + * - The PoX address must have partial committed STX. + * - The Reward Cycle Index must be positive. + */ +export class StackAggregationIncreaseCommand implements PoxCommand { + readonly operator: Wallet; + readonly currentCycle: number; + readonly rewardCycleIndex: number; + + /** + * Constructs a `StackAggregationIncreaseCommand` to commit partially + * stacked STX to a PoX address which has already received some STX. + * + * @param operator - Represents the `Operator`'s wallet. + * @param currentCycle - The current reward cycle. + * @param rewardCycleIndex - The cycle index to increase the commit for. + */ + constructor( + operator: Wallet, + currentCycle: number, + rewardCycleIndex: number, + ) { + this.operator = operator; + this.currentCycle = currentCycle; + this.rewardCycleIndex = rewardCycleIndex; + } + + check(_model: Readonly): boolean { + // Constraints for running this command include: + // - The Operator must have locked STX on behalf of at least one stacker. + // - The PoX address must have partial committed STX. + // - The Reward Cycle Index must be positive. + + return ( + this.operator.lockedAddresses.length > 0 && + this.rewardCycleIndex >= 0 && + this.operator.amountToCommit > 0 + ); + } + + run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); + + const committedAmount = this.operator.amountToCommit; + + // Act + const stackAggregationIncrease = real.network.callPublicFn( + "ST000000000000000000002AMW42H.pox-4", + "stack-aggregation-increase", + [ + // (pox-addr { version: (buff 1), hashbytes: (buff 32) }) + poxAddressToTuple(this.operator.btcAddress), + // (reward-cycle uint) + Cl.uint(this.currentCycle + 1), + // (reward-cycle-index uint)) + Cl.uint(this.rewardCycleIndex), + ], + this.operator.stxAddress, + ); + + // Assert + expect(stackAggregationIncrease.result).toBeOk(Cl.bool(true)); + + const operatorWallet = model.wallets.get(this.operator.stxAddress)!; + operatorWallet.amountToCommit -= committedAmount; + + // 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.operator.label}`, + "stack-agg-increase", + "amount committed", + committedAmount.toString(), + "cycle index", + this.rewardCycleIndex.toString(), + ); + } + + 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-increase for reward cycle ${ + this.currentCycle + 1 + } index ${this.rewardCycleIndex}`; + } +} \ No newline at end of file From e0493305c485393ddc3ada036a5057d1b5fb4b11 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Mon, 8 Apr 2024 23:52:15 +0300 Subject: [PATCH 052/129] test(pox-4-tests): Add `DisallowContractCallerCommand` --- .../tests/pox-4/pox_Commands.ts | 15 +++ .../pox_DisallowContractCallerCommand.ts | 98 +++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 81f3967b24..0faa84c32c 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -16,6 +16,7 @@ import { StackAggregationCommitSigCommand } from "./pox_StackAggregationCommitSi import { StackAggregationCommitIndexedSigCommand } from "./pox_StackAggregationCommitIndexedSigCommand"; import { StackAggregationCommitIndexedAuthCommand } from "./pox_StackAggregationCommitIndexedAuthCommand"; import { StackAggregationIncreaseCommand } from "./pox_StackAggregationIncreaseCommand"; +import { DisallowContractCallerCommand } from "./pox_DisallowContractCallerCommand"; export function PoxCommands( wallets: Map, @@ -326,6 +327,20 @@ export function PoxCommands( r.alllowUntilBurnHt, ), ), + // DisallowContractCallerCommand + fc.record({ + stacker: fc.constantFrom(...wallets.values()), + callerToDisallow: fc.constantFrom(...wallets.values()), + }).map( + (r: { + stacker: Wallet; + callerToDisallow: Wallet; + }) => + new DisallowContractCallerCommand( + r.stacker, + r.callerToDisallow, + ), + ), // GetStxAccountCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts new file mode 100644 index 0000000000..9216f1eb2e --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts @@ -0,0 +1,98 @@ +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; +import { expect } from "vitest"; +import { boolCV, Cl } from "@stacks/transactions"; + +/** + * The `DisallowContractCallerComand` revokes a `contract-caller`'s + * authorization to call stacking methods. + * + * Constraints for running this command include: + * - The Caller to be disallowed must have been previously + * allowed by the Operator. + */ +export class DisallowContractCallerCommand implements PoxCommand { + readonly stacker: Wallet; + readonly callerToDisallow: Wallet; + + /** + * Constructs a `DisallowContractCallerComand` to revoke authorization + * for calling stacking methods. + * + * @param stacker - Represents the `Stacker`'s wallet. + * @param callerToDisallow - The `contract-caller` to be revoked. + */ + + constructor(stacker: Wallet, callerToDisallow: Wallet) { + this.stacker = stacker; + this.callerToDisallow = callerToDisallow; + } + + check(_model: Readonly): boolean { + // Constraints for running this command include: + // - The Caller to be disallowed must have been previously + // allowed by the Operator. + + return ( + this.stacker.allowedContractCaller === this.callerToDisallow.stxAddress && + this.callerToDisallow.callerAllowedBy.includes(this.stacker.stxAddress) === + true + ); + } + + run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); + + // Act + const disallowContractCaller = real.network.callPublicFn( + "ST000000000000000000002AMW42H.pox-4", + "disallow-contract-caller", + [ + // (caller principal) + Cl.principal(this.callerToDisallow.stxAddress), + ], + this.stacker.stxAddress, + ); + + // Assert + expect(disallowContractCaller.result).toBeOk(boolCV(true)); + + // Get the wallet to be revoked stacking rights from the model and + // update it with the new state. + const callerToDisallow = model.wallets.get( + this.callerToDisallow.stxAddress, + )!; + + // Update model so that we know that the stacker has revoked stacking + // allowance. + this.stacker.allowedContractCaller = ""; + + // Remove the operator from the caller to disallow's allowance list. + const walletIndexAllowedByList = callerToDisallow.callerAllowedBy.indexOf( + this.stacker.stxAddress, + ); + + expect(walletIndexAllowedByList).toBeGreaterThan(-1); + callerToDisallow.callerAllowedBy.splice(walletIndexAllowedByList, 1); + + // 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.stacker.label}`, + "disallow-contract-caller", + this.callerToDisallow.label, + ); + } + + 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.stacker.label} disallow-contract-caller ${this.callerToDisallow.label}`; + } +} From b75cb1e93b04df5b11e6cb6ed4db07ae5963a0f4 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Wed, 10 Apr 2024 18:24:47 +0300 Subject: [PATCH 053/129] fix(pox-4-tests): Refresh the model's state if the network gets to the next reward cycle --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 37 ++++++------ .../pox-4/pox_AllowContractCallerCommand.ts | 3 + .../tests/pox-4/pox_CommandModel.ts | 57 ++++++++++++++++++- .../tests/pox-4/pox_Commands.ts | 2 +- .../pox-4/pox_DelegateStackExtendCommand.ts | 3 + .../pox-4/pox_DelegateStackIncreaseCommand.ts | 3 + .../pox-4/pox_DelegateStackStxCommand.ts | 3 + .../tests/pox-4/pox_DelegateStxCommand.ts | 3 + .../pox_DisallowContractCallerCommand.ts | 3 + .../pox-4/pox_GetStackingMinimumCommand.ts | 3 + .../tests/pox-4/pox_GetStxAccountCommand.ts | 3 + .../pox-4/pox_RevokeDelegateStxCommand.ts | 3 + .../pox_StackAggregationCommitAuthCommand.ts | 7 ++- ...tackAggregationCommitIndexedAuthCommand.ts | 7 ++- ...StackAggregationCommitIndexedSigCommand.ts | 7 ++- .../pox_StackAggregationCommitSigCommand.ts | 7 ++- .../pox_StackAggregationIncreaseCommand.ts | 3 + .../tests/pox-4/pox_StackStxCommand.ts | 3 + 18 files changed, 133 insertions(+), 24 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index 6935d35cf6..eb34174c1d 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -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(); }); diff --git a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts index 13283af8a9..9682d286b4 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts @@ -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() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 91f68e68b0..e20bb4980b 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -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; readonly statistics: Map; stackingMinimum: number; - nextRewardSetIndex: number + nextRewardSetIndex: number; + lastRefreshedCycle: number; constructor( wallets: Map, @@ -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 = { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 0faa84c32c..bb1fc38cd5 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -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; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts index f66b42ddb4..0ec241a272 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts @@ -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() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts index eb1ee6bfe4..75f504b75e 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts @@ -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() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index 5b46c5443d..baaaad23ca 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -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() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts index 6de496d375..f94259d0b8 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts @@ -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() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts index 9216f1eb2e..1a90bd59f2 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts @@ -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() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts index c5a84e6a3d..173a722425 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts @@ -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() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts index 71cf99207c..aee09dd5b7 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts @@ -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() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts index 5ada55932d..68528fb492 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts @@ -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() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts index 22544274cb..698e36c74c 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts @@ -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 + }`; } } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts index 54e4639d7e..d84da451e2 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts @@ -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 + }`; } } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts index 3ee837852f..0fb6f36759 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts @@ -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 + }`; } } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts index e1bf233644..8e0f2d8f82 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts @@ -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 + }`; } } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts index e15ac26c5d..e56c733f53 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts @@ -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() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index 205704f978..4bd04b4ee5 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -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() { From c7b31f53d33a3a4d9ceb08c1ab94ec102a4329c2 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Thu, 11 Apr 2024 18:10:38 +0200 Subject: [PATCH 054/129] refactor(pox-4-tests): Rename stateRefresh to refreshStateForNextRewardCycle Rename `stateRefresh` to `refreshStateForNextRewardCycle` to more explicitly indicate its function of updating the model's state upon transitioning to the next reward cycle. --- .../tests/pox-4/pox_AllowContractCallerCommand.ts | 2 +- contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts | 2 +- .../tests/pox-4/pox_DelegateStackExtendCommand.ts | 2 +- .../tests/pox-4/pox_DelegateStackIncreaseCommand.ts | 2 +- .../tests/pox-4/pox_DelegateStackStxCommand.ts | 2 +- .../core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts | 2 +- .../tests/pox-4/pox_DisallowContractCallerCommand.ts | 2 +- .../tests/pox-4/pox_GetStackingMinimumCommand.ts | 2 +- .../core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts | 2 +- .../tests/pox-4/pox_RevokeDelegateStxCommand.ts | 2 +- .../tests/pox-4/pox_StackAggregationCommitAuthCommand.ts | 2 +- .../tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts | 2 +- .../tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts | 2 +- .../tests/pox-4/pox_StackAggregationCommitSigCommand.ts | 2 +- .../tests/pox-4/pox_StackAggregationIncreaseCommand.ts | 2 +- contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts index 9682d286b4..abb9936568 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts @@ -87,7 +87,7 @@ export class AllowContractCallerCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index e20bb4980b..80e8e28341 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -42,7 +42,7 @@ export class Stub { }); } - stateRefresh(real: Real) { + refreshStateForNextRewardCycle(real: Real) { const burnBlockHeightResult = real.network.runSnippet("burn-block-height"); const burnBlockHeight = cvToValue(burnBlockHeightResult as ClarityValue); const lastRefreshedCycle = this.lastRefreshedCycle; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts index 0ec241a272..5e4a536064 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts @@ -151,7 +151,7 @@ export class DelegateStackExtendCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts index 75f504b75e..92ec5d9e9a 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts @@ -125,7 +125,7 @@ export class DelegateStackIncreaseCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index baaaad23ca..7b09a8e6da 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -171,7 +171,7 @@ export class DelegateStackStxCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts index f94259d0b8..f6cfbfeb66 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts @@ -108,7 +108,7 @@ export class DelegateStxCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts index 1a90bd59f2..b1c99109be 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts @@ -89,7 +89,7 @@ export class DisallowContractCallerCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts index 173a722425..b05923ef1f 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts @@ -57,7 +57,7 @@ export class GetStackingMinimumCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts index aee09dd5b7..8610bc1050 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts @@ -56,7 +56,7 @@ export class GetStxAccountCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts index 68528fb492..605d461da9 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts @@ -87,7 +87,7 @@ export class RevokeDelegateStxCommand implements PoxCommand { logCommand(`✓ ${this.wallet.label}`, "revoke-delegate-stx"); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts index 698e36c74c..afe3be8dff 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts @@ -126,7 +126,7 @@ export class StackAggregationCommitAuthCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts index d84da451e2..6b7ba47b68 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts @@ -130,7 +130,7 @@ export class StackAggregationCommitIndexedAuthCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts index 0fb6f36759..56456ac3ef 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts @@ -130,7 +130,7 @@ export class StackAggregationCommitIndexedSigCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts index 8e0f2d8f82..390ae23603 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts @@ -126,7 +126,7 @@ export class StackAggregationCommitSigCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts index e56c733f53..7b3c21d863 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts @@ -98,7 +98,7 @@ export class StackAggregationIncreaseCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index 4bd04b4ee5..3fd5a5e596 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -174,7 +174,7 @@ export class StackStxCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { From 466f45b27dd328eca1db517e1de793397e516e26 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Thu, 11 Apr 2024 18:40:22 +0200 Subject: [PATCH 055/129] chore(pox-4-tests): Format code and wrap comments at 79 chars - Ran `deno fmt` to ensure code formatting adheres to standard practices. - Manually wrapped comments to 79 characters width for improved readability across various code editors and diff tools. - Fixed minor typos and standardized comment punctuation. - Added missing periods at the end of parameter descriptions. --- .../pox-4/pox_AllowContractCallerCommand.ts | 20 +++++---- .../pox-4/pox_DelegateStackExtendCommand.ts | 12 ++---- .../pox-4/pox_DelegateStackIncreaseCommand.ts | 6 +-- .../pox-4/pox_DelegateStackStxCommand.ts | 41 ++++++++++--------- .../tests/pox-4/pox_DelegateStxCommand.ts | 17 ++++---- .../pox_DisallowContractCallerCommand.ts | 13 +++--- .../pox-4/pox_GetStackingMinimumCommand.ts | 4 +- .../tests/pox-4/pox_GetStxAccountCommand.ts | 9 ++-- .../pox-4/pox_RevokeDelegateStxCommand.ts | 15 ++++--- ...tackAggregationCommitIndexedAuthCommand.ts | 2 +- ...StackAggregationCommitIndexedSigCommand.ts | 2 +- .../pox_StackAggregationIncreaseCommand.ts | 2 +- .../tests/pox-4/pox_StackStxCommand.ts | 2 + 13 files changed, 79 insertions(+), 66 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts index abb9936568..551441166e 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts @@ -15,10 +15,11 @@ import { } from "@stacks/transactions"; /** - * The `AllowContractCallerComand` gives a `contract-caller` authorization to call stacking methods. - * Normally, stacking methods may only be invoked by direct transactions (i.e., the tx-sender - * issues a direct contract-call to the stacking methods). - * By issuing an allowance, the tx-sender may call stacking methods through the allowed contract. + * The `AllowContractCallerCommand` authorizes a `contract-caller` to call + * stacking methods. Normally, stacking methods can only be invoked by direct + * transactions (i.e., the tx-sender issues a direct contract-call to the + * stacking methods). By issuing an allowance, the tx-sender may call stacking + * methods through the allowed contract. * * There are no constraints for running this command. */ @@ -28,12 +29,14 @@ export class AllowContractCallerCommand implements PoxCommand { readonly allowUntilBurnHt: OptionalCV; /** - * Constructs an `AllowContractCallerComand` that authorizes a `contract-caller` to call - * stacking methods. + * Constructs an `AllowContractCallerCommand` that authorizes a + * `contract-caller` to call stacking methods. * * @param wallet - Represents the Stacker's wallet. - * @param allowanceTo - Represents the authorized `contract-caller` (i.e. a stacking pool) - * @param alllowUntilBurnHt - The burn block height until the authorization is valid. + * @param allowanceTo - Represents the authorized `contract-caller` (i.e., a + * stacking pool). + * @param allowUntilBurnHt - The burn block height until which the + * authorization is valid. */ constructor( wallet: Wallet, @@ -52,6 +55,7 @@ export class AllowContractCallerCommand implements PoxCommand { run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); + // Act const allowContractCaller = real.network.callPublicFn( "ST000000000000000000002AMW42H.pox-4", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts index 5e4a536064..a555d89a37 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts @@ -7,11 +7,7 @@ import { } from "./pox_CommandModel.ts"; import { poxAddressToTuple } from "@stacks/stacking"; import { assert, expect } from "vitest"; -import { - Cl, - ClarityType, - isClarityType, -} from "@stacks/transactions"; +import { Cl, ClarityType, isClarityType } from "@stacks/transactions"; import { FIRST_BURNCHAIN_BLOCK_HEIGHT, REWARD_CYCLE_LENGTH, @@ -19,10 +15,10 @@ import { /** * The `DelegateStackExtendCommand` allows a pool operator to - * extend an active stacking lock, issuing a "partial commitment" + * extend an active stacking lock, issuing a "partial commitment" * for the extended-to cycles. - * - * This method extends stacker's current lockup for an additional + * + * This method extends stacker's current lockup for an additional * extend-count and partially commits those new cycles to `pox-addr`. * * Constraints for running this command include: diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts index 92ec5d9e9a..2f5a2590c2 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts @@ -13,7 +13,7 @@ import { Cl } from "@stacks/transactions"; * The DelegateStackIncreaseCommand allows a pool operator to * increase an active stacking lock, issuing a "partial commitment" * for the increased cycles. - * + * * This method increases stacker's current lockup and partially * commits the additional STX to `pox-addr`. * @@ -38,7 +38,7 @@ export class DelegateStackIncreaseCommand implements PoxCommand { * * @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 increaseBy - Represents the locked amount to be increased by. */ constructor(operator: Wallet, stacker: Wallet, increaseBy: number) { this.operator = operator; @@ -103,7 +103,7 @@ export class DelegateStackIncreaseCommand implements PoxCommand { // Get the Stacker's wallet from the model and update it with the new state. const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; - const operatorWallet = model.wallets.get(this.operator.stxAddress)! + const operatorWallet = model.wallets.get(this.operator.stxAddress)!; // Update model so that we know this stacker has increased the stacked amount. // Update locked and unlocked fields in the model. stackerWallet.amountLocked = newTotalLocked; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index 7b09a8e6da..6175658206 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -11,21 +11,21 @@ import { Cl, ClarityType, isClarityType } from "@stacks/transactions"; import { currentCycle } from "./pox_Commands.ts"; /** - * The `DelegateStackStxCommand` locks STX for stacking within PoX-4 on behalf of a delegator. - * This operation allows the `operator` to stack the `stacker`'s STX. + * The `DelegateStackStxCommand` locks STX for stacking within PoX-4 on behalf + * of a delegator. This operation allows the `operator` to stack the `stacker`'s + * STX. * * Constraints for running this command include: * - A minimum threshold of uSTX must be met, determined by the - * `get-stacking-minimum` function at the time of this call. - * - The Stacker cannot currently be engaged in another stacking - * operation. + * `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 amount. - * - The stacked uSTX amount should be less than or equal to the - * Stacker's balance. - * - The stacked uSTX amount should be greater than or equal to the - * minimum threshold of uSTX. + * - The stacked STX 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. + * - The stacked uSTX amount should be greater than or equal to the minimum + * threshold of uSTX. * - The Operator has to currently be delegated by the Stacker. * - The Period has to fit the last delegation burn block height. */ @@ -46,7 +46,7 @@ export class DelegateStackStxCommand implements PoxCommand { * @param startBurnHt - A burn height inside the current reward cycle. * @param period - Number of reward cycles to lock uSTX. * @param amountUstx - The uSTX amount stacked by the Operator on behalf - * of the Stacker + * of the Stacker. * @param unlockBurnHt - The burn height at which the uSTX is unlocked. */ constructor( @@ -55,7 +55,7 @@ export class DelegateStackStxCommand implements PoxCommand { startBurnHt: number, period: number, amountUstx: bigint, - unlockBurnHt: number + unlockBurnHt: number, ) { this.operator = operator; this.stacker = stacker; @@ -98,6 +98,7 @@ export class DelegateStackStxCommand implements PoxCommand { run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); + // Act const delegateStackStx = real.network.callPublicFn( "ST000000000000000000002AMW42H.pox-4", @@ -114,13 +115,13 @@ export class DelegateStackStxCommand implements PoxCommand { // (lock-period uint) Cl.uint(this.period), ], - this.operator.stxAddress + this.operator.stxAddress, ); const { result: rewardCycle } = real.network.callReadOnlyFn( "ST000000000000000000002AMW42H.pox-4", "burn-height-to-reward-cycle", [Cl.uint(real.network.blockHeight)], - this.operator.stxAddress + this.operator.stxAddress, ); assert(isClarityType(rewardCycle, ClarityType.UInt)); @@ -128,7 +129,7 @@ export class DelegateStackStxCommand implements PoxCommand { "ST000000000000000000002AMW42H.pox-4", "reward-cycle-to-burn-height", [Cl.uint(Number(rewardCycle.value) + this.period + 1)], - this.operator.stxAddress + this.operator.stxAddress, ); assert(isClarityType(unlockBurnHeight, ClarityType.UInt)); @@ -138,7 +139,7 @@ export class DelegateStackStxCommand implements PoxCommand { stacker: Cl.principal(this.stacker.stxAddress), "lock-amount": Cl.uint(this.amountUstx), "unlock-burn-height": Cl.uint(Number(unlockBurnHeight.value)), - }) + }), ); // Get the Stacker's wallet from the model and update it with the new state. @@ -154,8 +155,8 @@ export class DelegateStackStxCommand implements PoxCommand { stackerWallet.amountUnlocked -= Number(this.amountUstx); stackerWallet.firstLockedRewardCycle = currentCycle(real.network) + 1; // Add stacker to the operators lock list. This will help knowing that - // the stacker's funds are locked when calling delegate-stack-extend, - // delegate-stack-increase + // the stacker's funds are locked when calling delegate-stack-extend + // and delegate-stack-increase. operatorWallet.lockedAddresses.push(stackerWallet.stxAddress); operatorWallet.amountToCommit += Number(this.amountUstx); @@ -167,7 +168,7 @@ export class DelegateStackStxCommand implements PoxCommand { "lock-amount", this.amountUstx.toString(), "until", - this.stacker.unlockHeight.toString() + this.stacker.unlockHeight.toString(), ); // Refresh the model's state if the network gets to the next reward cycle. diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts index f6cfbfeb66..040dab3c8e 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts @@ -10,13 +10,14 @@ import { expect } from "vitest"; import { boolCV, Cl } from "@stacks/transactions"; /** - * The `DelegateStxCommand` delegates STX for stacking within PoX-4. This operation - * allows the `tx-sender` (the `wallet` in this case) to delegate stacking participation - * to a `delegatee`. + * The `DelegateStxCommand` delegates STX for stacking within PoX-4. This + * operation allows the `tx-sender` (the `wallet` in this case) to delegate + * stacking participation to a `delegatee`. * * Constraints for running this command include: * - The Stacker cannot currently be a delegator in another delegation. - * - The PoX address provided should have a valid version (between 0 and 6 inclusive). + * - The PoX address provided should have a valid version (between 0 and 6 + * inclusive). */ export class DelegateStxCommand implements PoxCommand { readonly wallet: Wallet; @@ -30,8 +31,8 @@ export class DelegateStxCommand implements PoxCommand { * @param wallet - Represents the Stacker's wallet. * @param delegateTo - Represents the Delegatee's STX address. * @param untilBurnHt - The burn block height until the delegation is valid. - * @param amount - The maximum amount the `Stacker` delegates the `Delegatee` to - * stack on his behalf + * @param amount - The maximum amount the `Stacker` delegates the `Delegatee` + * to stack on his behalf. */ constructor( wallet: Wallet, @@ -48,6 +49,7 @@ export class DelegateStxCommand implements PoxCommand { check(model: Readonly): boolean { // Constraints for running this command include: // - The Stacker cannot currently be a delegator in another delegation. + return ( model.stackingMinimum > 0 && !model.wallets.get(this.wallet.stxAddress)?.hasDelegated @@ -56,6 +58,7 @@ export class DelegateStxCommand implements PoxCommand { run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); + // The amount of uSTX delegated by the Stacker to the Delegatee. // Even if there are no constraints about the delegated amount, // it will be checked in the future, when calling delegate-stack-stx. @@ -104,7 +107,7 @@ export class DelegateStxCommand implements PoxCommand { "delegated to", this.delegateTo.label, "until", - this.untilBurnHt.toString() + this.untilBurnHt.toString(), ); // Refresh the model's state if the network gets to the next reward cycle. diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts index b1c99109be..f26afe7984 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts @@ -27,7 +27,6 @@ export class DisallowContractCallerCommand implements PoxCommand { * @param stacker - Represents the `Stacker`'s wallet. * @param callerToDisallow - The `contract-caller` to be revoked. */ - constructor(stacker: Wallet, callerToDisallow: Wallet) { this.stacker = stacker; this.callerToDisallow = callerToDisallow; @@ -35,12 +34,14 @@ export class DisallowContractCallerCommand implements PoxCommand { check(_model: Readonly): boolean { // Constraints for running this command include: - // - The Caller to be disallowed must have been previously - // allowed by the Operator. + // - The Caller to be disallowed must have been previously allowed + // by the Operator. return ( this.stacker.allowedContractCaller === this.callerToDisallow.stxAddress && - this.callerToDisallow.callerAllowedBy.includes(this.stacker.stxAddress) === + this.callerToDisallow.callerAllowedBy.includes( + this.stacker.stxAddress, + ) === true ); } @@ -62,13 +63,13 @@ export class DisallowContractCallerCommand implements PoxCommand { // Assert expect(disallowContractCaller.result).toBeOk(boolCV(true)); - // Get the wallet to be revoked stacking rights from the model and + // Get the wallet to be revoked stacking rights from the model and // update it with the new state. const callerToDisallow = model.wallets.get( this.callerToDisallow.stxAddress, )!; - // Update model so that we know that the stacker has revoked stacking + // Update model so that we know that the stacker has revoked stacking // allowance. this.stacker.allowedContractCaller = ""; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts index b05923ef1f..de58fd678a 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts @@ -26,13 +26,13 @@ export class GetStackingMinimumCommand implements PoxCommand { } check(_model: Readonly): boolean { - // Can always check the minimum number of uSTX to be stacked in the given - // reward cycle. + // There are no constraints for running this command. return true; } run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); + // Act const { result: stackingMinimum } = real.network.callReadOnlyFn( "ST000000000000000000002AMW42H.pox-4", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts index 8610bc1050..8efa7cce63 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts @@ -26,12 +26,13 @@ export class GetStxAccountCommand implements PoxCommand { } check(_model: Readonly): boolean { - // Can always check the `stx-account` info. + // There are no constraints for running this command. return true; } run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); + const actual = model.wallets.get(this.wallet.stxAddress)!; expect(real.network.runSnippet(`(stx-account '${actual.stxAddress})`)) .toBeTuple({ @@ -40,8 +41,10 @@ export class GetStxAccountCommand implements PoxCommand { "unlock-height": Cl.uint(actual.unlockHeight), }); - expect(actual.amountLocked + actual.amountUnlocked).toBe(actual.ustxBalance); - + expect(actual.amountLocked + actual.amountUnlocked).toBe( + actual.ustxBalance, + ); + // 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( diff --git a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts index 605d461da9..32e5f88756 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts @@ -10,7 +10,8 @@ import { expect } from "vitest"; import { Cl, someCV, tupleCV } from "@stacks/transactions"; /** - * The `RevokeDelegateStxCommand` revokes the delegation for stacking within PoX-4. + * The `RevokeDelegateStxCommand` revokes the delegation for stacking within + * PoX-4. * * Constraints for running this command include: * - The `Stacker` has to currently be delegating. @@ -30,6 +31,7 @@ export class RevokeDelegateStxCommand implements PoxCommand { check(model: Readonly): boolean { // Constraints for running this command include: // - The Stacker has to currently be delegating. + return ( model.stackingMinimum > 0 && model.wallets.get(this.wallet.stxAddress)!.hasDelegated === true @@ -38,7 +40,7 @@ export class RevokeDelegateStxCommand implements PoxCommand { run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); - // Get the Operator's wallet + const operatorWallet = model.wallets.get(this.wallet.delegatedTo)!; // Act @@ -65,17 +67,18 @@ export class RevokeDelegateStxCommand implements PoxCommand { ), ); - // Get the Stacker's wallet from the model and update the two wallets involved with the new state. + // Get the Stacker's wallet from the model and update the two wallets + // involved with the new state. const wallet = model.wallets.get(this.wallet.stxAddress)!; // Update model so that we know this wallet is not delegating anymore. - // This is important in order to prevent the test from revoking the delegation - // multiple times with the same address. + // This is important in order to prevent the test from revoking the + // delegation multiple times with the same address. wallet.hasDelegated = false; wallet.delegatedTo = ""; wallet.delegatedUntilBurnHt = 0; wallet.delegatedMaxAmount = 0; - // Remove the Stacker from the Pool Operator's pool members list + // Remove the Stacker from the Pool Operator's pool members list. const walletIndexInDelegatorsList = operatorWallet.poolMembers.indexOf( wallet.stxAddress, ); diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts index 6b7ba47b68..332cecbd7e 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts @@ -32,7 +32,7 @@ export class StackAggregationCommitIndexedAuthCommand implements PoxCommand { readonly currentCycle: number; /** - * Constructs a `StackAggregationCommitIndexedAuthCommand` to lock uSTX + * Constructs a `StackAggregationCommitIndexedAuthCommand` to lock uSTX * for stacking. * * @param operator - Represents the `Operator`'s wallet. diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts index 56456ac3ef..0f9521f53f 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts @@ -33,7 +33,7 @@ export class StackAggregationCommitIndexedSigCommand implements PoxCommand { readonly currentCycle: number; /** - * Constructs a `StackAggregationCommitIndexedSigCommand` to lock uSTX + * Constructs a `StackAggregationCommitIndexedSigCommand` to lock uSTX * for stacking. * * @param operator - Represents the `Operator`'s wallet. diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts index 7b3c21d863..328d3d0acc 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts @@ -109,4 +109,4 @@ export class StackAggregationIncreaseCommand implements PoxCommand { this.currentCycle + 1 } index ${this.rewardCycleIndex}`; } -} \ No newline at end of file +} diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index 3fd5a5e596..9814dfb5b8 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -57,6 +57,7 @@ export class StackStxCommand implements PoxCommand { // `get-stacking-minimum` function at the time of this call. // - The Stacker cannot currently be engaged in another stacking operation. // - The Stacker cannot currently be delegating STX to a delegatee. + return ( model.stackingMinimum > 0 && !model.wallets.get(this.wallet.stxAddress)?.isStacking && @@ -66,6 +67,7 @@ export class StackStxCommand implements PoxCommand { run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); + // The maximum amount of uSTX that can be used (per tx) with this signer // key. For our tests, we will use the minimum amount of uSTX to be stacked // in the given reward cycle multiplied by the margin, which is a randomly From 954e2949d2d3e55f6dc0265d3ceb54ecd806ab0c Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Sat, 16 Mar 2024 10:01:26 +0100 Subject: [PATCH 056/129] wip(pox-4-tests): StackStxCommand & stateful property tests planning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit lays the groundwork for the StackStxCommand and GetStackingMinimumCommand classes for PoX-4. It also proposes the introduction of fast-check based stateful tests, similar to the efforts for sBTC (https://github.com/stacks-network/sbtc/pull/152). As highlighted in https://github.com/stacks-network/stacks-core/issues/4548, this initiative is part of an ongoing effort to embrace a more rigorous, property-based testing strategy for PoX-4 interactions. The planned stateful tests aim to simulate various stacking scenarios, ensuring compliance with PoX-4 protocols and robust error handling. This strategy is expected to greatly enhance test coverage and the reliability of PoX-4 stacking operations, bolstering confidence in the protocol’s robustness and correctness. Note: This is an early-stage WIP commit. Implementation details and testing strategies are subject to substantial development and refinement. --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 92 ++++++++++ .../tests/pox-4/pox_CommandModel.ts | 32 ++++ .../tests/pox-4/pox_Commands.ts | 48 +++++ .../pox-4/pox_GetStackingMinimumCommand.ts | 60 +++++++ .../tests/pox-4/pox_StackStxCommand.ts | 169 ++++++++++++++++++ 5 files changed, 401 insertions(+) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_Commands.ts create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts new file mode 100644 index 0000000000..cdd26d843f --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -0,0 +1,92 @@ +import { describe, it } from "vitest"; + +import { initSimnet } from "@hirosystems/clarinet-sdk"; +import { Real, Stub, StxAddress, Wallet } from "./pox_CommandModel.ts"; + +import { + getPublicKeyFromPrivate, + publicKeyToBtcAddress, +} from "@stacks/encryption"; +import { StacksDevnet } from "@stacks/network"; +import { + createStacksPrivateKey, + getAddressFromPrivateKey, + TransactionVersion, +} from "@stacks/transactions"; +import { StackingClient } from "@stacks/stacking"; + +import fc from "fast-check"; +import { PoxCommands } from "./pox_Commands.ts"; + +describe("PoX-4 invariant tests", () => { + it("statefully does solo stacking with a signature", async () => { + // SUT stands for "System Under Test". + const sut: Real = { + network: await initSimnet(), + }; + + // This is the initial state of the model. + const model: Stub = { + stackingMinimum: 0, + wallets: new Map(), + }; + + const wallets = [ + "7287ba251d44a4d3fd9276c88ce34c5c52a038955511cccaf77e61068649c17801", + "d655b2523bcd65e34889725c73064feb17ceb796831c0e111ba1a552b0f31b3901", + "3eccc5dac8056590432db6a35d52b9896876a3d5cbdea53b72400bc9c2099fe801", + "7036b29cb5e235e5fd9b09ae3e8eec4404e44906814d5d01cbca968a60ed4bfb01", + "b463f0df6c05d2f156393eee73f8016c5372caa0e9e29a901bb7171d90dc4f1401", + ].map((prvKey) => { + const pubKey = getPublicKeyFromPrivate(prvKey); + const devnet = new StacksDevnet(); + const signerPrvKey = createStacksPrivateKey(prvKey); + const signerPubKey = getPublicKeyFromPrivate(signerPrvKey.data); + const btcAddress = publicKeyToBtcAddress(pubKey); + const stxAddress = getAddressFromPrivateKey( + prvKey, + TransactionVersion.Testnet, + ); + + return { + prvKey, + pubKey, + stxAddress, + btcAddress, + signerPrvKey, + signerPubKey, + client: new StackingClient(stxAddress, devnet), + ustxBalance: 100_000_000_000_000, + isStacking: false, + amountLocked: 0, + unlockHeight: 0, + }; + }); + + // Add the wallets to the model. + wallets.forEach((wallet) => { + model.wallets.set(wallet.stxAddress, wallet); + }); + + simnet.setEpoch("3.0"); + + fc.assert( + fc.property( + PoxCommands(model.wallets), + (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, + }, + ); + }); +}); diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts new file mode 100644 index 0000000000..b0ce6e5156 --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -0,0 +1,32 @@ +import fc from "fast-check"; + +import { Simnet } from "@hirosystems/clarinet-sdk"; +import { StacksPrivateKey } from "@stacks/transactions"; +import { StackingClient } from "@stacks/stacking"; + +export type StxAddress = string; + +export type Stub = { + stackingMinimum: number; + wallets: Map; +}; + +export type Real = { + network: Simnet; +}; + +export type Wallet = { + prvKey: string; + pubKey: string; + stxAddress: string; + btcAddress: string; + signerPrvKey: StacksPrivateKey; + signerPubKey: string; + client: StackingClient; + ustxBalance: number; + isStacking: boolean; + amountLocked: number; + unlockHeight: number; +}; + +export type PoxCommand = fc.Command; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts new file mode 100644 index 0000000000..397b8e88b3 --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -0,0 +1,48 @@ +import fc from "fast-check"; +import { Real, Stub, StxAddress, Wallet } from "./pox_CommandModel"; +import { GetStackingMinimumCommand } from "./pox_GetStackingMinimumCommand"; +import { StackStxCommand } from "./pox_StackStxCommand"; + +export function PoxCommands( + wallets: Map, +): fc.Arbitrary>> { + const cmds = [ + // GetStackingMinimumCommand + fc.record({ + wallet: fc.constantFrom(...wallets.values()), + }).map(( + r: { + wallet: Wallet; + }, + ) => + new GetStackingMinimumCommand( + r.wallet, + ) + ), + // StackStxCommand + fc.record({ + wallet: fc.constantFrom(...wallets.values()), + authId: fc.nat(), + period: fc.integer({ min: 1, max: 12 }), + margin: fc.integer({ min: 1, max: 9 }), + }).map(( + r: { + wallet: Wallet; + authId: number; + period: number; + margin: number; + }, + ) => + new StackStxCommand( + r.wallet, + r.authId, + r.period, + r.margin, + ) + ), + ]; + + // 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" }); +} diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts new file mode 100644 index 0000000000..14ba177c4d --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts @@ -0,0 +1,60 @@ +import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { assert } from "vitest"; +import { ClarityType, isClarityType } from "@stacks/transactions"; + +/** + * Implements the `PoxCommand` interface to get the minimum stacking amount + * required for a given reward cycle. + */ +export class GetStackingMinimumCommand implements PoxCommand { + readonly wallet: Wallet; + + /** + * Constructs a new `GetStackingMinimumCommand`. + * + * @param wallet The wallet information, including the STX address used to + * query the stacking minimum requirement. + */ + constructor(wallet: Wallet) { + this.wallet = wallet; + } + + check(_model: Readonly): boolean { + // Can always check the minimum number of uSTX to be stacked in the given + // reward cycle. + return true; + } + + run(model: Stub, real: Real): void { + // Act + const { result: stackingMinimum } = real.network.callReadOnlyFn( + "ST000000000000000000002AMW42H.pox-4", + "get-stacking-minimum", + [], + this.wallet.stxAddress, + ); + assert(isClarityType(stackingMinimum, ClarityType.UInt)); + + // Update the model with the new stacking minimum. This is important for + // the `check` method of the `StackStxCommand` class to work correctly, as + // we as other tests that may depend on the stacking minimum. + model.stackingMinimum = Number(stackingMinimum.value); + + // 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. + console.info( + `✓ ${this.wallet.stxAddress.padStart(8, " ")} ${ + "get-stacking-minimum".padStart(34, " ") + } ${"pox-4".padStart(12, " ")} ${ + stackingMinimum.value.toString().padStart(13, " ") + }`, + ); + } + + 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.wallet.stxAddress} get-stacking-minimum`; + } +} diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts new file mode 100644 index 0000000000..087331387c --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -0,0 +1,169 @@ +import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { Pox4SignatureTopic, poxAddressToTuple } from "@stacks/stacking"; +import { assert, expect } from "vitest"; +import { Cl, ClarityType, isClarityType } from "@stacks/transactions"; + +/** + * The `StackStxCommand` locks STX for stacking within PoX-4. This self-service + * operation allows the `tx-sender` (the `wallet` in this case) to participate + * as a Stacker. + * + * Constraints for running this command include: + * - The Stacker cannot currently be engaged in another stacking operation. + * - A minimum threshold of uSTX must be met, determined by the + * `get-stacking-minimum` function at the time of this call. + * - The amount of uSTX locked may need to be increased in future reward cycles + * if the minimum threshold rises. + */ +export class StackStxCommand implements PoxCommand { + readonly wallet: Wallet; + readonly authId: number; + readonly period: number; + readonly margin: number; + + /** + * Constructs a `StackStxCommand` to lock uSTX for stacking. + * + * @param wallet - Represents the Stacker's wallet. + * @param authId - Unique auth-id for the authorization. + * @param period - Number of reward cycles to lock uSTX. + * @param margin - Multiplier for minimum required uSTX to stack so that each + * Stacker locks a different amount of uSTX across test runs. + */ + constructor( + wallet: Wallet, + authId: number, + period: number, + margin: number, + ) { + this.wallet = wallet; + this.authId = authId; + this.period = period; + this.margin = margin; + } + + check(model: Readonly): boolean { + // Constraints for running this command include: + // - A minimum threshold of uSTX must be met, determined by the + // `get-stacking-minimum` function at the time of this call. + // - The Stacker cannot currently be engaged in another stacking operation. + return model.stackingMinimum > 0 && + !model.wallets.get(this.wallet.stxAddress)?.isStacking; + } + + run(model: Stub, real: Real): void { + // The maximum amount of uSTX that can be used (per tx) with this signer + // key. For our tests, we will use the minimum amount of uSTX to be stacked + // in the given reward cycle multiplied by the margin, which is a randomly + // generated number passed to the constructor of this class. + const maxAmount = model.stackingMinimum * this.margin; + + const signerSig = this.wallet.client.signPoxSignature({ + // The signer key being authorized. + signerPrivateKey: this.wallet.signerPrvKey, + // The reward cycle for which the authorization is valid. + // For `stack-stx` and `stack-extend`, this refers to the reward cycle + // where the transaction is confirmed. For `stack-aggregation-commit`, + // this refers to the reward cycle argument in that function. + rewardCycle: 0, + // For `stack-stx`, this refers to `lock-period`. For `stack-extend`, + // this refers to `extend-count`. For `stack-aggregation-commit`, this is + // `u1`. + period: this.period, + // A string representing the function where this authorization is valid. + // Either `stack-stx`, `stack-extend`, `stack-increase` or `agg-commit`. + topic: Pox4SignatureTopic.StackStx, + // The PoX address that can be used with this signer key. + poxAddress: this.wallet.btcAddress, + // The unique auth-id for this authorization. + authId: this.authId, + // The maximum amount of uSTX that can be used (per tx) with this signer + // key. + maxAmount: maxAmount, + }); + + // The amount of uSTX to be locked in the reward cycle. For this test, we + // will use the maximum amount of uSTX that can be used (per tx) with this + // signer key. + const amountUstx = maxAmount; + + // Act + const stackStx = real.network.callPublicFn( + "ST000000000000000000002AMW42H.pox-4", + "stack-stx", + [ + // (amount-ustx uint) + Cl.uint(amountUstx), + // (pox-addr (tuple (version (buff 1)) (hashbytes (buff 32)))) + poxAddressToTuple(this.wallet.btcAddress), + // (start-burn-ht uint) + Cl.uint(real.network.blockHeight), + // (lock-period uint) + Cl.uint(this.period), + // (signer-sig (optional (buff 65))) + Cl.some(Cl.bufferFromHex(signerSig)), + // (signer-key (buff 33)) + Cl.bufferFromHex(this.wallet.signerPubKey), + // (max-amount uint) + Cl.uint(maxAmount), + // (auth-id uint) + Cl.uint(this.authId), + ], + this.wallet.stxAddress, + ); + + const { result: rewardCycle } = real.network.callReadOnlyFn( + "ST000000000000000000002AMW42H.pox-4", + "burn-height-to-reward-cycle", + [Cl.uint(real.network.blockHeight)], + this.wallet.stxAddress, + ); + assert(isClarityType(rewardCycle, ClarityType.UInt)); + + const { result: unlockBurnHeight } = real.network.callReadOnlyFn( + "ST000000000000000000002AMW42H.pox-4", + "reward-cycle-to-burn-height", + [Cl.uint(Number(rewardCycle.value) + this.period + 1)], + this.wallet.stxAddress, + ); + assert(isClarityType(unlockBurnHeight, ClarityType.UInt)); + + // Assert + expect(stackStx.result).toBeOk( + Cl.tuple({ + "lock-amount": Cl.uint(amountUstx), + "signer-key": Cl.bufferFromHex(this.wallet.signerPubKey), + "stacker": Cl.principal(this.wallet.stxAddress), + "unlock-burn-height": Cl.uint(Number(unlockBurnHeight.value)), + }), + ); + + // Get the wallet from the model and update it with the new state. + const wallet = model.wallets.get(this.wallet.stxAddress)!; + // Update model so that we know this wallet is stacking. This is important + // in order to prevent the test from stacking multiple times with the same + // address. + wallet.isStacking = true; + // Update locked, unlocked, and unlock-height fields in the model. + wallet.amountLocked = amountUstx; + wallet.unlockHeight = Number(unlockBurnHeight.value); + wallet.ustxBalance -= amountUstx; + + // 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. + console.info( + `✓ ${this.wallet.stxAddress.padStart(8, " ")} ${ + "stack-stx".padStart(34, " ") + } ${"lock-amount".padStart(12, " ")} ${ + amountUstx.toString().padStart(13, " ") + }`, + ); + } + + 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.wallet.stxAddress} stack-stx auth-id ${this.authId} and period ${this.period}`; + } +} From 1496241d3ba295514ccdf62b7a7b3f0024cc7b07 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Mon, 18 Mar 2024 01:24:26 +0100 Subject: [PATCH 057/129] test(pox-4-tests): Add GetStxAccountCommand --- .../tests/pox-4/pox_Commands.ts | 13 +++++ .../tests/pox-4/pox_GetStxAccountCommand.ts | 57 +++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 397b8e88b3..e2e71fe479 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -1,6 +1,7 @@ import fc from "fast-check"; import { Real, Stub, StxAddress, Wallet } from "./pox_CommandModel"; import { GetStackingMinimumCommand } from "./pox_GetStackingMinimumCommand"; +import { GetStxAccountCommand } from "./pox_GetStxAccountCommand"; import { StackStxCommand } from "./pox_StackStxCommand"; export function PoxCommands( @@ -40,6 +41,18 @@ export function PoxCommands( r.margin, ) ), + // GetStxAccountCommand + fc.record({ + wallet: fc.constantFrom(...wallets.values()), + }).map(( + r: { + wallet: Wallet; + }, + ) => + new GetStxAccountCommand( + r.wallet, + ) + ), ]; // More on size: https://github.com/dubzzz/fast-check/discussions/2978 diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts new file mode 100644 index 0000000000..780f363417 --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts @@ -0,0 +1,57 @@ +import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { expect } from "vitest"; +import { Cl } from "@stacks/transactions"; + +/** + * Implements the `PoxCommand` interface to get the info returned from the + * `stx-account`. + */ +export class GetStxAccountCommand implements PoxCommand { + readonly wallet: Wallet; + + /** + * Constructs a new `GetStxAccountCommand`. + * + * @param wallet The wallet information, including the STX address used to + * query the `stx-account`. + */ + constructor(wallet: Wallet) { + this.wallet = wallet; + } + + check(_model: Readonly): boolean { + // Can always check the `stx-account` info. + return true; + } + + run(model: Stub, real: Real): void { + const actual = model.wallets.get(this.wallet.stxAddress)!; + expect(real.network.runSnippet(`(stx-account '${actual.stxAddress})`)) + .toBeTuple({ + "locked": Cl.uint(actual.amountLocked), + "unlocked": Cl.uint(actual.ustxBalance), + "unlock-height": Cl.uint(actual.unlockHeight), + }); + + // 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. + console.info( + `✓ ${this.wallet.stxAddress.padStart(8, " ")} ${ + "stx-account".padStart(34, " ") + } ${"lock-amount".padStart(12, " ")} ${ + actual.amountLocked.toString().padStart(13, " ") + } ${"unlocked-amount".padStart(12, " ")} ${ + actual.ustxBalance.toString().padStart(15, " ") + } ${"unlocked-height".padStart(12, " ")} ${ + actual.unlockHeight.toString().padStart(7, " ") + }`, + ); + } + + 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.wallet.stxAddress} stx-account`; + } +} From cb1be4b03ebd882b897bbbd26f06c8222a9e30bc Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Mon, 18 Mar 2024 14:42:43 +0200 Subject: [PATCH 058/129] test(pox-4-tests): Add DelegateStxCommand --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 2 + .../tests/pox-4/pox_CommandModel.ts | 2 + .../tests/pox-4/pox_Commands.ts | 22 ++++ .../tests/pox-4/pox_DelegateStxCommand.ts | 119 ++++++++++++++++++ .../tests/pox-4/pox_StackStxCommand.ts | 8 +- 5 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index cdd26d843f..009d70bbf3 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -58,6 +58,8 @@ describe("PoX-4 invariant tests", () => { client: new StackingClient(stxAddress, devnet), ustxBalance: 100_000_000_000_000, isStacking: false, + hasDelegated: false, + delegatedTo: "", amountLocked: 0, unlockHeight: 0, }; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index b0ce6e5156..39d08c6b79 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -25,6 +25,8 @@ export type Wallet = { client: StackingClient; ustxBalance: number; isStacking: boolean; + hasDelegated: boolean; + delegatedTo: string; amountLocked: number; unlockHeight: number; }; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index e2e71fe479..1e45237a94 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -3,6 +3,7 @@ import { Real, Stub, StxAddress, Wallet } from "./pox_CommandModel"; import { GetStackingMinimumCommand } from "./pox_GetStackingMinimumCommand"; import { GetStxAccountCommand } from "./pox_GetStxAccountCommand"; import { StackStxCommand } from "./pox_StackStxCommand"; +import { DelegateStxCommand } from "./pox_DelegateStxCommand"; export function PoxCommands( wallets: Map, @@ -41,6 +42,27 @@ export function PoxCommands( r.margin, ) ), + // DelegateStxCommand + fc.record({ + wallet: fc.constantFrom(...wallets.values()), + delegateTo: fc.constantFrom(...wallets.values()), + untilBurnHt: fc.integer({ min: 1 }), + margin: fc.integer({ min: 1, max: 9 }), + }).map(( + r: { + wallet: Wallet; + delegateTo: Wallet; + untilBurnHt: number; + margin: number; + }, + ) => + new DelegateStxCommand( + r.wallet, + r.delegateTo, + r.untilBurnHt, + r.margin, + ) + ), // GetStxAccountCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts new file mode 100644 index 0000000000..395a775175 --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts @@ -0,0 +1,119 @@ +import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { poxAddressToTuple } from "@stacks/stacking"; +import { expect } from "vitest"; +import { boolCV, Cl } from "@stacks/transactions"; + +/** + * The `DelegateStxCommand` delegates STX for stacking within PoX-4. This self-service + * operation allows the `tx-sender` (the `wallet` in this case) to delegate stacking + * participation to a `delegatee`. + * + * Constraints for running this command include: + * - The Stacker cannot currently be a delegator in another delegation. + * - The PoX address provided should have a valid version (between 0 and 6 inclusive). + */ +export class DelegateStxCommand implements PoxCommand { + readonly wallet: Wallet; + readonly delegateTo: Wallet; + readonly untilBurnHt: number; + readonly margin: number; + + /** + * Constructs a `DelegateStxCommand` to delegate uSTX for stacking. + * + * @param wallet - Represents the Stacker's wallet. + * @param delegateTo - Represents the Delegatee's STX address. + * @param untilBurnHt - The burn block height until the delegation is valid. + * @param margin - Multiplier for minimum required uSTX to stack so that each + * Stacker locks a different amount of uSTX across test runs. + */ + constructor( + wallet: Wallet, + delegateTo: Wallet, + untilBurnHt: number, + margin: number, + ) { + this.wallet = wallet; + this.delegateTo = delegateTo; + this.untilBurnHt = untilBurnHt; + this.margin = margin; + } + + check(model: Readonly): boolean { + // Constraints for running this command include: + // - The Stacker cannot currently be a delegator in another delegation. + return ( + model.stackingMinimum > 0 && + !model.wallets.get(this.wallet.stxAddress)?.hasDelegated + ); + } + + run(model: Stub, real: Real): void { + // The amount of uSTX delegated by the Stacker to the Delegatee. + // For our tests, we will use the minimum amount of uSTX to be stacked + // in the given reward cycle multiplied by the margin, which is a randomly + // generated number passed to the constructor of this class. Even if there + // are no constraints about the delegated amount, it will be checked in the + // future, when calling delegate-stack-stx. + const delegatedAmount = model.stackingMinimum * this.margin; + + // The amount of uSTX to be delegated. For this test, we will use the + // delegated amount calculated before. + const amountUstx = delegatedAmount; + + // Act + const delegateStx = real.network.callPublicFn( + "ST000000000000000000002AMW42H.pox-4", + "delegate-stx", + [ + // (amount-ustx uint) + Cl.uint(amountUstx), + // (delegate-to principal) + Cl.principal(this.delegateTo.stxAddress), + // (until-burn-ht (optional uint)) + Cl.some(Cl.uint(this.untilBurnHt)), + // (pox-addr (optional { version: (buff 1), hashbytes: (buff 32) })) + Cl.some(poxAddressToTuple(this.delegateTo.btcAddress)), + ], + this.wallet.stxAddress, + ); + + // Assert + expect(delegateStx.result).toBeOk(boolCV(true)); + + // Get the wallet from the model and update it with the new state. + const wallet = model.wallets.get(this.wallet.stxAddress)!; + // Update model so that we know this wallet has delegated. This is important + // in order to prevent the test from delegating multiple times with the same + // address. + wallet.hasDelegated = true; + wallet.delegatedTo = this.delegateTo.stxAddress; + + // 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. + console.info( + `✓ ${this.wallet.stxAddress.padStart(8, " ")} ${ + "delegate-stx".padStart( + 34, + " ", + ) + } ${"amount".padStart(12, " ")} ${ + amountUstx + .toString() + .padStart(13, " ") + } delegated to ${ + this.delegateTo.stxAddress.padStart( + 42, + " ", + ) + }`, + ); + } + + 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.wallet.stxAddress} delegate-stx to ${this.delegateTo.stxAddress} until burn ht ${this.untilBurnHt}`; + } +} diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index 087331387c..2a6de9e893 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -47,8 +47,12 @@ export class StackStxCommand implements PoxCommand { // - A minimum threshold of uSTX must be met, determined by the // `get-stacking-minimum` function at the time of this call. // - The Stacker cannot currently be engaged in another stacking operation. - return model.stackingMinimum > 0 && - !model.wallets.get(this.wallet.stxAddress)?.isStacking; + // - The Stacker cannot currently be delegating STX to a delegatee. + return ( + model.stackingMinimum > 0 && + !model.wallets.get(this.wallet.stxAddress)?.isStacking && + !model.wallets.get(this.wallet.stxAddress)?.hasDelegated + ); } run(model: Stub, real: Real): void { From 3b19a2293c4942a8ac7ae148a8f77aefce3d7269 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Tue, 19 Mar 2024 10:00:50 +0100 Subject: [PATCH 059/129] test(pox-4-tests): Incorporate wallet labels for clearer test logging Revamps the PoX-4 testing suite by introducing wallet labels, aiming for more intelligible logging and easier identification of wallets in tests. This enhancement affects various commands and test setups, making debugging and test verification processes more straightforward. Includes updates to wallet structures and all related command implementations to utilize these labels in their logging outputs. --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 19 +++++++++++++------ .../tests/pox-4/pox_CommandModel.ts | 1 + .../tests/pox-4/pox_DelegateStxCommand.ts | 6 +++--- .../pox-4/pox_GetStackingMinimumCommand.ts | 4 ++-- .../tests/pox-4/pox_GetStxAccountCommand.ts | 4 ++-- .../tests/pox-4/pox_StackStxCommand.ts | 4 ++-- 6 files changed, 23 insertions(+), 15 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index 009d70bbf3..f768c2bad6 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -32,12 +32,18 @@ describe("PoX-4 invariant tests", () => { }; const wallets = [ - "7287ba251d44a4d3fd9276c88ce34c5c52a038955511cccaf77e61068649c17801", - "d655b2523bcd65e34889725c73064feb17ceb796831c0e111ba1a552b0f31b3901", - "3eccc5dac8056590432db6a35d52b9896876a3d5cbdea53b72400bc9c2099fe801", - "7036b29cb5e235e5fd9b09ae3e8eec4404e44906814d5d01cbca968a60ed4bfb01", - "b463f0df6c05d2f156393eee73f8016c5372caa0e9e29a901bb7171d90dc4f1401", - ].map((prvKey) => { + ["wallet_1", "7287ba251d44a4d3fd9276c88ce34c5c52a038955511cccaf77e61068649c17801"], + ["wallet_2", "530d9f61984c888536871c6573073bdfc0058896dc1adfe9a6a10dfacadc209101"], + ["wallet_3", "d655b2523bcd65e34889725c73064feb17ceb796831c0e111ba1a552b0f31b3901"], + ["wallet_4", "f9d7206a47f14d2870c163ebab4bf3e70d18f5d14ce1031f3902fbbc894fe4c701"], + ["wallet_5", "3eccc5dac8056590432db6a35d52b9896876a3d5cbdea53b72400bc9c2099fe801"], + ["wallet_6", "7036b29cb5e235e5fd9b09ae3e8eec4404e44906814d5d01cbca968a60ed4bfb01"], + ["wallet_7", "b463f0df6c05d2f156393eee73f8016c5372caa0e9e29a901bb7171d90dc4f1401"], + ["wallet_8", "6a1a754ba863d7bab14adbbc3f8ebb090af9e871ace621d3e5ab634e1422885e01"], + ["wallet_9", "de433bdfa14ec43aa1098d5be594c8ffb20a31485ff9de2923b2689471c401b801"], + ].map((wallet) => { + const label = wallet[0]; + const prvKey = wallet[1]; const pubKey = getPublicKeyFromPrivate(prvKey); const devnet = new StacksDevnet(); const signerPrvKey = createStacksPrivateKey(prvKey); @@ -49,6 +55,7 @@ describe("PoX-4 invariant tests", () => { ); return { + label, prvKey, pubKey, stxAddress, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 39d08c6b79..acaf90658a 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -16,6 +16,7 @@ export type Real = { }; export type Wallet = { + label: string; prvKey: string; pubKey: string; stxAddress: string; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts index 395a775175..426d55f980 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts @@ -92,7 +92,7 @@ export class DelegateStxCommand 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. console.info( - `✓ ${this.wallet.stxAddress.padStart(8, " ")} ${ + `✓ ${this.wallet.label.padStart(8, " ")} ${ "delegate-stx".padStart( 34, " ", @@ -102,7 +102,7 @@ export class DelegateStxCommand implements PoxCommand { .toString() .padStart(13, " ") } delegated to ${ - this.delegateTo.stxAddress.padStart( + this.delegateTo.label.padStart( 42, " ", ) @@ -114,6 +114,6 @@ export class DelegateStxCommand implements PoxCommand { // 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.wallet.stxAddress} delegate-stx to ${this.delegateTo.stxAddress} until burn ht ${this.untilBurnHt}`; + return `${this.wallet.label} delegate-stx to ${this.delegateTo.label} until burn ht ${this.untilBurnHt}`; } } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts index 14ba177c4d..e9968e7060 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts @@ -43,7 +43,7 @@ export class GetStackingMinimumCommand 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. console.info( - `✓ ${this.wallet.stxAddress.padStart(8, " ")} ${ + `✓ ${this.wallet.label.padStart(8, " ")} ${ "get-stacking-minimum".padStart(34, " ") } ${"pox-4".padStart(12, " ")} ${ stackingMinimum.value.toString().padStart(13, " ") @@ -55,6 +55,6 @@ export class GetStackingMinimumCommand implements PoxCommand { // 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.wallet.stxAddress} get-stacking-minimum`; + return `${this.wallet.label} get-stacking-minimum`; } } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts index 780f363417..0d415f6a29 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts @@ -36,7 +36,7 @@ export class GetStxAccountCommand 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. console.info( - `✓ ${this.wallet.stxAddress.padStart(8, " ")} ${ + `✓ ${this.wallet.label.padStart(8, " ")} ${ "stx-account".padStart(34, " ") } ${"lock-amount".padStart(12, " ")} ${ actual.amountLocked.toString().padStart(13, " ") @@ -52,6 +52,6 @@ export class GetStxAccountCommand implements PoxCommand { // 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.wallet.stxAddress} stx-account`; + return `${this.wallet.label} stx-account`; } } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index 2a6de9e893..b0fa999280 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -156,7 +156,7 @@ export class StackStxCommand 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. console.info( - `✓ ${this.wallet.stxAddress.padStart(8, " ")} ${ + `✓ ${this.wallet.label.padStart(8, " ")} ${ "stack-stx".padStart(34, " ") } ${"lock-amount".padStart(12, " ")} ${ amountUstx.toString().padStart(13, " ") @@ -168,6 +168,6 @@ export class StackStxCommand implements PoxCommand { // 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.wallet.stxAddress} stack-stx auth-id ${this.authId} and period ${this.period}`; + return `${this.wallet.label} stack-stx auth-id ${this.authId} and period ${this.period}`; } } From 55f6bb37d92ea0c78e4350f78dd05f36326f6027 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Tue, 19 Mar 2024 15:01:30 +0100 Subject: [PATCH 060/129] refactor(pox-4-tests): Remove unused prvKey and pubKey from Wallet Simplifies the Wallet type and its usage in PoX-4 tests by removing the prvKey and pubKey fields. This change reflects an effort to simplify the data structures and focus on the essential elements needed for testing. The reduction in fields contributes to cleaner code and minimizes unnecessary data handling in the test setup and execution. --- .../core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts | 2 -- contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts | 2 -- 2 files changed, 4 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index f768c2bad6..809280b2aa 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -56,8 +56,6 @@ describe("PoX-4 invariant tests", () => { return { label, - prvKey, - pubKey, stxAddress, btcAddress, signerPrvKey, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index acaf90658a..0eb9a98e44 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -17,8 +17,6 @@ export type Real = { export type Wallet = { label: string; - prvKey: string; - pubKey: string; stxAddress: string; btcAddress: string; signerPrvKey: StacksPrivateKey; From 092cb4d33964c4370f827a638fede3888321cbc5 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Tue, 19 Mar 2024 15:03:14 +0100 Subject: [PATCH 061/129] refactor(pox-4-tests): Rename Wallet 'client' to 'stackingClient' Improves code clarity by renaming the 'client' field in the Wallet type to 'stackingClient'. This change better specifies the purpose of the client as specifically for stacking operations within the PoX-4 testing framework. The update is applied across all instances where the field is referenced, ensuring consistency and enhancing readability. --- .../core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts | 2 +- contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts | 2 +- contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index 809280b2aa..ab7dea06ae 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -60,7 +60,7 @@ describe("PoX-4 invariant tests", () => { btcAddress, signerPrvKey, signerPubKey, - client: new StackingClient(stxAddress, devnet), + stackingClient: new StackingClient(stxAddress, devnet), ustxBalance: 100_000_000_000_000, isStacking: false, hasDelegated: false, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 0eb9a98e44..b823248e58 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -21,7 +21,7 @@ export type Wallet = { btcAddress: string; signerPrvKey: StacksPrivateKey; signerPubKey: string; - client: StackingClient; + stackingClient: StackingClient; ustxBalance: number; isStacking: boolean; hasDelegated: boolean; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index b0fa999280..63ae48bbd2 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -62,7 +62,7 @@ export class StackStxCommand implements PoxCommand { // generated number passed to the constructor of this class. const maxAmount = model.stackingMinimum * this.margin; - const signerSig = this.wallet.client.signPoxSignature({ + const signerSig = this.wallet.stackingClient.signPoxSignature({ // The signer key being authorized. signerPrivateKey: this.wallet.signerPrvKey, // The reward cycle for which the authorization is valid. From 56e1f0602c8fbea9d806cd9edc8e0b95355c3e2c Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Tue, 19 Mar 2024 15:04:23 +0100 Subject: [PATCH 062/129] refactor(pox-4-tests): Typify 'delegatedTo' field in Wallet Enhances type safety by changing the 'delegatedTo' field in the Wallet type from a generic string to a more specific StxAddress type. This modification aids in preventing potential bugs by ensuring the field is used consistently as an STX address across the PoX-4 testing suite. The adjustment promotes clearer code, and better alignment with the domain model. --- contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index b823248e58..174ad1c805 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -25,7 +25,7 @@ export type Wallet = { ustxBalance: number; isStacking: boolean; hasDelegated: boolean; - delegatedTo: string; + delegatedTo: StxAddress; amountLocked: number; unlockHeight: number; }; From 559e1ec2633aafe14a2a7e0a5adedea067ff373b Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Tue, 19 Mar 2024 16:07:26 +0100 Subject: [PATCH 063/129] feat(pox-4-tests): Add amountUnlocked to Wallet for staking Introduces `amountUnlocked` to the Wallet model in PoX-4 tests to clearly differentiate between locked and available balances. This addition complements the existing balance field, enhancing understanding of staking dynamics without renaming or removing existing structures. Adjustments made in related commands and tests ensure accuracy and consistency. --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 4 +++- contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts | 1 + .../tests/pox-4/pox_GetStxAccountCommand.ts | 4 ++-- .../core-contract-tests/tests/pox-4/pox_StackStxCommand.ts | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index ab7dea06ae..f2e943bb32 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -46,6 +46,7 @@ describe("PoX-4 invariant tests", () => { const prvKey = wallet[1]; const pubKey = getPublicKeyFromPrivate(prvKey); const devnet = new StacksDevnet(); + const initialUstxBalance = 100_000_000_000_000; const signerPrvKey = createStacksPrivateKey(prvKey); const signerPubKey = getPublicKeyFromPrivate(signerPrvKey.data); const btcAddress = publicKeyToBtcAddress(pubKey); @@ -61,11 +62,12 @@ describe("PoX-4 invariant tests", () => { signerPrvKey, signerPubKey, stackingClient: new StackingClient(stxAddress, devnet), - ustxBalance: 100_000_000_000_000, + ustxBalance: initialUstxBalance, isStacking: false, hasDelegated: false, delegatedTo: "", amountLocked: 0, + amountUnlocked: initialUstxBalance, unlockHeight: 0, }; }); diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 174ad1c805..2f19482f39 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -27,6 +27,7 @@ export type Wallet = { hasDelegated: boolean; delegatedTo: StxAddress; amountLocked: number; + amountUnlocked: number; unlockHeight: number; }; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts index 0d415f6a29..0a902f0366 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts @@ -29,7 +29,7 @@ export class GetStxAccountCommand implements PoxCommand { expect(real.network.runSnippet(`(stx-account '${actual.stxAddress})`)) .toBeTuple({ "locked": Cl.uint(actual.amountLocked), - "unlocked": Cl.uint(actual.ustxBalance), + "unlocked": Cl.uint(actual.amountUnlocked), "unlock-height": Cl.uint(actual.unlockHeight), }); @@ -41,7 +41,7 @@ export class GetStxAccountCommand implements PoxCommand { } ${"lock-amount".padStart(12, " ")} ${ actual.amountLocked.toString().padStart(13, " ") } ${"unlocked-amount".padStart(12, " ")} ${ - actual.ustxBalance.toString().padStart(15, " ") + actual.amountUnlocked.toString().padStart(15, " ") } ${"unlocked-height".padStart(12, " ")} ${ actual.unlockHeight.toString().padStart(7, " ") }`, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index 63ae48bbd2..68aa2f1992 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -151,7 +151,7 @@ export class StackStxCommand implements PoxCommand { // Update locked, unlocked, and unlock-height fields in the model. wallet.amountLocked = amountUstx; wallet.unlockHeight = Number(unlockBurnHeight.value); - wallet.ustxBalance -= amountUstx; + wallet.amountUnlocked -= amountUstx; // 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. From e064778f4ad3a3945f3b8f5513a057dbf4fc9ad5 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Tue, 19 Mar 2024 23:16:34 +0200 Subject: [PATCH 064/129] test(pox-4-tests): Add DelegateStackStxCommand --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 39 ++++- .../tests/pox-4/pox_CommandModel.ts | 2 + .../tests/pox-4/pox_Commands.ts | 38 ++++- .../pox-4/pox_DelegateStackStxCommand.ts | 156 ++++++++++++++++++ .../tests/pox-4/pox_DelegateStxCommand.ts | 34 ++-- .../pox-4/pox_GetStackingMinimumCommand.ts | 2 +- .../tests/pox-4/pox_GetStxAccountCommand.ts | 2 +- .../tests/pox-4/pox_StackStxCommand.ts | 2 +- 8 files changed, 246 insertions(+), 29 deletions(-) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index f2e943bb32..d02101bb37 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -1,6 +1,5 @@ import { describe, it } from "vitest"; - -import { initSimnet } from "@hirosystems/clarinet-sdk"; +import { initSimnet, Simnet } from "@hirosystems/clarinet-sdk"; import { Real, Stub, StxAddress, Wallet } from "./pox_CommandModel.ts"; import { @@ -9,7 +8,9 @@ import { } from "@stacks/encryption"; import { StacksDevnet } from "@stacks/network"; import { + Cl, createStacksPrivateKey, + cvToValue, getAddressFromPrivateKey, TransactionVersion, } from "@stacks/transactions"; @@ -18,6 +19,36 @@ import { StackingClient } from "@stacks/stacking"; import fc from "fast-check"; import { PoxCommands } from "./pox_Commands.ts"; +export const currentCycle = (network: Simnet) => + Number(cvToValue( + network.callReadOnlyFn( + "ST000000000000000000002AMW42H.pox-4", + "current-pox-reward-cycle", + [], + "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM", + ).result, + )); + +export const currentCycleFirstBlock = (network: Simnet) => + Number(cvToValue( + network.callReadOnlyFn( + "ST000000000000000000002AMW42H.pox-4", + "reward-cycle-to-burn-height", + [Cl.uint(currentCycle(network))], + "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM", + ).result, + )); + +export const nextCycleFirstBlock = (network: Simnet) => + Number(cvToValue( + network.callReadOnlyFn( + "ST000000000000000000002AMW42H.pox-4", + "reward-cycle-to-burn-height", + [Cl.uint(currentCycle(network) + 1)], + "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM", + ).result, + )); + describe("PoX-4 invariant tests", () => { it("statefully does solo stacking with a signature", async () => { // SUT stands for "System Under Test". @@ -65,7 +96,9 @@ describe("PoX-4 invariant tests", () => { ustxBalance: initialUstxBalance, isStacking: false, hasDelegated: false, + hasPoolMembers: [], delegatedTo: "", + delegatedMaxAmount: 0, amountLocked: 0, amountUnlocked: initialUstxBalance, unlockHeight: 0, @@ -81,7 +114,7 @@ describe("PoX-4 invariant tests", () => { fc.assert( fc.property( - PoxCommands(model.wallets), + PoxCommands(model.wallets, sut.network), (cmds) => { const initialState = () => ({ model: model, real: sut }); fc.modelRun(initialState, cmds); diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 2f19482f39..f88d64ccd4 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -25,7 +25,9 @@ export type Wallet = { ustxBalance: number; isStacking: boolean; hasDelegated: boolean; + hasPoolMembers: StxAddress[]; delegatedTo: StxAddress; + delegatedMaxAmount: number; amountLocked: number; amountUnlocked: number; unlockHeight: number; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 1e45237a94..bea8907412 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -4,9 +4,12 @@ import { GetStackingMinimumCommand } from "./pox_GetStackingMinimumCommand"; import { GetStxAccountCommand } from "./pox_GetStxAccountCommand"; import { StackStxCommand } from "./pox_StackStxCommand"; import { DelegateStxCommand } from "./pox_DelegateStxCommand"; +import { DelegateStackStxCommand } from "./pox_DelegateStackStxCommand"; +import { Simnet } from "@hirosystems/clarinet-sdk"; +import { currentCycleFirstBlock, nextCycleFirstBlock } from "./pox-4.stateful-prop.test"; export function PoxCommands( - wallets: Map, + wallets: Map, network: Simnet, ): fc.Arbitrary>> { const cmds = [ // GetStackingMinimumCommand @@ -47,20 +50,47 @@ export function PoxCommands( wallet: fc.constantFrom(...wallets.values()), delegateTo: fc.constantFrom(...wallets.values()), untilBurnHt: fc.integer({ min: 1 }), - margin: fc.integer({ min: 1, max: 9 }), + amount: fc.bigInt({ min:0n, max: 100_000_000_000_000n }), }).map(( r: { wallet: Wallet; delegateTo: Wallet; untilBurnHt: number; - margin: number; + amount: bigint; }, ) => new DelegateStxCommand( r.wallet, r.delegateTo, r.untilBurnHt, - r.margin, + r.amount, + ) + ), + // DelegateStackStxCommand + fc.record({ + operator: fc.constantFrom(...wallets.values()), + stacker: fc.constantFrom(...wallets.values()), + startBurnHt: fc.integer({ + min: currentCycleFirstBlock(network), + max: nextCycleFirstBlock(network), + }), + period: fc.integer({ min: 1, max: 12 }), + amount: fc.bigInt({ min:0n, max: 100_000_000_000_000n }), + }).map(( + r: { + operator: Wallet; + stacker: Wallet; + startBurnHt: number; + period: number; + amount: bigint; + }, + ) => + new DelegateStackStxCommand( + r.operator, + r.stacker, + r.startBurnHt, + r.period, + r.amount ) ), // GetStxAccountCommand diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts new file mode 100644 index 0000000000..4fb9ed09a4 --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -0,0 +1,156 @@ +import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { poxAddressToTuple } from "@stacks/stacking"; +import { assert, expect } from "vitest"; +import { Cl, ClarityType, isClarityType } from "@stacks/transactions"; + +/** + * The `DelegateStackStxCommand` locks STX for stacking within PoX-4 on behalf of a delegator. + * This operation allows the `operator` to stack the `stacker`'s STX. + * + * Constraints for running this command include: + * - A minimum threshold of uSTX must be met, determined by the + * `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 amount. + * - The stacked uSTX amount should be less than or equal to the + * Stacker's balance + * - The stacked uSTX amount should be greater than or equal to the + * minimum threshold of uSTX + * - The Operator has to currently be delegated by the Stacker. + */ +export class DelegateStackStxCommand implements PoxCommand { + readonly operator: Wallet; + readonly stacker: Wallet; + readonly startBurnHt: number; + readonly period: number; + readonly amountUstx: bigint; + + /** + * Constructs a `DelegateStackStxCommand` to lock uSTX 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 startBurnHt - A burn height inside the current reward cycle. + * @param period - Number of reward cycles to lock uSTX. + * @param amountUstx - The uSTX amount stacked by the Operator on behalf + * of the Stacker + */ + constructor( + operator: Wallet, + stacker: Wallet, + startBurnHt: number, + period: number, + amountUstx: bigint, + ) { + this.operator = operator; + this.stacker = stacker; + this.startBurnHt = startBurnHt; + this.period = period; + this.amountUstx = amountUstx; + } + + check(model: Readonly): boolean { + // Constraints for running this command include: + // - A minimum threshold of uSTX must be met, determined by the + // `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 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 + // - The stacked uSTX amount should be greater than or equal to the + // minimum threshold of uSTX + // - The Operator has to currently be delegated by the Stacker + + const operatorWallet = model.wallets.get(this.operator.stxAddress)!; + const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; + return ( + model.stackingMinimum > 0 && + !stackerWallet.isStacking && + stackerWallet.hasDelegated && + stackerWallet.delegatedMaxAmount >= Number(this.amountUstx) && + Number(this.amountUstx) <= stackerWallet.ustxBalance && + Number(this.amountUstx) >= model.stackingMinimum && + operatorWallet.hasPoolMembers.includes(stackerWallet.stxAddress) + ); + } + + run(model: Stub, real: Real): void { + // Act + const delegateStackStx = real.network.callPublicFn( + "ST000000000000000000002AMW42H.pox-4", + "delegate-stack-stx", + [ + // (stacker principal) + Cl.principal(this.stacker.stxAddress), + // (amount-ustx uint) + Cl.uint(this.amountUstx), + // (pox-addr { version: (buff 1), hashbytes: (buff 32) }) + poxAddressToTuple(this.operator.btcAddress), + // (start-burn-ht uint) + Cl.uint(this.startBurnHt), + // (lock-period uint) + Cl.uint(this.period) + ], + this.operator.stxAddress, + ); + const { result: rewardCycle } = real.network.callReadOnlyFn( + "ST000000000000000000002AMW42H.pox-4", + "burn-height-to-reward-cycle", + [Cl.uint(real.network.blockHeight)], + this.operator.stxAddress, + ); + assert(isClarityType(rewardCycle, ClarityType.UInt)); + + const { result: unlockBurnHeight } = real.network.callReadOnlyFn( + "ST000000000000000000002AMW42H.pox-4", + "reward-cycle-to-burn-height", + [Cl.uint(Number(rewardCycle.value) + this.period + 1)], + this.operator.stxAddress, + ); + assert(isClarityType(unlockBurnHeight, ClarityType.UInt)); + + // Assert + expect(delegateStackStx.result).toBeOk( + Cl.tuple({ + stacker: Cl.principal(this.stacker.stxAddress), + "lock-amount": Cl.uint(this.amountUstx), + "unlock-burn-height": Cl.uint(Number(unlockBurnHeight.value)), + }), + ); + + // Get the Stacker's wallet from the model and update it with the new state. + const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; + // Update model so that we know this wallet is stacking. This is important + // in order to prevent the test from stacking multiple times with the same + // address. + stackerWallet.isStacking = true; + // Update locked, unlocked, and unlock-height fields in the model. + stackerWallet.amountLocked = Number(this.amountUstx); + stackerWallet.unlockHeight = Number(unlockBurnHeight.value); + stackerWallet.amountUnlocked -= Number(this.amountUstx); + + // 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. + console.info( + `✓ ${this.operator.label.padStart(8, " ")} Ӿ ${this.stacker.label.padStart(8, " ")} ${ + "delegate-stack-stx".padStart(23, " ") + } ${"lock-amount".padStart(12, " ")} ${ + this.amountUstx.toString().padStart(15, " ") + } ${"until".padStart(37)} ${this.stacker.unlockHeight.toString().padStart(17)}`, + ); + } + + 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-stx period ${this.period}`; + } +} diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts index 426d55f980..08d2988293 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts @@ -4,9 +4,9 @@ import { expect } from "vitest"; import { boolCV, Cl } from "@stacks/transactions"; /** - * The `DelegateStxCommand` delegates STX for stacking within PoX-4. This self-service - * operation allows the `tx-sender` (the `wallet` in this case) to delegate stacking - * participation to a `delegatee`. + * The `DelegateStxCommand` delegates STX for stacking within PoX-4. This operation + * allows the `tx-sender` (the `wallet` in this case) to delegate stacking participation + * to a `delegatee`. * * Constraints for running this command include: * - The Stacker cannot currently be a delegator in another delegation. @@ -16,7 +16,7 @@ export class DelegateStxCommand implements PoxCommand { readonly wallet: Wallet; readonly delegateTo: Wallet; readonly untilBurnHt: number; - readonly margin: number; + readonly amount: bigint; /** * Constructs a `DelegateStxCommand` to delegate uSTX for stacking. @@ -24,19 +24,19 @@ export class DelegateStxCommand implements PoxCommand { * @param wallet - Represents the Stacker's wallet. * @param delegateTo - Represents the Delegatee's STX address. * @param untilBurnHt - The burn block height until the delegation is valid. - * @param margin - Multiplier for minimum required uSTX to stack so that each - * Stacker locks a different amount of uSTX across test runs. + * @param amount - The maximum amount the `Stacker` delegates the `Delegatee` to + * stack on his behalf */ constructor( wallet: Wallet, delegateTo: Wallet, untilBurnHt: number, - margin: number, + amount: bigint, ) { this.wallet = wallet; this.delegateTo = delegateTo; this.untilBurnHt = untilBurnHt; - this.margin = margin; + this.amount = amount; } check(model: Readonly): boolean { @@ -50,16 +50,9 @@ export class DelegateStxCommand implements PoxCommand { run(model: Stub, real: Real): void { // The amount of uSTX delegated by the Stacker to the Delegatee. - // For our tests, we will use the minimum amount of uSTX to be stacked - // in the given reward cycle multiplied by the margin, which is a randomly - // generated number passed to the constructor of this class. Even if there - // are no constraints about the delegated amount, it will be checked in the - // future, when calling delegate-stack-stx. - const delegatedAmount = model.stackingMinimum * this.margin; - - // The amount of uSTX to be delegated. For this test, we will use the - // delegated amount calculated before. - const amountUstx = delegatedAmount; + // Even if there are no constraints about the delegated amount, + // it will be checked in the future, when calling delegate-stack-stx. + const amountUstx = Number(this.amount); // Act const delegateStx = real.network.callPublicFn( @@ -83,12 +76,15 @@ export class DelegateStxCommand implements PoxCommand { // Get the wallet from the model and update it with the new state. const wallet = model.wallets.get(this.wallet.stxAddress)!; + const delegatedWallet = model.wallets.get(this.delegateTo.stxAddress)!; // Update model so that we know this wallet has delegated. This is important // in order to prevent the test from delegating multiple times with the same // address. wallet.hasDelegated = true; wallet.delegatedTo = this.delegateTo.stxAddress; + wallet.delegatedMaxAmount = amountUstx; + delegatedWallet.hasPoolMembers.push(wallet.stxAddress); // 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. console.info( @@ -100,7 +96,7 @@ export class DelegateStxCommand implements PoxCommand { } ${"amount".padStart(12, " ")} ${ amountUstx .toString() - .padStart(13, " ") + .padStart(15, " ") } delegated to ${ this.delegateTo.label.padStart( 42, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts index e9968e7060..3f573f4d99 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts @@ -46,7 +46,7 @@ export class GetStackingMinimumCommand implements PoxCommand { `✓ ${this.wallet.label.padStart(8, " ")} ${ "get-stacking-minimum".padStart(34, " ") } ${"pox-4".padStart(12, " ")} ${ - stackingMinimum.value.toString().padStart(13, " ") + stackingMinimum.value.toString().padStart(15, " ") }`, ); } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts index 0a902f0366..58257cf529 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts @@ -39,7 +39,7 @@ export class GetStxAccountCommand implements PoxCommand { `✓ ${this.wallet.label.padStart(8, " ")} ${ "stx-account".padStart(34, " ") } ${"lock-amount".padStart(12, " ")} ${ - actual.amountLocked.toString().padStart(13, " ") + actual.amountLocked.toString().padStart(15, " ") } ${"unlocked-amount".padStart(12, " ")} ${ actual.amountUnlocked.toString().padStart(15, " ") } ${"unlocked-height".padStart(12, " ")} ${ diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index 68aa2f1992..c77fe9e206 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -159,7 +159,7 @@ export class StackStxCommand implements PoxCommand { `✓ ${this.wallet.label.padStart(8, " ")} ${ "stack-stx".padStart(34, " ") } ${"lock-amount".padStart(12, " ")} ${ - amountUstx.toString().padStart(13, " ") + amountUstx.toString().padStart(15, " ") }`, ); } From c5e0ea51c5a3db545cb75ee9ea94c7b643856e90 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Fri, 22 Mar 2024 16:32:29 +0100 Subject: [PATCH 065/129] refactor(pox-4-tests): Relocate cycle utility functions to PoxCommands - Removes `Cl` and `cvToValue` imports and cycle utility functions from `pox-4.stateful-prop.test.ts`, streamlining its focus on tests. - Adds these imports and functions to `pox_Commands.ts`, centralizing cycle-related logic within command utilities for better cohesion and reusability. This shift enhances modularity and clarity in handling reward cycle calculations across PoX-4 tests. --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 34 +------------------ .../tests/pox-4/pox_Commands.ts | 32 ++++++++++++++++- 2 files changed, 32 insertions(+), 34 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index d02101bb37..c18c11e6c9 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -1,5 +1,5 @@ import { describe, it } from "vitest"; -import { initSimnet, Simnet } from "@hirosystems/clarinet-sdk"; +import { initSimnet } from "@hirosystems/clarinet-sdk"; import { Real, Stub, StxAddress, Wallet } from "./pox_CommandModel.ts"; import { @@ -8,9 +8,7 @@ import { } from "@stacks/encryption"; import { StacksDevnet } from "@stacks/network"; import { - Cl, createStacksPrivateKey, - cvToValue, getAddressFromPrivateKey, TransactionVersion, } from "@stacks/transactions"; @@ -19,36 +17,6 @@ import { StackingClient } from "@stacks/stacking"; import fc from "fast-check"; import { PoxCommands } from "./pox_Commands.ts"; -export const currentCycle = (network: Simnet) => - Number(cvToValue( - network.callReadOnlyFn( - "ST000000000000000000002AMW42H.pox-4", - "current-pox-reward-cycle", - [], - "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM", - ).result, - )); - -export const currentCycleFirstBlock = (network: Simnet) => - Number(cvToValue( - network.callReadOnlyFn( - "ST000000000000000000002AMW42H.pox-4", - "reward-cycle-to-burn-height", - [Cl.uint(currentCycle(network))], - "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM", - ).result, - )); - -export const nextCycleFirstBlock = (network: Simnet) => - Number(cvToValue( - network.callReadOnlyFn( - "ST000000000000000000002AMW42H.pox-4", - "reward-cycle-to-burn-height", - [Cl.uint(currentCycle(network) + 1)], - "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM", - ).result, - )); - describe("PoX-4 invariant tests", () => { it("statefully does solo stacking with a signature", async () => { // SUT stands for "System Under Test". diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index bea8907412..88fbea9a6b 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -6,7 +6,7 @@ import { StackStxCommand } from "./pox_StackStxCommand"; import { DelegateStxCommand } from "./pox_DelegateStxCommand"; import { DelegateStackStxCommand } from "./pox_DelegateStackStxCommand"; import { Simnet } from "@hirosystems/clarinet-sdk"; -import { currentCycleFirstBlock, nextCycleFirstBlock } from "./pox-4.stateful-prop.test"; +import { Cl, cvToValue } from "@stacks/transactions"; export function PoxCommands( wallets: Map, network: Simnet, @@ -111,3 +111,33 @@ export function PoxCommands( // More on cmds: https://github.com/dubzzz/fast-check/discussions/3026 return fc.commands(cmds, { size: "large" }); } + +const currentCycle = (network: Simnet) => + Number(cvToValue( + network.callReadOnlyFn( + "ST000000000000000000002AMW42H.pox-4", + "current-pox-reward-cycle", + [], + "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM", + ).result, + )); + +const currentCycleFirstBlock = (network: Simnet) => + Number(cvToValue( + network.callReadOnlyFn( + "ST000000000000000000002AMW42H.pox-4", + "reward-cycle-to-burn-height", + [Cl.uint(currentCycle(network))], + "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM", + ).result, + )); + +const nextCycleFirstBlock = (network: Simnet) => + Number(cvToValue( + network.callReadOnlyFn( + "ST000000000000000000002AMW42H.pox-4", + "reward-cycle-to-burn-height", + [Cl.uint(currentCycle(network) + 1)], + "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM", + ).result, + )); From fa6c6ee3416159abed64e9250ecd9105b65a62ed Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Fri, 22 Mar 2024 23:04:13 +0200 Subject: [PATCH 066/129] test(pox-4-tests): Add RevokeDelegateStxCommand --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 1 + .../tests/pox-4/pox_CommandModel.ts | 1 + .../tests/pox-4/pox_Commands.ts | 19 ++++ .../tests/pox-4/pox_DelegateStxCommand.ts | 1 + .../pox-4/pox_RevokeDelegateStxCommand.ts | 96 +++++++++++++++++++ 5 files changed, 118 insertions(+) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index c18c11e6c9..805ea2f53a 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -67,6 +67,7 @@ describe("PoX-4 invariant tests", () => { hasPoolMembers: [], delegatedTo: "", delegatedMaxAmount: 0, + delegatedUntilBurnHt: 0, amountLocked: 0, amountUnlocked: initialUstxBalance, unlockHeight: 0, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index f88d64ccd4..138027d5d5 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -28,6 +28,7 @@ export type Wallet = { hasPoolMembers: StxAddress[]; delegatedTo: StxAddress; delegatedMaxAmount: number; + delegatedUntilBurnHt: number; amountLocked: number; amountUnlocked: number; unlockHeight: number; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 88fbea9a6b..92d2b87ae5 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -7,6 +7,7 @@ import { DelegateStxCommand } from "./pox_DelegateStxCommand"; import { DelegateStackStxCommand } from "./pox_DelegateStackStxCommand"; import { Simnet } from "@hirosystems/clarinet-sdk"; import { Cl, cvToValue } from "@stacks/transactions"; +import { RevokeDelegateStxCommand } from "./pox_RevokeDelegateStxCommand"; export function PoxCommands( wallets: Map, network: Simnet, @@ -66,6 +67,24 @@ export function PoxCommands( r.amount, ) ), + // RevokeDelegateStxCommand + fc.record({ + wallet: fc.constantFrom(...wallets.values()), + delegateTo: fc.constantFrom(...wallets.values()), + untilBurnHt: fc.integer({ min: 1 }), + amount: fc.bigInt({ min:0n, max: 100_000_000_000_000n }), + }).map(( + r: { + wallet: Wallet; + delegateTo: Wallet; + untilBurnHt: number; + amount: bigint; + }, + ) => + new RevokeDelegateStxCommand( + r.wallet + ) + ), // DelegateStackStxCommand fc.record({ operator: fc.constantFrom(...wallets.values()), diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts index 08d2988293..28fd596643 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts @@ -83,6 +83,7 @@ export class DelegateStxCommand implements PoxCommand { wallet.hasDelegated = true; wallet.delegatedTo = this.delegateTo.stxAddress; wallet.delegatedMaxAmount = amountUstx; + wallet.delegatedUntilBurnHt = this.untilBurnHt delegatedWallet.hasPoolMembers.push(wallet.stxAddress); // Log to console for debugging purposes. This is not necessary for the diff --git a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts new file mode 100644 index 0000000000..5882402e7e --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts @@ -0,0 +1,96 @@ +import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { poxAddressToTuple } from "@stacks/stacking"; +import { expect } from "vitest"; +import { Cl, someCV, tupleCV } from "@stacks/transactions"; + +/** + * The `RevokeDelegateStxCommand` revokes the delegation for stacking within PoX-4. + * + * Constraints for running this command include: + * - The `Stacker` has to currently be delegating. + */ +export class RevokeDelegateStxCommand implements PoxCommand { + readonly wallet: Wallet; + + /** + * Constructs a RevokeDelegateStxCommand to revoke delegate uSTX for stacking. + * + * @param wallet - Represents the Stacker's wallet. + */ + constructor(wallet: Wallet) { + this.wallet = wallet; + } + + check(model: Readonly): boolean { + // Constraints for running this command include: + // - The Stacker has to currently be delegating. + return ( + model.stackingMinimum > 0 && + model.wallets.get(this.wallet.stxAddress)!.hasDelegated === true + ); + } + + run(model: Stub, real: Real): void { + // Get the Operator's wallet + const operatorWallet = model.wallets.get(this.wallet.delegatedTo)!; + + // Act + const revokeDelegateStx = real.network.callPublicFn( + "ST000000000000000000002AMW42H.pox-4", + "revoke-delegate-stx", + [], + this.wallet.stxAddress, + ); + + // Assert + expect(revokeDelegateStx.result).toBeOk( + someCV( + tupleCV({ + "amount-ustx": Cl.uint(this.wallet.delegatedMaxAmount), + "delegated-to": Cl.principal( + operatorWallet.stxAddress || "", + ), + "pox-addr": Cl.some( + poxAddressToTuple(operatorWallet.btcAddress || ""), + ), + "until-burn-ht": Cl.some(Cl.uint(this.wallet.delegatedUntilBurnHt)), + }), + ), + ); + + // Get the Stacker's wallet from the model and update the two wallets involved with the new state. + const wallet = model.wallets.get(this.wallet.stxAddress)!; + // Update model so that we know this wallet is not delegating anymore. + // This is important in order to prevent the test from revoking the delegation + // multiple times with the same address. + wallet.hasDelegated = false; + wallet.delegatedTo = ""; + wallet.delegatedUntilBurnHt = 0; + wallet.delegatedMaxAmount = 0; + + // Remove the Stacker from the Pool Operator's pool members list + let walletIndexInDelegatorsList = operatorWallet.hasPoolMembers.indexOf( + wallet.stxAddress, + ); + expect(walletIndexInDelegatorsList).toBeGreaterThan(-1); + operatorWallet.hasPoolMembers.splice(walletIndexInDelegatorsList, 1); + + // 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. + console.info( + `✓ ${ + this.wallet.label.padStart( + 8, + " ", + ) + } ${"revoke-delegate-stx".padStart(34, " ")}`, + ); + } + + 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.wallet.stxAddress} revoke-delegate-stx`; + } +} From 849be91bd6b0ca7d318c970ea07ce4fe3810aa84 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Mon, 25 Mar 2024 15:46:26 +0200 Subject: [PATCH 067/129] test(pox-4-tests): Add AllowContractCallerCommand --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 2 + .../pox-4/pox_AllowContractCallerCommand.ts | 97 +++++++++++++++++++ .../tests/pox-4/pox_CommandModel.ts | 2 + .../tests/pox-4/pox_Commands.ts | 19 ++++ 4 files changed, 120 insertions(+) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index 805ea2f53a..4331f434a2 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -71,6 +71,8 @@ describe("PoX-4 invariant tests", () => { amountLocked: 0, amountUnlocked: initialUstxBalance, unlockHeight: 0, + allowedContractCaller: '', + callerAllowedBy: [] }; }); diff --git a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts new file mode 100644 index 0000000000..48dc8a6eb1 --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts @@ -0,0 +1,97 @@ +import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { expect } from "vitest"; +import { boolCV, Cl } from "@stacks/transactions"; + +/** + * The `AllowContractCallerComand` gives a `contract-caller` authorization to call stacking methods. + * Normally, stacking methods may only be invoked by direct transactions (i.e., the tx-sender + * issues a direct contract-call to the stacking methods). + * By issuing an allowance, the tx-sender may call stacking methods through the allowed contract. + * + * There are no constraints for running this command. + */ +export class AllowContractCallerCommand implements PoxCommand { + readonly wallet: Wallet; + readonly allowanceTo: Wallet; + readonly allowUntilBurnHt: number | undefined; + + /** + * Constructs an `AllowContractCallerComand` that authorizes a `contract-caller` to call + * stacking methods. + * + * @param wallet - Represents the Stacker's wallet. + * @param allowanceTo - Represents the authorized `contract-caller` (i.e. a stacking pool) + * @param alllowUntilBurnHt - The burn block height until the authorization is valid. + */ + + constructor( + wallet: Wallet, + allowanceTo: Wallet, + allowUntilBurnHt: number | undefined, + ) { + this.wallet = wallet; + this.allowanceTo = allowanceTo; + this.allowUntilBurnHt = allowUntilBurnHt; + } + + check(): boolean { + // There are no constraints for running this command. + return true; + } + + run(model: Stub, real: Real): void { + // Arrange + const untilBurnHtOptionalCv = this.allowUntilBurnHt === undefined + ? Cl.none() + : Cl.some(Cl.uint(this.allowUntilBurnHt)); + + // Act + const allowContractCaller = real.network.callPublicFn( + "ST000000000000000000002AMW42H.pox-4", + "allow-contract-caller", + [ + // (caller principal) + Cl.principal(this.allowanceTo.stxAddress), + // (until-burn-ht (optional uint)) + untilBurnHtOptionalCv, + ], + this.wallet.stxAddress, + ); + + // Assert + expect(allowContractCaller.result).toBeOk(boolCV(true)); + + // Get the wallets involved from the model and update it with the new state. + const wallet = model.wallets.get(this.wallet.stxAddress)!; + const callerToAllow = model.wallets.get(this.allowanceTo.stxAddress)!; + // Update model so that we know this wallet has authorized a contract-caller. + + wallet.allowedContractCaller = this.allowanceTo.stxAddress; + callerToAllow.callerAllowedBy.push(wallet.stxAddress); + + // 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. + console.info( + `✓ ${ + this.wallet.label.padStart( + 8, + " ", + ) + } ${ + "allow-contract-caller".padStart( + 34, + " ", + ) + } ${this.allowanceTo.label.padStart(12, " ")} ${"until".padStart(53)} ${ + (this.allowUntilBurnHt || "none").toString().padStart(17) + }`, + ); + } + + 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.wallet.stxAddress} allow-contract-caller ${this.allowanceTo.stxAddress} until burn ht ${this.allowUntilBurnHt}`; + } +} diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 138027d5d5..ad5b3dd2fa 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -32,6 +32,8 @@ export type Wallet = { amountLocked: number; amountUnlocked: number; unlockHeight: number; + allowedContractCaller: StxAddress; + callerAllowedBy: StxAddress[]; }; export type PoxCommand = fc.Command; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 92d2b87ae5..85a6777d3a 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -8,6 +8,7 @@ import { DelegateStackStxCommand } from "./pox_DelegateStackStxCommand"; import { Simnet } from "@hirosystems/clarinet-sdk"; import { Cl, cvToValue } from "@stacks/transactions"; import { RevokeDelegateStxCommand } from "./pox_RevokeDelegateStxCommand"; +import { AllowContractCallerCommand } from "./pox_AllowContractCallerCommand"; export function PoxCommands( wallets: Map, network: Simnet, @@ -112,6 +113,24 @@ export function PoxCommands( r.amount ) ), + // AllowContractCallerCommand + fc.record({ + wallet: fc.constantFrom(...wallets.values()), + allowanceTo: fc.constantFrom(...wallets.values()), + alllowUntilBurnHt: fc.option(fc.integer({ min: 1 }), {nil: undefined}), + }) + .map( + (r: { + wallet: Wallet; + allowanceTo: Wallet; + alllowUntilBurnHt: number | undefined; + }) => + new AllowContractCallerCommand( + r.wallet, + r.allowanceTo, + r.alllowUntilBurnHt, + ), + ), // GetStxAccountCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), From 83ef9c1f35e06c50fa6156f33db6f59a7e2ff8f4 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Mon, 25 Mar 2024 15:49:34 +0200 Subject: [PATCH 068/129] refactor(pox-4-tests): Remove unused generators from RevokeDelegateStxCommand --- contrib/core-contract-tests/tests/pox-4/pox_Commands.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 85a6777d3a..062afd2e59 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -71,15 +71,9 @@ export function PoxCommands( // RevokeDelegateStxCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), - delegateTo: fc.constantFrom(...wallets.values()), - untilBurnHt: fc.integer({ min: 1 }), - amount: fc.bigInt({ min:0n, max: 100_000_000_000_000n }), }).map(( r: { wallet: Wallet; - delegateTo: Wallet; - untilBurnHt: number; - amount: bigint; }, ) => new RevokeDelegateStxCommand( From 0139de9c7b9ca1f3c48917e71c84d54f62f87091 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Mon, 25 Mar 2024 17:31:58 +0200 Subject: [PATCH 069/129] wip(pox-4-tests): Add check for DelegateStackStx period --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 1 + .../tests/pox-4/pox_CommandModel.ts | 1 + .../tests/pox-4/pox_Commands.ts | 2 +- .../pox-4/pox_DelegateStackStxCommand.ts | 24 ++++++++++++------- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index 4331f434a2..bd01ccce7c 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -28,6 +28,7 @@ describe("PoX-4 invariant tests", () => { const model: Stub = { stackingMinimum: 0, wallets: new Map(), + network: sut.network }; const wallets = [ diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index ad5b3dd2fa..73ed4f9588 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -9,6 +9,7 @@ export type StxAddress = string; export type Stub = { stackingMinimum: number; wallets: Map; + network: Simnet; }; export type Real = { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 062afd2e59..a6de622eaf 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -154,7 +154,7 @@ const currentCycle = (network: Simnet) => ).result, )); -const currentCycleFirstBlock = (network: Simnet) => +export const currentCycleFirstBlock = (network: Simnet) => Number(cvToValue( network.callReadOnlyFn( "ST000000000000000000002AMW42H.pox-4", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index 4fb9ed09a4..4d6aafd095 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -2,6 +2,7 @@ import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; import { poxAddressToTuple } from "@stacks/stacking"; import { assert, expect } from "vitest"; import { Cl, ClarityType, isClarityType } from "@stacks/transactions"; +import { currentCycleFirstBlock } from "./pox_Commands.ts"; /** * The `DelegateStackStxCommand` locks STX for stacking within PoX-4 on behalf of a delegator. @@ -16,10 +17,11 @@ import { Cl, ClarityType, isClarityType } from "@stacks/transactions"; * - The stacked STX 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 + * Stacker's balance. * - The stacked uSTX amount should be greater than or equal to the - * minimum threshold of uSTX + * minimum threshold of uSTX. * - The Operator has to currently be delegated by the Stacker. + * - The Period has to fit the last delegation burn block height. */ export class DelegateStackStxCommand implements PoxCommand { readonly operator: Wallet; @@ -58,18 +60,21 @@ export class DelegateStackStxCommand implements PoxCommand { // - A minimum threshold of uSTX must be met, determined by the // `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 + // operation. + // - The Stacker has to currently be delegating to the Operator. // - The stacked uSTX amount should be less than or equal to the - // delegated amount + // delegated amount. // - The stacked uSTX amount should be less than or equal to the - // Stacker's balance + // Stacker's balance. // - The stacked uSTX amount should be greater than or equal to the - // minimum threshold of uSTX - // - The Operator has to currently be delegated by the Stacker + // minimum threshold of uSTX. + // - The Operator has to currently be delegated by the Stacker. + // - The Period has to fit the last delegation burn block height. const operatorWallet = model.wallets.get(this.operator.stxAddress)!; const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; + const unlockBurnHt = currentCycleFirstBlock(model.network) + 1050 * (this.period + 1) + return ( model.stackingMinimum > 0 && !stackerWallet.isStacking && @@ -77,7 +82,8 @@ export class DelegateStackStxCommand implements PoxCommand { stackerWallet.delegatedMaxAmount >= Number(this.amountUstx) && Number(this.amountUstx) <= stackerWallet.ustxBalance && Number(this.amountUstx) >= model.stackingMinimum && - operatorWallet.hasPoolMembers.includes(stackerWallet.stxAddress) + operatorWallet.hasPoolMembers.includes(stackerWallet.stxAddress) && + unlockBurnHt <= stackerWallet.delegatedUntilBurnHt ); } From 364ea595e865bcd111fa71d1914037a0786475c5 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Mon, 25 Mar 2024 18:57:40 +0100 Subject: [PATCH 070/129] refactor(pox-4-tests): Integrate Clarity value generation This change optimizes the generation of Clarity values for the allowUntilBurnHt property in the AllowContractCallerCommand tests. By directly creating Clarity optional values (none or some(uint)) within the fast-check generator, we remove the need for conditional post-processing. This approach simplifies the test setup and aligns more closely with the intended usage patterns of the Clarity and fast-check libraries. --- .../pox-4/pox_AllowContractCallerCommand.ts | 24 ++++++++++--------- .../tests/pox-4/pox_Commands.ts | 9 ++++--- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts index 48dc8a6eb1..d8988e1309 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts @@ -1,6 +1,6 @@ import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; import { expect } from "vitest"; -import { boolCV, Cl } from "@stacks/transactions"; +import { boolCV, Cl, ClarityType, OptionalCV, UIntCV } from "@stacks/transactions"; /** * The `AllowContractCallerComand` gives a `contract-caller` authorization to call stacking methods. @@ -13,7 +13,7 @@ import { boolCV, Cl } from "@stacks/transactions"; export class AllowContractCallerCommand implements PoxCommand { readonly wallet: Wallet; readonly allowanceTo: Wallet; - readonly allowUntilBurnHt: number | undefined; + readonly allowUntilBurnHt: OptionalCV; /** * Constructs an `AllowContractCallerComand` that authorizes a `contract-caller` to call @@ -27,7 +27,7 @@ export class AllowContractCallerCommand implements PoxCommand { constructor( wallet: Wallet, allowanceTo: Wallet, - allowUntilBurnHt: number | undefined, + allowUntilBurnHt: OptionalCV, ) { this.wallet = wallet; this.allowanceTo = allowanceTo; @@ -40,11 +40,6 @@ export class AllowContractCallerCommand implements PoxCommand { } run(model: Stub, real: Real): void { - // Arrange - const untilBurnHtOptionalCv = this.allowUntilBurnHt === undefined - ? Cl.none() - : Cl.some(Cl.uint(this.allowUntilBurnHt)); - // Act const allowContractCaller = real.network.callPublicFn( "ST000000000000000000002AMW42H.pox-4", @@ -53,7 +48,7 @@ export class AllowContractCallerCommand implements PoxCommand { // (caller principal) Cl.principal(this.allowanceTo.stxAddress), // (until-burn-ht (optional uint)) - untilBurnHtOptionalCv, + this.allowUntilBurnHt, ], this.wallet.stxAddress, ); @@ -83,7 +78,7 @@ export class AllowContractCallerCommand implements PoxCommand { " ", ) } ${this.allowanceTo.label.padStart(12, " ")} ${"until".padStart(53)} ${ - (this.allowUntilBurnHt || "none").toString().padStart(17) + optionalCVToString(this.allowUntilBurnHt).padStart(17) }`, ); } @@ -92,6 +87,13 @@ export class AllowContractCallerCommand implements PoxCommand { // 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.wallet.stxAddress} allow-contract-caller ${this.allowanceTo.stxAddress} until burn ht ${this.allowUntilBurnHt}`; + return `${this.wallet.stxAddress} allow-contract-caller ${this.allowanceTo.stxAddress} until burn ht ${ + optionalCVToString(this.allowUntilBurnHt) + }`; } } + +const optionalCVToString = (optional: OptionalCV): string => + optional.type === ClarityType.OptionalSome + ? (optional.value as UIntCV).value.toString() + : "none"; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index a6de622eaf..4ab67a63f9 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -6,7 +6,7 @@ import { StackStxCommand } from "./pox_StackStxCommand"; import { DelegateStxCommand } from "./pox_DelegateStxCommand"; import { DelegateStackStxCommand } from "./pox_DelegateStackStxCommand"; import { Simnet } from "@hirosystems/clarinet-sdk"; -import { Cl, cvToValue } from "@stacks/transactions"; +import { Cl, cvToValue, OptionalCV, UIntCV } from "@stacks/transactions"; import { RevokeDelegateStxCommand } from "./pox_RevokeDelegateStxCommand"; import { AllowContractCallerCommand } from "./pox_AllowContractCallerCommand"; @@ -111,13 +111,16 @@ export function PoxCommands( fc.record({ wallet: fc.constantFrom(...wallets.values()), allowanceTo: fc.constantFrom(...wallets.values()), - alllowUntilBurnHt: fc.option(fc.integer({ min: 1 }), {nil: undefined}), + alllowUntilBurnHt: fc.oneof( + fc.constant(Cl.none()), + fc.integer({ min: 1 }).map((value) => Cl.some(Cl.uint(value))), + ), }) .map( (r: { wallet: Wallet; allowanceTo: Wallet; - alllowUntilBurnHt: number | undefined; + alllowUntilBurnHt: OptionalCV; }) => new AllowContractCallerCommand( r.wallet, From 271c15bbe8991e004e62358606faeb69e0c5a924 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Mon, 25 Mar 2024 23:41:11 +0100 Subject: [PATCH 071/129] refactor(pox-4-tests): Dynamic `unlockBurnHt` and cleaner state - Moved `network` from `Stub` (Model) to `Real`, streamlining state management. - `unlockBurnHt` now dynamically calculated, passed via constructor, ensuring alignment with generated `period`. - Utilized `fast-check`'s `chain` for dynamic `unlockBurnHt` calculation, improving test accuracy. - Enforces discipline in constructor use and `check` method validation, highlighting the importance of explicit state and parameter handling for reliable testing. --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 1 - .../tests/pox-4/pox_CommandModel.ts | 1 - .../tests/pox-4/pox_Commands.ts | 22 ++++++++++--------- .../pox-4/pox_DelegateStackStxCommand.ts | 8 ++++--- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index bd01ccce7c..4331f434a2 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -28,7 +28,6 @@ describe("PoX-4 invariant tests", () => { const model: Stub = { stackingMinimum: 0, wallets: new Map(), - network: sut.network }; const wallets = [ diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 73ed4f9588..ad5b3dd2fa 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -9,7 +9,6 @@ export type StxAddress = string; export type Stub = { stackingMinimum: number; wallets: Map; - network: Simnet; }; export type Real = { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 4ab67a63f9..859316451c 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -90,21 +90,23 @@ export function PoxCommands( }), period: fc.integer({ min: 1, max: 12 }), amount: fc.bigInt({ min:0n, max: 100_000_000_000_000n }), - }).map(( - r: { - operator: Wallet; - stacker: Wallet; - startBurnHt: number; - period: number; - amount: bigint; - }, - ) => + }).chain((r) => + fc.record({ + unlockBurnHt: fc.constant( + currentCycleFirstBlock(network) + 1050 * (r.period + 1), + ), + }).map((unlockBurnHtRecord) => ({ + ...r, + ...unlockBurnHtRecord, + })) + ).map((r) => new DelegateStackStxCommand( r.operator, r.stacker, r.startBurnHt, r.period, - r.amount + r.amount, + r.unlockBurnHt, ) ), // AllowContractCallerCommand diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index 4d6aafd095..f23b4817a5 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -2,7 +2,6 @@ import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; import { poxAddressToTuple } from "@stacks/stacking"; import { assert, expect } from "vitest"; import { Cl, ClarityType, isClarityType } from "@stacks/transactions"; -import { currentCycleFirstBlock } from "./pox_Commands.ts"; /** * The `DelegateStackStxCommand` locks STX for stacking within PoX-4 on behalf of a delegator. @@ -29,6 +28,7 @@ export class DelegateStackStxCommand implements PoxCommand { readonly startBurnHt: number; readonly period: number; readonly amountUstx: bigint; + readonly unlockBurnHt: number; /** * Constructs a `DelegateStackStxCommand` to lock uSTX as a Pool Operator @@ -40,6 +40,7 @@ export class DelegateStackStxCommand implements PoxCommand { * @param period - Number of reward cycles to lock uSTX. * @param amountUstx - The uSTX amount stacked by the Operator on behalf * of the Stacker + * @param unlockBurnHt - The burn height at which the uSTX is unlocked. */ constructor( operator: Wallet, @@ -47,12 +48,14 @@ export class DelegateStackStxCommand implements PoxCommand { startBurnHt: number, period: number, amountUstx: bigint, + unlockBurnHt: number, ) { this.operator = operator; this.stacker = stacker; this.startBurnHt = startBurnHt; this.period = period; this.amountUstx = amountUstx; + this.unlockBurnHt = unlockBurnHt; } check(model: Readonly): boolean { @@ -73,7 +76,6 @@ export class DelegateStackStxCommand implements PoxCommand { const operatorWallet = model.wallets.get(this.operator.stxAddress)!; const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; - const unlockBurnHt = currentCycleFirstBlock(model.network) + 1050 * (this.period + 1) return ( model.stackingMinimum > 0 && @@ -83,7 +85,7 @@ export class DelegateStackStxCommand implements PoxCommand { Number(this.amountUstx) <= stackerWallet.ustxBalance && Number(this.amountUstx) >= model.stackingMinimum && operatorWallet.hasPoolMembers.includes(stackerWallet.stxAddress) && - unlockBurnHt <= stackerWallet.delegatedUntilBurnHt + this.unlockBurnHt <= stackerWallet.delegatedUntilBurnHt ); } From e1c0f0468509a2ed5869399ee67c1805c99faafc Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Tue, 26 Mar 2024 23:36:14 +0100 Subject: [PATCH 072/129] feat(dependencies): Update stacks.js packages for PoX-4 stacking client --- contrib/core-contract-tests/package-lock.json | 50 ++++++++++--------- contrib/core-contract-tests/package.json | 3 +- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/contrib/core-contract-tests/package-lock.json b/contrib/core-contract-tests/package-lock.json index 50ded82d38..5fd11568ce 100644 --- a/contrib/core-contract-tests/package-lock.json +++ b/contrib/core-contract-tests/package-lock.json @@ -11,7 +11,8 @@ "dependencies": { "@hirosystems/clarinet-sdk": "^2.4.1", "@stacks/clarunit": "0.0.1", - "@stacks/transactions": "^6.12.0", + "@stacks/stacking": "^6.13.0", + "@stacks/transactions": "^6.13.0", "chokidar-cli": "^3.0.0", "fast-check": "^3.15.1", "typescript": "^5.4.2", @@ -1219,23 +1220,23 @@ } }, "node_modules/@stacks/common": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/@stacks/common/-/common-6.10.0.tgz", - "integrity": "sha512-6x5Z7AKd9/kj3+DYE9xIDIkFLHihBH614i2wqrZIjN02WxVo063hWSjIlUxlx8P4gl6olVzlOy5LzhLJD9OP0A==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@stacks/common/-/common-6.13.0.tgz", + "integrity": "sha512-wwzyihjaSdmL6NxKvDeayy3dqM0L0Q2sawmdNtzJDi0FnXuJGm5PeapJj7bEfcI9XwI7Bw5jZoC6mCn9nc5YIw==", "dependencies": { "@types/bn.js": "^5.1.0", "@types/node": "^18.0.4" } }, "node_modules/@stacks/encryption": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@stacks/encryption/-/encryption-6.12.0.tgz", - "integrity": "sha512-CubE51pHrcxx3yA+xapevPgA9UDleIoEaUZ06/9uD91B42yvTg37HyS8t06rzukU9q+X7Cv2I/+vbuf4nJIo8g==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@stacks/encryption/-/encryption-6.13.0.tgz", + "integrity": "sha512-CsacBxY1XBVXBuJ5erJPjB5FmQ8KGJ/ft02/pIM6WrJ31ZcBdkn2BPV1AsPSD5qsIkiMdHAe14WKIwm8M2SWtQ==", "dependencies": { "@noble/hashes": "1.1.5", "@noble/secp256k1": "1.7.1", "@scure/bip39": "1.1.0", - "@stacks/common": "^6.10.0", + "@stacks/common": "^6.13.0", "@types/node": "^18.0.4", "base64-js": "^1.5.1", "bs58": "^5.0.0", @@ -1244,25 +1245,26 @@ } }, "node_modules/@stacks/network": { - "version": "6.11.3", - "resolved": "https://registry.npmjs.org/@stacks/network/-/network-6.11.3.tgz", - "integrity": "sha512-c4ClCU/QUwuu8NbHtDKPJNa0M5YxauLN3vYaR0+S4awbhVIKFQSxirm9Q9ckV1WBh7FtD6u2S0x+tDQGAODjNg==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@stacks/network/-/network-6.13.0.tgz", + "integrity": "sha512-Ss/Da4BNyPBBj1OieM981fJ7SkevKqLPkzoI1+Yo7cYR2df+0FipIN++Z4RfpJpc8ne60vgcx7nJZXQsiGhKBQ==", "dependencies": { - "@stacks/common": "^6.10.0", + "@stacks/common": "^6.13.0", "cross-fetch": "^3.1.5" } }, "node_modules/@stacks/stacking": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@stacks/stacking/-/stacking-6.12.0.tgz", - "integrity": "sha512-XBxwbaCGRPnjpjspb3CBXrlZl6xR+gghLMz9PQNPdpuIbBDFa0SGeHgqjtpVU+2DVL4UyBx8PVsAWtlssyVGng==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@stacks/stacking/-/stacking-6.13.0.tgz", + "integrity": "sha512-ivzFZkVpqzneJ71T1eZTW8Rr5oVYrs4HkwZqGHxDEySb1I6p96hojH5gEguj9g7szQiyeYLj1dreCvhLh6ET6A==", "dependencies": { + "@noble/hashes": "1.1.5", "@scure/base": "1.1.1", - "@stacks/common": "^6.10.0", - "@stacks/encryption": "^6.12.0", - "@stacks/network": "^6.11.3", + "@stacks/common": "^6.13.0", + "@stacks/encryption": "^6.13.0", + "@stacks/network": "^6.13.0", "@stacks/stacks-blockchain-api-types": "^0.61.0", - "@stacks/transactions": "^6.12.0", + "@stacks/transactions": "^6.13.0", "bs58": "^5.0.0" } }, @@ -1283,14 +1285,14 @@ "integrity": "sha512-yPOfTUboo5eA9BZL/hqMcM71GstrFs9YWzOrJFPeP4cOO1wgYvAcckgBRbgiE3NqeX0A7SLZLDAXLZbATuRq9w==" }, "node_modules/@stacks/transactions": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@stacks/transactions/-/transactions-6.12.0.tgz", - "integrity": "sha512-gRP3SfTaAIoTdjMvOiLrMZb/senqB8JQlT5Y4C3/CiHhiprYwTx7TbOCSa7WsNOU99H4aNfHvatmymuggXQVkA==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/@stacks/transactions/-/transactions-6.13.0.tgz", + "integrity": "sha512-xrx09qsXL/tWCkvAArzsFQqtZKDXyedjdVB9uX8xw+cQCi3xZ7r5MHMKzvEsTgJz3EO+MkQBXcvI1uzfuoqhcA==", "dependencies": { "@noble/hashes": "1.1.5", "@noble/secp256k1": "1.7.1", - "@stacks/common": "^6.10.0", - "@stacks/network": "^6.11.3", + "@stacks/common": "^6.13.0", + "@stacks/network": "^6.13.0", "c32check": "^2.0.0", "lodash.clonedeep": "^4.5.0" } diff --git a/contrib/core-contract-tests/package.json b/contrib/core-contract-tests/package.json index 7ba3ba62e2..0d80a4e570 100644 --- a/contrib/core-contract-tests/package.json +++ b/contrib/core-contract-tests/package.json @@ -13,7 +13,8 @@ "dependencies": { "@hirosystems/clarinet-sdk": "^2.4.1", "@stacks/clarunit": "0.0.1", - "@stacks/transactions": "^6.12.0", + "@stacks/stacking": "^6.13.0", + "@stacks/transactions": "^6.13.0", "chokidar-cli": "^3.0.0", "fast-check": "^3.15.1", "typescript": "^5.4.2", From 243c3c9b7dd0c53cbc1452e99fe5a8730b50454a Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Wed, 27 Mar 2024 00:53:54 +0100 Subject: [PATCH 073/129] feat(pox-4-tests): Add `logCommand` for structured output using `ololog` Replace direct `console.log` and manual padding with `logCommand`, enhancing readability and simplifying logging. --- contrib/core-contract-tests/package-lock.json | 85 +++++++++++++++++++ contrib/core-contract-tests/package.json | 1 + .../pox-4/pox_AllowContractCallerCommand.ts | 18 +--- .../tests/pox-4/pox_CommandModel.ts | 13 +++ .../pox-4/pox_DelegateStackStxCommand.ts | 10 +-- .../tests/pox-4/pox_DelegateStxCommand.ts | 20 +---- .../pox-4/pox_GetStackingMinimumCommand.ts | 10 +-- .../tests/pox-4/pox_GetStxAccountCommand.ts | 14 +-- .../pox-4/pox_RevokeDelegateStxCommand.ts | 11 +-- .../tests/pox-4/pox_StackStxCommand.ts | 10 +-- 10 files changed, 113 insertions(+), 79 deletions(-) diff --git a/contrib/core-contract-tests/package-lock.json b/contrib/core-contract-tests/package-lock.json index 5fd11568ce..f636a0d085 100644 --- a/contrib/core-contract-tests/package-lock.json +++ b/contrib/core-contract-tests/package-lock.json @@ -15,6 +15,7 @@ "@stacks/transactions": "^6.13.0", "chokidar-cli": "^3.0.0", "fast-check": "^3.15.1", + "ololog": "^1.1.175", "typescript": "^5.4.2", "vite": "^5.1.6", "vitest": "^1.3.1", @@ -1476,6 +1477,11 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/ansicolor": { + "version": "1.1.100", + "resolved": "https://registry.npmjs.org/ansicolor/-/ansicolor-1.1.100.tgz", + "integrity": "sha512-Jl0pxRfa9WaQVUX57AB8/V2my6FJxrOR1Pp2qqFbig20QB4HzUoQ48THTKAgHlUCJeQm/s2WoOPcoIDhyCL/kw==" + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -1493,6 +1499,14 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, + "node_modules/as-table": { + "version": "1.0.55", + "resolved": "https://registry.npmjs.org/as-table/-/as-table-1.0.55.tgz", + "integrity": "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==", + "dependencies": { + "printable-characters": "^1.0.42" + } + }, "node_modules/assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -1919,6 +1933,11 @@ "node": ">= 8" } }, + "node_modules/data-uri-to-buffer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-2.0.2.tgz", + "integrity": "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==" + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -2347,6 +2366,15 @@ "node": "*" } }, + "node_modules/get-source": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/get-source/-/get-source-2.0.12.tgz", + "integrity": "sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==", + "dependencies": { + "data-uri-to-buffer": "^2.0.0", + "source-map": "^0.6.1" + } + }, "node_modules/get-stream": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", @@ -2792,6 +2820,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ololog": { + "version": "1.1.175", + "resolved": "https://registry.npmjs.org/ololog/-/ololog-1.1.175.tgz", + "integrity": "sha512-DSPbsvZzLshFiPI1ul7iJDn6wI75goOLyrn8uRB92sPon5LS8J2KlAIkSoHXtRztb2idPjuzq3R1J58hN2qOEA==", + "dependencies": { + "ansicolor": "^1.1.84", + "pipez": "^1.1.12", + "printable-characters": "^1.0.42", + "stacktracey": "^2.1.6", + "string.bullet": "^1.0.12", + "string.ify": "^1.0.64" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -2939,6 +2980,11 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pipez": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/pipez/-/pipez-1.1.12.tgz", + "integrity": "sha512-VuJ+c44f3s/4cirqtBI3wa0LscCo1IG9sQH2DnClJWEMkGylE52mDjLLHR5QyLjij1EiGocMEIAJsmpyXczXJQ==" + }, "node_modules/pkg-types": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", @@ -3008,6 +3054,11 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/printable-characters": { + "version": "1.0.42", + "resolved": "https://registry.npmjs.org/printable-characters/-/printable-characters-1.0.42.tgz", + "integrity": "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==" + }, "node_modules/process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -3255,6 +3306,14 @@ "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", @@ -3268,6 +3327,15 @@ "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==" }, + "node_modules/stacktracey": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/stacktracey/-/stacktracey-2.1.8.tgz", + "integrity": "sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==", + "dependencies": { + "as-table": "^1.0.36", + "get-source": "^2.0.12" + } + }, "node_modules/std-env": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", @@ -3286,6 +3354,23 @@ "node": ">=8" } }, + "node_modules/string.bullet": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/string.bullet/-/string.bullet-1.0.12.tgz", + "integrity": "sha512-6+tQyad/ux52N+7wUcjmxeK5TfdeykBBLHQPk8MxUVrk9JwHzJnuxsJzjjpWAuz0x3EmnVGCg0ibMHqez1l/qQ==", + "dependencies": { + "printable-characters": "^1.0.26" + } + }, + "node_modules/string.ify": { + "version": "1.0.64", + "resolved": "https://registry.npmjs.org/string.ify/-/string.ify-1.0.64.tgz", + "integrity": "sha512-4Aa5yndnuOhE1GV2W3ht4rQ08XHq46JLXmSOv0jeUWEzqliBvm8lAXvt+66np+J9DkoCZikFzTzjXVLRR0F/Xw==", + "dependencies": { + "printable-characters": "^1.0.42", + "string.bullet": "^1.0.12" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", diff --git a/contrib/core-contract-tests/package.json b/contrib/core-contract-tests/package.json index 0d80a4e570..a6c8b23262 100644 --- a/contrib/core-contract-tests/package.json +++ b/contrib/core-contract-tests/package.json @@ -17,6 +17,7 @@ "@stacks/transactions": "^6.13.0", "chokidar-cli": "^3.0.0", "fast-check": "^3.15.1", + "ololog": "^1.1.175", "typescript": "^5.4.2", "vite": "^5.1.6", "vitest": "^1.3.1", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts index d8988e1309..64f4a32142 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts @@ -1,4 +1,4 @@ -import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; import { expect } from "vitest"; import { boolCV, Cl, ClarityType, OptionalCV, UIntCV } from "@stacks/transactions"; @@ -66,21 +66,7 @@ export class AllowContractCallerCommand 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. - console.info( - `✓ ${ - this.wallet.label.padStart( - 8, - " ", - ) - } ${ - "allow-contract-caller".padStart( - 34, - " ", - ) - } ${this.allowanceTo.label.padStart(12, " ")} ${"until".padStart(53)} ${ - optionalCVToString(this.allowUntilBurnHt).padStart(17) - }`, - ); + logCommand(`✓ ${this.wallet.label}`, "allow-contract-caller", this.allowanceTo.label, "until", optionalCVToString(this.allowUntilBurnHt)); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index ad5b3dd2fa..449ef3b672 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -1,4 +1,5 @@ import fc from "fast-check"; +import ololog from "ololog"; import { Simnet } from "@hirosystems/clarinet-sdk"; import { StacksPrivateKey } from "@stacks/transactions"; @@ -37,3 +38,15 @@ export type Wallet = { }; export type PoxCommand = fc.Command; + +export const logCommand = (...items: (string | undefined)[]) => { + // Ensure we only render up to the first 10 items for brevity. + const renderItems = items.slice(0, 10); + const columnWidth = 23; + // Pad each column to the same width. + const prettyPrint = renderItems.map((content) => + content ? content.padEnd(columnWidth) : "".padEnd(columnWidth) + ); + + ololog.configure({ locate: false })(prettyPrint.join("")); +}; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index f23b4817a5..ae4d61cc7b 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -1,4 +1,4 @@ -import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; import { poxAddressToTuple } from "@stacks/stacking"; import { assert, expect } from "vitest"; import { Cl, ClarityType, isClarityType } from "@stacks/transactions"; @@ -146,13 +146,7 @@ export class DelegateStackStxCommand 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. - console.info( - `✓ ${this.operator.label.padStart(8, " ")} Ӿ ${this.stacker.label.padStart(8, " ")} ${ - "delegate-stack-stx".padStart(23, " ") - } ${"lock-amount".padStart(12, " ")} ${ - this.amountUstx.toString().padStart(15, " ") - } ${"until".padStart(37)} ${this.stacker.unlockHeight.toString().padStart(17)}`, - ); + logCommand(`✓ ${this.operator.label} Ӿ ${this.stacker.label}`, "delegate-stack-stx", "lock-amount", this.amountUstx.toString(), "until", this.stacker.unlockHeight.toString()); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts index 28fd596643..bc638719fd 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts @@ -1,4 +1,4 @@ -import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; import { poxAddressToTuple } from "@stacks/stacking"; import { expect } from "vitest"; import { boolCV, Cl } from "@stacks/transactions"; @@ -88,23 +88,7 @@ export class DelegateStxCommand implements PoxCommand { delegatedWallet.hasPoolMembers.push(wallet.stxAddress); // 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. - console.info( - `✓ ${this.wallet.label.padStart(8, " ")} ${ - "delegate-stx".padStart( - 34, - " ", - ) - } ${"amount".padStart(12, " ")} ${ - amountUstx - .toString() - .padStart(15, " ") - } delegated to ${ - this.delegateTo.label.padStart( - 42, - " ", - ) - }`, - ); + logCommand(`✓ ${this.wallet.label}`, "delegate-stx", "amount", amountUstx.toString(), "delegated to", this.delegateTo.label); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts index 3f573f4d99..78b084f910 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts @@ -1,4 +1,4 @@ -import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; import { assert } from "vitest"; import { ClarityType, isClarityType } from "@stacks/transactions"; @@ -42,13 +42,7 @@ export class GetStackingMinimumCommand 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. - console.info( - `✓ ${this.wallet.label.padStart(8, " ")} ${ - "get-stacking-minimum".padStart(34, " ") - } ${"pox-4".padStart(12, " ")} ${ - stackingMinimum.value.toString().padStart(15, " ") - }`, - ); + logCommand(`✓ ${this.wallet.label}`, "get-stacking-minimum", "pox-4", stackingMinimum.value.toString()); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts index 58257cf529..b67079f404 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts @@ -1,4 +1,4 @@ -import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; import { expect } from "vitest"; import { Cl } from "@stacks/transactions"; @@ -35,17 +35,7 @@ export class GetStxAccountCommand 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. - console.info( - `✓ ${this.wallet.label.padStart(8, " ")} ${ - "stx-account".padStart(34, " ") - } ${"lock-amount".padStart(12, " ")} ${ - actual.amountLocked.toString().padStart(15, " ") - } ${"unlocked-amount".padStart(12, " ")} ${ - actual.amountUnlocked.toString().padStart(15, " ") - } ${"unlocked-height".padStart(12, " ")} ${ - actual.unlockHeight.toString().padStart(7, " ") - }`, - ); + logCommand(`✓ ${this.wallet.label}`, "stx-account", "lock-amount", actual.amountLocked.toString(), "unlocked-amount", actual.amountUnlocked.toString(), "unlocked-height", actual.unlockHeight.toString()); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts index 5882402e7e..c121146130 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts @@ -1,4 +1,4 @@ -import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; import { poxAddressToTuple } from "@stacks/stacking"; import { expect } from "vitest"; import { Cl, someCV, tupleCV } from "@stacks/transactions"; @@ -77,14 +77,7 @@ 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. - console.info( - `✓ ${ - this.wallet.label.padStart( - 8, - " ", - ) - } ${"revoke-delegate-stx".padStart(34, " ")}`, - ); + logCommand(`✓ ${this.wallet.label}`, "revoke-delegate-stx"); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index c77fe9e206..765441a68f 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -1,4 +1,4 @@ -import { PoxCommand, Real, Stub, Wallet } from "./pox_CommandModel.ts"; +import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; import { Pox4SignatureTopic, poxAddressToTuple } from "@stacks/stacking"; import { assert, expect } from "vitest"; import { Cl, ClarityType, isClarityType } from "@stacks/transactions"; @@ -155,13 +155,7 @@ export class StackStxCommand 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. - console.info( - `✓ ${this.wallet.label.padStart(8, " ")} ${ - "stack-stx".padStart(34, " ") - } ${"lock-amount".padStart(12, " ")} ${ - amountUstx.toString().padStart(15, " ") - }`, - ); + logCommand(`✓ ${this.wallet.label}`, "stack-stx", "lock-amount", amountUstx.toString()); } toString() { From 71f63586a49fe0bdf45ff355388ddd98368e3de8 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Wed, 27 Mar 2024 01:03:09 +0100 Subject: [PATCH 074/129] style(pox-4-tests): Run formatter on tests/pox-4/*.ts --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 49 ++++++++++++++----- .../pox-4/pox_AllowContractCallerCommand.ts | 27 ++++++++-- .../tests/pox-4/pox_Commands.ts | 9 ++-- .../pox-4/pox_DelegateStackStxCommand.ts | 19 +++++-- .../tests/pox-4/pox_DelegateStxCommand.ts | 25 +++++++--- .../pox-4/pox_GetStackingMinimumCommand.ts | 15 +++++- .../tests/pox-4/pox_GetStxAccountCommand.ts | 19 ++++++- .../pox-4/pox_RevokeDelegateStxCommand.ts | 8 ++- .../tests/pox-4/pox_StackStxCommand.ts | 15 +++++- 9 files changed, 150 insertions(+), 36 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index 4331f434a2..6c3df5fa0b 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -31,15 +31,42 @@ describe("PoX-4 invariant tests", () => { }; const wallets = [ - ["wallet_1", "7287ba251d44a4d3fd9276c88ce34c5c52a038955511cccaf77e61068649c17801"], - ["wallet_2", "530d9f61984c888536871c6573073bdfc0058896dc1adfe9a6a10dfacadc209101"], - ["wallet_3", "d655b2523bcd65e34889725c73064feb17ceb796831c0e111ba1a552b0f31b3901"], - ["wallet_4", "f9d7206a47f14d2870c163ebab4bf3e70d18f5d14ce1031f3902fbbc894fe4c701"], - ["wallet_5", "3eccc5dac8056590432db6a35d52b9896876a3d5cbdea53b72400bc9c2099fe801"], - ["wallet_6", "7036b29cb5e235e5fd9b09ae3e8eec4404e44906814d5d01cbca968a60ed4bfb01"], - ["wallet_7", "b463f0df6c05d2f156393eee73f8016c5372caa0e9e29a901bb7171d90dc4f1401"], - ["wallet_8", "6a1a754ba863d7bab14adbbc3f8ebb090af9e871ace621d3e5ab634e1422885e01"], - ["wallet_9", "de433bdfa14ec43aa1098d5be594c8ffb20a31485ff9de2923b2689471c401b801"], + [ + "wallet_1", + "7287ba251d44a4d3fd9276c88ce34c5c52a038955511cccaf77e61068649c17801", + ], + [ + "wallet_2", + "530d9f61984c888536871c6573073bdfc0058896dc1adfe9a6a10dfacadc209101", + ], + [ + "wallet_3", + "d655b2523bcd65e34889725c73064feb17ceb796831c0e111ba1a552b0f31b3901", + ], + [ + "wallet_4", + "f9d7206a47f14d2870c163ebab4bf3e70d18f5d14ce1031f3902fbbc894fe4c701", + ], + [ + "wallet_5", + "3eccc5dac8056590432db6a35d52b9896876a3d5cbdea53b72400bc9c2099fe801", + ], + [ + "wallet_6", + "7036b29cb5e235e5fd9b09ae3e8eec4404e44906814d5d01cbca968a60ed4bfb01", + ], + [ + "wallet_7", + "b463f0df6c05d2f156393eee73f8016c5372caa0e9e29a901bb7171d90dc4f1401", + ], + [ + "wallet_8", + "6a1a754ba863d7bab14adbbc3f8ebb090af9e871ace621d3e5ab634e1422885e01", + ], + [ + "wallet_9", + "de433bdfa14ec43aa1098d5be594c8ffb20a31485ff9de2923b2689471c401b801", + ], ].map((wallet) => { const label = wallet[0]; const prvKey = wallet[1]; @@ -71,8 +98,8 @@ describe("PoX-4 invariant tests", () => { amountLocked: 0, amountUnlocked: initialUstxBalance, unlockHeight: 0, - allowedContractCaller: '', - callerAllowedBy: [] + allowedContractCaller: "", + callerAllowedBy: [], }; }); diff --git a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts index 64f4a32142..591568a17c 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts @@ -1,6 +1,18 @@ -import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; import { expect } from "vitest"; -import { boolCV, Cl, ClarityType, OptionalCV, UIntCV } from "@stacks/transactions"; +import { + boolCV, + Cl, + ClarityType, + OptionalCV, + UIntCV, +} from "@stacks/transactions"; /** * The `AllowContractCallerComand` gives a `contract-caller` authorization to call stacking methods. @@ -23,7 +35,6 @@ export class AllowContractCallerCommand implements PoxCommand { * @param allowanceTo - Represents the authorized `contract-caller` (i.e. a stacking pool) * @param alllowUntilBurnHt - The burn block height until the authorization is valid. */ - constructor( wallet: Wallet, allowanceTo: Wallet, @@ -59,14 +70,20 @@ export class AllowContractCallerCommand implements PoxCommand { // Get the wallets involved from the model and update it with the new state. const wallet = model.wallets.get(this.wallet.stxAddress)!; const callerToAllow = model.wallets.get(this.allowanceTo.stxAddress)!; - // Update model so that we know this wallet has authorized a contract-caller. + // Update model so that we know this wallet has authorized a contract-caller. wallet.allowedContractCaller = this.allowanceTo.stxAddress; callerToAllow.callerAllowedBy.push(wallet.stxAddress); // 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}`, "allow-contract-caller", this.allowanceTo.label, "until", optionalCVToString(this.allowUntilBurnHt)); + logCommand( + `✓ ${this.wallet.label}`, + "allow-contract-caller", + this.allowanceTo.label, + "until", + optionalCVToString(this.allowUntilBurnHt), + ); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 859316451c..e0024ffbeb 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -11,7 +11,8 @@ import { RevokeDelegateStxCommand } from "./pox_RevokeDelegateStxCommand"; import { AllowContractCallerCommand } from "./pox_AllowContractCallerCommand"; export function PoxCommands( - wallets: Map, network: Simnet, + wallets: Map, + network: Simnet, ): fc.Arbitrary>> { const cmds = [ // GetStackingMinimumCommand @@ -52,7 +53,7 @@ export function PoxCommands( wallet: fc.constantFrom(...wallets.values()), delegateTo: fc.constantFrom(...wallets.values()), untilBurnHt: fc.integer({ min: 1 }), - amount: fc.bigInt({ min:0n, max: 100_000_000_000_000n }), + amount: fc.bigInt({ min: 0n, max: 100_000_000_000_000n }), }).map(( r: { wallet: Wallet; @@ -77,7 +78,7 @@ export function PoxCommands( }, ) => new RevokeDelegateStxCommand( - r.wallet + r.wallet, ) ), // DelegateStackStxCommand @@ -89,7 +90,7 @@ export function PoxCommands( max: nextCycleFirstBlock(network), }), period: fc.integer({ min: 1, max: 12 }), - amount: fc.bigInt({ min:0n, max: 100_000_000_000_000n }), + amount: fc.bigInt({ min: 0n, max: 100_000_000_000_000n }), }).chain((r) => fc.record({ unlockBurnHt: fc.constant( diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index ae4d61cc7b..23e1892a39 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -1,4 +1,10 @@ -import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; import { poxAddressToTuple } from "@stacks/stacking"; import { assert, expect } from "vitest"; import { Cl, ClarityType, isClarityType } from "@stacks/transactions"; @@ -104,7 +110,7 @@ export class DelegateStackStxCommand implements PoxCommand { // (start-burn-ht uint) Cl.uint(this.startBurnHt), // (lock-period uint) - Cl.uint(this.period) + Cl.uint(this.period), ], this.operator.stxAddress, ); @@ -146,7 +152,14 @@ export class DelegateStackStxCommand 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.operator.label} Ӿ ${this.stacker.label}`, "delegate-stack-stx", "lock-amount", this.amountUstx.toString(), "until", this.stacker.unlockHeight.toString()); + logCommand( + `✓ ${this.operator.label} Ӿ ${this.stacker.label}`, + "delegate-stack-stx", + "lock-amount", + this.amountUstx.toString(), + "until", + this.stacker.unlockHeight.toString(), + ); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts index bc638719fd..3fbf131a62 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts @@ -1,11 +1,17 @@ -import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; import { poxAddressToTuple } from "@stacks/stacking"; import { expect } from "vitest"; import { boolCV, Cl } from "@stacks/transactions"; /** - * The `DelegateStxCommand` delegates STX for stacking within PoX-4. This operation - * allows the `tx-sender` (the `wallet` in this case) to delegate stacking participation + * The `DelegateStxCommand` delegates STX for stacking within PoX-4. This operation + * allows the `tx-sender` (the `wallet` in this case) to delegate stacking participation * to a `delegatee`. * * Constraints for running this command include: @@ -50,7 +56,7 @@ export class DelegateStxCommand implements PoxCommand { run(model: Stub, real: Real): void { // The amount of uSTX delegated by the Stacker to the Delegatee. - // Even if there are no constraints about the delegated amount, + // Even if there are no constraints about the delegated amount, // it will be checked in the future, when calling delegate-stack-stx. const amountUstx = Number(this.amount); @@ -83,12 +89,19 @@ export class DelegateStxCommand implements PoxCommand { wallet.hasDelegated = true; wallet.delegatedTo = this.delegateTo.stxAddress; wallet.delegatedMaxAmount = amountUstx; - wallet.delegatedUntilBurnHt = this.untilBurnHt + wallet.delegatedUntilBurnHt = this.untilBurnHt; delegatedWallet.hasPoolMembers.push(wallet.stxAddress); // 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}`, "delegate-stx", "amount", amountUstx.toString(), "delegated to", this.delegateTo.label); + logCommand( + `✓ ${this.wallet.label}`, + "delegate-stx", + "amount", + amountUstx.toString(), + "delegated to", + this.delegateTo.label, + ); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts index 78b084f910..6e3ca20b43 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts @@ -1,4 +1,10 @@ -import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; import { assert } from "vitest"; import { ClarityType, isClarityType } from "@stacks/transactions"; @@ -42,7 +48,12 @@ export class GetStackingMinimumCommand 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}`, "get-stacking-minimum", "pox-4", stackingMinimum.value.toString()); + logCommand( + `✓ ${this.wallet.label}`, + "get-stacking-minimum", + "pox-4", + stackingMinimum.value.toString(), + ); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts index b67079f404..ac5a482b85 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts @@ -1,4 +1,10 @@ -import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; import { expect } from "vitest"; import { Cl } from "@stacks/transactions"; @@ -35,7 +41,16 @@ export class GetStxAccountCommand 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}`, "stx-account", "lock-amount", actual.amountLocked.toString(), "unlocked-amount", actual.amountUnlocked.toString(), "unlocked-height", actual.unlockHeight.toString()); + logCommand( + `✓ ${this.wallet.label}`, + "stx-account", + "lock-amount", + actual.amountLocked.toString(), + "unlocked-amount", + actual.amountUnlocked.toString(), + "unlocked-height", + actual.unlockHeight.toString(), + ); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts index c121146130..ecd9ddfec6 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts @@ -1,4 +1,10 @@ -import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; import { poxAddressToTuple } from "@stacks/stacking"; import { expect } from "vitest"; import { Cl, someCV, tupleCV } from "@stacks/transactions"; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index 765441a68f..66557bd473 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -1,4 +1,10 @@ -import { PoxCommand, Real, Stub, Wallet, logCommand } from "./pox_CommandModel.ts"; +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; import { Pox4SignatureTopic, poxAddressToTuple } from "@stacks/stacking"; import { assert, expect } from "vitest"; import { Cl, ClarityType, isClarityType } from "@stacks/transactions"; @@ -155,7 +161,12 @@ export class StackStxCommand 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}`, "stack-stx", "lock-amount", amountUstx.toString()); + logCommand( + `✓ ${this.wallet.label}`, + "stack-stx", + "lock-amount", + amountUstx.toString(), + ); } toString() { From 91b7d935c9b3eb0ad092f0be0056f1bc5f3f9c7d Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Wed, 27 Mar 2024 14:28:17 +0200 Subject: [PATCH 075/129] fix(pox-4-tests): Address delegated PoX address comment https://github.com/stacks-network/stacks-core/pull/4550#discussion_r1537538470 --- .../core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts | 1 + contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts | 2 ++ .../core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts | 1 + .../tests/pox-4/pox_RevokeDelegateStxCommand.ts | 2 +- 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index 6c3df5fa0b..ab6ed61d56 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -95,6 +95,7 @@ describe("PoX-4 invariant tests", () => { delegatedTo: "", delegatedMaxAmount: 0, delegatedUntilBurnHt: 0, + delegatedPoxAddress: "", amountLocked: 0, amountUnlocked: initialUstxBalance, unlockHeight: 0, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 449ef3b672..94d3739d46 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -6,6 +6,7 @@ import { StacksPrivateKey } from "@stacks/transactions"; import { StackingClient } from "@stacks/stacking"; export type StxAddress = string; +export type BtcAddress = string; export type Stub = { stackingMinimum: number; @@ -30,6 +31,7 @@ export type Wallet = { delegatedTo: StxAddress; delegatedMaxAmount: number; delegatedUntilBurnHt: number; + delegatedPoxAddress: BtcAddress; amountLocked: number; amountUnlocked: number; unlockHeight: number; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts index 3fbf131a62..f59131ce95 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts @@ -90,6 +90,7 @@ export class DelegateStxCommand implements PoxCommand { wallet.delegatedTo = this.delegateTo.stxAddress; wallet.delegatedMaxAmount = amountUstx; wallet.delegatedUntilBurnHt = this.untilBurnHt; + wallet.delegatedPoxAddress = this.delegateTo.btcAddress; delegatedWallet.hasPoolMembers.push(wallet.stxAddress); // Log to console for debugging purposes. This is not necessary for the diff --git a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts index ecd9ddfec6..dbd7ee6b74 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts @@ -57,7 +57,7 @@ export class RevokeDelegateStxCommand implements PoxCommand { operatorWallet.stxAddress || "", ), "pox-addr": Cl.some( - poxAddressToTuple(operatorWallet.btcAddress || ""), + poxAddressToTuple(this.wallet.delegatedPoxAddress || ""), ), "until-burn-ht": Cl.some(Cl.uint(this.wallet.delegatedUntilBurnHt)), }), From 642ec8dd682a89c75f7e36f60c0c84fdb9b5be55 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Wed, 27 Mar 2024 14:43:39 +0200 Subject: [PATCH 076/129] fix(pox-4-tests): Address current reward cycle comment https://github.com/stacks-network/stacks-core/pull/4550#discussion_r1537520283 --- contrib/core-contract-tests/tests/pox-4/pox_Commands.ts | 3 +++ .../core-contract-tests/tests/pox-4/pox_StackStxCommand.ts | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index e0024ffbeb..f2b08ce53f 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -33,12 +33,14 @@ export function PoxCommands( authId: fc.nat(), period: fc.integer({ min: 1, max: 12 }), margin: fc.integer({ min: 1, max: 9 }), + currentCycle: fc.constant(currentCycle(network)), }).map(( r: { wallet: Wallet; authId: number; period: number; margin: number; + currentCycle: number; }, ) => new StackStxCommand( @@ -46,6 +48,7 @@ export function PoxCommands( r.authId, r.period, r.margin, + r.currentCycle, ) ), // DelegateStxCommand diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index 66557bd473..da8a295bd5 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -26,6 +26,7 @@ export class StackStxCommand implements PoxCommand { readonly authId: number; readonly period: number; readonly margin: number; + readonly currentCycle: number; /** * Constructs a `StackStxCommand` to lock uSTX for stacking. @@ -41,11 +42,13 @@ export class StackStxCommand implements PoxCommand { authId: number, period: number, margin: number, + currentCycle: number, ) { this.wallet = wallet; this.authId = authId; this.period = period; this.margin = margin; + this.currentCycle = currentCycle; } check(model: Readonly): boolean { @@ -75,7 +78,7 @@ export class StackStxCommand implements PoxCommand { // For `stack-stx` and `stack-extend`, this refers to the reward cycle // where the transaction is confirmed. For `stack-aggregation-commit`, // this refers to the reward cycle argument in that function. - rewardCycle: 0, + rewardCycle: this.currentCycle, // For `stack-stx`, this refers to `lock-period`. For `stack-extend`, // this refers to `extend-count`. For `stack-aggregation-commit`, this is // `u1`. @@ -173,6 +176,6 @@ export class StackStxCommand implements PoxCommand { // 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.wallet.label} stack-stx auth-id ${this.authId} and period ${this.period}`; + return `${this.wallet.label} stack-stx auth-id ${this.authId} and period ${this.period} during reward cycle ${this.currentCycle}`; } } From b3901865fb5741b4cdba3ef3c68d6867f2fbe5f8 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Wed, 27 Mar 2024 15:37:31 +0200 Subject: [PATCH 077/129] fix(pox-4-tests): Address check balance command comment https://github.com/stacks-network/stacks-core/pull/4550#discussion_r1530409991 --- .../tests/pox-4/pox_CheckBalanceCommand.ts | 66 +++++++++++++++++++ .../tests/pox-4/pox_Commands.ts | 13 ++++ 2 files changed, 79 insertions(+) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_CheckBalanceCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CheckBalanceCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_CheckBalanceCommand.ts new file mode 100644 index 0000000000..d28613a226 --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_CheckBalanceCommand.ts @@ -0,0 +1,66 @@ +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; +import { expect } from "vitest"; +import { ClarityValue, cvToValue } from "@stacks/transactions"; + +/** + * Implements the `PoxCommand` interface to check a wallet's balance. + */ +export class CheckBalanceCommand implements PoxCommand { + readonly wallet: Wallet; + + /** + * Constructs a new `CheckBalanceCommand`. + * + * @param wallet The wallet information, including the STX address used to + * query the `stx-account`. + */ + constructor(wallet: Wallet) { + this.wallet = wallet; + } + + check(_model: Readonly): boolean { + // Can always check user's balance. + return true; + } + + run(model: Stub, real: Real): void { + const actual = model.wallets.get(this.wallet.stxAddress)!; + + // Get the real balance + const stxAccount = cvToValue( + real.network.runSnippet( + `(stx-account '${actual.stxAddress})`, + ) as ClarityValue, + ); + const lockedBalance = parseInt(stxAccount.locked.value); + const unlockedBalance = parseInt(stxAccount.unlocked.value); + const realBalance = lockedBalance + unlockedBalance; + + // Check the real balance to equal wallet's ustxBalance + expect(realBalance).toBe(this.wallet.ustxBalance); + + // 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}`, + "check-balance", + "real-balance", + realBalance.toString(), + "wallet-balance", + this.wallet.ustxBalance.toString(), + ); + } + + 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.wallet.label} check-balance`; + } +} diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index f2b08ce53f..c87c50e7d4 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -9,6 +9,7 @@ import { Simnet } from "@hirosystems/clarinet-sdk"; import { Cl, cvToValue, OptionalCV, UIntCV } from "@stacks/transactions"; import { RevokeDelegateStxCommand } from "./pox_RevokeDelegateStxCommand"; import { AllowContractCallerCommand } from "./pox_AllowContractCallerCommand"; +import { CheckBalanceCommand } from "./pox_CheckBalanceCommand"; export function PoxCommands( wallets: Map, @@ -146,6 +147,18 @@ export function PoxCommands( r.wallet, ) ), + // CheckBalanceCommand + fc.record({ + wallet: fc.constantFrom(...wallets.values()), + }).map(( + r: { + wallet: Wallet; + }, + ) => + new CheckBalanceCommand( + r.wallet, + ) + ), ]; // More on size: https://github.com/dubzzz/fast-check/discussions/2978 From d4cc53e0039950a80994f646a11fdcc94c6a9de4 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Wed, 27 Mar 2024 19:08:56 +0200 Subject: [PATCH 078/129] fix(pox-4-tests): Address stacker generation comment https://github.com/stacks-network/stacks-core/pull/4550#discussion_r1537470910 --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 2 +- .../tests/pox-4/pox_CommandModel.ts | 2 +- .../tests/pox-4/pox_Commands.ts | 61 +++++++++++++------ .../pox-4/pox_DelegateStackStxCommand.ts | 3 +- .../tests/pox-4/pox_DelegateStxCommand.ts | 4 +- .../pox-4/pox_RevokeDelegateStxCommand.ts | 4 +- 6 files changed, 50 insertions(+), 26 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index ab6ed61d56..d9e2f4a21e 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -91,7 +91,7 @@ describe("PoX-4 invariant tests", () => { ustxBalance: initialUstxBalance, isStacking: false, hasDelegated: false, - hasPoolMembers: [], + poolMembers: [], delegatedTo: "", delegatedMaxAmount: 0, delegatedUntilBurnHt: 0, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 94d3739d46..32971bc854 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -27,7 +27,7 @@ export type Wallet = { ustxBalance: number; isStacking: boolean; hasDelegated: boolean; - hasPoolMembers: StxAddress[]; + poolMembers: StxAddress[]; delegatedTo: StxAddress; delegatedMaxAmount: number; delegatedUntilBurnHt: number; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index c87c50e7d4..838b4d2a22 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -88,32 +88,53 @@ export function PoxCommands( // DelegateStackStxCommand fc.record({ operator: fc.constantFrom(...wallets.values()), - stacker: fc.constantFrom(...wallets.values()), startBurnHt: fc.integer({ min: currentCycleFirstBlock(network), max: nextCycleFirstBlock(network), }), period: fc.integer({ min: 1, max: 12 }), - amount: fc.bigInt({ min: 0n, max: 100_000_000_000_000n }), - }).chain((r) => - fc.record({ - unlockBurnHt: fc.constant( - currentCycleFirstBlock(network) + 1050 * (r.period + 1), - ), - }).map((unlockBurnHtRecord) => ({ + }).chain((r) => { + // Determine available stackers based on the operator + const availableStackers = r.operator.poolMembers.length > 0 + ? r.operator.poolMembers + : [r.operator.stxAddress]; + + return fc.record({ + stacker: fc.constantFrom(...availableStackers), + }).map((stacker) => ({ ...r, - ...unlockBurnHtRecord, - })) - ).map((r) => - new DelegateStackStxCommand( - r.operator, - r.stacker, - r.startBurnHt, - r.period, - r.amount, - r.unlockBurnHt, - ) - ), + stacker: wallets.get(stacker.stacker)!, + })).chain((resultWithStacker) => { + return fc.record({ + unlockBurnHt: fc.constant( + currentCycleFirstBlock(network) + + 1050 * (resultWithStacker.period + 1), + ), + }).map((additionalProps) => ({ + ...resultWithStacker, + ...additionalProps, + })); + }).chain((resultWithUnlockHeight) => { + return fc.record({ + amount: fc.bigInt({ + min: 0n, + max: BigInt(resultWithUnlockHeight.stacker.delegatedMaxAmount), + }), + }).map((amountProps) => ({ + ...resultWithUnlockHeight, + ...amountProps, + })); + }); + }).map((finalResult) => { + return new DelegateStackStxCommand( + finalResult.operator, + finalResult.stacker, + finalResult.startBurnHt, + finalResult.period, + finalResult.amount, + finalResult.unlockBurnHt, + ); + }), // AllowContractCallerCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index 23e1892a39..baa5b16abd 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -90,7 +90,8 @@ export class DelegateStackStxCommand implements PoxCommand { stackerWallet.delegatedMaxAmount >= Number(this.amountUstx) && Number(this.amountUstx) <= stackerWallet.ustxBalance && Number(this.amountUstx) >= model.stackingMinimum && - operatorWallet.hasPoolMembers.includes(stackerWallet.stxAddress) && + operatorWallet.poolMembers.length > 0 && + operatorWallet.poolMembers.includes(stackerWallet.stxAddress) && this.unlockBurnHt <= stackerWallet.delegatedUntilBurnHt ); } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts index f59131ce95..59a0b9cba4 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts @@ -92,7 +92,7 @@ export class DelegateStxCommand implements PoxCommand { wallet.delegatedUntilBurnHt = this.untilBurnHt; wallet.delegatedPoxAddress = this.delegateTo.btcAddress; - delegatedWallet.hasPoolMembers.push(wallet.stxAddress); + delegatedWallet.poolMembers.push(wallet.stxAddress); // 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( @@ -102,6 +102,8 @@ export class DelegateStxCommand implements PoxCommand { amountUstx.toString(), "delegated to", this.delegateTo.label, + "until", + this.untilBurnHt.toString() ); } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts index dbd7ee6b74..4e7f16e620 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts @@ -75,11 +75,11 @@ export class RevokeDelegateStxCommand implements PoxCommand { wallet.delegatedMaxAmount = 0; // Remove the Stacker from the Pool Operator's pool members list - let walletIndexInDelegatorsList = operatorWallet.hasPoolMembers.indexOf( + let walletIndexInDelegatorsList = operatorWallet.poolMembers.indexOf( wallet.stxAddress, ); expect(walletIndexInDelegatorsList).toBeGreaterThan(-1); - operatorWallet.hasPoolMembers.splice(walletIndexInDelegatorsList, 1); + operatorWallet.poolMembers.splice(walletIndexInDelegatorsList, 1); // 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. From 1223c0756403363bc4794bc6c5efe126edbbf90d Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Thu, 28 Mar 2024 12:37:23 +0100 Subject: [PATCH 079/129] feat(pox-4-tests): Print command output in real-time Thanks to @hugocaillard for swiftly implementing this feature. --- contrib/core-contract-tests/noopReporter.ts | 26 +++ contrib/core-contract-tests/package-lock.json | 85 ------- contrib/core-contract-tests/package.json | 1 - .../tests/pox-4/pox-4.stateful-prop.test.ts | 212 +++++++++--------- .../tests/pox-4/pox_CommandModel.ts | 4 +- contrib/core-contract-tests/vitest.config.js | 1 + 6 files changed, 134 insertions(+), 195 deletions(-) create mode 100644 contrib/core-contract-tests/noopReporter.ts diff --git a/contrib/core-contract-tests/noopReporter.ts b/contrib/core-contract-tests/noopReporter.ts new file mode 100644 index 0000000000..c97206f5f1 --- /dev/null +++ b/contrib/core-contract-tests/noopReporter.ts @@ -0,0 +1,26 @@ +import type { UserConsoleLog } from "vitest"; + +import { DefaultReporter } from "vitest/reporters"; + +export default class LoggerReporter extends DefaultReporter { + onInit() {} + onPathsCollected() {} + onCollected() {} + onFinished() { + return Promise.resolve(); + } + onTaskUpdate() {} + + onWatcherStart() { + return Promise.resolve(); + } + onWatcherRerun() { + return Promise.resolve(); + } + + onServerRestart() {} + + onProcessTimeou() {} + + onUserConsoleLog(log: UserConsoleLog) {} +} diff --git a/contrib/core-contract-tests/package-lock.json b/contrib/core-contract-tests/package-lock.json index f636a0d085..5fd11568ce 100644 --- a/contrib/core-contract-tests/package-lock.json +++ b/contrib/core-contract-tests/package-lock.json @@ -15,7 +15,6 @@ "@stacks/transactions": "^6.13.0", "chokidar-cli": "^3.0.0", "fast-check": "^3.15.1", - "ololog": "^1.1.175", "typescript": "^5.4.2", "vite": "^5.1.6", "vitest": "^1.3.1", @@ -1477,11 +1476,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/ansicolor": { - "version": "1.1.100", - "resolved": "https://registry.npmjs.org/ansicolor/-/ansicolor-1.1.100.tgz", - "integrity": "sha512-Jl0pxRfa9WaQVUX57AB8/V2my6FJxrOR1Pp2qqFbig20QB4HzUoQ48THTKAgHlUCJeQm/s2WoOPcoIDhyCL/kw==" - }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -1499,14 +1493,6 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, - "node_modules/as-table": { - "version": "1.0.55", - "resolved": "https://registry.npmjs.org/as-table/-/as-table-1.0.55.tgz", - "integrity": "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==", - "dependencies": { - "printable-characters": "^1.0.42" - } - }, "node_modules/assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -1933,11 +1919,6 @@ "node": ">= 8" } }, - "node_modules/data-uri-to-buffer": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-2.0.2.tgz", - "integrity": "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==" - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -2366,15 +2347,6 @@ "node": "*" } }, - "node_modules/get-source": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/get-source/-/get-source-2.0.12.tgz", - "integrity": "sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==", - "dependencies": { - "data-uri-to-buffer": "^2.0.0", - "source-map": "^0.6.1" - } - }, "node_modules/get-stream": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", @@ -2820,19 +2792,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ololog": { - "version": "1.1.175", - "resolved": "https://registry.npmjs.org/ololog/-/ololog-1.1.175.tgz", - "integrity": "sha512-DSPbsvZzLshFiPI1ul7iJDn6wI75goOLyrn8uRB92sPon5LS8J2KlAIkSoHXtRztb2idPjuzq3R1J58hN2qOEA==", - "dependencies": { - "ansicolor": "^1.1.84", - "pipez": "^1.1.12", - "printable-characters": "^1.0.42", - "stacktracey": "^2.1.6", - "string.bullet": "^1.0.12", - "string.ify": "^1.0.64" - } - }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -2980,11 +2939,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pipez": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/pipez/-/pipez-1.1.12.tgz", - "integrity": "sha512-VuJ+c44f3s/4cirqtBI3wa0LscCo1IG9sQH2DnClJWEMkGylE52mDjLLHR5QyLjij1EiGocMEIAJsmpyXczXJQ==" - }, "node_modules/pkg-types": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", @@ -3054,11 +3008,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/printable-characters": { - "version": "1.0.42", - "resolved": "https://registry.npmjs.org/printable-characters/-/printable-characters-1.0.42.tgz", - "integrity": "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==" - }, "node_modules/process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -3306,14 +3255,6 @@ "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", @@ -3327,15 +3268,6 @@ "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==" }, - "node_modules/stacktracey": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/stacktracey/-/stacktracey-2.1.8.tgz", - "integrity": "sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==", - "dependencies": { - "as-table": "^1.0.36", - "get-source": "^2.0.12" - } - }, "node_modules/std-env": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", @@ -3354,23 +3286,6 @@ "node": ">=8" } }, - "node_modules/string.bullet": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/string.bullet/-/string.bullet-1.0.12.tgz", - "integrity": "sha512-6+tQyad/ux52N+7wUcjmxeK5TfdeykBBLHQPk8MxUVrk9JwHzJnuxsJzjjpWAuz0x3EmnVGCg0ibMHqez1l/qQ==", - "dependencies": { - "printable-characters": "^1.0.26" - } - }, - "node_modules/string.ify": { - "version": "1.0.64", - "resolved": "https://registry.npmjs.org/string.ify/-/string.ify-1.0.64.tgz", - "integrity": "sha512-4Aa5yndnuOhE1GV2W3ht4rQ08XHq46JLXmSOv0jeUWEzqliBvm8lAXvt+66np+J9DkoCZikFzTzjXVLRR0F/Xw==", - "dependencies": { - "printable-characters": "^1.0.42", - "string.bullet": "^1.0.12" - } - }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", diff --git a/contrib/core-contract-tests/package.json b/contrib/core-contract-tests/package.json index a6c8b23262..0d80a4e570 100644 --- a/contrib/core-contract-tests/package.json +++ b/contrib/core-contract-tests/package.json @@ -17,7 +17,6 @@ "@stacks/transactions": "^6.13.0", "chokidar-cli": "^3.0.0", "fast-check": "^3.15.1", - "ololog": "^1.1.175", "typescript": "^5.4.2", "vite": "^5.1.6", "vitest": "^1.3.1", diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index d9e2f4a21e..70533ce605 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -1,4 +1,4 @@ -import { describe, it } from "vitest"; +import { it } from "vitest"; import { initSimnet } from "@hirosystems/clarinet-sdk"; import { Real, Stub, StxAddress, Wallet } from "./pox_CommandModel.ts"; @@ -17,117 +17,115 @@ import { StackingClient } from "@stacks/stacking"; import fc from "fast-check"; import { PoxCommands } from "./pox_Commands.ts"; -describe("PoX-4 invariant tests", () => { - it("statefully does solo stacking with a signature", async () => { - // SUT stands for "System Under Test". - const sut: Real = { - network: await initSimnet(), - }; +it("statefully interacts with PoX-4", async () => { + // SUT stands for "System Under Test". + const sut: Real = { + network: await initSimnet(), + }; - // This is the initial state of the model. - const model: Stub = { - stackingMinimum: 0, - wallets: new Map(), - }; + // This is the initial state of the model. + const model: Stub = { + stackingMinimum: 0, + wallets: new Map(), + }; - const wallets = [ - [ - "wallet_1", - "7287ba251d44a4d3fd9276c88ce34c5c52a038955511cccaf77e61068649c17801", - ], - [ - "wallet_2", - "530d9f61984c888536871c6573073bdfc0058896dc1adfe9a6a10dfacadc209101", - ], - [ - "wallet_3", - "d655b2523bcd65e34889725c73064feb17ceb796831c0e111ba1a552b0f31b3901", - ], - [ - "wallet_4", - "f9d7206a47f14d2870c163ebab4bf3e70d18f5d14ce1031f3902fbbc894fe4c701", - ], - [ - "wallet_5", - "3eccc5dac8056590432db6a35d52b9896876a3d5cbdea53b72400bc9c2099fe801", - ], - [ - "wallet_6", - "7036b29cb5e235e5fd9b09ae3e8eec4404e44906814d5d01cbca968a60ed4bfb01", - ], - [ - "wallet_7", - "b463f0df6c05d2f156393eee73f8016c5372caa0e9e29a901bb7171d90dc4f1401", - ], - [ - "wallet_8", - "6a1a754ba863d7bab14adbbc3f8ebb090af9e871ace621d3e5ab634e1422885e01", - ], - [ - "wallet_9", - "de433bdfa14ec43aa1098d5be594c8ffb20a31485ff9de2923b2689471c401b801", - ], - ].map((wallet) => { - const label = wallet[0]; - const prvKey = wallet[1]; - const pubKey = getPublicKeyFromPrivate(prvKey); - const devnet = new StacksDevnet(); - const initialUstxBalance = 100_000_000_000_000; - const signerPrvKey = createStacksPrivateKey(prvKey); - const signerPubKey = getPublicKeyFromPrivate(signerPrvKey.data); - const btcAddress = publicKeyToBtcAddress(pubKey); - const stxAddress = getAddressFromPrivateKey( - prvKey, - TransactionVersion.Testnet, - ); + const wallets = [ + [ + "wallet_1", + "7287ba251d44a4d3fd9276c88ce34c5c52a038955511cccaf77e61068649c17801", + ], + [ + "wallet_2", + "530d9f61984c888536871c6573073bdfc0058896dc1adfe9a6a10dfacadc209101", + ], + [ + "wallet_3", + "d655b2523bcd65e34889725c73064feb17ceb796831c0e111ba1a552b0f31b3901", + ], + [ + "wallet_4", + "f9d7206a47f14d2870c163ebab4bf3e70d18f5d14ce1031f3902fbbc894fe4c701", + ], + [ + "wallet_5", + "3eccc5dac8056590432db6a35d52b9896876a3d5cbdea53b72400bc9c2099fe801", + ], + [ + "wallet_6", + "7036b29cb5e235e5fd9b09ae3e8eec4404e44906814d5d01cbca968a60ed4bfb01", + ], + [ + "wallet_7", + "b463f0df6c05d2f156393eee73f8016c5372caa0e9e29a901bb7171d90dc4f1401", + ], + [ + "wallet_8", + "6a1a754ba863d7bab14adbbc3f8ebb090af9e871ace621d3e5ab634e1422885e01", + ], + [ + "wallet_9", + "de433bdfa14ec43aa1098d5be594c8ffb20a31485ff9de2923b2689471c401b801", + ], + ].map((wallet) => { + const label = wallet[0]; + const prvKey = wallet[1]; + const pubKey = getPublicKeyFromPrivate(prvKey); + const devnet = new StacksDevnet(); + const initialUstxBalance = 100_000_000_000_000; + const signerPrvKey = createStacksPrivateKey(prvKey); + const signerPubKey = getPublicKeyFromPrivate(signerPrvKey.data); + const btcAddress = publicKeyToBtcAddress(pubKey); + const stxAddress = getAddressFromPrivateKey( + prvKey, + TransactionVersion.Testnet, + ); - return { - label, - stxAddress, - btcAddress, - signerPrvKey, - signerPubKey, - stackingClient: new StackingClient(stxAddress, devnet), - ustxBalance: initialUstxBalance, - isStacking: false, - hasDelegated: false, - poolMembers: [], - delegatedTo: "", - delegatedMaxAmount: 0, - delegatedUntilBurnHt: 0, - delegatedPoxAddress: "", - amountLocked: 0, - amountUnlocked: initialUstxBalance, - unlockHeight: 0, - allowedContractCaller: "", - callerAllowedBy: [], - }; - }); + return { + label, + stxAddress, + btcAddress, + signerPrvKey, + signerPubKey, + stackingClient: new StackingClient(stxAddress, devnet), + ustxBalance: initialUstxBalance, + isStacking: false, + hasDelegated: false, + poolMembers: [], + delegatedTo: "", + delegatedMaxAmount: 0, + delegatedUntilBurnHt: 0, + delegatedPoxAddress: "", + amountLocked: 0, + amountUnlocked: initialUstxBalance, + unlockHeight: 0, + allowedContractCaller: "", + callerAllowedBy: [], + }; + }); - // Add the wallets to the model. - wallets.forEach((wallet) => { - model.wallets.set(wallet.stxAddress, wallet); - }); + // Add the wallets to the model. + wallets.forEach((wallet) => { + model.wallets.set(wallet.stxAddress, wallet); + }); - simnet.setEpoch("3.0"); + simnet.setEpoch("3.0"); - 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, + 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, + }, + ); }); diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 32971bc854..d31e11a426 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -1,5 +1,4 @@ import fc from "fast-check"; -import ololog from "ololog"; import { Simnet } from "@hirosystems/clarinet-sdk"; import { StacksPrivateKey } from "@stacks/transactions"; @@ -49,6 +48,7 @@ export const logCommand = (...items: (string | undefined)[]) => { const prettyPrint = renderItems.map((content) => content ? content.padEnd(columnWidth) : "".padEnd(columnWidth) ); + prettyPrint.push("\n"); - ololog.configure({ locate: false })(prettyPrint.join("")); + process.stdout.write(prettyPrint.join("")); }; diff --git a/contrib/core-contract-tests/vitest.config.js b/contrib/core-contract-tests/vitest.config.js index 364c55f735..3059a20050 100644 --- a/contrib/core-contract-tests/vitest.config.js +++ b/contrib/core-contract-tests/vitest.config.js @@ -29,6 +29,7 @@ export default defineConfig({ threads: { singleThread: true }, forks: { singleFork: true }, }, + reporters: ["./noopReporter.ts"], setupFiles: [ vitestSetupFilePath, // custom setup files can be added here From 764a8623bf20cb27755c2ecae4daa90e6f623ebe Mon Sep 17 00:00:00 2001 From: BowTiedRadone <92028479+BowTiedRadone@users.noreply.github.com> Date: Thu, 28 Mar 2024 13:42:16 +0200 Subject: [PATCH 080/129] fix(pox-4-tests): Update let to const RevokeDelegateStx Co-authored-by: Nikos Baxevanis --- .../tests/pox-4/pox_RevokeDelegateStxCommand.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts index 4e7f16e620..93c3844d92 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts @@ -75,7 +75,7 @@ export class RevokeDelegateStxCommand implements PoxCommand { wallet.delegatedMaxAmount = 0; // Remove the Stacker from the Pool Operator's pool members list - let walletIndexInDelegatorsList = operatorWallet.poolMembers.indexOf( + const walletIndexInDelegatorsList = operatorWallet.poolMembers.indexOf( wallet.stxAddress, ); expect(walletIndexInDelegatorsList).toBeGreaterThan(-1); From b5850fd670dbf6180363053a928e280360a4659b Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Thu, 28 Mar 2024 13:53:36 +0200 Subject: [PATCH 081/129] fix(pox-4-tests): Move balance check inside GetStxAccountCommand --- .../tests/pox-4/pox_CheckBalanceCommand.ts | 66 ------------------- .../tests/pox-4/pox_Commands.ts | 13 ---- .../tests/pox-4/pox_GetStxAccountCommand.ts | 2 + 3 files changed, 2 insertions(+), 79 deletions(-) delete mode 100644 contrib/core-contract-tests/tests/pox-4/pox_CheckBalanceCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CheckBalanceCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_CheckBalanceCommand.ts deleted file mode 100644 index d28613a226..0000000000 --- a/contrib/core-contract-tests/tests/pox-4/pox_CheckBalanceCommand.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { - logCommand, - PoxCommand, - Real, - Stub, - Wallet, -} from "./pox_CommandModel.ts"; -import { expect } from "vitest"; -import { ClarityValue, cvToValue } from "@stacks/transactions"; - -/** - * Implements the `PoxCommand` interface to check a wallet's balance. - */ -export class CheckBalanceCommand implements PoxCommand { - readonly wallet: Wallet; - - /** - * Constructs a new `CheckBalanceCommand`. - * - * @param wallet The wallet information, including the STX address used to - * query the `stx-account`. - */ - constructor(wallet: Wallet) { - this.wallet = wallet; - } - - check(_model: Readonly): boolean { - // Can always check user's balance. - return true; - } - - run(model: Stub, real: Real): void { - const actual = model.wallets.get(this.wallet.stxAddress)!; - - // Get the real balance - const stxAccount = cvToValue( - real.network.runSnippet( - `(stx-account '${actual.stxAddress})`, - ) as ClarityValue, - ); - const lockedBalance = parseInt(stxAccount.locked.value); - const unlockedBalance = parseInt(stxAccount.unlocked.value); - const realBalance = lockedBalance + unlockedBalance; - - // Check the real balance to equal wallet's ustxBalance - expect(realBalance).toBe(this.wallet.ustxBalance); - - // 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}`, - "check-balance", - "real-balance", - realBalance.toString(), - "wallet-balance", - this.wallet.ustxBalance.toString(), - ); - } - - 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.wallet.label} check-balance`; - } -} diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 838b4d2a22..62db94efab 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -9,7 +9,6 @@ import { Simnet } from "@hirosystems/clarinet-sdk"; import { Cl, cvToValue, OptionalCV, UIntCV } from "@stacks/transactions"; import { RevokeDelegateStxCommand } from "./pox_RevokeDelegateStxCommand"; import { AllowContractCallerCommand } from "./pox_AllowContractCallerCommand"; -import { CheckBalanceCommand } from "./pox_CheckBalanceCommand"; export function PoxCommands( wallets: Map, @@ -168,18 +167,6 @@ export function PoxCommands( r.wallet, ) ), - // CheckBalanceCommand - fc.record({ - wallet: fc.constantFrom(...wallets.values()), - }).map(( - r: { - wallet: Wallet; - }, - ) => - new CheckBalanceCommand( - r.wallet, - ) - ), ]; // More on size: https://github.com/dubzzz/fast-check/discussions/2978 diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts index ac5a482b85..7f6ddf6ca8 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts @@ -39,6 +39,8 @@ export class GetStxAccountCommand implements PoxCommand { "unlock-height": Cl.uint(actual.unlockHeight), }); + expect(actual.amountLocked + actual.amountUnlocked).toBe(actual.ustxBalance); + // 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( From 4a9e95caf7c21efcef1aea2a9c621e978e1d90ce Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Fri, 29 Mar 2024 07:22:00 +0100 Subject: [PATCH 082/129] fix(test-output): Remove global noopReporter to restore test visibility Removed the "./noopReporter.ts" from the global Vitest reporters configuration to ensure test outputs are visible by default. This change addresses an issue where the output from all tests was being hidden, making it difficult to observe test results directly. The noopReporter can still be used selectively for specific tests via: npx vitest --reporter=./noopReporter.ts run tests/pox-4/pox-4.stateful-prop.test.ts --- contrib/core-contract-tests/vitest.config.js | 1 - 1 file changed, 1 deletion(-) diff --git a/contrib/core-contract-tests/vitest.config.js b/contrib/core-contract-tests/vitest.config.js index 3059a20050..364c55f735 100644 --- a/contrib/core-contract-tests/vitest.config.js +++ b/contrib/core-contract-tests/vitest.config.js @@ -29,7 +29,6 @@ export default defineConfig({ threads: { singleThread: true }, forks: { singleFork: true }, }, - reporters: ["./noopReporter.ts"], setupFiles: [ vitestSetupFilePath, // custom setup files can be added here From 3062beddfa80d28ca576b8e9ec251c4ab8d42b1b Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Fri, 29 Mar 2024 08:09:38 +0100 Subject: [PATCH 083/129] feat(pox-4-tests): Track command execution in PoxCommand implementations Each `run` method now calls `model.trackCommandRun(this.constructor.name)`, enhancing observability and aiding in debugging by systematically tracking command executions. Example output: Command run method execution counts: AllowContractCallerCommand: 491 DelegateStackStxCommand: 1 DelegateStxCommand: 285 GetStackingMinimumCommand: 536 GetStxAccountCommand: 503 RevokeDelegateStxCommand: 281 StackStxCommand: 8 --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 29 ++++++++++++------- .../pox-4/pox_AllowContractCallerCommand.ts | 1 + .../tests/pox-4/pox_CommandModel.ts | 29 +++++++++++++++++-- .../pox-4/pox_DelegateStackStxCommand.ts | 1 + .../tests/pox-4/pox_DelegateStxCommand.ts | 1 + .../pox-4/pox_GetStackingMinimumCommand.ts | 1 + .../tests/pox-4/pox_GetStxAccountCommand.ts | 1 + .../pox-4/pox_RevokeDelegateStxCommand.ts | 1 + .../tests/pox-4/pox_StackStxCommand.ts | 1 + 9 files changed, 51 insertions(+), 14 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index 70533ce605..6c64d93c29 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -1,6 +1,6 @@ import { it } from "vitest"; import { initSimnet } from "@hirosystems/clarinet-sdk"; -import { Real, Stub, StxAddress, Wallet } from "./pox_CommandModel.ts"; +import { Real, Stub } from "./pox_CommandModel.ts"; import { getPublicKeyFromPrivate, @@ -17,18 +17,15 @@ import { StackingClient } from "@stacks/stacking"; import fc from "fast-check"; import { PoxCommands } from "./pox_Commands.ts"; +import fs from "fs"; +import path from "path"; + it("statefully interacts with PoX-4", async () => { // SUT stands for "System Under Test". const sut: Real = { network: await initSimnet(), }; - // This is the initial state of the model. - const model: Stub = { - stackingMinimum: 0, - wallets: new Map(), - }; - const wallets = [ [ "wallet_1", @@ -103,10 +100,18 @@ it("statefully interacts with PoX-4", async () => { }; }); - // Add the wallets to the model. - wallets.forEach((wallet) => { - model.wallets.set(wallet.stxAddress, wallet); - }); + // Track the number of times each command is run, so we can see if all the + // 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" + ).map((file) => file.slice(4, -3)); // Remove "pox_" prefix and ".ts" suffix. + + // This is the initial state of the model. + const model = new Stub( + new Map(wallets.map((wallet) => [wallet.stxAddress, wallet])), + new Map(statistics.map((commandName) => [commandName, 0])), + ); simnet.setEpoch("3.0"); @@ -128,4 +133,6 @@ it("statefully interacts with PoX-4", async () => { verbose: 2, }, ); + + model.reportCommandRuns(); }); diff --git a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts index 591568a17c..13283af8a9 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts @@ -51,6 +51,7 @@ export class AllowContractCallerCommand implements PoxCommand { } run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); // Act const allowContractCaller = real.network.callPublicFn( "ST000000000000000000002AMW42H.pox-4", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index d31e11a426..10dbbeaedc 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -6,11 +6,34 @@ import { StackingClient } from "@stacks/stacking"; export type StxAddress = string; export type BtcAddress = string; +export type CommandTag = string; -export type Stub = { +export class Stub { + readonly wallets: Map; + readonly statistics: Map; stackingMinimum: number; - wallets: Map; -}; + + constructor( + wallets: Map, + statistics: Map, + ) { + this.wallets = wallets; + this.statistics = statistics; + this.stackingMinimum = 0; + } + + trackCommandRun(commandName: string) { + const count = this.statistics.get(commandName) || 0; + this.statistics.set(commandName, count + 1); + } + + reportCommandRuns() { + process.stdout.write("Command run method execution counts:"); + this.statistics.forEach((count, commandName) => { + process.stdout.write(`\n${commandName}: ${count}`); + }); + } +} export type Real = { network: Simnet; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index baa5b16abd..5eeb43372e 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -97,6 +97,7 @@ export class DelegateStackStxCommand implements PoxCommand { } run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); // Act const delegateStackStx = real.network.callPublicFn( "ST000000000000000000002AMW42H.pox-4", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts index 59a0b9cba4..6de496d375 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts @@ -55,6 +55,7 @@ export class DelegateStxCommand implements PoxCommand { } run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); // The amount of uSTX delegated by the Stacker to the Delegatee. // Even if there are no constraints about the delegated amount, // it will be checked in the future, when calling delegate-stack-stx. diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts index 6e3ca20b43..c5a84e6a3d 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts @@ -32,6 +32,7 @@ export class GetStackingMinimumCommand implements PoxCommand { } run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); // Act const { result: stackingMinimum } = real.network.callReadOnlyFn( "ST000000000000000000002AMW42H.pox-4", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts index 7f6ddf6ca8..71cf99207c 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts @@ -31,6 +31,7 @@ export class GetStxAccountCommand implements PoxCommand { } run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); const actual = model.wallets.get(this.wallet.stxAddress)!; expect(real.network.runSnippet(`(stx-account '${actual.stxAddress})`)) .toBeTuple({ diff --git a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts index 93c3844d92..5ada55932d 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts @@ -37,6 +37,7 @@ export class RevokeDelegateStxCommand implements PoxCommand { } run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); // Get the Operator's wallet const operatorWallet = model.wallets.get(this.wallet.delegatedTo)!; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index da8a295bd5..cbdb782dc9 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -65,6 +65,7 @@ export class StackStxCommand implements PoxCommand { } run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); // The maximum amount of uSTX that can be used (per tx) with this signer // key. For our tests, we will use the minimum amount of uSTX to be stacked // in the given reward cycle multiplied by the margin, which is a randomly From 47fcfbd3392a87e1fc59621276d65b5b6ed84cac Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Fri, 29 Mar 2024 12:11:59 +0200 Subject: [PATCH 084/129] fix(pox-4-tests): Remove unnecessary check https://github.com/stacks-network/stacks-core/pull/4597/files/32e64e8ce33e440b5ddf9b3d804ce42e66e760ff#r1542690008 --- .../tests/pox-4/pox_DelegateStackStxCommand.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index 5eeb43372e..4da9cc6980 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -54,7 +54,7 @@ export class DelegateStackStxCommand implements PoxCommand { startBurnHt: number, period: number, amountUstx: bigint, - unlockBurnHt: number, + unlockBurnHt: number ) { this.operator = operator; this.stacker = stacker; @@ -90,7 +90,6 @@ export class DelegateStackStxCommand implements PoxCommand { stackerWallet.delegatedMaxAmount >= Number(this.amountUstx) && Number(this.amountUstx) <= stackerWallet.ustxBalance && Number(this.amountUstx) >= model.stackingMinimum && - operatorWallet.poolMembers.length > 0 && operatorWallet.poolMembers.includes(stackerWallet.stxAddress) && this.unlockBurnHt <= stackerWallet.delegatedUntilBurnHt ); @@ -114,13 +113,13 @@ export class DelegateStackStxCommand implements PoxCommand { // (lock-period uint) Cl.uint(this.period), ], - this.operator.stxAddress, + this.operator.stxAddress ); const { result: rewardCycle } = real.network.callReadOnlyFn( "ST000000000000000000002AMW42H.pox-4", "burn-height-to-reward-cycle", [Cl.uint(real.network.blockHeight)], - this.operator.stxAddress, + this.operator.stxAddress ); assert(isClarityType(rewardCycle, ClarityType.UInt)); @@ -128,7 +127,7 @@ export class DelegateStackStxCommand implements PoxCommand { "ST000000000000000000002AMW42H.pox-4", "reward-cycle-to-burn-height", [Cl.uint(Number(rewardCycle.value) + this.period + 1)], - this.operator.stxAddress, + this.operator.stxAddress ); assert(isClarityType(unlockBurnHeight, ClarityType.UInt)); @@ -138,7 +137,7 @@ export class DelegateStackStxCommand implements PoxCommand { stacker: Cl.principal(this.stacker.stxAddress), "lock-amount": Cl.uint(this.amountUstx), "unlock-burn-height": Cl.uint(Number(unlockBurnHeight.value)), - }), + }) ); // Get the Stacker's wallet from the model and update it with the new state. @@ -160,7 +159,7 @@ export class DelegateStackStxCommand implements PoxCommand { "lock-amount", this.amountUstx.toString(), "until", - this.stacker.unlockHeight.toString(), + this.stacker.unlockHeight.toString() ); } From b1272e0a791849140c484862a178231e465b0c75 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Fri, 29 Mar 2024 17:02:35 +0200 Subject: [PATCH 085/129] test(pox-4-tests): Add DelegateStackIncreaseCommand --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 1 + .../tests/pox-4/pox_CommandModel.ts | 1 + .../tests/pox-4/pox_Commands.ts | 24 ++++ .../pox-4/pox_DelegateStackIncreaseCommand.ts | 132 ++++++++++++++++++ .../pox-4/pox_DelegateStackStxCommand.ts | 5 + 5 files changed, 163 insertions(+) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index 6c64d93c29..f44a255351 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -87,6 +87,7 @@ it("statefully interacts with PoX-4", async () => { ustxBalance: initialUstxBalance, isStacking: false, hasDelegated: false, + hasLocked: [], poolMembers: [], delegatedTo: "", delegatedMaxAmount: 0, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 10dbbeaedc..de01266838 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -49,6 +49,7 @@ export type Wallet = { ustxBalance: number; isStacking: boolean; hasDelegated: boolean; + hasLocked: StxAddress[]; poolMembers: StxAddress[]; delegatedTo: StxAddress; delegatedMaxAmount: number; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 62db94efab..2abfd762be 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -9,6 +9,7 @@ import { Simnet } from "@hirosystems/clarinet-sdk"; import { Cl, cvToValue, OptionalCV, UIntCV } from "@stacks/transactions"; import { RevokeDelegateStxCommand } from "./pox_RevokeDelegateStxCommand"; import { AllowContractCallerCommand } from "./pox_AllowContractCallerCommand"; +import { DelegateStackIncreaseCommand } from "./pox_DelegateStackIncreaseCommand"; export function PoxCommands( wallets: Map, @@ -134,6 +135,29 @@ export function PoxCommands( finalResult.unlockBurnHt, ); }), + // DelegateStackIncreaseCommand + fc.record({ + operator: fc.constantFrom(...wallets.values()), + stacker: fc.constantFrom(...wallets.values()), + increaseBy: fc.bigInt({ min: 0n, max: 100_000_000_000_000n }), + }).chain((r) => { + const availableStackers = r.operator.poolMembers.length > 0 + ? r.operator.poolMembers + : [r.operator.stxAddress]; + + return fc.record({ + stacker: fc.constantFrom(...availableStackers), + }).map((stacker) => ({ + ...r, + stacker: wallets.get(stacker.stacker)!, + })); + }).map((final) => { + return new DelegateStackIncreaseCommand( + final.operator, + final.stacker, + final.increaseBy, + ); + }), // AllowContractCallerCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts new file mode 100644 index 0000000000..4df9f5f752 --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts @@ -0,0 +1,132 @@ +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; +import { poxAddressToTuple } from "@stacks/stacking"; +import { expect } from "vitest"; +import { Cl } from "@stacks/transactions"; + +/** + * The DelegateStackIncreaseCommand allows a pool operator to + * increase an active stacking lock, issuing a "partial commitment" + * for the increased cycles. + * + * This method increases stacker's current lockup and partially + * commits the additional STX to pox-addr + * + * Constraints for running this command include: + * - The Stacker must have locked uSTX. + * - The Operator has to currently be delegated by the Stacker. + * - The increase amount must be greater than 0. + * - Stacker's unlocked uSTX amount must be greater than or equal + * to the value of the increase amount. + * - Stacker's maximum delegated amount must be greater than or equal + * to the final locked amount. + * - The Operator must have locked the Stacker's previously locked funds. + */ +export class DelegateStackIncreaseCommand implements PoxCommand { + readonly operator: Wallet; + readonly stacker: Wallet; + readonly increaseBy: bigint; + + /** + * Constructs a DelegateStackIncreaseCommand 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 + */ + constructor(operator: Wallet, stacker: Wallet, increaseBy: bigint) { + this.operator = operator; + this.stacker = stacker; + this.increaseBy = increaseBy; + } + + check(model: Readonly): boolean { + // Constraints for running this command include: + // - The Stacker must have locked uSTX. + // - The Operator has to currently be delegated by the Stacker. + // - The increase amount must be greater than 0. + // - Stacker's unlocked uSTX amount must be greater than or equal + // to the value of the increase amount. + // - Stacker's maximum delegated amount must be greater than or equal + // to the final locked amount. + // - The Operator must have locked the Stacker's previously locked funds. + + const operatorWallet = model.wallets.get(this.operator.stxAddress)!; + const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; + + return ( + stackerWallet.amountLocked > 0 && + stackerWallet.hasDelegated === true && + stackerWallet.isStacking === true && + this.increaseBy > 0 && + operatorWallet.poolMembers.includes(stackerWallet.stxAddress) && + stackerWallet.amountUnlocked >= this.increaseBy && + stackerWallet.delegatedMaxAmount >= + Number(this.increaseBy) + stackerWallet.amountLocked && + operatorWallet.hasLocked.indexOf(stackerWallet.stxAddress) > -1 + ); + } + + run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); + + const prevLocked = this.stacker.amountLocked; + const newTotalLocked = prevLocked + Number(this.increaseBy); + // 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.stacker.delegatedPoxAddress), + // (increase-by uint) + Cl.uint(this.increaseBy), + ], + this.operator.stxAddress, + ); + + // Assert + expect(delegateStackIncrease.result).toBeOk( + Cl.tuple({ + stacker: Cl.principal(this.stacker.stxAddress), + "total-locked": Cl.uint(newTotalLocked), + }), + ); + + // Get the Stacker's wallet from the model and update it with the new state. + const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; + // Update model so that we know this stacker has increased the stacked amount. + // Update locked and unlocked fields in the model. + stackerWallet.amountLocked = newTotalLocked; + stackerWallet.amountUnlocked = stackerWallet.amountUnlocked - + Number(this.increaseBy); + + // 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.operator.label} Ӿ ${this.stacker.label}`, + "delegate-stack-increase", + "increased by", + this.increaseBy.toString(), + "previously locked", + prevLocked.toString(), + "total locked", + stackerWallet.amountLocked.toString(), + ); + } + + 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}`; + } +} diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index 4da9cc6980..73096a4d42 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -142,6 +142,7 @@ export class DelegateStackStxCommand implements PoxCommand { // Get the Stacker's wallet from the model and update it with the new state. const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; + const operatorWallet = model.wallets.get(this.operator.stxAddress)!; // Update model so that we know this wallet is stacking. This is important // in order to prevent the test from stacking multiple times with the same // address. @@ -150,6 +151,10 @@ export class DelegateStackStxCommand implements PoxCommand { stackerWallet.amountLocked = Number(this.amountUstx); stackerWallet.unlockHeight = Number(unlockBurnHeight.value); stackerWallet.amountUnlocked -= Number(this.amountUstx); + // Add stacker to the operators lock list. This will help knowing that + // the stacker's funds are locked when calling delegate-stack-extend, + // delegate-stack-increase + operatorWallet.hasLocked.push(stackerWallet.stxAddress); // 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. From 22feaa753341086ef58bd5efb3ff8dc74c5f1dc7 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Fri, 29 Mar 2024 17:03:02 +0200 Subject: [PATCH 086/129] fix(pox-4-tests): Remove noopReporter file --- contrib/core-contract-tests/noopReporter.ts | 26 --------------------- 1 file changed, 26 deletions(-) delete mode 100644 contrib/core-contract-tests/noopReporter.ts diff --git a/contrib/core-contract-tests/noopReporter.ts b/contrib/core-contract-tests/noopReporter.ts deleted file mode 100644 index c97206f5f1..0000000000 --- a/contrib/core-contract-tests/noopReporter.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { UserConsoleLog } from "vitest"; - -import { DefaultReporter } from "vitest/reporters"; - -export default class LoggerReporter extends DefaultReporter { - onInit() {} - onPathsCollected() {} - onCollected() {} - onFinished() { - return Promise.resolve(); - } - onTaskUpdate() {} - - onWatcherStart() { - return Promise.resolve(); - } - onWatcherRerun() { - return Promise.resolve(); - } - - onServerRestart() {} - - onProcessTimeou() {} - - onUserConsoleLog(log: UserConsoleLog) {} -} From fb5c0e746927f2eea73902064546673127968d33 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Mon, 1 Apr 2024 13:34:34 +0300 Subject: [PATCH 087/129] fix(pox-4-tests): Adjust delegate-stack-increase generator to address lock period comment https://github.com/stacks-network/stacks-core/pull/4607#discussion_r1544640858 --- .../tests/pox-4/pox_Commands.ts | 46 +++++++++++-------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 2abfd762be..0d672d9f67 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -138,26 +138,36 @@ export function PoxCommands( // DelegateStackIncreaseCommand fc.record({ operator: fc.constantFrom(...wallets.values()), - stacker: fc.constantFrom(...wallets.values()), increaseBy: fc.bigInt({ min: 0n, max: 100_000_000_000_000n }), - }).chain((r) => { - const availableStackers = r.operator.poolMembers.length > 0 - ? r.operator.poolMembers - : [r.operator.stxAddress]; + }) + .chain((r) => { + const delegatorsList = r.operator.poolMembers; - return fc.record({ - stacker: fc.constantFrom(...availableStackers), - }).map((stacker) => ({ - ...r, - stacker: wallets.get(stacker.stacker)!, - })); - }).map((final) => { - return new DelegateStackIncreaseCommand( - final.operator, - final.stacker, - final.increaseBy, - ); - }), + const availableStackers = delegatorsList.filter((delegator) => { + const delegatorWallet = wallets.get(delegator)!; + return delegatorWallet.unlockHeight > nextCycleFirstBlock(network); + }); + + const availableStackersOrFallback = availableStackers.length === 0 + ? [r.operator.stxAddress] + : availableStackers; + + return fc + .record({ + stacker: fc.constantFrom(...availableStackersOrFallback), + }) + .map((stacker) => ({ + ...r, + stacker: wallets.get(stacker.stacker)!, + })); + }) + .map((final) => { + return new DelegateStackIncreaseCommand( + final.operator, + final.stacker, + final.increaseBy, + ); + }), // AllowContractCallerCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), From 4a7d4a8662649a10b4e03175635c804c69db0dc5 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Mon, 1 Apr 2024 13:48:54 +0300 Subject: [PATCH 088/129] fix(pox-4-tests): Rename `haslocked` to `lockedAddresses` --- .../core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts | 2 +- contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts | 2 +- .../tests/pox-4/pox_DelegateStackIncreaseCommand.ts | 2 +- .../tests/pox-4/pox_DelegateStackStxCommand.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index f44a255351..51553de06a 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -87,7 +87,7 @@ it("statefully interacts with PoX-4", async () => { ustxBalance: initialUstxBalance, isStacking: false, hasDelegated: false, - hasLocked: [], + lockedAddresses: [], poolMembers: [], delegatedTo: "", delegatedMaxAmount: 0, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index de01266838..ef7740cff0 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -49,7 +49,7 @@ export type Wallet = { ustxBalance: number; isStacking: boolean; hasDelegated: boolean; - hasLocked: StxAddress[]; + lockedAddresses: StxAddress[]; poolMembers: StxAddress[]; delegatedTo: StxAddress; delegatedMaxAmount: number; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts index 4df9f5f752..dee49e8199 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts @@ -69,7 +69,7 @@ export class DelegateStackIncreaseCommand implements PoxCommand { stackerWallet.amountUnlocked >= this.increaseBy && stackerWallet.delegatedMaxAmount >= Number(this.increaseBy) + stackerWallet.amountLocked && - operatorWallet.hasLocked.indexOf(stackerWallet.stxAddress) > -1 + operatorWallet.lockedAddresses.indexOf(stackerWallet.stxAddress) > -1 ); } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index 73096a4d42..15eda03b31 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -154,7 +154,7 @@ export class DelegateStackStxCommand implements PoxCommand { // Add stacker to the operators lock list. This will help knowing that // the stacker's funds are locked when calling delegate-stack-extend, // delegate-stack-increase - operatorWallet.hasLocked.push(stackerWallet.stxAddress); + operatorWallet.lockedAddresses.push(stackerWallet.stxAddress); // 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. From f7d4dfa669a674abfe4cf860792cd207683c4656 Mon Sep 17 00:00:00 2001 From: BowTiedRadone <92028479+BowTiedRadone@users.noreply.github.com> Date: Mon, 1 Apr 2024 13:51:04 +0300 Subject: [PATCH 089/129] chore(pox-4-tests): Update `DelegateStackIncreaseCommand` documentation https://github.com/stacks-network/stacks-core/pull/4607#discussion_r1545250631 Co-authored-by: Nikos Baxevanis --- .../tests/pox-4/pox_DelegateStackIncreaseCommand.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts index dee49e8199..89ea9afbc3 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts @@ -15,7 +15,7 @@ import { Cl } from "@stacks/transactions"; * for the increased cycles. * * This method increases stacker's current lockup and partially - * commits the additional STX to pox-addr + * commits the additional STX to `pox-addr`. * * Constraints for running this command include: * - The Stacker must have locked uSTX. From 6c7d2e27711ab657e4469cd004b780211d40ad4e Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Mon, 1 Apr 2024 14:15:24 +0300 Subject: [PATCH 090/129] fix(pox-4-tests): Update `increaseBy` generator from bigint to number https://github.com/stacks-network/stacks-core/pull/4607#discussion_r1545253300 --- .../core-contract-tests/tests/pox-4/pox_Commands.ts | 2 +- .../tests/pox-4/pox_DelegateStackIncreaseCommand.ts | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 0d672d9f67..9603496273 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -138,7 +138,7 @@ export function PoxCommands( // DelegateStackIncreaseCommand fc.record({ operator: fc.constantFrom(...wallets.values()), - increaseBy: fc.bigInt({ min: 0n, max: 100_000_000_000_000n }), + increaseBy: fc.nat(), }) .chain((r) => { const delegatorsList = r.operator.poolMembers; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts index 89ea9afbc3..ff8ecfb98a 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts @@ -30,7 +30,7 @@ import { Cl } from "@stacks/transactions"; export class DelegateStackIncreaseCommand implements PoxCommand { readonly operator: Wallet; readonly stacker: Wallet; - readonly increaseBy: bigint; + readonly increaseBy: number; /** * Constructs a DelegateStackIncreaseCommand to increase the uSTX amount @@ -40,7 +40,7 @@ export class DelegateStackIncreaseCommand implements PoxCommand { * @param stacker - Represents the Stacker's wallet. * @param increaseBy - Represents the locked amount to be increased by */ - constructor(operator: Wallet, stacker: Wallet, increaseBy: bigint) { + constructor(operator: Wallet, stacker: Wallet, increaseBy: number) { this.operator = operator; this.stacker = stacker; this.increaseBy = increaseBy; @@ -68,7 +68,7 @@ export class DelegateStackIncreaseCommand implements PoxCommand { operatorWallet.poolMembers.includes(stackerWallet.stxAddress) && stackerWallet.amountUnlocked >= this.increaseBy && stackerWallet.delegatedMaxAmount >= - Number(this.increaseBy) + stackerWallet.amountLocked && + this.increaseBy + stackerWallet.amountLocked && operatorWallet.lockedAddresses.indexOf(stackerWallet.stxAddress) > -1 ); } @@ -77,7 +77,7 @@ export class DelegateStackIncreaseCommand implements PoxCommand { model.trackCommandRun(this.constructor.name); const prevLocked = this.stacker.amountLocked; - const newTotalLocked = prevLocked + Number(this.increaseBy); + const newTotalLocked = prevLocked + this.increaseBy; // Act const delegateStackIncrease = real.network.callPublicFn( "ST000000000000000000002AMW42H.pox-4", @@ -107,7 +107,7 @@ export class DelegateStackIncreaseCommand implements PoxCommand { // Update locked and unlocked fields in the model. stackerWallet.amountLocked = newTotalLocked; stackerWallet.amountUnlocked = stackerWallet.amountUnlocked - - Number(this.increaseBy); + this.increaseBy; // 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. From 838c98f61c7bb30676cf11ffdca81e9b067e5e10 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Mon, 1 Apr 2024 19:44:33 +0300 Subject: [PATCH 091/129] test(pox-4-tests): Add DelegateStackExtendCommand --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 1 + .../tests/pox-4/pox_CommandModel.ts | 1 + .../tests/pox-4/pox_Commands.ts | 39 ++++- .../pox-4/pox_DelegateStackExtendCommand.ts | 160 ++++++++++++++++++ .../pox-4/pox_DelegateStackStxCommand.ts | 2 + 5 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index 51553de06a..4c60af0dca 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -96,6 +96,7 @@ it("statefully interacts with PoX-4", async () => { amountLocked: 0, amountUnlocked: initialUstxBalance, unlockHeight: 0, + firstLockedRewardCycle: 0, allowedContractCaller: "", callerAllowedBy: [], }; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index ef7740cff0..668de39fc3 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -58,6 +58,7 @@ export type Wallet = { amountLocked: number; amountUnlocked: number; unlockHeight: number; + firstLockedRewardCycle: number; allowedContractCaller: StxAddress; callerAllowedBy: StxAddress[]; }; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 9603496273..79a54808c6 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -10,6 +10,7 @@ import { Cl, cvToValue, OptionalCV, UIntCV } from "@stacks/transactions"; import { RevokeDelegateStxCommand } from "./pox_RevokeDelegateStxCommand"; import { AllowContractCallerCommand } from "./pox_AllowContractCallerCommand"; import { DelegateStackIncreaseCommand } from "./pox_DelegateStackIncreaseCommand"; +import { DelegateStackExtendCommand } from "./pox_DelegateStackExtendCommand"; export function PoxCommands( wallets: Map, @@ -168,6 +169,38 @@ export function PoxCommands( final.increaseBy, ); }), + // DelegateStackExtendCommand + fc.record({ + operator: fc.constantFrom(...wallets.values()), + extendCount: fc.integer({ min: 1, max: 11 }), + }).chain((r) => { + const delegatorsList = r.operator.poolMembers; + const availableStackers = delegatorsList.filter((delegator) => { + const delegatorWallet = wallets.get(delegator)!; + return delegatorWallet.unlockHeight > nextCycleFirstBlock(network); + }); + + const availableStackersOrFallback = availableStackers.length === 0 + ? [r.operator.stxAddress] + : availableStackers; + + return fc.record({ + stacker: fc.constantFrom(...availableStackersOrFallback), + currentCycle: fc.constant(currentCycle(network)), + }) + .map((additionalProps) => ({ + ...r, + stacker: wallets.get(additionalProps.stacker)!, + currentCycle: additionalProps.currentCycle, + })); + }).map((final) => + new DelegateStackExtendCommand( + final.operator, + final.stacker, + final.extendCount, + final.currentCycle, + ) + ), // AllowContractCallerCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), @@ -208,7 +241,11 @@ export function PoxCommands( return fc.commands(cmds, { size: "large" }); } -const currentCycle = (network: Simnet) => +export const REWARD_CYCLE_LENGTH = 1050; + +export const FIRST_BURNCHAIN_BLOCK_HEIGHT = 0; + +export const currentCycle = (network: Simnet) => Number(cvToValue( network.callReadOnlyFn( "ST000000000000000000002AMW42H.pox-4", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts new file mode 100644 index 0000000000..f66b42ddb4 --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts @@ -0,0 +1,160 @@ +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; +import { poxAddressToTuple } from "@stacks/stacking"; +import { assert, expect } from "vitest"; +import { + Cl, + ClarityType, + isClarityType, +} from "@stacks/transactions"; +import { + FIRST_BURNCHAIN_BLOCK_HEIGHT, + REWARD_CYCLE_LENGTH, +} from "./pox_Commands.ts"; + +/** + * The `DelegateStackExtendCommand` allows a pool operator to + * extend an active stacking lock, issuing a "partial commitment" + * for the extended-to cycles. + * + * This method extends stacker's current lockup for an additional + * extend-count and partially commits those new cycles to `pox-addr`. + * + * Constraints for running this command include: + * - Stacker must have locked uSTX. + * - The Operator has to currently be delegated by the Stacker. + * - The new lock period must be less than or equal to 12. + */ +export class DelegateStackExtendCommand implements PoxCommand { + readonly operator: Wallet; + readonly stacker: Wallet; + readonly extendCount: number; + readonly currentCycle: number; + + /** + * Constructs a `DelegateStackExtendCommand` 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 cycles to be expended. + * @param currentCycle - Represents the current PoX reward cycle. + */ + constructor( + operator: Wallet, + stacker: Wallet, + extendCount: number, + currentCycle: number, + ) { + this.operator = operator; + this.stacker = stacker; + this.extendCount = extendCount; + this.currentCycle = currentCycle; + } + + check(model: Readonly): boolean { + // Constraints for running this command include: + // - Stacker must have locked uSTX. + // - The Stacker's uSTX must have been locked by the Operator. + // - The Operator has to currently be delegated by the Stacker. + // - The new lock period must be less than or equal to 12. + + const operatorWallet = model.wallets.get(this.operator.stxAddress)!; + const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; + + const firstRewardCycle = + this.currentCycle > this.stacker.firstLockedRewardCycle + ? this.currentCycle + : this.stacker.firstLockedRewardCycle; + const firstExtendCycle = Math.floor( + (this.stacker.unlockHeight - FIRST_BURNCHAIN_BLOCK_HEIGHT) / + REWARD_CYCLE_LENGTH, + ); + const lastExtendCycle = firstExtendCycle + this.extendCount - 1; + const totalPeriod = lastExtendCycle - firstRewardCycle + 1; + + return ( + stackerWallet.amountLocked > 0 && + stackerWallet.hasDelegated === true && + stackerWallet.isStacking === true && + operatorWallet.poolMembers.includes(stackerWallet.stxAddress) && + operatorWallet.lockedAddresses.includes(stackerWallet.stxAddress) && + totalPeriod <= 12 + ); + } + + run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); + + // 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.stacker.delegatedPoxAddress), + // (extend-count uint) + Cl.uint(this.extendCount), + ], + this.operator.stxAddress, + ); + + const { result: firstExtendCycle } = real.network.callReadOnlyFn( + "ST000000000000000000002AMW42H.pox-4", + "burn-height-to-reward-cycle", + [Cl.uint(this.stacker.unlockHeight)], + this.operator.stxAddress, + ); + assert(isClarityType(firstExtendCycle, ClarityType.UInt)); + + const lastExtendCycle = Number(firstExtendCycle.value) + this.extendCount - + 1; + + const { result: extendedUnlockHeight } = real.network.callReadOnlyFn( + "ST000000000000000000002AMW42H.pox-4", + "reward-cycle-to-burn-height", + [Cl.uint(lastExtendCycle + 1)], + this.operator.stxAddress, + ); + assert(isClarityType(extendedUnlockHeight, ClarityType.UInt)); + const newUnlockHeight = extendedUnlockHeight.value; + + // Assert + expect(delegateStackExtend.result).toBeOk( + Cl.tuple({ + stacker: Cl.principal(this.stacker.stxAddress), + "unlock-burn-height": Cl.uint(newUnlockHeight), + }), + ); + + // Get the Stacker's wallet from the model and update it with the new state. + const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; + // Update model so that we know this wallet's unlock height was extended. + stackerWallet.unlockHeight = Number(newUnlockHeight); + + // 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.operator.label} Ӿ ${this.stacker.label}`, + "delegate-stack-extend", + "extend count", + this.extendCount.toString(), + "new unlock height", + this.stacker.unlockHeight.toString(), + ); + } + + 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-extend extend count ${this.extendCount} previous unlock height ${this.stacker.unlockHeight}`; + } +} diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index 15eda03b31..1005765c54 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -8,6 +8,7 @@ import { import { poxAddressToTuple } from "@stacks/stacking"; import { assert, expect } from "vitest"; import { Cl, ClarityType, isClarityType } from "@stacks/transactions"; +import { currentCycle } from "./pox_Commands.ts"; /** * The `DelegateStackStxCommand` locks STX for stacking within PoX-4 on behalf of a delegator. @@ -151,6 +152,7 @@ export class DelegateStackStxCommand implements PoxCommand { stackerWallet.amountLocked = Number(this.amountUstx); stackerWallet.unlockHeight = Number(unlockBurnHeight.value); stackerWallet.amountUnlocked -= Number(this.amountUstx); + stackerWallet.firstLockedRewardCycle = currentCycle(real.network) + 1; // Add stacker to the operators lock list. This will help knowing that // the stacker's funds are locked when calling delegate-stack-extend, // delegate-stack-increase From 6b094458e13f2acbd776671549612a2c8d81effb Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Wed, 3 Apr 2024 00:34:11 +0300 Subject: [PATCH 092/129] test(pox-4-tests): Add StackAggregationCommitCommand authorization-based --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 1 + .../tests/pox-4/pox_CommandModel.ts | 1 + .../tests/pox-4/pox_Commands.ts | 19 +++ .../pox-4/pox_DelegateStackIncreaseCommand.ts | 2 + .../pox-4/pox_DelegateStackStxCommand.ts | 1 + .../pox_StackAggregationCommitCommand.ts | 140 ++++++++++++++++++ 6 files changed, 164 insertions(+) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index 4c60af0dca..6153640165 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -88,6 +88,7 @@ it("statefully interacts with PoX-4", async () => { isStacking: false, hasDelegated: false, lockedAddresses: [], + amountToCommit: 0, poolMembers: [], delegatedTo: "", delegatedMaxAmount: 0, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 668de39fc3..ea8fcbdad0 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -50,6 +50,7 @@ export type Wallet = { isStacking: boolean; hasDelegated: boolean; lockedAddresses: StxAddress[]; + amountToCommit: number; poolMembers: StxAddress[]; delegatedTo: StxAddress; delegatedMaxAmount: number; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 79a54808c6..2dcd804012 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -11,6 +11,7 @@ import { RevokeDelegateStxCommand } from "./pox_RevokeDelegateStxCommand"; import { AllowContractCallerCommand } from "./pox_AllowContractCallerCommand"; import { DelegateStackIncreaseCommand } from "./pox_DelegateStackIncreaseCommand"; import { DelegateStackExtendCommand } from "./pox_DelegateStackExtendCommand"; +import { StackAggregationCommitCommand } from "./pox_StackAggregationCommitCommand"; export function PoxCommands( wallets: Map, @@ -74,6 +75,24 @@ export function PoxCommands( r.amount, ) ), + // StackAggregationCommitCommand + fc.record({ + wallet: fc.constantFrom(...wallets.values()), + authId: fc.nat(), + currentCycle: fc.constant(currentCycle(network)), + }).map(( + r: { + wallet: Wallet; + authId: number; + currentCycle: number; + }, + ) => + new StackAggregationCommitCommand( + r.wallet, + r.authId, + r.currentCycle, + ) + ), // RevokeDelegateStxCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts index ff8ecfb98a..23cfd63413 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts @@ -103,11 +103,13 @@ export class DelegateStackIncreaseCommand implements PoxCommand { // Get the Stacker's wallet from the model and update it with the new state. const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; + const operatorWallet = model.wallets.get(this.operator.stxAddress)! // Update model so that we know this stacker has increased the stacked amount. // Update locked and unlocked fields in the model. stackerWallet.amountLocked = newTotalLocked; stackerWallet.amountUnlocked = stackerWallet.amountUnlocked - this.increaseBy; + operatorWallet.amountToCommit += this.increaseBy // 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. diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index 1005765c54..544c869f40 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -157,6 +157,7 @@ export class DelegateStackStxCommand implements PoxCommand { // the stacker's funds are locked when calling delegate-stack-extend, // delegate-stack-increase operatorWallet.lockedAddresses.push(stackerWallet.stxAddress); + operatorWallet.amountToCommit += Number(this.amountUstx) // 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. diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitCommand.ts new file mode 100644 index 0000000000..dfa5b971fd --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitCommand.ts @@ -0,0 +1,140 @@ +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; +import { poxAddressToTuple } from "@stacks/stacking"; +import { expect } from "vitest"; +import { Cl } from "@stacks/transactions"; + +/** + * The `StackAggregationCommitCommand` allows an operator commits partially + * stacked STX and allocate a new PoX reward address slot. This allows a + * stacker to lock fewer STX than the minimal threshold in multiple transactions, + * so long as: + * 1. The pox-addr is the same. + * 2. This "commit" transaction is called _before_ the PoX anchor block. + * + * Constraints for running this command include: + * - The Operator must have locked STX on behalf of at least one stacker. + * - The total amount previously locked by the Operator on behalf of the + * stackers has to be greater than the uSTX threshold. + * - All of the Stackers must have delegated to the same pox address. + */ +export class StackAggregationCommitCommand implements PoxCommand { + readonly operator: Wallet; + readonly authId: number; + readonly currentCycle: number; + + /** + * Constructs a `StackAggregationCommitCommand` to lock uSTX for stacking. + * + * @param operator - Represents the `Operator`'s wallet. + * @param authId - Unique `auth-id` for the authorization. + * @param currentCycle - The current reward cycle. + */ + constructor( + operator: Wallet, + authId: number, + currentCycle: number, + ) { + this.operator = operator; + this.authId = authId; + this.currentCycle = currentCycle; + } + + check(model: Readonly): boolean { + // Constraints for running this command include: + // - The Operator must have locked STX on behalf of at least one stacker. + // - The total amount previously locked by the Operator on behalf of the + // stackers has to be greater than the uSTX threshold. + // - All of the Stackers must have delegated to the same pox address. + let sameDelegatedPoxAddrAllStackers = true; + const firstDelegatedPoxAddress = this.operator.lockedAddresses.length > 0 + ? model.wallets.get(this.operator.lockedAddresses[0])!.delegatedPoxAddress + : this.operator.btcAddress; + + this.operator.lockedAddresses.forEach((stacker) => { + if ( + model.wallets.get(stacker)!.delegatedPoxAddress !== + firstDelegatedPoxAddress + ) sameDelegatedPoxAddrAllStackers = false; + }); + + return this.operator.lockedAddresses.length > 0 && + this.operator.amountToCommit >= model.stackingMinimum && + sameDelegatedPoxAddrAllStackers; + } + + run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); + + const committedAmount = this.operator.amountToCommit; + + const { result: setSignature } = real.network.callPublicFn( + "ST000000000000000000002AMW42H.pox-4", + "set-signer-key-authorization", + [ + // (pox-addr (tuple (version (buff 1)) (hashbytes (buff 32)))) + poxAddressToTuple(this.operator.btcAddress), + // (period uint) + Cl.uint(1), + // (reward-cycle uint) + Cl.uint(this.currentCycle + 1), + // (topic (string-ascii 14)) + Cl.stringAscii("agg-commit"), + // (signer-key (buff 33)) + Cl.bufferFromHex(this.operator.signerPubKey), + // (allowed bool) + Cl.bool(true), + // (max-amount uint) + Cl.uint(this.operator.amountToCommit), + // (auth-id uint) + Cl.uint(this.authId), + ], + this.operator.stxAddress, + ); + expect(setSignature).toBeOk(Cl.bool(true)); + + // Act + const stackAggregationCommit = real.network.callPublicFn( + "ST000000000000000000002AMW42H.pox-4", + "stack-aggregation-commit", + [ + // (pox-addr (tuple (version (buff 1)) (hashbytes (buff 32)))) + poxAddressToTuple(this.operator.btcAddress), + // (reward-cycle uint) + Cl.uint(this.currentCycle + 1), + // (signer-sig (optional (buff 65))) + Cl.none(), + // (signer-key (buff 33)) + Cl.bufferFromHex(this.operator.signerPubKey), + // (max-amount uint) + Cl.uint(committedAmount), + // (auth-id uint) + Cl.uint(this.authId), + ], + this.operator.stxAddress, + ); + + // Assert + expect(stackAggregationCommit.result).toBeOk(Cl.bool(true)); + + const operatorWallet = model.wallets.get(this.operator.stxAddress)!; + + operatorWallet.amountToCommit -= committedAmount; + + // 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.operator.label}`, "stack-aggregation-commit", 'amount committed', committedAmount.toString()); + } + + 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}`; + } +} From bebb7b7eae0fa09906524c7a6a619034c36706a4 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Wed, 3 Apr 2024 13:49:26 +0300 Subject: [PATCH 093/129] test(pox-4-tests): Rename `StackAggregationCommit` to `StackAggregationCommitAuth` --- contrib/core-contract-tests/tests/pox-4/pox_Commands.ts | 6 +++--- ...tCommand.ts => pox_StackAggregationCommitAuthCommand.ts} | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) rename contrib/core-contract-tests/tests/pox-4/{pox_StackAggregationCommitCommand.ts => pox_StackAggregationCommitAuthCommand.ts} (95%) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 2dcd804012..27a644aa07 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -11,7 +11,7 @@ import { RevokeDelegateStxCommand } from "./pox_RevokeDelegateStxCommand"; import { AllowContractCallerCommand } from "./pox_AllowContractCallerCommand"; import { DelegateStackIncreaseCommand } from "./pox_DelegateStackIncreaseCommand"; import { DelegateStackExtendCommand } from "./pox_DelegateStackExtendCommand"; -import { StackAggregationCommitCommand } from "./pox_StackAggregationCommitCommand"; +import { StackAggregationCommitAuthCommand } from "./pox_StackAggregationCommitAuthCommand"; export function PoxCommands( wallets: Map, @@ -75,7 +75,7 @@ export function PoxCommands( r.amount, ) ), - // StackAggregationCommitCommand + // StackAggregationCommitAuthCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), authId: fc.nat(), @@ -87,7 +87,7 @@ export function PoxCommands( currentCycle: number; }, ) => - new StackAggregationCommitCommand( + new StackAggregationCommitAuthCommand( r.wallet, r.authId, r.currentCycle, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts similarity index 95% rename from contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitCommand.ts rename to contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts index dfa5b971fd..1b8795ca00 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts @@ -10,7 +10,7 @@ import { expect } from "vitest"; import { Cl } from "@stacks/transactions"; /** - * The `StackAggregationCommitCommand` allows an operator commits partially + * The `StackAggregationCommitAuthCommand` allows an operator commits partially * stacked STX and allocate a new PoX reward address slot. This allows a * stacker to lock fewer STX than the minimal threshold in multiple transactions, * so long as: @@ -23,13 +23,13 @@ import { Cl } from "@stacks/transactions"; * stackers has to be greater than the uSTX threshold. * - All of the Stackers must have delegated to the same pox address. */ -export class StackAggregationCommitCommand implements PoxCommand { +export class StackAggregationCommitAuthCommand implements PoxCommand { readonly operator: Wallet; readonly authId: number; readonly currentCycle: number; /** - * Constructs a `StackAggregationCommitCommand` to lock uSTX for stacking. + * Constructs a `StackAggregationCommitAuthCommand` to lock uSTX for stacking. * * @param operator - Represents the `Operator`'s wallet. * @param authId - Unique `auth-id` for the authorization. From 3d778ce1a604c53498f148863ca6bba6e75b289c Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Wed, 3 Apr 2024 14:18:27 +0300 Subject: [PATCH 094/129] Add StackAggregationCommitCommand signature-based --- .../tests/pox-4/pox_Commands.ts | 19 +++ .../pox_StackAggregationCommitAuthCommand.ts | 10 +- .../pox_StackAggregationCommitSigCommand.ts | 148 ++++++++++++++++++ 3 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 27a644aa07..93b6dc3c89 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -12,6 +12,7 @@ import { AllowContractCallerCommand } from "./pox_AllowContractCallerCommand"; import { DelegateStackIncreaseCommand } from "./pox_DelegateStackIncreaseCommand"; import { DelegateStackExtendCommand } from "./pox_DelegateStackExtendCommand"; import { StackAggregationCommitAuthCommand } from "./pox_StackAggregationCommitAuthCommand"; +import { StackAggregationCommitSigCommand } from "./pox_StackAggregationCommitSigCommand"; export function PoxCommands( wallets: Map, @@ -93,6 +94,24 @@ export function PoxCommands( r.currentCycle, ) ), + // StackAggregationCommitSigCommand + fc.record({ + wallet: fc.constantFrom(...wallets.values()), + authId: fc.nat(), + currentCycle: fc.constant(currentCycle(network)), + }).map(( + r: { + wallet: Wallet; + authId: number; + currentCycle: number; + }, + ) => + new StackAggregationCommitSigCommand( + r.wallet, + r.authId, + r.currentCycle, + ) + ), // RevokeDelegateStxCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts index 1b8795ca00..24bb540e23 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts @@ -17,6 +17,8 @@ import { Cl } from "@stacks/transactions"; * 1. The pox-addr is the same. * 2. This "commit" transaction is called _before_ the PoX anchor block. * + * This command calls stack-aggregation-commit using an `authorization`. + * * Constraints for running this command include: * - The Operator must have locked STX on behalf of at least one stacker. * - The total amount previously locked by the Operator on behalf of the @@ -128,7 +130,13 @@ export class StackAggregationCommitAuthCommand 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.operator.label}`, "stack-aggregation-commit", 'amount committed', committedAmount.toString()); + logCommand( + `✓ ${this.operator.label}`, + "stack-agg-commit", + "amount committed", + committedAmount.toString(), + "authorization", + ); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts new file mode 100644 index 0000000000..bf8b2e61be --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts @@ -0,0 +1,148 @@ +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; +import { Pox4SignatureTopic, poxAddressToTuple } from "@stacks/stacking"; +import { expect } from "vitest"; +import { Cl } from "@stacks/transactions"; +import { bufferFromHex } from "@stacks/transactions/dist/cl"; + +/** + * The `StackAggregationCommitSigCommand` allows an operator commits partially + * stacked STX and allocate a new PoX reward address slot. This allows a + * stacker to lock fewer STX than the minimal threshold in multiple transactions, + * so long as: + * 1. The pox-addr is the same. + * 2. This "commit" transaction is called _before_ the PoX anchor block. + * + * This command calls `stack-aggregation-commit` using an `signature`. + * + * Constraints for running this command include: + * - The Operator must have locked STX on behalf of at least one stacker. + * - The total amount previously locked by the Operator on behalf of the + * stackers has to be greater than the uSTX threshold. + * - All of the Stackers must have delegated to the same pox address. + */ +export class StackAggregationCommitSigCommand implements PoxCommand { + readonly operator: Wallet; + readonly authId: number; + readonly currentCycle: number; + + /** + * Constructs a `StackAggregationCommitSigCommand` to lock uSTX for stacking. + * + * @param operator - Represents the `Operator`'s wallet. + * @param authId - Unique `auth-id` for the authorization. + * @param currentCycle - The current reward cycle. + */ + constructor( + operator: Wallet, + authId: number, + currentCycle: number, + ) { + this.operator = operator; + this.authId = authId; + this.currentCycle = currentCycle; + } + + check(model: Readonly): boolean { + // Constraints for running this command include: + // - The Operator must have locked STX on behalf of at least one stacker. + // - The total amount previously locked by the Operator on behalf of the + // stackers has to be greater than the uSTX threshold. + // - All of the Stackers must have delegated to the same pox address. + let sameDelegatedPoxAddrAllStackers = true; + const firstDelegatedPoxAddress = this.operator.lockedAddresses.length > 0 + ? model.wallets.get(this.operator.lockedAddresses[0])!.delegatedPoxAddress + : this.operator.btcAddress; + + this.operator.lockedAddresses.forEach((stacker) => { + if ( + model.wallets.get(stacker)!.delegatedPoxAddress !== + firstDelegatedPoxAddress + ) sameDelegatedPoxAddrAllStackers = false; + }); + + return this.operator.lockedAddresses.length > 0 && + this.operator.amountToCommit >= model.stackingMinimum && + sameDelegatedPoxAddrAllStackers; + } + + run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); + + const committedAmount = this.operator.amountToCommit; + + const signerSig = this.operator.stackingClient.signPoxSignature({ + // The signer key being authorized. + signerPrivateKey: this.operator.signerPrvKey, + // The reward cycle for which the authorization is valid. + // For stack-stx and stack-extend, this refers to the reward cycle + // where the transaction is confirmed. For stack-aggregation-commit, + // this refers to the reward cycle argument in that function. + rewardCycle: this.currentCycle + 1, + // For stack-stx, this refers to lock-period. For stack-extend, + // this refers to extend-count. For stack-aggregation-commit, this is + // u1. + period: 1, + // A string representing the function where this authorization is valid. + // Either stack-stx, stack-extend, stack-increase or agg-commit. + topic: Pox4SignatureTopic.AggregateCommit, + // The PoX address that can be used with this signer key. + poxAddress: this.operator.btcAddress, + // The unique auth-id for this authorization. + authId: this.authId, + // The maximum amount of uSTX that can be used (per tx) with this signer + // key. + maxAmount: committedAmount, + }); + + // Act + const stackAggregationCommit = real.network.callPublicFn( + "ST000000000000000000002AMW42H.pox-4", + "stack-aggregation-commit", + [ + // (pox-addr (tuple (version (buff 1)) (hashbytes (buff 32)))) + poxAddressToTuple(this.operator.btcAddress), + // (reward-cycle uint) + Cl.uint(this.currentCycle + 1), + // (signer-sig (optional (buff 65))) + Cl.some(bufferFromHex(signerSig)), + // (signer-key (buff 33)) + Cl.bufferFromHex(this.operator.signerPubKey), + // (max-amount uint) + Cl.uint(committedAmount), + // (auth-id uint) + Cl.uint(this.authId), + ], + this.operator.stxAddress, + ); + + // Assert + expect(stackAggregationCommit.result).toBeOk(Cl.bool(true)); + + const operatorWallet = model.wallets.get(this.operator.stxAddress)!; + + operatorWallet.amountToCommit -= committedAmount; + + // 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.operator.label}`, + "stack-agg-commit", + "amount committed", + committedAmount.toString(), + "signature", + ); + } + + 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}`; + } +} From 82aa13dcbda1445faf712e26e9f77f8e3b8e98e1 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Wed, 3 Apr 2024 15:18:04 +0300 Subject: [PATCH 095/129] fix(pox-4-tests): Address commands documentation comment https://github.com/stacks-network/stacks-core/pull/4628/files/852b0c5ca8b3dd7c6f91a55e464b9095fa8776d5#r1549587969 --- .../pox-4/pox_StackAggregationCommitAuthCommand.ts | 8 ++++---- .../pox-4/pox_StackAggregationCommitSigCommand.ts | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts index 24bb540e23..98c06c5bd1 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts @@ -10,10 +10,10 @@ import { expect } from "vitest"; import { Cl } from "@stacks/transactions"; /** - * The `StackAggregationCommitAuthCommand` allows an operator commits partially - * stacked STX and allocate a new PoX reward address slot. This allows a - * stacker to lock fewer STX than the minimal threshold in multiple transactions, - * so long as: + * The `StackAggregationCommitAuthCommand` allows an operator to commit + * partially stacked STX & to allocate a new PoX reward address slot. + * This allows a stacker to lock fewer STX than the minimal threshold + * in multiple transactions, so long as: * 1. The pox-addr is the same. * 2. This "commit" transaction is called _before_ the PoX anchor block. * diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts index bf8b2e61be..1fb93fa97e 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts @@ -11,14 +11,14 @@ import { Cl } from "@stacks/transactions"; import { bufferFromHex } from "@stacks/transactions/dist/cl"; /** - * The `StackAggregationCommitSigCommand` allows an operator commits partially - * stacked STX and allocate a new PoX reward address slot. This allows a - * stacker to lock fewer STX than the minimal threshold in multiple transactions, - * so long as: + * The `StackAggregationCommitSigCommand` allows an operator to commit + * partially stacked STX & to allocate a new PoX reward address slot. + * This allows a stacker to lock fewer STX than the minimal threshold + * in multiple transactions, so long as: * 1. The pox-addr is the same. * 2. This "commit" transaction is called _before_ the PoX anchor block. * - * This command calls `stack-aggregation-commit` using an `signature`. + * This command calls `stack-aggregation-commit` using a `signature`. * * Constraints for running this command include: * - The Operator must have locked STX on behalf of at least one stacker. From d572724911bde0da11d3f61d1ca724b3560673cd Mon Sep 17 00:00:00 2001 From: BowTiedRadone <92028479+BowTiedRadone@users.noreply.github.com> Date: Wed, 3 Apr 2024 15:19:38 +0300 Subject: [PATCH 096/129] fix(pox-4-tests): Address format comment https://github.com/stacks-network/stacks-core/pull/4628/files#r1549544398 Co-authored-by: Nikos Baxevanis --- .../tests/pox-4/pox_DelegateStackIncreaseCommand.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts index 23cfd63413..eb1ee6bfe4 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts @@ -109,7 +109,7 @@ export class DelegateStackIncreaseCommand implements PoxCommand { stackerWallet.amountLocked = newTotalLocked; stackerWallet.amountUnlocked = stackerWallet.amountUnlocked - this.increaseBy; - operatorWallet.amountToCommit += this.increaseBy + operatorWallet.amountToCommit += this.increaseBy; // 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. From 2b421da64f7384ca73520eab1c6ae9bb7e2bf7da Mon Sep 17 00:00:00 2001 From: BowTiedRadone <92028479+BowTiedRadone@users.noreply.github.com> Date: Wed, 3 Apr 2024 15:20:11 +0300 Subject: [PATCH 097/129] fix(pox-4-tests): Address format comment https://github.com/stacks-network/stacks-core/pull/4628/files#r1549544650 Co-authored-by: Nikos Baxevanis --- .../tests/pox-4/pox_DelegateStackStxCommand.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index 544c869f40..5b46c5443d 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -157,7 +157,7 @@ export class DelegateStackStxCommand implements PoxCommand { // the stacker's funds are locked when calling delegate-stack-extend, // delegate-stack-increase operatorWallet.lockedAddresses.push(stackerWallet.stxAddress); - operatorWallet.amountToCommit += Number(this.amountUstx) + operatorWallet.amountToCommit += Number(this.amountUstx); // 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. From 016f5fd672b7d66209030234c451a761db1983ec Mon Sep 17 00:00:00 2001 From: BowTiedRadone <92028479+BowTiedRadone@users.noreply.github.com> Date: Wed, 3 Apr 2024 15:20:33 +0300 Subject: [PATCH 098/129] fix(pox-4-tests): Address documentation comment https://github.com/stacks-network/stacks-core/pull/4628/files#r1549546009 Co-authored-by: Nikos Baxevanis --- .../tests/pox-4/pox_StackAggregationCommitAuthCommand.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts index 98c06c5bd1..8c8e85cf32 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts @@ -15,7 +15,7 @@ import { Cl } from "@stacks/transactions"; * This allows a stacker to lock fewer STX than the minimal threshold * in multiple transactions, so long as: * 1. The pox-addr is the same. - * 2. This "commit" transaction is called _before_ the PoX anchor block. + * 2. The "commit" transaction is called _before_ the PoX anchor block. * * This command calls stack-aggregation-commit using an `authorization`. * From 1bd351591b311a3d71a6d50f4fcefadd715a396d Mon Sep 17 00:00:00 2001 From: BowTiedRadone <92028479+BowTiedRadone@users.noreply.github.com> Date: Wed, 3 Apr 2024 15:26:52 +0300 Subject: [PATCH 099/129] fix(pox-4-tests): Addres not needed new line comment https://github.com/stacks-network/stacks-core/pull/4628/files#r1549557014 Co-authored-by: Nikos Baxevanis --- .../tests/pox-4/pox_StackAggregationCommitSigCommand.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts index 1fb93fa97e..55ec09ca0d 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts @@ -125,7 +125,6 @@ export class StackAggregationCommitSigCommand implements PoxCommand { expect(stackAggregationCommit.result).toBeOk(Cl.bool(true)); const operatorWallet = model.wallets.get(this.operator.stxAddress)!; - operatorWallet.amountToCommit -= committedAmount; // Log to console for debugging purposes. This is not necessary for the From d65444f60437d4d45c50b0e3f3a9bf8e00287819 Mon Sep 17 00:00:00 2001 From: BowTiedRadone <92028479+BowTiedRadone@users.noreply.github.com> Date: Wed, 3 Apr 2024 15:27:31 +0300 Subject: [PATCH 100/129] fix(pox-4-tests): Address not needed new line comment https://github.com/stacks-network/stacks-core/pull/4628/files#r1549556367 Co-authored-by: Nikos Baxevanis --- .../tests/pox-4/pox_StackAggregationCommitAuthCommand.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts index 8c8e85cf32..20887862ba 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts @@ -125,7 +125,6 @@ export class StackAggregationCommitAuthCommand implements PoxCommand { expect(stackAggregationCommit.result).toBeOk(Cl.bool(true)); const operatorWallet = model.wallets.get(this.operator.stxAddress)!; - operatorWallet.amountToCommit -= committedAmount; // Log to console for debugging purposes. This is not necessary for the From b24d1492d37c6fabcdbebeace43cffa1169309f5 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Wed, 3 Apr 2024 15:44:33 +0300 Subject: [PATCH 101/129] fix(pox-4-tests): Address committedAmount variable comment https://github.com/stacks-network/stacks-core/pull/4628/files#r1549622406 --- .../tests/pox-4/pox_StackAggregationCommitAuthCommand.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts index 20887862ba..76d6959499 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts @@ -92,7 +92,7 @@ export class StackAggregationCommitAuthCommand implements PoxCommand { // (allowed bool) Cl.bool(true), // (max-amount uint) - Cl.uint(this.operator.amountToCommit), + Cl.uint(committedAmount), // (auth-id uint) Cl.uint(this.authId), ], From 3be006ed3af71d87550d0dee2701ec9433217952 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Wed, 3 Apr 2024 19:21:05 +0300 Subject: [PATCH 102/129] fix(pox-4-tests): Address same pool pox address comment - removed check that verifies all the stackers have delegated to the same PoX address - addressed comments: - https://github.com/stacks-network/stacks-core/pull/4628#discussion_r1549535566 - https://github.com/stacks-network/stacks-core/pull/4628#discussion_r1549559748 - https://github.com/stacks-network/stacks-core/pull/4628#discussion_r1549631930 --- .../pox_StackAggregationCommitAuthCommand.ts | 22 ++++--------------- .../pox_StackAggregationCommitSigCommand.ts | 22 ++++--------------- 2 files changed, 8 insertions(+), 36 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts index 76d6959499..dc80fb4270 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts @@ -10,9 +10,9 @@ import { expect } from "vitest"; import { Cl } from "@stacks/transactions"; /** - * The `StackAggregationCommitAuthCommand` allows an operator to commit - * partially stacked STX & to allocate a new PoX reward address slot. - * This allows a stacker to lock fewer STX than the minimal threshold + * The `StackAggregationCommitAuthCommand` allows an operator to commit + * partially stacked STX & to allocate a new PoX reward address slot. + * This allows a stacker to lock fewer STX than the minimal threshold * in multiple transactions, so long as: * 1. The pox-addr is the same. * 2. The "commit" transaction is called _before_ the PoX anchor block. @@ -23,7 +23,6 @@ import { Cl } from "@stacks/transactions"; * - The Operator must have locked STX on behalf of at least one stacker. * - The total amount previously locked by the Operator on behalf of the * stackers has to be greater than the uSTX threshold. - * - All of the Stackers must have delegated to the same pox address. */ export class StackAggregationCommitAuthCommand implements PoxCommand { readonly operator: Wallet; @@ -52,22 +51,9 @@ export class StackAggregationCommitAuthCommand implements PoxCommand { // - The Operator must have locked STX on behalf of at least one stacker. // - The total amount previously locked by the Operator on behalf of the // stackers has to be greater than the uSTX threshold. - // - All of the Stackers must have delegated to the same pox address. - let sameDelegatedPoxAddrAllStackers = true; - const firstDelegatedPoxAddress = this.operator.lockedAddresses.length > 0 - ? model.wallets.get(this.operator.lockedAddresses[0])!.delegatedPoxAddress - : this.operator.btcAddress; - - this.operator.lockedAddresses.forEach((stacker) => { - if ( - model.wallets.get(stacker)!.delegatedPoxAddress !== - firstDelegatedPoxAddress - ) sameDelegatedPoxAddrAllStackers = false; - }); return this.operator.lockedAddresses.length > 0 && - this.operator.amountToCommit >= model.stackingMinimum && - sameDelegatedPoxAddrAllStackers; + this.operator.amountToCommit >= model.stackingMinimum; } run(model: Stub, real: Real): void { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts index 55ec09ca0d..677b7f052e 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts @@ -11,9 +11,9 @@ import { Cl } from "@stacks/transactions"; import { bufferFromHex } from "@stacks/transactions/dist/cl"; /** - * The `StackAggregationCommitSigCommand` allows an operator to commit - * partially stacked STX & to allocate a new PoX reward address slot. - * This allows a stacker to lock fewer STX than the minimal threshold + * The `StackAggregationCommitSigCommand` allows an operator to commit + * partially stacked STX & to allocate a new PoX reward address slot. + * This allows a stacker to lock fewer STX than the minimal threshold * in multiple transactions, so long as: * 1. The pox-addr is the same. * 2. This "commit" transaction is called _before_ the PoX anchor block. @@ -24,7 +24,6 @@ import { bufferFromHex } from "@stacks/transactions/dist/cl"; * - The Operator must have locked STX on behalf of at least one stacker. * - The total amount previously locked by the Operator on behalf of the * stackers has to be greater than the uSTX threshold. - * - All of the Stackers must have delegated to the same pox address. */ export class StackAggregationCommitSigCommand implements PoxCommand { readonly operator: Wallet; @@ -53,22 +52,9 @@ export class StackAggregationCommitSigCommand implements PoxCommand { // - The Operator must have locked STX on behalf of at least one stacker. // - The total amount previously locked by the Operator on behalf of the // stackers has to be greater than the uSTX threshold. - // - All of the Stackers must have delegated to the same pox address. - let sameDelegatedPoxAddrAllStackers = true; - const firstDelegatedPoxAddress = this.operator.lockedAddresses.length > 0 - ? model.wallets.get(this.operator.lockedAddresses[0])!.delegatedPoxAddress - : this.operator.btcAddress; - - this.operator.lockedAddresses.forEach((stacker) => { - if ( - model.wallets.get(stacker)!.delegatedPoxAddress !== - firstDelegatedPoxAddress - ) sameDelegatedPoxAddrAllStackers = false; - }); return this.operator.lockedAddresses.length > 0 && - this.operator.amountToCommit >= model.stackingMinimum && - sameDelegatedPoxAddrAllStackers; + this.operator.amountToCommit >= model.stackingMinimum; } run(model: Stub, real: Real): void { From f854333c44471fd537c0655564e6789d3755a1ad Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Thu, 4 Apr 2024 18:21:58 +0300 Subject: [PATCH 103/129] test(pox-4-tests): Add `StackAggregationCommitIndexedCommand` signature-based --- .../tests/pox-4/pox_CommandModel.ts | 2 + .../tests/pox-4/pox_Commands.ts | 19 +++ .../pox_StackAggregationCommitAuthCommand.ts | 1 + ...StackAggregationCommitIndexedSigCommand.ts | 138 ++++++++++++++++++ .../pox_StackAggregationCommitSigCommand.ts | 1 + .../tests/pox-4/pox_StackStxCommand.ts | 1 + 6 files changed, 162 insertions(+) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index ea8fcbdad0..aed279dba4 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -12,6 +12,7 @@ export class Stub { readonly wallets: Map; readonly statistics: Map; stackingMinimum: number; + nextRewardSetIndex: number constructor( wallets: Map, @@ -20,6 +21,7 @@ export class Stub { this.wallets = wallets; this.statistics = statistics; this.stackingMinimum = 0; + this.nextRewardSetIndex = 0; } trackCommandRun(commandName: string) { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 93b6dc3c89..2c6385f7f2 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -13,6 +13,7 @@ import { DelegateStackIncreaseCommand } from "./pox_DelegateStackIncreaseCommand import { DelegateStackExtendCommand } from "./pox_DelegateStackExtendCommand"; import { StackAggregationCommitAuthCommand } from "./pox_StackAggregationCommitAuthCommand"; import { StackAggregationCommitSigCommand } from "./pox_StackAggregationCommitSigCommand"; +import { StackAggregationCommitIndexedSigCommand } from "./pox_StackAggregationCommitIndexedSigCommand"; export function PoxCommands( wallets: Map, @@ -112,6 +113,24 @@ export function PoxCommands( r.currentCycle, ) ), + // StackAggregationCommitIndexedSigCommand + fc.record({ + wallet: fc.constantFrom(...wallets.values()), + authId: fc.nat(), + currentCycle: fc.constant(currentCycle(network)), + }).map(( + r: { + wallet: Wallet; + authId: number; + currentCycle: number; + }, + ) => + new StackAggregationCommitIndexedSigCommand( + r.wallet, + r.authId, + r.currentCycle, + ) + ), // RevokeDelegateStxCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts index dc80fb4270..289b6c03ca 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts @@ -112,6 +112,7 @@ export class StackAggregationCommitAuthCommand implements PoxCommand { const operatorWallet = model.wallets.get(this.operator.stxAddress)!; operatorWallet.amountToCommit -= committedAmount; + model.nextRewardSetIndex++; // 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. diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts new file mode 100644 index 0000000000..673625f301 --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts @@ -0,0 +1,138 @@ +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; +import { Pox4SignatureTopic, poxAddressToTuple } from "@stacks/stacking"; +import { expect } from "vitest"; +import { Cl } from "@stacks/transactions"; +import { bufferFromHex } from "@stacks/transactions/dist/cl"; + +/** + * The `StackAggregationCommitIndexedSigCommand` allows an operator to + * commit partially stacked STX & to allocate a new PoX reward address + * slot. + * This allows a stacker to lock fewer STX than the minimal threshold + * in multiple transactions, so long as: + * 1. The pox-addr is the same. + * 2. The "commit" transaction is called _before_ the PoX anchor block. + * + * This command calls `stack-aggregation-commit-indexed` using a + * `signature`. + * + * Constraints for running this command include: + * - The Operator must have locked STX on behalf of at least one stacker. + * - The total amount previously locked by the Operator on behalf of the + * stackers has to be greater than the uSTX threshold. + */ +export class StackAggregationCommitIndexedSigCommand implements PoxCommand { + readonly operator: Wallet; + readonly authId: number; + readonly currentCycle: number; + + /** + * Constructs a `StackAggregationCommitIndexedSigCommand` to lock uSTX + * for stacking. + * + * @param operator - Represents the `Operator`'s wallet. + * @param authId - Unique `auth-id` for the authorization. + * @param currentCycle - The current reward cycle. + */ + constructor(operator: Wallet, authId: number, currentCycle: number) { + this.operator = operator; + this.authId = authId; + this.currentCycle = currentCycle; + } + + check(model: Readonly): boolean { + // Constraints for running this command include: + // - The Operator must have locked STX on behalf of at least one stacker. + // - The total amount previously locked by the Operator on behalf of the + // stackers has to be greater than the uSTX threshold. + + return ( + this.operator.lockedAddresses.length > 0 && + this.operator.amountToCommit >= model.stackingMinimum + ); + } + + run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); + + const committedAmount = this.operator.amountToCommit; + + const signerSig = this.operator.stackingClient.signPoxSignature({ + // The signer key being authorized. + signerPrivateKey: this.operator.signerPrvKey, + // The reward cycle for which the authorization is valid. + // For stack-stx and stack-extend, this refers to the reward cycle + // where the transaction is confirmed. For stack-aggregation-commit, + // this refers to the reward cycle argument in that function. + rewardCycle: this.currentCycle + 1, + // For stack-stx, this refers to lock-period. For stack-extend, + // this refers to extend-count. For stack-aggregation-commit, this is + // u1. + period: 1, + // A string representing the function where this authorization is valid. + // Either stack-stx, stack-extend, stack-increase or agg-commit. + topic: Pox4SignatureTopic.AggregateCommit, + // The PoX address that can be used with this signer key. + poxAddress: this.operator.btcAddress, + // The unique auth-id for this authorization. + authId: this.authId, + // The maximum amount of uSTX that can be used (per tx) with this signer + // key. + maxAmount: committedAmount, + }); + + // Act + const stackAggregationCommitIndexed = real.network.callPublicFn( + "ST000000000000000000002AMW42H.pox-4", + "stack-aggregation-commit-indexed", + [ + // (pox-addr (tuple (version (buff 1)) (hashbytes (buff 32)))) + poxAddressToTuple(this.operator.btcAddress), + // (reward-cycle uint) + Cl.uint(this.currentCycle + 1), + // (signer-sig (optional (buff 65))) + Cl.some(bufferFromHex(signerSig)), + // (signer-key (buff 33)) + Cl.bufferFromHex(this.operator.signerPubKey), + // (max-amount uint) + Cl.uint(committedAmount), + // (auth-id uint) + Cl.uint(this.authId), + ], + this.operator.stxAddress, + ); + + // Assert + expect(stackAggregationCommitIndexed.result).toBeOk( + Cl.uint(model.nextRewardSetIndex), + ); + + // Update the model + const operatorWallet = model.wallets.get(this.operator.stxAddress)!; + operatorWallet.amountToCommit -= committedAmount; + model.nextRewardSetIndex++; + + // 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.operator.label}`, + "stack-agg-commit-indexed", + "amount committed", + committedAmount.toString(), + "signature", + ); + } + + 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}`; + } +} diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts index 677b7f052e..ed7b99447d 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts @@ -112,6 +112,7 @@ export class StackAggregationCommitSigCommand implements PoxCommand { const operatorWallet = model.wallets.get(this.operator.stxAddress)!; operatorWallet.amountToCommit -= committedAmount; + model.nextRewardSetIndex++; // 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. diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index cbdb782dc9..205704f978 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -162,6 +162,7 @@ export class StackStxCommand implements PoxCommand { wallet.amountLocked = amountUstx; wallet.unlockHeight = Number(unlockBurnHeight.value); wallet.amountUnlocked -= amountUstx; + model.nextRewardSetIndex++; // 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. From 574151839eb593138a92704da2dc3dcb0e85e707 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Thu, 4 Apr 2024 18:36:04 +0300 Subject: [PATCH 104/129] test(pox-4-tests): Add `StackAggregationCommitIndexedCommand` authorization-based --- .../tests/pox-4/pox_Commands.ts | 19 +++ ...tackAggregationCommitIndexedAuthCommand.ts | 138 ++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 2c6385f7f2..238538f08c 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -14,6 +14,7 @@ import { DelegateStackExtendCommand } from "./pox_DelegateStackExtendCommand"; import { StackAggregationCommitAuthCommand } from "./pox_StackAggregationCommitAuthCommand"; import { StackAggregationCommitSigCommand } from "./pox_StackAggregationCommitSigCommand"; import { StackAggregationCommitIndexedSigCommand } from "./pox_StackAggregationCommitIndexedSigCommand"; +import { StackAggregationCommitIndexedAuthCommand } from "./pox_StackAggregationCommitIndexedAuthCommand"; export function PoxCommands( wallets: Map, @@ -113,6 +114,24 @@ export function PoxCommands( r.currentCycle, ) ), + // StackAggregationCommitIndexedAuthCommand + fc.record({ + wallet: fc.constantFrom(...wallets.values()), + authId: fc.nat(), + currentCycle: fc.constant(currentCycle(network)), + }).map(( + r: { + wallet: Wallet; + authId: number; + currentCycle: number; + }, + ) => + new StackAggregationCommitIndexedAuthCommand( + r.wallet, + r.authId, + r.currentCycle, + ) + ), // StackAggregationCommitIndexedSigCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts new file mode 100644 index 0000000000..f33b509fcd --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts @@ -0,0 +1,138 @@ +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; +import { poxAddressToTuple } from "@stacks/stacking"; +import { expect } from "vitest"; +import { Cl } from "@stacks/transactions"; + +/** + * The `StackAggregationCommitIndexedAuthCommand` allows an operator to + * commit partially stacked STX & to allocate a new PoX reward address + * slot. + * This allows a stacker to lock fewer STX than the minimal threshold + * in multiple transactions, so long as: + * 1. The pox-addr is the same. + * 2. The "commit" transaction is called _before_ the PoX anchor block. + * + * This command calls `stack-aggregation-commit-indexed` using an + * `authorization`. + * + * Constraints for running this command include: + * - The Operator must have locked STX on behalf of at least one stacker. + * - The total amount previously locked by the Operator on behalf of the + * stackers has to be greater than the uSTX threshold. + */ +export class StackAggregationCommitIndexedAuthCommand implements PoxCommand { + readonly operator: Wallet; + readonly authId: number; + readonly currentCycle: number; + + /** + * Constructs a `StackAggregationCommitIndexedAuthCommand` to lock uSTX + * for stacking. + * + * @param operator - Represents the `Operator`'s wallet. + * @param authId - Unique `auth-id` for the authorization. + * @param currentCycle - The current reward cycle. + */ + constructor(operator: Wallet, authId: number, currentCycle: number) { + this.operator = operator; + this.authId = authId; + this.currentCycle = currentCycle; + } + + check(model: Readonly): boolean { + // Constraints for running this command include: + // - The Operator must have locked STX on behalf of at least one stacker. + // - The total amount previously locked by the Operator on behalf of the + // stackers has to be greater than the uSTX threshold. + + return ( + this.operator.lockedAddresses.length > 0 && + this.operator.amountToCommit >= model.stackingMinimum + ); + } + + run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); + + const committedAmount = this.operator.amountToCommit; + + const { result: setSignature } = real.network.callPublicFn( + "ST000000000000000000002AMW42H.pox-4", + "set-signer-key-authorization", + [ + // (pox-addr (tuple (version (buff 1)) (hashbytes (buff 32)))) + poxAddressToTuple(this.operator.btcAddress), + // (period uint) + Cl.uint(1), + // (reward-cycle uint) + Cl.uint(this.currentCycle + 1), + // (topic (string-ascii 14)) + Cl.stringAscii("agg-commit"), + // (signer-key (buff 33)) + Cl.bufferFromHex(this.operator.signerPubKey), + // (allowed bool) + Cl.bool(true), + // (max-amount uint) + Cl.uint(committedAmount), + // (auth-id uint) + Cl.uint(this.authId), + ], + this.operator.stxAddress, + ); + expect(setSignature).toBeOk(Cl.bool(true)); + + // Act + const stackAggregationCommitIndexed = real.network.callPublicFn( + "ST000000000000000000002AMW42H.pox-4", + "stack-aggregation-commit-indexed", + [ + // (pox-addr (tuple (version (buff 1)) (hashbytes (buff 32)))) + poxAddressToTuple(this.operator.btcAddress), + // (reward-cycle uint) + Cl.uint(this.currentCycle + 1), + // (signer-sig (optional (buff 65))) + Cl.none(), + // (signer-key (buff 33)) + Cl.bufferFromHex(this.operator.signerPubKey), + // (max-amount uint) + Cl.uint(committedAmount), + // (auth-id uint) + Cl.uint(this.authId), + ], + this.operator.stxAddress, + ); + + // Assert + expect(stackAggregationCommitIndexed.result).toBeOk( + Cl.uint(model.nextRewardSetIndex), + ); + + // Update the model + const operatorWallet = model.wallets.get(this.operator.stxAddress)!; + operatorWallet.amountToCommit -= committedAmount; + model.nextRewardSetIndex++; + + // 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.operator.label}`, + "stack-agg-commit-indexed", + "amount committed", + committedAmount.toString(), + "authorization", + ); + } + + 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}`; + } +} From f17b071d133fbfc0f4f0f89ae89e800a4a51a784 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Thu, 4 Apr 2024 18:39:18 +0300 Subject: [PATCH 105/129] chore(pox-4-tests): Update stdout logging to console.log --- contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index aed279dba4..1630f3e617 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -30,9 +30,9 @@ export class Stub { } reportCommandRuns() { - process.stdout.write("Command run method execution counts:"); + console.log("Command run method execution counts:"); this.statistics.forEach((count, commandName) => { - process.stdout.write(`\n${commandName}: ${count}`); + console.log(`${commandName}: ${count}`); }); } } From 185b91d9315ed1f9bbdd290e71ecf083b5d80e0f Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Sun, 7 Apr 2024 16:25:22 +0300 Subject: [PATCH 106/129] test(pox-4-tests): Add `StackAggregationIncreaseCommand` Adding the `StackAggregationIncreaseCommand` is currently causing the tests to fail. To investigate: - this may be a PoX-4 bug - this may be a command implementation issue --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 1 + .../tests/pox-4/pox_CommandModel.ts | 1 + .../tests/pox-4/pox_Commands.ts | 28 +++++ .../pox_StackAggregationCommitAuthCommand.ts | 1 + ...tackAggregationCommitIndexedAuthCommand.ts | 1 + ...StackAggregationCommitIndexedSigCommand.ts | 1 + .../pox_StackAggregationCommitSigCommand.ts | 1 + .../pox_StackAggregationIncreaseCommand.ts | 109 ++++++++++++++++++ 8 files changed, 143 insertions(+) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index 6153640165..6935d35cf6 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -100,6 +100,7 @@ it("statefully interacts with PoX-4", async () => { firstLockedRewardCycle: 0, allowedContractCaller: "", callerAllowedBy: [], + committedRewCycleIndexes: [], }; }); diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 1630f3e617..91f68e68b0 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -64,6 +64,7 @@ export type Wallet = { firstLockedRewardCycle: number; allowedContractCaller: StxAddress; callerAllowedBy: StxAddress[]; + committedRewCycleIndexes: number[]; }; export type PoxCommand = fc.Command; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 238538f08c..81f3967b24 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -15,6 +15,7 @@ import { StackAggregationCommitAuthCommand } from "./pox_StackAggregationCommitA import { StackAggregationCommitSigCommand } from "./pox_StackAggregationCommitSigCommand"; import { StackAggregationCommitIndexedSigCommand } from "./pox_StackAggregationCommitIndexedSigCommand"; import { StackAggregationCommitIndexedAuthCommand } from "./pox_StackAggregationCommitIndexedAuthCommand"; +import { StackAggregationIncreaseCommand } from "./pox_StackAggregationIncreaseCommand"; export function PoxCommands( wallets: Map, @@ -150,6 +151,33 @@ export function PoxCommands( r.currentCycle, ) ), + // StackAggregationIncreaseCommand + fc.record({ + wallet: fc.constantFrom(...wallets.values()), + currentCycle: fc.constant(currentCycle(network)), + }).chain((r) => { + const committedRewCycleIndexesOrFallback = + r.wallet.committedRewCycleIndexes.length > 0 + ? r.wallet.committedRewCycleIndexes + : [-1]; + return fc.record({ + rewardCycleIndex: fc.constantFrom( + ...committedRewCycleIndexesOrFallback, + ), + }).map((cycleIndex) => ({ ...r, ...cycleIndex })); + }).map(( + r: { + wallet: Wallet; + currentCycle: number; + rewardCycleIndex: number; + }, + ) => + new StackAggregationIncreaseCommand( + r.wallet, + r.currentCycle, + r.rewardCycleIndex, + ) + ), // RevokeDelegateStxCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts index 289b6c03ca..22544274cb 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts @@ -112,6 +112,7 @@ export class StackAggregationCommitAuthCommand implements PoxCommand { const operatorWallet = model.wallets.get(this.operator.stxAddress)!; operatorWallet.amountToCommit -= committedAmount; + operatorWallet.committedRewCycleIndexes.push(model.nextRewardSetIndex); model.nextRewardSetIndex++; // Log to console for debugging purposes. This is not necessary for the diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts index f33b509fcd..54e4639d7e 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts @@ -116,6 +116,7 @@ export class StackAggregationCommitIndexedAuthCommand implements PoxCommand { // Update the model const operatorWallet = model.wallets.get(this.operator.stxAddress)!; operatorWallet.amountToCommit -= committedAmount; + operatorWallet.committedRewCycleIndexes.push(model.nextRewardSetIndex); model.nextRewardSetIndex++; // Log to console for debugging purposes. This is not necessary for the diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts index 673625f301..3ee837852f 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts @@ -116,6 +116,7 @@ export class StackAggregationCommitIndexedSigCommand implements PoxCommand { // Update the model const operatorWallet = model.wallets.get(this.operator.stxAddress)!; operatorWallet.amountToCommit -= committedAmount; + operatorWallet.committedRewCycleIndexes.push(model.nextRewardSetIndex); model.nextRewardSetIndex++; // Log to console for debugging purposes. This is not necessary for the diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts index ed7b99447d..e1bf233644 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts @@ -112,6 +112,7 @@ export class StackAggregationCommitSigCommand implements PoxCommand { const operatorWallet = model.wallets.get(this.operator.stxAddress)!; operatorWallet.amountToCommit -= committedAmount; + operatorWallet.committedRewCycleIndexes.push(model.nextRewardSetIndex); model.nextRewardSetIndex++; // Log to console for debugging purposes. This is not necessary for the diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts new file mode 100644 index 0000000000..e15ac26c5d --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts @@ -0,0 +1,109 @@ +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; +import { poxAddressToTuple } from "@stacks/stacking"; +import { expect } from "vitest"; +import { Cl } from "@stacks/transactions"; + +/** + * The `StackAggregationIncreaseCommand` allows an operator to commit + * partially stacked STX to a PoX address which has already received + * some STX (more than the `stacking minimum`). + * This allows a delegator to lock up marginally more STX from new + * delegates, even if they collectively do not exceed the Stacking + * minimum, so long as the target PoX address already represents at + * least as many STX as the `stacking minimum`. + * This command calls stack-aggregation-increase. + * + * Constraints for running this command include: + * - The Operator must have locked STX on behalf of at least one stacker. + * - The PoX address must have partial committed STX. + * - The Reward Cycle Index must be positive. + */ +export class StackAggregationIncreaseCommand implements PoxCommand { + readonly operator: Wallet; + readonly currentCycle: number; + readonly rewardCycleIndex: number; + + /** + * Constructs a `StackAggregationIncreaseCommand` to commit partially + * stacked STX to a PoX address which has already received some STX. + * + * @param operator - Represents the `Operator`'s wallet. + * @param currentCycle - The current reward cycle. + * @param rewardCycleIndex - The cycle index to increase the commit for. + */ + constructor( + operator: Wallet, + currentCycle: number, + rewardCycleIndex: number, + ) { + this.operator = operator; + this.currentCycle = currentCycle; + this.rewardCycleIndex = rewardCycleIndex; + } + + check(_model: Readonly): boolean { + // Constraints for running this command include: + // - The Operator must have locked STX on behalf of at least one stacker. + // - The PoX address must have partial committed STX. + // - The Reward Cycle Index must be positive. + + return ( + this.operator.lockedAddresses.length > 0 && + this.rewardCycleIndex >= 0 && + this.operator.amountToCommit > 0 + ); + } + + run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); + + const committedAmount = this.operator.amountToCommit; + + // Act + const stackAggregationIncrease = real.network.callPublicFn( + "ST000000000000000000002AMW42H.pox-4", + "stack-aggregation-increase", + [ + // (pox-addr { version: (buff 1), hashbytes: (buff 32) }) + poxAddressToTuple(this.operator.btcAddress), + // (reward-cycle uint) + Cl.uint(this.currentCycle + 1), + // (reward-cycle-index uint)) + Cl.uint(this.rewardCycleIndex), + ], + this.operator.stxAddress, + ); + + // Assert + expect(stackAggregationIncrease.result).toBeOk(Cl.bool(true)); + + const operatorWallet = model.wallets.get(this.operator.stxAddress)!; + operatorWallet.amountToCommit -= committedAmount; + + // 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.operator.label}`, + "stack-agg-increase", + "amount committed", + committedAmount.toString(), + "cycle index", + this.rewardCycleIndex.toString(), + ); + } + + 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-increase for reward cycle ${ + this.currentCycle + 1 + } index ${this.rewardCycleIndex}`; + } +} \ No newline at end of file From e320a4db9d515a1f4205940bed8972a6cc9c7a6c Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Mon, 8 Apr 2024 23:52:15 +0300 Subject: [PATCH 107/129] test(pox-4-tests): Add `DisallowContractCallerCommand` --- .../tests/pox-4/pox_Commands.ts | 15 +++ .../pox_DisallowContractCallerCommand.ts | 98 +++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 81f3967b24..0faa84c32c 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -16,6 +16,7 @@ import { StackAggregationCommitSigCommand } from "./pox_StackAggregationCommitSi import { StackAggregationCommitIndexedSigCommand } from "./pox_StackAggregationCommitIndexedSigCommand"; import { StackAggregationCommitIndexedAuthCommand } from "./pox_StackAggregationCommitIndexedAuthCommand"; import { StackAggregationIncreaseCommand } from "./pox_StackAggregationIncreaseCommand"; +import { DisallowContractCallerCommand } from "./pox_DisallowContractCallerCommand"; export function PoxCommands( wallets: Map, @@ -326,6 +327,20 @@ export function PoxCommands( r.alllowUntilBurnHt, ), ), + // DisallowContractCallerCommand + fc.record({ + stacker: fc.constantFrom(...wallets.values()), + callerToDisallow: fc.constantFrom(...wallets.values()), + }).map( + (r: { + stacker: Wallet; + callerToDisallow: Wallet; + }) => + new DisallowContractCallerCommand( + r.stacker, + r.callerToDisallow, + ), + ), // GetStxAccountCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts new file mode 100644 index 0000000000..9216f1eb2e --- /dev/null +++ b/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts @@ -0,0 +1,98 @@ +import { + logCommand, + PoxCommand, + Real, + Stub, + Wallet, +} from "./pox_CommandModel.ts"; +import { expect } from "vitest"; +import { boolCV, Cl } from "@stacks/transactions"; + +/** + * The `DisallowContractCallerComand` revokes a `contract-caller`'s + * authorization to call stacking methods. + * + * Constraints for running this command include: + * - The Caller to be disallowed must have been previously + * allowed by the Operator. + */ +export class DisallowContractCallerCommand implements PoxCommand { + readonly stacker: Wallet; + readonly callerToDisallow: Wallet; + + /** + * Constructs a `DisallowContractCallerComand` to revoke authorization + * for calling stacking methods. + * + * @param stacker - Represents the `Stacker`'s wallet. + * @param callerToDisallow - The `contract-caller` to be revoked. + */ + + constructor(stacker: Wallet, callerToDisallow: Wallet) { + this.stacker = stacker; + this.callerToDisallow = callerToDisallow; + } + + check(_model: Readonly): boolean { + // Constraints for running this command include: + // - The Caller to be disallowed must have been previously + // allowed by the Operator. + + return ( + this.stacker.allowedContractCaller === this.callerToDisallow.stxAddress && + this.callerToDisallow.callerAllowedBy.includes(this.stacker.stxAddress) === + true + ); + } + + run(model: Stub, real: Real): void { + model.trackCommandRun(this.constructor.name); + + // Act + const disallowContractCaller = real.network.callPublicFn( + "ST000000000000000000002AMW42H.pox-4", + "disallow-contract-caller", + [ + // (caller principal) + Cl.principal(this.callerToDisallow.stxAddress), + ], + this.stacker.stxAddress, + ); + + // Assert + expect(disallowContractCaller.result).toBeOk(boolCV(true)); + + // Get the wallet to be revoked stacking rights from the model and + // update it with the new state. + const callerToDisallow = model.wallets.get( + this.callerToDisallow.stxAddress, + )!; + + // Update model so that we know that the stacker has revoked stacking + // allowance. + this.stacker.allowedContractCaller = ""; + + // Remove the operator from the caller to disallow's allowance list. + const walletIndexAllowedByList = callerToDisallow.callerAllowedBy.indexOf( + this.stacker.stxAddress, + ); + + expect(walletIndexAllowedByList).toBeGreaterThan(-1); + callerToDisallow.callerAllowedBy.splice(walletIndexAllowedByList, 1); + + // 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.stacker.label}`, + "disallow-contract-caller", + this.callerToDisallow.label, + ); + } + + 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.stacker.label} disallow-contract-caller ${this.callerToDisallow.label}`; + } +} From 58f02a324400b8233d57db32be5eb2ca93799a77 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Wed, 10 Apr 2024 18:24:47 +0300 Subject: [PATCH 108/129] fix(pox-4-tests): Refresh the model's state if the network gets to the next reward cycle --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 37 ++++++------ .../pox-4/pox_AllowContractCallerCommand.ts | 3 + .../tests/pox-4/pox_CommandModel.ts | 57 ++++++++++++++++++- .../tests/pox-4/pox_Commands.ts | 2 +- .../pox-4/pox_DelegateStackExtendCommand.ts | 3 + .../pox-4/pox_DelegateStackIncreaseCommand.ts | 3 + .../pox-4/pox_DelegateStackStxCommand.ts | 3 + .../tests/pox-4/pox_DelegateStxCommand.ts | 3 + .../pox_DisallowContractCallerCommand.ts | 3 + .../pox-4/pox_GetStackingMinimumCommand.ts | 3 + .../tests/pox-4/pox_GetStxAccountCommand.ts | 3 + .../pox-4/pox_RevokeDelegateStxCommand.ts | 3 + .../pox_StackAggregationCommitAuthCommand.ts | 7 ++- ...tackAggregationCommitIndexedAuthCommand.ts | 7 ++- ...StackAggregationCommitIndexedSigCommand.ts | 7 ++- .../pox_StackAggregationCommitSigCommand.ts | 7 ++- .../pox_StackAggregationIncreaseCommand.ts | 3 + .../tests/pox-4/pox_StackStxCommand.ts | 3 + 18 files changed, 133 insertions(+), 24 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index 6935d35cf6..eb34174c1d 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -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(); }); diff --git a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts index 13283af8a9..9682d286b4 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts @@ -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() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 91f68e68b0..e20bb4980b 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -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; readonly statistics: Map; stackingMinimum: number; - nextRewardSetIndex: number + nextRewardSetIndex: number; + lastRefreshedCycle: number; constructor( wallets: Map, @@ -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 = { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 0faa84c32c..bb1fc38cd5 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -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; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts index f66b42ddb4..0ec241a272 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts @@ -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() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts index eb1ee6bfe4..75f504b75e 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts @@ -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() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index 5b46c5443d..baaaad23ca 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -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() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts index 6de496d375..f94259d0b8 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts @@ -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() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts index 9216f1eb2e..1a90bd59f2 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts @@ -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() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts index c5a84e6a3d..173a722425 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts @@ -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() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts index 71cf99207c..aee09dd5b7 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts @@ -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() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts index 5ada55932d..68528fb492 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts @@ -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() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts index 22544274cb..698e36c74c 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts @@ -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 + }`; } } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts index 54e4639d7e..d84da451e2 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts @@ -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 + }`; } } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts index 3ee837852f..0fb6f36759 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts @@ -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 + }`; } } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts index e1bf233644..8e0f2d8f82 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts @@ -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 + }`; } } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts index e15ac26c5d..e56c733f53 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts @@ -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() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index 205704f978..4bd04b4ee5 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -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() { From 0b9d36e08304ae83525b8871a944907ed4ab252f Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Thu, 11 Apr 2024 18:10:38 +0200 Subject: [PATCH 109/129] refactor(pox-4-tests): Rename stateRefresh to refreshStateForNextRewardCycle Rename `stateRefresh` to `refreshStateForNextRewardCycle` to more explicitly indicate its function of updating the model's state upon transitioning to the next reward cycle. --- .../tests/pox-4/pox_AllowContractCallerCommand.ts | 2 +- contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts | 2 +- .../tests/pox-4/pox_DelegateStackExtendCommand.ts | 2 +- .../tests/pox-4/pox_DelegateStackIncreaseCommand.ts | 2 +- .../tests/pox-4/pox_DelegateStackStxCommand.ts | 2 +- .../core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts | 2 +- .../tests/pox-4/pox_DisallowContractCallerCommand.ts | 2 +- .../tests/pox-4/pox_GetStackingMinimumCommand.ts | 2 +- .../core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts | 2 +- .../tests/pox-4/pox_RevokeDelegateStxCommand.ts | 2 +- .../tests/pox-4/pox_StackAggregationCommitAuthCommand.ts | 2 +- .../tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts | 2 +- .../tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts | 2 +- .../tests/pox-4/pox_StackAggregationCommitSigCommand.ts | 2 +- .../tests/pox-4/pox_StackAggregationIncreaseCommand.ts | 2 +- contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts index 9682d286b4..abb9936568 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts @@ -87,7 +87,7 @@ export class AllowContractCallerCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index e20bb4980b..80e8e28341 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -42,7 +42,7 @@ export class Stub { }); } - stateRefresh(real: Real) { + refreshStateForNextRewardCycle(real: Real) { const burnBlockHeightResult = real.network.runSnippet("burn-block-height"); const burnBlockHeight = cvToValue(burnBlockHeightResult as ClarityValue); const lastRefreshedCycle = this.lastRefreshedCycle; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts index 0ec241a272..5e4a536064 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts @@ -151,7 +151,7 @@ export class DelegateStackExtendCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts index 75f504b75e..92ec5d9e9a 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts @@ -125,7 +125,7 @@ export class DelegateStackIncreaseCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index baaaad23ca..7b09a8e6da 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -171,7 +171,7 @@ export class DelegateStackStxCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts index f94259d0b8..f6cfbfeb66 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts @@ -108,7 +108,7 @@ export class DelegateStxCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts index 1a90bd59f2..b1c99109be 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts @@ -89,7 +89,7 @@ export class DisallowContractCallerCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts index 173a722425..b05923ef1f 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts @@ -57,7 +57,7 @@ export class GetStackingMinimumCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts index aee09dd5b7..8610bc1050 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts @@ -56,7 +56,7 @@ export class GetStxAccountCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts index 68528fb492..605d461da9 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts @@ -87,7 +87,7 @@ export class RevokeDelegateStxCommand implements PoxCommand { logCommand(`✓ ${this.wallet.label}`, "revoke-delegate-stx"); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts index 698e36c74c..afe3be8dff 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts @@ -126,7 +126,7 @@ export class StackAggregationCommitAuthCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts index d84da451e2..6b7ba47b68 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts @@ -130,7 +130,7 @@ export class StackAggregationCommitIndexedAuthCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts index 0fb6f36759..56456ac3ef 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts @@ -130,7 +130,7 @@ export class StackAggregationCommitIndexedSigCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts index 8e0f2d8f82..390ae23603 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts @@ -126,7 +126,7 @@ export class StackAggregationCommitSigCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts index e56c733f53..7b3c21d863 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts @@ -98,7 +98,7 @@ export class StackAggregationIncreaseCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index 4bd04b4ee5..3fd5a5e596 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -174,7 +174,7 @@ export class StackStxCommand implements PoxCommand { ); // Refresh the model's state if the network gets to the next reward cycle. - model.stateRefresh(real); + model.refreshStateForNextRewardCycle(real); } toString() { From 20ca4e28d0fde39a760912bedc4be1d09425c8c1 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Thu, 11 Apr 2024 18:40:22 +0200 Subject: [PATCH 110/129] chore(pox-4-tests): Format code and wrap comments at 79 chars - Ran `deno fmt` to ensure code formatting adheres to standard practices. - Manually wrapped comments to 79 characters width for improved readability across various code editors and diff tools. - Fixed minor typos and standardized comment punctuation. - Added missing periods at the end of parameter descriptions. --- .../pox-4/pox_AllowContractCallerCommand.ts | 20 +++++---- .../pox-4/pox_DelegateStackExtendCommand.ts | 12 ++---- .../pox-4/pox_DelegateStackIncreaseCommand.ts | 6 +-- .../pox-4/pox_DelegateStackStxCommand.ts | 41 ++++++++++--------- .../tests/pox-4/pox_DelegateStxCommand.ts | 17 ++++---- .../pox_DisallowContractCallerCommand.ts | 13 +++--- .../pox-4/pox_GetStackingMinimumCommand.ts | 4 +- .../tests/pox-4/pox_GetStxAccountCommand.ts | 9 ++-- .../pox-4/pox_RevokeDelegateStxCommand.ts | 15 ++++--- ...tackAggregationCommitIndexedAuthCommand.ts | 2 +- ...StackAggregationCommitIndexedSigCommand.ts | 2 +- .../pox_StackAggregationIncreaseCommand.ts | 2 +- .../tests/pox-4/pox_StackStxCommand.ts | 2 + 13 files changed, 79 insertions(+), 66 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts index abb9936568..551441166e 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts @@ -15,10 +15,11 @@ import { } from "@stacks/transactions"; /** - * The `AllowContractCallerComand` gives a `contract-caller` authorization to call stacking methods. - * Normally, stacking methods may only be invoked by direct transactions (i.e., the tx-sender - * issues a direct contract-call to the stacking methods). - * By issuing an allowance, the tx-sender may call stacking methods through the allowed contract. + * The `AllowContractCallerCommand` authorizes a `contract-caller` to call + * stacking methods. Normally, stacking methods can only be invoked by direct + * transactions (i.e., the tx-sender issues a direct contract-call to the + * stacking methods). By issuing an allowance, the tx-sender may call stacking + * methods through the allowed contract. * * There are no constraints for running this command. */ @@ -28,12 +29,14 @@ export class AllowContractCallerCommand implements PoxCommand { readonly allowUntilBurnHt: OptionalCV; /** - * Constructs an `AllowContractCallerComand` that authorizes a `contract-caller` to call - * stacking methods. + * Constructs an `AllowContractCallerCommand` that authorizes a + * `contract-caller` to call stacking methods. * * @param wallet - Represents the Stacker's wallet. - * @param allowanceTo - Represents the authorized `contract-caller` (i.e. a stacking pool) - * @param alllowUntilBurnHt - The burn block height until the authorization is valid. + * @param allowanceTo - Represents the authorized `contract-caller` (i.e., a + * stacking pool). + * @param allowUntilBurnHt - The burn block height until which the + * authorization is valid. */ constructor( wallet: Wallet, @@ -52,6 +55,7 @@ export class AllowContractCallerCommand implements PoxCommand { run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); + // Act const allowContractCaller = real.network.callPublicFn( "ST000000000000000000002AMW42H.pox-4", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts index 5e4a536064..a555d89a37 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts @@ -7,11 +7,7 @@ import { } from "./pox_CommandModel.ts"; import { poxAddressToTuple } from "@stacks/stacking"; import { assert, expect } from "vitest"; -import { - Cl, - ClarityType, - isClarityType, -} from "@stacks/transactions"; +import { Cl, ClarityType, isClarityType } from "@stacks/transactions"; import { FIRST_BURNCHAIN_BLOCK_HEIGHT, REWARD_CYCLE_LENGTH, @@ -19,10 +15,10 @@ import { /** * The `DelegateStackExtendCommand` allows a pool operator to - * extend an active stacking lock, issuing a "partial commitment" + * extend an active stacking lock, issuing a "partial commitment" * for the extended-to cycles. - * - * This method extends stacker's current lockup for an additional + * + * This method extends stacker's current lockup for an additional * extend-count and partially commits those new cycles to `pox-addr`. * * Constraints for running this command include: diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts index 92ec5d9e9a..2f5a2590c2 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts @@ -13,7 +13,7 @@ import { Cl } from "@stacks/transactions"; * The DelegateStackIncreaseCommand allows a pool operator to * increase an active stacking lock, issuing a "partial commitment" * for the increased cycles. - * + * * This method increases stacker's current lockup and partially * commits the additional STX to `pox-addr`. * @@ -38,7 +38,7 @@ export class DelegateStackIncreaseCommand implements PoxCommand { * * @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 increaseBy - Represents the locked amount to be increased by. */ constructor(operator: Wallet, stacker: Wallet, increaseBy: number) { this.operator = operator; @@ -103,7 +103,7 @@ export class DelegateStackIncreaseCommand implements PoxCommand { // Get the Stacker's wallet from the model and update it with the new state. const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; - const operatorWallet = model.wallets.get(this.operator.stxAddress)! + const operatorWallet = model.wallets.get(this.operator.stxAddress)!; // Update model so that we know this stacker has increased the stacked amount. // Update locked and unlocked fields in the model. stackerWallet.amountLocked = newTotalLocked; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index 7b09a8e6da..6175658206 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -11,21 +11,21 @@ import { Cl, ClarityType, isClarityType } from "@stacks/transactions"; import { currentCycle } from "./pox_Commands.ts"; /** - * The `DelegateStackStxCommand` locks STX for stacking within PoX-4 on behalf of a delegator. - * This operation allows the `operator` to stack the `stacker`'s STX. + * The `DelegateStackStxCommand` locks STX for stacking within PoX-4 on behalf + * of a delegator. This operation allows the `operator` to stack the `stacker`'s + * STX. * * Constraints for running this command include: * - A minimum threshold of uSTX must be met, determined by the - * `get-stacking-minimum` function at the time of this call. - * - The Stacker cannot currently be engaged in another stacking - * operation. + * `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 amount. - * - The stacked uSTX amount should be less than or equal to the - * Stacker's balance. - * - The stacked uSTX amount should be greater than or equal to the - * minimum threshold of uSTX. + * - The stacked STX 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. + * - The stacked uSTX amount should be greater than or equal to the minimum + * threshold of uSTX. * - The Operator has to currently be delegated by the Stacker. * - The Period has to fit the last delegation burn block height. */ @@ -46,7 +46,7 @@ export class DelegateStackStxCommand implements PoxCommand { * @param startBurnHt - A burn height inside the current reward cycle. * @param period - Number of reward cycles to lock uSTX. * @param amountUstx - The uSTX amount stacked by the Operator on behalf - * of the Stacker + * of the Stacker. * @param unlockBurnHt - The burn height at which the uSTX is unlocked. */ constructor( @@ -55,7 +55,7 @@ export class DelegateStackStxCommand implements PoxCommand { startBurnHt: number, period: number, amountUstx: bigint, - unlockBurnHt: number + unlockBurnHt: number, ) { this.operator = operator; this.stacker = stacker; @@ -98,6 +98,7 @@ export class DelegateStackStxCommand implements PoxCommand { run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); + // Act const delegateStackStx = real.network.callPublicFn( "ST000000000000000000002AMW42H.pox-4", @@ -114,13 +115,13 @@ export class DelegateStackStxCommand implements PoxCommand { // (lock-period uint) Cl.uint(this.period), ], - this.operator.stxAddress + this.operator.stxAddress, ); const { result: rewardCycle } = real.network.callReadOnlyFn( "ST000000000000000000002AMW42H.pox-4", "burn-height-to-reward-cycle", [Cl.uint(real.network.blockHeight)], - this.operator.stxAddress + this.operator.stxAddress, ); assert(isClarityType(rewardCycle, ClarityType.UInt)); @@ -128,7 +129,7 @@ export class DelegateStackStxCommand implements PoxCommand { "ST000000000000000000002AMW42H.pox-4", "reward-cycle-to-burn-height", [Cl.uint(Number(rewardCycle.value) + this.period + 1)], - this.operator.stxAddress + this.operator.stxAddress, ); assert(isClarityType(unlockBurnHeight, ClarityType.UInt)); @@ -138,7 +139,7 @@ export class DelegateStackStxCommand implements PoxCommand { stacker: Cl.principal(this.stacker.stxAddress), "lock-amount": Cl.uint(this.amountUstx), "unlock-burn-height": Cl.uint(Number(unlockBurnHeight.value)), - }) + }), ); // Get the Stacker's wallet from the model and update it with the new state. @@ -154,8 +155,8 @@ export class DelegateStackStxCommand implements PoxCommand { stackerWallet.amountUnlocked -= Number(this.amountUstx); stackerWallet.firstLockedRewardCycle = currentCycle(real.network) + 1; // Add stacker to the operators lock list. This will help knowing that - // the stacker's funds are locked when calling delegate-stack-extend, - // delegate-stack-increase + // the stacker's funds are locked when calling delegate-stack-extend + // and delegate-stack-increase. operatorWallet.lockedAddresses.push(stackerWallet.stxAddress); operatorWallet.amountToCommit += Number(this.amountUstx); @@ -167,7 +168,7 @@ export class DelegateStackStxCommand implements PoxCommand { "lock-amount", this.amountUstx.toString(), "until", - this.stacker.unlockHeight.toString() + this.stacker.unlockHeight.toString(), ); // Refresh the model's state if the network gets to the next reward cycle. diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts index f6cfbfeb66..040dab3c8e 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts @@ -10,13 +10,14 @@ import { expect } from "vitest"; import { boolCV, Cl } from "@stacks/transactions"; /** - * The `DelegateStxCommand` delegates STX for stacking within PoX-4. This operation - * allows the `tx-sender` (the `wallet` in this case) to delegate stacking participation - * to a `delegatee`. + * The `DelegateStxCommand` delegates STX for stacking within PoX-4. This + * operation allows the `tx-sender` (the `wallet` in this case) to delegate + * stacking participation to a `delegatee`. * * Constraints for running this command include: * - The Stacker cannot currently be a delegator in another delegation. - * - The PoX address provided should have a valid version (between 0 and 6 inclusive). + * - The PoX address provided should have a valid version (between 0 and 6 + * inclusive). */ export class DelegateStxCommand implements PoxCommand { readonly wallet: Wallet; @@ -30,8 +31,8 @@ export class DelegateStxCommand implements PoxCommand { * @param wallet - Represents the Stacker's wallet. * @param delegateTo - Represents the Delegatee's STX address. * @param untilBurnHt - The burn block height until the delegation is valid. - * @param amount - The maximum amount the `Stacker` delegates the `Delegatee` to - * stack on his behalf + * @param amount - The maximum amount the `Stacker` delegates the `Delegatee` + * to stack on his behalf. */ constructor( wallet: Wallet, @@ -48,6 +49,7 @@ export class DelegateStxCommand implements PoxCommand { check(model: Readonly): boolean { // Constraints for running this command include: // - The Stacker cannot currently be a delegator in another delegation. + return ( model.stackingMinimum > 0 && !model.wallets.get(this.wallet.stxAddress)?.hasDelegated @@ -56,6 +58,7 @@ export class DelegateStxCommand implements PoxCommand { run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); + // The amount of uSTX delegated by the Stacker to the Delegatee. // Even if there are no constraints about the delegated amount, // it will be checked in the future, when calling delegate-stack-stx. @@ -104,7 +107,7 @@ export class DelegateStxCommand implements PoxCommand { "delegated to", this.delegateTo.label, "until", - this.untilBurnHt.toString() + this.untilBurnHt.toString(), ); // Refresh the model's state if the network gets to the next reward cycle. diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts index b1c99109be..f26afe7984 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts @@ -27,7 +27,6 @@ export class DisallowContractCallerCommand implements PoxCommand { * @param stacker - Represents the `Stacker`'s wallet. * @param callerToDisallow - The `contract-caller` to be revoked. */ - constructor(stacker: Wallet, callerToDisallow: Wallet) { this.stacker = stacker; this.callerToDisallow = callerToDisallow; @@ -35,12 +34,14 @@ export class DisallowContractCallerCommand implements PoxCommand { check(_model: Readonly): boolean { // Constraints for running this command include: - // - The Caller to be disallowed must have been previously - // allowed by the Operator. + // - The Caller to be disallowed must have been previously allowed + // by the Operator. return ( this.stacker.allowedContractCaller === this.callerToDisallow.stxAddress && - this.callerToDisallow.callerAllowedBy.includes(this.stacker.stxAddress) === + this.callerToDisallow.callerAllowedBy.includes( + this.stacker.stxAddress, + ) === true ); } @@ -62,13 +63,13 @@ export class DisallowContractCallerCommand implements PoxCommand { // Assert expect(disallowContractCaller.result).toBeOk(boolCV(true)); - // Get the wallet to be revoked stacking rights from the model and + // Get the wallet to be revoked stacking rights from the model and // update it with the new state. const callerToDisallow = model.wallets.get( this.callerToDisallow.stxAddress, )!; - // Update model so that we know that the stacker has revoked stacking + // Update model so that we know that the stacker has revoked stacking // allowance. this.stacker.allowedContractCaller = ""; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts index b05923ef1f..de58fd678a 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts @@ -26,13 +26,13 @@ export class GetStackingMinimumCommand implements PoxCommand { } check(_model: Readonly): boolean { - // Can always check the minimum number of uSTX to be stacked in the given - // reward cycle. + // There are no constraints for running this command. return true; } run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); + // Act const { result: stackingMinimum } = real.network.callReadOnlyFn( "ST000000000000000000002AMW42H.pox-4", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts index 8610bc1050..8efa7cce63 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts @@ -26,12 +26,13 @@ export class GetStxAccountCommand implements PoxCommand { } check(_model: Readonly): boolean { - // Can always check the `stx-account` info. + // There are no constraints for running this command. return true; } run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); + const actual = model.wallets.get(this.wallet.stxAddress)!; expect(real.network.runSnippet(`(stx-account '${actual.stxAddress})`)) .toBeTuple({ @@ -40,8 +41,10 @@ export class GetStxAccountCommand implements PoxCommand { "unlock-height": Cl.uint(actual.unlockHeight), }); - expect(actual.amountLocked + actual.amountUnlocked).toBe(actual.ustxBalance); - + expect(actual.amountLocked + actual.amountUnlocked).toBe( + actual.ustxBalance, + ); + // 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( diff --git a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts index 605d461da9..32e5f88756 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts @@ -10,7 +10,8 @@ import { expect } from "vitest"; import { Cl, someCV, tupleCV } from "@stacks/transactions"; /** - * The `RevokeDelegateStxCommand` revokes the delegation for stacking within PoX-4. + * The `RevokeDelegateStxCommand` revokes the delegation for stacking within + * PoX-4. * * Constraints for running this command include: * - The `Stacker` has to currently be delegating. @@ -30,6 +31,7 @@ export class RevokeDelegateStxCommand implements PoxCommand { check(model: Readonly): boolean { // Constraints for running this command include: // - The Stacker has to currently be delegating. + return ( model.stackingMinimum > 0 && model.wallets.get(this.wallet.stxAddress)!.hasDelegated === true @@ -38,7 +40,7 @@ export class RevokeDelegateStxCommand implements PoxCommand { run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); - // Get the Operator's wallet + const operatorWallet = model.wallets.get(this.wallet.delegatedTo)!; // Act @@ -65,17 +67,18 @@ export class RevokeDelegateStxCommand implements PoxCommand { ), ); - // Get the Stacker's wallet from the model and update the two wallets involved with the new state. + // Get the Stacker's wallet from the model and update the two wallets + // involved with the new state. const wallet = model.wallets.get(this.wallet.stxAddress)!; // Update model so that we know this wallet is not delegating anymore. - // This is important in order to prevent the test from revoking the delegation - // multiple times with the same address. + // This is important in order to prevent the test from revoking the + // delegation multiple times with the same address. wallet.hasDelegated = false; wallet.delegatedTo = ""; wallet.delegatedUntilBurnHt = 0; wallet.delegatedMaxAmount = 0; - // Remove the Stacker from the Pool Operator's pool members list + // Remove the Stacker from the Pool Operator's pool members list. const walletIndexInDelegatorsList = operatorWallet.poolMembers.indexOf( wallet.stxAddress, ); diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts index 6b7ba47b68..332cecbd7e 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts @@ -32,7 +32,7 @@ export class StackAggregationCommitIndexedAuthCommand implements PoxCommand { readonly currentCycle: number; /** - * Constructs a `StackAggregationCommitIndexedAuthCommand` to lock uSTX + * Constructs a `StackAggregationCommitIndexedAuthCommand` to lock uSTX * for stacking. * * @param operator - Represents the `Operator`'s wallet. diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts index 56456ac3ef..0f9521f53f 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts @@ -33,7 +33,7 @@ export class StackAggregationCommitIndexedSigCommand implements PoxCommand { readonly currentCycle: number; /** - * Constructs a `StackAggregationCommitIndexedSigCommand` to lock uSTX + * Constructs a `StackAggregationCommitIndexedSigCommand` to lock uSTX * for stacking. * * @param operator - Represents the `Operator`'s wallet. diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts index 7b3c21d863..328d3d0acc 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts @@ -109,4 +109,4 @@ export class StackAggregationIncreaseCommand implements PoxCommand { this.currentCycle + 1 } index ${this.rewardCycleIndex}`; } -} \ No newline at end of file +} diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index 3fd5a5e596..9814dfb5b8 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -57,6 +57,7 @@ export class StackStxCommand implements PoxCommand { // `get-stacking-minimum` function at the time of this call. // - The Stacker cannot currently be engaged in another stacking operation. // - The Stacker cannot currently be delegating STX to a delegatee. + return ( model.stackingMinimum > 0 && !model.wallets.get(this.wallet.stxAddress)?.isStacking && @@ -66,6 +67,7 @@ export class StackStxCommand implements PoxCommand { run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); + // The maximum amount of uSTX that can be used (per tx) with this signer // key. For our tests, we will use the minimum amount of uSTX to be stacked // in the given reward cycle multiplied by the margin, which is a randomly From 5185e580dd8c99e5799efb8c38bb4305eceb08e9 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Fri, 12 Apr 2024 16:55:25 +0200 Subject: [PATCH 111/129] fix(pox-4-tests): update @hirosystems/clarinet-sdk-wasm to 2.4.2 for bug fixes This includes the fixes in - https://github.com/stacks-network/stacks-core/pull/4644 - https://github.com/stacks-network/stacks-core/pull/4670 --- contrib/core-contract-tests/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/core-contract-tests/package-lock.json b/contrib/core-contract-tests/package-lock.json index 5fd11568ce..0ab11dc6dc 100644 --- a/contrib/core-contract-tests/package-lock.json +++ b/contrib/core-contract-tests/package-lock.json @@ -449,9 +449,9 @@ } }, "node_modules/@hirosystems/clarinet-sdk-wasm": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@hirosystems/clarinet-sdk-wasm/-/clarinet-sdk-wasm-2.4.0.tgz", - "integrity": "sha512-qApXWsnWRtQcj5BsqoKd+AsEtDURA5CJQcRxgCAVjyRSjkbGJXxNgrW9oRnIkfIIKJ6D5mV7JGrr8CQ8BSJ/tg==" + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@hirosystems/clarinet-sdk-wasm/-/clarinet-sdk-wasm-2.4.2.tgz", + "integrity": "sha512-85RrDiqrfup/h7XLqysdm/J4csmimCRTXHnCiD+4HyKHVhgr7HWL7sGEGpGfThjPxukjV8A+b2GF2x9Rufpz9g==" }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", From fc235903715984aac7fca9bab87bd3e1aa9862c1 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Mon, 15 Apr 2024 14:43:38 +0200 Subject: [PATCH 112/129] fix(pox-4-tests): Separate stacker from wallet to ensure command updates propagate: - Split wallet data into Wallet and Stacker types in pox-4 tests. - Address fast-check execution order issues affecting state propagation. - Initialize Wallet in constructor, modify Stacker in command runs. - Ensure accurate reflection and propagation of updates across commands. --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 56 ++++++++++++------- .../pox-4/pox_AllowContractCallerCommand.ts | 6 +- .../tests/pox-4/pox_CommandModel.ts | 15 +++-- .../pox-4/pox_DelegateStackExtendCommand.ts | 25 +++++---- .../pox-4/pox_DelegateStackIncreaseCommand.ts | 16 +++--- .../pox-4/pox_DelegateStackStxCommand.ts | 14 ++--- .../tests/pox-4/pox_DelegateStxCommand.ts | 8 +-- .../pox_DisallowContractCallerCommand.ts | 15 +++-- .../tests/pox-4/pox_GetStxAccountCommand.ts | 4 +- .../pox-4/pox_RevokeDelegateStxCommand.ts | 16 +++--- .../pox_StackAggregationCommitAuthCommand.ts | 9 +-- ...tackAggregationCommitIndexedAuthCommand.ts | 9 +-- ...StackAggregationCommitIndexedSigCommand.ts | 9 +-- .../pox_StackAggregationCommitSigCommand.ts | 9 +-- .../pox_StackAggregationIncreaseCommand.ts | 11 ++-- .../tests/pox-4/pox_StackStxCommand.ts | 7 +-- 16 files changed, 131 insertions(+), 98 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index eb34174c1d..7dc6e2fa19 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -114,32 +114,48 @@ it("statefully interacts with PoX-4", async () => { // This is the initial state of the model. const model = new Stub( new Map(wallets.map((wallet) => [wallet.stxAddress, wallet])), + new Map(wallets.map((wallet) => [wallet.stxAddress, { + ustxBalance: 0, + isStacking: false, + hasDelegated: false, + lockedAddresses: [], + amountToCommit: 0, + poolMembers: [], + delegatedTo: "", + delegatedMaxAmount: 0, + delegatedUntilBurnHt: 0, + delegatedPoxAddress: "", + amountLocked: 0, + amountUnlocked: 0, + unlockHeight: 0, + firstLockedRewardCycle: 0, + allowedContractCaller: "", + callerAllowedBy: [], + committedRewCycleIndexes: [], + }])), new Map(statistics.map((commandName) => [commandName, 0])), ); simnet.setEpoch("3.0"); - // 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, + 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: 1000, + // 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(); }); diff --git a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts index 551441166e..de2db628de 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts @@ -73,12 +73,12 @@ export class AllowContractCallerCommand implements PoxCommand { expect(allowContractCaller.result).toBeOk(boolCV(true)); // Get the wallets involved from the model and update it with the new state. - const wallet = model.wallets.get(this.wallet.stxAddress)!; - const callerToAllow = model.wallets.get(this.allowanceTo.stxAddress)!; + const wallet = model.stackers.get(this.wallet.stxAddress)!; + const callerToAllow = model.stackers.get(this.allowanceTo.stxAddress)!; // Update model so that we know this wallet has authorized a contract-caller. wallet.allowedContractCaller = this.allowanceTo.stxAddress; - callerToAllow.callerAllowedBy.push(wallet.stxAddress); + callerToAllow.callerAllowedBy.push(this.wallet.stxAddress); // 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. diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 80e8e28341..49a2205374 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -15,16 +15,19 @@ export type CommandTag = string; export class Stub { readonly wallets: Map; readonly statistics: Map; + readonly stackers: Map; stackingMinimum: number; nextRewardSetIndex: number; lastRefreshedCycle: number; constructor( wallets: Map, + stackers: Map, statistics: Map, ) { this.wallets = wallets; this.statistics = statistics; + this.stackers = stackers; this.stackingMinimum = 0; this.nextRewardSetIndex = 0; this.lastRefreshedCycle = 0; @@ -51,14 +54,15 @@ export class Stub { if (lastRefreshedCycle < currentRewCycle) { this.nextRewardSetIndex = 0; - this.wallets.forEach((wallet) => { + this.wallets.forEach((w) => { + const wallet = this.stackers.get(w.stxAddress)!; const expiredDelegators = wallet.poolMembers.filter((stackerAddress) => - this.wallets.get(stackerAddress)!.delegatedUntilBurnHt + 1 < + this.stackers.get(stackerAddress)!.delegatedUntilBurnHt + 1 < burnBlockHeight ); const expiredStackers = wallet.lockedAddresses.filter( (stackerAddress) => - this.wallets.get(stackerAddress)!.unlockHeight + 1 <= + this.stackers.get(stackerAddress)!.unlockHeight + 1 <= burnBlockHeight, ); @@ -68,7 +72,7 @@ export class Stub { }); expiredStackers.forEach((expStacker) => { - const expStackerWallet = this.wallets.get(expStacker)!; + const expStackerWallet = this.stackers.get(expStacker)!; const expStackerIndex = wallet.lockedAddresses.indexOf(expStacker); wallet.lockedAddresses.splice(expStackerIndex, 1); wallet.amountToCommit -= expStackerWallet.amountLocked; @@ -101,6 +105,9 @@ export type Wallet = { signerPrvKey: StacksPrivateKey; signerPubKey: string; stackingClient: StackingClient; +}; + +export type Stacker = { ustxBalance: number; isStacking: boolean; hasDelegated: boolean; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts index a555d89a37..bcf4b15a8a 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts @@ -60,15 +60,15 @@ export class DelegateStackExtendCommand implements PoxCommand { // - The Operator has to currently be delegated by the Stacker. // - The new lock period must be less than or equal to 12. - const operatorWallet = model.wallets.get(this.operator.stxAddress)!; - const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; + const operatorWallet = model.stackers.get(this.operator.stxAddress)!; + const stackerWallet = model.stackers.get(this.stacker.stxAddress)!; const firstRewardCycle = - this.currentCycle > this.stacker.firstLockedRewardCycle + this.currentCycle > stackerWallet.firstLockedRewardCycle ? this.currentCycle - : this.stacker.firstLockedRewardCycle; + : stackerWallet.firstLockedRewardCycle; const firstExtendCycle = Math.floor( - (this.stacker.unlockHeight - FIRST_BURNCHAIN_BLOCK_HEIGHT) / + (stackerWallet.unlockHeight - FIRST_BURNCHAIN_BLOCK_HEIGHT) / REWARD_CYCLE_LENGTH, ); const lastExtendCycle = firstExtendCycle + this.extendCount - 1; @@ -78,8 +78,8 @@ export class DelegateStackExtendCommand implements PoxCommand { stackerWallet.amountLocked > 0 && stackerWallet.hasDelegated === true && stackerWallet.isStacking === true && - operatorWallet.poolMembers.includes(stackerWallet.stxAddress) && - operatorWallet.lockedAddresses.includes(stackerWallet.stxAddress) && + operatorWallet.poolMembers.includes(this.stacker.stxAddress) && + operatorWallet.lockedAddresses.includes(this.stacker.stxAddress) && totalPeriod <= 12 ); } @@ -87,6 +87,8 @@ export class DelegateStackExtendCommand implements PoxCommand { run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); + const stackerWallet = model.stackers.get(this.stacker.stxAddress)!; + // Act const delegateStackExtend = real.network.callPublicFn( "ST000000000000000000002AMW42H.pox-4", @@ -95,7 +97,7 @@ export class DelegateStackExtendCommand implements PoxCommand { // (stacker principal) Cl.principal(this.stacker.stxAddress), // (pox-addr { version: (buff 1), hashbytes: (buff 32) }) - poxAddressToTuple(this.stacker.delegatedPoxAddress), + poxAddressToTuple(stackerWallet.delegatedPoxAddress), // (extend-count uint) Cl.uint(this.extendCount), ], @@ -105,7 +107,7 @@ export class DelegateStackExtendCommand implements PoxCommand { const { result: firstExtendCycle } = real.network.callReadOnlyFn( "ST000000000000000000002AMW42H.pox-4", "burn-height-to-reward-cycle", - [Cl.uint(this.stacker.unlockHeight)], + [Cl.uint(stackerWallet.unlockHeight)], this.operator.stxAddress, ); assert(isClarityType(firstExtendCycle, ClarityType.UInt)); @@ -131,7 +133,6 @@ export class DelegateStackExtendCommand implements PoxCommand { ); // Get the Stacker's wallet from the model and update it with the new state. - const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; // Update model so that we know this wallet's unlock height was extended. stackerWallet.unlockHeight = Number(newUnlockHeight); @@ -143,7 +144,7 @@ export class DelegateStackExtendCommand implements PoxCommand { "extend count", this.extendCount.toString(), "new unlock height", - this.stacker.unlockHeight.toString(), + stackerWallet.unlockHeight.toString(), ); // Refresh the model's state if the network gets to the next reward cycle. @@ -154,6 +155,6 @@ export class DelegateStackExtendCommand implements PoxCommand { // 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-extend extend count ${this.extendCount} previous unlock height ${this.stacker.unlockHeight}`; + return `${this.operator.label} delegate-stack-extend extend count ${this.extendCount}`; } } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts index 2f5a2590c2..88d43cc1d9 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts @@ -57,26 +57,27 @@ export class DelegateStackIncreaseCommand implements PoxCommand { // to the final locked amount. // - The Operator must have locked the Stacker's previously locked funds. - const operatorWallet = model.wallets.get(this.operator.stxAddress)!; - const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; + const operatorWallet = model.stackers.get(this.operator.stxAddress)!; + const stackerWallet = model.stackers.get(this.stacker.stxAddress)!; return ( stackerWallet.amountLocked > 0 && stackerWallet.hasDelegated === true && stackerWallet.isStacking === true && this.increaseBy > 0 && - operatorWallet.poolMembers.includes(stackerWallet.stxAddress) && + operatorWallet.poolMembers.includes(this.stacker.stxAddress) && stackerWallet.amountUnlocked >= this.increaseBy && stackerWallet.delegatedMaxAmount >= this.increaseBy + stackerWallet.amountLocked && - operatorWallet.lockedAddresses.indexOf(stackerWallet.stxAddress) > -1 + operatorWallet.lockedAddresses.indexOf(this.stacker.stxAddress) > -1 ); } run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); - const prevLocked = this.stacker.amountLocked; + const stackerWallet = model.stackers.get(this.stacker.stxAddress)!; + const prevLocked = stackerWallet.amountLocked; const newTotalLocked = prevLocked + this.increaseBy; // Act const delegateStackIncrease = real.network.callPublicFn( @@ -86,7 +87,7 @@ export class DelegateStackIncreaseCommand implements PoxCommand { // (stacker principal) Cl.principal(this.stacker.stxAddress), // (pox-addr { version: (buff 1), hashbytes: (buff 32) }) - poxAddressToTuple(this.stacker.delegatedPoxAddress), + poxAddressToTuple(stackerWallet.delegatedPoxAddress), // (increase-by uint) Cl.uint(this.increaseBy), ], @@ -102,8 +103,7 @@ export class DelegateStackIncreaseCommand implements PoxCommand { ); // Get the Stacker's wallet from the model and update it with the new state. - const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; - const operatorWallet = model.wallets.get(this.operator.stxAddress)!; + const operatorWallet = model.stackers.get(this.operator.stxAddress)!; // Update model so that we know this stacker has increased the stacked amount. // Update locked and unlocked fields in the model. stackerWallet.amountLocked = newTotalLocked; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index 6175658206..c2d0cc466e 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -81,8 +81,8 @@ export class DelegateStackStxCommand implements PoxCommand { // - The Operator has to currently be delegated by the Stacker. // - The Period has to fit the last delegation burn block height. - const operatorWallet = model.wallets.get(this.operator.stxAddress)!; - const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; + const operatorWallet = model.stackers.get(this.operator.stxAddress)!; + const stackerWallet = model.stackers.get(this.stacker.stxAddress)!; return ( model.stackingMinimum > 0 && @@ -91,7 +91,7 @@ export class DelegateStackStxCommand implements PoxCommand { stackerWallet.delegatedMaxAmount >= Number(this.amountUstx) && Number(this.amountUstx) <= stackerWallet.ustxBalance && Number(this.amountUstx) >= model.stackingMinimum && - operatorWallet.poolMembers.includes(stackerWallet.stxAddress) && + operatorWallet.poolMembers.includes(this.stacker.stxAddress) && this.unlockBurnHt <= stackerWallet.delegatedUntilBurnHt ); } @@ -143,8 +143,8 @@ export class DelegateStackStxCommand implements PoxCommand { ); // Get the Stacker's wallet from the model and update it with the new state. - const stackerWallet = model.wallets.get(this.stacker.stxAddress)!; - const operatorWallet = model.wallets.get(this.operator.stxAddress)!; + const stackerWallet = model.stackers.get(this.stacker.stxAddress)!; + const operatorWallet = model.stackers.get(this.operator.stxAddress)!; // Update model so that we know this wallet is stacking. This is important // in order to prevent the test from stacking multiple times with the same // address. @@ -157,7 +157,7 @@ export class DelegateStackStxCommand implements PoxCommand { // Add stacker to the operators lock list. This will help knowing that // the stacker's funds are locked when calling delegate-stack-extend // and delegate-stack-increase. - operatorWallet.lockedAddresses.push(stackerWallet.stxAddress); + operatorWallet.lockedAddresses.push(this.stacker.stxAddress); operatorWallet.amountToCommit += Number(this.amountUstx); // Log to console for debugging purposes. This is not necessary for the @@ -168,7 +168,7 @@ export class DelegateStackStxCommand implements PoxCommand { "lock-amount", this.amountUstx.toString(), "until", - this.stacker.unlockHeight.toString(), + stackerWallet.unlockHeight.toString(), ); // Refresh the model's state if the network gets to the next reward cycle. diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts index 040dab3c8e..73285d4033 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts @@ -52,7 +52,7 @@ export class DelegateStxCommand implements PoxCommand { return ( model.stackingMinimum > 0 && - !model.wallets.get(this.wallet.stxAddress)?.hasDelegated + !model.stackers.get(this.wallet.stxAddress)?.hasDelegated ); } @@ -85,8 +85,8 @@ export class DelegateStxCommand implements PoxCommand { expect(delegateStx.result).toBeOk(boolCV(true)); // Get the wallet from the model and update it with the new state. - const wallet = model.wallets.get(this.wallet.stxAddress)!; - const delegatedWallet = model.wallets.get(this.delegateTo.stxAddress)!; + const wallet = model.stackers.get(this.wallet.stxAddress)!; + const delegatedWallet = model.stackers.get(this.delegateTo.stxAddress)!; // Update model so that we know this wallet has delegated. This is important // in order to prevent the test from delegating multiple times with the same // address. @@ -96,7 +96,7 @@ export class DelegateStxCommand implements PoxCommand { wallet.delegatedUntilBurnHt = this.untilBurnHt; wallet.delegatedPoxAddress = this.delegateTo.btcAddress; - delegatedWallet.poolMembers.push(wallet.stxAddress); + delegatedWallet.poolMembers.push(this.wallet.stxAddress); // 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( diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts index f26afe7984..effc4de88b 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts @@ -32,14 +32,18 @@ export class DisallowContractCallerCommand implements PoxCommand { this.callerToDisallow = callerToDisallow; } - check(_model: Readonly): boolean { + check(model: Readonly): boolean { // Constraints for running this command include: // - The Caller to be disallowed must have been previously allowed // by the Operator. + const stacker = model.stackers.get(this.stacker.stxAddress)!; + const callerToDisallow = model.stackers.get( + this.callerToDisallow.stxAddress, + )!; return ( - this.stacker.allowedContractCaller === this.callerToDisallow.stxAddress && - this.callerToDisallow.callerAllowedBy.includes( + stacker.allowedContractCaller === this.callerToDisallow.stxAddress && + callerToDisallow.callerAllowedBy.includes( this.stacker.stxAddress, ) === true @@ -65,13 +69,14 @@ export class DisallowContractCallerCommand implements PoxCommand { // Get the wallet to be revoked stacking rights from the model and // update it with the new state. - const callerToDisallow = model.wallets.get( + const callerToDisallow = model.stackers.get( this.callerToDisallow.stxAddress, )!; // Update model so that we know that the stacker has revoked stacking // allowance. - this.stacker.allowedContractCaller = ""; + const stacker = model.stackers.get(this.stacker.stxAddress)!; + stacker.allowedContractCaller = ""; // Remove the operator from the caller to disallow's allowance list. const walletIndexAllowedByList = callerToDisallow.callerAllowedBy.indexOf( diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts index 8efa7cce63..744e903090 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts @@ -33,8 +33,8 @@ export class GetStxAccountCommand implements PoxCommand { run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); - const actual = model.wallets.get(this.wallet.stxAddress)!; - expect(real.network.runSnippet(`(stx-account '${actual.stxAddress})`)) + const actual = model.stackers.get(this.wallet.stxAddress)!; + expect(real.network.runSnippet(`(stx-account '${this.wallet.stxAddress})`)) .toBeTuple({ "locked": Cl.uint(actual.amountLocked), "unlocked": Cl.uint(actual.amountUnlocked), diff --git a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts index 32e5f88756..c2ee037f1f 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts @@ -34,14 +34,15 @@ export class RevokeDelegateStxCommand implements PoxCommand { return ( model.stackingMinimum > 0 && - model.wallets.get(this.wallet.stxAddress)!.hasDelegated === true + model.stackers.get(this.wallet.stxAddress)!.hasDelegated === true ); } run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); - const operatorWallet = model.wallets.get(this.wallet.delegatedTo)!; + const wallet = model.stackers.get(this.wallet.stxAddress)!; + const operatorWallet = model.stackers.get(wallet.delegatedTo)!; // Act const revokeDelegateStx = real.network.callPublicFn( @@ -55,21 +56,20 @@ export class RevokeDelegateStxCommand implements PoxCommand { expect(revokeDelegateStx.result).toBeOk( someCV( tupleCV({ - "amount-ustx": Cl.uint(this.wallet.delegatedMaxAmount), + "amount-ustx": Cl.uint(wallet.delegatedMaxAmount), "delegated-to": Cl.principal( - operatorWallet.stxAddress || "", + this.wallet.stxAddress /*operatorWallet.stxAddress*/ || "", ), "pox-addr": Cl.some( - poxAddressToTuple(this.wallet.delegatedPoxAddress || ""), + poxAddressToTuple(wallet.delegatedPoxAddress || ""), ), - "until-burn-ht": Cl.some(Cl.uint(this.wallet.delegatedUntilBurnHt)), + "until-burn-ht": Cl.some(Cl.uint(wallet.delegatedUntilBurnHt)), }), ), ); // Get the Stacker's wallet from the model and update the two wallets // involved with the new state. - const wallet = model.wallets.get(this.wallet.stxAddress)!; // Update model so that we know this wallet is not delegating anymore. // This is important in order to prevent the test from revoking the // delegation multiple times with the same address. @@ -80,7 +80,7 @@ export class RevokeDelegateStxCommand implements PoxCommand { // Remove the Stacker from the Pool Operator's pool members list. const walletIndexInDelegatorsList = operatorWallet.poolMembers.indexOf( - wallet.stxAddress, + this.wallet.stxAddress, ); expect(walletIndexInDelegatorsList).toBeGreaterThan(-1); operatorWallet.poolMembers.splice(walletIndexInDelegatorsList, 1); diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts index afe3be8dff..35c9d35e11 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts @@ -52,14 +52,16 @@ export class StackAggregationCommitAuthCommand implements PoxCommand { // - The total amount previously locked by the Operator on behalf of the // stackers has to be greater than the uSTX threshold. - return this.operator.lockedAddresses.length > 0 && - this.operator.amountToCommit >= model.stackingMinimum; + const operator = model.stackers.get(this.operator.stxAddress)!; + return operator.lockedAddresses.length > 0 && + operator.amountToCommit >= model.stackingMinimum; } run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); - const committedAmount = this.operator.amountToCommit; + const operatorWallet = model.stackers.get(this.operator.stxAddress)!; + const committedAmount = operatorWallet.amountToCommit; const { result: setSignature } = real.network.callPublicFn( "ST000000000000000000002AMW42H.pox-4", @@ -110,7 +112,6 @@ export class StackAggregationCommitAuthCommand implements PoxCommand { // Assert expect(stackAggregationCommit.result).toBeOk(Cl.bool(true)); - const operatorWallet = model.wallets.get(this.operator.stxAddress)!; operatorWallet.amountToCommit -= committedAmount; operatorWallet.committedRewCycleIndexes.push(model.nextRewardSetIndex); model.nextRewardSetIndex++; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts index 332cecbd7e..9ac5bf715f 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts @@ -51,16 +51,18 @@ export class StackAggregationCommitIndexedAuthCommand implements PoxCommand { // - The total amount previously locked by the Operator on behalf of the // stackers has to be greater than the uSTX threshold. + const operator = model.stackers.get(this.operator.stxAddress)!; return ( - this.operator.lockedAddresses.length > 0 && - this.operator.amountToCommit >= model.stackingMinimum + operator.lockedAddresses.length > 0 && + operator.amountToCommit >= model.stackingMinimum ); } run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); - const committedAmount = this.operator.amountToCommit; + const operatorWallet = model.stackers.get(this.operator.stxAddress)!; + const committedAmount = operatorWallet.amountToCommit; const { result: setSignature } = real.network.callPublicFn( "ST000000000000000000002AMW42H.pox-4", @@ -114,7 +116,6 @@ export class StackAggregationCommitIndexedAuthCommand implements PoxCommand { ); // Update the model - const operatorWallet = model.wallets.get(this.operator.stxAddress)!; operatorWallet.amountToCommit -= committedAmount; operatorWallet.committedRewCycleIndexes.push(model.nextRewardSetIndex); model.nextRewardSetIndex++; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts index 0f9521f53f..36e02151b1 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts @@ -52,16 +52,18 @@ export class StackAggregationCommitIndexedSigCommand implements PoxCommand { // - The total amount previously locked by the Operator on behalf of the // stackers has to be greater than the uSTX threshold. + const operator = model.stackers.get(this.operator.stxAddress)!; return ( - this.operator.lockedAddresses.length > 0 && - this.operator.amountToCommit >= model.stackingMinimum + operator.lockedAddresses.length > 0 && + operator.amountToCommit >= model.stackingMinimum ); } run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); - const committedAmount = this.operator.amountToCommit; + const operatorWallet = model.stackers.get(this.operator.stxAddress)!; + const committedAmount = operatorWallet.amountToCommit; const signerSig = this.operator.stackingClient.signPoxSignature({ // The signer key being authorized. @@ -114,7 +116,6 @@ export class StackAggregationCommitIndexedSigCommand implements PoxCommand { ); // Update the model - const operatorWallet = model.wallets.get(this.operator.stxAddress)!; operatorWallet.amountToCommit -= committedAmount; operatorWallet.committedRewCycleIndexes.push(model.nextRewardSetIndex); model.nextRewardSetIndex++; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts index 390ae23603..d11672aecc 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts @@ -53,14 +53,16 @@ export class StackAggregationCommitSigCommand implements PoxCommand { // - The total amount previously locked by the Operator on behalf of the // stackers has to be greater than the uSTX threshold. - return this.operator.lockedAddresses.length > 0 && - this.operator.amountToCommit >= model.stackingMinimum; + const operator = model.stackers.get(this.operator.stxAddress)!; + return operator.lockedAddresses.length > 0 && + operator.amountToCommit >= model.stackingMinimum; } run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); - const committedAmount = this.operator.amountToCommit; + const operatorWallet = model.stackers.get(this.operator.stxAddress)!; + const committedAmount = operatorWallet.amountToCommit; const signerSig = this.operator.stackingClient.signPoxSignature({ // The signer key being authorized. @@ -110,7 +112,6 @@ export class StackAggregationCommitSigCommand implements PoxCommand { // Assert expect(stackAggregationCommit.result).toBeOk(Cl.bool(true)); - const operatorWallet = model.wallets.get(this.operator.stxAddress)!; operatorWallet.amountToCommit -= committedAmount; operatorWallet.committedRewCycleIndexes.push(model.nextRewardSetIndex); model.nextRewardSetIndex++; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts index 328d3d0acc..4f89e1aba0 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts @@ -47,23 +47,25 @@ export class StackAggregationIncreaseCommand implements PoxCommand { this.rewardCycleIndex = rewardCycleIndex; } - check(_model: Readonly): boolean { + check(model: Readonly): boolean { // Constraints for running this command include: // - The Operator must have locked STX on behalf of at least one stacker. // - The PoX address must have partial committed STX. // - The Reward Cycle Index must be positive. + const operator = model.stackers.get(this.operator.stxAddress)!; return ( - this.operator.lockedAddresses.length > 0 && + operator.lockedAddresses.length > 0 && this.rewardCycleIndex >= 0 && - this.operator.amountToCommit > 0 + operator.amountToCommit > 0 ); } run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); - const committedAmount = this.operator.amountToCommit; + const operatorWallet = model.stackers.get(this.operator.stxAddress)!; + const committedAmount = operatorWallet.amountToCommit; // Act const stackAggregationIncrease = real.network.callPublicFn( @@ -83,7 +85,6 @@ export class StackAggregationIncreaseCommand implements PoxCommand { // Assert expect(stackAggregationIncrease.result).toBeOk(Cl.bool(true)); - const operatorWallet = model.wallets.get(this.operator.stxAddress)!; operatorWallet.amountToCommit -= committedAmount; // Log to console for debugging purposes. This is not necessary for the diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index 9814dfb5b8..aea6ee0c73 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -58,10 +58,9 @@ export class StackStxCommand implements PoxCommand { // - The Stacker cannot currently be engaged in another stacking operation. // - The Stacker cannot currently be delegating STX to a delegatee. + const stacker = model.stackers.get(this.wallet.stxAddress)!; return ( - model.stackingMinimum > 0 && - !model.wallets.get(this.wallet.stxAddress)?.isStacking && - !model.wallets.get(this.wallet.stxAddress)?.hasDelegated + model.stackingMinimum > 0 && !stacker.isStacking && !stacker.hasDelegated ); } @@ -155,7 +154,7 @@ export class StackStxCommand implements PoxCommand { ); // Get the wallet from the model and update it with the new state. - const wallet = model.wallets.get(this.wallet.stxAddress)!; + const wallet = model.stackers.get(this.wallet.stxAddress)!; // Update model so that we know this wallet is stacking. This is important // in order to prevent the test from stacking multiple times with the same // address. From 7dba97566e239509ce64acbaa3dd318b97e76e35 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Tue, 16 Apr 2024 00:31:35 +0300 Subject: [PATCH 113/129] fix(pox-4-tests): Use stackers instead of wallets, update model initialization --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 6 ++--- .../tests/pox-4/pox_Commands.ts | 25 +++++++++++-------- .../pox-4/pox_RevokeDelegateStxCommand.ts | 2 +- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index 7dc6e2fa19..ba99ea2d49 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -115,7 +115,7 @@ it("statefully interacts with PoX-4", async () => { const model = new Stub( new Map(wallets.map((wallet) => [wallet.stxAddress, wallet])), new Map(wallets.map((wallet) => [wallet.stxAddress, { - ustxBalance: 0, + ustxBalance: 100_000_000_000_000, isStacking: false, hasDelegated: false, lockedAddresses: [], @@ -126,7 +126,7 @@ it("statefully interacts with PoX-4", async () => { delegatedUntilBurnHt: 0, delegatedPoxAddress: "", amountLocked: 0, - amountUnlocked: 0, + amountUnlocked: 100_000_000_000_000, unlockHeight: 0, firstLockedRewardCycle: 0, allowedContractCaller: "", @@ -140,7 +140,7 @@ it("statefully interacts with PoX-4", async () => { fc.assert( fc.property( - PoxCommands(model.wallets, sut.network), + PoxCommands(model.wallets, model.stackers, sut.network), (cmds) => { const initialState = () => ({ model: model, real: sut }); fc.modelRun(initialState, cmds); diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index bb1fc38cd5..87584483cc 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -1,5 +1,5 @@ import fc from "fast-check"; -import { Real, Stub, StxAddress, Wallet } from "./pox_CommandModel"; +import { Real, Stacker, Stub, StxAddress, Wallet } from "./pox_CommandModel"; import { GetStackingMinimumCommand } from "./pox_GetStackingMinimumCommand"; import { GetStxAccountCommand } from "./pox_GetStxAccountCommand"; import { StackStxCommand } from "./pox_StackStxCommand"; @@ -20,6 +20,7 @@ import { DisallowContractCallerCommand } from "./pox_DisallowContractCallerComma export function PoxCommands( wallets: Map, + stackers: Map, network: Simnet, ): fc.Arbitrary>> { const cmds = [ @@ -157,9 +158,10 @@ export function PoxCommands( wallet: fc.constantFrom(...wallets.values()), currentCycle: fc.constant(currentCycle(network)), }).chain((r) => { + const operator = stackers.get(r.wallet.stxAddress)! const committedRewCycleIndexesOrFallback = - r.wallet.committedRewCycleIndexes.length > 0 - ? r.wallet.committedRewCycleIndexes + operator.committedRewCycleIndexes.length > 0 + ? operator.committedRewCycleIndexes : [-1]; return fc.record({ rewardCycleIndex: fc.constantFrom( @@ -200,9 +202,10 @@ export function PoxCommands( }), period: fc.integer({ min: 1, max: 12 }), }).chain((r) => { + const operator = stackers.get(r.operator.stxAddress)! // Determine available stackers based on the operator - const availableStackers = r.operator.poolMembers.length > 0 - ? r.operator.poolMembers + const availableStackers = operator.poolMembers.length > 0 + ? operator.poolMembers : [r.operator.stxAddress]; return fc.record({ @@ -224,7 +227,7 @@ export function PoxCommands( return fc.record({ amount: fc.bigInt({ min: 0n, - max: BigInt(resultWithUnlockHeight.stacker.delegatedMaxAmount), + max: BigInt(stackers.get(resultWithUnlockHeight.stacker.stxAddress)!.delegatedMaxAmount), }), }).map((amountProps) => ({ ...resultWithUnlockHeight, @@ -247,10 +250,11 @@ export function PoxCommands( increaseBy: fc.nat(), }) .chain((r) => { - const delegatorsList = r.operator.poolMembers; + const operator = stackers.get(r.operator.stxAddress)! + const delegatorsList = operator.poolMembers; const availableStackers = delegatorsList.filter((delegator) => { - const delegatorWallet = wallets.get(delegator)!; + const delegatorWallet = stackers.get(delegator)!; return delegatorWallet.unlockHeight > nextCycleFirstBlock(network); }); @@ -279,9 +283,10 @@ export function PoxCommands( operator: fc.constantFrom(...wallets.values()), extendCount: fc.integer({ min: 1, max: 11 }), }).chain((r) => { - const delegatorsList = r.operator.poolMembers; + const operator = stackers.get(r.operator.stxAddress)! + const delegatorsList = operator.poolMembers; const availableStackers = delegatorsList.filter((delegator) => { - const delegatorWallet = wallets.get(delegator)!; + const delegatorWallet = stackers.get(delegator)!; return delegatorWallet.unlockHeight > nextCycleFirstBlock(network); }); diff --git a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts index c2ee037f1f..2d23fcc73c 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts @@ -58,7 +58,7 @@ export class RevokeDelegateStxCommand implements PoxCommand { tupleCV({ "amount-ustx": Cl.uint(wallet.delegatedMaxAmount), "delegated-to": Cl.principal( - this.wallet.stxAddress /*operatorWallet.stxAddress*/ || "", + model.stackers.get(this.wallet.stxAddress)!.delegatedTo /*operatorWallet.stxAddress*/ || "", ), "pox-addr": Cl.some( poxAddressToTuple(wallet.delegatedPoxAddress || ""), From 25ee419411c0fdd33dbd4378673c4f95feb4194f Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Tue, 16 Apr 2024 00:36:25 +0300 Subject: [PATCH 114/129] fix(pox-4-tests): Update `StackAggregationIncreaseCommand` to use a signature --- .../tests/pox-4/pox_Commands.ts | 3 ++ .../pox_StackAggregationIncreaseCommand.ts | 52 ++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 87584483cc..a35991d852 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -157,6 +157,7 @@ export function PoxCommands( fc.record({ wallet: fc.constantFrom(...wallets.values()), currentCycle: fc.constant(currentCycle(network)), + authId: fc.nat(), }).chain((r) => { const operator = stackers.get(r.wallet.stxAddress)! const committedRewCycleIndexesOrFallback = @@ -173,12 +174,14 @@ export function PoxCommands( wallet: Wallet; currentCycle: number; rewardCycleIndex: number; + authId: number; }, ) => new StackAggregationIncreaseCommand( r.wallet, r.currentCycle, r.rewardCycleIndex, + r.authId, ) ), // RevokeDelegateStxCommand diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts index 4f89e1aba0..0f2ad6d10c 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts @@ -7,7 +7,8 @@ import { } from "./pox_CommandModel.ts"; import { poxAddressToTuple } from "@stacks/stacking"; import { expect } from "vitest"; -import { Cl } from "@stacks/transactions"; +import { Cl, cvToJSON } from "@stacks/transactions"; +import { bufferFromHex } from "@stacks/transactions/dist/cl"; /** * The `StackAggregationIncreaseCommand` allows an operator to commit @@ -28,6 +29,7 @@ export class StackAggregationIncreaseCommand implements PoxCommand { readonly operator: Wallet; readonly currentCycle: number; readonly rewardCycleIndex: number; + readonly authId: number; /** * Constructs a `StackAggregationIncreaseCommand` to commit partially @@ -36,15 +38,18 @@ export class StackAggregationIncreaseCommand implements PoxCommand { * @param operator - Represents the `Operator`'s wallet. * @param currentCycle - The current reward cycle. * @param rewardCycleIndex - The cycle index to increase the commit for. + * @param authId - Unique `auth-id` for the authorization. */ constructor( operator: Wallet, currentCycle: number, rewardCycleIndex: number, + authId: number, ) { this.operator = operator; this.currentCycle = currentCycle; this.rewardCycleIndex = rewardCycleIndex; + this.authId = authId; } check(model: Readonly): boolean { @@ -67,6 +72,43 @@ export class StackAggregationIncreaseCommand implements PoxCommand { const operatorWallet = model.stackers.get(this.operator.stxAddress)!; const committedAmount = operatorWallet.amountToCommit; + const existingEntryCV = real.network.getMapEntry( + "ST000000000000000000002AMW42H.pox-4", + "reward-cycle-pox-address-list", + Cl.tuple({ + "index": Cl.uint(this.rewardCycleIndex), + "reward-cycle": Cl.uint(this.currentCycle + 1), + }), + ); + + const totalStackedBefore = + cvToJSON(existingEntryCV).value.value["total-ustx"].value; + const maxAmount = committedAmount + Number(totalStackedBefore); + + const signerSig = this.operator.stackingClient.signPoxSignature({ + // The signer key being authorized. + signerPrivateKey: this.operator.signerPrvKey, + // The reward cycle for which the authorization is valid. + // For stack-stx and stack-extend, this refers to the reward cycle + // where the transaction is confirmed. For stack-aggregation-commit, + // this refers to the reward cycle argument in that function. + rewardCycle: this.currentCycle + 1, + // For stack-stx, this refers to lock-period. For stack-extend, + // this refers to extend-count. For stack-aggregation-commit, this is + // u1. + period: 1, + // A string representing the function where this authorization is valid. + // Either stack-stx, stack-extend, stack-increase, agg-commit or agg-increase. + topic: "agg-increase", + // The PoX address that can be used with this signer key. + poxAddress: this.operator.btcAddress, + // The unique auth-id for this authorization. + authId: this.authId, + // The maximum amount of uSTX that can be used (per tx) with this signer + // key. + maxAmount: maxAmount, + }); + // Act const stackAggregationIncrease = real.network.callPublicFn( "ST000000000000000000002AMW42H.pox-4", @@ -78,6 +120,14 @@ export class StackAggregationIncreaseCommand implements PoxCommand { Cl.uint(this.currentCycle + 1), // (reward-cycle-index uint)) Cl.uint(this.rewardCycleIndex), + // (signer-sig (optional (buff 65))) + Cl.some(bufferFromHex(signerSig)), + // (signer-key (buff 33)) + Cl.bufferFromHex(this.operator.signerPubKey), + // (max-amount uint) + Cl.uint(maxAmount), + // (auth-id uint) + Cl.uint(this.authId), ], this.operator.stxAddress, ); From 53170b9da512057e2330e568cbb9b28b85c4a6f0 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Tue, 16 Apr 2024 12:53:24 +0300 Subject: [PATCH 115/129] fix(pox-4-tests): Update @stacks/stacking to version `6.13.2` --- contrib/core-contract-tests/package-lock.json | 24 +++++++++---------- contrib/core-contract-tests/package.json | 2 +- .../pox_StackAggregationIncreaseCommand.ts | 4 ++-- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/contrib/core-contract-tests/package-lock.json b/contrib/core-contract-tests/package-lock.json index 0ab11dc6dc..f15153b12e 100644 --- a/contrib/core-contract-tests/package-lock.json +++ b/contrib/core-contract-tests/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@hirosystems/clarinet-sdk": "^2.4.1", "@stacks/clarunit": "0.0.1", - "@stacks/stacking": "^6.13.0", + "@stacks/stacking": "^6.13.2", "@stacks/transactions": "^6.13.0", "chokidar-cli": "^3.0.0", "fast-check": "^3.15.1", @@ -1229,9 +1229,9 @@ } }, "node_modules/@stacks/encryption": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@stacks/encryption/-/encryption-6.13.0.tgz", - "integrity": "sha512-CsacBxY1XBVXBuJ5erJPjB5FmQ8KGJ/ft02/pIM6WrJ31ZcBdkn2BPV1AsPSD5qsIkiMdHAe14WKIwm8M2SWtQ==", + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/@stacks/encryption/-/encryption-6.13.1.tgz", + "integrity": "sha512-y5IFX3/nGI3fCk70gE0JwH70GpshD8RhUfvhMLcL96oNaec1cCdj1ZUiQupeicfYTHuraaVBYU9xLls4TRmypg==", "dependencies": { "@noble/hashes": "1.1.5", "@noble/secp256k1": "1.7.1", @@ -1254,17 +1254,17 @@ } }, "node_modules/@stacks/stacking": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@stacks/stacking/-/stacking-6.13.0.tgz", - "integrity": "sha512-ivzFZkVpqzneJ71T1eZTW8Rr5oVYrs4HkwZqGHxDEySb1I6p96hojH5gEguj9g7szQiyeYLj1dreCvhLh6ET6A==", + "version": "6.13.2", + "resolved": "https://registry.npmjs.org/@stacks/stacking/-/stacking-6.13.2.tgz", + "integrity": "sha512-4h1UQuL2+Xdra9zMqzUElvKG9X9fenuNE7hD9sIqyxyLFxeQ7gRqczmTYPsmaj4wY5004JNj+efzGJ0VmpOcAA==", "dependencies": { "@noble/hashes": "1.1.5", "@scure/base": "1.1.1", "@stacks/common": "^6.13.0", - "@stacks/encryption": "^6.13.0", + "@stacks/encryption": "^6.13.1", "@stacks/network": "^6.13.0", "@stacks/stacks-blockchain-api-types": "^0.61.0", - "@stacks/transactions": "^6.13.0", + "@stacks/transactions": "^6.13.1", "bs58": "^5.0.0" } }, @@ -1285,9 +1285,9 @@ "integrity": "sha512-yPOfTUboo5eA9BZL/hqMcM71GstrFs9YWzOrJFPeP4cOO1wgYvAcckgBRbgiE3NqeX0A7SLZLDAXLZbATuRq9w==" }, "node_modules/@stacks/transactions": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@stacks/transactions/-/transactions-6.13.0.tgz", - "integrity": "sha512-xrx09qsXL/tWCkvAArzsFQqtZKDXyedjdVB9uX8xw+cQCi3xZ7r5MHMKzvEsTgJz3EO+MkQBXcvI1uzfuoqhcA==", + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/@stacks/transactions/-/transactions-6.13.1.tgz", + "integrity": "sha512-PWw2I+2Fj3CaFYQIoVcqQN6E2qGHNhFv03nuR0CxMq0sx8stPgYZbdzUlnlBcJQdsFiHrw3sPeqnXDZt+Hg5YQ==", "dependencies": { "@noble/hashes": "1.1.5", "@noble/secp256k1": "1.7.1", diff --git a/contrib/core-contract-tests/package.json b/contrib/core-contract-tests/package.json index 0d80a4e570..fe3dee2eb5 100644 --- a/contrib/core-contract-tests/package.json +++ b/contrib/core-contract-tests/package.json @@ -13,7 +13,7 @@ "dependencies": { "@hirosystems/clarinet-sdk": "^2.4.1", "@stacks/clarunit": "0.0.1", - "@stacks/stacking": "^6.13.0", + "@stacks/stacking": "^6.13.2", "@stacks/transactions": "^6.13.0", "chokidar-cli": "^3.0.0", "fast-check": "^3.15.1", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts index 0f2ad6d10c..2a5ba81cbd 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts @@ -5,7 +5,7 @@ import { Stub, Wallet, } from "./pox_CommandModel.ts"; -import { poxAddressToTuple } from "@stacks/stacking"; +import { Pox4SignatureTopic, poxAddressToTuple } from "@stacks/stacking"; import { expect } from "vitest"; import { Cl, cvToJSON } from "@stacks/transactions"; import { bufferFromHex } from "@stacks/transactions/dist/cl"; @@ -99,7 +99,7 @@ export class StackAggregationIncreaseCommand implements PoxCommand { period: 1, // A string representing the function where this authorization is valid. // Either stack-stx, stack-extend, stack-increase, agg-commit or agg-increase. - topic: "agg-increase", + topic: Pox4SignatureTopic.AggregateIncrease, // The PoX address that can be used with this signer key. poxAddress: this.operator.btcAddress, // The unique auth-id for this authorization. From eb95d20ac3876ee2234c4ddabbdd92eda38c6dcd Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Tue, 16 Apr 2024 18:31:58 +0300 Subject: [PATCH 116/129] fix(pox-4-tests): Fix `DelegateStackStx`, `StackStx`, `DelegateStackExtend`, `RevokeDelegateStx` This commit fixes issues regarding values generated at the generator level that are not available after the reward cycle change. --- .../tests/pox-4/pox_CommandModel.ts | 20 ++++++++++++------- .../tests/pox-4/pox_Commands.ts | 4 ---- .../pox-4/pox_DelegateStackExtendCommand.ts | 5 +++++ .../pox-4/pox_DelegateStackStxCommand.ts | 14 ++++++------- .../pox-4/pox_RevokeDelegateStxCommand.ts | 1 + .../tests/pox-4/pox_StackStxCommand.ts | 15 +++++++------- 6 files changed, 33 insertions(+), 26 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 49a2205374..f094f8feca 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -47,7 +47,9 @@ export class Stub { refreshStateForNextRewardCycle(real: Real) { const burnBlockHeightResult = real.network.runSnippet("burn-block-height"); - const burnBlockHeight = cvToValue(burnBlockHeightResult as ClarityValue); + const burnBlockHeight = Number( + cvToValue(burnBlockHeightResult as ClarityValue), + ); const lastRefreshedCycle = this.lastRefreshedCycle; const currentRewCycle = Math.floor((Number(burnBlockHeight) - 0) / 1050); @@ -57,13 +59,13 @@ export class Stub { this.wallets.forEach((w) => { const wallet = this.stackers.get(w.stxAddress)!; const expiredDelegators = wallet.poolMembers.filter((stackerAddress) => - this.stackers.get(stackerAddress)!.delegatedUntilBurnHt + 1 < - burnBlockHeight + this.stackers.get(stackerAddress)!.delegatedUntilBurnHt < + burnBlockHeight + 1 ); const expiredStackers = wallet.lockedAddresses.filter( (stackerAddress) => - this.stackers.get(stackerAddress)!.unlockHeight + 1 <= - burnBlockHeight, + this.stackers.get(stackerAddress)!.unlockHeight <= + burnBlockHeight + 1, ); expiredDelegators.forEach((expDelegator) => { @@ -79,7 +81,7 @@ export class Stub { }); if ( - wallet.unlockHeight > 0 && wallet.unlockHeight + 1 <= burnBlockHeight + wallet.unlockHeight > 0 && wallet.unlockHeight <= burnBlockHeight + 1 ) { wallet.isStacking = false; wallet.amountUnlocked += wallet.amountLocked; @@ -89,8 +91,12 @@ export class Stub { } wallet.committedRewCycleIndexes = []; }); + this.stackers.forEach((stacker) => + process.stdout.write(`${JSON.stringify(stacker)}\n`) + ); + + this.lastRefreshedCycle = currentRewCycle; } - this.lastRefreshedCycle = currentRewCycle; } } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index a35991d852..8a0cd389da 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -42,14 +42,12 @@ export function PoxCommands( authId: fc.nat(), period: fc.integer({ min: 1, max: 12 }), margin: fc.integer({ min: 1, max: 9 }), - currentCycle: fc.constant(currentCycle(network)), }).map(( r: { wallet: Wallet; authId: number; period: number; margin: number; - currentCycle: number; }, ) => new StackStxCommand( @@ -57,7 +55,6 @@ export function PoxCommands( r.authId, r.period, r.margin, - r.currentCycle, ) ), // DelegateStxCommand @@ -241,7 +238,6 @@ export function PoxCommands( return new DelegateStackStxCommand( finalResult.operator, finalResult.stacker, - finalResult.startBurnHt, finalResult.period, finalResult.amount, finalResult.unlockBurnHt, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts index bcf4b15a8a..2a0e5808a2 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts @@ -73,11 +73,16 @@ export class DelegateStackExtendCommand implements PoxCommand { ); const lastExtendCycle = firstExtendCycle + this.extendCount - 1; const totalPeriod = lastExtendCycle - firstRewardCycle + 1; + const newUnlockHeight = (REWARD_CYCLE_LENGTH * (firstRewardCycle + totalPeriod - 1) + 0); + const stackedAmount = stackerWallet.amountLocked; return ( stackerWallet.amountLocked > 0 && stackerWallet.hasDelegated === true && stackerWallet.isStacking === true && + stackerWallet.delegatedTo === this.operator.stxAddress && + stackerWallet.delegatedUntilBurnHt >= newUnlockHeight && + stackerWallet.delegatedMaxAmount >= stackedAmount && operatorWallet.poolMembers.includes(this.stacker.stxAddress) && operatorWallet.lockedAddresses.includes(this.stacker.stxAddress) && totalPeriod <= 12 diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index c2d0cc466e..acc29cf898 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -7,7 +7,7 @@ import { } from "./pox_CommandModel.ts"; import { poxAddressToTuple } from "@stacks/stacking"; import { assert, expect } from "vitest"; -import { Cl, ClarityType, isClarityType } from "@stacks/transactions"; +import { Cl, ClarityType, ClarityValue, cvToValue, isClarityType } from "@stacks/transactions"; import { currentCycle } from "./pox_Commands.ts"; /** @@ -32,7 +32,6 @@ import { currentCycle } from "./pox_Commands.ts"; export class DelegateStackStxCommand implements PoxCommand { readonly operator: Wallet; readonly stacker: Wallet; - readonly startBurnHt: number; readonly period: number; readonly amountUstx: bigint; readonly unlockBurnHt: number; @@ -43,7 +42,6 @@ export class DelegateStackStxCommand implements PoxCommand { * * @param operator - Represents the Pool Operator's wallet. * @param stacker - Represents the STacker's wallet. - * @param startBurnHt - A burn height inside the current reward cycle. * @param period - Number of reward cycles to lock uSTX. * @param amountUstx - The uSTX amount stacked by the Operator on behalf * of the Stacker. @@ -52,14 +50,12 @@ export class DelegateStackStxCommand implements PoxCommand { constructor( operator: Wallet, stacker: Wallet, - startBurnHt: number, period: number, amountUstx: bigint, unlockBurnHt: number, ) { this.operator = operator; this.stacker = stacker; - this.startBurnHt = startBurnHt; this.period = period; this.amountUstx = amountUstx; this.unlockBurnHt = unlockBurnHt; @@ -98,6 +94,8 @@ export class DelegateStackStxCommand implements PoxCommand { run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); + const burnBlockHeightCV = real.network.runSnippet("burn-block-height"); + const burnBlockHeight = Number(cvToValue(burnBlockHeightCV as ClarityValue)); // Act const delegateStackStx = real.network.callPublicFn( @@ -111,7 +109,7 @@ export class DelegateStackStxCommand implements PoxCommand { // (pox-addr { version: (buff 1), hashbytes: (buff 32) }) poxAddressToTuple(this.operator.btcAddress), // (start-burn-ht uint) - Cl.uint(this.startBurnHt), + Cl.uint(burnBlockHeight), // (lock-period uint) Cl.uint(this.period), ], @@ -120,7 +118,7 @@ export class DelegateStackStxCommand implements PoxCommand { const { result: rewardCycle } = real.network.callReadOnlyFn( "ST000000000000000000002AMW42H.pox-4", "burn-height-to-reward-cycle", - [Cl.uint(real.network.blockHeight)], + [Cl.uint(burnBlockHeight)], this.operator.stxAddress, ); assert(isClarityType(rewardCycle, ClarityType.UInt)); @@ -179,6 +177,6 @@ export class DelegateStackStxCommand implements PoxCommand { // 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-stx period ${this.period}`; + return `${this.operator.label} delegate-stack-stx stacker ${this.stacker.label} period ${this.period}`; } } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts index 2d23fcc73c..f0758b568f 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts @@ -77,6 +77,7 @@ export class RevokeDelegateStxCommand implements PoxCommand { wallet.delegatedTo = ""; wallet.delegatedUntilBurnHt = 0; wallet.delegatedMaxAmount = 0; + wallet.delegatedPoxAddress = ''; // Remove the Stacker from the Pool Operator's pool members list. const walletIndexInDelegatorsList = operatorWallet.poolMembers.indexOf( diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index aea6ee0c73..13d27a9c35 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -7,7 +7,8 @@ import { } from "./pox_CommandModel.ts"; import { Pox4SignatureTopic, poxAddressToTuple } from "@stacks/stacking"; import { assert, expect } from "vitest"; -import { Cl, ClarityType, isClarityType } from "@stacks/transactions"; +import { Cl, ClarityType, ClarityValue, cvToJSON, cvToValue, isClarityType } from "@stacks/transactions"; +import { currentCycle } from "./pox_Commands.ts"; /** * The `StackStxCommand` locks STX for stacking within PoX-4. This self-service @@ -26,7 +27,6 @@ export class StackStxCommand implements PoxCommand { readonly authId: number; readonly period: number; readonly margin: number; - readonly currentCycle: number; /** * Constructs a `StackStxCommand` to lock uSTX for stacking. @@ -42,13 +42,11 @@ export class StackStxCommand implements PoxCommand { authId: number, period: number, margin: number, - currentCycle: number, ) { this.wallet = wallet; this.authId = authId; this.period = period; this.margin = margin; - this.currentCycle = currentCycle; } check(model: Readonly): boolean { @@ -66,6 +64,9 @@ export class StackStxCommand implements PoxCommand { run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); + const burnBlockHeightCV = real.network.runSnippet("burn-block-height"); + const burnBlockHeight = Number(cvToValue(burnBlockHeightCV as ClarityValue)); + const currentRewCycle = currentCycle(real.network) // The maximum amount of uSTX that can be used (per tx) with this signer // key. For our tests, we will use the minimum amount of uSTX to be stacked @@ -80,7 +81,7 @@ export class StackStxCommand implements PoxCommand { // For `stack-stx` and `stack-extend`, this refers to the reward cycle // where the transaction is confirmed. For `stack-aggregation-commit`, // this refers to the reward cycle argument in that function. - rewardCycle: this.currentCycle, + rewardCycle: currentRewCycle, // For `stack-stx`, this refers to `lock-period`. For `stack-extend`, // this refers to `extend-count`. For `stack-aggregation-commit`, this is // `u1`. @@ -112,7 +113,7 @@ export class StackStxCommand implements PoxCommand { // (pox-addr (tuple (version (buff 1)) (hashbytes (buff 32)))) poxAddressToTuple(this.wallet.btcAddress), // (start-burn-ht uint) - Cl.uint(real.network.blockHeight), + Cl.uint(burnBlockHeight), // (lock-period uint) Cl.uint(this.period), // (signer-sig (optional (buff 65))) @@ -182,6 +183,6 @@ export class StackStxCommand implements PoxCommand { // 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.wallet.label} stack-stx auth-id ${this.authId} and period ${this.period} during reward cycle ${this.currentCycle}`; + return `${this.wallet.label} stack-stx auth-id ${this.authId} and period ${this.period}`; } } From 552648ca43a59e30a199e1cb4010bae470495f38 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Tue, 16 Apr 2024 18:42:26 +0300 Subject: [PATCH 117/129] chore(pox-4-tests): Remove unused dependency `cvToJSON` --- contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index 13d27a9c35..41bd32708c 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -7,7 +7,7 @@ import { } from "./pox_CommandModel.ts"; import { Pox4SignatureTopic, poxAddressToTuple } from "@stacks/stacking"; import { assert, expect } from "vitest"; -import { Cl, ClarityType, ClarityValue, cvToJSON, cvToValue, isClarityType } from "@stacks/transactions"; +import { Cl, ClarityType, ClarityValue, cvToValue, isClarityType } from "@stacks/transactions"; import { currentCycle } from "./pox_Commands.ts"; /** From 1c0206bb6ca07806b2dd8907b66371d72a3a5ab0 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Tue, 16 Apr 2024 18:50:11 +0300 Subject: [PATCH 118/129] fix(pox-4-tests): Fix `StackAggregationCommitX` This commit fixes the way the current cycle is calculated. --- .../tests/pox-4/pox_Commands.ts | 12 ------------ .../pox_StackAggregationCommitAuthCommand.ts | 15 +++++---------- ...tackAggregationCommitIndexedAuthCommand.ts | 19 +++++++++---------- ...StackAggregationCommitIndexedSigCommand.ts | 19 +++++++++---------- .../pox_StackAggregationCommitSigCommand.ts | 15 +++++---------- 5 files changed, 28 insertions(+), 52 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 8a0cd389da..43f00ca387 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -82,72 +82,60 @@ export function PoxCommands( fc.record({ wallet: fc.constantFrom(...wallets.values()), authId: fc.nat(), - currentCycle: fc.constant(currentCycle(network)), }).map(( r: { wallet: Wallet; authId: number; - currentCycle: number; }, ) => new StackAggregationCommitAuthCommand( r.wallet, r.authId, - r.currentCycle, ) ), // StackAggregationCommitSigCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), authId: fc.nat(), - currentCycle: fc.constant(currentCycle(network)), }).map(( r: { wallet: Wallet; authId: number; - currentCycle: number; }, ) => new StackAggregationCommitSigCommand( r.wallet, r.authId, - r.currentCycle, ) ), // StackAggregationCommitIndexedAuthCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), authId: fc.nat(), - currentCycle: fc.constant(currentCycle(network)), }).map(( r: { wallet: Wallet; authId: number; - currentCycle: number; }, ) => new StackAggregationCommitIndexedAuthCommand( r.wallet, r.authId, - r.currentCycle, ) ), // StackAggregationCommitIndexedSigCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), authId: fc.nat(), - currentCycle: fc.constant(currentCycle(network)), }).map(( r: { wallet: Wallet; authId: number; - currentCycle: number; }, ) => new StackAggregationCommitIndexedSigCommand( r.wallet, r.authId, - r.currentCycle, ) ), // StackAggregationIncreaseCommand diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts index 35c9d35e11..03c4d5182a 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts @@ -8,6 +8,7 @@ import { import { poxAddressToTuple } from "@stacks/stacking"; import { expect } from "vitest"; import { Cl } from "@stacks/transactions"; +import { currentCycle } from "./pox_Commands.ts"; /** * The `StackAggregationCommitAuthCommand` allows an operator to commit @@ -27,23 +28,19 @@ import { Cl } from "@stacks/transactions"; export class StackAggregationCommitAuthCommand implements PoxCommand { readonly operator: Wallet; readonly authId: number; - readonly currentCycle: number; /** * Constructs a `StackAggregationCommitAuthCommand` to lock uSTX for stacking. * * @param operator - Represents the `Operator`'s wallet. * @param authId - Unique `auth-id` for the authorization. - * @param currentCycle - The current reward cycle. */ constructor( operator: Wallet, authId: number, - currentCycle: number, ) { this.operator = operator; this.authId = authId; - this.currentCycle = currentCycle; } check(model: Readonly): boolean { @@ -59,7 +56,7 @@ export class StackAggregationCommitAuthCommand implements PoxCommand { run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); - + const currentRewCycle = currentCycle(real.network); const operatorWallet = model.stackers.get(this.operator.stxAddress)!; const committedAmount = operatorWallet.amountToCommit; @@ -72,7 +69,7 @@ export class StackAggregationCommitAuthCommand implements PoxCommand { // (period uint) Cl.uint(1), // (reward-cycle uint) - Cl.uint(this.currentCycle + 1), + Cl.uint(currentRewCycle + 1), // (topic (string-ascii 14)) Cl.stringAscii("agg-commit"), // (signer-key (buff 33)) @@ -96,7 +93,7 @@ export class StackAggregationCommitAuthCommand implements PoxCommand { // (pox-addr (tuple (version (buff 1)) (hashbytes (buff 32)))) poxAddressToTuple(this.operator.btcAddress), // (reward-cycle uint) - Cl.uint(this.currentCycle + 1), + Cl.uint(currentRewCycle + 1), // (signer-sig (optional (buff 65))) Cl.none(), // (signer-key (buff 33)) @@ -134,8 +131,6 @@ export class StackAggregationCommitAuthCommand implements PoxCommand { // 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 + 1 - }`; + return `${this.operator.label} stack-aggregation-commit auth-id ${this.authId}`; } } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts index 9ac5bf715f..8a7249f7df 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts @@ -8,6 +8,7 @@ import { import { poxAddressToTuple } from "@stacks/stacking"; import { expect } from "vitest"; import { Cl } from "@stacks/transactions"; +import { currentCycle } from "./pox_Commands.ts"; /** * The `StackAggregationCommitIndexedAuthCommand` allows an operator to @@ -29,7 +30,6 @@ import { Cl } from "@stacks/transactions"; export class StackAggregationCommitIndexedAuthCommand implements PoxCommand { readonly operator: Wallet; readonly authId: number; - readonly currentCycle: number; /** * Constructs a `StackAggregationCommitIndexedAuthCommand` to lock uSTX @@ -37,12 +37,13 @@ export class StackAggregationCommitIndexedAuthCommand implements PoxCommand { * * @param operator - Represents the `Operator`'s wallet. * @param authId - Unique `auth-id` for the authorization. - * @param currentCycle - The current reward cycle. */ - constructor(operator: Wallet, authId: number, currentCycle: number) { + constructor( + operator: Wallet, + authId: number, + ) { this.operator = operator; this.authId = authId; - this.currentCycle = currentCycle; } check(model: Readonly): boolean { @@ -60,7 +61,7 @@ export class StackAggregationCommitIndexedAuthCommand implements PoxCommand { run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); - + const currentRewCycle = currentCycle(real.network); const operatorWallet = model.stackers.get(this.operator.stxAddress)!; const committedAmount = operatorWallet.amountToCommit; @@ -73,7 +74,7 @@ export class StackAggregationCommitIndexedAuthCommand implements PoxCommand { // (period uint) Cl.uint(1), // (reward-cycle uint) - Cl.uint(this.currentCycle + 1), + Cl.uint(currentRewCycle + 1), // (topic (string-ascii 14)) Cl.stringAscii("agg-commit"), // (signer-key (buff 33)) @@ -97,7 +98,7 @@ export class StackAggregationCommitIndexedAuthCommand implements PoxCommand { // (pox-addr (tuple (version (buff 1)) (hashbytes (buff 32)))) poxAddressToTuple(this.operator.btcAddress), // (reward-cycle uint) - Cl.uint(this.currentCycle + 1), + Cl.uint(currentRewCycle + 1), // (signer-sig (optional (buff 65))) Cl.none(), // (signer-key (buff 33)) @@ -138,8 +139,6 @@ export class StackAggregationCommitIndexedAuthCommand implements PoxCommand { // 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 + 1 - }`; + return `${this.operator.label} stack-aggregation-commit-indexed auth-id ${this.authId}`; } } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts index 36e02151b1..2b2b792458 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts @@ -9,6 +9,7 @@ import { Pox4SignatureTopic, poxAddressToTuple } from "@stacks/stacking"; import { expect } from "vitest"; import { Cl } from "@stacks/transactions"; import { bufferFromHex } from "@stacks/transactions/dist/cl"; +import { currentCycle } from "./pox_Commands.ts"; /** * The `StackAggregationCommitIndexedSigCommand` allows an operator to @@ -30,7 +31,6 @@ import { bufferFromHex } from "@stacks/transactions/dist/cl"; export class StackAggregationCommitIndexedSigCommand implements PoxCommand { readonly operator: Wallet; readonly authId: number; - readonly currentCycle: number; /** * Constructs a `StackAggregationCommitIndexedSigCommand` to lock uSTX @@ -38,12 +38,13 @@ export class StackAggregationCommitIndexedSigCommand implements PoxCommand { * * @param operator - Represents the `Operator`'s wallet. * @param authId - Unique `auth-id` for the authorization. - * @param currentCycle - The current reward cycle. */ - constructor(operator: Wallet, authId: number, currentCycle: number) { + constructor( + operator: Wallet, + authId: number, + ) { this.operator = operator; this.authId = authId; - this.currentCycle = currentCycle; } check(model: Readonly): boolean { @@ -61,7 +62,7 @@ export class StackAggregationCommitIndexedSigCommand implements PoxCommand { run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); - + const currentRewCycle = currentCycle(real.network); const operatorWallet = model.stackers.get(this.operator.stxAddress)!; const committedAmount = operatorWallet.amountToCommit; @@ -72,7 +73,7 @@ export class StackAggregationCommitIndexedSigCommand implements PoxCommand { // For stack-stx and stack-extend, this refers to the reward cycle // where the transaction is confirmed. For stack-aggregation-commit, // this refers to the reward cycle argument in that function. - rewardCycle: this.currentCycle + 1, + rewardCycle: currentRewCycle + 1, // For stack-stx, this refers to lock-period. For stack-extend, // this refers to extend-count. For stack-aggregation-commit, this is // u1. @@ -97,7 +98,7 @@ export class StackAggregationCommitIndexedSigCommand implements PoxCommand { // (pox-addr (tuple (version (buff 1)) (hashbytes (buff 32)))) poxAddressToTuple(this.operator.btcAddress), // (reward-cycle uint) - Cl.uint(this.currentCycle + 1), + Cl.uint(currentRewCycle + 1), // (signer-sig (optional (buff 65))) Cl.some(bufferFromHex(signerSig)), // (signer-key (buff 33)) @@ -138,8 +139,6 @@ export class StackAggregationCommitIndexedSigCommand implements PoxCommand { // 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 + 1 - }`; + return `${this.operator.label} stack-aggregation-commit-indexed auth-id ${this.authId}`; } } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts index d11672aecc..f8d9c7bd6a 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts @@ -9,6 +9,7 @@ import { Pox4SignatureTopic, poxAddressToTuple } from "@stacks/stacking"; import { expect } from "vitest"; import { Cl } from "@stacks/transactions"; import { bufferFromHex } from "@stacks/transactions/dist/cl"; +import { currentCycle } from "./pox_Commands.ts"; /** * The `StackAggregationCommitSigCommand` allows an operator to commit @@ -28,23 +29,19 @@ import { bufferFromHex } from "@stacks/transactions/dist/cl"; export class StackAggregationCommitSigCommand implements PoxCommand { readonly operator: Wallet; readonly authId: number; - readonly currentCycle: number; /** * Constructs a `StackAggregationCommitSigCommand` to lock uSTX for stacking. * * @param operator - Represents the `Operator`'s wallet. * @param authId - Unique `auth-id` for the authorization. - * @param currentCycle - The current reward cycle. */ constructor( operator: Wallet, authId: number, - currentCycle: number, ) { this.operator = operator; this.authId = authId; - this.currentCycle = currentCycle; } check(model: Readonly): boolean { @@ -60,7 +57,7 @@ export class StackAggregationCommitSigCommand implements PoxCommand { run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); - + const currentRewCycle = currentCycle(real.network); const operatorWallet = model.stackers.get(this.operator.stxAddress)!; const committedAmount = operatorWallet.amountToCommit; @@ -71,7 +68,7 @@ export class StackAggregationCommitSigCommand implements PoxCommand { // For stack-stx and stack-extend, this refers to the reward cycle // where the transaction is confirmed. For stack-aggregation-commit, // this refers to the reward cycle argument in that function. - rewardCycle: this.currentCycle + 1, + rewardCycle: currentRewCycle + 1, // For stack-stx, this refers to lock-period. For stack-extend, // this refers to extend-count. For stack-aggregation-commit, this is // u1. @@ -96,7 +93,7 @@ export class StackAggregationCommitSigCommand implements PoxCommand { // (pox-addr (tuple (version (buff 1)) (hashbytes (buff 32)))) poxAddressToTuple(this.operator.btcAddress), // (reward-cycle uint) - Cl.uint(this.currentCycle + 1), + Cl.uint(currentRewCycle + 1), // (signer-sig (optional (buff 65))) Cl.some(bufferFromHex(signerSig)), // (signer-key (buff 33)) @@ -134,8 +131,6 @@ export class StackAggregationCommitSigCommand implements PoxCommand { // 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 + 1 - }`; + return `${this.operator.label} stack-aggregation-commit auth-id ${this.authId}`; } } From 5a8c01712e1e6b5d9f9904364df5297c73bc4db5 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Tue, 16 Apr 2024 19:02:26 +0300 Subject: [PATCH 119/129] fix(pox-4-tests): Fix `StackAggregationIncrease` reward cycle calculation --- .../tests/pox-4/pox_Commands.ts | 3 --- .../pox_StackAggregationIncreaseCommand.ts | 19 ++++++++----------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 43f00ca387..57c87c4d70 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -141,7 +141,6 @@ export function PoxCommands( // StackAggregationIncreaseCommand fc.record({ wallet: fc.constantFrom(...wallets.values()), - currentCycle: fc.constant(currentCycle(network)), authId: fc.nat(), }).chain((r) => { const operator = stackers.get(r.wallet.stxAddress)! @@ -157,14 +156,12 @@ export function PoxCommands( }).map(( r: { wallet: Wallet; - currentCycle: number; rewardCycleIndex: number; authId: number; }, ) => new StackAggregationIncreaseCommand( r.wallet, - r.currentCycle, r.rewardCycleIndex, r.authId, ) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts index 2a5ba81cbd..4c2c93ccdd 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts @@ -9,6 +9,7 @@ import { Pox4SignatureTopic, poxAddressToTuple } from "@stacks/stacking"; import { expect } from "vitest"; import { Cl, cvToJSON } from "@stacks/transactions"; import { bufferFromHex } from "@stacks/transactions/dist/cl"; +import { currentCycle } from "./pox_Commands.ts"; /** * The `StackAggregationIncreaseCommand` allows an operator to commit @@ -27,7 +28,6 @@ import { bufferFromHex } from "@stacks/transactions/dist/cl"; */ export class StackAggregationIncreaseCommand implements PoxCommand { readonly operator: Wallet; - readonly currentCycle: number; readonly rewardCycleIndex: number; readonly authId: number; @@ -36,18 +36,15 @@ export class StackAggregationIncreaseCommand implements PoxCommand { * stacked STX to a PoX address which has already received some STX. * * @param operator - Represents the `Operator`'s wallet. - * @param currentCycle - The current reward cycle. * @param rewardCycleIndex - The cycle index to increase the commit for. * @param authId - Unique `auth-id` for the authorization. */ constructor( operator: Wallet, - currentCycle: number, rewardCycleIndex: number, authId: number, ) { this.operator = operator; - this.currentCycle = currentCycle; this.rewardCycleIndex = rewardCycleIndex; this.authId = authId; } @@ -57,7 +54,6 @@ export class StackAggregationIncreaseCommand implements PoxCommand { // - The Operator must have locked STX on behalf of at least one stacker. // - The PoX address must have partial committed STX. // - The Reward Cycle Index must be positive. - const operator = model.stackers.get(this.operator.stxAddress)!; return ( operator.lockedAddresses.length > 0 && @@ -68,6 +64,7 @@ export class StackAggregationIncreaseCommand implements PoxCommand { run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); + const currentRewCycle = currentCycle(real.network) const operatorWallet = model.stackers.get(this.operator.stxAddress)!; const committedAmount = operatorWallet.amountToCommit; @@ -77,7 +74,7 @@ export class StackAggregationIncreaseCommand implements PoxCommand { "reward-cycle-pox-address-list", Cl.tuple({ "index": Cl.uint(this.rewardCycleIndex), - "reward-cycle": Cl.uint(this.currentCycle + 1), + "reward-cycle": Cl.uint(currentRewCycle + 1), }), ); @@ -92,7 +89,7 @@ export class StackAggregationIncreaseCommand implements PoxCommand { // For stack-stx and stack-extend, this refers to the reward cycle // where the transaction is confirmed. For stack-aggregation-commit, // this refers to the reward cycle argument in that function. - rewardCycle: this.currentCycle + 1, + rewardCycle: currentRewCycle + 1, // For stack-stx, this refers to lock-period. For stack-extend, // this refers to extend-count. For stack-aggregation-commit, this is // u1. @@ -117,7 +114,7 @@ export class StackAggregationIncreaseCommand implements PoxCommand { // (pox-addr { version: (buff 1), hashbytes: (buff 32) }) poxAddressToTuple(this.operator.btcAddress), // (reward-cycle uint) - Cl.uint(this.currentCycle + 1), + Cl.uint(currentRewCycle + 1), // (reward-cycle-index uint)) Cl.uint(this.rewardCycleIndex), // (signer-sig (optional (buff 65))) @@ -131,6 +128,8 @@ export class StackAggregationIncreaseCommand implements PoxCommand { ], this.operator.stxAddress, ); + process.stdout.write(`stack-agg-increase result: ${JSON.stringify(cvToJSON(stackAggregationIncrease.result))}\n`) + // Assert expect(stackAggregationIncrease.result).toBeOk(Cl.bool(true)); @@ -156,8 +155,6 @@ export class StackAggregationIncreaseCommand implements PoxCommand { // 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-increase for reward cycle ${ - this.currentCycle + 1 - } index ${this.rewardCycleIndex}`; + return `${this.operator.label} stack-aggregation-increase for index ${this.rewardCycleIndex}`; } } From 4a3ca5ceb6b054e942275309dea06b03414a152e Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Tue, 16 Apr 2024 19:21:58 +0300 Subject: [PATCH 120/129] chore(pox-4-tests): Remove state update log --- contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index f094f8feca..7af5a69358 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -91,10 +91,6 @@ export class Stub { } wallet.committedRewCycleIndexes = []; }); - this.stackers.forEach((stacker) => - process.stdout.write(`${JSON.stringify(stacker)}\n`) - ); - this.lastRefreshedCycle = currentRewCycle; } } From 3089e8bfe11269870a86be1ef31c843bee7c86c0 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Tue, 16 Apr 2024 19:43:47 +0300 Subject: [PATCH 121/129] chore(pox-4-tests): Remove StackAggregationIncrease logging --- .../tests/pox-4/pox_StackAggregationIncreaseCommand.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts index 4c2c93ccdd..302b33f511 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts @@ -128,8 +128,6 @@ export class StackAggregationIncreaseCommand implements PoxCommand { ], this.operator.stxAddress, ); - process.stdout.write(`stack-agg-increase result: ${JSON.stringify(cvToJSON(stackAggregationIncrease.result))}\n`) - // Assert expect(stackAggregationIncrease.result).toBeOk(Cl.bool(true)); From a0d8352d3cf439d36d0b10c134c577637c326751 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Tue, 16 Apr 2024 19:45:27 +0300 Subject: [PATCH 122/129] chore(pox-4-tests): Add burn height logging --- contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 7af5a69358..e373be3523 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -53,6 +53,8 @@ export class Stub { const lastRefreshedCycle = this.lastRefreshedCycle; const currentRewCycle = Math.floor((Number(burnBlockHeight) - 0) / 1050); + process.stdout.write(`₿: ${(burnBlockHeight).toString().padStart(6, ' ')} `) + if (lastRefreshedCycle < currentRewCycle) { this.nextRewardSetIndex = 0; From cc176006e7b94da029a6695b194d040efd7bf0ac Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Wed, 17 Apr 2024 09:35:03 +0200 Subject: [PATCH 123/129] chore(pox-4-tests): Format code and wrap comments at 79 chars --- .../tests/pox-4/pox_CommandModel.ts | 2 +- .../tests/pox-4/pox_Commands.ts | 13 ++++++++----- .../tests/pox-4/pox_DelegateStackExtendCommand.ts | 3 ++- .../tests/pox-4/pox_DelegateStackStxCommand.ts | 12 ++++++++++-- .../tests/pox-4/pox_RevokeDelegateStxCommand.ts | 4 ++-- .../pox-4/pox_StackAggregationIncreaseCommand.ts | 2 +- .../tests/pox-4/pox_StackStxCommand.ts | 14 +++++++++++--- 7 files changed, 35 insertions(+), 15 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index e373be3523..5f6b953dba 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -53,7 +53,7 @@ export class Stub { const lastRefreshedCycle = this.lastRefreshedCycle; const currentRewCycle = Math.floor((Number(burnBlockHeight) - 0) / 1050); - process.stdout.write(`₿: ${(burnBlockHeight).toString().padStart(6, ' ')} `) + process.stdout.write(`₿: ${burnBlockHeight.toString().padStart(6, " ")} `); if (lastRefreshedCycle < currentRewCycle) { this.nextRewardSetIndex = 0; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 57c87c4d70..4767f91b70 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -143,7 +143,7 @@ export function PoxCommands( wallet: fc.constantFrom(...wallets.values()), authId: fc.nat(), }).chain((r) => { - const operator = stackers.get(r.wallet.stxAddress)! + const operator = stackers.get(r.wallet.stxAddress)!; const committedRewCycleIndexesOrFallback = operator.committedRewCycleIndexes.length > 0 ? operator.committedRewCycleIndexes @@ -187,7 +187,7 @@ export function PoxCommands( }), period: fc.integer({ min: 1, max: 12 }), }).chain((r) => { - const operator = stackers.get(r.operator.stxAddress)! + const operator = stackers.get(r.operator.stxAddress)!; // Determine available stackers based on the operator const availableStackers = operator.poolMembers.length > 0 ? operator.poolMembers @@ -212,7 +212,10 @@ export function PoxCommands( return fc.record({ amount: fc.bigInt({ min: 0n, - max: BigInt(stackers.get(resultWithUnlockHeight.stacker.stxAddress)!.delegatedMaxAmount), + max: BigInt( + stackers.get(resultWithUnlockHeight.stacker.stxAddress)! + .delegatedMaxAmount, + ), }), }).map((amountProps) => ({ ...resultWithUnlockHeight, @@ -234,7 +237,7 @@ export function PoxCommands( increaseBy: fc.nat(), }) .chain((r) => { - const operator = stackers.get(r.operator.stxAddress)! + const operator = stackers.get(r.operator.stxAddress)!; const delegatorsList = operator.poolMembers; const availableStackers = delegatorsList.filter((delegator) => { @@ -267,7 +270,7 @@ export function PoxCommands( operator: fc.constantFrom(...wallets.values()), extendCount: fc.integer({ min: 1, max: 11 }), }).chain((r) => { - const operator = stackers.get(r.operator.stxAddress)! + const operator = stackers.get(r.operator.stxAddress)!; const delegatorsList = operator.poolMembers; const availableStackers = delegatorsList.filter((delegator) => { const delegatorWallet = stackers.get(delegator)!; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts index 2a0e5808a2..135290b85f 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts @@ -73,7 +73,8 @@ export class DelegateStackExtendCommand implements PoxCommand { ); const lastExtendCycle = firstExtendCycle + this.extendCount - 1; const totalPeriod = lastExtendCycle - firstRewardCycle + 1; - const newUnlockHeight = (REWARD_CYCLE_LENGTH * (firstRewardCycle + totalPeriod - 1) + 0); + const newUnlockHeight = + REWARD_CYCLE_LENGTH * (firstRewardCycle + totalPeriod - 1) + 0; const stackedAmount = stackerWallet.amountLocked; return ( diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index acc29cf898..72126aea62 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -7,7 +7,13 @@ import { } from "./pox_CommandModel.ts"; import { poxAddressToTuple } from "@stacks/stacking"; import { assert, expect } from "vitest"; -import { Cl, ClarityType, ClarityValue, cvToValue, isClarityType } from "@stacks/transactions"; +import { + Cl, + ClarityType, + ClarityValue, + cvToValue, + isClarityType, +} from "@stacks/transactions"; import { currentCycle } from "./pox_Commands.ts"; /** @@ -95,7 +101,9 @@ export class DelegateStackStxCommand implements PoxCommand { run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); const burnBlockHeightCV = real.network.runSnippet("burn-block-height"); - const burnBlockHeight = Number(cvToValue(burnBlockHeightCV as ClarityValue)); + const burnBlockHeight = Number( + cvToValue(burnBlockHeightCV as ClarityValue), + ); // Act const delegateStackStx = real.network.callPublicFn( diff --git a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts index f0758b568f..f7cac6b74a 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts @@ -58,7 +58,7 @@ export class RevokeDelegateStxCommand implements PoxCommand { tupleCV({ "amount-ustx": Cl.uint(wallet.delegatedMaxAmount), "delegated-to": Cl.principal( - model.stackers.get(this.wallet.stxAddress)!.delegatedTo /*operatorWallet.stxAddress*/ || "", + model.stackers.get(this.wallet.stxAddress)!.delegatedTo || "", ), "pox-addr": Cl.some( poxAddressToTuple(wallet.delegatedPoxAddress || ""), @@ -77,7 +77,7 @@ export class RevokeDelegateStxCommand implements PoxCommand { wallet.delegatedTo = ""; wallet.delegatedUntilBurnHt = 0; wallet.delegatedMaxAmount = 0; - wallet.delegatedPoxAddress = ''; + wallet.delegatedPoxAddress = ""; // Remove the Stacker from the Pool Operator's pool members list. const walletIndexInDelegatorsList = operatorWallet.poolMembers.indexOf( diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts index 302b33f511..11b2927ceb 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts @@ -64,7 +64,7 @@ export class StackAggregationIncreaseCommand implements PoxCommand { run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); - const currentRewCycle = currentCycle(real.network) + const currentRewCycle = currentCycle(real.network); const operatorWallet = model.stackers.get(this.operator.stxAddress)!; const committedAmount = operatorWallet.amountToCommit; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index 41bd32708c..5f9a007f5c 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -7,7 +7,13 @@ import { } from "./pox_CommandModel.ts"; import { Pox4SignatureTopic, poxAddressToTuple } from "@stacks/stacking"; import { assert, expect } from "vitest"; -import { Cl, ClarityType, ClarityValue, cvToValue, isClarityType } from "@stacks/transactions"; +import { + Cl, + ClarityType, + ClarityValue, + cvToValue, + isClarityType, +} from "@stacks/transactions"; import { currentCycle } from "./pox_Commands.ts"; /** @@ -65,8 +71,10 @@ export class StackStxCommand implements PoxCommand { run(model: Stub, real: Real): void { model.trackCommandRun(this.constructor.name); const burnBlockHeightCV = real.network.runSnippet("burn-block-height"); - const burnBlockHeight = Number(cvToValue(burnBlockHeightCV as ClarityValue)); - const currentRewCycle = currentCycle(real.network) + const burnBlockHeight = Number( + cvToValue(burnBlockHeightCV as ClarityValue), + ); + const currentRewCycle = currentCycle(real.network); // The maximum amount of uSTX that can be used (per tx) with this signer // key. For our tests, we will use the minimum amount of uSTX to be stacked From 742dbf504e2070f05535f88aa2e906c92e1e1224 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Wed, 17 Apr 2024 10:11:05 +0200 Subject: [PATCH 124/129] feat(pox-4-tests): Pretty-print burn block height in each command --- .../pox-4/pox_AllowContractCallerCommand.ts | 1 + .../tests/pox-4/pox_CommandModel.ts | 20 ++++++++++++++----- .../pox-4/pox_DelegateStackExtendCommand.ts | 1 + .../pox-4/pox_DelegateStackIncreaseCommand.ts | 1 + .../pox-4/pox_DelegateStackStxCommand.ts | 1 + .../tests/pox-4/pox_DelegateStxCommand.ts | 1 + .../pox_DisallowContractCallerCommand.ts | 1 + .../pox-4/pox_GetStackingMinimumCommand.ts | 1 + .../tests/pox-4/pox_GetStxAccountCommand.ts | 1 + .../pox-4/pox_RevokeDelegateStxCommand.ts | 6 +++++- .../pox_StackAggregationCommitAuthCommand.ts | 1 + ...tackAggregationCommitIndexedAuthCommand.ts | 1 + ...StackAggregationCommitIndexedSigCommand.ts | 1 + .../pox_StackAggregationCommitSigCommand.ts | 1 + .../pox_StackAggregationIncreaseCommand.ts | 1 + .../tests/pox-4/pox_StackStxCommand.ts | 1 + 16 files changed, 34 insertions(+), 6 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts index de2db628de..f3168e7ecf 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts @@ -83,6 +83,7 @@ export class AllowContractCallerCommand 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( + `₿ ${model.burnBlockHeight}`, `✓ ${this.wallet.label}`, "allow-contract-caller", this.allowanceTo.label, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 5f6b953dba..cbaeb5ab76 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -19,6 +19,7 @@ export class Stub { stackingMinimum: number; nextRewardSetIndex: number; lastRefreshedCycle: number; + burnBlockHeight: number; constructor( wallets: Map, @@ -31,6 +32,7 @@ export class Stub { this.stackingMinimum = 0; this.nextRewardSetIndex = 0; this.lastRefreshedCycle = 0; + this.burnBlockHeight = 0; } trackCommandRun(commandName: string) { @@ -53,7 +55,10 @@ export class Stub { const lastRefreshedCycle = this.lastRefreshedCycle; const currentRewCycle = Math.floor((Number(burnBlockHeight) - 0) / 1050); - process.stdout.write(`₿: ${burnBlockHeight.toString().padStart(6, " ")} `); + // The `this.burnBlockHeight` instance member is used for logging purposes. + // However, it's not used in the actual implementation of the model and all + // usages below use the `burnBlockHeight` local variable. + this.burnBlockHeight = burnBlockHeight; if (lastRefreshedCycle < currentRewCycle) { this.nextRewardSetIndex = 0; @@ -136,10 +141,15 @@ export type PoxCommand = fc.Command; export const logCommand = (...items: (string | undefined)[]) => { // Ensure we only render up to the first 10 items for brevity. const renderItems = items.slice(0, 10); - const columnWidth = 23; - // Pad each column to the same width. - const prettyPrint = renderItems.map((content) => - content ? content.padEnd(columnWidth) : "".padEnd(columnWidth) + const columnWidth = 23; // Standard width for each column after the first two. + const halfColumns = Math.floor(columnWidth / 2); + + // Pad columns to their widths: half for the first two, full for the rest. + const prettyPrint = renderItems.map((content, index) => + // Check if the index is less than 2 (i.e., first two items). + content + ? (index < 2 ? content.padEnd(halfColumns) : content.padEnd(columnWidth)) + : (index < 2 ? "".padEnd(halfColumns) : "".padEnd(columnWidth)) ); prettyPrint.push("\n"); diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts index 135290b85f..a699cd2006 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts @@ -145,6 +145,7 @@ export class DelegateStackExtendCommand 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( + `₿ ${model.burnBlockHeight}`, `✓ ${this.operator.label} Ӿ ${this.stacker.label}`, "delegate-stack-extend", "extend count", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts index 88d43cc1d9..b9ec4a837c 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackIncreaseCommand.ts @@ -114,6 +114,7 @@ export class DelegateStackIncreaseCommand 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( + `₿ ${model.burnBlockHeight}`, `✓ ${this.operator.label} Ӿ ${this.stacker.label}`, "delegate-stack-increase", "increased by", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts index 72126aea62..456983807f 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackStxCommand.ts @@ -169,6 +169,7 @@ export class DelegateStackStxCommand 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( + `₿ ${model.burnBlockHeight}`, `✓ ${this.operator.label} Ӿ ${this.stacker.label}`, "delegate-stack-stx", "lock-amount", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts index 73285d4033..4a12b0140d 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStxCommand.ts @@ -100,6 +100,7 @@ export class DelegateStxCommand 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( + `₿ ${model.burnBlockHeight}`, `✓ ${this.wallet.label}`, "delegate-stx", "amount", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts index effc4de88b..09618db49c 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DisallowContractCallerCommand.ts @@ -89,6 +89,7 @@ export class DisallowContractCallerCommand 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( + `₿ ${model.burnBlockHeight}`, `✓ ${this.stacker.label}`, "disallow-contract-caller", this.callerToDisallow.label, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts index de58fd678a..50dd7bf16c 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStackingMinimumCommand.ts @@ -50,6 +50,7 @@ export class GetStackingMinimumCommand 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( + `₿ ${model.burnBlockHeight}`, `✓ ${this.wallet.label}`, "get-stacking-minimum", "pox-4", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts index 744e903090..60d8ff38b2 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_GetStxAccountCommand.ts @@ -48,6 +48,7 @@ export class GetStxAccountCommand 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( + `₿ ${model.burnBlockHeight}`, `✓ ${this.wallet.label}`, "stx-account", "lock-amount", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts index f7cac6b74a..1c30e3d569 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_RevokeDelegateStxCommand.ts @@ -88,7 +88,11 @@ 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"); + logCommand( + `₿ ${model.burnBlockHeight}`, + `✓ ${this.wallet.label}`, + "revoke-delegate-stx", + ); // Refresh the model's state if the network gets to the next reward cycle. model.refreshStateForNextRewardCycle(real); diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts index 03c4d5182a..5312679833 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitAuthCommand.ts @@ -116,6 +116,7 @@ export class StackAggregationCommitAuthCommand 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( + `₿ ${model.burnBlockHeight}`, `✓ ${this.operator.label}`, "stack-agg-commit", "amount committed", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts index 8a7249f7df..dfe7f2beef 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedAuthCommand.ts @@ -124,6 +124,7 @@ export class StackAggregationCommitIndexedAuthCommand 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( + `₿ ${model.burnBlockHeight}`, `✓ ${this.operator.label}`, "stack-agg-commit-indexed", "amount committed", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts index 2b2b792458..59707e21f4 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitIndexedSigCommand.ts @@ -124,6 +124,7 @@ export class StackAggregationCommitIndexedSigCommand 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( + `₿ ${model.burnBlockHeight}`, `✓ ${this.operator.label}`, "stack-agg-commit-indexed", "amount committed", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts index f8d9c7bd6a..32fe552477 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationCommitSigCommand.ts @@ -116,6 +116,7 @@ export class StackAggregationCommitSigCommand 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( + `₿ ${model.burnBlockHeight}`, `✓ ${this.operator.label}`, "stack-agg-commit", "amount committed", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts index 11b2927ceb..22ae0a0bea 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackAggregationIncreaseCommand.ts @@ -137,6 +137,7 @@ export class StackAggregationIncreaseCommand 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( + `₿ ${model.burnBlockHeight}`, `✓ ${this.operator.label}`, "stack-agg-increase", "amount committed", diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index 5f9a007f5c..0b6b6189e2 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -177,6 +177,7 @@ export class StackStxCommand 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( + `₿ ${model.burnBlockHeight}`, `✓ ${this.wallet.label}`, "stack-stx", "lock-amount", From 9945c5eba226a38b618f5e747e99bde53b4602b2 Mon Sep 17 00:00:00 2001 From: Nikos Baxevanis Date: Wed, 17 Apr 2024 10:17:11 +0200 Subject: [PATCH 125/129] fix(pox-4-tests): Set fast-check command size to 'small' from 'xsmall' --- contrib/core-contract-tests/tests/pox-4/pox_Commands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 4767f91b70..3e40da46ae 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -349,7 +349,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 fc.commands(cmds, { size: "small" }); } export const REWARD_CYCLE_LENGTH = 1050; From ab837a1739c375f84d77ee6893c6ef4eb72655ec Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Thu, 18 Apr 2024 18:17:30 +0300 Subject: [PATCH 126/129] fix(pox-4-tests): Refine refresh command, fix state simulation issues --- .../tests/pox-4/pox-4.stateful-prop.test.ts | 1 + .../tests/pox-4/pox_CommandModel.ts | 55 +++++++++++++++++-- .../tests/pox-4/pox_Commands.ts | 2 +- .../tests/pox-4/pox_StackStxCommand.ts | 1 + 4 files changed, 54 insertions(+), 5 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts index ba99ea2d49..15f4d4ddc0 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox-4.stateful-prop.test.ts @@ -117,6 +117,7 @@ it("statefully interacts with PoX-4", async () => { new Map(wallets.map((wallet) => [wallet.stxAddress, { ustxBalance: 100_000_000_000_000, isStacking: false, + isStackingSolo: false, hasDelegated: false, lockedAddresses: [], amountToCommit: 0, diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index cbaeb5ab76..915acf319e 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -64,37 +64,83 @@ export class Stub { this.nextRewardSetIndex = 0; this.wallets.forEach((w) => { + let updatedAmountToCommit = 0; const wallet = this.stackers.get(w.stxAddress)!; + + // Get the wallet's ex-delegators by comparing their delegatedUntilBurnHt + // to the current burn block height (only if the wallet is a delegatee). const expiredDelegators = wallet.poolMembers.filter((stackerAddress) => this.stackers.get(stackerAddress)!.delegatedUntilBurnHt < - burnBlockHeight + 1 + burnBlockHeight + ); + + // Get the operator's pool stackers that no longer have partially commited + // STX for the next reward cycle by comparing their unlock height to + // the next reward cycle's first block (only if the wallet is an operator). + const stackersToRemoveAmountToCommit = wallet.lockedAddresses.filter(( + stackerAddress, + ) => + this.stackers.get(stackerAddress)!.unlockHeight <= + burnBlockHeight + 1050 ); + + // Get the operator's ex-pool stackers by comparing their unlockHeight to + // the current burn block height (only if the wallet is an operator). const expiredStackers = wallet.lockedAddresses.filter( (stackerAddress) => this.stackers.get(stackerAddress)!.unlockHeight <= - burnBlockHeight + 1, + burnBlockHeight, ); + // For each remaining pool stacker (if any), increase the operator's + // amountToCommit (partial-stacked) for the next cycle by the + // stacker's amountLocked. + wallet.lockedAddresses.forEach((stacker) => { + const stackerWallet = this.stackers.get(stacker)!; + updatedAmountToCommit += stackerWallet?.amountLocked; + }); + + // Update the operator's amountToCommit (partial-stacked). + wallet.amountToCommit = updatedAmountToCommit; + + // Remove the expired delegators from the delegatee's poolMembers list. expiredDelegators.forEach((expDelegator) => { const expDelegatorIndex = wallet.poolMembers.indexOf(expDelegator); wallet.poolMembers.splice(expDelegatorIndex, 1); }); + // Remove the expired stackers from the operator's lockedAddresses list. expiredStackers.forEach((expStacker) => { - const expStackerWallet = this.stackers.get(expStacker)!; const expStackerIndex = wallet.lockedAddresses.indexOf(expStacker); wallet.lockedAddresses.splice(expStackerIndex, 1); + }); + + // For each pool stacker that no longer have partially commited STX for + // the next reward cycle, decrement the operator's amountToCommit + // (partial-stacked) by the stacker's amountLocked + stackersToRemoveAmountToCommit.forEach((expStacker) => { + const expStackerWallet = this.stackers.get(expStacker)!; wallet.amountToCommit -= expStackerWallet.amountLocked; }); + // Check the wallet's stack expiry and update the state accordingly. if ( - wallet.unlockHeight > 0 && wallet.unlockHeight <= burnBlockHeight + 1 + wallet.unlockHeight > 0 && wallet.unlockHeight <= burnBlockHeight ) { wallet.isStacking = false; + wallet.isStackingSolo = false; wallet.amountUnlocked += wallet.amountLocked; wallet.amountLocked = 0; wallet.unlockHeight = 0; wallet.firstLockedRewardCycle = 0; + } // If the wallet is solo stacking and its stack won't expire in the + // next reward cycle, increment the model's nextRewardSetIndex (the + // next empty reward slot) + else if ( + wallet.unlockHeight > 0 && + wallet.unlockHeight > burnBlockHeight + 1050 && wallet.isStackingSolo + ) { + this.nextRewardSetIndex++; } wallet.committedRewCycleIndexes = []; }); @@ -119,6 +165,7 @@ export type Wallet = { export type Stacker = { ustxBalance: number; isStacking: boolean; + isStackingSolo: boolean; hasDelegated: boolean; lockedAddresses: StxAddress[]; amountToCommit: number; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts index 3e40da46ae..4767f91b70 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_Commands.ts @@ -349,7 +349,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: "small" }); + return fc.commands(cmds, { size: "xsmall" }); } export const REWARD_CYCLE_LENGTH = 1050; diff --git a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts index 0b6b6189e2..9c8a467355 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_StackStxCommand.ts @@ -168,6 +168,7 @@ export class StackStxCommand implements PoxCommand { // in order to prevent the test from stacking multiple times with the same // address. wallet.isStacking = true; + wallet.isStackingSolo = true; // Update locked, unlocked, and unlock-height fields in the model. wallet.amountLocked = amountUstx; wallet.unlockHeight = Number(unlockBurnHeight.value); From d2c1eb74ddd89930ce3f83a6ac12924830cca384 Mon Sep 17 00:00:00 2001 From: BowTiedRadone <92028479+BowTiedRadone@users.noreply.github.com> Date: Fri, 19 Apr 2024 13:06:52 +0300 Subject: [PATCH 127/129] chore(pox-4-tests): Update comment Co-authored-by: Nikos Baxevanis --- contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 915acf319e..243b89a36e 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -117,7 +117,7 @@ export class Stub { // For each pool stacker that no longer have partially commited STX for // the next reward cycle, decrement the operator's amountToCommit - // (partial-stacked) by the stacker's amountLocked + // (partial-stacked) by the stacker's amountLocked. stackersToRemoveAmountToCommit.forEach((expStacker) => { const expStackerWallet = this.stackers.get(expStacker)!; wallet.amountToCommit -= expStackerWallet.amountLocked; From e33895fa78fd957d70654de49a9549872b783706 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Mon, 22 Apr 2024 16:19:13 +0300 Subject: [PATCH 128/129] fix(pox-4-tests): Update AllowContractCallerCommand to remove the wallet from ex-allowed's list --- .../pox-4/pox_AllowContractCallerCommand.ts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts index f3168e7ecf..dad1a381a5 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_AllowContractCallerCommand.ts @@ -74,6 +74,27 @@ export class AllowContractCallerCommand implements PoxCommand { // Get the wallets involved from the model and update it with the new state. const wallet = model.stackers.get(this.wallet.stxAddress)!; + const callerAllowedBefore = wallet.allowedContractCaller; + + const callerAllowedBeforeState = model.stackers.get(callerAllowedBefore) || + null; + + if (callerAllowedBeforeState) { + // Remove the allower from the ex-allowed caller's allowance list. + + const walletIndexInsideAllowedByList = callerAllowedBeforeState + .callerAllowedBy.indexOf( + this.wallet.stxAddress, + ); + + expect(walletIndexInsideAllowedByList).toBeGreaterThan(-1); + + callerAllowedBeforeState.callerAllowedBy.splice( + walletIndexInsideAllowedByList, + 1, + ); + } + const callerToAllow = model.stackers.get(this.allowanceTo.stxAddress)!; // Update model so that we know this wallet has authorized a contract-caller. From 5679afaca25ad3de9ef34e086812483830298580 Mon Sep 17 00:00:00 2001 From: BowTiedRadone Date: Mon, 22 Apr 2024 16:41:45 +0300 Subject: [PATCH 129/129] fix(pox-4-tests): Replace pox values `REWARD_CYCLE_LENGTH` and `FIRST_BURNCHAIN_BLOCK_HEIGHT` consts --- .../tests/pox-4/pox_CommandModel.ts | 14 +++++++++++--- .../tests/pox-4/pox_DelegateStackExtendCommand.ts | 3 ++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts index 243b89a36e..6d4d582b58 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_CommandModel.ts @@ -7,6 +7,10 @@ import { StacksPrivateKey, } from "@stacks/transactions"; import { StackingClient } from "@stacks/stacking"; +import { + FIRST_BURNCHAIN_BLOCK_HEIGHT, + REWARD_CYCLE_LENGTH, +} from "./pox_Commands"; export type StxAddress = string; export type BtcAddress = string; @@ -53,7 +57,10 @@ export class Stub { cvToValue(burnBlockHeightResult as ClarityValue), ); const lastRefreshedCycle = this.lastRefreshedCycle; - const currentRewCycle = Math.floor((Number(burnBlockHeight) - 0) / 1050); + const currentRewCycle = Math.floor( + (Number(burnBlockHeight) - FIRST_BURNCHAIN_BLOCK_HEIGHT) / + REWARD_CYCLE_LENGTH, + ); // The `this.burnBlockHeight` instance member is used for logging purposes. // However, it's not used in the actual implementation of the model and all @@ -81,7 +88,7 @@ export class Stub { stackerAddress, ) => this.stackers.get(stackerAddress)!.unlockHeight <= - burnBlockHeight + 1050 + burnBlockHeight + REWARD_CYCLE_LENGTH ); // Get the operator's ex-pool stackers by comparing their unlockHeight to @@ -138,7 +145,8 @@ export class Stub { // next empty reward slot) else if ( wallet.unlockHeight > 0 && - wallet.unlockHeight > burnBlockHeight + 1050 && wallet.isStackingSolo + wallet.unlockHeight > burnBlockHeight + REWARD_CYCLE_LENGTH && + wallet.isStackingSolo ) { this.nextRewardSetIndex++; } diff --git a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts index a699cd2006..cfd385cf5a 100644 --- a/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts +++ b/contrib/core-contract-tests/tests/pox-4/pox_DelegateStackExtendCommand.ts @@ -74,7 +74,8 @@ export class DelegateStackExtendCommand implements PoxCommand { const lastExtendCycle = firstExtendCycle + this.extendCount - 1; const totalPeriod = lastExtendCycle - firstRewardCycle + 1; const newUnlockHeight = - REWARD_CYCLE_LENGTH * (firstRewardCycle + totalPeriod - 1) + 0; + REWARD_CYCLE_LENGTH * (firstRewardCycle + totalPeriod - 1) + + FIRST_BURNCHAIN_BLOCK_HEIGHT; const stackedAmount = stackerWallet.amountLocked; return (