Skip to content

Ethereum. Refactoring, parametrised network ID & Reth support #167

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Feb 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 0 additions & 29 deletions lib/ethereum/.env-sample

This file was deleted.

81 changes: 46 additions & 35 deletions lib/ethereum/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ This is the Well-Architected checklist for Ethereum nodes implementation of the

### Open AWS CloudShell

To begin, ensure you login to your AWS account with permissions to create and modify resources in IAM, EC2, EBS, VPC, S3, KMS, and Secrets Manager.
To begin, ensure you login to your AWS account with permissions to create and modify resources in IAM, EC2, EBS, VPC, and S3.

From the AWS Management Console, open the [AWS CloudShell](https://docs.aws.amazon.com/cloudshell/latest/userguide/welcome.html), a web-based shell environment. If unfamiliar, review the [2-minute YouTube video](https://youtu.be/fz4rbjRaiQM) for an overview and check out [CloudShell with VPC environment](https://docs.aws.amazon.com/cloudshell/latest/userguide/creating-vpc-environment.html) that we'll use to test nodes API from internal IP address space.

Expand All @@ -73,9 +73,7 @@ cd aws-blockchain-node-runners
npm install
```

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

### Prepare to deploy nodes
### Prepare AWS account to deploy nodes

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

Expand All @@ -89,11 +87,11 @@ aws ec2 create-default-vpc

> **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`*

3. With the [Node Runners blueprints for Ethereum](https://github.com/aws-samples/aws-blockchain-node-runners/tree/main/lib/ethereum), you can deploy both single Ethereum nodes and multi-node high-availability configurations on AWS. Furthermore, Node Runners is designed to support client diversity, with configurations available for a variety of client combinations for the Execution Layer (EL) and Consensus Layer (CL).
### Configure your setup

Configure your setup.
#### Execution and Consensus Layer Client Options

### Execution and Consensus Layer Client Options
With the [Node Runners blueprints for Ethereum](https://github.com/aws-samples/aws-blockchain-node-runners/tree/main/lib/ethereum), you can deploy both single Ethereum nodes and multi-node high-availability configurations on AWS. Furthermore, Node Runners is designed to support client diversity, with configurations available for a variety of client combinations for the Execution Layer (EL) and Consensus Layer (CL).

<details>

Expand Down Expand Up @@ -135,17 +133,17 @@ nano .env

<details>

<summary>Erigon Prysm</summary>
<summary>Reth Lighthouse</summary>
<br/>

**Configure your Node Runners Ethereum - Erigon Prysm**
**Configure your Node Runners Ethereum - Reth Lighthouse**

To specify the Ethereum client combination you wish to deploy, create your own copy of `.env` file and edit it using your preferred text editor. The contents of your file for a Erigon / Prysm node deployment is as follows, which uses a sample config from the repository:
To specify the Ethereum client combination you wish to deploy, create your own copy of `.env` file and edit it using your preferred text editor. The contents of your file for a Reth / Lighthouse node deployment is as follows, which uses a sample config from the repository:
```bash
# Make sure you are in aws-blockchain-node-runners/lib/ethereum
cd lib/ethereum
pwd
cp ./sample-configs/.env-erigon-prysm .env
cp ./sample-configs/.env-erigon-lighthouse .env
nano .env
```
> **NOTE:** *You can find more examples inside the `sample-configs` directory, which illustrate other Ethereum client combinations.*
Expand Down Expand Up @@ -201,9 +199,32 @@ pwd
npx cdk deploy eth-common
```

### Option 1: Single RPC Node
### [OPTIONAL] (required only when ETH_SNAPSHOT_TYPE="s3") Deploy Sync Node

Sync node will sync with the network and periodically create data snapshots on S3 to speed up RPC nodes setup when `ETH_SNAPSHOT_TYPE="s3"`. It has no effect if `ETH_SNAPSHOT_TYPE="none"`.

1. Deploy `eth-sync-node` stack

```bash
pwd
# Make sure you are in aws-blockchain-node-runners/lib/ethereum
npx cdk deploy eth-sync-node --json --outputs-file sync-node-deploy.json
```

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:

- Navigate to [CloudWatch service](https://console.aws.amazon.com/cloudwatch/) (make sure you are in the region you have specified for `AWS_REGION`)
- Open `Dashboards` and select `eth-sync-node-<your-eth-client-combination>` from the list of dashboards.

Once synchronization process is over, the script will automatically stop both clients and copy all the contents of the `/data` directory to your snapshot S3 bucket. That may take from 30 minutes to about 2 hours. During the process on the dashboard you will see lower CPU and RAM utilization but high data disc throughput and outbound network traffic. The script will automatically start the clients after the process is done.

> **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.*

### Deploy Standalone RPC Node

> **NOTE:** *If `ETH_SNAPSHOT_TYPE="s3"` make sure you [deployed the Sync Node first](#optional-required-only-when-eth_snapshot_types3-deploy-sync-node).*

1. Deploy Single RPC Node
1. Deploy `eth-single-node` stack

```bash
pwd
Expand All @@ -212,12 +233,12 @@ npx cdk deploy eth-single-node --json --outputs-file single-node-deploy.json
```
> **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`*

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:
2. If you haven't used `ETH_SNAPSHOT_TYPE="s3"` with Sync Node, then your node will start syncing by itself. In that case, 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:

- Navigate to [CloudWatch service](https://console.aws.amazon.com/cloudwatch/) (make sure you are in the region you have specified for `AWS_REGION`)
- Open `Dashboards` and select `eth-sync-node-<your-eth-client-combination>` from the list of dashboards.
- Open `Dashboards` and select `eth-single-node-<your-eth-client-combination>` from the list of dashboards.

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. Turn the following query against the private IP of the single RPC node you deployed:
3. 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. Turn the following query against the private IP of the single RPC node you deployed:

```bash
INSTANCE_ID=$(cat single-node-deploy.json | jq -r '..|.node-instance-id? | select(. != null)')
Expand All @@ -240,35 +261,25 @@ The result should be like this (the actual balance might change):
{"jsonrpc":"2.0","id":1,"result":"0xe791d050f91d9949d344d"}
```

### Option 2: Highly Available RPC Nodes

1. Deploy Sync Node

```bash
pwd
# Make sure you are in aws-blockchain-node-runners/lib/ethereum
npx cdk deploy eth-sync-node --json --outputs-file sync-node-deploy.json
```
**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`*
### Deploy Highly Available RPC Nodes

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:
> **NOTE:** *If `ETH_SNAPSHOT_TYPE="s3"` make sure you [deployed the Sync Node first](#optional-required-only-when-eth_snapshot_types3-deploy-sync-node).*

- Navigate to [CloudWatch service](https://console.aws.amazon.com/cloudwatch/) (make sure you are in the region you have specified for `AWS_REGION`)
- Open `Dashboards` and select `eth-sync-node-<your-eth-client-combination>` from the list of dashboards.
> **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`*

Once synchronization process is over, the script will automatically stop both clients and copy all the contents of the `/data` directory to your snapshot S3 bucket. That may take from 30 minutes to about 2 hours. During the process on the dashboard you will see lower CPU and RAM utilization but high data disc throughput and outbound network traffic. The script will automatically start the clients after the process is done.
1. Deploy Sync Node

> **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.*
Use instructions from earlier: [Deploy Sync Node](#optional-required-only-when-eth_snapshot_types3-deploy-sync-node)

3. Configure and deploy 2 RPC Nodes
2. Deploy `eth-rpc-nodes` stack

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

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
3. 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 in front of your nods:

```bash
export ETH_RPC_ABL_URL=$(cat rpc-node-deploy.json | jq -r '..|.alburl? | select(. != null)')
Expand All @@ -288,7 +299,7 @@ The result should be like this (the actual balance might change):
{"jsonrpc":"2.0","id":1,"result":"0xe791d050f91d9949d344d"}
```

If the nodes are still starting and catching up with the chain, you will see the following repsonse:
If the nodes are still starting and catching up with the chain, you will see the following response:

```HTML
<html>
Expand All @@ -298,7 +309,7 @@ The result should be like this (the actual balance might change):
</body>
```

> **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.
> **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.*

### Clearing up and undeploying everything

Expand Down
34 changes: 25 additions & 9 deletions lib/ethereum/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,55 +3,71 @@ import 'dotenv/config'
import "source-map-support/register";
import * as cdk from "aws-cdk-lib";
import * as nag from "cdk-nag";
import * as config from "./lib/config/ethConfig";
import { EthNodeRole } from "./lib/config/ethConfig.interface";
import * as config from "./lib/config/node-config";
import { EthNodeRole } from "./lib/config/node-config.interface";

import { EthSingleNodeStack } from "./lib/single-node-stack";
import { EthCommonStack } from "./lib/common-stack";
import { EthRpcNodesStack } from "./lib/rpc-nodes-stack";

const app = new cdk.App();
cdk.Tags.of(app).add("Project", "Ethereum");
cdk.Tags.of(app).add("Project", "AWSEthereum");

new EthCommonStack(app, "eth-common", {
env: { account: config.baseConfig.accountId, region: config.baseConfig.region },
stackName: `eth-nodes-common`,
env: { account: config.baseConfig.accountId, region: config.baseConfig.region },
snapshotType: config.baseConfig.snapshotType,
});

new EthSingleNodeStack(app, "eth-sync-node", {
stackName: `eth-sync-node-${config.baseConfig.clientCombination}`,

env: { account: config.baseConfig.accountId, region: config.baseConfig.region },
ethClientCombination: config.baseConfig.clientCombination,
network: config.baseConfig.network,
snapshotType: config.baseConfig.snapshotType,
consensusSnapshotURL: config.baseConfig.consensusSnapshotURL,
executionSnapshotURL: config.baseConfig.executionSnapshotURL,
consensusCheckpointSyncURL: config.baseConfig.consensusCheckpointSyncURL,
nodeRole: <EthNodeRole> "sync-node",
instanceType: config.syncNodeConfig.instanceType,
instanceCpuType: config.syncNodeConfig.instanceCpuType,
dataVolumes: config.syncNodeConfig.dataVolumes,
dataVolume: config.syncNodeConfig.dataVolumes[0],
});

new EthSingleNodeStack(app, "eth-single-node", {
stackName: `eth-single-node-${config.baseConfig.clientCombination}`,

env: { account: config.baseConfig.accountId, region: config.baseConfig.region },
ethClientCombination: config.baseConfig.clientCombination,
network: config.baseConfig.network,
snapshotType: config.baseConfig.snapshotType,
consensusSnapshotURL: config.baseConfig.consensusSnapshotURL,
executionSnapshotURL: config.baseConfig.executionSnapshotURL,
consensusCheckpointSyncURL: config.baseConfig.consensusCheckpointSyncURL,
nodeRole: <EthNodeRole> "single-node",
instanceType: config.syncNodeConfig.instanceType,
instanceCpuType: config.syncNodeConfig.instanceCpuType,
dataVolumes: config.syncNodeConfig.dataVolumes,
instanceType: config.rpcNodeConfig.instanceType,
instanceCpuType: config.rpcNodeConfig.instanceCpuType,
dataVolume: config.rpcNodeConfig.dataVolumes[0],
});

new EthRpcNodesStack(app, "eth-rpc-nodes", {
stackName: `eth-rpc-nodes-${config.baseConfig.clientCombination}`,

env: { account: config.baseConfig.accountId, region: config.baseConfig.region },
ethClientCombination: config.baseConfig.clientCombination,
network: config.baseConfig.network,
snapshotType: config.baseConfig.snapshotType,
consensusSnapshotURL: config.baseConfig.consensusSnapshotURL,
executionSnapshotURL: config.baseConfig.executionSnapshotURL,
consensusCheckpointSyncURL: config.baseConfig.consensusCheckpointSyncURL,
nodeRole: <EthNodeRole> "rpc-node",
instanceType: config.rpcNodeConfig.instanceType,
instanceCpuType: config.rpcNodeConfig.instanceCpuType,
numberOfNodes: config.rpcNodeConfig.numberOfNodes,
albHealthCheckGracePeriodMin: config.rpcNodeConfig.albHealthCheckGracePeriodMin,
heartBeatDelayMin: config.rpcNodeConfig.heartBeatDelayMin,
dataVolumes: config.syncNodeConfig.dataVolumes,
dataVolume: config.syncNodeConfig.dataVolumes[0],
});


Expand Down
11 changes: 0 additions & 11 deletions lib/ethereum/lib/assets/copy-data-to-s3.sh

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[cfn-auto-reloader-hook]
triggers=post.update
path=Resources.WebServerHost.Metadata.AWS::CloudFormation::Init
action=/opt/aws/bin/cfn-init -v --stack __AWS_STACK_NAME__ --resource WebServerHost --region __AWS_REGION__
5 changes: 5 additions & 0 deletions lib/ethereum/lib/assets/instance/cfn-hup/cfn-hup.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[main]
stack=__AWS_STACK_ID__
region=__AWS_REGION__
# The interval used to check for changes to the resource metadata in minutes. Default is 15
interval=2
8 changes: 8 additions & 0 deletions lib/ethereum/lib/assets/instance/cfn-hup/cfn-hup.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[Unit]
Description=cfn-hup daemon
[Service]
Type=simple
ExecStart=/usr/local/bin/cfn-hup
Restart=always
[Install]
WantedBy=multi-user.target
Loading
Loading