-
Notifications
You must be signed in to change notification settings - Fork 709
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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.
- Loading branch information
Showing
16 changed files
with
421 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
module.exports = { | ||
grandpaPalletName: "bridgeRococoGrandpa", | ||
parachainsPalletName: "bridgeRococoParachains", | ||
messagesPalletName: "bridgeRococoMessages", | ||
bridgedBridgeHubParaId: 1013, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
module.exports = { | ||
grandpaPalletName: "bridgeWestendGrandpa", | ||
parachainsPalletName: "bridgeWestendParachains", | ||
messagesPalletName: "bridgeWestendMessages", | ||
bridgedBridgeHubParaId: 1002, | ||
} |
44 changes: 44 additions & 0 deletions
44
bridges/zombienet/helpers/only-mandatory-headers-synced-when-idle.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 } |
81 changes: 81 additions & 0 deletions
81
bridges/zombienet/helpers/only-required-headers-synced-when-idle.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
#!/bin/bash | ||
|
||
INVOKE_LOG=`mktemp -p $TEST_FOLDER invoke.XXXXX` | ||
|
||
pushd $POLKADOT_SDK_FOLDER/cumulus/scripts | ||
./bridges_rococo_westend.sh $1 | ||
./bridges_rococo_westend.sh $1 >$INVOKE_LOG 2>&1 | ||
popd |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
#!/bin/bash | ||
|
||
RELAY_LOG=`mktemp -p $TEST_FOLDER relay.XXXXX` | ||
|
||
pushd $POLKADOT_SDK_FOLDER/cumulus/scripts | ||
./bridges_rococo_westend.sh run-relay >$RELAY_LOG 2>&1& | ||
popd |
Oops, something went wrong.