mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
validator: Implement basic tx fee validation
This commit is contained in:
10
src/error.rs
10
src/error.rs
@@ -620,11 +620,17 @@ pub enum TxVerifyFailed {
|
||||
#[error("Missing contract calls in transaction")]
|
||||
MissingCalls,
|
||||
|
||||
#[error("Invalid ZK proof in transaction")]
|
||||
InvalidZkProof,
|
||||
|
||||
#[error("Missing Money::Fee call in transaction")]
|
||||
MissingFee,
|
||||
|
||||
#[error("Invalid ZK proof in transaction")]
|
||||
InvalidZkProof,
|
||||
#[error("Invalid Money::Fee call in transaction")]
|
||||
InvalidFee,
|
||||
|
||||
#[error("Insufficient fee paid")]
|
||||
InsufficientFee,
|
||||
|
||||
#[error("Erroneous transactions found")]
|
||||
ErroneousTxs(Vec<crate::tx::Transaction>),
|
||||
|
||||
@@ -24,7 +24,7 @@ use darkfi_sdk::{
|
||||
dark_tree::dark_leaf_vec_integrity_check,
|
||||
pasta::pallas,
|
||||
};
|
||||
use darkfi_serial::{Decodable, Encodable, WriteExt};
|
||||
use darkfi_serial::{deserialize_async, Decodable, Encodable, WriteExt};
|
||||
use log::{debug, error, warn};
|
||||
|
||||
use crate::{
|
||||
@@ -336,6 +336,7 @@ pub async fn verify_transaction(
|
||||
time_keeper: &TimeKeeper,
|
||||
tx: &Transaction,
|
||||
verifying_keys: &mut HashMap<[u8; 32], HashMap<String, VerifyingKey>>,
|
||||
verify_fee: bool, // FIXME: Remove this bool
|
||||
) -> Result<u64> {
|
||||
let tx_hash = tx.hash()?;
|
||||
debug!(target: "validator::verification::verify_transaction", "Validating transaction {}", tx_hash);
|
||||
@@ -351,6 +352,25 @@ pub async fn verify_transaction(
|
||||
// Table of public keys used for signature verification
|
||||
let mut sig_table = vec![];
|
||||
|
||||
// Verify that the first call is the transaction fee and that it has no parents or children.
|
||||
if verify_fee {
|
||||
if tx.calls[0].data.contract_id != *MONEY_CONTRACT_ID || tx.calls[0].data.data[0] != 0x00 {
|
||||
error!(
|
||||
target: "validator::verification::verify_transaction",
|
||||
"[VALIDATOR] First tx call is not Money::Fee",
|
||||
);
|
||||
return Err(TxVerifyFailed::MissingFee.into())
|
||||
}
|
||||
|
||||
if tx.calls[0].parent_index.is_some() || !tx.calls[0].children_indexes.is_empty() {
|
||||
error!(
|
||||
target: "validator::verification::verify_transaction",
|
||||
"[VALIDATOR] Fee call invalid (has parent/children)",
|
||||
);
|
||||
return Err(TxVerifyFailed::InvalidFee.into())
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate over all calls to get the metadata
|
||||
for (idx, call) in tx.calls.iter().enumerate() {
|
||||
// Transaction must not contain a reward call, Money::PoWReward(0x08) or Consensus::Proposal(0x02)
|
||||
@@ -447,6 +467,34 @@ pub async fn verify_transaction(
|
||||
return Err(TxVerifyFailed::InvalidZkProof.into())
|
||||
}
|
||||
|
||||
if verify_fee {
|
||||
// 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
|
||||
|
||||
// Deserialize the first call to find the paid fee
|
||||
let fee: u64 = match deserialize_async(&tx.calls[0].data.data[1..9]).await {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
error!(
|
||||
target: "validator::verification::verify_transaction",
|
||||
"[VALIDATOR] Failed deserializing tx {} fee call: {}", tx_hash, e,
|
||||
);
|
||||
return Err(TxVerifyFailed::InvalidFee.into())
|
||||
}
|
||||
};
|
||||
|
||||
// Check that enough fee has been paid for the used gas in this transaction.
|
||||
if gas_used > fee {
|
||||
error!(
|
||||
target: "validator::verification::verify_transaction",
|
||||
"[VALIDATOR] tx {} has insufficient fee. Required: {}, Paid: {}",
|
||||
tx_hash, gas_used, fee,
|
||||
);
|
||||
return Err(TxVerifyFailed::InsufficientFee.into())
|
||||
}
|
||||
}
|
||||
|
||||
debug!(target: "validator::verification::verify_transaction", "ZK proof verification successful");
|
||||
debug!(target: "validator::verification::verify_transaction", "Transaction {} verified successfully", tx_hash);
|
||||
|
||||
@@ -484,7 +532,7 @@ pub async fn verify_transactions(
|
||||
// Iterate over transactions and attempt to verify them
|
||||
for tx in txs {
|
||||
overlay.lock().unwrap().checkpoint();
|
||||
match verify_transaction(overlay, time_keeper, tx, &mut vks).await {
|
||||
match verify_transaction(overlay, time_keeper, tx, &mut vks, verify_fees).await {
|
||||
Ok(gas) => _gas_used += gas,
|
||||
Err(e) => {
|
||||
warn!(target: "validator::verification::verify_transactions", "Transaction verification failed: {}", e);
|
||||
@@ -495,7 +543,7 @@ pub async fn verify_transactions(
|
||||
}
|
||||
|
||||
if verify_fees {
|
||||
// Enforce that enough fee is paid
|
||||
// Enforce that enough fee is paid.
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user