فهرست منبع

update owncoin when spend it

ghassmo 4 سال پیش
والد
کامیت
869452b901
4فایلهای تغییر یافته به همراه84 افزوده شده و 32 حذف شده
  1. 2 1
      sql/schema.sql
  2. 2 1
      src/client.rs
  3. 1 1
      src/crypto/mod.rs
  4. 79 29
      src/wallet/walletdb.rs

+ 2 - 1
sql/schema.sql

@@ -13,7 +13,8 @@ CREATE TABLE IF NOT EXISTS coins(
     value INT NOT NULL,
     asset_id INT NOT NULL,
     witness BLOB NOT NULL,
-   	secret BLOB NOT NULL
+   	secret BLOB NOT NULL,
+	is_spent BLOB NOT NULL
 );
 CREATE TABLE IF NOT EXISTS cashier(
     key_id INTEGER PRIMARY KEY NOT NULL,

+ 2 - 1
src/client.rs

@@ -224,10 +224,11 @@ impl Client {
 
         let own_coins = self.state.lock().await.wallet.get_own_coins()?;
 
-        for own_coin in own_coins.iter() {
+        for (coin_id, own_coin) in own_coins.iter() {
             if inputs_value >= amount {
                 break;
             }
+            self.state.lock().await.wallet.confirm_spend_coin(coin_id)?;
             let witness = &own_coin.witness;
             let merkle_path = witness.path().unwrap();
             inputs_value += own_coin.note.value;

+ 1 - 1
src/crypto/mod.rs

@@ -27,7 +27,7 @@ pub struct OwnCoin {
     pub witness: merkle::IncrementalWitness<merkle_node::MerkleNode>,
 }
 
-pub type OwnCoins = Vec<OwnCoin>;
+pub type OwnCoins = Vec<(u64, OwnCoin)>;
 
 pub fn save_params(filename: &str, params: &groth16::Parameters<Bls12>) -> Result<()> {
     let buffer = std::fs::File::create(filename)?;

+ 79 - 29
src/wallet/walletdb.rs

@@ -125,13 +125,16 @@ impl WalletDb {
     pub fn get_own_coins(&self) -> Result<OwnCoins> {
         debug!(target: "WALLETDB", "Get own coins");
 
+        let is_spent = self.get_value_serialized(&false)?;
+
         let conn = Connection::open(&self.path)?;
         // unlock database
         conn.pragma_update(None, "key", &self.password)?;
 
-        let mut coins = conn.prepare("SELECT * FROM coins")?;
-        let rows = coins.query_map([], |row| {
+        let mut coins = conn.prepare("SELECT * FROM coins WHERE is_spent = :is_spent ;")?;
+        let rows = coins.query_map(&[(":is_spent", &is_spent)], |row| {
             Ok((
+                row.get(0)?,
                 row.get(1)?,
                 row.get(2)?,
                 row.get(3)?,
@@ -147,14 +150,15 @@ impl WalletDb {
 
         for row in rows {
             let row = row?;
-            let coin = self.get_value_deserialized(&row.0)?;
+            let coin_id: u64 = row.0;
+            let coin = self.get_value_deserialized(&row.1)?;
 
             // note
-            let serial = self.get_value_deserialized(&row.1)?;
-            let coin_blind = self.get_value_deserialized(&row.2)?;
-            let valcom_blind = self.get_value_deserialized(&row.3)?;
-            let value: u64 = row.4;
-            let asset_id = self.get_value_deserialized(&row.5)?;
+            let serial = self.get_value_deserialized(&row.2)?;
+            let coin_blind = self.get_value_deserialized(&row.3)?;
+            let valcom_blind = self.get_value_deserialized(&row.4)?;
+            let value: u64 = row.5;
+            let asset_id = self.get_value_deserialized(&row.6)?;
 
             let note = Note {
                 serial,
@@ -164,8 +168,8 @@ impl WalletDb {
                 valcom_blind,
             };
 
-            let witness = self.get_value_deserialized(&row.6)?;
-            let secret: jubjub::Fr = self.get_value_deserialized(&row.7)?;
+            let witness = self.get_value_deserialized(&row.7)?;
+            let secret: jubjub::Fr = self.get_value_deserialized(&row.8)?;
 
             let oc = OwnCoin {
                 coin,
@@ -174,7 +178,7 @@ impl WalletDb {
                 witness,
             };
 
-            own_coins.push(oc)
+            own_coins.push((coin_id, oc))
         }
 
         Ok(own_coins)
@@ -193,7 +197,8 @@ impl WalletDb {
         let asset_id = self.get_value_serialized(&own_coin.note.asset_id)?;
         let witness = self.get_value_serialized(&own_coin.witness)?;
         let secret = self.get_value_serialized(&own_coin.secret)?;
-        
+        let is_spent = self.get_value_serialized(&false)?;
+
         // open connection
         let conn = Connection::open(&self.path)?;
         // unlock database
@@ -201,9 +206,9 @@ impl WalletDb {
 
         conn.execute(
             "INSERT INTO coins
-            (coin, serial, value, asset_id, coin_blind, valcom_blind, witness, secret)
+            (coin, serial, value, asset_id, coin_blind, valcom_blind, witness, secret, is_spent)
             VALUES
-            (:coin, :serial, :value, :asset_id, :coin_blind, :valcom_blind, :witness, :secret);",
+            (:coin, :serial, :value, :asset_id, :coin_blind, :valcom_blind, :witness, :secret, :is_spent);",
             named_params! {
                 ":coin": coin,
                 ":serial": serial,
@@ -213,18 +218,44 @@ impl WalletDb {
                 ":valcom_blind": valcom_blind,
                 ":witness": witness,
                 ":secret": secret,
+                ":is_spent": is_spent,
             },
         )?;
         Ok(())
     }
 
+    pub fn confirm_spend_coin(
+        &self,
+        coin_id: &u64,
+    ) -> Result<()> {
+        debug!(target: "WALLETDB", "Confirm spend coin");
+
+        // open connection
+        let conn = Connection::open(&self.path)?;
+        // unlock database
+        conn.pragma_update(None, "key", &self.password)?;
+
+        let is_spent = self.get_value_serialized(&true)?;
+
+        conn.execute(
+            "UPDATE coins 
+            SET is_spent = ?1
+            WHERE coin_id = ?2 ;",
+            params![is_spent, coin_id],
+        )?;
+
+        Ok(())
+    }
+
     pub fn get_witnesses(&self) -> Result<Vec<(u64, IncrementalWitness<MerkleNode>)>> {
         let conn = Connection::open(&self.path)?;
         conn.pragma_update(None, "key", &self.password)?;
 
-        let mut witnesses = conn.prepare("SELECT coin_id, witness FROM coins;")?;
+        let is_spent = self.get_value_serialized(&false)?;
+
+        let mut witnesses = conn.prepare("SELECT coin_id, witness FROM coins WHERE is_spent = :is_spent;")?;
 
-        let rows = witnesses.query_map([], |row| Ok((row.get(0)?, row.get(1)?)))?;
+        let rows = witnesses.query_map(&[(":is_spent", &is_spent)], |row| Ok((row.get(0)?, row.get(1)?)))?;
 
         let mut witnesses = Vec::new();
         for i in rows {
@@ -248,10 +279,11 @@ impl WalletDb {
         conn.pragma_update(None, "key", &self.password)?;
 
         let witness = self.get_value_serialized(&witness)?;
+        let is_spent = self.get_value_serialized(&false)?;
 
         conn.execute(
-            "UPDATE coins SET witness = ?1  WHERE coin_id = ?2;",
-            params![witness, coin_id],
+            "UPDATE coins SET witness = ?1  WHERE coin_id = ?2 AND is_spent = ?3",
+            params![witness, coin_id, is_spent],
         )?;
 
         Ok(())
@@ -275,6 +307,7 @@ impl WalletDb {
         debug!(target: "WALLETDB", "Returning Cashier Public key...");
         let conn = Connection::open(&self.path)?;
         conn.pragma_update(None, "key", &self.password)?;
+
         let mut stmt = conn.prepare("SELECT key_public FROM cashier")?;
 
         let key_iter = stmt.query_map([], |row| row.get(0))?;
@@ -294,8 +327,13 @@ impl WalletDb {
         let conn = Connection::open(&self.path)?;
         conn.pragma_update(None, "key", &self.password)?;
 
-        let mut stmt = conn.prepare("SELECT coin_id, value, asset_id FROM coins ;")?;
-        let rows = stmt.query_map([], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)))?;
+        let is_spent = self.get_value_serialized(&false)?;
+
+        let mut stmt = conn
+            .prepare("SELECT coin_id, value, asset_id FROM coins  WHERE is_spent = :is_spent ;")?;
+        let rows = stmt.query_map(&[(":is_spent", &is_spent)], |row| {
+            Ok((row.get(0)?, row.get(1)?, row.get(2)?))
+        })?;
 
         let mut balances = HashMap::new();
 
@@ -315,8 +353,10 @@ impl WalletDb {
         let conn = Connection::open(&self.path)?;
         conn.pragma_update(None, "key", &self.password)?;
 
-        let mut stmt = conn.prepare("SELECT asset_id FROM coins")?;
-        let rows = stmt.query_map([], |row| row.get(0))?;
+        let is_spent = self.get_value_serialized(&false)?;
+
+        let mut stmt = conn.prepare("SELECT asset_id FROM coins WHERE is_spent = :is_spent ;")?;
+        let rows = stmt.query_map(&[(":is_spent", &is_spent)], |row| row.get(0))?;
 
         let mut token_ids = Vec::new();
         for row in rows {
@@ -333,9 +373,12 @@ impl WalletDb {
         debug!(target: "WALLETDB", "Check tokenID exists");
         let conn = Connection::open(&self.path)?;
         conn.pragma_update(None, "key", &self.password)?;
+
         let id = self.get_value_serialized(token_id)?;
-        let mut stmt = conn.prepare("SELECT * FROM coins WHERE asset_id = ?")?;
-        let id_check = stmt.exists(params![id])?;
+        let is_spent = self.get_value_serialized(&false)?;
+
+        let mut stmt = conn.prepare("SELECT * FROM coins WHERE asset_id = ? AND is_spent = ? ;")?;
+        let id_check = stmt.exists(params![id, is_spent])?;
         Ok(id_check)
     }
 
@@ -546,11 +589,18 @@ mod tests {
 
         let own_coin = wallet.get_own_coins()?[0].clone();
 
-        assert_eq!(&own_coin.note.valcom_blind, &note.valcom_blind);
-        assert_eq!(&own_coin.note.coin_blind, &note.coin_blind);
-        assert_eq!(own_coin.secret, secret);
-        assert_eq!(own_coin.witness.root(), witness.root());
-        assert_eq!(own_coin.witness.path(), witness.path());
+        assert_eq!(&own_coin.1.note.valcom_blind, &note.valcom_blind);
+        assert_eq!(&own_coin.1.note.coin_blind, &note.coin_blind);
+        assert_eq!(own_coin.1.secret, secret);
+        assert_eq!(own_coin.1.witness.root(), witness.root());
+        assert_eq!(own_coin.1.witness.path(), witness.path());
+        
+
+        wallet.confirm_spend_coin(&own_coin.0)?;
+
+        let own_coins = wallet.get_own_coins()?.clone();
+
+        assert_eq!(own_coins.len(), 0);
 
         std::fs::remove_file(walletdb_path)?;