main.rs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2022 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use std::{net::SocketAddr, path::PathBuf, str::FromStr};
  19. use async_executor::Executor;
  20. use async_std::sync::{Arc, Mutex};
  21. use async_trait::async_trait;
  22. use clap::{IntoApp, Parser};
  23. use easy_parallel::Parallel;
  24. use log::{debug, info};
  25. use rand::rngs::OsRng;
  26. use serde::{Deserialize, Serialize};
  27. use serde_json::{json, Value};
  28. use simplelog::{ColorChoice, TermLogger, TerminalMode};
  29. use darkfi::{
  30. blockchain::{rocks::columns, Rocks, RocksColumn},
  31. crypto::{
  32. address::Address,
  33. keypair::{PublicKey, SecretKey},
  34. proof::VerifyingKey,
  35. token_id::generate_id2,
  36. types::DrkTokenId,
  37. },
  38. node::{client::Client, state::State},
  39. rpc::{
  40. jsonrpc::{error as jsonerr, response as jsonresp, ErrorCode::*, JsonRequest, JsonResult},
  41. rpcserver::{listen_and_serve, RequestHandler, RpcServerConfig},
  42. },
  43. util::{
  44. cli::{log_config, spawn_config, Config},
  45. expand_path, join_config_path,
  46. parse::truncate,
  47. serial::serialize,
  48. NetworkName,
  49. },
  50. wallet::{cashierdb::CashierDb, walletdb::WalletDb},
  51. zk::circuit::{MintContract, SpendContract},
  52. Error, Result,
  53. };
  54. use cashierd::service::{bridge, bridge::Bridge};
  55. #[derive(Clone, Debug, Serialize, Deserialize)]
  56. pub struct FeatureNetwork {
  57. /// Network name
  58. pub name: String,
  59. /// Blockchain (mainnet/testnet/etc.)
  60. pub blockchain: String,
  61. /// Keypair
  62. pub keypair: String,
  63. }
  64. #[derive(Clone, Serialize, Deserialize, Debug)]
  65. pub struct CashierdConfig {
  66. /// The DNS name of the cashier (can also be an IP, or a .onion address)
  67. pub dns_addr: String,
  68. /// The endpoint where cashierd will bind its RPC socket
  69. pub rpc_listen_address: SocketAddr,
  70. /// Whether to listen with TLS or plain TCP
  71. pub serve_tls: bool,
  72. /// Path to DER-formatted PKCS#12 archive. (Unused if serve_tls=false)
  73. pub tls_identity_path: String,
  74. /// Password for the TLS identity. (Unused if serve_tls=false)
  75. pub tls_identity_password: String,
  76. /// The endpoint to a gatewayd protocol API
  77. pub gateway_protocol_url: String,
  78. /// The endpoint to a gatewayd publisher API
  79. pub gateway_publisher_url: String,
  80. /// Path to cashierd wallet
  81. pub cashier_wallet_path: String,
  82. /// Password for cashierd wallet
  83. pub cashier_wallet_password: String,
  84. /// Path to client wallet
  85. pub client_wallet_path: String,
  86. /// Password for client wallet
  87. pub client_wallet_password: String,
  88. /// Path to database
  89. pub database_path: String,
  90. /// Geth IPC endpoint
  91. pub geth_socket: String,
  92. /// Geth passphrase
  93. pub geth_passphrase: String,
  94. /// The configured networks to use
  95. pub networks: Vec<FeatureNetwork>,
  96. }
  97. /// Cashierd cli
  98. #[derive(Parser)]
  99. #[clap(name = "cashierd")]
  100. pub struct CliCashierd {
  101. /// Sets a custom config file
  102. #[clap(short, long)]
  103. pub config: Option<String>,
  104. /// Get Cashier Public key
  105. #[clap(short, long)]
  106. pub address: bool,
  107. /// Increase verbosity
  108. #[clap(short, parse(from_occurrences))]
  109. pub verbose: u8,
  110. /// Refresh the wallet and slabstore
  111. #[clap(short, long)]
  112. pub refresh: bool,
  113. }
  114. const CONFIG_FILE_CONTENTS: &[u8] = include_bytes!("../cashierd_config.toml");
  115. fn handle_bridge_error(error_code: u32) -> Result<()> {
  116. match error_code {
  117. 1 => Err(Error::CashierError("Not Supported Client".into())),
  118. 2 => Err(Error::CashierError("Unable to watch the deposit address".into())),
  119. 3 => Err(Error::CashierError("Unable to send the token".into())),
  120. _ => Err(Error::CashierError("Unknown error_code".into())),
  121. }
  122. }
  123. #[derive(Clone, Debug)]
  124. pub struct Network {
  125. pub name: NetworkName,
  126. pub blockchain: String,
  127. pub keypair: String,
  128. }
  129. struct Cashierd {
  130. bridge: Arc<Bridge>,
  131. cashier_wallet: Arc<CashierDb>,
  132. networks: Vec<Network>,
  133. public_key: Address,
  134. config: CashierdConfig,
  135. }
  136. #[async_trait]
  137. impl RequestHandler for Cashierd {
  138. async fn handle_request(&self, req: JsonRequest, executor: Arc<Executor<'_>>) -> JsonResult {
  139. if req.params.as_array().is_none() {
  140. return JsonResult::Err(jsonerr(InvalidParams, None, req.id))
  141. }
  142. debug!(target: "RPC", "--> {}", serde_json::to_string(&req).unwrap());
  143. match req.method.as_str() {
  144. Some("deposit") => return self.deposit(req.id, req.params, executor).await,
  145. Some("withdraw") => return self.withdraw(req.id, req.params).await,
  146. Some("features") => return self.features(req.id, req.params).await,
  147. Some(_) => {}
  148. None => {}
  149. };
  150. return JsonResult::Err(jsonerr(MethodNotFound, None, req.id))
  151. }
  152. }
  153. impl Cashierd {
  154. async fn new(config: CashierdConfig, public_key: Address) -> Result<Self> {
  155. debug!(target: "CASHIER DAEMON", "Initialize");
  156. let wallet_path =
  157. format!("sqlite://{}", expand_path(&config.cashier_wallet_path)?.to_str().unwrap());
  158. let cashier_wallet = CashierDb::new(&wallet_path, &config.cashier_wallet_password).await?;
  159. let mut networks = Vec::new();
  160. for network in config.clone().networks {
  161. networks.push(Network {
  162. name: NetworkName::from_str(&network.name)?,
  163. blockchain: network.blockchain,
  164. keypair: network.keypair,
  165. });
  166. }
  167. let bridge = bridge::Bridge::new();
  168. Ok(Self { bridge, cashier_wallet, networks, public_key, config })
  169. }
  170. async fn start(
  171. &mut self,
  172. mut client: Client,
  173. state: Arc<Mutex<State>>,
  174. executor: Arc<Executor<'_>>,
  175. ) -> Result<(smol::Task<Result<()>>, smol::Task<Result<()>>)> {
  176. self.cashier_wallet.init_db().await?;
  177. for network in self.networks.iter() {
  178. match network.name {
  179. #[cfg(feature = "sol")]
  180. NetworkName::Solana => {
  181. debug!(target: "CASHIER DAEMON", "Adding solana network");
  182. use cashierd::service::SolClient;
  183. let _bridge = self.bridge.clone();
  184. let sol_client = SolClient::new(
  185. self.cashier_wallet.clone(),
  186. &network.blockchain,
  187. &network.keypair,
  188. )
  189. .await?;
  190. _bridge.add_clients(NetworkName::Solana, sol_client).await?;
  191. }
  192. #[cfg(feature = "eth")]
  193. NetworkName::Ethereum => {
  194. debug!(target: "CASHIER DAEMON", "Adding ethereum network");
  195. use cashierd::service::EthClient;
  196. let _bridge = self.bridge.clone();
  197. let passphrase = self.config.geth_passphrase.clone();
  198. let mut eth_client = EthClient::new(
  199. &network.blockchain,
  200. expand_path(&self.config.geth_socket)?.to_str().unwrap(),
  201. &passphrase,
  202. );
  203. eth_client.setup_keypair(self.cashier_wallet.clone(), &network.keypair).await?;
  204. _bridge.add_clients(NetworkName::Ethereum, Arc::new(eth_client)).await?;
  205. }
  206. #[cfg(feature = "btc")]
  207. NetworkName::Bitcoin => {
  208. debug!(target: "CASHIER DAEMON", "Adding bitcoin network");
  209. use cashierd::service::btc::BtcClient;
  210. let _bridge = self.bridge.clone();
  211. let btc_client = BtcClient::new(
  212. self.cashier_wallet.clone(),
  213. &network.blockchain,
  214. &network.keypair,
  215. )
  216. .await?;
  217. _bridge.add_clients(NetworkName::Bitcoin, btc_client).await?;
  218. }
  219. _ => {}
  220. }
  221. }
  222. client.start().await?;
  223. let (notify, recv_coin) = async_channel::unbounded::<(PublicKey, u64)>();
  224. client
  225. .connect_to_subscriber_from_cashier(
  226. state.clone(),
  227. self.cashier_wallet.clone(),
  228. notify.clone(),
  229. executor.clone(),
  230. )
  231. .await?;
  232. let cashier_wallet = self.cashier_wallet.clone();
  233. let bridge = self.bridge.clone();
  234. let ex = executor.clone();
  235. let listen_for_receiving_coins_task: smol::Task<Result<()>> = executor.spawn(async move {
  236. let ex2 = ex.clone();
  237. loop {
  238. Self::listen_for_receiving_coins(
  239. bridge.clone(),
  240. cashier_wallet.clone(),
  241. recv_coin.clone(),
  242. ex2.clone(),
  243. )
  244. .await?;
  245. }
  246. });
  247. let bridge2 = self.bridge.clone();
  248. let listen_for_notification_from_bridge_task: smol::Task<Result<()>> =
  249. executor.spawn(async move {
  250. while let Some(token_notification) = bridge2.clone().listen().await {
  251. debug!(target: "CASHIER DAEMON", "Received notification from bridge");
  252. let token_notification = token_notification?;
  253. let received_balance = truncate(
  254. token_notification.received_balance,
  255. 8,
  256. token_notification.decimals,
  257. )?;
  258. client
  259. .send(
  260. token_notification.drk_pub_key,
  261. received_balance,
  262. token_notification.token_id,
  263. true,
  264. state.clone(),
  265. )
  266. .await?;
  267. }
  268. Ok(())
  269. });
  270. Ok((listen_for_receiving_coins_task, listen_for_notification_from_bridge_task))
  271. }
  272. async fn listen_for_receiving_coins(
  273. bridge: Arc<Bridge>,
  274. cashier_wallet: Arc<CashierDb>,
  275. recv_coin: async_channel::Receiver<(PublicKey, u64)>,
  276. executor: Arc<Executor<'_>>,
  277. ) -> Result<()> {
  278. // received drk coin
  279. let (drk_pub_key, amount) = recv_coin.recv().await?;
  280. debug!(target: "CASHIER DAEMON", "Receive coin with amount: {}", amount);
  281. // get public key, and token_id of the token
  282. let token =
  283. cashier_wallet.get_withdraw_token_public_key_by_dkey_public(&drk_pub_key).await?;
  284. // send a request to bridge to send equivalent amount of
  285. // received drk coin to token publickey
  286. if let Some(withdraw_token) = token {
  287. let bridge_subscribtion = bridge
  288. .subscribe(drk_pub_key, Some(withdraw_token.mint_address), executor.clone())
  289. .await;
  290. // send a request to the bridge to send amount of token
  291. // equivalent to the received drk
  292. bridge_subscribtion
  293. .sender
  294. .send(bridge::BridgeRequests {
  295. network: withdraw_token.network.clone(),
  296. payload: bridge::BridgeRequestsPayload::Send(
  297. withdraw_token.token_public_key.clone(),
  298. amount,
  299. ),
  300. })
  301. .await?;
  302. // receive a response
  303. let res = bridge_subscribtion.receiver.recv().await?;
  304. // check the response's error
  305. let error_code = res.error as u32;
  306. if error_code != 0 {
  307. return handle_bridge_error(error_code)
  308. }
  309. match res.payload {
  310. bridge::BridgeResponsePayload::Send => {
  311. cashier_wallet
  312. .confirm_withdraw_key_record(
  313. &withdraw_token.token_public_key,
  314. &withdraw_token.network,
  315. )
  316. .await?;
  317. }
  318. _ => {
  319. return Err(Error::CashierError(
  320. "Receive unknown value from Subscription".into(),
  321. ))
  322. }
  323. }
  324. }
  325. Ok(())
  326. }
  327. fn check_token_id(network: &NetworkName, _token_id: &str) -> Result<Option<String>> {
  328. match network {
  329. #[cfg(feature = "sol")]
  330. NetworkName::Solana => {
  331. use cashierd::service::sol::SOL_NATIVE_TOKEN_ID;
  332. if _token_id != SOL_NATIVE_TOKEN_ID {
  333. return Ok(Some(_token_id.to_string()))
  334. }
  335. Ok(None)
  336. }
  337. #[cfg(feature = "eth")]
  338. NetworkName::Ethereum => {
  339. use cashierd::service::eth::ETH_NATIVE_TOKEN_ID;
  340. if _token_id != ETH_NATIVE_TOKEN_ID {
  341. return Ok(Some(_token_id.to_string()))
  342. }
  343. Ok(None)
  344. }
  345. #[cfg(feature = "btc")]
  346. NetworkName::Bitcoin => Ok(None),
  347. _ => Err(Error::NotSupportedNetwork),
  348. }
  349. }
  350. // RPCAPI:
  351. // Executes a deposit request given `network` and `token_id`.
  352. // Returns the address where the deposit shall be transferred to.
  353. // --> {"jsonrpc": "2.0", "method": "deposit", "params": ["network", "token", "publickey"], "id": 1}
  354. // <-- {"jsonrpc": "2.0", "result": "Ht5G1RhkcKnpLVLMhqJc5aqZ4wYUEbxbtZwGCVbgU7DL", "id": 1}
  355. async fn deposit(&self, id: Value, params: Value, executor: Arc<Executor<'_>>) -> JsonResult {
  356. info!(target: "CASHIER DAEMON", "Received deposit request");
  357. let args: &Vec<serde_json::Value> = params.as_array().unwrap();
  358. if args.len() != 3 {
  359. return JsonResult::Err(jsonerr(InvalidParams, None, id))
  360. }
  361. let network: NetworkName;
  362. let mut mint_address: &str;
  363. let drk_pub_key: &str;
  364. match (args[0].as_str(), args[1].as_str(), args[2].as_str()) {
  365. (Some(n), Some(m), Some(d)) => {
  366. if NetworkName::from_str(n).is_err() {
  367. return JsonResult::Err(jsonerr(InvalidNetworkParam, None, id))
  368. }
  369. network = NetworkName::from_str(n).unwrap();
  370. mint_address = m;
  371. drk_pub_key = d;
  372. }
  373. (None, _, _) => return JsonResult::Err(jsonerr(InvalidNetworkParam, None, id)),
  374. (_, None, _) => return JsonResult::Err(jsonerr(InvalidTokenIdParam, None, id)),
  375. (_, _, None) => return JsonResult::Err(jsonerr(InvalidAddressParam, None, id)),
  376. }
  377. // Check if the features list contains this network
  378. if !self.networks.iter().any(|net| net.name == network) {
  379. return JsonResult::Err(jsonerr(
  380. InvalidParams,
  381. Some(format!("Cashier doesn't support this network: {}", network)),
  382. id,
  383. ))
  384. }
  385. let result: Result<String> = async {
  386. let token_id = generate_id2(mint_address, &network)?;
  387. let mint_address_opt = Self::check_token_id(&network, mint_address)?;
  388. if mint_address_opt.is_none() {
  389. mint_address = "";
  390. }
  391. let drk_pub_key = Address::from_str(drk_pub_key)?;
  392. let drk_pub_key: PublicKey = PublicKey::try_from(drk_pub_key)?;
  393. // check if the drk public key already exist
  394. let check = self
  395. .cashier_wallet
  396. .get_deposit_token_keys_by_dkey_public(&drk_pub_key, &network)
  397. .await?;
  398. // start new subscription from the bridge and then cashierd will
  399. // send a request to the bridge to generate keypair for the desired token
  400. // and start watch this token's keypair
  401. // once a bridge receive an update for this token's address
  402. // cashierd will get notification from bridge.listen() function
  403. //
  404. // The "if statement" check from the cashierdb if the node's drk_pub_key already exist
  405. // in this case it will not generate new keypair but it will
  406. // retrieve the old generated keypair
  407. //
  408. // Once receive a response from the bridge, the cashierd then save a deposit
  409. // record in cashierdb with the network name and token id
  410. let bridge = self.bridge.clone();
  411. let bridge_subscribtion =
  412. bridge.subscribe(drk_pub_key, mint_address_opt, executor).await;
  413. if check.is_empty() {
  414. bridge_subscribtion
  415. .sender
  416. .send(bridge::BridgeRequests {
  417. network: network.clone(),
  418. payload: bridge::BridgeRequestsPayload::Watch(None),
  419. })
  420. .await?;
  421. } else {
  422. let keypair = check[0].clone();
  423. bridge_subscribtion
  424. .sender
  425. .send(bridge::BridgeRequests {
  426. network: network.clone(),
  427. payload: bridge::BridgeRequestsPayload::Watch(Some(keypair)),
  428. })
  429. .await?;
  430. }
  431. let bridge_res = bridge_subscribtion.receiver.recv().await?;
  432. let error_code = bridge_res.error as u32;
  433. if error_code != 0 {
  434. return handle_bridge_error(error_code).map(|_| String::new())
  435. }
  436. match bridge_res.payload {
  437. bridge::BridgeResponsePayload::Watch(token_key) => {
  438. // add pairings to db
  439. self.cashier_wallet
  440. .put_deposit_keys(
  441. &drk_pub_key,
  442. &token_key.private_key,
  443. &serialize(&token_key.public_key),
  444. &network,
  445. &token_id,
  446. mint_address.into(),
  447. )
  448. .await?;
  449. Ok(token_key.public_key)
  450. }
  451. bridge::BridgeResponsePayload::Address(token_pub) => Ok(token_pub),
  452. _ => Err(Error::CashierError("Receive unknown value from Subscription".into())),
  453. }
  454. }
  455. .await;
  456. match result {
  457. Ok(res) => JsonResult::Resp(jsonresp(json!(res), json!(id))),
  458. Err(err) => JsonResult::Err(jsonerr(InternalError, Some(err.to_string()), json!(id))),
  459. }
  460. }
  461. // RPCAPI:
  462. // Executes a withdraw request given `network`, `token_id`, `publickey`
  463. // and `amount`. `publickey` is supposed to correspond to `network`.
  464. // Returns the transaction ID of the processed withdraw.
  465. // --> {"jsonrpc": "2.0", "method": "withdraw", "params": ["network", "token", "publickey", "amount"], "id": 1}
  466. // <-- {"jsonrpc": "2.0", "result": "txID", "id": 1}
  467. async fn withdraw(&self, id: Value, params: Value) -> JsonResult {
  468. info!(target: "CASHIER DAEMON", "Received withdraw request");
  469. let args: &Vec<serde_json::Value> = params.as_array().unwrap();
  470. if args.len() != 4 {
  471. return JsonResult::Err(jsonerr(InvalidParams, None, id))
  472. }
  473. let network: NetworkName;
  474. let mut mint_address: &str;
  475. let address: &str;
  476. match (args[0].as_str(), args[1].as_str(), args[2].as_str()) {
  477. (Some(n), Some(m), Some(a)) => {
  478. if NetworkName::from_str(n).is_err() {
  479. return JsonResult::Err(jsonerr(InvalidNetworkParam, None, id))
  480. }
  481. network = NetworkName::from_str(n).unwrap();
  482. mint_address = m;
  483. address = a;
  484. }
  485. (None, _, _) => return JsonResult::Err(jsonerr(InvalidNetworkParam, None, id)),
  486. (_, None, _) => return JsonResult::Err(jsonerr(InvalidTokenIdParam, None, id)),
  487. (_, _, None) => return JsonResult::Err(jsonerr(InvalidAddressParam, None, id)),
  488. }
  489. // Check if the features list contains this network
  490. if !self.networks.iter().any(|net| net.name == network) {
  491. return JsonResult::Err(jsonerr(
  492. InvalidParams,
  493. Some(format!("Cashier doesn't support this network: {}", network)),
  494. id,
  495. ))
  496. }
  497. let result: Result<String> = async {
  498. let token_id: DrkTokenId = generate_id2(mint_address, &network)?;
  499. let mint_address_opt = Self::check_token_id(&network, mint_address)?;
  500. if mint_address_opt.is_none() {
  501. // empty string
  502. mint_address = "";
  503. }
  504. let address = serialize(&address.to_string());
  505. let cashier_public: PublicKey;
  506. if let Some(addr) = self
  507. .cashier_wallet
  508. .get_withdraw_keys_by_token_public_key(&address, &network)
  509. .await?
  510. {
  511. cashier_public = addr.public;
  512. } else {
  513. let cashier_secret = SecretKey::random(&mut OsRng);
  514. cashier_public = PublicKey::from_secret(cashier_secret);
  515. self.cashier_wallet
  516. .put_withdraw_keys(
  517. &address,
  518. &cashier_public,
  519. &cashier_secret,
  520. &network,
  521. &token_id,
  522. mint_address.into(),
  523. )
  524. .await?;
  525. }
  526. let cashier_public_str = Address::from(cashier_public).to_string();
  527. Ok(cashier_public_str)
  528. }
  529. .await;
  530. match result {
  531. Ok(res) => JsonResult::Resp(jsonresp(json!(res), json!(id))),
  532. Err(err) => JsonResult::Err(jsonerr(InternalError, Some(err.to_string()), json!(id))),
  533. }
  534. }
  535. // RPCAPI:
  536. // Returns supported cashier features, like network, listening ports, etc.
  537. // --> {"jsonrpc": "2.0", "method": "features", "params": [], "id": 1}
  538. // <-- {"jsonrpc": "2.0", "result": {"network": ["btc", "sol"]}, "id": 1}
  539. async fn features(&self, id: Value, _params: Value) -> JsonResult {
  540. let tcp_port: Option<u16>;
  541. let tls_port: Option<u16>;
  542. let onionaddr: Option<String>;
  543. let dnsaddr: Option<String>;
  544. if self.config.serve_tls {
  545. tls_port = Some(self.config.rpc_listen_address.port());
  546. tcp_port = None;
  547. } else {
  548. tcp_port = Some(self.config.rpc_listen_address.port());
  549. tls_port = None;
  550. }
  551. if self.config.dns_addr.ends_with(".onion") {
  552. onionaddr = Some(self.config.dns_addr.clone());
  553. dnsaddr = None;
  554. } else {
  555. dnsaddr = Some(self.config.dns_addr.clone());
  556. onionaddr = None;
  557. }
  558. let mut resp: serde_json::Value = json!(
  559. {
  560. "server_version": env!("CARGO_PKG_VERSION"),
  561. "protocol_version": "1.0",
  562. "public_key": self.public_key.to_string(),
  563. "networks": [],
  564. "hosts": {
  565. "tcp_port": tcp_port,
  566. "tls_port": tls_port,
  567. "onion_addr": onionaddr,
  568. "dns_addr": dnsaddr,
  569. }
  570. }
  571. );
  572. for network in self.networks.iter() {
  573. resp.as_object_mut().unwrap()["networks"].as_array_mut().unwrap().push(json!(
  574. {
  575. network.name.to_string().to_lowercase():
  576. {"chain": network.blockchain.to_lowercase()}
  577. }
  578. ));
  579. }
  580. JsonResult::Resp(jsonresp(resp, id))
  581. }
  582. }
  583. async fn start(
  584. executor: Arc<Executor<'_>>,
  585. config: &CashierdConfig,
  586. get_address_flag: bool,
  587. ) -> Result<()> {
  588. let client_wallet_path =
  589. format!("sqlite://{}", expand_path(&config.client_wallet_path)?.to_str().unwrap());
  590. let client_wallet = WalletDb::new(&client_wallet_path, &config.client_wallet_password).await?;
  591. let rocks = Rocks::new(expand_path(&config.database_path.clone())?.as_path())?;
  592. info!("Building verifying key for the mint contract...");
  593. let mint_vk = VerifyingKey::build(11, &MintContract::default());
  594. info!("Building verifying key for the spend contract...");
  595. let spend_vk = VerifyingKey::build(11, &SpendContract::default());
  596. // new Client
  597. let gateway_urls =
  598. (config.gateway_protocol_url.parse()?, config.gateway_publisher_url.parse()?);
  599. let client = Client::new(rocks.clone(), gateway_urls, client_wallet.clone()).await?;
  600. let tree = client.get_tree().await?;
  601. let merkle_roots = RocksColumn::<columns::MerkleRoots>::new(rocks.clone());
  602. let nullifiers = RocksColumn::<columns::Nullifiers>::new(rocks);
  603. // get cashier public key
  604. let cashier_public = client.main_keypair.public;
  605. // new Cashier daemon
  606. let mut cashierd = Cashierd::new(config.clone(), Address::from(cashier_public)).await?;
  607. // this will print the cashier public key and exit
  608. if get_address_flag {
  609. info!("Public Key: {}", cashierd.public_key);
  610. return Ok(())
  611. };
  612. // new State
  613. let public_keys = vec![cashier_public];
  614. let state = Arc::new(Mutex::new(State {
  615. tree,
  616. merkle_roots,
  617. nullifiers,
  618. public_keys,
  619. mint_vk,
  620. spend_vk,
  621. }));
  622. // start cashier
  623. let (t1, t2) = cashierd.start(client, state, executor.clone()).await?;
  624. // config for rpc
  625. let cfg = RpcServerConfig {
  626. socket_addr: config.rpc_listen_address,
  627. use_tls: config.serve_tls,
  628. identity_path: expand_path(&config.clone().tls_identity_path)?,
  629. identity_pass: config.tls_identity_password.clone(),
  630. };
  631. // listen and serve RPC
  632. listen_and_serve(cfg, Arc::new(cashierd), executor).await?;
  633. t1.cancel().await;
  634. t2.cancel().await;
  635. Ok(())
  636. }
  637. #[async_std::main]
  638. async fn main() -> Result<()> {
  639. let args = CliCashierd::parse();
  640. let matches = CliCashierd::command().get_matches();
  641. let config_path = if args.config.is_some() {
  642. expand_path(&args.config.unwrap())?
  643. } else {
  644. join_config_path(&PathBuf::from("cashierd.toml"))?
  645. };
  646. // Spawn config file if it's not in place already.
  647. spawn_config(&config_path, CONFIG_FILE_CONTENTS)?;
  648. let verbosity_level = matches.occurrences_of("verbose");
  649. let (lvl, conf) = log_config(verbosity_level)?;
  650. TermLogger::init(lvl, conf, TerminalMode::Mixed, ColorChoice::Auto)?;
  651. let config: CashierdConfig = Config::<CashierdConfig>::load(config_path)?;
  652. if args.refresh {
  653. info!(target: "CASHIER DAEMON", "Refresh the wallet and the database");
  654. // refresh cashier's client wallet
  655. let client_wallet_path =
  656. format!("sqlite://{}", expand_path(&config.client_wallet_path)?.to_str().unwrap());
  657. let client_wallet =
  658. WalletDb::new(&client_wallet_path, &config.client_wallet_password).await?;
  659. client_wallet.remove_own_coins().await?;
  660. // refresh cashier wallet
  661. let wallet_path =
  662. format!("sqlite://{}", expand_path(&config.cashier_wallet_path)?.to_str().unwrap());
  663. let wallet = CashierDb::new(&wallet_path, &config.cashier_wallet_password).await?;
  664. wallet.remove_withdraw_and_deposit_keys().await?;
  665. // refresh rocks database
  666. if let Some(path) = expand_path(&config.database_path)?.to_str() {
  667. info!(target: "CASHIER DAEMON", "Remove database: {}", path);
  668. std::fs::remove_dir_all(path)?;
  669. }
  670. info!("Wallet updated successfully.");
  671. return Ok(())
  672. }
  673. let get_address_flag = args.address;
  674. let ex = Arc::new(Executor::new());
  675. let (signal, shutdown) = async_channel::unbounded::<()>();
  676. let ex2 = ex.clone();
  677. let nthreads = num_cpus::get();
  678. debug!(target: "CASHIER DAEMON", "Run {} executor threads", nthreads);
  679. let (_, result) = Parallel::new()
  680. .each(0..nthreads, |_| smol::future::block_on(ex.run(shutdown.recv())))
  681. // Run the main future on the current thread.
  682. .finish(|| {
  683. smol::future::block_on(async move {
  684. start(ex2, &config, get_address_flag).await?;
  685. drop(signal);
  686. Ok::<(), darkfi::Error>(())
  687. })
  688. });
  689. result
  690. }