simulate_upgrade 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. #!/bin/bash
  2. set -euo pipefail
  3. # This script ensures that the EVM contracts can be safely upgraded to without
  4. # bricking the contracts. It does this by simulating contract upgrades against
  5. # the mainnet state, and checks that the state is consistent after the upgrade.
  6. #
  7. # By default, the script will compile the contracts and run the upgrade. It's
  8. # possible to simulate an upgrade against an already deployed implementation
  9. # contract (which is useful for independent verification of a governance
  10. # proposal) -- see the usage instructions below.
  11. function usage() {
  12. cat <<EOF >&2
  13. Usage:
  14. $(basename "$0") [-h] [-m s] [-c s] [-x] [-k] [-d] [-a s] [-l s] -- Simulate an upgrade on a fork of mainnet, and check for any errors.
  15. where:
  16. -h show this help text
  17. -m module (bridge, token_bridge, nft_bridge)
  18. -c chain name
  19. -x run anvil
  20. -d don't compile contract first
  21. -k keep anvil alive
  22. -l file to loge to (by default creates a new tmp file)
  23. -a new code address (by default it builds the most recent contract in the repository)
  24. EOF
  25. exit 1
  26. }
  27. before=$(mktemp)
  28. after=$(mktemp)
  29. ### Parse command line options
  30. address=""
  31. module=""
  32. chain_name=""
  33. run_anvil=false
  34. skip_compile=false
  35. keepalive_anvil=false
  36. anvil_out=$(mktemp)
  37. while getopts ':hm:c:a:xkdl:' option; do
  38. case "$option" in
  39. h) usage
  40. ;;
  41. m) module=$OPTARG
  42. ;;
  43. a) address=$OPTARG
  44. ;;
  45. c) chain_name=$OPTARG
  46. ;;
  47. x) run_anvil=true
  48. ;;
  49. d) skip_compile=true
  50. ;;
  51. l) anvil_out=$OPTARG
  52. ;;
  53. k) keepalive_anvil=true
  54. run_anvil=true
  55. ;;
  56. :) printf "missing argument for -%s\n" "$OPTARG" >&2
  57. usage
  58. ;;
  59. \?) printf "illegal option: -%s\n" "$OPTARG" >&2
  60. usage
  61. ;;
  62. esac
  63. done
  64. shift $((OPTIND - 1))
  65. # Check that we have the required arguments
  66. [ -z "$chain_name" ] && usage
  67. [ -z "$module" ] && usage
  68. # Get core contract address
  69. CORE=$(worm contract mainnet "$chain_name" Core)
  70. echo "core: $CORE"
  71. # Use the local devnet guardian key (this is not a production key)
  72. GUARDIAN_ADDRESS=0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe
  73. GUARDIAN_SECRET=cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0
  74. ANVIL_PID=""
  75. function clean_up () {
  76. ARG=$?
  77. [ -n "$ANVIL_PID" ] && kill "$ANVIL_PID"
  78. exit $ARG
  79. }
  80. trap clean_up EXIT
  81. #TODO: make RPC an optional argument
  82. HOST="http://0.0.0.0"
  83. PORT="8545"
  84. RPC="$HOST:$PORT"
  85. if [[ $run_anvil = true ]]; then
  86. ./anvil_fork "$chain_name"
  87. ANVIL_PID=$!
  88. echo "🍴 Forking mainnet..."
  89. echo "Anvil logs in $anvil_out"
  90. sleep 5
  91. # ps | grep "$ANVIL_PID"
  92. fi
  93. MODULE=""
  94. SCRIPT=""
  95. case "$module" in
  96. bridge|core)
  97. MODULE=Core
  98. SCRIPT="scripts/deploy_core_bridge.js"
  99. ;;
  100. token_bridge)
  101. MODULE=TokenBridge
  102. SCRIPT="scripts/deploy_token_bridge.js"
  103. ;;
  104. nft_bridge)
  105. MODULE=NFTBridge
  106. SCRIPT="scripts/deploy_nft_bridge.js"
  107. ;;
  108. *) echo "unknown module $module" >&2
  109. usage
  110. ;;
  111. esac
  112. CONTRACT=$(worm contract mainnet "$chain_name" "$MODULE")
  113. # Step 1) Figure out the contract address depending on the flags -- either use
  114. # an address passed in as an argument, or use the most recent contract in the repo.
  115. if [[ -n "$address" ]]; then
  116. new_implementation="$address"
  117. else
  118. if [[ $skip_compile = false ]]; then
  119. echo "🛠 Compiling contract..."
  120. build_output=$(npm run build) || ( echo "$build_output" && exit 1 )
  121. fi
  122. printf "⬆️ Deploying implementation..."
  123. deploy_output=$(npx truffle exec $SCRIPT --network development) || ( echo "$deploy_output" && exit 1 )
  124. new_implementation=$(echo "$deploy_output" | grep "address:" | cut -d' ' -f3)
  125. fi
  126. printf " %s\n" "$new_implementation"
  127. # Step 2) generate upgrade VAA using the local guardian key
  128. vaa=$(worm generate upgrade -c "$chain_name" -a "$new_implementation" -m $MODULE -g "$GUARDIAN_SECRET")
  129. # Step 3) the VAA we just signed in Step 2) is not compatible with the guardian
  130. # set on mainnet (since that corresponds to a mainnet guardian network). We need
  131. # to thus locally replace the guardian set with the local guardian key.
  132. echo "💂 Overriding guardian set with $GUARDIAN_ADDRESS"
  133. worm evm hijack -g "$GUARDIAN_ADDRESS" -i 0 -a "$CORE" --rpc "$RPC"> /dev/null
  134. # Step 4) query state before upgrade
  135. echo "🔍 Querying old contract state"
  136. worm evm info -c "$chain_name" -m $MODULE -n devnet -a "$CONTRACT" --rpc "$RPC" | grep -v '"implementation":' > "$before"
  137. # Step 5) upgrade contract
  138. echo "🤝 Submitting VAA"
  139. worm submit "$vaa" -n devnet -a "$CONTRACT" --rpc "$RPC" > /dev/null
  140. # Step 6) query state after upgrade
  141. echo "🔍 Querying new contract state"
  142. worm evm info -c "$chain_name" -m $MODULE -n devnet -a "$CONTRACT" --rpc "$RPC" | grep -v '"implementation":' > "$after"
  143. # Step 7) compare old and new state and exit with error if they differ
  144. git diff --no-index "$before" "$after" --exit-code && echo "✅ Upgrade simulation successful" || exit 1
  145. # Anvil can be kept alive by setting the -k flag. This is useful for interacting
  146. # with the contract after it has been upgraded.
  147. if [[ $keepalive_anvil = true ]]; then
  148. echo "Listening on $RPC"
  149. # tail -f "$anvil_out"
  150. wait "$ANVIL_PID"
  151. fi