consensus.rs 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2025 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, HashSet};
  19. use darkfi_sdk::{crypto::MerkleTree, monotree::Monotree, tx::TransactionHash};
  20. use darkfi_serial::{async_trait, SerialDecodable, SerialEncodable};
  21. use num_bigint::BigUint;
  22. use sled_overlay::database::SledDbOverlayStateDiff;
  23. use smol::lock::RwLock;
  24. use tracing::{debug, info, warn};
  25. use crate::{
  26. blockchain::{
  27. block_store::{BlockDifficulty, BlockRanks},
  28. BlockInfo, Blockchain, BlockchainOverlay, BlockchainOverlayPtr, Header, HeaderHash,
  29. },
  30. runtime::vm_runtime::GAS_LIMIT,
  31. tx::{Transaction, MAX_TX_CALLS},
  32. validator::{
  33. pow::PoWModule,
  34. utils::{best_fork_index, block_rank, find_extended_fork_index},
  35. verification::{verify_proposal, verify_transaction},
  36. RandomXFactory,
  37. },
  38. zk::VerifyingKey,
  39. Error, Result,
  40. };
  41. /// Gas limit for total block transactions(50 full transactions).
  42. pub const BLOCK_GAS_LIMIT: u64 = GAS_LIMIT * MAX_TX_CALLS as u64 * 50;
  43. /// This struct represents the information required by the consensus algorithm
  44. pub struct Consensus {
  45. /// Canonical (confirmed) blockchain
  46. pub blockchain: Blockchain,
  47. /// Fork size(length) after which it can be confirmed
  48. pub confirmation_threshold: usize,
  49. /// RandomXFactory for native PoW
  50. pub darkfi_rx_factory: RandomXFactory,
  51. /// RandomXFactory for Monero PoW
  52. pub monero_rx_factory: RandomXFactory,
  53. /// Fork chains containing block proposals
  54. pub forks: RwLock<Vec<Fork>>,
  55. /// Canonical blockchain PoW module state
  56. pub module: RwLock<PoWModule>,
  57. /// Lock to restrict when proposals appends can happen
  58. pub append_lock: RwLock<()>,
  59. }
  60. impl Consensus {
  61. /// Generate a new Consensus state.
  62. pub fn new(
  63. blockchain: Blockchain,
  64. confirmation_threshold: usize,
  65. pow_target: u32,
  66. pow_fixed_difficulty: Option<BigUint>,
  67. ) -> Result<Self> {
  68. let forks = RwLock::new(vec![]);
  69. let darkfi_rx_factory = RandomXFactory::default();
  70. let monero_rx_factory = RandomXFactory::default();
  71. let module = RwLock::new(PoWModule::new(
  72. blockchain.clone(),
  73. pow_target,
  74. pow_fixed_difficulty,
  75. None,
  76. darkfi_rx_factory.clone(),
  77. monero_rx_factory.clone(),
  78. )?);
  79. let append_lock = RwLock::new(());
  80. Ok(Self {
  81. blockchain,
  82. confirmation_threshold,
  83. darkfi_rx_factory,
  84. monero_rx_factory,
  85. forks,
  86. module,
  87. append_lock,
  88. })
  89. }
  90. /// Generate a new empty fork.
  91. pub async fn generate_empty_fork(&self) -> Result<()> {
  92. debug!(target: "validator::consensus::generate_empty_fork", "Generating new empty fork...");
  93. let mut forks = self.forks.write().await;
  94. // Check if we already have an empty fork
  95. for fork in forks.iter() {
  96. if fork.proposals.is_empty() {
  97. debug!(target: "validator::consensus::generate_empty_fork", "An empty fork already exists.");
  98. drop(forks);
  99. return Ok(())
  100. }
  101. }
  102. let fork = Fork::new(self.blockchain.clone(), self.module.read().await.clone()).await?;
  103. forks.push(fork);
  104. drop(forks);
  105. debug!(target: "validator::consensus::generate_empty_fork", "Fork generated!");
  106. Ok(())
  107. }
  108. /// Given a proposal, the node verifys it and finds which fork it extends.
  109. /// If the proposal extends the canonical blockchain, a new fork chain is created.
  110. pub async fn append_proposal(&self, proposal: &Proposal, verify_fees: bool) -> Result<()> {
  111. debug!(target: "validator::consensus::append_proposal", "Appending proposal {}", proposal.hash);
  112. // Check if proposal already exists
  113. let lock = self.forks.read().await;
  114. for fork in lock.iter() {
  115. for p in fork.proposals.iter().rev() {
  116. if p == &proposal.hash {
  117. drop(lock);
  118. debug!(target: "validator::consensus::append_proposal", "Proposal {} already exists", proposal.hash);
  119. return Err(Error::ProposalAlreadyExists)
  120. }
  121. }
  122. }
  123. // Check if proposal is canonical
  124. if let Ok(canonical_headers) =
  125. self.blockchain.blocks.get_order(&[proposal.block.header.height], true)
  126. {
  127. if canonical_headers[0].unwrap() == proposal.hash {
  128. drop(lock);
  129. debug!(target: "validator::consensus::append_proposal", "Proposal {} already exists", proposal.hash);
  130. return Err(Error::ProposalAlreadyExists)
  131. }
  132. }
  133. drop(lock);
  134. // Verify proposal and grab corresponding fork
  135. let (mut fork, index) = verify_proposal(self, proposal, verify_fees).await?;
  136. // Append proposal to the fork
  137. fork.append_proposal(proposal).await?;
  138. // TODO: to keep memory usage low, we should only append forks that
  139. // are higher ranking than our current best one
  140. // If a fork index was found, replace forks with the mutated one,
  141. // otherwise push the new fork.
  142. let mut lock = self.forks.write().await;
  143. match index {
  144. Some(i) => {
  145. if i < lock.len() && lock[i].proposals == fork.proposals[..fork.proposals.len() - 1]
  146. {
  147. lock[i] = fork;
  148. } else {
  149. lock.push(fork);
  150. }
  151. }
  152. None => {
  153. lock.push(fork);
  154. }
  155. }
  156. drop(lock);
  157. info!(target: "validator::consensus::append_proposal", "Appended proposal {}", proposal.hash);
  158. Ok(())
  159. }
  160. /// Given a proposal, find the fork chain it extends, and return its full clone.
  161. /// If the proposal extends the fork not on its tail, a new fork is created and
  162. /// we re-apply the proposals up to the extending one. If proposal extends canonical,
  163. /// a new fork is created. Additionally, we return the fork index if a new fork
  164. /// was not created, so caller can replace the fork.
  165. pub async fn find_extended_fork(&self, proposal: &Proposal) -> Result<(Fork, Option<usize>)> {
  166. // Grab a lock over current forks
  167. let forks = self.forks.read().await;
  168. // Check if proposal extends any fork
  169. let found = find_extended_fork_index(&forks, proposal);
  170. if found.is_err() {
  171. if let Err(Error::ProposalAlreadyExists) = found {
  172. return Err(Error::ProposalAlreadyExists)
  173. }
  174. // Check if proposal extends canonical
  175. let (last_height, last_block) = self.blockchain.last()?;
  176. if proposal.block.header.previous != last_block ||
  177. proposal.block.header.height <= last_height
  178. {
  179. return Err(Error::ExtendedChainIndexNotFound)
  180. }
  181. // Check if we have an empty fork to use
  182. for (f_index, fork) in forks.iter().enumerate() {
  183. if fork.proposals.is_empty() {
  184. return Ok((forks[f_index].full_clone()?, Some(f_index)))
  185. }
  186. }
  187. // Generate a new fork extending canonical
  188. let fork = Fork::new(self.blockchain.clone(), self.module.read().await.clone()).await?;
  189. return Ok((fork, None))
  190. }
  191. let (f_index, p_index) = found.unwrap();
  192. let original_fork = &forks[f_index];
  193. // Check if proposal extends fork at last proposal
  194. if p_index == (original_fork.proposals.len() - 1) {
  195. return Ok((original_fork.full_clone()?, Some(f_index)))
  196. }
  197. // Rebuild fork
  198. let mut fork = Fork::new(self.blockchain.clone(), self.module.read().await.clone()).await?;
  199. fork.proposals = original_fork.proposals[..p_index + 1].to_vec();
  200. fork.diffs = original_fork.diffs[..p_index + 1].to_vec();
  201. // Retrieve proposals blocks from original fork
  202. let blocks = &original_fork.overlay.lock().unwrap().get_blocks_by_hash(&fork.proposals)?;
  203. for (index, block) in blocks.iter().enumerate() {
  204. // Apply block diffs
  205. fork.overlay.lock().unwrap().overlay.lock().unwrap().add_diff(&fork.diffs[index])?;
  206. // Grab next mine target and difficulty
  207. let (next_target, next_difficulty) = fork.module.next_mine_target_and_difficulty()?;
  208. // Calculate block rank
  209. let (target_distance_sq, hash_distance_sq) = block_rank(block, &next_target)?;
  210. // Update PoW module
  211. fork.module.append(block.header.timestamp, &next_difficulty);
  212. // Update fork ranks
  213. fork.targets_rank += target_distance_sq;
  214. fork.hashes_rank += hash_distance_sq;
  215. }
  216. // Rebuild fork contracts states monotree
  217. fork.compute_monotree()?;
  218. // Drop forks lock
  219. drop(forks);
  220. Ok((fork, None))
  221. }
  222. /// Check if best fork proposals can be confirmed.
  223. /// Consensus confirmation logic:
  224. /// - If the current best fork has reached greater length than the security threshold,
  225. /// and no other fork exist with same rank, first proposal(s) in that fork can be
  226. /// appended to canonical blockchain (confirme).
  227. ///
  228. /// When best fork can be confirmed, first block(s) should be appended to canonical,
  229. /// and forks should be rebuilt.
  230. pub async fn confirmation(&self) -> Result<Option<usize>> {
  231. debug!(target: "validator::consensus::confirmation", "Started confirmation check");
  232. // Grab best fork
  233. let forks = self.forks.read().await;
  234. let index = best_fork_index(&forks)?;
  235. let fork = &forks[index];
  236. // Check its length
  237. let length = fork.proposals.len();
  238. if length < self.confirmation_threshold {
  239. debug!(target: "validator::consensus::confirmation", "Nothing to confirme yet, best fork size: {length}");
  240. drop(forks);
  241. return Ok(None)
  242. }
  243. // Drop forks lock
  244. drop(forks);
  245. Ok(Some(index))
  246. }
  247. /// Auxiliary function to retrieve the fork header hash of provided height.
  248. /// The fork is identified by the provided header hash.
  249. pub async fn get_fork_header_hash(
  250. &self,
  251. height: u32,
  252. fork_header: &HeaderHash,
  253. ) -> Result<Option<HeaderHash>> {
  254. // Grab a lock over current forks
  255. let forks = self.forks.read().await;
  256. // Find the fork containing the provided header
  257. let mut found = None;
  258. 'outer: for (index, fork) in forks.iter().enumerate() {
  259. for p in fork.proposals.iter().rev() {
  260. if p == fork_header {
  261. found = Some(index);
  262. break 'outer
  263. }
  264. }
  265. }
  266. if found.is_none() {
  267. drop(forks);
  268. return Ok(None)
  269. }
  270. let index = found.unwrap();
  271. // Grab header if it exists
  272. let header = forks[index].overlay.lock().unwrap().blocks.get_order(&[height], false)?[0];
  273. // Drop forks lock
  274. drop(forks);
  275. Ok(header)
  276. }
  277. /// Auxiliary function to retrieve the fork headers of provided hashes.
  278. /// The fork is identified by the provided header hash. If fork doesn't
  279. /// exists, an empty vector is returned.
  280. pub async fn get_fork_headers(
  281. &self,
  282. headers: &[HeaderHash],
  283. fork_header: &HeaderHash,
  284. ) -> Result<Vec<Header>> {
  285. // Grab a lock over current forks
  286. let forks = self.forks.read().await;
  287. // Find the fork containing the provided header
  288. let mut found = None;
  289. 'outer: for (index, fork) in forks.iter().enumerate() {
  290. for p in fork.proposals.iter().rev() {
  291. if p == fork_header {
  292. found = Some(index);
  293. break 'outer
  294. }
  295. }
  296. }
  297. let Some(index) = found else {
  298. drop(forks);
  299. return Ok(vec![])
  300. };
  301. // Grab headers
  302. let headers = forks[index].overlay.lock().unwrap().get_headers_by_hash(headers)?;
  303. // Drop forks lock
  304. drop(forks);
  305. Ok(headers)
  306. }
  307. /// Auxiliary function to retrieve the fork proposals of provided hashes.
  308. /// The fork is identified by the provided header hash. If fork doesn't
  309. /// exists, an empty vector is returned.
  310. pub async fn get_fork_proposals(
  311. &self,
  312. headers: &[HeaderHash],
  313. fork_header: &HeaderHash,
  314. ) -> Result<Vec<Proposal>> {
  315. // Grab a lock over current forks
  316. let forks = self.forks.read().await;
  317. // Find the fork containing the provided header
  318. let mut found = None;
  319. 'outer: for (index, fork) in forks.iter().enumerate() {
  320. for p in fork.proposals.iter().rev() {
  321. if p == fork_header {
  322. found = Some(index);
  323. break 'outer
  324. }
  325. }
  326. }
  327. let Some(index) = found else {
  328. drop(forks);
  329. return Ok(vec![])
  330. };
  331. // Grab proposals
  332. let blocks = forks[index].overlay.lock().unwrap().get_blocks_by_hash(headers)?;
  333. let mut proposals = Vec::with_capacity(blocks.len());
  334. for block in blocks {
  335. proposals.push(Proposal::new(block));
  336. }
  337. // Drop forks lock
  338. drop(forks);
  339. Ok(proposals)
  340. }
  341. /// Auxiliary function to retrieve a fork proposals, starting from provided tip.
  342. /// If provided tip is too far behind, unknown, or fork doesn't exists, an empty
  343. /// vector is returned. The fork is identified by the optional provided header hash.
  344. /// If its `None`, we use our best fork.
  345. pub async fn get_fork_proposals_after(
  346. &self,
  347. tip: HeaderHash,
  348. fork_tip: Option<HeaderHash>,
  349. limit: u32,
  350. ) -> Result<Vec<Proposal>> {
  351. // Grab a lock over current forks
  352. let forks = self.forks.read().await;
  353. // Create return vector
  354. let mut proposals = vec![];
  355. // Grab fork index to use
  356. let index = match fork_tip {
  357. Some(fork_tip) => {
  358. let mut found = None;
  359. 'outer: for (index, fork) in forks.iter().enumerate() {
  360. for p in fork.proposals.iter().rev() {
  361. if p == &fork_tip {
  362. found = Some(index);
  363. break 'outer
  364. }
  365. }
  366. }
  367. if found.is_none() {
  368. drop(forks);
  369. return Ok(proposals)
  370. }
  371. found.unwrap()
  372. }
  373. None => best_fork_index(&forks)?,
  374. };
  375. // Check tip exists
  376. let Ok(existing_tips) = forks[index].overlay.lock().unwrap().get_blocks_by_hash(&[tip])
  377. else {
  378. drop(forks);
  379. return Ok(proposals)
  380. };
  381. // Check tip is not far behind
  382. let last_block_height = forks[index].overlay.lock().unwrap().last()?.0;
  383. if last_block_height - existing_tips[0].header.height >= limit {
  384. drop(forks);
  385. return Ok(proposals)
  386. }
  387. // Retrieve all proposals after requested one
  388. let headers = self.blockchain.blocks.get_all_after(existing_tips[0].header.height)?;
  389. let blocks = self.blockchain.get_blocks_by_hash(&headers)?;
  390. for block in blocks {
  391. proposals.push(Proposal::new(block));
  392. }
  393. let blocks =
  394. forks[index].overlay.lock().unwrap().get_blocks_by_hash(&forks[index].proposals)?;
  395. for block in blocks {
  396. proposals.push(Proposal::new(block));
  397. }
  398. // Drop forks lock
  399. drop(forks);
  400. Ok(proposals)
  401. }
  402. /// Auxiliary function to retrieve current best fork last header.
  403. /// If no forks exist, grab the last header from canonical.
  404. pub async fn best_fork_last_header(&self) -> Result<(u32, HeaderHash)> {
  405. // Grab a lock over current forks
  406. let forks = self.forks.read().await;
  407. // Check if node has any forks
  408. if forks.is_empty() {
  409. drop(forks);
  410. return self.blockchain.last()
  411. }
  412. // Grab best fork
  413. let fork = &forks[best_fork_index(&forks)?];
  414. // Grab its last header
  415. let last = fork.last_proposal()?;
  416. drop(forks);
  417. Ok((last.block.header.height, last.hash))
  418. }
  419. /// Auxiliary function to purge current forks and reset the ones starting
  420. /// with the provided prefix, excluding provided confirmed fork.
  421. /// Additionally, remove confirmed transactions from the forks mempools,
  422. /// along with the unporposed transactions sled trees.
  423. /// This function assumes that the prefix blocks have already been appended
  424. /// to canonical chain from the confirmed fork.
  425. pub async fn reset_forks(
  426. &self,
  427. prefix: &[HeaderHash],
  428. confirmed_fork_index: &usize,
  429. confirmed_txs: &[Transaction],
  430. ) -> Result<()> {
  431. // Grab a lock over current forks
  432. let mut forks = self.forks.write().await;
  433. // Find all the forks that start with the provided prefix,
  434. // excluding confirmed fork index, and remove their prefixed
  435. // proposals, and their corresponding diffs.
  436. // If the fork is not starting with the provided prefix,
  437. // drop it. Additionally, keep track of all the referenced
  438. // trees in overlays that are valid.
  439. let excess = prefix.len();
  440. let prefix_last_index = excess - 1;
  441. let prefix_last = prefix.last().unwrap();
  442. let mut keep = vec![true; forks.len()];
  443. let mut referenced_trees = HashSet::new();
  444. let mut referenced_txs = HashSet::new();
  445. let confirmed_txs_hashes: Vec<TransactionHash> =
  446. confirmed_txs.iter().map(|tx| tx.hash()).collect();
  447. for (index, fork) in forks.iter_mut().enumerate() {
  448. if &index == confirmed_fork_index {
  449. // Store its tree references
  450. let fork_overlay = fork.overlay.lock().unwrap();
  451. let overlay = fork_overlay.overlay.lock().unwrap();
  452. for tree in &overlay.state.initial_tree_names {
  453. referenced_trees.insert(tree.clone());
  454. }
  455. for tree in &overlay.state.new_tree_names {
  456. referenced_trees.insert(tree.clone());
  457. }
  458. for tree in overlay.state.dropped_trees.keys() {
  459. referenced_trees.insert(tree.clone());
  460. }
  461. // Remove confirmed proposals txs from fork's mempool
  462. fork.mempool.retain(|tx| !confirmed_txs_hashes.contains(tx));
  463. // Store its txs references
  464. for tx in &fork.mempool {
  465. referenced_txs.insert(*tx);
  466. }
  467. drop(overlay);
  468. drop(fork_overlay);
  469. continue
  470. }
  471. if fork.proposals.is_empty() ||
  472. prefix_last_index >= fork.proposals.len() ||
  473. &fork.proposals[prefix_last_index] != prefix_last
  474. {
  475. keep[index] = false;
  476. continue
  477. }
  478. // Remove confirmed proposals txs from fork's mempool
  479. fork.mempool.retain(|tx| !confirmed_txs_hashes.contains(tx));
  480. // Store its txs references
  481. for tx in &fork.mempool {
  482. referenced_txs.insert(*tx);
  483. }
  484. // Remove the commited differences
  485. let rest_proposals = fork.proposals.split_off(excess);
  486. let rest_diffs = fork.diffs.split_off(excess);
  487. let mut diffs = fork.diffs.clone();
  488. fork.proposals = rest_proposals;
  489. fork.diffs = rest_diffs;
  490. for diff in diffs.iter_mut() {
  491. fork.overlay.lock().unwrap().overlay.lock().unwrap().remove_diff(diff);
  492. }
  493. // Store its tree references
  494. let fork_overlay = fork.overlay.lock().unwrap();
  495. let overlay = fork_overlay.overlay.lock().unwrap();
  496. for tree in &overlay.state.initial_tree_names {
  497. referenced_trees.insert(tree.clone());
  498. }
  499. for tree in &overlay.state.new_tree_names {
  500. referenced_trees.insert(tree.clone());
  501. }
  502. for tree in overlay.state.dropped_trees.keys() {
  503. referenced_trees.insert(tree.clone());
  504. }
  505. drop(overlay);
  506. drop(fork_overlay);
  507. }
  508. // Find the trees and pending txs that are no longer referenced by valid forks
  509. let mut dropped_trees = HashSet::new();
  510. let mut dropped_txs = HashSet::new();
  511. for (index, fork) in forks.iter_mut().enumerate() {
  512. if keep[index] {
  513. continue
  514. }
  515. for tx in &fork.mempool {
  516. if !referenced_txs.contains(tx) {
  517. dropped_txs.insert(*tx);
  518. }
  519. }
  520. let fork_overlay = fork.overlay.lock().unwrap();
  521. let overlay = fork_overlay.overlay.lock().unwrap();
  522. for tree in &overlay.state.initial_tree_names {
  523. if !referenced_trees.contains(tree) {
  524. dropped_trees.insert(tree.clone());
  525. }
  526. }
  527. for tree in &overlay.state.new_tree_names {
  528. if !referenced_trees.contains(tree) {
  529. dropped_trees.insert(tree.clone());
  530. }
  531. }
  532. for tree in overlay.state.dropped_trees.keys() {
  533. if !referenced_trees.contains(tree) {
  534. dropped_trees.insert(tree.clone());
  535. }
  536. }
  537. drop(overlay);
  538. drop(fork_overlay);
  539. }
  540. // Drop unreferenced trees from the database
  541. for tree in dropped_trees {
  542. self.blockchain.sled_db.drop_tree(tree)?;
  543. }
  544. // Drop invalid forks
  545. let mut iter = keep.iter();
  546. forks.retain(|_| *iter.next().unwrap());
  547. // Remove confirmed proposals txs from the unporposed txs sled tree
  548. self.blockchain.remove_pending_txs_hashes(&confirmed_txs_hashes)?;
  549. // Remove unreferenced txs from the unporposed txs sled tree
  550. self.blockchain.remove_pending_txs_hashes(&Vec::from_iter(dropped_txs))?;
  551. // Drop forks lock
  552. drop(forks);
  553. Ok(())
  554. }
  555. /// Auxiliary function to fully purge current forks and leave only a new empty fork.
  556. pub async fn purge_forks(&self) -> Result<()> {
  557. debug!(target: "validator::consensus::purge_forks", "Purging current forks...");
  558. let mut forks = self.forks.write().await;
  559. *forks = vec![Fork::new(self.blockchain.clone(), self.module.read().await.clone()).await?];
  560. drop(forks);
  561. debug!(target: "validator::consensus::purge_forks", "Forks purged!");
  562. Ok(())
  563. }
  564. /// Auxiliary function to reset PoW module.
  565. pub async fn reset_pow_module(&self) -> Result<()> {
  566. debug!(target: "validator::consensus::reset_pow_module", "Resetting PoW module...");
  567. let mut module = self.module.write().await;
  568. *module = PoWModule::new(
  569. self.blockchain.clone(),
  570. module.target,
  571. module.fixed_difficulty.clone(),
  572. None,
  573. self.darkfi_rx_factory.clone(),
  574. self.monero_rx_factory.clone(),
  575. )?;
  576. drop(module);
  577. debug!(target: "validator::consensus::reset_pow_module", "PoW module reset successfully!");
  578. Ok(())
  579. }
  580. /// Auxiliary function to check current contracts states checksums
  581. /// Monotree(SMT) validity in all active forks and canonical.
  582. pub async fn healthcheck(&self) -> Result<()> {
  583. // Grab a lock over current forks
  584. let lock = self.forks.read().await;
  585. // Rebuild current canonical contract states checksums monotree
  586. let state_monotree = self.blockchain.get_state_monotree()?;
  587. // Check that the root matches last block header state root
  588. let Some(state_root) = state_monotree.get_headroot()? else {
  589. return Err(Error::ContractsStatesRootNotFoundError);
  590. };
  591. let last_block_state_root = self.blockchain.last_header()?.state_root;
  592. if state_root != last_block_state_root {
  593. return Err(Error::ContractsStatesRootError(
  594. blake3::Hash::from_bytes(state_root).to_string(),
  595. blake3::Hash::from_bytes(last_block_state_root).to_string(),
  596. ));
  597. }
  598. // Check each fork health
  599. for fork in lock.iter() {
  600. fork.healthcheck()?;
  601. }
  602. Ok(())
  603. }
  604. }
  605. /// This struct represents a block proposal, used for consensus.
  606. #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
  607. pub struct Proposal {
  608. /// Block hash
  609. pub hash: HeaderHash,
  610. /// Block data
  611. pub block: BlockInfo,
  612. }
  613. impl Proposal {
  614. pub fn new(block: BlockInfo) -> Self {
  615. let hash = block.hash();
  616. Self { hash, block }
  617. }
  618. }
  619. impl From<Proposal> for BlockInfo {
  620. fn from(proposal: Proposal) -> BlockInfo {
  621. proposal.block
  622. }
  623. }
  624. /// Struct representing a forked blockchain state.
  625. ///
  626. /// An overlay over the original blockchain is used, containing all pending to-write
  627. /// records. Additionally, each fork keeps a vector of valid pending transactions hashes,
  628. /// in order of receival, and the proposals hashes sequence, for validations.
  629. #[derive(Clone)]
  630. pub struct Fork {
  631. /// Canonical (confirmed) blockchain
  632. pub blockchain: Blockchain,
  633. /// Overlay cache over canonical Blockchain
  634. pub overlay: BlockchainOverlayPtr,
  635. /// Current PoW module state
  636. pub module: PoWModule,
  637. /// Current contracts states checksums Monotree(SMT)
  638. pub state_monotree: Monotree,
  639. /// Fork proposal hashes sequence
  640. pub proposals: Vec<HeaderHash>,
  641. /// Fork proposal overlay diffs sequence
  642. pub diffs: Vec<SledDbOverlayStateDiff>,
  643. /// Valid pending transaction hashes
  644. pub mempool: Vec<TransactionHash>,
  645. /// Current fork mining targets rank, cached for better performance
  646. pub targets_rank: BigUint,
  647. /// Current fork hashes rank, cached for better performance
  648. pub hashes_rank: BigUint,
  649. }
  650. impl Fork {
  651. pub async fn new(blockchain: Blockchain, module: PoWModule) -> Result<Self> {
  652. let mempool = blockchain.get_pending_txs()?.iter().map(|tx| tx.hash()).collect();
  653. let overlay = BlockchainOverlay::new(&blockchain)?;
  654. // Build current contract states checksums monotree
  655. let state_monotree = overlay.lock().unwrap().get_state_monotree()?;
  656. // Retrieve last block difficulty to access current ranks
  657. let last_difficulty = blockchain.last_block_difficulty()?;
  658. let targets_rank = last_difficulty.ranks.targets_rank;
  659. let hashes_rank = last_difficulty.ranks.hashes_rank;
  660. Ok(Self {
  661. blockchain,
  662. overlay,
  663. module,
  664. state_monotree,
  665. proposals: vec![],
  666. diffs: vec![],
  667. mempool,
  668. targets_rank,
  669. hashes_rank,
  670. })
  671. }
  672. /// Auxiliary function to append a proposal and update current fork rank.
  673. pub async fn append_proposal(&mut self, proposal: &Proposal) -> Result<()> {
  674. // Grab next mine target and difficulty
  675. let (next_target, next_difficulty) = self.module.next_mine_target_and_difficulty()?;
  676. // Calculate block rank
  677. let (target_distance_sq, hash_distance_sq) = block_rank(&proposal.block, &next_target)?;
  678. // Update fork ranks
  679. self.targets_rank += target_distance_sq.clone();
  680. self.hashes_rank += hash_distance_sq.clone();
  681. // Generate block difficulty and update PoW module
  682. let cumulative_difficulty =
  683. self.module.cumulative_difficulty.clone() + next_difficulty.clone();
  684. let ranks = BlockRanks::new(
  685. target_distance_sq,
  686. self.targets_rank.clone(),
  687. hash_distance_sq,
  688. self.hashes_rank.clone(),
  689. );
  690. let block_difficulty = BlockDifficulty::new(
  691. proposal.block.header.height,
  692. proposal.block.header.timestamp,
  693. next_difficulty,
  694. cumulative_difficulty,
  695. ranks,
  696. );
  697. self.module.append_difficulty(&self.overlay, block_difficulty)?;
  698. // Push proposal's hash
  699. self.proposals.push(proposal.hash);
  700. // Push proposal overlay diff
  701. self.diffs.push(self.overlay.lock().unwrap().overlay.lock().unwrap().diff(&self.diffs)?);
  702. Ok(())
  703. }
  704. /// Auxiliary function to retrieve last proposal.
  705. pub fn last_proposal(&self) -> Result<Proposal> {
  706. let block = if let Some(last) = self.proposals.last() {
  707. self.overlay.lock().unwrap().get_blocks_by_hash(&[*last])?[0].clone()
  708. } else {
  709. self.overlay.lock().unwrap().last_block()?
  710. };
  711. Ok(Proposal::new(block))
  712. }
  713. /// Auxiliary function to compute forks' next block height.
  714. pub fn get_next_block_height(&self) -> Result<u32> {
  715. let proposal = self.last_proposal()?;
  716. Ok(proposal.block.header.height + 1)
  717. }
  718. /// Auxiliary function to retrieve unproposed valid transactions,
  719. /// along with their total gas used, total paid fees and the overlay
  720. /// used to verify the transactions for further processing.
  721. ///
  722. /// Note: Always remember to purge new trees from the overlay if not needed.
  723. pub async fn unproposed_txs(
  724. &self,
  725. blockchain: &Blockchain,
  726. verifying_block_height: u32,
  727. block_target: u32,
  728. verify_fees: bool,
  729. ) -> Result<(Vec<Transaction>, u64, u64, BlockchainOverlayPtr)> {
  730. // Clone forks' overlay
  731. let overlay = self.overlay.lock().unwrap().full_clone()?;
  732. // Check if our mempool is not empty
  733. if self.mempool.is_empty() {
  734. return Ok((vec![], 0, 0, overlay))
  735. }
  736. // Transactions Merkle tree
  737. let mut tree = MerkleTree::new(1);
  738. // Total gas accumulators
  739. let mut total_gas_used = 0;
  740. let mut total_gas_paid = 0;
  741. // Map of ZK proof verifying keys for the current transaction batch
  742. let mut vks: HashMap<[u8; 32], HashMap<String, VerifyingKey>> = HashMap::new();
  743. // Grab all current proposals transactions hashes
  744. let proposals_txs = overlay.lock().unwrap().get_blocks_txs_hashes(&self.proposals)?;
  745. // Iterate through all pending transactions in the forks' mempool
  746. let mut unproposed_txs = vec![];
  747. for tx in &self.mempool {
  748. // If the hash is contained in the proposals transactions vec, skip it
  749. if proposals_txs.contains(tx) {
  750. continue
  751. }
  752. // Retrieve the actual unproposed transaction
  753. let unproposed_tx =
  754. blockchain.transactions.get_pending(&[*tx], true)?[0].clone().unwrap();
  755. // Update the verifying keys map
  756. for call in &unproposed_tx.calls {
  757. vks.entry(call.data.contract_id.to_bytes()).or_default();
  758. }
  759. // Verify the transaction against current state
  760. overlay.lock().unwrap().checkpoint();
  761. let gas_data = match verify_transaction(
  762. &overlay,
  763. verifying_block_height,
  764. block_target,
  765. &unproposed_tx,
  766. &mut tree,
  767. &mut vks,
  768. verify_fees,
  769. )
  770. .await
  771. {
  772. Ok(gas_values) => gas_values,
  773. Err(e) => {
  774. debug!(target: "validator::consensus::unproposed_txs", "Transaction verification failed: {e}");
  775. overlay.lock().unwrap().revert_to_checkpoint()?;
  776. continue
  777. }
  778. };
  779. // Store the gas used by the verified transaction
  780. let tx_gas_used = gas_data.total_gas_used();
  781. // Calculate current accumulated gas usage
  782. let accumulated_gas_usage = total_gas_used + tx_gas_used;
  783. // Check gas limit - if accumulated gas used exceeds it, break out of loop
  784. if accumulated_gas_usage > BLOCK_GAS_LIMIT {
  785. warn!(
  786. target: "validator::consensus::unproposed_txs",
  787. "Retrieving transaction {tx} would exceed configured unproposed transaction gas limit: {accumulated_gas_usage} - {BLOCK_GAS_LIMIT}"
  788. );
  789. overlay.lock().unwrap().revert_to_checkpoint()?;
  790. break
  791. }
  792. // Update accumulated total gas
  793. total_gas_used += tx_gas_used;
  794. total_gas_paid += gas_data.paid;
  795. // Push the tx hash into the unproposed transactions vector
  796. unproposed_txs.push(unproposed_tx);
  797. }
  798. Ok((unproposed_txs, total_gas_used, total_gas_paid, overlay))
  799. }
  800. /// Auxiliary function to create a full clone using BlockchainOverlay::full_clone.
  801. /// Changes to this copy don't affect original fork overlay records, since underlying
  802. /// overlay pointer have been updated to the cloned one.
  803. pub fn full_clone(&self) -> Result<Self> {
  804. let blockchain = self.blockchain.clone();
  805. let overlay = self.overlay.lock().unwrap().full_clone()?;
  806. let module = self.module.clone();
  807. let state_monotree = self.state_monotree.clone();
  808. let proposals = self.proposals.clone();
  809. let diffs = self.diffs.clone();
  810. let mempool = self.mempool.clone();
  811. let targets_rank = self.targets_rank.clone();
  812. let hashes_rank = self.hashes_rank.clone();
  813. Ok(Self {
  814. blockchain,
  815. overlay,
  816. module,
  817. state_monotree,
  818. proposals,
  819. diffs,
  820. mempool,
  821. targets_rank,
  822. hashes_rank,
  823. })
  824. }
  825. /// Build current contract states checksums monotree.
  826. pub fn compute_monotree(&mut self) -> Result<()> {
  827. self.state_monotree = self.overlay.lock().unwrap().get_state_monotree()?;
  828. Ok(())
  829. }
  830. /// Auxiliary function to check current contracts states checksums
  831. /// Monotree(SMT) validity.
  832. ///
  833. /// Note: This should be executed on fresh forks and/or when
  834. /// a fork doesn't contain changes over the last appended
  835. // proposal.
  836. pub fn healthcheck(&self) -> Result<()> {
  837. // Rebuild current contract states checksums monotree
  838. let state_monotree = self.overlay.lock().unwrap().get_state_monotree()?;
  839. // Check that it matches forks' tree
  840. let Some(state_root) = state_monotree.get_headroot()? else {
  841. return Err(Error::ContractsStatesRootNotFoundError);
  842. };
  843. let Some(fork_state_root) = self.state_monotree.get_headroot()? else {
  844. return Err(Error::ContractsStatesRootNotFoundError);
  845. };
  846. if state_root != fork_state_root {
  847. return Err(Error::ContractsStatesRootError(
  848. blake3::Hash::from_bytes(state_root).to_string(),
  849. blake3::Hash::from_bytes(fork_state_root).to_string(),
  850. ));
  851. }
  852. // Check that the root matches last block header state root
  853. let last_block_state_root = self.last_proposal()?.block.header.state_root;
  854. if state_root != last_block_state_root {
  855. return Err(Error::ContractsStatesRootError(
  856. blake3::Hash::from_bytes(state_root).to_string(),
  857. blake3::Hash::from_bytes(last_block_state_root).to_string(),
  858. ));
  859. }
  860. Ok(())
  861. }
  862. }