use ckb_constant::sync::{BAD_MESSAGE_BAN_TIME, SYNC_USELESS_BAN_TIME};
use ckb_types::core::error::ARGV_TOO_LONG_TEXT;
use std::fmt::{self, Display, Formatter};
use std::time::Duration;
#[macro_export]
macro_rules! attempt {
($code:expr) => {{
let ret = $code;
if !ret.is_ok() {
return ret;
}
ret
}};
}
#[repr(u16)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum StatusCode {
OK = 100,
Ignored = 101,
CompactBlockIsAlreadyPending = 102,
CompactBlockIsAlreadyInFlight = 103,
CompactBlockAlreadyStored = 104,
CompactBlockIsStaled = 105,
CompactBlockRequiresParent = 106,
CompactBlockRequiresFreshTransactions = 107,
CompactBlockMeetsShortIdsCollision = 108,
BlocksInFlightReachLimit = 109,
TooManyRequests = 110,
ProtocolMessageIsMalformed = 400,
BlockIsInvalid = 401,
CompactBlockHasInvalidHeader = 402,
CompactBlockHasDuplicatedShortIds = 403,
CompactBlockHasNotPrefilledCellbase = 404,
CompactBlockHasDuplicatedPrefilledTransactions = 405,
CompactBlockHasOutOfOrderPrefilledTransactions = 406,
CompactBlockHasOutOfIndexPrefilledTransactions = 407,
CompactBlockHasInvalidUncle = 408,
CompactBlockHasUnmatchedTransactionRootWithReconstructedBlock = 409,
BlockTransactionsLengthIsUnmatchedWithPendingCompactBlock = 410,
BlockTransactionsShortIdsAreUnmatchedWithPendingCompactBlock = 411,
BlockUnclesLengthIsUnmatchedWithPendingCompactBlock = 412,
BlockUnclesAreUnmatchedWithPendingCompactBlock = 413,
GetHeadersMissCommonAncestors = 414,
HeadersIsInvalid = 415,
TooManyUnknownTransactions = 416,
RequestGenesis = 417,
RequestDuplicate = 418,
TxPool = 501,
Network = 502,
}
impl StatusCode {
pub fn with_context<S: ToString>(self, context: S) -> Status {
Status::new(self, Some(context))
}
pub fn name(self) -> String {
format!("{:?}({})", self, self as u16)
}
}
#[derive(Clone, Debug, Eq)]
pub struct Status {
code: StatusCode,
context: Option<String>,
}
impl Status {
pub fn new<S: ToString>(code: StatusCode, context: Option<S>) -> Self {
Self {
code,
context: context.map(|s| s.to_string()),
}
}
pub fn ok() -> Self {
Self::new::<&str>(StatusCode::OK, None)
}
pub fn ignored() -> Self {
Self::new::<&str>(StatusCode::Ignored, None)
}
pub fn is_ok(&self) -> bool {
self.code == StatusCode::OK
}
pub fn should_ban(&self) -> Option<Duration> {
if !(400..500).contains(&(self.code as u16)) {
return None;
}
if let Some(context) = &self.context {
if context.contains(ARGV_TOO_LONG_TEXT) {
return None;
}
}
match self.code {
StatusCode::GetHeadersMissCommonAncestors => Some(SYNC_USELESS_BAN_TIME),
_ => Some(BAD_MESSAGE_BAN_TIME),
}
}
pub fn should_warn(&self) -> bool {
self.code as u16 >= 500
}
pub fn code(&self) -> StatusCode {
self.code
}
}
impl PartialEq for Status {
fn eq(&self, other: &Self) -> bool {
self.code == other.code
}
}
impl Display for Status {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self.context {
Some(ref context) => write!(f, "{:?}({}): {}", self.code, self.code as u16, context),
None => write!(f, "{:?}({})", self.code, self.code as u16),
}
}
}
impl From<StatusCode> for Status {
fn from(code: StatusCode) -> Self {
Self::new::<&str>(code, None)
}
}