// file: crates/ksp-onchain-transport-lib/unit_tests/rpc_blocks.rs // version: 1 #[test] fn transaction_details_and_get_block_config_preserve_all_modern_options() { assert_eq!(crate::SolanaTransactionDetails::Full.as_str(), "full"); assert_eq!(crate::SolanaTransactionDetails::Signatures.as_str(), "signatures"); assert_eq!(crate::SolanaTransactionDetails::None.as_str(), "none"); assert_eq!(crate::SolanaTransactionDetails::Accounts.as_str(), "accounts"); let config = crate::SolanaGetBlockConfig::new( std::option::Option::Some(crate::SolanaCommitment::Confirmed), std::option::Option::Some(crate::SolanaTransactionEncoding::JsonParsed), std::option::Option::Some(crate::SolanaTransactionDetails::Accounts), std::option::Option::Some(1), std::option::Option::Some(false), ); assert_eq!(config.commitment(), std::option::Option::Some(crate::SolanaCommitment::Confirmed)); assert_eq!(config.encoding(), std::option::Option::Some(crate::SolanaTransactionEncoding::JsonParsed)); assert_eq!(config.transaction_details(), std::option::Option::Some(crate::SolanaTransactionDetails::Accounts)); assert_eq!(config.max_supported_transaction_version(), std::option::Option::Some(1)); assert_eq!(config.rewards(), std::option::Option::Some(false)); assert_eq!( config.to_json_value(), serde_json::json!({ "commitment":"confirmed", "encoding":"jsonParsed", "transactionDetails":"accounts", "maxSupportedTransactionVersion":1, "rewards":false }) ); assert!(crate::SolanaGetBlockConfig::default().is_empty()); assert_eq!(crate::SolanaGetBlockConfig::default().to_json_value(), serde_json::json!({})); } #[test] fn block_production_config_preserves_identity_range_and_commitment() { let identity = "11111111111111111111111111111111".parse::().expect("fixture identity must parse"); let range = crate::SolanaBlockProductionRange::new(430_000_000, std::option::Option::Some(430_000_099)); let config = crate::SolanaBlockProductionConfig::new( std::option::Option::Some(crate::SolanaCommitment::Finalized), std::option::Option::Some(identity), std::option::Option::Some(range), ); assert_eq!(config.identity(), std::option::Option::Some(&identity)); assert_eq!(config.range().expect("range must be present").first_slot(), 430_000_000); assert_eq!(config.range().expect("range must be present").last_slot(), std::option::Option::Some(430_000_099)); assert_eq!( config.to_json_value(), serde_json::json!({ "commitment":"finalized", "identity":"11111111111111111111111111111111", "range":{"firstSlot":430000000,"lastSlot":430000099} }) ); assert!(crate::SolanaBlockProductionConfig::default().is_empty()); } #[test] fn block_commitment_fixture_preserves_nullable_distribution() { let values = serde_json::from_str::>(include_str!("../fixtures/http/block_commitment.variants.json")) .expect("block commitment fixtures must decode"); let present = crate::SolanaBlockCommitment::decode_wire("getBlockCommitment", values[0].clone()).expect("present commitment must decode"); let absent = crate::SolanaBlockCommitment::decode_wire("getBlockCommitment", values[1].clone()).expect("null commitment must decode"); assert_eq!(present.commitment(), std::option::Option::Some(&[1, 2, 3, 4][..])); assert_eq!(present.total_stake(), 1_000_000_000); assert_eq!(absent.commitment(), std::option::Option::None); } #[test] fn block_production_fixture_types_identity_keys_and_preserves_counts() { let value = serde_json::from_str::(include_str!("../fixtures/http/block_production.v4_2_1.json")).expect("block production fixture must decode"); let result = crate::SolanaBlockProduction::decode_wire("getBlockProduction", value).expect("block production result must decode"); let identity = "11111111111111111111111111111111".parse::().expect("fixture identity must parse"); assert_eq!(result.by_identity().get(&identity), std::option::Option::Some(&(8, 7))); assert_eq!(result.range().first_slot(), 430_000_000); assert_eq!(result.range().last_slot(), 430_000_099); } #[test] fn confirmed_block_fixture_preserves_rich_wire_and_simd_extensions() { let value = serde_json::from_str::(include_str!("../fixtures/http/confirmed_block.v4_2_1.json")).expect("confirmed block fixture must decode"); let block = crate::SolanaConfirmedBlock::decode_wire("getBlock", value).expect("confirmed block must decode"); assert_eq!(block.parent_slot(), 430_000_122); assert_eq!(block.block_time(), std::option::Option::Some(1_787_072_400)); assert_eq!(block.block_height(), std::option::Option::Some(410_000_000)); assert_eq!(block.num_reward_partitions().value(), std::option::Option::Some(&4)); let transactions = block.transactions().value().expect("transactions must be present"); assert_eq!(transactions.len(), 2); assert!(matches!(transactions[0].version(), crate::SolanaWireField::Value(crate::SolanaTransactionVersion::Number(1)))); assert!(transactions[1].version().is_omitted()); assert!(transactions[1].meta().is_null()); let rewards = block.rewards().value().expect("rewards must be present"); assert_eq!(rewards.len(), 2); assert_eq!(rewards[0].reward_type(), std::option::Option::Some("Fee")); assert_eq!(rewards[0].commission(), std::option::Option::None); assert_eq!(rewards[0].commission_bps().value(), std::option::Option::Some(&1_234)); assert_eq!(rewards[1].commission(), std::option::Option::Some(5)); assert!(rewards[1].commission_bps().is_omitted()); } #[test] fn confirmed_block_fixture_distinguishes_omitted_and_explicit_null_fields() { let values = serde_json::from_str::>(include_str!("../fixtures/http/confirmed_block.omissions.json")) .expect("confirmed block omission fixtures must decode"); let omitted = crate::SolanaConfirmedBlock::decode_wire("getBlock", values[0].clone()).expect("omitted-fields block must decode"); let nulls = crate::SolanaConfirmedBlock::decode_wire("getBlock", values[1].clone()).expect("null-fields block must decode"); assert!(omitted.transactions().is_omitted()); assert!(omitted.signatures().is_omitted()); assert!(omitted.rewards().is_omitted()); assert!(omitted.num_reward_partitions().is_omitted()); assert!(nulls.transactions().is_null()); assert!(nulls.signatures().is_null()); assert!(nulls.rewards().is_null()); assert!(nulls.num_reward_partitions().is_null()); } #[test] fn performance_sample_fixture_accepts_current_and_older_shapes() { let values = serde_json::from_str::>(include_str!("../fixtures/http/performance_sample.variants.json")) .expect("performance sample fixtures must decode"); let current = crate::SolanaPerformanceSample::decode_wire("getRecentPerformanceSamples", values[0].clone()).expect("current sample must decode"); let older = crate::SolanaPerformanceSample::decode_wire("getRecentPerformanceSamples", values[1].clone()).expect("older sample must decode"); assert_eq!(current.slot(), 430_000_123); assert_eq!(current.num_transactions(), 250_000); assert_eq!(current.num_non_vote_transactions(), std::option::Option::Some(175_000)); assert_eq!(current.num_slots(), 120); assert_eq!(current.sample_period_secs(), 60); assert_eq!(older.num_non_vote_transactions(), std::option::Option::None); } #[test] fn block_reward_rejects_invalid_pubkey_without_echoing_value() { let result = crate::SolanaConfirmedBlock::decode_wire( "getBlock", serde_json::json!({ "previousBlockhash":"previous", "blockhash":"block", "parentSlot":1, "rewards":[{"pubkey":"not-a-pubkey","lamports":1,"postBalance":2,"rewardType":"Fee","commission":null}], "blockTime":null, "blockHeight":null }), ); let error = result.expect_err("invalid reward pubkey must fail closed"); assert_eq!(error.code(), crate::ERROR_CODE_INVALID_RESPONSE); assert!(!error.to_string().contains("not-a-pubkey")); }