// file: crates/ksp-onchain-transport-lib/tests/release_completeness.rs // version: 21 //! Release-level completeness canaries for the staged HTTP wrapper sequence. #[test] fn release_registry_partition_matches_the_audited_http_plan() { let mut foundation = 0_usize; let mut accounts_tokens_cluster = 0_usize; let mut transactions = 0_usize; let mut blocks_economics = 0_usize; let mut historical_in_current = 0_usize; for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() { match descriptor.coverage_release() { ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_1 => foundation += 1, ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_2 => accounts_tokens_cluster += 1, ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3 => transactions += 1, ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_4 => blocks_economics += 1, ksp_onchain_transport_lib::HttpRpcCoverageRelease::Historical => historical_in_current += 1, } } assert_eq!(ksp_onchain_transport_lib::current_http_rpc_methods().len(), 52); assert_eq!(ksp_onchain_transport_lib::historical_http_rpc_methods().len(), 14); assert_eq!(foundation, 4); assert_eq!(accounts_tokens_cluster, 22); assert_eq!(transactions, 11); assert_eq!(blocks_economics, 15); assert_eq!(historical_in_current, 0); } #[test] fn release_foundation_canaries_and_historical_statuses_are_exact() { let mut foundation_names = std::vec::Vec::<&str>::new(); for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() { if descriptor.coverage_release() == ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_1 { foundation_names.push(descriptor.method()); assert_eq!(descriptor.runtime_status(), ksp_onchain_transport_lib::RpcRuntimeStatus::Supported); } } foundation_names.sort_unstable(); assert_eq!(foundation_names, std::vec!["getBalance", "getGenesisHash", "getHealth", "getVersion"]); for descriptor in ksp_onchain_transport_lib::historical_http_rpc_methods() { assert_eq!(descriptor.documentation_status(), ksp_onchain_transport_lib::RpcDocumentationStatus::Deprecated); assert_eq!(descriptor.runtime_status(), ksp_onchain_transport_lib::RpcRuntimeStatus::Removed); assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::Historical); assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::NotApplicable); } } #[test] fn release_pre_003_accounts_subset_is_exact_without_advancing_other_v0_2_2_families() { let mut account_names = std::vec::Vec::<&str>::new(); for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() { if descriptor.coverage_release() == ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_2 && descriptor.category() == ksp_onchain_transport_lib::HttpRpcCategory::Accounts { account_names.push(descriptor.method()); assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read); assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe); } } account_names.sort_unstable(); assert_eq!( account_names, std::vec!["getAccountInfo", "getLargestAccounts", "getMinimumBalanceForRentExemption", "getMultipleAccounts", "getProgramAccounts",], ); } #[test] fn release_pre_004_tokens_subset_is_exact_and_retry_safe() { let mut token_names = std::vec::Vec::<&str>::new(); for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() { if descriptor.coverage_release() == ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_2 && descriptor.category() == ksp_onchain_transport_lib::HttpRpcCategory::Tokens { token_names.push(descriptor.method()); assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read); assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe); } } token_names.sort_unstable(); assert_eq!( token_names, std::vec!["getTokenAccountBalance", "getTokenAccountsByDelegate", "getTokenAccountsByOwner", "getTokenLargestAccounts", "getTokenSupply",], ); } #[test] fn release_pre_005_simple_cluster_subset_is_exact_and_retry_safe() { let expected = std::vec![ "getClusterNodes", "getEpochInfo", "getEpochSchedule", "getHighestSnapshotSlot", "getIdentity", "getMaxRetransmitSlot", "getMaxShredInsertSlot", ]; let deferred = std::vec!["getLeaderSchedule", "getSlot", "getSlotLeader", "getSlotLeaders", "getVoteAccounts"]; for method_name in &expected { let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.005 cluster descriptor must exist"); assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Cluster); assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_2); assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read); assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe); } for method_name in &deferred { let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.006 cluster descriptor must remain registered"); assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_2); } assert_eq!(expected.len(), 7); assert_eq!(deferred.len(), 5); } #[test] fn release_pre_006_completes_cluster_subset_exactly_and_retry_safe() { let mut expected = std::vec![ "getClusterNodes", "getEpochInfo", "getEpochSchedule", "getHighestSnapshotSlot", "getIdentity", "getLeaderSchedule", "getMaxRetransmitSlot", "getMaxShredInsertSlot", "getSlot", "getSlotLeader", "getSlotLeaders", "getVoteAccounts", ]; let mut actual = std::vec::Vec::new(); for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() { if descriptor.coverage_release() == ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_2 && descriptor.category() == ksp_onchain_transport_lib::HttpRpcCategory::Cluster { actual.push(descriptor.method()); assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read); assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe); } } actual.sort_unstable(); expected.sort_unstable(); assert_eq!(actual, expected); assert_eq!(actual.len(), 12); } #[test] fn release_pre_007_v0_2_2_exact_set_is_complete_without_advancing_future_releases() { let mut expected = std::vec![ "getAccountInfo", "getClusterNodes", "getEpochInfo", "getEpochSchedule", "getHighestSnapshotSlot", "getIdentity", "getLargestAccounts", "getLeaderSchedule", "getMaxRetransmitSlot", "getMaxShredInsertSlot", "getMinimumBalanceForRentExemption", "getMultipleAccounts", "getProgramAccounts", "getSlot", "getSlotLeader", "getSlotLeaders", "getTokenAccountBalance", "getTokenAccountsByDelegate", "getTokenAccountsByOwner", "getTokenLargestAccounts", "getTokenSupply", "getVoteAccounts", ]; let mut actual = std::vec::Vec::new(); let mut future_transactions = 0_usize; let mut future_blocks_economics = 0_usize; for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() { match descriptor.coverage_release() { ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_2 => { actual.push(descriptor.method()); assert_eq!(descriptor.documentation_status(), ksp_onchain_transport_lib::RpcDocumentationStatus::Stable); assert_eq!(descriptor.runtime_status(), ksp_onchain_transport_lib::RpcRuntimeStatus::Supported); assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read); assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe); }, ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3 => future_transactions += 1, ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_4 => future_blocks_economics += 1, _ => {}, } } actual.sort_unstable(); expected.sort_unstable(); assert_eq!(actual, expected); assert_eq!(actual.len(), 22); assert_eq!(future_transactions, 11); assert_eq!(future_blocks_economics, 15); } #[test] fn release_v0_2_3_descriptor_set_and_safety_classes_are_exact() { let mut expected = std::vec![ "getFeeForMessage", "getLatestBlockhash", "getRecentPrioritizationFees", "getSignaturesForAddress", "getSignatureStatuses", "getTransaction", "getTransactionCount", "isBlockhashValid", "requestAirdrop", "sendTransaction", "simulateTransaction", ]; let mut actual = std::vec::Vec::new(); let mut reads = 0_usize; let mut writes = 0_usize; let mut simulations = 0_usize; for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() { if descriptor.coverage_release() != ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3 { continue; } actual.push(descriptor.method()); match descriptor.operation_kind() { ksp_onchain_transport_lib::RpcOperationKind::Read => { reads += 1; assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe); }, ksp_onchain_transport_lib::RpcOperationKind::WriteSubmission => { writes += 1; assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::NeverAfterDispatch); }, ksp_onchain_transport_lib::RpcOperationKind::Simulation => { simulations += 1; assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe); }, } } actual.sort_unstable(); expected.sort_unstable(); assert_eq!(actual, expected); assert_eq!(reads, 8); assert_eq!(writes, 2); assert_eq!(simulations, 1); } #[test] fn release_pre_003_transaction_read_subset_is_exact_and_retry_safe() { let mut expected = std::vec!["getFeeForMessage", "getLatestBlockhash", "getTransactionCount", "isBlockhashValid"]; let mut actual = std::vec::Vec::new(); for method_name in &expected { let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.003 Transaction descriptor must exist"); actual.push(descriptor.method()); assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Transactions); assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3); assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read); assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe); } actual.sort_unstable(); expected.sort_unstable(); assert_eq!(actual, expected); assert_eq!(actual.len(), 4); } #[test] fn release_pre_004_transaction_read_subset_is_exact_and_retry_safe() { let mut expected = std::vec![ "getFeeForMessage", "getLatestBlockhash", "getRecentPrioritizationFees", "getSignaturesForAddress", "getSignatureStatuses", "getTransactionCount", "isBlockhashValid", ]; let deferred = std::vec!["getTransaction", "requestAirdrop", "sendTransaction", "simulateTransaction"]; let mut actual = std::vec::Vec::new(); for method_name in &expected { let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.004 Transaction descriptor must exist"); actual.push(descriptor.method()); assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Transactions); assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3); assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read); assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe); } for method_name in &deferred { let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("deferred Transaction descriptor must remain registered"); assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3); } actual.sort_unstable(); expected.sort_unstable(); assert_eq!(actual, expected); assert_eq!(actual.len(), 7); assert_eq!(deferred.len(), 4); } #[test] fn release_pre_005_transaction_read_subset_adds_complete_get_transaction_without_advancing_writes_or_simulation() { let mut expected = std::vec![ "getFeeForMessage", "getLatestBlockhash", "getRecentPrioritizationFees", "getSignaturesForAddress", "getSignatureStatuses", "getTransaction", "getTransactionCount", "isBlockhashValid", ]; let deferred = std::vec!["requestAirdrop", "sendTransaction", "simulateTransaction"]; let mut actual = std::vec::Vec::new(); for method_name in &expected { let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.005 Transaction descriptor must exist"); actual.push(descriptor.method()); assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Transactions); assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3); assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read); assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe); } let get_transaction = ksp_onchain_transport_lib::find_http_rpc_method("getTransaction").expect("getTransaction descriptor must exist"); assert!(get_transaction.request_form_status().has_deprecated_legacy()); for method_name in &deferred { let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("deferred Transaction descriptor must remain registered"); assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3); } actual.sort_unstable(); expected.sort_unstable(); assert_eq!(actual, expected); assert_eq!(actual.len(), 8); assert_eq!(deferred.len(), 3); } #[test] fn release_pre_006_transaction_subset_adds_both_write_submissions_without_advancing_simulation() { let reads = std::vec![ "getFeeForMessage", "getLatestBlockhash", "getRecentPrioritizationFees", "getSignaturesForAddress", "getSignatureStatuses", "getTransaction", "getTransactionCount", "isBlockhashValid", ]; let writes = std::vec!["requestAirdrop", "sendTransaction"]; for method_name in &reads { let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.006 read descriptor must exist"); assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Transactions); assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3); assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read); assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe); } for method_name in &writes { let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.006 write descriptor must exist"); assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Transactions); assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3); assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::WriteSubmission); assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::NeverAfterDispatch); } let simulation = ksp_onchain_transport_lib::find_http_rpc_method("simulateTransaction").expect("simulation descriptor must remain registered"); assert_eq!(simulation.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Simulation); assert_eq!(reads.len(), 8); assert_eq!(writes.len(), 2); } #[test] fn release_pre_007_completes_all_v0_2_3_transaction_wrappers_with_exact_safety_classes() { let reads = std::vec![ "getFeeForMessage", "getLatestBlockhash", "getRecentPrioritizationFees", "getSignaturesForAddress", "getSignatureStatuses", "getTransaction", "getTransactionCount", "isBlockhashValid", ]; let writes = std::vec!["requestAirdrop", "sendTransaction"]; let simulations = std::vec!["simulateTransaction"]; for method_name in &reads { let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.007 read descriptor must exist"); assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Transactions); assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3); assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read); assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe); } for method_name in &writes { let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.007 write descriptor must exist"); assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Transactions); assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3); assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::WriteSubmission); assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::NeverAfterDispatch); } for method_name in &simulations { let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method_name).expect("pre.007 simulation descriptor must exist"); assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Transactions); assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3); assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Simulation); assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe); } assert_eq!(reads.len(), 8); assert_eq!(writes.len(), 2); assert_eq!(simulations.len(), 1); assert_eq!(reads.len() + writes.len() + simulations.len(), 11); } #[test] fn release_pre_008_ksp_transport_007_retro_audit_covers_all_typed_current_methods() { let mut audited = std::vec::Vec::<&str>::new(); for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() { if matches!( descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_1 | ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_2 | ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3 ) { audited.push(descriptor.method()); assert_eq!(descriptor.runtime_status(), ksp_onchain_transport_lib::RpcRuntimeStatus::Supported); match descriptor.operation_kind() { ksp_onchain_transport_lib::RpcOperationKind::Read | ksp_onchain_transport_lib::RpcOperationKind::Simulation => { assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe); }, ksp_onchain_transport_lib::RpcOperationKind::WriteSubmission => { assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::NeverAfterDispatch); }, } } } audited.sort_unstable(); assert_eq!(audited.len(), 37); assert_eq!(audited.first(), std::option::Option::Some(&"getAccountInfo")); assert_eq!(audited.last(), std::option::Option::Some(&"simulateTransaction")); let get_transaction = ksp_onchain_transport_lib::find_http_rpc_method("getTransaction").expect("getTransaction descriptor must exist"); assert!(get_transaction.request_form_status().has_deprecated_legacy()); } #[test] fn release_v0_2_4_descriptor_set_is_exact_and_remains_read_retry_safe_through_wrapper_completion() { let mut expected_blocks = std::vec![ "getBlock", "getBlockCommitment", "getBlockHeight", "getBlockProduction", "getBlocks", "getBlocksWithLimit", "getBlockTime", "getFirstAvailableBlock", "getRecentPerformanceSamples", "minimumLedgerSlot", ]; let mut expected_economics = std::vec!["getInflationGovernor", "getInflationRate", "getInflationReward", "getStakeMinimumDelegation", "getSupply",]; let mut actual_blocks = std::vec::Vec::new(); let mut actual_economics = std::vec::Vec::new(); for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() { if descriptor.coverage_release() != ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_4 { continue; } assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read); assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe); match descriptor.category() { ksp_onchain_transport_lib::HttpRpcCategory::Blocks => actual_blocks.push(descriptor.method()), ksp_onchain_transport_lib::HttpRpcCategory::Economics => actual_economics.push(descriptor.method()), _ => {}, } } actual_blocks.sort_unstable(); actual_economics.sort_unstable(); expected_blocks.sort_unstable(); expected_economics.sort_unstable(); assert_eq!(actual_blocks, expected_blocks); assert_eq!(actual_economics, expected_economics); assert_eq!(actual_blocks.len(), 10); assert_eq!(actual_economics.len(), 5); let get_block = ksp_onchain_transport_lib::find_http_rpc_method("getBlock").expect("getBlock descriptor must exist"); assert!(get_block.request_form_status().has_deprecated_legacy()); } #[test] fn release_v0_2_4_pre_003_simple_blocks_subset_is_exact_and_retry_safe() { let mut expected = std::vec!["getBlockCommitment", "getBlockHeight", "getBlockTime", "getFirstAvailableBlock", "minimumLedgerSlot"]; let mut actual = std::vec::Vec::new(); for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() { if descriptor.coverage_release() != ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_4 || descriptor.category() != ksp_onchain_transport_lib::HttpRpcCategory::Blocks { continue; } match descriptor.method() { "getBlockCommitment" | "getBlockHeight" | "getBlockTime" | "getFirstAvailableBlock" | "minimumLedgerSlot" => { assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read); assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe); actual.push(descriptor.method()); }, _ => {}, } } actual.sort_unstable(); expected.sort_unstable(); assert_eq!(actual, expected); assert_eq!(actual.len(), 5); } #[test] fn release_v0_2_4_pre_004_range_performance_subset_is_exact_and_retry_safe() { let mut expected = std::vec!["getBlocks", "getBlocksWithLimit", "getRecentPerformanceSamples"]; let mut actual = std::vec::Vec::new(); for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() { if descriptor.coverage_release() != ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_4 || descriptor.category() != ksp_onchain_transport_lib::HttpRpcCategory::Blocks { continue; } match descriptor.method() { "getBlocks" | "getBlocksWithLimit" | "getRecentPerformanceSamples" => { assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read); assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe); actual.push(descriptor.method()); }, _ => {}, } } actual.sort_unstable(); expected.sort_unstable(); assert_eq!(actual, expected); assert_eq!(actual.len(), 3); } #[test] fn release_v0_2_4_pre_005_block_production_subset_is_exact_and_retry_safe() { let descriptor = ksp_onchain_transport_lib::find_http_rpc_method("getBlockProduction").expect("getBlockProduction descriptor must exist"); assert_eq!(descriptor.category(), ksp_onchain_transport_lib::HttpRpcCategory::Blocks); assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_4); assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read); assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe); } #[test] fn release_v0_2_4_pre_006_get_block_completes_all_ten_block_wrappers_with_legacy_marker() { let expected = std::vec![ "getBlock", "getBlockCommitment", "getBlockHeight", "getBlockProduction", "getBlocks", "getBlocksWithLimit", "getBlockTime", "getFirstAvailableBlock", "getRecentPerformanceSamples", "minimumLedgerSlot", ]; let mut actual = std::vec::Vec::new(); for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() { if descriptor.coverage_release() == ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_4 && descriptor.category() == ksp_onchain_transport_lib::HttpRpcCategory::Blocks { assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read); assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe); actual.push(descriptor.method()); } } actual.sort_unstable(); let mut expected = expected; expected.sort_unstable(); assert_eq!(actual, expected); assert_eq!(actual.len(), 10); let get_block = ksp_onchain_transport_lib::find_http_rpc_method("getBlock").expect("getBlock descriptor must exist"); assert!(get_block.request_form_status().has_deprecated_legacy()); } #[test] fn release_v0_2_4_pre_007_simple_economics_subset_is_exact_and_retry_safe() { let mut expected = std::vec!["getInflationGovernor", "getInflationRate", "getStakeMinimumDelegation", "getSupply"]; let mut actual = std::vec::Vec::new(); for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() { if descriptor.coverage_release() != ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_4 || descriptor.category() != ksp_onchain_transport_lib::HttpRpcCategory::Economics { continue; } assert!(matches!( descriptor.method(), "getInflationGovernor" | "getInflationRate" | "getInflationReward" | "getStakeMinimumDelegation" | "getSupply" )); if descriptor.method() != "getInflationReward" { assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read); assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe); actual.push(descriptor.method()); } } actual.sort_unstable(); expected.sort_unstable(); assert_eq!(actual, expected); assert_eq!(actual.len(), 4); } #[test] fn release_v0_2_4_pre_008_completes_all_five_economics_wrappers_exactly_and_retry_safe() { let mut expected = std::vec!["getInflationGovernor", "getInflationRate", "getInflationReward", "getStakeMinimumDelegation", "getSupply"]; let mut actual = std::vec::Vec::new(); for descriptor in ksp_onchain_transport_lib::current_http_rpc_methods() { if descriptor.coverage_release() == ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_4 && descriptor.category() == ksp_onchain_transport_lib::HttpRpcCategory::Economics { actual.push(descriptor.method()); assert_eq!(descriptor.operation_kind(), ksp_onchain_transport_lib::RpcOperationKind::Read); assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe); } } actual.sort_unstable(); expected.sort_unstable(); assert_eq!(actual, expected); assert_eq!(actual.len(), 5); } #[test] fn release_v0_2_4_pre_009_final_http_inventory_and_coverage_partition_are_exact() { let expected_current = std::vec![ "getAccountInfo", "getBalance", "getBlock", "getBlockCommitment", "getBlockHeight", "getBlockProduction", "getBlocks", "getBlocksWithLimit", "getBlockTime", "getClusterNodes", "getEpochInfo", "getEpochSchedule", "getFeeForMessage", "getFirstAvailableBlock", "getGenesisHash", "getHealth", "getHighestSnapshotSlot", "getIdentity", "getInflationGovernor", "getInflationRate", "getInflationReward", "getLargestAccounts", "getLatestBlockhash", "getLeaderSchedule", "getMaxRetransmitSlot", "getMaxShredInsertSlot", "getMinimumBalanceForRentExemption", "getMultipleAccounts", "getProgramAccounts", "getRecentPerformanceSamples", "getRecentPrioritizationFees", "getSignaturesForAddress", "getSignatureStatuses", "getSlot", "getSlotLeader", "getSlotLeaders", "getStakeMinimumDelegation", "getSupply", "getTokenAccountBalance", "getTokenAccountsByDelegate", "getTokenAccountsByOwner", "getTokenLargestAccounts", "getTokenSupply", "getTransaction", "getTransactionCount", "getVersion", "getVoteAccounts", "isBlockhashValid", "minimumLedgerSlot", "requestAirdrop", "sendTransaction", "simulateTransaction", ]; let expected_historical = std::vec![ "confirmTransaction", "getConfirmedBlock", "getConfirmedBlocks", "getConfirmedBlocksWithLimit", "getConfirmedSignaturesForAddress2", "getConfirmedTransaction", "getFeeCalculatorForBlockhash", "getFeeRateGovernor", "getFees", "getRecentBlockhash", "getSignatureConfirmation", "getSignatureStatus", "getSnapshotSlot", "getStakeActivation", ]; let current = ksp_onchain_transport_lib::current_http_rpc_methods(); let historical = ksp_onchain_transport_lib::historical_http_rpc_methods(); let mut actual_current = std::vec::Vec::with_capacity(current.len()); let mut actual_historical = std::vec::Vec::with_capacity(historical.len()); let mut v0_2_1 = 0_usize; let mut v0_2_2 = 0_usize; let mut v0_2_3 = 0_usize; let mut v0_2_4 = 0_usize; let mut historical_current = 0_usize; for descriptor in current { actual_current.push(descriptor.method()); assert_eq!(descriptor.runtime_status(), ksp_onchain_transport_lib::RpcRuntimeStatus::Supported); assert_ne!(descriptor.documentation_status(), ksp_onchain_transport_lib::RpcDocumentationStatus::Deprecated); match descriptor.coverage_release() { ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_1 => v0_2_1 += 1, ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_2 => v0_2_2 += 1, ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_3 => v0_2_3 += 1, ksp_onchain_transport_lib::HttpRpcCoverageRelease::V0_2_4 => v0_2_4 += 1, ksp_onchain_transport_lib::HttpRpcCoverageRelease::Historical => historical_current += 1, } match descriptor.operation_kind() { ksp_onchain_transport_lib::RpcOperationKind::Read | ksp_onchain_transport_lib::RpcOperationKind::Simulation => { assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::RetrySafe); }, ksp_onchain_transport_lib::RpcOperationKind::WriteSubmission => { assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::NeverAfterDispatch); }, } } for descriptor in historical { actual_historical.push(descriptor.method()); assert_eq!(descriptor.documentation_status(), ksp_onchain_transport_lib::RpcDocumentationStatus::Deprecated); assert_eq!(descriptor.runtime_status(), ksp_onchain_transport_lib::RpcRuntimeStatus::Removed); assert_eq!(descriptor.coverage_release(), ksp_onchain_transport_lib::HttpRpcCoverageRelease::Historical); assert_eq!(descriptor.transport_retry_class(), ksp_onchain_transport_lib::TransportRetryClass::NotApplicable); } actual_current.sort_unstable(); actual_historical.sort_unstable(); let mut expected_current = expected_current; let mut expected_historical = expected_historical; expected_current.sort_unstable(); expected_historical.sort_unstable(); assert_eq!(actual_current, expected_current); assert_eq!(actual_historical, expected_historical); assert_eq!(actual_current.len(), 52); assert_eq!(actual_historical.len(), 14); assert_eq!((v0_2_1, v0_2_2, v0_2_3, v0_2_4), (4, 22, 11, 15)); assert_eq!(historical_current, 0); }