Skip to content

Commit

Permalink
ethereum: added e2e tests (#2218)
Browse files Browse the repository at this point in the history
# Goal
The goal of this PR is <!-- insert goal here -->

Closes #2203 

# Discussion
- added e2e tests for more usecase for ethereum keys
- Some clean up and refactoring
- Added eslint rules to enforce correct usage

# Checklist
- [X] e2e Tests added?
  • Loading branch information
aramikm authored Nov 22, 2024
1 parent 0c34adc commit f70489c
Show file tree
Hide file tree
Showing 19 changed files with 765 additions and 109 deletions.
5 changes: 3 additions & 2 deletions e2e/capacity/capacityFail.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
assertAddNewKey,
} from '../scaffolding/helpers';
import { getFundingSource } from '../scaffolding/funding';
import { getUnifiedPublicKey } from '../scaffolding/ethereum';

const FUNDS_AMOUNT: bigint = 50n * DOLLARS;
const fundingSource = getFundingSource('capacity-transactions-fail');
Expand Down Expand Up @@ -111,7 +112,7 @@ describe('Capacity Transaction Failures', function () {

// 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 newPublicKey = getUnifiedPublicKey(newControlKeypair);
const addKeyPayload: AddKeyData = await generateAddKeyPayload({
msaId: capacityProvider,
newPublicKey: newPublicKey,
Expand Down Expand Up @@ -193,7 +194,7 @@ describe('Capacity Transaction Failures', function () {
// Add new key
const newKeyPayload: AddKeyData = await generateAddKeyPayload({
msaId: new u64(ExtrinsicHelper.api.registry, capacityProvider),
newPublicKey: noTokensKeys.publicKey,
newPublicKey: getUnifiedPublicKey(noTokensKeys),
});
const addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', newKeyPayload);

Expand Down
5 changes: 3 additions & 2 deletions e2e/capacity/capacity_rpc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
} from '../scaffolding/helpers';
import { FeeDetails } from '@polkadot/types/interfaces';
import { getFundingSource } from '../scaffolding/funding';
import { getUnifiedPublicKey } from '../scaffolding/ethereum';

const FUNDS_AMOUNT: bigint = 50n * DOLLARS;
const fundingSource = getFundingSource('capacity-rpcs');
Expand Down Expand Up @@ -46,7 +47,7 @@ describe('Capacity RPC', function () {
const addProviderData = ExtrinsicHelper.api.registry.createType('PalletMsaAddProvider', addProviderPayload);
const delegatorKeys = createKeys('delegatorKeys');
const call = ExtrinsicHelper.api.tx.msa.createSponsoredAccountWithDelegation(
delegatorKeys.publicKey,
getUnifiedPublicKey(delegatorKeys),
signPayloadSr25519(delegatorKeys, addProviderData),
addProviderPayload
);
Expand Down Expand Up @@ -89,7 +90,7 @@ describe('Capacity RPC', function () {
const addProviderData = ExtrinsicHelper.api.registry.createType('PalletMsaAddProvider', addProviderPayload);
const delegatorKeys = createKeys('delegatorKeys');
const insideTx = ExtrinsicHelper.api.tx.msa.createSponsoredAccountWithDelegation(
delegatorKeys.publicKey,
getUnifiedPublicKey(delegatorKeys),
signPayloadSr25519(delegatorKeys, addProviderData),
addProviderPayload
);
Expand Down
3 changes: 2 additions & 1 deletion e2e/capacity/transactions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
} from '../scaffolding/helpers';
import { ipfsCid } from '../messages/ipfs';
import { getFundingSource } from '../scaffolding/funding';
import { getUnifiedPublicKey } from '../scaffolding/ethereum';

const FUNDS_AMOUNT: bigint = 50n * DOLLARS;
const fundingSource = getFundingSource('capacity-transactions');
Expand Down Expand Up @@ -92,7 +93,7 @@ describe('Capacity Transactions', function () {

authorizedKeys.push(await createAndFundKeypair(fundingSource, 50_000_000n));
defaultPayload.msaId = capacityProvider;
defaultPayload.newPublicKey = authorizedKeys[0].publicKey;
defaultPayload.newPublicKey = getUnifiedPublicKey(authorizedKeys[0]);

const payload = await generateAddKeyPayload(defaultPayload);
const addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', payload);
Expand Down
9 changes: 5 additions & 4 deletions e2e/capacity/transactionsBatch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
getTestHandle,
} from '../scaffolding/helpers';
import { getFundingSource } from '../scaffolding/funding';
import { getUnifiedPublicKey } from '../scaffolding/ethereum';

const FUNDS_AMOUNT: bigint = 50n * DOLLARS;
const fundingSource = getFundingSource('capacity-transactions-batch');
Expand Down Expand Up @@ -49,7 +50,7 @@ describe('Capacity Transactions Batch', function () {
const addProviderData = ExtrinsicHelper.api.registry.createType('PalletMsaAddProvider', addProviderPayload);
const delegatorKeys = createKeys('delegatorKeys');
const createSponsoredAccountWithDelegation = ExtrinsicHelper.api.tx.msa.createSponsoredAccountWithDelegation(
delegatorKeys.publicKey,
getUnifiedPublicKey(delegatorKeys),
signPayloadSr25519(delegatorKeys, addProviderData),
addProviderPayload
);
Expand All @@ -70,7 +71,7 @@ describe('Capacity Transactions Batch', function () {
};

const claimHandle = ExtrinsicHelper.api.tx.handles.claimHandle(
delegatorKeys.publicKey,
getUnifiedPublicKey(delegatorKeys),
claimHandleProof,
claimHandlePayload
);
Expand All @@ -95,7 +96,7 @@ describe('Capacity Transactions Batch', function () {
const addProviderData = ExtrinsicHelper.api.registry.createType('PalletMsaAddProvider', addProviderPayload);
const delegatorKeys = createKeys('delegatorKeys');
const createSponsoredAccountWithDelegation = ExtrinsicHelper.api.tx.msa.createSponsoredAccountWithDelegation(
delegatorKeys.publicKey,
getUnifiedPublicKey(delegatorKeys),
signPayloadSr25519(delegatorKeys, addProviderData),
addProviderPayload
);
Expand All @@ -116,7 +117,7 @@ describe('Capacity Transactions Batch', function () {
};

const claimHandle = ExtrinsicHelper.api.tx.handles.claimHandle(
delegatorKeys.publicKey,
getUnifiedPublicKey(delegatorKeys),
calimHandleProof,
claimHandlePayload
);
Expand Down
13 changes: 13 additions & 0 deletions e2e/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,19 @@ export default tseslint.config(
},
],
'allow-namespace': 'off',
'no-restricted-syntax': [
'error',
{
message:
'Direct usage of keyPair.address is not allowed in this file. please use getUnifiedAddress function.',
selector: 'MemberExpression[property.name="address"]',
},
{
message:
'Direct usage of keyPair.publicKey is not allowed in this file. please use getUnifiedPublicKey function',
selector: 'MemberExpression[property.name="publicKey"]',
},
],
},
}
);
4 changes: 2 additions & 2 deletions e2e/load-tests/signatureRegistry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { KeyringPair } from '@polkadot/keyring/types';
import { AddKeyData, ExtrinsicHelper } from '../scaffolding/extrinsicHelpers';
import { u64, Option } from '@polkadot/types';
import { getFundingSource } from '../scaffolding/funding';
import { getUnifiedAddress } from '../scaffolding/ethereum';
import { getUnifiedAddress, getUnifiedPublicKey } from '../scaffolding/ethereum';

interface GeneratedMsa {
id: u64;
Expand Down Expand Up @@ -154,7 +154,7 @@ async function addSigs(msaId: u64, keys: KeyringPair, blockNumber: number, nonce

const defaultPayload: AddKeyData = {};
defaultPayload.msaId = msaId;
defaultPayload.newPublicKey = newKeys.publicKey;
defaultPayload.newPublicKey = getUnifiedPublicKey(newKeys);
const payload = await generateAddKeyPayload(defaultPayload, 100, blockNumber);

const addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', payload);
Expand Down
67 changes: 67 additions & 0 deletions e2e/miscellaneous/balance.ethereum.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import '@frequency-chain/api-augment';
import assert from 'assert';
import { DOLLARS, createAndFundKeypair, createKeys } from '../scaffolding/helpers';
import { KeyringPair } from '@polkadot/keyring/types';
import { Extrinsic, ExtrinsicHelper } from '../scaffolding/extrinsicHelpers';
import { getFundingSource } from '../scaffolding/funding';
import { getUnifiedAddress } from '../scaffolding/ethereum';

const fundingSource: KeyringPair = getFundingSource('frequency-balance-ethereum');

describe('Balance transfer ethereum', function () {
describe('setup', function () {
let senderSr25519Keys: KeyringPair;
let senderEthereumKeys: KeyringPair;
let ethereumKeys: KeyringPair;
let ethereumKeys2: KeyringPair;
let sr25519Keys: KeyringPair;

before(async function () {
senderSr25519Keys = await createAndFundKeypair(fundingSource, 30n * DOLLARS);
senderEthereumKeys = await createAndFundKeypair(fundingSource, 30n * DOLLARS, undefined, undefined, 'ethereum');
ethereumKeys = await createKeys('another-key-1', 'ethereum');
ethereumKeys2 = await createKeys('another-key-2', 'ethereum');
sr25519Keys = await createKeys('another-sr25519', 'sr25519');
});

it('should transfer from sr25519 to ethereum style key', async function () {
const transferAmount = 10n * DOLLARS;
const extrinsic = new Extrinsic(
() => ExtrinsicHelper.api.tx.balances.transferKeepAlive(getUnifiedAddress(ethereumKeys), transferAmount),
senderSr25519Keys,
ExtrinsicHelper.api.events.balances.Transfer
);
const { target } = await extrinsic.signAndSend();
assert.notEqual(target, undefined, 'should have returned Transfer event');
const accountInfo = await ExtrinsicHelper.getAccountInfo(ethereumKeys);
assert(accountInfo.data.free.toBigInt() >= transferAmount);
});

it('should transfer from sr25519 to ethereum 20 byte address', async function () {
const transferAmount = 10n * DOLLARS;
const extrinsic = new Extrinsic(
// this is using MultiAddress::Address20 type in Rust since addressRaw is 20 bytes ethereum address
() => ExtrinsicHelper.api.tx.balances.transferKeepAlive(ethereumKeys2.addressRaw, transferAmount),
senderSr25519Keys,
ExtrinsicHelper.api.events.balances.Transfer
);
const { target } = await extrinsic.signAndSend();
assert.notEqual(target, undefined, 'should have returned Transfer event');
const accountInfo = await ExtrinsicHelper.getAccountInfo(ethereumKeys2);
assert(accountInfo.data.free.toBigInt() >= transferAmount);
});

it('should transfer from an ethereum key to sr25519 key', async function () {
const transferAmount = 10n * DOLLARS;
const extrinsic = new Extrinsic(
() => ExtrinsicHelper.api.tx.balances.transferKeepAlive(getUnifiedAddress(sr25519Keys), transferAmount),
senderEthereumKeys,
ExtrinsicHelper.api.events.balances.Transfer
);
const { target } = await extrinsic.signAndSend();
assert.notEqual(target, undefined, 'should have returned Transfer event');
const accountInfo = await ExtrinsicHelper.getAccountInfo(sr25519Keys);
assert(accountInfo.data.free.toBigInt() >= transferAmount);
});
});
});
6 changes: 3 additions & 3 deletions e2e/miscellaneous/frequency.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Extrinsic, ExtrinsicHelper } from '../scaffolding/extrinsicHelpers';
import { getFundingSource } from '../scaffolding/funding';
import { u8, Option } from '@polkadot/types';
import { u8aToHex } from '@polkadot/util/u8a/toHex';
import { getUnifiedAddress } from '../scaffolding/ethereum';
import { getUnifiedAddress, getUnifiedPublicKey } from '../scaffolding/ethereum';

const fundingSource: KeyringPair = getFundingSource('frequency-misc');

Expand All @@ -23,7 +23,7 @@ describe('Frequency', function () {
it('Get events successfully', async function () {
const balance_pallet = new u8(ExtrinsicHelper.api.registry, 10);
const transfer_event = new u8(ExtrinsicHelper.api.registry, 2);
const dest_account = u8aToHex(keypairB.publicKey).slice(2);
const dest_account = u8aToHex(getUnifiedPublicKey(keypairB)).slice(2);
const beforeBlockNumber = await getBlockNumber();

const extrinsic = new Extrinsic(
Expand Down Expand Up @@ -66,7 +66,7 @@ describe('Frequency', function () {
}
// wait a little for all of the above transactions to get queued
await new Promise((resolve) => setTimeout(resolve, 1000));
const missingNonce = await ExtrinsicHelper.getMissingNonceValues(keypairB.publicKey);
const missingNonce = await ExtrinsicHelper.getMissingNonceValues(getUnifiedPublicKey(keypairB));
assert.equal(missingNonce.length, 4, 'Could not get missing nonce values');

// applying the missing nonce values to next transactions to unblock the stuck ones
Expand Down
122 changes: 122 additions & 0 deletions e2e/msa/keyManagement.ethereum.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import '@frequency-chain/api-augment';
import assert from 'assert';
import {
createKeys,
createAndFundKeypair,
generateAddKeyPayload,
CENTS,
signPayload,
MultiSignatureType,
} from '../scaffolding/helpers';
import { KeyringPair } from '@polkadot/keyring/types';
import { AddKeyData, ExtrinsicHelper } from '../scaffolding/extrinsicHelpers';
import { u64 } from '@polkadot/types';
import { Codec } from '@polkadot/types/types';
import { getFundingSource } from '../scaffolding/funding';
import { getUnifiedPublicKey } from '../scaffolding/ethereum';

const maxU64 = 18_446_744_073_709_551_615n;
const fundingSource = getFundingSource('msa-key-management-ethereum');

describe('MSA Key management Ethereum', function () {
describe('addPublicKeyToMsa Ethereum', function () {
let keys: KeyringPair;
let msaId: u64;
let secondaryKey: KeyringPair;
const defaultPayload: AddKeyData = {};
let payload: AddKeyData;
let ownerSig: MultiSignatureType;
let newSig: MultiSignatureType;
let badSig: MultiSignatureType;
let addKeyData: Codec;

before(async function () {
// Setup an MSA with one key and a secondary funded key
keys = await createAndFundKeypair(fundingSource, 5n * CENTS, undefined, undefined, 'ethereum');
const { target } = await ExtrinsicHelper.createMsa(keys).signAndSend();
assert.notEqual(target?.data.msaId, undefined, 'MSA Id not in expected event');
msaId = target!.data.msaId;

secondaryKey = await createAndFundKeypair(fundingSource, 5n * CENTS, undefined, undefined, 'ethereum');

// Default payload making it easier to test `addPublicKeyToMsa`
defaultPayload.msaId = msaId;
defaultPayload.newPublicKey = getUnifiedPublicKey(secondaryKey);
});

beforeEach(async function () {
payload = await generateAddKeyPayload(defaultPayload);
});

it('should fail to add public key if origin is not one of the signers of the payload (MsaOwnershipInvalidSignature) for a Ethereum key', async function () {
const badKeys: KeyringPair = createKeys();
addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', payload);
newSig = signPayload(secondaryKey, addKeyData);
badSig = signPayload(badKeys, addKeyData);
const op = ExtrinsicHelper.addPublicKeyToMsa(keys, badSig, newSig, payload);
await assert.rejects(op.fundAndSend(fundingSource), {
name: 'MsaOwnershipInvalidSignature',
});
});

it('should fail to add public key if origin does not own MSA (NotMsaOwner) for a Ethereum key', async function () {
const newPayload = await generateAddKeyPayload({
...defaultPayload,
msaId: new u64(ExtrinsicHelper.api.registry, maxU64),
});
addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', newPayload);
ownerSig = signPayload(keys, addKeyData);
newSig = signPayload(secondaryKey, addKeyData);
const op = ExtrinsicHelper.addPublicKeyToMsa(keys, ownerSig, newSig, newPayload);
await assert.rejects(op.fundAndSend(fundingSource), {
name: 'NotMsaOwner',
});
});

it('should successfully add a new public key to an existing MSA & disallow duplicate signed payload submission (SignatureAlreadySubmitted) for a Ethereum key', async function () {
addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', payload);

ownerSig = signPayload(keys, addKeyData);
newSig = signPayload(secondaryKey, addKeyData);
const addPublicKeyOp = ExtrinsicHelper.addPublicKeyToMsa(keys, ownerSig, newSig, payload);

const { target: publicKeyEvents } = await addPublicKeyOp.fundAndSend(fundingSource);

assert.notEqual(publicKeyEvents, undefined, 'should have added public key');

await assert.rejects(
addPublicKeyOp.fundAndSend(fundingSource),
'should reject sending the same signed payload twice'
);
});

it('should fail if attempting to add the same key more than once (KeyAlreadyRegistered) for a Ethereum key', async function () {
const addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', payload);

const ownerSig = signPayload(keys, addKeyData);
const newSig = signPayload(secondaryKey, addKeyData);
const addPublicKeyOp = ExtrinsicHelper.addPublicKeyToMsa(keys, ownerSig, newSig, payload);

await assert.rejects(addPublicKeyOp.fundAndSend(fundingSource), {
name: 'KeyAlreadyRegistered',
});
});

it('should allow new keypair to act for/on MSA for a Ethereum key', async function () {
const thirdKey = createKeys();
const newPayload = await generateAddKeyPayload({
...defaultPayload,
newPublicKey: getUnifiedPublicKey(thirdKey),
});
addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', newPayload);
ownerSig = signPayload(secondaryKey, addKeyData);
newSig = signPayload(thirdKey, addKeyData);
const op = ExtrinsicHelper.addPublicKeyToMsa(secondaryKey, ownerSig, newSig, newPayload);
const { target: event } = await op.fundAndSend(fundingSource);
assert.notEqual(event, undefined, 'should have added public key');

// Cleanup
await assert.doesNotReject(ExtrinsicHelper.deletePublicKey(keys, getUnifiedPublicKey(thirdKey)).signAndSend());
});
});
});
Loading

0 comments on commit f70489c

Please sign in to comment.