mod.rs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  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::sync::Arc;
  19. use darkfi_sdk::{
  20. blockchain::{expected_reward, Slot},
  21. crypto::PublicKey,
  22. };
  23. use darkfi_serial::serialize;
  24. use log::{debug, error, info, warn};
  25. use num_bigint::BigUint;
  26. use smol::lock::RwLock;
  27. use crate::{
  28. blockchain::{
  29. block_store::{BlockDifficulty, BlockInfo},
  30. Blockchain, BlockchainOverlay,
  31. },
  32. error::TxVerifyFailed,
  33. tx::Transaction,
  34. util::time::TimeKeeper,
  35. Error, Result,
  36. };
  37. /// DarkFi consensus module
  38. pub mod consensus;
  39. use consensus::{Consensus, Proposal};
  40. /// DarkFi PoW module
  41. pub mod pow;
  42. use pow::PoWModule;
  43. /// DarkFi consensus PID controller
  44. pub mod pid;
  45. /// Verification functions
  46. pub mod verification;
  47. use verification::{
  48. verify_block, verify_genesis_block, verify_producer_transaction, verify_proposal,
  49. verify_transactions,
  50. };
  51. /// Validation functions
  52. pub mod validation;
  53. /// Helper utilities
  54. pub mod utils;
  55. use utils::deploy_native_contracts;
  56. /// Base 10 big float implementation for high precision arithmetics
  57. pub mod float_10;
  58. /// Configuration for initializing [`Validator`]
  59. #[derive(Clone)]
  60. pub struct ValidatorConfig {
  61. /// Helper structure to calculate time related operations
  62. pub time_keeper: TimeKeeper,
  63. /// Currently configured finalization security threshold
  64. pub finalization_threshold: usize,
  65. /// Currently configured PoW miner number of threads to use
  66. pub pow_threads: usize,
  67. /// Currently configured PoW target
  68. pub pow_target: usize,
  69. /// Optional fixed difficulty, for testing purposes
  70. pub pow_fixed_difficulty: Option<BigUint>,
  71. /// Genesis block
  72. pub genesis_block: BlockInfo,
  73. /// Total amount of minted tokens in genesis block
  74. pub genesis_txs_total: u64,
  75. /// Whitelisted faucet pubkeys (testnet stuff)
  76. pub faucet_pubkeys: Vec<PublicKey>,
  77. /// Flag to enable PoS testing mode
  78. pub pos_testing_mode: bool,
  79. }
  80. impl ValidatorConfig {
  81. #[allow(clippy::too_many_arguments)]
  82. pub fn new(
  83. time_keeper: TimeKeeper,
  84. finalization_threshold: usize,
  85. pow_threads: usize,
  86. pow_target: usize,
  87. pow_fixed_difficulty: Option<BigUint>,
  88. genesis_block: BlockInfo,
  89. genesis_txs_total: u64,
  90. faucet_pubkeys: Vec<PublicKey>,
  91. pos_testing_mode: bool,
  92. ) -> Self {
  93. Self {
  94. time_keeper,
  95. finalization_threshold,
  96. pow_threads,
  97. pow_target,
  98. pow_fixed_difficulty,
  99. genesis_block,
  100. genesis_txs_total,
  101. faucet_pubkeys,
  102. pos_testing_mode,
  103. }
  104. }
  105. }
  106. /// Atomic pointer to validator.
  107. pub type ValidatorPtr = Arc<RwLock<Validator>>;
  108. /// This struct represents a DarkFi validator node.
  109. pub struct Validator {
  110. /// Canonical (finalized) blockchain
  111. pub blockchain: Blockchain,
  112. /// Hot/Live data used by the consensus algorithm
  113. pub consensus: Consensus,
  114. /// Flag signalling node has finished initial sync
  115. pub synced: bool,
  116. /// Flag to enable PoS testing mode
  117. pub pos_testing_mode: bool,
  118. }
  119. impl Validator {
  120. pub async fn new(db: &sled::Db, config: ValidatorConfig) -> Result<ValidatorPtr> {
  121. info!(target: "validator::new", "Initializing Validator");
  122. let pos_testing_mode = config.pos_testing_mode;
  123. info!(target: "validator::new", "Initializing Blockchain");
  124. let blockchain = Blockchain::new(db)?;
  125. // Create an overlay over whole blockchain so we can write stuff
  126. let overlay = BlockchainOverlay::new(&blockchain)?;
  127. // Deploy native wasm contracts
  128. deploy_native_contracts(&overlay, &config.time_keeper, &config.faucet_pubkeys)?;
  129. // Add genesis block if blockchain is empty
  130. if blockchain.genesis().is_err() {
  131. info!(target: "validator::new", "Appending genesis block");
  132. verify_genesis_block(
  133. &overlay,
  134. &config.time_keeper,
  135. &config.genesis_block,
  136. config.genesis_txs_total,
  137. )
  138. .await?;
  139. };
  140. // Write the changes to the actual chain db
  141. overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
  142. info!(target: "validator::new", "Initializing Consensus");
  143. let consensus = Consensus::new(
  144. blockchain.clone(),
  145. config.time_keeper,
  146. config.finalization_threshold,
  147. config.pow_threads,
  148. config.pow_target,
  149. config.pow_fixed_difficulty,
  150. pos_testing_mode,
  151. )?;
  152. // Create the actual state
  153. let state =
  154. Arc::new(RwLock::new(Self { blockchain, consensus, synced: false, pos_testing_mode }));
  155. info!(target: "validator::new", "Finished initializing validator");
  156. Ok(state)
  157. }
  158. /// The node retrieves a transaction, validates its state transition,
  159. /// and appends it to the pending txs store.
  160. pub async fn append_tx(&mut self, tx: &Transaction) -> Result<()> {
  161. let tx_hash = blake3::hash(&serialize(tx));
  162. // Check if we have already seen this tx
  163. let tx_in_txstore = self.blockchain.transactions.contains(&tx_hash)?;
  164. let tx_in_pending_txs_store = self.blockchain.pending_txs.contains(&tx_hash)?;
  165. if tx_in_txstore || tx_in_pending_txs_store {
  166. info!(target: "validator::append_tx", "We have already seen this tx");
  167. return Err(TxVerifyFailed::AlreadySeenTx(tx_hash.to_string()).into())
  168. }
  169. // Verify state transition
  170. info!(target: "validator::append_tx", "Starting state transition validation");
  171. let tx_vec = [tx.clone()];
  172. let mut valid = false;
  173. // Generate a time keeper for current slot
  174. let time_keeper = self.consensus.time_keeper.current();
  175. // If node participates in consensus and holds any forks, iterate over them
  176. // to verify transaction validity in their overlays
  177. for fork in self.consensus.forks.iter_mut() {
  178. // Clone forks' overlay
  179. let overlay = fork.overlay.lock().unwrap().full_clone()?;
  180. // Verify transaction
  181. let erroneous_txs = verify_transactions(&overlay, &time_keeper, &tx_vec).await?;
  182. if !erroneous_txs.is_empty() {
  183. continue
  184. }
  185. valid = true;
  186. // Store transaction hash in forks' mempool
  187. fork.mempool.push(tx_hash);
  188. }
  189. // Verify transaction against canonical state
  190. let overlay = BlockchainOverlay::new(&self.blockchain)?;
  191. let erroneous_txs = verify_transactions(&overlay, &time_keeper, &tx_vec).await?;
  192. if erroneous_txs.is_empty() {
  193. valid = true
  194. }
  195. // Return error if transaction is not valid for canonical or any fork
  196. if !valid {
  197. return Err(TxVerifyFailed::ErroneousTxs(erroneous_txs).into())
  198. }
  199. // Add transaction to pending txs store
  200. self.blockchain.add_pending_txs(&tx_vec)?;
  201. info!(target: "validator::append_tx", "Appended tx to pending txs store");
  202. Ok(())
  203. }
  204. /// The node removes invalid transactions from the pending txs store.
  205. pub async fn purge_pending_txs(&mut self) -> Result<()> {
  206. info!(target: "validator::purge_pending_txs", "Removing invalid transactions from pending transactions store...");
  207. // Check if any pending transactions exist
  208. let pending_txs = self.blockchain.get_pending_txs()?;
  209. if pending_txs.is_empty() {
  210. info!(target: "validator::purge_pending_txs", "No pending transactions found");
  211. return Ok(())
  212. }
  213. // Generate a time keeper for current slot
  214. let time_keeper = self.consensus.time_keeper.current();
  215. let mut removed_txs = vec![];
  216. for tx in pending_txs {
  217. let tx_hash = &blake3::hash(&serialize(&tx));
  218. let tx_vec = [tx.clone()];
  219. let mut valid = false;
  220. // If node participates in consensus and holds any forks, iterate over them
  221. // to verify transaction validity in their overlays
  222. for fork in self.consensus.forks.iter_mut() {
  223. // Clone forks' overlay
  224. let overlay = fork.overlay.lock().unwrap().full_clone()?;
  225. // Verify transaction
  226. let erroneous_txs = verify_transactions(&overlay, &time_keeper, &tx_vec).await?;
  227. if erroneous_txs.is_empty() {
  228. valid = true;
  229. continue
  230. }
  231. // Remove erroneous transaction from forks' mempool
  232. fork.mempool.retain(|x| x != tx_hash);
  233. }
  234. // Verify transaction against canonical state
  235. let overlay = BlockchainOverlay::new(&self.blockchain)?;
  236. let erroneous_txs = verify_transactions(&overlay, &time_keeper, &tx_vec).await?;
  237. if erroneous_txs.is_empty() {
  238. valid = true
  239. }
  240. // Remove pending transaction if it's not valid for canonical or any fork
  241. if !valid {
  242. removed_txs.push(tx)
  243. }
  244. }
  245. if removed_txs.is_empty() {
  246. info!(target: "validator::purge_pending_txs", "No erroneous transactions found");
  247. return Ok(())
  248. }
  249. info!(target: "validator::purge_pending_txs", "Removing {} erroneous transactions...", removed_txs.len());
  250. self.blockchain.remove_pending_txs(&removed_txs)?;
  251. Ok(())
  252. }
  253. /// The node retrieves a block and tries to add it if it doesn't
  254. /// already exists.
  255. pub async fn append_block(&mut self, block: &BlockInfo) -> Result<()> {
  256. let block_hash = block.hash()?.to_string();
  257. // Check if block already exists
  258. if self.blockchain.has_block(block)? {
  259. debug!(target: "validator::append_block", "We have already seen this block");
  260. return Err(Error::BlockAlreadyExists(block_hash))
  261. }
  262. self.add_blocks(&[block.clone()]).await?;
  263. info!(target: "validator::append_block", "Block added: {}", block_hash);
  264. Ok(())
  265. }
  266. /// The node checks if proposals can be finalized.
  267. /// If proposals are found, node appends them to canonical, excluding the
  268. /// last one, and rebuild the finalized fork to contain the last one.
  269. pub async fn finalization(&mut self) -> Result<Vec<BlockInfo>> {
  270. info!(target: "validator::finalization", "Performing finalization check");
  271. // Grab blocks that can be finalized
  272. let mut finalized = self.consensus.finalization().await?;
  273. if finalized.is_empty() {
  274. info!(target: "validator::finalization", "No proposals can be finalized");
  275. return Ok(vec![])
  276. }
  277. // Exclude last proposal
  278. let last = finalized.pop().unwrap();
  279. // Append finalized blocks
  280. info!(target: "validator::finalization", "Finalizing {} proposals:", finalized.len());
  281. for block in &finalized {
  282. info!(target: "validator::finalization", "\t{}", block.hash()?);
  283. }
  284. self.add_blocks(&finalized).await?;
  285. // Rebuild best fork using last proposal
  286. self.consensus.forks = vec![];
  287. self.consensus.generate_pow_slot()?;
  288. self.consensus.append_proposal(&Proposal::new(last)?).await?;
  289. info!(target: "validator::finalization", "Finalization completed!");
  290. Ok(finalized)
  291. }
  292. // ==========================
  293. // State transition functions
  294. // ==========================
  295. // TODO TESTNET: Write down all cases below
  296. // State transition checks should be happening in the following cases for a sync node:
  297. // 1) When a finalized block is received
  298. // 2) When a transaction is being broadcasted to us
  299. // State transition checks should be happening in the following cases for a consensus participating node:
  300. // 1) When a finalized block is received
  301. // 2) When a transaction is being broadcasted to us
  302. // ==========================
  303. /// Validate a set of [`BlockInfo`] in sequence and apply them if all are valid.
  304. pub async fn add_blocks(&mut self, blocks: &[BlockInfo]) -> Result<()> {
  305. debug!(target: "validator::add_blocks", "Instantiating BlockchainOverlay");
  306. let overlay = BlockchainOverlay::new(&self.blockchain)?;
  307. // Retrieve last block
  308. let mut previous = &overlay.lock().unwrap().last_block()?;
  309. // Create a time keeper and a PoW module to validate each block
  310. let mut time_keeper = self.consensus.time_keeper.clone();
  311. let mut module = self.consensus.module.clone();
  312. // Keep track of all blocks transactions to remove them from pending txs store
  313. let mut removed_txs = vec![];
  314. // Validate and insert each block
  315. for block in blocks {
  316. // Use block height in time keeper
  317. time_keeper.verifying_slot = block.header.height;
  318. // Retrieve expected reward
  319. let expected_reward = expected_reward(time_keeper.verifying_slot);
  320. // Verify block
  321. if verify_block(
  322. &overlay,
  323. &time_keeper,
  324. &module,
  325. block,
  326. previous,
  327. expected_reward,
  328. self.pos_testing_mode,
  329. )
  330. .await
  331. .is_err()
  332. {
  333. error!(target: "validator::add_blocks", "Erroneous block found in set");
  334. overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
  335. return Err(Error::BlockIsInvalid(block.hash()?.to_string()))
  336. };
  337. // Update PoW module
  338. if block.header.version == 1 {
  339. // Generate block difficulty
  340. let difficulty = module.next_difficulty()?;
  341. let cummulative_difficulty =
  342. module.cummulative_difficulty.clone() + difficulty.clone();
  343. let block_difficulty = BlockDifficulty::new(
  344. block.header.height,
  345. block.header.timestamp.0,
  346. difficulty,
  347. cummulative_difficulty,
  348. );
  349. module.append_difficulty(&overlay, block_difficulty)?;
  350. }
  351. // Store block transactions
  352. for tx in &block.txs {
  353. removed_txs.push(tx.clone());
  354. }
  355. // Use last inserted block as next iteration previous
  356. previous = block;
  357. }
  358. debug!(target: "validator::add_blocks", "Applying overlay changes");
  359. overlay.lock().unwrap().overlay.lock().unwrap().apply()?;
  360. // Purge pending erroneous txs since canonical state has been changed
  361. self.blockchain.remove_pending_txs(&removed_txs)?;
  362. self.purge_pending_txs().await?;
  363. // Update PoW module
  364. self.consensus.module = module;
  365. Ok(())
  366. }
  367. /// Validate a set of [`Transaction`] in sequence and apply them if all are valid.
  368. /// In case any of the transactions fail, they will be returned to the caller.
  369. /// The function takes a boolean called `write` which tells it to actually write
  370. /// the state transitions to the database.
  371. pub async fn add_transactions(
  372. &self,
  373. txs: &[Transaction],
  374. verifying_slot: u64,
  375. write: bool,
  376. ) -> Result<()> {
  377. debug!(target: "validator::add_transactions", "Instantiating BlockchainOverlay");
  378. let overlay = BlockchainOverlay::new(&self.blockchain)?;
  379. // Generate a time keeper using transaction verifying slot
  380. let time_keeper = TimeKeeper::new(
  381. self.consensus.time_keeper.genesis_ts,
  382. self.consensus.time_keeper.epoch_length,
  383. self.consensus.time_keeper.slot_time,
  384. verifying_slot,
  385. );
  386. // Verify all transactions and get erroneous ones
  387. let erroneous_txs = verify_transactions(&overlay, &time_keeper, txs).await?;
  388. let lock = overlay.lock().unwrap();
  389. let mut overlay = lock.overlay.lock().unwrap();
  390. if !erroneous_txs.is_empty() {
  391. warn!(target: "validator::add_transactions", "Erroneous transactions found in set");
  392. overlay.purge_new_trees()?;
  393. return Err(TxVerifyFailed::ErroneousTxs(erroneous_txs).into())
  394. }
  395. if !write {
  396. debug!(target: "validator::add_transactions", "Skipping apply of state updates because write=false");
  397. overlay.purge_new_trees()?;
  398. return Ok(())
  399. }
  400. debug!(target: "validator::add_transactions", "Applying overlay changes");
  401. overlay.apply()?;
  402. Ok(())
  403. }
  404. /// Append to canonical state received slot.
  405. /// This should be only used for test purposes.
  406. pub async fn receive_test_slot(&mut self, slot: &Slot) -> Result<()> {
  407. debug!(target: "validator::receive_test_slot", "Appending slot to ledger");
  408. self.blockchain.slots.insert(&[slot.clone()])?;
  409. Ok(())
  410. }
  411. /// Validate a producer `Transaction` and apply it if valid.
  412. /// In case the transactions fail, ir will be returned to the caller.
  413. /// The function takes a boolean called `write` which tells it to actually write
  414. /// the state transitions to the database.
  415. /// This should be only used for test purposes.
  416. pub async fn add_test_producer_transaction(
  417. &self,
  418. tx: &Transaction,
  419. verifying_slot: u64,
  420. block_version: u8,
  421. write: bool,
  422. ) -> Result<()> {
  423. debug!(target: "validator::add_test_producer_transaction", "Instantiating BlockchainOverlay");
  424. let overlay = BlockchainOverlay::new(&self.blockchain)?;
  425. // Generate a time keeper using transaction verifying slot
  426. let time_keeper = TimeKeeper::new(
  427. self.consensus.time_keeper.genesis_ts,
  428. self.consensus.time_keeper.epoch_length,
  429. self.consensus.time_keeper.slot_time,
  430. verifying_slot,
  431. );
  432. // Verify transaction
  433. let mut erroneous_txs = vec![];
  434. if let Err(e) = verify_producer_transaction(&overlay, &time_keeper, tx, block_version).await
  435. {
  436. warn!(target: "validator::add_test_producer_transaction", "Transaction verification failed: {}", e);
  437. erroneous_txs.push(tx.clone());
  438. }
  439. let lock = overlay.lock().unwrap();
  440. let mut overlay = lock.overlay.lock().unwrap();
  441. if !erroneous_txs.is_empty() {
  442. warn!(target: "validator::add_test_producer_transaction", "Erroneous transactions found in set");
  443. overlay.purge_new_trees()?;
  444. return Err(TxVerifyFailed::ErroneousTxs(erroneous_txs).into())
  445. }
  446. if !write {
  447. debug!(target: "validator::add_test_producer_transaction", "Skipping apply of state updates because write=false");
  448. overlay.purge_new_trees()?;
  449. return Ok(())
  450. }
  451. debug!(target: "validator::add_test_producer_transaction", "Applying overlay changes");
  452. overlay.apply()?;
  453. Ok(())
  454. }
  455. /// Retrieve all existing blocks and try to apply them
  456. /// to an in memory overlay to verify their correctness.
  457. /// Be careful as this will try to load everything in memory.
  458. pub async fn validate_blockchain(
  459. &self,
  460. genesis_txs_total: u64,
  461. faucet_pubkeys: Vec<PublicKey>,
  462. pow_threads: usize,
  463. pow_target: usize,
  464. pow_fixed_difficulty: Option<BigUint>,
  465. ) -> Result<()> {
  466. let blocks = self.blockchain.get_all()?;
  467. // An empty blockchain is considered valid
  468. if blocks.is_empty() {
  469. return Ok(())
  470. }
  471. // Create an in memory blockchain overlay
  472. let sled_db = sled::Config::new().temporary(true).open()?;
  473. let blockchain = Blockchain::new(&sled_db)?;
  474. let overlay = BlockchainOverlay::new(&blockchain)?;
  475. // Set previous
  476. let mut previous = &blocks[0];
  477. // Create a time keeper and a PoW module to validate each block
  478. let mut time_keeper = self.consensus.time_keeper.clone();
  479. let mut module =
  480. PoWModule::new(blockchain.clone(), pow_threads, pow_target, pow_fixed_difficulty)?;
  481. // Deploy native wasm contracts
  482. deploy_native_contracts(&overlay, &time_keeper, &faucet_pubkeys)?;
  483. // Validate genesis block
  484. verify_genesis_block(&overlay, &time_keeper, previous, genesis_txs_total).await?;
  485. // Validate and insert each block
  486. for block in &blocks[1..] {
  487. // Use block height in time keeper
  488. time_keeper.verifying_slot = block.header.height;
  489. // Retrieve expected reward
  490. let expected_reward = expected_reward(time_keeper.verifying_slot);
  491. // Verify block
  492. if verify_block(
  493. &overlay,
  494. &time_keeper,
  495. &module,
  496. block,
  497. previous,
  498. expected_reward,
  499. self.pos_testing_mode,
  500. )
  501. .await
  502. .is_err()
  503. {
  504. error!(target: "validator::validate_blockchain", "Erroneous block found in set");
  505. overlay.lock().unwrap().overlay.lock().unwrap().purge_new_trees()?;
  506. return Err(Error::BlockIsInvalid(block.hash()?.to_string()))
  507. };
  508. // Update PoW module
  509. if block.header.version == 1 {
  510. module.append(block.header.timestamp.0, &module.next_difficulty()?);
  511. }
  512. // Use last inserted block as next iteration previous
  513. previous = block;
  514. }
  515. Ok(())
  516. }
  517. }