Skip to main content

ant_protocol/messages/
query.rs

1// Copyright 2024 MaidSafe.net limited.
2//
3// This SAFE Network Software is licensed to you under The General Public License (GPL), version 3.
4// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed
5// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
6// KIND, either express or implied. Please review the Licences for the specific language governing
7// permissions and limitations relating to use of the SAFE Network Software.
8
9use crate::{NetworkAddress, messages::Nonce};
10use libp2p::kad::U256;
11use serde::{Deserialize, Serialize};
12
13/// Data queries - retrieving data and inspecting their structure.
14///
15/// See the [`protocol`] module documentation for more details of the types supported by the Safe
16/// Network, and their semantics.
17///
18/// [`protocol`]: crate
19#[derive(Eq, PartialEq, PartialOrd, Clone, Serialize, Deserialize, custom_debug::Debug)]
20pub enum Query {
21    /// Retrieve the quote to store a record at the given address.
22    /// The storage verification is optional to be undertaken
23    GetStoreQuote {
24        /// The Address of the record to be stored.
25        key: NetworkAddress,
26        /// DataTypes as represented as its `index`
27        data_type: u32,
28        /// Data size of the record
29        data_size: usize,
30        /// The random nonce that nodes use to produce the Proof (i.e., hash(record+nonce))
31        /// Set to None if no need to carry out storage check.
32        nonce: Option<Nonce>,
33        /// Defines the expected number of answers to the challenge.
34        /// Node shall try their best to fulfill the number, based on their capacity.
35        /// Set to 0 to indicate not carry out any verification.
36        difficulty: usize,
37    },
38    /// Retrieve a specific record from a specific peer.
39    ///
40    /// This should eventually lead to a [`GetReplicatedRecord`] response.
41    ///
42    /// [`GetReplicatedRecord`]: super::QueryResponse::GetReplicatedRecord
43    GetReplicatedRecord {
44        /// Sender of the query
45        requester: NetworkAddress,
46        /// Key of the record to be fetched
47        key: NetworkAddress,
48    },
49    /// Get the proof that the chunk with the given NetworkAddress exists with the requested node.
50    GetChunkExistenceProof {
51        /// The Address of the chunk that we are trying to verify.
52        key: NetworkAddress,
53        /// The random nonce that the node uses to produce the Proof (i.e., hash(record+nonce))
54        nonce: Nonce,
55        /// Defines the expected number of answers to the challenge.
56        /// For client publish verification, use 1 for efficiency.
57        /// Node shall try their best to fulfill the number, based on their capacity.
58        difficulty: usize,
59    },
60    /// Queries close_group peers whether the target peer is a bad_node
61    CheckNodeInProblem(NetworkAddress),
62    /// Query the peers in range to the target address, from the receiver's perspective.
63    /// In case none of the parameters provided, returns nothing.
64    /// In case both of the parameters provided, `range` is preferred to be replied.
65    GetClosestPeers {
66        key: NetworkAddress,
67        // Shall be less than K_VALUE, as using the receiver's local knowledge
68        num_of_peers: Option<usize>,
69        // Defines the range that replied peers shall be within
70        range: Option<[u8; 32]>,
71        // For future econ usage,
72        sign_result: bool,
73    },
74    /// *** From now on, the order of variants shall be retained to be backward compatible
75    /// Query peer's cargo package version.
76    GetVersion(NetworkAddress),
77    /// Write operation to upload a record.
78    PutRecord {
79        /// Holder of the record.
80        holder: NetworkAddress,
81        /// serialized record.
82        #[debug(skip)]
83        serialized_record: Vec<u8>,
84        /// Address of the record.
85        address: NetworkAddress,
86    },
87    /// Get a Merkle payment candidate quote from a node
88    ///
89    /// Node signs its current state (metrics + reward address) with the
90    /// provided timestamp, creating a commitment that cryptographically
91    /// proves the binding between PeerId and RewardsAddress.
92    GetMerkleCandidateQuote {
93        /// Target address for topology verification
94        /// Client queries the 20 closest nodes to this target
95        /// target = hash(intersection_hash, root, timestamp)
96        key: NetworkAddress,
97        /// DataTypes as represented as its `index`
98        data_type: u32,
99        /// Data size of the record
100        data_size: usize,
101        /// Merkle payment timestamp (unix seconds)
102        /// Node verifies this is not expired/future, then signs its state with it
103        merkle_payment_timestamp: u64,
104    },
105    /// Developer/analytics query: Ask a node to query the network for closest peers.
106    /// Unlike GetClosestPeers which returns local routing table, this triggers a full network lookup.
107    /// Only available when the `developer` feature is enabled.
108    #[cfg(feature = "developer")]
109    DevGetClosestPeersFromNetwork {
110        /// Target address to find closest peers for
111        key: NetworkAddress,
112        /// Number of peers to return (optional, defaults to K_VALUE)
113        num_of_peers: Option<usize>,
114    },
115}
116
117impl Query {
118    /// Used to send a query to the close group of the address.
119    pub fn dst(&self) -> NetworkAddress {
120        match self {
121            Query::CheckNodeInProblem(address) | Query::GetVersion(address) => address.clone(),
122            // Shall not be called for this, as this is a `one-to-one` message,
123            // and the destination shall be decided by the requester already.
124            Query::GetStoreQuote { key, .. }
125            | Query::GetReplicatedRecord { key, .. }
126            | Query::GetChunkExistenceProof { key, .. }
127            | Query::GetClosestPeers { key, .. }
128            | Query::GetMerkleCandidateQuote { key, .. } => key.clone(),
129            #[cfg(feature = "developer")]
130            Query::DevGetClosestPeersFromNetwork { key, .. } => key.clone(),
131            Query::PutRecord { holder, .. } => holder.clone(),
132        }
133    }
134}
135
136impl std::fmt::Display for Query {
137    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138        match self {
139            Query::GetStoreQuote {
140                key,
141                data_type,
142                data_size,
143                nonce,
144                difficulty,
145            } => {
146                write!(
147                    f,
148                    "Query::GetStoreQuote({key:?} {data_type} {data_size} {nonce:?} {difficulty})"
149                )
150            }
151            Query::GetReplicatedRecord { key, requester } => {
152                write!(f, "Query::GetReplicatedRecord({requester:?} {key:?})")
153            }
154            Query::GetChunkExistenceProof {
155                key,
156                nonce,
157                difficulty,
158            } => {
159                write!(
160                    f,
161                    "Query::GetChunkExistenceProof({key:?} {nonce:?} {difficulty})"
162                )
163            }
164            Query::CheckNodeInProblem(address) => {
165                write!(f, "Query::CheckNodeInProblem({address:?})")
166            }
167            Query::GetClosestPeers {
168                key,
169                num_of_peers,
170                range,
171                sign_result,
172            } => {
173                let distance = range.as_ref().map(|value| U256::from_big_endian(value));
174                write!(
175                    f,
176                    "Query::GetClosestPeers({key:?} {num_of_peers:?} {distance:?} {sign_result})"
177                )
178            }
179            Query::GetVersion(address) => {
180                write!(f, "Query::GetVersion({address:?})")
181            }
182            Query::PutRecord {
183                holder,
184                address,
185                serialized_record,
186            } => {
187                write!(
188                    f,
189                    "Cmd::PutRecord(To {:?}, with record {address:?} has {} data_size)",
190                    holder.as_peer_id(),
191                    serialized_record.len()
192                )
193            }
194            Query::GetMerkleCandidateQuote {
195                key,
196                data_type,
197                data_size,
198                merkle_payment_timestamp,
199            } => {
200                write!(
201                    f,
202                    "Query::GetMerkleCandidateQuote({key:?} {data_type} {data_size} timestamp={merkle_payment_timestamp})"
203                )
204            }
205            #[cfg(feature = "developer")]
206            Query::DevGetClosestPeersFromNetwork { key, num_of_peers } => {
207                write!(
208                    f,
209                    "Query::DevGetClosestPeersFromNetwork({key:?} {num_of_peers:?})"
210                )
211            }
212        }
213    }
214}