cashier.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. use super::bridge;
  2. use super::reqrep::{PeerId, RepProtocol, Reply, ReqProtocol, Request};
  3. use crate::blockchain::Rocks;
  4. use crate::client::Client;
  5. use crate::serial::{deserialize, serialize};
  6. use crate::wallet::{CashierDbPtr, WalletPtr};
  7. use crate::{Error, Result};
  8. use ff::Field;
  9. use rand::rngs::OsRng;
  10. use async_executor::Executor;
  11. use log::*;
  12. use async_std::sync::{Arc, Mutex};
  13. use std::net::SocketAddr;
  14. use std::path::PathBuf;
  15. #[repr(u8)]
  16. enum CashierError {
  17. NoError,
  18. }
  19. #[repr(u8)]
  20. enum CashierCommand {
  21. GetAddress,
  22. Withdraw,
  23. }
  24. pub struct CashierService {
  25. addr: SocketAddr,
  26. wallet: CashierDbPtr,
  27. client: Arc<Mutex<Client>>,
  28. }
  29. impl CashierService {
  30. pub async fn new(
  31. addr: SocketAddr,
  32. wallet: CashierDbPtr,
  33. client_wallet: WalletPtr,
  34. cashier_database_path: PathBuf,
  35. gateway_addrs: (SocketAddr, SocketAddr),
  36. params_paths: (PathBuf, PathBuf),
  37. ) -> Result<CashierService> {
  38. let rocks = Rocks::new(&cashier_database_path)?;
  39. let client = Client::new(rocks, gateway_addrs, params_paths, client_wallet.clone())?;
  40. let client = Arc::new(Mutex::new(client));
  41. Ok(CashierService {
  42. addr,
  43. wallet,
  44. client,
  45. })
  46. }
  47. pub async fn start(
  48. &mut self,
  49. executor: Arc<Executor<'_>>,
  50. // TODO: make this a vector of assets
  51. asset_id: jubjub::Fr,
  52. ) -> Result<()> {
  53. debug!(target: "CASHIER DAEMON", "Start Cashier");
  54. let service_name = String::from("CASHIER DAEMON");
  55. let mut protocol = RepProtocol::new(self.addr.clone(), service_name.clone());
  56. let (send, recv) = protocol.start().await?;
  57. self.wallet.init_db()?;
  58. let wallet = self.wallet.clone();
  59. let bridge = bridge::Bridge::new();
  60. cfg_if::cfg_if! {
  61. if #[cfg(feature = "default")]{
  62. // TODO: the endpoint should be generic according to asset_id
  63. let btc_endpoint: (bitcoin::network::constants::Network, String) =
  64. (bitcoin::network::constants::Network::Bitcoin,
  65. String::from("ssl://blockstream.info:993"));
  66. let btc_client = super::btc::BtcClient::new(btc_endpoint)?;
  67. bridge.clone().add_clients(asset_id, Arc::new(btc_client)).await;
  68. }
  69. }
  70. let handle_request_task = executor.spawn(Self::handle_request_loop(
  71. send.clone(),
  72. recv.clone(),
  73. wallet.clone(),
  74. bridge.clone(),
  75. executor.clone(),
  76. ));
  77. self.client.lock().await.start().await?;
  78. let (notify, recv_coin) = async_channel::unbounded::<(jubjub::SubgroupPoint, u64)>();
  79. let cashier_client_subscriber_task =
  80. executor.spawn(Client::connect_to_subscriber_from_cashier(
  81. self.client.clone(),
  82. executor.clone(),
  83. self.wallet.clone(),
  84. notify.clone(),
  85. ));
  86. let wallet = self.wallet.clone();
  87. let ex = executor.clone();
  88. let subscribe_to_withdraw_keys_task = executor.spawn(async move {
  89. loop {
  90. let bridge = bridge.clone();
  91. let bridge_subscribtion = bridge.subscribe(ex.clone()).await;
  92. let (pub_key, amount) = recv_coin.recv().await.expect("Receive Own Coin");
  93. debug!(target: "CASHIER DAEMON", "Receive coin with following address and amount: {}, {}", pub_key, amount);
  94. let coin_addr = wallet.get_withdraw_coin_public_key_by_dkey_public(&pub_key, &serialize(&1))
  95. .expect("Get coin_key by pub_key");
  96. if let Some(addr) = coin_addr {
  97. // send equivalent amount of coin to this address
  98. bridge_subscribtion.sender.send(
  99. bridge::BridgeRequests {
  100. asset_id,
  101. payload: bridge::BridgeRequestsPayload::SendRequest(addr.clone(), amount)
  102. }
  103. ).await.expect("send request to bridge");
  104. let res = bridge_subscribtion.receiver.recv().await.expect("bridge resonse");
  105. if res.error == 0 {
  106. match res.payload {
  107. bridge::BridgeResponsePayload::SendResponse => {
  108. // TODO Send the received coins to the main address
  109. wallet.confirm_withdraw_key_record(&addr, &serialize(&1) )
  110. .expect("Confirm withdraw key record");
  111. }
  112. _ => {}
  113. }
  114. }
  115. }
  116. }
  117. });
  118. protocol.run(executor.clone()).await?;
  119. let _ = handle_request_task.cancel().await;
  120. let _ = cashier_client_subscriber_task.cancel().await;
  121. let _ = subscribe_to_withdraw_keys_task.cancel().await;
  122. Ok(())
  123. }
  124. async fn _mint_coin(
  125. &mut self,
  126. dkey_pub: jubjub::SubgroupPoint,
  127. value: u64,
  128. asset_id: jubjub::Fr,
  129. ) -> Result<()> {
  130. self.client
  131. .lock()
  132. .await
  133. .send(dkey_pub, value, asset_id, true)
  134. .await?;
  135. Ok(())
  136. }
  137. async fn handle_request_loop(
  138. send_queue: async_channel::Sender<(PeerId, Reply)>,
  139. recv_queue: async_channel::Receiver<(PeerId, Request)>,
  140. wallet: CashierDbPtr,
  141. bridge: Arc<bridge::Bridge>,
  142. executor: Arc<Executor<'_>>,
  143. ) -> Result<()> {
  144. loop {
  145. match recv_queue.recv().await {
  146. Ok(msg) => {
  147. let bridge = bridge.clone();
  148. let bridge_subscribtion = bridge.subscribe(executor.clone()).await;
  149. let _ = executor
  150. .spawn(Self::handle_request(
  151. msg,
  152. bridge_subscribtion,
  153. wallet.clone(),
  154. send_queue.clone(),
  155. ))
  156. .detach();
  157. }
  158. Err(_) => {
  159. break;
  160. }
  161. }
  162. }
  163. Ok(())
  164. }
  165. async fn handle_request(
  166. msg: (PeerId, Request),
  167. bridge_subscribtion: bridge::BridgeSubscribtion,
  168. cashier_wallet: CashierDbPtr,
  169. send_queue: async_channel::Sender<(PeerId, Reply)>,
  170. ) -> Result<()> {
  171. let request = msg.1;
  172. let peer = msg.0;
  173. debug!(target: "CASHIER DAEMON", "Get command");
  174. match request.get_command() {
  175. 0 => {
  176. debug!(target: "CASHIER DAEMON", "Received deposit request");
  177. // Exchange zk_pubkey for bitcoin address
  178. let (asset_id, dpub): (jubjub::Fr, jubjub::SubgroupPoint) =
  179. deserialize(&request.get_payload())?;
  180. let _check =
  181. cashier_wallet.get_deposit_coin_keys_by_dkey_public(&dpub, &serialize(&1));
  182. bridge_subscribtion
  183. .sender
  184. .send(bridge::BridgeRequests {
  185. asset_id,
  186. payload: bridge::BridgeRequestsPayload::WatchRequest,
  187. })
  188. .await?;
  189. let bridge_res = bridge_subscribtion.receiver.recv().await?;
  190. match bridge_res.payload {
  191. bridge::BridgeResponsePayload::WatchResponse(coin_priv, coin_pub) => {
  192. // add pairings to db
  193. let _result = cashier_wallet.put_exchange_keys(
  194. &dpub,
  195. &coin_priv,
  196. &coin_pub,
  197. &serialize(&asset_id),
  198. );
  199. let mut reply = Reply::from(&request, CashierError::NoError as u32, vec![]);
  200. reply.set_payload(coin_pub);
  201. // send reply
  202. send_queue.send((peer, reply)).await?;
  203. }
  204. _ => {}
  205. }
  206. debug!(target: "CASHIER DAEMON","Waiting for address balance");
  207. }
  208. 1 => {
  209. debug!(target: "CASHIER DAEMON", "Received withdraw request");
  210. let (asset_id, coin_address): (jubjub::Fr, Vec<u8>) =
  211. deserialize(&request.get_payload())?;
  212. let asset_id = serialize(&asset_id);
  213. let cashier_public: jubjub::SubgroupPoint;
  214. if let Some(addr) =
  215. cashier_wallet.get_withdraw_keys_by_coin_public_key(&coin_address, &asset_id)?
  216. {
  217. cashier_public = addr.public;
  218. } else {
  219. let cashier_secret = jubjub::Fr::random(&mut OsRng);
  220. cashier_public =
  221. zcash_primitives::constants::SPENDING_KEY_GENERATOR * cashier_secret;
  222. cashier_wallet.put_withdraw_keys(
  223. &coin_address,
  224. &cashier_public,
  225. &cashier_secret,
  226. &asset_id,
  227. )?;
  228. }
  229. let mut reply = Reply::from(&request, CashierError::NoError as u32, vec![]);
  230. reply.set_payload(serialize(&cashier_public));
  231. send_queue.send((peer, reply)).await?;
  232. }
  233. _ => {
  234. return Err(Error::ServicesError("received wrong command"));
  235. }
  236. }
  237. Ok(())
  238. }
  239. }
  240. pub struct CashierClient {
  241. protocol: ReqProtocol,
  242. }
  243. impl CashierClient {
  244. pub fn new(addr: SocketAddr) -> Result<Self> {
  245. let protocol = ReqProtocol::new(addr, String::from("CASHIER CLIENT"));
  246. Ok(CashierClient { protocol })
  247. }
  248. pub async fn start(&mut self) -> Result<()> {
  249. debug!(target: "CASHIER CLIENT", "Start CashierClient");
  250. self.protocol.start().await?;
  251. Ok(())
  252. }
  253. pub async fn withdraw(
  254. &mut self,
  255. asset_id: jubjub::Fr,
  256. coin_address: Vec<u8>,
  257. ) -> Result<Option<jubjub::SubgroupPoint>> {
  258. let handle_error = Arc::new(handle_error);
  259. let rep = self
  260. .protocol
  261. .request(
  262. CashierCommand::Withdraw as u8,
  263. serialize(&(asset_id, coin_address)),
  264. handle_error,
  265. )
  266. .await?;
  267. if let Some(key) = rep {
  268. let address: jubjub::SubgroupPoint = deserialize(&key)?;
  269. return Ok(Some(address));
  270. }
  271. Ok(None)
  272. }
  273. pub async fn get_address(
  274. &mut self,
  275. asset_id: jubjub::Fr,
  276. index: jubjub::SubgroupPoint,
  277. ) -> Result<Option<Vec<u8>>> {
  278. let handle_error = Arc::new(handle_error);
  279. let rep = self
  280. .protocol
  281. .request(
  282. CashierCommand::GetAddress as u8,
  283. serialize(&(asset_id, index)),
  284. handle_error,
  285. )
  286. .await?;
  287. if let Some(key) = rep {
  288. return Ok(Some(key));
  289. }
  290. Ok(None)
  291. }
  292. }
  293. fn handle_error(status_code: u32) {
  294. match status_code {
  295. _ => {}
  296. }
  297. }