diff --git a/kurtosis-devnet/tests/boilerplate.sh b/kurtosis-devnet/tests/boilerplate.sh index 70e088ab7f3d5..bc3f101edc21f 100644 --- a/kurtosis-devnet/tests/boilerplate.sh +++ b/kurtosis-devnet/tests/boilerplate.sh @@ -3,18 +3,18 @@ set -euo pipefail # Default values -DEVNET="" ENVIRONMENT="" +PERSPECTIVE="external" # Parse command line arguments while [[ $# -gt 0 ]]; do case "$1" in - --devnet) - DEVNET="$2" + --environment) + ENVIRONMENT=$(realpath "$2") shift 2 ;; - --environment) - ENVIRONMENT="$2" + --perspective) + PERSPECTIVE="$2" shift 2 ;; *) @@ -25,12 +25,86 @@ while [[ $# -gt 0 ]]; do done # Validate required arguments -if [ -z "$DEVNET" ]; then - echo "Error: --devnet argument is required" >&2 +if [ -z "$ENVIRONMENT" ]; then + echo "Error: --environment argument is required" >&2 exit 1 fi -if [ -z "$ENVIRONMENT" ]; then - echo "Error: --environment argument is required" >&2 +if [ "$PERSPECTIVE" != "external" ] && [ "$PERSPECTIVE" != "internal" ]; then + echo "Error: --perspective argument must be either 'external' or 'internal'" >&2 exit 1 fi + +# Some helper functions + +# Stepping through a test +blue=$(tput setaf 4 2>/dev/null || echo '') +normal=$(tput sgr0 2>/dev/null || echo '') + +function step() { + echo + echo "${blue}TEST STEP: $1${normal}" + echo +} + +function expect_error_message() { + MSG="$1" + OUTPUT="$2" + if echo "$OUTPUT" | grep -q "$MSG"; then + echo "Expected error message found: $MSG" + true + else + echo "Expected error message not found: $MSG" + exit 1 + fi +} + +# Getting data from the environment file +function getEnvData() { + jq -r "$1" "$ENVIRONMENT" +} + +# TODO: this is a chack. We need to adjust the environment to provide this info. +# Then we can remove this function. +function resolvePort() { + TYPE="$1" + case "$TYPE" in + rpc) + echo "8545" + ;; + *) + echo "Invalid type: $TYPE" + exit 1 + ;; + esac +} +function getSvcHostPort() { + SVC="$1" + TYPE="$2" + if [ "$PERSPECTIVE" == "external" ]; then + HOST=$(getEnvData "$SVC.endpoints.$TYPE.host") + PORT=$(getEnvData "$SVC.endpoints.$TYPE.port") + else + HOST=$(getEnvData "$SVC.name") + PORT=$(resolvePort "$TYPE") + fi + echo "$HOST:$PORT" +} + +function extract_cast_logs() { + input="$1" + # make a json file out of the logs field in the input file + grep '^logs\b' "$input" | sed -e 's/^logs/\{"logs":/' -e 's/$/\}/' | jq . +} + +function get_log_entry() { + logfile="$1" + address="$2" + jq -r --arg addr "$address" \ + '.logs[] | select(.address == $addr)' \ + "$logfile" +} + +# Temporary directory for storing logs and other files +TMPDIR=$(mktemp -d) +trap 'rm -rf "$TMPDIR"' EXIT diff --git a/kurtosis-devnet/tests/interop-smoke-test.sh b/kurtosis-devnet/tests/interop-smoke-test.sh index fec9bb07e0678..e064e1f34f4c1 100644 --- a/kurtosis-devnet/tests/interop-smoke-test.sh +++ b/kurtosis-devnet/tests/interop-smoke-test.sh @@ -6,11 +6,104 @@ # shellcheck disable=SC1091 source "$(dirname "$0")/boilerplate.sh" -echo "DEVNET: $DEVNET" -echo "ENVIRONMENT:" -cat "$ENVIRONMENT" +# we require 2+ L2s +if [ "$(getEnvData '.l2 | length')" -lt 2 ]; then + echo "Error: we require at least 2 L2s" + exit 1 +fi -l1_name=$(cat "$ENVIRONMENT" | jq -r '.l1.name') -echo "L1 NAME: $l1_name" +# First chain helpers +L2_1_RPC="http://$(getSvcHostPort '.l2[0].nodes[0].services.el' 'rpc')" +L2_1_CHAINID=$(getEnvData '.l2[0].id') -cast --version \ No newline at end of file +function cast_l2_1() { + cast "$@" --rpc-url "$L2_1_RPC" +} + +# Second chain helpers +L2_2_RPC="http://$(getSvcHostPort '.l2[1].nodes[0].services.el' 'rpc')" +L2_2_CHAINID=$(getEnvData '.l2[1].id') + +function cast_l2_2() { + cast "$@" --rpc-url "$L2_2_RPC" +} + +# Globally useful variables +MNEMONIC='test test test test test test test test test test test junk' +USER_ADDRESS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 + +# Contract adresses +L2ToL2CrossDomainMessenger=0x4200000000000000000000000000000000000023 +SuperchainWETH=0x4200000000000000000000000000000000000024 +SuperchainTokenBridge=0x4200000000000000000000000000000000000028 + +# Actual test +cd "$TMPDIR" || exit 1 + + +#### +step "Wrap ETH into SuperchainWETH" +cast_l2_1 send "$SuperchainWETH" \ + --value "10ether" \ + --mnemonic "$MNEMONIC" + + +#### +step "Check SuperchainWETH balance" +MIN_BALANCE=1000000000000000000 +BALANCE=$(cast_l2_1 call "$SuperchainWETH" \ + "balanceOf(address)(uint256)" "$USER_ADDRESS" | cut -d' ' -f 1) +echo +echo "SuperchainWETH balance: $BALANCE" +(( $(bc <<< "$BALANCE > $MIN_BALANCE") )) && true +echo "Balance is sufficient (greater than $MIN_BALANCE)" + + +#### +step "Send SuperchainWETH through the SuperchainTokenBridge" +DUMP_FILE=send_superchainweth_dump.txt +cast_l2_1 send "$SuperchainTokenBridge" \ + "sendERC20(address,address,uint256,uint256)" \ + "$SuperchainWETH" \ + "$USER_ADDRESS" \ + "$MIN_BALANCE" \ + "$L2_2_CHAINID" \ + --mnemonic "$MNEMONIC" | tee "$DUMP_FILE" + + +#### +step "Build Identifier and payload" +LOG_FILE=send_superchainweth_logs.json +extract_cast_logs "$DUMP_FILE" > "$LOG_FILE" + +LOG_ENTRY=L2ToL2CrossDomainMessenger_log.json +get_log_entry "$LOG_FILE" "$L2ToL2CrossDomainMessenger" > "$LOG_ENTRY" + +BLOCK_NUMBER=$(jq -r '.blockNumber' "$LOG_ENTRY") +LOG_INDEX=$(jq -r '.logIndex' "$LOG_ENTRY") + +DEC_BLOCK_NUMBER=$(cast to-dec "$BLOCK_NUMBER") +TIMESTAMP=$(cast_l2_1 block "$DEC_BLOCK_NUMBER" --field timestamp) + +# build the payload by joining the topics and data (without the 0x prefixes) +TOPICS=$(jq -r '(.topics | join("") | gsub("0x"; ""))' "$LOG_ENTRY") +DATA=$(jq -r '(.data | gsub("0x"; ""))' "$LOG_ENTRY") +EVENT_PAYLOAD="0x$TOPICS$DATA" +echo "Event payload: $EVENT_PAYLOAD" + + +#### +step "Relay SuperchainWETH through the L2toL2CrossDomainMessenger" +function relay_message() { + cast_l2_2 send "$L2ToL2CrossDomainMessenger" \ + "relayMessage((address,uint256,uint256,uint256,uint256),bytes)" \ + "($L2ToL2CrossDomainMessenger,$BLOCK_NUMBER,$LOG_INDEX,$TIMESTAMP,$L2_1_CHAINID)" \ + "$EVENT_PAYLOAD" \ + --mnemonic "$MNEMONIC" +} +relay_message + + +#### +step "Retry relay SuperchainWETH through the L2toL2CrossDomainMessenger, should be reverted" +expect_error_message "execution reverted" "$(! relay_message 2>&1)" diff --git a/kurtosis-devnet/tests/main.star b/kurtosis-devnet/tests/main.star index a962584f3c690..4109efd291491 100644 --- a/kurtosis-devnet/tests/main.star +++ b/kurtosis-devnet/tests/main.star @@ -12,7 +12,7 @@ def run(plan, devnet, timestamp, tests): for test in tests: plan.run_sh( - run = "/bin/bash /tests/{} --devnet {} --environment /tests/{}.json".format(test, devnet, devnet), + run = "/bin/bash /tests/{} --perspective internal --environment /tests/{}.json".format(test, devnet), name = "{}-{}".format(test, timestamp), image = "mslipper/deployment-utils:latest", wait="180s",