// file: crates/ksp-worker-raw-transaction-ingest-lib/unit_tests/runtime_resources.rs // version: 2 fn grpc_endpoint(cluster: &str) -> std::option::Option { return grpc_endpoint_with_identity(cluster, "yellowstone-fixture", "fixture-provider"); } fn grpc_endpoint_with_identity( cluster: &str, endpoint_name: &str, provider: &str, ) -> std::option::Option { let url = match ksp_onchain_transport_lib::YellowstoneGrpcEndpointUrl::parse("http://127.0.0.1:10000/GRPC-SECRET-CANARY") { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return std::option::Option::None, }; return std::option::Option::Some(ksp_onchain_transport_lib::YellowstoneGrpcEndpointSettings::new( endpoint_name, true, ksp_onchain_transport_lib::YellowstoneGrpcProviderName::new(provider), ksp_onchain_transport_lib::YellowstoneGrpcClusterName::new(cluster), url, ksp_onchain_transport_lib::YellowstoneGrpcSessionSettings::default(), )); } fn http_pool(cluster: &str, role_name: &str, request_kind: &str) -> std::option::Option { let url = match ksp_onchain_transport_lib::HttpEndpointUrl::parse("https://fixture.invalid/rpc?token=HTTP-SECRET-CANARY") { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return std::option::Option::None, }; let role = ksp_onchain_transport_lib::HttpEndpointRoleSettings::new( ksp_onchain_transport_lib::HttpRoleName::new(role_name), true, std::vec![ksp_onchain_transport_lib::HttpRequestKind::new(request_kind)], 10, ksp_onchain_transport_lib::HttpRoleLimits::new( std::option::Option::None, std::option::Option::None, std::option::Option::None, std::option::Option::None, ), ); let endpoint = ksp_onchain_transport_lib::HttpEndpointSettings::new( "http-fixture", true, ksp_onchain_transport_lib::HttpProviderName::new("fixture-provider"), ksp_onchain_transport_lib::HttpClusterName::new(cluster), url, std::time::Duration::from_secs(1), std::time::Duration::from_secs(2), std::option::Option::Some(4), std::vec![role], ); let settings = ksp_onchain_transport_lib::HttpTransportSettings::new( std::vec![endpoint], ksp_onchain_transport_lib::HttpRetrySettings::new(1, std::time::Duration::from_millis(10), std::time::Duration::from_millis(20)), ); return match ksp_onchain_transport_lib::HttpTransportPool::new(settings) { std::result::Result::Ok(value) => std::option::Option::Some(value), std::result::Result::Err(_) => std::option::Option::None, }; } fn transaction_request( commitment: std::option::Option, ) -> std::option::Option { let name = match ksp_onchain_transport_lib::YellowstoneSubscribeFilterName::new("tx-fixture") { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return std::option::Option::None, }; let mut request = ksp_onchain_transport_lib::YellowstoneSubscribeRequest::new(); if request.insert_transaction_filter(name, ksp_onchain_transport_lib::YellowstoneSubscribeTransactionFilter::new()).is_err() { return std::option::Option::None; } request.set_commitment(commitment); return std::option::Option::Some(request); } struct SignalViewFixture { created_at: std::option::Option, family: super::RawTransactionIngestSourceFamily, filters: std::vec::Vec, index: u64, signature: ksp_onchain_transport_lib::YellowstoneTransactionSignature, slot: u64, } impl super::RawTransactionIngestYellowstoneSignalView for SignalViewFixture { fn created_at(&self) -> std::option::Option { return self.created_at; } fn family(&self) -> super::RawTransactionIngestSourceFamily { return self.family; } fn filters(&self) -> &[ksp_onchain_transport_lib::YellowstoneSubscribeFilterName] { return self.filters.as_slice(); } fn index(&self) -> u64 { return self.index; } fn signature(&self) -> ksp_onchain_transport_lib::YellowstoneTransactionSignature { return self.signature; } fn slot(&self) -> u64 { return self.slot; } } fn filter_names(values: &[&str]) -> std::option::Option> { let mut filters = std::vec::Vec::with_capacity(values.len()); for value in values { let filter = match ksp_onchain_transport_lib::YellowstoneSubscribeFilterName::new(*value) { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return std::option::Option::None, }; filters.push(filter); } return std::option::Option::Some(filters); } fn signal_source() -> std::option::Option { let endpoint = match grpc_endpoint("devnet") { std::option::Option::Some(value) => value, std::option::Option::None => return std::option::Option::None, }; let channel = match ksp_onchain_transport_lib::YellowstoneGrpcChannel::prepare(&endpoint) { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return std::option::Option::None, }; let request = match transaction_request(std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Confirmed)) { std::option::Option::Some(value) => value, std::option::Option::None => return std::option::Option::None, }; let pool = match http_pool("devnet", "hydration", "get_transaction") { std::option::Option::Some(value) => value, std::option::Option::None => return std::option::Option::None, }; return match crate::RawTransactionIngestYellowstoneSource::new(channel, request, pool, ksp_onchain_transport_lib::HttpRoleName::new("hydration")) { std::result::Result::Ok(value) => std::option::Option::Some(value), std::result::Result::Err(_) => std::option::Option::None, }; } #[tokio::test(flavor = "current_thread")] async fn pre_002_source_accepts_matching_confirmed_transaction_and_get_transaction_route_without_io() { let endpoint = match grpc_endpoint("devnet") { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let channel = match ksp_onchain_transport_lib::YellowstoneGrpcChannel::prepare(&endpoint) { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return, }; let request = match transaction_request(std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Confirmed)) { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let pool = match http_pool("devnet", "hydration", "get_transaction") { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let source = crate::RawTransactionIngestYellowstoneSource::new(channel, request, pool, ksp_onchain_transport_lib::HttpRoleName::new("hydration")); assert!(source.is_ok()); return; } #[tokio::test(flavor = "current_thread")] async fn pre_002_source_rejects_processed_and_implicit_commitment() { for commitment in [std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Processed), std::option::Option::None] { let endpoint = match grpc_endpoint("devnet") { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let channel = match ksp_onchain_transport_lib::YellowstoneGrpcChannel::prepare(&endpoint) { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return, }; let request = match transaction_request(commitment) { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let pool = match http_pool("devnet", "hydration", "get_transaction") { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let source = crate::RawTransactionIngestYellowstoneSource::new(channel, request, pool, ksp_onchain_transport_lib::HttpRoleName::new("hydration")); let error = match source { std::result::Result::Ok(_) => return, std::result::Result::Err(error) => error, }; assert_eq!(error.code(), crate::ERROR_CODE_RAW_TRANSACTION_INGEST_RUNTIME_INVALID); assert!(error.context().iter().any(|context| return context.value() == "runtime_resources.hydration_commitment_invalid")); } return; } #[tokio::test(flavor = "current_thread")] async fn pre_002_source_requires_ingestion_bearing_filter_family() { let endpoint = match grpc_endpoint("devnet") { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let channel = match ksp_onchain_transport_lib::YellowstoneGrpcChannel::prepare(&endpoint) { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return, }; let mut request = ksp_onchain_transport_lib::YellowstoneSubscribeRequest::new(); request.set_commitment(std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Finalized)); let pool = match http_pool("devnet", "hydration", "get_transaction") { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let source = crate::RawTransactionIngestYellowstoneSource::new(channel, request, pool, ksp_onchain_transport_lib::HttpRoleName::new("hydration")); let error = match source { std::result::Result::Ok(_) => return, std::result::Result::Err(error) => error, }; assert_eq!(error.code(), crate::ERROR_CODE_RAW_TRANSACTION_INGEST_RUNTIME_INVALID); assert!(error.context().iter().any(|context| return context.value() == "runtime_resources.ingestion_filter_missing")); return; } #[tokio::test(flavor = "current_thread")] async fn pre_002_source_rejects_missing_hydration_capability_and_cross_transport_network() { for (http_cluster, request_kind, expected_condition) in [ ("devnet", "get_balance", "runtime_resources.hydration_role_unsupported"), ("mainnet", "get_transaction", "runtime_resources.transport_network_mismatch"), ] { let endpoint = match grpc_endpoint("devnet") { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let channel = match ksp_onchain_transport_lib::YellowstoneGrpcChannel::prepare(&endpoint) { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return, }; let request = match transaction_request(std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Confirmed)) { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let pool = match http_pool(http_cluster, "hydration", request_kind) { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let source = crate::RawTransactionIngestYellowstoneSource::new(channel, request, pool, ksp_onchain_transport_lib::HttpRoleName::new("hydration")); let error = match source { std::result::Result::Ok(_) => return, std::result::Result::Err(error) => error, }; assert_eq!(error.code(), crate::ERROR_CODE_RAW_TRANSACTION_INGEST_RUNTIME_INVALID); assert!(error.context().iter().any(|context| return context.value() == expected_condition)); } return; } #[tokio::test(flavor = "current_thread")] async fn pre_002_runtime_resource_debug_is_safe_and_exposes_no_client_inner() { let endpoint = match grpc_endpoint("devnet") { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let channel = match ksp_onchain_transport_lib::YellowstoneGrpcChannel::prepare(&endpoint) { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return, }; let request = match transaction_request(std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Confirmed)) { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let pool = match http_pool("devnet", "hydration", "get_transaction") { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let source = match crate::RawTransactionIngestYellowstoneSource::new(channel, request, pool, ksp_onchain_transport_lib::HttpRoleName::new("hydration")) { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return, }; let resources = crate::RawTransactionIngestRuntimeResources::new(source); let debug = std::format!("{resources:?}"); assert!(debug.contains("RawTransactionIngestRuntimeResources")); assert!(debug.contains("devnet")); assert!(!debug.contains("GRPC-SECRET-CANARY")); assert!(!debug.contains("HTTP-SECRET-CANARY")); assert!(!debug.contains("127.0.0.1")); assert!(!debug.contains("fixture.invalid")); assert!(!debug.contains("tx-fixture")); return; } #[tokio::test(flavor = "current_thread")] async fn pre_002_runtime_resources_reject_worker_network_mismatch_without_starting_source() { let endpoint = match grpc_endpoint("devnet") { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let channel = match ksp_onchain_transport_lib::YellowstoneGrpcChannel::prepare(&endpoint) { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return, }; let request = match transaction_request(std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Confirmed)) { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let pool = match http_pool("devnet", "hydration", "get_transaction") { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let source = match crate::RawTransactionIngestYellowstoneSource::new(channel, request, pool, ksp_onchain_transport_lib::HttpRoleName::new("hydration")) { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return, }; let resources = crate::RawTransactionIngestRuntimeResources::new(source); let network = match ksp_store_lib::RawNetworkId::new("mainnet") { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return, }; let error = match resources.validate_network(&network) { std::result::Result::Ok(()) => return, std::result::Result::Err(error) => error, }; assert_eq!(error.code(), crate::ERROR_CODE_RAW_TRANSACTION_INGEST_RUNTIME_INVALID); assert!(error.context().iter().any(|context| return context.value() == "runtime_resources.worker_network_mismatch")); return; } #[tokio::test(flavor = "current_thread")] async fn pre_003_transaction_signal_fixture_preserves_exact_source_neutral_identity() { let source = match signal_source() { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let filters = match filter_names(&["filter-b", "filter-a", "filter-a"]) { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let created_at = match ksp_onchain_transport_lib::YellowstoneUpdateTimestamp::new(1_760_000_123, 456_000_000) { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return, }; let fixture = SignalViewFixture { created_at: std::option::Option::Some(created_at), family: super::RawTransactionIngestSourceFamily::Transaction, filters, index: 7, signature: ksp_onchain_transport_lib::YellowstoneTransactionSignature::new([0xAB; 64]), slot: 42, }; let signal = super::project_yellowstone_signal(&source, &fixture); assert_eq!(signal.family, super::RawTransactionIngestSourceFamily::Transaction); assert_eq!(signal.network.as_str(), "devnet"); assert_eq!(signal.signature.as_bytes(), &[0xAB; 64]); assert_eq!(signal.slot, 42); assert_eq!(signal.transaction_index, std::option::Option::Some(7)); assert_eq!(signal.route.provider.as_str(), "fixture-provider"); assert_eq!(signal.route.endpoint_id.as_str(), "yellowstone-fixture"); assert_eq!(signal.matched_filter_count, 3); assert_eq!( signal.matched_filter_fingerprint, [ 0x20, 0x83, 0x1d, 0xc8, 0x37, 0x8b, 0x60, 0x70, 0xf9, 0x1d, 0x9d, 0xe6, 0xd3, 0xa1, 0xd2, 0xb3, 0xd7, 0x72, 0x98, 0xe3, 0xad, 0xa7, 0x6c, 0x01, 0xfa, 0xa3, 0x08, 0x26, 0xff, 0xab, 0xcd, 0x84, ] ); assert_eq!(signal.created_at, std::option::Option::Some(super::RawTransactionIngestSourceTimestamp { nanos: 456_000_000, seconds: 1_760_000_123 })); return; } #[tokio::test(flavor = "current_thread")] async fn pre_003_transaction_status_signal_has_no_payload_or_remote_error_material() { let source = match signal_source() { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let filters = match filter_names(&["status-secret-canary"]) { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let fixture = SignalViewFixture { created_at: std::option::Option::None, family: super::RawTransactionIngestSourceFamily::TransactionStatus, filters, index: 9, signature: ksp_onchain_transport_lib::YellowstoneTransactionSignature::new([0xCD; 64]), slot: 84, }; let signal = super::project_yellowstone_signal(&source, &fixture); assert_eq!(signal.family, super::RawTransactionIngestSourceFamily::TransactionStatus); assert_eq!(signal.signature.as_bytes(), &[0xCD; 64]); assert_eq!(signal.slot, 84); assert_eq!(signal.transaction_index, std::option::Option::Some(9)); assert_eq!(signal.created_at, std::option::Option::None); let debug = std::format!("{signal:?}"); assert!(!debug.contains("status-secret-canary")); assert!(debug.contains("signature_bytes")); assert!(!debug.contains("YellowstoneTransactionError")); assert!(!debug.contains("transaction_body")); assert!(!debug.contains("transaction_meta")); return; } #[tokio::test(flavor = "current_thread")] async fn pre_003_filter_fingerprint_is_order_and_duplicate_insensitive() { let source = match signal_source() { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let first_filters = match filter_names(&["filter-b", "filter-a", "filter-a"]) { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let second_filters = match filter_names(&["filter-a", "filter-b"]) { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let first = SignalViewFixture { created_at: std::option::Option::None, family: super::RawTransactionIngestSourceFamily::Transaction, filters: first_filters, index: 1, signature: ksp_onchain_transport_lib::YellowstoneTransactionSignature::new([1; 64]), slot: 1, }; let second = SignalViewFixture { created_at: std::option::Option::None, family: super::RawTransactionIngestSourceFamily::Transaction, filters: second_filters, index: 1, signature: ksp_onchain_transport_lib::YellowstoneTransactionSignature::new([1; 64]), slot: 1, }; let first_signal = super::project_yellowstone_signal(&source, &first); let second_signal = super::project_yellowstone_signal(&source, &second); assert_eq!(first_signal.matched_filter_fingerprint, second_signal.matched_filter_fingerprint); assert_eq!(first_signal.matched_filter_count, 3); assert_eq!(second_signal.matched_filter_count, 2); return; } #[tokio::test(flavor = "current_thread")] async fn pre_003_source_rejects_route_identity_that_cannot_become_safe_provenance() { for (endpoint_name, provider, expected_condition) in [ ("yellowstone-fixture", "fixture/provider", "runtime_resources.yellowstone_provider_unrepresentable"), ("yellowstone/fixture", "fixture-provider", "runtime_resources.yellowstone_endpoint_unrepresentable"), ] { let endpoint = match grpc_endpoint_with_identity("devnet", endpoint_name, provider) { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let channel = match ksp_onchain_transport_lib::YellowstoneGrpcChannel::prepare(&endpoint) { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return, }; let request = match transaction_request(std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Confirmed)) { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let pool = match http_pool("devnet", "hydration", "get_transaction") { std::option::Option::Some(value) => value, std::option::Option::None => return, }; let result = crate::RawTransactionIngestYellowstoneSource::new(channel, request, pool, ksp_onchain_transport_lib::HttpRoleName::new("hydration")); let error = match result { std::result::Result::Ok(_) => return, std::result::Result::Err(error) => error, }; assert_eq!(error.code(), crate::ERROR_CODE_RAW_TRANSACTION_INGEST_RUNTIME_INVALID); assert!(error.context().iter().any(|context| return context.value() == expected_condition)); } return; }