Skip to content

Commit a9beb3e

Browse files
committed
Solana. Added ARM support, new Agave client support, removed unused consensus option
1 parent 800cfe9 commit a9beb3e

13 files changed

+67
-42
lines changed

lib/solana/README.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
|:--------------------:|
55
| [@frbrkoala](https://github.com/frbrkoala) |
66

7-
Solana nodes on AWS can be deployed in 3 different configurations: Consensus, base RPC and extended RPC with secondary indexes. In addition, you can choose to deploy those configurations as a single node or a highly available (HA) nodes setup. See below the details on single node and HA deployment setups.
7+
Solana nodes on AWS can be deployed in 2 different configurations: base RPC and extended RPC with secondary indexes. In addition, you can choose to deploy those configurations as a single node or a highly available (HA) nodes setup and use x86 or ARM-powered EC2 instances (powered by Graviton 4). See below the details on single node and HA deployment setups.
88

99
## Overview of Deployment Architectures for Single and HA setups
1010

@@ -84,9 +84,8 @@ This is the Well-Architected checklist for Solana nodes implementation of the AW
8484

8585
| Usage pattern | Ideal configuration | Primary option on AWS | Data Transfer Estimates | Config reference |
8686
|---|---|---|---|---|
87-
| 1/ Consensus node | 48 vCPU, 384 GiB RAM, Accounts volume: 500GiB, 7K IOPS, 700 MB/s throughput, Data volume: 2TB, 9K IOPS, 700 MB/s throughput | r7a.12xlarge, Accounts volume: 500GiB, 7K IOPS, 700 MB/s throughput, Data volume: 2TB, 9K IOPS, 700 MB/s throughput | Proportional to the amount at stake. Between 200TB to 400TB/month | [.env-sample-consensus](./sample-configs/.env-sample-consensus) |
88-
| 2/ Base RPC node (no secondary indexes) | 48 vCPU, 384 GiB RAM, Accounts volume: EBS gp3, 500GiB, 7K IOPS, 700 MB/s throughput, Data volume: EBS gp3, 2TB, 9K IOPS, 700 MB/s throughput | r7a.12xlarge, Accounts volume: EBS gp3, 500GiB, 7K IOPS, 700 MB/s throughput, Data volume: EBS gp3, 2TB, 9K IOPS, 700 MB/s throughput | 13-15TB/month (no staking) | [.env-sample-baserpc](./sample-configs/.env-sample-baserpc) |
89-
| 3/ Extended RPC node (with all secondary indexes) | 96 vCPU, 768 GiB RAM, Accounts volume: 500GiB, 7K IOPS, 700 MB/s throughput, Data volume: 2TB, 9K IOPS, 700 MB/s throughput | r7a.24xlarge, Accounts volume: EBS io2, 500GiB, 7K IOPS, 700 MB/s throughput, Data volume: EBS gp3, 2TB, 9K IOPS, 700 MB/s throughput | 13-15TB/month (no staking) | [.env-sample-extendedrpc](./sample-configs/.env-sample-extendedrpc) |
87+
| 1/ Base RPC node (no secondary indexes) | 48 vCPU, 384 GiB RAM, Accounts volume: EBS gp3, 500GiB, 7K IOPS, 700 MB/s throughput, Data volume: EBS gp3, 2TB, 9K IOPS, 700 MB/s throughput | r7a.12xlarge, Accounts volume: EBS gp3, 500GiB, 7K IOPS, 700 MB/s throughput, Data volume: EBS gp3, 2TB, 9K IOPS, 700 MB/s throughput | 13-15TB/month (no staking) | [.env-sample-baserpc-x86](./sample-configs/.env-sample-baserpc-x86) |
88+
| 2/ Extended RPC node (with all secondary indexes) | 96 vCPU, 768 GiB RAM, Accounts volume: 500GiB, 7K IOPS, 700 MB/s throughput, Data volume: 2TB, 9K IOPS, 700 MB/s throughput | I8g.18xlarge, Accounts volume: Instance Store, Data volume: Instance Store | 20-38TB/month (no staking) | [.env-sample-extendedrpc-arm](./sample-configs/.env-sample-extendedrpc-arm) |
9089
</details>
9190

9291
## Setup Instructions
@@ -126,10 +125,10 @@ Create your own copy of `.env` file and edit it to update with your AWS Account
126125
# Make sure you are in aws-blockchain-node-runners/lib/solana
127126
cd lib/solana
128127
pwd
129-
cp ./sample-configs/.env-sample-baserpc .env
128+
cp ./sample-configs/.env-sample-baserpc-arm .env
130129
nano .env
131130
```
132-
> **NOTE:** *You can find more examples inside `sample-configs` directory.*
131+
> **NOTE:** *You can find more examples inside `sample-configs` directory: ARM-powered and x86-powered setups, base and extended RPC configurations.*
133132
134133

135134
4. Deploy common components such as IAM role, and Amazon S3 bucket to store data snapshots

lib/solana/lib/assets/setup-instance-store-volumes.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ if [ -n "$ACCOUNTS_VOLUME_ID" ]; then
5151
echo "Checking fstab for Accounts volume"
5252

5353
sudo mkfs.xfs -f $ACCOUNTS_VOLUME_ID
54+
if [ "$?" == 1 ]; then
55+
echo "Volume $ACCOUNTS_VOLUME_ID is busy, trying /dev/nvme3n1"
56+
export ACCOUNTS_VOLUME_ID=/dev/nvme3n1
57+
sudo mkfs.xfs -f $ACCOUNTS_VOLUME_ID
58+
fi
5459
sleep 10
5560
ACCOUNTS_VOLUME_UUID=$(lsblk -fn -o UUID $ACCOUNTS_VOLUME_ID)
5661
ACCOUNTS_VOLUME_FSTAB_CONF="UUID=$ACCOUNTS_VOLUME_UUID /data/solana/accounts xfs defaults 0 2"

lib/solana/lib/assets/solana/node-consensus-template.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,5 @@ __ENTRY_POINTS__ \
2929
--limit-ledger-size \
3030
--accounts /data/solana/accounts \
3131
--incremental-snapshot-interval-slots 0 \
32+
--no-port-check \
3233
--log -

lib/solana/lib/assets/solana/node-heavy-rpc-template.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,5 @@ __ENTRY_POINTS__ \
4141
--account-index-exclude-key kinXdEcpDQeHPEuQnqmUgtYykqKGVFq6CeVX5iAHJq6 \
4242
--account-index-exclude-key TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA \
4343
--incremental-snapshot-interval-slots 0 \
44+
--no-port-check \
4445
--log -

lib/solana/lib/assets/solana/node-light-rpc-template.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,5 @@ __ENTRY_POINTS__ \
3636
--limit-ledger-size \
3737
--accounts /data/solana/accounts \
3838
--incremental-snapshot-interval-slots 0 \
39+
--no-port-check \
3940
--log -

lib/solana/lib/assets/user-data/node.sh

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,35 @@ set +e
2323
source /etc/environment
2424

2525
apt-get -yqq update
26-
apt-get -yqq install awscli jq unzip python3-pip chrony
26+
apt-get -yqq install jq unzip python3-pip chrony
2727
apt install unzip
2828

2929
cd /opt
3030

31-
echo "Downloading assets zip file"
32-
aws s3 cp $ASSETS_S3_PATH ./assets.zip --region $AWS_REGION
33-
unzip -q assets.zip
34-
3531
echo "Install and configure CloudWatch agent"
32+
arch=$(uname -m)
3633
if [ "$arch" == "x86_64" ]; then
3734
CW_AGENT_BINARY_URI=https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/amd64/latest/amazon-cloudwatch-agent.deb
35+
AWS_CLI_BINARY_URI=https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip
3836
else
3937
CW_AGENT_BINARY_URI=https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/arm64/latest/amazon-cloudwatch-agent.deb
38+
AWS_CLI_BINARY_URI=https://awscli.amazonaws.com/awscli-exe-linux-aarch64.zip
4039
fi
4140

41+
42+
echo "Intalling AWS CLI"
43+
curl "$AWS_CLI_BINARY_URI" -o "awscliv2.zip"
44+
unzip awscliv2.zip
45+
sudo ./aws/install
46+
47+
echo "Downloading assets zip file"
48+
aws s3 cp $ASSETS_S3_PATH ./assets.zip --region $AWS_REGION
49+
unzip -q assets.zip
50+
51+
echo 'Install & configure CloudWatch Agent'
4252
wget -q $CW_AGENT_BINARY_URI
4353
dpkg -i -E amazon-cloudwatch-agent.deb
4454

45-
echo 'Configuring CloudWatch Agent'
4655
mkdir -p /opt/aws/amazon-cloudwatch-agent/etc/
4756
cp /opt/cw-agent.json /opt/aws/amazon-cloudwatch-agent/etc/custom-amazon-cloudwatch-agent.json
4857

@@ -110,13 +119,13 @@ sysctl -p /etc/sysctl.d/20-solana-mmaps.conf
110119
sysctl -p /etc/sysctl.d/20-solana-udp-buffers.conf
111120
sysctl -p /etc/sysctl.d/20-solana-additionals.conf
112121

113-
systemctl daemon-reload
114-
115122
bash -c "cat >/etc/security/limits.d/90-solana-nofiles.conf <<EOF
116123
# Increase process file descriptor count limit
117124
* - nofile 1000000
118125
EOF"
119126

127+
systemctl daemon-reload
128+
120129
echo 'Preparing fs for Solana installation'
121130
mkdir /data
122131
mkdir /data/solana
@@ -131,7 +140,7 @@ usermod -aG solana solana
131140
if [[ "$STACK_ID" != "none" ]]; then
132141
echo "Install CloudFormation helper scripts"
133142
mkdir -p /opt/aws/
134-
pip3 install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz
143+
pip3 install --break-system-packages https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz
135144
ln -s /usr/local/init/ubuntu/cfn-hup /etc/init.d/cfn-hup
136145

137146
echo "Configuring CloudFormation helper scripts"
@@ -140,7 +149,7 @@ if [[ "$STACK_ID" != "none" ]]; then
140149
sed -i "s;__AWS_STACK_ID__;\"$STACK_ID\";g" /etc/cfn/cfn-hup.conf
141150
sed -i "s;__AWS_REGION__;\"$AWS_REGION\";g" /etc/cfn/cfn-hup.conf
142151

143-
mkdir -p /etc/cfn/hooks.d/
152+
mkdir -p /etc/cfn/hooks.d/system
144153
mv /opt/cfn-hup/cfn-auto-reloader.conf /etc/cfn/hooks.d/cfn-auto-reloader.conf
145154
sed -i "s;__AWS_STACK_NAME__;\"$STACK_NAME\";g" /etc/cfn/hooks.d/cfn-auto-reloader.conf
146155
sed -i "s;__AWS_REGION__;\"$AWS_REGION\";g" /etc/cfn/hooks.d/cfn-auto-reloader.conf

lib/solana/lib/constructs/solana-node-security-group.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,25 @@ export interface SolanaNodeSecurityGroupConstructProps {
2020
const sg = new ec2.SecurityGroup(this, `rpc-node-security-group`, {
2121
vpc,
2222
description: "Security Group for Blockchain nodes",
23-
allowAllOutbound: true,
23+
allowAllOutbound: false,
2424
});
2525

26+
sg.addEgressRule(ec2.Peer.anyIpv4(), ec2.Port.HTTP, "allow HTTP");
27+
sg.addEgressRule(ec2.Peer.anyIpv4(), ec2.Port.HTTPS, "allow HTTPS");
28+
sg.addEgressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(123), "allow NTP");
29+
sg.addEgressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(8899), "allow Solana RPC");
30+
sg.addEgressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(8001), "allow TCP Solana P2P");
31+
sg.addEgressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(8801), "allow TCP Solana P2P");
32+
sg.addEgressRule(ec2.Peer.anyIpv4(), ec2.Port.udpRange(8000,8014), "allow UDP Solana P2P");
33+
sg.addEgressRule(ec2.Peer.anyIpv4(), ec2.Port.udpRange(8800,8814), "allow UDP Solana P2P");
34+
2635
// Public ports
27-
sg.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcpRange(8800, 8814), "P2P protocols (gossip, turbine, repair, etc)");
28-
sg.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.udpRange(8800, 8814), "P2P protocols (gossip, turbine, repair, etc)");
36+
sg.addIngressRule(ec2.Peer.ipv4(vpc.vpcCidrBlock), ec2.Port.tcpRange(8800, 8814), "allow internal TCP P2P protocols (gossip, turbine, repair, etc)");
37+
sg.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.udpRange(8800, 8814), "allow all UDP P2P protocols (gossip, turbine, repair, etc)");
2938

3039
// Private ports restricted only to the VPC IP range
31-
sg.addIngressRule(ec2.Peer.ipv4(vpc.vpcCidrBlock), ec2.Port.tcp(8899), "RPC port HTTP (user access needs to be restricted. Allowed access only from internal IPs)");
32-
sg.addIngressRule(ec2.Peer.ipv4(vpc.vpcCidrBlock), ec2.Port.tcp(8900), "RPC port WebSocket (user access needs to be restricted. Allowed access only from internal IPs)");
40+
sg.addIngressRule(ec2.Peer.ipv4(vpc.vpcCidrBlock), ec2.Port.tcp(8899), "allow internal RPC port HTTP (user access needs to be restricted. Allowed access only from internal IPs)");
41+
sg.addIngressRule(ec2.Peer.ipv4(vpc.vpcCidrBlock), ec2.Port.tcp(8900), "allow internal RPC port WebSocket (user access needs to be restricted. Allowed access only from internal IPs)");
3342

3443
this.securityGroup = sg
3544

lib/solana/lib/ha-nodes-stack.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,10 @@ export class SolanaHANodesStack extends cdk.Stack {
7171
asset.bucket.grantRead(instanceRole);
7272

7373
// Use Ubuntu 20.04 LTS image for amd64. Find more: https://discourse.ubuntu.com/t/finding-ubuntu-images-with-the-aws-ssm-parameter-store/15507
74-
let ubuntu204stableImageSsmName = "/aws/service/canonical/ubuntu/server/20.04/stable/current/amd64/hvm/ebs-gp2/ami-id"
74+
let ubuntu204stableImageSsmName = "/aws/service/canonical/ubuntu/server/24.04/stable/current/amd64/hvm/ebs-gp3/ami-id"
7575
// Setting up the node using generic Single Node constract
7676
if (instanceCpuType === ec2.AmazonLinuxCpuType.ARM_64) {
77-
ubuntu204stableImageSsmName = "/aws/service/canonical/ubuntu/server/20.04/stable/current/arm64/hvm/ebs-gp2/ami-id"
77+
ubuntu204stableImageSsmName = "/aws/service/canonical/ubuntu/server/24.04/stable/current/arm64/hvm/ebs-gp3/ami-id"
7878
}
7979

8080
// Parsing user data script and injecting necessary variables

lib/solana/lib/single-node-stack.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,10 @@ export class SolanaSingleNodeStack extends cdk.Stack {
7575
asset.bucket.grantRead(instanceRole);
7676

7777
// Use Ubuntu 20.04 LTS image for amd64. Find more: https://discourse.ubuntu.com/t/finding-ubuntu-images-with-the-aws-ssm-parameter-store/15507
78-
let ubuntu204stableImageSsmName = "/aws/service/canonical/ubuntu/server/20.04/stable/current/amd64/hvm/ebs-gp2/ami-id"
78+
let ubuntu204stableImageSsmName = "/aws/service/canonical/ubuntu/server/24.04/stable/current/amd64/hvm/ebs-gp3/ami-id"
7979
// Setting up the node using generic Single Node constract
8080
if (instanceCpuType === ec2.AmazonLinuxCpuType.ARM_64) {
81-
ubuntu204stableImageSsmName = "/aws/service/canonical/ubuntu/server/20.04/stable/current/arm64/hvm/ebs-gp2/ami-id"
81+
ubuntu204stableImageSsmName = "/aws/service/canonical/ubuntu/server/24.04/stable/current/arm64/hvm/ebs-gp3/ami-id"
8282
}
8383

8484
const node = new SingleNodeConstruct(this, "sync-node", {

lib/solana/sample-configs/.env-sample-consensus renamed to lib/solana/sample-configs/.env-sample-baserpc-arm

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ AWS_REGION="us-east-2"
88

99
## Common configuration parameters ##
1010
SOLANA_CLUSTER="mainnet-beta" # All options: "mainnet-beta", "testnet", "devnet"
11-
SOLANA_NODE_CONFIGURATION="consensus" # All options: "consensus", "baserpc", "extendedrpc"
12-
SOLANA_VERSION="2.0.18" # Latest required version of Agave above 2.x. Check for latest Mainnet version https://github.com/anza-xyz/agave/releases
11+
SOLANA_NODE_CONFIGURATION="baserpc" # All options: "consensus", "baserpc", "extendedrpc"
12+
SOLANA_VERSION="2.0.19" # Latest required version of Agave above 2.x. Check for latest Mainnet version https://github.com/anza-xyz/agave/releases
1313

14-
SOLANA_INSTANCE_TYPE="r7a.12xlarge"
15-
SOLANA_CPU_TYPE="x86_64" # All options: "x86_64", "ARM_64". IMPORTANT: Make sure the CPU type matches the instance type used
14+
SOLANA_INSTANCE_TYPE="r8g.12xlarge"
15+
SOLANA_CPU_TYPE="ARM_64" # All options: "x86_64", "ARM_64". IMPORTANT: Make sure the CPU type matches the instance type used
1616
# Data volume configuration
1717
SOLANA_DATA_VOL_TYPE="gp3" # Other options: "io1" | "io2" | "gp3" | "instance-store" . IMPORTANT: Use "instance-store" option only with instance types that support that feature, like popular for node im4gn, d3, i3en, and i4i instance families
1818
SOLANA_DATA_VOL_SIZE="2000" # Current required data size to keep both smapshot archive and unarchived version of it

0 commit comments

Comments
 (0)