state.rs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951
  1. // TODO: Use sets instead of vectors where possible.
  2. use std::{
  3. collections::{hash_map::DefaultHasher, BTreeMap},
  4. hash::{Hash, Hasher},
  5. time::Duration,
  6. };
  7. use async_std::sync::{Arc, Mutex, RwLock};
  8. use chrono::{NaiveDateTime, Utc};
  9. use lazy_init::Lazy;
  10. use log::{debug, error, info, warn};
  11. use rand::rngs::OsRng;
  12. use super::{
  13. Block, BlockInfo, BlockProposal, Metadata, Participant, ProposalChain, StreamletMetadata, Vote,
  14. };
  15. use crate::{
  16. blockchain::Blockchain,
  17. crypto::{
  18. address::Address,
  19. keypair::{PublicKey, SecretKey},
  20. schnorr::{SchnorrPublic, SchnorrSecret},
  21. },
  22. net,
  23. node::{
  24. state::{state_transition, ProgramState, StateUpdate},
  25. Client, MemoryState, State,
  26. },
  27. tx::Transaction,
  28. util::{
  29. serial::{serialize, Encodable, SerialDecodable, SerialEncodable},
  30. time::Timestamp,
  31. },
  32. Result,
  33. };
  34. /// `2 * DELTA` represents slot time
  35. pub const DELTA: u64 = 20;
  36. /// Slots in an epoch
  37. pub const EPOCH_SLOTS: u64 = 10;
  38. /// Quarantine duration, in slots
  39. pub const QUARANTINE_DURATION: u64 = 5;
  40. /// This struct represents the information required by the consensus algorithm
  41. #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
  42. pub struct ConsensusState {
  43. /// Genesis block creation timestamp
  44. pub genesis_ts: Timestamp,
  45. /// Genesis block hash
  46. pub genesis_block: blake3::Hash,
  47. /// Fork chains containing block proposals
  48. pub proposals: Vec<ProposalChain>,
  49. /// Orphan votes pool, in case a vote reaches a node before the
  50. /// corresponding block
  51. pub orphan_votes: Vec<Vote>,
  52. /// Validators currently participating in the consensus
  53. pub participants: BTreeMap<Address, Participant>,
  54. /// Validators to be added on the next slot as participants
  55. pub pending_participants: Vec<Participant>,
  56. /// Last slot participants where refreshed
  57. pub refreshed: u64,
  58. }
  59. impl ConsensusState {
  60. pub fn new(genesis_ts: Timestamp, genesis_data: blake3::Hash) -> Result<Self> {
  61. let genesis_block =
  62. blake3::hash(&serialize(&Block::genesis_block(genesis_ts, genesis_data)));
  63. Ok(Self {
  64. genesis_ts,
  65. genesis_block,
  66. proposals: vec![],
  67. orphan_votes: vec![],
  68. participants: BTreeMap::new(),
  69. pending_participants: vec![],
  70. refreshed: 0,
  71. })
  72. }
  73. }
  74. /// Auxiliary structure used for consensus syncing.
  75. #[derive(Debug, SerialEncodable, SerialDecodable)]
  76. pub struct ConsensusRequest {
  77. /// Validator wallet address
  78. pub address: Address,
  79. }
  80. impl net::Message for ConsensusRequest {
  81. fn name() -> &'static str {
  82. "consensusrequest"
  83. }
  84. }
  85. /// Auxiliary structure used for consensus syncing.
  86. #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
  87. pub struct ConsensusResponse {
  88. /// Hot/live data used by the consensus algorithm
  89. pub consensus: ConsensusState,
  90. }
  91. impl net::Message for ConsensusResponse {
  92. fn name() -> &'static str {
  93. "consensusresponse"
  94. }
  95. }
  96. /// Atomic pointer to validator state.
  97. pub type ValidatorStatePtr = Arc<RwLock<ValidatorState>>;
  98. /// This struct represents the state of a validator node.
  99. pub struct ValidatorState {
  100. /// Node wallet address
  101. pub address: Address,
  102. /// Secret key, to sign messages
  103. pub secret: SecretKey,
  104. /// Node public key
  105. pub public: PublicKey,
  106. /// Hot/Live data used by the consensus algorithm
  107. pub consensus: ConsensusState,
  108. /// Canonical (finalized) blockchain
  109. pub blockchain: Blockchain,
  110. /// Canonical state machine
  111. pub state_machine: Arc<Mutex<State>>,
  112. /// Client providing wallet access
  113. pub client: Arc<Client>,
  114. /// Pending transactions
  115. pub unconfirmed_txs: Vec<Transaction>,
  116. /// Participating start slot
  117. pub participating: Option<u64>,
  118. }
  119. impl ValidatorState {
  120. pub async fn new(
  121. db: &sled::Db, // <-- TODO: Avoid this with some wrapping, sled should only be in blockchain
  122. genesis_ts: Timestamp,
  123. genesis_data: blake3::Hash,
  124. client: Arc<Client>,
  125. cashier_pubkeys: Vec<PublicKey>,
  126. faucet_pubkeys: Vec<PublicKey>,
  127. ) -> Result<ValidatorStatePtr> {
  128. let secret = SecretKey::random(&mut OsRng);
  129. let public = PublicKey::from_secret(secret);
  130. let consensus = ConsensusState::new(genesis_ts, genesis_data)?;
  131. let blockchain = Blockchain::new(db, genesis_ts, genesis_data)?;
  132. let unconfirmed_txs = vec![];
  133. let participating = None;
  134. let address = client.wallet.get_default_address().await?;
  135. let state_machine = Arc::new(Mutex::new(State {
  136. tree: client.get_tree().await?,
  137. merkle_roots: blockchain.merkle_roots.clone(),
  138. nullifiers: blockchain.nullifiers.clone(),
  139. cashier_pubkeys,
  140. faucet_pubkeys,
  141. mint_vk: Lazy::new(),
  142. burn_vk: Lazy::new(),
  143. }));
  144. // Create zk proof verification keys
  145. let _ = state_machine.lock().await.mint_vk();
  146. let _ = state_machine.lock().await.burn_vk();
  147. let state = Arc::new(RwLock::new(ValidatorState {
  148. address,
  149. secret,
  150. public,
  151. consensus,
  152. blockchain,
  153. state_machine,
  154. client,
  155. unconfirmed_txs,
  156. participating,
  157. }));
  158. Ok(state)
  159. }
  160. /// The node retrieves a transaction and appends it to the unconfirmed
  161. /// transactions list. Additional validity rules must be defined by the
  162. /// protocol for transactions.
  163. pub fn append_tx(&mut self, tx: Transaction) -> bool {
  164. if self.unconfirmed_txs.contains(&tx) {
  165. debug!("append_tx(): We already have this tx");
  166. return false
  167. }
  168. debug!("append_tx(): Appended tx to mempool");
  169. self.unconfirmed_txs.push(tx);
  170. true
  171. }
  172. /// Calculates the epoch of the provided slot.
  173. /// Epoch duration is configured using the `EPOCH_SLOTS` value.
  174. pub fn slot_epoch(&self, slot: u64) -> u64 {
  175. slot / EPOCH_SLOTS
  176. }
  177. /// Calculates current slot, based on elapsed time from the genesis block.
  178. /// Slot duration is configured using the `DELTA` value.
  179. pub fn current_slot(&self) -> u64 {
  180. self.consensus.genesis_ts.elapsed() / (2 * DELTA)
  181. }
  182. /// Finds the last slot a proposal or block was generated.
  183. pub fn last_slot(&self) -> Result<u64> {
  184. let mut slot = 0;
  185. for chain in &self.consensus.proposals {
  186. for proposal in &chain.proposals {
  187. if proposal.block.sl > slot {
  188. slot = proposal.block.sl;
  189. }
  190. }
  191. }
  192. // We return here in case proposals exist,
  193. // so we don't query the sled database.
  194. if slot > 0 {
  195. return Ok(slot)
  196. }
  197. let (last_sl, _) = self.blockchain.last()?;
  198. Ok(last_sl)
  199. }
  200. /// Calculates seconds until next slot starting time.
  201. /// Slots durationis configured using the delta value.
  202. pub fn next_slot_start(&self) -> Duration {
  203. let start_time = NaiveDateTime::from_timestamp(self.consensus.genesis_ts.0, 0);
  204. let current_slot = self.current_slot() + 1;
  205. let next_slot_start = (current_slot * (2 * DELTA)) + (start_time.timestamp() as u64);
  206. let next_slot_start = NaiveDateTime::from_timestamp(next_slot_start as i64, 0);
  207. let current_time = NaiveDateTime::from_timestamp(Utc::now().timestamp(), 0);
  208. let diff = next_slot_start - current_time;
  209. Duration::new(diff.num_seconds().try_into().unwrap(), 0)
  210. }
  211. /// Set participating slot to next.
  212. pub fn set_participating(&mut self) -> Result<()> {
  213. self.participating = Some(self.current_slot() + 1);
  214. Ok(())
  215. }
  216. /// Find slot leader, using a simple hash method.
  217. /// Leader calculation is based on how many nodes are participating
  218. /// in the network.
  219. pub fn slot_leader(&mut self) -> Address {
  220. let slot = self.current_slot();
  221. // DefaultHasher is used to hash the slot number
  222. // because it produces a number string which then can be modulated by the len.
  223. // blake3 produces alphanumeric
  224. let mut hasher = DefaultHasher::new();
  225. slot.hash(&mut hasher);
  226. let pos = hasher.finish() % (self.consensus.participants.len() as u64);
  227. // Since BTreeMap orders by key in asceding order, each node will have
  228. // the same key in calculated position.
  229. self.consensus.participants.iter().nth(pos as usize).unwrap().1.address
  230. }
  231. /// Check if we're the current slot leader
  232. pub fn is_slot_leader(&mut self) -> bool {
  233. let address = self.address;
  234. address == self.slot_leader()
  235. }
  236. /// Generate a block proposal for the current slot, containing all
  237. /// unconfirmed transactions. Proposal extends the longest notarized fork
  238. /// chain the node is holding.
  239. pub fn propose(&self) -> Result<Option<BlockProposal>> {
  240. let slot = self.current_slot();
  241. let (prev_hash, index) = self.longest_notarized_chain_last_hash().unwrap();
  242. let unproposed_txs = self.unproposed_txs(index);
  243. let metadata = Metadata::new(
  244. Timestamp::current_time(),
  245. String::from("proof"),
  246. String::from("r"),
  247. String::from("s"),
  248. );
  249. let sm = StreamletMetadata::new(self.consensus.participants.values().cloned().collect());
  250. let prop = BlockProposal::to_proposal_hash(
  251. prev_hash,
  252. self.slot_epoch(slot),
  253. slot,
  254. &unproposed_txs,
  255. &metadata,
  256. );
  257. let signed_proposal = self.secret.sign(&prop.as_bytes()[..]);
  258. Ok(Some(BlockProposal::new(
  259. self.public,
  260. signed_proposal,
  261. self.address,
  262. prev_hash,
  263. self.slot_epoch(slot),
  264. slot,
  265. unproposed_txs,
  266. metadata,
  267. sm,
  268. )))
  269. }
  270. /// Retrieve all unconfirmed transactions not proposed in previous blocks
  271. /// of provided index chain.
  272. pub fn unproposed_txs(&self, index: i64) -> Vec<Transaction> {
  273. let mut unproposed_txs = self.unconfirmed_txs.clone();
  274. // If index is -1 (canonical blockchain) a new fork will be generated,
  275. // therefore all unproposed transactions can be included in the proposal.
  276. if index == -1 {
  277. return unproposed_txs
  278. }
  279. // We iterate over the fork chain proposals to find already proposed
  280. // transactions and remove them from the local unproposed_txs vector.
  281. let chain = &self.consensus.proposals[index as usize];
  282. for proposal in &chain.proposals {
  283. for tx in &proposal.block.txs {
  284. if let Some(pos) = unproposed_txs.iter().position(|txs| *txs == *tx) {
  285. unproposed_txs.remove(pos);
  286. }
  287. }
  288. }
  289. unproposed_txs
  290. }
  291. /// Finds the longest fully notarized blockchain the node holds and
  292. /// returns the last block hash and the chain index.
  293. pub fn longest_notarized_chain_last_hash(&self) -> Result<(blake3::Hash, i64)> {
  294. let mut longest_notarized_chain: Option<ProposalChain> = None;
  295. let mut length = 0;
  296. let mut index = -1;
  297. if !self.consensus.proposals.is_empty() {
  298. for (i, chain) in self.consensus.proposals.iter().enumerate() {
  299. if chain.notarized() && chain.proposals.len() > length {
  300. longest_notarized_chain = Some(chain.clone());
  301. length = chain.proposals.len();
  302. index = i as i64;
  303. }
  304. }
  305. }
  306. let hash = match longest_notarized_chain {
  307. Some(chain) => chain.proposals.last().unwrap().hash(),
  308. None => self.blockchain.last()?.1,
  309. };
  310. Ok((hash, index))
  311. }
  312. /// Receive the proposed block, verify its sender (slot leader),
  313. /// and proceed with voting on it.
  314. pub fn receive_proposal(&mut self, proposal: &BlockProposal) -> Result<Option<Vote>> {
  315. // Node hasn't started participating
  316. match self.participating {
  317. Some(start) => {
  318. if self.current_slot() < start {
  319. return Ok(None)
  320. }
  321. }
  322. None => return Ok(None),
  323. }
  324. // Node refreshes participants records
  325. self.refresh_participants()?;
  326. let leader = self.slot_leader();
  327. if leader != proposal.address {
  328. warn!(
  329. "Received proposal not from slot leader ({}), but from ({})",
  330. leader,
  331. proposal.address.to_string()
  332. );
  333. return Ok(None)
  334. }
  335. if !proposal.public_key.verify(
  336. BlockProposal::to_proposal_hash(
  337. proposal.block.st,
  338. proposal.block.e,
  339. proposal.block.sl,
  340. &proposal.block.txs,
  341. &proposal.block.metadata,
  342. )
  343. .as_bytes(),
  344. &proposal.signature,
  345. ) {
  346. warn!("Proposer ({}) signature could not be verified", proposal.address.to_string());
  347. return Ok(None)
  348. }
  349. self.vote(proposal)
  350. }
  351. /// Given a proposal, the node finds which blockchain it extends.
  352. /// If the proposal extends the canonical blockchain, a new fork chain
  353. /// is created. The node votes on the proposal only if it extends the
  354. /// longest notarized fork chain it has seen.
  355. pub fn vote(&mut self, proposal: &BlockProposal) -> Result<Option<Vote>> {
  356. let mut proposal = proposal.clone();
  357. // Generate proposal hash
  358. let proposal_hash = proposal.hash();
  359. // Add orphan votes
  360. let mut orphans = Vec::new();
  361. for vote in self.consensus.orphan_votes.iter() {
  362. if vote.proposal == proposal_hash {
  363. proposal.block.sm.votes.push(vote.clone());
  364. orphans.push(vote.clone());
  365. }
  366. }
  367. for vote in orphans {
  368. self.consensus.orphan_votes.retain(|v| *v != vote);
  369. }
  370. let index = self.find_extended_chain_index(&proposal)?;
  371. if index == -2 {
  372. return Ok(None)
  373. }
  374. let chain = match index {
  375. -1 => {
  376. let pc = ProposalChain::new(self.consensus.genesis_block, proposal.clone());
  377. self.consensus.proposals.push(pc);
  378. self.consensus.proposals.last().unwrap()
  379. }
  380. _ => {
  381. self.consensus.proposals[index as usize].add(&proposal);
  382. &self.consensus.proposals[index as usize]
  383. }
  384. };
  385. if !self.extends_notarized_chain(chain) {
  386. debug!("vote(): Proposal does not extend notarized chain");
  387. return Ok(None)
  388. }
  389. let signed_hash = self.secret.sign(&serialize(&proposal_hash));
  390. Ok(Some(Vote::new(
  391. self.public,
  392. signed_hash,
  393. proposal_hash,
  394. proposal.block.sl,
  395. self.address,
  396. )))
  397. }
  398. /// Verify if the provided chain is notarized excluding the last block.
  399. pub fn extends_notarized_chain(&self, chain: &ProposalChain) -> bool {
  400. for proposal in &chain.proposals[..(chain.proposals.len() - 1)] {
  401. if !proposal.block.sm.notarized {
  402. return false
  403. }
  404. }
  405. true
  406. }
  407. /// Given a proposal, find the index of the chain it extends.
  408. pub fn find_extended_chain_index(&mut self, proposal: &BlockProposal) -> Result<i64> {
  409. let mut fork = None;
  410. for (index, chain) in self.consensus.proposals.iter().enumerate() {
  411. let last = chain.proposals.last().unwrap();
  412. let hash = last.hash();
  413. if proposal.block.st == hash && proposal.block.sl > last.block.sl {
  414. return Ok(index as i64)
  415. }
  416. if proposal.block.st == last.block.st && proposal.block.sl == last.block.sl {
  417. debug!("find_extended_chain_index(): Proposal already received");
  418. return Ok(-2)
  419. }
  420. if proposal.block.st == last.block.st && proposal.block.sl > last.block.sl {
  421. fork = Some(chain.clone());
  422. }
  423. }
  424. match fork {
  425. Some(mut chain) => {
  426. debug!("Proposal to fork a forkchain was received.");
  427. chain.proposals.pop(); // removing last block to create the fork
  428. if !chain.proposals.is_empty() {
  429. // if len is 0 we will verify against blockchain last block
  430. self.consensus.proposals.push(chain);
  431. return Ok(self.consensus.proposals.len() as i64 - 1)
  432. }
  433. }
  434. None => (),
  435. }
  436. let (last_sl, last_block) = self.blockchain.last()?;
  437. if proposal.block.st != last_block || proposal.block.sl <= last_sl {
  438. debug!("find_extended_chain_index(): Proposal doesn't extend any known chain");
  439. return Ok(-2)
  440. }
  441. Ok(-1)
  442. }
  443. /// Receive a vote for a proposal.
  444. /// First, sender is verified using their public key.
  445. /// The proposal is then searched for in the node's fork chains.
  446. /// If the vote wasn't received before, it is appended to the proposal
  447. /// votes list.
  448. /// When a node sees 2n/3 votes for a proposal, it notarizes it.
  449. /// When a proposal gets notarized, the transactions it contains are
  450. /// removed from the node's unconfirmed tx list.
  451. /// Finally, we check if the notarization of the proposal can finalize
  452. /// parent proposals in its chain.
  453. pub async fn receive_vote(&mut self, vote: &Vote) -> Result<(bool, Option<Vec<BlockInfo>>)> {
  454. let current_slot = self.current_slot();
  455. // Node hasn't started participating
  456. match self.participating {
  457. Some(start) => {
  458. if current_slot < start {
  459. return Ok((false, None))
  460. }
  461. }
  462. None => return Ok((false, None)),
  463. }
  464. let mut encoded_proposal = vec![];
  465. if let Err(e) = vote.proposal.encode(&mut encoded_proposal) {
  466. error!("consensus: Proposal encoding failed: {:?}", e);
  467. return Ok((false, None))
  468. };
  469. let va = vote.address.to_string();
  470. if !vote.public_key.verify(&encoded_proposal, &vote.vote) {
  471. warn!("consensus: Voter ({}), signature couldn't be verified", va);
  472. return Ok((false, None))
  473. }
  474. // Node refreshes participants records
  475. self.refresh_participants()?;
  476. let node_count = self.consensus.participants.len();
  477. // Checking that the voter can actually vote.
  478. match self.consensus.participants.get(&vote.address) {
  479. Some(participant) => {
  480. let mut participant = participant.clone();
  481. if current_slot <= participant.joined {
  482. warn!("consensus: Voter ({}) joined after current slot.", va);
  483. return Ok((false, None))
  484. }
  485. // Updating participant vote
  486. match participant.voted {
  487. Some(voted) => {
  488. if vote.sl > voted {
  489. participant.voted = Some(vote.sl);
  490. }
  491. }
  492. None => participant.voted = Some(vote.sl),
  493. }
  494. // Invalidating quarantine
  495. participant.quarantined = None;
  496. self.consensus.participants.insert(participant.address, participant);
  497. }
  498. None => {
  499. warn!("consensus: Voter ({}) is not a participant!", vote.address.to_string());
  500. return Ok((false, None))
  501. }
  502. }
  503. let proposal = match self.find_proposal(&vote.proposal) {
  504. Ok(v) => v,
  505. Err(e) => {
  506. error!("consensus: find_proposal() failed: {}", e);
  507. return Err(e)
  508. }
  509. };
  510. if proposal.is_none() {
  511. debug!(target: "consensus", "Received vote for unknown proposal.");
  512. if !self.consensus.orphan_votes.contains(vote) {
  513. self.consensus.orphan_votes.push(vote.clone());
  514. }
  515. return Ok((false, None))
  516. }
  517. let (proposal, chain_idx) = proposal.unwrap();
  518. if proposal.block.sm.votes.contains(vote) {
  519. debug!("receive_vote(): Already seen this vote");
  520. return Ok((false, None))
  521. }
  522. proposal.block.sm.votes.push(vote.clone());
  523. let mut to_broadcast = vec![];
  524. if !proposal.block.sm.notarized && proposal.block.sm.votes.len() > (2 * node_count / 3) {
  525. debug!("receive_vote(): Notarized a block");
  526. proposal.block.sm.notarized = true;
  527. match self.chain_finalization(chain_idx).await {
  528. Ok(v) => {
  529. to_broadcast = v;
  530. }
  531. Err(e) => {
  532. error!("consensus: Block finalization failed: {}", e);
  533. return Err(e)
  534. }
  535. }
  536. }
  537. Ok((true, Some(to_broadcast)))
  538. }
  539. /// Search the chains we're holding for the given proposal.
  540. pub fn find_proposal(
  541. &mut self,
  542. vote_proposal: &blake3::Hash,
  543. ) -> Result<Option<(&mut BlockProposal, i64)>> {
  544. for (index, chain) in &mut self.consensus.proposals.iter_mut().enumerate() {
  545. for proposal in chain.proposals.iter_mut().rev() {
  546. let proposal_hash = proposal.hash();
  547. if vote_proposal == &proposal_hash {
  548. return Ok(Some((proposal, index as i64)))
  549. }
  550. }
  551. }
  552. Ok(None)
  553. }
  554. /// Remove provided transactions vector from unconfirmed_txs if they exist.
  555. pub fn remove_txs(&mut self, transactions: Vec<Transaction>) -> Result<()> {
  556. for tx in transactions {
  557. if let Some(pos) = self.unconfirmed_txs.iter().position(|txs| *txs == tx) {
  558. self.unconfirmed_txs.remove(pos);
  559. }
  560. }
  561. Ok(())
  562. }
  563. /// Provided an index, the node checks if the chain can be finalized.
  564. /// Consensus finalization logic:
  565. /// - If the node has observed the notarization of 3 consecutive
  566. /// proposals in a fork chain, it finalizes (appends to canonical
  567. /// blockchain) all proposals up to the middle block.
  568. /// When fork chain proposals are finalized, the rest of fork chains not
  569. /// starting by those proposals are removed.
  570. pub async fn chain_finalization(&mut self, chain_index: i64) -> Result<Vec<BlockInfo>> {
  571. let chain = &mut self.consensus.proposals[chain_index as usize];
  572. if chain.proposals.len() < 3 {
  573. debug!(
  574. "chain_finalization(): Less than 3 proposals in chain {}, nothing to finalize",
  575. chain_index
  576. );
  577. return Ok(vec![])
  578. }
  579. let mut consecutive = 0;
  580. for proposal in &chain.proposals {
  581. if proposal.block.sm.notarized {
  582. consecutive += 1;
  583. continue
  584. }
  585. break
  586. }
  587. if consecutive < 3 {
  588. debug!(
  589. "chain_finalization(): Less than 3 notarized blocks in chain {}, nothing to finalize",
  590. chain_index
  591. );
  592. return Ok(vec![])
  593. }
  594. let mut finalized = vec![];
  595. for proposal in &mut chain.proposals[..(consecutive - 1)] {
  596. proposal.block.sm.finalized = true;
  597. finalized.push(proposal.clone().into());
  598. }
  599. chain.proposals.drain(0..(consecutive - 1));
  600. info!("consensus: Adding {} finalized block to canonical chain", finalized.len());
  601. let blockhashes = match self.blockchain.add(&finalized) {
  602. Ok(v) => v,
  603. Err(e) => {
  604. error!("consensus: Failed appending finalized blocks to canonical chain: {}", e);
  605. return Err(e)
  606. }
  607. };
  608. for proposal in &finalized {
  609. // TODO: Is this the right place? We're already doing this in protocol_sync.
  610. // TODO: These state transitions have already been checked.
  611. debug!(target: "consensus", "Applying state transition for finalized block");
  612. let canon_state_clone = self.state_machine.lock().await.clone();
  613. let mem_st = MemoryState::new(canon_state_clone);
  614. let state_updates = ValidatorState::validate_state_transitions(mem_st, &proposal.txs)?;
  615. self.update_canon_state(state_updates, None).await?;
  616. self.remove_txs(proposal.txs.clone())?;
  617. }
  618. let last_block = *blockhashes.last().unwrap();
  619. let last_sl = finalized.last().unwrap().sl;
  620. let mut dropped = vec![];
  621. for chain in self.consensus.proposals.iter() {
  622. let first = chain.proposals.first().unwrap();
  623. if first.block.st != last_block || first.block.sl <= last_sl {
  624. dropped.push(chain.clone());
  625. }
  626. }
  627. for chain in dropped {
  628. self.consensus.proposals.retain(|c| *c != chain);
  629. }
  630. // Remove orphan votes
  631. let mut orphans = vec![];
  632. for vote in self.consensus.orphan_votes.iter() {
  633. if vote.sl <= last_sl {
  634. orphans.push(vote.clone());
  635. }
  636. }
  637. for vote in orphans {
  638. self.consensus.orphan_votes.retain(|v| *v != vote);
  639. }
  640. Ok(finalized)
  641. }
  642. /// Append a new participant to the pending participants list.
  643. pub fn append_participant(&mut self, participant: Participant) -> bool {
  644. if self.consensus.pending_participants.contains(&participant) {
  645. return false
  646. }
  647. self.consensus.pending_participants.push(participant);
  648. true
  649. }
  650. /// Refresh the participants map, to retain only the active ones.
  651. /// Active nodes are considered those that joined previous slot
  652. /// or on the slot the last proposal was generated, either voted
  653. /// or joined the previous of that slot. That ensures we cover
  654. /// the case of a node joining while the chosen slot leader is inactive.
  655. /// Inactive nodes are marked as quarantined, so they can be removed if
  656. /// they are in quarantine more than the predifined quarantine period.
  657. pub fn refresh_participants(&mut self) -> Result<()> {
  658. // Node checks if it should refresh its participants list
  659. let current = self.current_slot();
  660. if current <= self.consensus.refreshed {
  661. debug!("refresh_participants(): Participants have been refreshed this slot.");
  662. return Ok(())
  663. }
  664. debug!("refresh_participants(): Adding pending participants");
  665. for participant in &self.consensus.pending_participants {
  666. self.consensus.participants.insert(participant.address, participant.clone());
  667. }
  668. if self.consensus.pending_participants.is_empty() {
  669. debug!(
  670. "refresh_participants(): Didn't manage to add any participant, pending were empty."
  671. );
  672. }
  673. self.consensus.pending_participants = vec![];
  674. let mut inactive = Vec::new();
  675. let mut last_slot = self.last_slot()?;
  676. // This check ensures that we don't chech the current slot,
  677. // as a node might receive the proposal of current slot before
  678. // starting refreshing participants, so the last_slot will be
  679. // the current one.
  680. if last_slot >= current {
  681. last_slot = current - 1;
  682. }
  683. let previous_slot = current - 1;
  684. // This check ensures that when restarting the network, previous
  685. // from last slot is not u64::MAX
  686. let previous_from_last_slot = match last_slot {
  687. 0 => 0,
  688. _ => last_slot - 1,
  689. };
  690. debug!(
  691. "refresh_participants(): Node {:?} checking slots: previous - {:?}, last - {:?}, previous from last - {:?}",
  692. self.address.to_string(), previous_slot, last_slot, previous_from_last_slot
  693. );
  694. let leader = self.slot_leader();
  695. for (index, participant) in self.consensus.participants.iter_mut() {
  696. match participant.quarantined {
  697. Some(slot) => {
  698. if (current - slot) > QUARANTINE_DURATION {
  699. warn!(
  700. "refresh_participants(): Removing participant: {:?} (joined {:?}, voted {:?})",
  701. participant.address.to_string(),
  702. participant.joined,
  703. participant.voted
  704. );
  705. inactive.push(*index);
  706. }
  707. }
  708. None => {
  709. // Slot leader is always quarantined, to cover the case they become inactive the slot before
  710. // becoming the leader. This can be used for slashing in the future.
  711. if participant.address == leader {
  712. debug!(
  713. "refresh_participants(): Quaranteening leader: {:?} (joined {:?}, voted {:?})",
  714. participant.address.to_string(),
  715. participant.joined,
  716. participant.voted
  717. );
  718. participant.quarantined = Some(current);
  719. continue
  720. }
  721. match participant.voted {
  722. Some(slot) => {
  723. if slot < last_slot {
  724. warn!(
  725. "refresh_participants(): Quaranteening participant: {:?} (joined {:?}, voted {:?})",
  726. participant.address.to_string(),
  727. participant.joined,
  728. participant.voted
  729. );
  730. participant.quarantined = Some(current);
  731. }
  732. }
  733. None => {
  734. if (previous_slot == last_slot && participant.joined < previous_slot) ||
  735. (previous_slot != last_slot &&
  736. participant.joined < previous_from_last_slot)
  737. {
  738. warn!(
  739. "refresh_participants(): Quaranteening participant: {:?} (joined {:?}, voted {:?})",
  740. participant.address.to_string(),
  741. participant.joined,
  742. participant.voted
  743. );
  744. participant.quarantined = Some(current);
  745. }
  746. }
  747. }
  748. }
  749. }
  750. }
  751. for index in inactive {
  752. self.consensus.participants.remove(&index);
  753. }
  754. if self.consensus.participants.is_empty() {
  755. // If no nodes are active, node becomes a single node network.
  756. let participant = Participant::new(self.address, self.current_slot());
  757. self.consensus.participants.insert(participant.address, participant);
  758. }
  759. self.consensus.refreshed = current;
  760. Ok(())
  761. }
  762. /// Utility function to reset the current consensus state.
  763. pub fn reset_consensus_state(&mut self) -> Result<()> {
  764. let genesis_ts = self.consensus.genesis_ts;
  765. let genesis_block = self.consensus.genesis_block;
  766. let consensus = ConsensusState {
  767. genesis_ts,
  768. genesis_block,
  769. proposals: vec![],
  770. orphan_votes: vec![],
  771. participants: BTreeMap::new(),
  772. pending_participants: vec![],
  773. refreshed: 0,
  774. };
  775. self.consensus = consensus;
  776. Ok(())
  777. }
  778. // ==========================
  779. // State transition functions
  780. // ==========================
  781. /// Validate state transitions for given transactions and state and
  782. /// return a vector of [`StateUpdate`]
  783. pub fn validate_state_transitions(
  784. state: MemoryState,
  785. txs: &[Transaction],
  786. ) -> Result<Vec<StateUpdate>> {
  787. let mut ret = vec![];
  788. let mut st = state;
  789. for (i, tx) in txs.iter().enumerate() {
  790. let update = match state_transition(&st, tx.clone()) {
  791. Ok(v) => v,
  792. Err(e) => {
  793. warn!("validate_state_transition(): Failed for tx {}: {}", i, e);
  794. return Err(e.into())
  795. }
  796. };
  797. st.apply(update.clone());
  798. ret.push(update);
  799. }
  800. Ok(ret)
  801. }
  802. /// Apply a vector of [`StateUpdate`] to the canonical state.
  803. pub async fn update_canon_state(
  804. &self,
  805. updates: Vec<StateUpdate>,
  806. notify: Option<async_channel::Sender<(PublicKey, u64)>>,
  807. ) -> Result<()> {
  808. let secret_keys: Vec<SecretKey> =
  809. self.client.get_keypairs().await?.iter().map(|x| x.secret).collect();
  810. debug!("update_canon_state(): Acquiring state machine lock");
  811. let mut state = self.state_machine.lock().await;
  812. for update in updates {
  813. state
  814. .apply(
  815. update,
  816. secret_keys.clone(),
  817. notify.clone(),
  818. self.client.wallet.clone(),
  819. self.client.tokenlist.clone(),
  820. )
  821. .await?;
  822. }
  823. drop(state);
  824. debug!("update_canon_state(): Dropped state machine lock");
  825. debug!("update_canon_state(): Successfully applied state updates");
  826. Ok(())
  827. }
  828. }