rpc_wallet.rs 13 KB

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