cfxcore/light_protocol/
error.rs

1// Copyright 2019 Conflux Foundation. All rights reserved.
2// Conflux is free software and distributed under GNU General Public License.
3// See http://www.gnu.org/licenses/
4
5use crate::{
6    message::{Message, MsgId, RequestId},
7    sync::message::Throttled,
8    NodeType,
9};
10use cfx_internal_common::ChainIdParamsOneChainInner;
11use cfx_types::{H160, H256};
12use network::{node_table::NodeId, NetworkContext, UpdateNodeOperation};
13use parking_lot::Mutex;
14use primitives::{account::AccountError, filter::FilterError, StateRoot};
15use rlp::DecoderError;
16use std::sync::Arc;
17use thiserror::Error;
18
19#[derive(Debug, Error)]
20pub enum Error {
21    #[error(transparent)]
22    Network(#[from] network::Error),
23    #[error(transparent)]
24    StateDb(#[from] cfx_statedb::Error),
25    #[error(transparent)]
26    Storage(#[from] cfx_storage::Error),
27    #[error(transparent)]
28    Decoder(#[from] DecoderError),
29    #[error(transparent)]
30    Filter(#[from] FilterError),
31    #[error(transparent)]
32    AccountError(#[from] AccountError),
33    #[error("packet already throttled: {0:?}")]
34    AlreadyThrottled(&'static str),
35    #[error("ChainId mismatch, ours={ours:?}, theirs={theirs:?}.")]
36    ChainIdMismatch {
37        ours: ChainIdParamsOneChainInner,
38        theirs: ChainIdParamsOneChainInner,
39    },
40    #[error("{:?}", .0.display_error())]
41    ClonableErrorWrapper(ClonableError),
42    #[error("Genesis mismatch, ours={ours:?}, theirs={theirs:?}.")]
43    GenesisMismatch { ours: H256, theirs: H256 },
44    #[error("Internal error: {0:?}")]
45    InternalError(String),
46    #[error("Logs bloom hash validation for epoch {epoch} failed, expected={expected:?}, received={received:?}")]
47    InvalidBloom {
48        epoch: u64,
49        expected: H256,
50        received: H256,
51    },
52    #[error("Header verification failed")]
53    InvalidHeader,
54    #[error("Invalid ledger proof size for header {hash:?}: expected={expected}, received={received}")]
55    InvalidLedgerProofSize {
56        hash: H256,
57        expected: u64,
58        received: u64,
59    },
60    #[error("Invalid message format")]
61    InvalidMessageFormat,
62    #[error("Invalid previous state root for epoch {current_epoch} with snapshot epoch count {snapshot_epoch_count}: {root:?}")]
63    InvalidPreviousStateRoot {
64        current_epoch: u64,
65        snapshot_epoch_count: u64,
66        root: Option<StateRoot>,
67    },
68    #[error("Receipts root validation for epoch {epoch} failed, expected={expected:?}, received={received:?}")]
69    InvalidReceipts {
70        epoch: u64,
71        expected: H256,
72        received: H256,
73    },
74    #[error(
75        "Invalid state proof for key {value:?} and value {key:?} in epoch {epoch}: {reason:?}"
76    )]
77    InvalidStateProof {
78        epoch: u64,
79        key: Vec<u8>,
80        value: Option<Vec<u8>>,
81        reason: &'static str,
82        #[source]
83        source: Option<Box<Error>>,
84    },
85    #[error("State root validation for epoch {epoch} failed, expected={expected:?}, received={received:?}")]
86    InvalidStateRoot {
87        epoch: u64,
88        expected: H256,
89        received: H256,
90    },
91    #[error("Invalid storage root proof for address {address:?} in epoch {epoch}: {reason}")]
92    InvalidStorageRootProof {
93        epoch: u64,
94        address: H160,
95        reason: &'static str,
96        #[source]
97        source: Option<Box<Error>>,
98    },
99    #[error("Invalid tx info: {reason:?}")]
100    InvalidTxInfo { reason: String },
101    #[error("Transaction root validation for block {hash:?} failed, expected={expected:?}, received={received:?}")]
102    InvalidTxRoot {
103        hash: H256,
104        expected: H256,
105        received: H256,
106    },
107    #[error("Invalid signature for transaction {hash:?}")]
108    InvalidTxSignature { hash: H256 },
109    #[error("Witness root validation for header {hash:?} failed, expected={expected:?}, received={received:?}")]
110    InvalidWitnessRoot {
111        hash: H256,
112        expected: H256,
113        received: H256,
114    },
115    #[error("Failed to send status to peer {peer:?}")]
116    SendStatusFailed {
117        peer: NodeId,
118        #[source]
119        source: Option<Box<Error>>,
120    },
121    #[error("Operation timeout: {0:?}")]
122    Timeout(String),
123    #[error("packet {0:?} throttled: {1:?}")]
124    Throttled(&'static str, Throttled),
125    #[error("Unable to produce tx info: {reason:?}")]
126    UnableToProduceTxInfo { reason: String },
127    #[error(
128        "Unexpected message id={received:?}, expected one of {expected:?}"
129    )]
130    UnexpectedMessage {
131        expected: Vec<MsgId>,
132        received: MsgId,
133    },
134    #[error("Unexpected peer type: {node_type:?}")]
135    UnexpectedPeerType { node_type: NodeType },
136    #[error("Unexpected response id; expected = {expected:?}, received = {received:?}")]
137    UnexpectedResponse {
138        expected: Option<RequestId>,
139        received: RequestId,
140    },
141    #[error("Unknown message: {id:?}")]
142    UnknownMessage { id: MsgId },
143    #[error("Witness for epoch {epoch} is not available")]
144    WitnessUnavailable { epoch: u64 },
145    #[error("{0}")]
146    Msg(String),
147}
148
149pub type Result<T> = std::result::Result<T, Error>;
150
151pub fn handle(
152    io: &dyn NetworkContext, peer: &NodeId, msg_id: MsgId, e: &Error,
153) {
154    // for clonable errors, we will print the error in the recursive call
155    if !matches!(e, Error::ClonableErrorWrapper(_)) {
156        warn!(
157            "Error while handling message, peer={}, msg_id={:?}, error={}",
158            peer, msg_id, e,
159        );
160    }
161
162    let mut disconnect = true;
163    let reason = format!("{}", e);
164    let mut op = None;
165
166    // NOTE: do not use wildcard; this way, the compiler
167    // will help covering all the cases.
168    match &e {
169        // for wrapped errors, handle based on the inner error
170        Error::ClonableErrorWrapper(e) => {
171            handle(io, peer, msg_id, &*e.0.lock());
172
173            // if we need to disconnect, we will do it in the call above
174            disconnect = false
175        }
176
177        Error::Filter(_)
178        | Error::InternalError(_)
179
180        // NOTE: we should be tolerant of non-critical errors,
181        // e.g. do not disconnect on requesting non-existing epoch
182        | Error::Msg(_)
183
184        // NOTE: in order to let other protocols run,
185        // we should not disconnect on protocol failure
186        | Error::SendStatusFailed{..}
187
188        | Error::Timeout(_)
189
190        // if the tx requested has been removed locally,
191        // we should not disconnect the peer
192        | Error::UnableToProduceTxInfo{..}
193
194        // if the witness is not available, it is probably
195        // due to the local witness sync process
196        | Error::WitnessUnavailable{..}
197
198        // NOTE: to help with backward-compatibility, we
199        // should not disconnect on `UnknownMessage`
200        | Error::UnknownMessage{..} => disconnect = false,
201
202
203        Error::GenesisMismatch{..}
204        | Error::InvalidHeader
205        | Error::ChainIdMismatch{..}
206        | Error::UnexpectedMessage{..}
207        | Error::UnexpectedPeerType{..} => op = Some(UpdateNodeOperation::Failure),
208
209        Error::UnexpectedResponse{..} => {
210            op = Some(UpdateNodeOperation::Demotion)
211        }
212
213        Error::InvalidBloom{..}
214        | Error::InvalidLedgerProofSize{..}
215        | Error::InvalidMessageFormat
216        | Error::InvalidPreviousStateRoot{..}
217        | Error::InvalidReceipts{..}
218        | Error::InvalidStateProof{..}
219        | Error::InvalidStateRoot{..}
220        | Error::InvalidStorageRootProof{..}
221        | Error::InvalidTxInfo{..}
222        | Error::InvalidTxRoot{..}
223        | Error::InvalidTxSignature{..}
224        | Error::InvalidWitnessRoot{..}
225        | Error::AlreadyThrottled(_)
226        | Error::Decoder(_)
227        | Error::AccountError(_) => op = Some(UpdateNodeOperation::Remove),
228
229        Error::Throttled(_, resp) => {
230            disconnect = false;
231
232            if let Err(e) = resp.send(io, peer) {
233                error!("failed to send throttled packet: {:?}", e);
234                disconnect = true;
235            }
236        }
237
238        // network errors
239        Error::Network(kind) => match kind {
240            network::Error::SendUnsupportedMessage{..} => {
241                unreachable!("This is a bug in protocol version maintenance. {:?}", kind);
242            }
243
244            network::Error::MessageDeprecated{..} => {
245                op = Some(UpdateNodeOperation::Failure);
246                error!(
247                    "Peer sent us a deprecated message {:?}. Either it's a bug \
248                    in protocol version maintenance or the peer is malicious.",
249                    kind,
250                );
251            }
252
253            network::Error::AddressParse
254            | network::Error::AddressResolve(_)
255            | network::Error::Auth
256            | network::Error::BadAddr
257            | network::Error::Disconnect(_)
258            | network::Error::Expired
259            | network::Error::InvalidNodeId
260            | network::Error::Io(_)
261            | network::Error::OversizedPacket
262            | network::Error::Throttling(_) => disconnect = false,
263
264            network::Error::BadProtocol | network::Error::Decoder(_) => {
265                op = Some(UpdateNodeOperation::Remove)
266            }
267
268            network::Error::SocketIo(_) | network::Error::Msg(_) => {
269                op = Some(UpdateNodeOperation::Failure)
270            }
271        },
272
273        Error::StateDb(_)| Error::Storage(_) => disconnect = false,
274
275        // Error::__Nonexhaustive {} => {
276        //     op = Some(UpdateNodeOperation::Failure)
277        // }
278    };
279
280    if disconnect {
281        io.disconnect_peer(peer, op, reason.as_str());
282    }
283}
284
285#[derive(Clone, Debug)]
286pub struct ClonableError(Arc<Mutex<Error>>);
287
288impl Into<Error> for ClonableError {
289    fn into(self) -> Error { Error::ClonableErrorWrapper(self).into() }
290}
291
292impl From<Error> for ClonableError {
293    fn from(e: Error) -> ClonableError {
294        ClonableError(Arc::new(Mutex::new(e)))
295    }
296}
297
298impl ClonableError {
299    fn display_error(&self) -> String { self.0.lock().to_string() }
300}
301
302impl From<&str> for Error {
303    fn from(e: &str) -> Self { Error::Msg(e.into()) }
304}
305impl From<String> for Error {
306    fn from(e: String) -> Self { Error::Msg(e) }
307}