state.rs 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2023 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::time::Duration;
  19. use chrono::{NaiveDateTime, Utc};
  20. use darkfi_sdk::{
  21. crypto::{constants::MERKLE_DEPTH, MerkleNode},
  22. incrementalmerkletree::bridgetree::BridgeTree,
  23. pasta::{group::ff::PrimeField, pallas},
  24. };
  25. use darkfi_serial::{deserialize, serialize, SerialDecodable, SerialEncodable};
  26. use log::info;
  27. use rand::{thread_rng, Rng};
  28. use sqlx::Row;
  29. use super::{
  30. constants,
  31. lead_coin::{LeadCoin, LeadCoinSecrets},
  32. utils::fbig2base,
  33. Block, BlockProposal, Float10,
  34. };
  35. use crate::{
  36. blockchain::Blockchain, net, tx::Transaction, util::time::Timestamp, wallet::WalletPtr, Error,
  37. Result,
  38. };
  39. use std::{
  40. fs::File,
  41. io::{prelude::*, BufWriter},
  42. };
  43. /// This struct represents the information required by the consensus algorithm
  44. pub struct ConsensusState {
  45. /// Wallet interface
  46. pub wallet: WalletPtr,
  47. /// Canonical (finalized) blockchain
  48. pub blockchain: Blockchain,
  49. /// Network bootstrap timestamp
  50. pub bootstrap_ts: Timestamp,
  51. /// Genesis block creation timestamp
  52. pub genesis_ts: Timestamp,
  53. /// Genesis block hash
  54. pub genesis_block: blake3::Hash,
  55. /// Total sum of initial staking coins
  56. pub initial_distribution: u64,
  57. /// Flag to enable single-node mode
  58. pub single_node: bool,
  59. /// Slot the network was bootstrapped
  60. pub bootstrap_slot: u64,
  61. /// Participating start slot
  62. pub participating: Option<u64>,
  63. /// Node is able to propose proposals
  64. pub proposing: bool,
  65. /// Last slot node check for finalization
  66. pub checked_finalization: u64,
  67. /// Fork chains containing block proposals
  68. pub forks: Vec<Fork>,
  69. /// Current epoch
  70. pub epoch: u64,
  71. /// Hot/live slot checkpoints
  72. pub slot_checkpoints: Vec<SlotCheckpoint>,
  73. /// Last slot leaders count
  74. pub previous_leaders: u64,
  75. /// Controller output history
  76. pub f_history: Vec<Float10>,
  77. /// Controller proportional error history
  78. pub err_history: Vec<Float10>,
  79. // TODO: Aren't these already in db after finalization?
  80. /// Canonical competing coins
  81. pub coins: Vec<LeadCoin>,
  82. /// Canonical coin commitments tree
  83. pub coins_tree: BridgeTree<MerkleNode, MERKLE_DEPTH>,
  84. /// Canonical seen nullifiers from proposals
  85. pub nullifiers: Vec<pallas::Base>,
  86. }
  87. impl ConsensusState {
  88. pub fn new(
  89. wallet: WalletPtr,
  90. blockchain: Blockchain,
  91. bootstrap_ts: Timestamp,
  92. genesis_ts: Timestamp,
  93. genesis_data: blake3::Hash,
  94. initial_distribution: u64,
  95. single_node: bool,
  96. ) -> Result<Self> {
  97. let genesis_block = Block::genesis_block(genesis_ts, genesis_data).blockhash();
  98. Ok(Self {
  99. wallet,
  100. blockchain,
  101. bootstrap_ts,
  102. genesis_ts,
  103. genesis_block,
  104. initial_distribution,
  105. single_node,
  106. bootstrap_slot: 0,
  107. participating: None,
  108. proposing: false,
  109. checked_finalization: 0,
  110. forks: vec![],
  111. epoch: 0,
  112. slot_checkpoints: vec![],
  113. previous_leaders: 0,
  114. f_history: vec![constants::FLOAT10_ZERO.clone()],
  115. err_history: vec![constants::FLOAT10_ZERO.clone(), constants::FLOAT10_ZERO.clone()],
  116. coins: vec![],
  117. coins_tree: BridgeTree::<MerkleNode, MERKLE_DEPTH>::new(constants::EPOCH_LENGTH * 100),
  118. nullifiers: vec![],
  119. })
  120. }
  121. /// Calculates current epoch.
  122. pub fn current_epoch(&self) -> u64 {
  123. self.slot_epoch(self.current_slot())
  124. }
  125. /// Calculates the epoch of the provided slot.
  126. /// Epoch duration is configured using the `EPOCH_LENGTH` value.
  127. pub fn slot_epoch(&self, slot: u64) -> u64 {
  128. slot / constants::EPOCH_LENGTH as u64
  129. }
  130. /// Calculates current slot, based on elapsed time from the genesis block.
  131. /// Slot duration is configured using the `SLOT_TIME` constant.
  132. pub fn current_slot(&self) -> u64 {
  133. self.genesis_ts.elapsed() / constants::SLOT_TIME
  134. }
  135. /// Calculates the relative number of the provided slot.
  136. pub fn relative_slot(&self, slot: u64) -> u64 {
  137. slot % constants::EPOCH_LENGTH as u64
  138. }
  139. /// Finds the last slot a proposal or block was generated.
  140. pub fn last_slot(&self) -> Result<u64> {
  141. let mut slot = 0;
  142. for chain in &self.forks {
  143. for state_checkpoint in &chain.sequence {
  144. if state_checkpoint.proposal.block.header.slot > slot {
  145. slot = state_checkpoint.proposal.block.header.slot;
  146. }
  147. }
  148. }
  149. // We return here in case proposals exist,
  150. // so we don't query the sled database.
  151. if slot > 0 {
  152. return Ok(slot)
  153. }
  154. let (last_slot, _) = self.blockchain.last()?;
  155. Ok(last_slot)
  156. }
  157. /// Calculates seconds until next Nth slot starting time.
  158. /// Slots duration is configured using the SLOT_TIME constant.
  159. pub fn next_n_slot_start(&self, n: u64) -> Duration {
  160. assert!(n > 0);
  161. let start_time = NaiveDateTime::from_timestamp_opt(self.genesis_ts.0, 0).unwrap();
  162. let current_slot = self.current_slot() + n;
  163. let next_slot_start =
  164. (current_slot * constants::SLOT_TIME) + (start_time.timestamp() as u64);
  165. let next_slot_start = NaiveDateTime::from_timestamp_opt(next_slot_start as i64, 0).unwrap();
  166. let current_time = NaiveDateTime::from_timestamp_opt(Utc::now().timestamp(), 0).unwrap();
  167. let diff = next_slot_start - current_time;
  168. Duration::new(diff.num_seconds().try_into().unwrap(), 0)
  169. }
  170. /// Calculate slots until next Nth epoch.
  171. /// Epoch duration is configured using the EPOCH_LENGTH value.
  172. pub fn slots_to_next_n_epoch(&self, n: u64) -> u64 {
  173. assert!(n > 0);
  174. let slots_till_next_epoch =
  175. constants::EPOCH_LENGTH as u64 - self.relative_slot(self.current_slot());
  176. ((n - 1) * constants::EPOCH_LENGTH as u64) + slots_till_next_epoch
  177. }
  178. /// Calculates seconds until next Nth epoch starting time.
  179. pub fn next_n_epoch_start(&self, n: u64) -> Duration {
  180. self.next_n_slot_start(self.slots_to_next_n_epoch(n))
  181. }
  182. /// Set participating slot to next.
  183. pub fn set_participating(&mut self) -> Result<()> {
  184. self.participating = Some(self.current_slot() + 1);
  185. Ok(())
  186. }
  187. /// Generate current slot checkpoint
  188. fn generate_slot_checkpoint(&mut self, sigma1: pallas::Base, sigma2: pallas::Base) {
  189. let slot = self.current_slot();
  190. let eta = self.get_eta();
  191. info!(target: "consensus::state", "generate_slot_checkpoint: slot: {:?}, eta: {:?}", slot, eta);
  192. let checkpoint = SlotCheckpoint { slot, eta, sigma1, sigma2 };
  193. self.slot_checkpoints.push(checkpoint);
  194. }
  195. // Initialize node lead coins and set current epoch and eta.
  196. pub async fn init_coins(&mut self) -> Result<()> {
  197. self.epoch = self.current_epoch();
  198. self.coins = self.create_coins().await?;
  199. self.update_forks_checkpoints();
  200. Ok(())
  201. }
  202. /// Check if new epoch has started and generate slot checkpoint.
  203. /// Returns flag to signify if epoch has changed.
  204. pub async fn epoch_changed(
  205. &mut self,
  206. sigma1: pallas::Base,
  207. sigma2: pallas::Base,
  208. ) -> Result<bool> {
  209. self.generate_slot_checkpoint(sigma1, sigma2);
  210. let epoch = self.current_epoch();
  211. if epoch <= self.epoch {
  212. return Ok(false)
  213. }
  214. self.epoch = epoch;
  215. Ok(true)
  216. }
  217. /// Return 2-term target approximation sigma coefficients.
  218. pub fn sigmas(&mut self) -> (pallas::Base, pallas::Base) {
  219. let f = self.win_inv_prob_with_full_stake();
  220. let total_stake = self.total_stake();
  221. let total_sigma = Float10::try_from(total_stake).unwrap();
  222. self.calc_sigmas(f, total_sigma)
  223. }
  224. fn calc_sigmas(&self, f: Float10, total_sigma: Float10) -> (pallas::Base, pallas::Base) {
  225. info!(target: "consensus::state", "sigmas(): f: {}", f);
  226. info!(target: "consensus::state", "sigmas(): total network stake: {:}", total_sigma);
  227. let one = constants::FLOAT10_ONE.clone();
  228. let neg_one = constants::FLOAT10_NEG_ONE.clone();
  229. let two = constants::FLOAT10_TWO.clone();
  230. let field_p = Float10::try_from(constants::P).unwrap();
  231. let x = one - f;
  232. let c = x.ln();
  233. let neg_c = neg_one * c;
  234. let sigma1_fbig = neg_c.clone() /
  235. (total_sigma.clone() + constants::FLOAT10_EPSILON.clone()) *
  236. field_p.clone();
  237. info!(target: "consensus::state", "sigma1_fbig: {:}", sigma1_fbig);
  238. let sigma1 = fbig2base(sigma1_fbig);
  239. let sigma2_fbig = (neg_c / (total_sigma + constants::FLOAT10_EPSILON.clone()))
  240. .powf(two.clone()) *
  241. (field_p / two);
  242. info!(target: "consensus::state", "sigma2_fbig: {:}", sigma2_fbig);
  243. let sigma2 = fbig2base(sigma2_fbig);
  244. (sigma1, sigma2)
  245. }
  246. /// Generate coins for provided sigmas.
  247. /// NOTE: The strategy here is having a single competing coin per slot.
  248. // TODO: DRK coin need to be burned, and consensus coin to be minted.
  249. async fn create_coins(&mut self) -> Result<Vec<LeadCoin>> {
  250. // TODO: cleanup LeadCoinSecrets, no need to keep a vector
  251. let (seeds, epoch_secrets) = {
  252. let mut rng = thread_rng();
  253. let mut seeds: Vec<u64> = Vec::with_capacity(constants::EPOCH_LENGTH);
  254. for _ in 0..constants::EPOCH_LENGTH {
  255. seeds.push(rng.gen());
  256. }
  257. (seeds, LeadCoinSecrets::generate())
  258. };
  259. // LeadCoin matrix containing node competing coins.
  260. let mut coins: Vec<LeadCoin> = Vec::with_capacity(constants::EPOCH_LENGTH);
  261. // Retrieve coin from wallet
  262. // NOTE: In future this will be retrieved from the money contract.
  263. // Get a wallet connection
  264. let mut conn = self.wallet.conn.acquire().await?;
  265. // Execute the query and see if we find any rows
  266. let query_str = format!("SELECT * FROM {}", constants::CONSENSUS_COIN_TABLE);
  267. let mut query = sqlx::query(&query_str);
  268. let coin = match query.fetch_one(&mut conn).await {
  269. Ok(row) => {
  270. let bytes: Vec<u8> = row.try_get(constants::CONSENSUS_COIN_COL)?;
  271. deserialize(&bytes)?
  272. }
  273. Err(_) => {
  274. // If no records are found, we generate a new coin and save it to the database
  275. info!(target: "consensus::state", "create_coins(): No LeadCoin was found in DB, generating new one...");
  276. // Temporarily, we compete with fixed stake.
  277. // This stake should be based on how many nodes we want to run, and they all
  278. // must sum to initial distribution total coins.
  279. //let stake = self.initial_distribution;
  280. let c = LeadCoin::new(
  281. 0,
  282. self.current_slot(),
  283. epoch_secrets.secret_keys[0].inner(),
  284. epoch_secrets.merkle_roots[0],
  285. 0,
  286. epoch_secrets.merkle_paths[0].clone(),
  287. pallas::Base::from(seeds[0]),
  288. &mut self.coins_tree,
  289. );
  290. let query_str = format!(
  291. "INSERT INTO {} ({}) VALUES (?1);",
  292. constants::CONSENSUS_COIN_TABLE,
  293. constants::CONSENSUS_COIN_COL
  294. );
  295. query = sqlx::query(&query_str);
  296. query = query.bind(serialize(&c));
  297. query.execute(&mut conn).await?;
  298. c
  299. }
  300. };
  301. info!(target: "consensus::state", "create_coins(): Will use LeadCoin with value: {}", coin.value);
  302. coins.push(coin);
  303. Ok(coins)
  304. }
  305. /// Leadership reward, assuming constant reward
  306. /// TODO (res) implement reward mechanism with accord to DRK,DARK token-economics
  307. fn reward(&self) -> u64 {
  308. constants::REWARD
  309. }
  310. /// Auxillary function to calculate total slot rewards.
  311. fn slot_rewards(&self) -> u64 {
  312. // Retrieve existing blocks excluding genesis
  313. let blocks = (self.blockchain.len() as u64) - 1;
  314. // Retrieve longest fork length, to include those proposals in the calculation
  315. let max_fork_length = self.longest_chain_length() as u64;
  316. // Calculate rewarded slots
  317. let rewarded_slots = blocks + max_fork_length;
  318. rewarded_slots * self.reward()
  319. }
  320. /// Network total stake, assuming constant reward.
  321. /// Only used for fine-tuning. At genesis epoch first slot, of absolute index 0,
  322. /// if no stake was distributed, the total stake would be 0.
  323. /// To avoid division by zero, we asume total stake at first division is GENESIS_TOTAL_STAKE(1).
  324. fn total_stake(&self) -> u64 {
  325. let total_stake = self.slot_rewards() + self.initial_distribution;
  326. if total_stake == 0 {
  327. return constants::GENESIS_TOTAL_STAKE
  328. }
  329. total_stake
  330. }
  331. fn f_err(&mut self) -> Float10 {
  332. info!(target: "consensus::state", "Previous leaders: {}", self.previous_leaders);
  333. // Write counter to file
  334. let mut count_str: String = self.previous_leaders.to_string();
  335. count_str.push_str(",");
  336. let f =
  337. File::options().append(true).create(true).open(constants::LEADER_HISTORY_LOG).unwrap();
  338. {
  339. let mut writer = BufWriter::new(f);
  340. writer.write(&count_str.into_bytes()).unwrap();
  341. }
  342. // Calculate feedback
  343. let feedback = Float10::try_from(self.previous_leaders as i64).unwrap();
  344. // Reset previous leaders counter
  345. self.previous_leaders = 0;
  346. let target = constants::FLOAT10_ONE.clone();
  347. target - feedback
  348. }
  349. fn discrete_pid(&mut self) -> Float10 {
  350. let k1 = constants::KP.clone() + constants::KI.clone() + constants::KD.clone();
  351. let k2 = constants::FLOAT10_NEG_ONE.clone() * constants::KP.clone() +
  352. constants::FLOAT10_NEG_TWO.clone() * constants::KD.clone();
  353. let k3 = constants::KD.clone();
  354. let f_len = self.f_history.len();
  355. let err = self.f_err();
  356. let err_len = self.err_history.len();
  357. let ret = self.f_history[f_len - 1].clone() +
  358. k1.clone() * err.clone() +
  359. k2.clone() * self.err_history[err_len - 1].clone() +
  360. k3.clone() * self.err_history[err_len - 2].clone();
  361. info!(target: "consensus::state", "pid::f-1: {:}", self.f_history[f_len - 1].clone());
  362. info!(target: "consensus::state", "pid::err: {:}", err);
  363. info!(target: "consensus::state", "pid::err-1: {}", self.err_history[err_len - 1].clone());
  364. info!(target: "consensus::state", "pid::err-2: {}", self.err_history[err_len - 2].clone());
  365. info!(target: "consensus::state", "pid::k1: {}", k1.clone());
  366. info!(target: "consensus::state", "pid::k2: {}", k2.clone());
  367. info!(target: "consensus::state", "pid::k3: {}", k3.clone());
  368. self.err_history.push(err.clone());
  369. ret
  370. }
  371. /// the probability inverse of winnig lottery having all the stake
  372. /// returns f
  373. fn win_inv_prob_with_full_stake(&mut self) -> Float10 {
  374. let mut f = self.discrete_pid();
  375. if f <= constants::FLOAT10_ZERO.clone() {
  376. f = constants::MIN_F.clone()
  377. } else if f >= constants::FLOAT10_ONE.clone() {
  378. f = constants::MAX_F.clone()
  379. }
  380. // log f history
  381. let file =
  382. File::options().append(true).create(true).open(constants::F_HISTORY_LOG).unwrap();
  383. {
  384. let mut f_history = format!("{:}", f);
  385. f_history.push_str(",");
  386. let mut writer = BufWriter::new(file);
  387. writer.write(&f_history.into_bytes()).unwrap();
  388. }
  389. self.f_history.push(f.clone());
  390. f
  391. }
  392. /// Check that the participant/stakeholder coins win the slot lottery.
  393. /// If the stakeholder has multiple competing winning coins, only the highest value
  394. /// coin is selected, since the stakeholder can't give more than one proof per block/slot.
  395. /// * 'sigma1', 'sigma2': slot sigmas
  396. /// Returns: (check: bool, idx: usize) where idx is the winning coin's index
  397. pub fn is_slot_leader(
  398. &mut self,
  399. sigma1: pallas::Base,
  400. sigma2: pallas::Base,
  401. ) -> (bool, i64, usize) {
  402. // Check if node can produce proposals
  403. if !self.proposing {
  404. return (false, 0, 0)
  405. }
  406. let fork_index = self.longest_chain_index();
  407. let competing_coins = if fork_index == -1 {
  408. self.coins.clone()
  409. } else {
  410. self.forks[fork_index as usize].sequence.last().unwrap().coins.clone()
  411. };
  412. // If on single-node mode, node always proposes by extending the
  413. // single fork it holds.
  414. if self.single_node {
  415. return (true, fork_index, 0)
  416. }
  417. let mut won = false;
  418. let mut highest_stake = 0;
  419. let mut highest_stake_idx = 0;
  420. let total_stake = self.total_stake();
  421. for (winning_idx, coin) in competing_coins.iter().enumerate() {
  422. info!(target: "consensus::state", "is_slot_leader: coin stake: {:?}", coin.value);
  423. info!(target: "consensus::state", "is_slot_leader: total stake: {}", total_stake);
  424. info!(target: "consensus::state", "is_slot_leader: relative stake: {}", (coin.value as f64) / total_stake as f64);
  425. let first_winning = coin.is_leader(
  426. sigma1,
  427. sigma2,
  428. self.get_eta(),
  429. pallas::Base::from(self.current_slot()),
  430. );
  431. if first_winning && !won {
  432. highest_stake_idx = winning_idx;
  433. }
  434. won |= first_winning;
  435. if won && coin.value > highest_stake {
  436. highest_stake = coin.value;
  437. highest_stake_idx = winning_idx;
  438. }
  439. }
  440. (won, fork_index, highest_stake_idx)
  441. }
  442. /// Finds the longest forkchain the node holds and
  443. /// returns its index.
  444. pub fn longest_chain_index(&self) -> i64 {
  445. let mut length = 0;
  446. let mut index = -1;
  447. if !self.forks.is_empty() {
  448. for (i, chain) in self.forks.iter().enumerate() {
  449. if chain.sequence.len() > length {
  450. length = chain.sequence.len();
  451. index = i as i64;
  452. }
  453. }
  454. }
  455. index
  456. }
  457. /// Finds the length of longest fork chain the node holds.
  458. pub fn longest_chain_length(&self) -> usize {
  459. let mut max = 0;
  460. for fork in &self.forks {
  461. if fork.sequence.len() > max {
  462. max = fork.sequence.len();
  463. }
  464. }
  465. max
  466. }
  467. /// Given a proposal, find the index of the fork chain it extends.
  468. pub fn find_extended_chain_index(&mut self, proposal: &BlockProposal) -> Result<i64> {
  469. // We iterate through all forks to find which fork to extend
  470. let mut chain_index = -1;
  471. let mut state_checkpoint_index = 0;
  472. for (c_index, chain) in self.forks.iter().enumerate() {
  473. // Traverse sequence in reverse
  474. for (sc_index, state_checkpoint) in chain.sequence.iter().enumerate().rev() {
  475. if proposal.block.header.previous == state_checkpoint.proposal.hash {
  476. chain_index = c_index as i64;
  477. state_checkpoint_index = sc_index;
  478. break
  479. }
  480. }
  481. if chain_index != -1 {
  482. break
  483. }
  484. }
  485. // If no fork was found, we check with canonical
  486. if chain_index == -1 {
  487. let (last_slot, last_block) = self.blockchain.last()?;
  488. if proposal.block.header.previous != last_block ||
  489. proposal.block.header.slot <= last_slot
  490. {
  491. info!(target: "consensus::state", "find_extended_chain_index(): Proposal doesn't extend any known chain");
  492. return Ok(-2)
  493. }
  494. // Proposal extends canonical chain
  495. return Ok(-1)
  496. }
  497. // Found fork chain
  498. let chain = &self.forks[chain_index as usize];
  499. // Proposal extends fork at last proposal
  500. if state_checkpoint_index == (chain.sequence.len() - 1) {
  501. return Ok(chain_index)
  502. }
  503. info!(target: "consensus::state", "find_extended_chain_index(): Proposal to fork a forkchain was received.");
  504. let mut chain = self.forks[chain_index as usize].clone();
  505. // We keep all proposals until the one it extends
  506. chain.sequence.drain((state_checkpoint_index + 1)..);
  507. self.forks.push(chain);
  508. Ok(self.forks.len() as i64 - 1)
  509. }
  510. /// Search the chains we're holding for the given proposal.
  511. pub fn proposal_exists(&self, input_proposal: &blake3::Hash) -> bool {
  512. for chain in self.forks.iter() {
  513. for state_checkpoint in chain.sequence.iter().rev() {
  514. if input_proposal == &state_checkpoint.proposal.hash {
  515. return true
  516. }
  517. }
  518. }
  519. false
  520. }
  521. /// Utility function to extract leader selection lottery randomness(eta),
  522. /// defined as the hash of the last block, converted to pallas base.
  523. pub fn get_eta(&self) -> pallas::Base {
  524. let (_, hash) = self.blockchain.last().unwrap();
  525. let mut bytes: [u8; 32] = *hash.as_bytes();
  526. // Read first 254 bits
  527. bytes[30] = 0;
  528. bytes[31] = 0;
  529. pallas::Base::from_repr(bytes).unwrap()
  530. }
  531. /// Auxillary function to retrieve slot checkpoint of provided slot UID.
  532. pub fn get_slot_checkpoint(&self, slot: u64) -> Result<SlotCheckpoint> {
  533. // Check hot/live slot checkpoints
  534. for slot_checkpoint in self.slot_checkpoints.iter().rev() {
  535. if slot_checkpoint.slot == slot {
  536. return Ok(slot_checkpoint.clone())
  537. }
  538. }
  539. // Check if slot is finalized
  540. if let Ok(slot_checkpoints) = self.blockchain.get_slot_checkpoints_by_slot(&[slot]) {
  541. if !slot_checkpoints.is_empty() {
  542. if let Some(slot_checkpoint) = &slot_checkpoints[0] {
  543. return Ok(slot_checkpoint.clone())
  544. }
  545. }
  546. }
  547. Err(Error::SlotCheckpointNotFound(slot))
  548. }
  549. /// Auxillary function to check if node has seen current or previous slot checkpoints.
  550. /// This check ensures that either the slots exist in memory or node has seen the finalization of these slots.
  551. pub fn slot_checkpoints_is_empty(&self) -> bool {
  552. let current_slot = self.current_slot();
  553. if self.get_slot_checkpoint(current_slot).is_ok() {
  554. return false
  555. }
  556. let previous_slot = current_slot - 1;
  557. !self.get_slot_checkpoint(previous_slot).is_ok()
  558. }
  559. /// Auxillary function to update all fork state checkpoints to nodes coins current canonical states.
  560. /// Note: This function should only be invoked once on nodes' coins creation.
  561. pub fn update_forks_checkpoints(&mut self) {
  562. for fork in &mut self.forks {
  563. for state_checkpoint in &mut fork.sequence {
  564. state_checkpoint.coins = self.coins.clone();
  565. state_checkpoint.coins_tree = self.coins_tree.clone();
  566. }
  567. }
  568. }
  569. /// Auxiliary structure to reset consensus state for a resync
  570. pub fn reset(&mut self) {
  571. self.participating = None;
  572. self.proposing = false;
  573. self.forks = vec![];
  574. self.slot_checkpoints = vec![];
  575. self.previous_leaders = 0;
  576. self.f_history = vec![constants::FLOAT10_ZERO.clone()];
  577. self.err_history = vec![constants::FLOAT10_ZERO.clone(), constants::FLOAT10_ZERO.clone()];
  578. self.nullifiers = vec![];
  579. }
  580. }
  581. /// Auxiliary structure used for consensus syncing.
  582. #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
  583. pub struct ConsensusRequest {}
  584. impl net::Message for ConsensusRequest {
  585. fn name() -> &'static str {
  586. "consensusrequest"
  587. }
  588. }
  589. /// Auxiliary structure used for consensus syncing.
  590. #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
  591. pub struct ConsensusResponse {
  592. /// Slot the network was bootstrapped
  593. pub bootstrap_slot: u64,
  594. /// Current slot
  595. pub current_slot: u64,
  596. /// Hot/live data used by the consensus algorithm
  597. pub forks: Vec<ForkInfo>,
  598. /// Pending transactions
  599. pub unconfirmed_txs: Vec<Transaction>,
  600. /// Hot/live slot checkpoints
  601. pub slot_checkpoints: Vec<SlotCheckpoint>,
  602. // TODO: When Float10 supports encoding/decoding this should be
  603. // replaced by directly using Vec<Float10>
  604. /// Controller output history
  605. pub f_history: Vec<String>,
  606. /// Controller proportional error history
  607. pub err_history: Vec<String>,
  608. /// Seen nullifiers from proposals
  609. pub nullifiers: Vec<pallas::Base>,
  610. }
  611. impl net::Message for ConsensusResponse {
  612. fn name() -> &'static str {
  613. "consensusresponse"
  614. }
  615. }
  616. /// Auxiliary structure used for consensus syncing.
  617. #[derive(Debug, SerialEncodable, SerialDecodable)]
  618. pub struct ConsensusSlotCheckpointsRequest {}
  619. impl net::Message for ConsensusSlotCheckpointsRequest {
  620. fn name() -> &'static str {
  621. "consensusslotcheckpointsrequest"
  622. }
  623. }
  624. /// Auxiliary structure used for consensus syncing.
  625. #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
  626. pub struct ConsensusSlotCheckpointsResponse {
  627. /// Node known bootstrap slot
  628. pub bootstrap_slot: u64,
  629. /// Node is able to propose proposals
  630. pub proposing: bool,
  631. /// Node has hot/live slot checkpoints
  632. pub is_empty: bool,
  633. }
  634. impl net::Message for ConsensusSlotCheckpointsResponse {
  635. fn name() -> &'static str {
  636. "consensusslotcheckpointsresponse"
  637. }
  638. }
  639. /// Auxiliary structure used to keep track of slot validation parameters.
  640. #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
  641. pub struct SlotCheckpoint {
  642. /// Slot UID
  643. pub slot: u64,
  644. /// Slot eta
  645. pub eta: pallas::Base,
  646. /// Slot sigma1
  647. pub sigma1: pallas::Base,
  648. /// Slot sigma2
  649. pub sigma2: pallas::Base,
  650. }
  651. impl SlotCheckpoint {
  652. pub fn new(slot: u64, eta: pallas::Base, sigma1: pallas::Base, sigma2: pallas::Base) -> Self {
  653. Self { slot, eta, sigma1, sigma2 }
  654. }
  655. /// Generate the genesis slot checkpoint.
  656. pub fn genesis_slot_checkpoint() -> Self {
  657. let eta = pallas::Base::zero();
  658. let sigma1 = pallas::Base::zero();
  659. let sigma2 = pallas::Base::zero();
  660. Self::new(0, eta, sigma1, sigma2)
  661. }
  662. }
  663. impl net::Message for SlotCheckpoint {
  664. fn name() -> &'static str {
  665. "slotcheckpoint"
  666. }
  667. }
  668. /// Auxiliary structure used for slot checkpoints syncing
  669. #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
  670. pub struct SlotCheckpointRequest {
  671. /// Slot UID
  672. pub slot: u64,
  673. }
  674. impl net::Message for SlotCheckpointRequest {
  675. fn name() -> &'static str {
  676. "slotcheckpointrequest"
  677. }
  678. }
  679. /// Auxiliary structure used for slot checkpoints syncing
  680. #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
  681. pub struct SlotCheckpointResponse {
  682. /// Response blocks.
  683. pub slot_checkpoints: Vec<SlotCheckpoint>,
  684. }
  685. impl net::Message for SlotCheckpointResponse {
  686. fn name() -> &'static str {
  687. "slotcheckpointresponse"
  688. }
  689. }
  690. /// Auxiliary structure used to keep track of consensus state checkpoints.
  691. #[derive(Debug, Clone)]
  692. pub struct StateCheckpoint {
  693. /// Block proposal
  694. pub proposal: BlockProposal,
  695. /// Node competing coins current state
  696. pub coins: Vec<LeadCoin>,
  697. /// Coin commitments tree current state
  698. pub coins_tree: BridgeTree<MerkleNode, MERKLE_DEPTH>,
  699. /// Seen nullifiers from proposals current state
  700. pub nullifiers: Vec<pallas::Base>,
  701. }
  702. impl StateCheckpoint {
  703. pub fn new(
  704. proposal: BlockProposal,
  705. coins: Vec<LeadCoin>,
  706. coins_tree: BridgeTree<MerkleNode, MERKLE_DEPTH>,
  707. nullifiers: Vec<pallas::Base>,
  708. ) -> Self {
  709. Self { proposal, coins, coins_tree, nullifiers }
  710. }
  711. }
  712. /// Auxiliary structure used for forked consensus state checkpoints syncing
  713. #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
  714. pub struct StateCheckpointInfo {
  715. /// Block proposal
  716. pub proposal: BlockProposal,
  717. /// Seen nullifiers from proposals current state
  718. pub nullifiers: Vec<pallas::Base>,
  719. }
  720. impl From<StateCheckpoint> for StateCheckpointInfo {
  721. fn from(state_checkpoint: StateCheckpoint) -> Self {
  722. Self { proposal: state_checkpoint.proposal, nullifiers: state_checkpoint.nullifiers }
  723. }
  724. }
  725. impl From<StateCheckpointInfo> for StateCheckpoint {
  726. fn from(state_checkpoint_info: StateCheckpointInfo) -> Self {
  727. Self {
  728. proposal: state_checkpoint_info.proposal,
  729. coins: vec![],
  730. coins_tree: BridgeTree::<MerkleNode, MERKLE_DEPTH>::new(constants::EPOCH_LENGTH * 100),
  731. nullifiers: state_checkpoint_info.nullifiers,
  732. }
  733. }
  734. }
  735. /// This struct represents a sequence of consensus state checkpoints.
  736. #[derive(Debug, Clone)]
  737. pub struct Fork {
  738. pub genesis_block: blake3::Hash,
  739. pub sequence: Vec<StateCheckpoint>,
  740. }
  741. impl Fork {
  742. pub fn new(genesis_block: blake3::Hash, initial_state_checkpoint: StateCheckpoint) -> Self {
  743. Self { genesis_block, sequence: vec![initial_state_checkpoint] }
  744. }
  745. /// Insertion of a valid state checkpoint.
  746. pub fn add(&mut self, state_checkpoint: &StateCheckpoint) {
  747. if self.check_state_checkpoint(state_checkpoint, self.sequence.last().unwrap()) {
  748. self.sequence.push(state_checkpoint.clone());
  749. }
  750. }
  751. /// A fork chain is considered valid when every state checkpoint is valid,
  752. /// based on the `check_state_checkpoint` function
  753. pub fn check_chain(&self) -> bool {
  754. for (index, state_checkpoint) in self.sequence[1..].iter().enumerate() {
  755. if !self.check_state_checkpoint(state_checkpoint, &self.sequence[index]) {
  756. return false
  757. }
  758. }
  759. true
  760. }
  761. /// A state checkpoint is considered valid when its proposal parent hash is equal to the
  762. /// hash of the previous checkpoint's proposal and their slots are incremental,
  763. /// excluding the genesis block proposal.
  764. pub fn check_state_checkpoint(
  765. &self,
  766. state_checkpoint: &StateCheckpoint,
  767. previous: &StateCheckpoint,
  768. ) -> bool {
  769. if state_checkpoint.proposal.block.header.previous == self.genesis_block {
  770. info!(target: "consensus::state", "check_checkpoint(): Genesis block proposal provided.");
  771. return false
  772. }
  773. if state_checkpoint.proposal.block.header.previous != previous.proposal.hash ||
  774. state_checkpoint.proposal.block.header.slot <= previous.proposal.block.header.slot
  775. {
  776. info!(target: "consensus::state", "check_checkpoint(): Provided state checkpoint proposal is invalid.");
  777. return false
  778. }
  779. // TODO: validate rest checkpoint info(like nullifiers)
  780. true
  781. }
  782. }
  783. /// Auxiliary structure used for forks syncing
  784. #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
  785. pub struct ForkInfo {
  786. pub genesis_block: blake3::Hash,
  787. pub sequence: Vec<StateCheckpointInfo>,
  788. }
  789. impl From<Fork> for ForkInfo {
  790. fn from(fork: Fork) -> Self {
  791. let mut sequence = vec![];
  792. for state_checkpoint in fork.sequence {
  793. sequence.push(state_checkpoint.into());
  794. }
  795. Self { genesis_block: fork.genesis_block, sequence }
  796. }
  797. }
  798. impl From<ForkInfo> for Fork {
  799. fn from(fork_info: ForkInfo) -> Self {
  800. let mut sequence = vec![];
  801. for checkpoint in fork_info.sequence {
  802. sequence.push(checkpoint.into());
  803. }
  804. Self { genesis_block: fork_info.genesis_block, sequence }
  805. }
  806. }
  807. #[cfg(test)]
  808. mod tests {
  809. use crate::consensus::{state::ConsensusState, utils::fbig2base, Float10};
  810. #[test]
  811. fn calc_sigmas_test() {
  812. let precision_diff = Float10::try_from(
  813. "10000000000000000000000000000000000000000000000000000000000000000000000000",
  814. )
  815. .unwrap();
  816. let precision_diff_base = fbig2base(precision_diff);
  817. let f = Float10::try_from("0.01").unwrap();
  818. let total_stake = Float10::try_from("100").unwrap();
  819. let (sigma1, sigma2) = ConsensusState::calc_sigmas(f, total_stake);
  820. let sigma1_rhs = Float10::try_from(
  821. "2909373465034095801035568917399197865646520818579502832252119592405565440",
  822. )
  823. .unwrap();
  824. let sigma1_rhs_base = fbig2base(sigma1_rhs);
  825. let sigma2_rhs = Float10::try_from(
  826. "9137556389643100714432609642916129738741963230846798778430644027392",
  827. )
  828. .unwrap();
  829. let sigma2_rhs_base = fbig2base(sigma2_rhs);
  830. let sigma1_delta = if sigma1_rhs_base > sigma1 {
  831. sigma1_rhs_base - sigma1
  832. } else {
  833. sigma1 - sigma1_rhs_base
  834. };
  835. let sigma2_delta = if sigma2_rhs_base > sigma2 {
  836. sigma2_rhs_base - sigma2
  837. } else {
  838. sigma2 - sigma2_rhs_base
  839. };
  840. //note! test cases were generated by low precision python scripts.
  841. //https://github.com/ertosns/lotterysim/blob/master/pallas_unittests.csv
  842. assert!(sigma1_delta < precision_diff_base);
  843. assert!(sigma2_delta < precision_diff_base);
  844. }
  845. }