Skip to content

Instantly share code, notes, and snippets.

@kajoseph
Last active April 24, 2024 15:06
Show Gist options
  • Save kajoseph/0a57e42ca40eac3dcaabea20128729c3 to your computer and use it in GitHub Desktop.
Save kajoseph/0a57e42ca40eac3dcaabea20128729c3 to your computer and use it in GitHub Desktop.
Polygon Edge
#!/usr/bin/env bash
# REF: https://wiki.polygon.technology/docs/supernets/operate/deploy/
NO_START=0
QUIET=0
CHAIN_ID=13375
NODE=1
LINES=50
VERSION="1.0.0-rc1"
BLOCK_TIME=10
# ETH_HEX_KEY=
Usage() {
echo "A Polygon-Edge script that sets up and manages a local Polygon network with 4 nodes"
echo
echo "Usage: ./polygon <command> [options]"
echo
echo "Commands:"
echo " init Downloads the docker images and creates, configures, and starts the local network"
# echo " --eth-key <value> (REQUIRED) Hex-encoded private key used to deploy contracts to your local ETH chain. Must have funds on ETH chain"
echo " --no-start Do not start the network after creation"
echo " --quiet Do not print the nodes info after creation"
echo " --chainId <value> Custom chain ID (default: $CHAIN_ID)"
echo " --version <value> Version of Polygon-Edge (default: $VERSION). Use \`latest\` at your own risk"
echo " --block-time <value> Interval (in seconds) for blocks to be mined (default: $BLOCK_TIME)"
echo " start Starts the local Polygon network"
echo " stop Stops the local Polygon network"
echo " info Prints info about each node"
echo " --quiet Do not print sensitive information (such as private keys) (default: $QUIET)"
echo " logs Tail the logs of a node"
echo " -n, --node <value> Specify which node (default: $NODE)"
echo " -l, --lines <value> Number of lines to tail (default: $LINES)"
echo " clean Deletes everything! Deletes all data, containers, and images"
echo " rebuild Recreates containers. Useful if you need to change ports."
echo " --block-time <value> Interval (in seconds) for blocks to be mined (default: $BLOCK_TIME)"
echo
}
Init() {
echo "Enter the JSON-RPC port to your local ETH node (defaut: 8545). Note: your local ETH node needs to be running"
read ETH_PORT
if [ "$ETH_PORT" == "" ]; then
ETH_PORT=8545
echo Using default ETH RPC port.
fi
docker pull 0xpolygon/polygon-edge:$VERSION
mkdir ~/.polygon-edge/ 2>/dev/null
BOOT_NODE_ID_1=
BOOT_NODE_ID_2=
NODE_ADDRESSES=()
NODE_PUB_KEYS=()
NODE_IDS=()
NODE_SIGS=()
WORKDIR=~/.polygon-edge
for i in {1..4}; do
NAME=polygon-edge-$i
# WORKDIR=~/.polygon-edge/node-$i
# mkdir $WORKDIR/node-$i 2>/dev/null
OUTPUT=$(docker container run \
--rm \
--workdir /workdir \
--volume $WORKDIR:/workdir \
0xpolygon/polygon-edge:$VERSION \
polybft-secrets --insecure --data-dir /workdir/node-$i)
PUB_KEY_ADDRESS=$(echo "${OUTPUT}" | grep "Public key (address)" | $SED -r 's/(Public key \(address\))[[:space:]]*=[[:space:]]//')
BLS_PUB_KEY=$(echo "${OUTPUT}" | grep "BLS Public key" | $SED -r 's/(BLS Public key)[[:space:]]*=[[:space:]]//')
BLS_SIGNATURE=$(echo "${OUTPUT}" | grep "BLS Signature" | $SED -r 's/(BLS Signature)[[:space:]]*=[[:space:]]//')
NODE_ID=$(echo "${OUTPUT}" | grep "Node ID" | $SED -r 's/(Node ID)[[:space:]]*=[[:space:]]//')
if [ "$i" == "1" ]; then
BOOT_NODE_ID_1=$NODE_ID
elif [ "$i" == "2" ]; then
BOOT_NODE_ID_2=$NODE_ID
fi
NODE_ADDRESSES+=($PUB_KEY_ADDRESS)
NODE_PUB_KEYS+=($BLS_PUB_KEY)
NODE_SIGS+=($BLS_SIGNATURE)
NODE_IDS+=($NODE_ID)
sudo chown :$USER -R $WORKDIR/node-$i
sudo chmod g+w -R $WORKDIR/node-$i
echo "$OUTPUT" | $SED '0,/^\[SECRETS INIT\]$/d' > $WORKDIR/node-$i/node.info
done
docker network create --subnet 190.180.170.0/24 polygon-edge
# docker container run \
# --rm \
# --workdir /workdir \
# --volume $WORKDIR:/workdir \
# 0xpolygon/polygon-edge:$VERSION \
# manifest \
# --chain-id $CHAIN_ID \
# --validators /ip4/190.180.170.11/tcp/30011/p2p/${NODE_IDS[0]}:${NODE_ADDRESSES[0]}:${NODE_PUB_KEYS[0]}:${NODE_SIGS[0]} \
# --validators /ip4/190.180.170.12/tcp/30021/p2p/${NODE_IDS[1]}:${NODE_ADDRESSES[1]}:${NODE_PUB_KEYS[1]}:${NODE_SIGS[1]} \
# --validators /ip4/190.180.170.13/tcp/30031/p2p/${NODE_IDS[2]}:${NODE_ADDRESSES[2]}:${NODE_PUB_KEYS[2]}:${NODE_SIGS[2]} \
# --validators /ip4/190.180.170.14/tcp/30041/p2p/${NODE_IDS[3]}:${NODE_ADDRESSES[3]}:${NODE_PUB_KEYS[3]}:${NODE_SIGS[3]} \
# --path ./manifest.json \
# --premine-validators 100
docker container run \
--rm \
--workdir /workdir \
--volume $WORKDIR:/workdir \
0xpolygon/polygon-edge:$VERSION \
genesis \
--epoch-size $BLOCK_TIME \
--consensus polybft \
--native-token-config "Matic:MATIC:18:true" \
--premine ${NODE_ADDRESSES[0]}:1000000000000000000000000000 \
--premine ${NODE_ADDRESSES[1]}:1000000000000000000000000000 \
--premine ${NODE_ADDRESSES[2]}:1000000000000000000000000000 \
--premine ${NODE_ADDRESSES[3]}:1000000000000000000000000000 \
--reward-wallet ${NODE_ADDRESSES[0]}:1000000000000000000000000000 \
--validators /ip4/190.180.170.11/tcp/30011/p2p/${NODE_IDS[0]}:${NODE_ADDRESSES[0]}:${NODE_PUB_KEYS[0]} \
--validators /ip4/190.180.170.12/tcp/30021/p2p/${NODE_IDS[1]}:${NODE_ADDRESSES[1]}:${NODE_PUB_KEYS[1]} \
--validators /ip4/190.180.170.13/tcp/30031/p2p/${NODE_IDS[2]}:${NODE_ADDRESSES[2]}:${NODE_PUB_KEYS[2]} \
--validators /ip4/190.180.170.14/tcp/30041/p2p/${NODE_IDS[3]}:${NODE_ADDRESSES[3]}:${NODE_PUB_KEYS[3]} \
--chain-id $CHAIN_ID
# --validators /ip4/190.180.170.11/tcp/30011/p2p/${NODE_IDS[0]}:${NODE_ADDRESSES[0]}:${NODE_PUB_KEYS[0]}:${NODE_SIGS[0]} \
# --validators /ip4/190.180.170.12/tcp/30021/p2p/${NODE_IDS[1]}:${NODE_ADDRESSES[1]}:${NODE_PUB_KEYS[1]}:${NODE_SIGS[1]} \
# --validators /ip4/190.180.170.13/tcp/30031/p2p/${NODE_IDS[2]}:${NODE_ADDRESSES[2]}:${NODE_PUB_KEYS[2]}:${NODE_SIGS[2]} \
# --validators /ip4/190.180.170.14/tcp/30041/p2p/${NODE_IDS[3]}:${NODE_ADDRESSES[3]}:${NODE_PUB_KEYS[3]}:${NODE_SIGS[3]}
# --manifest ./manifest.json
# --bridge-json-rpc http://127.0.0.1:8545 \
# --bootnode /ip4/190.180.170.11/tcp/10001/p2p/$BOOT_NODE_ID_1 \
# --bootnode /ip4/190.180.170.12/tcp/20001/p2p/$BOOT_NODE_ID_2
# --ibft-validator ${NODE_ADDRESSES[0]}:${NODE_PUB_KEYS[0]} \
# --ibft-validator ${NODE_ADDRESSES[1]}:${NODE_PUB_KEYS[1]} \
# --ibft-validator ${NODE_ADDRESSES[2]}:${NODE_PUB_KEYS[2]} \
# --ibft-validator ${NODE_ADDRESSES[3]}:${NODE_PUB_KEYS[3]} \
sudo chown :$USER -R $WORKDIR/genesis.json
sudo chmod g+w -R $WORKDIR/genesis.json
echo =================================================
echo DEPLOYING CONTRACTS. THIS MAY TAKE A WHILE, DEPENDING ON THE BLOCK FREQUENCY OF YOUR ETH NODE
echo =================================================
docker container run \
--rm \
--workdir /workdir \
--volume $WORKDIR:/workdir \
--network host \
0xpolygon/polygon-edge:$VERSION \
polybft stake-manager-deploy \
--jsonrpc http://127.0.0.1:$ETH_PORT \
--genesis ./genesis.json \
--test
STAKE_MGR_CONTRACT=$(cat $WORKDIR/genesis.json | grep stakeManagerAddr | sed -r 's/.*\"stakeManagerAddr\"\:[[:space:]]\"//' | sed -r 's/",//');
STAKE_TOKEN_CONTRACT=$(cat $WORKDIR/genesis.json | grep stakeTokenAddr | sed -r 's/.*\"stakeTokenAddr\"\:[[:space:]]\"//' | sed -r 's/",//');
OUTPUT=$(docker container run \
--rm \
--workdir /workdir \
--volume $WORKDIR:/workdir \
--network host \
0xpolygon/polygon-edge:$VERSION \
rootchain deploy \
--test \
--json-rpc http://127.0.0.1:$ETH_PORT \
--genesis ./genesis.json \
--stake-manager $STAKE_MGR_CONTRACT \
--stake-token $STAKE_TOKEN_CONTRACT)
echo "$OUTPUT" > $WORKDIR/rootchain-contracts.log
OUTPUT=$WORKDIR/rootchain-contracts.log
CONTRACT_LINE=$(grep 'Name = CustomSupernetManager' --no-group-separator -A1 $OUTPUT | grep -v 'Name = CustomSupernetManager')
SN_MGR_CONTRACT=$(echo "$CONTRACT_LINE" | $SED -r 's/(Contract \(address\))[[:space:]]*=[[:space:]]//')
echo $SN_MGR_CONTRACT
docker container run \
--rm \
--workdir /workdir \
--volume $WORKDIR:/workdir \
--network host \
0xpolygon/polygon-edge:$VERSION \
rootchain fund \
--addresses ${NODE_ADDRESSES[0]},${NODE_ADDRESSES[1]},${NODE_ADDRESSES[2]},${NODE_ADDRESSES[3]} \
--amounts 1000000000000000000,1000000000000000000,1000000000000000000,1000000000000000000 \
--json-rpc http://127.0.0.1:$ETH_PORT
docker container run \
--rm \
--workdir /workdir \
--volume $WORKDIR:/workdir \
--network host \
0xpolygon/polygon-edge:$VERSION \
polybft whitelist-validators \
--jsonrpc http://127.0.0.1:$ETH_PORT \
--supernet-manager $SN_MGR_CONTRACT \
--addresses ${NODE_ADDRESSES[0]},${NODE_ADDRESSES[1]},${NODE_ADDRESSES[2]},${NODE_ADDRESSES[3]} \
--private-key aa75e9a7d427efc732f8e4f1a5b7646adcc61fd5bae40f80d13c8419c9f43d6d
for i in {1..4}; do
docker container run \
--rm \
--workdir /workdir \
--volume $WORKDIR:/workdir \
--network host \
0xpolygon/polygon-edge:$VERSION \
polybft register-validator \
--data-dir /workdir/node-$i \
--jsonrpc http://127.0.0.1:$ETH_PORT \
--supernet-manager $SN_MGR_CONTRACT
done
CreateContainers
if [ "${NO_START}" == "0" ]; then
Start
fi
if [ "${QUIET}" == "0" ]; then
Info
fi
}
CreateContainers() {
for i in {1..4}; do
NAME=polygon-edge-$i
WORKDIR=~/.polygon-edge
GRPC_PORT=300${i}0
P2P_PORT=300${i}1
RPC_PORT=300${i}2
docker container create \
--hostname $NAME \
--name $NAME \
--workdir /workdir/node-$i \
--volume $WORKDIR:/workdir \
--network polygon-edge \
--ip 190.180.170.$((10+$i)) \
--publish ${GRPC_PORT}-${RPC_PORT}:${GRPC_PORT}-${RPC_PORT} \
--add-host host.docker.internal:host-gateway \
0xpolygon/polygon-edge:$VERSION \
server \
--data-dir /workdir/node-$i \
--chain /workdir/genesis.json \
--nat 190.180.170.$((10+$i)) \
--grpc-address 0.0.0.0:${GRPC_PORT} \
--libp2p 0.0.0.0:${P2P_PORT} \
--jsonrpc 0.0.0.0:${RPC_PORT} \
--seal
done
}
RemoveContainers() {
docker container rm $(docker container ls -aq --filter name=polygon-edge-*)
}
Start() {
docker container start $(docker container ls -aq --filter name=polygon-edge-*)
echo Local Polygon network started.
}
Stop() {
docker container stop $(docker container ls -aq --filter name=polygon-edge-*)
echo Local Polygon network stopped.
}
Info() {
CHAIN_ID=$(cat ~/.polygon-edge/genesis.json | grep chainID | $SED -r 's/[[:space:]]*"chainID":[[:space:]]//' | $SED -r 's/,//')
for i in {1..4}; do
echo "======= polygon-edge-${i} ========="
WORKDIR=~/.polygon-edge/node-$i
if [ -e $WORKDIR ]; then
echo "ChainId = $CHAIN_ID"
echo "$(cat $WORKDIR/node.info)"
if [ "${QUIET}" == "0" ]; then
echo "Private Key = $(cat $WORKDIR/consensus/validator.key)"
else
echo "Private Key = *************************************"
fi
echo "gRPC = localhost:300${i}0"
echo "P2P = localhost:300${i}1"
echo "JSON-RPC (http/ws) = localhost:300${i}2[/ws]"
echo
else
echo This node is not configured. Did you run init?
fi
done
}
Logs() {
docker container logs -f -n $LINES polygon-edge-$NODE
}
Clean() {
echo This will remove all data, containers, and images. This cannot be undone.
echo Do you wish to continue \(y/n\)?
read ANS
if [ "$ANS" == "y" ] || [ "$ANS" == "Y" ]; then
Stop
RemoveContainers
docker network rm polygon-edge
docker image rm 0xpolygon/polygon-edge:$VERSION
echo Removing ~/.polygon-edge
echo You might be asked for a sudo password.
sudo rm -rf ~/.polygon-edge
else
exit 0
fi
}
Rebuild() {
Stop
RemoveContainers
CreateContainers
}
# Check for docker
if [[ -z $(which docker) ]]; then
echo "Docker must be installed."
exit 1;
fi
# Check docker is running
if ! docker info > /dev/null 2>&1; then
echo "This script uses docker, and it isn't running - please start docker and try again!"
exit 1;
fi
# MacOS has a FreeBSD version of sed which is missing handy features.
SED=sed
SYSTEM_INFO=$(uname -a)
SI_ARR=(${SYSTEM_INFO// / })
if [ "${SI_ARR[0]}" == "Darwin" ]; then
if [[ -z $(which gsed) ]]; then
echo 'You are missing gnu-sed (a.k.a. gsed). The command to install it is: brew install gnu-sed'
echo 'Would you like to install it now? (y/n)'
read ANS
if [ "$ANS" == "y" ] || [ "$ANS" == "Y" ]; then
brew install gnu-sed
else
exit 1;
fi
fi
SED=gsed
fi
# Parse input options
for i in `seq 1 $#`; do
PLUS1=$(( $i + 1 ))
if [ "${!i}" == "--help" ] || [ "${!i}" == "-h" ]; then
Usage
exit
elif [ "${!i}" == "--no-start" ]; then
NO_START=1
elif [ "${!i}" == "--quiet" ]; then
QUIET=1
elif [ "${!i}" == "--chainId" ]; then
CHAIN_ID=${!PLUS1}
elif [ "${!i}" == "--node" ] || [ "${!i}" == "-n" ]; then
NODE=${!PLUS1}
elif [ "${!i}" == "--lines" ] || [ "${!i}" == "-l" ]; then
LINES=${!PLUS1}
elif [ "${!i}" == "--version" ]; then
VERSION=${!PLUS1}
elif [ "${!i}" == "--block-time" ]; then
BLOCK_TIME=${!PLUS1}
# elif [ "${!i}" == "--eth-key" ]; then
# ETH_HEX_KEY=${!PLUS1}
# # trim leading 0x
# if [ "$(expr substr $ETH_HEX_KEY 1 2)" == "0x" ]; then
# ETH_HEX_KEY=$(expr substr $ETH_HEX_KEY 3 99)
# fi
fi
done
if [ "$1" == "init" ]; then
Init
elif [ "$1" == "start" ]; then
Start
elif [ "$1" == "stop" ]; then
Stop
elif [ "$1" == "info" ]; then
Info
elif [ "$1" == "logs" ]; then
Logs
elif [ "$1" == "clean" ]; then
Clean
elif [ "$1" == "rebuild" ]; then
Rebuild
else
Usage
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment