Просмотр исходного кода

darkfid: Implement wallet.decrypt_note RPC endpoint.

parazyd 4 лет назад
Родитель
Сommit
3aa0a04d7b
4 измененных файлов с 50 добавлено и 2 удалено
  1. 2 0
      bin/darkfid/src/error.rs
  2. 1 0
      bin/darkfid/src/main.rs
  3. 46 1
      bin/darkfid/src/rpc_wallet.rs
  4. 1 1
      src/node/state.rs

+ 2 - 0
bin/darkfid/src/error.rs

@@ -17,6 +17,7 @@ pub enum RpcError {
     NotYetSynced = -32112,
     InvalidAddressParam = -32113,
     InvalidAmountParam = -32114,
+    DecryptionFailed = -32115,
 }
 
 fn to_tuple(e: RpcError) -> (i64, String) {
@@ -35,6 +36,7 @@ fn to_tuple(e: RpcError) -> (i64, String) {
         RpcError::NotYetSynced => "Blockchain not yet synced",
         RpcError::InvalidAddressParam => "Invalid address parameter",
         RpcError::InvalidAmountParam => "invalid amount parameter",
+        RpcError::DecryptionFailed => "Decryption failed",
     };
 
     (e as i64, msg.to_string())

+ 1 - 0
bin/darkfid/src/main.rs

@@ -185,6 +185,7 @@ impl RequestHandler for Darkfid {
             Some("wallet.get_balances") => return self.get_balances(req.id, params).await,
             Some("wallet.get_coins_valtok") => return self.get_coins_valtok(req.id, params).await,
             Some("wallet.get_merkle_path") => return self.get_merkle_path(req.id, params).await,
+            Some("wallet.decrypt_note") => return self.decrypt_note(req.id, params).await,
             Some(_) | None => return JsonError::new(MethodNotFound, None, req.id).into(),
         }
     }

+ 46 - 1
bin/darkfid/src/rpc_wallet.rs

@@ -10,11 +10,12 @@ use darkfi::{
         keypair::{Keypair, PublicKey, SecretKey},
         token_id,
     },
+    node::State,
     rpc::jsonrpc::{
         ErrorCode::{InternalError, InvalidParams, ParseError},
         JsonError, JsonResponse, JsonResult,
     },
-    util::serial::serialize,
+    util::serial::{deserialize, serialize},
 };
 
 use super::Darkfid;
@@ -283,4 +284,48 @@ impl Darkfid {
             merkle_path.iter().map(|x| bs58::encode(serialize(x)).into_string()).collect();
         JsonResponse::new(json!(ret), id).into()
     }
+
+    // RPCAPI:
+    // Try to decrypt a given encrypted note with the secret keys
+    // found in the wallet.
+    // --> {"jsonrpc": "2.0", "method": "wallet.decrypt_note", params": [ciphertext], "id": 1}
+    // <-- {"jsonrpc": "2.0", "result": "base58_encoded_plain_note", "id": 1}
+    pub async fn decrypt_note(&self, id: Value, params: &[Value]) -> JsonResult {
+        if params.len() != 1 || !params[0].is_string() {
+            return JsonError::new(InvalidParams, None, id).into()
+        }
+
+        let bytes = match bs58::decode(params[0].as_str().unwrap()).into_vec() {
+            Ok(v) => v,
+            Err(e) => {
+                error!("decrypt_note(): Failed decoding base58 string: {}", e);
+                return JsonError::new(ParseError, None, id).into()
+            }
+        };
+
+        let enc_note = match deserialize(&bytes) {
+            Ok(v) => v,
+            Err(e) => {
+                error!("decrypt_note(): Failed deserializing bytes into EncryptedNote: {}", e);
+                return JsonError::new(InternalError, None, id).into()
+            }
+        };
+
+        let keypairs = match self.client.get_keypairs().await {
+            Ok(v) => v,
+            Err(e) => {
+                error!("decrypt_note(): Failed fetching keypairs: {}", e);
+                return JsonError::new(InternalError, None, id).into()
+            }
+        };
+
+        for kp in keypairs {
+            if let Some(note) = State::try_decrypt_note(&enc_note, kp.secret) {
+                let s = bs58::encode(&serialize(&note)).into_string();
+                return JsonResponse::new(json!(s), id).into()
+            }
+        }
+
+        return server_error(RpcError::DecryptionFailed, id)
+    }
 }

+ 1 - 1
src/node/state.rs

@@ -195,7 +195,7 @@ impl State {
         Ok(())
     }
 
-    fn try_decrypt_note(ciphertext: &EncryptedNote, secret: SecretKey) -> Option<Note> {
+    pub fn try_decrypt_note(ciphertext: &EncryptedNote, secret: SecretKey) -> Option<Note> {
         match ciphertext.decrypt(&secret) {
             Ok(note) => Some(note),
             Err(_) => None,