validator: Account for Schnorr signature verification for fees in txs

This commit is contained in:
parazyd
2024-01-19 12:59:02 +01:00
committed by lunar-mining
parent bb5b015a00
commit bf43e8f77d
3 changed files with 55 additions and 27 deletions

20
src/validator/fees.rs Normal file
View File

@@ -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;

View File

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

View File

@@ -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);