darkfid.rs 25 KB

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