rpc.rs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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::{process::exit, str::FromStr};
  19. use darkfi_sdk::crypto::MerkleNode;
  20. use darkfi_serial::{deserialize, serialize};
  21. use serde_json::json;
  22. use darkfi::{
  23. crypto::{
  24. address::Address,
  25. coin::OwnCoin,
  26. note::{EncryptedNote, Note},
  27. },
  28. rpc::{client::RpcClient, jsonrpc::JsonRequest},
  29. Result,
  30. };
  31. /// The RPC object with functionality for connecting to darkfid.
  32. pub struct Rpc {
  33. pub rpc_client: RpcClient,
  34. }
  35. impl Rpc {
  36. /// Fetch wallet balance of given token ID and return its u64 representation.
  37. pub async fn balance_of(&self, token_id: &str) -> Result<u64> {
  38. let req = JsonRequest::new("wallet.get_balances", json!([]));
  39. let rep = self.rpc_client.request(req).await?;
  40. if !rep.is_object() {
  41. eprintln!("Error: Invalid balance data received from darkfid RPC endpoint.");
  42. exit(1);
  43. }
  44. for i in rep.as_object().unwrap().keys() {
  45. if i == token_id {
  46. if let Some(balance) = rep[i].as_u64() {
  47. return Ok(balance)
  48. }
  49. eprintln!("Error: Invalid balance data received from darkfid RPC endpoint.");
  50. exit(1);
  51. }
  52. }
  53. Ok(0)
  54. }
  55. /// Fetch default wallet address from the darkfid RPC endpoint.
  56. pub async fn wallet_address(&self) -> Result<Address> {
  57. let req = JsonRequest::new("wallet.get_addrs", json!([0_i64]));
  58. let rep = self.rpc_client.request(req).await?;
  59. if !rep.is_array() || !rep.as_array().unwrap()[0].is_string() {
  60. eprintln!("Error: Invalid wallet address received from darkfid RPC endpoint.");
  61. exit(1);
  62. }
  63. match Address::from_str(rep[0].as_str().unwrap()) {
  64. Ok(v) => Ok(v),
  65. Err(e) => {
  66. eprintln!(
  67. "Error: Invalid wallet address received from darkfid RPC endpoint: {}",
  68. e
  69. );
  70. exit(1)
  71. }
  72. }
  73. }
  74. /// Query wallet for unspent coins in wallet matching value and token_id.
  75. pub async fn get_coins_valtok(&self, value: u64, token_id: &str) -> Result<Vec<OwnCoin>> {
  76. let req = JsonRequest::new("wallet.get_coins_valtok", json!([value, token_id, true]));
  77. let rep = self.rpc_client.request(req).await?;
  78. if !rep.is_array() {
  79. eprintln!("Error: Invalid coin data received from darkfid RPC endpoint.");
  80. exit(1);
  81. }
  82. let rep = rep.as_array().unwrap();
  83. let mut ret = vec![];
  84. for i in rep {
  85. if !i.is_string() {
  86. eprintln!(
  87. "Error: Invalid base58 data for OwnCoin received from darkfid RPC endpoint."
  88. );
  89. exit(1);
  90. }
  91. let data = match bs58::decode(i.as_str().unwrap()).into_vec() {
  92. Ok(v) => v,
  93. Err(e) => {
  94. eprintln!("Error: Failed decoding base58 data for OwnCoin: {}", e);
  95. exit(1);
  96. }
  97. };
  98. let oc = match deserialize(&data) {
  99. Ok(v) => v,
  100. Err(e) => {
  101. eprintln!("Error: Failed deserializing OwnCoin: {}", e);
  102. exit(1);
  103. }
  104. };
  105. ret.push(oc);
  106. }
  107. Ok(ret)
  108. }
  109. /// Fetch the merkle path for a given leaf position in the coin tree
  110. pub async fn get_merkle_path(&self, leaf_pos: usize) -> Result<Vec<MerkleNode>> {
  111. let req = JsonRequest::new("wallet.get_merkle_path", json!([leaf_pos as u64]));
  112. let rep = self.rpc_client.request(req).await?;
  113. if !rep.is_array() {
  114. eprintln!("Error: Invalid merkle path data received from darkfid RPC endpoint.");
  115. exit(1);
  116. }
  117. let rep = rep.as_array().unwrap();
  118. let mut ret = vec![];
  119. for i in rep {
  120. if !i.is_string() {
  121. eprintln!("Error: Invalid base58 data received for MerkleNode");
  122. exit(1);
  123. }
  124. let n = match bs58::decode(i.as_str().unwrap()).into_vec() {
  125. Ok(v) => v,
  126. Err(e) => {
  127. eprintln!("Error: Failed decoding base58 for MerkleNode: {}", e);
  128. exit(1);
  129. }
  130. };
  131. if n.len() != 32 {
  132. eprintln!("error: MerkleNode byte length is not 32");
  133. exit(1);
  134. }
  135. let n = MerkleNode::from_bytes(n.try_into().unwrap());
  136. if n.is_none() {
  137. eprintln!("Error: Noncanonical bytes of MerkleNode");
  138. exit(1);
  139. }
  140. ret.push(n.unwrap());
  141. }
  142. Ok(ret)
  143. }
  144. /// Try to decrypt a given `EncryptedNote`
  145. pub async fn decrypt_note(&self, enc_note: &EncryptedNote) -> Result<Option<Note>> {
  146. let encoded = bs58::encode(&serialize(enc_note)).into_string();
  147. let req = JsonRequest::new("wallet.decrypt_note", json!([encoded]));
  148. let rep = self.rpc_client.oneshot_request(req).await?;
  149. if !rep.is_string() {
  150. eprintln!("Error: decrypt_note() RPC call returned invalid data");
  151. exit(1);
  152. }
  153. let decoded = match bs58::decode(rep.as_str().unwrap()).into_vec() {
  154. Ok(v) => v,
  155. Err(e) => {
  156. eprintln!("Error decoding base58 data received from RPC call: {}", e);
  157. exit(1);
  158. }
  159. };
  160. let note = match deserialize(&decoded) {
  161. Ok(v) => v,
  162. Err(e) => {
  163. eprintln!("Failed deserializing bytes into Note: {}", e);
  164. exit(1);
  165. }
  166. };
  167. Ok(Some(note))
  168. }
  169. }