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
//! This module contains all the RPC methods.
use std::io;

use serde::Deserialize;
use serde_json::json;
use thiserror::Error;

mod private {
    pub trait Sealed {}
}

/// A trait identifying valid unc JSON-RPC methods.
pub trait RpcMethod: private::Sealed
where
    Self::Response: RpcHandlerResponse,
    Self::Error: RpcHandlerError,
{
    type Response;
    type Error;

    fn method_name(&self) -> &str;

    fn params(&self) -> Result<serde_json::Value, io::Error>;

    fn parse_handler_response(
        response: serde_json::Value,
    ) -> Result<Result<Self::Response, Self::Error>, serde_json::Error> {
        Self::Response::parse(response).map(Ok)
    }
}

impl<T> private::Sealed for &T where T: private::Sealed {}
impl<T> RpcMethod for &T
where
    T: RpcMethod,
{
    type Response = T::Response;
    type Error = T::Error;

    fn method_name(&self) -> &str {
        T::method_name(self)
    }

    fn params(&self) -> Result<serde_json::Value, io::Error> {
        T::params(self)
    }

    fn parse_handler_response(
        response: serde_json::Value,
    ) -> Result<Result<Self::Response, Self::Error>, serde_json::Error> {
        T::parse_handler_response(response)
    }
}

/// A trait identifying valid unc JSON-RPC method responses.
pub trait RpcHandlerResponse: serde::de::DeserializeOwned {
    fn parse(value: serde_json::Value) -> Result<Self, serde_json::Error> {
        serde_json::from_value(value)
    }
}

/// A trait identifying valid unc JSON-RPC errors.
pub trait RpcHandlerError: serde::de::DeserializeOwned {
    /// Parser for the `.error_struct` field in RpcError.
    fn parse(handler_error: serde_json::Value) -> Result<Self, serde_json::Error> {
        serde_json::from_value(handler_error)
    }

    /// Parser for the `.data` field in RpcError, not `.error_struct`.
    ///
    /// This would only ever be used as a fallback if [`RpcHandlerError::parse`] fails.
    ///
    /// Defaults to `None` meaning there's no alternative deserialization available.
    fn parse_legacy_error(_error: serde_json::Value) -> Option<Result<Self, serde_json::Error>> {
        None
    }
}

pub mod block;
pub mod broadcast_tx_async;
pub mod broadcast_tx_commit;
pub mod chunk;
pub mod gas_price;
pub mod health;
pub mod light_client_proof;
pub mod network_info;
pub mod next_light_client_block;
pub mod query;
pub mod status;
pub mod tx;
pub mod validators;

// ======== experimental ========
mod experimental;
pub use experimental::EXPERIMENTAL_changes;
pub use experimental::EXPERIMENTAL_changes_in_block;
pub use experimental::EXPERIMENTAL_check_tx;
pub use experimental::EXPERIMENTAL_genesis_config;
pub use experimental::EXPERIMENTAL_protocol_config;
pub use experimental::EXPERIMENTAL_receipt;
pub use experimental::EXPERIMENTAL_tx_status;
pub use experimental::EXPERIMENTAL_validators_ordered;
// ======== experimental ========

// ======== any ========
#[cfg(feature = "any")]
mod any;
#[cfg(feature = "any")]
pub use any::{request as any, RpcAnyRequest};
// ======== any ========

// ======== sandbox ========
#[cfg(feature = "sandbox")]
mod sandbox;

#[cfg(feature = "sandbox")]
pub use sandbox::sandbox_patch_state;

#[cfg(feature = "sandbox")]
pub use sandbox::sandbox_fast_forward;
// ======== sandbox ========

// ======== adversarial ========
#[cfg(feature = "adversarial")]
mod adversarial;

#[cfg(feature = "adversarial")]
pub use adversarial::adv_set_weight;

#[cfg(feature = "adversarial")]
pub use adversarial::adv_disable_header_sync;

#[cfg(feature = "adversarial")]
pub use adversarial::adv_disable_doomslug;

#[cfg(feature = "adversarial")]
pub use adversarial::adv_produce_blocks;

#[cfg(feature = "adversarial")]
pub use adversarial::adv_switch_to_height;

#[cfg(feature = "adversarial")]
pub use adversarial::adv_get_saved_blocks;

#[cfg(feature = "adversarial")]
pub use adversarial::adv_check_store;
// ======== adversarial ========

/// Converts an RPC Method into JSON.
pub fn to_json<M: RpcMethod>(method: &M) -> Result<serde_json::Value, io::Error> {
    let request_payload = unc_jsonrpc_primitives::message::Message::request(
        method.method_name().to_string(),
        method.params()?,
    );

    Ok(json!(request_payload))
}

mod common {
    use super::*;

    // workaround for deserializing partially serialized
    // error types missing the `error_message` field in
    // their UnknownBlock variants.
    macro_rules! _parse_unknown_block {
        ($json:expr => $err_ty:ident) => {
            match $json {
                err => {
                    if err["name"] == "UNKNOWN_BLOCK" {
                        Ok($err_ty::UnknownBlock {
                            error_message: "".to_string(),
                        })
                    } else {
                        serde_json::from_value(err)
                    }
                }
            }
        };
    }
    pub(crate) use _parse_unknown_block as parse_unknown_block;

    pub fn serialize_signed_transaction(
        tx: &unc_primitives::transaction::SignedTransaction,
    ) -> Result<String, io::Error> {
        Ok(unc_primitives::serialize::to_base64(&borsh::to_vec(&tx)?))
    }

    // adv_*
    #[cfg(feature = "adversarial")]
    impl RpcHandlerError for () {}

    // adv_*
    #[cfg(feature = "adversarial")]
    impl RpcHandlerResponse for () {
        fn parse(_value: serde_json::Value) -> Result<Self, serde_json::Error> {
            Ok(())
        }
    }

    #[cfg(feature = "any")]
    impl RpcHandlerResponse for serde_json::Value {
        fn parse(value: serde_json::Value) -> Result<Self, serde_json::Error> {
            Ok(value)
        }
    }

    #[cfg(feature = "any")]
    impl RpcHandlerError for serde_json::Value {
        fn parse(handler_error: serde_json::Value) -> Result<Self, serde_json::Error> {
            Ok(handler_error)
        }
    }

    // broadcast_tx_commit, tx
    impl RpcHandlerResponse for unc_primitives::views::FinalExecutionOutcomeView {}

    // broadcast_tx_commit, tx, EXPERIMENTAL_check_tx, EXPERIMENTAL_tx_status
    impl RpcHandlerError for unc_jsonrpc_primitives::types::transactions::RpcTransactionError {
        fn parse_legacy_error(value: serde_json::Value) -> Option<Result<Self, serde_json::Error>> {
            match serde_json::from_value::<unc_jsonrpc_primitives::errors::ServerError>(value) {
                Ok(unc_jsonrpc_primitives::errors::ServerError::TxExecutionError(
                    unc_primitives::errors::TxExecutionError::InvalidTxError(context),
                )) => Some(Ok(Self::InvalidTransaction { context })),
                Err(err) => Some(Err(err)),
                _ => None,
            }
        }
    }

    // health, status
    impl RpcHandlerError for unc_jsonrpc_primitives::types::status::RpcStatusError {}

    // EXPERIMENTAL_changes, EXPERIMENTAL_changes_in_block
    impl RpcHandlerError for unc_jsonrpc_primitives::types::changes::RpcStateChangesError {
        fn parse(value: serde_json::Value) -> Result<Self, serde_json::Error> {
            parse_unknown_block!(value => Self)
        }
    }

    // EXPERIMENTAL_broadcast_tx_sync, EXPERIMENTAL_check_tx
    impl RpcHandlerResponse
        for unc_jsonrpc_primitives::types::transactions::RpcBroadcastTxSyncResponse
    {
    }

    // validators, EXPERIMENTAL_validators_ordered
    impl RpcHandlerError for unc_jsonrpc_primitives::types::validator::RpcValidatorError {}
}