Skip to content

Commit

Permalink
Fix/e2e test improvements (#2195)
Browse files Browse the repository at this point in the history
# Goal
The goal of this PR is to add a final set of e2e test improvements to
allow e2e tests to run against testnet again post async-backing

Closes #2154 

# Discussion

- Added a way to wait for finalization
- Added errors instead of waiting forever for blocks
- Reduced timeouts thanks to 6s blocktimes on testnet
- Split up more tests for better parallelization

# Testing

-
https://github.com/frequency-chain/frequency/actions/runs/11489493946/job/31978401849
  • Loading branch information
wilwade authored Oct 24, 2024
1 parent 11225b1 commit 9ba9bdd
Show file tree
Hide file tree
Showing 10 changed files with 277 additions and 202 deletions.
2 changes: 1 addition & 1 deletion e2e/.relay-chain.mocharc.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
"require": ["scaffolding/globalHooks.ts", "scaffolding/rootHooks.ts", "scaffolding/extrinsicHelpers.ts"],
"import": "tsx/esm",
"spec": ["./{,!(node_modules|load-tests)/**}/*.test.ts"],
"timeout": 600000
"timeout": 180000
}
226 changes: 226 additions & 0 deletions e2e/capacity/capacityFail.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
import '@frequency-chain/api-augment';
import { KeyringPair } from '@polkadot/keyring/types';
import { Bytes, u64, u16 } from '@polkadot/types';
import assert from 'assert';
import { AddKeyData, ExtrinsicHelper } from '../scaffolding/extrinsicHelpers';
import {
createKeys,
createAndFundKeypair,
createMsaAndProvider,
generateDelegationPayload,
getBlockNumber,
signPayloadSr25519,
stakeToProvider,
generateAddKeyPayload,
CENTS,
DOLLARS,
getOrCreateGraphChangeSchema,
getTestHandle,
assertAddNewKey,
} from '../scaffolding/helpers';
import { getFundingSource } from '../scaffolding/funding';

const FUNDS_AMOUNT: bigint = 50n * DOLLARS;
const fundingSource = getFundingSource('capacity-transactions-fail');

describe('Capacity Transaction Failures', function () {
describe('pay_with_capacity', function () {
describe('when caller does not have a Capacity account', function () {
let delegatorKeys: KeyringPair;
let delegatorProviderId: u64;
let schemaId: u16;

beforeEach(async function () {
// Create and fund a keypair with EXISTENTIAL_DEPOSIT
// Use this keypair for delegator operations
delegatorKeys = createKeys('OtherProviderKeys');
delegatorProviderId = await createMsaAndProvider(fundingSource, delegatorKeys, 'Delegator', FUNDS_AMOUNT);
schemaId = new u16(ExtrinsicHelper.api.registry, 0);
});

describe('but has an MSA account that has not been registered as a Provider', function () {
it('fails to pay for a transaction', async function () {
// Create a keypair with msaId, but no provider
const noProviderKeys = await createAndFundKeypair(fundingSource, FUNDS_AMOUNT, 'NoProviderKeys');

const createMsaOp = ExtrinsicHelper.createMsa(noProviderKeys);

const { target: msaCreatedEvent } = await createMsaOp.fundAndSend(fundingSource);
assert.notEqual(msaCreatedEvent, undefined, 'should have returned MsaCreated event');

// When a user is not a registered provider and attempts to pay with Capacity,
// it should error with InvalidTransaction::Payment, which is a 1010 error, Inability to pay some fees.
const payload = await generateDelegationPayload({
authorizedMsaId: delegatorProviderId,
schemaIds: [schemaId],
});
const addProviderData = ExtrinsicHelper.api.registry.createType('PalletMsaAddProvider', payload);
const grantDelegationOp = ExtrinsicHelper.grantDelegation(
delegatorKeys,
noProviderKeys,
signPayloadSr25519(delegatorKeys, addProviderData),
payload
);

await assert.rejects(grantDelegationOp.payWithCapacity('current'), {
name: 'RpcError',
message: '1010: Invalid Transaction: Inability to pay some fees , e.g. account balance too low',
});
});
});

describe('and does not have an MSA account associated to signing keys', function () {
it('fails to pay for a transaction', async function () {
const emptyKeys = await createAndFundKeypair(fundingSource, 50_000_000n);

const payload = await generateDelegationPayload({
authorizedMsaId: delegatorProviderId,
schemaIds: [schemaId],
});
const addProviderData = ExtrinsicHelper.api.registry.createType('PalletMsaAddProvider', payload);
const grantDelegationOp = ExtrinsicHelper.grantDelegation(
delegatorKeys,
emptyKeys,
signPayloadSr25519(delegatorKeys, addProviderData),
payload
);

await assert.rejects(grantDelegationOp.payWithCapacity('current'), {
name: 'RpcError',
message: '1010: Invalid Transaction: Custom error: 1',
});
});
});
});

describe('when caller has a Capacity account', function () {
let schemaId: u16;
const amountStaked = 3n * DOLLARS;

before(async function () {
// Create schemas for testing with Grant Delegation to test pay_with_capacity
schemaId = await getOrCreateGraphChangeSchema(fundingSource);
assert.notEqual(schemaId, undefined, 'setup should populate schemaId');
});

it('fails when a provider makes an eligible extrinsic call using non-funded control key', async function () {
const capacityKeys = createKeys('CapacityKeysNSF');
const capacityProvider = await createMsaAndProvider(fundingSource, capacityKeys, 'CapProvNSF', FUNDS_AMOUNT);
// this will first fund 'capacityKeys' before staking
await assert.doesNotReject(stakeToProvider(fundingSource, fundingSource, capacityProvider, amountStaked));

// As current owner, add a new set of control keys that do not have a balance.
const newControlKeypair = createKeys('NewKeyNoBalance');
const newPublicKey = newControlKeypair.publicKey;
const addKeyPayload: AddKeyData = await generateAddKeyPayload({
msaId: capacityProvider,
newPublicKey: newPublicKey,
});
await assertAddNewKey(capacityKeys, addKeyPayload, newControlKeypair);

// attempt a capacity transaction using the new unfunded key: claimHandle
const handle = getTestHandle();
const expiration = (await getBlockNumber()) + 10;
const handle_vec = new Bytes(ExtrinsicHelper.api.registry, handle);
const handlePayload = {
baseHandle: handle_vec,
expiration: expiration,
};
const claimHandlePayload = ExtrinsicHelper.api.registry.createType(
'CommonPrimitivesHandlesClaimHandlePayload',
handlePayload
);
const claimHandle = ExtrinsicHelper.claimHandle(newControlKeypair, claimHandlePayload);
await assert.rejects(claimHandle.payWithCapacity('current'), {
name: 'RpcError',
message: '1010: Invalid Transaction: Inability to pay some fees , e.g. account balance too low',
});
});

// When a user attempts to pay for a non-capacity transaction with Capacity,
// it should error and drop the transaction from the transaction-pool.
it('fails to pay with Capacity for a non-capacity transaction', async function () {
const capacityKeys = createKeys('CapacityKeys');
const capacityProvider = await createMsaAndProvider(
fundingSource,
capacityKeys,
'CapacityProvider',
FUNDS_AMOUNT
);
const nonCapacityTxn = ExtrinsicHelper.stake(capacityKeys, capacityProvider, 1n * CENTS);
await assert.rejects(nonCapacityTxn.payWithCapacity('current'), {
name: 'RpcError',
message: '1010: Invalid Transaction: Custom error: 0',
});
});

// When a user does not have enough capacity to pay for the transaction fee
// and is NOT eligible to replenish Capacity, it should error and be dropped
// from the transaction pool.
it('fails to pay for a transaction with empty capacity', async function () {
const noCapacityKeys = createKeys('noCapacityKeys');
const noCapacityProvider = await createMsaAndProvider(fundingSource, noCapacityKeys, 'NoCapProvider');

const delegatorKeys = createKeys('delegatorKeys');

const payload = await generateDelegationPayload({
authorizedMsaId: noCapacityProvider,
schemaIds: [schemaId],
});
const addProviderData = ExtrinsicHelper.api.registry.createType('PalletMsaAddProvider', payload);
const grantDelegationOp = ExtrinsicHelper.createSponsoredAccountWithDelegation(
delegatorKeys,
noCapacityKeys,
signPayloadSr25519(noCapacityKeys, addProviderData),
payload
);

await assert.rejects(grantDelegationOp.payWithCapacity('current'), {
name: 'RpcError',
message: '1010: Invalid Transaction: Inability to pay some fees , e.g. account balance too low',
});
});

// *All keys should have at least an EXISTENTIAL_DEPOSIT = 1M.
it('fails to pay for transaction when key does has not met the min deposit', async function () {
const capacityKeys = createKeys('CapKeysUnder');
const capacityProvider = await createMsaAndProvider(fundingSource, capacityKeys, 'CapProvUnder', FUNDS_AMOUNT);
const noTokensKeys = createKeys('noTokensKeys');
const delegatorKeys = createKeys('delegatorKeys');

await assert.doesNotReject(stakeToProvider(fundingSource, fundingSource, capacityProvider, 1n * DOLLARS));

// Add new key
const newKeyPayload: AddKeyData = await generateAddKeyPayload({
msaId: new u64(ExtrinsicHelper.api.registry, capacityProvider),
newPublicKey: noTokensKeys.publicKey,
});
const addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', newKeyPayload);

const ownerSig = signPayloadSr25519(capacityKeys, addKeyData);
const newSig = signPayloadSr25519(noTokensKeys, addKeyData);
const addPublicKeyOp = ExtrinsicHelper.addPublicKeyToMsa(capacityKeys, ownerSig, newSig, newKeyPayload);

const { target: publicKeyEvent } = await addPublicKeyOp.fundAndSend(fundingSource);
assert.notEqual(publicKeyEvent, undefined, 'should have added public key');

const payload = await generateDelegationPayload({
authorizedMsaId: capacityProvider,
schemaIds: [schemaId],
});
const addProviderData = ExtrinsicHelper.api.registry.createType('PalletMsaAddProvider', payload);
const grantDelegationOp = ExtrinsicHelper.createSponsoredAccountWithDelegation(
delegatorKeys,
noTokensKeys,
signPayloadSr25519(delegatorKeys, addProviderData),
payload
);

await assert.rejects(grantDelegationOp.payWithCapacity('current'), {
name: 'RpcError',
message: '1010: Invalid Transaction: Inability to pay some fees , e.g. account balance too low',
});
});
});
});
});
Loading

0 comments on commit 9ba9bdd

Please sign in to comment.