Ver código fonte

Merge branch 'master' of github.com:darkrenaissance/darkfi

x 3 anos atrás
pai
commit
39916af33f

+ 80 - 0
bin/drk/src/main.rs

@@ -210,6 +210,10 @@ enum Subcmd {
     /// Explorer related subcommands
     #[command(subcommand)]
     Explorer(ExplorerSubcmd),
+
+    /// Manage Token aliases
+    #[command(subcommand)]
+    Alias(AliasSubcmd),
 }
 
 #[derive(Subcommand)]
@@ -343,6 +347,36 @@ enum ExplorerSubcmd {
     SimulateTx,
 }
 
+#[derive(Subcommand)]
+enum AliasSubcmd {
+    /// Create a Token alias
+    Add {
+        /// Token alias
+        alias: String,
+
+        /// Token to create alias for
+        token: String,
+    },
+
+    /// Print alias info of optional arguments.
+    /// If no argument is provided, list all the aliases in the wallet.
+    Show {
+        /// Token alias to search for
+        #[clap(short, long)]
+        alias: Option<String>,
+
+        /// Token to search alias for
+        #[clap(short, long)]
+        token: Option<String>,
+    },
+
+    /// Remove a Token alias
+    Remove {
+        /// Token alias to remove
+        alias: String,
+    },
+}
+
 pub struct Drk {
     pub rpc_client: RpcClient,
 }
@@ -949,5 +983,51 @@ async fn main() -> Result<()> {
                 Ok(())
             }
         },
+
+        Subcmd::Alias(cmd) => match cmd {
+            AliasSubcmd::Add { alias, token } => {
+                let token_id =
+                    TokenId::try_from(token.as_str()).with_context(|| "Invalid Token ID")?;
+                let drk = Drk::new(args.endpoint).await?;
+                drk.add_alias(alias, token_id).await?;
+
+                Ok(())
+            }
+
+            AliasSubcmd::Show { alias, token } => {
+                let token_id = match token {
+                    Some(t) => {
+                        Some(TokenId::try_from(t.as_str()).with_context(|| "Invalid Token ID")?)
+                    }
+                    None => None,
+                };
+
+                let drk = Drk::new(args.endpoint).await?;
+                let map = drk.get_aliases(alias, token_id).await?;
+
+                // Create a prettytable with the new data:
+                let mut table = Table::new();
+                table.set_format(*format::consts::FORMAT_NO_BORDER_LINE_SEPARATOR);
+                table.set_titles(row!["Alias", "Token ID"]);
+                for (alias, token_id) in map.iter() {
+                    table.add_row(row![alias, token_id]);
+                }
+
+                if table.is_empty() {
+                    println!("No aliases found");
+                } else {
+                    println!("{}", table);
+                }
+
+                Ok(())
+            }
+
+            AliasSubcmd::Remove { alias } => {
+                let drk = Drk::new(args.endpoint).await?;
+                drk.remove_alias(alias).await?;
+
+                Ok(())
+            }
+        },
     }
 }

+ 101 - 1
bin/drk/src/wallet_money.rs

@@ -21,7 +21,8 @@ use anyhow::{anyhow, Result};
 use darkfi::{rpc::jsonrpc::JsonRequest, tx::Transaction, wallet::walletdb::QueryType};
 use darkfi_money_contract::{
     client::{
-        Coin, EncryptedNote, Note, OwnCoin, MONEY_COINS_COL_COIN, MONEY_COINS_COL_COIN_BLIND,
+        Coin, EncryptedNote, Note, OwnCoin, MONEY_ALIASES_COL_ALIAS, MONEY_ALIASES_COL_TOKEN_ID,
+        MONEY_ALIASES_TABLE, MONEY_COINS_COL_COIN, MONEY_COINS_COL_COIN_BLIND,
         MONEY_COINS_COL_IS_SPENT, MONEY_COINS_COL_LEAF_POSITION, MONEY_COINS_COL_MEMO,
         MONEY_COINS_COL_NULLIFIER, MONEY_COINS_COL_SECRET, MONEY_COINS_COL_SERIAL,
         MONEY_COINS_COL_SPEND_HOOK, MONEY_COINS_COL_TOKEN_BLIND, MONEY_COINS_COL_TOKEN_ID,
@@ -638,4 +639,103 @@ impl Drk {
 
         Ok(serde_json::from_value(rep[0].clone())?)
     }
+
+    /// Create an alias record for provided Token ID
+    pub async fn add_alias(&self, alias: String, token_id: TokenId) -> Result<()> {
+        eprintln!("Generating alias {} for Token: {}", alias, token_id);
+        let query = format!(
+            "INSERT OR REPLACE INTO {} ({}, {}) VALUES (?1, ?2);",
+            MONEY_ALIASES_TABLE, MONEY_ALIASES_COL_ALIAS, MONEY_ALIASES_COL_TOKEN_ID,
+        );
+
+        let params = json!([
+            query,
+            QueryType::Blob as u8,
+            serialize(&alias),
+            QueryType::Blob as u8,
+            serialize(&token_id),
+        ]);
+
+        let req = JsonRequest::new("wallet.exec_sql", params);
+        let rep = self.rpc_client.request(req).await?;
+
+        if rep == true {
+            eprintln!("Successfully added new alias to wallet");
+        } else {
+            eprintln!("[add_alias] Got unexpected reply from darkfid: {}", rep);
+        }
+
+        Ok(())
+    }
+
+    /// Fetch all aliases from the wallet.
+    /// Optionally filter using alias name and/or token id.
+    pub async fn get_aliases(
+        &self,
+        alias_filter: Option<String>,
+        token_id_filter: Option<TokenId>,
+    ) -> Result<HashMap<String, TokenId>> {
+        eprintln!("Fetching Aliases from the wallet");
+
+        let query = format!("SELECT * FROM {}", MONEY_ALIASES_TABLE);
+        let params = json!([
+            query,
+            QueryType::Blob as u8,
+            MONEY_ALIASES_COL_ALIAS,
+            QueryType::Blob as u8,
+            MONEY_ALIASES_COL_TOKEN_ID,
+        ]);
+
+        let req = JsonRequest::new("wallet.query_row_multi", params);
+        let rep = self.rpc_client.request(req).await?;
+
+        // The returned thing should be an array of found rows.
+        let Some(rows) = rep.as_array() else {
+            return Err(anyhow!("[get_aliases] Unexpected response from darkfid: {}", rep))
+        };
+
+        // Fill this map with aliases
+        let mut map: HashMap<String, TokenId> = HashMap::new();
+        for row in rows {
+            let Some(row) = row.as_array() else {
+                return Err(anyhow!("[get_aliases] Unexpected response from darkfid: {}", rep))
+            };
+
+            let alias_bytes: Vec<u8> = serde_json::from_value(row[0].clone())?;
+            let alias: String = deserialize(&alias_bytes)?;
+            if alias_filter.is_some() && alias_filter.as_ref().unwrap() != &alias {
+                continue
+            }
+
+            let token_id_bytes: Vec<u8> = serde_json::from_value(row[1].clone())?;
+            let token_id: TokenId = deserialize(&token_id_bytes)?;
+            if token_id_filter.is_some() && token_id_filter.as_ref().unwrap() != &token_id {
+                continue
+            }
+
+            map.insert(alias, token_id);
+        }
+
+        Ok(map)
+    }
+
+    /// Create an alias record for provided Token ID
+    pub async fn remove_alias(&self, alias: String) -> Result<()> {
+        eprintln!("Removing alias: {}", alias);
+        let query =
+            format!("DELETE FROM {} WHERE {} = ?1;", MONEY_ALIASES_TABLE, MONEY_ALIASES_COL_ALIAS,);
+
+        let params = json!([query, QueryType::Blob as u8, serialize(&alias),]);
+
+        let req = JsonRequest::new("wallet.exec_sql", params);
+        let rep = self.rpc_client.request(req).await?;
+
+        if rep == true {
+            eprintln!("Successfully removed alias from wallet");
+        } else {
+            eprintln!("[remove_alias] Got unexpected reply from darkfid: {}", rep);
+        }
+
+        Ok(())
+    }
 }

+ 4 - 0
src/contract/money/src/client.rs

@@ -81,6 +81,10 @@ pub const MONEY_COINS_COL_NULLIFIER: &str = "nullifier";
 pub const MONEY_COINS_COL_LEAF_POSITION: &str = "leaf_position";
 pub const MONEY_COINS_COL_MEMO: &str = "memo";
 
+pub const MONEY_ALIASES_TABLE: &str = "money_aliases";
+pub const MONEY_ALIASES_COL_ALIAS: &str = "alias";
+pub const MONEY_ALIASES_COL_TOKEN_ID: &str = "token_id";
+
 /// Byte length of the AEAD tag of the chacha20 cipher used for note encryption
 pub const AEAD_TAG_SIZE: usize = 16;
 

+ 6 - 0
src/contract/money/wallet.sql

@@ -37,3 +37,9 @@ CREATE TABLE IF NOT EXISTS money_coins (
 	leaf_position BLOB NOT NULL,
 	memo BLOB
 );
+
+-- The token aliases in our wallet
+CREATE TABLE IF NOT EXISTS money_aliases (
+	alias BLOB PRIMARY KEY NOT NULL,
+	token_id BLOB NOT NULL
+);