main.rs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. use std::{net::SocketAddr, thread, time};
  2. use async_executor::Executor;
  3. use async_std::sync::Arc;
  4. use clap::{IntoApp, Parser};
  5. use easy_parallel::Parallel;
  6. use serde::{Deserialize, Serialize};
  7. use simplelog::{ColorChoice, TermLogger, TerminalMode};
  8. use darkfi::{
  9. rpc::rpcserver::{listen_and_serve, RpcServerConfig},
  10. util::{
  11. cli::{log_config, spawn_config, Config},
  12. expand_path,
  13. path::get_config_path,
  14. },
  15. Result,
  16. };
  17. use consensusd::service::{APIService, State};
  18. /// This struct represent the configuration parameters used by the Consensus daemon.
  19. #[derive(Debug, Clone, Deserialize, Serialize)]
  20. pub struct ConsensusdConfig {
  21. /// The endpoint where chaind will bind its RPC socket
  22. pub rpc_listen_address: SocketAddr,
  23. /// Whether to listen with TLS or plain TCP
  24. pub serve_tls: bool,
  25. /// Path to DER-formatted PKCS#12 archive. (Unused if serve_tls=false)
  26. pub tls_identity_path: String,
  27. /// Password for the TLS identity. (Unused if serve_tls=false)
  28. pub tls_identity_password: String,
  29. /// Path to the state file
  30. pub state_path: String,
  31. /// Node ID, used only for testing
  32. pub id: u64,
  33. }
  34. /// Chaind cli configuration.
  35. #[derive(Parser)]
  36. #[clap(name = "consensusd")]
  37. pub struct CliConsensusd {
  38. /// Sets a custom config file
  39. #[clap(short, long)]
  40. pub config: Option<String>,
  41. /// Increase verbosity
  42. #[clap(short, parse(from_occurrences))]
  43. pub verbose: u8,
  44. }
  45. /// RPCAPI service initialization.
  46. async fn api_service_init(executor: Arc<Executor<'_>>, config: &ConsensusdConfig) -> Result<()> {
  47. let server_config = RpcServerConfig {
  48. socket_addr: config.rpc_listen_address,
  49. use_tls: config.serve_tls,
  50. identity_path: expand_path(&config.clone().tls_identity_path)?,
  51. identity_pass: config.tls_identity_password.clone(),
  52. };
  53. let state_path = expand_path(&config.state_path)?;
  54. let id = config.id;
  55. let api_service = APIService::new(id, state_path)?;
  56. listen_and_serve(server_config, api_service, executor).await
  57. }
  58. /// RPCAPI:
  59. /// Node checks if its the current slot leader and generates the slot Block (represented as a Vote structure).
  60. /// TODO: 1. Nodes count not hard coded.
  61. /// 2. Proposed block broadcast.
  62. fn proposal_task(config: &ConsensusdConfig) {
  63. let state_path = expand_path(&config.state_path).unwrap();
  64. let id = config.id;
  65. let nodes_count = 1;
  66. println!("Waiting for state initialization...");
  67. thread::sleep(time::Duration::from_secs(10));
  68. // After initialization node should wait for next epoch
  69. let state = State::load_current_state(id, &state_path).unwrap();
  70. let seconds_until_next_epoch = state.get_seconds_until_next_epoch_start();
  71. println!("Waiting for next epoch({:?} sec)...", seconds_until_next_epoch);
  72. thread::sleep(seconds_until_next_epoch);
  73. loop {
  74. let state = State::load_current_state(id, &state_path).unwrap();
  75. let proposed_block =
  76. if state.check_if_epoch_leader(nodes_count) { state.propose_block() } else { None };
  77. if proposed_block.is_none() {
  78. println!("Node is not the epoch leader. Sleeping till next epoch...");
  79. } else {
  80. // TODO: Proposed block broadcast.
  81. println!("Node is the epoch leader. Proposed block: {:?}", proposed_block);
  82. }
  83. let seconds_until_next_epoch = state.get_seconds_until_next_epoch_start();
  84. println!("Waiting for next epoch({:?} sec)...", seconds_until_next_epoch);
  85. thread::sleep(seconds_until_next_epoch);
  86. }
  87. }
  88. const CONFIG_FILE_CONTENTS: &[u8] = include_bytes!("../consensusd_config.toml");
  89. /// Consensus daemon initialization.
  90. #[async_std::main]
  91. async fn main() -> Result<()> {
  92. let args = CliConsensusd::parse();
  93. let matches = CliConsensusd::command().get_matches();
  94. let verbosity_level = matches.occurrences_of("verbose");
  95. let (lvl, conf) = log_config(verbosity_level)?;
  96. TermLogger::init(lvl, conf, TerminalMode::Mixed, ColorChoice::Auto)?;
  97. let config_path = get_config_path(args.config, "consensusd_config.toml")?;
  98. spawn_config(&config_path, CONFIG_FILE_CONTENTS)?;
  99. let config: ConsensusdConfig = Config::<ConsensusdConfig>::load(config_path)?;
  100. let main_ex = Arc::new(Executor::new());
  101. let api_ex = main_ex.clone();
  102. let (signal, shutdown) = async_channel::unbounded::<()>();
  103. let signal1 = signal.clone();
  104. let signal2 = signal.clone();
  105. let (result, _) = Parallel::new()
  106. // Run the RCP API service future in background.
  107. .add(|| {
  108. smol::future::block_on(async {
  109. api_service_init(api_ex, &config).await?;
  110. drop(signal1);
  111. Ok::<(), darkfi::Error>(())
  112. })
  113. })
  114. // Run the proposal task in background.
  115. .add(|| {
  116. proposal_task(&config);
  117. drop(signal2);
  118. Ok::<(), darkfi::Error>(())
  119. })
  120. // Run the shutdown signal receive future on the current thread.
  121. .finish(|| smol::future::block_on(main_ex.run(shutdown.recv())));
  122. result.first().unwrap().clone()
  123. }