Skip to content

Commit

Permalink
Adds rest and cdn support for client nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
howardwu committed Sep 22, 2023
1 parent 53998a1 commit ab8a77f
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 29 deletions.
31 changes: 17 additions & 14 deletions cli/src/commands/start.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ const RECOMMENDED_MIN_NOFILES_LIMIT: u64 = 2048;

/// The development mode RNG seed.
const DEVELOPMENT_MODE_RNG_SEED: u64 = 1234567890u64;
/// The development mode number of validators.
const DEVELOPMENT_MODE_NUM_VALIDATORS: u16 = 4;
/// The development mode number of genesis committee members.
const DEVELOPMENT_MODE_NUM_GENESIS_COMMITTEE_MEMBERS: u16 = 4;
/// The development mode number of nodes with public balance.
const DEVELOPMENT_MODE_NUM_NODES_WITH_PUBLIC_BALANCE: u16 = 50;

/// Starts the snarkOS node.
#[derive(Clone, Debug, Parser)]
Expand Down Expand Up @@ -183,10 +185,9 @@ impl Start {
// Disable CDN if:
// 1. The node is in development mode.
// 2. The user has explicitly disabled CDN.
// 3. The node is a client (no need to sync).
// 4. The node is a prover (no need to sync).
// 5. The node type is not declared (defaults to client) (no need to sync).
if self.dev.is_some() || self.cdn.is_empty() || self.client || self.prover || is_no_node_type {
// 3. The node is a prover (no need to sync).
// 4. The node type is not declared (defaults to client) (no need to sync).
if self.dev.is_some() || self.cdn.is_empty() || self.prover || is_no_node_type {
None
}
// Enable the CDN otherwise.
Expand Down Expand Up @@ -243,7 +244,7 @@ impl Start {
crate::commands::Clean::remove_ledger(N::ID, Some(dev))?;

// To avoid ambiguity, we define the first few nodes to be the trusted validators to connect to.
for i in 0..DEVELOPMENT_MODE_NUM_VALIDATORS {
for i in 0..DEVELOPMENT_MODE_NUM_GENESIS_COMMITTEE_MEMBERS {
if i != dev {
trusted_validators.push(SocketAddr::from_str(&format!("127.0.0.1:{}", MEMORY_POOL_PORT + i))?);
}
Expand Down Expand Up @@ -271,25 +272,27 @@ impl Start {
// Initialize the (fixed) RNG.
let mut rng = ChaChaRng::seed_from_u64(DEVELOPMENT_MODE_RNG_SEED);
// Initialize the development private keys.
let development_private_keys = (0..DEVELOPMENT_MODE_NUM_VALIDATORS)
let development_private_keys = (0..DEVELOPMENT_MODE_NUM_NODES_WITH_PUBLIC_BALANCE)
.map(|_| PrivateKey::<N>::new(&mut rng))
.collect::<Result<Vec<_>>>()?;

// Construct the committee members.
let members = development_private_keys
.iter()
.take(DEVELOPMENT_MODE_NUM_GENESIS_COMMITTEE_MEMBERS as usize)
.map(|private_key| Ok((Address::try_from(private_key)?, (MIN_VALIDATOR_STAKE, true))))
.collect::<Result<indexmap::IndexMap<_, _>>>()?;
// Construct the committee.
let committee = Committee::<N>::new_genesis(members)?;

// Determine the public balance per validator.
let public_balance_per_validator = (N::STARTING_SUPPLY
- (DEVELOPMENT_MODE_NUM_VALIDATORS as u64 * MIN_VALIDATOR_STAKE))
/ (DEVELOPMENT_MODE_NUM_VALIDATORS as u64);
- (DEVELOPMENT_MODE_NUM_GENESIS_COMMITTEE_MEMBERS as u64 * MIN_VALIDATOR_STAKE))
/ (DEVELOPMENT_MODE_NUM_NODES_WITH_PUBLIC_BALANCE as u64);
assert_eq!(
N::STARTING_SUPPLY,
(MIN_VALIDATOR_STAKE + public_balance_per_validator) * DEVELOPMENT_MODE_NUM_VALIDATORS as u64,
(DEVELOPMENT_MODE_NUM_GENESIS_COMMITTEE_MEMBERS as u64 * MIN_VALIDATOR_STAKE)
+ (DEVELOPMENT_MODE_NUM_NODES_WITH_PUBLIC_BALANCE as u64 * public_balance_per_validator),
"The public balance per validator is not correct."
);

Expand Down Expand Up @@ -383,7 +386,7 @@ impl Start {
match node_type {
NodeType::Validator => Node::new_validator(self.node, rest_ip, account, &trusted_peers, &trusted_validators, genesis, cdn, self.dev).await,
NodeType::Prover => Node::new_prover(self.node, account, &trusted_peers, genesis, self.dev).await,
NodeType::Client => Node::new_client(self.node, account, &trusted_peers, genesis, self.dev).await,
NodeType::Client => Node::new_client(self.node, rest_ip, account, &trusted_peers, genesis, cdn, self.dev).await,
}
}

Expand Down Expand Up @@ -523,10 +526,10 @@ mod tests {

// Client (Prod)
let config = Start::try_parse_from(["snarkos", "--client", "--private-key", "aleo1xx"].iter()).unwrap();
assert!(config.parse_cdn().is_none());
assert!(config.parse_cdn().is_some());
let config =
Start::try_parse_from(["snarkos", "--client", "--private-key", "aleo1xx", "--cdn", "url"].iter()).unwrap();
assert!(config.parse_cdn().is_none());
assert!(config.parse_cdn().is_some());
let config =
Start::try_parse_from(["snarkos", "--client", "--private-key", "aleo1xx", "--cdn", ""].iter()).unwrap();
assert!(config.parse_cdn().is_none());
Expand Down
5 changes: 1 addition & 4 deletions node/rest/src/routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,7 @@ impl<N: Network, C: ConsensusStorage<N>, R: Routing<N>> Rest<N, C, R> {

// GET /testnet3/committee/latest
pub(crate) async fn get_committee_latest(State(rest): State<Self>) -> Result<ErasedJson, RestError> {
match rest.consensus {
Some(consensus) => Ok(ErasedJson::pretty(consensus.ledger().current_committee()?)),
None => Err(RestError("route isn't available for this node type".to_string())),
}
Ok(ErasedJson::pretty(rest.ledger.latest_committee()?))
}

// GET /testnet3/peers/count
Expand Down
46 changes: 36 additions & 10 deletions node/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ mod router;
use crate::traits::NodeInterface;
use snarkos_account::Account;
use snarkos_node_narwhal::ledger_service::CoreLedgerService;
use snarkos_node_rest::Rest;
use snarkos_node_router::{
messages::{Message, NodeType, UnconfirmedSolution},
Heartbeat,
Expand Down Expand Up @@ -52,8 +53,12 @@ use tokio::task::JoinHandle;
/// A client node is a full node, capable of querying with the network.
#[derive(Clone)]
pub struct Client<N: Network, C: ConsensusStorage<N>> {
/// The ledger of the node.
ledger: Ledger<N, C>,
/// The router of the node.
router: Router<N>,
/// The REST server of the node.
rest: Option<Rest<N, C, Self>>,
/// The sync module.
sync: Arc<BlockSync<N>>,
/// The genesis block.
Expand All @@ -76,27 +81,29 @@ impl<N: Network, C: ConsensusStorage<N>> Client<N, C> {
/// Initializes a new client node.
pub async fn new(
node_ip: SocketAddr,
rest_ip: Option<SocketAddr>,
account: Account<N>,
trusted_peers: &[SocketAddr],
genesis: Block<N>,
cdn: Option<String>,
dev: Option<u16>,
) -> Result<Self> {
// Initialize the signal handler.
let signal_node = Self::handle_signals();

// Initialize the ledger.
let ledger = Ledger::<N, C>::load(genesis.clone(), dev)?;
// // Initialize the CDN.
// if let Some(base_url) = cdn {
// // Sync the ledger with the CDN.
// if let Err((_, error)) = snarkos_node_cdn::sync_ledger_with_cdn(&base_url, ledger.clone()).await {
// crate::helpers::log_clean_error(dev);
// return Err(error);
// }
// }
// Initialize the CDN.
if let Some(base_url) = cdn {
// Sync the ledger with the CDN.
if let Err((_, error)) = snarkos_node_cdn::sync_ledger_with_cdn(&base_url, ledger.clone()).await {
crate::log_clean_error(dev);
return Err(error);
}
}

// Initialize the ledger service.
let ledger_service = Arc::new(CoreLedgerService::<N, C>::new(ledger));
let ledger_service = Arc::new(CoreLedgerService::<N, C>::new(ledger.clone()));
// Initialize the sync module.
let sync = BlockSync::new(BlockSyncMode::Router, ledger_service.clone());

Expand All @@ -113,8 +120,10 @@ impl<N: Network, C: ConsensusStorage<N>> Client<N, C> {
// Load the coinbase puzzle.
let coinbase_puzzle = CoinbasePuzzle::<N>::load()?;
// Initialize the node.
let node = Self {
let mut node = Self {
ledger: ledger.clone(),
router,
rest: None,
sync: Arc::new(sync),
genesis,
coinbase_puzzle,
Expand All @@ -124,6 +133,11 @@ impl<N: Network, C: ConsensusStorage<N>> Client<N, C> {
shutdown: Default::default(),
_phantom: PhantomData,
};

// Initialize the REST server.
if let Some(rest_ip) = rest_ip {
node.rest = Some(Rest::start(rest_ip, None, ledger.clone(), Arc::new(node.clone()))?);
}
// Initialize the routing.
node.initialize_routing().await;
// Initialize the sync module.
Expand All @@ -134,6 +148,18 @@ impl<N: Network, C: ConsensusStorage<N>> Client<N, C> {
Ok(node)
}

/// Returns the ledger.
pub fn ledger(&self) -> &Ledger<N, C> {
&self.ledger
}

/// Returns the REST server.
pub fn rest(&self) -> &Option<Rest<N, C, Self>> {
&self.rest
}
}

impl<N: Network, C: ConsensusStorage<N>> Client<N, C> {
/// Initializes the sync pool.
fn initialize_sync(&self) {
// Start the sync loop.
Expand Down
4 changes: 3 additions & 1 deletion node/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,14 @@ impl<N: Network> Node<N> {
/// Initializes a new client node.
pub async fn new_client(
node_ip: SocketAddr,
rest_ip: Option<SocketAddr>,
account: Account<N>,
trusted_peers: &[SocketAddr],
genesis: Block<N>,
cdn: Option<String>,
dev: Option<u16>,
) -> Result<Self> {
Ok(Self::Client(Arc::new(Client::new(node_ip, account, trusted_peers, genesis, dev).await?)))
Ok(Self::Client(Arc::new(Client::new(node_ip, rest_ip, account, trusted_peers, genesis, cdn, dev).await?)))
}

/// Returns the node type.
Expand Down
2 changes: 2 additions & 0 deletions node/tests/common/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ use std::str::FromStr;
pub async fn client() -> Client<CurrentNetwork, ConsensusMemory<CurrentNetwork>> {
Client::new(
"127.0.0.1:0".parse().unwrap(),
None,
Account::<CurrentNetwork>::from_str("APrivateKey1zkp2oVPTci9kKcUprnbzMwq95Di1MQERpYBhEeqvkrDirK1").unwrap(),
&[],
sample_genesis_block(),
None, // No CDN.
None,
)
.await
Expand Down

0 comments on commit ab8a77f

Please sign in to comment.