protocol_sync.rs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2024 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 std::sync::Arc;
  19. use async_trait::async_trait;
  20. use log::{debug, error};
  21. use smol::Executor;
  22. use darkfi::{
  23. blockchain::{BlockInfo, Header, HeaderHash},
  24. impl_p2p_message,
  25. net::{
  26. ChannelPtr, Message, MessageSubscription, ProtocolBase, ProtocolBasePtr,
  27. ProtocolJobsManager, ProtocolJobsManagerPtr,
  28. },
  29. validator::{consensus::Proposal, ValidatorPtr},
  30. Result,
  31. };
  32. use darkfi_serial::{SerialDecodable, SerialEncodable};
  33. // Constant defining how many blocks we send during syncing.
  34. pub const BATCH: usize = 10;
  35. /// Structure represening a request to ask a node for their current
  36. /// canonical(finalized) tip block hash, if they are synced. We also
  37. /// include our own tip, so they can verify we follow the same sequence.
  38. #[derive(Debug, SerialEncodable, SerialDecodable)]
  39. pub struct TipRequest {
  40. /// Canonical(finalized) tip block hash
  41. pub tip: HeaderHash,
  42. }
  43. impl_p2p_message!(TipRequest, "tiprequest");
  44. /// Structure representing the response to `TipRequest`,
  45. /// containing a boolean flag to indicate if we are synced,
  46. /// and our canonical(finalized) tip block height and hash.
  47. #[derive(Debug, SerialEncodable, SerialDecodable)]
  48. pub struct TipResponse {
  49. /// Flag indicating the node is synced
  50. pub synced: bool,
  51. /// Canonical(finalized) tip block height
  52. pub height: Option<u32>,
  53. /// Canonical(finalized) tip block hash
  54. pub hash: Option<HeaderHash>,
  55. }
  56. impl_p2p_message!(TipResponse, "tipresponse");
  57. /// Structure represening a request to ask a node for up to `BATCH` headers before
  58. /// the provided header height.
  59. #[derive(Debug, SerialEncodable, SerialDecodable)]
  60. pub struct HeaderSyncRequest {
  61. /// Header height
  62. pub height: u32,
  63. }
  64. impl_p2p_message!(HeaderSyncRequest, "headersyncrequest");
  65. /// Structure representing the response to `HeaderSyncRequest`,
  66. /// containing up to `BATCH` headers before the requested block height.
  67. #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
  68. pub struct HeaderSyncResponse {
  69. /// Response headers
  70. pub headers: Vec<Header>,
  71. }
  72. impl_p2p_message!(HeaderSyncResponse, "headersyncresponse");
  73. /// Structure represening a request to ask a node for up to`BATCH` blocks
  74. /// of provided headers.
  75. #[derive(Debug, SerialEncodable, SerialDecodable)]
  76. pub struct SyncRequest {
  77. /// Header hashes
  78. pub headers: Vec<HeaderHash>,
  79. }
  80. impl_p2p_message!(SyncRequest, "syncrequest");
  81. /// Structure representing the response to `SyncRequest`,
  82. /// containing up to `BATCH` blocks after the requested block height.
  83. #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
  84. pub struct SyncResponse {
  85. /// Response blocks
  86. pub blocks: Vec<BlockInfo>,
  87. }
  88. impl_p2p_message!(SyncResponse, "syncresponse");
  89. /// Structure represening a request to ask a node a fork sequence.
  90. /// If we include a specific fork tip, they have to return its sequence,
  91. /// otherwise they respond with their best fork sequence.
  92. /// We also include our own canonical(finalized) tip, so they can verify
  93. /// we follow the same sequence.
  94. #[derive(Debug, SerialEncodable, SerialDecodable)]
  95. pub struct ForkSyncRequest {
  96. /// Canonical(finalized) tip block hash
  97. pub tip: HeaderHash,
  98. /// Optional fork tip block hash
  99. pub fork_tip: Option<HeaderHash>,
  100. }
  101. impl_p2p_message!(ForkSyncRequest, "forksyncrequest");
  102. /// Structure representing the response to `ForkSyncRequest`,
  103. /// containing the requested fork sequence.
  104. #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
  105. pub struct ForkSyncResponse {
  106. /// Response fork proposals
  107. pub proposals: Vec<Proposal>,
  108. }
  109. impl_p2p_message!(ForkSyncResponse, "forksyncresponse");
  110. pub struct ProtocolSync {
  111. tip_sub: MessageSubscription<TipRequest>,
  112. header_sub: MessageSubscription<HeaderSyncRequest>,
  113. request_sub: MessageSubscription<SyncRequest>,
  114. fork_request_sub: MessageSubscription<ForkSyncRequest>,
  115. jobsman: ProtocolJobsManagerPtr,
  116. validator: ValidatorPtr,
  117. channel: ChannelPtr,
  118. }
  119. impl ProtocolSync {
  120. pub async fn init(channel: ChannelPtr, validator: ValidatorPtr) -> Result<ProtocolBasePtr> {
  121. debug!(
  122. target: "darkfid::proto::protocol_sync::init",
  123. "Adding ProtocolSync to the protocol registry"
  124. );
  125. let msg_subsystem = channel.message_subsystem();
  126. msg_subsystem.add_dispatch::<TipRequest>().await;
  127. msg_subsystem.add_dispatch::<TipResponse>().await;
  128. msg_subsystem.add_dispatch::<HeaderSyncRequest>().await;
  129. msg_subsystem.add_dispatch::<HeaderSyncResponse>().await;
  130. msg_subsystem.add_dispatch::<SyncRequest>().await;
  131. msg_subsystem.add_dispatch::<SyncResponse>().await;
  132. msg_subsystem.add_dispatch::<ForkSyncRequest>().await;
  133. msg_subsystem.add_dispatch::<ForkSyncResponse>().await;
  134. let tip_sub = channel.subscribe_msg::<TipRequest>().await?;
  135. let header_sub = channel.subscribe_msg::<HeaderSyncRequest>().await?;
  136. let request_sub = channel.subscribe_msg::<SyncRequest>().await?;
  137. let fork_request_sub = channel.subscribe_msg::<ForkSyncRequest>().await?;
  138. Ok(Arc::new(Self {
  139. tip_sub,
  140. header_sub,
  141. request_sub,
  142. fork_request_sub,
  143. jobsman: ProtocolJobsManager::new("SyncProtocol", channel.clone()),
  144. validator,
  145. channel,
  146. }))
  147. }
  148. async fn handle_receive_tip_request(self: Arc<Self>) -> Result<()> {
  149. debug!(target: "darkfid::proto::protocol_sync::handle_receive_tip_request", "START");
  150. loop {
  151. let request = match self.tip_sub.receive().await {
  152. Ok(v) => v,
  153. Err(e) => {
  154. debug!(
  155. target: "darkfid::proto::protocol_sync::handle_receive_tip_request",
  156. "recv fail: {}",
  157. e
  158. );
  159. continue
  160. }
  161. };
  162. // Check if node has finished syncing its blockchain
  163. let response = if !*self.validator.synced.read().await {
  164. debug!(
  165. target: "darkfid::proto::protocol_sync::handle_receive_tip_request",
  166. "Node still syncing blockchain, skipping..."
  167. );
  168. TipResponse { synced: false, height: None, hash: None }
  169. } else {
  170. // Check we follow the same sequence
  171. match self.validator.blockchain.blocks.contains(&request.tip) {
  172. Ok(contains) => {
  173. if !contains {
  174. debug!(
  175. target: "darkfid::proto::protocol_sync::handle_receive_tip_request",
  176. "Node doesn't follow request sequence"
  177. );
  178. continue
  179. }
  180. }
  181. Err(e) => {
  182. error!(
  183. target: "darkfid::proto::protocol_sync::handle_receive_tip_request",
  184. "block_store.contains fail: {}",
  185. e
  186. );
  187. continue
  188. }
  189. }
  190. // Grab our current tip and return it
  191. let tip = match self.validator.blockchain.last() {
  192. Ok(v) => v,
  193. Err(e) => {
  194. error!(
  195. target: "darkfid::proto::protocol_sync::handle_receive_tip_request",
  196. "blockchain.last fail: {}",
  197. e
  198. );
  199. continue
  200. }
  201. };
  202. TipResponse { synced: true, height: Some(tip.0), hash: Some(tip.1) }
  203. };
  204. if let Err(e) = self.channel.send(&response).await {
  205. error!(
  206. target: "darkfid::proto::protocol_sync::handle_receive_tip_request",
  207. "channel send fail: {}",
  208. e
  209. )
  210. };
  211. }
  212. }
  213. async fn handle_receive_header_request(self: Arc<Self>) -> Result<()> {
  214. debug!(target: "darkfid::proto::protocol_sync::handle_receive_header_request", "START");
  215. loop {
  216. let request = match self.header_sub.receive().await {
  217. Ok(v) => v,
  218. Err(e) => {
  219. debug!(
  220. target: "darkfid::proto::protocol_sync::handle_receive_header_request",
  221. "recv fail: {}",
  222. e
  223. );
  224. continue
  225. }
  226. };
  227. // Check if node has finished syncing its blockchain
  228. if !*self.validator.synced.read().await {
  229. debug!(
  230. target: "darkfid::proto::protocol_sync::handle_receive_header_request",
  231. "Node still syncing blockchain, skipping..."
  232. );
  233. continue
  234. }
  235. let headers = match self.validator.blockchain.get_headers_before(request.height, BATCH)
  236. {
  237. Ok(v) => v,
  238. Err(e) => {
  239. error!(
  240. target: "darkfid::proto::protocol_sync::handle_receive_header_request",
  241. "get_headers_before fail: {}",
  242. e
  243. );
  244. continue
  245. }
  246. };
  247. let response = HeaderSyncResponse { headers };
  248. if let Err(e) = self.channel.send(&response).await {
  249. error!(
  250. target: "darkfid::proto::protocol_sync::handle_receive_header_request",
  251. "channel send fail: {}",
  252. e
  253. )
  254. };
  255. }
  256. }
  257. async fn handle_receive_request(self: Arc<Self>) -> Result<()> {
  258. debug!(target: "darkfid::proto::protocol_sync::handle_receive_request", "START");
  259. loop {
  260. let request = match self.request_sub.receive().await {
  261. Ok(v) => v,
  262. Err(e) => {
  263. debug!(
  264. target: "darkfid::proto::protocol_sync::handle_receive_request",
  265. "recv fail: {}",
  266. e
  267. );
  268. continue
  269. }
  270. };
  271. // Check if node has finished syncing its blockchain
  272. if !*self.validator.synced.read().await {
  273. debug!(
  274. target: "darkfid::proto::protocol_sync::handle_receive_request",
  275. "Node still syncing blockchain, skipping..."
  276. );
  277. continue
  278. }
  279. // Check if request exists the configured limit
  280. if request.headers.len() > BATCH {
  281. debug!(
  282. target: "darkfid::proto::protocol_sync::handle_receive_request",
  283. "Node requested more blocks than allowed."
  284. );
  285. continue
  286. }
  287. let blocks = match self.validator.blockchain.get_blocks_by_hash(&request.headers) {
  288. Ok(v) => v,
  289. Err(e) => {
  290. error!(
  291. target: "darkfid::proto::protocol_sync::handle_receive_request",
  292. "get_blocks_after fail: {}",
  293. e
  294. );
  295. continue
  296. }
  297. };
  298. let response = SyncResponse { blocks };
  299. if let Err(e) = self.channel.send(&response).await {
  300. error!(
  301. target: "darkfid::proto::protocol_sync::handle_receive_request",
  302. "channel send fail: {}",
  303. e
  304. )
  305. };
  306. }
  307. }
  308. async fn handle_receive_fork_request(self: Arc<Self>) -> Result<()> {
  309. debug!(target: "darkfid::proto::protocol_sync::handle_receive_fork_request", "START");
  310. loop {
  311. let request = match self.fork_request_sub.receive().await {
  312. Ok(v) => v,
  313. Err(e) => {
  314. debug!(
  315. target: "darkfid::proto::protocol_sync::handle_receive_fork_request",
  316. "recv fail: {}",
  317. e
  318. );
  319. continue
  320. }
  321. };
  322. // Check if node has finished syncing its blockchain
  323. if !*self.validator.synced.read().await {
  324. debug!(
  325. target: "darkfid::proto::protocol_sync::handle_receive_fork_request",
  326. "Node still syncing blockchain, skipping..."
  327. );
  328. continue
  329. }
  330. debug!(target: "darkfid::proto::protocol_sync::handle_receive_request", "Received request: {request:?}");
  331. // If a fork tip is provided, grab its fork proposals sequence.
  332. // Otherwise, grab best fork proposals sequence.
  333. let proposals = match request.fork_tip {
  334. Some(fork_tip) => {
  335. self.validator.consensus.get_fork_proposals(request.tip, fork_tip).await
  336. }
  337. None => self.validator.consensus.get_best_fork_proposals(request.tip).await,
  338. };
  339. let proposals = match proposals {
  340. Ok(p) => p,
  341. Err(e) => {
  342. debug!(
  343. target: "darkfid::proto::protocol_sync::handle_receive_request",
  344. "Getting fork proposals failed: {}",
  345. e
  346. );
  347. continue
  348. }
  349. };
  350. let response = ForkSyncResponse { proposals };
  351. debug!(target: "darkfid::proto::protocol_sync::handle_receive_request", "Response: {response:?}");
  352. if let Err(e) = self.channel.send(&response).await {
  353. debug!(
  354. target: "darkfid::proto::protocol_sync::handle_receive_fork_request",
  355. "channel send fail: {}",
  356. e
  357. )
  358. };
  359. }
  360. }
  361. }
  362. #[async_trait]
  363. impl ProtocolBase for ProtocolSync {
  364. async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> Result<()> {
  365. debug!(target: "darkfid::proto::protocol_sync::start", "START");
  366. self.jobsman.clone().start(executor.clone());
  367. self.jobsman
  368. .clone()
  369. .spawn(self.clone().handle_receive_tip_request(), executor.clone())
  370. .await;
  371. self.jobsman
  372. .clone()
  373. .spawn(self.clone().handle_receive_header_request(), executor.clone())
  374. .await;
  375. self.jobsman.clone().spawn(self.clone().handle_receive_request(), executor.clone()).await;
  376. self.jobsman
  377. .clone()
  378. .spawn(self.clone().handle_receive_fork_request(), executor.clone())
  379. .await;
  380. debug!(target: "darkfid::proto::protocol_sync::start", "END");
  381. Ok(())
  382. }
  383. fn name(&self) -> &'static str {
  384. "ProtocolSync"
  385. }
  386. }