consensus_sync.rs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2023 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use log::{info, warn};
  19. use crate::{
  20. consensus::{
  21. state::{ConsensusRequest, ConsensusResponse, ConsensusSyncRequest, ConsensusSyncResponse},
  22. Float10, ValidatorStatePtr,
  23. },
  24. net::P2pPtr,
  25. system::sleep,
  26. Result,
  27. };
  28. /// async task used for consensus state syncing.
  29. /// Returns flag if node is not connected to other peers or consensus hasn't started,
  30. /// so it can immediately start proposing proposals.
  31. pub async fn consensus_sync_task(p2p: P2pPtr, state: ValidatorStatePtr) -> Result<bool> {
  32. info!(target: "consensus::consensus_sync", "Starting consensus state sync...");
  33. let current_slot = state.read().await.consensus.time_keeper.current_slot();
  34. // Loop through connected channels
  35. let channels = p2p.channels().await;
  36. if channels.is_empty() {
  37. warn!(target: "consensus::consensus_sync", "Node is not connected to other nodes");
  38. let mut lock = state.write().await;
  39. lock.consensus.bootstrap_slot = current_slot;
  40. lock.consensus.init_coins().await?;
  41. info!(target: "consensus::consensus_sync", "Consensus state synced!");
  42. return Ok(true)
  43. }
  44. // Node iterates the channel peers to check if at least on peer has seen slots
  45. let mut peer = None;
  46. for channel in channels {
  47. // Communication setup
  48. let msg_subsystem = channel.message_subsystem();
  49. msg_subsystem.add_dispatch::<ConsensusSyncResponse>().await;
  50. let response_sub = channel.subscribe_msg::<ConsensusSyncResponse>().await?;
  51. // Node creates a `ConsensusSyncRequest` and sends it
  52. let request = ConsensusSyncRequest {};
  53. channel.send(&request).await?;
  54. // Node checks response
  55. let response = response_sub.receive().await?;
  56. if response.bootstrap_slot == current_slot {
  57. warn!(target: "consensus::consensus_sync", "Network was just bootstraped, checking rest nodes");
  58. continue
  59. }
  60. if !response.proposing {
  61. warn!(target: "consensus::consensus_sync", "Node is not proposing, checking rest nodes");
  62. continue
  63. }
  64. if response.is_empty {
  65. warn!(target: "consensus::consensus_sync", "Node has not seen any slots, retrying...");
  66. continue
  67. }
  68. // Keep peer to ask for consensus state
  69. peer = Some(channel.clone());
  70. break
  71. }
  72. // If no peer knows about any slots, that means that the network was bootstrapped or restarted
  73. // and no node has started consensus.
  74. if peer.is_none() {
  75. warn!(target: "consensus::consensus_sync", "No node that has seen any slots was found, or network was just boostrapped.");
  76. let mut lock = state.write().await;
  77. lock.consensus.bootstrap_slot = current_slot;
  78. lock.consensus.init_coins().await?;
  79. info!(target: "consensus::consensus_sync", "Consensus state synced!");
  80. return Ok(true)
  81. }
  82. let peer = peer.unwrap();
  83. // Listen for next finalization
  84. info!(target: "consensus::consensus_sync", "Waiting for next finalization...");
  85. let subscriber = state.read().await.subscribers.get("blocks").unwrap().clone();
  86. let subscription = subscriber.sub.subscribe().await;
  87. subscription.receive().await;
  88. subscription.unsubscribe().await;
  89. // After finalization occurs, sync our consensus state.
  90. // This ensures that the received state always consists of 1 fork with one proposal.
  91. info!(target: "consensus::consensus_sync", "Finalization signal received, requesting consensus state...");
  92. // Communication setup
  93. let msg_subsystem = peer.message_subsystem();
  94. msg_subsystem.add_dispatch::<ConsensusResponse>().await;
  95. let response_sub = peer.subscribe_msg::<ConsensusResponse>().await?;
  96. // Node creates a `ConsensusRequest` and sends it
  97. peer.send(&ConsensusRequest {}).await?;
  98. // Node verifies response came from a participating node.
  99. // Extra validations can be added here.
  100. let mut response = response_sub.receive().await?;
  101. // Verify that peer has finished finalizing forks
  102. loop {
  103. if !response.forks.is_empty() {
  104. warn!(target: "consensus::consensus_sync", "Peer has not finished finalization, retrying...");
  105. sleep(1).await;
  106. peer.send(&ConsensusRequest {}).await?;
  107. response = response_sub.receive().await?;
  108. continue
  109. }
  110. break
  111. }
  112. // Verify that the node has received all finalized blocks
  113. loop {
  114. if !state.read().await.blockchain.has_slot_order(response.current_slot)? {
  115. warn!(target: "consensus::consensus_sync", "Node has not finished finalization, retrying...");
  116. sleep(1).await;
  117. continue
  118. }
  119. break
  120. }
  121. // Node stores response data.
  122. let mut lock = state.write().await;
  123. let mut forks = vec![];
  124. for fork in &response.forks {
  125. forks.push(fork.clone().into());
  126. }
  127. lock.consensus.bootstrap_slot = response.bootstrap_slot;
  128. lock.consensus.forks = forks;
  129. lock.append_pending_txs(&response.pending_txs).await;
  130. lock.consensus.slots = response.slots.clone();
  131. lock.consensus.previous_leaders = 1;
  132. let mut f_history = vec![];
  133. for f in &response.f_history {
  134. let f_float = Float10::try_from(f.as_str()).unwrap();
  135. f_history.push(f_float);
  136. }
  137. lock.consensus.f_history = f_history;
  138. let mut err_history = vec![];
  139. for err in &response.err_history {
  140. let err_float = Float10::try_from(err.as_str()).unwrap();
  141. err_history.push(err_float);
  142. }
  143. lock.consensus.err_history = err_history;
  144. lock.consensus.nullifiers = response.nullifiers.clone();
  145. lock.consensus.init_coins().await?;
  146. info!(target: "consensus::consensus_sync", "Consensus state synced!");
  147. Ok(false)
  148. }