rpc_wallet.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  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 darkfi_serial::{deserialize, serialize};
  19. use fxhash::FxHashMap;
  20. use incrementalmerkletree::Tree;
  21. use log::error;
  22. use pasta_curves::group::ff::PrimeField;
  23. use serde_json::{json, Value};
  24. use darkfi::{
  25. crypto::{
  26. address::Address,
  27. keypair::{Keypair, PublicKey, SecretKey},
  28. token_id,
  29. },
  30. node::State,
  31. rpc::jsonrpc::{
  32. ErrorCode::{InternalError, InvalidParams, ParseError},
  33. JsonError, JsonResponse, JsonResult,
  34. },
  35. };
  36. use super::Darkfid;
  37. use crate::{server_error, RpcError};
  38. impl Darkfid {
  39. // RPCAPI:
  40. // Attempts to generate a new keypair and returns its address upon success.
  41. //
  42. // --> {"jsonrpc": "2.0", "method": "wallet.keygen", "params": [], "id": 1}
  43. // <-- {"jsonrpc": "2.0", "result": "1DarkFi...", "id": 1}
  44. pub async fn wallet_keygen(&self, id: Value, params: &[Value]) -> JsonResult {
  45. if !params.is_empty() {
  46. return JsonError::new(InvalidParams, None, id).into()
  47. }
  48. match self.client.keygen().await {
  49. Ok(a) => JsonResponse::new(json!(a.to_string()), id).into(),
  50. Err(e) => {
  51. error!("[RPC] wallet.keygen: Failed creating keypair: {}", e);
  52. server_error(RpcError::Keygen, id, None)
  53. }
  54. }
  55. }
  56. // RPCAPI:
  57. // Fetches public keys by given indexes from the wallet and returns it in an
  58. // encoded format. `-1` is supported to fetch all available keys.
  59. //
  60. // --> {"jsonrpc": "2.0", "method": "wallet.get_addrs", "params": [1, 2], "id": 1}
  61. // <-- {"jsonrpc": "2.0", "result": ["foo", "bar"], "id": 1}
  62. pub async fn wallet_get_addrs(&self, id: Value, params: &[Value]) -> JsonResult {
  63. if params.is_empty() {
  64. return JsonError::new(InvalidParams, None, id).into()
  65. }
  66. let mut fetch_all = false;
  67. for (i, elem) in params.iter().enumerate() {
  68. if !elem.is_i64() {
  69. error!("[RPC] wallet.get_addrs: Param {} is not i64", i);
  70. return server_error(RpcError::NaN, id, Some(&format!("Param {} is not i64", i)))
  71. }
  72. if elem.as_i64() == Some(-1) {
  73. if params.len() != 1 {
  74. return server_error(
  75. RpcError::ParseError,
  76. id,
  77. Some("-1 can only be used as a single param"),
  78. )
  79. }
  80. fetch_all = true;
  81. break
  82. }
  83. if elem.as_i64() < Some(-1) {
  84. return server_error(RpcError::LessThanNegOne, id, None)
  85. }
  86. }
  87. let keypairs = match self.client.get_keypairs().await {
  88. Ok(v) => v,
  89. Err(e) => {
  90. error!("[RPC] wallet.get_addrs: Failed fetching keypairs: {}", e);
  91. return server_error(RpcError::KeypairFetch, id, None)
  92. }
  93. };
  94. if fetch_all {
  95. let ret: Vec<String> =
  96. keypairs.iter().map(|x| Address::from(x.public).to_string()).collect();
  97. return JsonResponse::new(json!(ret), id).into()
  98. }
  99. let mut ret = vec![];
  100. for i in params {
  101. // This cast is safe on 64bit since we've already sorted out
  102. // all negative cases above.
  103. let idx = i.as_i64().unwrap() as usize;
  104. if let Some(kp) = keypairs.get(idx) {
  105. ret.push(Some(Address::from(kp.public).to_string()));
  106. } else {
  107. ret.push(None)
  108. }
  109. }
  110. JsonResponse::new(json!(ret), id).into()
  111. }
  112. // RPCAPI:
  113. // Exports the given keypair index.
  114. // Returns the encoded secret key upon success.
  115. //
  116. // --> {"jsonrpc": "2.0", "method": "wallet.export_keypair", "params": [0], "id": 1}
  117. // <-- {"jsonrpc": "2.0", "result": "foobar", "id": 1}
  118. pub async fn wallet_export_keypair(&self, id: Value, params: &[Value]) -> JsonResult {
  119. if params.len() != 1 || !params[0].is_u64() {
  120. return JsonError::new(InvalidParams, None, id).into()
  121. }
  122. let keypairs = match self.client.get_keypairs().await {
  123. Ok(v) => v,
  124. Err(e) => {
  125. error!("[RPC] wallet.export_keypair: Failed fetching keypairs: {}", e);
  126. return server_error(RpcError::KeypairFetch, id, None)
  127. }
  128. };
  129. if let Some(kp) = keypairs.get(params[0].as_u64().unwrap() as usize) {
  130. return JsonResponse::new(json!(kp.secret.to_bytes()), id).into()
  131. }
  132. server_error(RpcError::KeypairNotFound, id, None)
  133. }
  134. // RPCAPI:
  135. // Imports a given secret key into the wallet as a keypair.
  136. // Returns the public counterpart as the result upon success.
  137. //
  138. // --> {"jsonrpc": "2.0", "method": "wallet.import_keypair", "params": ["foobar"], "id": 1}
  139. // <-- {"jsonrpc": "2.0", "result": "pubfoobar", "id": 1}
  140. pub async fn wallet_import_keypair(&self, id: Value, params: &[Value]) -> JsonResult {
  141. if params.len() != 1 || !params[0].is_string() {
  142. return JsonError::new(InvalidParams, None, id).into()
  143. }
  144. let bytes: [u8; 32] = match serde_json::from_str(params[0].as_str().unwrap()) {
  145. Ok(v) => v,
  146. Err(e) => {
  147. error!("[RPC] wallet.import_keypair: Failed parsing secret key from string: {}", e);
  148. return server_error(RpcError::InvalidKeypair, id, None)
  149. }
  150. };
  151. let secret = match SecretKey::from_bytes(bytes) {
  152. Ok(v) => v,
  153. Err(e) => {
  154. error!("[RPC] wallet.import_keypair: Failed parsing secret key from string: {}", e);
  155. return server_error(RpcError::InvalidKeypair, id, None)
  156. }
  157. };
  158. let public = PublicKey::from_secret(secret);
  159. let keypair = Keypair { secret, public };
  160. let address = Address::from(public).to_string();
  161. if let Err(e) = self.client.put_keypair(&keypair).await {
  162. error!("[RPC] wallet.import_keypair: Failed inserting keypair into wallet: {}", e);
  163. return JsonError::new(InternalError, None, id).into()
  164. }
  165. JsonResponse::new(json!(address), id).into()
  166. }
  167. // RPCAPI:
  168. // Sets the default wallet address to the given index.
  169. // Returns `true` upon success.
  170. //
  171. // --> {"jsonrpc": "2.0", "method": "wallet.set_default_address", "params": [2], "id": 1}
  172. // <-- {"jsonrpc": "2.0", "result": true, "id": 1}
  173. pub async fn wallet_set_default_address(&self, id: Value, params: &[Value]) -> JsonResult {
  174. if params.len() != 1 || !params[0].is_u64() {
  175. return JsonError::new(InvalidParams, None, id).into()
  176. }
  177. let idx = params[0].as_u64().unwrap();
  178. let keypairs = match self.client.get_keypairs().await {
  179. Ok(v) => v,
  180. Err(e) => {
  181. error!("[RPC] wallet.set_default_address: Failed fetching keypairs: {}", e);
  182. return server_error(RpcError::KeypairFetch, id, None)
  183. }
  184. };
  185. if keypairs.len() as u64 != idx - 1 {
  186. return server_error(RpcError::KeypairNotFound, id, None)
  187. }
  188. let kp = keypairs[idx as usize];
  189. if let Err(e) = self.client.set_default_keypair(&kp.public).await {
  190. error!("[RPC] wallet.set_default_address: Failed setting default keypair: {}", e);
  191. return JsonError::new(InternalError, None, id).into()
  192. }
  193. JsonResponse::new(json!(true), id).into()
  194. }
  195. // RPCAPI:
  196. // Queries the wallet for known tokens with active balances.
  197. // Returns a map of balances, indexed by the token ID.
  198. //
  199. // --> {"jsonrpc": "2.0", "method": "wallet.get_balances", "params": [], "id": 1}
  200. // <-- {"jsonrpc": "2.0", "result": [{"1Foobar...": 100}, {...}]", "id": 1}
  201. pub async fn wallet_get_balances(&self, id: Value, _params: &[Value]) -> JsonResult {
  202. let balances = match self.client.get_balances().await {
  203. Ok(v) => v,
  204. Err(e) => {
  205. error!("[RPC] wallet.get_balances: Failed fetching balances from wallet: {}", e);
  206. return JsonError::new(InternalError, None, id).into()
  207. }
  208. };
  209. // k: token_id, v: [amount]
  210. let mut ret: FxHashMap<String, u64> = FxHashMap::default();
  211. for balance in balances.list {
  212. let token_id = bs58::encode(balance.token_id.to_repr()).into_string();
  213. let mut amount = balance.value;
  214. if let Some(prev) = ret.get(&token_id) {
  215. amount += prev;
  216. }
  217. ret.insert(token_id, amount);
  218. }
  219. JsonResponse::new(json!(ret), id).into()
  220. }
  221. // RPCAPI:
  222. // Queries the wallet for a coin containing given parameters (value, token_id, unspent),
  223. // and returns the entire row with the coin's data:
  224. //
  225. // --> {"jsonrpc": "2.0", "method": "wallet.get_coins_valtok", "params": [1234, "F00b4r...", true], "id": 1}
  226. // <-- {"jsonrpc": "2.0", "result": ["coin", "data", ...], "id": 1}
  227. pub async fn wallet_get_coins_valtok(&self, id: Value, params: &[Value]) -> JsonResult {
  228. if params.len() != 3 ||
  229. !params[0].is_u64() ||
  230. !params[1].is_string() ||
  231. !params[2].is_boolean()
  232. {
  233. return JsonError::new(InvalidParams, None, id).into()
  234. }
  235. let value = params[0].as_u64().unwrap();
  236. let unspent = params[2].as_bool().unwrap();
  237. let token_id = match token_id::parse_b58(params[1].as_str().unwrap()) {
  238. Ok(v) => v,
  239. Err(e) => {
  240. error!("[RPC] wallet.get_coins_valtok: Failed parsing token_id from base58: {}", e);
  241. return JsonError::new(ParseError, None, id).into()
  242. }
  243. };
  244. let coins = match self.client.get_coins_valtok(value, token_id, unspent).await {
  245. Ok(v) => v,
  246. Err(e) => {
  247. error!("[RPC] wallet.get_coins_valtok: Failed fetching from wallet: {}", e);
  248. return JsonError::new(InternalError, None, id).into()
  249. }
  250. };
  251. let ret: Vec<String> =
  252. coins.iter().map(|x| bs58::encode(serialize(x)).into_string()).collect();
  253. JsonResponse::new(json!(ret), id).into()
  254. }
  255. // RPCAPI:
  256. // Query the state merkle tree for the merkle path of a given leaf position.
  257. //
  258. // --> {"jsonrpc": "2.0", "method": "wallet.get_merkle_path", "params": [3], "id": 1}
  259. // <-- {"jsonrpc": "2.0", "result": ["f091uf1...", "081ff0h10w1h0...", ...], "id": 1}
  260. pub async fn wallet_get_merkle_path(&self, id: Value, params: &[Value]) -> JsonResult {
  261. if params.len() != 1 || !params[0].is_u64() {
  262. return JsonError::new(InvalidParams, None, id).into()
  263. }
  264. let leaf_pos: incrementalmerkletree::Position =
  265. ((params[0].as_u64().unwrap() as u64) as usize).into();
  266. let validator_state = self.validator_state.read().await;
  267. let state = validator_state.state_machine.lock().await;
  268. let root = state.tree.root(0).unwrap();
  269. let merkle_path = state.tree.authentication_path(leaf_pos, &root).unwrap();
  270. drop(state);
  271. drop(validator_state);
  272. let ret: Vec<String> =
  273. merkle_path.iter().map(|x| bs58::encode(serialize(x)).into_string()).collect();
  274. JsonResponse::new(json!(ret), id).into()
  275. }
  276. // RPCAPI:
  277. // Try to decrypt a given encrypted note with the secret keys
  278. // found in the wallet.
  279. //
  280. // --> {"jsonrpc": "2.0", "method": "wallet.decrypt_note", params": [ciphertext], "id": 1}
  281. // <-- {"jsonrpc": "2.0", "result": "base58_encoded_plain_note", "id": 1}
  282. pub async fn wallet_decrypt_note(&self, id: Value, params: &[Value]) -> JsonResult {
  283. if params.len() != 1 || !params[0].is_string() {
  284. return JsonError::new(InvalidParams, None, id).into()
  285. }
  286. let bytes = match bs58::decode(params[0].as_str().unwrap()).into_vec() {
  287. Ok(v) => v,
  288. Err(e) => {
  289. error!("[RPC] wallet.decrypt_note: Failed decoding base58 string: {}", e);
  290. return JsonError::new(ParseError, None, id).into()
  291. }
  292. };
  293. let enc_note = match deserialize(&bytes) {
  294. Ok(v) => v,
  295. Err(e) => {
  296. error!("[RPC] wallet.decrypt_note: Failed deserializing into EncryptedNote: {}", e);
  297. return JsonError::new(InternalError, None, id).into()
  298. }
  299. };
  300. let keypairs = match self.client.get_keypairs().await {
  301. Ok(v) => v,
  302. Err(e) => {
  303. error!("[RPC] wallet.decrypt_note: Failed fetching keypairs: {}", e);
  304. return JsonError::new(InternalError, None, id).into()
  305. }
  306. };
  307. for kp in keypairs {
  308. if let Some(note) = State::try_decrypt_note(&enc_note, kp.secret) {
  309. let s = bs58::encode(&serialize(&note)).into_string();
  310. return JsonResponse::new(json!(s), id).into()
  311. }
  312. }
  313. server_error(RpcError::DecryptionFailed, id, None)
  314. }
  315. }