state.rs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  1. // TODO: Use sets instead of vectors where possible.
  2. use std::time::Duration;
  3. use async_std::sync::{Arc, RwLock};
  4. use chrono::{NaiveDateTime, Utc};
  5. use fxhash::FxBuildHasher;
  6. use indexmap::IndexMap;
  7. use log::{debug, error, info, warn};
  8. use rand::{rngs::OsRng, Rng};
  9. use super::{
  10. Block, BlockInfo, BlockProposal, Metadata, Participant, ProposalChain, StreamletMetadata,
  11. Timestamp, Tx, Vote,
  12. };
  13. use crate::{
  14. blockchain::Blockchain,
  15. crypto::{
  16. keypair::{PublicKey, SecretKey},
  17. schnorr::{SchnorrPublic, SchnorrSecret},
  18. },
  19. util::serial::{serialize, Encodable},
  20. Result,
  21. };
  22. type FxIndexMap<K, V> = IndexMap<K, V, FxBuildHasher>;
  23. const DELTA: u64 = 10;
  24. /// This struct represents the information required by the consensus algorithm
  25. #[derive(Debug)]
  26. pub struct ConsensusState {
  27. /// Genesis block creation timestamp
  28. pub genesis_ts: Timestamp,
  29. /// Genesis block hash
  30. pub genesis_block: blake3::Hash,
  31. /// Fork chains containing block proposals
  32. pub proposals: Vec<ProposalChain>,
  33. /// Orphan votes pool, in case a vote reaches a node before the
  34. /// corresponding block
  35. pub orphan_votes: Vec<Vote>,
  36. /// Validators currently participating in the consensus
  37. pub participants: FxIndexMap<u64, Participant>,
  38. /// Validators to be added on the next epoch as participants
  39. pub pending_participants: Vec<Participant>,
  40. }
  41. impl ConsensusState {
  42. pub fn new(genesis_ts: Timestamp, genesis_data: blake3::Hash) -> Result<Self> {
  43. let genesis_block =
  44. blake3::hash(&serialize(&Block::genesis_block(genesis_ts, genesis_data)));
  45. Ok(Self {
  46. genesis_ts,
  47. genesis_block,
  48. proposals: vec![],
  49. orphan_votes: vec![],
  50. participants: FxIndexMap::with_hasher(FxBuildHasher::default()),
  51. pending_participants: vec![],
  52. })
  53. }
  54. }
  55. /// Atomic pointer to validator state.
  56. pub type ValidatorStatePtr = Arc<RwLock<ValidatorState>>;
  57. /// This struct represents the state of a validator node.
  58. pub struct ValidatorState {
  59. /// Validator ID
  60. pub id: u64,
  61. /// Secret key, to sign messages
  62. pub secret: SecretKey,
  63. /// Validator public key
  64. pub public: PublicKey,
  65. /// Hot/Live data used by the consensus algorithm
  66. pub consensus: ConsensusState,
  67. /// Canonical (finalized) blockchain
  68. pub blockchain: Blockchain,
  69. /// Pending transactions
  70. pub unconfirmed_txs: Vec<Tx>,
  71. }
  72. impl ValidatorState {
  73. // TODO: Clock sync
  74. // TODO: ID shouldn't be done like this
  75. pub fn new(
  76. db: &sled::Db, // <-- TODO: Avoid this with some wrapping, sled should only be in blockchain
  77. id: u64,
  78. genesis_ts: Timestamp,
  79. genesis_data: blake3::Hash,
  80. ) -> Result<ValidatorStatePtr> {
  81. let secret = SecretKey::random(&mut OsRng);
  82. let public = PublicKey::from_secret(secret);
  83. let consensus = ConsensusState::new(genesis_ts, genesis_data)?;
  84. let blockchain = Blockchain::new(db, genesis_ts, genesis_data)?;
  85. let unconfirmed_txs = vec![];
  86. let state = Arc::new(RwLock::new(ValidatorState {
  87. id,
  88. secret,
  89. public,
  90. consensus,
  91. blockchain,
  92. unconfirmed_txs,
  93. }));
  94. Ok(state)
  95. }
  96. /// The node retrieves a transaction and appends it to the unconfirmed
  97. /// transactions list. Additional validity rules must be defined by the
  98. /// protocol for transactions.
  99. pub fn append_tx(&mut self, tx: Tx) -> bool {
  100. if self.unconfirmed_txs.contains(&tx) {
  101. debug!("append_tx(): We already have this tx");
  102. return false
  103. }
  104. debug!("append_tx(): Appended tx to mempool");
  105. self.unconfirmed_txs.push(tx);
  106. true
  107. }
  108. /// Calculates current epoch, based on elapsed time from the genesis block.
  109. /// Epoch duration is configured using the `DELTA` value.
  110. pub fn current_epoch(&self) -> u64 {
  111. self.consensus.genesis_ts.elapsed() / (2 * DELTA)
  112. }
  113. /// Calculates seconds until next epoch starting time.
  114. /// Epochs durationis configured using the delta value.
  115. pub fn next_epoch_start(&self) -> Duration {
  116. let start_time = NaiveDateTime::from_timestamp(self.consensus.genesis_ts.0, 0);
  117. let current_epoch = self.current_epoch() + 1;
  118. let next_epoch_start = (current_epoch * (2 * DELTA)) + (start_time.timestamp() as u64);
  119. let next_epoch_start = NaiveDateTime::from_timestamp(next_epoch_start as i64, 0);
  120. let current_time = NaiveDateTime::from_timestamp(Utc::now().timestamp(), 0);
  121. let diff = next_epoch_start - current_time;
  122. Duration::new(diff.num_seconds().try_into().unwrap(), 0)
  123. }
  124. /// Find epoch leader, using a simple hash method.
  125. /// Leader calculation is based on how many nodes are participating
  126. /// in the network.
  127. pub fn epoch_leader(&mut self) -> u64 {
  128. let len = self.consensus.participants.len();
  129. assert!(len > 0);
  130. let idx = rand::thread_rng().gen_range(0..len);
  131. self.consensus.participants.get_index(idx).unwrap().1.id
  132. }
  133. /// Check if we're the current epoch leader
  134. pub fn is_epoch_leader(&mut self) -> bool {
  135. self.id == self.epoch_leader()
  136. }
  137. /// Generate a block proposal for the current epoch, containing all
  138. /// unconfirmed transactions. Proposal extends the longest notarized fork
  139. /// chain the node is holding.
  140. pub fn propose(&self) -> Result<Option<BlockProposal>> {
  141. let epoch = self.current_epoch();
  142. let (prev_hash, index) = self.longest_notarized_chain_last_hash().unwrap();
  143. let unproposed_txs = self.unproposed_txs(index);
  144. let metadata = Metadata::new(
  145. Timestamp::current_time(),
  146. String::from("proof"),
  147. String::from("r"),
  148. String::from("s"),
  149. );
  150. let sm = StreamletMetadata::new(self.consensus.participants.values().cloned().collect());
  151. let prop = BlockProposal::to_proposal_hash(prev_hash, epoch, &unproposed_txs, &metadata);
  152. let signed_proposal = self.secret.sign(&prop.as_bytes()[..]);
  153. Ok(Some(BlockProposal::new(
  154. self.public,
  155. signed_proposal,
  156. self.id,
  157. prev_hash,
  158. epoch,
  159. unproposed_txs,
  160. metadata,
  161. sm,
  162. )))
  163. }
  164. /// Retrieve all unconfirmed transactions not proposed in previous blocks
  165. /// of provided index chain.
  166. pub fn unproposed_txs(&self, index: i64) -> Vec<Tx> {
  167. let mut unproposed_txs = self.unconfirmed_txs.clone();
  168. // If index is -1 (canonical blockchain) a new fork will be generated,
  169. // therefore all unproposed transactions can be included in the proposal.
  170. if index == -1 {
  171. return unproposed_txs
  172. }
  173. // We iterate over the fork chain proposals to find already proposed
  174. // transactions and remove them from the local unproposed_txs vector.
  175. let chain = &self.consensus.proposals[index as usize];
  176. for proposal in &chain.proposals {
  177. for tx in &proposal.block.txs {
  178. if let Some(pos) = unproposed_txs.iter().position(|txs| *txs == *tx) {
  179. unproposed_txs.remove(pos);
  180. }
  181. }
  182. }
  183. unproposed_txs
  184. }
  185. /// Finds the longest fully notarized blockchain the node holds and
  186. /// returns the last block hash and the chain index.
  187. pub fn longest_notarized_chain_last_hash(&self) -> Result<(blake3::Hash, i64)> {
  188. let mut longest_notarized_chain = &self.consensus.proposals[0];
  189. let mut length = longest_notarized_chain.proposals.len();
  190. let mut index = -1;
  191. let hash = if !self.consensus.proposals.is_empty() {
  192. if self.consensus.proposals.len() > 1 {
  193. for (i, chain) in self.consensus.proposals.iter().enumerate() {
  194. if chain.notarized() && chain.proposals.len() > length {
  195. length = chain.proposals.len();
  196. longest_notarized_chain = chain;
  197. index = i as i64;
  198. }
  199. }
  200. }
  201. longest_notarized_chain.proposals.last().unwrap().hash()
  202. } else {
  203. self.blockchain.last()?.unwrap().1
  204. };
  205. Ok((hash, index))
  206. }
  207. /// Receive the proposed block, verify its sender (epoch leader),
  208. /// and proceed with voting on it.
  209. pub fn receive_proposal(&mut self, proposal: &BlockProposal) -> Result<Option<Vote>> {
  210. let leader = self.epoch_leader();
  211. if leader != proposal.id {
  212. warn!(
  213. "Received proposal not from epoch leader ({}), but from ({})",
  214. leader, proposal.id
  215. );
  216. return Ok(None)
  217. }
  218. if !proposal.public_key.verify(
  219. BlockProposal::to_proposal_hash(
  220. proposal.block.st,
  221. proposal.block.sl,
  222. &proposal.block.txs,
  223. &proposal.block.metadata,
  224. )
  225. .as_bytes(),
  226. &proposal.signature,
  227. ) {
  228. warn!("Proposer ({}) signature could not be verified", proposal.id);
  229. return Ok(None)
  230. }
  231. self.vote(proposal)
  232. }
  233. /// Given a proposal, the node finds which blockchain it extends.
  234. /// If the proposal extends the canonical blockchain, a new fork chain
  235. /// is created. The node votes on the proposal only if it extends the
  236. /// longest notarized fork chain it has seen.
  237. pub fn vote(&mut self, proposal: &BlockProposal) -> Result<Option<Vote>> {
  238. self.zero_participants_check();
  239. let mut proposal = proposal.clone();
  240. // Generate proposal hash
  241. let proposal_hash = proposal.hash();
  242. // Add orphan votes
  243. let mut orphans = Vec::new();
  244. for vote in self.consensus.orphan_votes.iter() {
  245. if vote.proposal == proposal_hash {
  246. proposal.block.sm.votes.push(vote.clone());
  247. orphans.push(vote.clone());
  248. }
  249. }
  250. for vote in orphans {
  251. self.consensus.orphan_votes.retain(|v| *v != vote);
  252. }
  253. let index = self.find_extended_chain_index(&proposal)?;
  254. if index == -2 {
  255. return Ok(None)
  256. }
  257. let chain = match index {
  258. -1 => {
  259. let pc = ProposalChain::new(self.consensus.genesis_block, proposal.clone());
  260. self.consensus.proposals.push(pc);
  261. self.consensus.proposals.last().unwrap()
  262. }
  263. _ => {
  264. self.consensus.proposals[index as usize].add(&proposal);
  265. &self.consensus.proposals[index as usize]
  266. }
  267. };
  268. if !self.extends_notarized_chain(chain) {
  269. debug!("vote(): Proposal does not extend notarized chain");
  270. return Ok(None)
  271. }
  272. let signed_hash = self.secret.sign(&serialize(&proposal_hash));
  273. Ok(Some(Vote::new(self.public, signed_hash, proposal_hash, proposal.block.sl, self.id)))
  274. }
  275. /// Verify if the provided chain is notarized excluding the last block.
  276. pub fn extends_notarized_chain(&self, chain: &ProposalChain) -> bool {
  277. for proposal in &chain.proposals[..(chain.proposals.len() - 1)] {
  278. if !proposal.block.sm.notarized {
  279. return false
  280. }
  281. }
  282. true
  283. }
  284. /// Given a proposal, find the index of the chain it extends.
  285. pub fn find_extended_chain_index(&self, proposal: &BlockProposal) -> Result<i64> {
  286. for (index, chain) in self.consensus.proposals.iter().enumerate() {
  287. let last = chain.proposals.last().unwrap();
  288. let hash = last.hash();
  289. if proposal.block.st == hash && proposal.block.sl > last.block.sl {
  290. return Ok(index as i64)
  291. }
  292. if proposal.block.st == last.block.st && proposal.block.sl == last.block.sl {
  293. debug!("find_extended_chain_index(): Proposal already received");
  294. return Ok(-2)
  295. }
  296. }
  297. let (last_sl, last_block) = self.blockchain.last()?.unwrap();
  298. if proposal.block.st != last_block || proposal.block.sl <= last_sl {
  299. debug!("find_extended_chain_index(): Proposal doesn't extend any known chain");
  300. return Ok(-2)
  301. }
  302. Ok(-1)
  303. }
  304. /// Receive a vote for a proposal.
  305. /// First, sender is verified using their public key.
  306. /// The proposal is then searched for in the node's fork chains.
  307. /// If the vote wasn't received before, it is appended to the proposal
  308. /// votes list.
  309. /// When a node sees 2n/3 votes for a proposal, it notarizes it.
  310. /// When a proposal gets notarized, the transactions it contains are
  311. /// removed from the node's unconfirmed tx list.
  312. /// Finally, we check if the notarization of the proposal can finalize
  313. /// parent proposals in its chain.
  314. pub fn receive_vote(&mut self, vote: &Vote) -> Result<(bool, Option<Vec<BlockInfo>>)> {
  315. let mut encoded_proposal = vec![];
  316. match vote.proposal.encode(&mut encoded_proposal) {
  317. Ok(_) => (),
  318. Err(e) => {
  319. error!(target: "consensus", "Proposal encoding failed: {:?}", e);
  320. return Ok((false, None))
  321. }
  322. };
  323. if !vote.public_key.verify(&encoded_proposal, &vote.vote) {
  324. warn!(target: "consensus", "Voter ({}), signature couldn't be verified", vote.id);
  325. return Ok((false, None))
  326. }
  327. let node_count = self.consensus.participants.len();
  328. self.zero_participants_check();
  329. // Checking that the voter can actually vote.
  330. match self.consensus.participants.get(&vote.id) {
  331. Some(participant) => {
  332. if self.current_epoch() <= participant.joined {
  333. warn!(target: "consensus", "Voter ({}) joined after current epoch.", vote.id);
  334. return Ok((false, None))
  335. }
  336. }
  337. None => {
  338. warn!(target: "consensus", "Voter ({}) is not a participant!", vote.id);
  339. return Ok((false, None))
  340. }
  341. }
  342. let proposal = match self.find_proposal(&vote.proposal) {
  343. Ok(v) => v,
  344. Err(e) => {
  345. error!(target: "consensus", "find_proposal() failed: {}", e);
  346. return Err(e)
  347. }
  348. };
  349. if proposal.is_none() {
  350. warn!(target: "consensus", "Received vote for unknown proposal.");
  351. if !self.consensus.orphan_votes.contains(vote) {
  352. self.consensus.orphan_votes.push(vote.clone());
  353. }
  354. return Ok((false, None))
  355. }
  356. let (proposal, chain_idx) = proposal.unwrap();
  357. if proposal.block.sm.votes.contains(vote) {
  358. debug!("receive_vote(): Already seen this proposal");
  359. return Ok((false, None))
  360. }
  361. proposal.block.sm.votes.push(vote.clone());
  362. let mut to_broadcast = vec![];
  363. if !proposal.block.sm.notarized && proposal.block.sm.votes.len() > (2 * node_count / 3) {
  364. debug!("receive_vote(): Notarized a block");
  365. proposal.block.sm.notarized = true;
  366. match self.chain_finalization(chain_idx) {
  367. Ok(v) => {
  368. to_broadcast = v;
  369. }
  370. Err(e) => {
  371. error!(target: "consensus", "Block finalization failed: {}", e);
  372. return Err(e)
  373. }
  374. }
  375. }
  376. // Updating participant vote
  377. let mut participant = match self.consensus.participants.get(&vote.id) {
  378. Some(p) => p.clone(),
  379. None => Participant::new(vote.id, vote.sl),
  380. };
  381. match participant.voted {
  382. Some(voted) => {
  383. if vote.sl > voted {
  384. participant.voted = Some(vote.sl);
  385. }
  386. }
  387. None => participant.voted = Some(vote.sl),
  388. }
  389. self.consensus.participants.insert(participant.id, participant);
  390. Ok((true, Some(to_broadcast)))
  391. }
  392. /// Search the chains we're holding for the given proposal.
  393. pub fn find_proposal(
  394. &mut self,
  395. vote_proposal: &blake3::Hash,
  396. ) -> Result<Option<(&mut BlockProposal, i64)>> {
  397. for (index, chain) in &mut self.consensus.proposals.iter_mut().enumerate() {
  398. for proposal in chain.proposals.iter_mut().rev() {
  399. let proposal_hash = proposal.hash();
  400. if vote_proposal == &proposal_hash {
  401. return Ok(Some((proposal, index as i64)))
  402. }
  403. }
  404. }
  405. Ok(None)
  406. }
  407. /// Remove provided transactions vector from unconfirmed_txs if they exist.
  408. pub fn remove_txs(&mut self, transactions: Vec<Tx>) -> Result<()> {
  409. for tx in transactions {
  410. if let Some(pos) = self.unconfirmed_txs.iter().position(|txs| *txs == tx) {
  411. self.unconfirmed_txs.remove(pos);
  412. }
  413. }
  414. Ok(())
  415. }
  416. /// Provided an index, the node checks if the chain can be finalized.
  417. /// Consensus finalization logic:
  418. /// - If the node has observed the notarization of 3 consecutive
  419. /// proposals in a fork chain, it finalizes (appends to canonical
  420. /// blockchain) all proposals up to the middle block.
  421. /// When fork chain proposals are finalized, the rest of fork chains not
  422. /// starting by those proposals are removed.
  423. pub fn chain_finalization(&mut self, chain_index: i64) -> Result<Vec<BlockInfo>> {
  424. let chain = &mut self.consensus.proposals[chain_index as usize];
  425. if chain.proposals.len() < 3 {
  426. debug!(
  427. "chain_finalization(): Less than 3 proposals in chain {}, nothing to finalize",
  428. chain_index
  429. );
  430. return Ok(vec![])
  431. }
  432. let mut consecutive = 0;
  433. for proposal in &chain.proposals {
  434. if proposal.block.sm.notarized {
  435. consecutive += 1;
  436. continue
  437. }
  438. break
  439. }
  440. if consecutive < 3 {
  441. debug!(
  442. "chain_finalization(): Less than 3 notarized blocks in chain {}, nothing to finalize",
  443. chain_index
  444. );
  445. return Ok(vec![])
  446. }
  447. let mut finalized = vec![];
  448. for proposal in &mut chain.proposals[..(consecutive - 1)] {
  449. proposal.block.sm.finalized = true;
  450. finalized.push(proposal.clone().into());
  451. }
  452. chain.proposals.drain(0..(consecutive - 1));
  453. info!(target: "consensus", "Adding finalized block to canonical chain");
  454. let blockhashes = match self.blockchain.add(&finalized) {
  455. Ok(v) => v,
  456. Err(e) => {
  457. error!(target: "consensus", "Failed appending finalized blocks to canonical chain: {}", e);
  458. return Err(e)
  459. }
  460. };
  461. for proposal in &finalized {
  462. self.remove_txs(proposal.txs.clone())?;
  463. }
  464. let last_block = *blockhashes.last().unwrap();
  465. let last_sl = finalized.last().unwrap().sl;
  466. let mut dropped = vec![];
  467. for chain in self.consensus.proposals.iter() {
  468. let first = chain.proposals.first().unwrap();
  469. if first.block.st != last_block || first.block.sl <= last_sl {
  470. dropped.push(chain.clone());
  471. }
  472. }
  473. for chain in dropped {
  474. self.consensus.proposals.retain(|c| *c != chain);
  475. }
  476. // Remove orphan votes
  477. let mut orphans = vec![];
  478. for vote in self.consensus.orphan_votes.iter() {
  479. if vote.sl <= last_sl {
  480. orphans.push(vote.clone());
  481. }
  482. }
  483. for vote in orphans {
  484. self.consensus.orphan_votes.retain(|v| *v != vote);
  485. }
  486. Ok(finalized)
  487. }
  488. /// Append a new participant to the pending participants list.
  489. pub fn append_participant(&mut self, participant: Participant) -> bool {
  490. if self.consensus.pending_participants.contains(&participant) {
  491. return false
  492. }
  493. self.consensus.pending_participants.push(participant);
  494. true
  495. }
  496. /// Prevent the extreme case scenario where network is initialized, but
  497. /// some nodes have not pushed the initial participants in the map.
  498. pub fn zero_participants_check(&mut self) {
  499. if self.consensus.participants.is_empty() {
  500. debug!("zero_participants_check(): Participants are empty, trying to add pending ones");
  501. for participant in &self.consensus.pending_participants {
  502. self.consensus.participants.insert(participant.id, participant.clone());
  503. }
  504. if self.consensus.participants.is_empty() {
  505. debug!("zero_participants_check(): Didn't manage to add any participant, pending were empty");
  506. }
  507. self.consensus.pending_participants = Vec::new();
  508. }
  509. }
  510. /// Refresh the participants map, to retain only the active ones.
  511. /// Active nodes are considered those who joined or voted on a previous epoch.
  512. pub fn refresh_participants(&mut self) {
  513. debug!("refresh_participants(): Adding pending participants");
  514. for participant in &self.consensus.pending_participants {
  515. self.consensus.participants.insert(participant.id, participant.clone());
  516. }
  517. if self.consensus.participants.is_empty() {
  518. debug!(
  519. "refresh_participants(): Didn't manage to add any participant, pending were empty"
  520. );
  521. }
  522. self.consensus.pending_participants = vec![];
  523. let mut inactive = Vec::new();
  524. let previous_epoch = self.current_epoch() - 1;
  525. for (index, participant) in self.consensus.participants.clone().iter() {
  526. match participant.voted {
  527. Some(epoch) => {
  528. if epoch < previous_epoch {
  529. inactive.push(*index);
  530. }
  531. }
  532. None => {
  533. if participant.joined < previous_epoch {
  534. inactive.push(*index);
  535. }
  536. }
  537. }
  538. }
  539. for index in inactive {
  540. self.consensus.participants.remove(&index);
  541. }
  542. }
  543. /// Utility function to reset the current consensus state.
  544. pub fn reset_consensus_state(&mut self) -> Result<()> {
  545. let genesis_ts = self.consensus.genesis_ts.clone();
  546. let genesis_block = self.consensus.genesis_block.clone();
  547. let consensus = ConsensusState {
  548. genesis_ts,
  549. genesis_block,
  550. proposals: vec![],
  551. orphan_votes: vec![],
  552. participants: FxIndexMap::with_hasher(FxBuildHasher::default()),
  553. pending_participants: vec![],
  554. };
  555. self.consensus = consensus;
  556. Ok(())
  557. }
  558. }