Skip to content
Snippets Groups Projects
Commit 71aa0b09 authored by Robert Hambrock's avatar Robert Hambrock Committed by GitHub
Browse files

BEEFY & MMR zombienet tests (#7068)


* test that successfully verify self-generated proof

* verify proof result on all unpaused nodes

* tighten interface: reuse connection

* generate the proof on arbitrary node

* s/stub-name/validator

seems this doesn't pass some regex

* rename script

* add basic mmr-leaves test

* documentation formatting

* check lower bound on mmr leaves

* test beefy rpc: finalized heads match

* test mmr api: stateless proofs

* set lower bound on number of leaves

* change leaves in proof generation

* remove TODOs

* cleanup: consistently ignore zndsl name arg

* refactor: simplify returns

Co-authored-by: default avatarSerban Iorga <serban@parity.io>

* lax finalized head test

Co-authored-by: default avatarAdrian Catangiu <adrian@parity.io>

* fixup! refactor: simplify returns

* refactor out getApis

Co-authored-by: default avatarSerban Iorga <serban@parity.io>

* split out paused validator from group

* refactor: don't ignore node arg

don't randomize selection of proof generating / finalized head
retrieving node, but use the node arg for this.

* only check min block height, not relative

Co-authored-by: default avatarAdrian Catangiu <adrian@parity.io>

* verify finalized heads share same canonical chain

picks the node with the highest finalized head, gets its blockchain
headers since genesis, and verifies that all other nodes' finalized
heads are in said blockchain.

* fixup! split out paused validator from group

Co-authored-by: default avatarSerban Iorga <serban@parity.io>

---------

Co-authored-by: default avatarSerban Iorga <serban@parity.io>
Co-authored-by: default avatarAdrian Catangiu <adrian@parity.io>
parent 87159f8a
No related merge requests found
......@@ -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.
......
......@@ -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"]
......@@ -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
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 };
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 };
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 };
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 };
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment