Skip to content

Commit

Permalink
Add basic zombienet test to be used in the future (paritytech#2649) (p…
Browse files Browse the repository at this point in the history
…aritytech#2660)

* add basic zombienet test to be used in the future

* removed unneeded variables

* add README.md for zombienet folder
  • Loading branch information
svyatonik authored Oct 30, 2023
1 parent 93b6b3f commit 55eb44e
Show file tree
Hide file tree
Showing 10 changed files with 281 additions and 0 deletions.
31 changes: 31 additions & 0 deletions zombienet/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
### Bridges Tests for Local Rococo <> Wococo Bridge

This folder contains [zombienet](https://github.com/paritytech/zombienet/) based integration tests for both
onchain and offchain bridges code. Due to some
[technical diffuculties](https://github.com/paritytech/parity-bridges-common/pull/2649#issue-1965339051), we
are using native zombienet provider, which means that you need to build some binaries locally.

To start those tests, you need to:

- download latest [zombienet release](https://github.com/paritytech/zombienet/releases);

- build polkadot binary by running `cargo build -p polkadot --release` command in the
[`polkadot-sdk`](https://github.com/paritytech/polkadot-sdk) repository clone;

- build polkadot binary by running `cargo build -p polkadot-parachain-bin --release` command in the
[`polkadot-sdk`](https://github.com/paritytech/polkadot-sdk) repository clone;

- ensure that you have [`node`](https://nodejs.org/en) installed. Additionally, we'll need globally installed
`polkadot/api-cli` package (use `npm install -g @polkadot/api-cli@beta` to install it);

- build substrate relay by running `cargo build -p substrate-relay --release` command in the
[`parity-bridges-common`](https://github.com/paritytech/parity-bridges-common) repository clone.

- copy fresh `substrate-relay` binary, built in previous point, to the `~/local_bridge_testing/bin/substrate-relay`;

- change the `POLKADOT_SDK_FOLDER` and `ZOMBIENET_BINARY_PATH` (and ensure that the nearby variables
have correct values) in the `./run-tests.sh`.

After that, you could run tests with the `./run-tests.sh` command. Hopefully, it'll show the
"All tests have completed successfully" message in the end. Otherwise, it'll print paths to zombienet
process logs, which, in turn, may be used to track locations of all spinned relay and parachain nodes.
25 changes: 25 additions & 0 deletions zombienet/helpers/best-finalized-header-at-bridged-chain.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
async function run(nodeName, networkInfo, args) {
const {wsUri, userDefinedTypes} = networkInfo.nodesByName[nodeName];
const api = await zombie.connect(wsUri, userDefinedTypes);

// TODO: could be replaced with https://github.com/polkadot-js/api/issues/4930 (depends on metadata v15) later
const bridgedChainName = args[0];
const expectedBridgedChainHeaderNumber = Number(args[1]);
const runtimeApiMethod = bridgedChainName + "FinalityApi_best_finalized";

while (true) {
const encodedBestFinalizedHeaderId = await api.rpc.state.call(runtimeApiMethod, []);
const bestFinalizedHeaderId = api.createType("Option<BpRuntimeHeaderId>", encodedBestFinalizedHeaderId);
if (bestFinalizedHeaderId.isSome) {
const bestFinalizedHeaderNumber = Number(bestFinalizedHeaderId.unwrap().toHuman()[0]);
if (bestFinalizedHeaderNumber > expectedBridgedChainHeaderNumber) {
return bestFinalizedHeaderNumber;
}
}

// else sleep and retry
await new Promise((resolve) => setTimeout(resolve, 12000));
}
}

module.exports = { run }
28 changes: 28 additions & 0 deletions zombienet/helpers/relayer-rewards.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
async function run(nodeName, networkInfo, args) {
const {wsUri, userDefinedTypes} = networkInfo.nodesByName[nodeName];
const api = await zombie.connect(wsUri, userDefinedTypes);

// TODO: could be replaced with https://github.com/polkadot-js/api/issues/4930 (depends on metadata v15) later
const relayerAccountAddress = args[0];
const laneId = args[1];
const bridgedChainId = args[2];
const relayerFundOwner = args[3];
const expectedRelayerReward = BigInt(args[4]);
while (true) {
const relayerReward = await api.query.bridgeRelayers.relayerRewards(
relayerAccountAddress,
{ laneId: laneId, bridgedChainId: bridgedChainId, owner: relayerFundOwner }
);
if (relayerReward.isSome) {
const relayerRewardBalance = relayerReward.unwrap().toBigInt();
if (relayerRewardBalance > expectedRelayerReward) {
return relayerRewardBalance;
}
}

// else sleep and retry
await new Promise((resolve) => setTimeout(resolve, 12000));
}
}

module.exports = { run }
26 changes: 26 additions & 0 deletions zombienet/helpers/wrapped-assets-balance.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
async function run(nodeName, networkInfo, args) {
const {wsUri, userDefinedTypes} = networkInfo.nodesByName[nodeName];
const api = await zombie.connect(wsUri, userDefinedTypes);

// TODO: could be replaced with https://github.com/polkadot-js/api/issues/4930 (depends on metadata v15) later
const accountAddress = args[0];
const expectedForeignAssetBalance = BigInt(args[1]);
const bridgedNetworkName = args[2];
while (true) {
const foreignAssetAccount = await api.query.foreignAssets.account(
{ parents: 2, interior: { X1: { GlobalConsensus: bridgedNetworkName } } },
accountAddress
);
if (foreignAssetAccount.isSome) {
const foreignAssetAccountBalance = foreignAssetAccount.unwrap().balance.toBigInt();
if (foreignAssetAccountBalance > expectedForeignAssetBalance) {
return foreignAssetAccountBalance;
}
}

// else sleep and retry
await new Promise((resolve) => setTimeout(resolve, 12000));
}
}

module.exports = { run }
97 changes: 97 additions & 0 deletions zombienet/run-tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#!/bin/bash
#set -eu
shopt -s nullglob

trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT

# assuming that we'll be using native provide && all processes will be executing locally
# (we need absolute paths here, because they're used when scripts are called by zombienet from tmp folders)
export POLKADOT_SDK_FOLDER=`realpath $(dirname "$0")/../..`
export BRIDGE_TESTS_FOLDER=$POLKADOT_SDK_FOLDER/bridges/zombienet/tests
export POLKADOT_BINARY_PATH=$POLKADOT_SDK_FOLDER/target/release/polkadot
export POLKADOT_PARACHAIN_BINARY_PATH=$POLKADOT_SDK_FOLDER/target/release/polkadot-parachain
export POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_ROCOCO=$POLKADOT_PARACHAIN_BINARY_PATH
export POLKADOT_PARACHAIN_BINARY_PATH_FOR_ASSET_HUB_WOCOCO=$POLKADOT_PARACHAIN_BINARY_PATH
export ZOMBIENET_BINARY_PATH=~/local_bridge_testing/bin/zombienet-linux

# bridge configuration
export LANE_ID="00000001"

# tests configuration
ALL_TESTS_FOLDER=`mktemp -d`

function start_coproc() {
local command=$1
local name=$2
local coproc_log=`mktemp -p $TEST_FOLDER`
coproc COPROC {
$command >$coproc_log 2>&1
}
TEST_COPROCS[$COPROC_PID, 0]=$name
TEST_COPROCS[$COPROC_PID, 1]=$coproc_log
echo "Spawned $name coprocess. StdOut + StdErr: $coproc_log"

return $COPROC_PID
}

# execute every test from tests folder
TEST_INDEX=1
while true
do
declare -A TEST_COPROCS
TEST_COPROCS_COUNT=0
TEST_PREFIX=$(printf "%04d" $TEST_INDEX)

# it'll be used by the `sync-exit.sh` script
export TEST_FOLDER=`mktemp -d -p $ALL_TESTS_FOLDER`

# check if there are no more tests
zndsl_files=($BRIDGE_TESTS_FOLDER/$TEST_PREFIX-*.zndsl)
if [ ${#zndsl_files[@]} -eq 0 ]; then
break
fi

# start relay
if [ -f $BRIDGE_TESTS_FOLDER/$TEST_PREFIX-start-relay.sh ]; then
start_coproc "${BRIDGE_TESTS_FOLDER}/${TEST_PREFIX}-start-relay.sh" "relay"
RELAY_COPROC=$COPROC_PID
((TEST_COPROCS_COUNT++))
fi
# start tests
for zndsl_file in "${zndsl_files[@]}"; do
start_coproc "$ZOMBIENET_BINARY_PATH --provider native test $zndsl_file" "$zndsl_file"
echo -n "1">>$TEST_FOLDER/exit-sync
((TEST_COPROCS_COUNT++))
done
# wait until all tests are completed
relay_exited=0
for n in `seq 1 $TEST_COPROCS_COUNT`; do
wait -n -p COPROC_PID
exit_code=$?
coproc_name=${TEST_COPROCS[$COPROC_PID, 0]}
coproc_log=${TEST_COPROCS[$COPROC_PID, 1]}
coproc_stdout=$(cat $coproc_log)
relay_exited=$(expr "${coproc_name}" == "relay")
echo "Process $coproc_name has finished with exit code: $exit_code"

# if exit code is not zero, exit
if [ $exit_code -ne 0 ]; then
echo "====================================================================="
echo "=== Shutting down. Log of failed process below ==="
echo "====================================================================="
echo $coproc_stdout
exit 1
fi

# if last test has exited, exit relay too
if [ $n -eq $(($TEST_COPROCS_COUNT - 1)) ] && [ $relay_exited -eq 0 ]; then
kill $RELAY_COPROC
break
fi
done
((TEST_INDEX++))
done

echo "====================================================================="
echo "=== All tests have completed successfully ==="
echo "====================================================================="
5 changes: 5 additions & 0 deletions zombienet/scripts/invoke-script.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash

pushd $POLKADOT_SDK_FOLDER/cumulus/scripts
./bridges_rococo_wococo.sh $1
popd
14 changes: 14 additions & 0 deletions zombienet/scripts/sync-exit.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash
set -e

# every network adds a char to the file, let's remove ours
truncate -s -1 $TEST_FOLDER/exit-sync

# when all chars are removed, then our test is done
while true
do
if [ `stat --printf="%s" $TEST_FOLDER/exit-sync` -eq 0 ]; then
exit
fi
sleep 100
done
25 changes: 25 additions & 0 deletions zombienet/tests/0001-asset-transfer-works-rococo-to-wococo.zndsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Description: User is able to transfer ROC from Rococo Asset Hub to Wococo Asset Hub
Network: ../../../cumulus/zombienet/bridge-hubs/bridge_hub_wococo_local_network.toml
Creds: config

# step 1: initialize Wococo asset hub
asset-hub-wococo-collator1: run ../scripts/invoke-script.sh with "init-asset-hub-wococo-local" within 120 seconds

# step 2: initialize Wococo bridge hub
bridge-hub-wococo-collator1: run ../scripts/invoke-script.sh with "init-bridge-hub-wococo-local" within 120 seconds

# step 3: relay is started elsewhere - let's wait until with-Rococo GRANPDA pallet is initialized at Wococo
bridge-hub-wococo-collator1: js-script ../helpers/best-finalized-header-at-bridged-chain.js with "Rococo,0" within 400 seconds

# step 2: send WOC to Rococo
asset-hub-wococo-collator1: run ../scripts/invoke-script.sh with "reserve-transfer-assets-from-asset-hub-wococo-local" within 60 seconds

# step 3: elsewhere Rococo has sent ROC to //Alice - let's wait for it
asset-hub-wococo-collator1: js-script ../helpers/wrapped-assets-balance.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,0,Rococo" within 600 seconds

# step 4: check that the relayer //Charlie is rewarded by both our AH and target AH
bridge-hub-wococo-collator1: js-script ../helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000001,0x6268726F,BridgedChain,0" within 300 seconds
bridge-hub-wococo-collator1: js-script ../helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000001,0x6268726F,ThisChain,0" within 300 seconds

# wait until other network test has completed OR exit with an error too
asset-hub-wococo-collator1: run ../scripts/sync-exit.sh within 600 seconds
25 changes: 25 additions & 0 deletions zombienet/tests/0001-asset-transfer-works-wococo-to-rococo.zndsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Description: User is able to transfer WOC from Wococo Asset Hub to Rococo Asset Hub
Network: ../../../cumulus/zombienet/bridge-hubs/bridge_hub_rococo_local_network.toml
Creds: config

# step 1: initialize Rococo asset hub
asset-hub-rococo-collator1: run ../scripts/invoke-script.sh with "init-asset-hub-rococo-local" within 120 seconds

# step 2: initialize Rococo bridge hub
bridge-hub-rococo-collator1: run ../scripts/invoke-script.sh with "init-bridge-hub-rococo-local" within 120 seconds

# step 3: relay is started elsewhere - let's wait until with-Wococo GRANPDA pallet is initialized at Rococo
bridge-hub-rococo-collator1: js-script ../helpers/best-finalized-header-at-bridged-chain.js with "Wococo,0" within 400 seconds

# step 4: send ROC to Wococo
asset-hub-rococo-collator1: run ../scripts/invoke-script.sh with "reserve-transfer-assets-from-asset-hub-rococo-local" within 60 seconds

# step 5: elsewhere Wococo has sent WOC to //Alice - let's wait for it
asset-hub-rococo-collator1: js-script ../helpers/wrapped-assets-balance.js with "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY,0,Wococo" within 600 seconds

# step 6: check that the relayer //Charlie is rewarded by both our AH and target AH
bridge-hub-rococo-collator1: js-script ../helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000001,0x6268776F,BridgedChain,0" within 300 seconds
bridge-hub-rococo-collator1: js-script ../helpers/relayer-rewards.js with "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y,0x00000001,0x6268776F,ThisChain,0" within 300 seconds

# wait until other network test has completed OR exit with an error too
asset-hub-rococo-collator1: run ../scripts/sync-exit.sh within 600 seconds
5 changes: 5 additions & 0 deletions zombienet/tests/0001-start-relay.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash

pushd $POLKADOT_SDK_FOLDER/cumulus/scripts
./bridges_rococo_wococo.sh run-relay
popd

0 comments on commit 55eb44e

Please sign in to comment.