#!/bin/bash set -euo pipefail function usage() { cat<<-EOF >&2 Usage: $(basename "$0") [-h] [-n network] <.so file> -- 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) EOF exit 1 } network="" if [[ -n $NETWORK ]]; then network=$NETWORK fi while getopts ':hn:' option; do case "$option" in h) usage ;; n) network=$OPTARG ;; :) printf "missing argument for -%s\n" "$OPTARG" >&2 usage ;; \?) printf "illegal option: -%s\n" "$OPTARG" >&2 usage ;; esac done shift $((OPTIND - 1)) case "$network" in mainnet) moniker="m";; testnet) moniker="d";; devnet) moniker="l";; *) printf "Network not set. Specify with -n\n" >&2 usage ;; esac [ $# -ne 2 ] && usage obj_file=$1 sol_addr=$2 account_json=$(mktemp) account_dump=$(mktemp) # Grab account content as JSON solana account "$sol_addr" -u $moniker --output-file "$account_json" --output json-compact >/dev/null # decode the base64 account data to binary jq '.account.data[0]' "$account_json" | sed s/\"//g | base64 -d > "$account_dump" # The first 37 bytes are irrelevant, the actual ELF object code starts after, # so we drop these bytes. Presumably those bytes correspond to an encoded rust # enum constructor? # Set the block size to 37 bytes and skip the first block. dd bs=37 skip=1 if="$account_dump" of=/tmp/bytecode.dump 2>/dev/null hash1=$(sha256sum /tmp/bytecode.dump | cut -f1 -d' ') 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" >&2; echo "JSON: $account_json" >&2; echo "Dump: $account_dump" >&2; exit 1; fi