1use ckb_jsonrpc_types::{JsonBytes, Transaction};
2use faster_hex::{hex_decode, hex_string};
3use serde::de::DeserializeOwned;
4use std::convert::TryFrom;
5use std::str::FromStr;
6
7use super::{
8 method, CallbackRequest, IndexerRequest, JsonrpcRequest, JsonrpcResponse, KeyStoreRequest,
9 LiveCellIndexType, PluginRequest, PluginResponse, RpcRequest, JSONRPC_VERSION,
10};
11
12impl From<(u64, PluginRequest)> for JsonrpcRequest {
13 fn from((id, request): (u64, PluginRequest)) -> JsonrpcRequest {
14 let (method, params) = match request {
15 PluginRequest::Quit => (method::QUIT, Vec::new()),
16 PluginRequest::GetConfig => (method::GET_CONFIG, Vec::new()),
17 PluginRequest::ReadPassword(prompt) => {
18 (method::READ_PASSWORD, vec![serde_json::json!(prompt)])
19 }
20 PluginRequest::PrintStdout(content) => {
21 (method::PRINT_STDOUT, vec![serde_json::json!(content)])
22 }
23 PluginRequest::PrintStderr(content) => {
24 (method::PRINT_STDERR, vec![serde_json::json!(content)])
25 }
26 PluginRequest::RpcUrlChanged(url) => {
27 (method::RPC_URL_CHANGED, vec![serde_json::json!(url)])
28 }
29 PluginRequest::SubCommand(args) => (method::SUB_COMMAND, vec![serde_json::json!(args)]),
30 PluginRequest::Callback(callback_request) => callback_request.into(),
31 PluginRequest::Rpc(rpc_request) => rpc_request.into(),
32 PluginRequest::Indexer {
33 genesis_hash,
34 request: indexer_request,
35 } => {
36 let (method, mut params) = indexer_request.into();
37 params.insert(0, serde_json::json!(genesis_hash));
38 (method, params)
39 }
40 PluginRequest::KeyStore(keystore_request) => keystore_request.into(),
41 };
42 JsonrpcRequest {
43 jsonrpc: JSONRPC_VERSION.to_string(),
44 id: serde_json::json!(id),
45 method: method.to_string(),
46 params,
47 }
48 }
49}
50
51impl TryFrom<JsonrpcRequest> for (u64, PluginRequest) {
52 type Error = String;
53 fn try_from(data: JsonrpcRequest) -> Result<(u64, PluginRequest), Self::Error> {
54 if data.jsonrpc != JSONRPC_VERSION {
55 return Err(format!("Invalid jsonrpc field: {}", data.jsonrpc));
56 }
57 let request_id: u64 = serde_json::from_value(data.id.clone())
58 .map_err(|err| format!("Request id must be integer number, error={}", err))?;
59
60 let request = match data.method.as_str() {
61 method::QUIT => PluginRequest::Quit,
62 method::GET_CONFIG => PluginRequest::GetConfig,
63 method::READ_PASSWORD => PluginRequest::ReadPassword(parse_param(&data, 0, "prompt")?),
64 method::PRINT_STDOUT => PluginRequest::PrintStdout(parse_param(&data, 0, "content")?),
65 method::PRINT_STDERR => PluginRequest::PrintStderr(parse_param(&data, 0, "content")?),
66 method::RPC_URL_CHANGED => PluginRequest::RpcUrlChanged(parse_param(&data, 0, "url")?),
67 method::SUB_COMMAND => PluginRequest::SubCommand(parse_param(&data, 0, "args")?),
68 method if method.starts_with(method::CALLBACK_PREFIX) => {
69 CallbackRequest::try_from(&data).map(PluginRequest::Callback)?
70 }
71 method if method.starts_with(method::RPC_PREFIX) => {
72 RpcRequest::try_from(&data).map(PluginRequest::Rpc)?
73 }
74 method if method.starts_with(method::INDEXER_PREFIX) => {
75 let genesis_hash = parse_param(&data, 0, "genesis_hash")?;
76 IndexerRequest::try_from(&data).map(|request| PluginRequest::Indexer {
77 genesis_hash,
78 request,
79 })?
80 }
81 method if method.starts_with(method::KEYSTORE_PREFIX) => {
82 KeyStoreRequest::try_from(&data).map(PluginRequest::KeyStore)?
83 }
84 method => {
85 return Err(format!("Invalid request method: {}", method));
86 }
87 };
88 Ok((request_id, request))
89 }
90}
91
92impl From<CallbackRequest> for (&'static str, Vec<serde_json::Value>) {
93 fn from(request: CallbackRequest) -> (&'static str, Vec<serde_json::Value>) {
94 match request {
95 CallbackRequest::SendTransaction { tx, sub_command } => {
96 let params = vec![
97 serde_json::to_value(&tx).expect("Serialize json failed"),
98 serde_json::json!(sub_command),
99 ];
100 (method::CALLBACK_SEND_TRANSACTION, params)
101 }
102 }
103 }
104}
105impl TryFrom<&JsonrpcRequest> for CallbackRequest {
106 type Error = String;
107 fn try_from(data: &JsonrpcRequest) -> Result<CallbackRequest, Self::Error> {
108 let request = match data.method.as_str() {
109 method::CALLBACK_SEND_TRANSACTION => {
110 let tx: Transaction = parse_param(data, 0, "transaction")?;
111 let sub_command: String = parse_param(data, 1, "sub-command")?;
112 CallbackRequest::SendTransaction { tx, sub_command }
113 }
114 _ => {
115 return Err(format!("Invalid request method: {}", data.method));
116 }
117 };
118 Ok(request)
119 }
120}
121
122impl From<KeyStoreRequest> for (&'static str, Vec<serde_json::Value>) {
123 fn from(request: KeyStoreRequest) -> (&'static str, Vec<serde_json::Value>) {
124 match request {
125 KeyStoreRequest::ListAccount => (method::KEYSTORE_LIST_ACCOUNT, Vec::new()),
126 KeyStoreRequest::HasAccount(hash160) => (
127 method::KEYSTORE_HAS_ACCOUNT,
128 vec![serde_json::json!(hash160)],
129 ),
130 KeyStoreRequest::CreateAccount(password) => (
131 method::KEYSTORE_CREATE_ACCOUNT,
132 vec![serde_json::json!(password)],
133 ),
134 KeyStoreRequest::UpdatePassword {
135 hash160,
136 password,
137 new_password,
138 } => {
139 let params = vec![
140 serde_json::json!(hash160),
141 serde_json::json!(password),
142 serde_json::json!(new_password),
143 ];
144 (method::KEYSTORE_UPDATE_PASSWORD, params)
145 }
146 KeyStoreRequest::Import {
147 privkey,
148 chain_code,
149 password,
150 } => {
151 let privkey = format!("0x{}", hex_string(&privkey));
152 let chain_code = format!("0x{}", hex_string(&chain_code));
153 let params = vec![
154 serde_json::json!(privkey),
155 serde_json::json!(chain_code),
156 serde_json::json!(password),
157 ];
158 (method::KEYSTORE_IMPORT, params)
159 }
160 KeyStoreRequest::ImportAccount {
161 account_id,
162 password,
163 } => {
164 let account_id = format!("0x{}", hex_string(account_id.as_bytes()));
165 let params = vec![serde_json::json!(account_id), serde_json::json!(password)];
166 (method::KEYSTORE_IMPORT_ACCOUNT, params)
167 }
168 KeyStoreRequest::Export { hash160, password } => {
169 let params = vec![serde_json::json!(hash160), serde_json::json!(password)];
170 (method::KEYSTORE_EXPORT, params)
171 }
172 KeyStoreRequest::Sign {
173 hash160,
174 path,
175 message,
176 target,
177 recoverable,
178 password,
179 } => {
180 let params = vec![
181 serde_json::json!(hash160),
182 serde_json::json!(path),
183 serde_json::json!(message),
184 serde_json::json!(target),
185 serde_json::json!(recoverable),
186 serde_json::json!(password),
187 ];
188 (method::KEYSTORE_SIGN, params)
189 }
190 KeyStoreRequest::ExtendedPubkey {
191 hash160,
192 path,
193 password,
194 } => {
195 let params = vec![
196 serde_json::json!(hash160),
197 serde_json::json!(path),
198 serde_json::json!(password),
199 ];
200 (method::KEYSTORE_EXTENDED_PUBKEY, params)
201 }
202 KeyStoreRequest::DerivedKeySet {
203 hash160,
204 external_max_len,
205 change_last,
206 change_max_len,
207 password,
208 } => {
209 let params = vec![
210 serde_json::json!(hash160),
211 serde_json::json!(external_max_len),
212 serde_json::json!(change_last),
213 serde_json::json!(change_max_len),
214 serde_json::json!(password),
215 ];
216 (method::KEYSTORE_DERIVED_KEY_SET, params)
217 }
218 KeyStoreRequest::DerivedKeySetByIndex {
219 hash160,
220 external_start,
221 external_length,
222 change_start,
223 change_length,
224 password,
225 } => {
226 let params = vec![
227 serde_json::json!(hash160),
228 serde_json::json!(external_start),
229 serde_json::json!(external_length),
230 serde_json::json!(change_start),
231 serde_json::json!(change_length),
232 serde_json::json!(password),
233 ];
234 (method::KEYSTORE_DERIVED_KEY_SET_BY_INDEX, params)
235 }
236 KeyStoreRequest::Any(value) => (method::KEYSTORE_ANY, vec![value]),
237 }
238 }
239}
240impl TryFrom<&JsonrpcRequest> for KeyStoreRequest {
241 type Error = String;
242 fn try_from(data: &JsonrpcRequest) -> Result<KeyStoreRequest, Self::Error> {
243 let request = match data.method.as_str() {
244 method::KEYSTORE_LIST_ACCOUNT => KeyStoreRequest::ListAccount,
245 method::KEYSTORE_HAS_ACCOUNT => {
246 KeyStoreRequest::HasAccount(parse_param(data, 0, "hash160")?)
247 }
248 method::KEYSTORE_CREATE_ACCOUNT => {
249 KeyStoreRequest::CreateAccount(parse_param(data, 0, "password")?)
250 }
251 method::KEYSTORE_UPDATE_PASSWORD => KeyStoreRequest::UpdatePassword {
252 hash160: parse_param(data, 0, "hash160")?,
253 password: parse_param(data, 1, "hash160")?,
254 new_password: parse_param(data, 2, "hash160")?,
255 },
256 method::KEYSTORE_IMPORT => KeyStoreRequest::Import {
257 privkey: parse_h256(data, 0, "privkey")?,
258 chain_code: parse_h256(data, 1, "chain_code")?,
259 password: parse_param(data, 2, "password")?,
260 },
261 method::KEYSTORE_IMPORT_ACCOUNT => KeyStoreRequest::ImportAccount {
262 account_id: JsonBytes::from_vec(parse_bytes(data, 0, "account_id")?),
263 password: parse_param(data, 1, "password")?,
264 },
265 method::KEYSTORE_EXPORT => KeyStoreRequest::Export {
266 hash160: parse_param(data, 0, "hash160")?,
267 password: parse_param(data, 1, "password")?,
268 },
269 method::KEYSTORE_SIGN => KeyStoreRequest::Sign {
270 hash160: parse_param(data, 0, "hash160")?,
271 path: parse_param(data, 1, "path")?,
272 message: parse_param(data, 2, "message")?,
273 target: parse_param(data, 3, "target")?,
274 recoverable: parse_param(data, 4, "recoverable")?,
275 password: parse_param(data, 5, "password")?,
276 },
277 method::KEYSTORE_EXTENDED_PUBKEY => KeyStoreRequest::ExtendedPubkey {
278 hash160: parse_param(data, 0, "hash160")?,
279 path: parse_param(data, 1, "path")?,
280 password: parse_param(data, 2, "password")?,
281 },
282 method::KEYSTORE_DERIVED_KEY_SET => KeyStoreRequest::DerivedKeySet {
283 hash160: parse_param(data, 0, "hash160")?,
284 external_max_len: parse_param(data, 1, "external_max_len")?,
285 change_last: parse_param(data, 2, "change_last")?,
286 change_max_len: parse_param(data, 3, "change_max_len")?,
287 password: parse_param(data, 4, "password")?,
288 },
289 method::KEYSTORE_DERIVED_KEY_SET_BY_INDEX => KeyStoreRequest::DerivedKeySetByIndex {
290 hash160: parse_param(data, 0, "hash160")?,
291 external_start: parse_param(data, 1, "external_start")?,
292 external_length: parse_param(data, 2, "external_length")?,
293 change_start: parse_param(data, 3, "change_start")?,
294 change_length: parse_param(data, 4, "change_length")?,
295 password: parse_param(data, 5, "password")?,
296 },
297 method::KEYSTORE_ANY => KeyStoreRequest::Any(parse_param(data, 0, "value")?),
298 _ => {
299 return Err(format!("Invalid request method: {}", data.method));
300 }
301 };
302 Ok(request)
303 }
304}
305
306impl From<RpcRequest> for (&'static str, Vec<serde_json::Value>) {
307 fn from(request: RpcRequest) -> (&'static str, Vec<serde_json::Value>) {
308 match request {
309 RpcRequest::GetBlock { hash } => (method::RPC_GET_BLOCK, vec![serde_json::json!(hash)]),
310 RpcRequest::GetBlockByNumber { number } => (
311 method::RPC_GET_BLOCK_BY_NUMBER,
312 vec![serde_json::json!(number)],
313 ),
314 RpcRequest::GetBlockHash { number } => {
315 (method::RPC_GET_BLOCK_HASH, vec![serde_json::json!(number)])
316 }
317 }
318 }
319}
320impl TryFrom<&JsonrpcRequest> for RpcRequest {
321 type Error = String;
322 fn try_from(data: &JsonrpcRequest) -> Result<RpcRequest, Self::Error> {
323 let request = match data.method.as_str() {
324 method::RPC_GET_BLOCK => RpcRequest::GetBlock {
325 hash: parse_param(data, 0, "hash")?,
326 },
327 method::RPC_GET_BLOCK_BY_NUMBER => RpcRequest::GetBlockByNumber {
328 number: parse_param(data, 0, "number")?,
329 },
330 method::RPC_GET_BLOCK_HASH => RpcRequest::GetBlockHash {
331 number: parse_param(data, 0, "number")?,
332 },
333 _ => {
334 return Err(format!("Invalid request method: {}", data.method));
335 }
336 };
337 Ok(request)
338 }
339}
340
341impl From<IndexerRequest> for (&'static str, Vec<serde_json::Value>) {
342 fn from(request: IndexerRequest) -> (&'static str, Vec<serde_json::Value>) {
343 match request {
344 IndexerRequest::TipHeader => (method::INDEXER_TIP_HEADER, Vec::new()),
345 IndexerRequest::LastHeader => (method::INDEXER_LAST_HEADER, Vec::new()),
346 IndexerRequest::GetCapacity(lock_hash) => (
347 method::INDEXER_GET_CAPACITY,
348 vec![serde_json::json!(lock_hash)],
349 ),
350 IndexerRequest::LiveCells {
351 index,
352 hash,
353 from_number,
354 to_number,
355 limit,
356 } => {
357 let params = vec![
358 serde_json::json!(index.to_string()),
359 serde_json::json!(hash),
360 serde_json::json!(from_number),
361 serde_json::json!(to_number),
362 serde_json::json!(limit),
363 ];
364 (method::INDEXER_GET_LIVE_CELLS, params)
365 }
366 IndexerRequest::TopN(n) => (method::INDEXER_GET_TOPN, vec![serde_json::json!(n)]),
367 IndexerRequest::IndexerInfo => (method::INDEXER_GET_INDEXER_INFO, Vec::new()),
368 IndexerRequest::Any(value) => (method::INDEXER_ANY, vec![value]),
369 }
370 }
371}
372impl TryFrom<&JsonrpcRequest> for IndexerRequest {
373 type Error = String;
374 fn try_from(data: &JsonrpcRequest) -> Result<IndexerRequest, Self::Error> {
375 let request = match data.method.as_str() {
377 method::INDEXER_TIP_HEADER => IndexerRequest::TipHeader,
378 method::INDEXER_LAST_HEADER => IndexerRequest::LastHeader,
379 method::INDEXER_GET_CAPACITY => {
380 IndexerRequest::GetCapacity(parse_param(data, 1, "lock_hash")?)
381 }
382 method::INDEXER_GET_LIVE_CELLS => {
383 let index_string: String = parse_param(data, 1, "index-type")?;
384 let index = LiveCellIndexType::from_str(index_string.as_str())?;
385 IndexerRequest::LiveCells {
386 index,
387 hash: parse_param(data, 2, "hash")?,
388 from_number: parse_param(data, 3, "from_number")?,
389 to_number: parse_param(data, 4, "to_number")?,
390 limit: parse_param(data, 5, "limit")?,
391 }
392 }
393 method::INDEXER_GET_TOPN => IndexerRequest::TopN(parse_param(data, 1, "n")?),
394 method::INDEXER_GET_INDEXER_INFO => IndexerRequest::IndexerInfo,
395 method::INDEXER_ANY => IndexerRequest::Any(parse_param(data, 1, "value")?),
396 _ => {
397 return Err(format!("Invalid request method: {}", data.method));
398 }
399 };
400 Ok(request)
401 }
402}
403
404fn parse_param<T: DeserializeOwned>(
405 data: &JsonrpcRequest,
406 index: usize,
407 field_name: &str,
408) -> Result<T, String> {
409 data.params
410 .get(index)
411 .cloned()
412 .map(|value| {
413 let content: T = serde_json::from_value(value.clone()).map_err(|err| {
414 format!(
415 "Parse {}'s parameter(field={}, index={}) value: {:?}, failed: {}",
416 data.method, field_name, index, value, err
417 )
418 })?;
419 Ok(content)
420 })
421 .unwrap_or_else(|| {
422 Err(format!(
423 "Not enough parameter for {}, length: {}, expected: {}",
424 data.method,
425 data.params.len(),
426 index + 1
427 ))
428 })
429}
430
431fn parse_bytes(data: &JsonrpcRequest, index: usize, field: &str) -> Result<Vec<u8>, String> {
432 let hex: String = parse_param(data, index, field)?;
433 if !hex.starts_with("0x") || hex.len() % 2 == 1 {
434 return Err(format!(
435 "Field {} is not valid hex string, method={} (0x prefix is required)",
436 field, data.method
437 ));
438 }
439 let mut dst = vec![0u8; hex.len() / 2 - 1];
440 hex_decode(&hex.as_bytes()[2..], &mut dst).map_err(|err| err.to_string())?;
441 Ok(dst)
442}
443
444fn parse_h256(data: &JsonrpcRequest, index: usize, field: &str) -> Result<[u8; 32], String> {
445 let vec = parse_bytes(data, index, field)?;
446 if vec.len() != 32 {
447 return Err(format!(
448 "Invalid data length for field {}, method={}, expected 32bytes data hex string",
449 field, data.method
450 ));
451 }
452 let mut dst = [0u8; 32];
453 dst.copy_from_slice(&vec);
454 Ok(dst)
455}
456
457impl From<(u64, PluginResponse)> for JsonrpcResponse {
458 fn from((id, response): (u64, PluginResponse)) -> JsonrpcResponse {
459 let (result, error) = match response {
460 PluginResponse::Error(err) => (None, Some(err)),
461 response => (
462 Some(serde_json::to_value(response).expect("Serialize failed")),
463 None,
464 ),
465 };
466 JsonrpcResponse {
467 jsonrpc: JSONRPC_VERSION.to_string(),
468 id: serde_json::json!(id),
469 result,
470 error,
471 }
472 }
473}
474
475impl TryFrom<JsonrpcResponse> for (u64, PluginResponse) {
476 type Error = String;
477 fn try_from(data: JsonrpcResponse) -> Result<(u64, PluginResponse), Self::Error> {
478 if data.jsonrpc != JSONRPC_VERSION {
479 return Err(format!("Invalid jsonrpc field: {}", data.jsonrpc));
480 }
481 let request_id: u64 = serde_json::from_value(data.id)
482 .map_err(|err| format!("Request id must be integer number, error={}", err))?;
483 let response: PluginResponse = if let Some(result) = data.result {
484 serde_json::from_value(result)
485 .map_err(|err| format!("Deserialize response failed, error={}", err))?
486 } else if let Some(error) = data.error {
487 PluginResponse::Error(error)
488 } else {
489 return Err(String::from("Invalid jsonrpc response"));
490 };
491 Ok((request_id, response))
492 }
493}