state.rs 38 KB

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