darkfid.rs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  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 log::debug;
  8. use serde_json::{json, Value};
  9. use drk::{
  10. blockchain::{rocks::columns, Rocks, RocksColumn},
  11. cli::{Config, DarkfidConfig},
  12. client::{Client, State},
  13. crypto::{
  14. load_params, merkle::CommitmentTree, save_params, setup_mint_prover, setup_spend_prover,
  15. },
  16. rpc::{
  17. jsonrpc::{error as jsonerr, request as jsonreq, response as jsonresp, send_request},
  18. jsonrpc::{ErrorCode::*, JsonRequest, JsonResult},
  19. rpcserver::{listen_and_serve, RequestHandler, RpcServerConfig},
  20. },
  21. serial::{deserialize, serialize},
  22. util::{
  23. assign_id, decode_base10, encode_base10, expand_path, join_config_path, DrkTokenList,
  24. NetworkName, SolTokenList,
  25. },
  26. wallet::WalletDb,
  27. Error, Result,
  28. };
  29. #[derive(Clone, Debug)]
  30. pub struct Cashier {
  31. pub name: String,
  32. pub rpc_url: String,
  33. pub public_key: jubjub::SubgroupPoint,
  34. }
  35. #[async_trait]
  36. impl RequestHandler for Darkfid {
  37. async fn handle_request(&self, req: JsonRequest) -> JsonResult {
  38. if req.params.as_array().is_none() {
  39. return JsonResult::Err(jsonerr(InvalidParams, None, req.id));
  40. }
  41. debug!(target: "RPC", "--> {}", serde_json::to_string(&req).unwrap());
  42. match req.method.as_str() {
  43. Some("say_hello") => return self.say_hello(req.id, req.params).await,
  44. Some("create_wallet") => return self.create_wallet(req.id, req.params).await,
  45. Some("key_gen") => return self.key_gen(req.id, req.params).await,
  46. Some("get_key") => return self.get_key(req.id, req.params).await,
  47. Some("get_balances") => return self.get_balances(req.id, req.params).await,
  48. Some("get_token_id") => return self.get_token_id(req.id, req.params).await,
  49. Some("features") => return self.features(req.id, req.params).await,
  50. Some("deposit") => return self.deposit(req.id, req.params).await,
  51. Some("withdraw") => return self.withdraw(req.id, req.params).await,
  52. Some("transfer") => return self.transfer(req.id, req.params).await,
  53. Some(_) | None => return JsonResult::Err(jsonerr(MethodNotFound, None, req.id)),
  54. };
  55. }
  56. }
  57. struct Darkfid {
  58. client: Arc<Mutex<Client>>,
  59. sol_tokenlist: SolTokenList,
  60. drk_tokenlist: DrkTokenList,
  61. cashiers: Vec<Cashier>,
  62. }
  63. impl Darkfid {
  64. async fn new(client: Arc<Mutex<Client>>, cashiers: Vec<Cashier>) -> Result<Self> {
  65. let sol_tokenlist = SolTokenList::new()?;
  66. let drk_tokenlist = DrkTokenList::new(sol_tokenlist.clone())?;
  67. Ok(Self {
  68. client,
  69. sol_tokenlist,
  70. drk_tokenlist,
  71. cashiers,
  72. })
  73. }
  74. async fn start(&mut self, state: Arc<Mutex<State>>) -> Result<()> {
  75. self.client.lock().await.start().await?;
  76. self.client
  77. .lock()
  78. .await
  79. .connect_to_subscriber(state)
  80. .await?;
  81. Ok(())
  82. }
  83. // --> {"method": "say_hello", "params": []}
  84. // <-- {"result": "hello world"}
  85. async fn say_hello(&self, id: Value, _params: Value) -> JsonResult {
  86. JsonResult::Resp(jsonresp(json!("hello world"), id))
  87. }
  88. // --> {"method": "create_wallet", "params": []}
  89. // <-- {"result": true}
  90. async fn create_wallet(&self, id: Value, _params: Value) -> JsonResult {
  91. match self.client.lock().await.init_db().await {
  92. Ok(()) => return JsonResult::Resp(jsonresp(json!(true), id)),
  93. Err(e) => {
  94. return JsonResult::Err(jsonerr(ServerError(-32001), Some(e.to_string()), id))
  95. }
  96. }
  97. }
  98. // --> {"method": "key_gen", "params": []}
  99. // <-- {"result": true}
  100. async fn key_gen(&self, id: Value, _params: Value) -> JsonResult {
  101. match self.client.lock().await.key_gen().await {
  102. Ok(()) => return JsonResult::Resp(jsonresp(json!(true), id)),
  103. Err(e) => {
  104. return JsonResult::Err(jsonerr(ServerError(-32002), Some(e.to_string()), id))
  105. }
  106. }
  107. }
  108. // --> {"method": "get_key", "params": []}
  109. // <-- {"result": "vdNS7oBj7KvsMWWmo9r96SV4SqATLrGsH2a3PGpCfJC"}
  110. async fn get_key(&self, id: Value, _params: Value) -> JsonResult {
  111. let pk = self.client.lock().await.main_keypair.public;
  112. let b58 = bs58::encode(serialize(&pk)).into_string();
  113. return JsonResult::Resp(jsonresp(json!(b58), id));
  114. }
  115. // --> {"method": "get_balances", "params": []}
  116. // <-- {"result": "get_balances": "[ {"btc": (value, network)}, .. ]"}
  117. async fn get_balances(&self, id: Value, _params: Value) -> JsonResult {
  118. let result: Result<HashMap<String, (String, String)>> = async {
  119. let balances = self.client.lock().await.get_balances().await?;
  120. let mut symbols: HashMap<String, (String, String)> = HashMap::new();
  121. for balance in balances.list.iter() {
  122. // this is hardcoded for SOL
  123. // TODO: if id == btc_id:
  124. // network = bitcoin
  125. // else
  126. // network = solana
  127. let network = "solana";
  128. if let Some(symbol) = self.drk_tokenlist.symbol_from_id(balance.token_id)? {
  129. let amount = encode_base10(balance.value, 8);
  130. symbols.insert(symbol, (amount, network.to_string()));
  131. }
  132. }
  133. Ok(symbols)
  134. }
  135. .await;
  136. match result {
  137. Ok(res) => JsonResult::Resp(jsonresp(json!(res), json!(res))),
  138. Err(err) => JsonResult::Err(jsonerr(InternalError, Some(err.to_string()), json!(id))),
  139. }
  140. }
  141. // --> {"method": "get_token_id", "params": [network, token]}
  142. // <-- {"result": "Ht5G1RhkcKnpLVLMhqJc5aqZ4wYUEbxbtZwGCVbgU7DL"}
  143. async fn get_token_id(&self, id: Value, params: Value) -> JsonResult {
  144. let args = params.as_array();
  145. if args.is_none() {
  146. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  147. }
  148. let args = args.unwrap();
  149. if args.len() != 2 {
  150. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  151. }
  152. let network: &str;
  153. let symbol: &str;
  154. match (args[0].as_str(), args[1].as_str()) {
  155. (Some(net), Some(sym)) => {
  156. network = net;
  157. symbol = sym;
  158. }
  159. (None, _) => {
  160. return JsonResult::Err(jsonerr(InvalidNetworkParam, None, id));
  161. }
  162. (_, None) => {
  163. return JsonResult::Err(jsonerr(InvalidSymbolParam, None, id));
  164. }
  165. }
  166. let result: Result<Value> = async {
  167. let network = NetworkName::from_str(&network)?;
  168. match network {
  169. #[cfg(feature = "sol")]
  170. NetworkName::Solana => {
  171. let token_id = self.sol_tokenlist.search_id(symbol)?;
  172. Ok(json!(token_id))
  173. }
  174. #[cfg(feature = "btc")]
  175. NetworkName::Bitcoin => {
  176. //hardcoded genesis coinbase address
  177. let token_id = "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa".to_string();
  178. Ok(json!(token_id))
  179. }
  180. _ => Err(Error::NotSupportedNetwork),
  181. }
  182. }
  183. .await;
  184. match result {
  185. Ok(res) => JsonResult::Resp(jsonresp(json!(res), json!(res))),
  186. Err(err) => JsonResult::Err(jsonerr(InternalError, Some(err.to_string()), json!(id))),
  187. }
  188. }
  189. // --> {""method": "features", "params": []}
  190. // <-- {"result": { "network": ["btc", "sol"] } }
  191. async fn features(&self, id: Value, _params: Value) -> JsonResult {
  192. let req = jsonreq(json!("features"), json!([]));
  193. let rep: JsonResult;
  194. // NOTE: this just selects the first cashier in the list
  195. match send_request(&self.cashiers[0].rpc_url, json!(req)).await {
  196. Ok(v) => rep = v,
  197. Err(e) => {
  198. return JsonResult::Err(jsonerr(ServerError(-32004), Some(e.to_string()), id))
  199. }
  200. }
  201. match rep {
  202. JsonResult::Resp(r) => return JsonResult::Resp(r),
  203. JsonResult::Err(e) => return JsonResult::Err(e),
  204. JsonResult::Notif(_) => return JsonResult::Err(jsonerr(InternalError, None, id)),
  205. }
  206. }
  207. // --> {"method": "deposit", "params": [network, token, publickey]}
  208. // The publickey sent here is used so the cashier can know where to send
  209. // tokens once the deposit is received.
  210. // <-- {"result": "Ht5G1RhkcKnpLVLMhqJc5aqZ4wYUEbxbtZwGCVbgU7DL"}
  211. async fn deposit(&self, id: Value, params: Value) -> JsonResult {
  212. let args = params.as_array();
  213. if args.is_none() {
  214. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  215. }
  216. let args = args.unwrap();
  217. if args.len() != 2 {
  218. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  219. }
  220. let network: &str;
  221. let token: &str;
  222. match (args[0].as_str(), args[1].as_str()) {
  223. (Some(net), Some(tkn)) => {
  224. network = net;
  225. token = tkn;
  226. }
  227. (None, _) => {
  228. return JsonResult::Err(jsonerr(InvalidNetworkParam, None, id));
  229. }
  230. (_, None) => {
  231. return JsonResult::Err(jsonerr(InvalidTokenIdParam, None, id));
  232. }
  233. }
  234. let token_id = match assign_id(&network, &token, &self.sol_tokenlist) {
  235. Ok(t) => t,
  236. Err(e) => {
  237. return JsonResult::Err(jsonerr(InternalError, Some(e.to_string()), id));
  238. }
  239. };
  240. // TODO: Optional sanity checking here, but cashier *must* do so too.
  241. let pk = self.client.lock().await.main_keypair.public;
  242. let pubkey = bs58::encode(serialize(&pk)).into_string();
  243. // Send request to cashier. If the cashier supports the requested network
  244. // (and token), it shall return a valid address where tokens can be deposited.
  245. // If not, an error is returned, and forwarded to the method caller.
  246. let req = jsonreq(json!("deposit"), json!([network, token_id, pubkey]));
  247. let rep: JsonResult;
  248. match send_request(&self.cashiers[0].rpc_url, json!(req)).await {
  249. Ok(v) => rep = v,
  250. Err(e) => {
  251. debug!(target: "DARKFID", "REQUEST IS ERR");
  252. return JsonResult::Err(jsonerr(ServerError(-32004), Some(e.to_string()), id));
  253. }
  254. }
  255. match rep {
  256. JsonResult::Resp(r) => return JsonResult::Resp(r),
  257. JsonResult::Err(e) => return JsonResult::Err(e),
  258. JsonResult::Notif(_n) => return JsonResult::Err(jsonerr(InternalError, None, id)),
  259. }
  260. }
  261. // --> {"method": "withdraw", "params": [network, token, publickey, amount]}
  262. // The publickey sent here is the address where the caller wants to receive
  263. // the tokens they plan to withdraw.
  264. // On request, send request to cashier to get deposit address, and then transfer
  265. // dark tokens to the cashier's wallet. Following that, the cashier should return
  266. // a transaction ID of them sending the funds that are requested for withdrawal.
  267. // <-- {"result": "txID"}
  268. async fn withdraw(&self, id: Value, params: Value) -> JsonResult {
  269. let args = params.as_array();
  270. if args.is_none() {
  271. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  272. }
  273. let args = args.unwrap();
  274. if args.len() != 4 {
  275. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  276. }
  277. let network: &str;
  278. let token: &str;
  279. let address: &str;
  280. let amount: &str;
  281. match (
  282. args[0].as_str(),
  283. args[1].as_str(),
  284. args[2].as_str(),
  285. args[3].as_str(),
  286. ) {
  287. (Some(net), Some(tkn), Some(addr), Some(val)) => {
  288. network = net;
  289. token = tkn;
  290. address = addr;
  291. amount = val;
  292. }
  293. (None, _, _, _) => {
  294. return JsonResult::Err(jsonerr(InvalidNetworkParam, None, id));
  295. }
  296. (_, None, _, _) => {
  297. return JsonResult::Err(jsonerr(InvalidTokenIdParam, None, id));
  298. }
  299. (_, _, None, _) => {
  300. return JsonResult::Err(jsonerr(InvalidAddressParam, None, id));
  301. }
  302. (_, _, _, None) => {
  303. return JsonResult::Err(jsonerr(InvalidAmountParam, None, id));
  304. }
  305. }
  306. let amount_in_apo = match decode_base10(&amount, 8, true) {
  307. Ok(a) => a,
  308. Err(e) => {
  309. return JsonResult::Err(jsonerr(InvalidAmountParam, Some(e.to_string()), id));
  310. }
  311. };
  312. let token_id = match assign_id(&network, &token, &self.sol_tokenlist) {
  313. Ok(t) => t,
  314. Err(e) => {
  315. return JsonResult::Err(jsonerr(InternalError, Some(e.to_string()), id));
  316. }
  317. };
  318. let req = jsonreq(
  319. json!("withdraw"),
  320. json!([network, token_id, address, amount_in_apo]),
  321. );
  322. let mut rep: JsonResult;
  323. match send_request(&self.cashiers[0].rpc_url, json!(req)).await {
  324. Ok(v) => rep = v,
  325. Err(e) => {
  326. return JsonResult::Err(jsonerr(ServerError(-32004), Some(e.to_string()), id));
  327. }
  328. }
  329. let token_id: &jubjub::Fr;
  330. // get the id for the token
  331. if let Some(tk_id) = self.drk_tokenlist.tokens.get(&token.to_uppercase()) {
  332. token_id = tk_id;
  333. } else {
  334. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  335. }
  336. // send drk to cashier_public
  337. if let JsonResult::Resp(cashier_public) = &rep {
  338. let result: Result<()> = async {
  339. let cashier_public = cashier_public.result.as_str().unwrap();
  340. let cashier_public: jubjub::SubgroupPoint =
  341. deserialize(&bs58::decode(cashier_public).into_vec()?)?;
  342. self.client
  343. .lock()
  344. .await
  345. .transfer(token_id.clone(), cashier_public, amount_in_apo)
  346. .await?;
  347. Ok(())
  348. }
  349. .await;
  350. match result {
  351. Err(e) => {
  352. rep = JsonResult::Err(jsonerr(InternalError, Some(e.to_string()), id.clone()))
  353. }
  354. Ok(_) => {
  355. rep = JsonResult::Resp(jsonresp(
  356. json!(format!(
  357. "Sent request to withdraw {} amount of {}",
  358. amount, token_id
  359. )),
  360. json!(id.clone()),
  361. ))
  362. }
  363. }
  364. };
  365. match rep {
  366. JsonResult::Resp(r) => return JsonResult::Resp(r),
  367. JsonResult::Err(e) => return JsonResult::Err(e),
  368. JsonResult::Notif(_n) => return JsonResult::Err(jsonerr(InternalError, None, id)),
  369. }
  370. }
  371. // --> {"method": "transfer", [dToken, address, amount]}
  372. // <-- {"result": "txID"}
  373. async fn transfer(&self, id: Value, params: Value) -> JsonResult {
  374. let args = params.as_array();
  375. if args.is_none() {
  376. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  377. }
  378. let args = args.unwrap();
  379. if args.len() != 3 {
  380. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  381. }
  382. let token: &str;
  383. let address: &str;
  384. let amount: &str;
  385. match (args[0].as_str(), args[1].as_str(), args[2].as_str()) {
  386. (Some(tkn), Some(addr), Some(val)) => {
  387. token = tkn;
  388. address = addr;
  389. amount = val;
  390. }
  391. (None, _, _) => {
  392. return JsonResult::Err(jsonerr(InvalidTokenIdParam, None, id));
  393. }
  394. (_, None, _) => {
  395. return JsonResult::Err(jsonerr(InvalidAddressParam, None, id));
  396. }
  397. (_, _, None) => {
  398. return JsonResult::Err(jsonerr(InvalidAmountParam, None, id));
  399. }
  400. }
  401. let token_id: &jubjub::Fr;
  402. // get the id for the token
  403. if let Some(tk_id) = self.drk_tokenlist.tokens.get(&token.to_uppercase()) {
  404. token_id = tk_id;
  405. } else {
  406. return JsonResult::Err(jsonerr(InvalidParams, None, id));
  407. }
  408. let result: Result<()> = async {
  409. let drk_address = bs58::decode(&address).into_vec()?;
  410. let drk_address: jubjub::SubgroupPoint = deserialize(&drk_address)?;
  411. let decimals: usize = 8;
  412. let amount = decode_base10(&amount, decimals, true)?;
  413. self.client
  414. .lock()
  415. .await
  416. .transfer(token_id.clone(), drk_address, amount)
  417. .await?;
  418. Ok(())
  419. }
  420. .await;
  421. match result {
  422. Ok(msg) => JsonResult::Resp(jsonresp(json!(msg), json!(id))),
  423. Err(err) => JsonResult::Err(jsonerr(InternalError, Some(err.to_string()), json!(id))),
  424. }
  425. }
  426. }
  427. #[async_std::main]
  428. async fn main() -> Result<()> {
  429. let args = clap_app!(darkfid =>
  430. (@arg CONFIG: -c --config +takes_value "Sets a custom config file")
  431. (@arg verbose: -v --verbose "Increase verbosity")
  432. )
  433. .get_matches();
  434. let config_path = if args.is_present("CONFIG") {
  435. PathBuf::from(args.value_of("CONFIG").unwrap())
  436. } else {
  437. join_config_path(&PathBuf::from("darkfid.toml"))?
  438. };
  439. let loglevel = if args.is_present("verbose") {
  440. log::Level::Debug
  441. } else {
  442. log::Level::Info
  443. };
  444. simple_logger::init_with_level(loglevel)?;
  445. let config: DarkfidConfig = Config::<DarkfidConfig>::load(config_path)?;
  446. let wallet = WalletDb::new(
  447. expand_path(&config.wallet_path)?.as_path(),
  448. config.wallet_password.clone(),
  449. )?;
  450. let rocks = Rocks::new(expand_path(&config.database_path.clone())?.as_path())?;
  451. let mut cashiers = Vec::new();
  452. let mut cashier_keys = Vec::new();
  453. for cashier in config.clone().cashiers {
  454. if cashier.public_key.is_empty() {
  455. return Err(Error::CashierKeysNotFound);
  456. }
  457. let cashier_public: jubjub::SubgroupPoint =
  458. deserialize(&bs58::decode(cashier.public_key).into_vec()?)?;
  459. cashiers.push(Cashier {
  460. name: cashier.name,
  461. rpc_url: cashier.rpc_url,
  462. public_key: cashier_public,
  463. });
  464. cashier_keys.push(cashier_public);
  465. }
  466. // Load trusted setup parameters
  467. let params_paths = (
  468. expand_path(&config.mint_params_path.clone())?,
  469. expand_path(&config.spend_params_path.clone())?,
  470. );
  471. let mint_params_path = params_paths.0.to_str().unwrap_or("mint.params");
  472. let spend_params_path = params_paths.1.to_str().unwrap_or("spend.params");
  473. // Auto create trusted ceremony parameters if they don't exist
  474. if !params_paths.0.exists() {
  475. let params = setup_mint_prover();
  476. save_params(mint_params_path, &params)?;
  477. }
  478. if !params_paths.1.exists() {
  479. let params = setup_spend_prover();
  480. save_params(spend_params_path, &params)?;
  481. }
  482. let (mint_params, mint_pvk) = load_params(mint_params_path)?;
  483. let (spend_params, spend_pvk) = load_params(spend_params_path)?;
  484. let client = Client::new(
  485. rocks.clone(),
  486. (
  487. config.gateway_protocol_url.parse()?,
  488. config.gateway_publisher_url.parse()?,
  489. ),
  490. wallet.clone(),
  491. mint_params,
  492. spend_params,
  493. )
  494. .await?;
  495. let client = Arc::new(Mutex::new(client));
  496. let mut darkfid = Darkfid::new(client, cashiers).await?;
  497. let merkle_roots = RocksColumn::<columns::MerkleRoots>::new(rocks.clone());
  498. let nullifiers = RocksColumn::<columns::Nullifiers>::new(rocks);
  499. let state = Arc::new(Mutex::new(State {
  500. tree: CommitmentTree::empty(),
  501. merkle_roots,
  502. nullifiers,
  503. mint_pvk,
  504. spend_pvk,
  505. public_keys: cashier_keys,
  506. }));
  507. let server_config = RpcServerConfig {
  508. socket_addr: config.rpc_listen_address.clone(),
  509. use_tls: config.serve_tls,
  510. identity_path: expand_path(&config.tls_identity_path.clone())?,
  511. identity_pass: config.tls_identity_password.clone(),
  512. };
  513. darkfid.start(state).await?;
  514. listen_and_serve(server_config, Arc::new(darkfid)).await
  515. }