mirror of
https://github.com/0glabs/0g-storage-node.git
synced 2025-04-04 15:35:18 +00:00
135 lines
4.3 KiB
Rust
135 lines
4.3 KiB
Rust
![]() |
use crate::{kbucket::Key, rpc::RequestBody, Enr};
|
||
|
use enr::NodeId;
|
||
|
use sha2::digest::generic_array::GenericArray;
|
||
|
use smallvec::SmallVec;
|
||
|
use tokio::sync::oneshot;
|
||
|
|
||
|
/// Information about a query.
|
||
|
#[derive(Debug)]
|
||
|
pub struct QueryInfo {
|
||
|
/// What we are querying and why.
|
||
|
pub query_type: QueryType,
|
||
|
|
||
|
/// Temporary ENRs used when trying to reach nodes.
|
||
|
pub untrusted_enrs: SmallVec<[Enr; 16]>,
|
||
|
|
||
|
/// A callback channel for the service that requested the query.
|
||
|
pub callback: oneshot::Sender<Vec<Enr>>,
|
||
|
|
||
|
/// The number of distances we request for each peer.
|
||
|
pub distances_to_request: usize,
|
||
|
}
|
||
|
|
||
|
/// Additional information about the query.
|
||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||
|
pub enum QueryType {
|
||
|
/// The user requested a `FIND_NODE` query to be performed. It should be reported when finished.
|
||
|
FindNode(NodeId),
|
||
|
}
|
||
|
|
||
|
impl QueryInfo {
|
||
|
/// Builds an RPC Request, given the QueryInfo
|
||
|
pub(crate) fn rpc_request(&self, peer: NodeId) -> Result<RequestBody, &'static str> {
|
||
|
let request = match self.query_type {
|
||
|
QueryType::FindNode(node_id) => {
|
||
|
let distances = findnode_log2distance(node_id, peer, self.distances_to_request)
|
||
|
.ok_or("Requested a node find itself")?;
|
||
|
RequestBody::FindNode { distances }
|
||
|
}
|
||
|
};
|
||
|
|
||
|
Ok(request)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl crate::query_pool::TargetKey<NodeId> for QueryInfo {
|
||
|
fn key(&self) -> Key<NodeId> {
|
||
|
match self.query_type {
|
||
|
QueryType::FindNode(ref node_id) => {
|
||
|
Key::new_raw(*node_id, *GenericArray::from_slice(&node_id.raw()))
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Calculates the log2 distance for a destination peer given a target and the size (number of
|
||
|
/// distances to request).
|
||
|
///
|
||
|
/// As the iteration increases, FINDNODE requests adjacent distances from the exact peer distance.
|
||
|
///
|
||
|
/// As an example, if the target has a distance of 12 from the remote peer, the sequence of distances that are sent for increasing iterations would be [12, 13, 11, 14, 10, .. ].
|
||
|
fn findnode_log2distance(target: NodeId, peer: NodeId, size: usize) -> Option<Vec<u64>> {
|
||
|
if size > 127 {
|
||
|
// invoke and endless loop - coding error
|
||
|
panic!("Iterations cannot be greater than 127");
|
||
|
}
|
||
|
|
||
|
let dst_key: Key<NodeId> = peer.into();
|
||
|
let distance = dst_key.log2_distance(&target.into())?;
|
||
|
|
||
|
let mut result_list = vec![distance];
|
||
|
let mut difference = 1;
|
||
|
while result_list.len() < size {
|
||
|
if distance + difference <= 256 {
|
||
|
result_list.push(distance + difference);
|
||
|
}
|
||
|
if result_list.len() < size {
|
||
|
if let Some(d) = distance.checked_sub(difference) {
|
||
|
result_list.push(d);
|
||
|
}
|
||
|
}
|
||
|
difference += 1;
|
||
|
}
|
||
|
Some(result_list[..size].to_vec())
|
||
|
}
|
||
|
|
||
|
#[cfg(test)]
|
||
|
mod tests {
|
||
|
use super::*;
|
||
|
|
||
|
#[test]
|
||
|
fn test_log2distance() {
|
||
|
let target = NodeId::new(&[0u8; 32]);
|
||
|
let mut destination = [0u8; 32];
|
||
|
destination[10] = 1; // gives a log2 distance of 169
|
||
|
let destination = NodeId::new(&destination);
|
||
|
|
||
|
let expected_distances = vec![169, 170, 168, 171, 167, 172, 166, 173, 165];
|
||
|
|
||
|
assert_eq!(
|
||
|
findnode_log2distance(target, destination, expected_distances.len()).unwrap(),
|
||
|
expected_distances
|
||
|
);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn test_log2distance_lower() {
|
||
|
let target = NodeId::new(&[0u8; 32]);
|
||
|
let mut destination = [0u8; 32];
|
||
|
destination[31] = 8; // gives a log2 distance of 5
|
||
|
let destination = NodeId::new(&destination);
|
||
|
|
||
|
let expected_distances = vec![4, 5, 3, 6, 2, 7, 1, 8, 0, 9, 10];
|
||
|
|
||
|
assert_eq!(
|
||
|
findnode_log2distance(target, destination, expected_distances.len()).unwrap(),
|
||
|
expected_distances
|
||
|
);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn test_log2distance_upper() {
|
||
|
let target = NodeId::new(&[0u8; 32]);
|
||
|
let mut destination = [0u8; 32];
|
||
|
destination[0] = 8; // gives a log2 distance of 252
|
||
|
let destination = NodeId::new(&destination);
|
||
|
|
||
|
let expected_distances = vec![252, 253, 251, 254, 250, 255, 249, 256, 248, 247, 246];
|
||
|
|
||
|
assert_eq!(
|
||
|
findnode_log2distance(target, destination, expected_distances.len()).unwrap(),
|
||
|
expected_distances
|
||
|
);
|
||
|
}
|
||
|
}
|