consensus.rs 37 KB

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