diff --git a/zombienet_tests/README.md b/zombienet_tests/README.md index 021d3643e7f9..5a4c97355f09 100644 --- a/zombienet_tests/README.md +++ b/zombienet_tests/README.md @@ -25,7 +25,7 @@ To run any test locally use the native provider (`zombienet test -p native ...`) To build them use: * adder-collator -> `cargo build --profile testnet -p test-parachain-adder-collator` * undying-collator -> `cargo build --profile testnet -p test-parachain-undying-collator` -* malus -> cargo build --profile testnet -p polkadot-test-malus +* malus -> `cargo build --profile testnet -p polkadot-test-malus` * polkadot (in polkadot repo) and polkadot-collator (in cumulus repo) -> `cargo build --profile testnet` One solution is to use the `.set_env` file (from this directory) and fill the `CUSTOM_PATHS` before *source* it to patch the PATH of your system to find the binaries you just built. diff --git a/zombienet_tests/functional/0003-beefy-and-mmr.toml b/zombienet_tests/functional/0003-beefy-and-mmr.toml index 1608976abdf2..bea5ac1ba64f 100644 --- a/zombienet_tests/functional/0003-beefy-and-mmr.toml +++ b/zombienet_tests/functional/0003-beefy-and-mmr.toml @@ -8,5 +8,9 @@ command = "polkadot" [[relaychain.node_groups]] name = "validator" -count = 4 +count = 3 +args = ["--log=beefy=debug", "--beefy", "--enable-offchain-indexing=true"] + +[[relaychain.nodes]] +name = "validator-unstable" args = ["--log=beefy=debug", "--beefy", "--enable-offchain-indexing=true"] diff --git a/zombienet_tests/functional/0003-beefy-and-mmr.zndsl b/zombienet_tests/functional/0003-beefy-and-mmr.zndsl index c927a671658d..8300ef051f09 100644 --- a/zombienet_tests/functional/0003-beefy-and-mmr.zndsl +++ b/zombienet_tests/functional/0003-beefy-and-mmr.zndsl @@ -3,45 +3,37 @@ Network: ./0003-beefy-and-mmr.toml Creds: config # Check authority status. -validator-0: reports node_roles is 4 -validator-1: reports node_roles is 4 -validator-2: reports node_roles is 4 -validator-3: reports node_roles is 4 +validator: reports node_roles is 4 +validator-unstable: reports node_roles is 4 # BEEFY sanity checks. -validator-0: reports substrate_beefy_validator_set_id is 0 -validator-1: reports substrate_beefy_validator_set_id is 0 -validator-2: reports substrate_beefy_validator_set_id is 0 -validator-3: reports substrate_beefy_validator_set_id is 0 +validator: reports substrate_beefy_validator_set_id is 0 +validator-unstable: reports substrate_beefy_validator_set_id is 0 # Verify voting happens and 1st mandatory block is finalized within 1st session. -validator-0: reports substrate_beefy_best_block is at least 1 within 60 seconds -validator-1: reports substrate_beefy_best_block is at least 1 within 60 seconds -validator-2: reports substrate_beefy_best_block is at least 1 within 60 seconds -validator-3: reports substrate_beefy_best_block is at least 1 within 60 seconds +validator: reports substrate_beefy_best_block is at least 1 within 60 seconds +validator-unstable: reports substrate_beefy_best_block is at least 1 within 60 seconds -# Pause validator-3 and test chain is making progress without it. -validator-3: pause +# Pause validator-unstable and test chain is making progress without it. +validator-unstable: pause # Verify validator sets get changed on new sessions. -validator-0: reports substrate_beefy_validator_set_id is at least 1 within 70 seconds -validator-1: reports substrate_beefy_validator_set_id is at least 1 within 70 seconds -validator-2: reports substrate_beefy_validator_set_id is at least 1 within 70 seconds +validator: reports substrate_beefy_validator_set_id is at least 1 within 70 seconds # Check next session too. -validator-0: reports substrate_beefy_validator_set_id is at least 2 within 130 seconds -validator-1: reports substrate_beefy_validator_set_id is at least 2 within 130 seconds -validator-2: reports substrate_beefy_validator_set_id is at least 2 within 130 seconds +validator: reports substrate_beefy_validator_set_id is at least 2 within 130 seconds # Verify voting happens and blocks are being finalized for new sessions too: # since we verified we're at least in the 3rd session, verify BEEFY finalized mandatory #21. -validator-0: reports substrate_beefy_best_block is at least 21 within 130 seconds -validator-1: reports substrate_beefy_best_block is at least 21 within 130 seconds -validator-2: reports substrate_beefy_best_block is at least 21 within 130 seconds +validator: reports substrate_beefy_best_block is at least 21 within 130 seconds -# TODO (issue #11972): Custom JS to test BEEFY RPCs -# TODO (issue #11972): Custom JS to test MMR RPCs +# Custom JS to test BEEFY RPCs. +validator-0: js-script ./0003-beefy-finalized-heads.js with "validator-0,validator-1,validator-2" return is 1 within 5 seconds -# Resume validator-3 and verify it imports all BEEFY justification and catches up. -validator-3: resume -validator-3: reports substrate_beefy_validator_set_id is at least 2 within 30 seconds -validator-3: reports substrate_beefy_best_block is at least 21 within 30 seconds +# Custom JS to test MMR RPCs. +validator: js-script ./0003-mmr-leaves.js with "21" return is 1 within 5 seconds +validator: js-script ./0003-mmr-generate-and-verify-proof.js with "validator-0,validator-1,validator-2" return is 1 within 5 seconds + +# Resume validator-unstable and verify it imports all BEEFY justification and catches up. +validator-unstable: resume +validator-unstable: reports substrate_beefy_validator_set_id is at least 2 within 30 seconds +validator-unstable: reports substrate_beefy_best_block is at least 21 within 30 seconds diff --git a/zombienet_tests/functional/0003-beefy-finalized-heads.js b/zombienet_tests/functional/0003-beefy-finalized-heads.js new file mode 100644 index 000000000000..9696a540a18c --- /dev/null +++ b/zombienet_tests/functional/0003-beefy-finalized-heads.js @@ -0,0 +1,35 @@ +const common = require('./0003-common.js'); + +async function run(_, networkInfo, nodeNames) { + const apis = await common.getApis(networkInfo, nodeNames); + + const finalizedHeads = await Promise.all( + Object.entries(apis).map(async ([nodeName, api]) => { + const finalizedHead = await api.rpc.beefy.getFinalizedHead(); + return { nodeName, finalizedHead, finalizedHeight: await api.rpc.chain.getHeader(finalizedHead).then((header) => header.number) }; + }) + ); + + // select the node with the highest finalized height + const highestFinalizedHeight = finalizedHeads.reduce( + (acc, { nodeName, finalizedHeight }) => + finalizedHeight >= acc.finalizedHeight + ? { nodeName, finalizedHeight } + : acc, + { nodeName: 'validator', finalizedHeight: 0 } + ); + + // get all block hashes up until the highest finalized height + const blockHashes = []; + for (let blockNumber = 0; blockNumber <= highestFinalizedHeight.finalizedHeight; blockNumber++) { + const blockHash = await apis[highestFinalizedHeight.nodeName].rpc.chain.getBlockHash(blockNumber); + blockHashes.push(blockHash); + } + + // verify that height(finalized_head) is at least as high as the substrate_beefy_best_block test already verified + return finalizedHeads.every(({ finalizedHead, finalizedHeight }) => + finalizedHeight >= 21 && finalizedHead.toHex() === blockHashes[finalizedHeight].toHex() + ) +} + +module.exports = { run }; diff --git a/zombienet_tests/functional/0003-common.js b/zombienet_tests/functional/0003-common.js new file mode 100644 index 000000000000..743828ec6b9e --- /dev/null +++ b/zombienet_tests/functional/0003-common.js @@ -0,0 +1,16 @@ +async function getApis(networkInfo, nodeNames) { + const connectionPromises = nodeNames.map(async (nodeName) => { + const { wsUri, userDefinedTypes } = networkInfo.nodesByName[nodeName]; + const connection = await zombie.connect(wsUri, userDefinedTypes); + return { nodeName, connection }; + }); + + const connections = await Promise.all(connectionPromises); + + return connections.reduce((map, { nodeName, connection }) => { + map[nodeName] = connection; + return map; + }, {}); +} + +module.exports = { getApis }; diff --git a/zombienet_tests/functional/0003-mmr-generate-and-verify-proof.js b/zombienet_tests/functional/0003-mmr-generate-and-verify-proof.js new file mode 100644 index 000000000000..6583173e40c3 --- /dev/null +++ b/zombienet_tests/functional/0003-mmr-generate-and-verify-proof.js @@ -0,0 +1,26 @@ +const common = require('./0003-common.js'); + +async function run(nodeName, networkInfo, nodeNames) { + const apis = await common.getApis(networkInfo, nodeNames); + + const proof = await apis[nodeName].rpc.mmr.generateProof([1, 9, 20]); + + const root = await apis[nodeName].rpc.mmr.root() + + const proofVerifications = await Promise.all( + Object.values(apis).map(async (api) => { + return api.rpc.mmr.verifyProof(proof); + }) + ); + + const proofVerificationsStateless = await Promise.all( + Object.values(apis).map(async (api) => { + return api.rpc.mmr.verifyProofStateless(root, proof); + }) + ); + + // check that all nodes accepted the proof + return proofVerifications.every((proofVerification) => proofVerification) && proofVerificationsStateless.every((proofVerification) => proofVerification) +} + +module.exports = { run }; diff --git a/zombienet_tests/functional/0003-mmr-leaves.js b/zombienet_tests/functional/0003-mmr-leaves.js new file mode 100644 index 000000000000..df58194c5769 --- /dev/null +++ b/zombienet_tests/functional/0003-mmr-leaves.js @@ -0,0 +1,9 @@ +async function run(nodeName, networkInfo, args) { + const { wsUri, userDefinedTypes } = networkInfo.nodesByName[nodeName]; + const api = await zombie.connect(wsUri, userDefinedTypes); + + const mmrLeaves = await api.query.mmr.numberOfLeaves(); + return mmrLeaves.toNumber() >= args[0] +} + +module.exports = { run };