main.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. use std::{net::SocketAddr, path::PathBuf, sync::Arc, thread};
  2. use async_executor::Executor;
  3. use async_trait::async_trait;
  4. use easy_parallel::Parallel;
  5. use log::{debug, error, info};
  6. use serde::{Deserialize, Serialize};
  7. use serde_json::{json, Value};
  8. use simplelog::{ColorChoice, TermLogger, TerminalMode};
  9. use structopt::StructOpt;
  10. use structopt_toml::StructOptToml;
  11. use darkfi::{
  12. consensus::{
  13. participant::Participant,
  14. state::{ValidatorState, ValidatorStatePtr},
  15. tx::Tx,
  16. },
  17. net,
  18. rpc::{
  19. jsonrpc,
  20. jsonrpc::{
  21. from_result,
  22. ErrorCode::{InternalError, InvalidParams, InvalidRequest, MethodNotFound},
  23. JsonRequest, JsonResult, ValueResult,
  24. },
  25. rpcserver::{listen_and_serve, RequestHandler, RpcServerConfig},
  26. },
  27. util::{
  28. cli::{log_config, spawn_config},
  29. expand_path,
  30. path::get_config_path,
  31. },
  32. Result,
  33. };
  34. use validatord::protocols::{
  35. protocol_participant::ProtocolParticipant, protocol_proposal::ProtocolProposal,
  36. protocol_tx::ProtocolTx, protocol_vote::ProtocolVote,
  37. };
  38. const CONFIG_FILE: &str = r"validatord_config.toml";
  39. const CONFIG_FILE_CONTENTS: &[u8] = include_bytes!("../validatord_config.toml");
  40. #[derive(Debug, Deserialize, Serialize, StructOpt, StructOptToml)]
  41. #[serde(default)]
  42. struct Opt {
  43. #[structopt(short, long, default_value = CONFIG_FILE)]
  44. /// Configuration file to use
  45. config: String,
  46. #[structopt(long, default_value = "0.0.0.0:11000")]
  47. /// Accept address
  48. accept: SocketAddr,
  49. #[structopt(long)]
  50. /// Seed nodes
  51. seeds: Vec<SocketAddr>,
  52. #[structopt(long)]
  53. /// Manual connections
  54. connect: Vec<SocketAddr>,
  55. #[structopt(long, default_value = "5")]
  56. /// Connection slots
  57. slots: u32,
  58. #[structopt(long, default_value = "127.0.0.1:11000")]
  59. /// External address
  60. external: SocketAddr,
  61. #[structopt(long, default_value = "/tmp/darkfid.log")]
  62. /// Logfile path
  63. log: String,
  64. #[structopt(long, default_value = "127.0.0.1:6660")]
  65. /// The endpoint where validatord will bind its RPC socket
  66. rpc: SocketAddr,
  67. #[structopt(long)]
  68. /// Whether to listen with TLS or plain TCP
  69. tls: bool,
  70. #[structopt(long, default_value = "~/.config/darkfi/validatord_identity.pfx")]
  71. /// TLS certificate to use
  72. identity: PathBuf,
  73. #[structopt(long, default_value = "FOOBAR")]
  74. /// Password for the created TLS identity
  75. password: String,
  76. #[structopt(long, default_value = "1648383795")]
  77. /// Timestamp of the genesis block creation
  78. genesis: i64,
  79. #[structopt(long, default_value = "~/.config/darkfi/validatord_db_0")]
  80. /// Path to the sled database folder
  81. database: String,
  82. #[structopt(long, default_value = "0")]
  83. /// Node ID, used only for testing
  84. id: u64,
  85. #[structopt(short, long, default_value = "0")]
  86. /// How many threads to utilize
  87. threads: usize,
  88. #[structopt(short, long, parse(from_occurrences))]
  89. /// Multiple levels can be used (-vv)
  90. verbose: u8,
  91. }
  92. async fn proposal_task(p2p: net::P2pPtr, state: ValidatorStatePtr) {
  93. // Node signals the network that it starts participating
  94. let participant =
  95. Participant::new(state.read().unwrap().id, state.read().unwrap().current_epoch());
  96. state.write().unwrap().append_participant(participant.clone());
  97. let result = p2p.broadcast(participant).await;
  98. match result {
  99. Ok(()) => info!("Participation message broadcasted successfuly."),
  100. Err(e) => error!("Broadcast failed. Error: {:?}", e),
  101. }
  102. // After initialization node should wait for next epoch
  103. let seconds_until_next_epoch = state.read().unwrap().next_epoch_start();
  104. info!("Waiting for next epoch({:?} sec)...", seconds_until_next_epoch);
  105. thread::sleep(seconds_until_next_epoch);
  106. loop {
  107. // Node refreshes participants records
  108. state.write().unwrap().refresh_participants();
  109. // Node checks if its the epoch leader to generate a new proposal for that epoch
  110. let result = if state.write().unwrap().is_epoch_leader() {
  111. state.read().unwrap().propose()
  112. } else {
  113. Ok(None)
  114. };
  115. match result {
  116. Ok(proposal) => {
  117. if proposal.is_none() {
  118. info!("Node is not the epoch leader. Sleeping till next epoch...");
  119. } else {
  120. // Leader creates a vote for the proposal and broadcasts them both
  121. let unwrapped = proposal.unwrap();
  122. info!("Node is the epoch leader. Proposed block: {:?}", unwrapped);
  123. let vote = state.write().unwrap().receive_proposal(&unwrapped);
  124. match vote {
  125. Ok(x) => {
  126. if x.is_none() {
  127. debug!("Node did not vote for the proposed block.");
  128. } else {
  129. let vote = x.unwrap();
  130. let result = state.write().unwrap().receive_vote(&vote);
  131. match result {
  132. Ok(_) => info!("Vote saved successfuly."),
  133. Err(e) => error!("Vote save failed. Error: {:?}", e),
  134. }
  135. // Broadcasting block
  136. let result = p2p.broadcast(unwrapped).await;
  137. match result {
  138. Ok(()) => info!("Proposal broadcasted successfuly."),
  139. Err(e) => error!("Broadcast failed. Error: {:?}", e),
  140. }
  141. // Broadcasting leader vote
  142. let result = p2p.broadcast(vote).await;
  143. match result {
  144. Ok(()) => info!("Leader vote broadcasted successfuly."),
  145. Err(e) => error!("Broadcast failed. Error: {:?}", e),
  146. }
  147. }
  148. }
  149. Err(e) => {
  150. error!("Error prosessing proposal: {:?}", e)
  151. }
  152. }
  153. }
  154. }
  155. Err(e) => error!("Block proposal failed. Error: {:?}", e),
  156. }
  157. // Current node state is flushed to sled database
  158. let result = state.read().unwrap().save_consensus_state();
  159. match result {
  160. Ok(()) => (),
  161. Err(e) => {
  162. error!("State could not be flushed: {:?}", e)
  163. }
  164. };
  165. // Node waits untile next epoch
  166. let seconds_until_next_epoch = state.read().unwrap().next_epoch_start();
  167. info!("Waiting for next epoch({:?} sec)...", seconds_until_next_epoch);
  168. thread::sleep(seconds_until_next_epoch);
  169. }
  170. }
  171. async fn start(executor: Arc<Executor<'_>>, opts: &Opt) -> Result<()> {
  172. let rpc_server_config = RpcServerConfig {
  173. socket_addr: opts.rpc,
  174. use_tls: opts.tls,
  175. identity_path: opts.identity.clone(),
  176. identity_pass: opts.password.clone(),
  177. };
  178. let network_settings = net::Settings {
  179. inbound: Some(opts.accept),
  180. outbound_connections: opts.slots,
  181. external_addr: Some(opts.external),
  182. peers: opts.connect.clone(),
  183. seeds: opts.seeds.clone(),
  184. ..Default::default()
  185. };
  186. // State setup
  187. let genesis = opts.genesis;
  188. let database_path = expand_path(&opts.database).unwrap();
  189. let id = opts.id.clone();
  190. let state = ValidatorState::new(database_path, id, genesis).unwrap();
  191. // P2P registry setup
  192. let p2p = net::P2p::new(network_settings).await;
  193. let registry = p2p.protocol_registry();
  194. // Adding ProtocolTx to the registry
  195. let state2 = state.clone();
  196. registry
  197. .register(net::SESSION_ALL, move |channel, p2p| {
  198. let state = state2.clone();
  199. async move { ProtocolTx::init(channel, state, p2p).await }
  200. })
  201. .await;
  202. // Adding PropotolVote to the registry
  203. let state2 = state.clone();
  204. registry
  205. .register(net::SESSION_ALL, move |channel, p2p| {
  206. let state = state2.clone();
  207. async move { ProtocolVote::init(channel, state, p2p).await }
  208. })
  209. .await;
  210. // Adding ProtocolProposal to the registry
  211. let state2 = state.clone();
  212. registry
  213. .register(net::SESSION_ALL, move |channel, p2p| {
  214. let state = state2.clone();
  215. async move { ProtocolProposal::init(channel, state, p2p).await }
  216. })
  217. .await;
  218. // Adding ProtocolParticipant to the registry
  219. let state2 = state.clone();
  220. registry
  221. .register(net::SESSION_ALL, move |channel, p2p| {
  222. let state = state2.clone();
  223. async move { ProtocolParticipant::init(channel, state, p2p).await }
  224. })
  225. .await;
  226. // Performs seed session
  227. p2p.clone().start(executor.clone()).await?;
  228. // Actual main p2p session
  229. let ex2 = executor.clone();
  230. let p2p2 = p2p.clone();
  231. executor
  232. .spawn(async move {
  233. if let Err(err) = p2p2.run(ex2).await {
  234. error!("Error: p2p run failed {}", err);
  235. }
  236. })
  237. .detach();
  238. // RPC interface
  239. let ex2 = executor.clone();
  240. let ex3 = ex2.clone();
  241. let rpc_interface = Arc::new(JsonRpcInterface {
  242. state: state.clone(),
  243. p2p: p2p.clone(),
  244. _rpc_listen_addr: opts.rpc,
  245. });
  246. executor
  247. .spawn(async move { listen_and_serve(rpc_server_config, rpc_interface, ex3).await })
  248. .detach();
  249. proposal_task(p2p, state).await;
  250. Ok(())
  251. }
  252. struct JsonRpcInterface {
  253. state: ValidatorStatePtr,
  254. p2p: net::P2pPtr,
  255. _rpc_listen_addr: SocketAddr,
  256. }
  257. #[async_trait]
  258. impl RequestHandler for JsonRpcInterface {
  259. async fn handle_request(&self, req: JsonRequest, _executor: Arc<Executor<'_>>) -> JsonResult {
  260. if req.params.as_array().is_none() {
  261. return jsonrpc::error(InvalidRequest, None, req.id).into()
  262. }
  263. debug!(target: "RPC", "--> {}", serde_json::to_string(&req).unwrap());
  264. from_result(
  265. match req.method.as_str() {
  266. Some("ping") => self.pong().await,
  267. Some("get_info") => self.get_info().await,
  268. Some("receive_tx") => self.receive_tx(req.params).await,
  269. Some(_) | None => Err(MethodNotFound),
  270. },
  271. req.id,
  272. )
  273. }
  274. }
  275. impl JsonRpcInterface {
  276. // --> {"jsonrpc": "2.0", "method": "ping", "params": [], "id": 42}
  277. // <-- {"jsonrpc": "2.0", "result": "pong", "id": 42}
  278. async fn pong(&self) -> ValueResult<Value> {
  279. Ok(json!("pong"))
  280. }
  281. // --> {"jsonrpc": "2.0", "method": "get_info", "params": [], "id": 42}
  282. // <-- {"jsonrpc": "2.0", "result": {"nodeID": [], "nodeinfo" [], "id": 42}
  283. async fn get_info(&self) -> ValueResult<Value> {
  284. Ok(self.p2p.get_info().await)
  285. }
  286. // --> {"jsonrpc": "2.0", "method": "receive_tx", "params": ["tx"], "id": 42}
  287. // <-- {"jsonrpc": "2.0", "result": true, "id": 0}
  288. async fn receive_tx(&self, params: Value) -> ValueResult<Value> {
  289. let args = params.as_array().unwrap();
  290. if args.len() != 1 {
  291. return Err(InvalidParams)
  292. }
  293. let payload = String::from(args[0].as_str().unwrap());
  294. let tx = Tx { payload };
  295. self.state.write().unwrap().append_tx(tx.clone());
  296. let result = self.p2p.broadcast(tx).await;
  297. match result {
  298. Ok(()) => Ok(json!(true)),
  299. Err(_) => Err(InternalError),
  300. }
  301. }
  302. }
  303. #[async_std::main]
  304. async fn main() -> Result<()> {
  305. let opts = Opt::from_args_with_toml(&String::from_utf8(CONFIG_FILE_CONTENTS.to_vec()).unwrap())
  306. .unwrap();
  307. let config_path = get_config_path(Some(opts.config.clone()), CONFIG_FILE)?;
  308. spawn_config(&config_path, CONFIG_FILE_CONTENTS)?;
  309. let opts = Opt::from_args_with_toml(&String::from_utf8(CONFIG_FILE_CONTENTS.to_vec()).unwrap())
  310. .unwrap();
  311. let (lvl, conf) = log_config(opts.verbose.into())?;
  312. TermLogger::init(lvl, conf, TerminalMode::Mixed, ColorChoice::Auto)?;
  313. let ex = Arc::new(Executor::new());
  314. let (signal, shutdown) = async_channel::unbounded::<()>();
  315. let ex2 = ex.clone();
  316. let nthreads = if opts.threads == 0 { num_cpus::get() } else { opts.threads };
  317. debug!(target: "VALIDATOR DAEMON", "Executing with opts: {:?}", opts);
  318. debug!(target: "VALIDATOR DAEMON", "Run {} executor threads", nthreads);
  319. let (_, result) = Parallel::new()
  320. .each(0..nthreads, |_| smol::future::block_on(ex.run(shutdown.recv())))
  321. // Run the main future on the current thread.
  322. .finish(|| {
  323. smol::future::block_on(async move {
  324. start(ex2.clone(), &opts).await?;
  325. drop(signal);
  326. Ok::<(), darkfi::Error>(())
  327. })
  328. });
  329. result
  330. }