consensus.rs 32 KB

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