1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
// Copyright Rivtower Technologies LLC.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use num_derive::FromPrimitive;

/// The response status code
#[derive(Debug, Clone, Copy, Eq, PartialEq, FromPrimitive)]
pub enum StatusCode {
    /// Success: 0
    Success = 0,
    /// Convert int to status Error
    ConvertIntError,
    /// status code is none
    NoneStatusCode,
    /// fate error
    FatalError,

    /// controller error, start from 100
    /// node in misbehave list
    MisbehaveNode = 100,
    /// node in ban list
    BannedNode,
    /// address not consistent with record origin
    AddressOriginCheckError,
    /// provide address len is not 20
    ProvideAddressError,
    /// message not provide address
    NoProvideAddress,
    /// not get the block
    NoBlock,
    /// not get the proof
    NoProof,
    /// not get height of block which wrap tx
    NoTxHeight,
    /// not get tx index
    NoTxIndex,
    /// not get transaction
    NoTransaction,
    /// not get the block height base on hash
    NoBlockHeight,
    /// not get the block hash base on height
    NoBlockHash,
    /// proposal is none
    NoneProposal,
    /// block body is none
    NoneBlockBody,
    /// block header is none
    NoneBlockHeader,
    /// chain status is none
    NoneChainStatus,
    /// transaction's witness is none
    NoneWitness,
    /// transaction is none
    NoneTransaction,
    /// utxo is none
    NoneUtxo,
    /// raw tx is none
    NoneRawTx,
    /// early status received
    EarlyStatus,
    /// execute error
    ExecuteError,
    /// proto struct encode error
    EncodeError,
    /// proto struct encode error
    DecodeError,
    /// no candidate block
    NoCandidate,
    /// not get early status
    NoEarlyStatus,
    /// fork tree no block
    NoForkTree,
    /// find dup transaction
    DupTransaction,
    /// proposal too high
    ProposalTooHigh,
    /// proposal too low
    ProposalTooLow,
    /// proposal check error
    ProposalCheckError,
    /// consensus check proposal error
    ConsensusProposalCheckError,
    /// block hash check error
    BlockCheckError,
    /// the sig of chain status init check error
    CSISigCheckError,
    /// chain version or chain id check error
    VersionOrIdCheckError,
    /// hash check error
    HashCheckError,
    /// hash len is not correct
    HashLenError,
    /// signature len is not correct
    SigLenError,
    /// signature check error
    SigCheckError,
    /// the node in sync mode
    NodeInSyncMode,
    /// Dup tx in history
    HistoryDupTx,
    /// emergency brake
    EmergencyBrake,
    /// auth check tx's version error
    InvalidVersion,
    /// auth check tx's to error
    InvalidTo,
    /// auth check tx's nonce error
    InvalidNonce,
    /// auth check tx's valid until block error
    InvalidValidUntilBlock,
    /// auth check tx's value error
    InvalidValue,
    /// auth check tx's chain id error
    InvalidChainId,
    /// auth limit utxo's witness only one
    InvalidWitness,
    /// auth check utxo's lock id error
    InvalidLockId,
    /// auth check utxo's pre tx hash error
    InvalidPreHash,
    /// auth check send is not admin
    AdminCheckError,
    /// network msg's module not controller
    ModuleNotController,

    /// Consensus from 200
    /// check proposal proof error
    ConsensusServerNotReady = 200,
    /// proof of proposal error
    ProposalProofError,

    /// Kms from 300
    /// Kms server not ready
    KmsServerNotReady = 300,
    /// hash result is none
    NoneHashResult,
    /// kms not found account base on id
    NotFoundAccount,
    /// construct signature error
    ConstructSigError,
    /// construct key pair error
    ConstructKeyPairError,
    /// sign error
    SignError,
    /// insert account error
    InsertAccountError,

    /// Network from 400
    /// Network server not ready
    NetworkServerNotReady = 400,
    /// send message error
    SendMsgError,
    /// broadcast message error
    BroadcastMsgError,
    /// multi-addr error
    MultiAddrParseError,
    /// dial node failed
    DialNodeFail,
    // add an existed peer
    AddExistedPeer,

    /// executor from 500
    /// Executor server not ready
    ExecuteServerNotReady = 500,
    /// internal channel disconnected
    InternalChannelDisconnected,
    /// early same block reenter
    ReenterBlock,
    /// invalid block reenter
    ReenterInvalidBlock,

    /// storage from 600
    /// storage server not ready
    StorageServerNotReady = 600,
    /// kv not found
    NotFound,
    /// invalid region
    InvalidRegion,
    /// invalid key
    InvalidKey,
    /// bad region
    BadRegion,
    /// store data error
    StoreError,
    /// load data error
    LoadError,
    /// delete data error
    DeleteError,
}

impl StatusCode {
    pub fn is_success(&self) -> Result<(), StatusCode> {
        if self != &StatusCode::Success {
            Err(*self)
        } else {
            Ok(())
        }
    }
}

impl ::std::fmt::Display for StatusCode {
    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
        write!(f, "{:?}", self)
    }
}

impl ::std::error::Error for StatusCode {}

macro_rules! impl_int_from_status {
    ($myty : ty) => {
        impl From<StatusCode> for $myty {
            fn from(v: StatusCode) -> Self {
                v as $myty
            }
        }
    };
}

impl_int_from_status!(u16);
impl_int_from_status!(u32);
impl_int_from_status!(u64);
impl_int_from_status!(u128);

macro_rules! impl_status_from_int {
    ($int_t : ty,$from_int :ident) => {
        impl From<$int_t> for StatusCode {
            fn from(v: $int_t) -> Self {
                let s = num::FromPrimitive::$from_int(v);
                s.unwrap_or(StatusCode::ConvertIntError)
            }
        }
    };
}

impl_status_from_int!(u16, from_u16);
impl_status_from_int!(u32, from_u32);
impl_status_from_int!(u64, from_u64);
impl_status_from_int!(u128, from_u128);

impl From<cita_cloud_proto::common::StatusCode> for StatusCode {
    fn from(status: cita_cloud_proto::common::StatusCode) -> Self {
        StatusCode::from(status.code)
    }
}

impl Into<cita_cloud_proto::common::StatusCode> for StatusCode {
    fn into(self) -> cita_cloud_proto::common::StatusCode {
        cita_cloud_proto::common::StatusCode { code: self.into() }
    }
}

#[cfg(test)]
mod tests {
    use crate::StatusCode;

    #[test]
    fn it_works() {
        let num: u32 = StatusCode::BannedNode.into();
        assert_eq!(num, 101);

        let s = StatusCode::from(104 as u64);
        assert_eq!(StatusCode::NoProvideAddress, s);

        let s = StatusCode::from(65535 as u16);
        assert_eq!(StatusCode::ConvertIntError, s);

        let status = cita_cloud_proto::common::StatusCode { code: 0 };
        let s = StatusCode::from(status);
        assert_eq!(StatusCode::Success, s);
    }
}