dht.rs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2025 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;
  21. use num_bigint::BigUint;
  22. use rand::{rngs::OsRng, Rng};
  23. use url::Url;
  24. use darkfi::{
  25. dht::{impl_dht_node_defaults, Dht, DhtHandler, DhtLookupReply, DhtNode},
  26. geode::hash_to_string,
  27. net::ChannelPtr,
  28. util::time::Timestamp,
  29. Error, Result,
  30. };
  31. use darkfi_sdk::crypto::schnorr::SchnorrPublic;
  32. use darkfi_serial::{SerialDecodable, SerialEncodable};
  33. use crate::{
  34. pow::VerifiableNodeData,
  35. proto::{
  36. FudAnnounce, FudFindNodesReply, FudFindNodesRequest, FudFindSeedersReply,
  37. FudFindSeedersRequest, FudPingReply, FudPingRequest,
  38. },
  39. Fud,
  40. };
  41. #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
  42. pub struct FudNode {
  43. pub data: VerifiableNodeData,
  44. pub addresses: Vec<Url>,
  45. }
  46. impl_dht_node_defaults!(FudNode);
  47. impl DhtNode for FudNode {
  48. fn id(&self) -> blake3::Hash {
  49. self.data.id()
  50. }
  51. fn addresses(&self) -> Vec<Url> {
  52. self.addresses.clone()
  53. }
  54. }
  55. /// The values of the DHT are `Vec<FudSeeder>`, mapping resource hashes to lists of [`FudSeeder`]s
  56. #[derive(Debug, Clone, SerialEncodable, SerialDecodable, Eq)]
  57. pub struct FudSeeder {
  58. /// Resource that this seeder provides
  59. pub key: blake3::Hash,
  60. /// Seeder's node data
  61. pub node: FudNode,
  62. /// When this [`FudSeeder`] was added to our hash table.
  63. /// This is not sent to other nodes.
  64. #[skip_serialize]
  65. pub timestamp: u64,
  66. }
  67. impl PartialEq for FudSeeder {
  68. fn eq(&self, other: &Self) -> bool {
  69. self.key == other.key && self.node.id() == other.node.id()
  70. }
  71. }
  72. /// [`DhtHandler`] implementation for fud
  73. #[async_trait]
  74. impl DhtHandler for Fud {
  75. type Value = Vec<FudSeeder>;
  76. type Node = FudNode;
  77. fn dht(&self) -> Arc<Dht<Self>> {
  78. self.dht.clone()
  79. }
  80. async fn node(&self) -> FudNode {
  81. FudNode {
  82. data: self.node_data.read().await.clone(),
  83. addresses: self
  84. .p2p
  85. .clone()
  86. .hosts()
  87. .external_addrs()
  88. .await
  89. .iter()
  90. .filter(|addr| !addr.to_string().contains("[::]"))
  91. .cloned()
  92. .collect(),
  93. }
  94. }
  95. async fn ping(&self, channel: ChannelPtr) -> Result<FudNode> {
  96. debug!(target: "fud::DhtHandler::ping()", "Sending ping to channel {}", channel.info.id);
  97. let msg_subsystem = channel.message_subsystem();
  98. msg_subsystem.add_dispatch::<FudPingReply>().await;
  99. let msg_subscriber = channel.subscribe_msg::<FudPingReply>().await.unwrap();
  100. // Send `FudPingRequest`
  101. let mut rng = OsRng;
  102. let request = FudPingRequest { random: rng.gen() };
  103. channel.send(&request).await?;
  104. // Wait for `FudPingReply`
  105. let reply = msg_subscriber.receive_with_timeout(self.dht().settings.timeout).await;
  106. msg_subscriber.unsubscribe().await;
  107. let reply = reply?;
  108. // Verify the signature
  109. if !reply.node.data.public_key.verify(&request.random.to_be_bytes(), &reply.sig) {
  110. channel.ban().await;
  111. return Err(Error::InvalidSignature)
  112. }
  113. // Verify PoW
  114. if let Err(e) = self.pow.write().await.verify_node(&reply.node.data).await {
  115. channel.ban().await;
  116. return Err(e)
  117. }
  118. Ok(reply.node.clone())
  119. }
  120. // TODO: Optimize this
  121. async fn on_new_node(&self, node: &FudNode) -> Result<()> {
  122. debug!(target: "fud::DhtHandler::on_new_node()", "New node {}", hash_to_string(&node.id()));
  123. // If this is the first node we know about, then bootstrap and announce our files
  124. if !self.dht.is_bootstrapped().await {
  125. let _ = self.init().await;
  126. }
  127. // Send keys that are closer to this node than we are
  128. let self_id = self.node_data.read().await.id();
  129. let channel = self.dht.get_channel(node, None).await?;
  130. for (key, seeders) in self.dht.hash_table.read().await.iter() {
  131. let node_distance = BigUint::from_bytes_be(&self.dht().distance(key, &node.id()));
  132. let self_distance = BigUint::from_bytes_be(&self.dht().distance(key, &self_id));
  133. if node_distance <= self_distance {
  134. let _ = channel.send(&FudAnnounce { key: *key, seeders: seeders.clone() }).await;
  135. }
  136. }
  137. self.dht.cleanup_channel(channel).await;
  138. Ok(())
  139. }
  140. async fn find_nodes(&self, node: &FudNode, key: &blake3::Hash) -> Result<Vec<FudNode>> {
  141. debug!(target: "fud::DhtHandler::find_nodes()", "Fetching nodes close to {} from node {}", hash_to_string(key), hash_to_string(&node.id()));
  142. let channel = self.dht.get_channel(node, None).await?;
  143. let msg_subsystem = channel.message_subsystem();
  144. msg_subsystem.add_dispatch::<FudFindNodesReply>().await;
  145. let msg_subscriber_nodes = channel.subscribe_msg::<FudFindNodesReply>().await.unwrap();
  146. let request = FudFindNodesRequest { key: *key };
  147. channel.send(&request).await?;
  148. let reply = msg_subscriber_nodes.receive_with_timeout(self.dht().settings.timeout).await;
  149. msg_subscriber_nodes.unsubscribe().await;
  150. self.dht.cleanup_channel(channel).await;
  151. Ok(reply?.nodes.clone())
  152. }
  153. async fn find_value(
  154. &self,
  155. node: &FudNode,
  156. key: &blake3::Hash,
  157. ) -> Result<DhtLookupReply<FudNode, Vec<FudSeeder>>> {
  158. debug!(target: "fud::DhtHandler::find_value()", "Fetching value {} from node {}", hash_to_string(key), hash_to_string(&node.id()));
  159. let channel = self.dht.get_channel(node, None).await?;
  160. let msg_subsystem = channel.message_subsystem();
  161. msg_subsystem.add_dispatch::<FudFindSeedersReply>().await;
  162. let msg_subscriber = channel.subscribe_msg::<FudFindSeedersReply>().await.unwrap();
  163. let request = FudFindSeedersRequest { key: *key };
  164. channel.send(&request).await?;
  165. let recv = msg_subscriber.receive_with_timeout(self.dht().settings.timeout).await;
  166. msg_subscriber.unsubscribe().await;
  167. self.dht.cleanup_channel(channel).await;
  168. let rep = recv?;
  169. Ok(DhtLookupReply::NodesAndValue(rep.nodes.clone(), rep.seeders.clone()))
  170. }
  171. async fn add_value(&self, key: &blake3::Hash, value: &Vec<FudSeeder>) {
  172. let mut seeders = value.clone();
  173. // Remove seeders with no external addresses
  174. seeders.retain(|item| !item.node.addresses().is_empty());
  175. // Set all seeders' timestamp. They are not sent to others nodes so they default to 0.
  176. let timestamp = Timestamp::current_time().inner();
  177. for seeder in &mut seeders {
  178. seeder.timestamp = timestamp;
  179. }
  180. debug!(target: "fud::DhtHandler::add_value()", "Inserting {} seeders for resource {}", seeders.len(), hash_to_string(key));
  181. let mut seeders_write = self.dht.hash_table.write().await;
  182. let existing_seeders = seeders_write.get_mut(key);
  183. if let Some(existing_seeders) = existing_seeders {
  184. existing_seeders.retain(|it| !seeders.contains(it));
  185. existing_seeders.extend(seeders.clone());
  186. } else {
  187. let mut vec = Vec::new();
  188. vec.extend(seeders.clone());
  189. seeders_write.insert(*key, vec);
  190. }
  191. }
  192. fn key_to_string(key: &blake3::Hash) -> String {
  193. hash_to_string(key)
  194. }
  195. }