state.rs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888
  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, KeepAlive, LeadProof, Metadata, Participant,
  15. ProposalChain,
  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. serial::{serialize, SerialDecodable, SerialEncodable},
  32. tx::Transaction,
  33. util::time::Timestamp,
  34. Result,
  35. };
  36. /// `2 * DELTA` represents slot time
  37. pub const DELTA: u64 = 20;
  38. /// Slots in an epoch
  39. pub const EPOCH_SLOTS: u64 = 10;
  40. /// Quarantine duration, in slots
  41. pub const QUARANTINE_DURATION: u64 = 5;
  42. /// This struct represents the information required by the consensus algorithm
  43. #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
  44. pub struct ConsensusState {
  45. /// Genesis block creation timestamp
  46. pub genesis_ts: Timestamp,
  47. /// Genesis block hash
  48. pub genesis_block: blake3::Hash,
  49. /// Fork chains containing block proposals
  50. pub proposals: Vec<ProposalChain>,
  51. /// Validators currently participating in the consensus
  52. pub participants: BTreeMap<Address, Participant>,
  53. /// Validators to be added on the next slot as participants
  54. pub pending_participants: Vec<Participant>,
  55. /// Last slot participants where refreshed
  56. pub refreshed: u64,
  57. }
  58. impl ConsensusState {
  59. pub fn new(genesis_ts: Timestamp, genesis_data: blake3::Hash) -> Result<Self> {
  60. let genesis_block =
  61. blake3::hash(&serialize(&Block::genesis_block(genesis_ts, genesis_data)));
  62. Ok(Self {
  63. genesis_ts,
  64. genesis_block,
  65. proposals: vec![],
  66. participants: BTreeMap::new(),
  67. pending_participants: vec![],
  68. refreshed: 0,
  69. })
  70. }
  71. }
  72. /// Auxiliary structure used for consensus syncing.
  73. #[derive(Debug, SerialEncodable, SerialDecodable)]
  74. pub struct ConsensusRequest {
  75. /// Validator wallet address
  76. pub address: Address,
  77. }
  78. impl net::Message for ConsensusRequest {
  79. fn name() -> &'static str {
  80. "consensusrequest"
  81. }
  82. }
  83. /// Auxiliary structure used for consensus syncing.
  84. #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
  85. pub struct ConsensusResponse {
  86. /// Hot/live data used by the consensus algorithm
  87. pub consensus: ConsensusState,
  88. }
  89. impl net::Message for ConsensusResponse {
  90. fn name() -> &'static str {
  91. "consensusresponse"
  92. }
  93. }
  94. /// Atomic pointer to validator state.
  95. pub type ValidatorStatePtr = Arc<RwLock<ValidatorState>>;
  96. /// This struct represents the state of a validator node.
  97. pub struct ValidatorState {
  98. /// Node wallet address
  99. pub address: Address,
  100. /// Secret key, to sign messages
  101. pub secret: SecretKey,
  102. /// Node public key
  103. pub public: PublicKey,
  104. /// Hot/Live data used by the consensus algorithm
  105. pub consensus: ConsensusState,
  106. /// Canonical (finalized) blockchain
  107. pub blockchain: Blockchain,
  108. /// Canonical state machine
  109. pub state_machine: Arc<Mutex<State>>,
  110. /// Client providing wallet access
  111. pub client: Arc<Client>,
  112. /// Pending transactions
  113. pub unconfirmed_txs: Vec<Transaction>,
  114. /// Participating start slot
  115. pub participating: Option<u64>,
  116. }
  117. impl ValidatorState {
  118. pub async fn new(
  119. db: &sled::Db, // <-- TODO: Avoid this with some wrapping, sled should only be in blockchain
  120. genesis_ts: Timestamp,
  121. genesis_data: blake3::Hash,
  122. client: Arc<Client>,
  123. cashier_pubkeys: Vec<PublicKey>,
  124. faucet_pubkeys: Vec<PublicKey>,
  125. ) -> Result<ValidatorStatePtr> {
  126. let secret = SecretKey::random(&mut OsRng);
  127. let public = PublicKey::from_secret(secret);
  128. let consensus = ConsensusState::new(genesis_ts, genesis_data)?;
  129. let blockchain = Blockchain::new(db, genesis_ts, genesis_data)?;
  130. let unconfirmed_txs = vec![];
  131. let participating = None;
  132. let address = client.wallet.get_default_address().await?;
  133. let state_machine = Arc::new(Mutex::new(State {
  134. tree: client.get_tree().await?,
  135. merkle_roots: blockchain.merkle_roots.clone(),
  136. nullifiers: blockchain.nullifiers.clone(),
  137. cashier_pubkeys,
  138. faucet_pubkeys,
  139. mint_vk: Lazy::new(),
  140. burn_vk: Lazy::new(),
  141. }));
  142. // Create zk proof verification keys
  143. let _ = state_machine.lock().await.mint_vk();
  144. let _ = state_machine.lock().await.burn_vk();
  145. let state = Arc::new(RwLock::new(ValidatorState {
  146. address,
  147. secret,
  148. public,
  149. consensus,
  150. blockchain,
  151. state_machine,
  152. client,
  153. unconfirmed_txs,
  154. participating,
  155. }));
  156. Ok(state)
  157. }
  158. /// The node retrieves a transaction, validates its state transition,
  159. /// and appends it to the unconfirmed transactions list.
  160. pub async fn append_tx(&mut self, tx: Transaction) -> bool {
  161. let tx_hash = blake3::hash(&serialize(&tx));
  162. let tx_in_txstore = match self.blockchain.transactions.contains(&tx_hash) {
  163. Ok(v) => v,
  164. Err(e) => {
  165. error!("append_tx(): Failed querying txstore: {}", e);
  166. return false
  167. }
  168. };
  169. if self.unconfirmed_txs.contains(&tx) || tx_in_txstore {
  170. debug!("append_tx(): We have already seen this tx.");
  171. return false
  172. }
  173. debug!("append_tx(): Starting state transition validation");
  174. let canon_state_clone = self.state_machine.lock().await.clone();
  175. let mem_state = MemoryState::new(canon_state_clone);
  176. match Self::validate_state_transitions(mem_state, &[tx.clone()]) {
  177. Ok(_) => debug!("append_tx(): State transition valid"),
  178. Err(e) => {
  179. warn!("append_tx(): State transition fail: {}", e);
  180. return false
  181. }
  182. }
  183. debug!("append_tx(): Appended tx to mempool");
  184. self.unconfirmed_txs.push(tx);
  185. true
  186. }
  187. /// Calculates the epoch of the provided slot.
  188. /// Epoch duration is configured using the `EPOCH_SLOTS` value.
  189. pub fn slot_epoch(&self, slot: u64) -> u64 {
  190. slot / EPOCH_SLOTS
  191. }
  192. /// Calculates current slot, based on elapsed time from the genesis block.
  193. /// Slot duration is configured using the `DELTA` value.
  194. pub fn current_slot(&self) -> u64 {
  195. self.consensus.genesis_ts.elapsed() / (2 * DELTA)
  196. }
  197. /// Finds the last slot a proposal or block was generated.
  198. pub fn last_slot(&self) -> Result<u64> {
  199. let mut slot = 0;
  200. for chain in &self.consensus.proposals {
  201. for proposal in &chain.proposals {
  202. if proposal.block.header.slot > slot {
  203. slot = proposal.block.header.slot;
  204. }
  205. }
  206. }
  207. // We return here in case proposals exist,
  208. // so we don't query the sled database.
  209. if slot > 0 {
  210. return Ok(slot)
  211. }
  212. let (last_slot, _) = self.blockchain.last()?;
  213. Ok(last_slot)
  214. }
  215. /// Calculates seconds until next Nth slot starting time.
  216. /// Slots duration is configured using the delta value.
  217. pub fn next_n_slot_start(&self, n: u64) -> Duration {
  218. let start_time = NaiveDateTime::from_timestamp(self.consensus.genesis_ts.0, 0);
  219. let current_slot = self.current_slot() + n;
  220. let next_slot_start = (current_slot * (2 * DELTA)) + (start_time.timestamp() as u64);
  221. let next_slot_start = NaiveDateTime::from_timestamp(next_slot_start as i64, 0);
  222. let current_time = NaiveDateTime::from_timestamp(Utc::now().timestamp(), 0);
  223. let diff = next_slot_start - current_time;
  224. Duration::new(diff.num_seconds().try_into().unwrap(), 0)
  225. }
  226. /// Set participating slot to next.
  227. pub fn set_participating(&mut self) -> Result<()> {
  228. self.participating = Some(self.current_slot() + 1);
  229. Ok(())
  230. }
  231. /// Find slot leader, using a simple hash method.
  232. /// Leader calculation is based on how many nodes are participating
  233. /// in the network.
  234. pub fn slot_leader(&mut self) -> Participant {
  235. let slot = self.current_slot();
  236. // DefaultHasher is used to hash the slot number
  237. // because it produces a number string which then can be modulated by the len.
  238. // blake3 produces alphanumeric
  239. let mut hasher = DefaultHasher::new();
  240. slot.hash(&mut hasher);
  241. let pos = hasher.finish() % (self.consensus.participants.len() as u64);
  242. // Since BTreeMap orders by key in asceding order, each node will have
  243. // the same key in calculated position.
  244. self.consensus.participants.iter().nth(pos as usize).unwrap().1.clone()
  245. }
  246. /// Check if we're the current slot leader
  247. pub fn is_slot_leader(&mut self) -> bool {
  248. let address = self.address;
  249. address == self.slot_leader().address
  250. }
  251. /// Generate a block proposal for the current slot, containing all
  252. /// unconfirmed transactions. Proposal extends the longest fork
  253. /// chain the node is holding.
  254. pub fn propose(&self) -> Result<Option<BlockProposal>> {
  255. let slot = self.current_slot();
  256. let (prev_hash, index) = self.longest_chain_last_hash().unwrap();
  257. let unproposed_txs = self.unproposed_txs(index);
  258. let mut tree = BridgeTree::<MerkleNode, MERKLE_DEPTH>::new(100);
  259. for tx in &unproposed_txs {
  260. for output in &tx.outputs {
  261. tree.append(&MerkleNode::from_coin(&output.revealed.coin));
  262. tree.witness();
  263. }
  264. }
  265. let root = tree.root(0).unwrap();
  266. let header =
  267. Header::new(prev_hash, self.slot_epoch(slot), slot, Timestamp::current_time(), root);
  268. let signed_proposal = self.secret.sign(&header.headerhash().as_bytes()[..]);
  269. // TODO: Replace with correct proof
  270. let eta: [u8; 32] = *blake3::hash(b"let there be dark!").as_bytes();
  271. let proof = LeadProof::default();
  272. let participants = self.consensus.participants.values().cloned().collect();
  273. let metadata = Metadata::new(signed_proposal, self.address, eta, proof, participants);
  274. // TODO: [PLACEHOLDER] Add balance proof creation
  275. // TODO: [PLACEHOLDER] Add crypsinous leader proof creation (to replace balance proof)
  276. // TODO: [PLACEHOLDER] Add rewards calculation (proof?)
  277. // TODO: [PLACEHOLDER] Create and add rewards transaction
  278. Ok(Some(BlockProposal::new(header, unproposed_txs, metadata)))
  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 blockchain the node holds and
  302. /// returns the last block hash and the chain index.
  303. pub fn longest_chain_last_hash(&self) -> Result<(blake3::Hash, i64)> {
  304. let mut longest: 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.proposals.len() > length {
  310. longest = Some(chain.clone());
  311. length = chain.proposals.len();
  312. index = i as i64;
  313. }
  314. }
  315. }
  316. let hash = match longest {
  317. Some(chain) => chain.proposals.last().unwrap().block.header.headerhash(),
  318. None => self.blockchain.last()?.1,
  319. };
  320. Ok((hash, index))
  321. }
  322. /// Given a proposal, the node verify its sender (slot leader), finds which blockchain
  323. /// it extends and check if it can be finalized. If the proposal extends
  324. /// the canonical blockchain, a new fork chain is created.
  325. pub async fn receive_proposal(
  326. &mut self,
  327. proposal: &BlockProposal,
  328. ) -> Result<Option<Vec<BlockInfo>>> {
  329. let current = self.current_slot();
  330. // Node hasn't started participating
  331. match self.participating {
  332. Some(start) => {
  333. if current < start {
  334. return Ok(None)
  335. }
  336. }
  337. None => return Ok(None),
  338. }
  339. // Node refreshes participants records
  340. self.refresh_participants()?;
  341. let mut leader = self.slot_leader();
  342. if leader.address != proposal.block.metadata.address {
  343. warn!(
  344. "Received proposal not from slot leader ({}), but from ({})",
  345. leader.address, proposal.block.metadata.address
  346. );
  347. return Ok(None)
  348. }
  349. if !leader.public_key.verify(
  350. proposal.block.header.headerhash().as_bytes(),
  351. &proposal.block.metadata.signature,
  352. ) {
  353. warn!("Proposer ({}) signature could not be verified", proposal.block.metadata.address);
  354. return Ok(None)
  355. }
  356. debug!("receive_proposal(): Starting state transition validation");
  357. let canon_state_clone = self.state_machine.lock().await.clone();
  358. let mem_state = MemoryState::new(canon_state_clone);
  359. match Self::validate_state_transitions(mem_state, &proposal.block.txs) {
  360. Ok(_) => {
  361. debug!("receive_proposal(): State transition valid")
  362. }
  363. Err(e) => {
  364. warn!("receive_proposal(): State transition fail: {}", e);
  365. return Ok(None)
  366. }
  367. }
  368. // TODO: [PLACEHOLDER] Add balance proof validation
  369. // TODO: [PLACEHOLDER] Add crypsinous proof validation (to replace balance proof)
  370. // TODO: [PLACEHOLDER] Add rewards validation
  371. if current > leader.seen {
  372. leader.seen = current;
  373. }
  374. // Invalidating quarantine
  375. leader.quarantined = None;
  376. self.consensus.participants.insert(leader.address, leader);
  377. let index = self.find_extended_chain_index(&proposal)?;
  378. if index == -2 {
  379. return Ok(None)
  380. }
  381. let mut to_broadcast = vec![];
  382. match index {
  383. -1 => {
  384. let pc = ProposalChain::new(self.consensus.genesis_block, proposal.clone());
  385. self.consensus.proposals.push(pc);
  386. }
  387. _ => {
  388. self.consensus.proposals[index as usize].add(&proposal);
  389. match self.chain_finalization(index).await {
  390. Ok(v) => {
  391. to_broadcast = v;
  392. }
  393. Err(e) => {
  394. error!("consensus: Block finalization failed: {}", e);
  395. return Err(e)
  396. }
  397. }
  398. }
  399. };
  400. Ok(Some(to_broadcast))
  401. }
  402. /// Given a proposal, find the index of the chain it extends.
  403. pub fn find_extended_chain_index(&mut self, proposal: &BlockProposal) -> Result<i64> {
  404. let mut fork = None;
  405. for (index, chain) in self.consensus.proposals.iter().enumerate() {
  406. let last = chain.proposals.last().unwrap();
  407. let hash = last.block.header.headerhash();
  408. if proposal.block.header.previous == hash &&
  409. proposal.block.header.slot > last.block.header.slot
  410. {
  411. return Ok(index as i64)
  412. }
  413. if proposal.block.header.previous == last.block.header.previous &&
  414. proposal.block.header.slot == last.block.header.slot
  415. {
  416. debug!("find_extended_chain_index(): Proposal already received");
  417. return Ok(-2)
  418. }
  419. if proposal.block.header.previous == last.block.header.previous &&
  420. proposal.block.header.slot > last.block.header.slot
  421. {
  422. fork = Some(chain.clone());
  423. }
  424. }
  425. if let Some(mut chain) = fork {
  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. let (last_slot, last_block) = self.blockchain.last()?;
  435. if proposal.block.header.previous != last_block || proposal.block.header.slot <= last_slot {
  436. debug!("find_extended_chain_index(): Proposal doesn't extend any known chain");
  437. return Ok(-2)
  438. }
  439. Ok(-1)
  440. }
  441. /// Search the chains we're holding for the given proposal.
  442. pub fn find_proposal(
  443. &mut self,
  444. input_proposal: &blake3::Hash,
  445. ) -> Result<Option<(&mut BlockProposal, i64)>> {
  446. for (index, chain) in &mut self.consensus.proposals.iter_mut().enumerate() {
  447. for proposal in chain.proposals.iter_mut().rev() {
  448. let proposal_hash = proposal.block.header.headerhash();
  449. if input_proposal == &proposal_hash {
  450. return Ok(Some((proposal, index as i64)))
  451. }
  452. }
  453. }
  454. Ok(None)
  455. }
  456. /// Remove provided transactions vector from unconfirmed_txs if they exist.
  457. pub fn remove_txs(&mut self, transactions: Vec<Transaction>) -> Result<()> {
  458. for tx in transactions {
  459. if let Some(pos) = self.unconfirmed_txs.iter().position(|txs| *txs == tx) {
  460. self.unconfirmed_txs.remove(pos);
  461. }
  462. }
  463. Ok(())
  464. }
  465. /// Provided an index, the node checks if the chain can be finalized.
  466. /// Consensus finalization logic:
  467. /// - If the node has observed the creation of 3 proposals in a fork chain,
  468. /// it finalizes (appends to canonical blockchain) all proposals up to the last one.
  469. /// When fork chain proposals are finalized, the rest of fork chains not
  470. /// starting by those proposals are removed.
  471. pub async fn chain_finalization(&mut self, chain_index: i64) -> Result<Vec<BlockInfo>> {
  472. let chain = &mut self.consensus.proposals[chain_index as usize];
  473. if chain.proposals.len() < 3 {
  474. debug!(
  475. "chain_finalization(): Less than 3 proposals in chain {}, nothing to finalize",
  476. chain_index
  477. );
  478. return Ok(vec![])
  479. }
  480. let bound = chain.proposals.len() - 1;
  481. let mut finalized = vec![];
  482. for proposal in &mut chain.proposals[..bound] {
  483. finalized.push(proposal.clone().into());
  484. }
  485. chain.proposals.drain(0..bound);
  486. info!("consensus: Adding {} finalized block to canonical chain.", finalized.len());
  487. let blockhashes = match self.blockchain.add(&finalized) {
  488. Ok(v) => v,
  489. Err(e) => {
  490. error!("consensus: Failed appending finalized blocks to canonical chain: {}", e);
  491. return Err(e)
  492. }
  493. };
  494. for proposal in &finalized {
  495. // TODO: Is this the right place? We're already doing this in protocol_sync.
  496. // TODO: These state transitions have already been checked.
  497. debug!(target: "consensus", "Applying state transition for finalized block");
  498. let canon_state_clone = self.state_machine.lock().await.clone();
  499. let mem_st = MemoryState::new(canon_state_clone);
  500. let state_updates = Self::validate_state_transitions(mem_st, &proposal.txs)?;
  501. self.update_canon_state(state_updates, None).await?;
  502. self.remove_txs(proposal.txs.clone())?;
  503. }
  504. let last_block = *blockhashes.last().unwrap();
  505. let last_slot = finalized.last().unwrap().header.slot;
  506. let mut dropped = vec![];
  507. for chain in self.consensus.proposals.iter() {
  508. let first = chain.proposals.first().unwrap();
  509. if first.block.header.previous != last_block || first.block.header.slot <= last_slot {
  510. dropped.push(chain.clone());
  511. }
  512. }
  513. for chain in dropped {
  514. self.consensus.proposals.retain(|c| *c != chain);
  515. }
  516. Ok(finalized)
  517. }
  518. /// Append a new participant to the pending participants list.
  519. pub fn append_participant(&mut self, participant: Participant) -> bool {
  520. if self.consensus.pending_participants.contains(&participant) {
  521. return false
  522. }
  523. // TODO: [PLACEHOLDER] Add balance proof validation
  524. self.consensus.pending_participants.push(participant);
  525. true
  526. }
  527. /// Update participant seen.
  528. pub fn participant_keep_alive(&mut self, keep_alive: KeepAlive) -> bool {
  529. match self.consensus.participants.get(&keep_alive.address) {
  530. None => {
  531. warn!(
  532. "Keep alive message from unknown participant: {}",
  533. keep_alive.address.to_string()
  534. );
  535. false
  536. }
  537. Some(participant) => {
  538. let current = self.current_slot();
  539. if current != keep_alive.slot {
  540. warn!("keep alive message slot is not current one for: {}", keep_alive.address);
  541. return false
  542. }
  543. let serialized = serialize(&current);
  544. if !participant.public_key.verify(&serialized, &keep_alive.signature) {
  545. warn!(
  546. "Keep alive message signature could not be verified for: {}",
  547. keep_alive.address
  548. );
  549. return false
  550. }
  551. // TODO: [PLACEHOLDER] Add balance proof validation
  552. // Updating participant last seen slot
  553. let mut participant = participant.clone();
  554. participant.seen = current;
  555. // Invalidating quarantine
  556. participant.quarantined = None;
  557. self.consensus.participants.insert(participant.address, participant);
  558. true
  559. }
  560. }
  561. }
  562. /// Refresh the participants map, to retain only the active ones.
  563. /// Active nodes are considered those that their last seen slot is
  564. /// in range: [current_slot - QUARANTINE_DURATION, current_slot]
  565. /// Inactive nodes are marked as quarantined, so they can be removed if
  566. /// they are in quarantine more than the predifined quarantine period.
  567. pub fn refresh_participants(&mut self) -> Result<()> {
  568. // Node checks if it should refresh its participants list
  569. let current = self.current_slot();
  570. if current <= self.consensus.refreshed {
  571. debug!("refresh_participants(): Participants have been refreshed this slot.");
  572. return Ok(())
  573. }
  574. debug!("refresh_participants(): Adding pending participants");
  575. for participant in &self.consensus.pending_participants {
  576. self.consensus.participants.insert(participant.address, participant.clone());
  577. }
  578. if self.consensus.pending_participants.is_empty() {
  579. debug!(
  580. "refresh_participants(): Didn't manage to add any participant, pending were empty."
  581. );
  582. }
  583. self.consensus.pending_participants = vec![];
  584. let mut inactive = Vec::new();
  585. let low_bound = current - QUARANTINE_DURATION;
  586. debug!(
  587. "refresh_participants(): Node {} checking slots range: {} -> {}",
  588. self.address, low_bound, current
  589. );
  590. let leader = self.slot_leader();
  591. for (index, participant) in self.consensus.participants.iter_mut() {
  592. match participant.quarantined {
  593. Some(slot) => {
  594. if slot < low_bound {
  595. warn!(
  596. "refresh_participants(): Removing participant: {} (seen {}, quarantined {})",
  597. participant.address,
  598. participant.seen,
  599. slot
  600. );
  601. inactive.push(*index);
  602. }
  603. }
  604. None => {
  605. // Slot leader is always quarantined, to cover the case they become inactive the slot before
  606. // becoming the leader. This can be used for slashing in the future.
  607. if participant.address == leader.address {
  608. debug!(
  609. "refresh_participants(): Quaranteening leader: {} (seen {})",
  610. participant.address, participant.seen
  611. );
  612. participant.quarantined = Some(current);
  613. continue
  614. }
  615. if participant.seen < low_bound {
  616. warn!(
  617. "refresh_participants(): Quaranteening participant: {} (seen {})",
  618. participant.address, participant.seen
  619. );
  620. participant.quarantined = Some(current);
  621. }
  622. }
  623. }
  624. }
  625. for index in inactive {
  626. self.consensus.participants.remove(&index);
  627. }
  628. if self.consensus.participants.is_empty() {
  629. // If no nodes are active, node becomes a single node network.
  630. let participant = Participant::new(self.public, self.address, self.current_slot());
  631. self.consensus.participants.insert(participant.address, participant);
  632. }
  633. self.consensus.refreshed = current;
  634. Ok(())
  635. }
  636. /// Utility function to reset the current consensus state.
  637. pub fn reset_consensus_state(&mut self) -> Result<()> {
  638. let genesis_ts = self.consensus.genesis_ts;
  639. let genesis_block = self.consensus.genesis_block;
  640. let consensus = ConsensusState {
  641. genesis_ts,
  642. genesis_block,
  643. proposals: vec![],
  644. participants: BTreeMap::new(),
  645. pending_participants: vec![],
  646. refreshed: 0,
  647. };
  648. self.consensus = consensus;
  649. Ok(())
  650. }
  651. // ==========================
  652. // State transition functions
  653. // ==========================
  654. /// Validate and append to canonical state received blocks.
  655. pub async fn receive_blocks(&mut self, blocks: &[BlockInfo]) -> Result<()> {
  656. // Verify state transitions for all blocks and their respective transactions.
  657. debug!("receive_blocks(): Starting state transition validations");
  658. let mut canon_updates = vec![];
  659. let canon_state_clone = self.state_machine.lock().await.clone();
  660. let mut mem_state = MemoryState::new(canon_state_clone);
  661. for block in blocks {
  662. let mut state_updates =
  663. Self::validate_state_transitions(mem_state.clone(), &block.txs)?;
  664. for update in &state_updates {
  665. mem_state.apply(update.clone());
  666. }
  667. canon_updates.append(&mut state_updates);
  668. }
  669. debug!("receive_blocks(): All state transitions passed");
  670. debug!("receive_blocks(): Updating canon state");
  671. self.update_canon_state(canon_updates, None).await?;
  672. debug!("receive_blocks(): Appending blocks to ledger");
  673. self.blockchain.add(blocks)?;
  674. Ok(())
  675. }
  676. /// Validate and append to canonical state received finalized block.
  677. /// Returns boolean flag indicating already existing block.
  678. pub async fn receive_finalized_block(&mut self, block: BlockInfo) -> Result<bool> {
  679. match self.blockchain.has_block(&block) {
  680. Ok(v) => {
  681. if v {
  682. debug!("receive_finalized_block(): Existing block received");
  683. return Ok(false)
  684. }
  685. }
  686. Err(e) => {
  687. error!("receive_finalized_block(): failed checking for has_block(): {}", e);
  688. return Ok(false)
  689. }
  690. };
  691. debug!("receive_finalized_block(): Executing state transitions");
  692. self.receive_blocks(&[block.clone()]).await?;
  693. debug!("receive_finalized_block(): Removing block transactions from unconfirmed_txs");
  694. self.remove_txs(block.txs.clone())?;
  695. Ok(true)
  696. }
  697. /// Validate and append to canonical state received finalized blocks from block sync task.
  698. /// Already existing blocks are ignored.
  699. pub async fn receive_sync_blocks(&mut self, blocks: &[BlockInfo]) -> Result<()> {
  700. let mut new_blocks = vec![];
  701. for block in blocks {
  702. match self.blockchain.has_block(block) {
  703. Ok(v) => {
  704. if v {
  705. debug!("receive_sync_blocks(): Existing block received");
  706. continue
  707. }
  708. new_blocks.push(block.clone());
  709. }
  710. Err(e) => {
  711. error!("receive_sync_blocks(): failed checking for has_block(): {}", e);
  712. continue
  713. }
  714. };
  715. }
  716. if new_blocks.is_empty() {
  717. debug!("receive_sync_blocks(): no new blocks to append");
  718. return Ok(())
  719. }
  720. debug!("receive_sync_blocks(): Executing state transitions");
  721. self.receive_blocks(&new_blocks[..]).await?;
  722. Ok(())
  723. }
  724. /// Validate state transitions for given transactions and state and
  725. /// return a vector of [`StateUpdate`]
  726. pub fn validate_state_transitions(
  727. state: MemoryState,
  728. txs: &[Transaction],
  729. ) -> Result<Vec<StateUpdate>> {
  730. let mut ret = vec![];
  731. let mut st = state;
  732. for (i, tx) in txs.iter().enumerate() {
  733. let update = match state_transition(&st, tx.clone()) {
  734. Ok(v) => v,
  735. Err(e) => {
  736. warn!("validate_state_transition(): Failed for tx {}: {}", i, e);
  737. return Err(e.into())
  738. }
  739. };
  740. st.apply(update.clone());
  741. ret.push(update);
  742. }
  743. Ok(ret)
  744. }
  745. /// Apply a vector of [`StateUpdate`] to the canonical state.
  746. pub async fn update_canon_state(
  747. &self,
  748. updates: Vec<StateUpdate>,
  749. notify: Option<smol::channel::Sender<(PublicKey, u64)>>,
  750. ) -> Result<()> {
  751. let secret_keys: Vec<SecretKey> =
  752. self.client.get_keypairs().await?.iter().map(|x| x.secret).collect();
  753. debug!("update_canon_state(): Acquiring state machine lock");
  754. let mut state = self.state_machine.lock().await;
  755. for update in updates {
  756. state
  757. .apply(update, secret_keys.clone(), notify.clone(), self.client.wallet.clone())
  758. .await?;
  759. }
  760. drop(state);
  761. debug!("update_canon_state(): Dropped state machine lock");
  762. debug!("update_canon_state(): Successfully applied state updates");
  763. Ok(())
  764. }
  765. }