1use serde::{Deserialize, Serialize};
10use validator::Validate;
11
12use crate::{
13 messages::send_transaction::SendTransactionConfig,
14 validation::{
15 validate_airdrop_amount_i64, validate_base58, validate_protocol_version, validate_pubkey,
16 validate_signature, validate_transaction_data,
17 },
18 GetBlockRequest, GetSignatureStatusesRequest,
19};
20
21#[derive(Debug, Deserialize, Serialize, Clone, Validate)]
23pub struct GetSubscriptionRequest {
24 #[serde(default)]
25 #[validate(custom(function = validate_protocol_version))]
26 pub version: u16,
27
28 #[validate(length(min = 1, message = "Subscriber pubkey cannot be empty"))]
29 #[validate(custom(function = validate_pubkey))]
30 pub subscriber: String,
31
32 #[serde(skip_serializing_if = "Option::is_none")]
33 pub nonce: Option<String>,
34}
35
36impl GetSubscriptionRequest {
37 pub fn new(subscriber: String, nonce: Option<String>) -> Self {
38 Self {
39 version: 0,
40 subscriber,
41 nonce,
42 }
43 }
44}
45
46#[derive(Debug, Deserialize, Serialize, Clone, Validate)]
48pub struct GetTriggeredTransactionsRequest {
49 #[serde(default)]
50 #[validate(custom(function = validate_protocol_version))]
51 pub version: u16,
52
53 #[validate(length(min = 1, message = "Subscription pubkey cannot be empty"))]
54 #[validate(custom(function = validate_pubkey))]
55 pub subscription_pubkey: String,
56
57 #[serde(skip_serializing_if = "Option::is_none")]
58 pub limit: Option<String>,
59}
60
61impl GetTriggeredTransactionsRequest {
62 pub fn new(subscription_pubkey: String, limit: Option<String>) -> Self {
63 Self {
64 version: 0,
65 subscription_pubkey,
66 limit,
67 }
68 }
69}
70
71#[derive(Debug, Deserialize, Serialize, Clone, Validate, PartialEq)]
73pub struct SendTransactionRequest {
74 #[validate(length(min = 1, message = "Transaction cannot be empty"))]
75 #[validate(custom(function = validate_transaction_data))]
76 pub transaction: String,
77
78 #[validate(nested)]
79 pub config: crate::messages::send_transaction::SendTransactionConfig,
80}
81
82impl SendTransactionRequest {
83 pub fn new(
84 transaction: String,
85 config: crate::messages::send_transaction::SendTransactionConfig,
86 ) -> Self {
87 Self {
88 transaction,
89 config,
90 }
91 }
92}
93
94#[derive(Debug, Deserialize, Serialize, Clone, Validate)]
96pub struct GetTransactionRequest {
97 #[validate(length(min = 1, message = "Signature cannot be empty"))]
98 #[validate(custom(function = validate_signature))]
99 pub signature: String,
100
101 #[serde(skip_serializing_if = "Option::is_none")]
102 pub config: Option<serde_json::Value>,
103}
104
105impl GetTransactionRequest {
106 pub fn new(signature: String, config: Option<serde_json::Value>) -> Self {
107 Self { signature, config }
108 }
109
110 pub fn new_simple(signature: String) -> Self {
111 Self {
112 signature,
113 config: Some(serde_json::json!({"encoding": "json"})),
114 }
115 }
116}
117
118#[derive(Debug, Deserialize, Serialize, Clone, Validate)]
120pub struct IsBlockhashValidRequest {
121 #[serde(default)]
122 #[validate(custom(function = validate_protocol_version))]
123 pub version: u16,
124
125 #[validate(length(min = 1, message = "Blockhash cannot be empty"))]
126 #[validate(custom(function = validate_base58))]
127 pub blockhash: String,
128}
129
130impl IsBlockhashValidRequest {
131 pub fn new(blockhash: String) -> Self {
132 Self {
133 version: 0,
134 blockhash,
135 }
136 }
137
138 pub fn new_simple(blockhash: String) -> Self {
139 Self {
140 version: 0,
141 blockhash,
142 }
143 }
144}
145
146#[derive(Debug, Deserialize, Serialize, Clone, Validate)]
148pub struct RequestAirdropRequest {
149 #[validate(length(min = 1, message = "Pubkey cannot be empty"))]
151 #[validate(custom(function = validate_pubkey))]
152 pub pubkey: String,
153
154 #[validate(custom(function = validate_airdrop_amount_i64))]
156 pub kelvins: i64,
157}
158
159impl RequestAirdropRequest {
160 pub fn new(pubkey: String, kelvins: i64) -> Self {
161 Self { pubkey, kelvins }
162 }
163}
164
165#[derive(Debug, Clone)]
167pub enum RpcRequestParams<T> {
168 Object(T),
170 Array(Vec<serde_json::Value>),
172}
173
174impl<T> RpcRequestParams<T>
175where
176 T: for<'de> serde::Deserialize<'de>,
177{
178 pub fn from_value(value: serde_json::Value) -> Result<Self, serde_json::Error> {
180 if value.is_array() {
181 let array = value.as_array().unwrap().clone();
182 Ok(RpcRequestParams::Array(array))
183 } else {
184 let object = serde_json::from_value::<T>(value)?;
185 Ok(RpcRequestParams::Object(object))
186 }
187 }
188
189 pub fn into_object(self) -> Result<T, Box<dyn std::error::Error + Send + Sync>> {
191 match self {
192 RpcRequestParams::Object(obj) => Ok(obj),
193 RpcRequestParams::Array(_array) => {
194 Err("Array format not supported for this request type".into())
196 }
197 }
198 }
199}
200
201pub trait FromArrayParams: Sized {
203 fn from_array_params(
205 params: &[serde_json::Value],
206 ) -> Result<Self, Box<dyn std::error::Error + Send + Sync>>;
207}
208
209impl FromArrayParams for GetSubscriptionRequest {
210 fn from_array_params(
211 params: &[serde_json::Value],
212 ) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
213 if params.is_empty() {
214 return Err("Missing subscriber parameter".into());
215 }
216
217 let subscriber = params[0]
218 .as_str()
219 .ok_or("Subscriber must be a string")?
220 .to_string();
221
222 let nonce = if let Some(nonce_param) = params.get(1) {
223 if nonce_param.is_null() {
224 None
225 } else if let Some(nonce_str) = nonce_param.as_str() {
226 Some(nonce_str.to_string())
227 } else {
228 return Err("Nonce must be a string".into());
229 }
230 } else {
231 None
232 };
233
234 Ok(GetSubscriptionRequest::new(subscriber, nonce))
235 }
236}
237
238impl FromArrayParams for GetTriggeredTransactionsRequest {
239 fn from_array_params(
240 params: &[serde_json::Value],
241 ) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
242 if params.is_empty() {
243 return Err("Missing subscription_pubkey parameter".into());
244 }
245
246 let subscription_pubkey = params[0]
247 .as_str()
248 .ok_or("Subscription pubkey is not a string")?
249 .to_string();
250
251 let limit = params
252 .get(1)
253 .and_then(|v| v.as_str())
254 .map(|s| s.to_string());
255
256 Ok(GetTriggeredTransactionsRequest::new(
257 subscription_pubkey,
258 limit,
259 ))
260 }
261}
262
263impl FromArrayParams for SendTransactionRequest {
264 fn from_array_params(
265 params: &[serde_json::Value],
266 ) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
267 if params.len() > 2 {
268 return Err(format!(
269 "Expected one or two request params, got {}",
270 params.len()
271 ))?;
272 }
273 let transaction = params
274 .first()
275 .ok_or_else(|| "Missing the transaction parameter".to_string())?
276 .as_str()
277 .ok_or("Transaction must be a string")?
278 .to_string();
279
280 let config = match params.get(1) {
281 Some(value) => serde_json::from_value::<SendTransactionConfig>(value.clone())
282 .map_err(|e| format!("Failed to parse config: {e}"))?,
283 None => SendTransactionConfig::default(),
284 };
285 Ok(SendTransactionRequest::new(transaction, config))
286 }
287}
288
289impl FromArrayParams for GetTransactionRequest {
290 fn from_array_params(
291 params: &[serde_json::Value],
292 ) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
293 if params.is_empty() {
294 return Err("Missing signature parameter".into());
295 }
296
297 let signature = params[0]
298 .as_str()
299 .ok_or("Signature must be a string")?
300 .to_string();
301
302 let config = if params.len() > 1 {
303 Some(params[1].clone())
304 } else {
305 None
306 };
307
308 Ok(GetTransactionRequest::new(signature, config))
309 }
310}
311
312impl FromArrayParams for IsBlockhashValidRequest {
313 fn from_array_params(
314 params: &[serde_json::Value],
315 ) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
316 if params.is_empty() {
317 return Err("Missing blockhash parameter".into());
318 }
319
320 let blockhash = params[0]
321 .as_str()
322 .ok_or("Blockhash must be a string")?
323 .to_string();
324
325 Ok(IsBlockhashValidRequest::new(blockhash))
326 }
327}
328
329impl FromArrayParams for RequestAirdropRequest {
330 fn from_array_params(
331 params: &[serde_json::Value],
332 ) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
333 if params.is_empty() {
334 return Err("Missing pubkey parameter".into());
335 }
336
337 if params.len() < 2 {
338 return Err("Missing kelvins parameter".into());
339 }
340
341 let pubkey = params[0]
342 .as_str()
343 .ok_or("Pubkey must be a string")?
344 .to_string();
345
346 let kelvins = params[1].as_i64().ok_or("Kelvins must be a number")?;
347
348 Ok(RequestAirdropRequest::new(pubkey, kelvins))
349 }
350}
351
352impl FromArrayParams for GetBlockRequest {
353 fn from_array_params(
354 params: &[serde_json::Value],
355 ) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
356 if params.is_empty() {
357 return Err("Missing the block height parameter".into());
358 }
359 if params.len() > 2 {
360 return Err("Too many parameters: expected either one or two".into());
361 }
362
363 if params.len() == 1 && params[0].is_object() {
364 return Ok(serde_json::from_value(params[0].clone())?);
365 }
366
367 let block_height = params[0]
368 .as_u64()
369 .ok_or("The first parameter must be the block height")?;
370
371 let config = match params.get(1) {
372 Some(value) => Some(
373 serde_json::from_value(value.clone())
374 .map_err(|e| format!("Failed to parse the config parameter: {e}"))?,
375 ),
376 None => None,
377 };
378
379 Ok(GetBlockRequest {
380 version: 0,
381 block_height,
382 config,
383 })
384 }
385}
386
387impl FromArrayParams for GetSignatureStatusesRequest {
388 fn from_array_params(
389 params: &[serde_json::Value],
390 ) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
391 if params.is_empty() {
392 return Err("Missing the signatures parameter".into());
393 }
394 if params.len() > 2 {
395 return Err("Too many parameters: expected either one or two".into());
396 }
397
398 if params.len() == 1 && params[0].is_object() {
399 return Ok(serde_json::from_value(params[0].clone())?);
400 }
401
402 let signatures: Vec<String> = serde_json::from_value(params[0].clone())
403 .map_err(|e| format!("Failed to parse the signatures parameter: {e}"))?;
404
405 let config = match params.get(1) {
406 Some(value) => Some(
407 serde_json::from_value(value.clone())
408 .map_err(|e| format!("Failed to parse the config parameter: {e}"))?,
409 ),
410 None => None,
411 };
412
413 Ok(GetSignatureStatusesRequest {
414 version: 0,
415 signatures,
416 config,
417 })
418 }
419}
420
421#[cfg(test)]
422mod tests {
423 use serde_json::{from_value, json, to_value};
424
425 use super::*;
426 use crate::messages::send_transaction::{SendTransactionConfig, TransactionEncoding};
427
428 #[test]
429 fn test_get_subscription_request_serialization() {
430 let request = GetSubscriptionRequest::new(
431 "84astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDVcgri".to_string(),
432 Some("test_nonce".to_string()),
433 );
434
435 let json = to_value(&request).unwrap();
436 assert_eq!(
437 json,
438 json!({
439 "version": 0,
440 "subscriber": "84astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDVcgri",
441 "nonce": "test_nonce"
442 })
443 );
444
445 let deserialized: GetSubscriptionRequest = from_value(json).unwrap();
446 assert_eq!(deserialized.version, 0);
447 assert_eq!(deserialized.subscriber, request.subscriber);
448 assert_eq!(deserialized.nonce, request.nonce);
449 }
450
451 #[test]
452 fn test_get_triggered_transactions_request_serialization() {
453 let request = GetTriggeredTransactionsRequest::new(
454 "84astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDVcgri".to_string(),
455 Some("10".to_string()),
456 );
457
458 let json = to_value(&request).unwrap();
459 assert_eq!(
460 json,
461 json!({
462 "version": 0,
463 "subscription_pubkey": "84astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDVcgri",
464 "limit": "10"
465 })
466 );
467
468 let deserialized: GetTriggeredTransactionsRequest = from_value(json).unwrap();
469 assert_eq!(deserialized.version, 0);
470 assert_eq!(
471 deserialized.subscription_pubkey,
472 request.subscription_pubkey
473 );
474 assert_eq!(deserialized.limit, request.limit);
475 }
476
477 #[test]
478 fn test_get_transaction_request_serialization() {
479 let request = GetTransactionRequest::new_simple("signature123".to_string());
480
481 let json = to_value(&request).unwrap();
482 assert_eq!(
483 json,
484 json!({
485 "signature": "signature123",
486 "config": {"encoding": "json"}
487 })
488 );
489
490 let deserialized: GetTransactionRequest = from_value(json).unwrap();
491 assert_eq!(deserialized.signature, request.signature);
492 }
493
494 #[test]
495 fn test_from_array_params_get_subscription() {
496 let params = vec![
497 json!("84astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDVcgri"),
498 json!("test_nonce"),
499 ];
500
501 let request = GetSubscriptionRequest::from_array_params(¶ms).unwrap();
502 assert_eq!(
503 request.subscriber,
504 "84astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDVcgri"
505 );
506 assert_eq!(request.nonce, Some("test_nonce".to_string()));
507 }
508
509 #[test]
510 fn test_from_array_params_get_subscription_invalid_nonce() {
511 let params = vec![
512 json!("84astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDVcgri"),
513 json!(123), ];
515
516 let result = GetSubscriptionRequest::from_array_params(¶ms);
517 assert!(result.is_err());
518 assert_eq!(result.unwrap_err().to_string(), "Nonce must be a string");
519 }
520
521 #[test]
522 fn test_from_array_params_get_triggered_transactions() {
523 let params = vec![
524 json!("84astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDVcgri"),
525 json!("5"),
526 ];
527
528 let request = GetTriggeredTransactionsRequest::from_array_params(¶ms).unwrap();
529 assert_eq!(
530 request.subscription_pubkey,
531 "84astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDVcgri"
532 );
533 assert_eq!(request.limit, Some("5".to_string()));
534 }
535
536 #[test]
537 fn test_from_array_params_get_transaction() {
538 let params = vec![json!("signature123"), json!({"encoding": "json"})];
539
540 let request = GetTransactionRequest::from_array_params(¶ms).unwrap();
541 assert_eq!(request.signature, "signature123");
542 assert!(request.config.is_some());
543 }
544
545 #[test]
546 fn test_from_array_params_is_blockhash_valid() {
547 let params = vec![json!("blockhash123")];
548
549 let request = IsBlockhashValidRequest::from_array_params(¶ms).unwrap();
550 assert_eq!(request.blockhash, "blockhash123");
551 }
552
553 #[test]
554 fn test_from_array_params_request_airdrop() {
555 let params = vec![
556 json!("83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcgri"),
557 json!(1000000),
558 ];
559
560 let request = RequestAirdropRequest::from_array_params(¶ms).unwrap();
561 assert_eq!(
562 request.pubkey,
563 "83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcgri"
564 );
565 assert_eq!(request.kelvins, 1000000);
566 }
567
568 #[test]
569 fn test_from_array_params_request_airdrop_missing_params() {
570 let params = vec![json!("83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcgri")];
571
572 let result = RequestAirdropRequest::from_array_params(¶ms);
573 assert!(result.is_err());
574 assert_eq!(result.unwrap_err().to_string(), "Missing kelvins parameter");
575 }
576
577 #[test]
578 fn test_from_array_params_request_airdrop_invalid_type() {
579 let params = vec![
580 json!("83astBRguLMdt2h5U1Tpdq5tjFoJ6noeGwaY3mDLVcgri"),
581 json!("thousand"), ];
583
584 let result = RequestAirdropRequest::from_array_params(¶ms);
585 assert!(result.is_err());
586 assert_eq!(result.unwrap_err().to_string(), "Kelvins must be a number");
587 }
588
589 #[test]
590 fn test_send_transaction_from_array_missing_optional_config() {
591 let encoded_tx = "4hXTCkRzt9WyecNzV1XPgCDfGAZzQKNxLXgynz5QDuWWPSAZBZSHptvWRL3BjCvzUXRdKvHL2b7yGrRQcWyaqsaBCncVG7BFggS8w9snUts67BSh3EqKpXLUm5UMHfD7ZBe9GhARjbNQMLJ1QD3Spr6oMTBU6EhdB4RD8CP2xUxr2u3d6fos36PD98XS6oX8TQjLpsMwncs5DAMiD4nNnR8NBfyghGCWvCVifVwvA8B8TJxE1aiyiv2L429BCWfyzAme5sZW8rDb14NeCQHhZbtNqfXhcp2tAnaAT";
592 let params = vec![json!(encoded_tx)];
593 assert_eq!(
594 SendTransactionRequest::from_array_params(¶ms)
595 .expect("failed to parse a transaction from params"),
596 SendTransactionRequest {
597 transaction: encoded_tx.to_string(),
598 config: SendTransactionConfig::default()
599 }
600 );
601 }
602
603 #[test]
604 fn test_send_transaction_from_array_default_config() {
605 let encoded_tx = "4hXTCkRzt9WyecNzV1XPgCDfGAZzQKNxLXgynz5QDuWWPSAZBZSHptvWRL3BjCvzUXRdKvHL2b7yGrRQcWyaqsaBCncVG7BFggS8w9snUts67BSh3EqKpXLUm5UMHfD7ZBe9GhARjbNQMLJ1QD3Spr6oMTBU6EhdB4RD8CP2xUxr2u3d6fos36PD98XS6oX8TQjLpsMwncs5DAMiD4nNnR8NBfyghGCWvCVifVwvA8B8TJxE1aiyiv2L429BCWfyzAme5sZW8rDb14NeCQHhZbtNqfXhcp2tAnaAT";
606 let params = vec![json!(encoded_tx), json!({})];
607 assert_eq!(
608 SendTransactionRequest::from_array_params(¶ms)
609 .expect("failed to parse a transaction from params"),
610 SendTransactionRequest {
611 transaction: encoded_tx.to_string(),
612 config: SendTransactionConfig::default(),
613 }
614 );
615 }
616
617 #[test]
618 fn test_send_transaction_from_array_config() {
619 let encoded_tx = "4hXTCkRzt9WyecNzV1XPgCDfGAZzQKNxLXgynz5QDuWWPSAZBZSHptvWRL3BjCvzUXRdKvHL2b7yGrRQcWyaqsaBCncVG7BFggS8w9snUts67BSh3EqKpXLUm5UMHfD7ZBe9GhARjbNQMLJ1QD3Spr6oMTBU6EhdB4RD8CP2xUxr2u3d6fos36PD98XS6oX8TQjLpsMwncs5DAMiD4nNnR8NBfyghGCWvCVifVwvA8B8TJxE1aiyiv2L429BCWfyzAme5sZW8rDb14NeCQHhZbtNqfXhcp2tAnaAT";
620 let params = vec![
621 json!(encoded_tx),
622 json!({
623 "encoding": "base58",
624 }),
625 ];
626 assert_eq!(
627 SendTransactionRequest::from_array_params(¶ms)
628 .expect("failed to parse a transaction from params"),
629 SendTransactionRequest {
630 transaction: encoded_tx.to_string(),
631 config: SendTransactionConfig::new(TransactionEncoding::Base58),
632 }
633 );
634 }
635
636 #[test]
637 fn test_send_transaction_from_array_too_many_params() {
638 let encoded_tx = "4hXTCkRzt9WyecNzV1XPgCDfGAZzQKNxLXgynz5QDuWWPSAZBZSHptvWRL3BjCvzUXRdKvHL2b7yGrRQcWyaqsaBCncVG7BFggS8w9snUts67BSh3EqKpXLUm5UMHfD7ZBe9GhARjbNQMLJ1QD3Spr6oMTBU6EhdB4RD8CP2xUxr2u3d6fos36PD98XS6oX8TQjLpsMwncs5DAMiD4nNnR8NBfyghGCWvCVifVwvA8B8TJxE1aiyiv2L429BCWfyzAme5sZW8rDb14NeCQHhZbtNqfXhcp2tAnaAT";
639 let params = vec![json!(encoded_tx), json!({}), json!({})];
640 SendTransactionRequest::from_array_params(¶ms).unwrap_err();
641 }
642
643 #[test]
644 fn test_from_array_params_get_block_basic() {
645 let params = vec![json!(123456)];
646
647 let request = GetBlockRequest::from_array_params(¶ms).unwrap();
648 assert_eq!(request.block_height, 123456);
649 assert!(request.config.is_none());
650 }
651
652 #[test]
653 fn test_from_array_params_get_block_with_config() {
654 let params = vec![
655 json!(123456),
656 json!({
657 "transactionDetails": "full"
658 }),
659 ];
660
661 let request = GetBlockRequest::from_array_params(¶ms).unwrap();
662 assert_eq!(request.block_height, 123456);
663 assert!(request.config.is_some());
664 }
665
666 #[test]
667 fn test_from_array_params_get_block_single_object() {
668 let params = vec![json!({
669 "version": 0,
670 "blockHeight": 789012,
671 "config": {
672 "transactionDetails": "signatures"
673 }
674 })];
675
676 let request = GetBlockRequest::from_array_params(¶ms).unwrap();
677 assert_eq!(request.block_height, 789012);
678 assert!(request.config.is_some());
679 }
680
681 #[test]
682 #[should_panic(expected = "block height")]
683 fn test_from_array_params_get_block_empty_params() {
684 GetBlockRequest::from_array_params(&[]).unwrap();
685 }
686
687 #[test]
688 #[should_panic(expected = "Too many parameters")]
689 fn test_from_array_params_get_block_too_many_params() {
690 GetBlockRequest::from_array_params(&[json!(123456), json!({}), json!({})]).unwrap();
691 }
692
693 #[test]
694 #[should_panic(expected = "block height")]
695 fn test_from_array_params_get_block_invalid_height_type() {
696 GetBlockRequest::from_array_params(&[json!("not_a_number")]).unwrap();
697 }
698
699 #[test]
700 #[should_panic(expected = "config parameter")]
701 fn test_from_array_params_get_block_invalid_config() {
702 GetBlockRequest::from_array_params(&[
703 json!(123456),
704 json!("invalid_config"), ])
706 .unwrap();
707 }
708
709 #[test]
710 #[should_panic(expected = "config parameter")]
711 fn test_from_array_params_get_block_null_config() {
712 GetBlockRequest::from_array_params(&[json!(123456), json!(null)]).unwrap();
713 }
714
715 #[test]
716 fn test_from_array_params_get_signature_statuses_basic() {
717 let signatures = vec![
718 "5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW",
719 "4hXTCkRzt9WyecNzV1XPgCDfGAZzQKNxLXgynz5QDuWWPSAZBZSHptvWRL3BjCvzUXRdKvHL2b7yGrRQcWyaqsaB"
720 ];
721 let params = vec![json!(signatures)];
722
723 let request = GetSignatureStatusesRequest::from_array_params(¶ms).unwrap();
724 assert_eq!(request.signatures, signatures);
725 assert!(request.config.is_none());
726 }
727
728 #[test]
729 fn test_from_array_params_get_signature_statuses_with_config() {
730 let signatures = vec![
731 "5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW"
732 ];
733 let config = json!({"searchTransactionHistory": true});
734 let params = vec![json!(signatures), config.clone()];
735
736 let request = GetSignatureStatusesRequest::from_array_params(¶ms).unwrap();
737 assert_eq!(request.signatures, signatures);
738 assert!(request.config.is_some());
739 }
740
741 #[test]
742 fn test_from_array_params_get_signature_statuses_single_object() {
743 let signatures = vec![
744 "5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW"
745 ];
746 let params = vec![json!({
747 "version": 0,
748 "signatures": signatures,
749 "config": {"searchTransactionHistory": false}
750 })];
751
752 let request = GetSignatureStatusesRequest::from_array_params(¶ms).unwrap();
753 assert_eq!(request.signatures, signatures);
754 assert!(request.config.is_some());
755 }
756
757 #[test]
758 fn test_from_array_params_get_signature_statuses_empty_signatures() {
759 let request = GetSignatureStatusesRequest::from_array_params(&[json!([])]).unwrap();
760 assert!(request.signatures.is_empty());
761 assert!(request.config.is_none());
762 }
763
764 #[test]
765 #[should_panic(expected = "Missing the signatures parameter")]
766 fn test_from_array_params_get_signature_statuses_empty_params() {
767 GetSignatureStatusesRequest::from_array_params(&[]).unwrap();
768 }
769
770 #[test]
771 #[should_panic(expected = "Too many parameters")]
772 fn test_from_array_params_get_signature_statuses_too_many_params() {
773 GetSignatureStatusesRequest::from_array_params(&[json!(["sig1"]), json!({}), json!({})])
774 .unwrap();
775 }
776
777 #[test]
778 #[should_panic(expected = "Failed to parse the signatures parameter")]
779 fn test_from_array_params_get_signature_statuses_invalid_signatures_type() {
780 GetSignatureStatusesRequest::from_array_params(&[json!("not an array")]).unwrap();
781 }
782
783 #[test]
784 #[should_panic(expected = "Failed to parse the config parameter")]
785 fn test_from_array_params_get_signature_statuses_invalid_config() {
786 GetSignatureStatusesRequest::from_array_params(&[
787 json!(["5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW"]),
788 json!("invalid config")
789 ]).unwrap();
790 }
791
792 #[test]
793 fn test_from_array_params_get_signature_statuses_multiple_signatures() {
794 let signatures: Vec<&str> = (0..100).map(|i| {
795 if i % 2 == 0 {
796 "5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW"
797 } else {
798 "4hXTCkRzt9WyecNzV1XPgCDfGAZzQKNxLXgynz5QDuWWPSAZBZSHptvWRL3BjCvzUXRdKvHL2b7yGrRQcWyaqsaB"
799 }
800 }).collect();
801 let params = vec![json!(signatures)];
802
803 let request = GetSignatureStatusesRequest::from_array_params(¶ms).unwrap();
804 assert_eq!(request.signatures.len(), 100);
805 assert!(request.config.is_none());
806 }
807
808 #[test]
809 #[should_panic(expected = "Failed to parse the config parameter")]
810 fn test_from_array_params_get_signature_statuses_null_config() {
811 GetSignatureStatusesRequest::from_array_params(&[
812 json!(["5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW"]),
813 json!(null)]
814 ).unwrap();
815 }
816}