darkfi/validator/
fees.rs

1/* This file is part of DarkFi (https://dark.fi)
2 *
3 * Copyright (C) 2020-2026 Dyne.org foundation
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as
7 * published by the Free Software Foundation, either version 3 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18
19use darkfi_sdk::crypto::constants::{MERKLE_DEPTH_ORCHARD, SPARSE_MERKLE_DEPTH};
20use darkfi_serial::{async_trait, SerialDecodable, SerialEncodable};
21
22use crate::zkas::{Opcode, VarType, ZkBinary};
23
24/// Fixed fee for verifying Schnorr signatures using the Pallas
25/// elliptic curve.
26pub const PALLAS_SCHNORR_SIGNATURE_FEE: u64 = 1000;
27
28/// Calculate the gas use for verifying a given zkas circuit.
29/// This function assumes that the zkbin was properly decoded.
30pub fn circuit_gas_use(zkbin: &ZkBinary) -> u64 {
31    let mut accumulator: u64 = 0;
32
33    // Constants each with a cost of 10
34    accumulator = accumulator.saturating_add(10u64.saturating_mul(zkbin.constants.len() as u64));
35
36    // Literals each with a cost of 10 (for now there's only 1 type of
37    // literal).
38    accumulator = accumulator.saturating_add(10u64.saturating_mul(zkbin.literals.len() as u64));
39
40    // Witnesses have cost by type
41    for witness in &zkbin.witnesses {
42        let cost = match witness {
43            VarType::Dummy => unreachable!(),
44            VarType::EcPoint => 20,
45            VarType::EcFixedPoint => unreachable!(),
46            VarType::EcFixedPointShort => unreachable!(),
47            VarType::EcFixedPointBase => unreachable!(),
48            VarType::EcNiPoint => 20,
49            VarType::Base => 10,
50            VarType::BaseArray => unreachable!(),
51            VarType::Scalar => 20,
52            VarType::ScalarArray => unreachable!(),
53            VarType::MerklePath => 10 * MERKLE_DEPTH_ORCHARD as u64,
54            VarType::SparseMerklePath => 10 * SPARSE_MERKLE_DEPTH as u64,
55            VarType::Uint32 => 10,
56            VarType::Uint64 => 10,
57            VarType::Any => 10,
58        };
59
60        accumulator = accumulator.saturating_add(cost);
61    }
62
63    // Opcodes depending on how heavy they are
64    for opcode in &zkbin.opcodes {
65        let cost = match opcode.0 {
66            Opcode::Noop => unreachable!(),
67            Opcode::EcAdd => 30,
68            Opcode::EcMul => 30,
69            Opcode::EcMulBase => 30,
70            Opcode::EcMulShort => 30,
71            Opcode::EcMulVarBase => 30,
72            Opcode::EcGetX => 5,
73            Opcode::EcGetY => 5,
74            Opcode::PoseidonHash => {
75                20u64.saturating_add(10u64.saturating_mul(opcode.1.len() as u64))
76            }
77            Opcode::MerkleRoot => 10 * MERKLE_DEPTH_ORCHARD as u64,
78            Opcode::SparseMerkleRoot => 10 * SPARSE_MERKLE_DEPTH as u64,
79            Opcode::BaseAdd => 15,
80            Opcode::BaseMul => 15,
81            Opcode::BaseSub => 15,
82            Opcode::WitnessBase => 10,
83            Opcode::RangeCheck => 60,
84            Opcode::LessThanStrict => 100,
85            Opcode::LessThanLoose => 100,
86            Opcode::BoolCheck => 20,
87            Opcode::CondSelect => 10,
88            Opcode::ZeroCondSelect => 10,
89            Opcode::ConstrainEqualBase => 10,
90            Opcode::ConstrainEqualPoint => 20,
91            Opcode::ConstrainInstance => 10,
92            Opcode::DebugPrint => 100,
93        };
94
95        accumulator = accumulator.saturating_add(cost);
96    }
97
98    accumulator
99}
100
101/// Auxiliary struct representing the full gas usage breakdown of a
102/// transaction.
103///
104/// This data is used for accounting of fees, providing details
105/// relating to resource consumption across different transactions.
106#[derive(Default, Clone, Eq, PartialEq, SerialEncodable, SerialDecodable)]
107pub struct GasData {
108    /// Wasm calls gas consumption
109    pub wasm: u64,
110    /// ZK circuits gas consumption
111    pub zk_circuits: u64,
112    /// Signature fee
113    pub signatures: u64,
114    /// Contract deployment gas
115    pub deployments: u64,
116    /// Transaction paid fee
117    pub paid: u64,
118}
119
120impl GasData {
121    /// Calculates the total gas used by summing all individual gas
122    /// usage fields.
123    pub fn total_gas_used(&self) -> u64 {
124        self.wasm
125            .saturating_add(self.zk_circuits)
126            .saturating_add(self.signatures)
127            .saturating_add(self.deployments)
128    }
129}
130
131/// Implements custom debug trait to include
132/// [`GasData::total_gas_used`].
133impl std::fmt::Debug for GasData {
134    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
135        f.debug_struct("GasData")
136            .field("total", &self.total_gas_used())
137            .field("wasm", &self.wasm)
138            .field("zk_circuits", &self.zk_circuits)
139            .field("signatures", &self.signatures)
140            .field("deployments", &self.deployments)
141            .field("paid", &self.paid)
142            .finish()
143    }
144}
145
146/// Auxiliary function to compute the corresponding fee value
147/// for the provided gas.
148///
149/// Currently we simply divide the gas value by 100.
150pub fn compute_fee(gas: &u64) -> u64 {
151    gas / 100
152}