1use std::collections::HashMap;
20
21use darkfi_sdk::{
22 blockchain::block_version,
23 crypto::{
24 schnorr::{SchnorrPublic, Signature},
25 ContractId, MerkleTree, PublicKey,
26 },
27 dark_tree::dark_forest_leaf_vec_integrity_check,
28 deploy::DeployParamsV1,
29 pasta::pallas,
30};
31use darkfi_serial::{deserialize_async, serialize_async, AsyncDecodable, AsyncEncodable};
32use num_bigint::BigUint;
33use sled_overlay::SledDbOverlayStateDiff;
34use smol::io::Cursor;
35use tracing::{debug, error, warn};
36
37use crate::{
38 blockchain::{
39 block_store::append_tx_to_merkle_tree, header_store::PowData::DarkFi, BlockInfo,
40 Blockchain, BlockchainOverlayPtr, HeaderHash,
41 },
42 error::TxVerifyFailed,
43 runtime::vm_runtime::Runtime,
44 tx::{Transaction, MAX_TX_CALLS, MIN_TX_CALLS},
45 validator::{
46 consensus::{Consensus, Fork, Proposal, BLOCK_GAS_LIMIT},
47 fees::{circuit_gas_use, compute_fee, GasData, PALLAS_SCHNORR_SIGNATURE_FEE},
48 pow::PoWModule,
49 },
50 zk::VerifyingKey,
51 Error, Result,
52};
53
54pub async fn verify_genesis_block(
60 overlay: &BlockchainOverlayPtr,
61 diffs: &[SledDbOverlayStateDiff],
62 block: &BlockInfo,
63 block_target: u32,
64) -> Result<()> {
65 let block_hash = block.hash().as_string();
66 debug!(target: "validator::verification::verify_genesis_block", "Validating genesis block {block_hash}");
67
68 if overlay.lock().unwrap().has_block(block)? {
70 return Err(Error::BlockAlreadyExists(block_hash))
71 }
72
73 if block.header.height != 0 {
75 return Err(Error::BlockIsInvalid(block_hash))
76 }
77
78 if block.header.version != block_version(block.header.height) {
80 return Err(Error::BlockIsInvalid(block_hash))
81 }
82
83 match block.header.pow_data {
85 DarkFi => { }
86 _ => return Err(Error::BlockIsInvalid(block_hash)),
87 }
88
89 if block.txs.is_empty() {
91 return Err(Error::BlockContainsNoTransactions(block_hash))
92 }
93
94 let producer_tx = block.txs.last().unwrap();
96 if producer_tx != &Transaction::default() {
97 error!(target: "validator::verification::verify_genesis_block", "Genesis producer transaction is not default one");
98 return Err(TxVerifyFailed::ErroneousTxs(vec![producer_tx.clone()]).into())
99 }
100
101 let mut tree = MerkleTree::new(1);
104 let txs = &block.txs[..block.txs.len() - 1];
105 if let Err(e) =
106 verify_transactions(overlay, block.header.height, block_target, txs, &mut tree, false).await
107 {
108 warn!(
109 target: "validator::verification::verify_genesis_block",
110 "[VALIDATOR] Erroneous transactions found in set",
111 );
112 return Err(e)
113 }
114
115 append_tx_to_merkle_tree(&mut tree, producer_tx);
117 if tree.root(0).unwrap() != block.header.transactions_root {
118 error!(target: "validator::verification::verify_genesis_block", "Genesis Merkle tree is invalid");
119 return Err(Error::BlockIsInvalid(block_hash))
120 }
121
122 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(diffs)?;
124 let state_root = overlay.lock().unwrap().contracts.update_state_monotree(&diff)?;
125 if state_root != block.header.state_root {
126 return Err(Error::ContractsStatesRootError(
127 blake3::Hash::from_bytes(state_root).to_string(),
128 blake3::Hash::from_bytes(block.header.state_root).to_string(),
129 ));
130 }
131
132 if block.signature != Signature::dummy() {
134 error!(target: "validator::verification::verify_genesis_block", "Genesis producer signature is not dummy one");
135 return Err(Error::InvalidSignature)
136 }
137
138 overlay.lock().unwrap().add_block(block)?;
140
141 debug!(target: "validator::verification::verify_genesis_block", "Genesis block {block_hash} verified successfully");
142 Ok(())
143}
144
145pub fn validate_block(block: &BlockInfo, previous: &BlockInfo, module: &PoWModule) -> Result<()> {
156 if block.header.version != block_version(block.header.height) {
158 return Err(Error::BlockIsInvalid(block.hash().as_string()))
159 }
160
161 if block.header.previous != previous.hash() {
163 return Err(Error::BlockIsInvalid(block.hash().as_string()))
164 }
165
166 if block.header.height != previous.header.height + 1 {
168 return Err(Error::BlockIsInvalid(block.hash().as_string()))
169 }
170
171 if !module.verify_timestamp_by_median(block.header.timestamp) {
173 return Err(Error::BlockIsInvalid(block.hash().as_string()))
174 }
175
176 if !block.header.validate_powdata() {
178 return Err(Error::BlockIsInvalid(block.hash().as_string()))
179 }
180
181 module.verify_block_hash(&block.header)?;
183
184 Ok(())
185}
186
187pub fn validate_blockchain(
191 blockchain: &Blockchain,
192 pow_target: u32,
193 pow_fixed_difficulty: Option<BigUint>,
194) -> Result<()> {
195 let mut module = PoWModule::new(blockchain.clone(), pow_target, pow_fixed_difficulty, Some(0))?;
197
198 let blocks = blockchain.blocks.get_all_order()?;
200 for (index, block) in blocks[1..].iter().enumerate() {
201 let full_blocks = blockchain.get_blocks_by_hash(&[blocks[index].1, block.1])?;
202 let full_block = &full_blocks[1];
203 validate_block(full_block, &full_blocks[0], &module)?;
204 module.append(&full_block.header, &module.next_difficulty()?)?;
206 }
207
208 Ok(())
209}
210
211pub async fn verify_block(
216 overlay: &BlockchainOverlayPtr,
217 diffs: &[SledDbOverlayStateDiff],
218 module: &PoWModule,
219 block: &BlockInfo,
220 previous: &BlockInfo,
221 verify_fees: bool,
222) -> Result<()> {
223 let block_hash = block.hash();
224 debug!(target: "validator::verification::verify_block", "Validating block {block_hash}");
225
226 if overlay.lock().unwrap().has_block(block)? {
228 return Err(Error::BlockAlreadyExists(block_hash.as_string()))
229 }
230
231 validate_block(block, previous, module)?;
233
234 if block.txs.is_empty() {
236 return Err(Error::BlockContainsNoTransactions(block_hash.as_string()))
237 }
238
239 let mut tree = MerkleTree::new(1);
241 let txs = &block.txs[..block.txs.len() - 1];
242 if let Err(e) = verify_transactions(
243 overlay,
244 block.header.height,
245 module.target,
246 txs,
247 &mut tree,
248 verify_fees,
249 )
250 .await
251 {
252 warn!(
253 target: "validator::verification::verify_block",
254 "[VALIDATOR] Erroneous transactions found in set",
255 );
256 return Err(e)
257 }
258
259 let public_key = verify_producer_transaction(
261 overlay,
262 block.header.height,
263 module.target,
264 block.txs.last().unwrap(),
265 &mut tree,
266 )
267 .await?;
268
269 if tree.root(0).unwrap() != block.header.transactions_root {
271 error!(target: "validator::verification::verify_block", "Block Merkle tree root is invalid");
272 return Err(Error::BlockIsInvalid(block_hash.as_string()))
273 }
274
275 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(diffs)?;
277 let state_root = overlay.lock().unwrap().contracts.update_state_monotree(&diff)?;
278 if state_root != block.header.state_root {
279 return Err(Error::ContractsStatesRootError(
280 blake3::Hash::from_bytes(state_root).to_string(),
281 blake3::Hash::from_bytes(block.header.state_root).to_string(),
282 ));
283 }
284
285 verify_producer_signature(block, &public_key)?;
287
288 overlay.lock().unwrap().add_block(block)?;
290
291 debug!(target: "validator::verification::verify_block", "Block {block_hash} verified successfully");
292 Ok(())
293}
294
295pub async fn verify_checkpoint_block(
301 overlay: &BlockchainOverlayPtr,
302 diffs: &[SledDbOverlayStateDiff],
303 block: &BlockInfo,
304 header: &HeaderHash,
305 block_target: u32,
306) -> Result<()> {
307 let block_hash = block.hash();
308 debug!(target: "validator::verification::verify_checkpoint_block", "Validating block {block_hash}");
309
310 if overlay.lock().unwrap().has_block(block)? {
312 return Err(Error::BlockAlreadyExists(block_hash.as_string()))
313 }
314
315 if block_hash != *header {
317 error!(target: "validator::verification::verify_checkpoint_block", "Block hash doesn't match the expected one");
318 return Err(Error::BlockIsInvalid(block_hash.as_string()))
319 }
320
321 if block.txs.is_empty() {
323 return Err(Error::BlockContainsNoTransactions(block_hash.as_string()))
324 }
325
326 let mut tree = MerkleTree::new(1);
328 let txs = &block.txs[..block.txs.len() - 1];
329 if let Err(e) =
330 apply_transactions(overlay, block.header.height, block_target, txs, &mut tree).await
331 {
332 warn!(
333 target: "validator::verification::verify_checkpoint_block",
334 "[VALIDATOR] Erroneous transactions found in set",
335 );
336 return Err(e)
337 }
338
339 let public_key = apply_producer_transaction(
341 overlay,
342 block.header.height,
343 block_target,
344 block.txs.last().unwrap(),
345 &mut tree,
346 )
347 .await?;
348
349 if tree.root(0).unwrap() != block.header.transactions_root {
351 error!(target: "validator::verification::verify_checkpoint_block", "Block Merkle tree root is invalid");
352 return Err(Error::BlockIsInvalid(block_hash.as_string()))
353 }
354
355 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(diffs)?;
357 let state_root = overlay.lock().unwrap().contracts.update_state_monotree(&diff)?;
358 if state_root != block.header.state_root {
359 return Err(Error::ContractsStatesRootError(
360 blake3::Hash::from_bytes(state_root).to_string(),
361 blake3::Hash::from_bytes(block.header.state_root).to_string(),
362 ));
363 }
364
365 verify_producer_signature(block, &public_key)?;
367
368 overlay.lock().unwrap().add_block(block)?;
370
371 debug!(target: "validator::verification::verify_checkpoint_block", "Block {block_hash} verified successfully");
372 Ok(())
373}
374
375pub fn verify_producer_signature(block: &BlockInfo, public_key: &PublicKey) -> Result<()> {
378 if !public_key.verify(block.header.hash().inner(), &block.signature) {
379 warn!(target: "validator::verification::verify_producer_signature", "Proposer {public_key} signature could not be verified");
380 return Err(Error::InvalidSignature)
381 }
382
383 Ok(())
384}
385
386pub async fn verify_producer_transaction(
392 overlay: &BlockchainOverlayPtr,
393 verifying_block_height: u32,
394 block_target: u32,
395 tx: &Transaction,
396 tree: &mut MerkleTree,
397) -> Result<PublicKey> {
398 let tx_hash = tx.hash();
399 debug!(target: "validator::verification::verify_producer_transaction", "Validating producer transaction {tx_hash}");
400
401 if !tx.is_pow_reward() {
403 return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
404 }
405
406 let call = &tx.calls[0];
408
409 let mut verifying_keys: HashMap<[u8; 32], HashMap<String, VerifyingKey>> = HashMap::new();
411
412 verifying_keys.insert(call.data.contract_id.to_bytes(), HashMap::new());
414
415 let mut zkp_table = vec![];
417 let mut sig_table = vec![];
419
420 debug!(target: "validator::verification::verify_producer_transaction", "Executing contract call");
421
422 let mut payload = vec![];
424 tx.calls.encode_async(&mut payload).await?; debug!(target: "validator::verification::verify_producer_transaction", "Instantiating WASM runtime");
427 let wasm = overlay.lock().unwrap().contracts.get(call.data.contract_id)?;
428
429 let mut runtime = Runtime::new(
430 &wasm,
431 overlay.clone(),
432 call.data.contract_id,
433 verifying_block_height,
434 block_target,
435 tx_hash,
436 0,
438 )?;
439
440 debug!(target: "validator::verification::verify_producer_transaction", "Executing \"metadata\" call");
441 let metadata = runtime.metadata(&payload)?;
442
443 let mut decoder = Cursor::new(&metadata);
445
446 let zkp_pub: Vec<(String, Vec<pallas::Base>)> =
448 AsyncDecodable::decode_async(&mut decoder).await?;
449 let sig_pub: Vec<PublicKey> = AsyncDecodable::decode_async(&mut decoder).await?;
450
451 if zkp_pub.len() != 1 || sig_pub.len() != 1 {
453 error!(target: "validator::verification::verify_producer_transaction", "Producer transaction contains multiple ZK proofs or signature public keys");
454 return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
455 }
456
457 debug!(target: "validator::verification::verify_producer_transaction", "Successfully executed \"metadata\" call");
459
460 debug!(target: "validator::verification::verify_producer_transaction", "Performing VerifyingKey lookups from the sled db");
462 for (zkas_ns, _) in &zkp_pub {
463 let inner_vk_map = verifying_keys.get_mut(&call.data.contract_id.to_bytes()).unwrap();
465 if inner_vk_map.contains_key(zkas_ns.as_str()) {
466 continue
467 }
468
469 let (_zkbin, vk) =
470 overlay.lock().unwrap().contracts.get_zkas(&call.data.contract_id, zkas_ns)?;
471
472 inner_vk_map.insert(zkas_ns.to_string(), vk);
473 }
474
475 zkp_table.push(zkp_pub);
476 let signature_public_key = *sig_pub.last().unwrap();
477 sig_table.push(sig_pub);
478
479 debug!(target: "validator::verification::verify_producer_transaction", "Executing \"exec\" call");
483 let mut state_update = vec![call.data.data[0]];
484 state_update.append(&mut runtime.exec(&payload)?);
485 debug!(target: "validator::verification::verify_producer_transaction", "Successfully executed \"exec\" call");
486
487 debug!(target: "validator::verification::verify_producer_transaction", "Executing \"apply\" call");
489 runtime.apply(&state_update)?;
490 debug!(target: "validator::verification::verify_producer_transaction", "Successfully executed \"apply\" call");
491
492 debug!(target: "validator::verification::verify_producer_transaction", "Verifying signatures for transaction {tx_hash}");
495 if sig_table.len() != tx.signatures.len() {
496 error!(target: "validator::verification::verify_producer_transaction", "Incorrect number of signatures in tx {tx_hash}");
497 return Err(TxVerifyFailed::MissingSignatures.into())
498 }
499
500 if let Err(e) = tx.verify_sigs(sig_table) {
503 error!(target: "validator::verification::verify_producer_transaction", "Signature verification for tx {tx_hash} failed: {e}");
504 return Err(TxVerifyFailed::InvalidSignature.into())
505 }
506
507 debug!(target: "validator::verification::verify_producer_transaction", "Signature verification successful");
508
509 debug!(target: "validator::verification::verify_producer_transaction", "Verifying ZK proofs for transaction {tx_hash}");
510 if let Err(e) = tx.verify_zkps(&verifying_keys, zkp_table).await {
511 error!(target: "validator::verification::verify_producer_transaction", "ZK proof verification for tx {tx_hash} failed: {e}");
512 return Err(TxVerifyFailed::InvalidZkProof.into())
513 }
514 debug!(target: "validator::verification::verify_producer_transaction", "ZK proof verification successful");
515
516 append_tx_to_merkle_tree(tree, tx);
518
519 debug!(target: "validator::verification::verify_producer_transaction", "Producer transaction {tx_hash} verified successfully");
520
521 Ok(signature_public_key)
522}
523
524pub async fn apply_producer_transaction(
527 overlay: &BlockchainOverlayPtr,
528 verifying_block_height: u32,
529 block_target: u32,
530 tx: &Transaction,
531 tree: &mut MerkleTree,
532) -> Result<PublicKey> {
533 let tx_hash = tx.hash();
534 debug!(target: "validator::verification::apply_producer_transaction", "Applying producer transaction {tx_hash}");
535
536 if !tx.is_single_call() {
538 return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
539 }
540
541 debug!(target: "validator::verification::apply_producer_transaction", "Executing contract call");
542
543 let mut payload = vec![];
545 tx.calls.encode_async(&mut payload).await?; debug!(target: "validator::verification::apply_producer_transaction", "Instantiating WASM runtime");
548 let call = &tx.calls[0];
549 let wasm = overlay.lock().unwrap().contracts.get(call.data.contract_id)?;
550
551 let mut runtime = Runtime::new(
552 &wasm,
553 overlay.clone(),
554 call.data.contract_id,
555 verifying_block_height,
556 block_target,
557 tx_hash,
558 0,
560 )?;
561
562 debug!(target: "validator::verification::apply_producer_transaction", "Executing \"metadata\" call");
563 let metadata = runtime.metadata(&payload)?;
564
565 let mut decoder = Cursor::new(&metadata);
567
568 let _: Vec<(String, Vec<pallas::Base>)> = AsyncDecodable::decode_async(&mut decoder).await?;
570 let sig_pub: Vec<PublicKey> = AsyncDecodable::decode_async(&mut decoder).await?;
571
572 if sig_pub.len() != 1 {
574 error!(target: "validator::verification::apply_producer_transaction", "Producer transaction contains multiple ZK proofs or signature public keys");
575 return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
576 }
577
578 let signature_public_key = *sig_pub.last().unwrap();
579
580 debug!(target: "validator::verification::apply_producer_transaction", "Executing \"exec\" call");
584 let mut state_update = vec![call.data.data[0]];
585 state_update.append(&mut runtime.exec(&payload)?);
586 debug!(target: "validator::verification::apply_producer_transaction", "Successfully executed \"exec\" call");
587
588 debug!(target: "validator::verification::apply_producer_transaction", "Executing \"apply\" call");
590 runtime.apply(&state_update)?;
591 debug!(target: "validator::verification::apply_producer_transaction", "Successfully executed \"apply\" call");
592
593 append_tx_to_merkle_tree(tree, tx);
595
596 debug!(target: "validator::verification::apply_producer_transaction", "Producer transaction {tx_hash} executed successfully");
597
598 Ok(signature_public_key)
599}
600
601pub async fn verify_transaction(
605 overlay: &BlockchainOverlayPtr,
606 verifying_block_height: u32,
607 block_target: u32,
608 tx: &Transaction,
609 tree: &mut MerkleTree,
610 verifying_keys: &mut HashMap<[u8; 32], HashMap<String, VerifyingKey>>,
611 verify_fee: bool,
612) -> Result<GasData> {
613 let tx_hash = tx.hash();
614 debug!(target: "validator::verification::verify_transaction", "Validating transaction {tx_hash}");
615
616 let mut gas_data = GasData::default();
618
619 if verify_fee {
621 dark_forest_leaf_vec_integrity_check(
622 &tx.calls,
623 Some(MIN_TX_CALLS + 1),
624 Some(MAX_TX_CALLS),
625 )?;
626 } else {
627 dark_forest_leaf_vec_integrity_check(&tx.calls, Some(MIN_TX_CALLS), Some(MAX_TX_CALLS))?;
628 }
629
630 let mut zkp_table = vec![];
632 let mut sig_table = vec![];
634
635 let mut fee_call_idx = 0;
637
638 if verify_fee {
639 let mut found_fee = false;
641 for (call_idx, call) in tx.calls.iter().enumerate() {
642 if !call.data.is_money_fee() {
643 continue
644 }
645
646 if found_fee {
647 error!(
648 target: "validator::verification::verify_transcation",
649 "[VALIDATOR] Transaction {tx_hash} contains multiple fee payment calls"
650 );
651 return Err(TxVerifyFailed::InvalidFee.into())
652 }
653
654 found_fee = true;
655 fee_call_idx = call_idx;
656 }
657
658 if !found_fee {
659 error!(
660 target: "validator::verification::verify_transcation",
661 "[VALIDATOR] Transaction {tx_hash} does not contain fee payment call"
662 );
663 return Err(TxVerifyFailed::InvalidFee.into())
664 }
665 }
666
667 let mut payload = vec![];
669 tx.calls.encode_async(&mut payload).await?;
670
671 let mut _call_payload = vec![];
673
674 let mut circuits_to_verify = vec![];
676
677 for (idx, call) in tx.calls.iter().enumerate() {
679 debug!(target: "validator::verification::verify_transaction", "Executing contract call {idx}");
680
681 if call.data.is_money_pow_reward() {
683 error!(target: "validator::verification::verify_transaction", "Reward transaction detected");
684 return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
685 }
686
687 let (call_idx, call_payload) = if call.data.is_money_fee() {
689 _call_payload = vec![];
690 vec![call.clone()].encode_async(&mut _call_payload).await?;
691 (0_u8, &_call_payload)
692 } else {
693 (idx as u8, &payload)
694 };
695
696 debug!(target: "validator::verification::verify_transaction", "Instantiating WASM runtime");
697 let wasm = overlay.lock().unwrap().contracts.get(call.data.contract_id)?;
698 let mut runtime = Runtime::new(
699 &wasm,
700 overlay.clone(),
701 call.data.contract_id,
702 verifying_block_height,
703 block_target,
704 tx_hash,
705 call_idx,
706 )?;
707
708 debug!(target: "validator::verification::verify_transaction", "Executing \"metadata\" call");
709 let metadata = runtime.metadata(call_payload)?;
710
711 let mut decoder = Cursor::new(&metadata);
713
714 let zkp_pub: Vec<(String, Vec<pallas::Base>)> =
716 AsyncDecodable::decode_async(&mut decoder).await?;
717 let sig_pub: Vec<PublicKey> = AsyncDecodable::decode_async(&mut decoder).await?;
718
719 if decoder.position() != metadata.len() as u64 {
720 error!(
721 target: "validator::verification::verify_transaction",
722 "[VALIDATOR] Failed decoding entire metadata buffer for {tx_hash}:{idx}"
723 );
724 return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
725 }
726
727 debug!(target: "validator::verification::verify_transaction", "Successfully executed \"metadata\" call");
728
729 debug!(target: "validator::verification::verify_transaction", "Performing VerifyingKey lookups from the sled db");
732 for (zkas_ns, _) in &zkp_pub {
733 let inner_vk_map = verifying_keys.get_mut(&call.data.contract_id.to_bytes()).unwrap();
734
735 if inner_vk_map.contains_key(zkas_ns.as_str()) {
739 continue
740 }
741
742 let (zkbin, vk) =
743 overlay.lock().unwrap().contracts.get_zkas(&call.data.contract_id, zkas_ns)?;
744
745 inner_vk_map.insert(zkas_ns.to_string(), vk);
746 circuits_to_verify.push(zkbin);
747 }
748
749 zkp_table.push(zkp_pub);
750 sig_table.push(sig_pub);
751
752 debug!(target: "validator::verification::verify_transaction", "Executing \"exec\" call");
756 let mut state_update = vec![call.data.data[0]];
757 state_update.append(&mut runtime.exec(call_payload)?);
758 debug!(target: "validator::verification::verify_transaction", "Successfully executed \"exec\" call");
759
760 debug!(target: "validator::verification::verify_transaction", "Executing \"apply\" call");
762 runtime.apply(&state_update)?;
763 debug!(target: "validator::verification::verify_transaction", "Successfully executed \"apply\" call");
764
765 if call.data.is_deployment()
768 {
770 debug!(target: "validator::verification::verify_transaction", "Deploying new contract");
771 let deploy_params: DeployParamsV1 = deserialize_async(&call.data.data[1..]).await?;
773 let deploy_cid = ContractId::derive_public(deploy_params.public_key);
774
775 let mut deploy_runtime = Runtime::new(
777 &deploy_params.wasm_bincode,
778 overlay.clone(),
779 deploy_cid,
780 verifying_block_height,
781 block_target,
782 tx_hash,
783 call_idx,
784 )?;
785
786 deploy_runtime.deploy(&deploy_params.ix)?;
787
788 let deploy_gas_used = deploy_runtime.gas_used();
789 debug!(target: "validator::verification::verify_transaction", "The gas used for deployment call {call:?} of transaction {tx_hash}: {deploy_gas_used}");
790 gas_data.deployments += deploy_gas_used;
791 }
792
793 let wasm_gas_used = runtime.gas_used();
796 debug!(target: "validator::verification::verify_transaction", "The gas used for WASM call {call:?} of transaction {tx_hash}: {wasm_gas_used}");
797
798 gas_data.wasm += wasm_gas_used;
800 }
801
802 gas_data.signatures = (PALLAS_SCHNORR_SIGNATURE_FEE * tx.signatures.len() as u64) +
804 serialize_async(tx).await.len() as u64;
805 debug!(target: "validator::verification::verify_transaction", "The gas used for signature of transaction {tx_hash}: {}", gas_data.signatures);
806
807 for zkbin in circuits_to_verify.iter() {
809 let zk_circuit_gas_used = circuit_gas_use(zkbin);
810 debug!(target: "validator::verification::verify_transaction", "The gas used for ZK circuit in namespace {} of transaction {tx_hash}: {zk_circuit_gas_used}", zkbin.namespace);
811
812 gas_data.zk_circuits += zk_circuit_gas_used;
814 }
815
816 let total_gas_used = gas_data.total_gas_used();
818
819 if verify_fee {
820 let fee: u64 = match deserialize_async(&tx.calls[fee_call_idx].data.data[1..9]).await {
822 Ok(v) => v,
823 Err(e) => {
824 error!(
825 target: "validator::verification::verify_transaction",
826 "[VALIDATOR] Failed deserializing tx {tx_hash} fee call: {e}"
827 );
828 return Err(TxVerifyFailed::InvalidFee.into())
829 }
830 };
831
832 let required_fee = compute_fee(&total_gas_used);
834
835 if required_fee > fee {
837 error!(
838 target: "validator::verification::verify_transaction",
839 "[VALIDATOR] Transaction {tx_hash} has insufficient fee. Required: {required_fee}, Paid: {fee}"
840 );
841 return Err(TxVerifyFailed::InsufficientFee.into())
842 }
843 debug!(target: "validator::verification::verify_transaction", "The gas paid for transaction {tx_hash}: {}", gas_data.paid);
844
845 gas_data.paid = fee;
847 }
848
849 debug!(target: "validator::verification::verify_transaction", "Verifying signatures for transaction {tx_hash}");
854 if sig_table.len() != tx.signatures.len() {
855 error!(
856 target: "validator::verification::verify_transaction",
857 "[VALIDATOR] Incorrect number of signatures in tx {tx_hash}"
858 );
859 return Err(TxVerifyFailed::MissingSignatures.into())
860 }
861
862 if let Err(e) = tx.verify_sigs(sig_table) {
863 error!(
864 target: "validator::verification::verify_transaction",
865 "[VALIDATOR] Signature verification for tx {tx_hash} failed: {e}"
866 );
867 return Err(TxVerifyFailed::InvalidSignature.into())
868 }
869 debug!(target: "validator::verification::verify_transaction", "Signature verification successful");
870
871 debug!(target: "validator::verification::verify_transaction", "Verifying ZK proofs for transaction {tx_hash}");
872 if let Err(e) = tx.verify_zkps(verifying_keys, zkp_table).await {
873 error!(
874 target: "validator::verification::verify_transaction",
875 "[VALIDATOR] ZK proof verification for tx {tx_hash} failed: {e}"
876 );
877 return Err(TxVerifyFailed::InvalidZkProof.into())
878 }
879 debug!(target: "validator::verification::verify_transaction", "ZK proof verification successful");
880
881 append_tx_to_merkle_tree(tree, tx);
883
884 debug!(target: "validator::verification::verify_transaction", "The total gas used for transaction {tx_hash}: {total_gas_used}");
885 debug!(target: "validator::verification::verify_transaction", "Transaction {tx_hash} verified successfully");
886 Ok(gas_data)
887}
888
889pub async fn apply_transaction(
892 overlay: &BlockchainOverlayPtr,
893 verifying_block_height: u32,
894 block_target: u32,
895 tx: &Transaction,
896 tree: &mut MerkleTree,
897) -> Result<()> {
898 let tx_hash = tx.hash();
899 debug!(target: "validator::verification::apply_transaction", "Applying transaction {tx_hash}");
900
901 let mut payload = vec![];
903 tx.calls.encode_async(&mut payload).await?;
904
905 for (idx, call) in tx.calls.iter().enumerate() {
907 debug!(target: "validator::verification::apply_transaction", "Executing contract call {idx}");
908
909 debug!(target: "validator::verification::apply_transaction", "Instantiating WASM runtime");
910 let wasm = overlay.lock().unwrap().contracts.get(call.data.contract_id)?;
911 let mut runtime = Runtime::new(
912 &wasm,
913 overlay.clone(),
914 call.data.contract_id,
915 verifying_block_height,
916 block_target,
917 tx_hash,
918 idx as u8,
919 )?;
920
921 debug!(target: "validator::verification::apply_transaction", "Executing \"exec\" call");
924 let mut state_update = vec![call.data.data[0]];
925 state_update.append(&mut runtime.exec(&payload)?);
926 debug!(target: "validator::verification::apply_transaction", "Successfully executed \"exec\" call");
927
928 debug!(target: "validator::verification::apply_transaction", "Executing \"apply\" call");
930 runtime.apply(&state_update)?;
931 debug!(target: "validator::verification::apply_transaction", "Successfully executed \"apply\" call");
932
933 if call.data.is_deployment()
936 {
938 debug!(target: "validator::verification::apply_transaction", "Deploying new contract");
939 let deploy_params: DeployParamsV1 = deserialize_async(&call.data.data[1..]).await?;
941 let deploy_cid = ContractId::derive_public(deploy_params.public_key);
942
943 let mut deploy_runtime = Runtime::new(
945 &deploy_params.wasm_bincode,
946 overlay.clone(),
947 deploy_cid,
948 verifying_block_height,
949 block_target,
950 tx_hash,
951 idx as u8,
952 )?;
953
954 deploy_runtime.deploy(&deploy_params.ix)?;
955 }
956 }
957
958 append_tx_to_merkle_tree(tree, tx);
960
961 debug!(target: "validator::verification::apply_transaction", "Transaction {tx_hash} applied successfully");
962 Ok(())
963}
964
965pub async fn verify_transactions(
975 overlay: &BlockchainOverlayPtr,
976 verifying_block_height: u32,
977 block_target: u32,
978 txs: &[Transaction],
979 tree: &mut MerkleTree,
980 verify_fees: bool,
981) -> Result<(u64, u64)> {
982 debug!(target: "validator::verification::verify_transactions", "Verifying {} transactions", txs.len());
983 if txs.is_empty() {
984 return Ok((0, 0))
985 }
986
987 let mut erroneous_txs = vec![];
989
990 let mut total_gas_used = 0;
992 let mut total_gas_paid = 0;
993
994 let mut vks: HashMap<[u8; 32], HashMap<String, VerifyingKey>> = HashMap::new();
996
997 for tx in txs {
999 for call in &tx.calls {
1000 vks.insert(call.data.contract_id.to_bytes(), HashMap::new());
1001 }
1002 }
1003
1004 for tx in txs {
1006 overlay.lock().unwrap().checkpoint();
1007 let gas_data = match verify_transaction(
1008 overlay,
1009 verifying_block_height,
1010 block_target,
1011 tx,
1012 tree,
1013 &mut vks,
1014 verify_fees,
1015 )
1016 .await
1017 {
1018 Ok(gas_values) => gas_values,
1019 Err(e) => {
1020 warn!(target: "validator::verification::verify_transactions", "Transaction verification failed: {e}");
1021 erroneous_txs.push(tx.clone());
1022 overlay.lock().unwrap().revert_to_checkpoint();
1023 continue
1024 }
1025 };
1026
1027 let tx_gas_used = gas_data.total_gas_used();
1029
1030 let accumulated_gas_usage = total_gas_used + tx_gas_used;
1032
1033 if accumulated_gas_usage > BLOCK_GAS_LIMIT {
1035 warn!(
1036 target: "validator::verification::verify_transactions",
1037 "Transaction {} exceeds configured transaction gas limit: {accumulated_gas_usage} - {BLOCK_GAS_LIMIT}",
1038 tx.hash()
1039 );
1040 erroneous_txs.push(tx.clone());
1041 overlay.lock().unwrap().revert_to_checkpoint();
1042 break
1043 }
1044
1045 total_gas_used += tx_gas_used;
1047 total_gas_paid += gas_data.paid;
1048 }
1049
1050 if !erroneous_txs.is_empty() {
1051 return Err(TxVerifyFailed::ErroneousTxs(erroneous_txs).into())
1052 }
1053
1054 Ok((total_gas_used, total_gas_paid))
1055}
1056
1057async fn apply_transactions(
1061 overlay: &BlockchainOverlayPtr,
1062 verifying_block_height: u32,
1063 block_target: u32,
1064 txs: &[Transaction],
1065 tree: &mut MerkleTree,
1066) -> Result<()> {
1067 debug!(target: "validator::verification::apply_transactions", "Applying {} transactions", txs.len());
1068 if txs.is_empty() {
1069 return Ok(())
1070 }
1071
1072 let mut erroneous_txs = vec![];
1074
1075 for tx in txs {
1077 overlay.lock().unwrap().checkpoint();
1078 if let Err(e) =
1079 apply_transaction(overlay, verifying_block_height, block_target, tx, tree).await
1080 {
1081 warn!(target: "validator::verification::apply_transactions", "Transaction apply failed: {e}");
1082 erroneous_txs.push(tx.clone());
1083 overlay.lock().unwrap().revert_to_checkpoint();
1084 };
1085 }
1086
1087 if !erroneous_txs.is_empty() {
1088 return Err(TxVerifyFailed::ErroneousTxs(erroneous_txs).into())
1089 }
1090
1091 Ok(())
1092}
1093
1094pub async fn verify_proposal(
1104 consensus: &Consensus,
1105 proposal: &Proposal,
1106 verify_fees: bool,
1107) -> Result<(Fork, Option<usize>)> {
1108 let proposal_hash = proposal.block.hash();
1110 if proposal.hash != proposal_hash {
1111 warn!(
1112 target: "validator::verification::verify_proposal", "Received proposal contains mismatched hashes: {} - {proposal_hash}",
1113 proposal.hash
1114 );
1115 return Err(Error::ProposalHashesMissmatchError)
1116 }
1117
1118 let (fork, index) = consensus.find_extended_fork(proposal).await?;
1120
1121 let previous = fork.overlay.lock().unwrap().last_block()?;
1123
1124 if let Err(e) = verify_block(
1126 &fork.overlay,
1127 &fork.diffs,
1128 &fork.module,
1129 &proposal.block,
1130 &previous,
1131 verify_fees,
1132 )
1133 .await
1134 {
1135 error!(target: "validator::verification::verify_proposal", "Erroneous proposal block found: {e}");
1136 return Err(Error::BlockIsInvalid(proposal.hash.as_string()))
1137 };
1138
1139 Ok((fork, index))
1140}
1141
1142pub async fn verify_fork_proposal(
1152 fork: &mut Fork,
1153 proposal: &Proposal,
1154 verify_fees: bool,
1155) -> Result<()> {
1156 let proposal_hash = proposal.block.hash();
1158 if proposal.hash != proposal_hash {
1159 warn!(
1160 target: "validator::verification::verify_fork_proposal", "Received proposal contains mismatched hashes: {} - {proposal_hash}",
1161 proposal.hash
1162 );
1163 return Err(Error::ProposalHashesMissmatchError)
1164 }
1165
1166 let previous = fork.overlay.lock().unwrap().last_block()?;
1168
1169 if let Err(e) = verify_block(
1171 &fork.overlay,
1172 &fork.diffs,
1173 &fork.module,
1174 &proposal.block,
1175 &previous,
1176 verify_fees,
1177 )
1178 .await
1179 {
1180 error!(target: "validator::verification::verify_fork_proposal", "Erroneous proposal block found: {e}");
1181 return Err(Error::BlockIsInvalid(proposal.hash.as_string()))
1182 };
1183
1184 Ok(())
1185}