mod.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2025 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. use std::collections::HashMap;
  19. use darkfi_sdk::{
  20. crypto::{
  21. schnorr::{SchnorrPublic, SchnorrSecret, Signature},
  22. PublicKey, SecretKey,
  23. },
  24. dark_tree::{dark_forest_leaf_vec_integrity_check, DarkForest, DarkLeaf, DarkTree},
  25. error::DarkTreeResult,
  26. pasta::pallas,
  27. tx::{ContractCall, TransactionHash},
  28. };
  29. #[cfg(feature = "async-serial")]
  30. use darkfi_serial::async_trait;
  31. use darkfi_serial::{Encodable, SerialDecodable, SerialEncodable};
  32. use log::{debug, error};
  33. use crate::{
  34. error::TxVerifyFailed,
  35. zk::{proof::VerifyingKey, Proof},
  36. Error, Result,
  37. };
  38. macro_rules! zip {
  39. ($x:expr) => ($x);
  40. ($x:expr, $($y:expr), +) => (
  41. $x.iter().zip(zip!($($y), +))
  42. )
  43. }
  44. // ANCHOR: transaction
  45. /// A Transaction contains an arbitrary number of `ContractCall` objects,
  46. /// along with corresponding ZK proofs and Schnorr signatures.
  47. ///
  48. /// `DarkLeaf` is used to map relations between contract calls in the transaction.
  49. #[derive(Clone, Default, Eq, PartialEq, SerialEncodable, SerialDecodable)]
  50. pub struct Transaction {
  51. /// Calls executed in this transaction
  52. pub calls: Vec<DarkLeaf<ContractCall>>,
  53. /// Attached ZK proofs
  54. pub proofs: Vec<Vec<Proof>>,
  55. /// Attached Schnorr signatures
  56. pub signatures: Vec<Vec<Signature>>,
  57. }
  58. // ANCHOR_END: transaction
  59. impl Transaction {
  60. /// Verify ZK proofs for the entire transaction.
  61. pub async fn verify_zkps(
  62. &self,
  63. verifying_keys: &HashMap<[u8; 32], HashMap<String, VerifyingKey>>,
  64. zkp_table: Vec<Vec<(String, Vec<pallas::Base>)>>,
  65. ) -> Result<()> {
  66. // TODO: Are we sure we should assert here?
  67. assert_eq!(self.calls.len(), self.proofs.len());
  68. assert_eq!(self.calls.len(), zkp_table.len());
  69. for (call, (proofs, pubvals)) in zip!(self.calls, self.proofs, zkp_table) {
  70. assert_eq!(proofs.len(), pubvals.len());
  71. let Some(contract_map) = verifying_keys.get(&call.data.contract_id.to_bytes()) else {
  72. error!(
  73. target: "tx::verify_zkps",
  74. "[TX] Verifying keys not found for contract {}",
  75. call.data.contract_id,
  76. );
  77. return Err(TxVerifyFailed::InvalidZkProof.into())
  78. };
  79. for (proof, (zk_ns, public_vals)) in proofs.iter().zip(pubvals.iter()) {
  80. if let Some(vk) = contract_map.get(zk_ns) {
  81. // We have a verifying key for this
  82. debug!(target: "tx::verify_zkps", "[TX] public inputs: {:#?}", public_vals);
  83. if let Err(e) = proof.verify(vk, public_vals) {
  84. error!(
  85. target: "tx::verify_zkps",
  86. "[TX] Failed verifying {}::{} ZK proof: {:#?}",
  87. call.data.contract_id, zk_ns, e
  88. );
  89. return Err(TxVerifyFailed::InvalidZkProof.into())
  90. }
  91. debug!(
  92. target: "tx::verify_zkps",
  93. "[TX] Successfully verified {}::{} ZK proof",
  94. call.data.contract_id, zk_ns,
  95. );
  96. continue
  97. }
  98. error!(
  99. target: "tx::verify_zkps",
  100. "[TX] {}::{} circuit VK nonexistent",
  101. call.data.contract_id, zk_ns,
  102. );
  103. return Err(TxVerifyFailed::InvalidZkProof.into())
  104. }
  105. }
  106. Ok(())
  107. }
  108. /// Verify Schnorr signatures for the entire transaction.
  109. pub fn verify_sigs(&self, pub_table: Vec<Vec<PublicKey>>) -> Result<()> {
  110. // Hash the transaction without the signatures
  111. let mut hasher = blake3::Hasher::new();
  112. self.calls.encode(&mut hasher)?;
  113. self.proofs.encode(&mut hasher)?;
  114. let data_hash = hasher.finalize();
  115. debug!(target: "tx::verify_sigs", "tx.verify_sigs: data_hash: {data_hash}");
  116. assert_eq!(self.signatures.len(), pub_table.len());
  117. for (i, (sigs, pubkeys)) in self.signatures.iter().zip(pub_table.iter()).enumerate() {
  118. assert_eq!(sigs.len(), pubkeys.len());
  119. for (pubkey, signature) in pubkeys.iter().zip(sigs) {
  120. debug!(target: "tx::verify_sigs", "[TX] Verifying signature with public key: {pubkey}");
  121. if !pubkey.verify(&data_hash.as_bytes()[..], signature) {
  122. error!(target: "tx::verify_sigs", "[TX] tx::verify_sigs[{i}] failed to verify signature");
  123. return Err(Error::InvalidSignature)
  124. }
  125. }
  126. debug!(target: "tx::verify_sigs", "[TX] tx::verify_sigs[{i}] passed");
  127. }
  128. Ok(())
  129. }
  130. /// Create Schnorr signatures for the entire transaction.
  131. pub fn create_sigs(&self, secret_keys: &[SecretKey]) -> Result<Vec<Signature>> {
  132. // Hash the transaction without the signatures
  133. let mut hasher = blake3::Hasher::new();
  134. self.calls.encode(&mut hasher)?;
  135. self.proofs.encode(&mut hasher)?;
  136. let data_hash = hasher.finalize();
  137. debug!(target: "tx::create_sigs", "[TX] tx.create_sigs: data_hash: {data_hash}");
  138. let mut sigs = vec![];
  139. for secret in secret_keys {
  140. debug!(
  141. target: "tx::create_sigs",
  142. "[TX] Creating signature with public key: {}", PublicKey::from_secret(*secret),
  143. );
  144. let signature = secret.sign(&data_hash.as_bytes()[..]);
  145. sigs.push(signature);
  146. }
  147. Ok(sigs)
  148. }
  149. /// Get the transaction hash
  150. pub fn hash(&self) -> TransactionHash {
  151. let mut hasher = blake3::Hasher::new();
  152. // Blake3 hasher .update() method never fails.
  153. // This call returns a Result due to how the Write trait is specified.
  154. // Calling unwrap() here should be safe.
  155. self.encode(&mut hasher).expect("blake3 hasher");
  156. TransactionHash(hasher.finalize().into())
  157. }
  158. /// Returns true if transaction is a PoW reward one.
  159. pub fn is_pow_reward(&self) -> bool {
  160. // PoW rewards must be single contract calls
  161. if !self.is_single_call() {
  162. return false;
  163. }
  164. self.calls[0].data.is_money_pow_reward()
  165. }
  166. /// Returns true if the transaction consists of a single call with non-empty data.
  167. pub fn is_single_call(&self) -> bool {
  168. self.calls.len() == 1 && !self.calls[0].data.data.is_empty()
  169. }
  170. }
  171. // Avoid showing the proofs and sigs in the debug output since often they are very long.
  172. impl std::fmt::Debug for Transaction {
  173. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  174. writeln!(f, "Transaction {{")?;
  175. for (i, call) in self.calls.iter().enumerate() {
  176. writeln!(f, " Call {} {{", i)?;
  177. writeln!(f, " contract_id: {:?}", call.data.contract_id.inner())?;
  178. let calldata = &call.data.data;
  179. if !calldata.is_empty() {
  180. writeln!(f, " function_code: {}", calldata[0])?;
  181. }
  182. writeln!(f, " parent: {:?}", call.parent_index)?;
  183. writeln!(f, " children: {:?}", call.children_indexes)?;
  184. writeln!(f, " }},")?;
  185. }
  186. writeln!(f, "}}")
  187. }
  188. }
  189. #[cfg(feature = "net")]
  190. use crate::{
  191. net::{metering::MeteringConfiguration, Message},
  192. util::time::NanoTimestamp,
  193. };
  194. #[cfg(feature = "net")]
  195. // TODO: Fine tune
  196. // Since messages are asynchronous we will define loose rules to prevent spamming.
  197. // Each message score will be 1, with a threshold of 100 and expiry time of 5.
  198. // We are not limiting `Transaction` size.
  199. crate::impl_p2p_message!(
  200. Transaction,
  201. "tx",
  202. 0,
  203. 1,
  204. MeteringConfiguration {
  205. threshold: 100,
  206. sleep_step: 500,
  207. expiry_time: NanoTimestamp::from_secs(5),
  208. }
  209. );
  210. /// Calls tree bounds definitions
  211. // TODO: increase min to 2 when fees are implement
  212. pub const MIN_TX_CALLS: usize = 1;
  213. // TODO: verify max value
  214. pub const MAX_TX_CALLS: usize = 20;
  215. /// Auxiliarry structure containing all the information
  216. /// required to execute a contract call.
  217. #[derive(Clone)]
  218. pub struct ContractCallLeaf {
  219. /// Call executed
  220. pub call: ContractCall,
  221. /// Attached ZK proofs
  222. pub proofs: Vec<Proof>,
  223. }
  224. /// Auxiliary structure to build a full [`Transaction`] using
  225. /// [`DarkTree`] to order everything.
  226. pub struct TransactionBuilder {
  227. /// Contract calls trees forest
  228. pub calls: DarkForest<ContractCallLeaf>,
  229. }
  230. // TODO: for now we build the trees manually, but we should
  231. // add all the proper functions for easier building.
  232. impl TransactionBuilder {
  233. /// Initialize the builder, using provided data to
  234. /// generate its initial [`DarkTree`] root.
  235. pub fn new(
  236. data: ContractCallLeaf,
  237. children: Vec<DarkTree<ContractCallLeaf>>,
  238. ) -> DarkTreeResult<Self> {
  239. let calls = DarkForest::new(Some(MIN_TX_CALLS), Some(MAX_TX_CALLS));
  240. let mut self_ = Self { calls };
  241. self_.append(data, children)?;
  242. Ok(self_)
  243. }
  244. /// Append a new call tree to the forest
  245. pub fn append(
  246. &mut self,
  247. data: ContractCallLeaf,
  248. children: Vec<DarkTree<ContractCallLeaf>>,
  249. ) -> DarkTreeResult<()> {
  250. let tree = DarkTree::new(data, children, None, None);
  251. self.calls.append(tree)
  252. }
  253. /// Builder builds the calls vector using the [`DarkForest`]
  254. /// and generates the corresponding [`Transaction`].
  255. pub fn build(&mut self) -> DarkTreeResult<Transaction> {
  256. // Build the leafs vector
  257. let leafs = self.calls.build_vec()?;
  258. // Double check integrity
  259. dark_forest_leaf_vec_integrity_check(&leafs, Some(MIN_TX_CALLS), Some(MAX_TX_CALLS))?;
  260. // Build the corresponding transaction
  261. let mut calls = Vec::with_capacity(leafs.len());
  262. let mut proofs = Vec::with_capacity(leafs.len());
  263. for leaf in leafs {
  264. let call = DarkLeaf {
  265. data: leaf.data.call,
  266. parent_index: leaf.parent_index,
  267. children_indexes: leaf.children_indexes,
  268. };
  269. calls.push(call);
  270. proofs.push(leaf.data.proofs);
  271. }
  272. Ok(Transaction { calls, proofs, signatures: vec![] })
  273. }
  274. }