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

add command to simulate tx and show erroneous state for fetch-tx

x 3 лет назад
Родитель
Сommit
89736f3f86

+ 4 - 2
bin/darkfid/src/main.rs

@@ -215,6 +215,7 @@ impl RequestHandler for Darkfid {
             // Blockchain methods
             // ==================
             Some("blockchain.get_slot") => return self.blockchain_get_slot(req.id, params).await,
+            Some("blockchain.get_tx") => return self.blockchain_get_tx(req.id, params).await,
             Some("blockchain.last_known_slot") => {
                 return self.blockchain_last_known_slot(req.id, params).await
             }
@@ -224,13 +225,14 @@ impl RequestHandler for Darkfid {
             Some("blockchain.lookup_zkas") => {
                 return self.blockchain_lookup_zkas(req.id, params).await
             }
-            Some("blockchain.is_erroneous_tx") => {
-                return self.blockchain_is_erroneous_tx(req.id, params).await
+            Some("blockchain.was_erroneous_tx") => {
+                return self.blockchain_was_erroneous_tx(req.id, params).await
             }
 
             // ===================
             // Transaction methods
             // ===================
+            Some("tx.simulate") => return self.tx_simulate(req.id, params).await,
             Some("tx.broadcast") => return self.tx_broadcast(req.id, params).await,
 
             // ==============

+ 35 - 3
bin/darkfid/src/rpc_blockchain.rs

@@ -62,6 +62,38 @@ impl Darkfid {
         JsonResponse::new(json!(serialize(&blocks[0])), id).into()
     }
 
+    // RPCAPI:
+    // Queries the blockchain database for a block in the given slot.
+    // Returns a readable block upon success.
+    //
+    // --> {"jsonrpc": "2.0", "method": "blockchain.get_tx", "params": ["TxHash"], "id": 1}
+    // <-- {"jsonrpc": "2.0", "result": {...}, "id": 1}
+    pub async fn blockchain_get_tx(&self, id: Value, params: &[Value]) -> JsonResult {
+        if params.len() != 1 || !params[0].is_u64() {
+            return JsonError::new(InvalidParams, None, id).into()
+        }
+
+        let tx_hash = blake3::Hash::from_hex(params[0].as_str().unwrap()).unwrap();
+        let validator_state = self.validator_state.read().await;
+
+        let txs = match validator_state.blockchain.transactions.get(&[tx_hash], true) {
+            Ok(txs) => {
+                drop(validator_state);
+                txs
+            }
+            Err(e) => {
+                error!("[RPC] blockchain.get_tx: Failed fetching tx by hash: {}", e);
+                return JsonError::new(InternalError, None, id).into()
+            }
+        };
+        // This would be an logic error somewhere
+        assert_eq!(txs.len(), 1);
+        // and strict was used during .get()
+        let tx = txs[0].as_ref().unwrap();
+
+        JsonResponse::new(json!(serialize(tx)), id).into()
+    }
+
     // RPCAPI:
     // Queries the blockchain database to find the last known slot
     //
@@ -147,16 +179,16 @@ impl Darkfid {
     // Queries the blockchain database to check if the provided transaction hash exists
     // in the erroneous transactions set.
     //
-    // --> {"jsonrpc": "2.0", "method": "blockchain.is_erroneous_tx", "params": [[tx_hash bytes]], "id": 1}
+    // --> {"jsonrpc": "2.0", "method": "blockchain.was_erroneous_tx", "params": [[tx_hash bytes]], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": bool, "id": 1}
-    pub async fn blockchain_is_erroneous_tx(&self, id: Value, params: &[Value]) -> JsonResult {
+    pub async fn blockchain_was_erroneous_tx(&self, id: Value, params: &[Value]) -> JsonResult {
         if params.len() != 1 || !params[0].is_array() {
             return JsonError::new(InvalidParams, None, id).into()
         }
         let hash_bytes: [u8; 32] = serde_json::from_value(params[0].clone()).unwrap();
         let tx_hash = blake3::Hash::try_from(hash_bytes).unwrap();
         let blockchain = { self.validator_state.read().await.blockchain.clone() };
-        let Ok(result) = blockchain.is_erroneous_tx(&tx_hash) else {
+        let Ok(result) = blockchain.was_erroneous_tx(&tx_hash) else {
                 return JsonError::new(InternalError, None, id).into()
         };
 

+ 9 - 4
bin/drk/src/main.rs

@@ -920,7 +920,11 @@ async fn main() -> Result<()> {
                 };
 
                 println!("Transaction ID: {}", tx_hash);
-                // TODO: display the actual tx
+                let is_err = drk
+                    .was_erroneous_tx(&tx_hash)
+                    .await
+                    .with_context(|| "Failed to get tx state")?;
+                println!("State: {}", if is_err { "failed" } else { "passed" });
 
                 Ok(())
             }
@@ -934,10 +938,11 @@ async fn main() -> Result<()> {
 
                 let drk = Drk::new(args.endpoint).await?;
 
-                let is_err =
-                    drk.is_erroneous_tx(&tx).await.with_context(|| "Failed to check tx state")?;
+                let is_valid =
+                    drk.simulate_tx(&tx).await.with_context(|| "Failed to simulate tx")?;
 
-                println!("State: {}", if is_err { "valid" } else { "invalid" });
+                println!("Transaction ID: {}", tx.hash());
+                println!("State: {}", if is_valid { "valid" } else { "invalid" });
 
                 Ok(())
             }

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

@@ -118,7 +118,7 @@ impl Drk {
         eprintln!("[DAO] Iterating over {} transactions", block.txs.len());
         for tx in block.txs.iter() {
             // Verify transaction is not in the erroneous set
-            if self.is_erroneous_tx(tx).await? {
+            if self.was_erroneous_tx(&tx.hash()).await? {
                 continue
             }
             self.apply_tx_dao_data(tx, true).await?;
@@ -136,7 +136,7 @@ impl Drk {
 
         for tx in block.txs.iter() {
             // Verify transaction is not in the erroneous set
-            if self.is_erroneous_tx(tx).await? {
+            if self.was_erroneous_tx(&tx.hash()).await? {
                 continue
             }
             self.apply_tx_money_data(tx, true).await?;
@@ -187,6 +187,16 @@ impl Drk {
         Ok(txid)
     }
 
+    /// Simulate the transaction with the state machine
+    pub async fn simulate_tx(&self, tx: &Transaction) -> Result<bool> {
+        let params = json!([bs58::encode(&serialize(tx)).into_string()]);
+        let req = JsonRequest::new("tx.simulate", params);
+        let rep = self.rpc_client.request(req).await?;
+
+        let is_valid = serde_json::from_value(rep)?;
+        Ok(is_valid)
+    }
+
     /// Queries darkfid for a block with given slot
     async fn get_block_by_slot(&self, slot: u64) -> Result<Option<BlockInfo>> {
         let req = JsonRequest::new("blockchain.get_slot", json!([slot]));
@@ -297,10 +307,8 @@ impl Drk {
     }
 
     /// Queries darkfid to check if transaction is in the erroneous set
-    pub async fn is_erroneous_tx(&self, tx: &Transaction) -> Result<bool> {
-        let serialized = serialize(tx);
-        let tx_hash = blake3::hash(&serialized);
-        let req = JsonRequest::new("blockchain.is_erroneous_tx", json!([tx_hash.as_bytes()]));
+    pub async fn was_erroneous_tx(&self, tx_hash: &blake3::Hash) -> Result<bool> {
+        let req = JsonRequest::new("blockchain.was_erroneous_tx", json!([tx_hash.as_bytes()]));
         match self.rpc_client.request(req).await {
             Ok(v) => Ok(serde_json::from_value(v)?),
             Err(_) => Ok(false),

+ 1 - 1
src/blockchain/mod.rs

@@ -228,7 +228,7 @@ impl Blockchain {
     }
 
     /// Check if the erroneoustxstore contains given transaction hash.
-    pub fn is_erroneous_tx(&self, tx_hash: &blake3::Hash) -> Result<bool> {
+    pub fn was_erroneous_tx(&self, tx_hash: &blake3::Hash) -> Result<bool> {
         self.erroneous_txs.contains(tx_hash)
     }
 }

+ 7 - 0
src/tx/mod.rs

@@ -149,4 +149,11 @@ impl Transaction {
         self.proofs.encode(&mut buf)?;
         Ok(buf)
     }
+
+    /// Get the transaction hash
+    pub fn hash(&self) -> blake3::Hash {
+        let mut tx_data = vec![];
+        self.encode(&mut tx_data).expect("serialize tx");
+        blake3::hash(&tx_data)
+    }
 }