diff --git a/sn_networking/src/lib.rs b/sn_networking/src/lib.rs index cd0875fa5e..cd5c513fad 100644 --- a/sn_networking/src/lib.rs +++ b/sn_networking/src/lib.rs @@ -380,7 +380,12 @@ impl Network { return Err(NetworkError::NoStoreCostResponses); } - let request = Request::Query(Query::GetStoreCost(record_address.clone())); + // Client shall decide whether to carry out storage verification or not. + let request = Request::Query(Query::GetStoreCost { + key: record_address.clone(), + nonce: None, + difficulty: 0, + }); let responses = self .send_and_get_responses(&close_nodes, &request, true) .await; @@ -398,7 +403,11 @@ impl Network { quote: Ok(quote), payment_address, peer_address, + storage_proofs, }) => { + if !storage_proofs.is_empty() { + debug!("Storage proofing during GetStoreCost to be implemented."); + } // Check the quote itself is valid. if quote.cost != AttoTokens::from_u64(calculate_cost_for_records( @@ -416,7 +425,11 @@ impl Network { quote: Err(ProtocolError::RecordExists(_)), payment_address, peer_address, + storage_proofs, }) => { + if !storage_proofs.is_empty() { + debug!("Storage proofing during GetStoreCost to be implemented."); + } all_costs.push((peer_address, payment_address, PaymentQuote::zero())); } _ => { diff --git a/sn_node/src/node.rs b/sn_node/src/node.rs index 4fb6294727..bd4e31c36b 100644 --- a/sn_node/src/node.rs +++ b/sn_node/src/node.rs @@ -514,13 +514,30 @@ impl Node { payment_address: RewardsAddress, ) -> Response { let resp: QueryResponse = match query { - Query::GetStoreCost(address) => { - debug!("Got GetStoreCost request for {address:?}"); - let record_key = address.to_record_key(); + Query::GetStoreCost { + key, + nonce, + difficulty, + } => { + debug!("Got GetStoreCost request for {key:?} with difficulty {difficulty}"); + let record_key = key.to_record_key(); let self_id = network.peer_id(); let store_cost = network.get_local_storecost(record_key.clone()).await; + let storage_proofs = if let Some(nonce) = nonce { + Self::respond_x_closest_record_proof( + network, + key.clone(), + nonce, + difficulty, + false, + ) + .await + } else { + vec![] + }; + match store_cost { Ok((cost, quoting_metrics, bad_nodes)) => { if cost == AttoTokens::zero() { @@ -530,19 +547,21 @@ impl Node { )), payment_address, peer_address: NetworkAddress::from_peer(self_id), + storage_proofs, } } else { QueryResponse::GetStoreCost { quote: Self::create_quote_for_storecost( network, cost, - &address, + &key, "ing_metrics, bad_nodes, &payment_address, ), payment_address, peer_address: NetworkAddress::from_peer(self_id), + storage_proofs, } } } @@ -550,6 +569,7 @@ impl Node { quote: Err(ProtocolError::GetStoreCostFailed), payment_address, peer_address: NetworkAddress::from_peer(self_id), + storage_proofs, }, } } diff --git a/sn_protocol/src/messages/query.rs b/sn_protocol/src/messages/query.rs index dc941e634f..c7e4a56639 100644 --- a/sn_protocol/src/messages/query.rs +++ b/sn_protocol/src/messages/query.rs @@ -18,7 +18,18 @@ use serde::{Deserialize, Serialize}; #[derive(Eq, PartialEq, PartialOrd, Clone, Serialize, Deserialize, Debug)] pub enum Query { /// Retrieve the cost of storing a record at the given address. - GetStoreCost(NetworkAddress), + /// The storage verification is optional to be undertaken + GetStoreCost { + /// The Address of the record to be stored. + key: NetworkAddress, + /// The random nonce that nodes use to produce the Proof (i.e., hash(record+nonce)) + /// Set to None if no need to carry out storage check. + nonce: Option, + /// Defines the expected number of answers to the challenge. + /// Node shall try their best to fulfill the number, based on their capacity. + /// Set to 0 to indicate not carry out any verification. + difficulty: usize, + }, /// Retrieve a specific record from a specific peer. /// /// This should eventually lead to a [`GetReplicatedRecord`] response. @@ -60,10 +71,11 @@ impl Query { /// Used to send a query to the close group of the address. pub fn dst(&self) -> NetworkAddress { match self { - Query::GetStoreCost(address) | Query::CheckNodeInProblem(address) => address.clone(), + Query::CheckNodeInProblem(address) => address.clone(), // Shall not be called for this, as this is a `one-to-one` message, // and the destination shall be decided by the requester already. - Query::GetReplicatedRecord { key, .. } + Query::GetStoreCost { key, .. } + | Query::GetReplicatedRecord { key, .. } | Query::GetRegisterRecord { key, .. } | Query::GetChunkExistenceProof { key, .. } => key.clone(), } @@ -73,8 +85,12 @@ impl Query { impl std::fmt::Display for Query { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Query::GetStoreCost(address) => { - write!(f, "Query::GetStoreCost({address:?})") + Query::GetStoreCost { + key, + nonce, + difficulty, + } => { + write!(f, "Query::GetStoreCost({key:?} {nonce:?} {difficulty})") } Query::GetReplicatedRecord { key, requester } => { write!(f, "Query::GetReplicatedRecord({requester:?} {key:?})") diff --git a/sn_protocol/src/messages/response.rs b/sn_protocol/src/messages/response.rs index 44e9932c23..f29aecc76f 100644 --- a/sn_protocol/src/messages/response.rs +++ b/sn_protocol/src/messages/response.rs @@ -30,6 +30,8 @@ pub enum QueryResponse { payment_address: RewardsAddress, /// Node's Peer Address peer_address: NetworkAddress, + /// Storage proofs based on requested target address and difficulty + storage_proofs: Vec<(NetworkAddress, Result)>, }, CheckNodeInProblem { /// Address of the peer that queried @@ -67,10 +69,12 @@ impl Debug for QueryResponse { quote, payment_address, peer_address, + storage_proofs, } => { write!( f, - "GetStoreCost(quote: {quote:?}, from {peer_address:?} w/ payment_address: {payment_address:?})" + "GetStoreCost(quote: {quote:?}, from {peer_address:?} w/ payment_address: {payment_address:?}, and {} storage proofs)", + storage_proofs.len() ) } QueryResponse::CheckNodeInProblem {