cashierd.rs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718
  1. use async_std::sync::{Arc, Mutex};
  2. use std::collections::HashMap;
  3. use std::path::PathBuf;
  4. use std::str::FromStr;
  5. use async_trait::async_trait;
  6. use clap::clap_app;
  7. use ff::Field;
  8. use log::debug;
  9. use rand::rngs::OsRng;
  10. use serde_json::{json, Value};
  11. use drk::{
  12. blockchain::{rocks::columns, Rocks, RocksColumn},
  13. cli::{CashierdConfig, Config},
  14. client::{Client, State},
  15. crypto::{
  16. load_params, merkle::CommitmentTree, save_params, setup_mint_prover, setup_spend_prover,
  17. },
  18. rpc::{
  19. jsonrpc::{error as jsonerr, response as jsonresp},
  20. jsonrpc::{ErrorCode::*, JsonRequest, JsonResult},
  21. rpcserver::{listen_and_serve, RequestHandler, RpcServerConfig},
  22. },
  23. serial::{deserialize, serialize},
  24. service::{bridge, bridge::Bridge},
  25. util::{expand_path, generate_id, join_config_path, parse::truncate, NetworkName},
  26. wallet::{cashierdb::TokenKey, CashierDb, WalletDb},
  27. Error, Result,
  28. };
  29. fn handle_bridge_error(error_code: u32) -> Result<()> {
  30. match error_code {
  31. 1 => Err(Error::BridgeError("Not Supported Client".into())),
  32. 2 => Err(Error::BridgeError(
  33. "Unable to watch the deposit address".into(),
  34. )),
  35. 3 => Err(Error::BridgeError("Unable to send the token".into())),
  36. _ => Err(Error::BridgeError("Unknown error_code".into())),
  37. }
  38. }
  39. #[derive(Clone, Debug)]
  40. pub struct Network {
  41. pub name: NetworkName,
  42. pub blockchain: String,
  43. pub keypair: String,
  44. }
  45. struct Cashierd {
  46. bridge: Arc<Bridge>,
  47. cashier_wallet: Arc<CashierDb>,
  48. networks: Vec<Network>,
  49. }
  50. #[async_trait]
  51. impl RequestHandler for Cashierd {
  52. async fn handle_request(&self, req: JsonRequest) -> 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. match req.method.as_str() {
  58. Some("deposit") => return self.deposit(req.id, req.params).await,
  59. Some("withdraw") => return self.withdraw(req.id, req.params).await,
  60. Some("features") => return self.features(req.id, req.params).await,
  61. Some(_) => {}
  62. None => {}
  63. };
  64. return JsonResult::Err(jsonerr(MethodNotFound, None, req.id));
  65. }
  66. }
  67. impl Cashierd {
  68. async fn new(config: CashierdConfig) -> Result<Self> {
  69. debug!(target: "CASHIER DAEMON", "Initialize");
  70. let cashier_wallet = CashierDb::new(
  71. expand_path(&config.cashier_wallet_path.clone())?.as_path(),
  72. config.cashier_wallet_password.clone(),
  73. )?;
  74. let mut networks = Vec::new();
  75. for network in config.clone().networks {
  76. networks.push(Network {
  77. name: NetworkName::from_str(&network.name)?,
  78. blockchain: network.blockchain,
  79. keypair: network.keypair,
  80. });
  81. }
  82. let bridge = bridge::Bridge::new();
  83. Ok(Self {
  84. bridge,
  85. cashier_wallet,
  86. networks,
  87. })
  88. }
  89. async fn resume_watch_deposit_keys(
  90. bridge: Arc<Bridge>,
  91. cashier_wallet: Arc<CashierDb>,
  92. networks: Vec<Network>,
  93. ) -> Result<()> {
  94. debug!(target: "CASHIER DAEMON", "Resume watch deposit keys");
  95. for network in networks.iter() {
  96. let keypairs_to_watch =
  97. cashier_wallet.get_deposit_token_keys_by_network(&network.name)?;
  98. for deposit_token in keypairs_to_watch {
  99. let bridge = bridge.clone();
  100. let bridge_subscribtion = bridge
  101. .subscribe(
  102. deposit_token.drk_public_key,
  103. Some(deposit_token.mint_address),
  104. )
  105. .await;
  106. bridge_subscribtion
  107. .sender
  108. .send(bridge::BridgeRequests {
  109. network: network.name.clone(),
  110. payload: bridge::BridgeRequestsPayload::Watch(Some(
  111. deposit_token.token_key,
  112. )),
  113. })
  114. .await?;
  115. }
  116. }
  117. Ok(())
  118. }
  119. async fn listen_for_receiving_coins(
  120. bridge: Arc<Bridge>,
  121. cashier_wallet: Arc<CashierDb>,
  122. recv_coin: async_channel::Receiver<(jubjub::SubgroupPoint, u64)>,
  123. ) -> Result<()> {
  124. // received drk coin
  125. let (drk_pub_key, amount) = recv_coin.recv().await?;
  126. debug!(target: "CASHIER DAEMON", "Receive coin with amount: {}", amount);
  127. // get public key, and token_id of the token
  128. let token = cashier_wallet.get_withdraw_token_public_key_by_dkey_public(&drk_pub_key)?;
  129. // send a request to bridge to send equivalent amount of
  130. // received drk coin to token publickey
  131. if let Some(withdraw_token) = token {
  132. let bridge_subscribtion = bridge
  133. .subscribe(drk_pub_key, Some(withdraw_token.mint_address))
  134. .await;
  135. // send a request to the bridge to send amount of token
  136. // equivalent to the received drk
  137. bridge_subscribtion
  138. .sender
  139. .send(bridge::BridgeRequests {
  140. network: withdraw_token.network.clone(),
  141. payload: bridge::BridgeRequestsPayload::Send(
  142. withdraw_token.token_public_key.clone(),
  143. amount,
  144. ),
  145. })
  146. .await?;
  147. // receive a response
  148. let res = bridge_subscribtion.receiver.recv().await?;
  149. // check the response's error
  150. let error_code = res.error as u32;
  151. if error_code != 0 {
  152. return handle_bridge_error(error_code);
  153. }
  154. match res.payload {
  155. bridge::BridgeResponsePayload::Send => {
  156. cashier_wallet.confirm_withdraw_key_record(
  157. &withdraw_token.token_public_key,
  158. &withdraw_token.network,
  159. )?;
  160. }
  161. _ => {
  162. return Err(Error::BridgeError(
  163. "Receive unknown value from Subscription".into(),
  164. ));
  165. }
  166. }
  167. }
  168. Ok(())
  169. }
  170. async fn deposit(&self, id: Value, params: Value) -> JsonResult {
  171. debug!(target: "CASHIER DAEMON", "RECEIVED DEPOSIT REQUEST");
  172. let args: &Vec<serde_json::Value> = params.as_array().unwrap();
  173. if args.len() != 3 {
  174. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  175. }
  176. let network: NetworkName;
  177. let mut mint_address: &str;
  178. let drk_pub_key: &str;
  179. match (args[0].as_str(), args[1].as_str(), args[2].as_str()) {
  180. (Some(n), Some(m), Some(d)) => {
  181. if NetworkName::from_str(n).is_err() {
  182. return JsonResult::Err(jsonerr(InvalidNetworkParam, None, id));
  183. }
  184. network = NetworkName::from_str(n).unwrap();
  185. mint_address = m;
  186. drk_pub_key = d;
  187. }
  188. (None, _, _) => {
  189. return JsonResult::Err(jsonerr(InvalidNetworkParam, None, id));
  190. }
  191. (_, None, _) => {
  192. return JsonResult::Err(jsonerr(InvalidTokenIdParam, None, id));
  193. }
  194. (_, _, None) => {
  195. return JsonResult::Err(jsonerr(InvalidAddressParam, None, id));
  196. }
  197. }
  198. // Check if the features list contains this network
  199. if self
  200. .networks
  201. .iter()
  202. .find(|net| net.name == network)
  203. .is_none()
  204. {
  205. return JsonResult::Err(jsonerr(
  206. InvalidParams,
  207. Some(format!("Cashier doesn't support this network: {}", network)),
  208. id,
  209. ));
  210. }
  211. let result: Result<String> = async {
  212. let token_id = generate_id(&mint_address, &network)?;
  213. let mint_address_opt = Self::check_token_id(&network, &mint_address)?;
  214. if mint_address_opt.is_none() {
  215. mint_address = "";
  216. }
  217. let drk_pub_key = bs58::decode(&drk_pub_key).into_vec()?;
  218. let drk_pub_key: jubjub::SubgroupPoint = deserialize(&drk_pub_key)?;
  219. // check if the drk public key already exist
  220. let check = self
  221. .cashier_wallet
  222. .get_deposit_token_keys_by_dkey_public(&drk_pub_key, &network)?;
  223. // start new subscription from the bridge and then cashierd will
  224. // send a request to the bridge to generate keypair for the desired token
  225. // and start watch this token's keypair
  226. // once a bridge receive an update for this token's address
  227. // cashierd will get notification from bridge.listen() function
  228. //
  229. // The "if statement" check from the cashierdb if the node's drk_pub_key already exist
  230. // in this case it will not generate new keypair but it will
  231. // retrieve the old generated keypair
  232. //
  233. // Once receive a response from the bridge, the cashierd then save a deposit
  234. // record in cashierdb with the network name and token id
  235. let bridge = self.bridge.clone();
  236. let bridge_subscribtion = bridge.subscribe(drk_pub_key, mint_address_opt).await;
  237. if check.is_empty() {
  238. bridge_subscribtion
  239. .sender
  240. .send(bridge::BridgeRequests {
  241. network: network.clone(),
  242. payload: bridge::BridgeRequestsPayload::Watch(None),
  243. })
  244. .await?;
  245. } else {
  246. let keypair = check[0].clone();
  247. bridge_subscribtion
  248. .sender
  249. .send(bridge::BridgeRequests {
  250. network: network.clone(),
  251. payload: bridge::BridgeRequestsPayload::Watch(Some(keypair)),
  252. })
  253. .await?;
  254. }
  255. let bridge_res = bridge_subscribtion.receiver.recv().await?;
  256. let error_code = bridge_res.error as u32;
  257. if error_code != 0 {
  258. return handle_bridge_error(error_code).map(|_| String::new());
  259. }
  260. match bridge_res.payload {
  261. bridge::BridgeResponsePayload::Watch(token_key) => {
  262. // add pairings to db
  263. self.cashier_wallet.put_deposit_keys(
  264. &drk_pub_key,
  265. &token_key.private_key,
  266. &serialize(&token_key.public_key),
  267. &network,
  268. &token_id,
  269. mint_address.into(),
  270. )?;
  271. return Ok(token_key.public_key);
  272. }
  273. bridge::BridgeResponsePayload::Address(token_pub) => {
  274. return Ok(token_pub);
  275. }
  276. _ => Err(Error::BridgeError(
  277. "Receive unknown value from Subscription".into(),
  278. )),
  279. }
  280. }
  281. .await;
  282. match result {
  283. Ok(res) => JsonResult::Resp(jsonresp(json!(res), json!(id))),
  284. Err(err) => JsonResult::Err(jsonerr(InternalError, Some(err.to_string()), json!(id))),
  285. }
  286. }
  287. async fn withdraw(&self, id: Value, params: Value) -> JsonResult {
  288. debug!(target: "CASHIER DAEMON", "RECEIVED WITHDRAW REQUEST");
  289. let args: &Vec<serde_json::Value> = params.as_array().unwrap();
  290. if args.len() != 4 {
  291. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  292. }
  293. let network: NetworkName;
  294. let mut mint_address: &str;
  295. let address: &str;
  296. match (args[0].as_str(), args[1].as_str(), args[2].as_str()) {
  297. (Some(n), Some(m), Some(a)) => {
  298. if NetworkName::from_str(n).is_err() {
  299. return JsonResult::Err(jsonerr(InvalidNetworkParam, None, id));
  300. }
  301. network = NetworkName::from_str(n).unwrap();
  302. mint_address = m;
  303. address = a;
  304. }
  305. (None, _, _) => {
  306. return JsonResult::Err(jsonerr(InvalidNetworkParam, None, id));
  307. }
  308. (_, None, _) => {
  309. return JsonResult::Err(jsonerr(InvalidTokenIdParam, None, id));
  310. }
  311. (_, _, None) => {
  312. return JsonResult::Err(jsonerr(InvalidAddressParam, None, id));
  313. }
  314. }
  315. // Check if the features list contains this network
  316. if self
  317. .networks
  318. .iter()
  319. .find(|net| net.name == network)
  320. .is_none()
  321. {
  322. return JsonResult::Err(jsonerr(
  323. InvalidParams,
  324. Some(format!("Cashier doesn't support this network: {}", network)),
  325. id,
  326. ));
  327. }
  328. let result: Result<String> = async {
  329. let token_id = generate_id(&mint_address, &network)?;
  330. let mint_address_opt = Self::check_token_id(&network, &mint_address)?;
  331. if mint_address_opt.is_none() {
  332. // empty string
  333. mint_address = "";
  334. }
  335. let address = serialize(&address.to_string());
  336. let cashier_public: jubjub::SubgroupPoint;
  337. if let Some(addr) = self
  338. .cashier_wallet
  339. .get_withdraw_keys_by_token_public_key(&address, &network)?
  340. {
  341. cashier_public = addr.public;
  342. } else {
  343. let cashier_secret = jubjub::Fr::random(&mut OsRng);
  344. cashier_public =
  345. zcash_primitives::constants::SPENDING_KEY_GENERATOR * cashier_secret;
  346. self.cashier_wallet.put_withdraw_keys(
  347. &address,
  348. &cashier_public,
  349. &cashier_secret,
  350. &network,
  351. &token_id,
  352. mint_address.into(),
  353. )?;
  354. }
  355. let cashier_public_str = bs58::encode(serialize(&cashier_public)).into_string();
  356. Ok(cashier_public_str)
  357. }
  358. .await;
  359. match result {
  360. Ok(res) => JsonResult::Resp(jsonresp(json!(res), json!(id))),
  361. Err(err) => JsonResult::Err(jsonerr(InternalError, Some(err.to_string()), json!(id))),
  362. }
  363. }
  364. async fn features(&self, id: Value, _params: Value) -> JsonResult {
  365. JsonResult::Resp(jsonresp(
  366. json!(self
  367. .networks
  368. .iter()
  369. .map(|net| (net.name.to_string(), net.blockchain.to_owned()))
  370. .collect::<HashMap<String, String>>()),
  371. id,
  372. ))
  373. }
  374. fn check_token_id(network: &NetworkName, _token_id: &str) -> Result<Option<String>> {
  375. match network {
  376. #[cfg(feature = "sol")]
  377. NetworkName::Solana => {
  378. use drk::service::sol::SOL_NATIVE_TOKEN_ID;
  379. if _token_id != SOL_NATIVE_TOKEN_ID {
  380. return Ok(Some(_token_id.to_string()));
  381. }
  382. return Ok(None);
  383. }
  384. #[cfg(feature = "btc")]
  385. NetworkName::Bitcoin => Ok(None),
  386. _ => Err(Error::NotSupportedNetwork),
  387. }
  388. }
  389. async fn start(
  390. &mut self,
  391. mut client: Client,
  392. state: Arc<Mutex<State>>,
  393. ) -> Result<(
  394. smol::Task<Result<()>>,
  395. smol::Task<Result<()>>,
  396. smol::Task<Result<()>>,
  397. )> {
  398. self.cashier_wallet.init_db().await?;
  399. for network in self.networks.iter() {
  400. match network.name {
  401. #[cfg(feature = "sol")]
  402. NetworkName::Solana => {
  403. debug!(target: "CASHIER DAEMON", "Add sol network");
  404. use drk::service::{sol::SolFailed, SolClient};
  405. use solana_sdk::{signature::Signer, signer::keypair::Keypair};
  406. let bridge2 = self.bridge.clone();
  407. let main_keypair: Keypair;
  408. let main_keypairs = self.cashier_wallet.get_main_keys(&NetworkName::Solana)?;
  409. if network.keypair.is_empty() {
  410. if main_keypairs.is_empty() {
  411. main_keypair = Keypair::new();
  412. self.cashier_wallet.put_main_keys(
  413. &TokenKey {
  414. private_key: serialize(&main_keypair),
  415. public_key: serialize(&main_keypair.pubkey()),
  416. },
  417. &NetworkName::Solana,
  418. )?;
  419. } else {
  420. main_keypair =
  421. deserialize(&main_keypairs[main_keypairs.len() - 1].private_key)?;
  422. }
  423. } else {
  424. let keypair_str = drk::cli::cli_config::load_keypair_to_str(
  425. PathBuf::from(expand_path(&network.keypair.clone())?),
  426. )?;
  427. let keypair_bytes: Vec<u8> = serde_json::from_str(&keypair_str)?;
  428. main_keypair = Keypair::from_bytes(&keypair_bytes)
  429. .map_err(|e| SolFailed::ParseError(e.to_string()))?;
  430. }
  431. let sol_client = SolClient::new(main_keypair, &network.blockchain).await?;
  432. bridge2.add_clients(NetworkName::Solana, sol_client).await?;
  433. }
  434. #[cfg(feature = "btc")]
  435. NetworkName::Bitcoin => {
  436. debug!(target: "CASHIER DAEMON", "Add btc network");
  437. use drk::service::btc::{BtcClient, BtcFailed, Keypair};
  438. let bridge2 = self.bridge.clone();
  439. let main_keypair: Keypair;
  440. let main_keypairs = self.cashier_wallet.get_main_keys(&NetworkName::Bitcoin)?;
  441. if network.keypair.is_empty() {
  442. if main_keypairs.is_empty() {
  443. main_keypair = Keypair::new();
  444. self.cashier_wallet.put_main_keys(
  445. &TokenKey {
  446. private_key: serialize(&main_keypair),
  447. public_key: serialize(&main_keypair.pubkey()),
  448. },
  449. &NetworkName::Bitcoin,
  450. )?;
  451. } else {
  452. main_keypair =
  453. deserialize(&main_keypairs[main_keypairs.len() - 1].private_key)?;
  454. }
  455. } else {
  456. let keypair_str = drk::cli::cli_config::load_keypair_to_str(
  457. PathBuf::from(expand_path(&network.keypair.clone())?),
  458. )?;
  459. let keypair_bytes: Vec<u8> = serde_json::from_str(&keypair_str)?;
  460. main_keypair = Keypair::from_bytes(&keypair_bytes)
  461. .map_err(|e| BtcFailed::DecodeAndEncodeError(e.to_string()))?;
  462. }
  463. let btc_client = BtcClient::new(main_keypair, &network.blockchain).await?;
  464. bridge2
  465. .add_clients(NetworkName::Bitcoin, btc_client)
  466. .await?;
  467. }
  468. _ => {}
  469. }
  470. }
  471. let resume_watch_deposit_keys_task = smol::spawn(Self::resume_watch_deposit_keys(
  472. self.bridge.clone(),
  473. self.cashier_wallet.clone(),
  474. self.networks.clone(),
  475. ));
  476. client.start().await?;
  477. let (notify, recv_coin) = async_channel::unbounded::<(jubjub::SubgroupPoint, u64)>();
  478. client
  479. .connect_to_subscriber_from_cashier(state, self.cashier_wallet.clone(), notify.clone())
  480. .await?;
  481. let cashier_wallet = self.cashier_wallet.clone();
  482. let bridge = self.bridge.clone();
  483. let listen_for_receiving_coins_task: smol::Task<Result<()>> = smol::spawn(async move {
  484. loop {
  485. Self::listen_for_receiving_coins(
  486. bridge.clone(),
  487. cashier_wallet.clone(),
  488. recv_coin.clone(),
  489. )
  490. .await?;
  491. }
  492. });
  493. let bridge2 = self.bridge.clone();
  494. let listen_for_notification_from_bridge_task: smol::Task<Result<()>> =
  495. smol::spawn(async move {
  496. while let Some(token_notification) = bridge2.clone().listen().await {
  497. debug!(target: "CASHIER DAEMON", "Notification from birdge");
  498. let token_notification = token_notification?;
  499. let received_balance = truncate(
  500. token_notification.received_balance,
  501. 8,
  502. token_notification.decimals,
  503. )?;
  504. client
  505. .send(
  506. token_notification.drk_pub_key,
  507. received_balance,
  508. token_notification.token_id,
  509. true,
  510. )
  511. .await?;
  512. }
  513. Ok(())
  514. });
  515. Ok((
  516. resume_watch_deposit_keys_task,
  517. listen_for_receiving_coins_task,
  518. listen_for_notification_from_bridge_task,
  519. ))
  520. }
  521. }
  522. #[async_std::main]
  523. async fn main() -> Result<()> {
  524. let args = clap_app!(cashierd =>
  525. (@arg CONFIG: -c --config +takes_value "Sets a custom config file")
  526. (@arg ADDRESS: -a --address "Get Cashier Public key")
  527. (@arg verbose: -v --verbose "Increase verbosity")
  528. )
  529. .get_matches();
  530. let config_path = if args.is_present("CONFIG") {
  531. PathBuf::from(args.value_of("CONFIG").unwrap())
  532. } else {
  533. join_config_path(&PathBuf::from("cashierd.toml"))?
  534. };
  535. let loglevel = if args.is_present("verbose") {
  536. log::Level::Debug
  537. } else {
  538. log::Level::Info
  539. };
  540. simple_logger::init_with_level(loglevel)?;
  541. let config: CashierdConfig = Config::<CashierdConfig>::load(config_path)?;
  542. let mut cashierd = Cashierd::new(config.clone()).await?;
  543. let client_wallet = WalletDb::new(
  544. expand_path(&config.client_wallet_path.clone())?.as_path(),
  545. config.client_wallet_password.clone(),
  546. )?;
  547. let rocks = Rocks::new(expand_path(&config.database_path.clone())?.as_path())?;
  548. let params_paths = (
  549. expand_path(&config.mint_params_path.clone())?,
  550. expand_path(&config.spend_params_path.clone())?,
  551. );
  552. let mint_params_path = params_paths.0.to_str().unwrap_or("mint.params");
  553. let spend_params_path = params_paths.1.to_str().unwrap_or("spend.params");
  554. // Auto create trusted ceremony parameters if they don't exist
  555. if !params_paths.0.exists() {
  556. let params = setup_mint_prover();
  557. save_params(mint_params_path, &params)?;
  558. }
  559. if !params_paths.1.exists() {
  560. let params = setup_spend_prover();
  561. save_params(spend_params_path, &params)?;
  562. }
  563. // Load trusted setup parameters
  564. let (mint_params, mint_pvk) = load_params(mint_params_path)?;
  565. let (spend_params, spend_pvk) = load_params(spend_params_path)?;
  566. let client = Client::new(
  567. rocks.clone(),
  568. (
  569. config.gateway_protocol_url.parse()?,
  570. config.gateway_publisher_url.parse()?,
  571. ),
  572. client_wallet.clone(),
  573. mint_params,
  574. spend_params,
  575. )
  576. .await?;
  577. let merkle_roots = RocksColumn::<columns::MerkleRoots>::new(rocks.clone());
  578. let nullifiers = RocksColumn::<columns::Nullifiers>::new(rocks);
  579. let cashier_public_keys = vec![client.main_keypair.public];
  580. let state = Arc::new(Mutex::new(State {
  581. tree: CommitmentTree::empty(),
  582. merkle_roots,
  583. nullifiers,
  584. mint_pvk,
  585. spend_pvk,
  586. public_keys: cashier_public_keys,
  587. }));
  588. if args.is_present("ADDRESS") {
  589. let cashier_public = client.main_keypair.public;
  590. let cashier_public = bs58::encode(&serialize(&cashier_public)).into_string();
  591. println!("Public Key: {}", cashier_public);
  592. return Ok(());
  593. };
  594. let cfg = RpcServerConfig {
  595. socket_addr: config.rpc_listen_address.clone(),
  596. use_tls: config.serve_tls,
  597. identity_path: expand_path(&config.clone().tls_identity_path)?,
  598. identity_pass: config.tls_identity_password.clone(),
  599. };
  600. let (t1, t2, t3) = cashierd.start(client, state).await?;
  601. listen_and_serve(cfg, Arc::new(cashierd)).await?;
  602. t1.cancel().await;
  603. t2.cancel().await;
  604. t3.cancel().await;
  605. Ok(())
  606. }