consensus.rs 30 KB

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