import { Chain, Observe } from "../src/test-case"; import { logger, nullifySigned, nullifyUnsigned, type ApiDeclarations } from "../src/utils"; // An unsigned solution scenario: // // When no staking-miner is running (and for simplicity the signed phase is also set to zero). We // expect an unsigned solution to successfullly proceed and submit a solution with `minerPages` out // of the total `pages`. export function commonUnsignedSteps( expectedValidatorSetCount: number, minerPages: number, pages: number, doNullifySigned: boolean, apis: ApiDeclarations ): Observe[] { return [ // first relay session change at block 11 Observe.on(Chain.Relay, "Session", "NewSession").byBlock(11), // by block 10 we will plan a new era Observe.on(Chain.Teyrchain, "Staking", "SessionRotated") .withDataCheck((x: any) => x.active_era == 0 && x.planned_era == 1) .onPass(() => { if (doNullifySigned) { nullifySigned(apis.paraApi).then((ok) => { logger.verbose("Nullified signed phase:", ok); }); } }), // eventually we will verify all pages ...Array.from({ length: minerPages }, (_, __) => { return Observe.on(Chain.Teyrchain, "MultiBlockElectionVerifier", "Verified"); }), // eventually it will be queued Observe.on(Chain.Teyrchain, "MultiBlockElectionVerifier", "Queued"), // eventually multiblock election will transition to `Done` Observe.on(Chain.Teyrchain, "MultiBlockElection", "PhaseTransitioned").withDataCheck( (x: any) => x.to.type === "Done" ), // eventually we will export all 4 pages to staking // export events. ...Array.from({ length: pages }, (_, __) => { return Observe.on(Chain.Teyrchain, "Staking", "PagedElectionProceeded"); }), // eventually multiblock goes back to `Off` Observe.on(Chain.Teyrchain, "MultiBlockElection", "PhaseTransitioned").withDataCheck( (x: any) => x.to.type === "Off" ), // eventually we will send it back to RC Observe.on(Chain.Relay, "StakingAhClient", "ValidatorSetReceived").withDataCheck( (x: any) => x.id === 1 && x.new_validator_set_count === expectedValidatorSetCount ), Observe.on(Chain.Relay, "Session", "NewQueued"), // eventually we will receive a session report back in AH with activation timestamp Observe.on(Chain.Teyrchain, "StakingRcClient", "SessionReportReceived").withDataCheck( (x) => x.activation_timestamp !== undefined ), // eventually we will have era paid (inflation) Observe.on(Chain.Teyrchain, "Staking", "EraPaid"), ].map((s) => s.build()); } // A signed solution scenario. // // This test expect you to call `spawnMiner` in the final test code. A full solution of `pages` is // expected to be submitted. export function commonSignedSteps( pages: number, expectedValidatorSetCount: number, apis: ApiDeclarations ): Observe[] { return [ // first relay session change at block 11 Observe.on(Chain.Relay, "Session", "NewSession").byBlock(11), // by block 10 we will plan a new era Observe.on(Chain.Teyrchain, "Staking", "SessionRotated") .withDataCheck((x: any) => x.active_era == 0 && x.planned_era == 1) .onPass(() => { nullifyUnsigned(apis.paraApi).then((ok) => { logger.verbose("Nullified unsigned phase:", ok); }); }), // Eventually a signed submission is registered... Observe.on(Chain.Teyrchain, "MultiBlockElectionSigned", "Registered"), // ... and exact number of pages are generated ...Array.from({ length: pages }, () => Observe.on(Chain.Teyrchain, "MultiBlockElectionSigned", "Stored") ), // ... and exact number of pages are verified ...Array.from({ length: pages }, () => Observe.on(Chain.Teyrchain, "MultiBlockElectionVerifier", "Verified") ), // eventually it will be queued Observe.on(Chain.Teyrchain, "MultiBlockElectionVerifier", "Queued"), // eventually the signed submitter is rewarded. // TODO: check rewarded account is Bob Observe.on(Chain.Teyrchain, "MultiBlockElectionSigned", "Rewarded"), // eventually multiblock election will transition to `Done` Observe.on(Chain.Teyrchain, "MultiBlockElection", "PhaseTransitioned").withDataCheck( (x: any) => x.to.type === "Done" ), // eventually we will export all pages. ...Array.from({ length: pages }, () => Observe.on(Chain.Teyrchain, "Staking", "PagedElectionProceeded") ), // eventually multiblock goes back to `Off` Observe.on(Chain.Teyrchain, "MultiBlockElection", "PhaseTransitioned").withDataCheck( (x: any) => x.to.type === "Off" ), // eventually we will send it back to RC Observe.on(Chain.Relay, "StakingAhClient", "ValidatorSetReceived").withDataCheck( (x: any) => x.id === 1 && x.new_validator_set_count === expectedValidatorSetCount ), Observe.on(Chain.Relay, "Session", "NewQueued"), // eventually we will receive a session report back in AH with activation timestamp Observe.on(Chain.Teyrchain, "StakingRcClient", "SessionReportReceived").withDataCheck( (x) => x.activation_timestamp !== undefined ), // eventually we will have era paid (inflation) Observe.on(Chain.Teyrchain, "Staking", "EraPaid"), ].map((s) => s.build()); }