1mod json_rpc_request;
2mod json_rpc_response;
3
4pub use json_rpc_request::{
5 DevnetSpecRequest, JsonRpcRequest, JsonRpcSubscriptionRequest, JsonRpcWsRequest,
6 StarknetSpecRequest, ToRpcResponseResult, WILDCARD_RPC_ERROR_CODE, to_json_rpc_request,
7};
8pub use json_rpc_response::{DevnetResponse, JsonRpcResponse, StarknetResponse};
9use serde::{Deserialize, Serialize};
10use starknet_rs_core::types::{Felt, Hash256, TransactionExecutionStatus};
11use starknet_types::contract_address::ContractAddress;
12use starknet_types::felt::{BlockHash, ClassHash, TransactionHash};
13use starknet_types::num_bigint::BigUint;
14use starknet_types::patricia_key::PatriciaKey;
15use starknet_types::rpc::block::{BlockId, SubscriptionBlockId};
16use starknet_types::rpc::messaging::{MessageToL1, MessageToL2};
17use starknet_types::rpc::transaction_receipt::FeeUnit;
18use starknet_types::rpc::transactions::{
19 BroadcastedDeclareTransaction, BroadcastedDeployAccountTransaction,
20 BroadcastedInvokeTransaction, BroadcastedTransaction, EventFilter, FunctionCall,
21 SimulationFlag, TransactionFinalityStatus,
22};
23use starknet_types::serde_helpers::dec_string::deserialize_biguint;
24use starknet_types::starknet_api::block::BlockNumber;
25
26use crate::rpc_core::request::RpcMethodCall;
27use crate::subscribe::{TransactionFinalityStatusWithoutL1, TransactionStatusWithoutL1};
28
29#[derive(Deserialize, Clone, Debug)]
30#[serde(deny_unknown_fields)]
31pub struct BlockIdInput {
32 pub block_id: BlockId,
33}
34
35#[derive(Deserialize, Clone, Debug)]
36#[serde(deny_unknown_fields)]
37pub struct TransactionHashInput {
38 pub transaction_hash: TransactionHash,
39}
40
41#[derive(Deserialize, Clone, Debug)]
42#[serde(deny_unknown_fields)]
43pub struct ClassHashInput {
44 pub class_hash: ClassHash,
45}
46
47#[derive(Deserialize, Clone, Debug)]
48#[serde(deny_unknown_fields)]
49#[cfg_attr(test, derive(PartialEq, Eq))]
50pub struct GetStorageInput {
51 pub contract_address: ContractAddress,
52 pub key: PatriciaKey,
53 pub block_id: BlockId,
54}
55
56#[derive(Deserialize, Clone, Debug)]
57pub struct ContractStorage {
58 pub contract_address: ContractAddress,
59 pub storage_keys: Vec<Felt>,
60}
61
62#[derive(Deserialize, Clone, Debug)]
63#[serde(deny_unknown_fields)]
64pub struct GetStorageProofInput {
65 pub block_id: BlockId,
66 pub class_hashes: Option<Vec<Felt>>,
67 pub contract_addresses: Option<Vec<ContractAddress>>,
68 pub contracts_storage_keys: Option<Vec<ContractStorage>>,
69}
70
71#[derive(Deserialize, Clone, Debug)]
72#[serde(deny_unknown_fields)]
73pub struct BlockAndIndexInput {
74 pub block_id: BlockId,
75 pub index: u64,
76}
77
78#[derive(Deserialize, Clone, Debug)]
79#[serde(deny_unknown_fields)]
80pub struct BlockAndClassHashInput {
81 pub block_id: BlockId,
82 pub class_hash: ClassHash,
83}
84
85#[derive(Deserialize, Clone, Debug)]
86#[serde(deny_unknown_fields)]
87pub struct BlockAndContractAddressInput {
88 pub block_id: BlockId,
89 pub contract_address: ContractAddress,
90}
91
92#[derive(Deserialize, Clone, Debug)]
93#[serde(deny_unknown_fields)]
94pub struct AccountAddressInput {
95 pub account_address: ContractAddress,
96}
97
98#[derive(Debug, Clone, Deserialize)]
99#[cfg_attr(test, derive(PartialEq, Eq))]
100#[serde(deny_unknown_fields)]
101pub struct CallInput {
102 pub request: FunctionCall,
103 pub block_id: BlockId,
104}
105
106#[derive(Debug, Clone, Deserialize)]
107#[serde(deny_unknown_fields)]
108pub struct EstimateFeeInput {
109 pub request: Vec<BroadcastedTransaction>,
110 pub simulation_flags: Vec<SimulationFlag>,
111 pub block_id: BlockId,
112}
113
114#[derive(Debug, Clone, Serialize)]
115#[cfg_attr(test, derive(Deserialize))]
116#[serde(deny_unknown_fields)]
117pub struct BlockHashAndNumberOutput {
118 pub block_hash: BlockHash,
119 pub block_number: BlockNumber,
120}
121
122#[derive(Debug, Clone, Serialize)]
123#[cfg_attr(test, derive(Deserialize))]
124#[serde(untagged)]
125pub enum SyncingOutput {
126 False(bool), }
128
129#[derive(Debug, Clone, Deserialize)]
130pub struct EventsInput {
131 pub filter: EventFilter,
132}
133
134#[derive(Deserialize, Debug, Clone)]
135#[serde(tag = "type")]
136pub enum BroadcastedDeclareTransactionEnumWrapper {
137 #[serde(rename = "DECLARE")]
138 Declare(BroadcastedDeclareTransaction),
139}
140
141#[derive(Debug, Clone, Deserialize)]
142#[serde(deny_unknown_fields)]
143pub struct BroadcastedDeclareTransactionInput {
144 pub declare_transaction: BroadcastedDeclareTransactionEnumWrapper,
145}
146
147#[derive(Debug, Clone, Serialize)]
148#[cfg_attr(test, derive(Deserialize))]
149#[serde(deny_unknown_fields)]
150pub struct DeclareTransactionOutput {
151 pub transaction_hash: TransactionHash,
152 pub class_hash: ClassHash,
153}
154
155#[derive(Deserialize, Debug, Clone)]
156#[serde(tag = "type")]
157pub enum BroadcastedDeployAccountTransactionEnumWrapper {
158 #[serde(rename = "DEPLOY_ACCOUNT")]
159 DeployAccount(BroadcastedDeployAccountTransaction),
160}
161
162#[derive(Debug, Clone, Deserialize)]
163#[serde(deny_unknown_fields)]
164pub struct BroadcastedDeployAccountTransactionInput {
165 pub deploy_account_transaction: BroadcastedDeployAccountTransactionEnumWrapper,
166}
167
168#[derive(Debug, Clone, Serialize)]
169#[cfg_attr(test, derive(Deserialize))]
170#[serde(deny_unknown_fields)]
171pub struct DeployAccountTransactionOutput {
172 pub transaction_hash: TransactionHash,
173 pub contract_address: ContractAddress,
174}
175
176#[derive(Deserialize, Debug, Clone)]
177#[serde(tag = "type", rename_all = "SCREAMING_SNAKE_CASE")]
178pub enum BroadcastedInvokeTransactionEnumWrapper {
179 Invoke(BroadcastedInvokeTransaction),
180}
181
182#[derive(Debug, Clone, Deserialize)]
183#[serde(deny_unknown_fields)]
184pub struct BroadcastedInvokeTransactionInput {
185 pub invoke_transaction: BroadcastedInvokeTransactionEnumWrapper,
186}
187
188#[derive(Debug, Clone, Serialize)]
189#[cfg_attr(test, derive(Deserialize))]
190#[serde(deny_unknown_fields)]
191pub struct TransactionHashOutput {
192 pub transaction_hash: TransactionHash,
193}
194
195#[derive(Debug, Clone, Deserialize)]
196#[serde(deny_unknown_fields)]
197pub struct SimulateTransactionsInput {
198 pub block_id: BlockId,
199 pub transactions: Vec<BroadcastedTransaction>,
200 pub simulation_flags: Vec<SimulationFlag>,
201}
202
203#[derive(Debug, Serialize)]
204#[cfg_attr(test, derive(Deserialize))]
205#[serde(deny_unknown_fields)]
206pub struct TransactionStatusOutput {
207 pub finality_status: TransactionFinalityStatus,
208 pub execution_status: TransactionExecutionStatus,
209}
210
211#[derive(Debug, Serialize, Deserialize)]
212#[serde(deny_unknown_fields)]
213pub struct L1TransactionHashInput {
214 pub transaction_hash: Hash256,
215}
216
217#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
218pub struct SubscriptionId(u64);
219
220impl From<u64> for SubscriptionId {
221 fn from(value: u64) -> Self {
222 Self(value)
223 }
224}
225
226impl Serialize for SubscriptionId {
227 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
228 where
229 S: serde::Serializer,
230 {
231 serializer.serialize_str(&self.0.to_string())
232 }
233}
234
235impl<'de> Deserialize<'de> for SubscriptionId {
237 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
238 where
239 D: serde::Deserializer<'de>,
240 {
241 let u64_as_string = String::deserialize(deserializer)?;
242 let subscription_id = u64_as_string.parse::<u64>().map_err(|_| {
243 serde::de::Error::invalid_type(serde::de::Unexpected::Str(&u64_as_string), &"u64")
244 })?;
245
246 Ok(SubscriptionId(subscription_id))
247 }
248}
249
250#[derive(Deserialize, Clone, Debug)]
251#[serde(deny_unknown_fields)]
252pub struct SubscriptionIdInput {
253 pub subscription_id: SubscriptionId,
254}
255
256#[derive(Deserialize, Clone, Debug)]
257#[serde(deny_unknown_fields)]
258pub struct SubscriptionBlockIdInput {
259 pub block_id: SubscriptionBlockId,
260}
261
262#[derive(Deserialize, Clone, Debug)]
263#[serde(deny_unknown_fields)]
264pub struct EventsSubscriptionInput {
265 pub block_id: Option<SubscriptionBlockId>,
266 pub from_address: Option<ContractAddress>,
267 pub keys: Option<Vec<Vec<Felt>>>,
268 pub finality_status: Option<TransactionFinalityStatus>,
269}
270
271#[derive(Deserialize, Clone, Debug)]
272#[serde(deny_unknown_fields)]
273pub struct TransactionSubscriptionInput {
274 pub sender_address: Option<Vec<ContractAddress>>,
275 pub finality_status: Option<Vec<TransactionStatusWithoutL1>>,
276}
277
278#[derive(Deserialize, Clone, Debug)]
279#[serde(deny_unknown_fields)]
280pub struct TransactionReceiptSubscriptionInput {
281 pub sender_address: Option<Vec<ContractAddress>>,
282 pub finality_status: Option<Vec<TransactionFinalityStatusWithoutL1>>,
283}
284
285#[derive(Deserialize)]
286#[serde(deny_unknown_fields)]
287#[cfg_attr(test, derive(Debug))]
288pub struct DumpPath {
289 pub path: String,
290}
291
292#[derive(Deserialize)]
293#[serde(deny_unknown_fields)]
294#[cfg_attr(test, derive(Debug))]
295pub struct LoadPath {
296 pub path: String,
297}
298
299#[derive(Deserialize)]
300#[serde(deny_unknown_fields)]
301#[cfg_attr(test, derive(Debug))]
302pub struct PostmanLoadL1MessagingContract {
303 pub network_url: String,
304 #[serde(alias = "address")]
305 pub messaging_contract_address: Option<String>,
306 pub deployer_account_private_key: Option<String>,
307}
308
309#[derive(Serialize)]
310pub struct MessageHash {
311 pub message_hash: Hash256,
312}
313
314pub type DumpResponseBody = Option<Vec<RpcMethodCall>>;
316
317#[derive(Serialize)]
318pub struct CreatedBlock {
319 pub block_hash: BlockHash,
320}
321
322#[derive(Deserialize)]
323#[serde(deny_unknown_fields)]
324#[cfg_attr(test, derive(Debug))]
325pub struct AbortingBlocks {
326 pub(crate) starting_block_id: BlockId,
327}
328
329#[derive(Serialize)]
330pub struct AbortedBlocks {
331 pub(crate) aborted: Vec<BlockHash>,
332}
333
334#[derive(Deserialize)]
335#[serde(deny_unknown_fields)]
336#[cfg_attr(test, derive(Debug))]
337pub struct AcceptOnL1Request {
338 pub(crate) starting_block_id: BlockId,
339}
340
341#[derive(Serialize)]
342pub struct AcceptedOnL1Blocks {
343 pub(crate) accepted: Vec<BlockHash>,
344}
345
346#[derive(Deserialize)]
347#[serde(deny_unknown_fields)]
348#[cfg_attr(test, derive(Debug))]
349pub struct IncreaseTime {
350 pub time: u64,
351}
352
353#[derive(Deserialize)]
354#[serde(deny_unknown_fields)]
355#[cfg_attr(test, derive(Debug))]
356pub struct SetTime {
357 pub time: u64,
358 pub generate_block: Option<bool>,
359}
360
361#[derive(Serialize)]
362pub struct SetTimeResponse {
363 pub block_timestamp: u64,
364 pub block_hash: Option<BlockHash>,
365}
366
367#[derive(Serialize)]
368pub struct IncreaseTimeResponse {
369 pub timestamp_increased_by: u64,
370 pub block_hash: BlockHash,
371}
372
373#[derive(Serialize)]
374pub struct SerializableAccount {
375 pub initial_balance: String,
376 pub address: ContractAddress,
377 pub public_key: Felt,
378 pub private_key: Felt,
379 pub balance: Option<AccountBalancesResponse>,
380}
381
382#[derive(Serialize)]
383pub struct AccountBalancesResponse {
384 pub eth: AccountBalanceResponse,
385 pub strk: AccountBalanceResponse,
386}
387
388#[derive(Serialize)]
389pub struct AccountBalanceResponse {
390 pub amount: String,
391 pub unit: FeeUnit,
392}
393
394#[derive(Serialize)]
395pub struct FeeToken {
396 symbol: String,
397 address: ContractAddress,
398}
399
400#[derive(Deserialize)]
401#[serde(deny_unknown_fields)]
402#[cfg_attr(test, derive(Debug))]
403pub struct MintTokensRequest {
404 pub address: ContractAddress,
405 #[serde(deserialize_with = "deserialize_biguint")]
406 pub amount: BigUint,
407 #[serde(skip_serializing_if = "Option::is_none")]
408 pub unit: Option<FeeUnit>,
409}
410
411#[derive(Serialize)]
412pub struct MintTokensResponse {
413 pub new_balance: String,
415 pub unit: FeeUnit,
416 pub tx_hash: TransactionHash,
417}
418
419#[derive(Serialize)]
420pub struct ForkStatus {
421 #[serde(skip_serializing_if = "Option::is_none")]
422 pub url: Option<String>,
423 #[serde(skip_serializing_if = "Option::is_none")]
424 pub block: Option<u64>,
425}
426
427#[derive(Serialize, Deserialize)]
428pub struct FlushedMessages {
429 pub messages_to_l1: Vec<MessageToL1>,
430 pub messages_to_l2: Vec<MessageToL2>,
431 pub generated_l2_transactions: Vec<TransactionHash>,
432 pub l1_provider: String,
433}
434
435#[derive(Serialize, Deserialize)]
436#[serde(deny_unknown_fields)]
437#[cfg_attr(test, derive(Debug))]
438pub struct FlushParameters {
439 pub dry_run: bool,
440}
441
442#[derive(Serialize, Deserialize)]
443pub struct MessagingLoadAddress {
444 pub messaging_contract_address: String,
445}
446
447#[derive(Serialize, Deserialize, Default)]
448#[serde(deny_unknown_fields)]
449#[cfg_attr(test, derive(Debug))]
450pub struct RestartParameters {
451 pub restart_l1_to_l2_messaging: bool,
452}
453#[cfg(test)]
454mod tests {
455 use starknet_rs_core::types::Felt;
456 use starknet_types::contract_address::ContractAddress;
457 use starknet_types::felt::felt_from_prefixed_hex;
458 use starknet_types::patricia_key::PatriciaKey;
459 use starknet_types::rpc::block::{BlockId, BlockTag};
460 use starknet_types::rpc::transactions::{
461 BroadcastedDeclareTransaction, BroadcastedTransaction,
462 };
463
464 use super::{BlockIdInput, EstimateFeeInput, GetStorageInput};
465 use crate::test_utils::{EXPECTED_INVALID_BLOCK_ID_MSG, assert_contains};
466
467 #[test]
468 fn errored_deserialization_of_estimate_fee_with_broadcasted_declare_transaction() {
469 let json_str = r#"{
471 "request": [{
472 "type": "DECLARE",
473 "version": "0x3",
474 "signature": ["0xFF", "0xAA"],
475 "nonce": "0x0",
476 "sender_address": "0x0001",
477 "resource_bounds": {
478 "l1_gas": {
479 "max_amount": "0x1",
480 "max_price_per_unit": "0x2"
481 },
482 "l1_data_gas": {
483 "max_amount": "0x1",
484 "max_price_per_unit": "0x2"
485 },
486 "l2_gas": {
487 "max_amount": "0x1",
488 "max_price_per_unit": "0x2"
489 }
490 },
491 "compiled_class_hash": "0x01",
492 "tip": "0xabc",
493 "paymaster_data": [],
494 "account_deployment_data": [],
495 "contract_class": {
496 "abi": [{
497 "inputs": [],
498 "name": "getPublicKey",
499 "outputs": [
500 {
501 "name": "publicKey",
502 "type": "felt"
503 }
504 ],
505 "stateMutability": "view",
506 "type": "function"
507 },
508 {
509 "inputs": [],
510 "name": "setPublicKey",
511 "outputs": [
512 {
513 "name": "publicKey",
514 "type": "felt"
515 }
516 ],
517 "type": "function"
518 }],
519 "program": "",
520 "entry_points_by_type": {}
521 },
522 "nonce_data_availability_mode": "L1",
523 "fee_data_availability_mode": "L1"
524 }],
525 "block_id": {
526 "block_number": 1
527 }
528 }"#;
529
530 match serde_json::from_str::<EstimateFeeInput>(json_str) {
531 Err(err) => assert_contains(
532 &err.to_string(),
533 "Invalid declare transaction v3: missing field `state_mutability`",
535 )
536 .unwrap(),
537 other => panic!("Invalid result: {other:?}"),
538 }
539 }
540
541 #[test]
542 fn deserialize_estimate_fee_input() {
543 let json_str = r#"{
544 "request": [
545 {
546 "type": "DECLARE",
547 "version": "0x3",
548 "signature": ["0xFF", "0xAA"],
549 "nonce": "0x0",
550 "sender_address": "0x0001",
551 "resource_bounds": {
552 "l1_gas": {
553 "max_amount": "0x1",
554 "max_price_per_unit": "0x2"
555 },
556 "l1_data_gas": {
557 "max_amount": "0x1",
558 "max_price_per_unit": "0x2"
559 },
560 "l2_gas": {
561 "max_amount": "0x1",
562 "max_price_per_unit": "0x2"
563 }
564 },
565 "compiled_class_hash": "0x01",
566 "tip": "0xabc",
567 "paymaster_data": [],
568 "account_deployment_data": [],
569 "contract_class": {
570 "sierra_program": ["0xAA", "0xBB"],
571 "contract_class_version": "1.0",
572 "entry_points_by_type": {
573 "EXTERNAL": [
574 {
575 "selector": "0x3c118a68e16e12e97ed25cb4901c12f4d3162818669cc44c391d8049924c14",
576 "function_idx": 4
577 },
578 {
579 "selector": "0xe7510edcf6e9f1b70f7bd1f488767b50f0363422f3c563160ab77adf62467b",
580 "function_idx": 7
581 }
582 ],
583 "L1_HANDLER": [
584 {
585 "selector": "0x39edbbb129ad752107a94d40c3873cae369a46fd2fc578d075679aa67e85d12",
586 "function_idx": 11
587 }
588 ],
589 "CONSTRUCTOR": [
590 {
591 "selector": "0x28ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194",
592 "function_idx": 12
593 }
594 ]
595 },
596 "abi": [
597 {
598 "type": "constructor",
599 "name": "constructor",
600 "inputs": [
601 {
602 "name": "arg1",
603 "type": "core::felt252"
604 },
605 {
606 "name": "arg2",
607 "type": "core::felt252"
608 }
609 ]
610 }
611 ]
612 },
613 "nonce_data_availability_mode": "L1",
614 "fee_data_availability_mode": "L1"
615 },
616 {
617 "type": "INVOKE",
618 "resource_bounds": {
619 "l1_gas": {
620 "max_amount": "0x1",
621 "max_price_per_unit": "0x2"
622 },
623 "l1_data_gas": {
624 "max_amount": "0x1",
625 "max_price_per_unit": "0x2"
626 },
627 "l2_gas": {
628 "max_amount": "0x1",
629 "max_price_per_unit": "0x2"
630 }
631 },
632 "tip": "0xabc",
633 "paymaster_data": [],
634 "account_deployment_data": [],
635 "version": "0x100000000000000000000000000000003",
636 "signature": ["0x2"],
637 "nonce": "0x1",
638 "sender_address": "0x3",
639 "calldata": [
640 "0x1",
641 "0x2",
642 "0x3"
643 ],
644 "nonce_data_availability_mode": "L1",
645 "fee_data_availability_mode": "L1"
646 },
647 {
648 "type":"DEPLOY_ACCOUNT",
649 "resource_bounds": {
650 "l1_gas": {
651 "max_amount": "0x1",
652 "max_price_per_unit": "0x2"
653 },
654 "l1_data_gas": {
655 "max_amount": "0x1",
656 "max_price_per_unit": "0x2"
657 },
658 "l2_gas": {
659 "max_amount": "0x1",
660 "max_price_per_unit": "0x2"
661 }
662 },
663 "tip": "0xabc",
664 "paymaster_data": [],
665 "version": "0x100000000000000000000000000000003",
666 "signature": ["0xFF", "0xAA"],
667 "nonce": "0x0",
668 "contract_address_salt": "0x01",
669 "class_hash": "0x01",
670 "constructor_calldata": ["0x01"],
671 "nonce_data_availability_mode": "L1",
672 "fee_data_availability_mode": "L1"
673 }
674 ],
675 "block_id": {
676 "block_number": 1
677 },
678 "simulation_flags": []
679 }"#;
680
681 let estimate_fee_input = serde_json::from_str::<super::EstimateFeeInput>(json_str).unwrap();
682 assert_eq!(estimate_fee_input.block_id, BlockId::Number(1));
683 assert_eq!(estimate_fee_input.request.len(), 3);
684 assert!(matches!(
685 estimate_fee_input.request[0],
686 BroadcastedTransaction::Declare(BroadcastedDeclareTransaction::V3(_))
687 ));
688 assert!(matches!(estimate_fee_input.request[1], BroadcastedTransaction::Invoke(_)));
689 assert!(matches!(estimate_fee_input.request[2], BroadcastedTransaction::DeployAccount(_)));
690 }
691
692 #[test]
693 fn deserialize_call_input() {
694 let json_str = r#"{"request": {"contract_address": "0x01", "entry_point_selector": "0x02", "calldata": ["0x03"]}, "block_id": {"block_number": 1}}"#;
695 let call_input = serde_json::from_str::<super::CallInput>(json_str).unwrap();
696
697 assert_eq!(
698 call_input,
699 super::CallInput {
700 request: super::FunctionCall {
701 contract_address: ContractAddress::new(Felt::ONE).unwrap(),
702 entry_point_selector: Felt::TWO,
703 calldata: vec![Felt::THREE],
704 },
705 block_id: BlockId::Number(1),
706 }
707 );
708 }
709
710 #[test]
711 fn deserialize_get_storage_input() {
712 fn assert_get_storage_input_correctness(
713 should_be_correct: bool,
714 expected_storage_input: GetStorageInput,
715 json_str: &str,
716 ) {
717 let is_correct =
718 if let Ok(get_storage_input) = serde_json::from_str::<GetStorageInput>(json_str) {
719 get_storage_input == expected_storage_input
720 } else {
721 false
722 };
723
724 assert_eq!(should_be_correct, is_correct);
725 }
726
727 let expected_storage_input = GetStorageInput {
728 block_id: BlockId::Hash(Felt::ONE),
729 contract_address: ContractAddress::new(Felt::TWO).unwrap(),
730 key: PatriciaKey::new(Felt::THREE).unwrap(),
731 };
732
733 assert_get_storage_input_correctness(
734 true,
735 expected_storage_input.clone(),
736 r#"{"block_id": {"block_hash": "0x01"}, "contract_address": "0x02", "key": "0x03"}"#,
737 );
738
739 assert_get_storage_input_correctness(
741 false,
742 expected_storage_input.clone(),
743 r#"{"block_id": {"block_hash": "0x01"}, "contract_address_mock": "0x02", "key": "0x03"}"#,
744 );
745
746 assert_get_storage_input_correctness(
748 false,
749 expected_storage_input,
750 r#"{"block_id": {"block_hash": "0x01"}, "contract_address": "0x02", "keyy": "0x03"}"#,
751 );
752 }
753
754 #[test]
756 fn deserialize_transaction_hash_input() {
757 assert_transaction_hash_correctness(true, "0x01", r#"{"transaction_hash": "0x01"}"#);
758
759 assert_transaction_hash_correctness(false, "0x01", r#"{"transaction_hashh": "0x01"}"#);
761
762 assert_transaction_hash_correctness(false, "0x02", r#"{"transaction_hash": "0x01"}"#);
764
765 assert_transaction_hash_correctness(false, "0x02", r#"{"transaction_hash": "01"}"#);
767 }
768 #[test]
769 fn deserialize_block_id_tag_variants() {
770 assert_block_id_tag_correctness(true, BlockTag::Latest, r#"{"block_id": "latest"}"#);
771 assert_block_id_tag_correctness(
772 true,
773 BlockTag::PreConfirmed,
774 r#"{"block_id": "pre_confirmed"}"#,
775 );
776
777 assert_block_id_tag_correctness(false, BlockTag::Latest, r#"{"block_id": "latestx"}"#);
779 assert_block_id_tag_correctness(false, BlockTag::Latest, r#"{"block_id": "pending"}"#);
780 assert_block_id_tag_correctness(
781 false,
782 BlockTag::PreConfirmed,
783 r#"{"block_id": "pre_confirmed_d"}"#,
784 );
785
786 assert_block_id_tag_correctness(false, BlockTag::Latest, r#"{"block": "latest"}"#);
788 assert_block_id_tag_correctness(false, BlockTag::PreConfirmed, r#"{"block": "pending"}"#);
789 assert_block_id_tag_correctness(
790 false,
791 BlockTag::PreConfirmed,
792 r#"{"block": "pre_confirmed"}"#,
793 );
794 }
795
796 #[test]
797 fn deserialize_block_id_block_hash_variants() {
798 assert_block_id_block_hash_correctness(
799 true,
800 "0x01",
801 r#"{"block_id": {"block_hash": "0x01"}}"#,
802 );
803
804 assert_block_id_block_hash_correctness(
806 false,
807 "0x01",
808 r#"{"block": {"block_hash": "0x01"}}"#,
809 );
810
811 assert_block_id_block_hash_correctness(
813 false,
814 "0x01",
815 r#"{"block_id": {"block_hasha": "0x01"}}"#,
816 );
817
818 assert_block_id_block_hash_correctness(
820 false,
821 "0x02",
822 r#"{"block_id": {"block_hash": "0x01"}}"#,
823 );
824
825 assert_block_id_block_hash_correctness(
827 false,
828 "0x01",
829 r#"{"block_id": {"block_hash": "0x004134134134134134134134134134134134134134134134134134134134134134"}}"#,
830 );
831
832 assert_block_id_block_hash_correctness(
834 false,
835 "0x01",
836 r#"{"block_id": {"block_hash": "01"}}"#,
837 );
838 }
839
840 #[test]
841 fn deserialize_block_id_block_number_variants() {
842 assert_block_id_block_number_correctness(true, 10, r#"{"block_id": {"block_number": 10}}"#);
843
844 assert_block_id_block_number_correctness(false, 10, r#"{"block": {"block_number": 10}}"#);
846
847 assert_block_id_block_number_correctness(
849 false,
850 10,
851 r#"{"block_id": {"block_number_mock": 10}}"#,
852 );
853
854 assert_block_id_block_number_correctness(
856 false,
857 10,
858 r#"{"block_id": {"block_number": "0x01"}}"#,
859 );
860 }
861
862 #[test]
863 fn assert_error_message_for_failed_block_id_deserialization() {
864 for json_str in [
865 r#"{"block_id": {"block_number": 10, "block_hash": "0x1"}}"#,
866 r#"{"block_id": {"block_number": "123"}}"#,
867 r#"{"block_id": {"block_number": -123}}"#,
868 r#"{"block_id": {"invalid_key": ""}}"#,
869 r#"{"block_id": {"block_hash": 123}}"#,
870 r#"{"block_id": {"block_hash": ""}}"#,
871 ] {
872 match serde_json::from_str::<BlockIdInput>(json_str) {
873 Err(e) => assert_contains(&e.to_string(), EXPECTED_INVALID_BLOCK_ID_MSG).unwrap(),
874 other => panic!("Invalid result: {other:?}"),
875 }
876 }
877 }
878
879 fn assert_block_id_tag_correctness(
880 should_be_correct: bool,
881 expected_tag: BlockTag,
882 json_str_block_id: &str,
883 ) {
884 let is_correct =
885 serde_json::from_str::<BlockIdInput>(json_str_block_id)
886 .map(|BlockIdInput { block_id }| matches!(block_id, BlockId::Tag(generated_tag) if generated_tag == expected_tag))
887 .unwrap_or(false);
888
889 assert_eq!(should_be_correct, is_correct);
890 }
891
892 fn assert_block_id_block_number_correctness(
893 should_be_correct: bool,
894 expected_block_number: u64,
895 json_str_block_id: &str,
896 ) {
897 let is_correct =
898 serde_json::from_str::<BlockIdInput>(json_str_block_id)
899 .map(
900 |BlockIdInput { block_id }|
901 matches!(block_id,
902 BlockId::Number(generated_block_number) if generated_block_number == expected_block_number)
903 ).unwrap_or(false);
904
905 assert_eq!(should_be_correct, is_correct);
906 }
907
908 fn assert_block_id_block_hash_correctness(
909 should_be_correct: bool,
910 expected_block_hash: &str,
911 json_str_block_id: &str,
912 ) {
913 let is_correct =
914 serde_json::from_str::<BlockIdInput>(json_str_block_id)
915 .map(|BlockIdInput { block_id }| matches!(block_id, BlockId::Hash(generated_block_hash) if generated_block_hash == felt_from_prefixed_hex(expected_block_hash).unwrap()))
916 .unwrap_or(false);
917
918 assert_eq!(should_be_correct, is_correct)
919 }
920
921 fn assert_transaction_hash_correctness(
922 should_be_correct: bool,
923 expected_transaction_hash: &str,
924 json_str_transaction_hash: &str,
925 ) {
926 let is_correct = if let Ok(transaction_hash_input) =
927 serde_json::from_str::<super::TransactionHashInput>(json_str_transaction_hash)
928 {
929 transaction_hash_input.transaction_hash
930 == felt_from_prefixed_hex(expected_transaction_hash).unwrap()
931 } else {
932 false
933 };
934
935 assert_eq!(should_be_correct, is_correct);
936 }
937}