consensus.rs 34 KB

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