verification.rs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2024 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, ContractId, MerkleTree, PublicKey, DEPLOYOOOR_CONTRACT_ID,
  23. MONEY_CONTRACT_ID,
  24. },
  25. dark_tree::dark_forest_leaf_vec_integrity_check,
  26. deploy::DeployParamsV1,
  27. pasta::pallas,
  28. };
  29. use darkfi_serial::{deserialize_async, serialize_async, AsyncDecodable, AsyncEncodable};
  30. use log::{debug, error, warn};
  31. use num_bigint::BigUint;
  32. use smol::io::Cursor;
  33. use crate::{
  34. blockchain::{
  35. block_store::append_tx_to_merkle_tree, BlockInfo, Blockchain, BlockchainOverlayPtr,
  36. },
  37. error::TxVerifyFailed,
  38. runtime::vm_runtime::Runtime,
  39. tx::{Transaction, MAX_TX_CALLS, MIN_TX_CALLS},
  40. validator::{
  41. consensus::{Consensus, Fork, Proposal, TXS_CAP},
  42. fees::{circuit_gas_use, PALLAS_SCHNORR_SIGNATURE_FEE},
  43. pow::PoWModule,
  44. },
  45. zk::VerifyingKey,
  46. Error, Result,
  47. };
  48. /// Verify given genesis [`BlockInfo`], and apply it to the provided overlay
  49. pub async fn verify_genesis_block(overlay: &BlockchainOverlayPtr, block: &BlockInfo) -> Result<()> {
  50. let block_hash = block.hash().as_string();
  51. debug!(target: "validator::verification::verify_genesis_block", "Validating genesis block {}", block_hash);
  52. // Check if block already exists
  53. if overlay.lock().unwrap().has_block(block)? {
  54. return Err(Error::BlockAlreadyExists(block_hash))
  55. }
  56. // Block height must be 0
  57. if block.header.height != 0 {
  58. return Err(Error::BlockIsInvalid(block_hash))
  59. }
  60. // Block version must be correct
  61. if block.header.version != block_version(block.header.height) {
  62. return Err(Error::BlockIsInvalid(block_hash))
  63. }
  64. // Verify transactions vector contains at least one(producers) transaction
  65. if block.txs.is_empty() {
  66. return Err(Error::BlockContainsNoTransactions(block_hash))
  67. }
  68. // Genesis producer transaction must be the Transaction::default() one(empty)
  69. let producer_tx = block.txs.last().unwrap();
  70. if producer_tx != &Transaction::default() {
  71. error!(target: "validator::verification::verify_genesis_block", "Genesis producer transaction is not default one");
  72. return Err(TxVerifyFailed::ErroneousTxs(vec![producer_tx.clone()]).into())
  73. }
  74. // Verify transactions, exluding producer(last) one
  75. let mut tree = MerkleTree::new(1);
  76. let txs = &block.txs[..block.txs.len() - 1];
  77. if let Err(e) = verify_transactions(overlay, block.header.height, txs, &mut tree, false).await {
  78. warn!(
  79. target: "validator::verification::verify_genesis_block",
  80. "[VALIDATOR] Erroneous transactions found in set",
  81. );
  82. overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
  83. return Err(e)
  84. }
  85. // Append producer transaction to the tree and check tree matches header one
  86. append_tx_to_merkle_tree(&mut tree, producer_tx);
  87. if tree.root(0).unwrap() != block.header.root {
  88. error!(target: "validator::verification::verify_genesis_block", "Genesis Merkle tree is invalid");
  89. return Err(Error::BlockIsInvalid(block_hash))
  90. }
  91. // Insert block
  92. overlay.lock().unwrap().add_block(block)?;
  93. debug!(target: "validator::verification::verify_genesis_block", "Genesis block {} verified successfully", block_hash);
  94. Ok(())
  95. }
  96. /// A block is considered valid when the following rules apply:
  97. /// 1. Block version is correct for its height
  98. /// 2. Parent hash is equal to the hash of the previous block
  99. /// 3. Block height increments previous block height by 1
  100. /// 4. Timestamp is valid based on PoWModule validation
  101. /// 5. Block hash is valid based on PoWModule validation
  102. /// Additional validity rules can be applied.
  103. pub fn validate_block(block: &BlockInfo, previous: &BlockInfo, module: &PoWModule) -> Result<()> {
  104. // Check block version (1)
  105. if block.header.version != block_version(block.header.height) {
  106. return Err(Error::BlockIsInvalid(block.hash().as_string()))
  107. }
  108. // Check previous hash (2)
  109. if block.header.previous != previous.hash() {
  110. return Err(Error::BlockIsInvalid(block.hash().as_string()))
  111. }
  112. // Check heights are incremental (3)
  113. if block.header.height != previous.header.height + 1 {
  114. return Err(Error::BlockIsInvalid(block.hash().as_string()))
  115. }
  116. // Check timestamp validity (4)
  117. if !module.verify_timestamp_by_median(block.header.timestamp) {
  118. return Err(Error::BlockIsInvalid(block.hash().as_string()))
  119. }
  120. // Check block hash corresponds to next one (5)
  121. module.verify_block_hash(block)?;
  122. Ok(())
  123. }
  124. /// A blockchain is considered valid, when every block is valid,
  125. /// based on validate_block checks.
  126. /// Be careful as this will try to load everything in memory.
  127. pub fn validate_blockchain(
  128. blockchain: &Blockchain,
  129. pow_target: usize,
  130. pow_fixed_difficulty: Option<BigUint>,
  131. ) -> Result<()> {
  132. // Generate a PoW module
  133. let mut module = PoWModule::new(blockchain.clone(), pow_target, pow_fixed_difficulty)?;
  134. // We use block order store here so we have all blocks in order
  135. let blocks = blockchain.blocks.get_all_order()?;
  136. for (index, block) in blocks[1..].iter().enumerate() {
  137. let full_blocks = blockchain.get_blocks_by_hash(&[blocks[index].1, block.1])?;
  138. let full_block = &full_blocks[1];
  139. validate_block(full_block, &full_blocks[0], &module)?;
  140. // Update PoW module
  141. module.append(full_block.header.timestamp, &module.next_difficulty()?);
  142. }
  143. Ok(())
  144. }
  145. /// Verify given [`BlockInfo`], and apply it to the provided overlay
  146. pub async fn verify_block(
  147. overlay: &BlockchainOverlayPtr,
  148. module: &PoWModule,
  149. block: &BlockInfo,
  150. previous: &BlockInfo,
  151. ) -> Result<()> {
  152. let block_hash = block.hash();
  153. debug!(target: "validator::verification::verify_block", "Validating block {}", block_hash);
  154. // Check if block already exists
  155. if overlay.lock().unwrap().has_block(block)? {
  156. return Err(Error::BlockAlreadyExists(block_hash.as_string()))
  157. }
  158. // Validate block, using its previous
  159. validate_block(block, previous, module)?;
  160. // Verify transactions vector contains at least one(producers) transaction
  161. if block.txs.is_empty() {
  162. return Err(Error::BlockContainsNoTransactions(block_hash.as_string()))
  163. }
  164. // Verify transactions, exluding producer(last) one
  165. let mut tree = MerkleTree::new(1);
  166. let txs = &block.txs[..block.txs.len() - 1];
  167. let e = verify_transactions(overlay, block.header.height, txs, &mut tree, false).await;
  168. if let Err(e) = e {
  169. warn!(
  170. target: "validator::verification::verify_block",
  171. "[VALIDATOR] Erroneous transactions found in set",
  172. );
  173. overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
  174. return Err(e)
  175. }
  176. // Verify producer transaction
  177. let public_key = verify_producer_transaction(
  178. overlay,
  179. block.header.height,
  180. block.txs.last().unwrap(),
  181. &mut tree,
  182. )
  183. .await?;
  184. // Verify transactions merkle tree root matches header one
  185. if tree.root(0).unwrap() != block.header.root {
  186. error!(target: "validator::verification::verify_block", "Block Merkle tree root is invalid");
  187. return Err(Error::BlockIsInvalid(block_hash.as_string()))
  188. }
  189. // Verify producer signature
  190. verify_producer_signature(block, &public_key)?;
  191. // Insert block
  192. overlay.lock().unwrap().add_block(block)?;
  193. debug!(target: "validator::verification::verify_block", "Block {} verified successfully", block_hash);
  194. Ok(())
  195. }
  196. /// Verify block proposer signature, using the proposal transaction signature as signing key
  197. /// over blocks header hash.
  198. pub fn verify_producer_signature(block: &BlockInfo, public_key: &PublicKey) -> Result<()> {
  199. if !public_key.verify(block.header.hash().inner(), &block.signature) {
  200. warn!(target: "validator::verification::verify_producer_signature", "Proposer {} signature could not be verified", public_key);
  201. return Err(Error::InvalidSignature)
  202. }
  203. Ok(())
  204. }
  205. /// Verify WASM execution, signatures, and ZK proofs for a given producer [`Transaction`],
  206. /// and apply it to the provided overlay. Returns transaction signature public key.
  207. /// Additionally, append its hash to the provided Merkle tree.
  208. pub async fn verify_producer_transaction(
  209. overlay: &BlockchainOverlayPtr,
  210. verifying_block_height: u32,
  211. tx: &Transaction,
  212. tree: &mut MerkleTree,
  213. ) -> Result<PublicKey> {
  214. let tx_hash = tx.hash();
  215. debug!(target: "validator::verification::verify_producer_transaction", "Validating proposal transaction {}", tx_hash);
  216. // Producer transactions must contain a single, non-empty call
  217. if tx.calls.len() != 1 || tx.calls[0].data.data.is_empty() {
  218. return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
  219. }
  220. // Verify call based on version
  221. let call = &tx.calls[0];
  222. // Block must contain a Money::PoWReward(0x06) call
  223. if call.data.contract_id != *MONEY_CONTRACT_ID || call.data.data[0] != 0x06 {
  224. return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
  225. }
  226. // Map of ZK proof verifying keys for the current transaction
  227. let mut verifying_keys: HashMap<[u8; 32], HashMap<String, VerifyingKey>> = HashMap::new();
  228. // Initialize the map
  229. verifying_keys.insert(call.data.contract_id.to_bytes(), HashMap::new());
  230. // Table of public inputs used for ZK proof verification
  231. let mut zkp_table = vec![];
  232. // Table of public keys used for signature verification
  233. let mut sig_table = vec![];
  234. debug!(target: "validator::verification::verify_producer_transaction", "Executing contract call");
  235. // Write the actual payload data
  236. let mut payload = vec![];
  237. tx.calls.encode_async(&mut payload).await?; // Actual call data
  238. debug!(target: "validator::verification::verify_producer_transaction", "Instantiating WASM runtime");
  239. let wasm = overlay.lock().unwrap().contracts.get(call.data.contract_id)?;
  240. let mut runtime = Runtime::new(
  241. &wasm,
  242. overlay.clone(),
  243. call.data.contract_id,
  244. verifying_block_height,
  245. tx_hash,
  246. // Call index in producer tx is 0
  247. 0,
  248. )?;
  249. debug!(target: "validator::verification::verify_producer_transaction", "Executing \"metadata\" call");
  250. let metadata = runtime.metadata(&payload)?;
  251. // Decode the metadata retrieved from the execution
  252. let mut decoder = Cursor::new(&metadata);
  253. // The tuple is (zkas_ns, public_inputs)
  254. let zkp_pub: Vec<(String, Vec<pallas::Base>)> =
  255. AsyncDecodable::decode_async(&mut decoder).await?;
  256. let sig_pub: Vec<PublicKey> = AsyncDecodable::decode_async(&mut decoder).await?;
  257. // Check that only one ZK proof and signature public key exist
  258. if zkp_pub.len() != 1 || sig_pub.len() != 1 {
  259. error!(target: "validator::verification::verify_producer_transaction", "Proposal contains multiple ZK proofs or signature public keys");
  260. return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
  261. }
  262. // TODO: Make sure we've read all the bytes above.
  263. debug!(target: "validator::verification::verify_producer_transaction", "Successfully executed \"metadata\" call");
  264. // Here we'll look up verifying keys and insert them into the map.
  265. debug!(target: "validator::verification::verify_producer_transaction", "Performing VerifyingKey lookups from the sled db");
  266. for (zkas_ns, _) in &zkp_pub {
  267. // TODO: verify this is correct behavior
  268. let inner_vk_map = verifying_keys.get_mut(&call.data.contract_id.to_bytes()).unwrap();
  269. if inner_vk_map.contains_key(zkas_ns.as_str()) {
  270. continue
  271. }
  272. let (_zkbin, vk) =
  273. overlay.lock().unwrap().contracts.get_zkas(&call.data.contract_id, zkas_ns)?;
  274. inner_vk_map.insert(zkas_ns.to_string(), vk);
  275. }
  276. zkp_table.push(zkp_pub);
  277. let signature_public_key = *sig_pub.last().unwrap();
  278. sig_table.push(sig_pub);
  279. // After getting the metadata, we run the "exec" function with the same runtime
  280. // and the same payload.
  281. debug!(target: "validator::verification::verify_producer_transaction", "Executing \"exec\" call");
  282. let state_update = runtime.exec(&payload)?;
  283. debug!(target: "validator::verification::verify_producer_transaction", "Successfully executed \"exec\" call");
  284. // If that was successful, we apply the state update in the ephemeral overlay.
  285. debug!(target: "validator::verification::verify_producer_transaction", "Executing \"apply\" call");
  286. runtime.apply(&state_update)?;
  287. debug!(target: "validator::verification::verify_producer_transaction", "Successfully executed \"apply\" call");
  288. // When we're done executing over the tx's contract call, we now move on with verification.
  289. // First we verify the signatures as that's cheaper, and then finally we verify the ZK proofs.
  290. debug!(target: "validator::verification::verify_producer_transaction", "Verifying signatures for transaction {}", tx_hash);
  291. if sig_table.len() != tx.signatures.len() {
  292. error!(target: "validator::verification::verify_producer_transaction", "Incorrect number of signatures in tx {}", tx_hash);
  293. return Err(TxVerifyFailed::MissingSignatures.into())
  294. }
  295. // TODO: Go through the ZK circuits that have to be verified and account for the opcodes.
  296. if let Err(e) = tx.verify_sigs(sig_table) {
  297. error!(target: "validator::verification::verify_producer_transaction", "Signature verification for tx {} failed: {}", tx_hash, e);
  298. return Err(TxVerifyFailed::InvalidSignature.into())
  299. }
  300. debug!(target: "validator::verification::verify_producer_transaction", "Signature verification successful");
  301. debug!(target: "validator::verification::verify_producer_transaction", "Verifying ZK proofs for transaction {}", tx_hash);
  302. if let Err(e) = tx.verify_zkps(&verifying_keys, zkp_table).await {
  303. error!(target: "validator::verification::verify_proposal_transaction", "ZK proof verification for tx {} failed: {}", tx_hash, e);
  304. return Err(TxVerifyFailed::InvalidZkProof.into())
  305. }
  306. debug!(target: "validator::verification::verify_producer_transaction", "ZK proof verification successful");
  307. // Append hash to merkle tree
  308. append_tx_to_merkle_tree(tree, tx);
  309. debug!(target: "validator::verification::verify_producer_transaction", "Proposal transaction {} verified successfully", tx_hash);
  310. Ok(signature_public_key)
  311. }
  312. /// Verify WASM execution, signatures, and ZK proofs for a given [`Transaction`],
  313. /// and apply it to the provided overlay. Additionally, append its hash to the
  314. /// provided Merkle tree.
  315. pub async fn verify_transaction(
  316. overlay: &BlockchainOverlayPtr,
  317. verifying_block_height: u32,
  318. tx: &Transaction,
  319. tree: &mut MerkleTree,
  320. verifying_keys: &mut HashMap<[u8; 32], HashMap<String, VerifyingKey>>,
  321. verify_fee: bool,
  322. ) -> Result<u64> {
  323. let tx_hash = tx.hash();
  324. debug!(target: "validator::verification::verify_transaction", "Validating transaction {}", tx_hash);
  325. // Gas accumulator
  326. let mut gas_used = 0;
  327. // Verify calls indexes integrity
  328. if verify_fee {
  329. dark_forest_leaf_vec_integrity_check(
  330. &tx.calls,
  331. Some(MIN_TX_CALLS + 1),
  332. Some(MAX_TX_CALLS),
  333. )?;
  334. } else {
  335. dark_forest_leaf_vec_integrity_check(&tx.calls, Some(MIN_TX_CALLS), Some(MAX_TX_CALLS))?;
  336. }
  337. // Table of public inputs used for ZK proof verification
  338. let mut zkp_table = vec![];
  339. // Table of public keys used for signature verification
  340. let mut sig_table = vec![];
  341. // Index of the Fee-paying call
  342. let mut fee_call_idx = 0;
  343. if verify_fee {
  344. let mut found_fee = false;
  345. // Verify that there is a Money::FeeV1 (0x00) call in the transaction
  346. for (call_idx, call) in tx.calls.iter().enumerate() {
  347. if call.data.contract_id == *MONEY_CONTRACT_ID && call.data.data[0] == 0x00 {
  348. found_fee = true;
  349. fee_call_idx = call_idx;
  350. break
  351. }
  352. }
  353. if !found_fee {
  354. error!(
  355. target: "validator::verification::verify_transcation",
  356. "[VALIDATOR] Transaction {} does not contain fee payment call", tx_hash,
  357. );
  358. return Err(TxVerifyFailed::InvalidFee.into())
  359. }
  360. }
  361. // We'll also take note of all the circuits in a Vec so we can calculate their verification cost.
  362. let mut circuits_to_verify = vec![];
  363. // Iterate over all calls to get the metadata
  364. for (idx, call) in tx.calls.iter().enumerate() {
  365. // Transaction must not contain a Money::PoWReward(0x06) call
  366. if call.data.contract_id == *MONEY_CONTRACT_ID && call.data.data[0] == 0x06 {
  367. error!(target: "validator::verification::verify_transaction", "Reward transaction detected");
  368. return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
  369. }
  370. debug!(target: "validator::verification::verify_transaction", "Executing contract call {}", idx);
  371. // Write the actual payload data
  372. let mut payload = vec![];
  373. tx.calls.encode_async(&mut payload).await?;
  374. debug!(target: "validator::verification::verify_transaction", "Instantiating WASM runtime");
  375. let wasm = overlay.lock().unwrap().contracts.get(call.data.contract_id)?;
  376. let mut runtime = Runtime::new(
  377. &wasm,
  378. overlay.clone(),
  379. call.data.contract_id,
  380. verifying_block_height,
  381. tx_hash,
  382. idx as u8,
  383. )?;
  384. debug!(target: "validator::verification::verify_transaction", "Executing \"metadata\" call");
  385. let metadata = runtime.metadata(&payload)?;
  386. // Decode the metadata retrieved from the execution
  387. let mut decoder = Cursor::new(&metadata);
  388. // The tuple is (zkas_ns, public_inputs)
  389. let zkp_pub: Vec<(String, Vec<pallas::Base>)> =
  390. AsyncDecodable::decode_async(&mut decoder).await?;
  391. let sig_pub: Vec<PublicKey> = AsyncDecodable::decode_async(&mut decoder).await?;
  392. if decoder.position() != metadata.len() as u64 {
  393. error!(
  394. target: "validator::verification::verify_transaction",
  395. "[VALIDATOR] Failed decoding entire metadata buffer for {}:{}", tx_hash, idx,
  396. );
  397. return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
  398. }
  399. debug!(target: "validator::verification::verify_transaction", "Successfully executed \"metadata\" call");
  400. // Here we'll look up verifying keys and insert them into the per-contract map.
  401. // TODO: This vk map can potentially use a lot of RAM. Perhaps load keys on-demand at verification time?
  402. debug!(target: "validator::verification::verify_transaction", "Performing VerifyingKey lookups from the sled db");
  403. for (zkas_ns, _) in &zkp_pub {
  404. let inner_vk_map = verifying_keys.get_mut(&call.data.contract_id.to_bytes()).unwrap();
  405. // TODO: This will be a problem in case of ::deploy, unless we force a different
  406. // namespace and disable updating existing circuit. Might be a smart idea to do
  407. // so in order to have to care less about being able to verify historical txs.
  408. if inner_vk_map.contains_key(zkas_ns.as_str()) {
  409. continue
  410. }
  411. let (zkbin, vk) =
  412. overlay.lock().unwrap().contracts.get_zkas(&call.data.contract_id, zkas_ns)?;
  413. inner_vk_map.insert(zkas_ns.to_string(), vk);
  414. circuits_to_verify.push(zkbin);
  415. }
  416. zkp_table.push(zkp_pub);
  417. sig_table.push(sig_pub);
  418. // After getting the metadata, we run the "exec" function with the same runtime
  419. // and the same payload.
  420. debug!(target: "validator::verification::verify_transaction", "Executing \"exec\" call");
  421. let state_update = runtime.exec(&payload)?;
  422. debug!(target: "validator::verification::verify_transaction", "Successfully executed \"exec\" call");
  423. // If that was successful, we apply the state update in the ephemeral overlay.
  424. debug!(target: "validator::verification::verify_transaction", "Executing \"apply\" call");
  425. runtime.apply(&state_update)?;
  426. debug!(target: "validator::verification::verify_transaction", "Successfully executed \"apply\" call");
  427. // If this call is supposed to deploy a new contract, we have to instantiate
  428. // a new `Runtime` and run its deploy function.
  429. if call.data.contract_id == *DEPLOYOOOR_CONTRACT_ID && call.data.data[0] == 0x00
  430. /* DeployV1 */
  431. {
  432. debug!(target: "validator::verification::verify_transaction", "Deploying new contract");
  433. // Deserialize the deployment parameters
  434. let deploy_params: DeployParamsV1 = deserialize_async(&call.data.data[1..]).await?;
  435. let deploy_cid = ContractId::derive_public(deploy_params.public_key);
  436. // Instantiate the new deployment runtime
  437. let mut deploy_runtime = Runtime::new(
  438. &deploy_params.wasm_bincode,
  439. overlay.clone(),
  440. deploy_cid,
  441. verifying_block_height,
  442. tx_hash,
  443. idx as u8,
  444. )?;
  445. deploy_runtime.deploy(&deploy_params.ix)?;
  446. // Append the used gas
  447. gas_used += deploy_runtime.gas_used();
  448. }
  449. // At this point we're done with the call and move on to the next one.
  450. // Accumulate the WASM gas used.
  451. gas_used += runtime.gas_used();
  452. }
  453. // The signature fee is tx_size + fixed_sig_fee * n_signatures
  454. gas_used += (PALLAS_SCHNORR_SIGNATURE_FEE * tx.signatures.len() as u64) +
  455. serialize_async(tx).await.len() as u64;
  456. // The ZK circuit fee is calculated using a function in validator/fees.rs
  457. for zkbin in circuits_to_verify.iter() {
  458. gas_used += circuit_gas_use(zkbin);
  459. }
  460. if verify_fee {
  461. // Deserialize the fee call to find the paid fee
  462. let fee: u64 = match deserialize_async(&tx.calls[fee_call_idx].data.data[1..9]).await {
  463. Ok(v) => v,
  464. Err(e) => {
  465. error!(
  466. target: "validator::verification::verify_transaction",
  467. "[VALIDATOR] Failed deserializing tx {} fee call: {}", tx_hash, e,
  468. );
  469. return Err(TxVerifyFailed::InvalidFee.into())
  470. }
  471. };
  472. // TODO: This counts 1 gas as 1 token unit. Pricing should be better specified.
  473. // Check that enough fee has been paid for the used gas in this transaction.
  474. if gas_used > fee {
  475. error!(
  476. target: "validator::verification::verify_transaction",
  477. "[VALIDATOR] Transaction {} has insufficient fee. Required: {}, Paid: {}",
  478. tx_hash, gas_used, fee,
  479. );
  480. return Err(TxVerifyFailed::InsufficientFee.into())
  481. }
  482. }
  483. // When we're done looping and executing over the tx's contract calls and
  484. // (optionally) made sure that enough fee was paid, we now move on with
  485. // verification. First we verify the transaction signatures and then we
  486. // verify any accompanying ZK proofs.
  487. debug!(target: "validator::verification::verify_transaction", "Verifying signatures for transaction {}", tx_hash);
  488. if sig_table.len() != tx.signatures.len() {
  489. error!(
  490. target: "validator::verification::verify_transaction",
  491. "[VALIDATOR] Incorrect number of signatures in tx {}", tx_hash,
  492. );
  493. return Err(TxVerifyFailed::MissingSignatures.into())
  494. }
  495. if let Err(e) = tx.verify_sigs(sig_table) {
  496. error!(
  497. target: "validator::verification::verify_transaction",
  498. "[VALIDATOR] Signature verification for tx {} failed: {}", tx_hash, e,
  499. );
  500. return Err(TxVerifyFailed::InvalidSignature.into())
  501. }
  502. debug!(target: "validator::verification::verify_transaction", "Signature verification successful");
  503. debug!(target: "validator::verification::verify_transaction", "Verifying ZK proofs for transaction {}", tx_hash);
  504. if let Err(e) = tx.verify_zkps(verifying_keys, zkp_table).await {
  505. error!(
  506. target: "validator::verification::verify_transaction",
  507. "[VALIDATOR] ZK proof verification for tx {} failed: {}", tx_hash, e,
  508. );
  509. return Err(TxVerifyFailed::InvalidZkProof.into())
  510. }
  511. debug!(target: "validator::verification::verify_transaction", "ZK proof verification successful");
  512. // Append hash to merkle tree
  513. append_tx_to_merkle_tree(tree, tx);
  514. debug!(target: "validator::verification::verify_transaction", "Transaction {} verified successfully", tx_hash);
  515. Ok(gas_used)
  516. }
  517. /// Verify a set of [`Transaction`] in sequence and apply them if all are valid.
  518. /// In case any of the transactions fail, they will be returned to the caller as an error.
  519. /// If all transactions are valid, the function will return the accumulated gas used from
  520. /// all the transactions. Additionally, their hash is appended to the provided Merkle tree.
  521. pub async fn verify_transactions(
  522. overlay: &BlockchainOverlayPtr,
  523. verifying_block_height: u32,
  524. txs: &[Transaction],
  525. tree: &mut MerkleTree,
  526. verify_fees: bool,
  527. ) -> Result<u64> {
  528. debug!(target: "validator::verification::verify_transactions", "Verifying {} transactions", txs.len());
  529. if txs.is_empty() {
  530. return Ok(0)
  531. }
  532. // Tracker for failed txs
  533. let mut erroneous_txs = vec![];
  534. // Gas accumulator
  535. let mut gas_used = 0;
  536. // Map of ZK proof verifying keys for the current transaction batch
  537. let mut vks: HashMap<[u8; 32], HashMap<String, VerifyingKey>> = HashMap::new();
  538. // Initialize the map
  539. for tx in txs {
  540. for call in &tx.calls {
  541. vks.insert(call.data.contract_id.to_bytes(), HashMap::new());
  542. }
  543. }
  544. // Iterate over transactions and attempt to verify them
  545. for tx in txs {
  546. overlay.lock().unwrap().checkpoint();
  547. match verify_transaction(overlay, verifying_block_height, tx, tree, &mut vks, verify_fees)
  548. .await
  549. {
  550. Ok(gas) => gas_used += gas,
  551. Err(e) => {
  552. warn!(target: "validator::verification::verify_transactions", "Transaction verification failed: {}", e);
  553. erroneous_txs.push(tx.clone());
  554. overlay.lock().unwrap().revert_to_checkpoint()?;
  555. }
  556. }
  557. }
  558. if erroneous_txs.is_empty() {
  559. Ok(gas_used)
  560. } else {
  561. Err(TxVerifyFailed::ErroneousTxs(erroneous_txs).into())
  562. }
  563. }
  564. /// Verify given [`Proposal`] against provided consensus state,
  565. /// A proposal is considered valid when the following rules apply:
  566. /// 1. Proposal hash matches the actual block one
  567. /// 2. Block transactions don't exceed set limit
  568. /// 3. Block is valid
  569. /// Additional validity rules can be applied.
  570. pub async fn verify_proposal(
  571. consensus: &Consensus,
  572. proposal: &Proposal,
  573. ) -> Result<(Fork, Option<usize>)> {
  574. // Check if proposal hash matches actual one (1)
  575. let proposal_hash = proposal.block.hash();
  576. if proposal.hash != proposal_hash {
  577. warn!(
  578. target: "validator::verification::verify_pow_proposal", "Received proposal contains mismatched hashes: {} - {}",
  579. proposal.hash, proposal_hash
  580. );
  581. return Err(Error::ProposalHashesMissmatchError)
  582. }
  583. // Check that proposal transactions don't exceed limit (2)
  584. if proposal.block.txs.len() > TXS_CAP + 1 {
  585. warn!(
  586. target: "validator::verification::verify_pow_proposal", "Received proposal transactions exceed configured cap: {} - {}",
  587. proposal.block.txs.len(),
  588. TXS_CAP
  589. );
  590. return Err(Error::ProposalTxsExceedCapError)
  591. }
  592. // Check if proposal extends any existing forks
  593. let (fork, index) = consensus.find_extended_fork(proposal).await?;
  594. // Grab overlay last block
  595. let previous = fork.overlay.lock().unwrap().last_block()?;
  596. // Verify proposal block (3)
  597. if verify_block(&fork.overlay, &fork.module, &proposal.block, &previous).await.is_err() {
  598. error!(target: "validator::verification::verify_pow_proposal", "Erroneous proposal block found");
  599. fork.overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
  600. return Err(Error::BlockIsInvalid(proposal.hash.as_string()))
  601. };
  602. Ok((fork, index))
  603. }