Skip to main content

Akash Blockchain Build

Overview

Follow the steps in this guide to scaffold and build an Akash blockchain for testing purposes.

Sections:

Environment Overview

The topology used in this guide to build an Akash blockchain instance are as follows. Alternate toplogies could be used including a single host Kubernetes environment.

Hosts

  • Single Kubernetes master node
  • Single Kubernetes worker node

Components

  • Akssh Validator created as a Kubernetes stateful set
  • Akash RPC node created as a Kubernetes stateful set
  • Akash Provider built using Helm Charts and within the same Kubernetes cluster as the validator

Akash Blockchain Build

STEP 1 - Build Kubernetes Cluster

For this build we will use a K3s cluster.

Follow the steps in this Akash documentation guide to build the K3s cluster.

The build in this guide uses a two cluster topolgy with a single control-plane and single dedicated worker node.

STEP 2 - Deploy Initial Validator

NOTE - example blockchain deployed on Google Cloud (GCP) and thus manually creating Kubernetes Persistent Volumes. In other environments this may be seen as unnecessary and may allow Container Storage Interface (CSI) to auto provision the PVs.

Create Mount Point Directories

  • Create the /mnt/validatordirectory on each of the Kubernetes hosts
mkdir -p /mnt/validator

Create the Persistent Volumes

  • Create the Kubernetes Persistent Volumes using the following manifest
  • Adjust the node names in the nodeAffinity stanza to reflect the actual hostnames in your cluster
  • Add additional sections if mutliple validators are in the genesis
apiVersion: v1
kind: PersistentVolume
metadata:
name: local-pv-validator-node1
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: validator-storage
local:
path: /mnt/validator
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- master
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: local-pv-validator-node2
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: validator-storage
local:
path: /mnt/validator
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- worker

Create the Validtor Stateful Set

# StatefulSet for validator-01 service
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: validator-01
namespace: akash-services
spec:
serviceName: "validator-01-service"
replicas: 1
selector:
matchLabels:
app: validator-01
template:
metadata:
labels:
app: validator-01
spec:
containers:
- name: validator-01
image: "ghcr.io/akash-network/cosmos-omnibus:v0.4.11-rc1-generic"
command: ["/bin/sh", "-c"]
args: ["sleep infinity"]
env:
- name: PROJECT_BIN
value: akash
- name: BINARY_URL
value: "https://github.com/akash-network/node/releases/download/v1.0.0-rc10/akash_1.0.0-rc10_linux_amd64.zip" # Updated URL
- name: MONIKER
value: validator-01
- name: MINIMUM_GAS_PRICES
value: 0.025uakt
- name: FASTSYNC_VERSION
value: v0
- name: CHAIN_ID
value: testnet-6
- name: COSMOVISOR_ENABLED
value: "1"
- name: DAEMON_ALLOW_DOWNLOAD_BINARIES
value: "true"
- name: DAEMON_RESTART_AFTER_UPGRADE
value: "true"
- name: DAEMON_LOG_BUFFER_SIZE
value: "512"
- name: UNSAFE_SKIP_BACKUP
value: "true"
ports:
- name: p2p
containerPort: 26656
- name: rpc
containerPort: 26657
volumeMounts:
- name: data
mountPath: /root/.akash
nodeSelector:
kubernetes.io/hostname: worker-01
volumeClaimTemplates:
- metadata:
name: data
annotations:
volume.alpha.kubernetes.io/storage-class: validator-storage
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 100Gi
storageClassName: validator-storage

---
apiVersion: v1
kind: Service
metadata:
name: validator-01
namespace: akash-services
spec:
selector:
app: validator-01
ports:
- protocol: TCP
port: 26656
targetPort: 26656
name: p2p
- protocol: TCP
port: 26657
targetPort: 26657
name: rpc

Verify Validator Deployment

ENSURE PVC BINDING

kubectl get pvc -n akash-services

EXPECTED/EXAMPLE OUTPUT

root@blockchain:~# kubectl get pvc -n akash-services

NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
data-validator-01-0 Bound validator-pv-1 50Gi RWO validator-storage <unset> 62s

Verify Validator Pod

kubectl get pods -n akash-services

EXPECTED/EXAMPLE OUTPUT

root@blockchain:~# kubectl get pods -n akash-services

NAME READY STATUS RESTARTS AGE
validator-01-0 1/1 Running 0 6m3s

STEP 3 - Configure the Initial Validator

NOTE - ensure the validator pod created in the prior step is in a Running status prior to completing the steps in this section

Create a Session into the Validator Pod

NOTE - following this section all remaining commands in this seciton shold be conducted from within the validator pod CLI session established

kubectl exec -ti validator-01-0 -n akash-services -- bash

Install the Akash Node Binary within the Pod

NOTE - replace the specific binary link used in the example with the current/desired binary version

cd

wget -c https://github.com/akash-network/node/releases/download/v0.32.2/akash_0.32.2_linux_amd64.zip

unzip akash_0.32.2_linux_amd64.zip

install akash /usr/local/bin/

rm akash_0.32.2_linux_amd64.zip akash

Confirm Akash Binary Installation

akash version

EXPECTED/EXAMPLE OUTPUT

root@validator-01-0:~# akash version

v0.32.2

STEP 4 - Initialize the New Blockchain

Ensure the .akash Directory is Empty

rm -rf  ~/.akash/*

Create Validator Initial Genesis File

  • Create genesis.json with the node/validator with the chain ID of sandbox-01 and a moniker of validator-01
  • Adjust the chain ID as necessary for specific network build
  • The genesis will be further updated in subsequent steps
akash genesis init --chain-id sandbox-01 validator-01

EXAMPLE/EXPECTED OUTPUT

{"app_message":{"agov":{"deposit_params":{"min_initial_deposit_rate":"0.400000000000000000"}},"astaking":{"params":{"min_commission_rate":"0.050000000000000000"}},"audit":{"attributes":[]},"auth":{"accounts":[],"params":{"max_memo_characters":"256","sig_verify_cost_ed25519":"590","sig_verify_cost_secp256k1":"1000","tx_sig_limit":"7","tx_size_cost_per_byte":"10"}},"authz":{"authorization":[]},"bank":{"balances":[],"denom_metadata":[],"params":{"default_send_enabled":true,"send_enabled":[]},"supply":[]},"capability":{"index":"1","owners":[]},"cert":{"certificates":[]},"crisis":{"constant_fee":{"amount":"1000","denom":"stake"}},"deployment":{"deployments":[],"params":{"min_deposits":[{"amount":"500000","denom":"uakt"}]}},"distribution":{"delegator_starting_infos":[],"delegator_withdraw_infos":[],"fee_pool":{"community_pool":[]},"outstanding_rewards":[],"params":{"base_proposer_reward":"0.010000000000000000","bonus_proposer_reward":"0.040000000000000000","community_tax":"0.020000000000000000","withdraw_addr_enabled":true},"previous_proposer":"","validator_accumulated_commissions":[],"validator_current_rewards":[],"validator_historical_rewards":[],"validator_slash_events":[]},"escrow":{"accounts":[],"payments":[]},"evidence":{"evidence":[]},"feegrant":{"allowances":[]},"genutil":{"gen_txs":[]},"gov":{"deposit_params":{"max_deposit_period":"172800s","min_deposit":[{"amount":"10000000","denom":"stake"}]},"deposits":[],"proposals":[],"starting_proposal_id":"1","tally_params":{"quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto_threshold":"0.334000000000000000"},"votes":[],"voting_params":{"voting_period":"172800s"}},"ibc":{"channel_genesis":{"ack_sequences":[],"acknowledgements":[],"channels":[],"commitments":[],"next_channel_sequence":"0","receipts":[],"recv_sequences":[],"send_sequences":[]},"client_genesis":{"clients":[],"clients_consensus":[],"clients_metadata":[],"create_localhost":false,"next_client_sequence":"0","params":{"allowed_clients":["06-solomachine","07-tendermint"]}},"connection_genesis":{"client_connection_paths":[],"connections":[],"next_connection_sequence":"0","params":{"max_expected_time_per_block":"30000000000"}}},"inflation":{"params":{"inflation_decay_factor":"2.000000000000000000","initial_inflation":"100.000000000000000000","variance":"0.050000000000000000"}},"market":{"bids":[],"leases":[],"orders":[],"params":{"bid_min_deposit":{"amount":"500000","denom":"uakt"},"order_max_bids":20}},"mint":{"minter":{"annual_provisions":"0.000000000000000000","inflation":"0.130000000000000000"},"params":{"blocks_per_year":"6311520","goal_bonded":"0.670000000000000000","inflation_max":"0.200000000000000000","inflation_min":"0.070000000000000000","inflation_rate_change":"0.130000000000000000","mint_denom":"stake"}},"params":null,"provider":{"providers":[]},"slashing":{"missed_blocks":[],"params":{"downtime_jail_duration":"600s","min_signed_per_window":"0.500000000000000000","signed_blocks_window":"100","slash_fraction_double_sign":"0.050000000000000000","slash_fraction_downtime":"0.010000000000000000"},"signing_infos":[]},"staking":{"delegations":[],"exported":false,"last_total_power":"0","last_validator_powers":[],"params":{"bond_denom":"stake","historical_entries":10000,"max_entries":7,"max_validators":100,"unbonding_time":"1814400s"},"redelegations":[],"unbonding_delegations":[],"validators":[]},"take":{"params":{"default_take_rate":20,"denom_take_rates":[{"denom":"uakt","rate":2}]}},"transfer":{"denom_traces":[],"params":{"receive_enabled":true,"send_enabled":true},"port_id":"transfer"},"upgrade":{},"vesting":{}},"chain_id":"sandbox-01","gentxs_dir":"","moniker":"validator-01","node_id":"af88523de02b3943d0e29c8b4d97408b3f0c1098"}

Recover accounts or create anew

export AKASH_KEYRING_BACKEND=test
akash keys add default

Create a single genesis account with 100 Million AKT

akash genesis add-account $(akash keys show default -a) 100000000000000uakt

Create initial validator with 1 Million AKT staked

akash genesis gentx default 1000000000000uakt --chain-id sandbox-01

Run collect-gentxs

akash genesis collect

Update Expedited Voting Period (Testnet Only)

  • In a testnet environment, it is useful to reduce the expedited governance proposal voting period from the default 24 hours to 30 minutes
  • This allows for quicker parameter updates and testing of governance proposals
# Update the expedited_voting_period from 86400s (24 hours) to 1800s (30 minutes)
sed -i 's/"expedited_voting_period": "86400s"/"expedited_voting_period": "1800s"/g' ~/.akash/config/genesis.json

# Verify the change
grep "expedited_voting_period" ~/.akash/config/genesis.json

EXPECTED/EXAMPLE OUTPUT

      "expedited_voting_period": "1800s",

Capture the Node ID of the Validator**

  • Store the captured output/node ID exposed in this step for use in subsequent steps
akash tendermint show-node-id

EXAMPLE/EXPECTED OUTPUT

NOTE - your Node ID will be different/unique

root@validator-01-0:~# akash tendermint show-node-id

af88523de02b3943d0e29c8b4d97408b3f0c1098

STEP 5 - Initialize the Blockchain

NOTE - conduct the steps in this section from the Kubernetes control-plane node

Update Validator Statefull Set

  • Update the Validator stateful set with removal of initial commands that initially put the associated pod in a sleep infinity condition to allow access and configuration.
  • Now with the node configured we can remove sleep infinity and allow the pod to initialize the first validator on the network
kubectl patch statefulset validator-01 -n akash-services --type='json' -p='[{"op": "remove", "path": "/spec/template/spec/containers/0/command"}, {"op": "remove", "path": "/spec/template/spec/containers/0/args"}]'

Verify the Validator is Writing Blocks

  • Verify that the validator is writing blocks to the blochchain by continually monitoring the validator pod
kubectl logs validator-01-0 -n akash-services -f

EXAMPLE/EXPECTED OUTPUT

  • This is an example message from a single blockchain write and for a single block. There should be incrementing block numbers/writes every several second and each with this type of log message.
INF committed state app_hash=B423ACA69FB037927DCD3FEBFD7B70F448673372380811273F7E3096F1DFA648 height=39 module=state num_txs=0
INF indexed block exents height=39 module=txindex
INF Timed out dur=4986.142971 height=40 module=consensus round=0 step=1

RPC Node Build

  • With a functional/live blockchain, we will launch the network's first RPC node for use by the Akash Provider we will build eventually and for other network query/transaction operations

NOTE - the RPC Node build uses a similar methodology to the Validator build. We deploy the pod initially in a sleep infinity state to allow manual configuration, then remove the sleep command once the node is properly initialized. This is necessary because current cosmos-omnibus images use the legacy akash init command instead of the newer akash genesis init syntax required by recent Akash node versions.

STEP 1 - Create Persistent Volumes

NOTE - example blockchain deployed on Google Cloud (GCP) and thus manually creating Kubernetes Persistent Volumes. In other environments this may be seen as unnecessary and may allow Container Storage Interface (CSI) to auto provision the PVs.

Create Mount Point Directories

  • Create the /mnt/rpc directory on each of the Kubernetes hosts
mkdir -p /mnt/rpc

Create the Persistent Volumes

  • Create the Kubernetes Persistent Volumes using the following manifest
  • Adjust the node names in the nodeAffinity stanza to reflect the actual hostnames in your cluster
apiVersion: v1
kind: PersistentVolume
metadata:
name: local-pv-rpc-node1
spec:
capacity:
storage: 100Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: akash-nodes
local:
path: /mnt/rpc
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- master
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: local-pv-rpc-node2
spec:
capacity:
storage: 100Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: akash-nodes
local:
path: /mnt/rpc
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- worker

STEP 2 - Deploy RPC Node Stateful Set

Create the RPC Node Stateful Set

  • Prior to creating this RPC Node stateful set via the manifest below - ensure to update these fields:
  • image - uses latest stable Omnibus generic image (v1.2.36-generic as of this writing). Find latest versions here
  • BINARY_URL - update with current/desired Akash Node version
  • P2P_SEEDS, AKASH_P2P_PRIVATE_PEER_IDS, AKASH_P2P_PERSISTENT_PEERS, AKASH_P2P_UNCONDITIONAL_PEER_IDS - update each of these env variables with the validator node ID captured in the Capture the Node ID of the Validator step
  • CHAIN_ID - update to match your testnet chain ID
  • GENESIS_URL - replace with the URL hosting the genesis.json file
  • nodeSelector - update hostname to match your cluster worker node

NOTE - the manifest uses sleep infinity to allow initial configuration. The node will be started in a later step after manual initialization.

# StorageClass for akash nodes
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: akash-nodes
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

---
# StatefulSet for rpc service
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: rpc
namespace: akash-services
spec:
serviceName: "rpc-service"
replicas: 1
selector:
matchLabels:
app: rpc
template:
metadata:
labels:
app: rpc
spec:
containers:
- name: rpc
image: "ghcr.io/akash-network/cosmos-omnibus:v1.2.36-generic"
command: ["/bin/sh", "-c"]
args: ["sleep infinity"]
env:
- name: PROJECT_BIN
value: akash
- name: BINARY_URL
value: "https://github.com/akash-network/node/releases/download/v0.32.2/akash_0.32.2_linux_amd64.zip"
- name: MONIKER
value: rpc-01
- name: MINIMUM_GAS_PRICES
value: 0.025uakt
- name: FASTSYNC_VERSION
value: v0
- name: P2P_SEEDS
value: <VALIDATOR_NODE_ID>@validator-01:26656
- name: AKASH_P2P_PRIVATE_PEER_IDS
value: <VALIDATOR_NODE_ID>
- name: AKASH_P2P_PERSISTENT_PEERS
value: <VALIDATOR_NODE_ID>@validator-01:26656
- name: AKASH_P2P_UNCONDITIONAL_PEER_IDS
value: <VALIDATOR_NODE_ID>
- name: CHAIN_ID
value: sandbox-01
- name: GENESIS_URL
value: "<YOUR_GENESIS_URL>"
- name: AKASH_API_ENABLE
value: "true"
- name: AKASH_PRUNING
value: custom
- name: AKASH_PRUNING_INTERVAL
value: "10"
- name: AKASH_PRUNING_KEEP_EVERY
value: "500"
- name: AKASH_PRUNING_KEEP_RECENT
value: "100"
- name: AKASH_STATE_SYNC_SNAPSHOT_INTERVAL
value: "500"
- name: COSMOVISOR_ENABLED
value: "0"
- name: DAEMON_ALLOW_DOWNLOAD_BINARIES
value: "true"
- name: DAEMON_RESTART_AFTER_UPGRADE
value: "true"
- name: DAEMON_LOG_BUFFER_SIZE
value: "512"
- name: UNSAFE_SKIP_BACKUP
value: "true"
volumeMounts:
- name: data
mountPath: /root/.akash
ports:
- name: api
containerPort: 1317
- name: grpc
containerPort: 9090
- name: p2p
containerPort: 26656
- name: rpc
containerPort: 26657
nodeSelector:
kubernetes.io/hostname: worker
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 100Gi
storageClassName: akash-nodes

---
# ClusterIP Service for internal access
apiVersion: v1
kind: Service
metadata:
name: rpc
namespace: akash-services
spec:
selector:
app: rpc
ports:
- protocol: TCP
port: 1317
targetPort: 1317
name: api
- protocol: TCP
port: 9090
targetPort: 9090
name: grpc
- protocol: TCP
port: 26656
targetPort: 26656
name: p2p
- protocol: TCP
port: 26657
targetPort: 26657
name: rpc

Verify RPC Node Deployment

ENSURE PVC BINDING

kubectl get pvc -n akash-services

EXPECTED/EXAMPLE OUTPUT

NAME         STATUS   VOLUME              CAPACITY   ACCESS MODES   STORAGECLASS   AGE
data-rpc-0 Bound local-pv-rpc-node1 100Gi RWO akash-nodes 30s

Verify RPC Node Pod

kubectl get pods -n akash-services

EXPECTED/EXAMPLE OUTPUT

NAME             READY   STATUS    RESTARTS   AGE
validator-01-0 1/1 Running 0 10m
rpc-0 1/1 Running 0 60s

STEP 3 - Configure the RPC Node

NOTE - ensure the RPC Node pod created in the prior step is in a Running status prior to completing the steps in this section

Create a Session into the RPC Node Pod

NOTE - following this section all remaining commands in this section should be conducted from within the RPC Node pod CLI session established

kubectl exec -ti rpc-0 -n akash-services -- bash

Install the Akash Node Binary within the Pod

NOTE - replace the specific binary link used in the example with the current/desired binary version matching your testnet

cd

wget -c https://github.com/akash-network/node/releases/download/v0.32.2/akash_0.32.2_linux_amd64.zip

unzip akash_0.32.2_linux_amd64.zip

install akash /usr/local/bin/

rm akash_0.32.2_linux_amd64.zip akash

Confirm Akash Binary Installation

akash version

EXPECTED/EXAMPLE OUTPUT

root@rpc-0:~# akash version

v0.32.2

Initialize the RPC Node

  • The GENESIS_URL env var in the manifest causes omnibus to download the correct genesis.json file on pod startup
  • The akash genesis init command will overwrite this file, so we backup first and restore after initialization
  • Adjust the chain ID and moniker to match your network
# Backup the genesis file downloaded via GENESIS_URL
cp ~/.akash/config/genesis.json /tmp/genesis.json.bak

# Initialize the node (creates config structure but overwrites genesis)
akash genesis init --chain-id sandbox-01 rpc-01

# Restore the correct genesis file
cp /tmp/genesis.json.bak ~/.akash/config/genesis.json

Configure External Access Bindings

  • By default, the RPC and API endpoints bind to localhost. Update to allow external access:
# Update RPC binding to allow external connections
sed -i 's/laddr = "tcp:\/\/127.0.0.1:26657"/laddr = "tcp:\/\/0.0.0.0:26657"/g' ~/.akash/config/config.toml

# Update API binding in app.toml
sed -i 's/address = "tcp:\/\/localhost:1317"/address = "tcp:\/\/0.0.0.0:1317"/g' ~/.akash/config/app.toml

# Update gRPC binding in app.toml
sed -i 's/address = "localhost:9090"/address = "0.0.0.0:9090"/g' ~/.akash/config/app.toml

# Ensure API is enabled
sed -i '/^\[api\]/,/^\[/ s/enable = false/enable = true/' ~/.akash/config/app.toml

# Ensure gRPC is enabled
sed -i '/^\[grpc\]/,/^\[/ s/enable = false/enable = true/' ~/.akash/config/app.toml

Exit the RPC Node Pod

exit

STEP 4 - Start the RPC Node

NOTE - conduct the steps in this section from the Kubernetes control-plane node

Update RPC Node StatefulSet

  • Update the RPC Node stateful set with removal of initial commands that initially put the associated pod in a sleep infinity condition to allow access and configuration
  • Now with the node configured we can remove sleep infinity and allow the pod to start syncing
kubectl patch statefulset rpc -n akash-services --type='json' -p='[{"op": "remove", "path": "/spec/template/spec/containers/0/command"}, {"op": "remove", "path": "/spec/template/spec/containers/0/args"}]'

Verify the RPC Node is Syncing

  • Monitor the RPC node logs to verify it's connecting to the validator and syncing blocks
kubectl logs rpc-0 -n akash-services -f

EXPECTED/EXAMPLE OUTPUT

  • You should see the node connecting to the validator and syncing blocks:
INF Starting Node service impl=Node
INF Connecting to peer addr=<VALIDATOR_NODE_ID>@validator-01:26656
INF committed state app_hash=... height=100 module=state num_txs=0

STEP 5 - Confirm RPC Node Status

Create a Session into the RPC Node Pod

kubectl exec -ti rpc-0 -n akash-services -- bash

Query Node Status

  • Checking the RPC node status will display latest block height received, if the RPC Node is in sync, etc
akash status

EXAMPLE/EXPECTED OUTPUT

  • The node should eventually reach a status of "catching_up":false as demonstrated in the JSON output below
  • Search for catching_up to see example/expected status. It may take the RPC node some time to catch up depending on how many blocks are on the blockchain. Should sync very quickly if you are performing this build shortly after the chain initiation.
{"NodeInfo":{"protocol_version":{"p2p":"8","block":"11","app":"0"},"id":"7cacf5b9b4609955651832dc956462748e6d5683","listen_addr":"tcp://0.0.0.0:26656","network":"sandbox-01","version":"0.34.27","channels":"40202122233038606100","moniker":"rpc-01","other":{"tx_index":"on","rpc_address":"tcp://0.0.0.0:26657"}},"SyncInfo":{"latest_block_hash":"354FE2E80583C4C5035473557C1268C5CEB4EA020A04ED2F23B1C8A64840538F","latest_app_hash":"C8D05A64741A9F80003482397A62C47BA8AF71198AB46901EFD4FBB2666A9A84","latest_block_height":"4055","latest_block_time":"2024-03-23T01:45:43.804861718Z","earliest_block_hash":"667680E786A4F4D371202BA1D184433405161F9A2775283BA79AB8937EF08F53","earliest_app_hash":"E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855","earliest_block_height":"1","earliest_block_time":"2024-03-22T18:25:20.428854275Z","catching_up":false},"ValidatorInfo":{"Address":"19764CA8E5E85F2186DAF1CF64923D99D9AFCB17","PubKey":{"type":"tendermint/PubKeyEd25519","value":"hv05xEVMkG5zYA7m6MiiGVLncTUn3FssG1HO1NnSIts="},"VotingPower":"0"}}

STEP 6 - Create NodePort Service for External Access (Optional)

  • If external access to the RPC node is required, create a NodePort service
  • This is necessary for external validators to peer with your RPC node and for external clients to query the network

NOTE - the externalTrafficPolicy: Local setting is critical for P2P protocol compatibility. Without this setting, kube-proxy's SNAT can interfere with the Tendermint P2P handshake.

Create the NodePort Service Manifest

apiVersion: v1
kind: Service
metadata:
name: rpc-nodeport
namespace: akash-services
spec:
type: NodePort
externalTrafficPolicy: Local # Critical for P2P protocol compatibility
selector:
app: rpc
ports:
- protocol: TCP
port: 26656 # P2P port
targetPort: 26656 # Pod P2P port
nodePort: 30656 # External P2P access
name: p2p
- protocol: TCP
port: 26657 # RPC port
targetPort: 26657 # Pod RPC port
nodePort: 30657 # External RPC access
name: rpc
- protocol: TCP
port: 1317 # API port
targetPort: 1317
nodePort: 30317 # External API access
name: api
- protocol: TCP
port: 9090 # gRPC port
targetPort: 9090
nodePort: 30090 # External gRPC access
name: grpc

Apply the NodePort Service

kubectl apply -f rpc-nodeport-service.yaml

Verify the NodePort Service

kubectl get svc -n akash-services

EXPECTED/EXAMPLE OUTPUT

NAME           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                                                                   AGE
rpc ClusterIP 10.233.27.177 <none> 1317/TCP,9090/TCP,26656/TCP,26657/TCP 10m
rpc-nodeport NodePort 10.233.45.89 <none> 26656:30656/TCP,26657:30657/TCP,1317:30317/TCP,9090:30090/TCP 30s
validator-01 ClusterIP 10.233.12.34 <none> 26656/TCP,26657/TCP 30m

DNS Configuration (If Required)

To make the RPC node accessible via a domain name (e.g., rpc.dev.akash.pub):

  1. Point the DNS A record to your Kubernetes node's external IP
  2. Access endpoints:
    • P2P: rpc.dev.akash.pub:30656
    • RPC: rpc.dev.akash.pub:30657
    • API: rpc.dev.akash.pub:30317
    • gRPC: rpc.dev.akash.pub:30090

Test External Access

# Test RPC endpoint
curl http://<NODE_EXTERNAL_IP>:30657/status

# Test API endpoint
curl http://<NODE_EXTERNAL_IP>:30317/cosmos/base/tendermint/v1beta1/node_info

Akash Provider Build

  • Build the Akash Provider via Helm Charts and via this documentation
  • Conduct build from control-plane node of pre-existing Kubernetes cluster
  • Review additional notes section below for guidance on setting up a provider for test blockchain use

Additional Notes Provider Build

Ingress Rules

  • To expose the validator to the outside world, update the ingress TCP rules such as the following example
  • Ensure the new configmap settings have been applied post build via - kubectl get svc -n ingress-nginx - and check exposed TCP ports
  • Testing of external validator access is possible via (I.e.) - curl http://34.172.54.64:30057/status
tcp:
"8443": "akash-services/akash-provider:8443"
"8444": "akash-services/akash-provider:8444"
"30056": "akash-services/validator-01:26656"
"30057": "akash-services/validator-01:26657"

Provider Account Creation and Configuration

  • Install provider-services binary and create/import provider Akash address
  • Configure environment variables as follows replacing the account address with your provider address
AKASH_KEY_NAME=default

AKASH_KEYRING_BACKEND=test

export AKASH_CHAIN_ID="sandbox-01"

export AKASH_ACCOUNT_ADDRESS=akash1mtnuc449l0mckz4cevs835qg72nvqwlul5wzyf

export AKASH_NODE=http://rpc:26657

export AKASH_GAS=auto
export AKASH_GAS_ADJUSTMENT=1.5
export AKASH_GAS_PRICES=0.025uakt
export AKASH_SIGN_MODE=amino-json

Fund Provider Account

  • Import the validator account to send funds to the provider account
  • Enter the mnemonic for the account when prompted
  • Example:
provider-services keys add validator --recover
  • Transfer funds from the valiadtor account to the provider account
  • Example:
provider-services tx send <valdiator-address> <provider-address> 100000000uakt

Chain ID Specification

  • Ensure the chain ID is specified as sandbox-01 in the provider.yaml file such as (replace address and other elements as necessary):
---
from: "$ACCOUNT_ADDRESS"
key: "$(cat ~/key.pem | openssl base64 -A)"
keysecret: "$(echo $KEY_PASSWORD | openssl base64 -A)"
domain: "$DOMAIN"
node: "$NODE"
withdrawalperiod: 12h
chainid: sandbox-01
attributes:
- key: region
value: "us-central"
- key: host
value: akash
- key: tier
value: community
- key: organization
value: "akashtesting"

CosmoVisor Network Upgrade Test

Create Proposal, Deposit, and Vote

Notes on Proposal Customization

Create a network upgrade proposal on the blockchain using the Example Proposal below. This JSON proposal example should be updated for your purposes in the following sections:

Example Proposal

NOTES:

  • Ensure to use the raw content URL such as:

'https://raw.githubusercontent.com/akash-network/net/main/sandbox/upgrades/v0.36.0/info.json`

  • Default voting period is 10 minutes
akash tx gov submit-proposal software-upgrade v0.34.0 --title "v0.34.0" --description "SW upgrade proposal for v0.34.0" --upgrade-height 1857050 --upgrade-info "https://raw.githubusercontent.com/akash-network/net/main/sandbox/upgrades/v0.34.0/info.json" --deposit 4000000uakt

Example Query Proposal

akash query gov proposal 4 | jq -r .

Example Deposit

akash tx gov deposit 4 10000000uakt

Example Query Proposal to Validate Deposit

akash query gov proposal 4 | jq -r .

Example Vote

  • Repeat across sufficient number of accounts to reach consesus
akash tx gov vote 4 yes

Example Query Tally/Votes

akash query gov tally 4 | jq -r .

Upgrade Validations

Validator Logs Showing Upgrade Initiation

INF service stop impl={"Dir":"/root/.akash/data/cs.wal","Head":{"ID":"6ZRpIvNrxK4C:/root/.akash/data/cs.wal/wal","Path":"/root/.akash/data/cs.wal/wal"},"ID":"group:6ZRpIvNrxK4C:/root/.akash/data/cs.wal/wal","Logger":{}} module=consensus msg={} wal=/root/.akash/data/cs.wal/wal
4:11PM INF daemon shutting down in an attempt to restart module=cosmovisor
4:12PM INF no upgrade binary found, beginning to download it module=cosmovisor
4:12PM INF downloading binary complete module=cosmovisor
4:12PM INF pre-upgrade command does not exist. continuing the upgrade. module=cosmovisor
4:12PM INF upgrade detected, relaunching app=akash module=cosmovisor
4:12PM INF running app args=["start"] module=cosmovisor path=/root/.akash/cosmovisor/upgrades/v0.34.0/bin/akash

root-validator1-1 | INF applying upgrade "v0.34.0" at height: 628

Additional Validations

NOTE - in testing akash status did not show new version despite successful Cosmovisor upgrade. This section provides additional verification examples - with example output - to ensure the upgrade was completed.

ps -ef | grep akash
root 89 1 12 16:12 ? 00:02:02 /root/.akash/cosmovisor/upgrades/v0.34.0/bin/akash start
root 229 169 0 16:28 pts/1 00:00:00 grep akash

/root/.akash/cosmovisor/upgrades/v0.34.0/bin/akash version
v0.34.1