Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More e2e Cleanups and Improvements #1756

Merged
merged 8 commits into from
Nov 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 22 additions & 21 deletions e2e/capacity/replenishment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
DOLLARS,
TokenPerCapacity,
assertEvent,
getRemainingCapacity,
getCapacity,
getNonce,
} from "../scaffolding/helpers";
import { getFundingSource } from "../scaffolding/funding";
Expand Down Expand Up @@ -48,26 +48,27 @@ describe("Capacity Replenishment Testing: ", function () {
const [stakeKeys, stakeProviderId] = await createAndStakeProvider("ReplFirst", totalStaked);
const payload = JSON.stringify({ changeType: 1, fromId: 1, objectId: 2 })
const call = ExtrinsicHelper.addOnChainMessage(stakeKeys, schemaId, payload);
let nonce = await getNonce(stakeKeys);

// confirm that we start with a full tank
await ExtrinsicHelper.runToBlock(await getNextEpochBlock());
let remainingCapacity = (await getRemainingCapacity(stakeProviderId)).toBigInt();
let remainingCapacity = (await getCapacity(stakeProviderId)).remainingCapacity.toBigInt();
assert.equal(expectedCapacity, remainingCapacity, "Our expected capacity from staking is wrong");

await call.payWithCapacity(-1);
remainingCapacity = (await getRemainingCapacity(stakeProviderId)).toBigInt();
await call.payWithCapacity(nonce++);
remainingCapacity = (await getCapacity(stakeProviderId)).remainingCapacity.toBigInt();
assert(expectedCapacity > remainingCapacity, "Our remaining capacity is much higher than expected.");
const capacityPerCall = expectedCapacity - remainingCapacity;
assert(remainingCapacity > capacityPerCall, "We don't have enough to make a second call");

// one more txn to deplete capacity more so this current remaining is different from when
// we submitted the first message.
await call.payWithCapacity(-1);
await call.payWithCapacity(nonce++);
await ExtrinsicHelper.runToBlock(await getNextEpochBlock());

// this should cause capacity to be refilled and then deducted by the cost of one message.
await call.payWithCapacity(-1);
let newRemainingCapacity = (await getRemainingCapacity(stakeProviderId)).toBigInt();
await call.payWithCapacity(nonce++);
const newRemainingCapacity = (await getCapacity(stakeProviderId)).remainingCapacity.toBigInt();

// this should be the same as after sending the first message, since it is the first message after
// the epoch.
Expand All @@ -87,7 +88,7 @@ describe("Capacity Replenishment Testing: ", function () {
let call = ExtrinsicHelper.addOnChainMessage(stakeKeys, schemaId, payload);

// run until we can't afford to send another message.
await drainCapacity(call, stakeProviderId, stakeKeys);
await drainCapacity(call, stakeProviderId);

await assert_capacity_call_fails_with_balance_too_low(call);
});
Expand All @@ -103,17 +104,17 @@ describe("Capacity Replenishment Testing: ", function () {
// new user/msa stakes to provider
const userKeys = createKeys("userKeys");
await fundKeypair(fundingSource, userKeys, 5n * DOLLARS);
const { eventMap } = await ExtrinsicHelper.stake(userKeys, stakeProviderId, userStakeAmt).fundAndSend(fundingSource);
const { eventMap } = await ExtrinsicHelper.stake(userKeys, stakeProviderId, userStakeAmt).signAndSend();
assertEvent(eventMap, 'system.ExtrinsicSuccess');

const payload = JSON.stringify({ changeType: 1, fromId: 1, objectId: 2 })
const call = ExtrinsicHelper.addOnChainMessage(stakeKeys, schemaId, payload);

let expectedCapacity = (providerStakeAmt + userStakeAmt) / TokenPerCapacity;
const totalCapacity = (await getRemainingCapacity(stakeProviderId)).toBigInt();
const totalCapacity = (await getCapacity(stakeProviderId)).totalCapacityIssued.toBigInt();
assert.equal(expectedCapacity, totalCapacity, `expected ${expectedCapacity} capacity, got ${totalCapacity}`);

const callCapacityCost = await drainCapacity(call, stakeProviderId, stakeKeys);
const callCapacityCost = await drainCapacity(call, stakeProviderId);

// ensure provider can't send a message; they are out of capacity
await assert_capacity_call_fails_with_balance_too_low(call);
Expand All @@ -122,37 +123,37 @@ describe("Capacity Replenishment Testing: ", function () {
let nextEpochBlock = await getNextEpochBlock();
await ExtrinsicHelper.runToBlock(nextEpochBlock);

let remainingCapacity = (await getRemainingCapacity(stakeProviderId)).toBigInt();
let remainingCapacity = (await getCapacity(stakeProviderId)).remainingCapacity.toBigInt();
// double check we still do not have enough to send another message
assert(remainingCapacity < callCapacityCost);

// user stakes tiny additional amount
const { eventMap: hasStaked } = await ExtrinsicHelper.stake(userKeys, stakeProviderId, userIncrementAmt).fundAndSend(fundingSource);
const { eventMap: hasStaked } = await ExtrinsicHelper.stake(userKeys, stakeProviderId, userIncrementAmt).signAndSend();
assertEvent(hasStaked, 'capacity.Staked');

// provider can now send a message
const { eventMap: hasCapacityWithdrawn } = await call.payWithCapacity(-1);
assertEvent(hasCapacityWithdrawn, 'capacity.CapacityWithdrawn');

remainingCapacity = (await getRemainingCapacity(stakeProviderId)).toBigInt();
remainingCapacity = (await getCapacity(stakeProviderId)).remainingCapacity.toBigInt();
// show that capacity was replenished and then fee deducted.
let approxExpected = providerStakeAmt + userStakeAmt + userIncrementAmt - callCapacityCost;
assert(remainingCapacity <= approxExpected, `remainingCapacity = ${remainingCapacity.toString()}`);
});
});
});

async function drainCapacity(call, stakeProviderId: u64, stakeKeys: KeyringPair): Promise<bigint> {
const totalCapacity = (await getRemainingCapacity(stakeProviderId)).toBigInt();
async function drainCapacity(call, stakeProviderId: u64): Promise<bigint> {
const totalCapacity = (await getCapacity(stakeProviderId)).totalCapacityIssued.toBigInt();
let nonce = await getNonce(call.keys);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, I didn't know you could do that.

// Figure out the cost per call in Capacity
await call.payWithCapacity(-1);
let remainingCapacity = (await getRemainingCapacity(stakeProviderId)).toBigInt();
const callCapacityCost = totalCapacity - remainingCapacity;
const { eventMap } = await call.payWithCapacity(nonce++);

// Run them out of funds, but don't flake just because it landed near an epoch boundary.
const callCapacityCost = eventMap["capacity.CapacityWithdrawn"].data.amount.toBigInt();

// // Run them out of funds, but don't flake just because it landed near an epoch boundary.
await ExtrinsicHelper.runToBlock(await getNextEpochBlock());
const callsBeforeEmpty = Math.floor(Number(totalCapacity) / Number(callCapacityCost));
const nonce = await getNonce(stakeKeys);
await Promise.all(Array.from({ length: callsBeforeEmpty }, (_, k) => call.payWithCapacity(nonce + k)));
return callCapacityCost;
}
54 changes: 26 additions & 28 deletions e2e/capacity/staking.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@ import {
createKeys, createMsaAndProvider,
stakeToProvider,
getNextEpochBlock, TEST_EPOCH_LENGTH,
CENTS, DOLLARS, createAndFundKeypair
}
from "../scaffolding/helpers";
import { firstValueFrom } from "rxjs";
CENTS, DOLLARS, createAndFundKeypair, getCapacity, createMsa
} from "../scaffolding/helpers";
import { isDev } from "../scaffolding/env";
import { getFundingSource } from "../scaffolding/funding";

Expand Down Expand Up @@ -45,7 +43,7 @@ describe("Capacity Staking Tests", function () {
assert.equal(stakedAcctInfo.data.frozen, tokenMinStake, `expected ${tokenMinStake} frozen balance, got ${stakedAcctInfo.data.frozen}`)

// Confirm that the capacity was added to the stakeProviderId using the query API
const capacityStaked = (await firstValueFrom(ExtrinsicHelper.api.query.capacity.capacityLedger(stakeProviderId))).unwrap();
const capacityStaked = await getCapacity(stakeProviderId);
assert.equal(capacityStaked.remainingCapacity, capacityMin, `expected capacityLedger.remainingCapacity = 1CENT, got ${capacityStaked.remainingCapacity}`);
assert.equal(capacityStaked.totalTokensStaked, tokenMinStake, `expected capacityLedger.totalTokensStaked = 1CENT, got ${capacityStaked.totalTokensStaked}`);
assert.equal(capacityStaked.totalCapacityIssued, capacityMin, `expected capacityLedger.totalCapacityIssued = 1CENT, got ${capacityStaked.totalCapacityIssued}`);
Expand All @@ -54,12 +52,12 @@ describe("Capacity Staking Tests", function () {

it("successfully unstakes the minimum amount", async function () {
const stakeObj = ExtrinsicHelper.unstake(stakeKeys, stakeProviderId, tokenMinStake);
const { target: unStakeEvent } = await stakeObj.fundAndSend(fundingSource);
const { target: unStakeEvent } = await stakeObj.signAndSend();
assert.notEqual(unStakeEvent, undefined, "should return an UnStaked event");
assert.equal(unStakeEvent?.data.capacity, capacityMin, "should return an UnStaked event with 1 CENT reduced capacity");

// Confirm that the tokens were unstaked in the stakeProviderId account using the query API
const capacityStaked = (await firstValueFrom(ExtrinsicHelper.api.query.capacity.capacityLedger(stakeProviderId))).unwrap();
const capacityStaked = await getCapacity(stakeProviderId);
assert.equal(capacityStaked.remainingCapacity, 0, "should return a capacityLedger with 0 remainingCapacity");
assert.equal(capacityStaked.totalTokensStaked, 0, "should return a capacityLedger with 0 total tokens staked");
assert.equal(capacityStaked.totalCapacityIssued, 0, "should return a capacityLedger with 0 capacity issued");
Expand All @@ -76,7 +74,7 @@ describe("Capacity Staking Tests", function () {
await ExtrinsicHelper.runToBlock(newEpochBlock + TEST_EPOCH_LENGTH + 1);

const withdrawObj = ExtrinsicHelper.withdrawUnstaked(stakeKeys);
const { target: withdrawEvent } = await withdrawObj.fundAndSend(fundingSource);
const { target: withdrawEvent } = await withdrawObj.signAndSend();
assert.notEqual(withdrawEvent, undefined, "should return a StakeWithdrawn event");

const amount = withdrawEvent!.data.amount;
Expand All @@ -87,7 +85,7 @@ describe("Capacity Staking Tests", function () {
assert.equal(unStakedAcctInfo.data.frozen, 0, "should return an account with 0 frozen balance")

// Confirm that the staked capacity was removed from the stakeProviderId account using the query API
const capacityStaked = (await firstValueFrom(ExtrinsicHelper.api.query.capacity.capacityLedger(stakeProviderId))).unwrap();
const capacityStaked = await getCapacity(stakeProviderId);
assert.equal(capacityStaked.remainingCapacity, 0, "should return a capacityLedger with 0 remainingCapacity");
assert.equal(capacityStaked.totalTokensStaked, 0, "should return a capacityLedger with 0 total tokens staked");
assert.equal(capacityStaked.totalCapacityIssued, 0, "should return a capacityLedger with 0 capacity issued");
Expand All @@ -99,7 +97,7 @@ describe("Capacity Staking Tests", function () {
it("successfully increases the amount that was targeted to provider", async function () {
await assert.doesNotReject(stakeToProvider(fundingSource, stakeKeys, stakeProviderId, tokenMinStake));

const capacityStaked = (await firstValueFrom(ExtrinsicHelper.api.query.capacity.capacityLedger(stakeProviderId))).unwrap();
const capacityStaked = await getCapacity(stakeProviderId);
assert.equal(capacityStaked.remainingCapacity, capacityMin,
`expected capacityStaked.remainingCapacity = ${capacityMin}, got ${capacityStaked.remainingCapacity}`);
assert.equal(capacityStaked.totalTokensStaked, tokenMinStake,
Expand Down Expand Up @@ -135,13 +133,13 @@ describe("Capacity Staking Tests", function () {
// Confirm that the staked capacity of the original stakeProviderId account is unchanged
// stakeProviderId should still have 1M from first test case in this describe.
// otherProvider should now have 1M
const origStaked = (await firstValueFrom(ExtrinsicHelper.api.query.capacity.capacityLedger(stakeProviderId))).unwrap();
const origStaked = await getCapacity(stakeProviderId);
assert.equal(origStaked.remainingCapacity, expectedCapacity, `expected 1/50 CENT remaining capacity, got ${origStaked.remainingCapacity}`);
assert.equal(origStaked.totalTokensStaked, 1n * CENTS, `expected 1 CENT staked, got ${origStaked.totalTokensStaked}`);
assert.equal(origStaked.totalCapacityIssued, expectedCapacity, `expected 1/50 CENT capacity issued, got ${origStaked.totalCapacityIssued}`);

// Confirm that the staked capacity was added to the otherProviderId account using the query API
const capacityStaked = (await firstValueFrom(ExtrinsicHelper.api.query.capacity.capacityLedger(otherProviderId))).unwrap();
const capacityStaked = await getCapacity(otherProviderId);
assert.equal(capacityStaked.remainingCapacity, expectedCapacity, "should return a capacityLedger with 1/50M remainingCapacity");
assert.equal(capacityStaked.totalTokensStaked, 1n * CENTS, "should return a capacityLedger with 1M total tokens staked");
assert.equal(capacityStaked.totalCapacityIssued, expectedCapacity, "should return a capacityLedger with 1/50M capacity issued");
Expand All @@ -153,11 +151,11 @@ describe("Capacity Staking Tests", function () {

// get the current account info
let currentAcctInfo = await ExtrinsicHelper.getAccountInfo(additionalKeys.address);
const currentStaked = (await firstValueFrom(ExtrinsicHelper.api.query.capacity.capacityLedger(stakeProviderId))).unwrap();
const currentStaked = await getCapacity(stakeProviderId);

await assert.doesNotReject(stakeToProvider(fundingSource, additionalKeys, stakeProviderId, tokenMinStake));

const capacityStaked = (await firstValueFrom(ExtrinsicHelper.api.query.capacity.capacityLedger(stakeProviderId))).unwrap();
const capacityStaked = await getCapacity(stakeProviderId);
assert.equal(
capacityStaked.remainingCapacity,
currentStaked.remainingCapacity.toBigInt() + capacityMin,
Expand Down Expand Up @@ -189,13 +187,13 @@ describe("Capacity Staking Tests", function () {

describe("when staking and targeting an InvalidTarget", async function () {
it("fails to stake", async function () {
const maxMsaId = (await ExtrinsicHelper.getCurrentMsaIdentifierMaximum()).toNumber();

const stakeAmount = 10n * CENTS;
const stakeKeys = await createAndFundKeypair(fundingSource, stakeAmount + 1n, "StakeKeys");
const stakeKeys = await createAndFundKeypair(fundingSource, accountBalance, "StakeKeys");

const [notProviderMsaId] = await createMsa(fundingSource);

const failStakeObj = ExtrinsicHelper.stake(stakeKeys, maxMsaId + 1, stakeAmount);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this test is running in parallel, it cannot just use maxMsaId + 1 as other msas are being created and might be providers.

await assert.rejects(failStakeObj.fundAndSend(fundingSource), { name: "InvalidTarget" });
const failStakeObj = ExtrinsicHelper.stake(stakeKeys, notProviderMsaId, stakeAmount);
await assert.rejects(failStakeObj.signAndSend(), { name: "InvalidTarget" });
});
});

Expand All @@ -206,28 +204,28 @@ describe("Capacity Staking Tests", function () {
let stakeAmount = 1500n;

const failStakeObj = ExtrinsicHelper.stake(stakingKeys, providerId, stakeAmount);
await assert.rejects(failStakeObj.fundAndSend(fundingSource), { name: "InsufficientStakingAmount" });
await assert.rejects(failStakeObj.signAndSend(), { name: "InsufficientStakingAmount" });
});
});

describe("when attempting to stake a zero amount", async function () {
it("fails to stake and errors ZeroAmountNotAllowed", async function () {
let stakingKeys = createKeys("stakingKeys");
let providerId = await createMsaAndProvider(fundingSource, stakingKeys, "stakingKeys", );
let providerId = await createMsaAndProvider(fundingSource, stakingKeys, "stakingKeys", 10n * CENTS);

const failStakeObj = ExtrinsicHelper.stake(stakingKeys, providerId, 0);
await assert.rejects(failStakeObj.fundAndSend(fundingSource), { name: "ZeroAmountNotAllowed" });
await assert.rejects(failStakeObj.signAndSend(), { name: "ZeroAmountNotAllowed" });
});
});

describe("when staking an amount and account balance is too low", async function () {
it("fails to stake and errors BalanceTooLowtoStake", async function () {
let stakingKeys = createKeys("stakingKeys");
let providerId = await createMsaAndProvider(fundingSource, stakingKeys, "stakingKeys");
let providerId = await createMsaAndProvider(fundingSource, stakingKeys, "stakingKeys", 10n * CENTS);
let stakingAmount = 1n * DOLLARS;

const failStakeObj = ExtrinsicHelper.stake(stakingKeys, providerId, stakingAmount);
await assert.rejects(failStakeObj.fundAndSend(fundingSource), { name: "BalanceTooLowtoStake" });
await assert.rejects(failStakeObj.signAndSend(), { name: "BalanceTooLowtoStake" });
});
});

Expand All @@ -245,14 +243,14 @@ describe("Capacity Staking Tests", function () {
describe("when attempting to unstake a Zero amount", async function () {
it("errors with UnstakedAmountIsZero", async function () {
const failUnstakeObj = ExtrinsicHelper.unstake(unstakeKeys, providerId, 0);
await assert.rejects(failUnstakeObj.fundAndSend(fundingSource), { name: "UnstakedAmountIsZero" });
await assert.rejects(failUnstakeObj.signAndSend(), { name: "UnstakedAmountIsZero" });
});
})

describe("when account has not staked", async function () {
it("errors with StakingAccountNotFound", async function () {
const failUnstakeObj = ExtrinsicHelper.unstake(unstakeKeys, providerId, tokenMinStake);
await assert.rejects(failUnstakeObj.fundAndSend(fundingSource), { name: "NotAStakingAccount" });
await assert.rejects(failUnstakeObj.signAndSend(), { name: "NotAStakingAccount" });
});
});
});
Expand All @@ -264,11 +262,11 @@ describe("Capacity Staking Tests", function () {
let providerId: u64 = await createMsaAndProvider(fundingSource, stakingKeys, "stakingKeys", accountBalance);

const stakeObj = ExtrinsicHelper.stake(stakingKeys, providerId, tokenMinStake);
const { target: stakeEvent } = await stakeObj.fundAndSend(fundingSource);
const { target: stakeEvent } = await stakeObj.signAndSend();
assert.notEqual(stakeEvent, undefined, "should return a Stake event");

const withdrawObj = ExtrinsicHelper.withdrawUnstaked(stakingKeys);
await assert.rejects(withdrawObj.fundAndSend(fundingSource), { name: "NoUnstakedTokensAvailable" });
await assert.rejects(withdrawObj.signAndSend(), { name: "NoUnstakedTokensAvailable" });
});
})
});
Expand Down
Loading