mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 13:21:01 +00:00
Add two new zombienet tests for bridges (manual run) (#3072)
extracted useful code from #2982 This PR: - adds test 2 for Rococo <> Westend bridge: checks that relayer doesn't submit any extra headers while there are no any messages; - adds test 3 for Rococo <> Westend bridge: checks that relayer doesn't submit any extra headers when there are messages; - fixes most of comments from #2439 (like: log names, ability to run specify test number when calling `run-tests.sh`). Right now of all our tests, only test 2 is working (until BHs will be upgraded to use async backing), so you can test it with `./bridges/zombienet/run-tests.sh --test 2` locally.
This commit is contained in:
committed by
GitHub
parent
008e0fe45e
commit
2e6067d768
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
grandpaPalletName: "bridgeRococoGrandpa",
|
||||
parachainsPalletName: "bridgeRococoParachains",
|
||||
messagesPalletName: "bridgeRococoMessages",
|
||||
bridgedBridgeHubParaId: 1013,
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
grandpaPalletName: "bridgeWestendGrandpa",
|
||||
parachainsPalletName: "bridgeWestendParachains",
|
||||
messagesPalletName: "bridgeWestendMessages",
|
||||
bridgedBridgeHubParaId: 1002,
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
const utils = require("./utils");
|
||||
|
||||
async function run(nodeName, networkInfo, args) {
|
||||
const {wsUri, userDefinedTypes} = networkInfo.nodesByName[nodeName];
|
||||
const api = await zombie.connect(wsUri, userDefinedTypes);
|
||||
|
||||
// parse arguments
|
||||
const exitAfterSeconds = Number(args[0]);
|
||||
const bridgedChain = require("./chains/" + args[1]);
|
||||
|
||||
// start listening to new blocks
|
||||
let totalGrandpaHeaders = 0;
|
||||
let totalParachainHeaders = 0;
|
||||
api.rpc.chain.subscribeNewHeads(async function (header) {
|
||||
const apiAtParent = await api.at(header.parentHash);
|
||||
const apiAtCurrent = await api.at(header.hash);
|
||||
const currentEvents = await apiAtCurrent.query.system.events();
|
||||
|
||||
totalGrandpaHeaders += await utils.ensureOnlyMandatoryGrandpaHeadersImported(
|
||||
bridgedChain,
|
||||
apiAtParent,
|
||||
apiAtCurrent,
|
||||
currentEvents,
|
||||
);
|
||||
totalParachainHeaders += await utils.ensureOnlyInitialParachainHeaderImported(
|
||||
bridgedChain,
|
||||
apiAtParent,
|
||||
apiAtCurrent,
|
||||
currentEvents,
|
||||
);
|
||||
});
|
||||
|
||||
// wait given time
|
||||
await new Promise(resolve => setTimeout(resolve, exitAfterSeconds * 1000));
|
||||
// if we haven't seen any new GRANDPA or parachain headers => fail
|
||||
if (totalGrandpaHeaders == 0) {
|
||||
throw new Error("No bridged relay chain headers imported");
|
||||
}
|
||||
if (totalParachainHeaders == 0) {
|
||||
throw new Error("No bridged parachain headers imported");
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { run }
|
||||
@@ -0,0 +1,81 @@
|
||||
const utils = require("./utils");
|
||||
|
||||
async function run(nodeName, networkInfo, args) {
|
||||
const {wsUri, userDefinedTypes} = networkInfo.nodesByName[nodeName];
|
||||
const api = await zombie.connect(wsUri, userDefinedTypes);
|
||||
|
||||
// parse arguments
|
||||
const exitAfterSeconds = Number(args[0]);
|
||||
const bridgedChain = require("./chains/" + args[1]);
|
||||
|
||||
// start listening to new blocks
|
||||
let atLeastOneMessageReceived = false;
|
||||
let atLeastOneMessageDelivered = false;
|
||||
const unsubscribe = await api.rpc.chain.subscribeNewHeads(async function (header) {
|
||||
const apiAtParent = await api.at(header.parentHash);
|
||||
const apiAtCurrent = await api.at(header.hash);
|
||||
const currentEvents = await apiAtCurrent.query.system.events();
|
||||
|
||||
const messagesReceived = currentEvents.find((record) => {
|
||||
return record.event.section == bridgedChain.messagesPalletName
|
||||
&& record.event.method == "MessagesReceived";
|
||||
}) != undefined;
|
||||
const messagesDelivered = currentEvents.find((record) => {
|
||||
return record.event.section == bridgedChain.messagesPalletName &&
|
||||
record.event.method == "MessagesDelivered";
|
||||
}) != undefined;
|
||||
const hasMessageUpdates = messagesReceived || messagesDelivered;
|
||||
atLeastOneMessageReceived = atLeastOneMessageReceived || messagesReceived;
|
||||
atLeastOneMessageDelivered = atLeastOneMessageDelivered || messagesDelivered;
|
||||
|
||||
if (!hasMessageUpdates) {
|
||||
// if there are no any message update transactions, we only expect mandatory GRANDPA
|
||||
// headers and initial parachain headers
|
||||
await utils.ensureOnlyMandatoryGrandpaHeadersImported(
|
||||
bridgedChain,
|
||||
apiAtParent,
|
||||
apiAtCurrent,
|
||||
currentEvents,
|
||||
);
|
||||
await utils.ensureOnlyInitialParachainHeaderImported(
|
||||
bridgedChain,
|
||||
apiAtParent,
|
||||
apiAtCurrent,
|
||||
currentEvents,
|
||||
);
|
||||
} else {
|
||||
const messageTransactions = (messagesReceived ? 1 : 0) + (messagesDelivered ? 1 : 0);
|
||||
|
||||
// otherwise we only accept at most one GRANDPA header
|
||||
const newGrandpaHeaders = utils.countGrandpaHeaderImports(bridgedChain, currentEvents);
|
||||
if (newGrandpaHeaders > 1) {
|
||||
utils.logEvents(currentEvents);
|
||||
throw new Error("Unexpected relay chain header import: " + newGrandpaHeaders + " / " + messageTransactions);
|
||||
}
|
||||
|
||||
// ...and at most one parachain header
|
||||
const newParachainHeaders = utils.countParachainHeaderImports(bridgedChain, currentEvents);
|
||||
if (newParachainHeaders > 1) {
|
||||
utils.logEvents(currentEvents);
|
||||
throw new Error("Unexpected parachain header import: " + newParachainHeaders + " / " + messageTransactions);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// wait until we have received + delivered messages OR until timeout
|
||||
await utils.pollUntil(
|
||||
exitAfterSeconds,
|
||||
() => { return atLeastOneMessageReceived && atLeastOneMessageDelivered; },
|
||||
() => { unsubscribe(); },
|
||||
() => {
|
||||
if (!atLeastOneMessageReceived) {
|
||||
throw new Error("No messages received from bridged chain");
|
||||
}
|
||||
if (!atLeastOneMessageDelivered) {
|
||||
throw new Error("No messages delivered to bridged chain");
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = { run }
|
||||
@@ -0,0 +1,103 @@
|
||||
module.exports = {
|
||||
logEvents: function(events) {
|
||||
let stringifiedEvents = "";
|
||||
events.forEach((record) => {
|
||||
if (stringifiedEvents != "") {
|
||||
stringifiedEvents += ", ";
|
||||
}
|
||||
stringifiedEvents += record.event.section + "::" + record.event.method;
|
||||
});
|
||||
console.log("Block events: " + stringifiedEvents);
|
||||
},
|
||||
countGrandpaHeaderImports: function(bridgedChain, events) {
|
||||
return events.reduce(
|
||||
(count, record) => {
|
||||
const { event } = record;
|
||||
if (event.section == bridgedChain.grandpaPalletName && event.method == "UpdatedBestFinalizedHeader") {
|
||||
count += 1;
|
||||
}
|
||||
return count;
|
||||
},
|
||||
0,
|
||||
);
|
||||
},
|
||||
countParachainHeaderImports: function(bridgedChain, events) {
|
||||
return events.reduce(
|
||||
(count, record) => {
|
||||
const { event } = record;
|
||||
if (event.section == bridgedChain.parachainsPalletName && event.method == "UpdatedParachainHead") {
|
||||
count += 1;
|
||||
}
|
||||
return count;
|
||||
},
|
||||
0,
|
||||
);
|
||||
},
|
||||
pollUntil: async function(
|
||||
timeoutInSecs,
|
||||
predicate,
|
||||
cleanup,
|
||||
onFailure,
|
||||
) {
|
||||
const begin = new Date().getTime();
|
||||
const end = begin + timeoutInSecs * 1000;
|
||||
while (new Date().getTime() < end) {
|
||||
if (predicate()) {
|
||||
cleanup();
|
||||
return;
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
}
|
||||
|
||||
cleanup();
|
||||
onFailure();
|
||||
},
|
||||
ensureOnlyMandatoryGrandpaHeadersImported: async function(
|
||||
bridgedChain,
|
||||
apiAtParent,
|
||||
apiAtCurrent,
|
||||
currentEvents,
|
||||
) {
|
||||
// remember id of bridged relay chain GRANDPA authorities set at parent block
|
||||
const authoritySetAtParent = await apiAtParent.query[bridgedChain.grandpaPalletName].currentAuthoritySet();
|
||||
const authoritySetIdAtParent = authoritySetAtParent["setId"];
|
||||
|
||||
// now read the id of bridged relay chain GRANDPA authorities set at current block
|
||||
const authoritySetAtCurrent = await apiAtCurrent.query[bridgedChain.grandpaPalletName].currentAuthoritySet();
|
||||
const authoritySetIdAtCurrent = authoritySetAtCurrent["setId"];
|
||||
|
||||
// we expect to see no more than `authoritySetIdAtCurrent - authoritySetIdAtParent` new GRANDPA headers
|
||||
const maxNewGrandpaHeaders = authoritySetIdAtCurrent - authoritySetIdAtParent;
|
||||
const newGrandpaHeaders = module.exports.countGrandpaHeaderImports(bridgedChain, currentEvents);
|
||||
|
||||
// check that our assumptions are correct
|
||||
if (newGrandpaHeaders > maxNewGrandpaHeaders) {
|
||||
module.exports.logEvents(currentEvents);
|
||||
throw new Error("Unexpected relay chain header import: " + newGrandpaHeaders + " / " + maxNewGrandpaHeaders);
|
||||
}
|
||||
|
||||
return newGrandpaHeaders;
|
||||
},
|
||||
ensureOnlyInitialParachainHeaderImported: async function(
|
||||
bridgedChain,
|
||||
apiAtParent,
|
||||
apiAtCurrent,
|
||||
currentEvents,
|
||||
) {
|
||||
// remember whether we already know bridged parachain header at a parent block
|
||||
const bestBridgedParachainHeader = await apiAtParent.query[bridgedChain.parachainsPalletName].parasInfo(bridgedChain.bridgedBridgeHubParaId);;
|
||||
const hasBestBridgedParachainHeader = bestBridgedParachainHeader.isSome;
|
||||
|
||||
// we expect to see: no more than `1` bridged parachain header if there were no parachain header before.
|
||||
const maxNewParachainHeaders = hasBestBridgedParachainHeader ? 0 : 1;
|
||||
const newParachainHeaders = module.exports.countParachainHeaderImports(bridgedChain, currentEvents);
|
||||
|
||||
// check that our assumptions are correct
|
||||
if (newParachainHeaders > maxNewParachainHeaders) {
|
||||
module.exports.logEvents(currentEvents);
|
||||
throw new Error("Unexpected parachain header import: " + newParachainHeaders + " / " + maxNewParachainHeaders);
|
||||
}
|
||||
|
||||
return newParachainHeaders;
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user