darkfid.rs 25 KB

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