Skip to content

Commit

Permalink
Full node initial (MystenLabs#1969)
Browse files Browse the repository at this point in the history
* Initial full node impl
  • Loading branch information
oxade authored May 16, 2022
1 parent 71128f5 commit a74e7c3
Show file tree
Hide file tree
Showing 15 changed files with 991 additions and 184 deletions.
1 change: 1 addition & 0 deletions crates/sui-config/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ move-binary-format = { git = "https://github.com/move-language/move", rev = "1b2
move-package = { git = "https://github.com/move-language/move", rev = "1b2d3b4274345f5b4b6a1a1bde5aee452003ab5b" }

sui-framework = { path = "../../sui_programmability/framework" }

sui-adapter = { path = "../sui-adapter" }
sui-types = { path = "../sui-types" }
26 changes: 17 additions & 9 deletions sui/src/bin/node.rs → sui/src/bin/full_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,20 @@ use std::{
};
use sui::{
api::{RpcGatewayOpenRpc, RpcGatewayServer},
config::sui_config_dir,
sui_node::SuiNode,
config::{sui_config_dir, FULL_NODE_DB_PATH},
sui_full_node::SuiFullNode,
};
use tracing::info;

const DEFAULT_NODE_SERVER_PORT: &str = "5002";
const DEFAULT_NODE_SERVER_ADDR_IPV4: &str = "127.0.0.1";

#[derive(Parser)]
#[clap(
name = "Sui Node",
about = "A Byzantine fault tolerant chain with low-latency finality and high throughput",
rename_all = "kebab-case"
)]
#[clap(name = "Sui Full Node", about = "TODO", rename_all = "kebab-case")]
struct SuiNodeOpt {
#[clap(long)]
db_path: Option<String>,

#[clap(long)]
config: Option<PathBuf>,

Expand All @@ -50,9 +49,14 @@ async fn main() -> anyhow::Result<()> {
let guard = telemetry_subscribers::init(config);

let options: SuiNodeOpt = SuiNodeOpt::parse();
let db_path = options
.db_path
.map(PathBuf::from)
.unwrap_or(sui_config_dir()?.join(FULL_NODE_DB_PATH));

let config_path = options
.config
.unwrap_or(sui_config_dir()?.join("node.conf"));
.unwrap_or(sui_config_dir()?.join("network.conf"));
info!("Node config file path: {:?}", config_path);

let server_builder = HttpServerBuilder::default();
Expand All @@ -75,7 +79,11 @@ async fn main() -> anyhow::Result<()> {
let mut module = RpcModule::new(());
let open_rpc = RpcGatewayOpenRpc::open_rpc();
module.register_method("rpc.discover", move |_, _| Ok(open_rpc.clone()))?;
module.merge(SuiNode::new(&config_path)?.into_rpc())?;
module.merge(
SuiFullNode::start_with_genesis(&config_path, &db_path)
.await?
.into_rpc(),
)?;

info!(
"Available JSON-RPC methods : {:?}",
Expand Down
2 changes: 2 additions & 0 deletions sui/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ const SUI_CONFIG_DIR: &str = "sui_config";
pub const SUI_NETWORK_CONFIG: &str = "network.conf";
pub const SUI_WALLET_CONFIG: &str = "wallet.conf";
pub const SUI_GATEWAY_CONFIG: &str = "gateway.conf";
pub const FULL_NODE_DB_PATH: &str = "full_node_db";

pub const SUI_DEV_NET_URL: &str = "https://gateway.devnet.sui.io:9000";

pub fn sui_config_dir() -> Result<PathBuf, anyhow::Error> {
Expand Down
2 changes: 1 addition & 1 deletion sui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ pub mod rpc_gateway;
pub mod rpc_gateway_client;
pub mod shell;
pub mod sui_commands;
pub mod sui_node;
pub mod sui_full_node;
pub mod wallet_commands;
1 change: 1 addition & 0 deletions sui/src/sui_commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::{
use anyhow::{anyhow, bail};
use base64ct::{Base64, Encoding};
use clap::*;

use std::fs;
use std::num::NonZeroUsize;
use std::path::PathBuf;
Expand Down
218 changes: 218 additions & 0 deletions sui/src/sui_full_node.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use std::{
collections::BTreeMap,
path::{Path, PathBuf},
sync::Arc,
time::Duration,
};
use sui_types::sui_serde::Base64;

use crate::{
api::{RpcGatewayServer, TransactionBytes},
rpc_gateway::responses::{ObjectResponse, SuiTypeTag},
};
use anyhow::anyhow;
use async_trait::async_trait;
use jsonrpsee::core::RpcResult;
use sui_config::{NetworkConfig, PersistedConfig};
use sui_core::{
authority::ReplicaStore,
full_node::FullNodeState,
gateway_types::{
GetObjectInfoResponse, SuiObjectRef, TransactionEffectsResponse, TransactionResponse,
},
sui_json::SuiJsonValue,
};
use sui_core::{
authority_client::NetworkAuthorityClient, full_node::FullNode,
gateway_state::GatewayTxSeqNumber,
};
use sui_types::{
base_types::{ObjectID, SuiAddress, TransactionDigest},
error::SuiError,
};
use tracing::info;

pub struct SuiFullNode {
client: FullNode<NetworkAuthorityClient>,
}

impl SuiFullNode {
pub async fn start_with_genesis(
network_config_path: &Path,
db_path: &Path,
) -> anyhow::Result<Self> {
// Network config is all we need for now
let network_config: NetworkConfig = PersistedConfig::read(network_config_path)?;

// Start a full node
let full_node = make_full_node(db_path.to_path_buf(), &network_config).await?;
full_node.spawn_tasks().await;
info!("Started full node ");

Ok(Self { client: full_node })
}
}

#[async_trait]
impl RpcGatewayServer for SuiFullNode {
async fn transfer_coin(
&self,
_signer: SuiAddress,
_object_id: ObjectID,
_gas: Option<ObjectID>,
_gas_budget: u64,
_recipient: SuiAddress,
) -> RpcResult<TransactionBytes> {
Err(anyhow!("Sui Node only supports read-only methods").into())
}

async fn publish(
&self,
_sender: SuiAddress,
_compiled_modules: Vec<Base64>,
_gas: Option<ObjectID>,
_gas_budget: u64,
) -> RpcResult<TransactionBytes> {
Err(anyhow!("Sui Node only supports read-only methods").into())
}

async fn split_coin(
&self,
_signer: SuiAddress,
_coin_object_id: ObjectID,
_split_amounts: Vec<u64>,
_gas: Option<ObjectID>,
_gas_budget: u64,
) -> RpcResult<TransactionBytes> {
Err(anyhow!("Sui Node only supports read-only methods").into())
}

async fn merge_coin(
&self,
_signer: SuiAddress,
_primary_coin: ObjectID,
_coin_to_merge: ObjectID,
_gas: Option<ObjectID>,
_gas_budget: u64,
) -> RpcResult<TransactionBytes> {
Err(anyhow!("Sui Node only supports read-only methods").into())
}

async fn execute_transaction(
&self,
_tx_bytes: Base64,
_signature: Base64,
_pub_key: Base64,
) -> RpcResult<TransactionResponse> {
Err(anyhow!("Sui Node only supports read-only methods").into())
}

async fn move_call(
&self,
_signer: SuiAddress,
_package_object_id: ObjectID,
_module: String,
_function: String,
_type_arguments: Vec<SuiTypeTag>,
_rpc_arguments: Vec<SuiJsonValue>,
_gas: Option<ObjectID>,
_gas_budget: u64,
) -> RpcResult<TransactionBytes> {
Err(anyhow!("Sui Node only supports read-only methods").into())
}

async fn sync_account_state(&self, _address: SuiAddress) -> RpcResult<()> {
todo!()
}

//
// Read APIs
//

async fn get_owned_objects(&self, owner: SuiAddress) -> RpcResult<ObjectResponse> {
let resp = ObjectResponse {
objects: self
.client
.get_owned_objects(owner)
.await?
.iter()
.map(|w| SuiObjectRef::from(*w))
.collect(),
};
Ok(resp)
}

async fn get_object_info(&self, object_id: ObjectID) -> RpcResult<GetObjectInfoResponse> {
Ok(self
.client
.get_object_info(object_id)
.await?
.try_into()
.map_err(|e| anyhow!("{}", e))?)
}

async fn get_total_transaction_number(&self) -> RpcResult<u64> {
Ok(self.client.state.get_total_transaction_number()?)
}

async fn get_transactions_in_range(
&self,
start: GatewayTxSeqNumber,
end: GatewayTxSeqNumber,
) -> RpcResult<Vec<(GatewayTxSeqNumber, TransactionDigest)>> {
Ok(self.client.state.get_transactions_in_range(start, end)?)
}

async fn get_recent_transactions(
&self,
count: u64,
) -> RpcResult<Vec<(GatewayTxSeqNumber, TransactionDigest)>> {
Ok(self.client.state.get_recent_transactions(count)?)
}

async fn get_transaction(
&self,
digest: TransactionDigest,
) -> RpcResult<TransactionEffectsResponse> {
Ok(self.client.state.get_transaction(digest).await?)
}
}

pub async fn make_full_node(
db_store_path: PathBuf,
net_config: &NetworkConfig,
) -> Result<FullNode<NetworkAuthorityClient>, SuiError> {
let store = Arc::new(ReplicaStore::open(db_store_path, None));

let val_config = net_config
.validator_configs()
.iter()
.next()
.expect("Validtor set must be non empty");

let follower_node_state =
FullNodeState::new_with_genesis(net_config.committee(), store, val_config.genesis())
.await?;

let mut authority_clients = BTreeMap::new();
let mut config = mysten_network::config::Config::new();
config.connect_timeout = Some(Duration::from_secs(5));
config.request_timeout = Some(Duration::from_secs(5));
for validator in net_config
.validator_configs()
.iter()
.next()
.unwrap()
.committee_config()
.validator_set()
{
let channel = config.connect_lazy(validator.network_address()).unwrap();
let client = NetworkAuthorityClient::new(channel);
authority_clients.insert(validator.public_key(), client);
}

Ok(FullNode::new(Arc::new(follower_node_state), authority_clients).unwrap())
}
Loading

0 comments on commit a74e7c3

Please sign in to comment.