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

validator: Account for Schnorr signature verification for fees in txs

parazyd 2 лет назад
Родитель
Сommit
f733f094e7
3 измененных файлов с 55 добавлено и 27 удалено
  1. 20 0
      src/validator/fees.rs
  2. 3 0
      src/validator/mod.rs
  3. 32 27
      src/validator/verification.rs

+ 20 - 0
src/validator/fees.rs

@@ -0,0 +1,20 @@
+/* This file is part of DarkFi (https://dark.fi)
+ *
+ * Copyright (C) 2020-2024 Dyne.org foundation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+/// Fixed fee for verifying Schnorr signatures using the Pallas elliptic curve
+pub const PALLAS_SCHNORR_SIGNATURE_FEE: u64 = 1000;

+ 3 - 0
src/validator/mod.rs

@@ -56,6 +56,9 @@ use verification::{
     verify_transactions,
 };
 
+/// Fee calculation helpers
+pub mod fees;
+
 /// Validation functions
 pub mod validation;
 

+ 32 - 27
src/validator/verification.rs

@@ -28,7 +28,9 @@ use darkfi_sdk::{
     deploy::DeployParamsV1,
     pasta::pallas,
 };
-use darkfi_serial::{deserialize_async, AsyncDecodable, AsyncEncodable, AsyncWriteExt, WriteExt};
+use darkfi_serial::{
+    deserialize_async, serialize_async, AsyncDecodable, AsyncEncodable, AsyncWriteExt, WriteExt,
+};
 use log::{debug, error, warn};
 use smol::io::Cursor;
 
@@ -40,6 +42,7 @@ use crate::{
     util::time::TimeKeeper,
     validator::{
         consensus::{Consensus, Fork, Proposal, TXS_CAP},
+        fees::PALLAS_SCHNORR_SIGNATURE_FEE,
         pow::PoWModule,
         validation::validate_block,
     },
@@ -493,34 +496,13 @@ pub async fn verify_transaction(
         gas_used += runtime.gas_used();
     }
 
-    // When we're done looping and executing over the tx's contract calls, we now
-    // move on with verification. First we verify the signatures as that's cheaper,
-    // and then finally we verify the ZK proofs.
-    debug!(target: "validator::verification::verify_transaction", "Verifying signatures for transaction {}", tx_hash);
-    if sig_table.len() != tx.signatures.len() {
-        error!(target: "validator::verification::verify_transaction", "Incorrect number of signatures in tx {}", tx_hash);
-        return Err(TxVerifyFailed::MissingSignatures.into())
-    }
-
-    // TODO: Go through the ZK circuits that have to be verified and account for the opcodes.
-
-    if let Err(e) = tx.verify_sigs(sig_table) {
-        error!(target: "validator::verification::verify_transaction", "Signature verification for tx {} failed: {}", tx_hash, e);
-        return Err(TxVerifyFailed::InvalidSignature.into())
-    }
-
-    debug!(target: "validator::verification::verify_transaction", "Signature verification successful");
-
-    debug!(target: "validator::verification::verify_transaction", "Verifying ZK proofs for transaction {}", tx_hash);
-    if let Err(e) = tx.verify_zkps(verifying_keys, zkp_table).await {
-        error!(target: "validator::verification::verify_transaction", "ZK proof verification for tx {} failed: {}", tx_hash, e);
-        return Err(TxVerifyFailed::InvalidZkProof.into())
-    }
-
     if verify_fee {
+        // The signature fee is tx_size + fixed_sig_fee * n_signatures
+        gas_used += (PALLAS_SCHNORR_SIGNATURE_FEE * tx.signatures.len() as u64) +
+            serialize_async(tx).await.len() as u64;
+
         // TODO: This counts 1 gas as 1 token unit. Pricing should be better specified.
-        // TODO: Currently this doesn't account for signatures or ZK proofs
-        // TODO: Currently this doesn't account for WASM host functions
+        // TODO: Currently this doesn't account for ZK proofs
 
         // Deserialize the fee call to find the paid fee
         let fee: u64 = match deserialize_async(&tx.calls[fee_call_idx].data.data[1..9]).await {
@@ -545,6 +527,29 @@ pub async fn verify_transaction(
         }
     }
 
+    // When we're done looping and executing over the tx's contract calls and
+    // (optionally) made sure that enough fee was paid, we now move on with
+    // verification. First we verify the transaction signatures and then we
+    // verify any accompanying ZK proofs.
+    debug!(target: "validator::verification::verify_transaction", "Verifying signatures for transaction {}", tx_hash);
+    if sig_table.len() != tx.signatures.len() {
+        error!(target: "validator::verification::verify_transaction", "Incorrect number of signatures in tx {}", tx_hash);
+        return Err(TxVerifyFailed::MissingSignatures.into())
+    }
+
+    if let Err(e) = tx.verify_sigs(sig_table) {
+        error!(target: "validator::verification::verify_transaction", "Signature verification for tx {} failed: {}", tx_hash, e);
+        return Err(TxVerifyFailed::InvalidSignature.into())
+    }
+
+    debug!(target: "validator::verification::verify_transaction", "Signature verification successful");
+
+    debug!(target: "validator::verification::verify_transaction", "Verifying ZK proofs for transaction {}", tx_hash);
+    if let Err(e) = tx.verify_zkps(verifying_keys, zkp_table).await {
+        error!(target: "validator::verification::verify_transaction", "ZK proof verification for tx {} failed: {}", tx_hash, e);
+        return Err(TxVerifyFailed::InvalidZkProof.into())
+    }
+
     debug!(target: "validator::verification::verify_transaction", "ZK proof verification successful");
     debug!(target: "validator::verification::verify_transaction", "Transaction {} verified successfully", tx_hash);