Coverage Report

Created: 2022-11-10 19:56

/home/runner/work/creditcoin/creditcoin/pallets/creditcoin/src/ocw/rpc.rs
Line
Count
Source (jump to first uncovered line)
1
use self::errors::RpcError;
2
3
use super::OffchainResult;
4
use alloc::string::String;
5
use core::{convert::TryFrom, fmt};
6
use ethereum_types::{H160, H256, U256, U64};
7
use serde::{
8
  de::{Error, Unexpected, Visitor},
9
  Deserialize, Deserializer, Serialize, Serializer,
10
};
11
use sp_runtime::offchain::{http, Duration, Timestamp};
12
use sp_std::{prelude::*, vec::Vec};
13
14
use crate::ExternalTxId;
15
16
pub mod errors {
17
  use super::JsonRpcError;
18
  use crate::ocw::errors::impl_from_error;
19
  use sp_runtime::offchain::{http::PendingRequest, HttpError};
20
21
1
  #[derive(Debug)]
22
  pub enum RpcError {
23
    NoResult,
24
    FailureResponse(JsonRpcError),
25
    SerdeError(serde_json::Error),
26
    HttpError(HttpError),
27
    RequestError(sp_runtime::offchain::http::Error),
28
    InvalidArgument(&'static str),
29
    Timeout(PendingRequest),
30
  }
31
32
  impl_from_error!(
33
    RpcError,
34
    JsonRpcError => FailureResponse,
35
    serde_json::Error => SerdeError,
36
    HttpError => HttpError,
37
    sp_runtime::offchain::http::Error => RequestError,
38
    PendingRequest => Timeout
39
  );
40
}
41
42
#[repr(transparent)]
43
0
#[derive(Clone, Debug)]
44
pub struct VecString(Vec<u8>, ());
45
46
impl TryFrom<&[u8]> for VecString {
47
  type Error = core::str::Utf8Error;
48
  fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
49
0
    let _ = core::str::from_utf8(value)?;
50
0
    Ok(VecString(Vec::from(value), ()))
51
0
  }
52
}
53
54
impl From<&str> for VecString {
55
432
  fn from(s: &str) -> Self {
56
432
    VecString(Vec::from(s.as_bytes()), ())
57
432
  }
58
}
59
60
impl serde::Serialize for VecString {
61
567
  fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
62
567
  where
63
567
    S: serde::Serializer,
64
567
  {
65
567
    serde::Serialize::serialize(
66
567
      core::str::from_utf8(&self.0)
67
567
        .expect("vecstrings cannot be constructed without validating utf8; qed"),
68
567
      serializer,
69
567
    )
70
567
  }
71
}
72
73
impl<'de> serde::Deserialize<'de> for VecString {
74
87
  fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
75
87
  where
76
87
    D: serde::Deserializer<'de>,
77
87
  {
78
87
    let s: &str = serde::Deserialize::deserialize(deserializer)
?0
;
79
87
    Ok(VecString(Vec::from(s.as_bytes()), ()))
80
87
  }
81
}
82
83
/// Raw bytes wrapper
84
18
#[derive(
Clone16
,
Debug0
, Default,
PartialEq0
, Eq,
Hash0
)]
85
pub struct Bytes(pub Vec<u8>);
86
87
impl<T: Into<Vec<u8>>> From<T> for Bytes {
88
1
  fn from(data: T) -> Self {
89
1
    Bytes(data.into())
90
1
  }
91
}
92
93
impl Serialize for Bytes {
94
0
  fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
95
0
  where
96
0
    S: Serializer,
97
0
  {
98
0
    let mut serialized = String::from("0x");
99
0
    serialized.push_str(&hex::encode(&self.0));
100
0
    serializer.serialize_str(serialized.as_ref())
101
0
  }
102
}
103
104
impl<'a> Deserialize<'a> for Bytes {
105
22
  fn deserialize<D>(deserializer: D) -> Result<Bytes, D::Error>
106
22
  where
107
22
    D: Deserializer<'a>,
108
22
  {
109
22
    deserializer.deserialize_identifier(BytesVisitor)
110
22
  }
111
}
112
113
pub type Address = H160;
114
115
struct BytesVisitor;
116
117
impl<'a> Visitor<'a> for BytesVisitor {
118
  type Value = Bytes;
119
120
0
  fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
121
0
    write!(formatter, "a 0x-prefixed hex-encoded vector of bytes")
122
0
  }
123
124
22
  fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
125
22
  where
126
22
    E: Error,
127
22
  {
128
22
    if value.len() >= 2 && &value[0..2] == "0x" {
129
22
      let bytes = hex::decode(&value[2..])
130
22
        .map_err(|e| 
Error::custom(alloc::format!("Invalid hex: {}", e))0
)
?0
;
131
22
      Ok(Bytes(bytes))
132
    } else {
133
0
      Err(Error::invalid_value(Unexpected::Str(value), &"0x prefix"))
134
    }
135
22
  }
136
137
0
  fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
138
0
  where
139
0
    E: Error,
140
0
  {
141
0
    self.visit_str(value.as_ref())
142
0
  }
143
}
144
145
212
#[derive(serde::Serialize, 
s0
erd
e::Deserializ0
e0
,
Clone0
,
Debug0
)]
146
pub struct JsonRpcRequest {
147
  jsonrpc: VecString,
148
  method: VecString,
149
  params: Vec<serde_json::Value>,
150
  id: u64,
151
}
152
153
const REQUEST_TIMEOUT_PERIOD: Duration = Duration::from_millis(5000);
154
155
77
fn timeout() -> Timestamp {
156
77
  sp_io::offchain::timestamp().add(REQUEST_TIMEOUT_PERIOD)
157
77
}
158
159
impl JsonRpcRequest {
160
  #[allow(dead_code)]
161
0
  pub fn with_method(method: impl Into<VecString>) -> Self {
162
0
    let method = method.into();
163
0
    Self { jsonrpc: VecString::from("2.0"), method, params: Vec::new(), id: 1 }
164
0
  }
165
212
  pub fn new(
166
212
    method: impl Into<VecString>,
167
212
    params: impl IntoIterator<Item = serde_json::Value>,
168
212
  ) -> Self {
169
212
    Self {
170
212
      jsonrpc: VecString::from("2.0"),
171
212
      method: method.into(),
172
212
      params: params.into_iter().collect(),
173
212
      id: 1,
174
212
    }
175
212
  }
176
177
  #[allow(dead_code)]
178
0
  pub fn param(&mut self, param: serde_json::Value) -> &mut Self {
179
0
    self.params.push(param);
180
0
    self
181
0
  }
182
183
  #[allow(dead_code)]
184
135
  pub fn to_bytes(&self) -> Vec<u8> {
185
135
    serde_json::to_vec(self).expect("serialization cannot fail; qed")
186
135
  }
187
188
77
  pub fn send<T: for<'de> serde::Deserialize<'de>>(
189
77
    self,
190
77
    rpc_url: &str,
191
77
  ) -> OffchainResult<T, RpcError> {
192
77
    let rpc_bytes = serde_json::to_vec(&self).map_err(RpcError::SerdeError)
?0
;
193
77
    let timeout = timeout();
194
77
    let response = http::Request::post(rpc_url, vec![rpc_bytes])
195
77
      .add_header("Content-Type", "application/json")
196
77
      .send()
?0
197
77
      .try_wait(timeout)
?0
?0
;
198
77
    let body: Vec<u8> = response.body().collect();
199
77
    let rpc_response: JsonRpcResponse<T> = serde_json::from_slice(&body)
?0
;
200
77
    rpc_response.result()
201
77
  }
202
}
203
204
763
#[derive(
s338
erd
e::Deserializ87
e,
serd143
e::Serializ143
e143
,
Clone0
,
Debug0
)]
205
pub struct JsonRpcResponse<T> {
206
  #[allow(dead_code)]
207
  pub jsonrpc: VecString,
208
  #[allow(dead_code)]
209
  pub id: u64,
210
  pub error: Option<JsonRpcError>,
211
  pub result: Option<T>,
212
}
213
214
impl<T> JsonRpcResponse<T> {
215
  pub fn result(self) -> Result<T, RpcError> {
216
77
    if let Some(
err1
) = self.error {
217
1
      return Err(err.into());
218
76
    }
219
76
    if let Some(
result71
) = self.result {
220
71
      Ok(result)
221
    } else {
222
5
      Err(RpcError::NoResult)
223
    }
224
77
  }
225
}
226
227
#[allow(dead_code)]
228
5
#[derive(
s2
erd
e::Deserializ0
e,
serd1
e::Serializ1
e1
,
Clone0
,
Debug1
)]
229
pub struct JsonRpcError {
230
  pub code: i32,
231
  pub message: String,
232
}
233
234
572
#[derive(
s418
erd
e::Deserializ22
e,
Clone16
,
Debug0
,
Default18
)]
235
pub struct EthTransaction {
236
  /// Hash
237
  pub hash: H256,
238
  /// Block number. None when pending.
239
  #[serde(rename = "blockNumber")]
240
  pub block_number: Option<U64>,
241
  /// Sender
242
  #[serde(default, skip_serializing_if = "Option::is_none")]
243
  pub from: Option<Address>,
244
  /// Recipient (None when contract creation)
245
  pub to: Option<Address>,
246
  /// Transfered value
247
  pub value: U256,
248
  /// Input data
249
  input: Bytes,
250
}
251
252
impl EthTransaction {
253
9
  pub fn selector(&self) -> &[u8] {
254
9
    &self.input.0[..4]
255
9
  }
256
257
10
  pub fn is_input_empty(&self) -> bool {
258
10
    self.input.0.len() <= 4
259
10
  }
260
261
22
  pub fn input(&self) -> &[u8] {
262
22
    &self.input.0[4..]
263
22
  }
264
}
265
266
#[cfg(test)]
267
impl EthTransaction {
268
21
  pub fn set_input(&mut self, input: &[u8]) {
269
21
    self.input.0 = input.to_vec();
270
21
  }
271
}
272
273
420
#[derive(
s294
erd
e::Deserializ21
e,
Clone0
,
Debug0
,
Default29
)]
274
pub struct EthTransactionReceipt {
275
  /// Transaction hash.
276
  #[serde(rename = "transactionHash")]
277
  pub transaction_hash: H256,
278
  /// Number of the block this transaction was included within.
279
  #[serde(rename = "blockNumber")]
280
  pub block_number: Option<U64>,
281
  /// Sender
282
  /// Note: default address if the client did not return this value
283
  /// (maintains backwards compatibility for <= 0.7.0 when this field was missing)
284
  #[serde(default)]
285
  pub from: Address,
286
  /// Recipient (None when contract creation)
287
  /// Note: Also `None` if the client did not return this value
288
  /// (maintains backwards compatibility for <= 0.7.0 when this field was missing)
289
  #[serde(default)]
290
  pub to: Option<Address>,
291
  /// Status: either 1 (success) or 0 (failure).
292
  pub status: Option<U64>,
293
}
294
295
115
#[derive(
s110
erde::Deserialize,
Clone0
,
Debug0
,
Default0
)]
296
pub struct EthBlock {
297
  /// Timestamp of the block's collation.
298
  pub timestamp: U64,
299
}
300
301
impl EthTransactionReceipt {
302
  pub fn is_success(&self) -> bool {
303
41
    if let Some(status) = self.status {
304
41
      !status.is_zero()
305
    } else {
306
0
      false
307
    }
308
41
  }
309
}
310
311
50
fn to_json_hex(bytes: &[u8]) -> String {
312
50
  use core::ops::Not;
313
50
  let hex = hex::encode(bytes);
314
50
  if hex.is_empty().not() {
315
49
    let mut buf = String::with_capacity(hex.len() + 2);
316
49
    buf.push_str("0x");
317
49
    buf.push_str(&hex);
318
49
    buf
319
  } else {
320
1
    hex
321
  }
322
50
}
323
324
7
fn format_as_hex<T: sp_std::fmt::LowerHex>(value: T) -> String {
325
7
  alloc::format!("0x{:x}", value)
326
7
}
327
328
25
pub fn eth_get_transaction(
329
25
  tx_id: &ExternalTxId,
330
25
  rpc_url: &str,
331
25
) -> OffchainResult<EthTransaction, RpcError> {
332
25
  let rpc_req = JsonRpcRequest::new(
333
25
    "eth_getTransactionByHash",
334
25
    Some(serde_json::Value::String(to_json_hex(tx_id.as_ref()))),
335
25
  );
336
25
  rpc_req.send(rpc_url)
337
25
}
338
339
22
pub fn eth_get_transaction_receipt(
340
22
  tx_id: &ExternalTxId,
341
22
  rpc_url: &str,
342
22
) -> OffchainResult<EthTransactionReceipt, RpcError> {
343
22
  let rpc_req = JsonRpcRequest::new(
344
22
    "eth_getTransactionReceipt",
345
22
    Some(serde_json::Value::String(to_json_hex(tx_id.as_ref()))),
346
22
  );
347
22
  rpc_req.send(rpc_url)
348
22
}
349
350
21
pub fn eth_get_block_number(rpc_url: &str) -> OffchainResult<U64, RpcError> {
351
21
  let rpc_req = JsonRpcRequest::new("eth_blockNumber", None);
352
21
  rpc_req.send(rpc_url)
353
21
}
354
355
6
pub fn eth_get_block_by_number(
356
6
  block_number: U64,
357
6
  rpc_url: &str,
358
6
) -> OffchainResult<EthBlock, RpcError> {
359
6
  let rpc_req = JsonRpcRequest::new(
360
6
    "eth_getBlockByNumber",
361
6
    [serde_json::Value::String(format_as_hex(block_number)), serde_json::Value::Bool(false)],
362
6
  );
363
6
  rpc_req.send(rpc_url)
364
6
}
365
366
3
pub fn eth_chain_id(rpc_url: &str) -> OffchainResult<U64, RpcError> {
367
3
  let rpc_req = JsonRpcRequest::new("eth_chainId", None);
368
3
  rpc_req.send(rpc_url)
369
3
}
370
371
#[cfg(test)]
372
mod tests {
373
1
  #[test]
374
1
  fn to_json_hex_works() {
375
1
    assert_eq!(super::to_json_hex(&[0x01, 0x02, 0x03]), "0x010203");
376
1
    assert_eq!(super::to_json_hex(&[0x01, 0x00, 0x03]), "0x010003");
377
1
    assert_eq!(super::to_json_hex(&[]), "");
378
1
  }
379
380
1
  #[test]
381
1
  fn format_as_hex_works() {
382
1
    assert_eq!(super::format_as_hex(0x123456789abcdefu64), "0x123456789abcdef");
383
1
  }
384
}