rpc.rs 5.7 KB

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