verification.rs 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183
  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. use std::collections::HashMap;
  19. use darkfi_sdk::{
  20. blockchain::block_version,
  21. crypto::{
  22. schnorr::{SchnorrPublic, Signature},
  23. ContractId, MerkleTree, PublicKey,
  24. },
  25. dark_tree::dark_forest_leaf_vec_integrity_check,
  26. deploy::DeployParamsV1,
  27. monotree::{self, Monotree},
  28. pasta::pallas,
  29. };
  30. use darkfi_serial::{deserialize_async, serialize_async, AsyncDecodable, AsyncEncodable};
  31. use num_bigint::BigUint;
  32. use sled_overlay::SledDbOverlayStateDiff;
  33. use smol::io::Cursor;
  34. use tracing::{debug, error, warn};
  35. use crate::{
  36. blockchain::{
  37. block_store::append_tx_to_merkle_tree, header_store::PowData::DarkFi, BlockInfo,
  38. Blockchain, BlockchainOverlayPtr, HeaderHash,
  39. },
  40. error::TxVerifyFailed,
  41. runtime::vm_runtime::Runtime,
  42. tx::{Transaction, MAX_TX_CALLS, MIN_TX_CALLS},
  43. validator::{
  44. consensus::{Consensus, Fork, Proposal, BLOCK_GAS_LIMIT},
  45. fees::{circuit_gas_use, compute_fee, GasData, PALLAS_SCHNORR_SIGNATURE_FEE},
  46. pow::PoWModule,
  47. },
  48. zk::VerifyingKey,
  49. Error, Result,
  50. };
  51. /// Verify given genesis [`BlockInfo`], and apply it to the provided overlay.
  52. pub async fn verify_genesis_block(
  53. overlay: &BlockchainOverlayPtr,
  54. block: &BlockInfo,
  55. block_target: u32,
  56. ) -> Result<()> {
  57. let block_hash = block.hash().as_string();
  58. debug!(target: "validator::verification::verify_genesis_block", "Validating genesis block {block_hash}");
  59. // Check if block already exists
  60. if overlay.lock().unwrap().has_block(block)? {
  61. return Err(Error::BlockAlreadyExists(block_hash))
  62. }
  63. // Block height must be 0
  64. if block.header.height != 0 {
  65. return Err(Error::BlockIsInvalid(block_hash))
  66. }
  67. // Block version must be correct
  68. if block.header.version != block_version(block.header.height) {
  69. return Err(Error::BlockIsInvalid(block_hash))
  70. }
  71. // Block must use Darkfi native Proof of Work data
  72. match block.header.pow_data {
  73. DarkFi => { /* do nothing */ }
  74. _ => return Err(Error::BlockIsInvalid(block_hash)),
  75. }
  76. // Verify transactions vector contains at least one(producers) transaction
  77. if block.txs.is_empty() {
  78. return Err(Error::BlockContainsNoTransactions(block_hash))
  79. }
  80. // Genesis producer transaction must be the Transaction::default() one(empty)
  81. let producer_tx = block.txs.last().unwrap();
  82. if producer_tx != &Transaction::default() {
  83. error!(target: "validator::verification::verify_genesis_block", "Genesis producer transaction is not default one");
  84. return Err(TxVerifyFailed::ErroneousTxs(vec![producer_tx.clone()]).into())
  85. }
  86. // Verify transactions, exluding producer(last) one/
  87. // Genesis block doesn't check for fees
  88. let mut tree = MerkleTree::new(1);
  89. let txs = &block.txs[..block.txs.len() - 1];
  90. if let Err(e) =
  91. verify_transactions(overlay, block.header.height, block_target, txs, &mut tree, false).await
  92. {
  93. warn!(
  94. target: "validator::verification::verify_genesis_block",
  95. "[VALIDATOR] Erroneous transactions found in set",
  96. );
  97. overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
  98. return Err(e)
  99. }
  100. // Append producer transaction to the tree and check tree matches header one
  101. append_tx_to_merkle_tree(&mut tree, producer_tx);
  102. if tree.root(0).unwrap() != block.header.transactions_root {
  103. error!(target: "validator::verification::verify_genesis_block", "Genesis Merkle tree is invalid");
  104. return Err(Error::BlockIsInvalid(block_hash))
  105. }
  106. // Verify header contracts states root
  107. let state_monotree = overlay.lock().unwrap().contracts.get_state_monotree()?;
  108. let Some(state_root) = state_monotree.get_headroot()? else {
  109. return Err(Error::ContractsStatesRootNotFoundError);
  110. };
  111. if state_root != block.header.state_root {
  112. return Err(Error::ContractsStatesRootError(
  113. blake3::Hash::from_bytes(state_root).to_string(),
  114. blake3::Hash::from_bytes(block.header.state_root).to_string(),
  115. ));
  116. }
  117. // Genesis producer signature must be the Signature::dummy() one(empty)
  118. if block.signature != Signature::dummy() {
  119. error!(target: "validator::verification::verify_genesis_block", "Genesis producer signature is not dummy one");
  120. return Err(Error::InvalidSignature)
  121. }
  122. // Insert block
  123. overlay.lock().unwrap().add_block(block)?;
  124. debug!(target: "validator::verification::verify_genesis_block", "Genesis block {block_hash} verified successfully");
  125. Ok(())
  126. }
  127. /// Validate provided block according to set rules.
  128. ///
  129. /// A block is considered valid when the following rules apply:
  130. /// 1. Block version is correct for its height
  131. /// 2. Previous hash is equal to the hash of the provided previous block
  132. /// 3. Block height increments previous block height by 1
  133. /// 4. Timestamp is valid based on PoWModule validation
  134. /// 5. Block header Proof of Work data are valid
  135. /// 6. Block hash is valid based on PoWModule validation
  136. /// Additional validity rules can be applied.
  137. pub fn validate_block(block: &BlockInfo, previous: &BlockInfo, module: &PoWModule) -> Result<()> {
  138. // Check block version (1)
  139. if block.header.version != block_version(block.header.height) {
  140. return Err(Error::BlockIsInvalid(block.hash().as_string()))
  141. }
  142. // Check previous hash (2)
  143. if block.header.previous != previous.hash() {
  144. return Err(Error::BlockIsInvalid(block.hash().as_string()))
  145. }
  146. // Check heights are incremental (3)
  147. if block.header.height != previous.header.height + 1 {
  148. return Err(Error::BlockIsInvalid(block.hash().as_string()))
  149. }
  150. // Check timestamp validity (4)
  151. if !module.verify_timestamp_by_median(block.header.timestamp) {
  152. return Err(Error::BlockIsInvalid(block.hash().as_string()))
  153. }
  154. // Check PoW data validty (5)
  155. if !block.header.validate_powdata() {
  156. return Err(Error::BlockIsInvalid(block.hash().as_string()))
  157. }
  158. // Check block hash corresponds to next mine target (6)
  159. module.verify_block_hash(&block.header)?;
  160. Ok(())
  161. }
  162. /// A blockchain is considered valid, when every block is valid,
  163. /// based on validate_block checks.
  164. /// Be careful as this will try to load everything in memory.
  165. pub fn validate_blockchain(
  166. blockchain: &Blockchain,
  167. pow_target: u32,
  168. pow_fixed_difficulty: Option<BigUint>,
  169. ) -> Result<()> {
  170. // Generate a PoW module
  171. let mut module = PoWModule::new(blockchain.clone(), pow_target, pow_fixed_difficulty, Some(0))?;
  172. // We use block order store here so we have all blocks in order
  173. let blocks = blockchain.blocks.get_all_order()?;
  174. for (index, block) in blocks[1..].iter().enumerate() {
  175. let full_blocks = blockchain.get_blocks_by_hash(&[blocks[index].1, block.1])?;
  176. let full_block = &full_blocks[1];
  177. validate_block(full_block, &full_blocks[0], &module)?;
  178. // Update PoW module
  179. module.append(&full_block.header, &module.next_difficulty()?)?;
  180. }
  181. Ok(())
  182. }
  183. /// Verify given [`BlockInfo`], and apply it to the provided overlay.
  184. pub async fn verify_block(
  185. overlay: &BlockchainOverlayPtr,
  186. diffs: &[SledDbOverlayStateDiff],
  187. module: &PoWModule,
  188. state_monotree: &mut Monotree<monotree::MemoryDb>,
  189. block: &BlockInfo,
  190. previous: &BlockInfo,
  191. verify_fees: bool,
  192. ) -> Result<()> {
  193. let block_hash = block.hash();
  194. debug!(target: "validator::verification::verify_block", "Validating block {block_hash}");
  195. // Check if block already exists
  196. if overlay.lock().unwrap().has_block(block)? {
  197. return Err(Error::BlockAlreadyExists(block_hash.as_string()))
  198. }
  199. // Validate block, using its previous
  200. validate_block(block, previous, module)?;
  201. // Verify transactions vector contains at least one(producers) transaction
  202. if block.txs.is_empty() {
  203. return Err(Error::BlockContainsNoTransactions(block_hash.as_string()))
  204. }
  205. // Verify transactions, exluding producer(last) one
  206. let mut tree = MerkleTree::new(1);
  207. let txs = &block.txs[..block.txs.len() - 1];
  208. let e = verify_transactions(
  209. overlay,
  210. block.header.height,
  211. module.target,
  212. txs,
  213. &mut tree,
  214. verify_fees,
  215. )
  216. .await;
  217. if let Err(e) = e {
  218. warn!(
  219. target: "validator::verification::verify_block",
  220. "[VALIDATOR] Erroneous transactions found in set",
  221. );
  222. overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
  223. return Err(e)
  224. }
  225. // Verify producer transaction
  226. let public_key = verify_producer_transaction(
  227. overlay,
  228. block.header.height,
  229. module.target,
  230. block.txs.last().unwrap(),
  231. &mut tree,
  232. )
  233. .await?;
  234. // Verify transactions merkle tree root matches header one
  235. if tree.root(0).unwrap() != block.header.transactions_root {
  236. error!(target: "validator::verification::verify_block", "Block Merkle tree root is invalid");
  237. return Err(Error::BlockIsInvalid(block_hash.as_string()))
  238. }
  239. // Update the provided contracts states monotree and verify header contracts states root
  240. let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(diffs)?;
  241. overlay.lock().unwrap().contracts.update_state_monotree(&diff, state_monotree)?;
  242. let Some(state_root) = state_monotree.get_headroot()? else {
  243. return Err(Error::ContractsStatesRootNotFoundError);
  244. };
  245. if state_root != block.header.state_root {
  246. return Err(Error::ContractsStatesRootError(
  247. blake3::Hash::from_bytes(state_root).to_string(),
  248. blake3::Hash::from_bytes(block.header.state_root).to_string(),
  249. ));
  250. }
  251. // Verify producer signature
  252. verify_producer_signature(block, &public_key)?;
  253. // Insert block
  254. overlay.lock().unwrap().add_block(block)?;
  255. debug!(target: "validator::verification::verify_block", "Block {block_hash} verified successfully");
  256. Ok(())
  257. }
  258. /// Verify given checkpoint [`BlockInfo`], and apply it to the provided overlay.
  259. pub async fn verify_checkpoint_block(
  260. overlay: &BlockchainOverlayPtr,
  261. diffs: &[SledDbOverlayStateDiff],
  262. state_monotree: &mut Monotree<monotree::MemoryDb>,
  263. block: &BlockInfo,
  264. header: &HeaderHash,
  265. block_target: u32,
  266. ) -> Result<()> {
  267. let block_hash = block.hash();
  268. debug!(target: "validator::verification::verify_checkpoint_block", "Validating block {block_hash}");
  269. // Check if block already exists
  270. if overlay.lock().unwrap().has_block(block)? {
  271. return Err(Error::BlockAlreadyExists(block_hash.as_string()))
  272. }
  273. // Check if block hash matches the expected(provided) one
  274. if block_hash != *header {
  275. error!(target: "validator::verification::verify_checkpoint_block", "Block hash doesn't match the expected one");
  276. return Err(Error::BlockIsInvalid(block_hash.as_string()))
  277. }
  278. // Verify transactions vector contains at least one(producers) transaction
  279. if block.txs.is_empty() {
  280. return Err(Error::BlockContainsNoTransactions(block_hash.as_string()))
  281. }
  282. // Apply transactions, excluding producer(last) one
  283. let mut tree = MerkleTree::new(1);
  284. let txs = &block.txs[..block.txs.len() - 1];
  285. let e = apply_transactions(overlay, block.header.height, block_target, txs, &mut tree).await;
  286. if let Err(e) = e {
  287. warn!(
  288. target: "validator::verification::verify_checkpoint_block",
  289. "[VALIDATOR] Erroneous transactions found in set",
  290. );
  291. overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
  292. return Err(e)
  293. }
  294. // Apply producer transaction
  295. let public_key = apply_producer_transaction(
  296. overlay,
  297. block.header.height,
  298. block_target,
  299. block.txs.last().unwrap(),
  300. &mut tree,
  301. )
  302. .await?;
  303. // Verify transactions merkle tree root matches header one
  304. if tree.root(0).unwrap() != block.header.transactions_root {
  305. error!(target: "validator::verification::verify_checkpoint_block", "Block Merkle tree root is invalid");
  306. return Err(Error::BlockIsInvalid(block_hash.as_string()))
  307. }
  308. // Update the provided contracts states monotree and verify header contracts states root
  309. let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(diffs)?;
  310. overlay.lock().unwrap().contracts.update_state_monotree(&diff, state_monotree)?;
  311. let Some(state_root) = state_monotree.get_headroot()? else {
  312. return Err(Error::ContractsStatesRootNotFoundError);
  313. };
  314. if state_root != block.header.state_root {
  315. return Err(Error::ContractsStatesRootError(
  316. blake3::Hash::from_bytes(state_root).to_string(),
  317. blake3::Hash::from_bytes(block.header.state_root).to_string(),
  318. ));
  319. }
  320. // Verify producer signature
  321. verify_producer_signature(block, &public_key)?;
  322. // Insert block
  323. overlay.lock().unwrap().add_block(block)?;
  324. debug!(target: "validator::verification::verify_checkpoint_block", "Block {block_hash} verified successfully");
  325. Ok(())
  326. }
  327. /// Verify block proposer signature, using the producer transaction signature as signing key
  328. /// over blocks header hash.
  329. pub fn verify_producer_signature(block: &BlockInfo, public_key: &PublicKey) -> Result<()> {
  330. if !public_key.verify(block.header.hash().inner(), &block.signature) {
  331. warn!(target: "validator::verification::verify_producer_signature", "Proposer {public_key} signature could not be verified");
  332. return Err(Error::InvalidSignature)
  333. }
  334. Ok(())
  335. }
  336. /// Verify provided producer [`Transaction`].
  337. ///
  338. /// Verify WASM execution, signatures, and ZK proofs and apply it to the provided,
  339. /// provided overlay. Returns transaction signature public key. Additionally,
  340. /// append its hash to the provided Merkle tree.
  341. pub async fn verify_producer_transaction(
  342. overlay: &BlockchainOverlayPtr,
  343. verifying_block_height: u32,
  344. block_target: u32,
  345. tx: &Transaction,
  346. tree: &mut MerkleTree,
  347. ) -> Result<PublicKey> {
  348. let tx_hash = tx.hash();
  349. debug!(target: "validator::verification::verify_producer_transaction", "Validating producer transaction {tx_hash}");
  350. // Transaction must be a PoW reward one
  351. if !tx.is_pow_reward() {
  352. return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
  353. }
  354. // Retrieve first call from the transaction for further processing
  355. let call = &tx.calls[0];
  356. // Map of ZK proof verifying keys for the current transaction
  357. let mut verifying_keys: HashMap<[u8; 32], HashMap<String, VerifyingKey>> = HashMap::new();
  358. // Initialize the map
  359. verifying_keys.insert(call.data.contract_id.to_bytes(), HashMap::new());
  360. // Table of public inputs used for ZK proof verification
  361. let mut zkp_table = vec![];
  362. // Table of public keys used for signature verification
  363. let mut sig_table = vec![];
  364. debug!(target: "validator::verification::verify_producer_transaction", "Executing contract call");
  365. // Write the actual payload data
  366. let mut payload = vec![];
  367. tx.calls.encode_async(&mut payload).await?; // Actual call data
  368. debug!(target: "validator::verification::verify_producer_transaction", "Instantiating WASM runtime");
  369. let wasm = overlay.lock().unwrap().contracts.get(call.data.contract_id)?;
  370. let mut runtime = Runtime::new(
  371. &wasm,
  372. overlay.clone(),
  373. call.data.contract_id,
  374. verifying_block_height,
  375. block_target,
  376. tx_hash,
  377. // Call index in producer tx is 0
  378. 0,
  379. )?;
  380. debug!(target: "validator::verification::verify_producer_transaction", "Executing \"metadata\" call");
  381. let metadata = runtime.metadata(&payload)?;
  382. // Decode the metadata retrieved from the execution
  383. let mut decoder = Cursor::new(&metadata);
  384. // The tuple is (zkas_ns, public_inputs)
  385. let zkp_pub: Vec<(String, Vec<pallas::Base>)> =
  386. AsyncDecodable::decode_async(&mut decoder).await?;
  387. let sig_pub: Vec<PublicKey> = AsyncDecodable::decode_async(&mut decoder).await?;
  388. // Check that only one ZK proof and signature public key exist
  389. if zkp_pub.len() != 1 || sig_pub.len() != 1 {
  390. error!(target: "validator::verification::verify_producer_transaction", "Producer transaction contains multiple ZK proofs or signature public keys");
  391. return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
  392. }
  393. // TODO: Make sure we've read all the bytes above.
  394. debug!(target: "validator::verification::verify_producer_transaction", "Successfully executed \"metadata\" call");
  395. // Here we'll look up verifying keys and insert them into the map.
  396. debug!(target: "validator::verification::verify_producer_transaction", "Performing VerifyingKey lookups from the sled db");
  397. for (zkas_ns, _) in &zkp_pub {
  398. // TODO: verify this is correct behavior
  399. let inner_vk_map = verifying_keys.get_mut(&call.data.contract_id.to_bytes()).unwrap();
  400. if inner_vk_map.contains_key(zkas_ns.as_str()) {
  401. continue
  402. }
  403. let (_zkbin, vk) =
  404. overlay.lock().unwrap().contracts.get_zkas(&call.data.contract_id, zkas_ns)?;
  405. inner_vk_map.insert(zkas_ns.to_string(), vk);
  406. }
  407. zkp_table.push(zkp_pub);
  408. let signature_public_key = *sig_pub.last().unwrap();
  409. sig_table.push(sig_pub);
  410. // After getting the metadata, we run the "exec" function with the same runtime
  411. // and the same payload. We keep the returned state update in a buffer, prefixed
  412. // by the call function ID, enforcing the state update function in the contract.
  413. debug!(target: "validator::verification::verify_producer_transaction", "Executing \"exec\" call");
  414. let mut state_update = vec![call.data.data[0]];
  415. state_update.append(&mut runtime.exec(&payload)?);
  416. debug!(target: "validator::verification::verify_producer_transaction", "Successfully executed \"exec\" call");
  417. // If that was successful, we apply the state update in the ephemeral overlay.
  418. debug!(target: "validator::verification::verify_producer_transaction", "Executing \"apply\" call");
  419. runtime.apply(&state_update)?;
  420. debug!(target: "validator::verification::verify_producer_transaction", "Successfully executed \"apply\" call");
  421. // When we're done executing over the tx's contract call, we now move on with verification.
  422. // First we verify the signatures as that's cheaper, and then finally we verify the ZK proofs.
  423. debug!(target: "validator::verification::verify_producer_transaction", "Verifying signatures for transaction {tx_hash}");
  424. if sig_table.len() != tx.signatures.len() {
  425. error!(target: "validator::verification::verify_producer_transaction", "Incorrect number of signatures in tx {tx_hash}");
  426. return Err(TxVerifyFailed::MissingSignatures.into())
  427. }
  428. // TODO: Go through the ZK circuits that have to be verified and account for the opcodes.
  429. if let Err(e) = tx.verify_sigs(sig_table) {
  430. error!(target: "validator::verification::verify_producer_transaction", "Signature verification for tx {tx_hash} failed: {e}");
  431. return Err(TxVerifyFailed::InvalidSignature.into())
  432. }
  433. debug!(target: "validator::verification::verify_producer_transaction", "Signature verification successful");
  434. debug!(target: "validator::verification::verify_producer_transaction", "Verifying ZK proofs for transaction {tx_hash}");
  435. if let Err(e) = tx.verify_zkps(&verifying_keys, zkp_table).await {
  436. error!(target: "validator::verification::verify_producer_transaction", "ZK proof verification for tx {tx_hash} failed: {e}");
  437. return Err(TxVerifyFailed::InvalidZkProof.into())
  438. }
  439. debug!(target: "validator::verification::verify_producer_transaction", "ZK proof verification successful");
  440. // Append hash to merkle tree
  441. append_tx_to_merkle_tree(tree, tx);
  442. debug!(target: "validator::verification::verify_producer_transaction", "Producer transaction {tx_hash} verified successfully");
  443. Ok(signature_public_key)
  444. }
  445. /// Apply given producer [`Transaction`] to the provided overlay, without formal verification.
  446. /// Returns transaction signature public key. Additionally, append its hash to the provided Merkle tree.
  447. pub async fn apply_producer_transaction(
  448. overlay: &BlockchainOverlayPtr,
  449. verifying_block_height: u32,
  450. block_target: u32,
  451. tx: &Transaction,
  452. tree: &mut MerkleTree,
  453. ) -> Result<PublicKey> {
  454. let tx_hash = tx.hash();
  455. debug!(target: "validator::verification::apply_producer_transaction", "Applying producer transaction {tx_hash}");
  456. // Producer transactions must contain a single, non-empty call
  457. if !tx.is_single_call() {
  458. return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
  459. }
  460. debug!(target: "validator::verification::apply_producer_transaction", "Executing contract call");
  461. // Write the actual payload data
  462. let mut payload = vec![];
  463. tx.calls.encode_async(&mut payload).await?; // Actual call data
  464. debug!(target: "validator::verification::apply_producer_transaction", "Instantiating WASM runtime");
  465. let call = &tx.calls[0];
  466. let wasm = overlay.lock().unwrap().contracts.get(call.data.contract_id)?;
  467. let mut runtime = Runtime::new(
  468. &wasm,
  469. overlay.clone(),
  470. call.data.contract_id,
  471. verifying_block_height,
  472. block_target,
  473. tx_hash,
  474. // Call index in producer tx is 0
  475. 0,
  476. )?;
  477. debug!(target: "validator::verification::apply_producer_transaction", "Executing \"metadata\" call");
  478. let metadata = runtime.metadata(&payload)?;
  479. // Decode the metadata retrieved from the execution
  480. let mut decoder = Cursor::new(&metadata);
  481. // The tuple is (zkas_ns, public_inputs)
  482. let _: Vec<(String, Vec<pallas::Base>)> = AsyncDecodable::decode_async(&mut decoder).await?;
  483. let sig_pub: Vec<PublicKey> = AsyncDecodable::decode_async(&mut decoder).await?;
  484. // Check that only one ZK proof and signature public key exist
  485. if sig_pub.len() != 1 {
  486. error!(target: "validator::verification::apply_producer_transaction", "Producer transaction contains multiple ZK proofs or signature public keys");
  487. return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
  488. }
  489. let signature_public_key = *sig_pub.last().unwrap();
  490. // After getting the metadata, we run the "exec" function with the same runtime
  491. // and the same payload. We keep the returned state update in a buffer, prefixed
  492. // by the call function ID, enforcing the state update function in the contract.
  493. debug!(target: "validator::verification::apply_producer_transaction", "Executing \"exec\" call");
  494. let mut state_update = vec![call.data.data[0]];
  495. state_update.append(&mut runtime.exec(&payload)?);
  496. debug!(target: "validator::verification::apply_producer_transaction", "Successfully executed \"exec\" call");
  497. // If that was successful, we apply the state update in the ephemeral overlay.
  498. debug!(target: "validator::verification::apply_producer_transaction", "Executing \"apply\" call");
  499. runtime.apply(&state_update)?;
  500. debug!(target: "validator::verification::apply_producer_transaction", "Successfully executed \"apply\" call");
  501. // Append hash to merkle tree
  502. append_tx_to_merkle_tree(tree, tx);
  503. debug!(target: "validator::verification::apply_producer_transaction", "Producer transaction {tx_hash} executed successfully");
  504. Ok(signature_public_key)
  505. }
  506. /// Verify WASM execution, signatures, and ZK proofs for a given [`Transaction`],
  507. /// and apply it to the provided overlay. Additionally, append its hash to the
  508. /// provided Merkle tree.
  509. pub async fn verify_transaction(
  510. overlay: &BlockchainOverlayPtr,
  511. verifying_block_height: u32,
  512. block_target: u32,
  513. tx: &Transaction,
  514. tree: &mut MerkleTree,
  515. verifying_keys: &mut HashMap<[u8; 32], HashMap<String, VerifyingKey>>,
  516. verify_fee: bool,
  517. ) -> Result<GasData> {
  518. let tx_hash = tx.hash();
  519. debug!(target: "validator::verification::verify_transaction", "Validating transaction {tx_hash}");
  520. // Create a FeeData instance to hold the calculated fee data
  521. let mut gas_data = GasData::default();
  522. // Verify calls indexes integrity
  523. if verify_fee {
  524. dark_forest_leaf_vec_integrity_check(
  525. &tx.calls,
  526. Some(MIN_TX_CALLS + 1),
  527. Some(MAX_TX_CALLS),
  528. )?;
  529. } else {
  530. dark_forest_leaf_vec_integrity_check(&tx.calls, Some(MIN_TX_CALLS), Some(MAX_TX_CALLS))?;
  531. }
  532. // Table of public inputs used for ZK proof verification
  533. let mut zkp_table = vec![];
  534. // Table of public keys used for signature verification
  535. let mut sig_table = vec![];
  536. // Index of the Fee-paying call
  537. let mut fee_call_idx = 0;
  538. if verify_fee {
  539. // Verify that there is a single money fee call in the transaction
  540. let mut found_fee = false;
  541. for (call_idx, call) in tx.calls.iter().enumerate() {
  542. if !call.data.is_money_fee() {
  543. continue
  544. }
  545. if found_fee {
  546. error!(
  547. target: "validator::verification::verify_transcation",
  548. "[VALIDATOR] Transaction {tx_hash} contains multiple fee payment calls"
  549. );
  550. return Err(TxVerifyFailed::InvalidFee.into())
  551. }
  552. found_fee = true;
  553. fee_call_idx = call_idx;
  554. }
  555. if !found_fee {
  556. error!(
  557. target: "validator::verification::verify_transcation",
  558. "[VALIDATOR] Transaction {tx_hash} does not contain fee payment call"
  559. );
  560. return Err(TxVerifyFailed::InvalidFee.into())
  561. }
  562. }
  563. // Write the transaction calls payload data
  564. let mut payload = vec![];
  565. tx.calls.encode_async(&mut payload).await?;
  566. // Define a buffer in case we want to use a different payload in a specific call
  567. let mut _call_payload = vec![];
  568. // We'll also take note of all the circuits in a Vec so we can calculate their verification cost.
  569. let mut circuits_to_verify = vec![];
  570. // Iterate over all calls to get the metadata
  571. for (idx, call) in tx.calls.iter().enumerate() {
  572. debug!(target: "validator::verification::verify_transaction", "Executing contract call {idx}");
  573. // Transaction must not contain a Pow reward call
  574. if call.data.is_money_pow_reward() {
  575. error!(target: "validator::verification::verify_transaction", "Reward transaction detected");
  576. return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
  577. }
  578. // Check if its the fee call so we only pass its payload
  579. let (call_idx, call_payload) = if call.data.is_money_fee() {
  580. _call_payload = vec![];
  581. vec![call.clone()].encode_async(&mut _call_payload).await?;
  582. (0_u8, &_call_payload)
  583. } else {
  584. (idx as u8, &payload)
  585. };
  586. debug!(target: "validator::verification::verify_transaction", "Instantiating WASM runtime");
  587. let wasm = overlay.lock().unwrap().contracts.get(call.data.contract_id)?;
  588. let mut runtime = Runtime::new(
  589. &wasm,
  590. overlay.clone(),
  591. call.data.contract_id,
  592. verifying_block_height,
  593. block_target,
  594. tx_hash,
  595. call_idx,
  596. )?;
  597. debug!(target: "validator::verification::verify_transaction", "Executing \"metadata\" call");
  598. let metadata = runtime.metadata(call_payload)?;
  599. // Decode the metadata retrieved from the execution
  600. let mut decoder = Cursor::new(&metadata);
  601. // The tuple is (zkas_ns, public_inputs)
  602. let zkp_pub: Vec<(String, Vec<pallas::Base>)> =
  603. AsyncDecodable::decode_async(&mut decoder).await?;
  604. let sig_pub: Vec<PublicKey> = AsyncDecodable::decode_async(&mut decoder).await?;
  605. if decoder.position() != metadata.len() as u64 {
  606. error!(
  607. target: "validator::verification::verify_transaction",
  608. "[VALIDATOR] Failed decoding entire metadata buffer for {tx_hash}:{idx}"
  609. );
  610. return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
  611. }
  612. debug!(target: "validator::verification::verify_transaction", "Successfully executed \"metadata\" call");
  613. // Here we'll look up verifying keys and insert them into the per-contract map.
  614. // TODO: This vk map can potentially use a lot of RAM. Perhaps load keys on-demand at verification time?
  615. debug!(target: "validator::verification::verify_transaction", "Performing VerifyingKey lookups from the sled db");
  616. for (zkas_ns, _) in &zkp_pub {
  617. let inner_vk_map = verifying_keys.get_mut(&call.data.contract_id.to_bytes()).unwrap();
  618. // TODO: This will be a problem in case of ::deploy, unless we force a different
  619. // namespace and disable updating existing circuit. Might be a smart idea to do
  620. // so in order to have to care less about being able to verify historical txs.
  621. if inner_vk_map.contains_key(zkas_ns.as_str()) {
  622. continue
  623. }
  624. let (zkbin, vk) =
  625. overlay.lock().unwrap().contracts.get_zkas(&call.data.contract_id, zkas_ns)?;
  626. inner_vk_map.insert(zkas_ns.to_string(), vk);
  627. circuits_to_verify.push(zkbin);
  628. }
  629. zkp_table.push(zkp_pub);
  630. sig_table.push(sig_pub);
  631. // After getting the metadata, we run the "exec" function with the same runtime
  632. // and the same payload. We keep the returned state update in a buffer, prefixed
  633. // by the call function ID, enforcing the state update function in the contract.
  634. debug!(target: "validator::verification::verify_transaction", "Executing \"exec\" call");
  635. let mut state_update = vec![call.data.data[0]];
  636. state_update.append(&mut runtime.exec(call_payload)?);
  637. debug!(target: "validator::verification::verify_transaction", "Successfully executed \"exec\" call");
  638. // If that was successful, we apply the state update in the ephemeral overlay.
  639. debug!(target: "validator::verification::verify_transaction", "Executing \"apply\" call");
  640. runtime.apply(&state_update)?;
  641. debug!(target: "validator::verification::verify_transaction", "Successfully executed \"apply\" call");
  642. // If this call is supposed to deploy a new contract, we have to instantiate
  643. // a new `Runtime` and run its deploy function.
  644. if call.data.is_deployment()
  645. /* DeployV1 */
  646. {
  647. debug!(target: "validator::verification::verify_transaction", "Deploying new contract");
  648. // Deserialize the deployment parameters
  649. let deploy_params: DeployParamsV1 = deserialize_async(&call.data.data[1..]).await?;
  650. let deploy_cid = ContractId::derive_public(deploy_params.public_key);
  651. // Instantiate the new deployment runtime
  652. let mut deploy_runtime = Runtime::new(
  653. &deploy_params.wasm_bincode,
  654. overlay.clone(),
  655. deploy_cid,
  656. verifying_block_height,
  657. block_target,
  658. tx_hash,
  659. call_idx,
  660. )?;
  661. deploy_runtime.deploy(&deploy_params.ix)?;
  662. let deploy_gas_used = deploy_runtime.gas_used();
  663. debug!(target: "validator::verification::verify_transaction", "The gas used for deployment call {call:?} of transaction {tx_hash}: {deploy_gas_used}");
  664. gas_data.deployments += deploy_gas_used;
  665. }
  666. // At this point we're done with the call and move on to the next one.
  667. // Accumulate the WASM gas used.
  668. let wasm_gas_used = runtime.gas_used();
  669. debug!(target: "validator::verification::verify_transaction", "The gas used for WASM call {call:?} of transaction {tx_hash}: {wasm_gas_used}");
  670. // Append the used wasm gas
  671. gas_data.wasm += wasm_gas_used;
  672. }
  673. // The signature fee is tx_size + fixed_sig_fee * n_signatures
  674. gas_data.signatures = (PALLAS_SCHNORR_SIGNATURE_FEE * tx.signatures.len() as u64) +
  675. serialize_async(tx).await.len() as u64;
  676. debug!(target: "validator::verification::verify_transaction", "The gas used for signature of transaction {tx_hash}: {}", gas_data.signatures);
  677. // The ZK circuit fee is calculated using a function in validator/fees.rs
  678. for zkbin in circuits_to_verify.iter() {
  679. let zk_circuit_gas_used = circuit_gas_use(zkbin);
  680. debug!(target: "validator::verification::verify_transaction", "The gas used for ZK circuit in namespace {} of transaction {tx_hash}: {zk_circuit_gas_used}", zkbin.namespace);
  681. // Append the used zk circuit gas
  682. gas_data.zk_circuits += zk_circuit_gas_used;
  683. }
  684. // Store the calculated total gas used to avoid recalculating it for subsequent uses
  685. let total_gas_used = gas_data.total_gas_used();
  686. if verify_fee {
  687. // Deserialize the fee call to find the paid fee
  688. let fee: u64 = match deserialize_async(&tx.calls[fee_call_idx].data.data[1..9]).await {
  689. Ok(v) => v,
  690. Err(e) => {
  691. error!(
  692. target: "validator::verification::verify_transaction",
  693. "[VALIDATOR] Failed deserializing tx {tx_hash} fee call: {e}"
  694. );
  695. return Err(TxVerifyFailed::InvalidFee.into())
  696. }
  697. };
  698. // Compute the required fee for this transaction
  699. let required_fee = compute_fee(&total_gas_used);
  700. // Check that enough fee has been paid for the used gas in this transaction
  701. if required_fee > fee {
  702. error!(
  703. target: "validator::verification::verify_transaction",
  704. "[VALIDATOR] Transaction {tx_hash} has insufficient fee. Required: {required_fee}, Paid: {fee}"
  705. );
  706. return Err(TxVerifyFailed::InsufficientFee.into())
  707. }
  708. debug!(target: "validator::verification::verify_transaction", "The gas paid for transaction {tx_hash}: {}", gas_data.paid);
  709. // Store paid fee
  710. gas_data.paid = fee;
  711. }
  712. // When we're done looping and executing over the tx's contract calls and
  713. // (optionally) made sure that enough fee was paid, we now move on with
  714. // verification. First we verify the transaction signatures and then we
  715. // verify any accompanying ZK proofs.
  716. debug!(target: "validator::verification::verify_transaction", "Verifying signatures for transaction {tx_hash}");
  717. if sig_table.len() != tx.signatures.len() {
  718. error!(
  719. target: "validator::verification::verify_transaction",
  720. "[VALIDATOR] Incorrect number of signatures in tx {tx_hash}"
  721. );
  722. return Err(TxVerifyFailed::MissingSignatures.into())
  723. }
  724. if let Err(e) = tx.verify_sigs(sig_table) {
  725. error!(
  726. target: "validator::verification::verify_transaction",
  727. "[VALIDATOR] Signature verification for tx {tx_hash} failed: {e}"
  728. );
  729. return Err(TxVerifyFailed::InvalidSignature.into())
  730. }
  731. debug!(target: "validator::verification::verify_transaction", "Signature verification successful");
  732. debug!(target: "validator::verification::verify_transaction", "Verifying ZK proofs for transaction {tx_hash}");
  733. if let Err(e) = tx.verify_zkps(verifying_keys, zkp_table).await {
  734. error!(
  735. target: "validator::verification::verify_transaction",
  736. "[VALIDATOR] ZK proof verification for tx {tx_hash} failed: {e}"
  737. );
  738. return Err(TxVerifyFailed::InvalidZkProof.into())
  739. }
  740. debug!(target: "validator::verification::verify_transaction", "ZK proof verification successful");
  741. // Append hash to merkle tree
  742. append_tx_to_merkle_tree(tree, tx);
  743. debug!(target: "validator::verification::verify_transaction", "The total gas used for transaction {tx_hash}: {total_gas_used}");
  744. debug!(target: "validator::verification::verify_transaction", "Transaction {tx_hash} verified successfully");
  745. Ok(gas_data)
  746. }
  747. /// Apply given [`Transaction`] to the provided overlay.
  748. /// Additionally, append its hash to the provided Merkle tree.
  749. pub async fn apply_transaction(
  750. overlay: &BlockchainOverlayPtr,
  751. verifying_block_height: u32,
  752. block_target: u32,
  753. tx: &Transaction,
  754. tree: &mut MerkleTree,
  755. ) -> Result<()> {
  756. let tx_hash = tx.hash();
  757. debug!(target: "validator::verification::apply_transaction", "Applying transaction {tx_hash}");
  758. // Write the transaction calls payload data
  759. let mut payload = vec![];
  760. tx.calls.encode_async(&mut payload).await?;
  761. // Iterate over all calls to get the metadata
  762. for (idx, call) in tx.calls.iter().enumerate() {
  763. debug!(target: "validator::verification::apply_transaction", "Executing contract call {idx}");
  764. debug!(target: "validator::verification::apply_transaction", "Instantiating WASM runtime");
  765. let wasm = overlay.lock().unwrap().contracts.get(call.data.contract_id)?;
  766. let mut runtime = Runtime::new(
  767. &wasm,
  768. overlay.clone(),
  769. call.data.contract_id,
  770. verifying_block_height,
  771. block_target,
  772. tx_hash,
  773. idx as u8,
  774. )?;
  775. // Run the "exec" function. We keep the returned state update in a buffer, prefixed
  776. // by the call function ID, enforcing the state update function in the contract.
  777. debug!(target: "validator::verification::apply_transaction", "Executing \"exec\" call");
  778. let mut state_update = vec![call.data.data[0]];
  779. state_update.append(&mut runtime.exec(&payload)?);
  780. debug!(target: "validator::verification::apply_transaction", "Successfully executed \"exec\" call");
  781. // If that was successful, we apply the state update in the ephemeral overlay
  782. debug!(target: "validator::verification::apply_transaction", "Executing \"apply\" call");
  783. runtime.apply(&state_update)?;
  784. debug!(target: "validator::verification::apply_transaction", "Successfully executed \"apply\" call");
  785. // If this call is supposed to deploy a new contract, we have to instantiate
  786. // a new `Runtime` and run its deploy function.
  787. if call.data.is_deployment()
  788. /* DeployV1 */
  789. {
  790. debug!(target: "validator::verification::apply_transaction", "Deploying new contract");
  791. // Deserialize the deployment parameters
  792. let deploy_params: DeployParamsV1 = deserialize_async(&call.data.data[1..]).await?;
  793. let deploy_cid = ContractId::derive_public(deploy_params.public_key);
  794. // Instantiate the new deployment runtime
  795. let mut deploy_runtime = Runtime::new(
  796. &deploy_params.wasm_bincode,
  797. overlay.clone(),
  798. deploy_cid,
  799. verifying_block_height,
  800. block_target,
  801. tx_hash,
  802. idx as u8,
  803. )?;
  804. deploy_runtime.deploy(&deploy_params.ix)?;
  805. }
  806. }
  807. // Append hash to merkle tree
  808. append_tx_to_merkle_tree(tree, tx);
  809. debug!(target: "validator::verification::apply_transaction", "Transaction {tx_hash} applied successfully");
  810. Ok(())
  811. }
  812. /// Verify a set of [`Transaction`] in sequence and apply them if all are valid.
  813. ///
  814. /// In case any of the transactions fail, they will be returned to the caller as an error.
  815. /// If all transactions are valid, the function will return the total gas used and total
  816. /// paid fees from all the transactions. Additionally, their hash is appended to the provided
  817. /// Merkle tree.
  818. pub async fn verify_transactions(
  819. overlay: &BlockchainOverlayPtr,
  820. verifying_block_height: u32,
  821. block_target: u32,
  822. txs: &[Transaction],
  823. tree: &mut MerkleTree,
  824. verify_fees: bool,
  825. ) -> Result<(u64, u64)> {
  826. debug!(target: "validator::verification::verify_transactions", "Verifying {} transactions", txs.len());
  827. if txs.is_empty() {
  828. return Ok((0, 0))
  829. }
  830. // Tracker for failed txs
  831. let mut erroneous_txs = vec![];
  832. // Total gas accumulators
  833. let mut total_gas_used = 0;
  834. let mut total_gas_paid = 0;
  835. // Map of ZK proof verifying keys for the current transaction batch
  836. let mut vks: HashMap<[u8; 32], HashMap<String, VerifyingKey>> = HashMap::new();
  837. // Initialize the map
  838. for tx in txs {
  839. for call in &tx.calls {
  840. vks.insert(call.data.contract_id.to_bytes(), HashMap::new());
  841. }
  842. }
  843. // Iterate over transactions and attempt to verify them
  844. for tx in txs {
  845. overlay.lock().unwrap().checkpoint();
  846. let gas_data = match verify_transaction(
  847. overlay,
  848. verifying_block_height,
  849. block_target,
  850. tx,
  851. tree,
  852. &mut vks,
  853. verify_fees,
  854. )
  855. .await
  856. {
  857. Ok(gas_values) => gas_values,
  858. Err(e) => {
  859. warn!(target: "validator::verification::verify_transactions", "Transaction verification failed: {e}");
  860. erroneous_txs.push(tx.clone());
  861. overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
  862. overlay.lock().unwrap().revert_to_checkpoint()?;
  863. continue
  864. }
  865. };
  866. // Store the gas used by the verified transaction
  867. let tx_gas_used = gas_data.total_gas_used();
  868. // Calculate current accumulated gas usage
  869. let accumulated_gas_usage = total_gas_used + tx_gas_used;
  870. // Check gas limit - if accumulated gas used exceeds it, break out of loop
  871. if accumulated_gas_usage > BLOCK_GAS_LIMIT {
  872. warn!(
  873. target: "validator::verification::verify_transactions",
  874. "Transaction {} exceeds configured transaction gas limit: {accumulated_gas_usage} - {BLOCK_GAS_LIMIT}",
  875. tx.hash()
  876. );
  877. erroneous_txs.push(tx.clone());
  878. overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
  879. overlay.lock().unwrap().revert_to_checkpoint()?;
  880. break
  881. }
  882. // Update accumulated total gas
  883. total_gas_used += tx_gas_used;
  884. total_gas_paid += gas_data.paid;
  885. }
  886. if !erroneous_txs.is_empty() {
  887. return Err(TxVerifyFailed::ErroneousTxs(erroneous_txs).into())
  888. }
  889. Ok((total_gas_used, total_gas_paid))
  890. }
  891. /// Apply given set of [`Transaction`] in sequence, without formal verification.
  892. /// In case any of the transactions fail, they will be returned to the caller as an error.
  893. /// Additionally, their hash is appended to the provided Merkle tree.
  894. async fn apply_transactions(
  895. overlay: &BlockchainOverlayPtr,
  896. verifying_block_height: u32,
  897. block_target: u32,
  898. txs: &[Transaction],
  899. tree: &mut MerkleTree,
  900. ) -> Result<()> {
  901. debug!(target: "validator::verification::apply_transactions", "Applying {} transactions", txs.len());
  902. if txs.is_empty() {
  903. return Ok(())
  904. }
  905. // Tracker for failed txs
  906. let mut erroneous_txs = vec![];
  907. // Iterate over transactions and attempt to apply them
  908. for tx in txs {
  909. overlay.lock().unwrap().checkpoint();
  910. if let Err(e) =
  911. apply_transaction(overlay, verifying_block_height, block_target, tx, tree).await
  912. {
  913. warn!(target: "validator::verification::apply_transactions", "Transaction apply failed: {e}");
  914. erroneous_txs.push(tx.clone());
  915. overlay.lock().unwrap().revert_to_checkpoint()?;
  916. };
  917. }
  918. if !erroneous_txs.is_empty() {
  919. return Err(TxVerifyFailed::ErroneousTxs(erroneous_txs).into())
  920. }
  921. Ok(())
  922. }
  923. /// Verify given [`Proposal`] against provided consensus state.
  924. ///
  925. /// A proposal is considered valid when the following rules apply:
  926. /// 1. Proposal hash matches the actual block one
  927. /// 2. Block is valid
  928. /// Additional validity rules can be applied.
  929. pub async fn verify_proposal(
  930. consensus: &Consensus,
  931. proposal: &Proposal,
  932. verify_fees: bool,
  933. ) -> Result<(Fork, Option<usize>)> {
  934. // Check if proposal hash matches actual one (1)
  935. let proposal_hash = proposal.block.hash();
  936. if proposal.hash != proposal_hash {
  937. warn!(
  938. target: "validator::verification::verify_proposal", "Received proposal contains mismatched hashes: {} - {proposal_hash}",
  939. proposal.hash
  940. );
  941. return Err(Error::ProposalHashesMissmatchError)
  942. }
  943. // Check if proposal extends any existing forks
  944. let (mut fork, index) = consensus.find_extended_fork(proposal).await?;
  945. // Grab overlay last block
  946. let previous = fork.overlay.lock().unwrap().last_block()?;
  947. // Verify proposal block (2)
  948. if let Err(e) = verify_block(
  949. &fork.overlay,
  950. &fork.diffs,
  951. &fork.module,
  952. &mut fork.state_monotree,
  953. &proposal.block,
  954. &previous,
  955. verify_fees,
  956. )
  957. .await
  958. {
  959. error!(target: "validator::verification::verify_proposal", "Erroneous proposal block found: {e}");
  960. fork.overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
  961. return Err(Error::BlockIsInvalid(proposal.hash.as_string()))
  962. };
  963. Ok((fork, index))
  964. }
  965. /// Verify given [`Proposal`] against provided fork state.
  966. ///
  967. /// A proposal is considered valid when the following rules apply:
  968. /// 1. Proposal hash matches the actual block one
  969. /// 2. Block is valid
  970. /// Additional validity rules can be applied.
  971. pub async fn verify_fork_proposal(
  972. fork: &mut Fork,
  973. proposal: &Proposal,
  974. verify_fees: bool,
  975. ) -> Result<()> {
  976. // Check if proposal hash matches actual one (1)
  977. let proposal_hash = proposal.block.hash();
  978. if proposal.hash != proposal_hash {
  979. warn!(
  980. target: "validator::verification::verify_fork_proposal", "Received proposal contains mismatched hashes: {} - {proposal_hash}",
  981. proposal.hash
  982. );
  983. return Err(Error::ProposalHashesMissmatchError)
  984. }
  985. // Grab overlay last block
  986. let previous = fork.overlay.lock().unwrap().last_block()?;
  987. // Verify proposal block (2)
  988. if let Err(e) = verify_block(
  989. &fork.overlay,
  990. &fork.diffs,
  991. &fork.module,
  992. &mut fork.state_monotree,
  993. &proposal.block,
  994. &previous,
  995. verify_fees,
  996. )
  997. .await
  998. {
  999. error!(target: "validator::verification::verify_fork_proposal", "Erroneous proposal block found: {e}");
  1000. fork.overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
  1001. return Err(Error::BlockIsInvalid(proposal.hash.as_string()))
  1002. };
  1003. Ok(())
  1004. }