From c972f4839641cfd7fd9fa9f1b2adb4c94aff6bda Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Tue, 15 Jul 2025 16:04:05 +0530 Subject: [PATCH 01/31] add solana to default values --- starship/charts/devnet/defaults.yaml | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/starship/charts/devnet/defaults.yaml b/starship/charts/devnet/defaults.yaml index 5b6d5e71f..c0531f92a 100644 --- a/starship/charts/devnet/defaults.yaml +++ b/starship/charts/devnet/defaults.yaml @@ -803,6 +803,38 @@ defaultChains: png: https://raw.githubusercontent.com/cosmos/chain-registry/master/xpla/images/xpla.png svg: https://raw.githubusercontent.com/cosmos/chain-registry/master/xpla/images/xpla.svg coingecko_id: xpla + solana: + image: ghcr.io/hyperweb-io/starship/solana:v1.18.26 + home: /root/.solana + binary: solana-validator + prefix: sol + denom: lamports + prettyName: Solana + coins: 1000000000000000lamports + hdPath: m/44'/501'/0'/0' + coinType: 501 + repo: https://github.com/solana-labs/solana + scripts: + createGenesis: + file: scripts/solana/create-genesis.sh + updateGenesis: + file: scripts/solana/update-genesis.sh + assets: + - base: lamports + description: "The native token of Solana" + name: Solana + display: sol + symbol: SOL + logo_URIs: + png: "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/So11111111111111111111111111111111111111112/logo.png" + svg: "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/So11111111111111111111111111111111111111112/logo.svg" + denom_units: + - denom: lamports + exponent: 0 + - denom: sol + exponent: 9 + coingecko_id: solana + keywords: ["layer1"] ethereum: image: ghcr.io/hyperweb-io/starship/ethereum/client-go:v1.14.12 home: /ethereum From 1adb24959e11b3221c771fac5c52ea0b9b274cd0 Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Tue, 15 Jul 2025 17:21:58 +0530 Subject: [PATCH 02/31] add initial setup for solana nodes --- starship/charts/devnet/defaults.yaml | 30 ++++- .../charts/devnet/scripts/solana/bench-tps.sh | 16 +++ .../scripts/solana/bootstrap-validator.sh | 11 ++ .../charts/devnet/scripts/solana/common.sh | 111 ++++++++++++++++++ .../charts/devnet/scripts/solana/faucet.sh | 7 ++ .../devnet/scripts/solana/fetch-perf-libs.sh | 6 + .../charts/devnet/scripts/solana/setup.sh | 41 +++++++ .../devnet/scripts/solana/validator-x.sh | 21 ++++ .../devnet/templates/chains/solana/bench.yaml | 30 +++++ .../templates/chains/solana/configmap.yaml | 26 ++++ .../templates/chains/solana/faucet.yaml | 49 ++++++++ .../templates/chains/solana/genesis.yaml | 33 ++++++ .../templates/chains/solana/validator.yaml | 40 +++++++ 13 files changed, 417 insertions(+), 4 deletions(-) create mode 100644 starship/charts/devnet/scripts/solana/bench-tps.sh create mode 100644 starship/charts/devnet/scripts/solana/bootstrap-validator.sh create mode 100644 starship/charts/devnet/scripts/solana/common.sh create mode 100644 starship/charts/devnet/scripts/solana/faucet.sh create mode 100644 starship/charts/devnet/scripts/solana/fetch-perf-libs.sh create mode 100644 starship/charts/devnet/scripts/solana/setup.sh create mode 100644 starship/charts/devnet/scripts/solana/validator-x.sh create mode 100644 starship/charts/devnet/templates/chains/solana/bench.yaml create mode 100644 starship/charts/devnet/templates/chains/solana/configmap.yaml create mode 100644 starship/charts/devnet/templates/chains/solana/faucet.yaml create mode 100644 starship/charts/devnet/templates/chains/solana/genesis.yaml create mode 100644 starship/charts/devnet/templates/chains/solana/validator.yaml diff --git a/starship/charts/devnet/defaults.yaml b/starship/charts/devnet/defaults.yaml index c0531f92a..5f3a8f978 100644 --- a/starship/charts/devnet/defaults.yaml +++ b/starship/charts/devnet/defaults.yaml @@ -804,6 +804,7 @@ defaultChains: svg: https://raw.githubusercontent.com/cosmos/chain-registry/master/xpla/images/xpla.svg coingecko_id: xpla solana: + type: solana image: ghcr.io/hyperweb-io/starship/solana:v1.18.26 home: /root/.solana binary: solana-validator @@ -815,10 +816,31 @@ defaultChains: coinType: 501 repo: https://github.com/solana-labs/solana scripts: - createGenesis: - file: scripts/solana/create-genesis.sh - updateGenesis: - file: scripts/solana/update-genesis.sh + common: + name: common.sh + file: scripts/solana/common.sh + fetch-perf-libs: + name: fetch-perf-libs.sh + file: scripts/solana/fetch-perf-libs.sh + setup: + name: setup.sh + file: scripts/solana/setup.sh + faucet: + name: faucet.sh + file: scripts/solana/faucet.sh + bootstrap-validator: + name: bootstrap-validator.sh + file: scripts/solana/bootstrap-validator.sh + validator-x: + name: validator-x.sh + file: scripts/solana/validator-x.sh + bench-tps: + name: bench-tps.sh + file: scripts/solana/bench-tps.sh + faucet: + enabled: true + bench: + enabled: true assets: - base: lamports description: "The native token of Solana" diff --git a/starship/charts/devnet/scripts/solana/bench-tps.sh b/starship/charts/devnet/scripts/solana/bench-tps.sh new file mode 100644 index 000000000..bc95a19c2 --- /dev/null +++ b/starship/charts/devnet/scripts/solana/bench-tps.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +here=$(dirname "$0") +# shellcheck source=multinode-demo/common.sh +source "$here"/common.sh + +# shellcheck source=net/common.sh +source "$(cd "$here"/..; pwd)"/net/common.sh + +args=() +default_arg --entrypoint 127.0.0.1:8001 +default_arg --faucet 127.0.0.1:9900 +default_arg --tx_count 50000 +default_arg --duration 90 + +exec "$solana_bench_tps" "${args[@]}" "$@" \ No newline at end of file diff --git a/starship/charts/devnet/scripts/solana/bootstrap-validator.sh b/starship/charts/devnet/scripts/solana/bootstrap-validator.sh new file mode 100644 index 000000000..7eb2359e9 --- /dev/null +++ b/starship/charts/devnet/scripts/solana/bootstrap-validator.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +here=$(dirname "$0") +# shellcheck source=multinode-demo/common.sh +source "$here"/common.sh + +if [[ -z $1 ]]; then + $agave_validator_cuda "$@" +else + $agave_validator "$@" +fi \ No newline at end of file diff --git a/starship/charts/devnet/scripts/solana/common.sh b/starship/charts/devnet/scripts/solana/common.sh new file mode 100644 index 000000000..8ef3298d7 --- /dev/null +++ b/starship/charts/devnet/scripts/solana/common.sh @@ -0,0 +1,111 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Locate this script’s directory +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# shellcheck disable=2034 +# +# shellcheck source=net/common.sh +source "$(cd "$(dirname "${BASH_SOURCE[0]}")"/.. || exit 1; pwd)"/net/common.sh + +prebuild= +if [[ $1 = "--prebuild" ]]; then + prebuild=true +fi + +if [[ $(uname) != Linux ]]; then + # Protect against unsupported configurations to prevent non-obvious errors + # later. Arguably these should be fatal errors but for now prefer tolerance. + if [[ -n $SOLANA_CUDA ]]; then + echo "Warning: CUDA is not supported on $(uname)" + SOLANA_CUDA= + fi +fi + +if [[ -n $USE_INSTALL || ! -f "$SOLANA_ROOT"/Cargo.toml ]]; then + solana_program() { + declare program="$1" + if [[ -z $program ]]; then + printf "solana" + else + if [[ $program == "validator" || $program == "ledger-tool" || $program == "watchtower" || $program == "install" ]]; then + printf "agave-%s" "$program" + else + printf "solana-%s" "$program" + fi + fi + } +else + solana_program() { + declare program="$1" + declare crate="$program" + + if [[ -z $program ]]; then + crate="cli" + program="solana" + elif [[ $program == "validator" || $program == "ledger-tool" || $program == "watchtower" || $program == "install" ]]; then + program="agave-$program" + else + program="solana-$program" + fi + + if [[ -n $CARGO_BUILD_PROFILE ]]; then + profile_arg="--profile $CARGO_BUILD_PROFILE" + fi + + # Prebuild binaries so that CI sanity check timeout doesn't include build time + if [[ $prebuild ]]; then + ( + set -x + # shellcheck disable=SC2086 # Don't want to double quote cargo + $CARGO_TOOLCHAIN build $profile_arg --bin $program + ) + fi + printf "cargo $CARGO_TOOLCHAIN run $profile_arg --bin %s %s -- " "$program" + } +fi + +solana_bench_tps=$(solana_program bench-tps) +solana_faucet=$(solana_program faucet) +agave_validator=$(solana_program validator) +agave_validator_cuda="$agave_validator --cuda" +solana_genesis=$(solana_program genesis) +solana_gossip=$(solana_program gossip) +solana_keygen=$(solana_program keygen) +solana_ledger_tool=$(solana_program ledger-tool) +solana_cli=$(solana_program) + +export RUST_BACKTRACE=1 + +default_arg() { + declare name=$1 + declare value=$2 + + for arg in "${args[@]}"; do + if [[ $arg = "$name" ]]; then + return + fi + done + + if [[ -n $value ]]; then + args+=("$name" "$value") + else + args+=("$name") + fi +} + +replace_arg() { + declare name=$1 + declare value=$2 + + default_arg "$name" "$value" + + declare index=0 + for arg in "${args[@]}"; do + index=$((index + 1)) + if [[ $arg = "$name" ]]; then + args[$index]="$value" + fi + done +} \ No newline at end of file diff --git a/starship/charts/devnet/scripts/solana/faucet.sh b/starship/charts/devnet/scripts/solana/faucet.sh new file mode 100644 index 000000000..5ff864181 --- /dev/null +++ b/starship/charts/devnet/scripts/solana/faucet.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +here=$(dirname "$0") +# shellcheck source=multinode-demo/common.sh +source "$here"/common.sh + +exec "$solana_faucet" --keypair "$SOLANA_CONFIG_DIR"/faucet.json \ No newline at end of file diff --git a/starship/charts/devnet/scripts/solana/fetch-perf-libs.sh b/starship/charts/devnet/scripts/solana/fetch-perf-libs.sh new file mode 100644 index 000000000..5350224e7 --- /dev/null +++ b/starship/charts/devnet/scripts/solana/fetch-perf-libs.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +# This script is a placeholder for fetching performance libraries. +# The actual implementation will be added later. + +echo "Fetching performance libraries..." \ No newline at end of file diff --git a/starship/charts/devnet/scripts/solana/setup.sh b/starship/charts/devnet/scripts/solana/setup.sh new file mode 100644 index 000000000..cdf672c10 --- /dev/null +++ b/starship/charts/devnet/scripts/solana/setup.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# +# Creates a full-featured setup for a multinode Solana testnet +# + +here=$(dirname "$0") +# shellcheck source=multinode-demo/common.sh +source "$here"/common.sh + +# Create a keypair for the faucet +# +# The faucet is a Solana account that is funded with a large amount of SOL at +# genesis. It is then used to fund other accounts on the testnet. +# +# The faucet keypair is created in the config directory so that it can be easily +# accessed by the faucet service. +# +if [[ ! -f "$SOLANA_CONFIG_DIR"/faucet.json ]]; then + "$solana_keygen" new --no-passphrase -o "$SOLANA_CONFIG_DIR"/faucet.json +fi + +# Create the genesis ledger +# +# The genesis ledger is the first block in the blockchain. It contains a number +# of configuration settings, as well as the initial set of accounts and their +# balances. +# +# The genesis ledger is created using the solana-genesis command. The command +# takes a number of arguments, including the location of the faucet keypair, +# the initial amount of SOL to fund the faucet with, and the location of the +# ledger directory. +# +args=( + --faucet-pubkey "$SOLANA_CONFIG_DIR"/faucet.json + --faucet-lamports 500000000000000000 + --ledger "$SOLANA_CONFIG_DIR"/ledger + --bootstrap-validator-lamports 500000000000000000 + --bootstrap-validator-stake-lamports 100000000000000000 +) + +"$solana_genesis" "${args[@]}" \ No newline at end of file diff --git a/starship/charts/devnet/scripts/solana/validator-x.sh b/starship/charts/devnet/scripts/solana/validator-x.sh new file mode 100644 index 000000000..76c5d9911 --- /dev/null +++ b/starship/charts/devnet/scripts/solana/validator-x.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +here=$(dirname "$0") +# shellcheck source=multinode-demo/common.sh +source "$here"/common.sh + +# shellcheck source=net/common.sh +source "$(cd "$here"/..; pwd)"/net/common.sh + +if [[ -z $1 ]]; then + # + # Start a validator that connects to a bootstrap validator + # + $agave_validator_cuda \ + --contact-info 127.0.0.1:8001 \ + "$@" +else + $agave_validator \ + --contact-info 127.0.0.1:8001 \ + "$@" +fi \ No newline at end of file diff --git a/starship/charts/devnet/templates/chains/solana/bench.yaml b/starship/charts/devnet/templates/chains/solana/bench.yaml new file mode 100644 index 000000000..b711a3f39 --- /dev/null +++ b/starship/charts/devnet/templates/chains/solana/bench.yaml @@ -0,0 +1,30 @@ +{{- range $chain := .Values.chains }} +{{- if and (eq $chain.type "solana") $chain.bench.enabled }} +{{ $defaultFile := $.Files.Get "defaults.yaml" | fromYaml }} +{{ $chain := include "devnet.fullchain" (dict "name" $chain.id "file" $defaultFile "context" $) | fromJson }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: "{{ $chain.hostname }}-bench" +spec: + template: + spec: + containers: + - name: bench + image: {{ $chain.image }} + command: ["/bin/bash", "-c"] + args: + - /scripts/bench-tps.sh + volumeMounts: + - name: scripts + mountPath: /scripts + volumes: + - name: scripts + configMap: + name: setup-scripts-{{ $chain.hostname }} + defaultMode: 0777 + restartPolicy: Never + backoffLimit: 1 +{{- end }} +{{- end }} \ No newline at end of file diff --git a/starship/charts/devnet/templates/chains/solana/configmap.yaml b/starship/charts/devnet/templates/chains/solana/configmap.yaml new file mode 100644 index 000000000..b1d23dd00 --- /dev/null +++ b/starship/charts/devnet/templates/chains/solana/configmap.yaml @@ -0,0 +1,26 @@ +{{- range $chain := .Values.chains }} +{{- if eq $chain.type "solana" }} +{{ $defaultFile := $.Files.Get "defaults.yaml" | fromYaml }} +{{ $chain := include "devnet.fullchain" (dict "name" $chain.id "file" $defaultFile "context" $) | fromJson }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: setup-scripts-{{ $chain.hostname }} +data: + common.sh: |- + {{- $.Files.Get "scripts/solana/common.sh" | nindent 4 }} + fetch-perf-libs.sh: |- + {{- $.Files.Get "scripts/solana/fetch-perf-libs.sh" | nindent 4 }} + setup.sh: |- + {{- $.Files.Get "scripts/solana/setup.sh" | nindent 4 }} + faucet.sh: |- + {{- $.Files.Get "scripts/solana/faucet.sh" | nindent 4 }} + bootstrap-validator.sh: |- + {{- $.Files.Get "scripts/solana/bootstrap-validator.sh" | nindent 4 }} + validator-x.sh: |- + {{- $.Files.Get "scripts/solana/validator-x.sh" | nindent 4 }} + bench-tps.sh: |- + {{- $.Files.Get "scripts/solana/bench-tps.sh" | nindent 4 }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/starship/charts/devnet/templates/chains/solana/faucet.yaml b/starship/charts/devnet/templates/chains/solana/faucet.yaml new file mode 100644 index 000000000..da11a2d08 --- /dev/null +++ b/starship/charts/devnet/templates/chains/solana/faucet.yaml @@ -0,0 +1,49 @@ +{{- range $chain := .Values.chains }} +{{- if and (eq $chain.type "solana") $chain.faucet.enabled }} +{{ $defaultFile := $.Files.Get "defaults.yaml" | fromYaml }} +{{ $chain := include "devnet.fullchain" (dict "name" $chain.id "file" $defaultFile "context" $) | fromJson }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ $chain.hostname }}-faucet +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/instance: {{ $chain.name }} + app.kubernetes.io/name: {{ $chain.id }}-faucet + template: + metadata: + labels: + app.kubernetes.io/instance: {{ $chain.name }} + app.kubernetes.io/name: {{ $chain.id }}-faucet + spec: + containers: + - name: faucet + image: {{ $chain.image }} + command: ["/bin/bash", "-c"] + args: + - /scripts/faucet.sh + volumeMounts: + - name: scripts + mountPath: /scripts + volumes: + - name: scripts + configMap: + name: setup-scripts-{{ $chain.hostname }} + defaultMode: 0777 +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ $chain.hostname }}-faucet +spec: + selector: + app.kubernetes.io/name: {{ $chain.id }}-faucet + ports: + - protocol: TCP + port: 8899 + targetPort: 8899 +{{- end }} +{{- end }} \ No newline at end of file diff --git a/starship/charts/devnet/templates/chains/solana/genesis.yaml b/starship/charts/devnet/templates/chains/solana/genesis.yaml new file mode 100644 index 000000000..7f2810829 --- /dev/null +++ b/starship/charts/devnet/templates/chains/solana/genesis.yaml @@ -0,0 +1,33 @@ +{{- range $chain := .Values.chains }} +{{- if eq $chain.type "solana" }} +{{ $defaultFile := $.Files.Get "defaults.yaml" | fromYaml }} +{{ $chain := include "devnet.fullchain" (dict "name" $chain.id "file" $defaultFile "context" $) | fromJson }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: "{{ $chain.hostname }}-genesis" +spec: + template: + spec: + containers: + - name: genesis + image: {{ $chain.image }} + command: ["/bin/bash", "-c"] + args: + - | + /scripts/fetch-perf-libs.sh + /scripts/setup.sh + /scripts/bootstrap-validator.sh + volumeMounts: + - name: scripts + mountPath: /scripts + volumes: + - name: scripts + configMap: + name: setup-scripts-{{ $chain.hostname }} + defaultMode: 0777 + restartPolicy: Never + backoffLimit: 1 +{{- end }} +{{- end }} \ No newline at end of file diff --git a/starship/charts/devnet/templates/chains/solana/validator.yaml b/starship/charts/devnet/templates/chains/solana/validator.yaml new file mode 100644 index 000000000..6c2a92e1f --- /dev/null +++ b/starship/charts/devnet/templates/chains/solana/validator.yaml @@ -0,0 +1,40 @@ +{{- range $chain := .Values.chains }} +{{- if eq $chain.type "solana" }} +{{ $defaultFile := $.Files.Get "defaults.yaml" | fromYaml }} +{{ $chain := include "devnet.fullchain" (dict "name" $chain.id "file" $defaultFile "context" $) | fromJson }} +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ $chain.hostname }}-validator +spec: + serviceName: {{ $chain.hostname }}-validator + replicas: {{ sub $chain.numValidators 1 }} + selector: + matchLabels: + app.kubernetes.io/instance: {{ $chain.name }} + app.kubernetes.io/name: {{ $chain.id }}-validator + template: + metadata: + labels: + app.kubernetes.io/instance: {{ $chain.name }} + app.kubernetes.io/name: {{ $chain.id }}-validator + spec: + containers: + - name: validator + image: {{ $chain.image }} + command: ["/bin/bash", "-c"] + args: + - | + VAL_INDEX=${HOSTNAME##*-} + /scripts/validator-x.sh $VAL_INDEX + volumeMounts: + - name: scripts + mountPath: /scripts + volumes: + - name: scripts + configMap: + name: setup-scripts-{{ $chain.hostname }} + defaultMode: 0777 +{{- end }} +{{- end }} \ No newline at end of file From 4460f6b9e32adc2c4078e08574c29b33ae29417a Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Tue, 15 Jul 2025 17:22:52 +0530 Subject: [PATCH 03/31] add validator sh script --- starship/charts/devnet/defaults.yaml | 3 +++ starship/charts/devnet/scripts/solana/validator.sh | 11 +++++++++++ .../devnet/templates/chains/solana/configmap.yaml | 2 ++ 3 files changed, 16 insertions(+) create mode 100644 starship/charts/devnet/scripts/solana/validator.sh diff --git a/starship/charts/devnet/defaults.yaml b/starship/charts/devnet/defaults.yaml index 5f3a8f978..feca0462d 100644 --- a/starship/charts/devnet/defaults.yaml +++ b/starship/charts/devnet/defaults.yaml @@ -834,6 +834,9 @@ defaultChains: validator-x: name: validator-x.sh file: scripts/solana/validator-x.sh + validator: + name: validator.sh + file: scripts/solana/validator.sh bench-tps: name: bench-tps.sh file: scripts/solana/bench-tps.sh diff --git a/starship/charts/devnet/scripts/solana/validator.sh b/starship/charts/devnet/scripts/solana/validator.sh new file mode 100644 index 000000000..7eb2359e9 --- /dev/null +++ b/starship/charts/devnet/scripts/solana/validator.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +here=$(dirname "$0") +# shellcheck source=multinode-demo/common.sh +source "$here"/common.sh + +if [[ -z $1 ]]; then + $agave_validator_cuda "$@" +else + $agave_validator "$@" +fi \ No newline at end of file diff --git a/starship/charts/devnet/templates/chains/solana/configmap.yaml b/starship/charts/devnet/templates/chains/solana/configmap.yaml index b1d23dd00..fe56f2b6e 100644 --- a/starship/charts/devnet/templates/chains/solana/configmap.yaml +++ b/starship/charts/devnet/templates/chains/solana/configmap.yaml @@ -20,6 +20,8 @@ data: {{- $.Files.Get "scripts/solana/bootstrap-validator.sh" | nindent 4 }} validator-x.sh: |- {{- $.Files.Get "scripts/solana/validator-x.sh" | nindent 4 }} + validator.sh: |- + {{- $.Files.Get "scripts/solana/validator.sh" | nindent 4 }} bench-tps.sh: |- {{- $.Files.Get "scripts/solana/bench-tps.sh" | nindent 4 }} {{- end }} From d5d6a7083a6b391bd545c1e2dc5103035b23d985 Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Wed, 16 Jul 2025 19:50:45 +0530 Subject: [PATCH 04/31] add solana test, update genesis and other charts for solana, add check for solana specific checks --- starship/charts/devnet/defaults.yaml | 27 --- .../scripts/solana/bootstrap-validator.sh | 209 +++++++++++++++++- .../charts/devnet/scripts/solana/common.sh | 66 ++---- .../devnet/scripts/solana/fetch-core-bpf.sh | 33 +++ .../devnet/scripts/solana/fetch-programs.sh | 64 ++++++ .../charts/devnet/scripts/solana/fetch-spl.sh | 36 +++ .../charts/devnet/scripts/solana/setup.sh | 85 ++++--- .../templates/chains/cosmos/cometmock.yaml | 2 +- .../templates/chains/cosmos/configmap.yaml | 2 +- .../templates/chains/cosmos/genesis.yaml | 2 +- .../templates/chains/cosmos/service.yaml | 2 +- .../templates/chains/cosmos/validator.yaml | 2 +- .../devnet/templates/chains/solana/bench.yaml | 30 --- .../templates/chains/solana/configmap.yaml | 24 +- .../templates/chains/solana/faucet.yaml | 49 ---- .../templates/chains/solana/genesis.yaml | 113 ++++++++-- .../templates/chains/solana/service.yaml | 80 +++++++ .../templates/chains/solana/validator.yaml | 2 +- starship/charts/devnet/values.schema.json | 3 +- starship/tests/e2e/configs/solana.yaml | 11 + 20 files changed, 605 insertions(+), 237 deletions(-) create mode 100644 starship/charts/devnet/scripts/solana/fetch-core-bpf.sh create mode 100644 starship/charts/devnet/scripts/solana/fetch-programs.sh create mode 100644 starship/charts/devnet/scripts/solana/fetch-spl.sh delete mode 100644 starship/charts/devnet/templates/chains/solana/bench.yaml delete mode 100644 starship/charts/devnet/templates/chains/solana/faucet.yaml create mode 100644 starship/charts/devnet/templates/chains/solana/service.yaml create mode 100644 starship/tests/e2e/configs/solana.yaml diff --git a/starship/charts/devnet/defaults.yaml b/starship/charts/devnet/defaults.yaml index feca0462d..a5ce5a45d 100644 --- a/starship/charts/devnet/defaults.yaml +++ b/starship/charts/devnet/defaults.yaml @@ -815,35 +815,8 @@ defaultChains: hdPath: m/44'/501'/0'/0' coinType: 501 repo: https://github.com/solana-labs/solana - scripts: - common: - name: common.sh - file: scripts/solana/common.sh - fetch-perf-libs: - name: fetch-perf-libs.sh - file: scripts/solana/fetch-perf-libs.sh - setup: - name: setup.sh - file: scripts/solana/setup.sh - faucet: - name: faucet.sh - file: scripts/solana/faucet.sh - bootstrap-validator: - name: bootstrap-validator.sh - file: scripts/solana/bootstrap-validator.sh - validator-x: - name: validator-x.sh - file: scripts/solana/validator-x.sh - validator: - name: validator.sh - file: scripts/solana/validator.sh - bench-tps: - name: bench-tps.sh - file: scripts/solana/bench-tps.sh faucet: enabled: true - bench: - enabled: true assets: - base: lamports description: "The native token of Solana" diff --git a/starship/charts/devnet/scripts/solana/bootstrap-validator.sh b/starship/charts/devnet/scripts/solana/bootstrap-validator.sh index 7eb2359e9..1f63c5e57 100644 --- a/starship/charts/devnet/scripts/solana/bootstrap-validator.sh +++ b/starship/charts/devnet/scripts/solana/bootstrap-validator.sh @@ -1,11 +1,208 @@ #!/usr/bin/env bash +# +# Start the bootstrap validator node +# +set -e here=$(dirname "$0") -# shellcheck source=multinode-demo/common.sh -source "$here"/common.sh -if [[ -z $1 ]]; then - $agave_validator_cuda "$@" +if [[ "$SOLANA_GPU_MISSING" -eq 1 ]]; then + echo "Testnet requires GPUs, but none were found! Aborting..." + exit 1 +fi + +if [[ -n $SOLANA_CUDA ]]; then + program=$agave_validator_cuda else - $agave_validator "$@" -fi \ No newline at end of file + program=$agave_validator +fi + +no_restart=0 +maybeRequireTower=true + +args=() +while [[ -n $1 ]]; do + if [[ ${1:0:1} = - ]]; then + if [[ $1 = --init-complete-file ]]; then + args+=("$1" "$2") + shift 2 + elif [[ $1 = --bind-address ]]; then + args+=("$1" "$2") + shift 2 + elif [[ $1 = --gossip-port ]]; then + args+=("$1" "$2") + shift 2 + elif [[ $1 = --dev-halt-at-slot ]]; then + args+=("$1" "$2") + shift 2 + elif [[ $1 = --dynamic-port-range ]]; then + args+=("$1" "$2") + shift 2 + elif [[ $1 = --limit-ledger-size ]]; then + args+=("$1" "$2") + shift 2 + elif [[ $1 = --no-rocksdb-compaction ]]; then + args+=("$1") + shift + elif [[ $1 = --enable-rpc-transaction-history ]]; then + args+=("$1") + shift + elif [[ $1 = --rpc-pubsub-enable-block-subscription ]]; then + args+=("$1") + shift + elif [[ $1 = --enable-cpi-and-log-storage ]]; then + args+=("$1") + shift + elif [[ $1 = --enable-extended-tx-metadata-storage ]]; then + args+=("$1") + shift + elif [[ $1 = --enable-rpc-bigtable-ledger-storage ]]; then + args+=("$1") + shift + elif [[ $1 = --tpu-disable-quic ]]; then + args+=("$1") + shift + elif [[ $1 = --tpu-enable-udp ]]; then + args+=("$1") + shift + elif [[ $1 = --rpc-send-batch-ms ]]; then + args+=("$1" "$2") + shift 2 + elif [[ $1 = --rpc-send-batch-size ]]; then + args+=("$1" "$2") + shift 2 + elif [[ $1 = --skip-poh-verify ]]; then + args+=("$1") + shift + elif [[ $1 = --log ]]; then + args+=("$1" "$2") + shift 2 + elif [[ $1 = --no-restart ]]; then + no_restart=1 + shift + elif [[ $1 == --wait-for-supermajority ]]; then + args+=("$1" "$2") + shift 2 + elif [[ $1 == --expected-bank-hash ]]; then + args+=("$1" "$2") + shift 2 + elif [[ $1 == --expected-shred-version ]]; then + args+=("$1" "$2") + shift 2 + elif [[ $1 == --accounts ]]; then + args+=("$1" "$2") + shift 2 + elif [[ $1 == --maximum-snapshots-to-retain ]]; then + args+=("$1" "$2") + shift 2 + elif [[ $1 == --no-snapshot-fetch ]]; then + args+=("$1") + shift + elif [[ $1 == --accounts-db-skip-shrink ]]; then + args+=("$1") + shift + elif [[ $1 == --skip-require-tower ]]; then + maybeRequireTower=false + shift + elif [[ $1 = --log-messages-bytes-limit ]]; then + args+=("$1" "$2") + shift 2 + elif [[ $1 == --block-production-method ]]; then + args+=("$1" "$2") + shift 2 + elif [[ $1 == --transaction-structure ]]; then + args+=("$1" "$2") + shift 2 + elif [[ $1 == --wen-restart ]]; then + args+=("$1" "$2") + shift 2 + elif [[ $1 == --wen-restart-coordinator ]]; then + args+=("$1" "$2") + shift 2 + else + echo "Unknown argument: $1" + $program --help + exit 1 + fi + else + echo "Unknown argument: $1" + $program --help + exit 1 + fi +done + +# These keypairs are created by ./setup.sh and included in the genesis config +identity=$SOLANA_CONFIG_DIR/bootstrap-validator/identity.json +vote_account="$SOLANA_CONFIG_DIR"/bootstrap-validator/vote-account.json + +ledger_dir="$SOLANA_CONFIG_DIR"/bootstrap-validator +[[ -d "$ledger_dir" ]] || { + echo "$ledger_dir does not exist" + echo + echo "Please run: $here/setup.sh" + exit 1 +} + +if [[ $maybeRequireTower = true ]]; then + args+=(--require-tower) +fi + +args+=( + --ledger "$ledger_dir" + --rpc-port 8899 + --snapshot-interval-slots 200 + --no-incremental-snapshots + --identity "$identity" + --vote-account "$vote_account" + --rpc-faucet-address 127.0.0.1:9900 + --no-poh-speed-test + --no-os-network-limits-test + --no-wait-for-vote-to-start-leader + --full-rpc-api + --allow-private-addr +) +default_arg --gossip-port 8001 +default_arg --log - + + +pid= +kill_node() { + # Note: do not echo anything from this function to ensure $pid is actually + # killed when stdout/stderr are redirected + set +ex + if [[ -n $pid ]]; then + declare _pid=$pid + pid= + kill "$_pid" || true + wait "$_pid" || true + fi +} + +kill_node_and_exit() { + kill_node + exit +} + +trap 'kill_node_and_exit' INT TERM ERR + +while true; do + echo "$program ${args[*]}" + $program "${args[@]}" & + pid=$! + echo "pid: $pid" + + if ((no_restart)); then + wait "$pid" + exit $? + fi + + while true; do + if [[ -z $pid ]] || ! kill -0 "$pid"; then + echo "############## validator exited, restarting ##############" + break + fi + sleep 1 + done + + kill_node +done \ No newline at end of file diff --git a/starship/charts/devnet/scripts/solana/common.sh b/starship/charts/devnet/scripts/solana/common.sh index 8ef3298d7..91977504e 100644 --- a/starship/charts/devnet/scripts/solana/common.sh +++ b/starship/charts/devnet/scripts/solana/common.sh @@ -1,13 +1,11 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Locate this script’s directory -HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - +# |source| this file +# +# Common utilities shared by other scripts in this directory +# +# The following directive disable complaints about unused variables in this +# file: # shellcheck disable=2034 # -# shellcheck source=net/common.sh -source "$(cd "$(dirname "${BASH_SOURCE[0]}")"/.. || exit 1; pwd)"/net/common.sh prebuild= if [[ $1 = "--prebuild" ]]; then @@ -23,48 +21,18 @@ if [[ $(uname) != Linux ]]; then fi fi -if [[ -n $USE_INSTALL || ! -f "$SOLANA_ROOT"/Cargo.toml ]]; then - solana_program() { - declare program="$1" - if [[ -z $program ]]; then - printf "solana" - else - if [[ $program == "validator" || $program == "ledger-tool" || $program == "watchtower" || $program == "install" ]]; then - printf "agave-%s" "$program" - else - printf "solana-%s" "$program" - fi - fi - } -else - solana_program() { - declare program="$1" - declare crate="$program" - - if [[ -z $program ]]; then - crate="cli" - program="solana" - elif [[ $program == "validator" || $program == "ledger-tool" || $program == "watchtower" || $program == "install" ]]; then - program="agave-$program" +solana_program() { + declare program="$1" + if [[ -z $program ]]; then + printf "solana" + else + if [[ $program == "validator" || $program == "ledger-tool" || $program == "watchtower" || $program == "install" ]]; then + printf "agave-%s" "$program" else - program="solana-$program" + printf "solana-%s" "$program" fi - - if [[ -n $CARGO_BUILD_PROFILE ]]; then - profile_arg="--profile $CARGO_BUILD_PROFILE" - fi - - # Prebuild binaries so that CI sanity check timeout doesn't include build time - if [[ $prebuild ]]; then - ( - set -x - # shellcheck disable=SC2086 # Don't want to double quote cargo - $CARGO_TOOLCHAIN build $profile_arg --bin $program - ) - fi - printf "cargo $CARGO_TOOLCHAIN run $profile_arg --bin %s %s -- " "$program" - } -fi + fi +} solana_bench_tps=$(solana_program bench-tps) solana_faucet=$(solana_program faucet) @@ -108,4 +76,4 @@ replace_arg() { args[$index]="$value" fi done -} \ No newline at end of file +} diff --git a/starship/charts/devnet/scripts/solana/fetch-core-bpf.sh b/starship/charts/devnet/scripts/solana/fetch-core-bpf.sh new file mode 100644 index 000000000..0ac70f366 --- /dev/null +++ b/starship/charts/devnet/scripts/solana/fetch-core-bpf.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# +# Fetches the latest Core BPF programs and produces the solana-genesis +# command-line arguments needed to install them +# + +set -e + +here=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) + +source "$here"/fetch-programs.sh + +PREFIX="core-bpf" + +programs=() + +add_core_bpf_program_to_fetch() { + declare name=$1 + declare version=$2 + declare address=$3 + declare loader=$4 + + so_name="solana_${name//-/_}_program.so" + declare download_url="https://github.com/solana-program/$name/releases/download/program%40$version/$so_name" + + programs+=("$name $version $address $loader $download_url") +} + +add_core_bpf_program_to_fetch address-lookup-table 3.0.0 AddressLookupTab1e1111111111111111111111111 BPFLoaderUpgradeab1e11111111111111111111111 +add_core_bpf_program_to_fetch config 3.0.0 Config1111111111111111111111111111111111111 BPFLoaderUpgradeab1e11111111111111111111111 +add_core_bpf_program_to_fetch feature-gate 0.0.1 Feature111111111111111111111111111111111111 BPFLoaderUpgradeab1e11111111111111111111111 + +fetch_programs "$PREFIX" "${programs[@]}" diff --git a/starship/charts/devnet/scripts/solana/fetch-programs.sh b/starship/charts/devnet/scripts/solana/fetch-programs.sh new file mode 100644 index 000000000..d0df34a44 --- /dev/null +++ b/starship/charts/devnet/scripts/solana/fetch-programs.sh @@ -0,0 +1,64 @@ +# Source this file. +# +# Fetches on-chain programs and produces the solana-genesis command-line +# arguments needed to install them +# + +upgradeableLoader=BPFLoaderUpgradeab1e11111111111111111111111 + +fetch_program() { + declare prefix=$1 + declare name=$2 + declare version=$3 + declare address=$4 + declare loader=$5 + declare download_url=$6 + + declare so=$prefix-$name-$version.so + + if [[ $loader == "$upgradeableLoader" ]]; then + genesis_args+=(--upgradeable-program "$address" "$loader" "$so" none) + else + genesis_args+=(--bpf-program "$address" "$loader" "$so") + fi + + if [[ -r $so ]]; then + return + fi + + if [[ -r ~/.cache/solana-$prefix/$so ]]; then + cp ~/.cache/solana-"$prefix"/"$so" "$so" + else + echo "Downloading $name $version" + ( + set -x + curl -L --retry 5 --retry-delay 2 --retry-connrefused -o "$so" "$download_url" + ) + + mkdir -p ~/.cache/solana-"$prefix" + cp "$so" ~/.cache/solana-"$prefix"/"$so" + fi + +} + +fetch_programs() { + declare prefix=$1 + shift + + declare -a programs=("$@") + + for program in "${programs[@]}"; do + # shellcheck disable=SC2086 + fetch_program "$prefix" $program + done + + echo "${genesis_args[@]}" > "$prefix"-genesis-args.sh + + echo + echo "Available $prefix programs:" + ls -l "$prefix"-*.so + + echo + echo "solana-genesis command-line arguments ($prefix-genesis-args.sh):" + cat "$prefix"-genesis-args.sh +} diff --git a/starship/charts/devnet/scripts/solana/fetch-spl.sh b/starship/charts/devnet/scripts/solana/fetch-spl.sh new file mode 100644 index 000000000..a8f5b53a6 --- /dev/null +++ b/starship/charts/devnet/scripts/solana/fetch-spl.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +# +# Fetches the latest SPL programs and produces the solana-genesis command-line +# arguments needed to install them +# + +set -e + +here=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) + +source "$here"/fetch-programs.sh + +PREFIX="spl" + +programs=() + +add_spl_program_to_fetch() { + declare name=$1 + declare version=$2 + declare address=$3 + declare loader=$4 + + so_name="${PREFIX}_${name//-/_}.so" + download_url="https://github.com/solana-program/$name/releases/download/program@v$version/$so_name" + + programs+=("$name $version $address $loader $download_url") +} + +add_spl_program_to_fetch token 3.5.0 TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA BPFLoader2111111111111111111111111111111111 +add_spl_program_to_fetch token-2022 8.0.0 TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb BPFLoaderUpgradeab1e11111111111111111111111 +add_spl_program_to_fetch memo 1.0.0 Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo BPFLoader1111111111111111111111111111111111 +add_spl_program_to_fetch memo 3.0.0 MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr BPFLoader2111111111111111111111111111111111 +add_spl_program_to_fetch associated-token-account 1.1.2 ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL BPFLoader2111111111111111111111111111111111 +add_spl_program_to_fetch feature-proposal 1.0.0 Feat1YXHhH6t1juaWF74WLcfv4XoNocjXA6sPWHNgAse BPFLoader2111111111111111111111111111111111 + +fetch_programs "$PREFIX" "${programs[@]}" diff --git a/starship/charts/devnet/scripts/solana/setup.sh b/starship/charts/devnet/scripts/solana/setup.sh index cdf672c10..b75efd854 100644 --- a/starship/charts/devnet/scripts/solana/setup.sh +++ b/starship/charts/devnet/scripts/solana/setup.sh @@ -1,41 +1,66 @@ #!/usr/bin/env bash -# -# Creates a full-featured setup for a multinode Solana testnet -# here=$(dirname "$0") # shellcheck source=multinode-demo/common.sh source "$here"/common.sh -# Create a keypair for the faucet -# -# The faucet is a Solana account that is funded with a large amount of SOL at -# genesis. It is then used to fund other accounts on the testnet. -# -# The faucet keypair is created in the config directory so that it can be easily -# accessed by the faucet service. -# -if [[ ! -f "$SOLANA_CONFIG_DIR"/faucet.json ]]; then - "$solana_keygen" new --no-passphrase -o "$SOLANA_CONFIG_DIR"/faucet.json +set -e + +rm -rf "$SOLANA_CONFIG_DIR"/bootstrap-validator +mkdir -p "$SOLANA_CONFIG_DIR"/bootstrap-validator + +# Create genesis ledger +if [[ -r $FAUCET_KEYPAIR ]]; then + cp -f "$FAUCET_KEYPAIR" "$SOLANA_CONFIG_DIR"/faucet.json +else + $solana_keygen new --no-passphrase -fso "$SOLANA_CONFIG_DIR"/faucet.json +fi + +if [[ -f $BOOTSTRAP_VALIDATOR_IDENTITY_KEYPAIR ]]; then + cp -f "$BOOTSTRAP_VALIDATOR_IDENTITY_KEYPAIR" "$SOLANA_CONFIG_DIR"/bootstrap-validator/identity.json +else + $solana_keygen new --no-passphrase -so "$SOLANA_CONFIG_DIR"/bootstrap-validator/identity.json +fi +if [[ -f $BOOTSTRAP_VALIDATOR_STAKE_KEYPAIR ]]; then + cp -f "$BOOTSTRAP_VALIDATOR_STAKE_KEYPAIR" "$SOLANA_CONFIG_DIR"/bootstrap-validator/stake-account.json +else + $solana_keygen new --no-passphrase -so "$SOLANA_CONFIG_DIR"/bootstrap-validator/stake-account.json +fi +if [[ -f $BOOTSTRAP_VALIDATOR_VOTE_KEYPAIR ]]; then + cp -f "$BOOTSTRAP_VALIDATOR_VOTE_KEYPAIR" "$SOLANA_CONFIG_DIR"/bootstrap-validator/vote-account.json +else + $solana_keygen new --no-passphrase -so "$SOLANA_CONFIG_DIR"/bootstrap-validator/vote-account.json fi -# Create the genesis ledger -# -# The genesis ledger is the first block in the blockchain. It contains a number -# of configuration settings, as well as the initial set of accounts and their -# balances. -# -# The genesis ledger is created using the solana-genesis command. The command -# takes a number of arguments, including the location of the faucet keypair, -# the initial amount of SOL to fund the faucet with, and the location of the -# ledger directory. -# args=( - --faucet-pubkey "$SOLANA_CONFIG_DIR"/faucet.json - --faucet-lamports 500000000000000000 - --ledger "$SOLANA_CONFIG_DIR"/ledger - --bootstrap-validator-lamports 500000000000000000 - --bootstrap-validator-stake-lamports 100000000000000000 + "$@" + --max-genesis-archive-unpacked-size 1073741824 + --enable-warmup-epochs + --bootstrap-validator "$SOLANA_CONFIG_DIR"/bootstrap-validator/identity.json + "$SOLANA_CONFIG_DIR"/bootstrap-validator/vote-account.json + "$SOLANA_CONFIG_DIR"/bootstrap-validator/stake-account.json ) -"$solana_genesis" "${args[@]}" \ No newline at end of file +"$here"/fetch-core-bpf.sh +if [[ -r core-bpf-genesis-args.sh ]]; then + CORE_BPF_GENESIS_ARGS=$(cat core-bpf-genesis-args.sh) + #shellcheck disable=SC2207 + #shellcheck disable=SC2206 + args+=($CORE_BPF_GENESIS_ARGS) +fi + +"$here"/fetch-spl.sh +if [[ -r spl-genesis-args.sh ]]; then + SPL_GENESIS_ARGS=$(cat spl-genesis-args.sh) + #shellcheck disable=SC2207 + #shellcheck disable=SC2206 + args+=($SPL_GENESIS_ARGS) +fi + +default_arg --ledger "$SOLANA_CONFIG_DIR"/bootstrap-validator +default_arg --faucet-pubkey "$SOLANA_CONFIG_DIR"/faucet.json +default_arg --faucet-lamports 500000000000000000 +default_arg --hashes-per-tick auto +default_arg --cluster-type development + +$solana_genesis "${args[@]}" diff --git a/starship/charts/devnet/templates/chains/cosmos/cometmock.yaml b/starship/charts/devnet/templates/chains/cosmos/cometmock.yaml index 5f98b128e..c862e76f2 100644 --- a/starship/charts/devnet/templates/chains/cosmos/cometmock.yaml +++ b/starship/charts/devnet/templates/chains/cosmos/cometmock.yaml @@ -1,5 +1,5 @@ {{- range $chain := .Values.chains }} -{{- if not (hasPrefix "ethereum" $chain.name) }} +{{- if not (or (hasPrefix "ethereum" $chain.name) (hasPrefix "solana" $chain.name)) }} {{ $dataExposer := dict "chain" $chain.id "port" ($.Values.exposer.ports.rest | quote | default "8081") }} {{ $defaultFile := $.Files.Get "defaults.yaml" | fromYaml }} diff --git a/starship/charts/devnet/templates/chains/cosmos/configmap.yaml b/starship/charts/devnet/templates/chains/cosmos/configmap.yaml index ac7df34ef..18890ad9b 100644 --- a/starship/charts/devnet/templates/chains/cosmos/configmap.yaml +++ b/starship/charts/devnet/templates/chains/cosmos/configmap.yaml @@ -1,5 +1,5 @@ {{- range $chain := .Values.chains }} -{{- if not (hasPrefix "ethereum" $chain.name) }} +{{- if not (or (hasPrefix "ethereum" $chain.name) (hasPrefix "solana" $chain.name)) }} {{ $defaultFile := $.Files.Get "defaults.yaml" | fromYaml }} {{ $chain := include "devnet.fullchain" (dict "name" $chain.id "file" $defaultFile "context" $) | fromJson }} --- diff --git a/starship/charts/devnet/templates/chains/cosmos/genesis.yaml b/starship/charts/devnet/templates/chains/cosmos/genesis.yaml index 79837e62f..4bdc1138c 100644 --- a/starship/charts/devnet/templates/chains/cosmos/genesis.yaml +++ b/starship/charts/devnet/templates/chains/cosmos/genesis.yaml @@ -1,5 +1,5 @@ {{- range $chain := .Values.chains }} -{{- if not (hasPrefix "ethereum" $chain.name) }} +{{- if not (or (hasPrefix "ethereum" $chain.name) (hasPrefix "solana" $chain.name)) }} {{ $dataExposer := dict "chain" $chain.id "port" ($.Values.exposer.ports.rest | quote | default "8081") }} {{ $defaultFile := $.Files.Get "defaults.yaml" | fromYaml }} diff --git a/starship/charts/devnet/templates/chains/cosmos/service.yaml b/starship/charts/devnet/templates/chains/cosmos/service.yaml index 75234cae5..3e0f76114 100644 --- a/starship/charts/devnet/templates/chains/cosmos/service.yaml +++ b/starship/charts/devnet/templates/chains/cosmos/service.yaml @@ -1,6 +1,6 @@ {{ $portMap := dict "p2p" 26656 "address" 26658 "grpc" 9090 "grpc-web" 9091 "rest" 1317 }} {{- range $chain := .Values.chains }} -{{- if not (hasPrefix "ethereum" $chain.name) }} +{{- if not (or (hasPrefix "ethereum" $chain.name) (hasPrefix "solana" $chain.name)) }} {{ $defaultFile := $.Files.Get "defaults.yaml" | fromYaml }} {{ $chain := include "devnet.fullchain" (dict "name" $chain.id "file" $defaultFile "context" $) | fromJson }} diff --git a/starship/charts/devnet/templates/chains/cosmos/validator.yaml b/starship/charts/devnet/templates/chains/cosmos/validator.yaml index d72a05fc8..d1a2d9c73 100644 --- a/starship/charts/devnet/templates/chains/cosmos/validator.yaml +++ b/starship/charts/devnet/templates/chains/cosmos/validator.yaml @@ -1,5 +1,5 @@ {{- range $chain := .Values.chains }} -{{- if not (hasPrefix "ethereum" $chain.name) }} +{{- if not (or (hasPrefix "ethereum" $chain.name) (hasPrefix "solana" $chain.name)) }} {{- if gt $chain.numValidators 1.0 }} {{ $dataExposer := dict "chain" $chain.id "port" ($.Values.exposer.ports.rest | quote | default "8081") }} {{ $defaultFile := $.Files.Get "defaults.yaml" | fromYaml }} diff --git a/starship/charts/devnet/templates/chains/solana/bench.yaml b/starship/charts/devnet/templates/chains/solana/bench.yaml deleted file mode 100644 index b711a3f39..000000000 --- a/starship/charts/devnet/templates/chains/solana/bench.yaml +++ /dev/null @@ -1,30 +0,0 @@ -{{- range $chain := .Values.chains }} -{{- if and (eq $chain.type "solana") $chain.bench.enabled }} -{{ $defaultFile := $.Files.Get "defaults.yaml" | fromYaml }} -{{ $chain := include "devnet.fullchain" (dict "name" $chain.id "file" $defaultFile "context" $) | fromJson }} ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: "{{ $chain.hostname }}-bench" -spec: - template: - spec: - containers: - - name: bench - image: {{ $chain.image }} - command: ["/bin/bash", "-c"] - args: - - /scripts/bench-tps.sh - volumeMounts: - - name: scripts - mountPath: /scripts - volumes: - - name: scripts - configMap: - name: setup-scripts-{{ $chain.hostname }} - defaultMode: 0777 - restartPolicy: Never - backoffLimit: 1 -{{- end }} -{{- end }} \ No newline at end of file diff --git a/starship/charts/devnet/templates/chains/solana/configmap.yaml b/starship/charts/devnet/templates/chains/solana/configmap.yaml index fe56f2b6e..89779004a 100644 --- a/starship/charts/devnet/templates/chains/solana/configmap.yaml +++ b/starship/charts/devnet/templates/chains/solana/configmap.yaml @@ -1,5 +1,5 @@ {{- range $chain := .Values.chains }} -{{- if eq $chain.type "solana" }} +{{- if eq $chain.name "solana" }} {{ $defaultFile := $.Files.Get "defaults.yaml" | fromYaml }} {{ $chain := include "devnet.fullchain" (dict "name" $chain.id "file" $defaultFile "context" $) | fromJson }} --- @@ -8,21 +8,9 @@ kind: ConfigMap metadata: name: setup-scripts-{{ $chain.hostname }} data: - common.sh: |- - {{- $.Files.Get "scripts/solana/common.sh" | nindent 4 }} - fetch-perf-libs.sh: |- - {{- $.Files.Get "scripts/solana/fetch-perf-libs.sh" | nindent 4 }} - setup.sh: |- - {{- $.Files.Get "scripts/solana/setup.sh" | nindent 4 }} - faucet.sh: |- - {{- $.Files.Get "scripts/solana/faucet.sh" | nindent 4 }} - bootstrap-validator.sh: |- - {{- $.Files.Get "scripts/solana/bootstrap-validator.sh" | nindent 4 }} - validator-x.sh: |- - {{- $.Files.Get "scripts/solana/validator-x.sh" | nindent 4 }} - validator.sh: |- - {{- $.Files.Get "scripts/solana/validator.sh" | nindent 4 }} - bench-tps.sh: |- - {{- $.Files.Get "scripts/solana/bench-tps.sh" | nindent 4 }} + {{- range $path, $_ := $.Files.Glob "scripts/solana/*" }} + {{ base $path }}: |- + {{- $.Files.Get $path | nindent 4 }} + {{- end }} {{- end }} -{{- end }} \ No newline at end of file +{{- end }} diff --git a/starship/charts/devnet/templates/chains/solana/faucet.yaml b/starship/charts/devnet/templates/chains/solana/faucet.yaml deleted file mode 100644 index da11a2d08..000000000 --- a/starship/charts/devnet/templates/chains/solana/faucet.yaml +++ /dev/null @@ -1,49 +0,0 @@ -{{- range $chain := .Values.chains }} -{{- if and (eq $chain.type "solana") $chain.faucet.enabled }} -{{ $defaultFile := $.Files.Get "defaults.yaml" | fromYaml }} -{{ $chain := include "devnet.fullchain" (dict "name" $chain.id "file" $defaultFile "context" $) | fromJson }} ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ $chain.hostname }}-faucet -spec: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/instance: {{ $chain.name }} - app.kubernetes.io/name: {{ $chain.id }}-faucet - template: - metadata: - labels: - app.kubernetes.io/instance: {{ $chain.name }} - app.kubernetes.io/name: {{ $chain.id }}-faucet - spec: - containers: - - name: faucet - image: {{ $chain.image }} - command: ["/bin/bash", "-c"] - args: - - /scripts/faucet.sh - volumeMounts: - - name: scripts - mountPath: /scripts - volumes: - - name: scripts - configMap: - name: setup-scripts-{{ $chain.hostname }} - defaultMode: 0777 ---- -apiVersion: v1 -kind: Service -metadata: - name: {{ $chain.hostname }}-faucet -spec: - selector: - app.kubernetes.io/name: {{ $chain.id }}-faucet - ports: - - protocol: TCP - port: 8899 - targetPort: 8899 -{{- end }} -{{- end }} \ No newline at end of file diff --git a/starship/charts/devnet/templates/chains/solana/genesis.yaml b/starship/charts/devnet/templates/chains/solana/genesis.yaml index 7f2810829..55530081e 100644 --- a/starship/charts/devnet/templates/chains/solana/genesis.yaml +++ b/starship/charts/devnet/templates/chains/solana/genesis.yaml @@ -1,33 +1,104 @@ {{- range $chain := .Values.chains }} -{{- if eq $chain.type "solana" }} +{{- if eq $chain.name "solana" }} {{ $defaultFile := $.Files.Get "defaults.yaml" | fromYaml }} {{ $chain := include "devnet.fullchain" (dict "name" $chain.id "file" $defaultFile "context" $) | fromJson }} --- -apiVersion: batch/v1 -kind: Job +apiVersion: apps/v1 +kind: StatefulSet metadata: - name: "{{ $chain.hostname }}-genesis" + name: {{ $chain.hostname }}-genesis spec: + serviceName: {{ $chain.hostname }}-genesis + replicas: 1 + revisionHistoryLimit: 3 + selector: + matchLabels: + app.kubernetes.io/instance: {{ $chain.name }} + app.kubernetes.io/name: {{ $chain.id }}-genesis template: + metadata: + annotations: + quality: release + role: api-gateway + sla: high + tier: gateway + labels: + app.kubernetes.io/instance: {{ $chain.name }} + app.kubernetes.io/type: {{ $chain.id }} + app.kubernetes.io/name: {{ $chain.id }}-genesis + app.kubernetes.io/rawname: {{ $chain.id }} + app.kubernetes.io/version: {{ $.Chart.AppVersion }} spec: + {{- include "imagePullSecrets" $chain | indent 6 }} + initContainers: + - name: init-genesis + image: {{ $chain.image }} + imagePullPolicy: {{ $.Values.images.imagePullPolicy }} + env: + {{- include "devnet.defaultEvnVars" $chain | indent 12 }} + {{- include "devnet.evnVars" $chain | indent 12 }} + - name: KEYS_CONFIG + value: /configs/keys.json + - name: FAUCET_ENABLED + value: "{{ $chain.faucet.enabled }}" + - name: NUM_VALIDATORS + value: "{{ $chain.numValidators }}" + - name: SOLANA_CONFIG_DIR + value: {{ $chain.home }} + command: + - bash + - "-c" + - | + VAL_INDEX=${HOSTNAME##*-} + echo "Validator Index: $VAL_INDEX" + + echo "Move scripts to config dir" + mkdir -p {{ $chain.home }}/scripts/ + cp -L /scripts/* {{ $chain.home }}/scripts/ + chmod +x {{ $chain.home }}/scripts/* + + echo "Running setup genesis script..." + bash -e {{ $chain.home }}/scripts/setup.sh + resources: {{- include "devnet.node.resources" ( dict "node" $chain "context" $ ) | trim | nindent 12 }} + volumeMounts: + - mountPath: {{ $chain.home }} + name: node + - mountPath: /scripts + name: scripts containers: - - name: genesis - image: {{ $chain.image }} - command: ["/bin/bash", "-c"] - args: - - | - /scripts/fetch-perf-libs.sh - /scripts/setup.sh - /scripts/bootstrap-validator.sh - volumeMounts: - - name: scripts - mountPath: /scripts + - name: validator + image: {{ $chain.image }} + imagePullPolicy: {{ $.Values.images.imagePullPolicy }} + env: + {{- include "devnet.defaultEvnVars" $chain | indent 12 }} + {{- include "devnet.evnVars" $chain | indent 12 }} + - name: FAUCET_ENABLED + value: "{{ $chain.faucet.enabled }}" + - name: SOLANA_CONFIG_DIR + value: {{ $chain.home }} + {{- range $env := $chain.env }} + - name: {{ $env.name }} + value: {{ $env.value | quote }} + {{- end }} + command: + - bash + - "-c" + - | + sleep 1000000000000000000000 + + bash -e {{ $chain.home }}/scripts/bootstrap-validator.sh + resources: {{- include "devnet.node.resources" ( dict "node" $chain "context" $ ) | trim | nindent 12 }} + volumeMounts: + - mountPath: {{ $chain.home }} + name: node + - mountPath: /scripts + name: scripts volumes: - - name: scripts - configMap: - name: setup-scripts-{{ $chain.hostname }} - defaultMode: 0777 - restartPolicy: Never - backoffLimit: 1 + - name: node + emptyDir: { } + - name: scripts + configMap: + name: setup-scripts-{{- include "devnet.chain.name" $chain.id }} +--- {{- end }} {{- end }} \ No newline at end of file diff --git a/starship/charts/devnet/templates/chains/solana/service.yaml b/starship/charts/devnet/templates/chains/solana/service.yaml new file mode 100644 index 000000000..e40dd67b9 --- /dev/null +++ b/starship/charts/devnet/templates/chains/solana/service.yaml @@ -0,0 +1,80 @@ +{{ $portMap := dict "p2p" 26656 "address" 26658 "grpc" 9090 "grpc-web" 9091 "rest" 1317 }} +{{- range $chain := .Values.chains }} +{{- if (eq $chain.name "solana") }} +{{ $defaultFile := $.Files.Get "defaults.yaml" | fromYaml }} + +{{ $chain := include "devnet.fullchain" (dict "name" $chain.id "file" $defaultFile "context" $) | fromJson }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ $chain.hostname }}-genesis + labels: + app.kubernetes.io/name: {{ $chain.id }}-genesis +spec: + clusterIP: None + ports: + {{- range $name, $port := $portMap }} + - name: {{ $name }} + port: {{ $port }} + protocol: TCP + targetPort: {{ $port }} + {{- end }} + - name: rpc + port: 26657 + protocol: TCP + targetPort: 26657 + {{- if $chain.metrics }} + - name: metrics + port: 26660 + protocol: TCP + targetPort: 26660 + {{- end }} + - name: exposer + port: {{ $.Values.exposer.ports.rest | default 8081 }} + protocol: TCP + targetPort: {{ $.Values.exposer.ports.rest | default 8081 }} + - name: faucet + port: 8000 + protocol: TCP + targetPort: 8000 + selector: + app.kubernetes.io/name: {{ $chain.id }}-genesis +--- +{{- if gt $chain.numValidators 1.0}} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "devnet.chain.name" $chain.id }}-validator + labels: + app.kubernetes.io/name: {{ $chain.id }}-validator +spec: + clusterIP: None + ports: + {{- range $name, $port := $portMap }} + - name: {{ $name }} + port: {{ $port }} + protocol: TCP + targetPort: {{ $port }} + {{- end }} + - name: rpc + port: 26657 + protocol: TCP + targetPort: 26657 + {{- if $chain.metrics }} + - name: metrics + port: 26660 + protocol: TCP + targetPort: 26660 + {{- end }} + - name: exposer + port: {{ $.Values.exposer.ports.rest | default 8081 }} + protocol: TCP + targetPort: {{ $.Values.exposer.ports.rest | default 8081 }} + selector: + app.kubernetes.io/name: {{ $chain.id }}-validator +--- +{{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/starship/charts/devnet/templates/chains/solana/validator.yaml b/starship/charts/devnet/templates/chains/solana/validator.yaml index 6c2a92e1f..c7e48bc7f 100644 --- a/starship/charts/devnet/templates/chains/solana/validator.yaml +++ b/starship/charts/devnet/templates/chains/solana/validator.yaml @@ -1,5 +1,5 @@ {{- range $chain := .Values.chains }} -{{- if eq $chain.type "solana" }} +{{- if eq $chain.name "solana" }} {{ $defaultFile := $.Files.Get "defaults.yaml" | fromYaml }} {{ $chain := include "devnet.fullchain" (dict "name" $chain.id "file" $defaultFile "context" $) | fromJson }} --- diff --git a/starship/charts/devnet/values.schema.json b/starship/charts/devnet/values.schema.json index b852d1090..c310a642f 100644 --- a/starship/charts/devnet/values.schema.json +++ b/starship/charts/devnet/values.schema.json @@ -148,7 +148,8 @@ "hyperweb", "noble", "xpla", - "ethereum" + "ethereum", + "solana" ] }, "numValidators": { diff --git a/starship/tests/e2e/configs/solana.yaml b/starship/tests/e2e/configs/solana.yaml new file mode 100644 index 000000000..fdf1aafbb --- /dev/null +++ b/starship/tests/e2e/configs/solana.yaml @@ -0,0 +1,11 @@ +name: starship-e2e-tests +version: 1.7.0 + +chains: +- id: solana + name: solana + numValidators: 1 + ports: + rest: 1317 + rpc: 26657 + grpc: 9091 From a391a7987a41d116bb38d6225b63b6436929935e Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Wed, 16 Jul 2025 20:00:58 +0530 Subject: [PATCH 05/31] get initial version of solana running --- starship/charts/devnet/scripts/solana/bootstrap-validator.sh | 1 + starship/charts/devnet/scripts/solana/common.sh | 2 +- starship/charts/devnet/scripts/solana/setup.sh | 1 - starship/charts/devnet/templates/chains/solana/genesis.yaml | 3 +-- starship/tests/e2e/configs/solana.yaml | 3 +++ 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/starship/charts/devnet/scripts/solana/bootstrap-validator.sh b/starship/charts/devnet/scripts/solana/bootstrap-validator.sh index 1f63c5e57..7e6edcc44 100644 --- a/starship/charts/devnet/scripts/solana/bootstrap-validator.sh +++ b/starship/charts/devnet/scripts/solana/bootstrap-validator.sh @@ -5,6 +5,7 @@ set -e here=$(dirname "$0") +source "$here"/common.sh if [[ "$SOLANA_GPU_MISSING" -eq 1 ]]; then echo "Testnet requires GPUs, but none were found! Aborting..." diff --git a/starship/charts/devnet/scripts/solana/common.sh b/starship/charts/devnet/scripts/solana/common.sh index 91977504e..01a692dcf 100644 --- a/starship/charts/devnet/scripts/solana/common.sh +++ b/starship/charts/devnet/scripts/solana/common.sh @@ -27,7 +27,7 @@ solana_program() { printf "solana" else if [[ $program == "validator" || $program == "ledger-tool" || $program == "watchtower" || $program == "install" ]]; then - printf "agave-%s" "$program" + printf "solana-%s" "$program" else printf "solana-%s" "$program" fi diff --git a/starship/charts/devnet/scripts/solana/setup.sh b/starship/charts/devnet/scripts/solana/setup.sh index b75efd854..c500590b6 100644 --- a/starship/charts/devnet/scripts/solana/setup.sh +++ b/starship/charts/devnet/scripts/solana/setup.sh @@ -1,7 +1,6 @@ #!/usr/bin/env bash here=$(dirname "$0") -# shellcheck source=multinode-demo/common.sh source "$here"/common.sh set -e diff --git a/starship/charts/devnet/templates/chains/solana/genesis.yaml b/starship/charts/devnet/templates/chains/solana/genesis.yaml index 55530081e..af7b9c68b 100644 --- a/starship/charts/devnet/templates/chains/solana/genesis.yaml +++ b/starship/charts/devnet/templates/chains/solana/genesis.yaml @@ -84,8 +84,7 @@ spec: - bash - "-c" - | - sleep 1000000000000000000000 - + echo "Running bootstrap validator script..." bash -e {{ $chain.home }}/scripts/bootstrap-validator.sh resources: {{- include "devnet.node.resources" ( dict "node" $chain "context" $ ) | trim | nindent 12 }} volumeMounts: diff --git a/starship/tests/e2e/configs/solana.yaml b/starship/tests/e2e/configs/solana.yaml index fdf1aafbb..a5dba4396 100644 --- a/starship/tests/e2e/configs/solana.yaml +++ b/starship/tests/e2e/configs/solana.yaml @@ -9,3 +9,6 @@ chains: rest: 1317 rpc: 26657 grpc: 9091 + resources: + cpu: 2000m + memory: 2048Mi From a08dc48f9dddaa8a2f561cd09706caeaf6ace86d Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Fri, 18 Jul 2025 20:15:23 +0530 Subject: [PATCH 06/31] update services and faucet, ws and p2p ports --- .../devnet/scripts/solana/delegate-stake.sh | 127 ++++++ .../charts/devnet/scripts/solana/faucet.sh | 16 +- .../devnet/scripts/solana/validator-x.sh | 22 +- .../charts/devnet/scripts/solana/validator.sh | 372 +++++++++++++++++- .../templates/chains/solana/service.yaml | 33 +- starship/tests/e2e/configs/solana.yaml | 6 +- 6 files changed, 529 insertions(+), 47 deletions(-) create mode 100644 starship/charts/devnet/scripts/solana/delegate-stake.sh diff --git a/starship/charts/devnet/scripts/solana/delegate-stake.sh b/starship/charts/devnet/scripts/solana/delegate-stake.sh new file mode 100644 index 000000000..62bcb2e50 --- /dev/null +++ b/starship/charts/devnet/scripts/solana/delegate-stake.sh @@ -0,0 +1,127 @@ +#!/usr/bin/env bash +# +# Delegate stake to a validator +# +set -e + +here=$(dirname "$0") +# shellcheck source=multinode-demo/common.sh +source "$here"/common.sh + +stake_sol=10 # default number of SOL to assign as stake (10 SOL) +url=http://127.0.0.1:8899 # default RPC url + +usage() { + if [[ -n $1 ]]; then + echo "$*" + echo + fi + cat < + +Add stake to a validator + +OPTIONS: + --url RPC_URL - RPC URL to the cluster ($url) + --label LABEL - Append the given label to the configuration files, useful when running + multiple validators in the same workspace + --no-airdrop - Do not attempt to airdrop the stake + --keypair FILE - Keypair to fund the stake from + --force - Override delegate-stake sanity checks + --vote-account - Path to vote-account keypair file + --stake-account - Path to stake-account keypair file + +EOF + exit 1 +} + +common_args=() +label= +airdrops_enabled=1 +maybe_force= +keypair= + +positional_args=() +while [[ -n $1 ]]; do + if [[ ${1:0:1} = - ]]; then + if [[ $1 = --label ]]; then + label="-$2" + shift 2 + elif [[ $1 = --keypair || $1 = -k ]]; then + keypair="$2" + shift 2 + elif [[ $1 = --force ]]; then + maybe_force=--force + shift 1 + elif [[ $1 = --url || $1 = -u ]]; then + url=$2 + shift 2 + elif [[ $1 = --vote-account ]]; then + vote_account=$2 + shift 2 + elif [[ $1 = --stake-account ]]; then + stake_account=$2 + shift 2 + elif [[ $1 = --no-airdrop ]]; then + airdrops_enabled=0 + shift + elif [[ $1 = -h ]]; then + usage "$@" + else + echo "Unknown argument: $1" + usage + exit 1 + fi + else + positional_args+=("$1") + shift + fi +done + +common_args+=(--url "$url") + +if [[ ${#positional_args[@]} -gt 1 ]]; then + usage "$@" +fi +if [[ -n ${positional_args[0]} ]]; then + stake_sol=${positional_args[0]} +fi + +VALIDATOR_KEYS_DIR=$SOLANA_CONFIG_DIR/validator$label +vote_account="${vote_account:-$VALIDATOR_KEYS_DIR/vote-account.json}" +stake_account="${stake_account:-$VALIDATOR_KEYS_DIR/stake-account.json}" + +if [[ ! -f $vote_account ]]; then + echo "Error: $vote_account not found" + exit 1 +fi + +if ((airdrops_enabled)); then + if [[ -z $keypair ]]; then + echo "--keypair argument must be provided" + exit 1 + fi + $solana_cli \ + "${common_args[@]}" --keypair "$SOLANA_CONFIG_DIR/faucet.json" \ + transfer --allow-unfunded-recipient "$keypair" "$stake_sol" +fi + +if [[ -n $keypair ]]; then + common_args+=(--keypair "$keypair") +fi + +if ! [[ -f "$stake_account" ]]; then + $solana_keygen new --no-passphrase -so "$stake_account" +else + echo "$stake_account already exists! Using it" +fi + +set -x +$solana_cli "${common_args[@]}" \ + vote-account "$vote_account" +$solana_cli "${common_args[@]}" \ + create-stake-account "$stake_account" "$stake_sol" +$solana_cli "${common_args[@]}" \ + delegate-stake $maybe_force "$stake_account" "$vote_account" +$solana_cli "${common_args[@]}" stake-account "$stake_account" diff --git a/starship/charts/devnet/scripts/solana/faucet.sh b/starship/charts/devnet/scripts/solana/faucet.sh index 5ff864181..81aa36481 100644 --- a/starship/charts/devnet/scripts/solana/faucet.sh +++ b/starship/charts/devnet/scripts/solana/faucet.sh @@ -1,7 +1,19 @@ #!/usr/bin/env bash - +# +# Starts an instance of solana-faucet +# here=$(dirname "$0") + # shellcheck source=multinode-demo/common.sh source "$here"/common.sh -exec "$solana_faucet" --keypair "$SOLANA_CONFIG_DIR"/faucet.json \ No newline at end of file +[[ -f "$SOLANA_CONFIG_DIR"/faucet.json ]] || { + echo "$SOLANA_CONFIG_DIR/faucet.json not found, create it by running:" + echo + echo " ${here}/setup.sh" + exit 1 +} + +set -x +# shellcheck disable=SC2086 # Don't want to double quote $solana_faucet +exec $solana_faucet --keypair "$SOLANA_CONFIG_DIR"/faucet.json "$@" diff --git a/starship/charts/devnet/scripts/solana/validator-x.sh b/starship/charts/devnet/scripts/solana/validator-x.sh index 76c5d9911..455fdd486 100644 --- a/starship/charts/devnet/scripts/solana/validator-x.sh +++ b/starship/charts/devnet/scripts/solana/validator-x.sh @@ -1,21 +1,7 @@ #!/usr/bin/env bash +# +# Start a dynamically-configured validator +# here=$(dirname "$0") -# shellcheck source=multinode-demo/common.sh -source "$here"/common.sh - -# shellcheck source=net/common.sh -source "$(cd "$here"/..; pwd)"/net/common.sh - -if [[ -z $1 ]]; then - # - # Start a validator that connects to a bootstrap validator - # - $agave_validator_cuda \ - --contact-info 127.0.0.1:8001 \ - "$@" -else - $agave_validator \ - --contact-info 127.0.0.1:8001 \ - "$@" -fi \ No newline at end of file +exec "$here"/validator.sh --label x$$ "$@" diff --git a/starship/charts/devnet/scripts/solana/validator.sh b/starship/charts/devnet/scripts/solana/validator.sh index 7eb2359e9..800b4ce9d 100644 --- a/starship/charts/devnet/scripts/solana/validator.sh +++ b/starship/charts/devnet/scripts/solana/validator.sh @@ -1,11 +1,373 @@ #!/usr/bin/env bash - +# +# Start a validator +# here=$(dirname "$0") # shellcheck source=multinode-demo/common.sh source "$here"/common.sh -if [[ -z $1 ]]; then - $agave_validator_cuda "$@" +args=( + --max-genesis-archive-unpacked-size 1073741824 + --no-poh-speed-test + --no-os-network-limits-test +) +airdrops_enabled=1 +node_sol=500 # 500 SOL: number of SOL to airdrop the node for transaction fees and vote account rent exemption (ignored if airdrops_enabled=0) +label= +identity= +vote_account= +no_restart=0 +gossip_entrypoint= +ledger_dir= + +usage() { + if [[ -n $1 ]]; then + echo "$*" + echo + fi + cat < Date: Fri, 18 Jul 2025 20:39:17 +0530 Subject: [PATCH 07/31] update images and scripts to use agave --- starship/charts/devnet/defaults.yaml | 4 ++-- starship/charts/devnet/scripts/solana/common.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/starship/charts/devnet/defaults.yaml b/starship/charts/devnet/defaults.yaml index a5ce5a45d..6af98f02c 100644 --- a/starship/charts/devnet/defaults.yaml +++ b/starship/charts/devnet/defaults.yaml @@ -805,7 +805,7 @@ defaultChains: coingecko_id: xpla solana: type: solana - image: ghcr.io/hyperweb-io/starship/solana:v1.18.26 + image: ghcr.io/hyperweb-io/starship/solana-agave:v2.3.4 home: /root/.solana binary: solana-validator prefix: sol @@ -814,7 +814,7 @@ defaultChains: coins: 1000000000000000lamports hdPath: m/44'/501'/0'/0' coinType: 501 - repo: https://github.com/solana-labs/solana + repo: https://github.com/anzaxyz/agave faucet: enabled: true assets: diff --git a/starship/charts/devnet/scripts/solana/common.sh b/starship/charts/devnet/scripts/solana/common.sh index 01a692dcf..91977504e 100644 --- a/starship/charts/devnet/scripts/solana/common.sh +++ b/starship/charts/devnet/scripts/solana/common.sh @@ -27,7 +27,7 @@ solana_program() { printf "solana" else if [[ $program == "validator" || $program == "ledger-tool" || $program == "watchtower" || $program == "install" ]]; then - printf "solana-%s" "$program" + printf "agave-%s" "$program" else printf "solana-%s" "$program" fi From 06e16d6f10b7ec42d4047e671b71bc113547e0d8 Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Sat, 19 Jul 2025 00:51:36 +0530 Subject: [PATCH 08/31] add readinessprobe and chain ready script --- .../scripts/solana/bootstrap-validator.sh | 47 +-------- .../devnet/scripts/solana/chain-rpc-ready.sh | 96 +++++++++++++++++++ .../templates/chains/solana/genesis.yaml | 41 ++++++++ starship/scripts/port-forward.sh | 15 +++ 4 files changed, 156 insertions(+), 43 deletions(-) create mode 100644 starship/charts/devnet/scripts/solana/chain-rpc-ready.sh diff --git a/starship/charts/devnet/scripts/solana/bootstrap-validator.sh b/starship/charts/devnet/scripts/solana/bootstrap-validator.sh index 7e6edcc44..4fd0aa81e 100644 --- a/starship/charts/devnet/scripts/solana/bootstrap-validator.sh +++ b/starship/charts/devnet/scripts/solana/bootstrap-validator.sh @@ -150,12 +150,14 @@ fi args+=( --ledger "$ledger_dir" + --bind-address 0.0.0.0 + --rpc-bind-address 0.0.0.0 --rpc-port 8899 --snapshot-interval-slots 200 --no-incremental-snapshots --identity "$identity" --vote-account "$vote_account" - --rpc-faucet-address 127.0.0.1:9900 + --rpc-faucet-address 0.0.0.0:9900 --no-poh-speed-test --no-os-network-limits-test --no-wait-for-vote-to-start-leader @@ -165,45 +167,4 @@ args+=( default_arg --gossip-port 8001 default_arg --log - - -pid= -kill_node() { - # Note: do not echo anything from this function to ensure $pid is actually - # killed when stdout/stderr are redirected - set +ex - if [[ -n $pid ]]; then - declare _pid=$pid - pid= - kill "$_pid" || true - wait "$_pid" || true - fi -} - -kill_node_and_exit() { - kill_node - exit -} - -trap 'kill_node_and_exit' INT TERM ERR - -while true; do - echo "$program ${args[*]}" - $program "${args[@]}" & - pid=$! - echo "pid: $pid" - - if ((no_restart)); then - wait "$pid" - exit $? - fi - - while true; do - if [[ -z $pid ]] || ! kill -0 "$pid"; then - echo "############## validator exited, restarting ##############" - break - fi - sleep 1 - done - - kill_node -done \ No newline at end of file +$program "${args[@]}" diff --git a/starship/charts/devnet/scripts/solana/chain-rpc-ready.sh b/starship/charts/devnet/scripts/solana/chain-rpc-ready.sh new file mode 100644 index 000000000..2d49d38db --- /dev/null +++ b/starship/charts/devnet/scripts/solana/chain-rpc-ready.sh @@ -0,0 +1,96 @@ +#!/bin/bash +# chain-rpc-ready.sh - Check if a Solana RPC service is ready +# Usage: chain-rpc-ready.sh [RPC_URL] + +set -euo pipefail + +RPC_URL=${1:-"http://localhost:8899"} + +echo 1>&2 "Checking if Solana RPC at $RPC_URL is ready..." + +# Check if the RPC URL is reachable +json=$(curl -s --connect-timeout 2 -X POST -H "Content-Type: application/json" \ + -d '{"jsonrpc":"2.0","id":1,"method":"getHealth"}' \ + "$RPC_URL") + +# Check if we got a valid response +if [ $? -ne 0 ]; then + echo 1>&2 "$RPC_URL is not reachable" + exit 1 +fi + +# Check if the response contains an error +if echo "$json" | jq -e '.error' > /dev/null 2>&1; then + echo 1>&2 "$RPC_URL returned an error: $(echo "$json" | jq -r '.error.message // "Unknown error"')" + exit 1 +fi + +# Check if the health status is ok +health_status=$(echo "$json" | jq -r '.result // "unknown"') +if [ "$health_status" != "ok" ]; then + echo 1>&2 "$RPC_URL is not healthy: status is $health_status" + exit 1 +fi + +# Get slot info to check if the node is processing blocks +slot_info=$(curl -s --connect-timeout 2 -X POST -H "Content-Type: application/json" \ + -d '{"jsonrpc":"2.0","id":1,"method":"getSlot"}' \ + "$RPC_URL") + +# Check if we can get slot info +if [ $? -ne 0 ]; then + echo 1>&2 "$RPC_URL slot info not available" + exit 1 +fi + +# Check if slot is progressing (not stuck at 0) +current_slot=$(echo "$slot_info" | jq -r '.result // 0') +if [ "$current_slot" -eq 0 ]; then + echo 1>&2 "$RPC_URL is not ready: slot is 0 (node may not be synced)" + exit 1 +fi + +# Get epoch info to check if the node is properly synced +epoch_info=$(curl -s --connect-timeout 2 -X POST -H "Content-Type: application/json" \ + -d '{"jsonrpc":"2.0","id":1,"method":"getEpochInfo"}' \ + "$RPC_URL") + +# Check if we can get epoch info +if [ $? -ne 0 ]; then + echo 1>&2 "$RPC_URL epoch info not available" + exit 1 +fi + +# Check if epoch info is valid +if echo "$epoch_info" | jq -e '.error' > /dev/null 2>&1; then + echo 1>&2 "$RPC_URL epoch info error: $(echo "$epoch_info" | jq -r '.error.message // "Unknown error"')" + exit 1 +fi + +# Get cluster nodes to check if the node is part of the network +cluster_info=$(curl -s --connect-timeout 2 -X POST -H "Content-Type: application/json" \ + -d '{"jsonrpc":"2.0","id":1,"method":"getClusterNodes"}' \ + "$RPC_URL") + +# Check if we can get cluster info +if [ $? -ne 0 ]; then + echo 1>&2 "$RPC_URL cluster info not available" + exit 1 +fi + +# Check if cluster info is valid +if echo "$cluster_info" | jq -e '.error' > /dev/null 2>&1; then + echo 1>&2 "$RPC_URL cluster info error: $(echo "$cluster_info" | jq -r '.error.message // "Unknown error"')" + exit 1 +fi + +# Check if there are nodes in the cluster +node_count=$(echo "$cluster_info" | jq -r '.result | length // 0') +if [ "$node_count" -eq 0 ]; then + echo 1>&2 "$RPC_URL is not ready: no nodes in cluster" + exit 1 +fi + +echo 1>&2 "Solana RPC at $RPC_URL is ready and healthy" +echo "Health: $health_status, Slot: $current_slot, Cluster Nodes: $node_count" +exit 0 \ No newline at end of file diff --git a/starship/charts/devnet/templates/chains/solana/genesis.yaml b/starship/charts/devnet/templates/chains/solana/genesis.yaml index af7b9c68b..0d398e699 100644 --- a/starship/charts/devnet/templates/chains/solana/genesis.yaml +++ b/starship/charts/devnet/templates/chains/solana/genesis.yaml @@ -2,6 +2,7 @@ {{- if eq $chain.name "solana" }} {{ $defaultFile := $.Files.Get "defaults.yaml" | fromYaml }} {{ $chain := include "devnet.fullchain" (dict "name" $chain.id "file" $defaultFile "context" $) | fromJson }} +{{ $dataPublicRPC := dict "chain" $chain.id "port" "'8899'" }} --- apiVersion: apps/v1 kind: StatefulSet @@ -37,6 +38,8 @@ spec: env: {{- include "devnet.defaultEvnVars" $chain | indent 12 }} {{- include "devnet.evnVars" $chain | indent 12 }} + {{- include "devnet.timeoutVars" $.Values | indent 12 }} + {{- include "devnet.genesisVars" $dataPublicRPC | indent 12 }} - name: KEYS_CONFIG value: /configs/keys.json - name: FAUCET_ENABLED @@ -59,6 +62,9 @@ spec: echo "Running setup genesis script..." bash -e {{ $chain.home }}/scripts/setup.sh + + echo "Set config" + solana config set --url localhost resources: {{- include "devnet.node.resources" ( dict "node" $chain "context" $ ) | trim | nindent 12 }} volumeMounts: - mountPath: {{ $chain.home }} @@ -72,6 +78,8 @@ spec: env: {{- include "devnet.defaultEvnVars" $chain | indent 12 }} {{- include "devnet.evnVars" $chain | indent 12 }} + {{- include "devnet.timeoutVars" $.Values | indent 12 }} + {{- include "devnet.genesisVars" $dataPublicRPC | indent 12 }} - name: FAUCET_ENABLED value: "{{ $chain.faucet.enabled }}" - name: SOLANA_CONFIG_DIR @@ -92,6 +100,39 @@ spec: name: node - mountPath: /scripts name: scripts + startupProbe: + exec: + command: + - bash + - -e + - /scripts/chain-rpc-ready.sh + - http://0.0.0.0:8899 + initialDelaySeconds: 10 + periodSeconds: 30 + timeoutSeconds: 15 + failureThreshold: 10 + readinessProbe: + exec: + command: + - bash + - -e + - /scripts/chain-rpc-ready.sh + - http://0.0.0.0:8899 + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 15 + failureThreshold: 3 + livenessProbe: + exec: + command: + - bash + - -e + - /scripts/chain-rpc-ready.sh + - http://0.0.0.0:8899 + initialDelaySeconds: 60 + periodSeconds: 30 + timeoutSeconds: 15 + failureThreshold: 5 volumes: - name: node emptyDir: { } diff --git a/starship/scripts/port-forward.sh b/starship/scripts/port-forward.sh index a0055ece8..ad92594e4 100755 --- a/starship/scripts/port-forward.sh +++ b/starship/scripts/port-forward.sh @@ -27,6 +27,9 @@ CHAIN_GRPCWEB_PORT=9091 CHAIN_LCD_PORT=1317 CHAIN_EXPOSER_PORT=8081 CHAIN_FAUCET_PORT=8000 +SOLANA_RPC_PORT=8899 +SOLANA_WS_PORT=8900 +SOLANA_FAUCET_PORT=9900 ETHEREUM_REST_PORT=8545 ETHEREUM_RPC_PORT=8551 RELAYER_REST_PORT=3000 @@ -73,6 +76,18 @@ if [[ $num_chains -gt -1 ]]; then color yellow " Forwarding RPC: http://localhost:$localrpc" kubectl port-forward pods/$chain_name-$chain-0 $localrest:$ETHEREUM_REST_PORT > /dev/null 2>&1 & kubectl port-forward pods/$chain_name-$chain-0 $localrpc:$ETHEREUM_RPC_PORT > /dev/null 2>&1 & + elif [[ "$chain_name" == *"solana"* ]]; then + localrpc=$SOLANA_RPC_PORT + localws=$SOLANA_WS_PORT + localfaucet=$SOLANA_FAUCET_PORT + color yellow "Solana chain detected: $chain" + color yellow " Forwarding RPC: http://localhost:$localrpc" + color yellow " Forwarding WS: http://localhost:$localws" + color yellow " Forwarding Faucet: http://localhost:$localfaucet" + kubectl port-forward pods/$chain_name-$chain-0 $localrpc:$SOLANA_RPC_PORT > /dev/null 2>&1 & + kubectl port-forward pods/$chain_name-$chain-0 $localws:$SOLANA_WS_PORT > /dev/null 2>&1 & + kubectl port-forward pods/$chain_name-$chain-0 $localfaucet:$SOLANA_FAUCET_PORT > /dev/null 2>&1 & + sleep 1 else localrpc=$(yq -r ".chains[$i].ports.rpc" ${CONFIGFILE} ) localgrpc=$(yq -r ".chains[$i].ports.grpc" ${CONFIGFILE} ) From c18b339fdc7390fc5c90181ff1f37bb344c7093c Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Sat, 19 Jul 2025 01:09:26 +0530 Subject: [PATCH 09/31] add registry to solana testing --- starship/charts/devnet/scripts/solana/chain-rpc-ready.sh | 2 +- starship/charts/devnet/scripts/solana/common.sh | 7 ++++++- starship/tests/e2e/configs/solana.yaml | 8 ++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/starship/charts/devnet/scripts/solana/chain-rpc-ready.sh b/starship/charts/devnet/scripts/solana/chain-rpc-ready.sh index 2d49d38db..eba37183a 100644 --- a/starship/charts/devnet/scripts/solana/chain-rpc-ready.sh +++ b/starship/charts/devnet/scripts/solana/chain-rpc-ready.sh @@ -93,4 +93,4 @@ fi echo 1>&2 "Solana RPC at $RPC_URL is ready and healthy" echo "Health: $health_status, Slot: $current_slot, Cluster Nodes: $node_count" -exit 0 \ No newline at end of file +exit 0 diff --git a/starship/charts/devnet/scripts/solana/common.sh b/starship/charts/devnet/scripts/solana/common.sh index 91977504e..8dfcb0b05 100644 --- a/starship/charts/devnet/scripts/solana/common.sh +++ b/starship/charts/devnet/scripts/solana/common.sh @@ -27,7 +27,12 @@ solana_program() { printf "solana" else if [[ $program == "validator" || $program == "ledger-tool" || $program == "watchtower" || $program == "install" ]]; then - printf "agave-%s" "$program" + # Check if agave- prefixed binary exists + if command -v "agave-$program" >/dev/null 2>&1; then + printf "agave-%s" "$program" + else + printf "solana-%s" "$program" + fi else printf "solana-%s" "$program" fi diff --git a/starship/tests/e2e/configs/solana.yaml b/starship/tests/e2e/configs/solana.yaml index ea0df08b4..6657fdaaf 100644 --- a/starship/tests/e2e/configs/solana.yaml +++ b/starship/tests/e2e/configs/solana.yaml @@ -12,3 +12,11 @@ chains: resources: cpu: 2000m memory: 2048Mi + +registry: + enabled: true + ports: + rest: 8081 + resources: + cpu: "0.1" + memory: "100M" From 359c5157905c75ffb52d0365db53b9c31a840ea0 Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Thu, 31 Jul 2025 14:45:01 +0530 Subject: [PATCH 10/31] add exposer for genesis node for solana --- .../scripts/solana/bootstrap-validator.sh | 2 +- .../charts/devnet/scripts/solana/setup.sh | 3 ++- .../templates/chains/solana/genesis.yaml | 24 +++++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/starship/charts/devnet/scripts/solana/bootstrap-validator.sh b/starship/charts/devnet/scripts/solana/bootstrap-validator.sh index 4fd0aa81e..d2da97ebc 100644 --- a/starship/charts/devnet/scripts/solana/bootstrap-validator.sh +++ b/starship/charts/devnet/scripts/solana/bootstrap-validator.sh @@ -2,7 +2,7 @@ # # Start the bootstrap validator node # -set -e +set -ex here=$(dirname "$0") source "$here"/common.sh diff --git a/starship/charts/devnet/scripts/solana/setup.sh b/starship/charts/devnet/scripts/solana/setup.sh index c500590b6..6a8567bf3 100644 --- a/starship/charts/devnet/scripts/solana/setup.sh +++ b/starship/charts/devnet/scripts/solana/setup.sh @@ -3,7 +3,7 @@ here=$(dirname "$0") source "$here"/common.sh -set -e +set -ex rm -rf "$SOLANA_CONFIG_DIR"/bootstrap-validator mkdir -p "$SOLANA_CONFIG_DIR"/bootstrap-validator @@ -33,6 +33,7 @@ fi args=( "$@" + --bootstrap-validator-lamports 500000000000 --max-genesis-archive-unpacked-size 1073741824 --enable-warmup-epochs --bootstrap-validator "$SOLANA_CONFIG_DIR"/bootstrap-validator/identity.json diff --git a/starship/charts/devnet/templates/chains/solana/genesis.yaml b/starship/charts/devnet/templates/chains/solana/genesis.yaml index 0d398e699..bbfceee15 100644 --- a/starship/charts/devnet/templates/chains/solana/genesis.yaml +++ b/starship/charts/devnet/templates/chains/solana/genesis.yaml @@ -1,5 +1,6 @@ {{- range $chain := .Values.chains }} {{- if eq $chain.name "solana" }} +{{ $dataExposer := dict "chain" $chain.id "port" ($.Values.exposer.ports.rest | quote | default "8081") }} {{ $defaultFile := $.Files.Get "defaults.yaml" | fromYaml }} {{ $chain := include "devnet.fullchain" (dict "name" $chain.id "file" $defaultFile "context" $) | fromJson }} {{ $dataPublicRPC := dict "chain" $chain.id "port" "'8899'" }} @@ -63,6 +64,11 @@ spec: echo "Running setup genesis script..." bash -e {{ $chain.home }}/scripts/setup.sh + echo "Create node id json file" + mkdir -p $CHAIN_DIR/config/ + NODE_ID=$(solana address --keypair $CHAIN_DIR/bootstrap-validator/identity.json) + echo '{"node_id":"'$NODE_ID'"}' > $CHAIN_DIR/config/node_id.json + echo "Set config" solana config set --url localhost resources: {{- include "devnet.node.resources" ( dict "node" $chain "context" $ ) | trim | nindent 12 }} @@ -133,6 +139,24 @@ spec: periodSeconds: 30 timeoutSeconds: 15 failureThreshold: 5 + - name: exposer + image: {{ $.Values.exposer.image }} + imagePullPolicy: {{ $.Values.images.imagePullPolicy }} + env: + {{- include "devnet.genesisVars" $dataExposer | indent 12}} + - name: EXPOSER_HTTP_PORT + value: "8081" + - name: EXPOSER_GRPC_PORT + value: "9099" + - name: EXPOSER_GENESIS_FILE + value: {{ $chain.home }}/bootstrap-validator/genesis.bin + - name: EXPOSER_NODE_ID_FILE + value: {{ $chain.home }}/config/node_id.json + command: [ "exposer" ] + resources: {{- include "getResourceObject" $.Values.exposer.resources | trim | nindent 12 }} + volumeMounts: + - mountPath: {{ $chain.home }} + name: node volumes: - name: node emptyDir: { } From a73ece74c4b9ba5cac225a70485591cc0c823ab5 Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Thu, 31 Jul 2025 15:13:26 +0530 Subject: [PATCH 11/31] set config for the chain better, use it properly for the validator nodes --- .../charts/devnet/templates/chains/solana/genesis.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/starship/charts/devnet/templates/chains/solana/genesis.yaml b/starship/charts/devnet/templates/chains/solana/genesis.yaml index bbfceee15..6b8d26129 100644 --- a/starship/charts/devnet/templates/chains/solana/genesis.yaml +++ b/starship/charts/devnet/templates/chains/solana/genesis.yaml @@ -71,6 +71,8 @@ spec: echo "Set config" solana config set --url localhost + solana config set --keypair $CHAIN_DIR/bootstrap-validator/identity.json + cp /root/.config/solana/cli/config.yml $CHAIN_DIR/config/config.yml resources: {{- include "devnet.node.resources" ( dict "node" $chain "context" $ ) | trim | nindent 12 }} volumeMounts: - mountPath: {{ $chain.home }} @@ -98,6 +100,9 @@ spec: - bash - "-c" - | + mkdir -p /root/.config/solana/cli/ + cp $CHAIN_DIR/config/config.yml /root/.config/solana/cli/config.yml + echo "Running bootstrap validator script..." bash -e {{ $chain.home }}/scripts/bootstrap-validator.sh resources: {{- include "devnet.node.resources" ( dict "node" $chain "context" $ ) | trim | nindent 12 }} @@ -152,6 +157,8 @@ spec: value: {{ $chain.home }}/bootstrap-validator/genesis.bin - name: EXPOSER_NODE_ID_FILE value: {{ $chain.home }}/config/node_id.json + - name: EXPOSER_CONFIG_FILE + value: {{ $chain.home }}/config/config.yml command: [ "exposer" ] resources: {{- include "getResourceObject" $.Values.exposer.resources | trim | nindent 12 }} volumeMounts: From ac71f51362f13bffa002b7a9d6f55bd8a9f2f26c Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Thu, 31 Jul 2025 17:07:47 +0530 Subject: [PATCH 12/31] add solana-faucet to faucet types --- starship/charts/devnet/defaults.yaml | 4 +++ .../charts/devnet/scripts/solana/faucet.sh | 8 ++++- .../templates/chains/solana/genesis.yaml | 34 +++++++++++++++++++ .../templates/chains/solana/validator.yaml | 4 ++- starship/charts/devnet/values.schema.json | 3 +- 5 files changed, 50 insertions(+), 3 deletions(-) diff --git a/starship/charts/devnet/defaults.yaml b/starship/charts/devnet/defaults.yaml index 6af98f02c..da8ee67ab 100644 --- a/starship/charts/devnet/defaults.yaml +++ b/starship/charts/devnet/defaults.yaml @@ -817,6 +817,7 @@ defaultChains: repo: https://github.com/anzaxyz/agave faucet: enabled: true + type: solana-faucet assets: - base: lamports description: "The native token of Solana" @@ -1038,6 +1039,9 @@ defaultFaucet: starship: image: ghcr.io/hyperweb-io/starship/faucet:20250325-2207109 concurrency: 5 + solana-faucet: + image: ghcr.io/hyperweb-io/starship/solana-agave:v2.3.4 + concurrency: 5 defaultCometmock: image: ghcr.io/informalsystems/cometmock:v0.37.x diff --git a/starship/charts/devnet/scripts/solana/faucet.sh b/starship/charts/devnet/scripts/solana/faucet.sh index 81aa36481..18e96dee3 100644 --- a/starship/charts/devnet/scripts/solana/faucet.sh +++ b/starship/charts/devnet/scripts/solana/faucet.sh @@ -16,4 +16,10 @@ source "$here"/common.sh set -x # shellcheck disable=SC2086 # Don't want to double quote $solana_faucet -exec $solana_faucet --keypair "$SOLANA_CONFIG_DIR"/faucet.json "$@" +exec $solana_faucet \ + --keypair "$SOLANA_CONFIG_DIR"/faucet.json \ + --port 9999 \ + --allow-ip 0.0.0.0/0 \ + --per-time-cap 999999999 \ + --per-request-cap 999999999 \ + "$@" diff --git a/starship/charts/devnet/templates/chains/solana/genesis.yaml b/starship/charts/devnet/templates/chains/solana/genesis.yaml index 6b8d26129..d3cc248e0 100644 --- a/starship/charts/devnet/templates/chains/solana/genesis.yaml +++ b/starship/charts/devnet/templates/chains/solana/genesis.yaml @@ -164,6 +164,40 @@ spec: volumeMounts: - mountPath: {{ $chain.home }} name: node + {{- if $chain.faucet.enabled }} + {{- if eq $chain.faucet.type "solana-faucet" }} + - name: faucet + image: {{ $chain.image }} + imagePullPolicy: {{ $.Values.images.imagePullPolicy }} + env: + {{- include "devnet.genesisVars" $dataExposer | indent 12}} + - name: SOLANA_CONFIG_DIR + value: {{ $chain.home }} + - name: SOLANA_FAUCET_PORT + value: "9900" + - name: SOLANA_FAUCET_ALLOW_IP + value: "0.0.0.0/0" + - name: SOLANA_FAUCET_PER_TIME_CAP + value: "1000000000000000000" + command: + - bash + - -c + - | + set -ex + solana-faucet \ + --keypair {{ $chain.home }}/faucet.json \ + --port $SOLANA_FAUCET_PORT \ + --allow-ip $SOLANA_FAUCET_ALLOW_IP \ + --per-time-cap $SOLANA_FAUCET_PER_TIME_CAP \ + --per-request-cap $SOLANA_FAUCET_PER_REQUEST_CAP + resources: {{- include "getResourceObject" $chain.faucet.resources | trim | nindent 12 }} + volumeMounts: + - mountPath: {{ $chain.home }} + name: node + - mountPath: /scripts + name: scripts + {{- end }} + {{- end }} volumes: - name: node emptyDir: { } diff --git a/starship/charts/devnet/templates/chains/solana/validator.yaml b/starship/charts/devnet/templates/chains/solana/validator.yaml index c7e48bc7f..5ca090e5e 100644 --- a/starship/charts/devnet/templates/chains/solana/validator.yaml +++ b/starship/charts/devnet/templates/chains/solana/validator.yaml @@ -1,5 +1,6 @@ {{- range $chain := .Values.chains }} {{- if eq $chain.name "solana" }} +{{- if gt $chain.numValidators 1.0 }} {{ $defaultFile := $.Files.Get "defaults.yaml" | fromYaml }} {{ $chain := include "devnet.fullchain" (dict "name" $chain.id "file" $defaultFile "context" $) | fromJson }} --- @@ -37,4 +38,5 @@ spec: name: setup-scripts-{{ $chain.hostname }} defaultMode: 0777 {{- end }} -{{- end }} \ No newline at end of file +{{- end }} +{{- end }} diff --git a/starship/charts/devnet/values.schema.json b/starship/charts/devnet/values.schema.json index c310a642f..c3ed3da0b 100644 --- a/starship/charts/devnet/values.schema.json +++ b/starship/charts/devnet/values.schema.json @@ -53,7 +53,8 @@ "type": "string", "enum": [ "cosmjs", - "starship" + "starship", + "solana-faucet" ] }, "image": { From 411ddd6875e406df6780827a5d23180c37c9d062 Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Thu, 31 Jul 2025 18:05:02 +0530 Subject: [PATCH 13/31] fix solana-faucet container --- starship/charts/devnet/templates/chains/solana/genesis.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/starship/charts/devnet/templates/chains/solana/genesis.yaml b/starship/charts/devnet/templates/chains/solana/genesis.yaml index d3cc248e0..9879ac31a 100644 --- a/starship/charts/devnet/templates/chains/solana/genesis.yaml +++ b/starship/charts/devnet/templates/chains/solana/genesis.yaml @@ -179,14 +179,15 @@ spec: value: "0.0.0.0/0" - name: SOLANA_FAUCET_PER_TIME_CAP value: "1000000000000000000" + - name: SOLANA_FAUCET_PER_REQUEST_CAP + value: "1000000000000000000" command: - bash - -c - | set -ex solana-faucet \ - --keypair {{ $chain.home }}/faucet.json \ - --port $SOLANA_FAUCET_PORT \ + --keypair $SOLANA_CONFIG_DIR/faucet.json \ --allow-ip $SOLANA_FAUCET_ALLOW_IP \ --per-time-cap $SOLANA_FAUCET_PER_TIME_CAP \ --per-request-cap $SOLANA_FAUCET_PER_REQUEST_CAP From d8c577f1cbe985d8391a8ddf5b62c85e5de10215 Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Thu, 31 Jul 2025 21:04:27 +0530 Subject: [PATCH 14/31] add initial setup for multi-validator solana setup --- .../templates/chains/solana/validator.yaml | 140 ++++++++++++++++-- starship/tests/e2e/configs/solana.yaml | 2 +- 2 files changed, 131 insertions(+), 11 deletions(-) diff --git a/starship/charts/devnet/templates/chains/solana/validator.yaml b/starship/charts/devnet/templates/chains/solana/validator.yaml index 5ca090e5e..d97a42248 100644 --- a/starship/charts/devnet/templates/chains/solana/validator.yaml +++ b/starship/charts/devnet/templates/chains/solana/validator.yaml @@ -1,8 +1,10 @@ {{- range $chain := .Values.chains }} {{- if eq $chain.name "solana" }} {{- if gt $chain.numValidators 1.0 }} +{{- $dataExposer := dict "chain" $chain.id "port" ($.Values.exposer.ports.rest | quote | default "8081") }} {{ $defaultFile := $.Files.Get "defaults.yaml" | fromYaml }} {{ $chain := include "devnet.fullchain" (dict "name" $chain.id "file" $defaultFile "context" $) | fromJson }} +{{ $initParams := dict "chains" (list $chain.id) "port" $.Values.exposer.ports.rest "context" $ }} --- apiVersion: apps/v1 kind: StatefulSet @@ -17,22 +19,140 @@ spec: app.kubernetes.io/name: {{ $chain.id }}-validator template: metadata: + annotations: + quality: release + role: api-gateway + sla: high + tier: gateway labels: app.kubernetes.io/instance: {{ $chain.name }} + app.kubernetes.io/type: {{ $chain.id }} app.kubernetes.io/name: {{ $chain.id }}-validator + app.kubernetes.io/rawname: {{ $chain.id }} + app.kubernetes.io/version: {{ $.Chart.AppVersion }} spec: + {{- include "imagePullSecrets" $chain | indent 6 }} + initContainers: + {{- include "devnet.init.wait" $initParams | indent 8 }} + - name: init-validator + image: {{ $chain.image }} + imagePullPolicy: {{ $.Values.images.imagePullPolicy }} + env: + {{- include "devnet.defaultEvnVars" $chain | indent 12 }} + {{- include "devnet.evnVars" $chain | indent 12 }} + {{- include "devnet.timeoutVars" $.Values | indent 12 }} + {{- include "devnet.genesisVars" $dataExposer | indent 12 }} + - name: KEYS_CONFIG + value: /configs/keys.json + - name: FAUCET_ENABLED + value: "{{ $chain.faucet.enabled }}" + - name: NUM_VALIDATORS + value: "{{ $chain.numValidators }}" + - name: SOLANA_CONFIG_DIR + value: {{ $chain.home }} + command: + - bash + - "-c" + - | + set -ex + + VAL_INDEX=${HOSTNAME##*-} + echo "Validator Index: $VAL_INDEX" + + echo "Move scripts to config dir" + mkdir -p $SOLANA_CONFIG_DIR/scripts/ + cp -L /scripts/* $SOLANA_CONFIG_DIR/scripts/ + chmod +x $SOLANA_CONFIG_DIR/scripts/* + + # Run validator setup + solana-keygen new --no-passphrase -so $SOLANA_CONFIG_DIR/identity.json + solana-keygen new --no-passphrase -so $SOLANA_CONFIG_DIR/vote-account.json + solana-keygen new --no-passphrase -so $SOLANA_CONFIG_DIR/authorized-withdrawer.json + + # Set config + solana config set --url http://solana-genesis.svc.cluster.local:8899 + solana config set --keypair $SOLANA_CONFIG_DIR/identity.json + + echo "Create node id json file" + mkdir -p $SOLANA_CONFIG_DIR/config/ + NODE_ID=$(solana address --keypair $SOLANA_CONFIG_DIR/identity.json) + echo '{"node_id":"'$NODE_ID'"}' > $SOLANA_CONFIG_DIR/config/node_id.json + + # Transfer from faucet + ## Get validator pubkey + VALIDATOR_PUBKEY=$(solana-keygen pubkey $SOLANA_CONFIG_DIR/identity.json) + solana airdrop 100 $VALIDATOR_PUBKEY + ## Verify balance + solana balance $VALIDATOR_PUBKEY + + cp /root/.config/solana/cli/config.yml $SOLANA_CONFIG_DIR/config/config.yml + resources: {{- include "devnet.node.resources" ( dict "node" $chain "context" $ ) | trim | nindent 12 }} + volumeMounts: + - mountPath: {{ $chain.home }} + name: node + - mountPath: /scripts + name: scripts containers: - - name: validator - image: {{ $chain.image }} - command: ["/bin/bash", "-c"] - args: - - | - VAL_INDEX=${HOSTNAME##*-} - /scripts/validator-x.sh $VAL_INDEX - volumeMounts: - - name: scripts - mountPath: /scripts + - name: validator + image: {{ $chain.image }} + imagePullPolicy: {{ $.Values.images.imagePullPolicy }} + env: + {{- include "devnet.defaultEvnVars" $chain | indent 12 }} + {{- include "devnet.evnVars" $chain | indent 12 }} + {{- include "devnet.timeoutVars" $.Values | indent 12 }} + {{- include "devnet.genesisVars" $dataExposer | indent 12 }} + - name: KEYS_CONFIG + value: /configs/keys.json + - name: FAUCET_ENABLED + value: "{{ $chain.faucet.enabled }}" + - name: NUM_VALIDATORS + value: "{{ $chain.numValidators }}" + - name: SOLANA_CONFIG_DIR + value: {{ $chain.home }} + command: ["/bin/bash", "-c"] + args: + - | + set -ex + + # Copy config + mkdir -p /root/.config/solana/cli/ + cp $SOLANA_CONFIG_DIR/config/config.yml /root/.config/solana/cli/config.yml + + agave-validator \ + --identity $SOLANA_CONFIG_DIR/identity.json \ + --vote-account $SOLANA_CONFIG_DIR/vote-account.json \ + --authorized-withdrawer $SOLANA_CONFIG_DIR/authorized-withdrawer.json \ + --rpc-port 8899 \ + --entrypoint solana-genesis.svc.cluster.local:8001 + resources: {{- include "devnet.node.resources" ( dict "node" $chain "context" $ ) | trim | nindent 12 }} + volumeMounts: + - mountPath: {{ $chain.home }} + name: node + - mountPath: /scripts + name: scripts + - name: exposer + image: {{ $.Values.exposer.image }} + imagePullPolicy: {{ $.Values.images.imagePullPolicy }} + env: + {{- include "devnet.genesisVars" $dataExposer | indent 12}} + - name: EXPOSER_HTTP_PORT + value: "8081" + - name: EXPOSER_GRPC_PORT + value: "9099" + - name: EXPOSER_GENESIS_FILE + value: {{ $chain.home }}/genesis.bin + - name: EXPOSER_NODE_ID_FILE + value: {{ $chain.home }}/config/node_id.json + - name: EXPOSER_CONFIG_FILE + value: {{ $chain.home }}/config/config.yml + command: [ "exposer" ] + resources: {{- include "getResourceObject" $.Values.exposer.resources | trim | nindent 12 }} + volumeMounts: + - mountPath: {{ $chain.home }} + name: node volumes: + - name: node + emptyDir: { } - name: scripts configMap: name: setup-scripts-{{ $chain.hostname }} diff --git a/starship/tests/e2e/configs/solana.yaml b/starship/tests/e2e/configs/solana.yaml index 6657fdaaf..19ee0e9d2 100644 --- a/starship/tests/e2e/configs/solana.yaml +++ b/starship/tests/e2e/configs/solana.yaml @@ -4,7 +4,7 @@ version: 1.7.0 chains: - id: solana name: solana - numValidators: 1 + numValidators: 2 ports: rpc: 8899 ws: 8900 From 82c3e0988eea39a55346d949ee9edeb68a0f369b Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Thu, 31 Jul 2025 21:35:27 +0530 Subject: [PATCH 15/31] fix dns for genesis rpc endpoint --- .../charts/devnet/templates/chains/solana/validator.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/starship/charts/devnet/templates/chains/solana/validator.yaml b/starship/charts/devnet/templates/chains/solana/validator.yaml index d97a42248..6f64f3c2d 100644 --- a/starship/charts/devnet/templates/chains/solana/validator.yaml +++ b/starship/charts/devnet/templates/chains/solana/validator.yaml @@ -55,7 +55,7 @@ spec: - "-c" - | set -ex - + VAL_INDEX=${HOSTNAME##*-} echo "Validator Index: $VAL_INDEX" @@ -70,7 +70,7 @@ spec: solana-keygen new --no-passphrase -so $SOLANA_CONFIG_DIR/authorized-withdrawer.json # Set config - solana config set --url http://solana-genesis.svc.cluster.local:8899 + solana config set --url http://solana-genesis.$NAMESPACE.svc.cluster.local:8899 solana config set --keypair $SOLANA_CONFIG_DIR/identity.json echo "Create node id json file" @@ -123,7 +123,7 @@ spec: --vote-account $SOLANA_CONFIG_DIR/vote-account.json \ --authorized-withdrawer $SOLANA_CONFIG_DIR/authorized-withdrawer.json \ --rpc-port 8899 \ - --entrypoint solana-genesis.svc.cluster.local:8001 + --entrypoint solana-genesis.$NAMESPACE.svc.cluster.local:8001 resources: {{- include "devnet.node.resources" ( dict "node" $chain "context" $ ) | trim | nindent 12 }} volumeMounts: - mountPath: {{ $chain.home }} From 969942684b7c1f8dfadea5c9a6a43dd881decd85 Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Sat, 2 Aug 2025 12:32:40 +0530 Subject: [PATCH 16/31] get validator working with the bootstrap node --- .../scripts/solana/bootstrap-validator.sh | 4 + .../templates/chains/solana/genesis.yaml | 6 ++ .../templates/chains/solana/service.yaml | 4 +- .../templates/chains/solana/validator.yaml | 78 ++++++++++++++++--- 4 files changed, 81 insertions(+), 11 deletions(-) diff --git a/starship/charts/devnet/scripts/solana/bootstrap-validator.sh b/starship/charts/devnet/scripts/solana/bootstrap-validator.sh index d2da97ebc..2aca3e9ae 100644 --- a/starship/charts/devnet/scripts/solana/bootstrap-validator.sh +++ b/starship/charts/devnet/scripts/solana/bootstrap-validator.sh @@ -148,11 +148,15 @@ if [[ $maybeRequireTower = true ]]; then args+=(--require-tower) fi +POD_IP=$(hostname -i | awk '{print $1}') + args+=( --ledger "$ledger_dir" + --public-rpc-address $POD_IP:8899 --bind-address 0.0.0.0 --rpc-bind-address 0.0.0.0 --rpc-port 8899 + --gossip-host $POD_IP --snapshot-interval-slots 200 --no-incremental-snapshots --identity "$identity" diff --git a/starship/charts/devnet/templates/chains/solana/genesis.yaml b/starship/charts/devnet/templates/chains/solana/genesis.yaml index 9879ac31a..995a4fc4b 100644 --- a/starship/charts/devnet/templates/chains/solana/genesis.yaml +++ b/starship/charts/devnet/templates/chains/solana/genesis.yaml @@ -67,7 +67,9 @@ spec: echo "Create node id json file" mkdir -p $CHAIN_DIR/config/ NODE_ID=$(solana address --keypair $CHAIN_DIR/bootstrap-validator/identity.json) + NODE_PUBKEY=$(solana-keygen pubkey $CHAIN_DIR/bootstrap-validator/identity.json) echo '{"node_id":"'$NODE_ID'"}' > $CHAIN_DIR/config/node_id.json + echo '{"priv_key":{"type":"solana","value":"'$NODE_PUBKEY'"}}' > $CHAIN_DIR/config/node_key.json echo "Set config" solana config set --url localhost @@ -100,6 +102,8 @@ spec: - bash - "-c" - | + set -ex + mkdir -p /root/.config/solana/cli/ cp $CHAIN_DIR/config/config.yml /root/.config/solana/cli/config.yml @@ -159,6 +163,8 @@ spec: value: {{ $chain.home }}/config/node_id.json - name: EXPOSER_CONFIG_FILE value: {{ $chain.home }}/config/config.yml + - name: EXPOSER_NODE_KEY_FILE + value: {{ $chain.home }}/config/node_key.json command: [ "exposer" ] resources: {{- include "getResourceObject" $.Values.exposer.resources | trim | nindent 12 }} volumeMounts: diff --git a/starship/charts/devnet/templates/chains/solana/service.yaml b/starship/charts/devnet/templates/chains/solana/service.yaml index 8b6db8048..d6f884ec9 100644 --- a/starship/charts/devnet/templates/chains/solana/service.yaml +++ b/starship/charts/devnet/templates/chains/solana/service.yaml @@ -21,9 +21,9 @@ spec: port: 8900 protocol: TCP targetPort: 8900 - - name: p2p + - name: p2p-udp port: 8001 - protocol: TCP + protocol: UDP targetPort: 8001 {{- if $chain.metrics }} - name: metrics diff --git a/starship/charts/devnet/templates/chains/solana/validator.yaml b/starship/charts/devnet/templates/chains/solana/validator.yaml index 6f64f3c2d..3e925573a 100644 --- a/starship/charts/devnet/templates/chains/solana/validator.yaml +++ b/starship/charts/devnet/templates/chains/solana/validator.yaml @@ -65,9 +65,21 @@ spec: chmod +x $SOLANA_CONFIG_DIR/scripts/* # Run validator setup - solana-keygen new --no-passphrase -so $SOLANA_CONFIG_DIR/identity.json - solana-keygen new --no-passphrase -so $SOLANA_CONFIG_DIR/vote-account.json - solana-keygen new --no-passphrase -so $SOLANA_CONFIG_DIR/authorized-withdrawer.json + if [ ! -f $SOLANA_CONFIG_DIR/identity.json ]; then + solana-keygen new --no-passphrase -so $SOLANA_CONFIG_DIR/identity.json + fi + if [ ! -f $SOLANA_CONFIG_DIR/vote-account.json ]; then + solana-keygen new --no-passphrase -so $SOLANA_CONFIG_DIR/vote-account.json + fi + if [ ! -f $SOLANA_CONFIG_DIR/authorized-voter.json ]; then + solana-keygen new --no-passphrase -so $SOLANA_CONFIG_DIR/authorized-voter.json + fi + if [ ! -f $SOLANA_CONFIG_DIR/authorized-withdrawer.json ]; then + solana-keygen new --no-passphrase -so $SOLANA_CONFIG_DIR/authorized-withdrawer.json + fi + if [ ! -f $SOLANA_CONFIG_DIR/stake-account.json ]; then + solana-keygen new --no-passphrase -so $SOLANA_CONFIG_DIR/stake-account.json + fi # Set config solana config set --url http://solana-genesis.$NAMESPACE.svc.cluster.local:8899 @@ -78,13 +90,40 @@ spec: NODE_ID=$(solana address --keypair $SOLANA_CONFIG_DIR/identity.json) echo '{"node_id":"'$NODE_ID'"}' > $SOLANA_CONFIG_DIR/config/node_id.json - # Transfer from faucet - ## Get validator pubkey + # Setup validator accounts (like multinode-demo) VALIDATOR_PUBKEY=$(solana-keygen pubkey $SOLANA_CONFIG_DIR/identity.json) - solana airdrop 100 $VALIDATOR_PUBKEY - ## Verify balance + STAKE_ACCOUNT_PUBKEY=$(solana-keygen pubkey $SOLANA_CONFIG_DIR/stake-account.json) + VOTE_ACCOUNT_PUBKEY=$(solana-keygen pubkey $SOLANA_CONFIG_DIR/vote-account.json) + AUTHORIZED_WITHDRAWER_PUBKEY=$(solana-keygen pubkey $SOLANA_CONFIG_DIR/authorized-withdrawer.json) + + # Fund validator identity account + echo "Funding validator identity account with 500 SOL" + solana airdrop 500 $VALIDATOR_PUBKEY + + # Create vote account with both authorities + echo "Creating validator vote account" + solana create-vote-account $SOLANA_CONFIG_DIR/vote-account.json $SOLANA_CONFIG_DIR/identity.json $AUTHORIZED_WITHDRAWER_PUBKEY + + # Vote for the vote account + echo "Voting for the vote account" + solana vote-account $VOTE_ACCOUNT_PUBKEY + + # Verify balance + echo "Validator identity account balance:" solana balance $VALIDATOR_PUBKEY + # Create stake account + echo "Creating stake account" + solana create-stake-account $SOLANA_CONFIG_DIR/stake-account.json 10 + solana delegate-stake $STAKE_ACCOUNT_PUBKEY $VOTE_ACCOUNT_PUBKEY + + # Get bootstrap validator's public key + BOOTSTRAP_PUBKEY=$(curl -s http://solana-genesis.$NAMESPACE.svc.cluster.local:8081/node_key | jq -r '.priv_key.value') + echo "Bootstrap validator public key: $BOOTSTRAP_PUBKEY" + + POD_IP=$(hostname -i | awk '{print $1}') + echo "Pod IP: $POD_IP" + cp /root/.config/solana/cli/config.yml $SOLANA_CONFIG_DIR/config/config.yml resources: {{- include "devnet.node.resources" ( dict "node" $chain "context" $ ) | trim | nindent 12 }} volumeMounts: @@ -96,6 +135,9 @@ spec: - name: validator image: {{ $chain.image }} imagePullPolicy: {{ $.Values.images.imagePullPolicy }} + #securityContext: + # runAsUser: 0 # Run as root to set ulimit + # fsGroup: 0 env: {{- include "devnet.defaultEvnVars" $chain | indent 12 }} {{- include "devnet.evnVars" $chain | indent 12 }} @@ -118,12 +160,30 @@ spec: mkdir -p /root/.config/solana/cli/ cp $SOLANA_CONFIG_DIR/config/config.yml /root/.config/solana/cli/config.yml + # Get bootstrap validator's public key + BOOTSTRAP_PUBKEY=$(curl -s http://solana-genesis.$NAMESPACE.svc.cluster.local:8081/node_key | jq -r '.priv_key.value') + echo "Bootstrap validator public key: $BOOTSTRAP_PUBKEY" + + POD_IP=$(hostname -i | awk '{print $1}') + agave-validator \ --identity $SOLANA_CONFIG_DIR/identity.json \ + --max-genesis-archive-unpacked-size 1073741824 \ --vote-account $SOLANA_CONFIG_DIR/vote-account.json \ - --authorized-withdrawer $SOLANA_CONFIG_DIR/authorized-withdrawer.json \ + --bind-address 0.0.0.0 \ + --rpc-bind-address 0.0.0.0 \ --rpc-port 8899 \ - --entrypoint solana-genesis.$NAMESPACE.svc.cluster.local:8001 + --gossip-port 8001 \ + --public-rpc-address $POD_IP:8899 \ + --rpc-faucet-address solana-genesis.$NAMESPACE.svc.cluster.local:9900 \ + --allow-private-addr \ + --entrypoint solana-genesis.$NAMESPACE.svc.cluster.local:8001 \ + --known-validator $BOOTSTRAP_PUBKEY \ + --no-os-network-limits-test \ + --log - \ + --full-rpc-api \ + --no-incremental-snapshots \ + --require-tower resources: {{- include "devnet.node.resources" ( dict "node" $chain "context" $ ) | trim | nindent 12 }} volumeMounts: - mountPath: {{ $chain.home }} From 2631f4df6d632c7874eaebbdd773f45196cffc60 Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Mon, 4 Aug 2025 18:53:34 +0530 Subject: [PATCH 17/31] test cases for solana chain --- starship/tests/e2e/solana_test.go | 423 ++++++++++++++++++++++++++++++ 1 file changed, 423 insertions(+) create mode 100644 starship/tests/e2e/solana_test.go diff --git a/starship/tests/e2e/solana_test.go b/starship/tests/e2e/solana_test.go new file mode 100644 index 000000000..0e46036fb --- /dev/null +++ b/starship/tests/e2e/solana_test.go @@ -0,0 +1,423 @@ +package e2e + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + "strconv" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/suite" +) + +// SolanaRPCResponse represents a generic Solana RPC response +type SolanaRPCResponse struct { + JSONRPC string `json:"jsonrpc"` + ID int `json:"id"` + Result interface{} `json:"result,omitempty"` + Error *struct { + Code int `json:"code"` + Message string `json:"message"` + } `json:"error,omitempty"` +} + +// SolanaSlotResponse represents the slot response +type SolanaSlotResponse struct { + JSONRPC string `json:"jsonrpc"` + ID int `json:"id"` + Result uint64 `json:"result"` +} + +// SolanaVoteAccountsResponse represents vote accounts response +type SolanaVoteAccountsResponse struct { + JSONRPC string `json:"jsonrpc"` + ID int `json:"id"` + Result struct { + Current []VoteAccount `json:"current"` + Delinquent []VoteAccount `json:"delinquent"` + } `json:"result"` +} + +// VoteAccount represents a vote account +type VoteAccount struct { + VotePubkey string `json:"votePubkey"` + NodePubkey string `json:"nodePubkey"` + ActivatedStake uint64 `json:"activatedStake"` + Commission int `json:"commission"` + LastVote uint64 `json:"lastVote"` + RootSlot uint64 `json:"rootSlot"` +} + +// SolanaClusterNodesResponse represents cluster nodes response +type SolanaClusterNodesResponse struct { + JSONRPC string `json:"jsonrpc"` + ID int `json:"id"` + Result []ClusterNode `json:"result"` +} + +// ClusterNode represents a cluster node +type ClusterNode struct { + Pubkey string `json:"pubkey"` + Gossip string `json:"gossip"` + TPU string `json:"tpu"` + TPUForwards string `json:"tpuForwards"` + TVU string `json:"tvu"` + RPC string `json:"rpc"` + Pubsub string `json:"pubsub"` + Version string `json:"version"` + FeatureSet uint32 `json:"featureSet"` + ShredVersion uint16 `json:"shredVersion"` +} + +// SolanaBalanceResponse represents balance response +type SolanaBalanceResponse struct { + JSONRPC string `json:"jsonrpc"` + ID int `json:"id"` + Result struct { + Context struct { + Slot uint64 `json:"slot"` + } `json:"context"` + Value uint64 `json:"value"` + } `json:"result"` +} + +// SolanaSignatureResponse represents signature response +type SolanaSignatureResponse struct { + JSONRPC string `json:"jsonrpc"` + ID int `json:"id"` + Result string `json:"result"` +} + +// SolanaExposerResponse represents exposer response +type SolanaExposerResponse struct { + NodeID string `json:"node_id"` +} + +func (s *TestSuite) MakeSolanaRPCRequest(method string, params []interface{}, response interface{}) { + // Get the Solana chain from config + var solanaChain *Chain + for _, chain := range s.config.Chains { + if chain.Name == "solana" { + solanaChain = chain + break + } + } + + if solanaChain == nil { + s.T().Skip("Solana chain not found in config") + } + + // Prepare RPC request + rpcRequest := map[string]interface{}{ + "jsonrpc": "2.0", + "id": 1, + "method": method, + "params": params, + } + + jsonData, err := json.Marshal(rpcRequest) + s.Require().NoError(err) + + // Make HTTP request to Solana RPC + url := fmt.Sprintf("http://0.0.0.0:%d", solanaChain.Ports.Rpc) + req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(jsonData)) + s.Require().NoError(err) + req.Header.Set("Content-Type", "application/json") + + body := s.MakeRequest(req, 200) + err = json.NewDecoder(body).Decode(response) + s.Require().NoError(err) +} + +func (s *TestSuite) MakeSolanaExposerRequest(endpoint string, response interface{}) { + // Get the Solana chain from config + var solanaChain *Chain + for _, chain := range s.config.Chains { + if chain.Name == "solana" { + solanaChain = chain + break + } + } + + if solanaChain == nil { + s.T().Skip("Solana chain not found in config") + } + + url := fmt.Sprintf("http://0.0.0.0:%d%s", solanaChain.Ports.Exposer, endpoint) + req, err := http.NewRequest(http.MethodGet, url, nil) + s.Require().NoError(err) + + body := s.MakeRequest(req, 200) + err = json.NewDecoder(body).Decode(response) + s.Require().NoError(err) +} + +func (s *TestSuite) TestSolana_Status() { + s.T().Log("running test for Solana RPC status") + + var response SolanaRPCResponse + s.MakeSolanaRPCRequest("getHealth", []interface{}{}, &response) + + // Check for RPC errors + s.Require().Nil(response.Error, "RPC should not return error") + s.Require().Equal("2.0", response.JSONRPC) + s.Require().Equal(1, response.ID) + s.Require().Equal("ok", response.Result) +} + +func (s *TestSuite) TestSolana_BlockHeight() { + s.T().Log("running test for Solana block height increasing") + + // Get initial slot + var initialResponse SolanaSlotResponse + s.MakeSolanaRPCRequest("getSlot", []interface{}{}, &initialResponse) + s.Require().Nil(initialResponse.Error, "RPC should not return error") + initialSlot := initialResponse.Result + + s.T().Logf("Initial slot: %d", initialSlot) + + // Wait for a few seconds to allow block progression + time.Sleep(5 * time.Second) + + // Get current slot + var currentResponse SolanaSlotResponse + s.MakeSolanaRPCRequest("getSlot", []interface{}{}, ¤tResponse) + s.Require().Nil(currentResponse.Error, "RPC should not return error") + currentSlot := currentResponse.Result + + s.T().Logf("Current slot: %d", currentSlot) + + // Assert that block height is increasing + s.Require().GreaterOrEqual(currentSlot, initialSlot, "Block height should be increasing") +} + +func (s *TestSuite) TestSolana_VoteAccounts() { + s.T().Log("running test for Solana vote accounts") + + var response SolanaVoteAccountsResponse + s.MakeSolanaRPCRequest("getVoteAccounts", []interface{}{}, &response) + + // Check for RPC errors + s.Require().Nil(response.Error, "RPC should not return error") + s.Require().Equal("2.0", response.JSONRPC) + s.Require().Equal(1, response.ID) + + // Assert that we have at least one vote account (bootstrap validator) + s.Require().GreaterOrEqual(len(response.Result.Current), 1, "Should have at least one active vote account") + + // Log vote account details + for i, account := range response.Result.Current { + s.T().Logf("Vote Account %d: %s (Node: %s, Stake: %d)", + i+1, account.VotePubkey, account.NodePubkey, account.ActivatedStake) + } +} + +func (s *TestSuite) TestSolana_ClusterNodes() { + s.T().Log("running test for Solana cluster nodes") + + var response SolanaClusterNodesResponse + s.MakeSolanaRPCRequest("getClusterNodes", []interface{}{}, &response) + + // Check for RPC errors + s.Require().Nil(response.Error, "RPC should not return error") + s.Require().Equal("2.0", response.JSONRPC) + s.Require().Equal(1, response.ID) + + // Assert that we have at least one node + s.Require().GreaterOrEqual(len(response.Result), 1, "Should have at least one cluster node") + + // Log cluster node details + for i, node := range response.Result { + s.T().Logf("Cluster Node %d: %s (Gossip: %s, RPC: %s, Version: %s)", + i+1, node.Pubkey, node.Gossip, node.RPC, node.Version) + } +} + +func (s *TestSuite) TestSolana_Faucet() { + s.T().Log("running test for Solana faucet via RPC") + + // Create a test address (you might want to generate a real keypair) + testAddress := "11111111111111111111111111111112" // System Program ID as test + + // Request airdrop + var airdropResponse SolanaSignatureResponse + s.MakeSolanaRPCRequest("requestAirdrop", []interface{}{testAddress, 1000000000}, &airdropResponse) + + // Check for RPC errors + s.Require().Nil(airdropResponse.Error, "RPC should not return error") + s.Require().Equal("2.0", airdropResponse.JSONRPC) + s.Require().Equal(1, airdropResponse.ID) + s.Require().NotEmpty(airdropResponse.Result, "Should return a transaction signature") + + s.T().Logf("Airdrop transaction signature: %s", airdropResponse.Result) + + // Wait for transaction confirmation + time.Sleep(2 * time.Second) + + // Check balance + var balanceResponse SolanaBalanceResponse + s.MakeSolanaRPCRequest("getBalance", []interface{}{testAddress}, &balanceResponse) + + // Check for RPC errors + s.Require().Nil(balanceResponse.Error, "RPC should not return error") + s.Require().Equal("2.0", balanceResponse.JSONRPC) + s.Require().Equal(1, balanceResponse.ID) + s.Require().GreaterOrEqual(balanceResponse.Result.Value, uint64(1000000000), "Balance should be at least 1 SOL") +} + +func (s *TestSuite) TestSolana_BankTransfer() { + s.T().Log("running test for Solana bank transfer") + + // This test would require creating keypairs and performing actual transfers + // For now, we'll test the transfer instruction creation + // In a real implementation, you'd need to: + // 1. Create source and destination keypairs + // 2. Fund the source account + // 3. Create and send transfer transaction + // 4. Verify the transfer + + s.T().Skip("Bank transfer test requires keypair generation and transaction signing - implement based on your needs") +} + +func (s *TestSuite) TestSolana_Exposer_NodeID() { + s.T().Log("running test for Solana exposer node ID") + + var response SolanaExposerResponse + s.MakeSolanaExposerRequest("/node_id", &response) + + // Assert that we get a valid node ID + s.Require().NotEmpty(response.NodeID, "Should return a valid node ID") + s.T().Logf("Node ID: %s", response.NodeID) +} + +func (s *TestSuite) TestSolana_Exposer_Genesis() { + s.T().Log("running test for Solana exposer genesis") + + // Get the Solana chain from config + var solanaChain *Chain + for _, chain := range s.config.Chains { + if chain.Name == "solana" { + solanaChain = chain + break + } + } + + if solanaChain == nil { + s.T().Skip("Solana chain not found in config") + } + + url := fmt.Sprintf("http://0.0.0.0:%d/genesis", solanaChain.Ports.Exposer) + req, err := http.NewRequest(http.MethodGet, url, nil) + s.Require().NoError(err) + + body := s.MakeRequest(req, 200) + + // Read the response as string to verify it's not empty + genesisData, err := io.ReadAll(body) + s.Require().NoError(err) + s.Require().NotEmpty(genesisData, "Genesis data should not be empty") + + s.T().Logf("Genesis data length: %d bytes", len(genesisData)) +} + +func (s *TestSuite) TestSolana_Exposer_Keys() { + s.T().Log("running test for Solana exposer keys") + + // Get the Solana chain from config + var solanaChain *Chain + for _, chain := range s.config.Chains { + if chain.Name == "solana" { + solanaChain = chain + break + } + } + + if solanaChain == nil { + s.T().Skip("Solana chain not found in config") + } + + url := fmt.Sprintf("http://0.0.0.0:%d/keys", solanaChain.Ports.Exposer) + req, err := http.NewRequest(http.MethodGet, url, nil) + s.Require().NoError(err) + + body := s.MakeRequest(req, 200) + + // Parse the keys response + var keysResponse map[string]interface{} + err = json.NewDecoder(body).Decode(&keysResponse) + s.Require().NoError(err) + + // Assert that we have keys data + s.Require().NotEmpty(keysResponse, "Should return keys data") + + s.T().Logf("Keys response: %+v", keysResponse) +} + +func (s *TestSuite) TestSolana_ValidatorCount() { + s.T().Log("running test for Solana validator count") + + var response SolanaVoteAccountsResponse + s.MakeSolanaRPCRequest("getVoteAccounts", []interface{}{}, &response) + + // Check for RPC errors + s.Require().Nil(response.Error, "RPC should not return error") + + currentValidators := len(response.Result.Current) + delinquentValidators := len(response.Result.Delinquent) + totalValidators := currentValidators + delinquentValidators + + s.T().Logf("Current validators: %d", currentValidators) + s.T().Logf("Delinquent validators: %d", delinquentValidators) + s.T().Logf("Total validators: %d", totalValidators) + + // Assert that we have at least the bootstrap validator + s.Require().GreaterOrEqual(currentValidators, 1, "Should have at least one current validator (bootstrap)") + + // If you have multiple validators configured, check for them + var solanaChain *Chain + for _, chain := range s.config.Chains { + if chain.Name == "solana" { + solanaChain = chain + break + } + } + + if solanaChain != nil && solanaChain.NumValidators > 1 { + expectedValidators := solanaChain.NumValidators + s.Require().GreaterOrEqual(totalValidators, expectedValidators, + fmt.Sprintf("Should have at least %d validators", expectedValidators)) + } +} + +func (s *TestSuite) TestSolana_NetworkHealth() { + s.T().Log("running test for Solana network health") + + // Test multiple health indicators + tests := []struct { + name string + method string + params []interface{} + }{ + {"Health", "getHealth", []interface{}{}}, + {"Slot", "getSlot", []interface{}{}}, + {"Cluster Nodes", "getClusterNodes", []interface{}{}}, + {"Vote Accounts", "getVoteAccounts", []interface{}{}}, + } + + for _, test := range tests { + s.Run(test.name, func() { + var response SolanaRPCResponse + s.MakeSolanaRPCRequest(test.method, test.params, &response) + + // Check for RPC errors + s.Require().Nil(response.Error, fmt.Sprintf("%s should not return error", test.name)) + s.Require().Equal("2.0", response.JSONRPC) + s.Require().Equal(1, response.ID) + s.Require().NotNil(response.Result, fmt.Sprintf("%s should return result", test.name)) + }) + } +} \ No newline at end of file From 9401ebaa08f58f68315dafc3c264fb87ac3981c7 Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Mon, 4 Aug 2025 20:23:05 +0530 Subject: [PATCH 18/31] add test for the solana chain --- starship/scripts/port-forward.sh | 17 ++- starship/tests/e2e/configs/solana.yaml | 1 + starship/tests/e2e/solana_test.go | 201 ++++++++----------------- 3 files changed, 73 insertions(+), 146 deletions(-) diff --git a/starship/scripts/port-forward.sh b/starship/scripts/port-forward.sh index ad92594e4..f1be7d5ed 100755 --- a/starship/scripts/port-forward.sh +++ b/starship/scripts/port-forward.sh @@ -30,6 +30,7 @@ CHAIN_FAUCET_PORT=8000 SOLANA_RPC_PORT=8899 SOLANA_WS_PORT=8900 SOLANA_FAUCET_PORT=9900 +SOLANA_EXPOSER_PORT=8081 ETHEREUM_REST_PORT=8545 ETHEREUM_RPC_PORT=8551 RELAYER_REST_PORT=3000 @@ -77,16 +78,20 @@ if [[ $num_chains -gt -1 ]]; then kubectl port-forward pods/$chain_name-$chain-0 $localrest:$ETHEREUM_REST_PORT > /dev/null 2>&1 & kubectl port-forward pods/$chain_name-$chain-0 $localrpc:$ETHEREUM_RPC_PORT > /dev/null 2>&1 & elif [[ "$chain_name" == *"solana"* ]]; then - localrpc=$SOLANA_RPC_PORT - localws=$SOLANA_WS_PORT - localfaucet=$SOLANA_FAUCET_PORT + localrpc=$(yq -r ".chains[$i].ports.rpc" ${CONFIGFILE} ) + localws=$(yq -r ".chains[$i].ports.ws" ${CONFIGFILE} ) + localfaucet=$(yq -r ".chains[$i].ports.faucet" ${CONFIGFILE} ) + localexposer=$(yq -r ".chains[$i].ports.exposer" ${CONFIGFILE} ) color yellow "Solana chain detected: $chain" color yellow " Forwarding RPC: http://localhost:$localrpc" color yellow " Forwarding WS: http://localhost:$localws" color yellow " Forwarding Faucet: http://localhost:$localfaucet" - kubectl port-forward pods/$chain_name-$chain-0 $localrpc:$SOLANA_RPC_PORT > /dev/null 2>&1 & - kubectl port-forward pods/$chain_name-$chain-0 $localws:$SOLANA_WS_PORT > /dev/null 2>&1 & - kubectl port-forward pods/$chain_name-$chain-0 $localfaucet:$SOLANA_FAUCET_PORT > /dev/null 2>&1 & + color yellow " Forwarding Exposer: http://localhost:$localexposer" + # For Solana, use the genesis pod for RPC and faucet + kubectl port-forward pods/$chain-genesis-0 $localrpc:$SOLANA_RPC_PORT > /dev/null 2>&1 & + kubectl port-forward pods/$chain-genesis-0 $localws:$SOLANA_WS_PORT > /dev/null 2>&1 & + kubectl port-forward pods/$chain-genesis-0 $localfaucet:$SOLANA_FAUCET_PORT > /dev/null 2>&1 & + kubectl port-forward pods/$chain-genesis-0 $localexposer:$SOLANA_EXPOSER_PORT > /dev/null 2>&1 & sleep 1 else localrpc=$(yq -r ".chains[$i].ports.rpc" ${CONFIGFILE} ) diff --git a/starship/tests/e2e/configs/solana.yaml b/starship/tests/e2e/configs/solana.yaml index 19ee0e9d2..f9e405607 100644 --- a/starship/tests/e2e/configs/solana.yaml +++ b/starship/tests/e2e/configs/solana.yaml @@ -8,6 +8,7 @@ chains: ports: rpc: 8899 ws: 8900 + exposer: 8001 faucet: 9900 resources: cpu: 2000m diff --git a/starship/tests/e2e/solana_test.go b/starship/tests/e2e/solana_test.go index 0e46036fb..d90eca61f 100644 --- a/starship/tests/e2e/solana_test.go +++ b/starship/tests/e2e/solana_test.go @@ -4,14 +4,8 @@ import ( "bytes" "encoding/json" "fmt" - "io" "net/http" - "strconv" - "strings" - "testing" "time" - - "github.com/stretchr/testify/suite" ) // SolanaRPCResponse represents a generic Solana RPC response @@ -25,23 +19,6 @@ type SolanaRPCResponse struct { } `json:"error,omitempty"` } -// SolanaSlotResponse represents the slot response -type SolanaSlotResponse struct { - JSONRPC string `json:"jsonrpc"` - ID int `json:"id"` - Result uint64 `json:"result"` -} - -// SolanaVoteAccountsResponse represents vote accounts response -type SolanaVoteAccountsResponse struct { - JSONRPC string `json:"jsonrpc"` - ID int `json:"id"` - Result struct { - Current []VoteAccount `json:"current"` - Delinquent []VoteAccount `json:"delinquent"` - } `json:"result"` -} - // VoteAccount represents a vote account type VoteAccount struct { VotePubkey string `json:"votePubkey"` @@ -52,13 +29,6 @@ type VoteAccount struct { RootSlot uint64 `json:"rootSlot"` } -// SolanaClusterNodesResponse represents cluster nodes response -type SolanaClusterNodesResponse struct { - JSONRPC string `json:"jsonrpc"` - ID int `json:"id"` - Result []ClusterNode `json:"result"` -} - // ClusterNode represents a cluster node type ClusterNode struct { Pubkey string `json:"pubkey"` @@ -73,25 +43,6 @@ type ClusterNode struct { ShredVersion uint16 `json:"shredVersion"` } -// SolanaBalanceResponse represents balance response -type SolanaBalanceResponse struct { - JSONRPC string `json:"jsonrpc"` - ID int `json:"id"` - Result struct { - Context struct { - Slot uint64 `json:"slot"` - } `json:"context"` - Value uint64 `json:"value"` - } `json:"result"` -} - -// SolanaSignatureResponse represents signature response -type SolanaSignatureResponse struct { - JSONRPC string `json:"jsonrpc"` - ID int `json:"id"` - Result string `json:"result"` -} - // SolanaExposerResponse represents exposer response type SolanaExposerResponse struct { NodeID string `json:"node_id"` @@ -159,37 +110,52 @@ func (s *TestSuite) MakeSolanaExposerRequest(endpoint string, response interface func (s *TestSuite) TestSolana_Status() { s.T().Log("running test for Solana RPC status") - var response SolanaRPCResponse - s.MakeSolanaRPCRequest("getHealth", []interface{}{}, &response) + // Get the Solana chain from config + var solanaChain *Chain + for _, chain := range s.config.Chains { + if chain.Name == "solana" { + solanaChain = chain + break + } + } + + if solanaChain == nil { + s.T().Skip("Solana chain not found in config") + } - // Check for RPC errors - s.Require().Nil(response.Error, "RPC should not return error") - s.Require().Equal("2.0", response.JSONRPC) - s.Require().Equal(1, response.ID) - s.Require().Equal("ok", response.Result) + s.Run("solana health check", func() { + var response SolanaRPCResponse + s.MakeSolanaRPCRequest("getHealth", []interface{}{}, &response) + + // Check for RPC errors + s.Require().Nil(response.Error, "RPC should not return error") + s.Require().Equal("2.0", response.JSONRPC) + s.Require().Equal(1, response.ID) + s.Require().Equal("ok", response.Result) + }) } func (s *TestSuite) TestSolana_BlockHeight() { s.T().Log("running test for Solana block height increasing") // Get initial slot - var initialResponse SolanaSlotResponse + var initialResponse SolanaRPCResponse s.MakeSolanaRPCRequest("getSlot", []interface{}{}, &initialResponse) s.Require().Nil(initialResponse.Error, "RPC should not return error") - initialSlot := initialResponse.Result + initialSlot := initialResponse.Result.(float64) - s.T().Logf("Initial slot: %d", initialSlot) + s.T().Logf("Initial slot: %v", initialSlot) // Wait for a few seconds to allow block progression time.Sleep(5 * time.Second) // Get current slot - var currentResponse SolanaSlotResponse + var currentResponse SolanaRPCResponse s.MakeSolanaRPCRequest("getSlot", []interface{}{}, ¤tResponse) s.Require().Nil(currentResponse.Error, "RPC should not return error") - currentSlot := currentResponse.Result + currentSlot := currentResponse.Result.(float64) - s.T().Logf("Current slot: %d", currentSlot) + s.T().Logf("Current slot: %v", currentSlot) // Assert that block height is increasing s.Require().GreaterOrEqual(currentSlot, initialSlot, "Block height should be increasing") @@ -198,7 +164,7 @@ func (s *TestSuite) TestSolana_BlockHeight() { func (s *TestSuite) TestSolana_VoteAccounts() { s.T().Log("running test for Solana vote accounts") - var response SolanaVoteAccountsResponse + var response SolanaRPCResponse s.MakeSolanaRPCRequest("getVoteAccounts", []interface{}{}, &response) // Check for RPC errors @@ -206,20 +172,25 @@ func (s *TestSuite) TestSolana_VoteAccounts() { s.Require().Equal("2.0", response.JSONRPC) s.Require().Equal(1, response.ID) + // Parse the result + result := response.Result.(map[string]interface{}) + current := result["current"].([]interface{}) + // Assert that we have at least one vote account (bootstrap validator) - s.Require().GreaterOrEqual(len(response.Result.Current), 1, "Should have at least one active vote account") + s.Require().GreaterOrEqual(len(current), 1, "Should have at least one active vote account") // Log vote account details - for i, account := range response.Result.Current { - s.T().Logf("Vote Account %d: %s (Node: %s, Stake: %d)", - i+1, account.VotePubkey, account.NodePubkey, account.ActivatedStake) + for i, account := range current { + acc := account.(map[string]interface{}) + s.T().Logf("Vote Account %d: %s (Node: %s, Stake: %v)", + i+1, acc["votePubkey"], acc["nodePubkey"], acc["activatedStake"]) } } func (s *TestSuite) TestSolana_ClusterNodes() { s.T().Log("running test for Solana cluster nodes") - var response SolanaClusterNodesResponse + var response SolanaRPCResponse s.MakeSolanaRPCRequest("getClusterNodes", []interface{}{}, &response) // Check for RPC errors @@ -227,13 +198,17 @@ func (s *TestSuite) TestSolana_ClusterNodes() { s.Require().Equal("2.0", response.JSONRPC) s.Require().Equal(1, response.ID) + // Parse the result + nodes := response.Result.([]interface{}) + // Assert that we have at least one node - s.Require().GreaterOrEqual(len(response.Result), 1, "Should have at least one cluster node") + s.Require().GreaterOrEqual(len(nodes), 1, "Should have at least one cluster node") // Log cluster node details - for i, node := range response.Result { + for i, node := range nodes { + n := node.(map[string]interface{}) s.T().Logf("Cluster Node %d: %s (Gossip: %s, RPC: %s, Version: %s)", - i+1, node.Pubkey, node.Gossip, node.RPC, node.Version) + i+1, n["pubkey"], n["gossip"], n["rpc"], n["version"]) } } @@ -244,7 +219,7 @@ func (s *TestSuite) TestSolana_Faucet() { testAddress := "11111111111111111111111111111112" // System Program ID as test // Request airdrop - var airdropResponse SolanaSignatureResponse + var airdropResponse SolanaRPCResponse s.MakeSolanaRPCRequest("requestAirdrop", []interface{}{testAddress, 1000000000}, &airdropResponse) // Check for RPC errors @@ -259,14 +234,18 @@ func (s *TestSuite) TestSolana_Faucet() { time.Sleep(2 * time.Second) // Check balance - var balanceResponse SolanaBalanceResponse + var balanceResponse SolanaRPCResponse s.MakeSolanaRPCRequest("getBalance", []interface{}{testAddress}, &balanceResponse) // Check for RPC errors s.Require().Nil(balanceResponse.Error, "RPC should not return error") s.Require().Equal("2.0", balanceResponse.JSONRPC) s.Require().Equal(1, balanceResponse.ID) - s.Require().GreaterOrEqual(balanceResponse.Result.Value, uint64(1000000000), "Balance should be at least 1 SOL") + + // Parse balance result + balanceResult := balanceResponse.Result.(map[string]interface{}) + balance := balanceResult["value"].(float64) + s.Require().GreaterOrEqual(balance, float64(1000000000), "Balance should be at least 1 SOL") } func (s *TestSuite) TestSolana_BankTransfer() { @@ -294,80 +273,22 @@ func (s *TestSuite) TestSolana_Exposer_NodeID() { s.T().Logf("Node ID: %s", response.NodeID) } -func (s *TestSuite) TestSolana_Exposer_Genesis() { - s.T().Log("running test for Solana exposer genesis") - - // Get the Solana chain from config - var solanaChain *Chain - for _, chain := range s.config.Chains { - if chain.Name == "solana" { - solanaChain = chain - break - } - } - - if solanaChain == nil { - s.T().Skip("Solana chain not found in config") - } - - url := fmt.Sprintf("http://0.0.0.0:%d/genesis", solanaChain.Ports.Exposer) - req, err := http.NewRequest(http.MethodGet, url, nil) - s.Require().NoError(err) - - body := s.MakeRequest(req, 200) - - // Read the response as string to verify it's not empty - genesisData, err := io.ReadAll(body) - s.Require().NoError(err) - s.Require().NotEmpty(genesisData, "Genesis data should not be empty") - - s.T().Logf("Genesis data length: %d bytes", len(genesisData)) -} - -func (s *TestSuite) TestSolana_Exposer_Keys() { - s.T().Log("running test for Solana exposer keys") - - // Get the Solana chain from config - var solanaChain *Chain - for _, chain := range s.config.Chains { - if chain.Name == "solana" { - solanaChain = chain - break - } - } - - if solanaChain == nil { - s.T().Skip("Solana chain not found in config") - } - - url := fmt.Sprintf("http://0.0.0.0:%d/keys", solanaChain.Ports.Exposer) - req, err := http.NewRequest(http.MethodGet, url, nil) - s.Require().NoError(err) - - body := s.MakeRequest(req, 200) - - // Parse the keys response - var keysResponse map[string]interface{} - err = json.NewDecoder(body).Decode(&keysResponse) - s.Require().NoError(err) - - // Assert that we have keys data - s.Require().NotEmpty(keysResponse, "Should return keys data") - - s.T().Logf("Keys response: %+v", keysResponse) -} - func (s *TestSuite) TestSolana_ValidatorCount() { s.T().Log("running test for Solana validator count") - var response SolanaVoteAccountsResponse + var response SolanaRPCResponse s.MakeSolanaRPCRequest("getVoteAccounts", []interface{}{}, &response) // Check for RPC errors s.Require().Nil(response.Error, "RPC should not return error") - currentValidators := len(response.Result.Current) - delinquentValidators := len(response.Result.Delinquent) + // Parse the result + result := response.Result.(map[string]interface{}) + current := result["current"].([]interface{}) + delinquent := result["delinquent"].([]interface{}) + + currentValidators := len(current) + delinquentValidators := len(delinquent) totalValidators := currentValidators + delinquentValidators s.T().Logf("Current validators: %d", currentValidators) From a8d0f556842384508f10f93c098585251f633f6b Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Tue, 5 Aug 2025 12:54:03 +0530 Subject: [PATCH 19/31] get solana test to work --- starship/tests/e2e/e2e_test.go | 6 +++--- starship/tests/e2e/exposer_test.go | 19 +++++++++++++++++-- starship/tests/e2e/faucet_test.go | 9 +++++++++ starship/tests/e2e/registry_test.go | 18 ++++++++++++++++++ 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/starship/tests/e2e/e2e_test.go b/starship/tests/e2e/e2e_test.go index 4d11f4970..1c04cbccb 100644 --- a/starship/tests/e2e/e2e_test.go +++ b/starship/tests/e2e/e2e_test.go @@ -66,7 +66,7 @@ func (s *TestSuite) TestChains_Status() { s.T().Log("running test for /status endpoint for each chain") for _, chain := range s.config.Chains { - if chain.Name == "neutron" || chain.Name == "ethereum" { + if chain.Name == "neutron" || chain.Name == "ethereum" || chain.Name == "solana" { s.T().Skip("skip tests for neutron") } url := fmt.Sprintf("http://0.0.0.0:%d/status", chain.Ports.Rpc) @@ -88,7 +88,7 @@ func (s *TestSuite) TestChains_StakingParams() { s.T().Skip("skip staking params test for non rest endpoint") } s.T().Log("running test for /staking/parameters endpoint for each chain") - if s.config.Chains[0].Name == "neutron" || s.config.Chains[0].Name == "ethereum" { + if s.config.Chains[0].Name == "neutron" || s.config.Chains[0].Name == "ethereum" || s.config.Chains[0].Name == "solana" { s.T().Skip("skip tests for neutron") } @@ -176,7 +176,7 @@ func (s *TestSuite) TestChainsEth_Block() { s.T().Log("Running test for eth_blockNumber endpoint") for _, chain := range s.config.Chains { - if !strings.HasPrefix(chain.Name, "ethereum") { + if !strings.HasPrefix(chain.Name, "ethereum") || chain.Name == "solana" { continue } diff --git a/starship/tests/e2e/exposer_test.go b/starship/tests/e2e/exposer_test.go index 46dc01174..c23285836 100644 --- a/starship/tests/e2e/exposer_test.go +++ b/starship/tests/e2e/exposer_test.go @@ -48,9 +48,12 @@ func (s *TestSuite) TestExposer_GetGenesisFile() { s.T().Log("running test for /genesis endpoint for exposer") chain := s.config.Chains[0] - if chain.Ports.Exposer == 0 { + if chain.Ports.Exposer == 0{ s.T().Skip("skipping /node_id test since no exposer") } + if chain.Name == "solana" { + s.T().Skip("skipping /genesis test since solana exposer is not supported") + } req, err := http.NewRequest(http.MethodGet, "/genesis", nil) s.Require().NoError(err) @@ -74,6 +77,9 @@ func (s *TestSuite) TestExposer_GetPubKey() { if chain.Cometmock != nil && chain.Cometmock.Enabled { s.T().Skip("skipping tests for cometmock enabled chain") } + if chain.Name == "solana" { + s.T().Skip("skipping /genesis test since solana exposer is not supported") + } req, err := http.NewRequest(http.MethodGet, "/pub_key", nil) s.Require().NoError(err) @@ -94,6 +100,9 @@ func (s *TestSuite) TestExposer_GetPrivKey() { if chain.Ports.Exposer == 0 { s.T().Skip("skipping /node_id test since no exposer") } + if chain.Name == "solana" { + s.T().Skip("skipping /genesis test since solana exposer is not supported") + } req, err := http.NewRequest(http.MethodGet, "/priv_keys", nil) s.Require().NoError(err) @@ -114,6 +123,9 @@ func (s *TestSuite) TestExposer_GetPrivValState() { if chain.Ports.Exposer == 0 { s.T().Skip("skipping /node_id test since no exposer") } + if chain.Name == "solana" { + s.T().Skip("skipping /genesis test since solana exposer is not supported") + } req, err := http.NewRequest(http.MethodGet, "/priv_validator_state", nil) s.Require().NoError(err) @@ -131,7 +143,7 @@ func (s *TestSuite) TestExposer_GetNodeKey() { chain := s.config.Chains[0] if chain.Ports.Exposer == 0 { - s.T().Skip("skipping /node_id test since no exposer") + s.T().Skip("skipping /node_key test since no exposer") } req, err := http.NewRequest(http.MethodGet, "/node_key", nil) @@ -152,6 +164,9 @@ func (s *TestSuite) TestExposer_GetKeys() { if chain.Ports.Exposer == 0 { s.T().Skip("skipping /node_id test since no exposer") } + if chain.Name == "solana" { + s.T().Skip("skipping /genesis test since solana exposer is not supported") + } req, err := http.NewRequest(http.MethodGet, "/keys", nil) s.Require().NoError(err) diff --git a/starship/tests/e2e/faucet_test.go b/starship/tests/e2e/faucet_test.go index d54b17912..8fabb584b 100644 --- a/starship/tests/e2e/faucet_test.go +++ b/starship/tests/e2e/faucet_test.go @@ -34,6 +34,9 @@ func (s *TestSuite) TestFaucet_Status() { if chain.Ports.Faucet == 0 { s.T().Skip("faucet not exposed via ports") } + if chain.Name == "solana" { + s.T().Skip("skipping /status test since solana faucet is not supported") + } req, err := http.NewRequest(http.MethodGet, "/status", nil) s.Require().NoError(err) @@ -157,6 +160,9 @@ func (s *TestSuite) TestFaucet_Credit() { if chain.Ports.Faucet == 0 { s.T().Skip("faucet not exposed via ports") } + if chain.Name == "solana" { + s.T().Skip("skipping /credit test since solana faucet is not supported") + } // fetch denom and address from an account on chain denom := s.getChainDenoms(chain) @@ -186,6 +192,9 @@ func (s *TestSuite) TestFaucet_Credit_MultipleRequests() { if chain.Ports.Faucet == 0 { s.T().Skip("faucet not exposed via ports") } + if chain.Name == "solana" { + s.T().Skip("skipping /credit test since solana faucet is not supported") + } // fetch denom and address from an account on chain denom := s.getChainDenoms(chain) diff --git a/starship/tests/e2e/registry_test.go b/starship/tests/e2e/registry_test.go index 0208cdb31..484962348 100644 --- a/starship/tests/e2e/registry_test.go +++ b/starship/tests/e2e/registry_test.go @@ -46,6 +46,9 @@ func (s *TestSuite) TestRegistry_ListChains() { if s.config.Registry == nil || !s.config.Registry.Enabled { s.T().Skip("registry not enabled") } + if s.config.Chains[0].Name == "solana" { + s.T().Skip("skipping /chains test since solana registry is not supported") + } s.T().Log("running test for /chains endpoint for registry") req, err := http.NewRequest(http.MethodGet, "/chains", nil) @@ -73,6 +76,9 @@ func (s *TestSuite) TestRegistry_GetChain() { if s.config.Registry == nil || !s.config.Registry.Enabled { s.T().Skip("registry not enabled") } + if s.config.Chains[0].Name == "solana" { + s.T().Skip("skipping /chains test since solana registry is not supported") + } s.T().Log("running test for /chains/{chain} endpoint for registry") for _, chain := range s.config.Chains { @@ -109,6 +115,9 @@ func (s *TestSuite) TestRegistry_ListChainPeers() { if s.config.Registry == nil || !s.config.Registry.Enabled { s.T().Skip("registry not enabled") } + if s.config.Chains[0].Name == "solana" { + s.T().Skip("skipping /chains/{chain}/peers test since solana registry is not supported") + } s.T().Log("running test for /chains/{chain}/peers endpoint for registry") for _, chain := range s.config.Chains { @@ -127,6 +136,9 @@ func (s *TestSuite) TestRegistry_ListChainApis() { if s.config.Registry == nil || !s.config.Registry.Enabled { s.T().Skip("registry not enabled") } + if s.config.Chains[0].Name == "solana" { + s.T().Skip("skipping /chains/{chain}/apis test since solana registry is not supported") + } s.T().Log("running test for /chains/{chain}/apis endpoint for registry") for _, chain := range s.config.Chains { @@ -155,6 +167,9 @@ func (s *TestSuite) TestRegistry_GetChainAssets() { if s.config.Registry == nil || !s.config.Registry.Enabled { s.T().Skip("registry not enabled") } + if s.config.Chains[0].Name == "solana" { + s.T().Skip("skipping /chains/{chain}/assets test since solana registry is not supported") + } s.T().Log("running test for /chains/{chain}/assets endpoint for registry") expectedAssets := map[string]int{ @@ -302,6 +317,9 @@ func (s *TestSuite) TestRegistry_GetChainKeys() { if s.config.Registry == nil || !s.config.Registry.Enabled { s.T().Skip("registry not enabled") } + if s.config.Chains[0].Name == "solana" { + s.T().Skip("skipping /chains/{chain}/keys test since solana registry is not supported") + } s.T().Log("running test for /chains/{chain}/keys endpoint for registry") for _, chain := range s.config.Chains { From 84d7f741e27826ab312e1fa7a722b9f1fde2470f Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Tue, 5 Aug 2025 12:57:14 +0530 Subject: [PATCH 20/31] add solana-lite to e2e tests and in the ci --- .github/workflows/pr-tests.yaml | 1 + starship/tests/e2e/configs/solana-lite.yaml | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 starship/tests/e2e/configs/solana-lite.yaml diff --git a/.github/workflows/pr-tests.yaml b/.github/workflows/pr-tests.yaml index 572883bb9..cf4314b03 100644 --- a/.github/workflows/pr-tests.yaml +++ b/.github/workflows/pr-tests.yaml @@ -45,6 +45,7 @@ jobs: - "one-chain-cometmock.yaml" - "one-cosmoshub-cosmjs-faucet.yaml" - "eth-lite.yaml" + - "solana-lite.yaml" fail-fast: true max-parallel: 3 diff --git a/starship/tests/e2e/configs/solana-lite.yaml b/starship/tests/e2e/configs/solana-lite.yaml new file mode 100644 index 000000000..78261f691 --- /dev/null +++ b/starship/tests/e2e/configs/solana-lite.yaml @@ -0,0 +1,19 @@ +name: starship-e2e-tests +version: 1.7.0 + +chains: +- id: solana + name: solana + numValidators: 1 + ports: + rpc: 8899 + ws: 8900 + exposer: 8001 + faucet: 9900 + resources: + cpu: 1200m + memory: 1200Mi + +exposer: + cpu: 100m + memory: 100Mi From 4ec5136b42316e7fa24c0f70ab86f82f79a7602e Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Tue, 5 Aug 2025 14:14:42 +0530 Subject: [PATCH 21/31] update the resources for the solana-lite example --- starship/tests/e2e/configs/solana-lite.yaml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/starship/tests/e2e/configs/solana-lite.yaml b/starship/tests/e2e/configs/solana-lite.yaml index 78261f691..af212762c 100644 --- a/starship/tests/e2e/configs/solana-lite.yaml +++ b/starship/tests/e2e/configs/solana-lite.yaml @@ -15,5 +15,11 @@ chains: memory: 1200Mi exposer: - cpu: 100m - memory: 100Mi + resources: + cpu: 100m + memory: 100Mi + +faucet: + resources: + cpu: 100m + memory: 100Mi From b92feca98b19c338674ad2e621f7d1e19ef85054 Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Tue, 5 Aug 2025 14:38:23 +0530 Subject: [PATCH 22/31] update resources of the faucet --- starship/tests/e2e/configs/solana-lite.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/starship/tests/e2e/configs/solana-lite.yaml b/starship/tests/e2e/configs/solana-lite.yaml index af212762c..1cd170be8 100644 --- a/starship/tests/e2e/configs/solana-lite.yaml +++ b/starship/tests/e2e/configs/solana-lite.yaml @@ -21,5 +21,5 @@ exposer: faucet: resources: - cpu: 100m - memory: 100Mi + cpu: 200m + memory: 200Mi From 08756fad1e23e13b68a69c4e9d3fea08f141373c Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Tue, 5 Aug 2025 14:38:44 +0530 Subject: [PATCH 23/31] try to increase resources of the main node --- starship/tests/e2e/configs/solana-lite.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/starship/tests/e2e/configs/solana-lite.yaml b/starship/tests/e2e/configs/solana-lite.yaml index 1cd170be8..c074037cf 100644 --- a/starship/tests/e2e/configs/solana-lite.yaml +++ b/starship/tests/e2e/configs/solana-lite.yaml @@ -11,8 +11,8 @@ chains: exposer: 8001 faucet: 9900 resources: - cpu: 1200m - memory: 1200Mi + cpu: 1500m + memory: 1500Mi exposer: resources: From b9d60d76b8e794ad2f2f163f9f6a768dbecd6f7b Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Tue, 5 Aug 2025 15:30:50 +0530 Subject: [PATCH 24/31] add solana chain to the port forwarding logic --- packages/packages/client/src/client.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/packages/client/src/client.ts b/packages/packages/client/src/client.ts index 61b816ec0..824d86cdc 100644 --- a/packages/packages/client/src/client.ts +++ b/packages/packages/client/src/client.ts @@ -74,6 +74,12 @@ const defaultPorts: PodPorts = { rest: 8545, ws: 8546 }, + solana: { + rpc: 8899, + ws: 8900, + exposer: 8081, + faucet: 8000 + }, defaultPorts: { rpc: 26657, grpc: 9090, From fd75b9be7abf6583f90d4713658c6c6f5ce048ce Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Tue, 19 Aug 2025 12:00:19 +0400 Subject: [PATCH 25/31] update the client for solana chain --- packages/packages/client/src/client.ts | 2 +- starship/scripts/port-forward.sh | 2 +- starship/tests/e2e/configs/solana.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/packages/client/src/client.ts b/packages/packages/client/src/client.ts index 824d86cdc..a263c0f47 100644 --- a/packages/packages/client/src/client.ts +++ b/packages/packages/client/src/client.ts @@ -78,7 +78,7 @@ const defaultPorts: PodPorts = { rpc: 8899, ws: 8900, exposer: 8081, - faucet: 8000 + faucet: 9900 }, defaultPorts: { rpc: 26657, diff --git a/starship/scripts/port-forward.sh b/starship/scripts/port-forward.sh index f1be7d5ed..bd62b42d1 100755 --- a/starship/scripts/port-forward.sh +++ b/starship/scripts/port-forward.sh @@ -30,7 +30,7 @@ CHAIN_FAUCET_PORT=8000 SOLANA_RPC_PORT=8899 SOLANA_WS_PORT=8900 SOLANA_FAUCET_PORT=9900 -SOLANA_EXPOSER_PORT=8081 +SOLANA_EXPOSER_PORT=8001 ETHEREUM_REST_PORT=8545 ETHEREUM_RPC_PORT=8551 RELAYER_REST_PORT=3000 diff --git a/starship/tests/e2e/configs/solana.yaml b/starship/tests/e2e/configs/solana.yaml index f9e405607..f985330b0 100644 --- a/starship/tests/e2e/configs/solana.yaml +++ b/starship/tests/e2e/configs/solana.yaml @@ -8,7 +8,7 @@ chains: ports: rpc: 8899 ws: 8900 - exposer: 8001 + exposer: 8081 faucet: 9900 resources: cpu: 2000m From d1dbd325fd23579a4007126d79afaf80f447f1a5 Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Tue, 19 Aug 2025 12:04:53 +0400 Subject: [PATCH 26/31] update clean to not remove test output, create new clean:test command to cleanup test output specifically --- packages/packages/generator/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/packages/generator/package.json b/packages/packages/generator/package.json index 888fe302b..d678234d7 100644 --- a/packages/packages/generator/package.json +++ b/packages/packages/generator/package.json @@ -21,7 +21,8 @@ }, "scripts": { "copy": "copyfiles -f ../../LICENSE README.md package.json dist", - "clean": "del dist/**; del __tests__/__output__/**", + "clean": "del dist/**", + "clean:test": "del __tests__/__output__/**", "prepare": "npm run build", "build": "npm run clean; tsc; tsc -p tsconfig.esm.json; npm run copy", "dev": "ts-node src/index", From 22dbb59821b3bc6b0319c03db48aed2f3ff99a56 Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Tue, 19 Aug 2025 12:24:56 +0400 Subject: [PATCH 27/31] sleep more --- starship/tests/e2e/configs/solana.yaml | 2 +- starship/tests/e2e/solana_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/starship/tests/e2e/configs/solana.yaml b/starship/tests/e2e/configs/solana.yaml index f985330b0..f9e405607 100644 --- a/starship/tests/e2e/configs/solana.yaml +++ b/starship/tests/e2e/configs/solana.yaml @@ -8,7 +8,7 @@ chains: ports: rpc: 8899 ws: 8900 - exposer: 8081 + exposer: 8001 faucet: 9900 resources: cpu: 2000m diff --git a/starship/tests/e2e/solana_test.go b/starship/tests/e2e/solana_test.go index d90eca61f..826a2f9c5 100644 --- a/starship/tests/e2e/solana_test.go +++ b/starship/tests/e2e/solana_test.go @@ -231,7 +231,7 @@ func (s *TestSuite) TestSolana_Faucet() { s.T().Logf("Airdrop transaction signature: %s", airdropResponse.Result) // Wait for transaction confirmation - time.Sleep(2 * time.Second) + time.Sleep(5 * time.Second) // Check balance var balanceResponse SolanaRPCResponse From a94c20c844933ece72b6b10ce17599a060602fa8 Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Tue, 19 Aug 2025 12:51:55 +0400 Subject: [PATCH 28/31] add sleep before txn as well --- starship/tests/e2e/solana_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/starship/tests/e2e/solana_test.go b/starship/tests/e2e/solana_test.go index 826a2f9c5..741de3a24 100644 --- a/starship/tests/e2e/solana_test.go +++ b/starship/tests/e2e/solana_test.go @@ -218,6 +218,9 @@ func (s *TestSuite) TestSolana_Faucet() { // Create a test address (you might want to generate a real keypair) testAddress := "11111111111111111111111111111112" // System Program ID as test + // Wait for transaction confirmation + time.Sleep(10 * time.Second) + // Request airdrop var airdropResponse SolanaRPCResponse s.MakeSolanaRPCRequest("requestAirdrop", []interface{}{testAddress, 1000000000}, &airdropResponse) From 003a0d0c48feeec278f42a55220b746672bafa24 Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Tue, 19 Aug 2025 13:22:37 +0400 Subject: [PATCH 29/31] add more timeout --- starship/tests/e2e/solana_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/starship/tests/e2e/solana_test.go b/starship/tests/e2e/solana_test.go index 741de3a24..32e05e9b9 100644 --- a/starship/tests/e2e/solana_test.go +++ b/starship/tests/e2e/solana_test.go @@ -234,7 +234,7 @@ func (s *TestSuite) TestSolana_Faucet() { s.T().Logf("Airdrop transaction signature: %s", airdropResponse.Result) // Wait for transaction confirmation - time.Sleep(5 * time.Second) + time.Sleep(15 * time.Second) // Check balance var balanceResponse SolanaRPCResponse From 6ff0e6c258d4fddd6bbf62842f118a27edafc549 Mon Sep 17 00:00:00 2001 From: Anmol Date: Tue, 19 Aug 2025 14:30:26 +0400 Subject: [PATCH 30/31] Update starship/tests/e2e/e2e_test.go --- starship/tests/e2e/e2e_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/starship/tests/e2e/e2e_test.go b/starship/tests/e2e/e2e_test.go index 1c04cbccb..30c9c972f 100644 --- a/starship/tests/e2e/e2e_test.go +++ b/starship/tests/e2e/e2e_test.go @@ -176,7 +176,7 @@ func (s *TestSuite) TestChainsEth_Block() { s.T().Log("Running test for eth_blockNumber endpoint") for _, chain := range s.config.Chains { - if !strings.HasPrefix(chain.Name, "ethereum") || chain.Name == "solana" { + if !strings.HasPrefix(chain.Name, "ethereum") { continue } From 8047d9fec013a7d1f3561f095bd9bce106aa3863 Mon Sep 17 00:00:00 2001 From: Anmol1696 Date: Tue, 19 Aug 2025 15:34:43 +0400 Subject: [PATCH 31/31] add solana chain to the docs --- docs/config/_meta.json | 3 +- docs/config/solana.mdx | 175 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 docs/config/solana.mdx diff --git a/docs/config/_meta.json b/docs/config/_meta.json index 412015dac..25ed403b6 100644 --- a/docs/config/_meta.json +++ b/docs/config/_meta.json @@ -3,5 +3,6 @@ "chains": "Chains Directive Syntax", "relayers": "Relayers Directive Syntax", "features": "Feature Toggles", - "ethereum": "Ethereum" + "ethereum": "Ethereum", + "solana": "Solana" } diff --git a/docs/config/solana.mdx b/docs/config/solana.mdx new file mode 100644 index 000000000..44f8efee9 --- /dev/null +++ b/docs/config/solana.mdx @@ -0,0 +1,175 @@ +# Solana Chain Configuration in Starship + +Solana support in Starship allows users to deploy Solana validator nodes using simple configurations. +This section details how to configure Solana-based chains within Starship. + +## Solana Chain + +The Solana chain runs a Solana validator node that can handle transactions and maintain the blockchain state. + +### Basic Config +```yaml +chains: + - id: solana + name: solana + numValidators: 2 + ports: + rpc: 8899 + ws: 8900 + exposer: 8001 + faucet: 9900 + resources: + cpu: 2000m + memory: 2048Mi +``` + +### Lite Configuration (CI/Testing) + +For CI environments or testing scenarios where you need minimal resource usage, you can use the lite configuration: + +```yaml +chains: + - id: solana + name: solana + numValidators: 1 + ports: + rpc: 8899 + ws: 8900 + exposer: 8001 + faucet: 9900 + resources: + cpu: 1500m + memory: 1500Mi + +exposer: + resources: + cpu: 100m + memory: 100Mi + +faucet: + resources: + cpu: 200m + memory: 200Mi +``` + +## Configuration Options + +### Chain Properties + +- **id**: The chain identifier (can be string or number) +- **name**: Must be `"solana"` for Solana chains +- **numValidators**: Number of validator nodes to deploy (minimum: 1) + +### Ports + +- **rpc**: JSON RPC port (default: 8899) +- **ws**: WebSocket port (default: 8900) +- **exposer**: Exposer service port for chain information +- **faucet**: Faucet service port for requesting test tokens + +### Resources + +You can specify CPU and memory resources for the Solana validators: + +```yaml +resources: + cpu: 2000m # 2 CPU cores + memory: 2048Mi # 2GB RAM +``` + +For lighter deployments (like CI), you can reduce these requirements: + +```yaml +resources: + cpu: 1500m # 1.5 CPU cores + memory: 1500Mi # 1.5GB RAM +``` + +## Default Configuration + +Starship uses the following defaults for Solana chains: + +- **Image**: `ghcr.io/hyperweb-io/starship/solana-agave:v2.3.4` +- **Binary**: `solana-validator` +- **Home Directory**: `/root/.solana` +- **Denomination**: `lamports` (base unit), `sol` (display unit) +- **HD Path**: `m/44'/501'/0'/0'` +- **Coin Type**: 501 +- **Faucet**: Enabled by default with Solana-specific faucet + +## Registry Integration + +When using the registry service, Solana chains are automatically registered with the following asset information: + +```yaml +registry: + enabled: true + ports: + rest: 8081 + resources: + cpu: "0.1" + memory: "100M" +``` + +## Usage Examples + +### Full Development Environment + +For a complete development setup with multiple validators: + +```yaml +name: solana-dev +version: 1.10.0 + +chains: + - id: solana + name: solana + numValidators: 2 + ports: + rpc: 8899 + ws: 8900 + exposer: 8001 + faucet: 9900 + resources: + cpu: 2000m + memory: 2048Mi + +registry: + enabled: true + ports: + rest: 8081 +``` + +### CI/Testing Environment + +For continuous integration or testing environments where resources are limited: + +```yaml +name: solana-ci +version: 1.10.0 + +chains: + - id: solana + name: solana + numValidators: 1 + ports: + rpc: 8899 + ws: 8900 + exposer: 8001 + faucet: 9900 + resources: + cpu: 1500m + memory: 1500Mi + +exposer: + resources: + cpu: 100m + memory: 100Mi + +faucet: + resources: + cpu: 200m + memory: 200Mi +``` + +This lite configuration is perfect for CI pipelines where you need to test Solana functionality with minimal resource overhead.