Skip to content

Commit 366ab81

Browse files
committed
Ethereum single node deployemnt option for issue #19
1 parent 5aea314 commit 366ab81

19 files changed

+341
-61
lines changed

lib/constructs/single-node.ts

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,29 @@ export class SingleNodeConstruct extends cdkContructs.Construct {
7474
throw new Error(`Number of data volumes can't be more than 6, current number: ${dataVolumeIndex}`);
7575
}
7676
if (dataVolume.type !== constants.InstanceStoreageDeviceVolumeType) {
77-
const newDataVolume = new ec2.Volume(this, `data-volume-${dataVolumeIndex}`, {
78-
availabilityZone: availabilityZone,
79-
size: cdk.Size.gibibytes(dataVolume.sizeGiB),
80-
volumeType: ec2.EbsDeviceVolumeType[dataVolume.type.toUpperCase() as keyof typeof ec2.EbsDeviceVolumeType],
81-
encrypted: true,
82-
iops: dataVolume.iops,
83-
throughput: dataVolume.throughput,
84-
removalPolicy: cdk.RemovalPolicy.DESTROY,
85-
});
77+
let newDataVolume: ec2.Volume;
78+
79+
if (dataVolume.type === ec2.EbsDeviceVolumeType.GP3) {
80+
newDataVolume = new ec2.Volume(this, `data-volume-${dataVolumeIndex}`, {
81+
availabilityZone: availabilityZone,
82+
size: cdk.Size.gibibytes(dataVolume.sizeGiB),
83+
volumeType: ec2.EbsDeviceVolumeType[dataVolume.type.toUpperCase() as keyof typeof ec2.EbsDeviceVolumeType],
84+
encrypted: true,
85+
iops: dataVolume.iops,
86+
throughput: dataVolume.throughput,
87+
removalPolicy: cdk.RemovalPolicy.DESTROY,
88+
});
89+
} else {
90+
newDataVolume = new ec2.Volume(this, `data-volume-${dataVolumeIndex}`, {
91+
availabilityZone: availabilityZone,
92+
size: cdk.Size.gibibytes(dataVolume.sizeGiB),
93+
volumeType: ec2.EbsDeviceVolumeType[dataVolume.type.toUpperCase() as keyof typeof ec2.EbsDeviceVolumeType],
94+
encrypted: true,
95+
iops: dataVolume.iops,
96+
removalPolicy: cdk.RemovalPolicy.DESTROY,
97+
});
98+
}
99+
86100

87101
new ec2.CfnVolumeAttachment(this, `data-volume${dataVolumeIndex}-attachment`, {
88102
// Device naming according to https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/device_naming.html

lib/ethereum/README.md

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ We will use AWS Cloud9 to execute the subsequent commands. Follow the instructio
6363

6464
**NOTE:** In this tutorial we will set all major configuration through environment variables, but you also can modify parameters in `config/config.ts`.
6565

66-
### Deploy Sync Node
66+
### Prepare to deploy nodes
6767

6868
1. Make sure you are in the root directory of the cloned repository
6969

@@ -75,6 +75,8 @@ We will use AWS Cloud9 to execute the subsequent commands. Follow the instructio
7575

7676
**NOTE:** You may see the following error if the default VPC already exists: `An error occurred (DefaultVpcAlreadyExists) when calling the CreateDefaultVpc operation: A Default VPC already exists for this account in this region.`. That means you can just continue with the following steps.
7777

78+
**NOTE:** The default VPC must have at least two public subnets in different Availability Zones, and public subnet must set `Auto-assign public IPv4 address` to `YES`
79+
7880
3. Configure your setup
7981

8082
Create your own copy of `.env` file and edit it:
@@ -96,7 +98,42 @@ Create your own copy of `.env` file and edit it:
9698
npx cdk deploy eth-common
9799
```
98100

99-
5. Deploy Sync Node
101+
### Option 1: Single RPC Node
102+
103+
1. Deploy Single RPC Node
104+
105+
```bash
106+
pwd
107+
# Make sure you are in aws-blockchain-node-runners/lib/ethereum
108+
npx cdk deploy eth-single-node --json --outputs-file single-node-deploy.json
109+
```
110+
**NOTE:** The default VPC must have at least two public subnets in different Availability Zones, and public subnet must set `Auto-assign public IPv4 address` to `YES`
111+
112+
2. After starting the node you need to wait for the inital syncronization process to finish. It may take from half a day to about 6-10 days depending on the client combination and the state of the network. You can use Amazon CloudWatch to track the progress. There is a script that publishes CloudWatch metrics every 5 minutes, where you can watch `sync distance` for consensus client and `blocks behind` for execution client. When the node is fully synced those two metrics shold show 0. To see them:
113+
114+
- Navigate to [CloudWatch service](https://console.aws.amazon.com/cloudwatch/) (make sure you are in the region you have specified for `AWS_REGION`)
115+
- Open `Dashboards` and select `eth-sync-node-<your-eth-client-combination>` from the list of dashboards.
116+
117+
4. Once the initial synchronization is done, you should be able to access the RPC API of that node from within the same VPC. The RPC port is not exposed to the Internet. Tun the following query against the private IP of the single RPC node you deployed:
118+
119+
```bash
120+
INSTANCE_ID=$(cat single-node-deploy.json | jq -r '..|.node-instance-id? | select(. != null)')
121+
NODE_INTERNAL_IP=$(aws ec2 describe-instances --instance-ids $INSTANCE_ID --query 'Reservations[*].Instances[*].PrivateIpAddress' --output text)
122+
123+
# We query token balance of Beacon deposit contract: https://etherscan.io/address/0x00000000219ab540356cbb839cbe05303d7705fa
124+
curl http://$NODE_INTERNAL_IP:8545 -X POST -H "Content-Type: application/json" \
125+
--data '{"method":"eth_getBalance","params":["0x00000000219ab540356cBB839Cbe05303d7705Fa", "latest"],"id":1,"jsonrpc":"2.0"}'
126+
```
127+
128+
The result should be like this (the actual balance might change):
129+
130+
```javascript
131+
{"jsonrpc":"2.0","id":1,"result":"0xe791d050f91d9949d344d"}
132+
```
133+
134+
### Option 2: Deploy the Highly Available RPC Nodes
135+
136+
1. Deploy Sync Node
100137

101138
```bash
102139
pwd
@@ -105,7 +142,7 @@ Create your own copy of `.env` file and edit it:
105142
```
106143
**NOTE:** The default VPC must have at least two public subnets in different Availability Zones, and public subnet must set `Auto-assign public IPv4 address` to `YES`
107144

108-
6. After starting the node you need to wait for the inital syncronization process to finish. It may take from half a day to about 6-10 days depending on the client combination and the state of the network. You can use Amazon CloudWatch to track the progress. There is a script that publishes CloudWatch metrics every 5 minutes, where you can watch `sync distance` for consensus client and `blocks behind` for execution client. When the node is fully synced those two metrics shold show 0. To see them:
145+
2. After starting the node you need to wait for the inital syncronization process to finish. It may take from half a day to about 6-10 days depending on the client combination and the state of the network. You can use Amazon CloudWatch to track the progress. There is a script that publishes CloudWatch metrics every 5 minutes, where you can watch `sync distance` for consensus client and `blocks behind` for execution client. When the node is fully synced those two metrics shold show 0. To see them:
109146

110147
- Navigate to [CloudWatch service](https://console.aws.amazon.com/cloudwatch/) (make sure you are in the region you have specified for `AWS_REGION`)
111148
- Open `Dashboards` and select `eth-sync-node-<your-eth-client-combination>` from the list of dashboards.
@@ -114,17 +151,15 @@ Once synchronization process is over, the script will automatically stop both cl
114151

115152
Note: the snapshot backup process will automatically run ever day at midnight time of the time zone were the sync node runs. To change the schedule, modify `crontab` of the root user on the node's EC2 instance.
116153

117-
### Deploy the RPC Nodes
118-
119-
1. Configure and deploy 2 RPC Nodes
154+
3. Configure and deploy 2 RPC Nodes
120155

121156
```bash
122157
pwd
123158
# Make sure you are in aws-blockchain-node-runners/lib/ethereum
124159
npx cdk deploy eth-rpc-nodes --json --outputs-file rpc-node-deploy.json
125160
```
126161

127-
2. Give the new RPC nodes about 30 minutes (up to 2 hours for Erigon) to initialize and then run the following query against the load balancer behind the RPC node created
162+
4. Give the new RPC nodes about 30 minutes (up to 2 hours for Erigon) to initialize and then run the following query against the load balancer behind the RPC node created
128163

129164
```bash
130165
export ETH_RPC_ABL_URL=$(cat rpc-node-deploy.json | jq -r '..|.alburl? | select(. != null)')
@@ -151,7 +186,7 @@ The result should be like this (the actual balance might change):
151186
</body>
152187
```
153188

154-
**NOTE:** By default and for security reasons the load balancer is available only from wihtin the default VPC in the region where it is deployed. It is not available from the Internet and is not open for external connections. Before opening it up please make sure you protect your RPC APIs.
189+
**NOTE:** By default and for security reasons the load balancer is available only from within the default VPC in the region where it is deployed. It is not available from the Internet and is not open for external connections. Before opening it up please make sure you protect your RPC APIs.
155190

156191
### Clearing up and undeploying everything
157192

@@ -165,6 +200,9 @@ The result should be like this (the actual balance might change):
165200
pwd
166201
# Make sure you are in aws-blockchain-node-runners/lib/ethereum
167202

203+
# Undeploy Single RPC Node
204+
cdk destroy eth-single-node
205+
168206
# Undeploy RPC Nodes
169207
cdk destroy eth-rpc-nodes
170208

lib/ethereum/app.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ import "source-map-support/register";
44
import * as cdk from "aws-cdk-lib";
55
import * as nag from "cdk-nag";
66
import * as config from "./lib/config/ethConfig";
7+
import { EthNodeRole } from "./lib/config/ethConfig.interface";
78

8-
import { EthSyncNodeStack } from "./lib/sync-node-stack";
9+
import { EthSingleNodeStack } from "./lib/single-node-stack";
910
import { EthCommonStack } from "./lib/common-stack";
1011
import { EthRpcNodesStack } from "./lib/rpc-nodes-stack";
1112

@@ -17,11 +18,23 @@ new EthCommonStack(app, "eth-common", {
1718
stackName: `eth-nodes-common`,
1819
});
1920

20-
new EthSyncNodeStack(app, "eth-sync-node", {
21+
new EthSingleNodeStack(app, "eth-sync-node", {
2122
stackName: `eth-sync-node-${config.baseConfig.clientCombination}`,
2223

2324
env: { account: config.baseConfig.accountId, region: config.baseConfig.region },
2425
ethClientCombination: config.baseConfig.clientCombination,
26+
nodeRole: <EthNodeRole> "sync-node",
27+
instanceType: config.syncNodeConfig.instanceType,
28+
instanceCpuType: config.syncNodeConfig.instanceCpuType,
29+
dataVolumes: config.syncNodeConfig.dataVolumes,
30+
});
31+
32+
new EthSingleNodeStack(app, "eth-single-node", {
33+
stackName: `eth-single-node-${config.baseConfig.clientCombination}`,
34+
35+
env: { account: config.baseConfig.accountId, region: config.baseConfig.region },
36+
ethClientCombination: config.baseConfig.clientCombination,
37+
nodeRole: <EthNodeRole> "single-node",
2538
instanceType: config.syncNodeConfig.instanceType,
2639
instanceCpuType: config.syncNodeConfig.instanceCpuType,
2740
dataVolumes: config.syncNodeConfig.dataVolumes,
@@ -32,6 +45,7 @@ new EthRpcNodesStack(app, "eth-rpc-nodes", {
3245

3346
env: { account: config.baseConfig.accountId, region: config.baseConfig.region },
3447
ethClientCombination: config.baseConfig.clientCombination,
48+
nodeRole: <EthNodeRole> "rpc-node",
3549
instanceType: config.rpcNodeConfig.instanceType,
3650
instanceCpuType: config.rpcNodeConfig.instanceCpuType,
3751
numberOfNodes: config.rpcNodeConfig.numberOfNodes,

lib/ethereum/lib/assets/docker-compose/docker-compose-besu-teku.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ services:
44
besu_node:
55
environment:
66
- "JAVA_OPTS=-Xmx8g"
7-
image: hyperledger/besu:23.4.5-SNAPSHOT
7+
image: hyperledger/besu:24.1.2-SNAPSHOT
88
container_name: execution
99
restart: always
1010
command:
@@ -43,7 +43,7 @@ services:
4343
environment:
4444
- "JAVA_OPTS=-Xmx4g"
4545
- "TEKU_OPTS=-XX:-HeapDumpOnOutOfMemoryError"
46-
image: consensys/teku:23.6.1-jdk16
46+
image: consensys/teku:24.1.0-jdk17
4747
container_name: consensus
4848
restart: always
4949
command:

lib/ethereum/lib/assets/docker-compose/docker-compose-erigon-lighthouse.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
version: "3"
33
services:
44
erigon_node:
5-
image: thorax/erigon:2.48.1-__IMAGE_ARCH__
5+
image: thorax/erigon:2.57.0-__IMAGE_ARCH__
66
container_name: execution
77
restart: always
88
command:
@@ -43,7 +43,7 @@ services:
4343
- "30303:30303/udp"
4444

4545
lighthouse_node:
46-
image: sigp/lighthouse:v4.3.0
46+
image: sigp/lighthouse:v4.5.0
4747
container_name: consensus
4848
restart: always
4949
command:

lib/ethereum/lib/assets/docker-compose/docker-compose-erigon-prysm.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
version: "3"
33
services:
44
erigon_node:
5-
image: thorax/erigon:2.48.1-__IMAGE_ARCH__
5+
image: thorax/erigon:2.57.0-__IMAGE_ARCH__
66
container_name: execution
77
restart: always
88
command:
@@ -43,7 +43,7 @@ services:
4343
- "30303:30303/udp"
4444

4545
prysm_node:
46-
image: rocketpool/prysm:v4.0.6
46+
image: rocketpool/prysm:v4.2.0
4747
container_name: consensus
4848
restart: always
4949
command:

lib/ethereum/lib/assets/docker-compose/docker-compose-geth-lighthouse.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
version: "3"
33
services:
44
geth_node:
5-
image: ethereum/client-go:v1.11.6
5+
image: ethereum/client-go:v1.13.10
66
container_name: execution
77
restart: always
88
command:
@@ -38,7 +38,7 @@ services:
3838
- "30303:30303/udp"
3939

4040
lighthouse_node:
41-
image: sigp/lighthouse:v4.3.0
41+
image: sigp/lighthouse:v4.5.0
4242
container_name: consensus
4343
restart: always
4444
command:

lib/ethereum/lib/assets/docker-compose/docker-compose-nethermind-teku.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ services:
44
nethermind_node:
55
environment:
66
- "DOTNET_BUNDLE_EXTRACT_BASE_DIR=/var/lib/nethermind/data"
7-
image: nethermind/nethermind:1.19.3
7+
image: nethermind/nethermind:1.25.2
88
container_name: execution
99
restart: always
1010
command: [
@@ -54,7 +54,7 @@ services:
5454
environment:
5555
- "JAVA_OPTS=-Xmx4g"
5656
- "TEKU_OPTS=-XX:-HeapDumpOnOutOfMemoryError"
57-
image: consensys/teku:23.6.1-jdk16
57+
image: consensys/teku:24.1.0-jdk17
5858
container_name: consensus
5959
restart: always
6060
command:

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -193,18 +193,18 @@ if [ "$NODE_ROLE" == "sync-node" ]; then
193193
chmod 766 /opt/copy-data-to-s3.sh
194194
fi
195195

196-
if [ "$NODE_ROLE" == "sync-node" ]; then
197-
echo "Sync node. Signaling completion to CloudFormation"
196+
if [ "$NODE_ROLE" == "sync-node" ] || [ "$NODE_ROLE" == "single-node" ]; then
197+
echo "Single node. Signaling completion to CloudFormation"
198198
/opt/aws/bin/cfn-signal --stack $STACK_NAME --resource $RESOURCE_ID --region $REGION
199199
fi
200200

201201
echo "Preparing data volume"
202202

203-
if [ "$NODE_ROLE" == "sync-node" ]; then
203+
if [ "$NODE_ROLE" == "sync-node" ] || [ "$NODE_ROLE" == "single-node" ]; then
204204
# echo "Sync node. Wait for the volume to be attached"
205205
# aws ec2 wait volume-available --volume-ids $DATA_VOLUME_ID --region $REGION
206206

207-
echo "Sync node. Wait for one minute for the volume to be available"
207+
echo "Single node. Wait for one minute for the volume to be available"
208208
sleep 60
209209
fi
210210

@@ -242,11 +242,11 @@ mkdir -p /data/consensus/data
242242
chown -R ethereum:ethereum /data
243243
chmod -R 755 /data
244244

245-
if [ "$NODE_ROLE" == "sync-node" ]; then
245+
if [ "$NODE_ROLE" == "sync-node" ] || [ "$NODE_ROLE" == "single-node" ]; then
246246
if [ "$AUTOSTART_CONTAINER" == "false" ]; then
247-
echo "Sync node. Autostart disabled. Start docker-compose manually!"
247+
echo "Single node. Autostart disabled. Start docker-compose manually!"
248248
else
249-
echo "Sync node. Autostart enabled. Starting docker-compose in 3 min."
249+
echo "Single node. Autostart enabled. Starting docker-compose in 3 min."
250250
echo "sudo su ethereum && /usr/local/bin/docker-compose -f /home/ethereum/docker-compose.yml up -d" | at now +3 minutes
251251
fi
252252
fi

lib/ethereum/lib/common-stack.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export interface EthCommonStackProps extends cdk.StackProps {}
1212
export class EthCommonStack extends cdk.Stack {
1313
AWS_STACKNAME = cdk.Stack.of(this).stackName;
1414
AWS_ACCOUNT_ID = cdk.Stack.of(this).account;
15+
AWS_REGION = cdk.Stack.of(this).region
1516

1617
constructor(scope: cdkConstructs.Construct, id: string, props: EthCommonStackProps) {
1718
super(scope, id, props);
@@ -23,7 +24,7 @@ export class EthCommonStack extends cdk.Stack {
2324
});
2425

2526
const snapshotsBucket = new SnapshotsS3BucketConstruct(this, `snapshots-s3-bucket`, {
26-
bucketName: `eth-snapshots-${this.AWS_ACCOUNT_ID}-${this.AWS_STACKNAME}`,
27+
bucketName: `eth-snapshots-${this.AWS_STACKNAME}-${this.AWS_ACCOUNT_ID}-${this.AWS_REGION}`,
2728
});
2829

2930
const s3VPCEndpoint = vpc.addGatewayEndpoint("s3-vpc-endpoint", {

0 commit comments

Comments
 (0)