Script to generate change registration governance (#1508)

* Script to generate change registration governance

Change-Id: If99e78b031dcd4049a9ee40b09914eeb93e7518a

* Rework from code review

Change-Id: I93cf3166c1ab961add2c524084de1981a44b194e

* Change chain_id to chain-id

Change-Id: Iae6f9854a64d8559d03c56949d03043a94dbf7f6
This commit is contained in:
bruce-riley 2022-09-06 08:20:51 -05:00 committed by GitHub
parent 8dc459b550
commit b357ad7061
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 267 additions and 6 deletions

View File

@ -10,6 +10,9 @@ import {
CONTRACTS,
setDefaultWasm,
hexToUint8Array,
getEmitterAddressSolana,
getEmitterAddressTerra,
getEmitterAddressEth,
} from "@certusone/wormhole-sdk";
import { execute_solana } from "./solana";
import {
@ -254,11 +257,17 @@ yargs(hideBin(process.argv))
describe: "Module to query",
type: "string",
choices: ["Core", "NFTBridge", "TokenBridge"],
})
.option("emitter", {
alias: "e",
describe: "Print in emitter address format",
type: "boolean",
default: false,
required: false,
});
},
async (argv) => {
assertChain(argv["chain"]);
assertEVMChain(argv["chain"]);
const network = argv.network.toUpperCase();
if (
network !== "MAINNET" &&
@ -267,20 +276,58 @@ yargs(hideBin(process.argv))
) {
throw Error(`Unknown network: ${network}`);
}
let chain = argv["chain"]
let module = argv["module"] as "Core" | "NFTBridge" | "TokenBridge";
let addr = ""
switch (module) {
case "Core":
console.log(CONTRACTS[network][argv["chain"]]["core"]);
addr = CONTRACTS[network][chain]["core"];
break;
case "NFTBridge":
console.log(CONTRACTS[network][argv["chain"]]["nft_bridge"]);
addr = CONTRACTS[network][chain]["nft_bridge"];
break;
case "TokenBridge":
console.log(CONTRACTS[network][argv["chain"]]["token_bridge"]);
addr = CONTRACTS[network][chain]["token_bridge"];
break;
default:
impossible(module);
}
if (argv["emitter"]) {
if (chain === "solana" || chain === "pythnet") { // TODO: Create an isSolanaChain()
addr = await getEmitterAddressSolana(addr);
} else if (isTerraChain(chain)) {
addr = await getEmitterAddressTerra(addr);
} else if (chain === "algorand") {
if (network !== "MAINNET") {
throw Error(`unable to look up algorand emitter address for ${network}`);
}
addr = "25e716e0618d9f38b603a97cc42db659069c0f5185230e5e61679fa876191ec4";
} else if (chain === "near") {
if (network !== "MAINNET") {
throw Error(`unable to look up near emitter address for ${network}`);
}
addr = "148410499d3fcda4dcfd68a1ebfcdddda16ab28326448d4aae4d2f0465cdfcb7";
} else {
addr = getEmitterAddressEth(addr);
}
}
console.log(addr);
}
)
.command(
"chain-id <chain>",
"Print the wormhole chain ID integer associated with the specified chain name",
(yargs) => {
return yargs
.positional("chain", {
describe: "Chain to query",
type: "string",
choices: Object.keys(CHAINS),
});
},
async (argv) => {
assertChain(argv["chain"]);
console.log(toChainId(argv["chain"]));
}
)
.command(

View File

@ -14,6 +14,7 @@ import (
"google.golang.org/protobuf/encoding/prototext"
nodev1 "github.com/certusone/wormhole/node/pkg/proto/node/v1"
"github.com/status-im/keycard-go/hexutils"
)
var AdminClientGovernanceVAAVerifyCmd = &cobra.Command{
@ -59,7 +60,7 @@ func runGovernanceVAAVerify(cmd *cobra.Command, args []string) {
log.Fatalf("invalid update: %v", err)
}
digest := v.SigningMsg()
digest := v.SigningMsg().Bytes()
if err != nil {
panic(err)
}
@ -71,6 +72,6 @@ func runGovernanceVAAVerify(cmd *cobra.Command, args []string) {
log.Printf("Serialized: %v", hex.EncodeToString(b))
log.Printf("VAA with digest %s: %+v", digest.Hex(), spew.Sdump(v))
log.Printf("VAA with digest %s: %+v", hexutils.BytesToHex(digest), spew.Sdump(v))
}
}

35
scripts/register-all-chains.sh Executable file
View File

@ -0,0 +1,35 @@
rm -rf my_proposal
./register-chain-governance.sh -m TokenBridge -c solana -o my_proposal > governance.md
./register-chain-governance.sh -m TokenBridge -c ethereum -o my_proposal > governance.md
./register-chain-governance.sh -m TokenBridge -c terra -o my_proposal > governance.md
./register-chain-governance.sh -m TokenBridge -c bsc -o my_proposal > governance.md
./register-chain-governance.sh -m TokenBridge -c polygon -o my_proposal > governance.md
./register-chain-governance.sh -m TokenBridge -c avalanche -o my_proposal > governance.md
./register-chain-governance.sh -m TokenBridge -c oasis -o my_proposal > governance.md
./register-chain-governance.sh -m TokenBridge -c fantom -o my_proposal > governance.md
./register-chain-governance.sh -m TokenBridge -c aurora -o my_proposal > governance.md
# These are already on the current guardian set.
# ./register-chain-governance.sh -m TokenBridge -c karura -o my_proposal > governance.md
# ./register-chain-governance.sh -m TokenBridge -c klaytn -o my_proposal > governance.md
# ./register-chain-governance.sh -m TokenBridge -c celo -o my_proposal > governance.md
# ./register-chain-governance.sh -m TokenBridge -c acala -o my_proposal > governance.md
# ./register-chain-governance.sh -m TokenBridge -c terra2 -o my_proposal > governance.md
# ./register-chain-governance.sh -m TokenBridge -c algorand -o my_proposal > governance.md
# ./register-chain-governance.sh -m TokenBridge -c near -o my_proposal > governance.md
./register-chain-governance.sh -m NFTBridge -c solana -o my_proposal > governance.md
./register-chain-governance.sh -m NFTBridge -c ethereum -o my_proposal > governance.md
./register-chain-governance.sh -m NFTBridge -c bsc -o my_proposal > governance.md
./register-chain-governance.sh -m NFTBridge -c polygon -o my_proposal > governance.md
./register-chain-governance.sh -m NFTBridge -c avalanche -o my_proposal > governance.md
./register-chain-governance.sh -m NFTBridge -c oasis -o my_proposal > governance.md
./register-chain-governance.sh -m NFTBridge -c fantom -o my_proposal > governance.md
./register-chain-governance.sh -m NFTBridge -c aurora -o my_proposal > governance.md
# These are already on the current guardian set.
# ./register-chain-governance.sh -m NFTBridge -c karura -o my_proposal > governance.md
# ./register-chain-governance.sh -m NFTBridge -c klaytn -o my_proposal > governance.md
# ./register-chain-governance.sh -m NFTBridge -c celo -o my_proposal > governance.md
# ./register-chain-governance.sh -m NFTBridge -c acala -o my_proposal > governance.md

View File

@ -0,0 +1,178 @@
#!/bin/bash
# This tool automates the process of writing bridge registration governance
# proposals in markdown format.
#
# There are two ways to run this script: either in "one-shot" mode, where a
# single governance VAA is generated:
#
# ./register-chain-governance.sh -m TokenBridge -c solana > governance.md
#
# or in "multi" mode, where multiple VAAs are created in the same proposal:
#
# ./register-chain-governance.sh -m TokenBridge -c solana -o my_proposal > governance.md
# ./register-chain-governance.sh -m TokenBridge -c avalanche -o my_proposal > governance.md
# ... -o my_proposal > governance.md
#
# In multi mode, there's an additional "-o" flag, which takes a directory name,
# where intermediate progress is saved between runs. If the directory doesn't
# exist, the tool will create it.
#
# In both one-shot and multi modes, the script outputs the markdown-formatted
# proposal to STDOUT, so it's a good idea to pipe it into a file (as in the above examples).
#
# In multi-mode, it always outputs the most recent version, so it's safe to
# override the previous files.
#
# Once a multi-mode run is completed, the directory specified with the -o flag can be deleted.
set -euo pipefail
function usage() {
cat <<EOF >&2
Usage:
$(basename "$0") [-h] [-m s] [-c s] [-o d] -- Generate bridge registration governance proposal for a given module
where:
-h show this help text
-m module (TokenBridge, NFTBridge)
-c chain name
-o multi-mode output directory
EOF
exit 1
}
# Check if guardiand and worm commands exist. They needed for generating the protoxt and
# computing the digest.
if ! command -v guardiand >/dev/null 2>&1; then
echo "ERROR: guardiand binary not found" >&2
exit 1
fi
if ! command -v worm >/dev/null 2>&1; then
echo "ERROR: worm binary not found" >&2
exit 1
fi
### Parse command line options
address=""
module=""
chain_name=""
multi_mode=false
out_dir=""
while getopts ':hm:c:a:o:' option; do
case "$option" in
h) usage
;;
m) module=$OPTARG
;;
c) chain_name=$OPTARG
;;
o) multi_mode=true
out_dir=$OPTARG
;;
:) printf "missing argument for -%s\n" "$OPTARG" >&2
usage
;;
\?) printf "illegal option: -%s\n" "$OPTARG" >&2
usage
;;
esac
done
shift $((OPTIND - 1))
[ -z "$chain_name" ] && usage
[ -z "$module" ] && usage
# Use the worm client to get the emitter address and wormhole chain ID.
address=`worm contract --emitter mainnet $chain_name $module`
[ -z "$address" ] && usage
chain=`worm chain-id $chain_name`
[ -z "$chain" ] && usage
### The script constructs the governance proposal in two different steps. First,
### the governance prototxt (for VAA injection by the guardiand tool), then the voting/verification instructions.
gov_msg_file=""
instructions_file=""
if [ "$multi_mode" = true ]; then
mkdir -p "$out_dir"
gov_msg_file="$out_dir/governance.prototxt"
instructions_file="$out_dir/instructions.md"
else
gov_msg_file=$(mktemp)
instructions_file=$(mktemp)
fi
# Generate the command to create the governance prototxt
function create_governance() {
case "$module" in
TokenBridge)
echo "\
guardiand template token-bridge-register-chain \\
--chain-id $chain --module \"TokenBridge\" \\
--new-address $address"
;;
NFTBridge)
echo "\
guardiand template token-bridge-register-chain \\
--chain-id $chain --module \"NFTBridge\" \\
--new-address $address"
;;
*) echo "unknown module $module" >&2
usage
;;
esac
}
################################################################################
# Construct the governance proto
echo "# Registration $chain_name $module" >> "$gov_msg_file"
# Append the new governance message to the gov file
eval "$(create_governance)" >> "$gov_msg_file"
# Multiple messages will include multiple 'current_set_index' fields, but the
# proto format only takes one. This next part cleans up the file so there's only
# a single 'current_set_index' field.
# 1. we grab the first one and save it
current_set_index=$(grep "current_set_index" "$gov_msg_file" | head -n 1)
# 2. remove all 'current_set_index' fields
rest=$(grep -v "current_set_index" "$gov_msg_file")
# 3. write the set index
echo "$current_set_index" > "$gov_msg_file"
# 4. then the rest of the file
echo "$rest" >> "$gov_msg_file"
################################################################################
# Compute expected digests
# just use the 'guardiand' command, which spits out a bunch of text to
# stderr. We grab that output and pick out the VAA hashes
verify=$(guardiand admin governance-vaa-verify "$gov_msg_file" 2>&1)
digest=$(echo "$verify" | grep "VAA with digest" | cut -d' ' -f6 | sed 's/://g')
################################################################################
# Print vote command and expected digests
# This we only print to stdout, because in multi mode, it gets recomputed each
# time. The rest of the output gets printed into the instructions file
cat <<-EOD
# Governance
Shell command for voting:
\`\`\`shell
cat << EOF > governance.prototxt
$(cat "$gov_msg_file")
EOF
guardiand admin governance-vaa-inject --socket /path/to/admin.sock governance.prototxt
\`\`\`
Expected digest(s):
\`\`\`
$digest
\`\`\`
EOD