main.rs 28 KB

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