mod.rs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  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 async_std::sync::{Arc, RwLock};
  19. use darkfi_sdk::{blockchain::Slot, crypto::PublicKey};
  20. use darkfi_serial::serialize;
  21. use log::{debug, error, info, warn};
  22. use crate::{
  23. blockchain::{BlockInfo, Blockchain, BlockchainOverlay},
  24. error::TxVerifyFailed,
  25. tx::Transaction,
  26. util::time::TimeKeeper,
  27. Error, Result,
  28. };
  29. /// DarkFi consensus module
  30. pub mod consensus;
  31. use consensus::{next_block_reward, Consensus};
  32. /// Verification functions
  33. pub mod verification;
  34. use verification::{verify_block, verify_genesis_block, verify_transactions};
  35. /// P2P net protocols
  36. pub mod proto;
  37. /// Helper utilities
  38. pub mod utils;
  39. use utils::deploy_native_contracts;
  40. /// Configuration for initializing [`Validator`]
  41. #[derive(Clone)]
  42. pub struct ValidatorConfig {
  43. /// Helper structure to calculate time related operations
  44. pub time_keeper: TimeKeeper,
  45. /// Genesis block
  46. pub genesis_block: BlockInfo,
  47. /// Total amount of minted tokens in genesis block
  48. pub genesis_txs_total: u64,
  49. /// Whitelisted faucet pubkeys (testnet stuff)
  50. pub faucet_pubkeys: Vec<PublicKey>,
  51. /// Flag to enable testing mode
  52. pub testing_mode: bool,
  53. }
  54. impl ValidatorConfig {
  55. pub fn new(
  56. time_keeper: TimeKeeper,
  57. genesis_block: BlockInfo,
  58. genesis_txs_total: u64,
  59. faucet_pubkeys: Vec<PublicKey>,
  60. testing_mode: bool,
  61. ) -> Self {
  62. Self { time_keeper, genesis_block, genesis_txs_total, faucet_pubkeys, testing_mode }
  63. }
  64. }
  65. /// Atomic pointer to validator.
  66. pub type ValidatorPtr = Arc<RwLock<Validator>>;
  67. /// This struct represents a DarkFi validator node.
  68. pub struct Validator {
  69. /// Canonical (finalized) blockchain
  70. pub blockchain: Blockchain,
  71. /// Hot/Live data used by the consensus algorithm
  72. pub consensus: Consensus,
  73. /// Flag signalling node has finished initial sync
  74. pub synced: bool,
  75. /// Flag to enable testing mode
  76. pub testing_mode: bool,
  77. }
  78. impl Validator {
  79. pub async fn new(db: &sled::Db, config: ValidatorConfig) -> Result<ValidatorPtr> {
  80. info!(target: "validator::new", "Initializing Validator");
  81. let testing_mode = config.testing_mode;
  82. info!(target: "validator::new", "Initializing Blockchain");
  83. let blockchain = Blockchain::new(db)?;
  84. // Create an overlay over whole blockchain so we can write stuff
  85. let overlay = BlockchainOverlay::new(&blockchain)?;
  86. // Deploy native wasm contracts
  87. deploy_native_contracts(&overlay, &config.time_keeper, &config.faucet_pubkeys)?;
  88. // Add genesis block if blockchain is empty
  89. if blockchain.genesis().is_err() {
  90. info!(target: "validator::new", "Appending genesis block");
  91. verify_genesis_block(
  92. &overlay,
  93. &config.time_keeper,
  94. &config.genesis_block,
  95. config.genesis_txs_total,
  96. )
  97. .await?;
  98. };
  99. // Write the changes to the actual chain db
  100. overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
  101. info!(target: "validator::new", "Initializing Consensus");
  102. let consensus = Consensus::new(blockchain.clone(), config.time_keeper, testing_mode);
  103. // Create the actual state
  104. let state =
  105. Arc::new(RwLock::new(Self { blockchain, consensus, synced: false, testing_mode }));
  106. info!(target: "validator::new", "Finished initializing validator");
  107. Ok(state)
  108. }
  109. /// The node retrieves a transaction, validates its state transition,
  110. /// and appends it to the pending txs store.
  111. pub async fn append_tx(&mut self, tx: Transaction) -> Result<()> {
  112. let tx_hash = blake3::hash(&serialize(&tx));
  113. // Check if we have already seen this tx
  114. let tx_in_txstore = self.blockchain.transactions.contains(&tx_hash)?;
  115. let tx_in_pending_txs_store = self.blockchain.pending_txs.contains(&tx_hash)?;
  116. if tx_in_txstore || tx_in_pending_txs_store {
  117. info!(target: "validator::append_tx", "We have already seen this tx");
  118. return Err(TxVerifyFailed::AlreadySeenTx(tx_hash.to_string()).into())
  119. }
  120. // Verify state transition
  121. info!(target: "validator::append_tx", "Starting state transition validation");
  122. let tx_vec = [tx];
  123. let mut valid = false;
  124. // Generate a time keeper for current slot
  125. let time_keeper = self.consensus.time_keeper.current();
  126. // If node participates in consensus and holds any forks, iterate over them
  127. // to verify transaction validity in their overlays
  128. for fork in self.consensus.forks.iter_mut() {
  129. // Verify transaction
  130. let erroneous_txs = verify_transactions(&fork.overlay, &time_keeper, &tx_vec).await?;
  131. if !erroneous_txs.is_empty() {
  132. continue
  133. }
  134. valid = true;
  135. // Store transaction hash in forks' mempool
  136. fork.mempool.push(tx_hash);
  137. }
  138. // Verify transaction against canonical state
  139. let overlay = BlockchainOverlay::new(&self.blockchain)?;
  140. let erroneous_txs = verify_transactions(&overlay, &time_keeper, &tx_vec).await?;
  141. if erroneous_txs.is_empty() {
  142. valid = true
  143. }
  144. // Return error if transaction is not valid for canonical or any fork
  145. if !valid {
  146. return Err(TxVerifyFailed::ErroneousTxs(erroneous_txs).into())
  147. }
  148. // Add transaction to pending txs store
  149. self.blockchain.add_pending_txs(&tx_vec)?;
  150. info!(target: "validator::append_tx", "Appended tx to pending txs store");
  151. Ok(())
  152. }
  153. /// The node removes invalid transactions from the pending txs store.
  154. pub async fn purge_pending_txs(&mut self) -> Result<()> {
  155. info!(target: "validator::purge_pending_txs", "Removing invalid transactions from pending transactions store...");
  156. // Check if any pending transactions exist
  157. let pending_txs = self.blockchain.get_pending_txs()?;
  158. if pending_txs.is_empty() {
  159. info!(target: "validator::purge_pending_txs", "No pending transactions found");
  160. return Ok(())
  161. }
  162. // Generate a time keeper for current slot
  163. let time_keeper = self.consensus.time_keeper.current();
  164. let mut removed_txs = vec![];
  165. for tx in pending_txs {
  166. let tx_hash = &blake3::hash(&serialize(&tx));
  167. let tx_vec = [tx.clone()];
  168. let mut valid = false;
  169. // If node participates in consensus and holds any forks, iterate over them
  170. // to verify transaction validity in their overlays
  171. for fork in self.consensus.forks.iter_mut() {
  172. // Verify transaction
  173. let erroneous_txs =
  174. verify_transactions(&fork.overlay, &time_keeper, &tx_vec).await?;
  175. if erroneous_txs.is_empty() {
  176. valid = true;
  177. continue
  178. }
  179. // Remove erroneous transaction from forks' mempool
  180. fork.mempool.retain(|x| x != tx_hash);
  181. }
  182. // Verify transaction against canonical state
  183. let overlay = BlockchainOverlay::new(&self.blockchain)?;
  184. let erroneous_txs = verify_transactions(&overlay, &time_keeper, &tx_vec).await?;
  185. if erroneous_txs.is_empty() {
  186. valid = true
  187. }
  188. // Remove pending transaction if it's not valid for canonical or any fork
  189. if !valid {
  190. removed_txs.push(tx)
  191. }
  192. }
  193. if removed_txs.is_empty() {
  194. info!(target: "validator::purge_pending_txs", "No erroneous transactions found");
  195. return Ok(())
  196. }
  197. info!(target: "validator::purge_pending_txs", "Removing {} erroneous transactions...", removed_txs.len());
  198. self.blockchain.remove_pending_txs(&removed_txs)?;
  199. Ok(())
  200. }
  201. /// The node retrieves a block and tries to add it if it doesn't
  202. /// already exists.
  203. pub async fn append_block(&mut self, block: &BlockInfo) -> Result<()> {
  204. let block_hash = block.blockhash().to_string();
  205. // Check if block already exists
  206. if self.blockchain.has_block(block)? {
  207. debug!(target: "validator::append_block", "We have already seen this block");
  208. return Err(Error::BlockAlreadyExists(block_hash))
  209. }
  210. self.add_blocks(&[block.clone()]).await?;
  211. info!(target: "validator::append_block", "Block added: {}", block_hash);
  212. Ok(())
  213. }
  214. // ==========================
  215. // State transition functions
  216. // ==========================
  217. // TODO TESTNET: Write down all cases below
  218. // State transition checks should be happening in the following cases for a sync node:
  219. // 1) When a finalized block is received
  220. // 2) When a transaction is being broadcasted to us
  221. // State transition checks should be happening in the following cases for a consensus participating node:
  222. // 1) When a finalized block is received
  223. // 2) When a transaction is being broadcasted to us
  224. // ==========================
  225. /// Validate a set of [`BlockInfo`] in sequence and apply them if all are valid.
  226. pub async fn add_blocks(&mut self, blocks: &[BlockInfo]) -> Result<()> {
  227. debug!(target: "validator::add_blocks", "Instantiating BlockchainOverlay");
  228. let overlay = BlockchainOverlay::new(&self.blockchain)?;
  229. // Retrieve last block
  230. let mut previous = &overlay.lock().unwrap().last_block()?;
  231. // Create a time keeper to validate each block
  232. let mut time_keeper = self.consensus.time_keeper.clone();
  233. // Keep track of all blocks transactions to remove them from pending txs store
  234. let mut removed_txs = vec![];
  235. // Validate and insert each block
  236. for block in blocks {
  237. // Use block slot in time keeper
  238. time_keeper.verifying_slot = block.header.slot;
  239. // Retrieve expected reward
  240. let expected_reward = next_block_reward();
  241. // Verify block
  242. if verify_block(
  243. &overlay,
  244. &time_keeper,
  245. block,
  246. previous,
  247. expected_reward,
  248. self.testing_mode,
  249. )
  250. .await
  251. .is_err()
  252. {
  253. error!(target: "validator::add_blocks", "Erroneous block found in set");
  254. overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
  255. return Err(Error::BlockIsInvalid(block.blockhash().to_string()))
  256. };
  257. // Store block transactions
  258. for tx in &block.txs {
  259. removed_txs.push(tx.clone());
  260. }
  261. // Use last inserted block as next iteration previous
  262. previous = block;
  263. }
  264. debug!(target: "validator::add_blocks", "Applying overlay changes");
  265. overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
  266. // Purge pending erroneous txs since canonical state has been changed
  267. self.blockchain.remove_pending_txs(&removed_txs)?;
  268. self.purge_pending_txs().await?;
  269. Ok(())
  270. }
  271. /// Validate a set of [`Transaction`] in sequence and apply them if all are valid.
  272. /// In case any of the transactions fail, they will be returned to the caller.
  273. /// The function takes a boolean called `write` which tells it to actually write
  274. /// the state transitions to the database.
  275. pub async fn add_transactions(
  276. &self,
  277. txs: &[Transaction],
  278. verifying_slot: u64,
  279. write: bool,
  280. ) -> Result<()> {
  281. debug!(target: "validator::add_transactions", "Instantiating BlockchainOverlay");
  282. let overlay = BlockchainOverlay::new(&self.blockchain)?;
  283. // Generate a time keeper using transaction verifying slot
  284. let time_keeper = TimeKeeper::new(
  285. self.consensus.time_keeper.genesis_ts,
  286. self.consensus.time_keeper.epoch_length,
  287. self.consensus.time_keeper.slot_time,
  288. verifying_slot,
  289. );
  290. // Verify all transactions and get erroneous ones
  291. let erroneous_txs = verify_transactions(&overlay, &time_keeper, txs).await?;
  292. let lock = overlay.lock().unwrap();
  293. let mut overlay = lock.overlay.lock().unwrap();
  294. if !erroneous_txs.is_empty() {
  295. warn!(target: "validator::add_transactions", "Erroneous transactions found in set");
  296. overlay.purge_new_trees()?;
  297. return Err(TxVerifyFailed::ErroneousTxs(erroneous_txs).into())
  298. }
  299. if !write {
  300. debug!(target: "validator::add_transactions", "Skipping apply of state updates because write=false");
  301. overlay.purge_new_trees()?;
  302. return Ok(())
  303. }
  304. debug!(target: "validator::add_transactions", "Applying overlay changes");
  305. overlay.apply()?;
  306. Ok(())
  307. }
  308. /// Append to canonical state received slot.
  309. /// This should be only used for test purposes.
  310. pub async fn receive_test_slot(&mut self, slot: &Slot) -> Result<()> {
  311. debug!(target: "validator::receive_test_slot", "Appending slot to ledger");
  312. self.blockchain.slots.insert(&[slot.clone()])?;
  313. Ok(())
  314. }
  315. /// Retrieve all existing blocks and try to apply them
  316. /// to an in memory overlay to verify their correctness.
  317. /// Be careful as this will try to load everything in memory.
  318. pub async fn validate_blockchain(
  319. &self,
  320. genesis_txs_total: u64,
  321. faucet_pubkeys: Vec<PublicKey>,
  322. ) -> Result<()> {
  323. let blocks = self.blockchain.get_all()?;
  324. // An empty blockchain is considered valid
  325. if blocks.is_empty() {
  326. return Ok(())
  327. }
  328. // Create an in memory blockchain overlay
  329. let sled_db = sled::Config::new().temporary(true).open()?;
  330. let blockchain = Blockchain::new(&sled_db)?;
  331. let overlay = BlockchainOverlay::new(&blockchain)?;
  332. // Set previous
  333. let mut previous = &blocks[0];
  334. // Create a time keeper to validate each block
  335. let mut time_keeper = self.consensus.time_keeper.clone();
  336. // Deploy native wasm contracts
  337. deploy_native_contracts(&overlay, &time_keeper, &faucet_pubkeys)?;
  338. // Validate genesis block
  339. verify_genesis_block(&overlay, &time_keeper, previous, genesis_txs_total).await?;
  340. // Validate and insert each block
  341. for block in &blocks[1..] {
  342. // Use block slot in time keeper
  343. time_keeper.verifying_slot = block.header.slot;
  344. // Retrieve expected reward
  345. let expected_reward = next_block_reward();
  346. // Verify block
  347. if verify_block(
  348. &overlay,
  349. &time_keeper,
  350. block,
  351. previous,
  352. expected_reward,
  353. self.testing_mode,
  354. )
  355. .await
  356. .is_err()
  357. {
  358. error!(target: "validator::validate_blockchain", "Erroneous block found in set");
  359. overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
  360. return Err(Error::BlockIsInvalid(block.blockhash().to_string()))
  361. };
  362. // Use last inserted block as next iteration previous
  363. previous = block;
  364. }
  365. Ok(())
  366. }
  367. }