rpc.rs 6.5 KB

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