consensus.rs 34 KB

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