Add scripts and readme to deploy and verify terra contracts

This commit is contained in:
Csongor Kiss 2022-04-02 13:30:40 +00:00 committed by Csongor Kiss
parent 879670c0e5
commit e1f4b8e10b
9 changed files with 316 additions and 42 deletions

3
.gitignore vendored
View File

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

15
Makefile.help Normal file
View File

@ -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"

View File

@ -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/

View File

@ -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
terra/Makefile Normal file
View File

@ -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

View File

@ -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.
## Mainnet
## Verify On-Chain
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/`:
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
```
This will write to the `token-bridge-upgrade-59614.prototxt` file, which can
now be shared with the guardians to vote on.
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 "..."
```

View File

@ -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
terra/generate_governance Executable file
View File

@ -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
terra/verify Executable file
View File

@ -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