darkfid.rs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. use async_std::sync::{Arc, Mutex};
  2. use std::collections::HashMap;
  3. use std::path::PathBuf;
  4. use std::str::FromStr;
  5. use async_executor::Executor;
  6. use async_trait::async_trait;
  7. use blake2s_simd::Params as Blake2sParams;
  8. use clap::clap_app;
  9. use easy_parallel::Parallel;
  10. use log::debug;
  11. use num_bigint::BigUint;
  12. use serde_json::{json, Value};
  13. use url::Url;
  14. use drk::{
  15. blockchain::{rocks::columns, Rocks, RocksColumn},
  16. cli::{Config, DarkfidConfig},
  17. client::{Client, State},
  18. crypto::{
  19. load_params, merkle::CommitmentTree, nullifier::Nullifier, save_params, setup_mint_prover,
  20. setup_spend_prover,
  21. },
  22. rpc::{
  23. jsonrpc::{error as jsonerr, request as jsonreq, response as jsonresp, send_raw_request},
  24. jsonrpc::{ErrorCode::*, JsonRequest, JsonResult},
  25. rpcserver::{listen_and_serve, RequestHandler, RpcServerConfig},
  26. },
  27. serial::{deserialize, serialize},
  28. state::ProgramState,
  29. util::{
  30. assign_id, decode_base10, encode_base10, expand_path, join_config_path, DrkTokenList,
  31. NetworkName, SolTokenList,
  32. },
  33. wallet::WalletDb,
  34. Error, Result,
  35. };
  36. #[derive(Clone, Debug)]
  37. pub struct Cashier {
  38. pub name: String,
  39. pub rpc_url: String,
  40. pub public_key: jubjub::SubgroupPoint,
  41. }
  42. #[async_trait]
  43. impl RequestHandler for Darkfid {
  44. async fn handle_request(&self, req: JsonRequest, _executor: Arc<Executor<'_>>) -> JsonResult {
  45. if req.params.as_array().is_none() {
  46. return JsonResult::Err(jsonerr(InvalidParams, None, req.id));
  47. }
  48. debug!(target: "RPC", "--> {}", serde_json::to_string(&req).unwrap());
  49. match req.method.as_str() {
  50. Some("say_hello") => return self.say_hello(req.id, req.params).await,
  51. Some("create_wallet") => return self.create_wallet(req.id, req.params).await,
  52. Some("key_gen") => return self.key_gen(req.id, req.params).await,
  53. Some("get_key") => return self.get_key(req.id, req.params).await,
  54. Some("get_balances") => return self.get_balances(req.id, req.params).await,
  55. Some("get_token_id") => return self.get_token_id(req.id, req.params).await,
  56. Some("features") => return self.features(req.id, req.params).await,
  57. Some("deposit") => return self.deposit(req.id, req.params).await,
  58. Some("withdraw") => return self.withdraw(req.id, req.params).await,
  59. Some("transfer") => return self.transfer(req.id, req.params).await,
  60. Some(_) | None => return JsonResult::Err(jsonerr(MethodNotFound, None, req.id)),
  61. };
  62. }
  63. }
  64. struct Darkfid {
  65. client: Arc<Mutex<Client>>,
  66. state: Arc<Mutex<State>>,
  67. sol_tokenlist: SolTokenList,
  68. drk_tokenlist: DrkTokenList,
  69. cashiers: Vec<Cashier>,
  70. }
  71. impl Darkfid {
  72. async fn new(
  73. client: Arc<Mutex<Client>>,
  74. state: Arc<Mutex<State>>,
  75. cashiers: Vec<Cashier>,
  76. ) -> Result<Self> {
  77. let sol_tokenlist = SolTokenList::new()?;
  78. let drk_tokenlist = DrkTokenList::new(sol_tokenlist.clone())?;
  79. Ok(Self {
  80. client,
  81. state,
  82. sol_tokenlist,
  83. drk_tokenlist,
  84. cashiers,
  85. })
  86. }
  87. async fn start(&mut self, executor: Arc<Executor<'_>>) -> Result<()> {
  88. self.client.lock().await.start().await?;
  89. self.client
  90. .lock()
  91. .await
  92. .connect_to_subscriber(self.state.clone(), executor)
  93. .await?;
  94. Ok(())
  95. }
  96. async fn update_balances(&self) -> Result<()> {
  97. let own_coins = self.client.lock().await.get_own_coins()?;
  98. for own_coin in own_coins {
  99. let mut nullifier = [0; 32];
  100. nullifier.copy_from_slice(
  101. Blake2sParams::new()
  102. .hash_length(32)
  103. .personal(zcash_primitives::constants::PRF_NF_PERSONALIZATION)
  104. .to_state()
  105. .update(&own_coin.secret.to_bytes())
  106. .update(&own_coin.note.serial.to_bytes())
  107. .finalize()
  108. .as_bytes(),
  109. );
  110. let nullifier = Nullifier::new(nullifier);
  111. let nullifier_exists = self.state.lock().await.nullifier_exists(&nullifier);
  112. if nullifier_exists {
  113. self.client
  114. .lock()
  115. .await
  116. .confirm_spend_coin(&own_coin.coin)?;
  117. }
  118. }
  119. Ok(())
  120. }
  121. // --> {"method": "say_hello", "params": []}
  122. // <-- {"result": "hello world"}
  123. async fn say_hello(&self, id: Value, _params: Value) -> JsonResult {
  124. JsonResult::Resp(jsonresp(json!("hello world"), id))
  125. }
  126. // --> {"method": "create_wallet", "params": []}
  127. // <-- {"result": true}
  128. async fn create_wallet(&self, id: Value, _params: Value) -> JsonResult {
  129. match self.client.lock().await.init_db().await {
  130. Ok(()) => return JsonResult::Resp(jsonresp(json!(true), id)),
  131. Err(e) => {
  132. return JsonResult::Err(jsonerr(ServerError(-32001), Some(e.to_string()), id))
  133. }
  134. }
  135. }
  136. // --> {"method": "key_gen", "params": []}
  137. // <-- {"result": true}
  138. async fn key_gen(&self, id: Value, _params: Value) -> JsonResult {
  139. match self.client.lock().await.key_gen() {
  140. Ok(()) => return JsonResult::Resp(jsonresp(json!(true), id)),
  141. Err(e) => {
  142. return JsonResult::Err(jsonerr(ServerError(-32002), Some(e.to_string()), id))
  143. }
  144. }
  145. }
  146. // --> {"method": "get_key", "params": []}
  147. // <-- {"result": "vdNS7oBj7KvsMWWmo9r96SV4SqATLrGsH2a3PGpCfJC"}
  148. async fn get_key(&self, id: Value, _params: Value) -> JsonResult {
  149. let pk = self.client.lock().await.main_keypair.public;
  150. let b58 = bs58::encode(serialize(&pk)).into_string();
  151. return JsonResult::Resp(jsonresp(json!(b58), id));
  152. }
  153. // --> {"method": "get_balances", "params": []}
  154. // <-- {"result": "get_balances": "[ {"btc": (value, network)}, .. ]"}
  155. async fn get_balances(&self, id: Value, _params: Value) -> JsonResult {
  156. let result: Result<HashMap<String, (String, String)>> = async {
  157. self.update_balances().await?;
  158. let balances = self.client.lock().await.get_balances()?;
  159. let mut symbols: HashMap<String, (String, String)> = HashMap::new();
  160. for balance in balances.list.iter() {
  161. // XXX: this must be changed once cashierd
  162. // supports more than two networks
  163. let mut network = "solana";
  164. if balance.token_id.to_string()
  165. == "0x01300f9bce0f9ba7168dc001a67bcbda3a5bf4bdb4c56ae900fe4698cee9a7bd"
  166. {
  167. network = "bitcoin"
  168. }
  169. if let Some(symbol) = self.drk_tokenlist.symbol_from_id(balance.token_id)? {
  170. let amount = encode_base10(BigUint::from(balance.value), 8);
  171. symbols.insert(symbol, (amount, network.to_string()));
  172. }
  173. }
  174. Ok(symbols)
  175. }
  176. .await;
  177. match result {
  178. Ok(res) => JsonResult::Resp(jsonresp(json!(res), json!(res))),
  179. Err(err) => JsonResult::Err(jsonerr(InternalError, Some(err.to_string()), json!(id))),
  180. }
  181. }
  182. // --> {"method": "get_token_id", "params": [network, token]}
  183. // <-- {"result": "Ht5G1RhkcKnpLVLMhqJc5aqZ4wYUEbxbtZwGCVbgU7DL"}
  184. async fn get_token_id(&self, id: Value, params: Value) -> JsonResult {
  185. let args = params.as_array();
  186. if args.is_none() {
  187. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  188. }
  189. let args = args.unwrap();
  190. if args.len() != 2 {
  191. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  192. }
  193. let network: &str;
  194. let symbol: &str;
  195. match (args[0].as_str(), args[1].as_str()) {
  196. (Some(net), Some(sym)) => {
  197. network = net;
  198. symbol = sym;
  199. }
  200. (None, _) => {
  201. return JsonResult::Err(jsonerr(InvalidNetworkParam, None, id));
  202. }
  203. (_, None) => {
  204. return JsonResult::Err(jsonerr(InvalidSymbolParam, None, id));
  205. }
  206. }
  207. let result: Result<Value> = async {
  208. let network = NetworkName::from_str(&network)?;
  209. match network {
  210. #[cfg(feature = "sol")]
  211. NetworkName::Solana => {
  212. let token_id = self.sol_tokenlist.search_id(symbol)?;
  213. Ok(json!(token_id))
  214. }
  215. #[cfg(feature = "btc")]
  216. NetworkName::Bitcoin => {
  217. //hardcoded genesis coinbase address
  218. let token_id = "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa".to_string();
  219. Ok(json!(token_id))
  220. }
  221. _ => Err(Error::NotSupportedNetwork),
  222. }
  223. }
  224. .await;
  225. match result {
  226. Ok(res) => JsonResult::Resp(jsonresp(json!(res), json!(res))),
  227. Err(err) => JsonResult::Err(jsonerr(InternalError, Some(err.to_string()), json!(id))),
  228. }
  229. }
  230. // --> {""method": "features", "params": []}
  231. // <-- {"result": { "network": ["btc", "sol"] } }
  232. async fn features(&self, id: Value, _params: Value) -> JsonResult {
  233. let req = jsonreq(json!("features"), json!([]));
  234. let rep: JsonResult;
  235. // NOTE: this just selects the first cashier in the list
  236. match send_raw_request(&self.cashiers[0].rpc_url, json!(req)).await {
  237. Ok(v) => rep = v,
  238. Err(e) => {
  239. return JsonResult::Err(jsonerr(ServerError(-32004), Some(e.to_string()), id))
  240. }
  241. }
  242. match rep {
  243. JsonResult::Resp(r) => return JsonResult::Resp(r),
  244. JsonResult::Err(e) => return JsonResult::Err(e),
  245. JsonResult::Notif(_) => return JsonResult::Err(jsonerr(InternalError, None, id)),
  246. }
  247. }
  248. // --> {"method": "deposit", "params": [network, token, publickey]}
  249. // The publickey sent here is used so the cashier can know where to send
  250. // tokens once the deposit is received.
  251. // <-- {"result": "Ht5G1RhkcKnpLVLMhqJc5aqZ4wYUEbxbtZwGCVbgU7DL"}
  252. async fn deposit(&self, id: Value, params: Value) -> JsonResult {
  253. let args = params.as_array();
  254. if args.is_none() {
  255. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  256. }
  257. let args = args.unwrap();
  258. if args.len() != 2 {
  259. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  260. }
  261. let network: &str;
  262. let token: &str;
  263. match (args[0].as_str(), args[1].as_str()) {
  264. (Some(net), Some(tkn)) => {
  265. network = net;
  266. token = tkn;
  267. }
  268. (None, _) => {
  269. return JsonResult::Err(jsonerr(InvalidNetworkParam, None, id));
  270. }
  271. (_, None) => {
  272. return JsonResult::Err(jsonerr(InvalidTokenIdParam, None, id));
  273. }
  274. }
  275. let token_id = match assign_id(&network, &token, &self.sol_tokenlist) {
  276. Ok(t) => t,
  277. Err(e) => {
  278. return JsonResult::Err(jsonerr(InternalError, Some(e.to_string()), id));
  279. }
  280. };
  281. // TODO: Optional sanity checking here, but cashier *must* do so too.
  282. let pk = self.client.lock().await.main_keypair.public;
  283. let pubkey = bs58::encode(serialize(&pk)).into_string();
  284. // Send request to cashier. If the cashier supports the requested network
  285. // (and token), it shall return a valid address where tokens can be deposited.
  286. // If not, an error is returned, and forwarded to the method caller.
  287. let req = jsonreq(json!("deposit"), json!([network, token_id, pubkey]));
  288. let rep: JsonResult;
  289. match send_raw_request(&self.cashiers[0].rpc_url, json!(req)).await {
  290. Ok(v) => rep = v,
  291. Err(e) => {
  292. debug!(target: "DARKFID", "REQUEST IS ERR");
  293. return JsonResult::Err(jsonerr(ServerError(-32004), Some(e.to_string()), id));
  294. }
  295. }
  296. match rep {
  297. JsonResult::Resp(r) => return JsonResult::Resp(r),
  298. JsonResult::Err(e) => return JsonResult::Err(e),
  299. JsonResult::Notif(_n) => return JsonResult::Err(jsonerr(InternalError, None, id)),
  300. }
  301. }
  302. // --> {"method": "withdraw", "params": [network, token, publickey, amount]}
  303. // The publickey sent here is the address where the caller wants to receive
  304. // the tokens they plan to withdraw.
  305. // On request, send request to cashier to get deposit address, and then transfer
  306. // dark tokens to the cashier's wallet. Following that, the cashier should return
  307. // a transaction ID of them sending the funds that are requested for withdrawal.
  308. // <-- {"result": "txID"}
  309. async fn withdraw(&self, id: Value, params: Value) -> JsonResult {
  310. let args = params.as_array();
  311. if args.is_none() {
  312. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  313. }
  314. let args = args.unwrap();
  315. if args.len() != 4 {
  316. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  317. }
  318. let network: &str;
  319. let token: &str;
  320. let address: &str;
  321. let amount: &str;
  322. match (
  323. args[0].as_str(),
  324. args[1].as_str(),
  325. args[2].as_str(),
  326. args[3].as_str(),
  327. ) {
  328. (Some(net), Some(tkn), Some(addr), Some(val)) => {
  329. network = net;
  330. token = tkn;
  331. address = addr;
  332. amount = val;
  333. }
  334. (None, _, _, _) => {
  335. return JsonResult::Err(jsonerr(InvalidNetworkParam, None, id));
  336. }
  337. (_, None, _, _) => {
  338. return JsonResult::Err(jsonerr(InvalidTokenIdParam, None, id));
  339. }
  340. (_, _, None, _) => {
  341. return JsonResult::Err(jsonerr(InvalidAddressParam, None, id));
  342. }
  343. (_, _, _, None) => {
  344. return JsonResult::Err(jsonerr(InvalidAmountParam, None, id));
  345. }
  346. }
  347. let amount_in_apo = match decode_base10(&amount, 8, true) {
  348. Ok(a) => a,
  349. Err(e) => {
  350. return JsonResult::Err(jsonerr(InvalidAmountParam, Some(e.to_string()), id));
  351. }
  352. };
  353. let token_id = match assign_id(&network, &token, &self.sol_tokenlist) {
  354. Ok(t) => t,
  355. Err(e) => {
  356. return JsonResult::Err(jsonerr(InternalError, Some(e.to_string()), id));
  357. }
  358. };
  359. let req = jsonreq(
  360. json!("withdraw"),
  361. json!([network, token_id, address, amount_in_apo]),
  362. );
  363. let mut rep: JsonResult;
  364. match send_raw_request(&self.cashiers[0].rpc_url, json!(req)).await {
  365. Ok(v) => rep = v,
  366. Err(e) => {
  367. return JsonResult::Err(jsonerr(ServerError(-32004), Some(e.to_string()), id));
  368. }
  369. }
  370. let token_id: &jubjub::Fr;
  371. // get the id for the token
  372. if let Some(tk_id) = self.drk_tokenlist.tokens.get(&token.to_uppercase()) {
  373. token_id = tk_id;
  374. } else {
  375. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  376. }
  377. // send drk to cashier_public
  378. if let JsonResult::Resp(cashier_public) = &rep {
  379. let result: Result<()> = async {
  380. let cashier_public = cashier_public.result.as_str().unwrap();
  381. let cashier_public: jubjub::SubgroupPoint =
  382. deserialize(&bs58::decode(cashier_public).into_vec()?)?;
  383. self.client
  384. .lock()
  385. .await
  386. .transfer(
  387. token_id.clone(),
  388. cashier_public,
  389. amount_in_apo,
  390. self.state.clone(),
  391. )
  392. .await?;
  393. Ok(())
  394. }
  395. .await;
  396. match result {
  397. Err(e) => {
  398. rep = JsonResult::Err(jsonerr(InternalError, Some(e.to_string()), id.clone()))
  399. }
  400. Ok(_) => {
  401. rep = JsonResult::Resp(jsonresp(
  402. json!(format!(
  403. "Sent request to withdraw {} amount of {}",
  404. amount, token_id
  405. )),
  406. json!(id.clone()),
  407. ))
  408. }
  409. }
  410. };
  411. match rep {
  412. JsonResult::Resp(r) => return JsonResult::Resp(r),
  413. JsonResult::Err(e) => return JsonResult::Err(e),
  414. JsonResult::Notif(_n) => return JsonResult::Err(jsonerr(InternalError, None, id)),
  415. }
  416. }
  417. // --> {"method": "transfer", [dToken, address, amount]}
  418. // <-- {"result": "txID"}
  419. async fn transfer(&self, id: Value, params: Value) -> JsonResult {
  420. let args = params.as_array();
  421. if args.is_none() {
  422. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  423. }
  424. let args = args.unwrap();
  425. if args.len() != 3 {
  426. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  427. }
  428. let token: &str;
  429. let address: &str;
  430. let amount: &str;
  431. match (args[0].as_str(), args[1].as_str(), args[2].as_str()) {
  432. (Some(tkn), Some(addr), Some(val)) => {
  433. token = tkn;
  434. address = addr;
  435. amount = val;
  436. }
  437. (None, _, _) => {
  438. return JsonResult::Err(jsonerr(InvalidTokenIdParam, None, id));
  439. }
  440. (_, None, _) => {
  441. return JsonResult::Err(jsonerr(InvalidAddressParam, None, id));
  442. }
  443. (_, _, None) => {
  444. return JsonResult::Err(jsonerr(InvalidAmountParam, None, id));
  445. }
  446. }
  447. let token_id: &jubjub::Fr;
  448. // get the id for the token
  449. if let Some(tk_id) = self.drk_tokenlist.tokens.get(&token.to_uppercase()) {
  450. token_id = tk_id;
  451. } else {
  452. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  453. }
  454. let result: Result<()> = async {
  455. let drk_address = bs58::decode(&address).into_vec()?;
  456. let drk_address: jubjub::SubgroupPoint = deserialize(&drk_address)?;
  457. let decimals: usize = 8;
  458. let amount = decode_base10(&amount, decimals, true)?;
  459. self.update_balances().await?;
  460. self.client
  461. .lock()
  462. .await
  463. .transfer(token_id.clone(), drk_address, amount, self.state.clone())
  464. .await?;
  465. Ok(())
  466. }
  467. .await;
  468. match result {
  469. Ok(msg) => JsonResult::Resp(jsonresp(json!(msg), json!(id))),
  470. Err(err) => JsonResult::Err(jsonerr(InternalError, Some(err.to_string()), json!(id))),
  471. }
  472. }
  473. }
  474. async fn start(executor: Arc<Executor<'_>>, config: &DarkfidConfig) -> Result<()> {
  475. let wallet = WalletDb::new(
  476. expand_path(&config.wallet_path)?.as_path(),
  477. config.wallet_password.clone(),
  478. )?;
  479. let rocks = Rocks::new(expand_path(&config.database_path.clone())?.as_path())?;
  480. let mut cashiers = Vec::new();
  481. let mut cashier_keys = Vec::new();
  482. for cashier in config.clone().cashiers {
  483. if cashier.public_key.is_empty() {
  484. return Err(Error::CashierKeysNotFound);
  485. }
  486. let cashier_public: jubjub::SubgroupPoint =
  487. deserialize(&bs58::decode(cashier.public_key).into_vec()?)?;
  488. cashiers.push(Cashier {
  489. name: cashier.name,
  490. rpc_url: cashier.rpc_url,
  491. public_key: cashier_public,
  492. });
  493. cashier_keys.push(cashier_public);
  494. }
  495. // Load trusted setup parameters
  496. let params_paths = (
  497. expand_path(&config.mint_params_path.clone())?,
  498. expand_path(&config.spend_params_path.clone())?,
  499. );
  500. let mint_params_path = params_paths.0.to_str().unwrap_or("mint.params");
  501. let spend_params_path = params_paths.1.to_str().unwrap_or("spend.params");
  502. // Auto create trusted ceremony parameters if they don't exist
  503. if !params_paths.0.exists() {
  504. let params = setup_mint_prover();
  505. save_params(mint_params_path, &params)?;
  506. }
  507. if !params_paths.1.exists() {
  508. let params = setup_spend_prover();
  509. save_params(spend_params_path, &params)?;
  510. }
  511. let (mint_params, mint_pvk) = load_params(mint_params_path)?;
  512. let (spend_params, spend_pvk) = load_params(spend_params_path)?;
  513. let client = Client::new(
  514. rocks.clone(),
  515. (
  516. Url::parse(&config.gateway_protocol_url)?,
  517. Url::parse(&config.gateway_publisher_url)?,
  518. ),
  519. wallet.clone(),
  520. mint_params,
  521. spend_params,
  522. )
  523. .await?;
  524. let client = Arc::new(Mutex::new(client));
  525. let merkle_roots = RocksColumn::<columns::MerkleRoots>::new(rocks.clone());
  526. let nullifiers = RocksColumn::<columns::Nullifiers>::new(rocks);
  527. let state = Arc::new(Mutex::new(State {
  528. tree: CommitmentTree::empty(),
  529. merkle_roots,
  530. nullifiers,
  531. mint_pvk,
  532. spend_pvk,
  533. public_keys: cashier_keys,
  534. }));
  535. let mut darkfid = Darkfid::new(client, state, cashiers).await?;
  536. let server_config = RpcServerConfig {
  537. socket_addr: config.rpc_listen_address.clone(),
  538. use_tls: config.serve_tls,
  539. identity_path: expand_path(&config.tls_identity_path.clone())?,
  540. identity_pass: config.tls_identity_password.clone(),
  541. };
  542. darkfid.start(executor.clone()).await?;
  543. listen_and_serve(server_config, Arc::new(darkfid), executor).await
  544. }
  545. #[async_std::main]
  546. async fn main() -> Result<()> {
  547. let args = clap_app!(darkfid =>
  548. (@arg CONFIG: -c --config +takes_value "Sets a custom config file")
  549. (@arg verbose: -v --verbose "Increase verbosity")
  550. (@arg refresh: -r --refresh "Refresh the wallet and own coins")
  551. )
  552. .get_matches();
  553. let config_path = if args.is_present("CONFIG") {
  554. PathBuf::from(args.value_of("CONFIG").unwrap())
  555. } else {
  556. join_config_path(&PathBuf::from("darkfid.toml"))?
  557. };
  558. let loglevel = if args.is_present("verbose") {
  559. log::Level::Debug
  560. } else {
  561. log::Level::Info
  562. };
  563. simple_logger::init_with_level(loglevel)?;
  564. let config: DarkfidConfig = Config::<DarkfidConfig>::load(config_path)?;
  565. if args.is_present("refresh") {
  566. debug!(target: "DARKFI DAEMON", "Refresh the wallet and the database");
  567. let wallet = WalletDb::new(
  568. expand_path(&config.wallet_path)?.as_path(),
  569. config.wallet_password.clone(),
  570. )?;
  571. wallet.remove_own_coins()?;
  572. if let Some(path) = expand_path(&config.database_path)?.to_str() {
  573. debug!(target: "DARKFI DAEMON", "Remove database: {}", path);
  574. std::fs::remove_dir_all(path)?;
  575. }
  576. println!("Wallet got updated successfully.");
  577. return Ok(());
  578. }
  579. let ex = Arc::new(Executor::new());
  580. let (signal, shutdown) = async_channel::unbounded::<()>();
  581. let ex2 = ex.clone();
  582. let nthreads = num_cpus::get();
  583. debug!(target: "DARKFI DAEMON", "Run {} executor threads", nthreads);
  584. let (_, result) = Parallel::new()
  585. .each(0..nthreads, |_| {
  586. smol::future::block_on(ex.run(shutdown.recv()))
  587. })
  588. // Run the main future on the current thread.
  589. .finish(|| {
  590. smol::future::block_on(async move {
  591. start(ex2, &config).await?;
  592. drop(signal);
  593. Ok::<(), drk::Error>(())
  594. })
  595. });
  596. result
  597. }