Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .github/workflows/trigger-devnet-upgrade.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
name: trigger-devnet-upgrade
permissions:
contents: read
id-token: write

on:
schedule:
- cron: '0 */2 * * *' # Runs every 2 hours
jobs:
push_dev_net_protocol_upgrade_if_needed:
runs-on: ubuntu-latest

steps:
- name: Install casper-client
run: |
sudo mkdir -m 0755 -p /etc/apt/keyrings/
sudo curl https://repo.casper.network/casper-repo-pubkey.gpg --output /etc/apt/keyrings/casper-repo-pubkey.gpg
sudo echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/casper-repo-pubkey.gpg] https://repo.casper.network/releases jammy main" | sudo tee /etc/apt/sources.list.d/casper.list
sudo apt-get update
sudo apt-get install casper-client -y

# Get script without checkout for use on any repo
- name: Get script
run: |
mkdir ci
cd ci
curl -JLO https://raw.githubusercontent.com/casper-network/casper-node/refs/heads/dev/ci/dev_net_protocol_generate.sh
chmod +x dev_net_protocol_generate.sh
curl -JLO https://raw.githubusercontent.com/casper-network/casper-node/refs/heads/dev/ci/next_upgrade_era_with_buffer.sh
chmod +x next_upgrade_era_with_buffer.sh

# Assign AWS PROD role to get access to production cloudfronts and S3 buckets
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ACCESS_ROLE_GENESIS }}
role-session-name: GitHub_to_AWS_via_FederatedOIDC
aws-region: ${{ secrets.AWS_ACCESS_REGION_GENESIS }}

- name: Build protocol update
run: ./ci/dev_net_protocol_generate.sh

- name: Upload artifacts to S3
run: aws s3 sync ./target/genesis/ s3://${{ secrets.AWS_BUCKET_GENESIS }}/devnet/

# Required in case of overwrite
- name: Invalidate CloudFront cache
run: aws cloudfront create-invalidation --distribution-id ${{ secrets.AWS_CLOUDFRONT_GENESIS }} --paths "/devnet/*"


53 changes: 53 additions & 0 deletions ci/approx_next_era_starts.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/usr/bin/env bash

if [ "$#" -lt 1 ]; then
echo "Usage: $0 <node ip for rpc | url for rpc> [number of future eras]"
exit 1
fi

if [[ $1 == http* ]]; then
# Starts with http, so assume good full url
NODE_ADDRESS="--node-address $1"
else
NODE_ADDRESS="--node-address http://$NODE_IP:7777"
fi

if ! command -v "casper-client" &> /dev/null ; then
echo "casper-client is not installed and required. Exiting..."
exit 1
fi

if [ "$#" -lt 2 ]; then
echo "No number of future eras given, using default."
FUTURE_ERAS=10
else
FUTURE_ERAS=$2
fi

LAST_SWITCH_BLOCK=$(casper-client get-era-summary $NODE_ADDRESS | jq -r .result.era_summary.block_hash | tr -d "/n")

# Getting Timestamp and Era with one call using `@` delimiter
SB_TIMESTAMP_AND_ERA=$(casper-client get-block -b $LAST_SWITCH_BLOCK $NODE_ADDRESS | jq -r '.result.block_with_signatures.block.Version2.header | [.timestamp,.era_id] | join("@")' | tr -d "/n")

# Parsing this back into seperate variables
IFS=@ read -r SB_TIMESTAMP LAST_ERA_ID <<< "$SB_TIMESTAMP_AND_ERA"

SB_EPOCH=$(date -d "$SB_TIMESTAMP" +%s)

START_ERA_ID=$(( LAST_ERA_ID + 1 ))
NEXT_ERA_ID=$(( START_ERA_ID + 1 ))

FINAL_ERA_ID=$(( START_ERA_ID + FUTURE_ERAS ))

ERA_TIME_SECONDS=$(( 120*60+9 ))

#echo "current_era:$START_ERA_ID started_utc:$SB_TIMESTAMP"

while (( NEXT_ERA_ID <= FINAL_ERA_ID )); do
TIMESTAMP_FROM_Z=$(date -u -d "@$SB_EPOCH" +"%Y-%m-%dT%H:%M:%SZ")
TIMESTAMP_FROM_L=$(date -d "@$SB_EPOCH" +"%Y-%m-%dT%H:%M:%S%z")
echo "era:$NEXT_ERA_ID utc:$TIMESTAMP_FROM_Z local:$TIMESTAMP_FROM_L"
let NEXT_ERA_ID++
SB_EPOCH=$(( SB_EPOCH + ERA_TIME_SECONDS ))
done

122 changes: 122 additions & 0 deletions ci/dev_net_protocol_generate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#!/usr/bin/env bash

if ! command -v "casper-client" &> /dev/null ; then
echo "casper-client is not installed and required. Exiting..."
exit 1
fi

# RPC for getting current era for activation point planning
NODE_RPC_URL="https://node-1.dev.casper.network/rpc"
# Delay in minutes till next era start for upgrade
NEXT_ERA_MIN_DELAY=20


ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." >/dev/null 2>&1 && pwd)"
CI_SCRIPT_DIR="$ROOT_DIR/ci"
TARGET_DIR="$ROOT_DIR/target"
GENESIS_DIR="$TARGET_DIR/genesis"
CONFIG_DIR="$TARGET_DIR/config"

# pull latest dev hash from artifacts
CURRENT_HASH=$(curl -s https://genesis.casper.network/artifacts/casper-node/dev.latest)
echo "Checked out Github hash $CURRENT_HASH"

LATEST_HASH=$(curl -s https://genesis.casper.network/devnet/latest_git_hash | tr -d '\n')
echo "Latest Hash from devnet protocol is $LATEST_HASH"
if [ ${#LATEST_HASH} -ne 40 ]; then
echo "Latest Hash Length is bad. Probably had retrieval error: $LATEST_HASH"
exit 1
fi

echo

if [ "$CURRENT_HASH" == "$LATEST_HASH" ]; then
echo "Last published devnet protocol has same hash, erroring out."
exit 1 # This fails job and stops workflow
fi

LATEST_PROTOCOL_VERSION="$(curl -s https://genesis.casper.network/devnet/protocol_versions | tail -n 1 | tr -d '\n')"
echo "Latest devnet protocol version: $LATEST_PROTOCOL_VERSION"

IFS="_"
# Read latest protocol parts into array
read -ra LPVA <<< "$LATEST_PROTOCOL_VERSION"

# Incrementing one to patch
NEW_PROTOCOL_VERSION=${LPVA[0]}_${LPVA[1]}_$((LPVA[2] + 1))
echo "New devnet protocol version: $NEW_PROTOCOL_VERSION"
echo

PROTOCOL_DIR="$GENESIS_DIR/$NEW_PROTOCOL_VERSION"
echo "## Creating $PROTOCOL_DIR"
mkdir -p "$PROTOCOL_DIR"
echo

echo "$NEW_PROTOCOL_VERSION" > "$GENESIS_DIR/protocol_versions"
echo "## protocol_versions file contents:"
echo "---"
cat "$GENESIS_DIR/protocol_versions"
echo "---"
echo

echo "$CURRENT_HASH" > "$GENESIS_DIR/latest_git_hash"
echo "## latest_git_hash file contents:"
echo "---"
cat "$GENESIS_DIR/latest_git_hash"
echo "---"
echo

mkdir -p "$CONFIG_DIR"
cd "$TARGET_DIR" || exit 1
DOWNLOAD_PATH="https://genesis.casper.network/artifacts/casper-node/$CURRENT_HASH"
echo "## Downloading: $DOWNLOAD_PATH/bin.tar.gz"
curl -JLO "$DOWNLOAD_PATH/bin.tar.gz" || exit 1

echo "## Downloading: $DOWNLOAD_PATH/config-dev.tar.gz"
curl -JLO "$DOWNLOAD_PATH/config-dev.tar.gz" || exit 1

cd "$CONFIG_DIR" || exit 1
# This will validate that files retrieved were good. Should error if just curl output

echo "## Decompressing config"
tar -xzvf ../config-dev.tar.gz . || exit 1

ACTIVATION_POINT=$("$CI_SCRIPT_DIR/next_upgrade_era_with_buffer.sh" "$NODE_RPC_URL" "$NEXT_ERA_MIN_DELAY")

echo "## Replacing activation_point in chainspec.toml with $ACTIVATION_POINT"
# chainspec.toml replacement
sed -i '/^activation_point = /c\activation_point = '"$ACTIVATION_POINT" chainspec.toml

# config_example.toml replacement
echo "## Retrieving statuses to make known_addresses"
KNOWN_ADDRESSES="[$( (curl -s https://node-1.dev.casper.network/status | jq -r '.peers[] | .address';
curl -s https://node-2.dev.casper.network/status | jq -r '.peers[] | .address';
curl -s https://node-3.dev.casper.network/status | jq -r '.peers[] | .address';
curl -s https://node-4.dev.casper.network/status | jq -r '.peers[] | .address';) |
sort | uniq | xargs -d '\n' printf "'%s'," | sed 's/, $//' )]"
echo "## Generated: $KNOWN_ADDRESSES"
# If KNOWN_ADDRESSES is very short, calls above failed. IPs should be 20 per min. -> 80
MIN_KNOWN_ADDRESSES_LEN=80
if [[ ${#KNOWN_ADDRESSES} -le $MIN_KNOWN_ADDRESSES_LEN ]]; then
echo "Generated known addresses is to short. Expected min of $MIN_KNOWN_ADDRESSES_LEN. Calls probably failed."
exit 1
fi
echo "## Replacing known_addresses in config-example.toml"
sed -i '/^known_addresses = /c\known_addresses = '"$KNOWN_ADDRESSES" config-example.toml

CS_PROTOCOL=$(echo -n "$NEW_PROTOCOL_VERSION" | tr '_' '.')
echo "## Replacing protocol.version with $CS_PROTOCOL"
sed -i '/^version = /c\version = '\'"$CS_PROTOCOL"\' chainspec.toml

echo "## Compressing new config.tar.gz"
tar -czvf ../config.tar.gz .

cd ..
pwd

echo "## Moving files bin and config into $PROTOCOL_DIR"
mv config.tar.gz "$PROTOCOL_DIR/"
mv bin.tar.gz "$PROTOCOL_DIR/"

echo "## Listing contents of $GENESIS_DIR"
ls -alrR "$GENESIS_DIR"
35 changes: 35 additions & 0 deletions ci/mins_to_switch_block.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/usr/bin/env bash

if [ "$#" -ne 1 ]; then
echo "Usage: $0 <node ip for rpc | url for rpc>"
exit 1
fi

if ! command -v "casper-client" &> /dev/null ; then
echo "casper-client is not installed and required. Exiting..."
exit 1
fi

if [[ $1 == http* ]]; then
# Starts with http, so assume good full url
NODE_ADDRESS="--node-address $1"
else
NODE_ADDRESS="--node-address http://$NODE_IP:7777"
fi

LAST_SWITCH_BLOCK=$(casper-client get-era-summary $NODE_ADDRESS | jq -r .result.era_summary.block_hash | tr -d "/n")

# Getting Timestamp and Era with one call using `@` delimiter
SB_TIMESTAMP_AND_ERA=$(casper-client get-block -b $LAST_SWITCH_BLOCK $NODE_ADDRESS | jq -r '.result.block_with_signatures.block.Version2.header | [.timestamp,.era_id] | join("@")' | tr -d "/n")

# Parsing this back into seperate variables
IFS=@ read -r SB_TIMESTAMP LAST_ERA_ID <<< "$SB_TIMESTAMP_AND_ERA"

# Converting timestamp into Unix second based Epoch
SB_EPOCH=$(date -d "$SB_TIMESTAMP" +%s)
NOW_EPOCH=$(date +%s)

# Assuming Era length 120 minutes, doing math till next Era
MINS_TILL_SB=$(( 120 - ((NOW_EPOCH - $SB_EPOCH) / 60) ))
NEXT_ERA=$(( LAST_ERA_ID + 1 ))
echo "$MINS_TILL_SB mins till era $NEXT_ERA"
41 changes: 41 additions & 0 deletions ci/next_upgrade_era_with_buffer.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/env bash

if [ "$#" -ne 2 ]; then
echo "Usage: $0 <node ip for rpc | url for rpc> <mins buffer>"
exit 1
fi

if ! command -v "casper-client" &> /dev/null ; then
echo "casper-client is not installed and required. Exiting..."
exit 1
fi

if [[ $1 == http* ]]; then
# Starts with http, so assume good full url
NODE_ADDRESS="--node-address $1"
else
NODE_ADDRESS="--node-address http://$NODE_IP:7777"
fi

BUFFER_MINS=$2

LAST_SWITCH_BLOCK=$(casper-client get-era-summary $NODE_ADDRESS | jq -r .result.era_summary.block_hash | tr -d "/n")

# Getting Timestamp and Era with one call using `@` delimiter
SB_TIMESTAMP_AND_ERA=$(casper-client get-block -b $LAST_SWITCH_BLOCK $NODE_ADDRESS | jq -r '.result.block_with_signatures.block.Version2.header | [.timestamp,.era_id] | join("@")' | tr -d "/n")

# Parsing this back into seperate variables
IFS=@ read -r SB_TIMESTAMP LAST_ERA_ID <<< "$SB_TIMESTAMP_AND_ERA"

SB_EPOCH=$(date -d "$SB_TIMESTAMP" +%s)
NOW_EPOCH=$(date +%s)

MINS_TILL_SB=$(( 120 - ((NOW_EPOCH - $SB_EPOCH) / 60) ))

if [ "$MINS_TILL_SB" -gt "$BUFFER_MINS" ]; then
NEXT_BUF_ERA=$(( LAST_ERA_ID + 2 ));
else
NEXT_BUF_ERA=$(( LAST_ERA_ID + 3 ));
fi

echo "$NEXT_BUF_ERA"