Skip to content

Commit f4112b9

Browse files
authored
Merge pull request #92 from aws-samples/sui
Sui
2 parents 8578024 + 577c623 commit f4112b9

20 files changed

+1816
-0
lines changed

lib/sui/README.md

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
# Sample AWS Blockchain Node Runner app for Sui Full Node
2+
3+
| Contributed by |
4+
|:--------------------:|
5+
| [@yinalaws](https://github.com/yinalaws), [@evertonfraga](https://github.com/evertonfraga) |
6+
7+
## Architecture Overview
8+
9+
This blueprint has step by step guides to set up a single Sui Full Node.
10+
11+
12+
### Sui Full Node setup
13+
![SingleNodeSetup](./doc/assets/Architecture-SingleNode.png)
14+
15+
This setup is for PoC or development environments and it supports Devnet, Testnet and Mainnet. It deploys a single EC2 instance with Sui client. The RPC port is exposed only to internal IP range of the VPC, while P2P ports allow external access to keep the client synced.
16+
17+
## Solution Walkthrough
18+
19+
### Setup Cloud9
20+
21+
We will use AWS Cloud9 to execute the subsequent commands. Follow the instructions in [Cloud9 Setup](../../docs/setup-cloud9.md)
22+
23+
### Clone this repository and install dependencies
24+
25+
```bash
26+
git clone https://github.com/aws-samples/aws-blockchain-node-runners.git
27+
cd aws-blockchain-node-runners
28+
npm install
29+
```
30+
31+
**NOTE:** In this tutorial we will set all major configuration through environment variables, but you also can modify parameters in `config/config.ts`.
32+
33+
### Prepare to deploy nodes
34+
35+
1. Make sure you are in the root directory of the cloned repository
36+
37+
2. If you have deleted or don't have the default VPC, create default VPC
38+
39+
```bash
40+
aws ec2 create-default-vpc
41+
```
42+
43+
**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.
44+
45+
**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`
46+
47+
3. Configure your setup
48+
49+
Create your own copy of `.env` file and edit it:
50+
```bash
51+
# Make sure you are in aws-blockchain-node-runners/lib/Sui
52+
cd lib/sui
53+
pwd
54+
cp ./sample-configs/.env-sample-full .env
55+
nano .env
56+
```
57+
**NOTE:** You can find more examples inside the `sample-configs` directory.
58+
59+
60+
4. Deploy common components such as IAM role, and Amazon S3 bucket to store data snapshots
61+
62+
```bash
63+
pwd
64+
# Make sure you are in aws-blockchain-node-runners/lib/sui
65+
npx cdk deploy sui-common
66+
```
67+
68+
### Deploy Sui Full-Node
69+
70+
1. Deploy Full Node
71+
72+
```bash
73+
pwd
74+
# Make sure you are in aws-blockchain-node-runners/lib/sui
75+
npx cdk deploy sui-single-node --json --outputs-file single-node-deploy.json
76+
```
77+
**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`.
78+
79+
The EC2 instance will deploy, initialize the node and start the first sync. In Cloudformation the instance will show as successful once the node is running. From that point it still takes a while until the node is synced to the blockchain. You can check the sync status with the REST call below in step 4. If the `curl cannot connect to the node on port 9000, then the node is still importing. Once that's done, the curl command works.
80+
81+
2. After starting the node you need to wait for the inital syncronization process to finish. It may take from an hour to half a day depending on the the state of the network. You can use Amazon CloudWatch to track the progress. To see them:
82+
83+
- Navigate to [CloudWatch service](https://console.aws.amazon.com/cloudwatch/) (make sure you are in the region you have specified for `AWS_REGION`)
84+
- Open `Dashboards` and select `tz-single-node-<type>-<network>` from the list of dashboards.
85+
86+
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. Check if the JSON-RPC port is open and working — run the following command from a terminal:
87+
88+
``` We query if the node is synced to main
89+
## replace <your IP address> with your server IP address
90+
curl --location --request POST <your IP address>:9000 \
91+
--header 'Content-Type: application/json' \
92+
--data-raw '{ "jsonrpc":"2.0", "method":"rpc.discover","id":1}'
93+
```
94+
95+
The result should start like like this (the actual balance might change):
96+
97+
```
98+
{"jsonrpc":"2.0","result":{"openrpc":"1.2.6","info":{"title":"Sui JSON-RPC","description":"Sui JSON-RPC API for interaction with Sui Full node. Make RPC calls using https://fullnode.NETWORK.sui.io:443, where NETWORK is the network you want to use (testnet, devnet, mainnet). By default, local networks use port 9000.","contact":{"name":"Mysten Labs","url":"https://mystenlabs.com","email":"[email protected]"},"license":{"name":"Apache-2.0","url":"https://raw.githubusercontent.com/MystenLabs/sui/main/LICENSE"},"version":"1.28.2"},"methods
99+
```
100+
101+
102+
103+
104+
105+
106+
107+
108+
### Clearing up and undeploying everything
109+
110+
1. Undeploy RPC Nodes, Sync Nodes and Common components
111+
112+
```bash
113+
# Setting the AWS account id and region in case local .env file is lost
114+
export AWS_ACCOUNT_ID=<your_target_AWS_account_id>
115+
export AWS_REGION=<your_target_AWS_region>
116+
117+
pwd
118+
# Make sure you are in aws-blockchain-node-runners/lib/Sui
119+
120+
# Undeploy Single Fullnode
121+
cdk destroy sui-single-node
122+
123+
124+
# You need to manually delete an s3 bucket with a name similar to 'sui-snapshots-$accountid-tz-nodes-common' on the console,firstly empty the bucket,secondly delete the bucket,and then execute
125+
# Delete all common components like IAM role and Security Group
126+
cdk destroy sui-common
127+
```
128+
129+
2. Follow steps to delete the Cloud9 instance in [Cloud9 Setup](../../doc/setup-cloud9.md)
130+
131+
### FAQ
132+
133+
1. How to check the logs from the EC2 user-data script?
134+
135+
**Note:** In this tutorial we chose not to use SSH and use Session Manager instead. That allows you to log all sessions in AWS CloudTrail to see who logged into the server and when. If you receive an error similar to `SessionManagerPlugin is not found`, [install Session Manager plugin for AWS CLI](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html)
136+
137+
```bash
138+
pwd
139+
# Make sure you are in aws-blockchain-node-runners/lib/Sui
140+
141+
export INSTANCE_ID=$(jq -r '.["sui-single-node-testnet"].nodeinstanceid' single-node-deploy.json)
142+
echo "INSTANCE_ID=" $INSTANCE_ID
143+
aws ssm start-session --target $INSTANCE_ID
144+
sudo cat /var/log/cloud-init-output.log
145+
```
146+
147+
2. If SSH is disabled, how to login to fullnode instance?
148+
149+
```bash
150+
NODE_INTERNAL_IP=$(aws ec2 describe-instances --instance-ids $INSTANCE_ID --query 'Reservations[*].Instances[*].PrivateIpAddress' --output text)
151+
echo "NODE_INTERNAL_IP="$NODE_INTERNAL_IP
152+
pwd
153+
# Make sure you are in aws-blockchain-node-runners/lib/Sui
154+
aws ssm start-session --target $INSTANCE_ID
155+
156+
```
157+
158+
3. Service Tools
159+
160+
```
161+
#Check Sui version
162+
sui -V
163+
# Check node logs
164+
sudo journalctl -fu suid -o cat
165+
# Check node status
166+
sudo service suid status
167+
# Restart node
168+
sudo systemctl restart suid
169+
# Stop Node
170+
sudo systemctl stop suid
171+
# Start Node
172+
sudo systemctl start suid
173+
```
174+
175+
4. Journalctl and Node Status throws errors:
176+
177+
Set up archival fallback to enable your node to fallback to an archive in case of lag, add this block to your fullnode.yaml file as described here https://docs.sui.io/guides/operator/archives#set-up-archival-fallback. Restart Node
178+
179+
```
180+
Example:
181+
182+
state-archive-read-config:
183+
- object-store-config:
184+
object-store: "S3"
185+
# Use mysten-testnet-archives for testnet
186+
# Use mysten-mainnet-archives for mainnet
187+
bucket: "mysten-testnet-archives"
188+
# Use your AWS account access key id
189+
aws-access-key-id: ""
190+
# Use your AWS account secret access key
191+
aws-secret-access-key: ""
192+
aws-region: "us-west-2"
193+
object-store-connection-limit: 20
194+
# How many objects to read ahead when catching up
195+
concurrency: 5
196+
# Whether to prune local state based on latest checkpoint in archive.
197+
# This should stay false for most use cases
198+
use-for-pruning-watermark: false
199+
200+
```
201+
202+
5. Restoring a Full node using snapshots: Restoring using RocksDB snapshots to restore from a RocksDB snapshot, follow these steps (https://docs.sui.io/guides/operator/snapshots):
203+
```
204+
Syntax:
205+
sui-tool download-db-snapshot --latest \
206+
--network <NETWORK> --snapshot-bucket <BUCKET-NAME> \
207+
--snapshot-bucket-type <TYPE> --path <PATH-TO-NODE-DB> \
208+
--num-parallel-downloads 25 \
209+
--skip-indexes \
210+
--no-sign-request
211+
212+
213+
Example:
214+
sudo sui-tool download-db-snapshot --latest --network testnet --path /data/sui/db/live --num-parallel-downloads 50 --skip-indexes --no-sign-request
215+
216+
```
217+
218+
6. Compare the number of checkpoints on your node and on chain
219+
220+
```bash
221+
## replace <your IP address> with your server IP address
222+
curl -q <your IP address>:9184/metrics 2>/dev/null |grep '^highest_synced_checkpoint'; echo
223+
```
224+
```bash
225+
## replace <Network_ID> with devnet| testnet | mainnet
226+
curl --location --request POST 'https://fullnode.<Network_ID>.sui.io:443/' --header 'Content-Type: application/json' --data-raw '{"jsonrpc":"2.0", "id":1,"method":"sui_getLatestCheckpointSequenceNumber"}'; echo
227+
```
228+
229+
7. Monitoring Sui node metrics over port TCP/9184
230+
231+
```
232+
Enter your node's external IP at https://node.sui.zvalid.com/
233+
```

lib/sui/app.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/usr/bin/env node
2+
import "dotenv/config"
3+
import "source-map-support/register";
4+
import * as cdk from "aws-cdk-lib";
5+
import * as nag from "cdk-nag";
6+
import * as config from "./lib/config/suiConfig";
7+
import {SuiCommonStack} from "./lib/common-stack";
8+
import {SuiSingleNodeStack} from "./lib/single-node-stack";
9+
10+
const app = new cdk.App();
11+
cdk.Tags.of(app).add("Project", "AWS_Sui");
12+
13+
new SuiCommonStack(app, "sui-common", {
14+
env: { account: config.baseConfig.accountId, region: config.baseConfig.region },
15+
stackName: "sui-nodes-common",
16+
});
17+
18+
19+
20+
new SuiSingleNodeStack(app, "sui-single-node", {
21+
stackName: `sui-single-node-${config.baseNodeConfig.suiNetworkId}`,
22+
env: { account: config.baseConfig.accountId, region: config.baseConfig.region },
23+
instanceType: config.baseNodeConfig.instanceType,
24+
instanceCpuType: config.baseNodeConfig.instanceCpuType,
25+
dataVolume: config.baseNodeConfig.dataVolume,
26+
suiNetworkId: config.baseNodeConfig.suiNetworkId,
27+
});
28+
29+
// Security Check
30+
cdk.Aspects.of(app).add(
31+
new nag.AwsSolutionsChecks({
32+
verbose: false,
33+
reports: true,
34+
logIgnores: false,
35+
})
36+
);

lib/sui/cdk.json

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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+
"@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true,
44+
"@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true,
45+
"@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true,
46+
"@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true,
47+
"@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true,
48+
"@aws-cdk/aws-redshift:columnId": true,
49+
"@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true,
50+
"@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true,
51+
"@aws-cdk/aws-apigateway:requestValidatorUniqueId": true,
52+
"@aws-cdk/aws-kms:aliasNameRef": true,
53+
"@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true,
54+
"@aws-cdk/core:includePrefixInUniqueNameGeneration": true,
55+
"@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true
56+
}
57+
}
44.2 KB
Loading

lib/sui/jest.config.js

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

0 commit comments

Comments
 (0)