mod.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2023 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, io::Cursor};
  19. use async_std::sync::{Arc, RwLock};
  20. use darkfi_sdk::{blockchain::Slot, crypto::PublicKey, pasta::pallas};
  21. use darkfi_serial::{Decodable, Encodable, WriteExt};
  22. use log::{debug, error, info, warn};
  23. use crate::{
  24. blockchain::{BlockInfo, Blockchain, BlockchainOverlay, BlockchainOverlayPtr},
  25. error::TxVerifyFailed,
  26. runtime::vm_runtime::Runtime,
  27. tx::Transaction,
  28. util::time::TimeKeeper,
  29. zk::VerifyingKey,
  30. Error, Result,
  31. };
  32. /// DarkFi consensus module
  33. pub mod consensus;
  34. use consensus::Consensus;
  35. /// Helper utilities
  36. pub mod utils;
  37. use utils::deploy_native_contracts;
  38. /// Configuration for initializing [`Validator`]
  39. pub struct ValidatorConfig {
  40. /// Helper structure to calculate time related operations
  41. pub time_keeper: TimeKeeper,
  42. /// Genesis block
  43. pub genesis_block: BlockInfo,
  44. /// Whitelisted faucet pubkeys (testnet stuff)
  45. pub faucet_pubkeys: Vec<PublicKey>,
  46. }
  47. impl ValidatorConfig {
  48. pub fn new(
  49. time_keeper: TimeKeeper,
  50. genesis_block: BlockInfo,
  51. faucet_pubkeys: Vec<PublicKey>,
  52. ) -> Self {
  53. Self { time_keeper, genesis_block, faucet_pubkeys }
  54. }
  55. }
  56. /// Atomic pointer to validator.
  57. pub type ValidatorPtr = Arc<RwLock<Validator>>;
  58. /// This struct represents a DarkFi validator node.
  59. pub struct Validator {
  60. /// Canonical (finalized) blockchain
  61. pub blockchain: Blockchain,
  62. /// Hot/Live data used by the consensus algorithm
  63. pub consensus: Consensus,
  64. }
  65. impl Validator {
  66. pub async fn new(db: &sled::Db, config: ValidatorConfig) -> Result<ValidatorPtr> {
  67. info!(target: "validator", "Initializing Validator");
  68. info!(target: "validator", "Initializing Blockchain");
  69. let blockchain = Blockchain::new(db)?;
  70. info!(target: "validator", "Initializing Consensus");
  71. let consensus = Consensus::new(blockchain.clone(), config.time_keeper.clone());
  72. // Create the actual state
  73. let mut state = Self { blockchain: blockchain.clone(), consensus };
  74. // Create an overlay over whole blockchain so we can write stuff
  75. let blockchain_overlay = BlockchainOverlay::new(&blockchain)?;
  76. // Add genesis block if blockchain is empty
  77. let genesis_block = match blockchain.genesis() {
  78. Ok((_, hash)) => hash,
  79. Err(_) => {
  80. info!(target: "validator", "Appending genesis block");
  81. state
  82. .add_blocks(
  83. blockchain_overlay.clone(),
  84. &config.time_keeper,
  85. &[config.genesis_block.clone()],
  86. )
  87. .await?;
  88. config.genesis_block.blockhash()
  89. }
  90. };
  91. state.consensus.genesis_block = genesis_block;
  92. // Deploy native wasm contracts
  93. deploy_native_contracts(
  94. blockchain_overlay.clone(),
  95. &config.time_keeper,
  96. &config.faucet_pubkeys,
  97. )?;
  98. // Write the changes to the actual chain db
  99. blockchain_overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
  100. info!(target: "validator", "Finished initializing validator");
  101. Ok(Arc::new(RwLock::new(state)))
  102. }
  103. // ==========================
  104. // State transition functions
  105. // ==========================
  106. // TODO TESTNET: Write down all cases below
  107. // State transition checks should be happening in the following cases for a sync node:
  108. // 1) When a finalized block is received
  109. // 2) When a transaction is being broadcasted to us
  110. // State transition checks should be happening in the following cases for a consensus participating node:
  111. // 1) When a finalized block is received
  112. // 2) When a transaction is being broadcasted to us
  113. // ==========================
  114. /// Append provided blocks to the provided overlay. Block sequence must be valid,
  115. /// meaning that each block and its transactions are valid, in order.
  116. pub async fn add_blocks(
  117. &self,
  118. overlay: BlockchainOverlayPtr,
  119. _time_keeper: &TimeKeeper,
  120. blocks: &[BlockInfo],
  121. ) -> Result<()> {
  122. // Retrieve last block
  123. let lock = overlay.lock().unwrap();
  124. let mut previous = if !lock.is_empty()? { Some(lock.last_block()?) } else { None };
  125. // Validate and insert each block
  126. for block in blocks {
  127. // Check if block already exists
  128. if lock.has_block(block)? {
  129. return Err(Error::BlockAlreadyExists(block.blockhash().to_string()))
  130. }
  131. // This will be true for every insert, apart from genesis
  132. if let Some(p) = previous {
  133. block.validate(&p)?;
  134. }
  135. // TODO: Add rest block verifications here
  136. /*
  137. let current_slot = self.consensus.time_keeper.current_slot();
  138. if slot.id > current_slot {
  139. return Err(Error::FutureSlotReceived(slot.id))
  140. }
  141. */
  142. // Insert block
  143. lock.add_block(block)?;
  144. // Use last inserted block as next iteration previous
  145. previous = Some(block.clone());
  146. }
  147. Ok(())
  148. }
  149. /// Validate WASM execution, signatures, and ZK proofs for a given [`Transaction`].
  150. async fn verify_transaction(
  151. &self,
  152. blockchain_overlay: BlockchainOverlayPtr,
  153. tx: &Transaction,
  154. time_keeper: &TimeKeeper,
  155. verifying_keys: &mut HashMap<[u8; 32], HashMap<String, VerifyingKey>>,
  156. ) -> Result<()> {
  157. let tx_hash = tx.hash();
  158. debug!(target: "validator", "Validating transaction {}", tx_hash);
  159. // Table of public inputs used for ZK proof verification
  160. let mut zkp_table = vec![];
  161. // Table of public keys used for signature verification
  162. let mut sig_table = vec![];
  163. // Iterate over all calls to get the metadata
  164. for (idx, call) in tx.calls.iter().enumerate() {
  165. debug!(target: "validator", "Executing contract call {}", idx);
  166. // Write the actual payload data
  167. let mut payload = vec![];
  168. payload.write_u32(idx as u32)?; // Call index
  169. tx.calls.encode(&mut payload)?; // Actual call data
  170. debug!(target: "validator", "Instantiating WASM runtime");
  171. let wasm = blockchain_overlay.lock().unwrap().wasm_bincode.get(call.contract_id)?;
  172. let mut runtime = Runtime::new(
  173. &wasm,
  174. blockchain_overlay.clone(),
  175. call.contract_id,
  176. time_keeper.clone(),
  177. )?;
  178. debug!(target: "validator", "Executing \"metadata\" call");
  179. let metadata = runtime.metadata(&payload)?;
  180. // Decode the metadata retrieved from the execution
  181. let mut decoder = Cursor::new(&metadata);
  182. // The tuple is (zkasa_ns, public_inputs)
  183. let zkp_pub: Vec<(String, Vec<pallas::Base>)> = Decodable::decode(&mut decoder)?;
  184. let sig_pub: Vec<PublicKey> = Decodable::decode(&mut decoder)?;
  185. // TODO: Make sure we've read all the bytes above.
  186. debug!(target: "validator", "Successfully executed \"metadata\" call");
  187. // Here we'll look up verifying keys and insert them into the per-contract map.
  188. debug!(target: "validator", "Performing VerifyingKey lookups from the sled db");
  189. for (zkas_ns, _) in &zkp_pub {
  190. let inner_vk_map = verifying_keys.get_mut(&call.contract_id.to_bytes()).unwrap();
  191. // TODO: This will be a problem in case of ::deploy, unless we force a different
  192. // namespace and disable updating existing circuit. Might be a smart idea to do
  193. // so in order to have to care less about being able to verify historical txs.
  194. if inner_vk_map.contains_key(zkas_ns.as_str()) {
  195. continue
  196. }
  197. let (_, vk) = blockchain_overlay
  198. .lock()
  199. .unwrap()
  200. .contracts
  201. .get_zkas(&call.contract_id, zkas_ns)?;
  202. inner_vk_map.insert(zkas_ns.to_string(), vk);
  203. }
  204. zkp_table.push(zkp_pub);
  205. sig_table.push(sig_pub);
  206. // After getting the metadata, we run the "exec" function with the same runtime
  207. // and the same payload.
  208. debug!(target: "validator", "Executing \"exec\" call");
  209. let state_update = runtime.exec(&payload)?;
  210. debug!(target: "validator", "Successfully executed \"exec\" call");
  211. // If that was successful, we apply the state update in the ephemeral overlay.
  212. debug!(target: "validator", "Executing \"apply\" call");
  213. runtime.apply(&state_update)?;
  214. debug!(target: "validator", "Successfully executed \"apply\" call");
  215. // At this point we're done with the call and move on to the next one.
  216. }
  217. // When we're done looping and executing over the tx's contract calls, we now
  218. // move on with verification. First we verify the signatures as that's cheaper,
  219. // and then finally we verify the ZK proofs.
  220. debug!(target: "validator", "Verifying signatures for transaction {}", tx_hash);
  221. if sig_table.len() != tx.signatures.len() {
  222. error!(target: "validator", "Incorrect number of signatures in tx {}", tx_hash);
  223. return Err(TxVerifyFailed::MissingSignatures.into())
  224. }
  225. // TODO: Go through the ZK circuits that have to be verified and account for the opcodes.
  226. if let Err(e) = tx.verify_sigs(sig_table) {
  227. error!(target: "validator", "Signature verification for tx {} failed: {}", tx_hash, e);
  228. return Err(TxVerifyFailed::InvalidSignature.into())
  229. }
  230. debug!(target: "validator", "Signature verification successful");
  231. debug!(target: "validator", "Verifying ZK proofs for transaction {}", tx_hash);
  232. if let Err(e) = tx.verify_zkps(verifying_keys, zkp_table).await {
  233. error!(target: "consensus::validator", "ZK proof verification for tx {} failed: {}", tx_hash, e);
  234. return Err(TxVerifyFailed::InvalidZkProof.into())
  235. }
  236. debug!(target: "validator", "ZK proof verification successful");
  237. debug!(target: "validator", "Transaction {} verified successfully", tx_hash);
  238. Ok(())
  239. }
  240. /// Validate a set of [`Transaction`] in sequence and apply them if all are valid.
  241. /// In case any of the transactions fail, they will be returned to the caller.
  242. /// The function takes a boolean called `write` which tells it to actually write
  243. /// the state transitions to the database.
  244. pub async fn verify_transactions(
  245. &self,
  246. txs: &[Transaction],
  247. verifying_slot: u64,
  248. write: bool,
  249. ) -> Result<()> {
  250. debug!(target: "validator", "Verifying {} transactions", txs.len());
  251. debug!(target: "validator", "Instantiating BlockchainOverlay");
  252. let blockchain_overlay = BlockchainOverlay::new(&self.blockchain)?;
  253. // Tracker for failed txs
  254. let mut erroneous_txs = vec![];
  255. // Map of ZK proof verifying keys for the current transaction batch
  256. let mut vks: HashMap<[u8; 32], HashMap<String, VerifyingKey>> = HashMap::new();
  257. // Initialize the map
  258. for tx in txs {
  259. for call in &tx.calls {
  260. vks.insert(call.contract_id.to_bytes(), HashMap::new());
  261. }
  262. }
  263. // Generate a time keeper using transaction verifying slot
  264. let time_keeper = TimeKeeper::new(
  265. self.consensus.time_keeper.genesis_ts,
  266. self.consensus.time_keeper.epoch_length,
  267. self.consensus.time_keeper.slot_time,
  268. verifying_slot,
  269. );
  270. // Iterate over transactions and attempt to verify them
  271. for tx in txs {
  272. blockchain_overlay.lock().unwrap().checkpoint();
  273. if let Err(e) = self
  274. .verify_transaction(blockchain_overlay.clone(), tx, &time_keeper, &mut vks)
  275. .await
  276. {
  277. warn!(target: "validator", "Transaction verification failed: {}", e);
  278. erroneous_txs.push(tx.clone());
  279. // TODO: verify this works as expected
  280. blockchain_overlay.lock().unwrap().revert_to_checkpoint()?;
  281. }
  282. }
  283. let lock = blockchain_overlay.lock().unwrap();
  284. let mut overlay = lock.overlay.lock().unwrap();
  285. if !erroneous_txs.is_empty() {
  286. warn!(target: "validator", "Erroneous transactions found in set");
  287. overlay.purge_new_trees()?;
  288. return Err(TxVerifyFailed::ErroneousTxs(erroneous_txs).into())
  289. }
  290. if !write {
  291. debug!(target: "validator", "Skipping apply of state updates because write=false");
  292. overlay.purge_new_trees()?;
  293. return Ok(())
  294. }
  295. debug!(target: "validator", "Applying overlay changes");
  296. overlay.apply()?;
  297. Ok(())
  298. }
  299. /// Append to canonical state received slot.
  300. /// This should be only used for test purposes.
  301. pub async fn receive_test_slot(&mut self, slot: &Slot) -> Result<()> {
  302. debug!(target: "validator", "receive_slot(): Appending slot to ledger");
  303. self.blockchain.slots.insert(&[slot.clone()])?;
  304. Ok(())
  305. }
  306. }