main.rs 12 KB

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