Publish Scoring Results (597.222968) #255
Workflow file for this run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Apply Scoring | |
on: | |
workflow_dispatch: | |
pull_request: | |
types: [closed] | |
branches: | |
- master | |
jobs: | |
apply_scoring: | |
runs-on: ubuntu-latest | |
if: github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request' && github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'scoring/')) | |
steps: | |
- name: Set start timestamp | |
run: | | |
start_timestamp=$(date +%s) | |
echo "start_timestamp=$start_timestamp" >> $GITHUB_ENV | |
- name: Checkout the repository | |
uses: actions/checkout@master | |
with: | |
ref: master | |
fetch-depth: 20 | |
- name: Load scoring details | |
run: | | |
set -ex | |
scores_csv=$(git log -1 --name-only --pretty=format: --grep 'scoring run' | grep scores.csv) | |
params_env=$(git log -1 --name-only --pretty=format: --grep 'scoring run' | grep params.env) | |
scoring_run_ui_id=$(git log -1 --name-only --pretty=format: --grep 'scoring run' | head -1 | awk -F / '{print $2}') | |
epoch=$(<<<"$scoring_run_ui_id" awk -F . '{print $1}') | |
if [[ -z $scores_csv ]] | |
then | |
echo "Failed to find CSV with scores in the PR!" | |
exit 1 | |
fi | |
if [[ -z $params_env ]] | |
then | |
echo "Failed to find ENV file with scoring params in the PR!" | |
exit 1 | |
fi | |
if [[ -z $scoring_run_ui_id ]] | |
then | |
echo "Failed to detect scoring run UI ID from the PR!" | |
exit 1 | |
fi | |
if [[ -z $epoch ]] | |
then | |
echo "Failed to detect epoch from the UI ID!" | |
exit 1 | |
fi | |
echo "scores_csv=$scores_csv" >> $GITHUB_ENV | |
echo "params_env=$params_env" >> $GITHUB_ENV | |
echo "scoring_run_ui_id=$scoring_run_ui_id" >> $GITHUB_ENV | |
echo "epoch=$epoch" >> $GITHUB_ENV | |
- name: Configure AWS credentials | |
uses: aws-actions/configure-aws-credentials@v1 | |
with: | |
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} | |
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | |
aws-region: ${{ secrets.AWS_DEFAULT_REGION }} | |
- name: Login to Amazon ECR | |
id: login-ecr | |
uses: aws-actions/amazon-ecr-login@v1 | |
- name: Prepare solana config | |
run: | | |
cat <<EOF > /tmp/solana-config.yml | |
json_rpc_url: "$RPC_URL" | |
websocket_url: "" | |
keypair_path: /.config/solana/id.json | |
address_labels: | |
"11111111111111111111111111111111": System Program | |
commitment: confirmed | |
EOF | |
echo "$KEYPAIR" > /tmp/id.json | |
env: | |
RPC_URL: ${{ secrets.RPC_URL }} | |
KEYPAIR: ${{ secrets.VALIDATOR_MANAGEMENT_KEYPAIR }} | |
- name: Configure image | |
run: | | |
images=$(aws ecr describe-images --repository-name marinade.finance/validator-manager) | |
latest=$(<<<"$images" jq '.imageDetails[] | .imagePushedAt + " " + .imageTags[0]' -r | sort | tail -1 | cut -d' ' -f2) | |
echo "latest=$latest" >> $GITHUB_ENV | |
- name: Run scoring - simulation | |
run: | | |
docker run --rm --user "$(id -u):$(id -g)" \ | |
-v /tmp/solana-config.yml:/.config/solana/cli/config.yml \ | |
-v /tmp/id.json:/.config/solana/id.json \ | |
-v "$(realpath "$SCORES_CSV"):/scores.csv" \ | |
"$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" \ | |
./validator-manager -s --print-only update-scores2 --scores-file /scores.csv | |
env: | |
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} | |
ECR_REPOSITORY: marinade.finance/validator-manager | |
SCORES_CSV: ${{ env.scores_csv }} | |
IMAGE_TAG: ${{ env.latest }} | |
- name: Run scoring | |
run: | | |
docker run --rm --user "$(id -u):$(id -g)" \ | |
-v /tmp/solana-config.yml:/.config/solana/cli/config.yml \ | |
-v /tmp/id.json:/.config/solana/id.json \ | |
-v "$(realpath "$SCORES_CSV"):/scores.csv" \ | |
"$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" \ | |
./validator-manager update-scores2 --scores-file /scores.csv | |
env: | |
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} | |
ECR_REPOSITORY: marinade.finance/validator-manager | |
SCORES_CSV: ${{ env.scores_csv }} | |
IMAGE_TAG: ${{ env.latest }} | |
- name: Publish scoring results | |
run: | | |
export $(grep -v '^#' "${{ env.params_env }}" | xargs -d '\n') | |
curl -sLfS "https://validators-api.marinade.finance/admin/scores?epoch=${{ env.epoch }}&components=$COMPONENTS&component_weights=$COMPONENT_WEIGHTS&ui_id=${{ env.scoring_run_ui_id }}" -X POST \ | |
-H "Content-Type: multipart/form-data" \ | |
-H "Authorization: ${{ secrets.VALIDATORS_API_ADMIN_TOKEN }}" \ | |
--form "scores_csv=@${{ env.scores_csv }}" | |
- name: Update job status and compute job duration | |
run: | | |
start_timestamp=${{ env.start_timestamp }} | |
duration=$(($(date +%s) - $start_timestamp)) | |
curl -sLfS "https://validators-api.marinade.finance/admin/metrics?job_success=true&apply_scoring_duration=$duration" -X POST \ | |
-H "Authorization: ${{ secrets.VALIDATORS_API_ADMIN_TOKEN }}" | |
- name: Report job failure | |
if: ${{ failure() }} | |
run: | | |
start_timestamp=${{ env.start_timestamp }} | |
duration=$(($(date +%s) - $start_timestamp)) | |
curl -sLfS "https://validators-api.marinade.finance/admin/metrics?job_error=true&apply_scoring_duration=$duration" -X POST \ | |
-H "Authorization: ${{ secrets.VALIDATORS_API_ADMIN_TOKEN }}" | |
- name: Send Discord Notification | |
run: | | |
curl "$DISCORD_WEBHOOK" -H "Content-Type: application/json" -d '{ | |
"username": "Delegation Strategy", | |
"avatar_url": "https://public.marinade.finance/ds-scoring-bot.png", | |
"embeds": [ | |
{ | |
"title": "Scoring successfully applied.", | |
"color": "52224" | |
} | |
] | |
}' | |
env: | |
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} | |
# - name: Approval stage | |
# uses: trstringer/manual-approval@v1 | |
# with: | |
# secret: ${{ github.TOKEN }} | |
# approvers: user1,user2,org-team1 | |
# minimum-approvals: 1 | |
# issue-title: "Deploying v1.3.5 to prod from staging" | |
# issue-body: "Please approve or deny the deployment of version v1.3.5." | |
# exclude-workflow-initiator-as-approver: false | |
# additional-approved-words: '' | |
# additional-denied-words: '' | |
emergency_unstake: | |
needs: apply_scoring | |
runs-on: ubuntu-latest | |
steps: | |
- name: Checkout the repository | |
uses: actions/checkout@master | |
with: | |
ref: master | |
fetch-depth: 20 | |
- name: Load scoring details | |
run: | | |
set -ex | |
unstake_hints_json=$(git log -1 --name-only --pretty=format: --grep 'scoring run' | grep unstake-hints.json) | |
scoring_run_ui_id=$(git log -1 --name-only --pretty=format: --grep 'scoring run' | head -1 | awk -F / '{print $2}') | |
epoch=$(<<<"$scoring_run_ui_id" awk -F . '{print $1}') | |
if [[ -z $unstake_hints_json ]] | |
then | |
echo "Failed to find JSON with unstake hints in the PR!" | |
exit 1 | |
fi | |
if [[ -z $epoch ]] | |
then | |
echo "Failed to detect epoch from the UI ID!" | |
exit 1 | |
fi | |
echo "unstake_hints_json=$unstake_hints_json" >> $GITHUB_ENV | |
echo "epoch=$epoch" >> $GITHUB_ENV | |
- name: Configure AWS credentials | |
uses: aws-actions/configure-aws-credentials@v1 | |
with: | |
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} | |
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | |
aws-region: ${{ secrets.AWS_DEFAULT_REGION }} | |
- name: Login to Amazon ECR | |
id: login-ecr | |
uses: aws-actions/amazon-ecr-login@v1 | |
- name: Prepare solana config | |
run: | | |
cat <<EOF > /tmp/solana-config.yml | |
json_rpc_url: "$RPC_URL" | |
websocket_url: "" | |
keypair_path: /.config/solana/id.json | |
address_labels: | |
"11111111111111111111111111111111": System Program | |
commitment: confirmed | |
EOF | |
echo "$KEYPAIR" > /tmp/id.json | |
env: | |
RPC_URL: ${{ secrets.RPC_URL }} | |
KEYPAIR: ${{ secrets.VALIDATOR_MANAGEMENT_KEYPAIR }} | |
- name: Configure image | |
run: | | |
images=$(aws ecr describe-images --repository-name marinade.finance/validator-manager) | |
latest=$(<<<"$images" jq '.imageDetails[] | .imagePushedAt + " " + .imageTags[0]' -r | sort | tail -1 | cut -d' ' -f2) | |
echo "latest=$latest" >> $GITHUB_ENV | |
- name: Emergency unstake - simulation | |
run: | | |
<"$UNSTAKE_HINTS_JSON" jq '.unstake_hints[].vote_account' -r | xargs -I{} \ | |
docker run --rm --user "$(id -u):$(id -g)" \ | |
-v /tmp/solana-config.yml:/.config/solana/cli/config.yml \ | |
-v /tmp/id.json:/.config/solana/id.json \ | |
"$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" \ | |
./validator-manager -s --print-only emergency-unstake {} | |
env: | |
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} | |
ECR_REPOSITORY: marinade.finance/validator-manager | |
UNSTAKE_HINTS_JSON: ${{ env.unstake_hints_json }} | |
IMAGE_TAG: ${{ env.latest }} | |
- name: Emergency unstake | |
run: | | |
<"$UNSTAKE_HINTS_JSON" jq '.unstake_hints[].vote_account' -r | xargs -I{} \ | |
docker run --rm --user "$(id -u):$(id -g)" \ | |
-v /tmp/solana-config.yml:/.config/solana/cli/config.yml \ | |
-v /tmp/id.json:/.config/solana/id.json \ | |
"$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" \ | |
./validator-manager emergency-unstake {} | |
env: | |
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} | |
ECR_REPOSITORY: marinade.finance/validator-manager | |
UNSTAKE_HINTS_JSON: ${{ env.unstake_hints_json }} | |
IMAGE_TAG: ${{ env.latest }} | |
- name: Send Discord Notification | |
run: | | |
validators_count=$(<"$UNSTAKE_HINTS_JSON" jq '[.unstake_hints[].marinade_stake] | length' -r) | |
unstaked_sol=$(<"$UNSTAKE_HINTS_JSON" jq '[.unstake_hints[].marinade_stake] | add' -r) | |
message="Emergency unstake successfully applied. ($validators_count validators, $unstaked_sol SOL)" | |
if (( $validators_count == 0 )) | |
then | |
message="No emergency unstakes needed this time." | |
fi | |
curl "$DISCORD_WEBHOOK" -H "Content-Type: application/json" -d '{ | |
"username": "Delegation Strategy - Emergency Unstake", | |
"avatar_url": "https://public.marinade.finance/ds-emergency-bot.png", | |
"embeds": [ | |
{ | |
"title": "'"$message"'", | |
"color": "52224" | |
} | |
] | |
}' | |
env: | |
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} | |
UNSTAKE_HINTS_JSON: ${{ env.unstake_hints_json }} |