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() {
92 return Err(Error::BlockContainsNoTransactions(block_hash))
93 }
94
95 let producer_tx = block.txs.last().unwrap();
98 if producer_tx != &Transaction::default() {
99 error!(target: "validator::verification::verify_genesis_block", "Genesis producer transaction is not default one");
100 return Err(TxVerifyFailed::ErroneousTxs(vec![producer_tx.clone()]).into())
101 }
102
103 let mut tree = MerkleTree::new(1);
106 let txs = &block.txs[..block.txs.len() - 1];
107 if let Err(e) =
108 verify_transactions(overlay, block.header.height, block_target, txs, &mut tree, false).await
109 {
110 warn!(
111 target: "validator::verification::verify_genesis_block",
112 "[VALIDATOR] Erroneous transactions found in set",
113 );
114 return Err(e)
115 }
116
117 append_tx_to_merkle_tree(&mut tree, producer_tx);
120 if tree.root(0).unwrap() != block.header.transactions_root {
121 error!(target: "validator::verification::verify_genesis_block", "Genesis Merkle tree is invalid");
122 return Err(Error::BlockIsInvalid(block_hash))
123 }
124
125 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(diffs)?;
128 let state_root = overlay.lock().unwrap().contracts.update_state_monotree(&diff)?;
129 if state_root != block.header.state_root {
130 return Err(Error::ContractsStatesRootError(
131 blake3::Hash::from_bytes(state_root).to_string(),
132 blake3::Hash::from_bytes(block.header.state_root).to_string(),
133 ));
134 }
135
136 if block.signature != Signature::dummy() {
139 error!(target: "validator::verification::verify_genesis_block", "Genesis producer signature is not dummy one");
140 return Err(Error::InvalidSignature)
141 }
142
143 overlay.lock().unwrap().add_block(block)?;
145
146 debug!(target: "validator::verification::verify_genesis_block", "Genesis block {block_hash} verified successfully");
147 Ok(())
148}
149
150pub fn validate_block(
162 block: &BlockInfo,
163 previous: &BlockInfo,
164 module: &mut PoWModule,
165 is_new: bool,
166) -> Result<()> {
167 if block.header.version != block_version(block.header.height) {
169 return Err(Error::BlockIsInvalid(block.hash().as_string()))
170 }
171
172 if block.header.previous != previous.hash() {
174 return Err(Error::BlockIsInvalid(block.hash().as_string()))
175 }
176
177 if block.header.height != previous.header.height + 1 {
179 return Err(Error::BlockIsInvalid(block.hash().as_string()))
180 }
181
182 let valid = if is_new {
184 module.verify_current_timestamp(block.header.timestamp)?
185 } else {
186 module.verify_timestamp_by_median(block.header.timestamp)
187 };
188 if !valid {
189 return Err(Error::BlockIsInvalid(block.hash().as_string()))
190 }
191
192 if !block.header.validate_powdata() {
194 return Err(Error::BlockIsInvalid(block.hash().as_string()))
195 }
196
197 module.verify_block_hash(&block.header)?;
199
200 Ok(())
201}
202
203pub fn validate_blockchain(
207 blockchain: &Blockchain,
208 pow_target: u32,
209 pow_fixed_difficulty: Option<BigUint>,
210) -> Result<()> {
211 let mut module = PoWModule::new(blockchain.clone(), pow_target, pow_fixed_difficulty, Some(0))?;
213
214 let blocks = blockchain.blocks.get_all_order()?;
216 for (index, block) in blocks[1..].iter().enumerate() {
217 let full_blocks = blockchain.get_blocks_by_hash(&[blocks[index].1, block.1])?;
218 let full_block = &full_blocks[1];
219 validate_block(full_block, &full_blocks[0], &mut module, false)?;
220 module.append(&full_block.header, &module.next_difficulty()?)?;
222 }
223
224 Ok(())
225}
226
227pub async fn verify_block(
232 overlay: &BlockchainOverlayPtr,
233 diffs: &[SledDbOverlayStateDiff],
234 module: &mut PoWModule,
235 block: &BlockInfo,
236 previous: &BlockInfo,
237 is_new: bool,
238 verify_fees: bool,
239) -> Result<()> {
240 let block_hash = block.hash();
241 debug!(target: "validator::verification::verify_block", "Validating block {block_hash}");
242
243 if overlay.lock().unwrap().has_block(block)? {
245 return Err(Error::BlockAlreadyExists(block_hash.as_string()))
246 }
247
248 validate_block(block, previous, module, is_new)?;
250
251 if block.txs.is_empty() {
254 return Err(Error::BlockContainsNoTransactions(block_hash.as_string()))
255 }
256
257 let mut tree = MerkleTree::new(1);
259 let txs = &block.txs[..block.txs.len() - 1];
260 if let Err(e) = verify_transactions(
261 overlay,
262 block.header.height,
263 module.target,
264 txs,
265 &mut tree,
266 verify_fees,
267 )
268 .await
269 {
270 warn!(
271 target: "validator::verification::verify_block",
272 "[VALIDATOR] Erroneous transactions found in set",
273 );
274 return Err(e)
275 }
276
277 let public_key = verify_producer_transaction(
279 overlay,
280 block.header.height,
281 module.target,
282 block.txs.last().unwrap(),
283 &mut tree,
284 )
285 .await?;
286
287 if tree.root(0).unwrap() != block.header.transactions_root {
289 error!(target: "validator::verification::verify_block", "Block Merkle tree root is invalid");
290 return Err(Error::BlockIsInvalid(block_hash.as_string()))
291 }
292
293 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(diffs)?;
296 let state_root = overlay.lock().unwrap().contracts.update_state_monotree(&diff)?;
297 if state_root != block.header.state_root {
298 return Err(Error::ContractsStatesRootError(
299 blake3::Hash::from_bytes(state_root).to_string(),
300 blake3::Hash::from_bytes(block.header.state_root).to_string(),
301 ));
302 }
303
304 verify_producer_signature(block, &public_key)?;
306
307 overlay.lock().unwrap().add_block(block)?;
309
310 debug!(target: "validator::verification::verify_block", "Block {block_hash} verified successfully");
311 Ok(())
312}
313
314pub async fn verify_checkpoint_block(
320 overlay: &BlockchainOverlayPtr,
321 diffs: &[SledDbOverlayStateDiff],
322 block: &BlockInfo,
323 header: &HeaderHash,
324 block_target: u32,
325) -> Result<()> {
326 let block_hash = block.hash();
327 debug!(target: "validator::verification::verify_checkpoint_block", "Validating block {block_hash}");
328
329 if overlay.lock().unwrap().has_block(block)? {
331 return Err(Error::BlockAlreadyExists(block_hash.as_string()))
332 }
333
334 if block_hash != *header {
336 error!(target: "validator::verification::verify_checkpoint_block", "Block hash doesn't match the expected one");
337 return Err(Error::BlockIsInvalid(block_hash.as_string()))
338 }
339
340 if block.txs.is_empty() {
343 return Err(Error::BlockContainsNoTransactions(block_hash.as_string()))
344 }
345
346 let mut tree = MerkleTree::new(1);
348 let txs = &block.txs[..block.txs.len() - 1];
349 if let Err(e) =
350 apply_transactions(overlay, block.header.height, block_target, txs, &mut tree).await
351 {
352 warn!(
353 target: "validator::verification::verify_checkpoint_block",
354 "[VALIDATOR] Erroneous transactions found in set",
355 );
356 return Err(e)
357 }
358
359 let public_key = apply_producer_transaction(
361 overlay,
362 block.header.height,
363 block_target,
364 block.txs.last().unwrap(),
365 &mut tree,
366 )
367 .await?;
368
369 if tree.root(0).unwrap() != block.header.transactions_root {
371 error!(target: "validator::verification::verify_checkpoint_block", "Block Merkle tree root is invalid");
372 return Err(Error::BlockIsInvalid(block_hash.as_string()))
373 }
374
375 let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(diffs)?;
378 let state_root = overlay.lock().unwrap().contracts.update_state_monotree(&diff)?;
379 if state_root != block.header.state_root {
380 return Err(Error::ContractsStatesRootError(
381 blake3::Hash::from_bytes(state_root).to_string(),
382 blake3::Hash::from_bytes(block.header.state_root).to_string(),
383 ));
384 }
385
386 verify_producer_signature(block, &public_key)?;
388
389 overlay.lock().unwrap().add_block(block)?;
391
392 debug!(target: "validator::verification::verify_checkpoint_block", "Block {block_hash} verified successfully");
393 Ok(())
394}
395
396pub fn verify_producer_signature(block: &BlockInfo, public_key: &PublicKey) -> Result<()> {
399 if !public_key.verify(block.header.hash().inner(), &block.signature) {
400 warn!(target: "validator::verification::verify_producer_signature", "Proposer {public_key} signature could not be verified");
401 return Err(Error::InvalidSignature)
402 }
403
404 Ok(())
405}
406
407pub async fn verify_producer_transaction(
413 overlay: &BlockchainOverlayPtr,
414 verifying_block_height: u32,
415 block_target: u32,
416 tx: &Transaction,
417 tree: &mut MerkleTree,
418) -> Result<PublicKey> {
419 let tx_hash = tx.hash();
420 debug!(target: "validator::verification::verify_producer_transaction", "Validating producer transaction {tx_hash}");
421
422 if !tx.is_pow_reward() {
424 return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
425 }
426
427 let call = &tx.calls[0];
429
430 let mut verifying_keys: HashMap<[u8; 32], HashMap<String, VerifyingKey>> = HashMap::new();
432
433 verifying_keys.insert(call.data.contract_id.to_bytes(), HashMap::new());
435
436 let mut zkp_table = vec![];
438 let mut sig_table = vec![];
440
441 debug!(target: "validator::verification::verify_producer_transaction", "Executing contract call");
442
443 let mut payload = vec![];
445 tx.calls.encode_async(&mut payload).await?; debug!(target: "validator::verification::verify_producer_transaction", "Instantiating WASM runtime");
448 let wasm = overlay.lock().unwrap().contracts.get(call.data.contract_id)?;
449
450 let mut runtime = Runtime::new(
451 &wasm,
452 overlay.clone(),
453 call.data.contract_id,
454 verifying_block_height,
455 block_target,
456 tx_hash,
457 0,
459 )?;
460
461 debug!(target: "validator::verification::verify_producer_transaction", "Executing \"metadata\" call");
462 let metadata = runtime.metadata(&payload)?;
463
464 let mut decoder = Cursor::new(&metadata);
466
467 let zkp_pub: Vec<(String, Vec<pallas::Base>)> =
469 AsyncDecodable::decode_async(&mut decoder).await?;
470 let sig_pub: Vec<PublicKey> = AsyncDecodable::decode_async(&mut decoder).await?;
471
472 if zkp_pub.len() != 1 || sig_pub.len() != 1 {
474 error!(target: "validator::verification::verify_producer_transaction", "Producer transaction contains multiple ZK proofs or signature public keys");
475 return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
476 }
477
478 debug!(target: "validator::verification::verify_producer_transaction", "Successfully executed \"metadata\" call");
480
481 debug!(target: "validator::verification::verify_producer_transaction", "Performing VerifyingKey lookups from the sled db");
483 for (zkas_ns, _) in &zkp_pub {
484 let inner_vk_map = verifying_keys.get_mut(&call.data.contract_id.to_bytes()).unwrap();
486 if inner_vk_map.contains_key(zkas_ns.as_str()) {
487 continue
488 }
489
490 let (_zkbin, vk) =
491 overlay.lock().unwrap().contracts.get_zkas(&call.data.contract_id, zkas_ns)?;
492
493 inner_vk_map.insert(zkas_ns.to_string(), vk);
494 }
495
496 zkp_table.push(zkp_pub);
497 let signature_public_key = *sig_pub.last().unwrap();
498 sig_table.push(sig_pub);
499
500 debug!(target: "validator::verification::verify_producer_transaction", "Executing \"exec\" call");
505 let mut state_update = vec![call.data.data[0]];
506 state_update.append(&mut runtime.exec(&payload)?);
507 debug!(target: "validator::verification::verify_producer_transaction", "Successfully executed \"exec\" call");
508
509 debug!(target: "validator::verification::verify_producer_transaction", "Executing \"apply\" call");
512 runtime.apply(&state_update)?;
513 debug!(target: "validator::verification::verify_producer_transaction", "Successfully executed \"apply\" call");
514
515 debug!(target: "validator::verification::verify_producer_transaction", "Verifying signatures for transaction {tx_hash}");
519 if sig_table.len() != tx.signatures.len() {
520 error!(target: "validator::verification::verify_producer_transaction", "Incorrect number of signatures in tx {tx_hash}");
521 return Err(TxVerifyFailed::MissingSignatures.into())
522 }
523
524 if let Err(e) = tx.verify_sigs(sig_table) {
528 error!(target: "validator::verification::verify_producer_transaction", "Signature verification for tx {tx_hash} failed: {e}");
529 return Err(TxVerifyFailed::InvalidSignature.into())
530 }
531
532 debug!(target: "validator::verification::verify_producer_transaction", "Signature verification successful");
533
534 debug!(target: "validator::verification::verify_producer_transaction", "Verifying ZK proofs for transaction {tx_hash}");
535 if let Err(e) = tx.verify_zkps(&verifying_keys, zkp_table).await {
536 error!(target: "validator::verification::verify_producer_transaction", "ZK proof verification for tx {tx_hash} failed: {e}");
537 return Err(TxVerifyFailed::InvalidZkProof.into())
538 }
539 debug!(target: "validator::verification::verify_producer_transaction", "ZK proof verification successful");
540
541 append_tx_to_merkle_tree(tree, tx);
543
544 debug!(target: "validator::verification::verify_producer_transaction", "Producer transaction {tx_hash} verified successfully");
545
546 Ok(signature_public_key)
547}
548
549pub async fn apply_producer_transaction(
553 overlay: &BlockchainOverlayPtr,
554 verifying_block_height: u32,
555 block_target: u32,
556 tx: &Transaction,
557 tree: &mut MerkleTree,
558) -> Result<PublicKey> {
559 let tx_hash = tx.hash();
560 debug!(target: "validator::verification::apply_producer_transaction", "Applying producer transaction {tx_hash}");
561
562 if !tx.is_single_call() {
564 return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
565 }
566
567 debug!(target: "validator::verification::apply_producer_transaction", "Executing contract call");
568
569 let mut payload = vec![];
571 tx.calls.encode_async(&mut payload).await?; debug!(target: "validator::verification::apply_producer_transaction", "Instantiating WASM runtime");
574 let call = &tx.calls[0];
575 let wasm = overlay.lock().unwrap().contracts.get(call.data.contract_id)?;
576
577 let mut runtime = Runtime::new(
578 &wasm,
579 overlay.clone(),
580 call.data.contract_id,
581 verifying_block_height,
582 block_target,
583 tx_hash,
584 0,
586 )?;
587
588 debug!(target: "validator::verification::apply_producer_transaction", "Executing \"metadata\" call");
589 let metadata = runtime.metadata(&payload)?;
590
591 let mut decoder = Cursor::new(&metadata);
593
594 let _: Vec<(String, Vec<pallas::Base>)> = AsyncDecodable::decode_async(&mut decoder).await?;
596 let sig_pub: Vec<PublicKey> = AsyncDecodable::decode_async(&mut decoder).await?;
597
598 if sig_pub.len() != 1 {
600 error!(target: "validator::verification::apply_producer_transaction", "Producer transaction contains multiple ZK proofs or signature public keys");
601 return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
602 }
603
604 let signature_public_key = *sig_pub.last().unwrap();
605
606 debug!(target: "validator::verification::apply_producer_transaction", "Executing \"exec\" call");
611 let mut state_update = vec![call.data.data[0]];
612 state_update.append(&mut runtime.exec(&payload)?);
613 debug!(target: "validator::verification::apply_producer_transaction", "Successfully executed \"exec\" call");
614
615 debug!(target: "validator::verification::apply_producer_transaction", "Executing \"apply\" call");
618 runtime.apply(&state_update)?;
619 debug!(target: "validator::verification::apply_producer_transaction", "Successfully executed \"apply\" call");
620
621 append_tx_to_merkle_tree(tree, tx);
623
624 debug!(target: "validator::verification::apply_producer_transaction", "Producer transaction {tx_hash} executed successfully");
625
626 Ok(signature_public_key)
627}
628
629pub async fn verify_transaction(
633 overlay: &BlockchainOverlayPtr,
634 verifying_block_height: u32,
635 block_target: u32,
636 tx: &Transaction,
637 tree: &mut MerkleTree,
638 verifying_keys: &mut HashMap<[u8; 32], HashMap<String, VerifyingKey>>,
639 verify_fee: bool,
640) -> Result<GasData> {
641 let tx_hash = tx.hash();
642 debug!(target: "validator::verification::verify_transaction", "Validating transaction {tx_hash}");
643
644 let mut gas_data = GasData::default();
646
647 if verify_fee {
649 dark_forest_leaf_vec_integrity_check(
650 &tx.calls,
651 Some(MIN_TX_CALLS + 1),
652 Some(MAX_TX_CALLS),
653 )?;
654 } else {
655 dark_forest_leaf_vec_integrity_check(&tx.calls, Some(MIN_TX_CALLS), Some(MAX_TX_CALLS))?;
656 }
657
658 let mut zkp_table = vec![];
660 let mut sig_table = vec![];
662
663 let mut fee_call_idx = 0;
665
666 if verify_fee {
667 let mut found_fee = false;
670 for (call_idx, call) in tx.calls.iter().enumerate() {
671 if !call.data.is_money_fee() {
672 continue
673 }
674
675 if found_fee {
676 error!(
677 target: "validator::verification::verify_transcation",
678 "[VALIDATOR] Transaction {tx_hash} contains multiple fee payment calls"
679 );
680 return Err(TxVerifyFailed::InvalidFee.into())
681 }
682
683 found_fee = true;
684 fee_call_idx = call_idx;
685 }
686
687 if !found_fee {
688 error!(
689 target: "validator::verification::verify_transcation",
690 "[VALIDATOR] Transaction {tx_hash} does not contain fee payment call"
691 );
692 return Err(TxVerifyFailed::InvalidFee.into())
693 }
694 }
695
696 let mut payload = vec![];
698 tx.calls.encode_async(&mut payload).await?;
699
700 let mut _call_payload = vec![];
703
704 let mut circuits_to_verify = vec![];
707
708 for (idx, call) in tx.calls.iter().enumerate() {
710 debug!(target: "validator::verification::verify_transaction", "Executing contract call {idx}");
711
712 if call.data.is_money_pow_reward() {
714 error!(target: "validator::verification::verify_transaction", "Reward transaction detected");
715 return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
716 }
717
718 let (call_idx, call_payload) = if call.data.is_money_fee() {
720 _call_payload = vec![];
721 vec![call.clone()].encode_async(&mut _call_payload).await?;
722 (0_u8, &_call_payload)
723 } else {
724 (idx as u8, &payload)
725 };
726
727 debug!(target: "validator::verification::verify_transaction", "Instantiating WASM runtime");
728 let wasm = overlay.lock().unwrap().contracts.get(call.data.contract_id)?;
729 let mut runtime = Runtime::new(
730 &wasm,
731 overlay.clone(),
732 call.data.contract_id,
733 verifying_block_height,
734 block_target,
735 tx_hash,
736 call_idx,
737 )?;
738
739 debug!(target: "validator::verification::verify_transaction", "Executing \"metadata\" call");
740 let metadata = runtime.metadata(call_payload)?;
741
742 let mut decoder = Cursor::new(&metadata);
744
745 let zkp_pub: Vec<(String, Vec<pallas::Base>)> =
747 AsyncDecodable::decode_async(&mut decoder).await?;
748 let sig_pub: Vec<PublicKey> = AsyncDecodable::decode_async(&mut decoder).await?;
749
750 if decoder.position() != metadata.len() as u64 {
751 error!(
752 target: "validator::verification::verify_transaction",
753 "[VALIDATOR] Failed decoding entire metadata buffer for {tx_hash}:{idx}"
754 );
755 return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
756 }
757
758 debug!(target: "validator::verification::verify_transaction", "Successfully executed \"metadata\" call");
759
760 debug!(target: "validator::verification::verify_transaction", "Performing VerifyingKey lookups from the sled db");
765 for (zkas_ns, _) in &zkp_pub {
766 let inner_vk_map = verifying_keys.get_mut(&call.data.contract_id.to_bytes()).unwrap();
767
768 if inner_vk_map.contains_key(zkas_ns.as_str()) {
774 continue
775 }
776
777 let (zkbin, vk) =
778 overlay.lock().unwrap().contracts.get_zkas(&call.data.contract_id, zkas_ns)?;
779
780 inner_vk_map.insert(zkas_ns.to_string(), vk);
781 circuits_to_verify.push(zkbin);
782 }
783
784 zkp_table.push(zkp_pub);
785 sig_table.push(sig_pub);
786
787 debug!(target: "validator::verification::verify_transaction", "Executing \"exec\" call");
792 let mut state_update = vec![call.data.data[0]];
793 state_update.append(&mut runtime.exec(call_payload)?);
794 debug!(target: "validator::verification::verify_transaction", "Successfully executed \"exec\" call");
795
796 debug!(target: "validator::verification::verify_transaction", "Executing \"apply\" call");
799 runtime.apply(&state_update)?;
800 debug!(target: "validator::verification::verify_transaction", "Successfully executed \"apply\" call");
801
802 if call.data.is_deployment()
805 {
807 debug!(target: "validator::verification::verify_transaction", "Deploying new contract");
808 let deploy_params: DeployParamsV1 = deserialize_async(&call.data.data[1..]).await?;
810 let deploy_cid = ContractId::derive_public(deploy_params.public_key);
811
812 let mut deploy_runtime = Runtime::new(
814 &deploy_params.wasm_bincode,
815 overlay.clone(),
816 deploy_cid,
817 verifying_block_height,
818 block_target,
819 tx_hash,
820 call_idx,
821 )?;
822
823 deploy_runtime.deploy(&deploy_params.ix)?;
824
825 let deploy_gas_used = deploy_runtime.gas_used();
826 debug!(target: "validator::verification::verify_transaction", "The gas used for deployment call {call:?} of transaction {tx_hash}: {deploy_gas_used}");
827 gas_data.deployments = gas_data.deployments.saturating_add(deploy_gas_used);
828 }
829
830 let wasm_gas_used = runtime.gas_used();
833 debug!(target: "validator::verification::verify_transaction", "The gas used for WASM call {call:?} of transaction {tx_hash}: {wasm_gas_used}");
834
835 gas_data.wasm = gas_data.wasm.saturating_add(wasm_gas_used);
837 }
838
839 gas_data.signatures = PALLAS_SCHNORR_SIGNATURE_FEE
841 .saturating_mul(tx.signatures.len() as u64)
842 .saturating_add(serialize_async(tx).await.len() as u64);
843 debug!(target: "validator::verification::verify_transaction", "The gas used for signature of transaction {tx_hash}: {}", gas_data.signatures);
844
845 for zkbin in circuits_to_verify.iter() {
848 let zk_circuit_gas_used = circuit_gas_use(zkbin);
849 debug!(target: "validator::verification::verify_transaction", "The gas used for ZK circuit in namespace {} of transaction {tx_hash}: {zk_circuit_gas_used}", zkbin.namespace);
850
851 gas_data.zk_circuits = gas_data.zk_circuits.saturating_add(zk_circuit_gas_used);
853 }
854
855 let total_gas_used = gas_data.total_gas_used();
858
859 if verify_fee {
860 let fee: u64 = match deserialize_async(&tx.calls[fee_call_idx].data.data[1..9]).await {
862 Ok(v) => v,
863 Err(e) => {
864 error!(
865 target: "validator::verification::verify_transaction",
866 "[VALIDATOR] Failed deserializing tx {tx_hash} fee call: {e}"
867 );
868 return Err(TxVerifyFailed::InvalidFee.into())
869 }
870 };
871
872 let required_fee = compute_fee(&total_gas_used);
874
875 if required_fee > fee {
878 error!(
879 target: "validator::verification::verify_transaction",
880 "[VALIDATOR] Transaction {tx_hash} has insufficient fee. Required: {required_fee}, Paid: {fee}"
881 );
882 return Err(TxVerifyFailed::InsufficientFee.into())
883 }
884 debug!(target: "validator::verification::verify_transaction", "The gas paid for transaction {tx_hash}: {}", gas_data.paid);
885
886 gas_data.paid = fee;
888 }
889
890 debug!(target: "validator::verification::verify_transaction", "Verifying signatures for transaction {tx_hash}");
895 if sig_table.len() != tx.signatures.len() {
896 error!(
897 target: "validator::verification::verify_transaction",
898 "[VALIDATOR] Incorrect number of signatures in tx {tx_hash}"
899 );
900 return Err(TxVerifyFailed::MissingSignatures.into())
901 }
902
903 if let Err(e) = tx.verify_sigs(sig_table) {
904 error!(
905 target: "validator::verification::verify_transaction",
906 "[VALIDATOR] Signature verification for tx {tx_hash} failed: {e}"
907 );
908 return Err(TxVerifyFailed::InvalidSignature.into())
909 }
910 debug!(target: "validator::verification::verify_transaction", "Signature verification successful");
911
912 debug!(target: "validator::verification::verify_transaction", "Verifying ZK proofs for transaction {tx_hash}");
913 if let Err(e) = tx.verify_zkps(verifying_keys, zkp_table).await {
914 error!(
915 target: "validator::verification::verify_transaction",
916 "[VALIDATOR] ZK proof verification for tx {tx_hash} failed: {e}"
917 );
918 return Err(TxVerifyFailed::InvalidZkProof.into())
919 }
920 debug!(target: "validator::verification::verify_transaction", "ZK proof verification successful");
921
922 append_tx_to_merkle_tree(tree, tx);
924
925 debug!(target: "validator::verification::verify_transaction", "The total gas used for transaction {tx_hash}: {total_gas_used}");
926 debug!(target: "validator::verification::verify_transaction", "Transaction {tx_hash} verified successfully");
927 Ok(gas_data)
928}
929
930pub async fn apply_transaction(
933 overlay: &BlockchainOverlayPtr,
934 verifying_block_height: u32,
935 block_target: u32,
936 tx: &Transaction,
937 tree: &mut MerkleTree,
938) -> Result<()> {
939 let tx_hash = tx.hash();
940 debug!(target: "validator::verification::apply_transaction", "Applying transaction {tx_hash}");
941
942 let mut payload = vec![];
944 tx.calls.encode_async(&mut payload).await?;
945
946 for (idx, call) in tx.calls.iter().enumerate() {
948 debug!(target: "validator::verification::apply_transaction", "Executing contract call {idx}");
949
950 debug!(target: "validator::verification::apply_transaction", "Instantiating WASM runtime");
951 let wasm = overlay.lock().unwrap().contracts.get(call.data.contract_id)?;
952 let mut runtime = Runtime::new(
953 &wasm,
954 overlay.clone(),
955 call.data.contract_id,
956 verifying_block_height,
957 block_target,
958 tx_hash,
959 idx as u8,
960 )?;
961
962 debug!(target: "validator::verification::apply_transaction", "Executing \"exec\" call");
966 let mut state_update = vec![call.data.data[0]];
967 state_update.append(&mut runtime.exec(&payload)?);
968 debug!(target: "validator::verification::apply_transaction", "Successfully executed \"exec\" call");
969
970 debug!(target: "validator::verification::apply_transaction", "Executing \"apply\" call");
973 runtime.apply(&state_update)?;
974 debug!(target: "validator::verification::apply_transaction", "Successfully executed \"apply\" call");
975
976 if call.data.is_deployment()
979 {
981 debug!(target: "validator::verification::apply_transaction", "Deploying new contract");
982 let deploy_params: DeployParamsV1 = deserialize_async(&call.data.data[1..]).await?;
984 let deploy_cid = ContractId::derive_public(deploy_params.public_key);
985
986 let mut deploy_runtime = Runtime::new(
988 &deploy_params.wasm_bincode,
989 overlay.clone(),
990 deploy_cid,
991 verifying_block_height,
992 block_target,
993 tx_hash,
994 idx as u8,
995 )?;
996
997 deploy_runtime.deploy(&deploy_params.ix)?;
998 }
999 }
1000
1001 append_tx_to_merkle_tree(tree, tx);
1003
1004 debug!(target: "validator::verification::apply_transaction", "Transaction {tx_hash} applied successfully");
1005 Ok(())
1006}
1007
1008pub async fn verify_transactions(
1018 overlay: &BlockchainOverlayPtr,
1019 verifying_block_height: u32,
1020 block_target: u32,
1021 txs: &[Transaction],
1022 tree: &mut MerkleTree,
1023 verify_fees: bool,
1024) -> Result<(u64, u64)> {
1025 debug!(target: "validator::verification::verify_transactions", "Verifying {} transactions", txs.len());
1026 if txs.is_empty() {
1027 return Ok((0, 0))
1028 }
1029
1030 let mut erroneous_txs = vec![];
1032
1033 let mut total_gas_used = 0_u64;
1035 let mut total_gas_paid = 0_u64;
1036
1037 let mut vks: HashMap<[u8; 32], HashMap<String, VerifyingKey>> = HashMap::new();
1039
1040 for tx in txs {
1042 for call in &tx.calls {
1043 vks.insert(call.data.contract_id.to_bytes(), HashMap::new());
1044 }
1045 }
1046
1047 for tx in txs {
1049 overlay.lock().unwrap().checkpoint();
1050 let gas_data = match verify_transaction(
1051 overlay,
1052 verifying_block_height,
1053 block_target,
1054 tx,
1055 tree,
1056 &mut vks,
1057 verify_fees,
1058 )
1059 .await
1060 {
1061 Ok(gas_values) => gas_values,
1062 Err(e) => {
1063 warn!(target: "validator::verification::verify_transactions", "Transaction verification failed: {e}");
1064 erroneous_txs.push(tx.clone());
1065 overlay.lock().unwrap().revert_to_checkpoint();
1066 continue
1067 }
1068 };
1069
1070 let tx_gas_used = gas_data.total_gas_used();
1072
1073 let accumulated_gas_usage = total_gas_used.saturating_add(tx_gas_used);
1075
1076 if accumulated_gas_usage > BLOCK_GAS_LIMIT {
1079 warn!(
1080 target: "validator::verification::verify_transactions",
1081 "Transaction {} exceeds configured transaction gas limit: {accumulated_gas_usage} - {BLOCK_GAS_LIMIT}",
1082 tx.hash()
1083 );
1084 erroneous_txs.push(tx.clone());
1085 overlay.lock().unwrap().revert_to_checkpoint();
1086 break
1087 }
1088
1089 total_gas_used = total_gas_used.saturating_add(tx_gas_used);
1091 total_gas_paid = total_gas_paid.saturating_add(gas_data.paid);
1092 }
1093
1094 if !erroneous_txs.is_empty() {
1095 return Err(TxVerifyFailed::ErroneousTxs(erroneous_txs).into())
1096 }
1097
1098 Ok((total_gas_used, total_gas_paid))
1099}
1100
1101async fn apply_transactions(
1106 overlay: &BlockchainOverlayPtr,
1107 verifying_block_height: u32,
1108 block_target: u32,
1109 txs: &[Transaction],
1110 tree: &mut MerkleTree,
1111) -> Result<()> {
1112 debug!(target: "validator::verification::apply_transactions", "Applying {} transactions", txs.len());
1113 if txs.is_empty() {
1114 return Ok(())
1115 }
1116
1117 let mut erroneous_txs = vec![];
1119
1120 for tx in txs {
1122 overlay.lock().unwrap().checkpoint();
1123 if let Err(e) =
1124 apply_transaction(overlay, verifying_block_height, block_target, tx, tree).await
1125 {
1126 warn!(target: "validator::verification::apply_transactions", "Transaction apply failed: {e}");
1127 erroneous_txs.push(tx.clone());
1128 overlay.lock().unwrap().revert_to_checkpoint();
1129 };
1130 }
1131
1132 if !erroneous_txs.is_empty() {
1133 return Err(TxVerifyFailed::ErroneousTxs(erroneous_txs).into())
1134 }
1135
1136 Ok(())
1137}
1138
1139pub async fn verify_proposal(
1149 consensus: &Consensus,
1150 proposal: &Proposal,
1151 is_new: bool,
1152 verify_fees: bool,
1153) -> Result<(Fork, Option<usize>)> {
1154 let proposal_hash = proposal.block.hash();
1156 if proposal.hash != proposal_hash {
1157 warn!(
1158 target: "validator::verification::verify_proposal", "Received proposal contains mismatched hashes: {} - {proposal_hash}",
1159 proposal.hash
1160 );
1161 return Err(Error::ProposalHashesMissmatchError)
1162 }
1163
1164 let (mut fork, index) = consensus.find_extended_fork(proposal).await?;
1166
1167 let previous = fork.overlay.lock().unwrap().last_block()?;
1169
1170 if let Err(e) = verify_block(
1172 &fork.overlay,
1173 &fork.diffs,
1174 &mut fork.module,
1175 &proposal.block,
1176 &previous,
1177 is_new,
1178 verify_fees,
1179 )
1180 .await
1181 {
1182 error!(target: "validator::verification::verify_proposal", "Erroneous proposal block found: {e}");
1183 return Err(Error::BlockIsInvalid(proposal.hash.as_string()))
1184 };
1185
1186 Ok((fork, index))
1187}
1188
1189pub async fn verify_fork_proposal(
1199 fork: &mut Fork,
1200 proposal: &Proposal,
1201 verify_fees: bool,
1202) -> Result<()> {
1203 let proposal_hash = proposal.block.hash();
1205 if proposal.hash != proposal_hash {
1206 warn!(
1207 target: "validator::verification::verify_fork_proposal", "Received proposal contains mismatched hashes: {} - {proposal_hash}",
1208 proposal.hash
1209 );
1210 return Err(Error::ProposalHashesMissmatchError)
1211 }
1212
1213 let previous = fork.overlay.lock().unwrap().last_block()?;
1215
1216 if let Err(e) = verify_block(
1218 &fork.overlay,
1219 &fork.diffs,
1220 &mut fork.module,
1221 &proposal.block,
1222 &previous,
1223 false,
1224 verify_fees,
1225 )
1226 .await
1227 {
1228 error!(target: "validator::verification::verify_fork_proposal", "Erroneous proposal block found: {e}");
1229 return Err(Error::BlockIsInvalid(proposal.hash.as_string()))
1230 };
1231
1232 Ok(())
1233}