Ver Fonte

Add scripts and readme to deploy and verify terra contracts

Csongor Kiss há 3 anos atrás
pai
commit
e1f4b8e10b
9 ficheiros alterados com 316 adições e 42 exclusões
  1. 3 0
      .gitignore
  2. 15 0
      Makefile.help
  3. 8 3
      terra/Dockerfile
  4. 0 11
      terra/Dockerfile.build
  5. 59 0
      terra/Makefile
  6. 99 22
      terra/README.md
  7. 0 6
      terra/build.sh
  8. 69 0
      terra/generate_governance
  9. 63 0
      terra/verify

+ 3 - 0
.gitignore

@@ -11,3 +11,6 @@ venv
 bigtable-admin.json
 bigtable-writer.json
 **/cert.pem
+**/payer-mainnet.json
+**/payer-testnet.json
+**/payer-devnet.json

+ 15 - 0
Makefile.help

@@ -0,0 +1,15 @@
+## This help screen
+help:
+	@printf "Available targets:\n\n"
+	@awk '/^[a-zA-Z\-\_0-9%:\\]+/ { \
+		helpMessage = match(lastLine, /^## (.*)/); \
+	if (helpMessage) { \
+	helpCommand = $$1; \
+	helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \
+	gsub("\\\\", "", helpCommand); \
+	gsub(":+$$", "", helpCommand); \
+		printf "  \x1b[32;01m%-35s\x1b[0m %s\n", helpCommand, helpMessage; \
+	} \
+	} \
+	{ lastLine = $$0 }' $(MAKEFILE_LIST)
+	@printf "\n"

+ 8 - 3
terra/Dockerfile

@@ -1,5 +1,7 @@
-# This is a multi-stage docker file, first stage builds contracts
-# And the second one creates node.js environment to deploy them
+# This is a multi-stage docker file:
+#  1. The first stage builds the contracts
+#  2. The second is an empty image with only the wasm files (useful for exporting)
+#  3. The third creates a node.js environment to deploy the contracts to devnet
 FROM cosmwasm/workspace-optimizer:0.12.1@sha256:1508cf7545f4b656ecafa34e29c1acf200cdab47fced85c2bc076c0c158b1338 AS builder
 COPY Cargo.lock /code/
 COPY Cargo.toml /code/
@@ -13,6 +15,9 @@ RUN if [ -e /certs/cert.pem ]; then cp /certs/cert.pem /etc/ssl/cert.pem; fi
 
 RUN optimize_workspace.sh
 
+FROM scratch as artifacts
+COPY --from=builder /code/artifacts /
+
 # Contract deployment stage
 FROM node:16-buster-slim@sha256:93c9fc3550f5f7d159f282027228e90e3a7f8bf38544758024f005e82607f546
 
@@ -28,7 +33,7 @@ RUN apt update && apt install netcat curl jq -y
 
 WORKDIR /app/tools
 
-COPY --from=builder /code/artifacts /app/artifacts
+COPY --from=artifacts / /app/artifacts
 COPY ./artifacts/cw20_base.wasm /app/artifacts/
 
 COPY ./tools/package.json ./tools/package-lock.json /app/tools/

+ 0 - 11
terra/Dockerfile.build

@@ -1,11 +0,0 @@
-# Run with:
-# docker build -f Dockerfile.build -o artifacts .
-FROM cosmwasm/workspace-optimizer:0.12.1@sha256:1508cf7545f4b656ecafa34e29c1acf200cdab47fced85c2bc076c0c158b1338 AS builder
-ADD Cargo.lock /code/
-ADD Cargo.toml /code/
-ADD contracts /code/contracts
-ADD packages /code/packages
-RUN optimize_workspace.sh
-
-FROM scratch AS export-stage
-COPY --from=builder /code/artifacts /

+ 59 - 0
terra/Makefile

@@ -0,0 +1,59 @@
+bridge_SOURCE=wormhole
+token_bridge_SOURCE=token_bridge
+nft_bridge_SOURCE=nft_bridge
+
+SOURCE_FILES=$(shell find . -name "*.rs" -or -name "*.lock" -or -name "*.toml" | grep -v target)
+
+PACKAGES=$(shell find . -name "Cargo.toml" | grep -E 'packages|contracts' | cut -d/ -f3 | sed s/-/_/g)
+WASMS=$(patsubst %, artifacts/%.wasm, $(PACKAGES))
+
+-include ../Makefile.help
+
+.PHONY: artifacts
+## Build contracts.
+artifacts: artifacts/checksums.txt
+
+VALID_mainnet=1
+VALID_testnet=1
+VALID_devnet=1
+.PHONY: check-network
+check-network:
+ifndef VALID_$(NETWORK)
+	$(error Invalid or missing NETWORK. Please call with `$(MAKE) $(MAKECMDGOALS) NETWORK=[mainnet | testnet | devnet]`)
+endif
+
+$(WASMS) artifacts/checksums.txt: $(SOURCE_FILES)
+	DOCKER_BUILDKIT=1 docker build --target artifacts -o artifacts .
+
+payer-$(NETWORK).json:
+	$(error Missing private key in payer-$(NETWORK).json)
+
+.PHONY: deploy/bridge
+## Deploy core bridge
+deploy/bridge: bridge-code-id-$(NETWORK).txt
+
+.PHONY: deploy/token_bridge
+## Deploy token bridge
+deploy/token_bridge: token_bridge-code-id-$(NETWORK).txt
+
+.PHONY: deploy/nft_bridge
+## Deploy NFT bridge
+deploy/nft_bridge: nft_bridge-code-id-$(NETWORK).txt
+
+%-code-id-$(NETWORK).txt: check-network tools/node_modules payer-$(NETWORK).json
+	@echo "Deploying artifacts/$($*_SOURCE).wasm on $(NETWORK)"
+	@node tools/deploy_single.js \
+		--network $(NETWORK) \
+		--artifact artifacts/$($*_SOURCE).wasm \
+		--mnemonic "$$(cat payer-$(NETWORK).json)" \
+		| grep -i "code id" | sed s/[^0-9]//g \
+		> $@
+	@echo "Deployed at code id $$(cat $@) (stored in $@)"
+
+tools/node_modules: tools/package-lock.json
+	cd tools && npm ci
+
+.PHONY: clean
+clean:
+	rm -f $(WASMS)
+	rm -f artifacts/checksums.txt

+ 99 - 22
terra/README.md

@@ -1,45 +1,122 @@
-# Deploy
+# Terra Wormhole Contract Deployment
 
-First build the contracts
+This readme describes the steps for building, verifying, and deploying Terra smart contracts for Wormhole.
 
+**WARNING**: *This process is only Linux host compatible at this time.*
 
-``` sh
-docker build -f Dockerfile.build -o artifacts .
+## Verify Tilt
+
+Before building Terra contracts, ensure that the specific commit you will be
+building from passes in tilt. This that ensures basic functionality of the
+Terra smart contracts that you are about to build and deploy.
+
+## Build Contracts
+
+The following command can be used to build Terra contracts via Docker.
+
+Build Target Options: [`mainnet`|`testnet`|`devnet`|
+
+These network names correspond to the naming convention used by wormhole
+elsewhere. This means that `mainnet` corresponds to Terra `mainnet`,
+`testnet` corresponds to Terra `testnet`, and `devnet` is `localterra`.
+
+```console
+wormhole/terra $ make artifacts
 ```
 
-Then, for example, to deploy `token_bridge.wasm`, run in the `tools` directory
+Upon completion, the compiled bytecode for the Terra contracts will be placed
+into the `artifacts` directory.
 
-``` sh
-npm ci
-node deploy_single.js --network mainnet --artifact ../artifacts/token_bridge.wasm --mnemonic "..."
+## Verify Checksums 
+
+Now that you have built the Terra contracts, you should ask a peer to build
+using the same process and compare the equivalent checksums.txt files to make
+sure the contract bytecode(s) are deterministic.
+
+```console
+wormhole/terra $ cat artifacts/checksums.txt
 ```
 
-which will print something along the lines of
+Once you have verified the Terra contracts are deterministic with a peer, you can now move to the deploy step.
 
-``` sh
-Storing WASM: ../artifacts/token_bridge.wasm (367689 bytes)
-Deploy fee:  88446uluna
-Code ID:  2435
+## Deploy Contracts
+
+Now that you have built and verified checksums, you can now deploy one or more relevant contracts to the Terra blockchain.
+
+Deploy Target Options: [`mainnet`|`testnet`|`devnet`]
+
+You will need to define a `payer-DEPLOY_TARGET.json` for the relevant deploy
+target (eg. `payer-testnet.json`).  This will contain the relevant wallet
+private key that you will be using to deploy the contracts.
+
+```console
+wormhole/terra $ make deploy/bridge
+wormhole/terra $ make deploy/token_bridge
+wormhole/terra $ make deploy/nft_bridge
 ```
 
-# Migrate
+For each deployed contract, you will get a code id for that relevant
+contract for the deployment, make note of these so you can use them in
+the next step for on-chain verification.
+
+## Verify On-Chain
+
+Now that you have deployed one or more contracts on-chain, you can verify the
+onchain bytecode and make sure it matches the same checksums you identified
+above.
+
+For each contract you wish to verify on-chain, you will need the following elements:
+
+- Path to the contracts bytecode (eg. `artifacts-testnet/token_bridge.wasm`)
+- Terra code id for the relevant contract (eg. `59614`)
+- A network to verify on (`mainnet`, `testnet`, or `devnet`)
+
+Below is how to verify all three contracts:
+
+```console
+wormhole/terra $ ./verify artifacts/wormhole.wasm NEW_BRIDGE_CODE_ID
+wormhole/terra $ ./verify artifacts/token_bridge.wasm NEW_TOKEN_BRIDGE_CODE_ID
+wormhole/terra $ ./verify artifacts/nft_bridge.wasm NEW_NFT_BRIDGE_CODE_ID
+```
+Example: `./verify artifacts/token_bridge.wasm 59614`
+
+For each contract, you should expect a `Successfully verified` output message.
+If all contracts can be successfully verified, you can engage in Wormhole
+protocol governance to obtain an authorized VAA for the contract upgrade(s).
+
+A verification failure should never happen, and is a sign of some error in the
+deployment process.  Do not proceed with governance until you can verify the
+on-chain bytecode with the locally compiled bytecode.
+
+
+## Governance
+
+### Mainnet
+
+Upgrades on mainnet have to go through governance. Once the code is deployed in
+the previous step, an unsigned governance VAA can be generated
+
+```sh
+./generate_governance -m token_bridge -c 59614 > token-bridge-upgrade-59614.prototxt
+```
 
-## Mainnet
+This will write to the `token-bridge-upgrade-59614.prototxt` file, which can
+now be shared with the guardians to vote on.
 
-Migrations on mainnet have to go through governance. Once the guardians sign the
-upgrade VAA, the contract can be upgraded by submitting the signed VAA to the
-appropriate contract. For example, to upgrade the token bridge on mainnet,
-in `wormhole/clients/token_bridge/`:
+Once the guardians have reached quorum, the VAA may be submitted from any
+funded wallet: TODO - make this easier and more unified
 
 ``` sh
 node main.js terra execute_governance_vaa <signed VAA (hex)> --rpc "https://lcd.terra.dev" --chain_id "columbus-5" --mnemonic "..." --token_bridge "terra10nmmwe8r3g99a9newtqa7a75xfgs2e8z87r2sf"
 ```
 
-## Testnet
+### Testnet
 
+For the contracts on testnet, the deployer wallet retains the upgrade
+authority, so these don't have to go through governance.
 
-For example, to migrate the token bridge to 37262, run in `tools/`:
+For example, to migrate the token bridge to 59614, run in `tools/`:
 
 ``` sh
-node migrate_testnet.js --code_id 37262 --contract terra1pseddrv0yfsn76u4zxrjmtf45kdlmalswdv39a --mnemonic "..."
+node migrate_testnet.js --code_id 59614 --contract terra1pseddrv0yfsn76u4zxrjmtf45kdlmalswdv39a --mnemonic "..."
 ```

+ 0 - 6
terra/build.sh

@@ -1,6 +0,0 @@
-#!/usr/bin/env bash
-
-docker run --rm -v "$(pwd)":/code \
-  --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \
-  --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
-  cosmwasm/workspace-optimizer:0.12.1

+ 69 - 0
terra/generate_governance

@@ -0,0 +1,69 @@
+#!/bin/bash
+
+set -euo pipefail
+
+usage="Usage:
+  $(basename "$0") [-h] [-m s] [-c n] -- Generate governance prototxt for a given module to be upgraded to a given code id
+
+  where:
+      -h  show this help text
+      -m  module (bridge, token_bridge, nft_bridge)
+      -c  code id (e.g. 4018)"
+
+code_id=""
+module=""
+while getopts ':hm:c:' option; do
+  case "$option" in
+    h) echo "$usage"
+       exit
+       ;;
+    m) module=$OPTARG
+       ;;
+    c) code_id=$OPTARG
+       ;;
+    :) printf "missing argument for -%s\n" "$OPTARG" >&2
+       echo "$usage" >&2
+       exit 1
+       ;;
+   \?) printf "illegal option: -%s\n" "$OPTARG" >&2
+       echo "$usage" >&2
+       exit 1
+       ;;
+  esac
+done
+shift $((OPTIND - 1))
+
+[ -z "$code_id" ] && { echo "$usage" >&2; exit 1; }
+[ -z "$module" ] && { echo "$usage" >&2; exit 1; }
+
+address=$(printf "%064x" "$code_id")
+TERRA_ID=3
+GUARDIAND=guardiand
+
+case "$module" in
+  bridge)
+    "$GUARDIAND" template contract-upgrade \
+      --chain-id $TERRA_ID \
+      --new-address "$address" \
+      > /tmp/gov.prototxt
+    ;;
+  token_bridge)
+    "$GUARDIAND" template token-bridge-upgrade-contract \
+      --chain-id $TERRA_ID --module "TokenBridge" \
+      --new-address "$address" \
+      > /tmp/gov.prototxt
+    ;;
+  nft_bridge)
+    "$GUARDIAND"  template token-bridge-upgrade-contract \
+      --chain-id $TERRA_ID --module "NFTBridge" \
+      --new-address "$address" \
+      > /tmp/gov.prototxt
+    ;;
+  *) echo "illegal module $module"
+     echo "$usage" >&2
+     exit 1
+     ;;
+esac
+
+cat /tmp/gov.prototxt
+"$GUARDIAND" admin governance-vaa-verify /tmp/gov.prototxt >&2

+ 63 - 0
terra/verify

@@ -0,0 +1,63 @@
+#!/bin/bash
+
+set -euo pipefail
+
+usage="Usage:
+  $(basename "$0") [-h] [-n network] <.wasm file> <code id> -- Verify that the deployed on-chain bytecode matches the local object file
+
+  where:
+      -h  show this help text
+      -n  set the network (mainnet, testnet, devnet. defaults to \$NETWORK if set)"
+
+network=$NETWORK
+while getopts ':hn:' option; do
+  case "$option" in
+    h) echo "$usage"
+       exit
+       ;;
+    n) network=$OPTARG
+       ;;
+    :) printf "missing argument for -%s\n" "$OPTARG" >&2
+       echo "$usage" >&2
+       exit 1
+       ;;
+   \?) printf "illegal option: -%s\n" "$OPTARG" >&2
+       echo "$usage" >&2
+       exit 1
+       ;;
+  esac
+done
+shift $((OPTIND - 1))
+
+
+case "$network" in
+  mainnet) url="https://lcd.terra.dev";;
+  testnet) url="https://bombay-lcd.terra.dev";;
+  devnet)  url="http://localhost:1317";;
+  *) printf "Network not set. Specify with -n\n" >&2
+     echo "$usage" >&2
+     exit 1
+     ;;
+esac
+
+[ $# -ne 2 ] && { echo "$usage" >&2; exit 1; }
+obj_file=$1
+code_id=$2
+
+
+hash1=`curl "$url"/terra/wasm/v1beta1/codes/"$code_id" --silent | jq '.code_info.code_hash' -r | base64 -d | hexdump -v -e '/1 "%02x" '`
+hash2=`sha256sum $obj_file | cut -f1 -d' '`
+
+echo "Deployed bytecode hash (on $network):"
+echo $hash1
+echo "$obj_file hash:"
+echo $hash2
+
+if [ "$hash1" == "$hash2" ]; then
+  printf "\033[0;32mSuccessfully verified\033[0m\n";
+  exit 0;
+else
+  printf "\033[0;31mFailed to verify\033[0m\n";
+  exit 1;
+fi
+