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}
106
107impl Query {
108 /// Used to send a query to the close group of the address.
109 pub fn dst(&self) -> NetworkAddress {
110 match self {
111 Query::CheckNodeInProblem(address) | Query::GetVersion(address) => address.clone(),
112 // Shall not be called for this, as this is a `one-to-one` message,
113 // and the destination shall be decided by the requester already.
114 Query::GetStoreQuote { key, .. }
115 | Query::GetReplicatedRecord { key, .. }
116 | Query::GetChunkExistenceProof { key, .. }
117 | Query::GetClosestPeers { key, .. }
118 | Query::GetMerkleCandidateQuote { key, .. } => key.clone(),
119 Query::PutRecord { holder, .. } => holder.clone(),
120 }
121 }
122}
123
124impl std::fmt::Display for Query {
125 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126 match self {
127 Query::GetStoreQuote {
128 key,
129 data_type,
130 data_size,
131 nonce,
132 difficulty,
133 } => {
134 write!(
135 f,
136 "Query::GetStoreQuote({key:?} {data_type} {data_size} {nonce:?} {difficulty})"
137 )
138 }
139 Query::GetReplicatedRecord { key, requester } => {
140 write!(f, "Query::GetReplicatedRecord({requester:?} {key:?})")
141 }
142 Query::GetChunkExistenceProof {
143 key,
144 nonce,
145 difficulty,
146 } => {
147 write!(
148 f,
149 "Query::GetChunkExistenceProof({key:?} {nonce:?} {difficulty})"
150 )
151 }
152 Query::CheckNodeInProblem(address) => {
153 write!(f, "Query::CheckNodeInProblem({address:?})")
154 }
155 Query::GetClosestPeers {
156 key,
157 num_of_peers,
158 range,
159 sign_result,
160 } => {
161 let distance = range.as_ref().map(|value| U256::from_big_endian(value));
162 write!(
163 f,
164 "Query::GetClosestPeers({key:?} {num_of_peers:?} {distance:?} {sign_result})"
165 )
166 }
167 Query::GetVersion(address) => {
168 write!(f, "Query::GetVersion({address:?})")
169 }
170 Query::PutRecord {
171 holder,
172 address,
173 serialized_record,
174 } => {
175 write!(
176 f,
177 "Cmd::PutRecord(To {:?}, with record {address:?} has {} data_size)",
178 holder.as_peer_id(),
179 serialized_record.len()
180 )
181 }
182 Query::GetMerkleCandidateQuote {
183 key,
184 data_type,
185 data_size,
186 merkle_payment_timestamp,
187 } => {
188 write!(
189 f,
190 "Query::GetMerkleCandidateQuote({key:?} {data_type} {data_size} timestamp={merkle_payment_timestamp})"
191 )
192 }
193 }
194 }
195}