1use ant_protocol::storage::GraphEntryAddress;
10use ant_protocol::{messages::Response, storage::RecordKind, NetworkAddress, PrettyPrintRecordKey};
11use libp2p::{
12 kad::{self, QueryId, Record},
13 request_response::{OutboundFailure, OutboundRequestId},
14 swarm::DialError,
15 PeerId, TransportError,
16};
17use std::{
18 collections::{HashMap, HashSet},
19 fmt::Debug,
20 io,
21 path::PathBuf,
22};
23use thiserror::Error;
24use tokio::sync::oneshot;
25use xor_name::XorName;
26
27pub(super) type Result<T, E = NetworkError> = std::result::Result<T, E>;
28
29#[derive(Error, Clone)]
31pub enum GetRecordError {
32 #[error("Get Record completed with non enough copies")]
33 NotEnoughCopies {
34 record: Record,
35 expected: usize,
36 got: usize,
37 },
38 #[error("Network query timed out")]
39 QueryTimeout,
40 #[error("Record retrieved from the network does not match the provided target record.")]
41 RecordDoesNotMatch(Record),
42 #[error("The record kind for the split records did not match")]
43 RecordKindMismatch,
44 #[error("Record not found in the network")]
45 RecordNotFound,
46 #[error("Split Record has {} different copies", result_map.len())]
50 SplitRecord {
51 result_map: HashMap<XorName, (Record, HashSet<PeerId>)>,
52 },
53}
54
55impl Debug for GetRecordError {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 match self {
58 Self::NotEnoughCopies {
59 record,
60 expected,
61 got,
62 } => {
63 let pretty_key = PrettyPrintRecordKey::from(&record.key);
64 f.debug_struct("NotEnoughCopies")
65 .field("record_key", &pretty_key)
66 .field("expected", &expected)
67 .field("got", &got)
68 .finish()
69 }
70 Self::QueryTimeout => write!(f, "QueryTimeout"),
71 Self::RecordDoesNotMatch(record) => {
72 let pretty_key = PrettyPrintRecordKey::from(&record.key);
73 f.debug_tuple("RecordDoesNotMatch")
74 .field(&pretty_key)
75 .finish()
76 }
77 Self::RecordKindMismatch => write!(f, "RecordKindMismatch"),
78 Self::RecordNotFound => write!(f, "RecordNotFound"),
79 Self::SplitRecord { result_map } => f
80 .debug_struct("SplitRecord")
81 .field("result_map_count", &result_map.len())
82 .finish(),
83 }
84 }
85}
86
87#[derive(Debug, Error)]
89pub enum NetworkError {
90 #[error("Dial Error")]
91 DialError(#[from] DialError),
92
93 #[error("I/O error: {0}")]
94 Io(#[from] io::Error),
95
96 #[error("Kademlia Store error: {0}")]
97 KademliaStoreError(#[from] kad::store::Error),
98
99 #[error("Transport Error")]
100 TransportError(#[from] TransportError<std::io::Error>),
101
102 #[error("SnProtocol Error: {0}")]
103 ProtocolError(#[from] ant_protocol::error::Error),
104
105 #[error("Evm payment Error {0}")]
106 EvmPaymemt(#[from] ant_evm::EvmError),
107
108 #[error("Failed to sign the message with the PeerId keypair")]
109 SigningFailed(#[from] libp2p::identity::SigningError),
110
111 #[error("GetRecord Query Error {0:?}")]
114 GetRecordError(#[from] GetRecordError),
115 #[error("Record not stored by nodes, it could be invalid, else you should retry: {0:?}")]
116 RecordNotStoredByNodes(NetworkAddress),
117
118 #[error("The RecordKind obtained from the Record did not match with the expected kind: {0}")]
120 RecordKindMismatch(RecordKind),
121
122 #[error("Record header is incorrect")]
123 InCorrectRecordHeader,
124
125 #[error("The operation is not allowed on a client record store")]
126 OperationNotAllowedOnClientRecordStore,
127
128 #[error("Failed to verify the ChunkProof with the provided quorum")]
130 FailedToVerifyChunkProof(NetworkAddress),
131
132 #[error("Graph entry not found: {0:?}")]
134 NoGraphEntryFoundInsideRecord(GraphEntryAddress),
135
136 #[error("Not Enough Peers for Store Cost Request")]
138 NotEnoughPeersForStoreCostRequest,
139
140 #[error("No Store Cost Responses")]
141 NoStoreCostResponses,
142
143 #[error("Could not create storage dir: {path:?}, error: {source}")]
144 FailedToCreateRecordStoreDir {
145 path: PathBuf,
146 source: std::io::Error,
147 },
148
149 #[error("Network GetClosest TimedOut")]
151 GetClosestTimedOut,
152
153 #[error("Could not get enough peers ({required}) to satisfy the request, found {found}")]
155 NotEnoughPeers { found: usize, required: usize },
156
157 #[error("Node Listen Address was not provided during construction")]
158 ListenAddressNotProvided,
159
160 #[cfg(feature = "open-metrics")]
161 #[error("Network Metric error")]
162 NetworkMetricError,
163
164 #[error("Outbound Error")]
166 OutboundError(#[from] OutboundFailure),
167
168 #[error("A Kademlia event has been dropped: {query_id:?} {event}")]
169 ReceivedKademliaEventDropped { query_id: QueryId, event: String },
170
171 #[error("The oneshot::sender has been dropped")]
172 SenderDropped(#[from] oneshot::error::RecvError),
173
174 #[error("Internal messaging channel was dropped")]
175 InternalMsgChannelDropped,
176
177 #[error("Response received for a request not found in our local tracking map: {0}")]
178 ReceivedResponseDropped(OutboundRequestId),
179
180 #[error("Outgoing response has been dropped due to a conn being closed or timeout: {0}")]
181 OutgoingResponseDropped(Response),
182
183 #[error("Error setting up behaviour: {0}")]
184 BehaviourErr(String),
185}
186
187#[cfg(test)]
188mod tests {
189 use ant_protocol::{storage::ChunkAddress, NetworkAddress, PrettyPrintKBucketKey};
190 use xor_name::XorName;
191
192 use super::*;
193
194 #[test]
195 fn test_client_sees_same_hex_in_errors_for_xorname_and_record_keys() {
196 let mut rng = rand::thread_rng();
197 let xor_name = XorName::random(&mut rng);
198 let address = ChunkAddress::new(xor_name);
199 let network_address = NetworkAddress::from(address);
200 let record_key = network_address.to_record_key();
201 let record_str = format!("{}", PrettyPrintRecordKey::from(&record_key));
202 let xor_name_str = &format!("{xor_name:64x}")[0..6]; let xor_name_str = format!(
204 "{xor_name_str}({:?})",
205 PrettyPrintKBucketKey(network_address.as_kbucket_key())
206 );
207 println!("record_str: {record_str}");
208 println!("xor_name_str: {xor_name_str}");
209 assert_eq!(record_str, xor_name_str);
210 }
211}