protocol_sync.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  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 async_std::sync::Arc;
  19. use async_trait::async_trait;
  20. use log::{debug, error, info};
  21. use smol::Executor;
  22. use darkfi_sdk::blockchain::Slot;
  23. use crate::{
  24. consensus::{
  25. block::{BlockInfo, BlockOrder, BlockResponse},
  26. state::{SlotRequest, SlotResponse},
  27. ValidatorStatePtr,
  28. },
  29. net::{
  30. ChannelPtr, MessageSubscription, P2pPtr, ProtocolBase, ProtocolBasePtr,
  31. ProtocolJobsManager, ProtocolJobsManagerPtr,
  32. },
  33. Result,
  34. };
  35. // Constant defining how many blocks we send during syncing.
  36. const BATCH: u64 = 10;
  37. pub struct ProtocolSync {
  38. channel: ChannelPtr,
  39. request_sub: MessageSubscription<BlockOrder>,
  40. slot_request_sub: MessageSubscription<SlotRequest>,
  41. block_sub: MessageSubscription<BlockInfo>,
  42. slots_sub: MessageSubscription<Slot>,
  43. jobsman: ProtocolJobsManagerPtr,
  44. state: ValidatorStatePtr,
  45. p2p: P2pPtr,
  46. consensus_mode: bool,
  47. }
  48. impl ProtocolSync {
  49. pub async fn init(
  50. channel: ChannelPtr,
  51. state: ValidatorStatePtr,
  52. p2p: P2pPtr,
  53. consensus_mode: bool,
  54. ) -> Result<ProtocolBasePtr> {
  55. let msg_subsystem = channel.message_subsystem();
  56. msg_subsystem.add_dispatch::<BlockOrder>().await;
  57. msg_subsystem.add_dispatch::<SlotRequest>().await;
  58. msg_subsystem.add_dispatch::<BlockInfo>().await;
  59. msg_subsystem.add_dispatch::<Slot>().await;
  60. let request_sub = channel.subscribe_msg::<BlockOrder>().await?;
  61. let slot_request_sub = channel.subscribe_msg::<SlotRequest>().await?;
  62. let block_sub = channel.subscribe_msg::<BlockInfo>().await?;
  63. let slots_sub = channel.subscribe_msg::<Slot>().await?;
  64. Ok(Arc::new(Self {
  65. channel: channel.clone(),
  66. request_sub,
  67. slot_request_sub,
  68. block_sub,
  69. slots_sub,
  70. jobsman: ProtocolJobsManager::new("SyncProtocol", channel),
  71. state,
  72. p2p,
  73. consensus_mode,
  74. }))
  75. }
  76. async fn handle_receive_request(self: Arc<Self>) -> Result<()> {
  77. debug!(
  78. target: "consensus::protocol_sync::handle_receive_request()",
  79. "START"
  80. );
  81. loop {
  82. let order = match self.request_sub.receive().await {
  83. Ok(v) => v,
  84. Err(e) => {
  85. debug!(
  86. target: "consensus::protocol_sync::handle_receive_request()",
  87. "recv fail: {}",
  88. e
  89. );
  90. continue
  91. }
  92. };
  93. debug!(
  94. target: "consensus::protocol_sync::handle_receive_request()",
  95. "received {:?}",
  96. order
  97. );
  98. // Extra validations can be added here
  99. /*
  100. let key = order.slot;
  101. let blocks = match self.state.read().await.blockchain.get_blocks_after(key, BATCH) {
  102. Ok(v) => v,
  103. Err(e) => {
  104. error!(
  105. target: "consensus::protocol_sync::handle_receive_request()",
  106. "get_blocks_after fail: {}",
  107. e
  108. );
  109. continue
  110. }
  111. };
  112. debug!(
  113. target: "consensus::protocol_sync::handle_receive_request()",
  114. "Found {} blocks",
  115. blocks.len()
  116. );
  117. */
  118. let blocks = vec![BlockInfo::default()];
  119. let response = BlockResponse { blocks };
  120. if let Err(e) = self.channel.send(&response).await {
  121. error!(
  122. target: "consensus::protocol_sync::handle_receive_request()",
  123. "channel send fail: {}",
  124. e
  125. )
  126. };
  127. }
  128. }
  129. async fn handle_receive_block(self: Arc<Self>) -> Result<()> {
  130. debug!(target: "consensus::protocol_sync::handle_receive_block()", "START");
  131. let _exclude_list = [self.channel.address()];
  132. loop {
  133. let info = match self.block_sub.receive().await {
  134. Ok(v) => v,
  135. Err(e) => {
  136. debug!(
  137. target: "consensus::protocol_sync::handle_receive_block()",
  138. "recv fail: {}",
  139. e
  140. );
  141. continue
  142. }
  143. };
  144. // Check if node has finished syncing its blockchain
  145. if !self.state.read().await.synced {
  146. debug!(
  147. target: "consensus::protocol_sync::handle_receive_block()",
  148. "Node still syncing blockchain, skipping..."
  149. );
  150. continue
  151. }
  152. // Check if node started participating in consensus.
  153. // Consensus-mode enabled nodes have already performed these steps,
  154. // during proposal finalization. They still listen to this sub,
  155. // in case they go out of sync and become a none-consensus node.
  156. if self.consensus_mode {
  157. let lock = self.state.read().await;
  158. let current = lock.consensus.time_keeper.current_slot();
  159. let participating = lock.consensus.participating;
  160. if participating.is_some() {
  161. let slot = participating.unwrap();
  162. if current >= slot {
  163. debug!(
  164. target: "consensus::protocol_sync::handle_receive_block()",
  165. "node runs in consensus mode, skipping..."
  166. );
  167. continue
  168. }
  169. }
  170. }
  171. info!(
  172. target: "consensus::protocol_sync::handle_receive_block()",
  173. "Received block: {}",
  174. info.blockhash()
  175. );
  176. debug!(
  177. target: "consensus::protocol_sync::handle_receive_block()",
  178. "Processing received block"
  179. );
  180. /*
  181. let info_copy = (*info).clone();
  182. match self.state.write().await.receive_finalized_block(info_copy.clone()).await {
  183. Ok(v) => {
  184. if v {
  185. debug!(
  186. target: "consensus::protocol_sync::handle_receive_block()",
  187. "block processed successfully, broadcasting..."
  188. );
  189. self.p2p.broadcast_with_exclude(&info_copy, &exclude_list).await;
  190. }
  191. }
  192. Err(e) => {
  193. debug!(
  194. target: "consensus::protocol_sync::handle_receive_block()",
  195. "error processing finalized block: {}",
  196. e
  197. );
  198. }
  199. };
  200. */
  201. }
  202. }
  203. async fn handle_receive_slot_request(self: Arc<Self>) -> Result<()> {
  204. debug!(
  205. target: "consensus::protocol_sync::handle_receive_slot_request()",
  206. "START"
  207. );
  208. loop {
  209. let request = match self.slot_request_sub.receive().await {
  210. Ok(v) => v,
  211. Err(e) => {
  212. debug!(
  213. target: "consensus::protocol_sync::handle_receive_slot_request()",
  214. "recv fail: {}",
  215. e
  216. );
  217. continue
  218. }
  219. };
  220. debug!(
  221. target: "consensus::protocol_sync::handle_receive_slot_request()",
  222. "received {:?}",
  223. request
  224. );
  225. // Extra validations can be added here
  226. let key = request.slot;
  227. let slots = match self.state.read().await.blockchain.get_slots_after(key, BATCH) {
  228. Ok(v) => v,
  229. Err(e) => {
  230. error!(
  231. target: "consensus::protocol_sync::handle_receive_slot_request()",
  232. "get_slots_after fail: {}",
  233. e
  234. );
  235. continue
  236. }
  237. };
  238. debug!(
  239. target: "consensus::protocol_sync::handle_receive_slot_request()",
  240. "Found {} slots",
  241. slots.len()
  242. );
  243. let response = SlotResponse { slots };
  244. if let Err(e) = self.channel.send(&response).await {
  245. error!(
  246. target: "consensus::protocol_sync::handle_receive_slot_request()",
  247. "channel send fail: {}",
  248. e
  249. )
  250. };
  251. }
  252. }
  253. async fn handle_receive_slot(self: Arc<Self>) -> Result<()> {
  254. debug!(
  255. target: "consensus::protocol_sync::handle_receive_slot()",
  256. "START"
  257. );
  258. let exclude_list = vec![self.channel.address().clone()];
  259. loop {
  260. let slot = match self.slots_sub.receive().await {
  261. Ok(v) => v,
  262. Err(e) => {
  263. debug!(
  264. target: "consensus::protocol_sync::handle_receive_slot()",
  265. "recv fail: {}",
  266. e
  267. );
  268. continue
  269. }
  270. };
  271. // Check if node has finished syncing its blockchain
  272. if !self.state.read().await.synced {
  273. debug!(
  274. target: "consensus::protocol_sync::handle_receive_slot()",
  275. "Node still syncing blockchain, skipping..."
  276. );
  277. continue
  278. }
  279. // Check if node started participating in consensus.
  280. // Consensus-mode enabled nodes have already performed these steps,
  281. // during proposal finalization. They still listen to this sub,
  282. // in case they go out of sync and become a none-consensus node.
  283. if self.consensus_mode {
  284. let lock = self.state.read().await;
  285. let current = lock.consensus.time_keeper.current_slot();
  286. let participating = lock.consensus.participating;
  287. if participating.is_some() {
  288. let slot = participating.unwrap();
  289. if current >= slot {
  290. debug!(
  291. target: "consensus::protocol_sync::handle_receive_slot()",
  292. "node runs in consensus mode, skipping..."
  293. );
  294. continue
  295. }
  296. }
  297. }
  298. info!(
  299. target: "consensus::protocol_sync::handle_receive_slot()",
  300. "Received slot: {}",
  301. slot.id
  302. );
  303. debug!(
  304. target: "consensus::protocol_sync::handle_receive_slot()",
  305. "Processing received slot"
  306. );
  307. let slot_copy = (*slot).clone();
  308. match self.state.write().await.receive_finalized_slots(slot_copy.clone()).await {
  309. Ok(v) => {
  310. if v {
  311. debug!(
  312. target: "consensus::protocol_sync::handle_receive_slot()",
  313. "slot processed successfully, broadcasting..."
  314. );
  315. self.p2p.broadcast_with_exclude(&slot_copy, &exclude_list).await;
  316. }
  317. }
  318. Err(e) => {
  319. debug!(
  320. target: "consensus::protocol_sync::handle_receive_slot()",
  321. "error processing finalized slot: {}",
  322. e
  323. );
  324. }
  325. };
  326. }
  327. }
  328. }
  329. #[async_trait]
  330. impl ProtocolBase for ProtocolSync {
  331. async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> Result<()> {
  332. debug!(target: "consensus::protocol_sync::start()", "START");
  333. self.jobsman.clone().start(executor.clone());
  334. self.jobsman.clone().spawn(self.clone().handle_receive_request(), executor.clone()).await;
  335. self.jobsman
  336. .clone()
  337. .spawn(self.clone().handle_receive_slot_request(), executor.clone())
  338. .await;
  339. self.jobsman.clone().spawn(self.clone().handle_receive_block(), executor.clone()).await;
  340. self.jobsman.clone().spawn(self.clone().handle_receive_slot(), executor.clone()).await;
  341. debug!(target: "consensus::protocol_sync::start()", "END");
  342. Ok(())
  343. }
  344. fn name(&self) -> &'static str {
  345. "ProtocolSync"
  346. }
  347. }