Skip to content

Commit 33a009a

Browse files
authored
Merge pull request #169 from acevesp/main
Add XRP Support
2 parents 056715c + a7dfc6f commit 33a009a

37 files changed

+4195
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,4 @@ ha-nodes-deploy*.json
3838
.env
3939
.idea
4040
.vscode
41+
.venv

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ If you'd like propose a Node Runner Blueprint for your node, see [Adding new Nod
1616
- `lib/constructs` - [CDK constructs](https://docs.aws.amazon.com/cdk/v2/guide/constructs.html) used in Node Runner Blueprints
1717
- `lib/your-chain` - Node Runner Blueprint for a specific chain
1818
- `website` - Content for the project web site built with [Docusaurus](https://docusaurus.io/)
19-
- `website/docs` - Place for the new blueprint deployment instructions. (If you are adding a new blueprint, use on of the existing examples to refer to the `README.md` file within your Node Runner Blueprint directory inside `lib`).
19+
- `website/docs` - Place for the new blueprint deployment instructions. (If you are adding a new blueprint, use one of the existing examples to refer to the `README.md` file within your Node Runner Blueprint directory inside `lib`).
2020

2121
### License
2222
This repository uses MIT License. See more in [LICENSE](./LICENSE).

lib/xrp/README.md

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
# Sample AWS Blockchain Node Runner app for XRP Nodes
2+
3+
| Contributed by |
4+
|:--------------------------------:|
5+
| [Pedro Aceves](https://github.com/acevesp)|
6+
7+
XRP node deployment on AWS. All nodes are configure as ["Stock Servers"](https://xrpl.org/docs/infrastructure/configuration/server-modes/run-rippled-as-a-stock-server)
8+
9+
## Overview of Deployment Architectures for Single and HA setups
10+
11+
### Single node setup
12+
13+
![Single Node Deployment](./doc/assets/Architecture-Single%20node.drawio.png)
14+
15+
1. A XRP node deployed in the [Default VPC](https://docs.aws.amazon.com/vpc/latest/userguide/default-vpc.html) continuously synchronizes with the rest of nodes on the configured xrp network through [Internet Gateway](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Internet_Gateway.html).
16+
2. The XRP node is used by dApps or development tools internally from within the Default VPC. RPC API is not exposed to the Internet directly to protect nodes from unauthorized access.
17+
3. The XRP node sends various monitoring metrics for both EC2 and current XRP ledger sequence to Amazon CloudWatch. It also updates the dashboard with correct storage device names to display respective metrics properly.
18+
19+
### HA setup
20+
21+
![Highly Available Nodes Deployment](./doc/assets/Architecture-HA%20Nodes.drawio.png)
22+
23+
1. A set of XRP nodes are deployed within an [Auto Scaling Group](https://docs.aws.amazon.com/autoscaling/ec2/userguide/auto-scaling-groups.html) in the [Default VPC](https://docs.aws.amazon.com/vpc/latest/userguide/default-vpc.html) continuously synchronizing with the rest of nodes on the configured xrp network through [Internet Gateway](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Internet_Gateway.html).
24+
2. The XRP nodes are accessed by dApps or development tools internally through [Application Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/introduction.html). RPC API is not exposed to the Internet to protect nodes from unauthorized access.
25+
3. The XRP nodes send various monitoring metrics for EC2 to Amazon CloudWatch.
26+
27+
## Well-Architected
28+
29+
<details>
30+
<summary>Review pros and cons of this solution.</summary>
31+
32+
### Well-Architected Checklist
33+
34+
This is the Well-Architected checklist for XRP nodes implementation of the AWS Blockchain Node Runner app. This checklist takes into account questions from the [AWS Well-Architected Framework](https://aws.amazon.com/architecture/well-architected/) which are relevant to this workload. Please feel free to add more checks from the framework if required for your workload.
35+
36+
| Pillar | Control | Question/Check | Remarks |
37+
|:------------------------|:----------------------------------|:---------------------------------------------------------------------------------|:-----------------|
38+
| Security | Network protection | Are there unnecessary open ports in security groups? | Please note that XRP sync ports remain open for outbound connections; Port 2459 and 51235 (TCP/UDP). |
39+
| | | Traffic inspection | AWS WAF could be implemented for traffic inspection. Additional charges will apply. |
40+
| | Compute protection | Reduce attack surface | This solution uses Amazon Linux 2 AMI. You may choose to run hardening scripts on it. |
41+
| | | Enable people to perform actions at a distance | This solution uses AWS Systems Manager for terminal session, not ssh ports. |
42+
| | Data protection at rest | Use encrypted Amazon Elastic Block Store (Amazon EBS) volumes | This solution uses encrypted Amazon EBS volumes. |
43+
| | | Use encrypted Amazon Simple Storage Service (Amazon S3) buckets | This solution uses Amazon S3 managed keys (SSE-S3) encryption. |
44+
| | Data protection in transit | Use TLS | The AWS Application Load balancer currently uses HTTP listener. Create HTTPS listener with self signed certificate if TLS is desired. |
45+
| | Authorization and access control | Use instance profile with Amazon Elastic Compute Cloud (Amazon EC2) instances | This solution uses AWS Identity and Access Management (AWS IAM) role instead of IAM user. |
46+
| | | Following principle of least privilege access | Privileges are scoped down. |
47+
| | Application security | Security focused development practices | cdk-nag is being used with appropriate suppressions. |
48+
| Cost optimization | Service selection | Use cost effective resources | Cost efficient R7a instances are being used, which are ideal for high transaction and low latecy workloads. |
49+
| Reliability | Resiliency implementation | Withstand component failures | This solution uses AWS Application Load Balancer with RPC nodes for high availability. |
50+
| | Resource monitoring | How are workload resources monitored? | Resources are being monitored using Amazon CloudWatch dashboards. Amazon CloudWatch custom metrics are being pushed via CloudWatch Agent. |
51+
| Performance efficiency | Compute selection | How is compute solution selected? | Compute solution is selected based on best price-performance. |
52+
| | Storage selection | How is storage solution selected? | Storage solution is selected based on best price-performance. |
53+
| Operational excellence | Workload health | How is health of workload determined? | Health of workload is determined via AWS Application Load Balancer Target Group Health Checks, on port 6005. |
54+
| Sustainability | Hardware & services | Select most efficient hardware for your workload | Amazon EC2 R7a instances support the Sustainability Pillar of the AWS Well-Architected Framework by offering memory optimization that enables more efficient resource utilization, potentially reducing overall energy consumption and hardware requirements for data-intensive workloads. |
55+
56+
</details>
57+
58+
## Setup Instructions
59+
60+
### Open AWS CloudShell
61+
62+
To begin, ensure you login to your AWS account with permissions to create and modify resources in IAM, EC2, EBS, VPC, S3, and KMS.
63+
64+
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.
65+
66+
Once ready, you can run the commands to deploy and test blueprints in the CloudShell.
67+
68+
### Clone this repository and install dependencies
69+
70+
```bash
71+
git clone https://github.com/aws-samples/aws-blockchain-node-runners.git
72+
cd aws-blockchain-node-runners
73+
npm install
74+
```
75+
76+
### Configure your setup
77+
78+
1. Make sure you are in the root directory of the cloned repository
79+
80+
2. If you have deleted or don't have the default VPC, create default VPC
81+
82+
```bash
83+
aws ec2 create-default-vpc
84+
```
85+
86+
> **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.*
87+
88+
3. Configure your setup
89+
90+
Create your own copy of `.env` file and edit it to update with your AWS Account ID and Region:
91+
```bash
92+
cd lib/xrp
93+
cp ./sample-configs/.env-sample-testnet .env
94+
nano .env
95+
```
96+
> **NOTE:** *You can find more examples inside `sample-configs`*
97+
98+
99+
4. Deploy common components such as IAM role:
100+
101+
```bash
102+
npx cdk deploy XRP-common
103+
```
104+
105+
106+
### Deploy a Single Node
107+
108+
1. Deploy the node
109+
110+
```bash
111+
npx cdk deploy XRP-single-node --json --outputs-file single-node-deploy.json
112+
```
113+
114+
2. After starting the node you need to wait for the initial synchronization process to finish. You can use Amazon CloudWatch to track the progress. There is a script that publishes CloudWatch metrics every 5 minutes, where you can watch `XRP Sequence` metrics. When the node is fully synced the sequence should match that of the configured xrp network (testnet, mainnet, etc). To see them:
115+
116+
- Navigate to [CloudWatch service](https://console.aws.amazon.com/cloudwatch/) (make sure you are in the region you have specified for `AWS_REGION`)
117+
- Open `Dashboards` and select dashboard that starts with `XRP-single-node` from the list of dashboards.
118+
119+
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. Run the following command to retrieve the private IP of the single RPC node you deployed:
120+
121+
```bash
122+
export INSTANCE_ID=$(cat single-node-deploy.json | jq -r '.["XRP-single-node"].nodeinstanceid')
123+
NODE_INTERNAL_IP=$(aws ec2 describe-instances --instance-ids $INSTANCE_ID --query 'Reservations[*].Instances[*].PrivateIpAddress' --output text)
124+
echo "NODE_INTERNAL_IP=$NODE_INTERNAL_IP"
125+
```
126+
127+
Copy output from the last `echo` command with `NODE_INTERNAL_IP=<internal_IP>` and open [CloudShell tab with VPC environment](https://docs.aws.amazon.com/cloudshell/latest/userguide/creating-vpc-environment.html) to access internal IP address space. Paste `NODE_INTERNAL_IP=<internal_IP>` into the new CloudShell tab.
128+
129+
Then query the RPC API to receive the latest block height:
130+
131+
``` bash
132+
# IMPORTANT: Run from CloudShell VPC environment tab
133+
curl -X POST -H "Content-Type: application/json" http://$NODE_INTERNAL_IP:6005/ -d '{
134+
"method": "ledger_current",
135+
"params": [{}]
136+
}'
137+
```
138+
You will get a response similar to this:
139+
140+
```json
141+
{"result":{"ledger_current_index":5147254,"status":"success"}}
142+
```
143+
144+
Note: If the node is still syncing, you will receive the following response:
145+
146+
```json
147+
{"result":{"error":"noNetwork","error_code":17,"error_message":"Not synced to the network.","request":{"command":"ledger_current"},"status":"error"}}
148+
```
149+
150+
### Deploy HA Nodes
151+
152+
1. Deploy multiple HA Nodes
153+
154+
```bash
155+
pwd
156+
# Make sure you are in aws-blockchain-node-runners/lib/xrp
157+
npx cdk deploy XRP-ha-nodes --json --outputs-file ha-nodes-deploy.json
158+
```
159+
160+
2. Give the new nodes time to initialize
161+
162+
3. To perform an RPC request to your load balancer, run the following command to retrieve the ALB URL:
163+
164+
```bash
165+
export XRP_RPC_ALB_URL=$(cat ha-nodes-deploy.json | jq -r '..|.alburl? | select(. != null)')
166+
echo XRP_RPC_ALB_URL=$XRP_RPC_ALB_URL
167+
```
168+
169+
Copy output from the last `echo` command with `XRP_RPC_ALB_URL=<alb_url>` and open [CloudShell tab with VPC environment](https://docs.aws.amazon.com/cloudshell/latest/userguide/creating-vpc-environment.html) to access internal IP address space. Paste `XRP_RPC_ALB_URL=<alb_url>` into the VPC CloudShell tab.
170+
171+
Then query the load balancer to retrieve the current block height:
172+
173+
```bash
174+
curl -X POST -H "Content-Type: application/json" http://$XRP_RPC_ALB_URL:6005/ -d '{
175+
"method": "ledger_current",
176+
"params": [{}]
177+
}'
178+
```
179+
180+
You will get a response similar to this:
181+
182+
```json
183+
{"result":{"ledger_current_index":5147300,"status":"success"}}
184+
```
185+
186+
> **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.*
187+
188+
### Cleaning up and undeploying everything
189+
190+
Destroy HA Nodes, Single Nodes and Common stacks
191+
192+
```bash
193+
pwd
194+
# Make sure you are in aws-blockchain-node-runners/lib/xrp
195+
196+
# Destroy HA Nodes
197+
npx cdk destroy XRP-ha-nodes
198+
199+
# Destroy Single Node
200+
npx cdk destroy XRP-single-node
201+
202+
# Delete all common components like IAM role and Security Group
203+
npx cdk destroy XRP-common
204+
```
205+
206+
### FAQ
207+
208+
1. How to check the logs from the EC2 user-data script?
209+
210+
```bash
211+
pwd
212+
# Make sure you are in aws-blockchain-node-runners/lib/xrp
213+
214+
export INSTANCE_ID=$(cat single-node-deploy.json | jq -r '.["XRP-single-node"].nodeinstanceid')
215+
echo "INSTANCE_ID=" $INSTANCE_ID
216+
aws ssm start-session --target $INSTANCE_ID --region $AWS_REGION
217+
sudo cat /var/log/cloud-init-output.log
218+
sudo cat /var/log/user-data.log
219+
```
220+
2. How can I change rippled (XRP) configuration?
221+
There are two places of configuration for the xrp nodes:
222+
223+
a. `.env` file. Here is where you specify the xrp network you want. This is the key for the config in part b
224+
225+
```bash
226+
HUB_NETWORK_ID="testnet"
227+
```
228+
229+
b. `lib/xrp/lib/assets/rippled/rippledconfig.py` file. Here you can setup listeners and network configuration for the network specified in part "a"

lib/xrp/app.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#!/usr/bin/env node
2+
import "dotenv/config";
3+
import * as cdk from "aws-cdk-lib";
4+
import * as nag from "cdk-nag";
5+
import * as config from "./lib/config/XRPConfig";
6+
7+
import { XRPSingleNodeStack } from "./lib/single-node-stack";
8+
import { XRPCommonStack } from "./lib/common-stack";
9+
import { XRPHANodesStack } from "./lib/ha-nodes-stack";
10+
11+
const app = new cdk.App();
12+
cdk.Tags.of(app).add("Project", "AWSXRP");
13+
14+
const commonStack = new XRPCommonStack(app, "XRP-common", {
15+
stackName: `XRP-nodes-common`,
16+
env: { account: config.baseConfig.accountId, region: config.baseConfig.region },
17+
});
18+
19+
new XRPSingleNodeStack(app, "XRP-single-node", {
20+
env: { account: config.baseConfig.accountId, region: config.baseConfig.region },
21+
stackName: `XRP-single-node`,
22+
instanceType: config.baseNodeConfig.instanceType,
23+
instanceCpuType: config.baseNodeConfig.instanceCpuType,
24+
dataVolume: config.baseNodeConfig.dataVolume,
25+
hubNetworkID: config.baseNodeConfig.hubNetworkID,
26+
instanceRole: commonStack.instanceRole,
27+
});
28+
29+
new XRPHANodesStack(app, "XRP-ha-nodes", {
30+
stackName: "xrp-ha-nodes",
31+
env: { account: config.baseConfig.accountId, region: config.baseConfig.region },
32+
instanceType: config.baseNodeConfig.instanceType,
33+
instanceCpuType: config.baseNodeConfig.instanceCpuType,
34+
dataVolume: config.baseNodeConfig.dataVolume,
35+
hubNetworkID: config.baseNodeConfig.hubNetworkID,
36+
instanceRole: commonStack.instanceRole,
37+
albHealthCheckGracePeriodMin: config.haNodeConfig.albHealthCheckGracePeriodMin,
38+
heartBeatDelayMin: config.haNodeConfig.heartBeatDelayMin,
39+
numberOfNodes: config.haNodeConfig.numberOfNodes,
40+
});
41+
42+
// Security Check
43+
cdk.Aspects.of(app).add(
44+
new nag.AwsSolutionsChecks({
45+
verbose: false,
46+
reports: true,
47+
logIgnores: false,
48+
})
49+
);

lib/xrp/cdk.json

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{
2+
"app": "npx ts-node --prefer-ts-exts app.ts",
3+
"watch": {
4+
"include": [
5+
"**"
6+
],
7+
"exclude": [
8+
"README.md",
9+
"cdk*.json",
10+
"**/*.d.ts",
11+
"**/*.js",
12+
"tsconfig.json",
13+
"package*.json",
14+
"yarn.lock",
15+
"node_modules",
16+
"test"
17+
]
18+
},
19+
"context": {
20+
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
21+
"@aws-cdk/core:checkSecretUsage": true,
22+
"@aws-cdk/core:target-partitions": [
23+
"aws",
24+
"aws-cn"
25+
],
26+
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
27+
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
28+
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
29+
"@aws-cdk/aws-iam:minimizePolicies": true,
30+
"@aws-cdk/core:validateSnapshotRemovalPolicy": true,
31+
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
32+
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
33+
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
34+
"@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
35+
"@aws-cdk/core:enablePartitionLiterals": true,
36+
"@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
37+
"@aws-cdk/aws-iam:standardizedServicePrincipals": true,
38+
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
39+
"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
40+
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
41+
"@aws-cdk/aws-route53-patters:useCertificate": true,
42+
"@aws-cdk/customresources:installLatestAwsSdkDefault": false
43+
}
44+
}
131 KB
Loading
99.1 KB
Loading

lib/xrp/jest.config.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module.exports = {
2+
testEnvironment: "node",
3+
roots: ["<rootDir>/test"],
4+
testMatch: ["**/*.test.ts"],
5+
transform: {
6+
"^.+\\.tsx?$": "ts-jest"
7+
},
8+
setupFiles: [
9+
"dotenv/config"
10+
]
11+
};

0 commit comments

Comments
 (0)