فهرست منبع

drk: Transaction broadcasting

parazyd 3 سال پیش
والد
کامیت
ec8898db24
4فایلهای تغییر یافته به همراه145 افزوده شده و 24 حذف شده
  1. 75 5
      bin/drk/src/main.rs
  2. 2 6
      bin/drk/src/rpc_blockchain.rs
  3. 36 8
      bin/drk/src/rpc_wallet.rs
  4. 32 5
      contrib/localnet/darkfid-temp/README.md

+ 75 - 5
bin/drk/src/main.rs

@@ -23,9 +23,14 @@ use std::{
     time::Instant,
     time::Instant,
 };
 };
 
 
-use anyhow::{Context, Result};
+use anyhow::{anyhow, Context, Result};
 use clap::{Parser, Subcommand};
 use clap::{Parser, Subcommand};
-use darkfi_sdk::crypto::{PublicKey, TokenId};
+use darkfi::tx::Transaction;
+use darkfi_money_contract::client::Coin;
+use darkfi_sdk::{
+    crypto::{PublicKey, TokenId},
+    pasta::{group::ff::PrimeField, pallas},
+};
 use darkfi_serial::{deserialize, serialize};
 use darkfi_serial::{deserialize, serialize};
 use serde_json::json;
 use serde_json::json;
 use simplelog::{ColorChoice, TermLogger, TerminalMode};
 use simplelog::{ColorChoice, TermLogger, TerminalMode};
@@ -94,6 +99,16 @@ enum Subcmd {
         #[arg(long)]
         #[arg(long)]
         /// Print the Merkle tree in the wallet
         /// Print the Merkle tree in the wallet
         tree: bool,
         tree: bool,
+
+        #[arg(long)]
+        /// Print all the coins in the wallet
+        coins: bool,
+    },
+
+    /// Unspend a coin
+    Unspend {
+        /// base58-encoded coin to mark as unspent
+        coin: String,
     },
     },
 
 
     /// Airdrop some tokens
     /// Airdrop some tokens
@@ -124,6 +139,9 @@ enum Subcmd {
         recipient: String,
         recipient: String,
     },
     },
 
 
+    /// Inspect a transaction from stdin
+    Inspect,
+
     /// Read a transaction from stdin and broadcast it
     /// Read a transaction from stdin and broadcast it
     Broadcast,
     Broadcast,
 
 
@@ -173,8 +191,8 @@ async fn main() -> Result<()> {
             Ok(())
             Ok(())
         }
         }
 
 
-        Subcmd::Wallet { initialize, keygen, balance, address, secrets, tree } => {
-            if !initialize && !keygen && !balance && !address && !secrets && !tree {
+        Subcmd::Wallet { initialize, keygen, balance, address, secrets, tree, coins } => {
+            if !initialize && !keygen && !balance && !address && !secrets && !tree && !coins {
                 eprintln!("Error: You must use at least one flag for this subcommand");
                 eprintln!("Error: You must use at least one flag for this subcommand");
                 eprintln!("Run with \"wallet -h\" to see the subcommand usage.");
                 eprintln!("Run with \"wallet -h\" to see the subcommand usage.");
                 exit(2);
                 exit(2);
@@ -234,9 +252,49 @@ async fn main() -> Result<()> {
                 return Ok(())
                 return Ok(())
             }
             }
 
 
+            if coins {
+                let coins = drk
+                    .wallet_coins(true)
+                    .await
+                    .with_context(|| "Failed to fetch coins from wallet")?;
+
+                drk.rpc_client.close().await?;
+
+                for i in coins {
+                    print!("{} ", bs58::encode(i.0.coin.inner().to_repr()).into_string());
+                    if i.1 {
+                        println!("(spent)");
+                    } else {
+                        println!("(unspent)");
+                    }
+                }
+
+                return Ok(())
+            }
+
             unreachable!()
             unreachable!()
         }
         }
 
 
+        Subcmd::Unspend { coin } => {
+            let bytes: [u8; 32] = bs58::decode(&coin).into_vec()?.try_into().unwrap();
+
+            let elem: pallas::Base = match pallas::Base::from_repr(bytes).into() {
+                Some(v) => v,
+                None => return Err(anyhow!("Invalid coin")),
+            };
+
+            let coin = Coin::from(elem);
+
+            let rpc_client = RpcClient::new(args.endpoint)
+                .await
+                .with_context(|| "Could not connect to darkfid RPC endpoint")?;
+
+            let drk = Drk { rpc_client };
+            drk.unspend_coin(&coin).await.with_context(|| "Failed to mark coin as unspent")?;
+
+            return Ok(())
+        }
+
         Subcmd::Airdrop { faucet_endpoint, amount, token, address } => {
         Subcmd::Airdrop { faucet_endpoint, amount, token, address } => {
             let amount = f64::from_str(&amount).with_context(|| "Invalid amount")?;
             let amount = f64::from_str(&amount).with_context(|| "Invalid amount")?;
             let token_id = TokenId::try_from(token.as_str()).with_context(|| "Invalid Token ID")?;
             let token_id = TokenId::try_from(token.as_str()).with_context(|| "Invalid Token ID")?;
@@ -284,12 +342,24 @@ async fn main() -> Result<()> {
             Ok(())
             Ok(())
         }
         }
 
 
+        Subcmd::Inspect => {
+            let mut buf = String::new();
+            stdin().read_to_string(&mut buf)?;
+
+            let bytes = bs58::decode(&buf.trim()).into_vec()?;
+            let tx: Transaction = deserialize(&bytes)?;
+
+            println!("{:#?}", tx);
+
+            Ok(())
+        }
+
         Subcmd::Broadcast => {
         Subcmd::Broadcast => {
             eprintln!("Reading transaction from stdin...");
             eprintln!("Reading transaction from stdin...");
             let mut buf = String::new();
             let mut buf = String::new();
             stdin().read_to_string(&mut buf)?;
             stdin().read_to_string(&mut buf)?;
 
 
-            let bytes = bs58::decode(&buf).into_vec()?;
+            let bytes = bs58::decode(&buf.trim()).into_vec()?;
             let tx = deserialize(&bytes)?;
             let tx = deserialize(&bytes)?;
 
 
             let rpc_client = RpcClient::new(args.endpoint)
             let rpc_client = RpcClient::new(args.endpoint)

+ 2 - 6
bin/drk/src/rpc_blockchain.rs

@@ -34,7 +34,7 @@ use darkfi_money_contract::{
         MONEY_COINS_COL_IS_SPENT, MONEY_COINS_COL_LEAF_POSITION, MONEY_COINS_COL_MEMO,
         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_NULLIFIER, MONEY_COINS_COL_SECRET, MONEY_COINS_COL_SERIAL,
         MONEY_COINS_COL_TOKEN_BLIND, MONEY_COINS_COL_TOKEN_ID, MONEY_COINS_COL_VALUE,
         MONEY_COINS_COL_TOKEN_BLIND, MONEY_COINS_COL_TOKEN_ID, MONEY_COINS_COL_VALUE,
-        MONEY_COINS_COL_VALUE_BLIND, MONEY_COINS_TABLE, MONEY_TREE_COL_TREE, MONEY_TREE_TABLE,
+        MONEY_COINS_COL_VALUE_BLIND, MONEY_COINS_TABLE,
     },
     },
     state::{MoneyTransferParams, Output},
     state::{MoneyTransferParams, Output},
     MoneyFunction,
     MoneyFunction,
@@ -178,11 +178,7 @@ impl Drk {
         }
         }
 
 
         eprintln!("Serializing the Merkle tree into the wallet");
         eprintln!("Serializing the Merkle tree into the wallet");
-        let query =
-            format!("INSERT INTO {} ({}) VALUES (?1)", MONEY_TREE_TABLE, MONEY_TREE_COL_TREE);
-        let params = json!([query, QueryType::Blob as u8, serialize(&tree)]);
-        let req = JsonRequest::new("wallet.exec_sql", params);
-        self.rpc_client.request(req).await?;
+        self.put_tree(&tree).await?;
         eprintln!("Merkle tree written successfully");
         eprintln!("Merkle tree written successfully");
 
 
         // This is the SQL query we'll be executing to insert coins into the wallet
         // This is the SQL query we'll be executing to insert coins into the wallet

+ 36 - 8
bin/drk/src/rpc_wallet.rs

@@ -80,14 +80,7 @@ impl Drk {
         if tree_needs_init {
         if tree_needs_init {
             println!("Initializing Merkle tree");
             println!("Initializing Merkle tree");
             let tree = BridgeTree::<MerkleNode, MERKLE_DEPTH>::new(100);
             let tree = BridgeTree::<MerkleNode, MERKLE_DEPTH>::new(100);
-            let tree_bytes = serialize(&tree);
-            let query = format!(
-                "DELETE FROM {}; INSERT INTO {} ({}) VALUES (?1);",
-                MONEY_TREE_TABLE, MONEY_TREE_TABLE, MONEY_TREE_COL_TREE
-            );
-            let params = json!([query, QueryType::Blob as u8, tree_bytes]);
-            let req = JsonRequest::new("wallet.exec_sql", params);
-            let _ = self.rpc_client.request(req).await?;
+            self.put_tree(&tree).await?;
             println!("Successfully initialized Merkle tree");
             println!("Successfully initialized Merkle tree");
         }
         }
 
 
@@ -389,4 +382,39 @@ impl Drk {
 
 
         Ok(())
         Ok(())
     }
     }
+
+    /// Mark a given coin in the wallet as unspent
+    pub async fn unspend_coin(&self, coin: &Coin) -> Result<()> {
+        let query = format!(
+            "UPDATE {} SET {} = ?1 WHERE {} = ?2;",
+            MONEY_COINS_TABLE, MONEY_COINS_COL_IS_SPENT, MONEY_COINS_COL_COIN
+        );
+
+        let params = json!([
+            query,
+            QueryType::Integer as u8,
+            0,
+            QueryType::Blob as u8,
+            serialize(&coin.inner())
+        ]);
+
+        let req = JsonRequest::new("wallet.exec_sql", params);
+        let _ = self.rpc_client.request(req).await?;
+
+        Ok(())
+    }
+
+    /// Replace the Merkle tree in the wallet
+    pub async fn put_tree(&self, tree: &BridgeTree<MerkleNode, MERKLE_DEPTH>) -> Result<()> {
+        let query = format!(
+            "DELETE FROM {}; INSERT INTO {} ({}) VALUES (?1);",
+            MONEY_TREE_TABLE, MONEY_TREE_TABLE, MONEY_TREE_COL_TREE
+        );
+
+        let params = json!([query, QueryType::Blob as u8, serialize(tree)]);
+        let req = JsonRequest::new("wallet.exec_sql", params);
+        let _ = self.rpc_client.request(req).await?;
+
+        Ok(())
+    }
 }
 }

+ 32 - 5
contrib/localnet/darkfid-temp/README.md

@@ -4,8 +4,8 @@ Some notes
 Start the nodes
 Start the nodes
 
 
 ```
 ```
-$ ../../../faucetd -c ./faucetd.config -v
-$ ../../../darkfid -c ./darkfid.config -v
+$ ../../../faucetd -c ./faucetd_config.toml -v
+$ ../../../darkfid -c ./darkfid_config.toml -v
 ```
 ```
 
 
 Wait for them to start up, then initialize wallet:
 Wait for them to start up, then initialize wallet:
@@ -27,6 +27,33 @@ Airdrop some coins
 $ ../../../drk -e tcp://127.0.0.1:18340 airdrop 42.69 A7f1RKsCUUHrSXA7a9ogmwg8p3bs6F47ggsW826HD4yd
 $ ../../../drk -e tcp://127.0.0.1:18340 airdrop 42.69 A7f1RKsCUUHrSXA7a9ogmwg8p3bs6F47ggsW826HD4yd
 ```
 ```
 
 
-Wait and look at the subscription. It gets the block correctly, but
-it seems to see the transaction again in new incoming blocks. What's
-happening?
+Wait and look at the subscription.
+
+Check balance
+
+```
+$ ../../../drk -e tcp://127.0.0.1:18340 wallet --balance
+```
+
+Make a new key
+
+```
+$ ../../../drk -e tcp://127.0.0.1:18340 wallet --keygen
+f00b4r
+```
+
+Create a tx to send some money to the new key
+
+```
+$ ../../../drk -e tcp://127.0.0.1:18340 transfer 11.11 A7f1RKsCUUHrSXA7a9ogmwg8p3bs6F47ggsW826HD4yd f00b4r > tx
+```
+
+Broadcast the tx
+
+```
+$ ../../../drk -e tcp://127.0.0.1:18340 broadcast < tx
+```
+
+Now watch darkfid, it gets the transaction, simulates it, and broadcasts
+over p2p, but the consensus doesn't get it and so it doesn't get appended
+to the mempool.