Files
khadhroony-solana-project/crates/ksp-onchain-transport-lib/tests/release_completeness.rs
2026-09-11 22:22:51 +02:00

1402 lines
70 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// file: crates/ksp-onchain-transport-lib/tests/release_completeness.rs
// version: 46
//! Release-level completeness canaries for staged HTTP and WebSocket Transport coverage.
#[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);
}
#[test]
fn release_v0_2_7_pre_012_websocket_surface_accounts_for_all_nine_standard_pairs() {
let kinds = [
ksp_onchain_transport_lib::WsSubscriptionKind::Account,
ksp_onchain_transport_lib::WsSubscriptionKind::Block,
ksp_onchain_transport_lib::WsSubscriptionKind::Logs,
ksp_onchain_transport_lib::WsSubscriptionKind::Program,
ksp_onchain_transport_lib::WsSubscriptionKind::Root,
ksp_onchain_transport_lib::WsSubscriptionKind::Signature,
ksp_onchain_transport_lib::WsSubscriptionKind::Slot,
ksp_onchain_transport_lib::WsSubscriptionKind::SlotsUpdates,
ksp_onchain_transport_lib::WsSubscriptionKind::Vote,
];
let expected_names = ["account", "block", "logs", "program", "root", "signature", "slot", "slots_updates", "vote"];
let actual_names = kinds.map(ksp_onchain_transport_lib::WsSubscriptionKind::as_str);
assert_eq!(actual_names, expected_names);
assert_eq!(kinds.len() * 2, 18);
let _account = ksp_onchain_transport_lib::WsSession::account_subscribe;
let _block = ksp_onchain_transport_lib::WsSession::block_subscribe;
let _logs = ksp_onchain_transport_lib::WsSession::logs_subscribe;
let _program = ksp_onchain_transport_lib::WsSession::program_subscribe;
let _root = ksp_onchain_transport_lib::WsSession::root_subscribe;
let _signature = ksp_onchain_transport_lib::WsSession::signature_subscribe;
let _slot = ksp_onchain_transport_lib::WsSession::slot_subscribe;
let _slots_updates = ksp_onchain_transport_lib::WsSession::slots_updates_subscribe;
let _vote = ksp_onchain_transport_lib::WsSession::vote_subscribe;
let _unsubscribe = ksp_onchain_transport_lib::WsSubscription::<serde_json::Value>::unsubscribe;
}
#[test]
fn release_v0_2_7_pre_012_http_inventory_remains_52_current_plus_14_historical() {
let current = ksp_onchain_transport_lib::current_http_rpc_methods();
let historical = ksp_onchain_transport_lib::historical_http_rpc_methods();
assert_eq!(current.len(), 52);
assert_eq!(historical.len(), 14);
assert!(current.iter().all(|descriptor| return descriptor.runtime_status() == ksp_onchain_transport_lib::RpcRuntimeStatus::Supported));
assert!(historical.iter().all(|descriptor| return descriptor.runtime_status() == ksp_onchain_transport_lib::RpcRuntimeStatus::Removed));
}
#[test]
fn release_v0_2_8_pre_002_protocol_facades_preserve_the_standard_partition() {
assert_eq!(ksp_onchain_transport_lib::WsProtocolKind::SolanaStandard.as_str(), "solana_standard");
assert_eq!(ksp_onchain_transport_lib::WsProtocolKind::HeliusLaserStream.as_str(), "helius_laserstream");
let standard_kinds = [
ksp_onchain_transport_lib::WsSubscriptionKind::Account,
ksp_onchain_transport_lib::WsSubscriptionKind::Block,
ksp_onchain_transport_lib::WsSubscriptionKind::Logs,
ksp_onchain_transport_lib::WsSubscriptionKind::Program,
ksp_onchain_transport_lib::WsSubscriptionKind::Root,
ksp_onchain_transport_lib::WsSubscriptionKind::Signature,
ksp_onchain_transport_lib::WsSubscriptionKind::Slot,
ksp_onchain_transport_lib::WsSubscriptionKind::SlotsUpdates,
ksp_onchain_transport_lib::WsSubscriptionKind::Vote,
];
assert_eq!(standard_kinds.len(), 9);
assert_eq!(
std::any::type_name::<ksp_onchain_transport_lib::SolanaStandardWsSession>().rsplit("::").next(),
std::option::Option::Some("SolanaStandardWsSession")
);
assert_eq!(
std::any::type_name::<ksp_onchain_transport_lib::HeliusLaserStreamWsSession>().rsplit("::").next(),
std::option::Option::Some("HeliusLaserStreamWsSession")
);
}
#[test]
fn release_v0_2_8_pre_003_original_six_standard_families_remain_available_after_provider_evolution() {
let _account = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::account_subscribe;
let _program = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::program_subscribe;
let _logs = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::logs_subscribe;
let _signature = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::signature_subscribe;
let _slot = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::slot_subscribe;
let _root = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::root_subscribe;
let source = include_str!("../src/ws_protocol_session.rs");
assert!(source.contains("unsupported_block"));
assert!(source.contains("unsupported_vote"));
assert!(!source.contains("pub async fn transaction_subscribe"));
assert_eq!(ksp_onchain_transport_lib::WsProtocolKind::HeliusLaserStream.as_str(), "helius_laserstream");
}
#[test]
fn release_v0_2_8_pre_005_helius_transaction_request_surface_is_typed_before_actor_integration() {
let filter = ksp_onchain_transport_lib::HeliusTransactionSubscribeFilter::new(
std::option::Option::None,
std::option::Option::None,
std::option::Option::None,
std::option::Option::None,
std::option::Option::None,
std::option::Option::None,
std::option::Option::Some(ksp_onchain_transport_lib::HeliusTokenAccountsFilter::All),
);
let options = ksp_onchain_transport_lib::HeliusTransactionSubscribeOptions::new(
std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Processed),
std::option::Option::Some(ksp_onchain_transport_lib::HeliusTransactionSubscribeEncoding::Base64),
std::option::Option::Some(ksp_onchain_transport_lib::SolanaTransactionDetails::Signatures),
std::option::Option::Some(true),
std::option::Option::None,
);
let request = ksp_onchain_transport_lib::HeliusTransactionSubscribeRequest::new(filter, std::option::Option::Some(options));
assert!(request.validate().is_ok());
let facade_source = include_str!("../src/ws_protocol_session.rs");
assert!(!facade_source.contains("pub async fn transaction_subscribe"));
assert_eq!(ksp_onchain_transport_lib::WsProtocolKind::HeliusLaserStream.as_str(), "helius_laserstream");
}
#[test]
fn release_v0_2_8_pre_006_helius_transaction_lifecycle_is_actor_integrated_without_advancing_heartbeat() {
let _transaction = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::transaction_subscribe;
assert_eq!(ksp_onchain_transport_lib::WsSubscriptionKind::HeliusTransaction.as_str(), "helius_transaction");
let source = include_str!("../src/ws_helius_transactions.rs");
assert!(source.contains("transactionNotification"));
assert!(source.contains("WsSubscriptionKind::HeliusTransaction"));
assert!(!source.contains("tokio_tungstenite::connect_async"));
let protocol_source = include_str!("../src/ws_protocol_session.rs");
assert!(protocol_source.contains("unsupported_block"));
assert!(protocol_source.contains("unsupported_vote"));
}
#[test]
fn release_v0_2_8_pre_007_helius_heartbeat_is_provider_owned_by_shared_actor_only() {
let actor_source = include_str!("../src/ws_session.rs");
assert!(actor_source.contains("HELIUS_WS_HEARTBEAT_INTERVAL"));
assert!(actor_source.contains("std::time::Duration::from_secs(60)"));
assert!(actor_source.contains("WsProtocolKind::HeliusLaserStream"));
assert!(actor_source.contains("tungstenite::Message::Ping"));
assert!(actor_source.contains("send_helius_heartbeat"));
let settings_source = include_str!("../src/ws_settings.rs");
assert!(!settings_source.contains("heartbeat_interval"));
assert!(!settings_source.contains("heartbeat_enabled"));
let protocol_source = include_str!("../src/ws_protocol_session.rs");
assert!(!protocol_source.contains("heartbeat_interval"));
}
#[test]
fn release_v0_2_8_pre_008_adversarial_guards_preserve_provider_isolation_and_safe_diagnostics() {
let protocol_source = include_str!("../src/ws_protocol_session.rs");
assert!(protocol_source.contains("unsupported_helius_transaction"));
assert!(protocol_source.contains("unsupported_block"));
assert!(protocol_source.contains("unsupported_vote"));
let helius_source = include_str!("../src/ws_helius_transactions.rs");
assert!(helius_source.contains("impl std::fmt::Debug for HeliusFullTransactionNotification"));
assert!(helius_source.contains("impl std::fmt::Debug for HeliusTransactionSignatureNotification"));
assert!(helius_source.contains("impl std::fmt::Debug for HeliusTransactionNotification"));
assert!(helius_source.contains("Self::Unknown(_)"));
assert!(helius_source.contains("<omitted>"));
let actor_source = include_str!("../src/ws_session.rs");
assert!(actor_source.contains("max_message_size_bytes"));
assert!(actor_source.contains("max_frame_size_bytes"));
assert!(actor_source.contains("WsNotificationDispatchOutcome::QueueFull"));
assert!(actor_source.contains("ERROR_CODE_WS_BACKPRESSURE_OVERFLOW"));
assert!(actor_source.contains("remote_to_local.remove"));
}
#[test]
fn release_v0_2_8_pre_009_http_and_standard_websocket_inventories_remain_exact() {
assert_eq!(ksp_onchain_transport_lib::current_http_rpc_methods().len(), 52);
assert_eq!(ksp_onchain_transport_lib::historical_http_rpc_methods().len(), 14);
let standard = [
ksp_onchain_transport_lib::WsSubscriptionKind::Account,
ksp_onchain_transport_lib::WsSubscriptionKind::Block,
ksp_onchain_transport_lib::WsSubscriptionKind::Logs,
ksp_onchain_transport_lib::WsSubscriptionKind::Program,
ksp_onchain_transport_lib::WsSubscriptionKind::Root,
ksp_onchain_transport_lib::WsSubscriptionKind::Signature,
ksp_onchain_transport_lib::WsSubscriptionKind::Slot,
ksp_onchain_transport_lib::WsSubscriptionKind::SlotsUpdates,
ksp_onchain_transport_lib::WsSubscriptionKind::Vote,
];
assert_eq!(standard.len(), 9);
let lifecycle_source = include_str!("../src/ws_lifecycle.rs");
for method in [
"accountSubscribe",
"accountUnsubscribe",
"blockSubscribe",
"blockUnsubscribe",
"logsSubscribe",
"logsUnsubscribe",
"programSubscribe",
"programUnsubscribe",
"rootSubscribe",
"rootUnsubscribe",
"signatureSubscribe",
"signatureUnsubscribe",
"slotSubscribe",
"slotUnsubscribe",
"slotsUpdatesSubscribe",
"slotsUpdatesUnsubscribe",
"voteSubscribe",
"voteUnsubscribe",
] {
assert!(lifecycle_source.contains(method), "missing standard WebSocket method mapping: {method}");
}
let _account = ksp_onchain_transport_lib::SolanaStandardWsSession::account_subscribe;
let _block = ksp_onchain_transport_lib::SolanaStandardWsSession::block_subscribe;
let _logs = ksp_onchain_transport_lib::SolanaStandardWsSession::logs_subscribe;
let _program = ksp_onchain_transport_lib::SolanaStandardWsSession::program_subscribe;
let _root = ksp_onchain_transport_lib::SolanaStandardWsSession::root_subscribe;
let _signature = ksp_onchain_transport_lib::SolanaStandardWsSession::signature_subscribe;
let _slot = ksp_onchain_transport_lib::SolanaStandardWsSession::slot_subscribe;
let _slots_updates = ksp_onchain_transport_lib::SolanaStandardWsSession::slots_updates_subscribe;
let _vote = ksp_onchain_transport_lib::SolanaStandardWsSession::vote_subscribe;
}
#[test]
fn release_v0_2_8_pre_009_helius_surface_is_seven_standard_families_plus_transaction() {
let _account = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::account_subscribe;
let _program = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::program_subscribe;
let _logs = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::logs_subscribe;
let _signature = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::signature_subscribe;
let _slot = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::slot_subscribe;
let _root = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::root_subscribe;
let _slots_updates = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::slots_updates_subscribe;
let _transaction = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::transaction_subscribe;
let protocol_source = include_str!("../src/ws_protocol_session.rs");
assert!(protocol_source.contains("unsupported_block"));
assert!(protocol_source.contains("unsupported_vote"));
assert!(!protocol_source.contains("unsupported_slots_updates"));
let cluster_source = include_str!("../src/ws_cluster.rs");
assert!(cluster_source.contains("impl crate::HeliusLaserStreamWsSession"));
assert!(cluster_source.contains("pub async fn slots_updates_subscribe"));
assert_eq!(ksp_onchain_transport_lib::WsSubscriptionKind::SlotsUpdates.as_str(), "slots_updates");
assert_eq!(ksp_onchain_transport_lib::WsSubscriptionKind::HeliusTransaction.as_str(), "helius_transaction");
}
#[test]
fn release_v0_2_8_pre_009_config_secret_and_dependency_boundaries_remain_wired() {
let manifest_directory = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
let workspace = manifest_directory.parent().and_then(std::path::Path::parent).expect("Transport integration test must resolve the workspace root");
let transport_manifest = std::fs::read_to_string(manifest_directory.join("Cargo.toml")).expect("Transport manifest must be readable");
for forbidden in ["ksp-config-lib", "ksp-store-api", "ksp-store-lib", "ksp-program-api", "ksp-program-lib", "tracing =", "tracing."] {
assert!(!transport_manifest.contains(forbidden), "forbidden direct Transport dependency detected: {forbidden}");
}
let config_manifest = std::fs::read_to_string(workspace.join("crates/ksp-config-lib/Cargo.toml")).expect("Config manifest must be readable");
assert!(config_manifest.contains("ksp-onchain-transport-lib"));
let config_transport =
std::fs::read_to_string(workspace.join("crates/ksp-config-lib/src/transport.rs")).expect("Config Transport adapter source must be readable");
assert!(config_transport.contains("WsProtocolKind::HeliusLaserStream"));
let transport_example = std::fs::read_to_string(workspace.join("config/examples/std.transport.example.json")).expect("Transport example must be readable");
assert!(transport_example.contains("\"kind\": \"helius_laserstream\""));
assert!(transport_example.contains("${KSP_SECRET_HELIUS_API_KEY"));
let env_example = std::fs::read_to_string(workspace.join(".env.example")).expect(".env.example must be readable");
assert!(env_example.contains("KSP_SECRET_HELIUS_API_KEY"));
}
#[test]
fn release_v0_2_8_pre_010_live_smoke_policy_preserves_secret_and_dependency_ownership() {
let manifest_directory = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
let workspace = manifest_directory.parent().and_then(std::path::Path::parent).expect("Transport integration test must resolve the workspace root");
let transport_manifest = std::fs::read_to_string(manifest_directory.join("Cargo.toml")).expect("Transport manifest must be readable");
assert!(!transport_manifest.contains("ksp-config-lib"));
let transport_ws_smoke =
std::fs::read_to_string(manifest_directory.join("tests/websocket_devnet_smoke.rs")).expect("Transport WebSocket smoke must be readable");
assert!(!transport_ws_smoke.contains("KSP_SECRET_HELIUS_API_KEY"));
assert!(!transport_ws_smoke.contains("ConfigEnvironment"));
assert!(!workspace.join("crates/ksp-config-lib/tests/helius_websocket_smoke.rs").exists());
let readme = std::fs::read_to_string(manifest_directory.join("README.md")).expect("Transport README must be readable");
assert!(readme.contains("Aucun smoke Helius live supplémentaire nest committé en `0.2.8-pre.010`"));
assert!(readme.contains("KSP_SECRET_HELIUS_API_KEY"));
let usage = std::fs::read_to_string(manifest_directory.join("USAGE.md")).expect("Transport USAGE must be readable");
assert!(usage.contains("### Smoke Helius live"));
assert!(usage.contains("surface KSP dintégration/orchestration dédiée"));
assert!(usage.contains("cargo tree -p ksp-onchain-transport-lib"));
let env_example = std::fs::read_to_string(workspace.join(".env.example")).expect(".env.example must be readable");
assert!(env_example.contains("KSP_SECRET_HELIUS_API_KEY"));
}
#[test]
fn release_v0_2_9_pre_002_materializes_minimal_yellowstone_engine_without_provider_or_ws_coupling() {
let manifest_directory = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
let transport_manifest = std::fs::read_to_string(manifest_directory.join("Cargo.toml")).expect("Transport manifest must be readable");
let settings_source = include_str!("../src/grpc_settings.rs");
let channel_source = include_str!("../src/grpc_channel.rs");
let crate_root = include_str!("../src/lib.rs");
assert!(transport_manifest.contains("tonic = { workspace = true, features = [\"channel\""));
assert!(transport_manifest.contains("yellowstone-grpc-proto.workspace = true"));
assert!(!transport_manifest.contains("yellowstone-grpc-client"));
assert!(!transport_manifest.contains("ksp-config-lib"));
assert!(settings_source.contains("YellowstoneGrpcEndpointUrl"));
assert!(settings_source.contains("YellowstoneGrpcSessionSettings"));
assert!(settings_source.contains("YellowstoneGrpcTransportSettings"));
assert!(!settings_source.contains("WsProtocolKind"));
assert!(!settings_source.contains("KSP_SECRET_"));
assert!(channel_source.contains("tonic::transport::Endpoint::from_shared"));
assert!(channel_source.contains("connect_lazy"));
assert!(!channel_source.contains("WsSession"));
assert!(!crate_root.contains("pub use tonic"));
assert!(!crate_root.contains("pub use yellowstone_grpc_proto"));
let _published_wire = std::any::type_name::<yellowstone_grpc_proto::geyser::SubscribeRequest>();
}
#[test]
fn release_v0_2_9_pre_003_adds_tls_metadata_and_exactly_seven_standard_unary_methods_without_subscribe() {
let manifest_directory = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
let transport_manifest = std::fs::read_to_string(manifest_directory.join("Cargo.toml")).expect("Transport manifest must be readable");
let settings_source = include_str!("../src/grpc_settings.rs");
let channel_source = include_str!("../src/grpc_channel.rs");
let unary_source = include_str!("../src/grpc_unary.rs");
let crate_root = include_str!("../src/lib.rs");
assert!(transport_manifest.contains("tonic = { workspace = true, features = [\"channel\", \"tls-aws-lc\", \"tls-webpki-roots\"] }"));
assert!(transport_manifest.contains("tonic = { workspace = true, features = [\"codegen\", \"server\"] }"));
assert!(transport_manifest.contains("tonic-prost.workspace = true"));
assert!(transport_manifest.contains("yellowstone-grpc-proto.workspace = true"));
assert!(transport_manifest.contains("yellowstone-grpc-proto = { workspace = true, features = [\"tonic\"] }"));
assert!(!transport_manifest.contains("yellowstone-grpc-client"));
assert!(settings_source.contains("YellowstoneGrpcMetadataEntry"));
assert!(settings_source.contains("set_sensitive"));
assert!(channel_source.contains("ClientTlsConfig"));
assert!(channel_source.contains("with_webpki_roots"));
assert!(channel_source.contains("pub async fn connect"));
for path in [
"/geyser.Geyser/SubscribeReplayInfo",
"/geyser.Geyser/Ping",
"/geyser.Geyser/GetLatestBlockhash",
"/geyser.Geyser/GetBlockHeight",
"/geyser.Geyser/GetSlot",
"/geyser.Geyser/IsBlockhashValid",
"/geyser.Geyser/GetVersion",
] {
assert!(unary_source.contains(path), "missing standard Yellowstone unary path: {path}");
}
assert!(!unary_source.contains("const PATH_SUBSCRIBE: "));
assert!(!unary_source.contains("SubscribeDeshred"));
assert!(!unary_source.contains("PublicNode"));
assert!(!crate_root.contains("pub use tonic"));
assert!(!crate_root.contains("pub use yellowstone_grpc_proto"));
let _client = std::any::type_name::<ksp_onchain_transport_lib::SolanaYellowstoneGrpcUnaryClient>();
}
#[test]
fn release_v0_2_9_pre_004_materializes_only_standard_subscribe_common_contract() {
let source = include_str!("../src/grpc_subscribe.rs");
let crate_root = include_str!("../src/lib.rs");
for wire_field in [
"accounts:",
"slots:",
"transactions:",
"transactions_status:",
"blocks:",
"blocks_meta:",
"entry:",
"commitment:",
"accounts_data_slice:",
"ping:",
"from_slot:",
] {
assert!(source.contains(wire_field), "missing standard Yellowstone SubscribeRequest field: {wire_field}");
}
assert!(source.contains("MAX_GRPC_SUBSCRIBE_FILTER_GROUP_COUNT"));
assert!(source.contains("MAX_GRPC_SUBSCRIBE_FILTER_NAME_LENGTH_BYTES"));
assert!(source.contains("MAX_GRPC_SUBSCRIBE_DATA_SLICE_COUNT"));
assert!(source.contains("offset.checked_add(length)"));
assert!(source.contains("globally unique"));
assert!(source.contains("SubscribeRequestFilterBlocksMeta"));
assert!(source.contains("SubscribeRequestFilterEntry"));
assert!(source.contains("YellowstoneSubscribeAccountFilter"));
assert!(source.contains("YellowstoneSubscribeSlotFilter"));
assert!(source.contains("YellowstoneSubscribeTransactionFilter"));
assert!(source.contains("YellowstoneSubscribeBlockFilter"));
assert!(!source.contains("SubscribeDeshred"));
assert!(!source.contains("PublicNode"));
assert!(!source.contains("OrbitFlare"));
assert!(!source.contains("Helius"));
assert!(!source.contains("pub fn to_wire"));
assert!(!source.contains("pub(crate) fn to_wire"));
assert!(!crate_root.contains("pub use tonic"));
assert!(!crate_root.contains("pub use yellowstone_grpc_proto"));
let _request = std::any::type_name::<ksp_onchain_transport_lib::YellowstoneSubscribeRequest>();
let _account = std::any::type_name::<ksp_onchain_transport_lib::YellowstoneSubscribeAccountFilter>();
let _slot = std::any::type_name::<ksp_onchain_transport_lib::YellowstoneSubscribeSlotFilter>();
let _transaction = std::any::type_name::<ksp_onchain_transport_lib::YellowstoneSubscribeTransactionFilter>();
let _block = std::any::type_name::<ksp_onchain_transport_lib::YellowstoneSubscribeBlockFilter>();
}
#[test]
fn release_v0_2_9_pre_005_accounts_and_slots_contract_remains_complete() {
let source = include_str!("../src/grpc_subscribe.rs");
let crate_root = include_str!("../src/lib.rs");
for required in [
"account: self.accounts",
"owner: self.owners",
"filters: self.filters",
"nonempty_txn_signature",
"cuckoo_accounts_filter",
"SubscribeRequestFilterAccountsFilterMemcmp",
"DataSize",
"TokenAccountState",
"YellowstoneAccountLamportsFilter",
"filter_by_commitment",
"interslot_updates",
"YellowstoneAccountUpdate",
"YellowstoneSlotUpdate",
"YellowstoneTransactionSignature",
"SlotFirstShredReceived",
"SlotCompleted",
"SlotCreatedBank",
"SlotDead",
"dead_error",
] {
assert!(source.contains(required), "missing pre.005 Accounts/Slots contract token: {required}");
}
assert!(source.contains("MAX_GRPC_SUBSCRIBE_ACCOUNT_SELECTOR_COUNT"));
assert!(source.contains("MAX_GRPC_SUBSCRIBE_ACCOUNT_PREDICATE_COUNT"));
assert!(source.contains("MAX_GRPC_SUBSCRIBE_CUCKOO_DATA_LENGTH_BYTES"));
assert!(source.contains("MAX_GRPC_SUBSCRIBE_ACCOUNT_DATA_LENGTH_BYTES"));
assert!(source.contains("MAX_GRPC_SUBSCRIBE_SLOT_DEAD_ERROR_LENGTH_BYTES"));
assert!(source.contains("fn decode_account_update"));
assert!(source.contains("fn decode_slot_update"));
assert!(!source.contains("SubscribeDeshred"));
assert!(!source.contains("PublicNode"));
assert!(!crate_root.contains("pub use tonic"));
assert!(!crate_root.contains("pub use yellowstone_grpc_proto"));
let _account = std::any::type_name::<ksp_onchain_transport_lib::YellowstoneAccountUpdate>();
let _slot = std::any::type_name::<ksp_onchain_transport_lib::YellowstoneSlotUpdate>();
}
#[test]
fn release_v0_2_9_pre_006_namespaces_unambiguously_http_owned_private_modules() {
let crate_root = include_str!("../src/lib.rs");
let http_client = include_str!("../src/http_client.rs");
let http_executor = include_str!("../src/http_executor.rs");
let http_pool = include_str!("../src/http_pool.rs");
let http_resilience = include_str!("../src/http_resilience.rs");
let http_settings = include_str!("../src/http_settings.rs");
for declaration in ["mod http_client;", "mod http_executor;", "mod http_pool;", "mod http_resilience;", "mod http_settings;"] {
assert!(crate_root.contains(declaration), "missing HTTP-owned private module declaration: {declaration}");
}
for historical in ["mod client;", "mod executor;", "mod pool;", "mod resilience;", "mod settings;"] {
assert!(!crate_root.contains(historical), "historical ambiguous private module declaration remains: {historical}");
}
assert!(http_client.contains("HttpEndpointClient"));
assert!(http_executor.contains("execute_standard_rpc"));
assert!(http_pool.contains("HttpTransportPool"));
assert!(http_resilience.contains("HttpRetryDecision"));
assert!(http_settings.contains("HttpTransportSettings"));
// Shared/protocol-oriented modules deliberately keep their existing names.
for shared in ["mod constants;", "mod error;", "mod json_rpc;", "mod rpc_common;", "mod rpc_accounts;", "mod rpc_blocks;", "mod rpc_transactions;"] {
assert!(crate_root.contains(shared), "shared/protocol module was incorrectly HTTP-prefixed: {shared}");
}
}
#[test]
fn release_v0_2_9_pre_007_transactions_contract_remains_complete() {
let source = include_str!("../src/grpc_subscribe.rs");
let crate_root = include_str!("../src/lib.rs");
for required in [
"YellowstoneSubscribeTransactionFilter",
"YellowstoneTransactionSignatureSelector",
"YellowstoneTokenAccountExpansion",
"account_include",
"account_exclude",
"account_required",
"cuckoo_account_include",
"token_accounts",
"YellowstoneTransactionUpdate",
"YellowstoneTransactionStatusUpdate",
"YellowstoneTransactionStatusMeta",
"YellowstoneTransactionMessage",
"YellowstoneMessageAddressTableLookup",
"YellowstoneTransactionConfig",
"compute_units_consumed",
"cost_units",
"inner_instructions_none",
"log_messages_none",
"return_data_none",
"decode_transaction_update",
"decode_transaction_status_update",
] {
assert!(source.contains(required), "missing pre.007 Transactions contract token: {required}");
}
assert!(source.contains("base58_decoded_length"));
assert!(source.contains("YELLOWSTONE_TRANSACTION_SIGNATURE_WIRE_LENGTH_BYTES"));
assert!(!source.contains("pub async fn subscribe("));
assert!(!source.contains("SubscribeDeshred"));
assert!(!source.contains("PublicNode"));
assert!(!crate_root.contains("pub use tonic"));
assert!(!crate_root.contains("pub use yellowstone_grpc_proto"));
let _filter = std::any::type_name::<ksp_onchain_transport_lib::YellowstoneSubscribeTransactionFilter>();
let _update = std::any::type_name::<ksp_onchain_transport_lib::YellowstoneTransactionUpdate>();
let _status = std::any::type_name::<ksp_onchain_transport_lib::YellowstoneTransactionStatusUpdate>();
}
#[test]
fn release_v0_2_9_pre_008_standard_blocks_contract_remains_complete() {
let source = include_str!("../src/grpc_subscribe.rs");
let crate_root = include_str!("../src/lib.rs");
for required in [
"YellowstoneSubscribeBlockFilter",
"account_include",
"include_transactions",
"include_accounts",
"include_entries",
"cuckoo_account_include",
"YellowstoneBlockRewards",
"YellowstoneBlockUpdate",
"YellowstoneBlockMetaUpdate",
"YellowstoneEntryInfo",
"YellowstoneEntryUpdate",
"executed_transaction_count",
"updated_account_count",
"entries_count",
"starting_transaction_index",
"decode_block_update",
"decode_block_meta_update",
"decode_entry_update",
"decode_block_rewards",
] {
assert!(source.contains(required), "missing pre.008 Blocks contract token: {required}");
}
assert!(source.contains("MAX_GRPC_BLOCK_VECTOR_COUNT"));
assert!(source.contains("base58_decoded_length(value.as_str())"));
assert!(source.contains("std::vec::Vec<crate::YellowstoneTransactionInfo>"));
assert!(source.contains("std::vec::Vec<crate::YellowstoneAccountInfo>"));
assert!(source.contains("std::vec::Vec<crate::YellowstoneEntryInfo>"));
assert!(source.contains("fn decode_block_update"));
assert!(!source.contains("pub async fn subscribe("));
assert!(!source.contains("SubscribeDeshred"));
assert!(!source.contains("PublicNode"));
assert!(!crate_root.contains("pub use tonic"));
assert!(!crate_root.contains("pub use yellowstone_grpc_proto"));
let _block = std::any::type_name::<ksp_onchain_transport_lib::YellowstoneBlockUpdate>();
let _meta = std::any::type_name::<ksp_onchain_transport_lib::YellowstoneBlockMetaUpdate>();
let _entry = std::any::type_name::<ksp_onchain_transport_lib::YellowstoneEntryUpdate>();
}
#[test]
fn release_v0_2_9_pre_009_bounded_standard_bidi_session_contract_remains_complete() {
let stream_source = include_str!("../src/grpc_stream.rs");
let subscribe_source = include_str!("../src/grpc_subscribe.rs");
let channel_source = include_str!("../src/grpc_channel.rs");
let crate_root = include_str!("../src/lib.rs");
for required in [
"const PATH_SUBSCRIBE: &str = \"/geyser.Geyser/Subscribe\"",
".streaming(",
"tokio::sync::mpsc::channel",
"tokio::sync::watch::channel",
"try_send",
"AUTO_SUBSCRIBE_PING_ID",
"ping_request_wire",
"finish_client_half_close",
"timeout_at",
"max_decoding_message_size",
"max_encoding_message_size",
"YellowstoneGrpcSubscribeState",
"SolanaYellowstoneGrpcSubscribeSession",
] {
assert!(stream_source.contains(required), "missing pre.009 bidi runtime token: {required}");
}
for required in [
"YellowstoneSubscribeUpdate",
"YellowstoneSubscribePingUpdate",
"YellowstoneSubscribePongUpdate",
"yellowstone_subscribe_request_to_wire",
"yellowstone_subscribe_update_from_wire",
] {
assert!(subscribe_source.contains(required), "missing pre.009 runtime wire bridge token: {required}");
}
assert!(channel_source.contains("pub async fn open_standard_subscribe"));
assert!(!stream_source.contains("unbounded_channel"));
assert!(!stream_source.contains("SubscribeDeshred"));
assert!(!stream_source.contains("PublicNode"));
assert!(!stream_source.contains("OrbitFlare"));
assert!(!stream_source.contains("Helius"));
assert!(!crate_root.contains("pub use tonic"));
assert!(!crate_root.contains("pub use yellowstone_grpc_proto"));
let _session = std::any::type_name::<ksp_onchain_transport_lib::SolanaYellowstoneGrpcSubscribeSession>();
let _state = ksp_onchain_transport_lib::YellowstoneGrpcSubscribeState::Active;
let _update = std::any::type_name::<ksp_onchain_transport_lib::YellowstoneSubscribeUpdate>();
}
#[test]
fn release_v0_2_9_pre_010_adds_bounded_reconnect_replay_and_conservative_continuity_observability() {
let stream_source = include_str!("../src/grpc_stream.rs");
let crate_root = include_str!("../src/lib.rs");
for required in [
"YellowstoneGrpcSubscribeState::Reconnecting",
"YellowstoneGrpcSubscribeSnapshot",
"YellowstoneGrpcSubscribeSnapshotSource",
"snapshot_source",
"wait_for_change",
"reconnect_subscribe_stream",
"replay_first_available",
"SubscribeReplayInfo",
"last_requested_from_slot",
"last_observed_slot",
"reconnect_count",
"replay_attempt_count",
"continuity_gap_count",
"duplicate_update_count",
"MAX_RECENT_UPDATE_IDENTITIES",
"first_available > requested",
"max_optional_slot",
"reconnect budget is exhausted",
"request mutation",
] {
assert!(stream_source.contains(required), "missing pre.010 reconnect/replay contract token: {required}");
}
assert!(stream_source.contains("still delivered to the caller"));
assert!(stream_source.contains("does not claim exactly-once delivery"));
assert!(!stream_source.contains("unbounded_channel"));
assert!(!stream_source.contains("SubscribeDeshred"));
assert!(!stream_source.contains("PublicNode"));
assert!(!stream_source.contains("OrbitFlare"));
assert!(!stream_source.contains("Helius"));
assert!(!crate_root.contains("pub use tonic"));
assert!(!crate_root.contains("pub use yellowstone_grpc_proto"));
let _snapshot = std::any::type_name::<ksp_onchain_transport_lib::YellowstoneGrpcSubscribeSnapshot>();
let _state = ksp_onchain_transport_lib::YellowstoneGrpcSubscribeState::Reconnecting;
}
#[test]
fn release_v0_3_13_pre_002_yellowstone_subscribe_identity_remains_opaque_and_dependency_neutral() {
let source = include_str!("../src/grpc_subscribe.rs");
let root = include_str!("../src/lib.rs");
let identity_start = source.find("pub struct YellowstoneSubscribeRequestIdentity").expect("identity struct must remain present");
let request_start = source.find("/// Provider-neutral standard Yellowstone subscribe request").expect("request contract marker must remain present");
let identity_surface = &source[identity_start..request_start];
assert!(source.contains("pub fn identity(&self)"));
assert!(root.contains("pub use self::grpc_subscribe::YellowstoneSubscribeRequestIdentity;"));
assert!(!identity_surface.contains("pub fn bytes("));
assert!(!identity_surface.contains("pub fn as_bytes("));
assert!(!root.contains("pub use yellowstone_grpc_proto"));
return;
}
#[test]
fn release_v0_3_14_pre_003_ws_snapshot_source_reuses_actor_watch_without_second_runtime() {
let session_source = include_str!("../src/ws_session.rs");
let facade_source = include_str!("../src/ws_protocol_session.rs");
let session_tests = include_str!("../unit_tests/ws_session.rs");
assert!(session_source.contains("pub struct WsSessionSnapshotSource"));
assert!(session_source.contains("self.snapshot_rx.clone()"));
assert!(facade_source.matches("pub fn snapshot_source").count() >= 2);
for required in [
"v0_3_14_pre_003_snapshot_source_tracks_latest_value_without_owning_runtime",
"websocket_reconnect_resubscribes_in_local_id_order_and_remaps_remote_ids",
"websocket_notification_queue_overflow_fails_only_slow_subscription_and_cleans_remote_binding",
] {
assert!(session_tests.contains(required), "missing pre.003 WebSocket continuity test: {required}");
}
assert!(!session_source.contains("WsSessionSnapshotSource {\n socket:"));
assert!(!facade_source.contains("tokio_tungstenite::connect_async"));
return;
}
#[test]
fn release_v0_3_14_pre_004_native_replay_evidence_never_conflates_attempt_delivery_and_coverage() {
let stream_source = include_str!("../src/grpc_stream.rs");
let stream_tests = include_str!("../unit_tests/grpc_stream.rs");
for required in [
"replay_attempt_count",
"replay_delivery_count",
"replay_coverage_unproven_count",
"pending_replay_from_slot",
"begin_replay",
"abandon_pending_replay",
"first_available > requested",
"This is conservative delivery evidence only",
"explicit lack of coverage proof",
] {
assert!(stream_source.contains(required), "missing pre.004 native replay evidence token: {required}");
}
assert!(stream_tests.contains("v0_3_14_pre_004_replay_acceptance_without_boundary_delivery_never_claims_coverage"));
assert!(stream_tests.contains("yellowstone_reconnect_replays_from_last_observed_slot_and_counts_duplicate_identity"));
assert!(stream_tests.contains("yellowstone_replay_info_proves_and_clamps_retention_gap_without_lossless_claim"));
assert!(!stream_source.contains("replay_covered_count"));
assert!(!stream_source.contains("replay_coverage_proven_count"));
return;
}