[testnet] Add AssetHubRococo <-> AssetHubWestend asset bridging support (#1967)

## Summary

Asset bridging support for AssetHub**Rococo** <-> AssetHub**Wococo** was
added [here](https://github.com/paritytech/polkadot-sdk/pull/1215), so
now we aim to bridge AssetHub**Rococo** and AssetHub**Westend**. (And
perhaps retire AssetHubWococo and the Wococo chains).

## Solution

**bridge-hub-westend-runtime**
- added new runtime as a copy of `bridge-hub-rococo-runtime`
- added support for bridging to `BridgeHubRococo`
- added tests and benchmarks

**bridge-hub-rococo-runtime**
- added support for bridging to `BridgeHubWestend`
- added tests and benchmarks
- internal refactoring by splitting bridge configuration per network,
e.g., `bridge_to_whatevernetwork_config.rs`.

**asset-hub-rococo-runtime**
- added support for asset bridging to `AssetHubWestend` (allows to
receive only WNDs)
- added new xcm router for `Westend`
- added tests and benchmarks

**asset-hub-westend-runtime**
- added support for asset bridging to `AssetHubRococo` (allows to
receive only ROCs)
- added new xcm router for `Rococo`
- added tests and benchmarks

## Deployment

All changes will be deployed as a part of
https://github.com/paritytech/polkadot-sdk/issues/1988.

## TODO

- [x] benchmarks for all pallet instances
- [x] integration tests
- [x] local run scripts


Relates to:
https://github.com/paritytech/parity-bridges-common/issues/2602
Relates to: https://github.com/paritytech/polkadot-sdk/issues/1988

---------

Co-authored-by: command-bot <>
Co-authored-by: Adrian Catangiu <adrian@parity.io>
Co-authored-by: joe petrowski <25483142+joepetrowski@users.noreply.github.com>
This commit is contained in:
Branislav Kontur
2023-11-02 00:39:49 +01:00
committed by GitHub
parent c66ae375e6
commit 1b1fab0da3
112 changed files with 10028 additions and 1638 deletions
+31
View File
@@ -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 Parachain 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.
@@ -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 }
@@ -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 }
@@ -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
View File
@@ -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
View File
@@ -0,0 +1,5 @@
#!/bin/bash
pushd $POLKADOT_SDK_FOLDER/cumulus/scripts
./bridges_rococo_wococo.sh $1
popd
+14
View File
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,5 @@
#!/bin/bash
pushd $POLKADOT_SDK_FOLDER/cumulus/scripts
./bridges_rococo_wococo.sh run-relay
popd