From 7a77b580f7f1a80043597f57116fa3ec7396e3cf Mon Sep 17 00:00:00 2001 From: Pablo Labarta Date: Wed, 23 Oct 2024 12:04:27 -0300 Subject: [PATCH 01/14] extract some storage key helpers --- test/helpers/storageQueries.ts | 37 +++++++++++++++++++-- test/suites/smoke/test-polkadot-decoding.ts | 22 +----------- 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/test/helpers/storageQueries.ts b/test/helpers/storageQueries.ts index 0ee205504e..0ff67c5cf4 100644 --- a/test/helpers/storageQueries.ts +++ b/test/helpers/storageQueries.ts @@ -15,7 +15,7 @@ const startReport = (total: () => number) => { const used = process.memoryUsage().heapUsed / 1024 / 1024; log( `🔍️ Queried ${total()} keys @ ${qps.toFixed(0)} keys/sec,` + - ` ${used.toFixed(0)} MB heap used\n` + ` ${used.toFixed(0)} MB heap used\n` ); timer = setTimeout(report, 5000); @@ -50,7 +50,7 @@ export async function processAllStorage( prefixes.map(async (prefix) => limiter.schedule(async () => { let startKey: string | undefined = undefined; - loop: for (;;) { + loop: for (; ;) { // @ts-expect-error _rpcCore is not yet exposed const keys: string = await api._rpcCore.provider.send("state_getKeysPaged", [ prefix, @@ -96,3 +96,36 @@ export async function processAllStorage( await limiter.disconnect(); } + +export async function getStartingKeySample(api: ApiPromise, prefix: string, blockHash: string) { + // @ts-expect-error _rpcCore is not yet exposed + const res: string = await api._rpcCore.provider.send("state_getKeysPaged", [ + prefix, + 1, + "", + blockHash, + ]); + + return res[0]; +} + +export const extractStorageKeyComponents = (storageKey: string) => { + // The full storage key is composed of + // - The 0x prefix (2 characters) + // - The module prefix (32 characters) + // - The method name (32 characters) + // - The parameters (variable length) + const regex = /(?0x[a-f0-9]{32})(?[a-f0-9]{32})(?[a-f0-9]*)/i; + const match = regex.exec(storageKey); + + if (!match) { + throw new Error("Invalid storage key format"); + } + + const { moduleKey, fnKey, paramsKey } = match.groups!; + return { + moduleKey, + fnKey, + paramsKey, + }; +}; \ No newline at end of file diff --git a/test/suites/smoke/test-polkadot-decoding.ts b/test/suites/smoke/test-polkadot-decoding.ts index 12d3ac1a0b..e14e32e0a7 100644 --- a/test/suites/smoke/test-polkadot-decoding.ts +++ b/test/suites/smoke/test-polkadot-decoding.ts @@ -4,6 +4,7 @@ import { describeSuite, beforeAll } from "@moonwall/cli"; import { ONE_HOURS } from "@moonwall/util"; import { ApiPromise } from "@polkadot/api"; import { fail } from "assert"; +import { extractStorageKeyComponents } from "../../helpers/storageQueries"; // Change the following line to reproduce a particular case const STARTING_KEY_OVERRIDE = ""; @@ -12,27 +13,6 @@ const FN_NAME = ""; const pageSize = (process.env.PAGE_SIZE && parseInt(process.env.PAGE_SIZE)) || 500; -const extractStorageKeyComponents = (storageKey: string) => { - // The full storage key is composed of - // - The 0x prefix (2 characters) - // - The module prefix (32 characters) - // - The method name (32 characters) - // - The parameters (variable length) - const regex = /(?0x[a-f0-9]{32})(?[a-f0-9]{32})(?[a-f0-9]*)/i; - const match = regex.exec(storageKey); - - if (!match) { - throw new Error("Invalid storage key format"); - } - - const { moduleKey, fnKey, paramsKey } = match.groups!; - return { - moduleKey, - fnKey, - paramsKey, - }; -}; - const randomHex = (nBytes) => [...crypto.getRandomValues(new Uint8Array(nBytes))] .map((m) => ("0" + m.toString(16)).slice(-2)) From fd469ee6d0d693f4d80cfa9ccccff300b81f2f34 Mon Sep 17 00:00:00 2001 From: Pablo Labarta Date: Mon, 4 Nov 2024 08:25:36 -0300 Subject: [PATCH 02/14] test random contract prefixes --- test/helpers/storageQueries.ts | 68 +++++++++++++++++++ .../smoke/test-ethereum-contract-code.ts | 5 +- 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/test/helpers/storageQueries.ts b/test/helpers/storageQueries.ts index 0ff67c5cf4..bdfc91c483 100644 --- a/test/helpers/storageQueries.ts +++ b/test/helpers/storageQueries.ts @@ -1,6 +1,7 @@ import { ApiPromise } from "@polkadot/api"; import Debugger from "debug"; import { rateLimiter } from "./common.js"; +import { randomAsHex } from "@polkadot/util-crypto"; const log = Debugger("test:storageQuery"); @@ -97,6 +98,73 @@ export async function processAllStorage( await limiter.disconnect(); } +export async function processRandomStoragePrefixes( + api: ApiPromise, + storagePrefix: string, + blockHash: string, + processor: (batchResult: { key: `0x${string}`; value: string }[]) => void +) { + const maxKeys = 1000; + let total = 0; + const preFilteredPrefixes = splitPrefix(storagePrefix); + const chanceToSample = 0.05; + const prefixes = preFilteredPrefixes.filter(() => Math.random() < chanceToSample); + + const limiter = rateLimiter(); + const stopReport = startReport(() => total); + + try { + await Promise.all( + prefixes.map(async (prefix) => + limiter.schedule(async () => { + let startKey: string | undefined = undefined; + loop: for (; ;) { + // @ts-expect-error _rpcCore is not yet exposed + const keys: string = await api._rpcCore.provider.send("state_getKeysPaged", [ + prefix, + maxKeys, + startKey, + blockHash, + ]); + + if (!keys.length) { + break loop; + } + + // @ts-expect-error _rpcCore is not yet exposed + const response = await api._rpcCore.provider.send("state_queryStorageAt", [ + keys, + blockHash, + ]); + + try { + processor( + response[0].changes.map((pair: [string, string]) => ({ + key: pair[0], + value: pair[1], + })) + ); + } catch (e) { + console.log(`Error processing ${prefix}: ${e}`); + } + + total += keys.length; + + if (keys.length !== maxKeys) { + break loop; + } + startKey = keys[keys.length - 1]; + } + }) + ) + ); + } finally { + stopReport(); + } + + await limiter.disconnect(); +} + export async function getStartingKeySample(api: ApiPromise, prefix: string, blockHash: string) { // @ts-expect-error _rpcCore is not yet exposed const res: string = await api._rpcCore.provider.send("state_getKeysPaged", [ diff --git a/test/suites/smoke/test-ethereum-contract-code.ts b/test/suites/smoke/test-ethereum-contract-code.ts index 4c30b0f6c2..5c8c8f8766 100644 --- a/test/suites/smoke/test-ethereum-contract-code.ts +++ b/test/suites/smoke/test-ethereum-contract-code.ts @@ -4,7 +4,7 @@ import { ONE_HOURS } from "@moonwall/util"; import { compactStripLength, hexToU8a, u8aConcat, u8aToHex } from "@polkadot/util"; import { xxhashAsU8a } from "@polkadot/util-crypto"; import chalk from "chalk"; -import { processAllStorage } from "../../helpers/storageQueries.js"; +import { processRandomStoragePrefixes } from "../../helpers/storageQueries.js"; describeSuite({ id: "S08", @@ -37,7 +37,8 @@ describeSuite({ u8aConcat(xxhashAsU8a("EVM", 128), xxhashAsU8a("AccountCodes", 128)) ); const t0 = performance.now(); - await processAllStorage(paraApi, keyPrefix, blockHash, (items) => { + + await processRandomStoragePrefixes(paraApi, keyPrefix, blockHash, (items) => { for (const item of items) { const codesize = getBytecodeSize(hexToU8a(item.value)); if (codesize > MAX_CONTRACT_SIZE_BYTES) { From 1d296a727ab27906aa613f195bee7f683c451ee1 Mon Sep 17 00:00:00 2001 From: Pablo Labarta Date: Mon, 4 Nov 2024 08:39:05 -0300 Subject: [PATCH 03/14] add reproduction steps to error --- test/helpers/storageQueries.ts | 9 ++++++--- test/suites/smoke/test-ethereum-contract-code.ts | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/test/helpers/storageQueries.ts b/test/helpers/storageQueries.ts index bdfc91c483..2d2ec451a8 100644 --- a/test/helpers/storageQueries.ts +++ b/test/helpers/storageQueries.ts @@ -102,14 +102,15 @@ export async function processRandomStoragePrefixes( api: ApiPromise, storagePrefix: string, blockHash: string, - processor: (batchResult: { key: `0x${string}`; value: string }[]) => void + processor: (batchResult: { key: `0x${string}`; value: string }[]) => void, + override: string = "", ) { const maxKeys = 1000; let total = 0; const preFilteredPrefixes = splitPrefix(storagePrefix); const chanceToSample = 0.05; - const prefixes = preFilteredPrefixes.filter(() => Math.random() < chanceToSample); - + const prefixes = override ? [override] : preFilteredPrefixes.filter(() => Math.random() < chanceToSample); + console.log(`Processing ${prefixes.length} prefixes: ${prefixes.join(", ")}`); const limiter = rateLimiter(); const stopReport = startReport(() => total); @@ -146,6 +147,8 @@ export async function processRandomStoragePrefixes( ); } catch (e) { console.log(`Error processing ${prefix}: ${e}`); + console.log(`Replace the empty string in smoke/test-ethereum-contract-code.ts:L51 + with the prefix to reproduce`); } total += keys.length; diff --git a/test/suites/smoke/test-ethereum-contract-code.ts b/test/suites/smoke/test-ethereum-contract-code.ts index 5c8c8f8766..f35ddd900d 100644 --- a/test/suites/smoke/test-ethereum-contract-code.ts +++ b/test/suites/smoke/test-ethereum-contract-code.ts @@ -47,7 +47,8 @@ describeSuite({ } } totalContracts += BigInt(items.length); - }); + // WHEN DEBUGGING REPLACE THE EMPTY STRING WITH A PREFIX TO FETCH + }, ""); const t1 = performance.now(); const checkTime = (t1 - t0) / 1000; From 4159ceed376c6417bf5097ec395017e1f4159ced Mon Sep 17 00:00:00 2001 From: Pablo Labarta Date: Mon, 4 Nov 2024 08:46:03 -0300 Subject: [PATCH 04/14] fmt --- test/helpers/storageQueries.ts | 14 +-- .../smoke/now/test-ethereum-contract-code.ts | 86 +++++++++++++++++++ .../smoke/test-ethereum-contract-code.ts | 26 +++--- 3 files changed, 110 insertions(+), 16 deletions(-) create mode 100644 test/suites/smoke/now/test-ethereum-contract-code.ts diff --git a/test/helpers/storageQueries.ts b/test/helpers/storageQueries.ts index 2d2ec451a8..055a0e31e6 100644 --- a/test/helpers/storageQueries.ts +++ b/test/helpers/storageQueries.ts @@ -16,7 +16,7 @@ const startReport = (total: () => number) => { const used = process.memoryUsage().heapUsed / 1024 / 1024; log( `🔍️ Queried ${total()} keys @ ${qps.toFixed(0)} keys/sec,` + - ` ${used.toFixed(0)} MB heap used\n` + ` ${used.toFixed(0)} MB heap used\n` ); timer = setTimeout(report, 5000); @@ -51,7 +51,7 @@ export async function processAllStorage( prefixes.map(async (prefix) => limiter.schedule(async () => { let startKey: string | undefined = undefined; - loop: for (; ;) { + loop: for (;;) { // @ts-expect-error _rpcCore is not yet exposed const keys: string = await api._rpcCore.provider.send("state_getKeysPaged", [ prefix, @@ -103,13 +103,15 @@ export async function processRandomStoragePrefixes( storagePrefix: string, blockHash: string, processor: (batchResult: { key: `0x${string}`; value: string }[]) => void, - override: string = "", + override: string = "" ) { const maxKeys = 1000; let total = 0; const preFilteredPrefixes = splitPrefix(storagePrefix); const chanceToSample = 0.05; - const prefixes = override ? [override] : preFilteredPrefixes.filter(() => Math.random() < chanceToSample); + const prefixes = override + ? [override] + : preFilteredPrefixes.filter(() => Math.random() < chanceToSample); console.log(`Processing ${prefixes.length} prefixes: ${prefixes.join(", ")}`); const limiter = rateLimiter(); const stopReport = startReport(() => total); @@ -119,7 +121,7 @@ export async function processRandomStoragePrefixes( prefixes.map(async (prefix) => limiter.schedule(async () => { let startKey: string | undefined = undefined; - loop: for (; ;) { + loop: for (;;) { // @ts-expect-error _rpcCore is not yet exposed const keys: string = await api._rpcCore.provider.send("state_getKeysPaged", [ prefix, @@ -199,4 +201,4 @@ export const extractStorageKeyComponents = (storageKey: string) => { fnKey, paramsKey, }; -}; \ No newline at end of file +}; diff --git a/test/suites/smoke/now/test-ethereum-contract-code.ts b/test/suites/smoke/now/test-ethereum-contract-code.ts new file mode 100644 index 0000000000..5ace587f7d --- /dev/null +++ b/test/suites/smoke/now/test-ethereum-contract-code.ts @@ -0,0 +1,86 @@ +import "@moonbeam-network/api-augment"; +import { beforeAll, describeSuite, expect } from "@moonwall/cli"; +import { ONE_HOURS } from "@moonwall/util"; +import { compactStripLength, hexToU8a, u8aConcat, u8aToHex } from "@polkadot/util"; +import { xxhashAsU8a } from "@polkadot/util-crypto"; +import chalk from "chalk"; +import { processRandomStoragePrefixes } from "../../../helpers/storageQueries.js"; + +describeSuite({ + id: "S08", + title: `Ethereum contract bytecode should not be large`, + foundationMethods: "read_only", + testCases: ({ context, it, log }) => { + let atBlockNumber: number; + let totalContracts: bigint = 0n; + const failedContractCodes: { accountId: string; codesize: number }[] = []; + + beforeAll(async function () { + const paraApi = context.polkadotJs("para"); + const blockHash = process.env.BLOCK_NUMBER + ? (await paraApi.rpc.chain.getBlockHash(parseInt(process.env.BLOCK_NUMBER))).toHex() + : (await paraApi.rpc.chain.getFinalizedHead()).toHex(); + atBlockNumber = (await paraApi.rpc.chain.getHeader(blockHash)).number.toNumber(); + + // taken from geth, e.g. search "MaxCodeSize": + // https://github.com/etclabscore/core-geth/blob/master/params/vars/protocol_params.go + const MAX_CONTRACT_SIZE_BYTES = 24576; + const getBytecodeSize = (storageValue: Uint8Array) => { + const [len, bytecode] = compactStripLength(storageValue); + const hex = u8aToHex(bytecode); + return (hex.length - 2) / 2; + }; + + // Max RPC response limit is 15728640 bytes (15MB), so pessimistically the pageLimit + // needs to be lower than if every contract was above the MAX_CONTRACT_SIZE + const keyPrefix = u8aToHex( + u8aConcat(xxhashAsU8a("EVM", 128), xxhashAsU8a("AccountCodes", 128)) + ); + const t0 = performance.now(); + + await processRandomStoragePrefixes( + paraApi, + keyPrefix, + blockHash, + (items) => { + for (const item of items) { + const codesize = getBytecodeSize(hexToU8a(item.value)); + if (codesize > MAX_CONTRACT_SIZE_BYTES) { + const accountId = "0x" + item.key.slice(-40); + failedContractCodes.push({ accountId, codesize }); + } + } + totalContracts += BigInt(items.length); + // WHEN DEBUGGING REPLACE THE EMPTY STRING WITH A PREFIX TO FETCH + }, + "" + ); + + const t1 = performance.now(); + const checkTime = (t1 - t0) / 1000; + const text = + checkTime < 60 + ? `${checkTime.toFixed(1)} seconds` + : `${(checkTime / 60).toFixed(1)} minutes`; + + log(`Finished checking ${totalContracts} EVM.AccountCodes storage values in ${text} ✅`); + }, ONE_HOURS); + + it({ + id: "C100", + title: "should not have excessively long account codes", + test: async function () { + expect( + failedContractCodes.length, + `Failed account codes (too long): ${failedContractCodes + .map( + ({ accountId, codesize }) => `accountId: ${accountId} - ${chalk.red(codesize)} bytes` + ) + .join(`, `)}` + ).to.equal(0); + + log(`Verified ${totalContracts} total account codes (at #${atBlockNumber})`); + }, + }); + }, +}); diff --git a/test/suites/smoke/test-ethereum-contract-code.ts b/test/suites/smoke/test-ethereum-contract-code.ts index f35ddd900d..e303b57cc6 100644 --- a/test/suites/smoke/test-ethereum-contract-code.ts +++ b/test/suites/smoke/test-ethereum-contract-code.ts @@ -38,17 +38,23 @@ describeSuite({ ); const t0 = performance.now(); - await processRandomStoragePrefixes(paraApi, keyPrefix, blockHash, (items) => { - for (const item of items) { - const codesize = getBytecodeSize(hexToU8a(item.value)); - if (codesize > MAX_CONTRACT_SIZE_BYTES) { - const accountId = "0x" + item.key.slice(-40); - failedContractCodes.push({ accountId, codesize }); + await processRandomStoragePrefixes( + paraApi, + keyPrefix, + blockHash, + (items) => { + for (const item of items) { + const codesize = getBytecodeSize(hexToU8a(item.value)); + if (codesize > MAX_CONTRACT_SIZE_BYTES) { + const accountId = "0x" + item.key.slice(-40); + failedContractCodes.push({ accountId, codesize }); + } } - } - totalContracts += BigInt(items.length); - // WHEN DEBUGGING REPLACE THE EMPTY STRING WITH A PREFIX TO FETCH - }, ""); + totalContracts += BigInt(items.length); + // WHEN DEBUGGING REPLACE THE EMPTY STRING WITH A PREFIX TO FETCH + }, + "" + ); const t1 = performance.now(); const checkTime = (t1 - t0) / 1000; From 9c6c9774325b19c977e587ce353b4171d968c3c5 Mon Sep 17 00:00:00 2001 From: Pablo Labarta Date: Mon, 4 Nov 2024 08:48:40 -0300 Subject: [PATCH 05/14] delete smoke/now --- .../smoke/now/test-ethereum-contract-code.ts | 86 ------------------- 1 file changed, 86 deletions(-) delete mode 100644 test/suites/smoke/now/test-ethereum-contract-code.ts diff --git a/test/suites/smoke/now/test-ethereum-contract-code.ts b/test/suites/smoke/now/test-ethereum-contract-code.ts deleted file mode 100644 index 5ace587f7d..0000000000 --- a/test/suites/smoke/now/test-ethereum-contract-code.ts +++ /dev/null @@ -1,86 +0,0 @@ -import "@moonbeam-network/api-augment"; -import { beforeAll, describeSuite, expect } from "@moonwall/cli"; -import { ONE_HOURS } from "@moonwall/util"; -import { compactStripLength, hexToU8a, u8aConcat, u8aToHex } from "@polkadot/util"; -import { xxhashAsU8a } from "@polkadot/util-crypto"; -import chalk from "chalk"; -import { processRandomStoragePrefixes } from "../../../helpers/storageQueries.js"; - -describeSuite({ - id: "S08", - title: `Ethereum contract bytecode should not be large`, - foundationMethods: "read_only", - testCases: ({ context, it, log }) => { - let atBlockNumber: number; - let totalContracts: bigint = 0n; - const failedContractCodes: { accountId: string; codesize: number }[] = []; - - beforeAll(async function () { - const paraApi = context.polkadotJs("para"); - const blockHash = process.env.BLOCK_NUMBER - ? (await paraApi.rpc.chain.getBlockHash(parseInt(process.env.BLOCK_NUMBER))).toHex() - : (await paraApi.rpc.chain.getFinalizedHead()).toHex(); - atBlockNumber = (await paraApi.rpc.chain.getHeader(blockHash)).number.toNumber(); - - // taken from geth, e.g. search "MaxCodeSize": - // https://github.com/etclabscore/core-geth/blob/master/params/vars/protocol_params.go - const MAX_CONTRACT_SIZE_BYTES = 24576; - const getBytecodeSize = (storageValue: Uint8Array) => { - const [len, bytecode] = compactStripLength(storageValue); - const hex = u8aToHex(bytecode); - return (hex.length - 2) / 2; - }; - - // Max RPC response limit is 15728640 bytes (15MB), so pessimistically the pageLimit - // needs to be lower than if every contract was above the MAX_CONTRACT_SIZE - const keyPrefix = u8aToHex( - u8aConcat(xxhashAsU8a("EVM", 128), xxhashAsU8a("AccountCodes", 128)) - ); - const t0 = performance.now(); - - await processRandomStoragePrefixes( - paraApi, - keyPrefix, - blockHash, - (items) => { - for (const item of items) { - const codesize = getBytecodeSize(hexToU8a(item.value)); - if (codesize > MAX_CONTRACT_SIZE_BYTES) { - const accountId = "0x" + item.key.slice(-40); - failedContractCodes.push({ accountId, codesize }); - } - } - totalContracts += BigInt(items.length); - // WHEN DEBUGGING REPLACE THE EMPTY STRING WITH A PREFIX TO FETCH - }, - "" - ); - - const t1 = performance.now(); - const checkTime = (t1 - t0) / 1000; - const text = - checkTime < 60 - ? `${checkTime.toFixed(1)} seconds` - : `${(checkTime / 60).toFixed(1)} minutes`; - - log(`Finished checking ${totalContracts} EVM.AccountCodes storage values in ${text} ✅`); - }, ONE_HOURS); - - it({ - id: "C100", - title: "should not have excessively long account codes", - test: async function () { - expect( - failedContractCodes.length, - `Failed account codes (too long): ${failedContractCodes - .map( - ({ accountId, codesize }) => `accountId: ${accountId} - ${chalk.red(codesize)} bytes` - ) - .join(`, `)}` - ).to.equal(0); - - log(`Verified ${totalContracts} total account codes (at #${atBlockNumber})`); - }, - }); - }, -}); From b7027bbaacfe862e25b5d4075721338c7394d443 Mon Sep 17 00:00:00 2001 From: Pablo Labarta Date: Thu, 12 Dec 2024 15:15:02 -0300 Subject: [PATCH 06/14] improve error/debug msg --- test/helpers/storageQueries.ts | 8 ++++---- test/suites/smoke/test-ethereum-contract-code.ts | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/test/helpers/storageQueries.ts b/test/helpers/storageQueries.ts index 055a0e31e6..ef25af46a9 100644 --- a/test/helpers/storageQueries.ts +++ b/test/helpers/storageQueries.ts @@ -16,7 +16,7 @@ const startReport = (total: () => number) => { const used = process.memoryUsage().heapUsed / 1024 / 1024; log( `🔍️ Queried ${total()} keys @ ${qps.toFixed(0)} keys/sec,` + - ` ${used.toFixed(0)} MB heap used\n` + ` ${used.toFixed(0)} MB heap used\n` ); timer = setTimeout(report, 5000); @@ -51,7 +51,7 @@ export async function processAllStorage( prefixes.map(async (prefix) => limiter.schedule(async () => { let startKey: string | undefined = undefined; - loop: for (;;) { + loop: for (; ;) { // @ts-expect-error _rpcCore is not yet exposed const keys: string = await api._rpcCore.provider.send("state_getKeysPaged", [ prefix, @@ -121,7 +121,7 @@ export async function processRandomStoragePrefixes( prefixes.map(async (prefix) => limiter.schedule(async () => { let startKey: string | undefined = undefined; - loop: for (;;) { + loop: for (; ;) { // @ts-expect-error _rpcCore is not yet exposed const keys: string = await api._rpcCore.provider.send("state_getKeysPaged", [ prefix, @@ -149,7 +149,7 @@ export async function processRandomStoragePrefixes( ); } catch (e) { console.log(`Error processing ${prefix}: ${e}`); - console.log(`Replace the empty string in smoke/test-ethereum-contract-code.ts:L51 + console.log(`Replace the empty string in smoke/test-ethereum-contract-code.ts with the prefix to reproduce`); } diff --git a/test/suites/smoke/test-ethereum-contract-code.ts b/test/suites/smoke/test-ethereum-contract-code.ts index e303b57cc6..5ca6cce732 100644 --- a/test/suites/smoke/test-ethereum-contract-code.ts +++ b/test/suites/smoke/test-ethereum-contract-code.ts @@ -51,8 +51,9 @@ describeSuite({ } } totalContracts += BigInt(items.length); - // WHEN DEBUGGING REPLACE THE EMPTY STRING WITH A PREFIX TO FETCH + }, + // WHEN DEBUGGING REPLACE THE EMPTY STRING WITH A PREFIX TO FETCH "" ); From 4d7f16538d26044efaeff367a75f4bd73f326da4 Mon Sep 17 00:00:00 2001 From: Pablo Labarta Date: Thu, 12 Dec 2024 15:17:31 -0300 Subject: [PATCH 07/14] slice if prefixes > 25 --- test/helpers/storageQueries.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/helpers/storageQueries.ts b/test/helpers/storageQueries.ts index ef25af46a9..26ac19d9f2 100644 --- a/test/helpers/storageQueries.ts +++ b/test/helpers/storageQueries.ts @@ -109,9 +109,12 @@ export async function processRandomStoragePrefixes( let total = 0; const preFilteredPrefixes = splitPrefix(storagePrefix); const chanceToSample = 0.05; - const prefixes = override + let prefixes = override ? [override] : preFilteredPrefixes.filter(() => Math.random() < chanceToSample); + if (prefixes.length > 25) { + prefixes = prefixes.slice(0, 25); + } console.log(`Processing ${prefixes.length} prefixes: ${prefixes.join(", ")}`); const limiter = rateLimiter(); const stopReport = startReport(() => total); From 9471053db7a2fcdadf72d4a3f8a3818a3e6626b0 Mon Sep 17 00:00:00 2001 From: Pablo Labarta Date: Thu, 12 Dec 2024 15:33:41 -0300 Subject: [PATCH 08/14] fmt --- test/helpers/storageQueries.ts | 6 +++--- test/suites/smoke/test-ethereum-contract-code.ts | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/test/helpers/storageQueries.ts b/test/helpers/storageQueries.ts index 26ac19d9f2..094f7b1198 100644 --- a/test/helpers/storageQueries.ts +++ b/test/helpers/storageQueries.ts @@ -16,7 +16,7 @@ const startReport = (total: () => number) => { const used = process.memoryUsage().heapUsed / 1024 / 1024; log( `🔍️ Queried ${total()} keys @ ${qps.toFixed(0)} keys/sec,` + - ` ${used.toFixed(0)} MB heap used\n` + ` ${used.toFixed(0)} MB heap used\n` ); timer = setTimeout(report, 5000); @@ -51,7 +51,7 @@ export async function processAllStorage( prefixes.map(async (prefix) => limiter.schedule(async () => { let startKey: string | undefined = undefined; - loop: for (; ;) { + loop: for (;;) { // @ts-expect-error _rpcCore is not yet exposed const keys: string = await api._rpcCore.provider.send("state_getKeysPaged", [ prefix, @@ -124,7 +124,7 @@ export async function processRandomStoragePrefixes( prefixes.map(async (prefix) => limiter.schedule(async () => { let startKey: string | undefined = undefined; - loop: for (; ;) { + loop: for (;;) { // @ts-expect-error _rpcCore is not yet exposed const keys: string = await api._rpcCore.provider.send("state_getKeysPaged", [ prefix, diff --git a/test/suites/smoke/test-ethereum-contract-code.ts b/test/suites/smoke/test-ethereum-contract-code.ts index 5ca6cce732..21efcf21ad 100644 --- a/test/suites/smoke/test-ethereum-contract-code.ts +++ b/test/suites/smoke/test-ethereum-contract-code.ts @@ -51,7 +51,6 @@ describeSuite({ } } totalContracts += BigInt(items.length); - }, // WHEN DEBUGGING REPLACE THE EMPTY STRING WITH A PREFIX TO FETCH "" From 5399ac8b2411cda80867fca09881836039b3b152 Mon Sep 17 00:00:00 2001 From: Pablo Labarta Date: Thu, 12 Dec 2024 15:34:43 -0300 Subject: [PATCH 09/14] remove unused import --- test/helpers/storageQueries.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/helpers/storageQueries.ts b/test/helpers/storageQueries.ts index 094f7b1198..dee17ba694 100644 --- a/test/helpers/storageQueries.ts +++ b/test/helpers/storageQueries.ts @@ -1,7 +1,6 @@ import { ApiPromise } from "@polkadot/api"; import Debugger from "debug"; import { rateLimiter } from "./common.js"; -import { randomAsHex } from "@polkadot/util-crypto"; const log = Debugger("test:storageQuery"); @@ -16,7 +15,7 @@ const startReport = (total: () => number) => { const used = process.memoryUsage().heapUsed / 1024 / 1024; log( `🔍️ Queried ${total()} keys @ ${qps.toFixed(0)} keys/sec,` + - ` ${used.toFixed(0)} MB heap used\n` + ` ${used.toFixed(0)} MB heap used\n` ); timer = setTimeout(report, 5000); @@ -51,7 +50,7 @@ export async function processAllStorage( prefixes.map(async (prefix) => limiter.schedule(async () => { let startKey: string | undefined = undefined; - loop: for (;;) { + loop: for (; ;) { // @ts-expect-error _rpcCore is not yet exposed const keys: string = await api._rpcCore.provider.send("state_getKeysPaged", [ prefix, @@ -124,7 +123,7 @@ export async function processRandomStoragePrefixes( prefixes.map(async (prefix) => limiter.schedule(async () => { let startKey: string | undefined = undefined; - loop: for (;;) { + loop: for (; ;) { // @ts-expect-error _rpcCore is not yet exposed const keys: string = await api._rpcCore.provider.send("state_getKeysPaged", [ prefix, From f81bdd3266b25380fcae5499814229d8d65d2b7c Mon Sep 17 00:00:00 2001 From: Pablo Labarta Date: Fri, 13 Dec 2024 11:38:01 -0300 Subject: [PATCH 10/14] fmt --- test/helpers/storageQueries.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/helpers/storageQueries.ts b/test/helpers/storageQueries.ts index dee17ba694..05ac027501 100644 --- a/test/helpers/storageQueries.ts +++ b/test/helpers/storageQueries.ts @@ -15,7 +15,7 @@ const startReport = (total: () => number) => { const used = process.memoryUsage().heapUsed / 1024 / 1024; log( `🔍️ Queried ${total()} keys @ ${qps.toFixed(0)} keys/sec,` + - ` ${used.toFixed(0)} MB heap used\n` + ` ${used.toFixed(0)} MB heap used\n` ); timer = setTimeout(report, 5000); @@ -50,7 +50,7 @@ export async function processAllStorage( prefixes.map(async (prefix) => limiter.schedule(async () => { let startKey: string | undefined = undefined; - loop: for (; ;) { + loop: for (;;) { // @ts-expect-error _rpcCore is not yet exposed const keys: string = await api._rpcCore.provider.send("state_getKeysPaged", [ prefix, @@ -123,7 +123,7 @@ export async function processRandomStoragePrefixes( prefixes.map(async (prefix) => limiter.schedule(async () => { let startKey: string | undefined = undefined; - loop: for (; ;) { + loop: for (;;) { // @ts-expect-error _rpcCore is not yet exposed const keys: string = await api._rpcCore.provider.send("state_getKeysPaged", [ prefix, From ee368e3143df53547b7adbb3072824c5d00927ad Mon Sep 17 00:00:00 2001 From: Pablo Labarta Date: Wed, 18 Dec 2024 12:31:02 -0300 Subject: [PATCH 11/14] remove label from loop --- test/helpers/storageQueries.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/helpers/storageQueries.ts b/test/helpers/storageQueries.ts index 05ac027501..113e7ddbb9 100644 --- a/test/helpers/storageQueries.ts +++ b/test/helpers/storageQueries.ts @@ -15,7 +15,7 @@ const startReport = (total: () => number) => { const used = process.memoryUsage().heapUsed / 1024 / 1024; log( `🔍️ Queried ${total()} keys @ ${qps.toFixed(0)} keys/sec,` + - ` ${used.toFixed(0)} MB heap used\n` + ` ${used.toFixed(0)} MB heap used\n` ); timer = setTimeout(report, 5000); @@ -50,7 +50,7 @@ export async function processAllStorage( prefixes.map(async (prefix) => limiter.schedule(async () => { let startKey: string | undefined = undefined; - loop: for (;;) { + loop: for (; ;) { // @ts-expect-error _rpcCore is not yet exposed const keys: string = await api._rpcCore.provider.send("state_getKeysPaged", [ prefix, @@ -123,7 +123,7 @@ export async function processRandomStoragePrefixes( prefixes.map(async (prefix) => limiter.schedule(async () => { let startKey: string | undefined = undefined; - loop: for (;;) { + while (true) { // @ts-expect-error _rpcCore is not yet exposed const keys: string = await api._rpcCore.provider.send("state_getKeysPaged", [ prefix, @@ -133,7 +133,7 @@ export async function processRandomStoragePrefixes( ]); if (!keys.length) { - break loop; + break; } // @ts-expect-error _rpcCore is not yet exposed @@ -158,7 +158,7 @@ export async function processRandomStoragePrefixes( total += keys.length; if (keys.length !== maxKeys) { - break loop; + break; } startKey = keys[keys.length - 1]; } From 1f438ad858a782e3e528b8e46ca4a4bbd7fc82f9 Mon Sep 17 00:00:00 2001 From: Pablo Labarta Date: Wed, 18 Dec 2024 12:31:32 -0300 Subject: [PATCH 12/14] remove unused fn --- test/helpers/storageQueries.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/test/helpers/storageQueries.ts b/test/helpers/storageQueries.ts index 113e7ddbb9..759a9d0d80 100644 --- a/test/helpers/storageQueries.ts +++ b/test/helpers/storageQueries.ts @@ -172,18 +172,6 @@ export async function processRandomStoragePrefixes( await limiter.disconnect(); } -export async function getStartingKeySample(api: ApiPromise, prefix: string, blockHash: string) { - // @ts-expect-error _rpcCore is not yet exposed - const res: string = await api._rpcCore.provider.send("state_getKeysPaged", [ - prefix, - 1, - "", - blockHash, - ]); - - return res[0]; -} - export const extractStorageKeyComponents = (storageKey: string) => { // The full storage key is composed of // - The 0x prefix (2 characters) From f40c558f83042df421ce5da49b41b9dff6830b7c Mon Sep 17 00:00:00 2001 From: Pablo Labarta Date: Wed, 18 Dec 2024 12:33:59 -0300 Subject: [PATCH 13/14] fmt --- test/helpers/storageQueries.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/helpers/storageQueries.ts b/test/helpers/storageQueries.ts index 759a9d0d80..c0d364cd86 100644 --- a/test/helpers/storageQueries.ts +++ b/test/helpers/storageQueries.ts @@ -15,7 +15,7 @@ const startReport = (total: () => number) => { const used = process.memoryUsage().heapUsed / 1024 / 1024; log( `🔍️ Queried ${total()} keys @ ${qps.toFixed(0)} keys/sec,` + - ` ${used.toFixed(0)} MB heap used\n` + ` ${used.toFixed(0)} MB heap used\n` ); timer = setTimeout(report, 5000); @@ -50,7 +50,7 @@ export async function processAllStorage( prefixes.map(async (prefix) => limiter.schedule(async () => { let startKey: string | undefined = undefined; - loop: for (; ;) { + loop: for (;;) { // @ts-expect-error _rpcCore is not yet exposed const keys: string = await api._rpcCore.provider.send("state_getKeysPaged", [ prefix, From 9495f90607df2fe9b625c55bb97cf0de863cc7e9 Mon Sep 17 00:00:00 2001 From: Pablo Labarta Date: Wed, 18 Dec 2024 12:44:11 -0300 Subject: [PATCH 14/14] appease linter --- test/helpers/storageQueries.ts | 2 +- test/suites/smoke/test-polkadot-decoding.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/helpers/storageQueries.ts b/test/helpers/storageQueries.ts index cf59c6e961..c506d867b3 100644 --- a/test/helpers/storageQueries.ts +++ b/test/helpers/storageQueries.ts @@ -102,7 +102,7 @@ export async function processRandomStoragePrefixes( storagePrefix: string, blockHash: string, processor: (batchResult: { key: `0x${string}`; value: string }[]) => void, - override: string = "" + override = "" ) { const maxKeys = 1000; let total = 0; diff --git a/test/suites/smoke/test-polkadot-decoding.ts b/test/suites/smoke/test-polkadot-decoding.ts index 0c4a2e39c9..cb49db1876 100644 --- a/test/suites/smoke/test-polkadot-decoding.ts +++ b/test/suites/smoke/test-polkadot-decoding.ts @@ -2,7 +2,7 @@ import type { ApiDecoration } from "@polkadot/api/types"; import chalk from "chalk"; import { describeSuite, beforeAll } from "@moonwall/cli"; import { ONE_HOURS } from "@moonwall/util"; -import { ApiPromise } from "@polkadot/api"; +import type { ApiPromise } from "@polkadot/api"; import { extractStorageKeyComponents } from "../../helpers/storageQueries"; import { fail } from "node:assert";