v0.3.15-pre.006-fix.001

This commit is contained in:
2026-09-13 15:47:32 +02:00
parent 0a8ce6e5f9
commit f3ed86e54c
19 changed files with 676 additions and 341 deletions

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-raw-transaction-ingest-desk/src/route_inventory.rs
// version: 1
// version: 2
//! Config-only logical route inventory for Raw Transaction Ingest Desk.
@@ -8,28 +8,74 @@ struct CompositeProfileCatalog {
profile_ids: std::vec::Vec<String>,
}
#[derive(Default)]
struct RouteCapabilities {
has_get_transaction: bool,
has_http_block_scan: bool,
has_yellowstone: bool,
has_standard_logs: bool,
has_standard_block: bool,
has_helius_transaction: bool,
helius_source_missing_secret: bool,
yellowstone_source_missing_secret: bool,
}
impl RouteCapabilities {
fn absorb_transport(&mut self, transport: &ksp_config_lib::ResolvedTransportConfig, network: &str) {
self.has_get_transaction |= http_role_supports_methods(transport.http_settings(), &["getTransaction"]);
self.has_http_block_scan |= http_role_supports_methods(transport.http_settings(), &["getSlot", "getBlocksWithLimit", "getBlock"]);
self.has_yellowstone |= has_yellowstone_grpc(transport, network);
self.has_standard_logs |= has_ws_capability(
transport,
network,
ksp_onchain_transport_lib::WsProtocolKind::SolanaStandard,
ksp_onchain_transport_lib::WsSubscriptionKind::Logs,
);
self.has_standard_block |= has_ws_capability(
transport,
network,
ksp_onchain_transport_lib::WsProtocolKind::SolanaStandard,
ksp_onchain_transport_lib::WsSubscriptionKind::Block,
);
self.has_helius_transaction |= has_ws_capability(
transport,
network,
ksp_onchain_transport_lib::WsProtocolKind::HeliusLaserStream,
ksp_onchain_transport_lib::WsSubscriptionKind::HeliusTransaction,
);
}
}
/// Rebuilds the complete safe route inventory from validated Config without opening any network, Store or Worker resource.
pub(crate) fn build_route_inventory(management: &ksp_config_lib::ConfigManagement, generation: u32) -> ksp_core_lib::Result<crate::RawIngestRouteInventoryDto> {
let catalog = composite_profile_catalog(management);
let catalog = match catalog {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let environment = ksp_config_lib::ConfigEnvironment::load();
let environment = match environment {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
return build_route_inventory_with_environment(management, &environment, generation);
}
fn build_route_inventory_with_environment(
management: &ksp_config_lib::ConfigManagement,
environment: &ksp_config_lib::ConfigEnvironment,
generation: u32,
) -> ksp_core_lib::Result<crate::RawIngestRouteInventoryDto> {
let catalog = composite_profile_catalog(management);
let catalog = match catalog {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let mut profiles = std::vec::Vec::with_capacity(catalog.profile_ids.len());
for profile_id in &catalog.profile_ids {
profiles.push(build_profile_inventory(management, &environment, profile_id.as_str(), profile_id == &catalog.default_profile));
profiles.push(build_profile_inventory(management, environment, profile_id.as_str(), profile_id == &catalog.default_profile));
}
ksp_logging_lib::debug!(
target: crate::TRACING_TARGET,
domain = crate::TRACING_DOMAIN_INVENTORY,
generation,
profile_count = profiles.len(),
"rebuilt Raw Transaction Ingest Desk Config-only route inventory"
"rebuilt Raw Transaction Ingest Desk network-centric Config-only route inventory"
);
return std::result::Result::Ok(crate::RawIngestRouteInventoryDto { default_profile: catalog.default_profile, generation, profiles });
}
@@ -92,14 +138,6 @@ fn build_profile_inventory(
return unavailable_profile(profile_id, is_default, std::option::Option::None, crate::RawIngestRouteUnavailableReason::ProfileUnresolved);
},
};
let transport_profile =
crate::required_composite_component_profile(&composite, crate::COMPOSITE_COMPONENT_ID_TRANSPORT, ksp_config_lib::FILE_ID_STD_TRANSPORT);
let transport_profile = match transport_profile {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => {
return unavailable_profile(profile_id, is_default, std::option::Option::None, crate::RawIngestRouteUnavailableReason::ProfileUnresolved);
},
};
let store_profile = crate::required_composite_component_profile(&composite, crate::COMPOSITE_COMPONENT_ID_STORE, ksp_config_lib::FILE_ID_STD_STORE);
let store_profile = match store_profile {
std::result::Result::Ok(value) => value,
@@ -107,91 +145,152 @@ fn build_profile_inventory(
return unavailable_profile(profile_id, is_default, std::option::Option::None, crate::RawIngestRouteUnavailableReason::ProfileUnresolved);
},
};
let transport = management.engine().resolve_transport_config_profile(&transport_profile, environment);
let store = management.engine().resolve_store_config_profile(&store_profile, environment);
let network_hint = resolved_network_hint(&transport, &store);
if transport.is_err() || store.is_err() {
let reason = resolution_failure_reason(&transport, &store);
return unavailable_profile(profile_id, is_default, network_hint.as_deref(), reason);
}
let transport = match transport {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => {
return unavailable_profile(profile_id, is_default, network_hint.as_deref(), crate::RawIngestRouteUnavailableReason::ProfileUnresolved);
},
};
let store = match store {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => {
return unavailable_profile(profile_id, is_default, network_hint.as_deref(), crate::RawIngestRouteUnavailableReason::ProfileUnresolved);
std::result::Result::Err(error) => {
let reason = resolution_error_reason(&error);
return unavailable_profile(profile_id, is_default, std::option::Option::None, reason);
},
};
let store_network = store.settings().network().as_str().to_owned();
if !transport_matches_network(&transport, store_network.as_str()) {
let network = store.settings().network().as_str().to_owned();
let base_transport_profile =
crate::required_composite_component_profile(&composite, crate::COMPOSITE_COMPONENT_ID_TRANSPORT, ksp_config_lib::FILE_ID_STD_TRANSPORT);
let base_transport_profile = match base_transport_profile {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => {
return unavailable_profile(
profile_id,
is_default,
std::option::Option::Some(network.as_str()),
crate::RawIngestRouteUnavailableReason::ProfileUnresolved,
);
},
};
let base_transport = management.engine().resolve_transport_config_profile(&base_transport_profile, environment);
let base_transport = match base_transport {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => {
return unavailable_profile(profile_id, is_default, std::option::Option::Some(network.as_str()), resolution_error_reason(&error));
},
};
if !transport_matches_network(&base_transport, network.as_str()) {
return unavailable_profile(
profile_id,
is_default,
std::option::Option::Some(store_network.as_str()),
std::option::Option::Some(network.as_str()),
crate::RawIngestRouteUnavailableReason::NetworkMismatch,
);
}
let routes = build_configured_profile_routes(&transport, store_network.as_str());
return crate::RawIngestProfileInventoryDto {
is_default,
network: std::option::Option::Some(store_network),
profile_id: profile_id.to_owned(),
routes,
};
let mut capabilities = RouteCapabilities::default();
capabilities.absorb_transport(&base_transport, network.as_str());
for (component_id, component) in composite.components() {
if component_id == crate::COMPOSITE_COMPONENT_ID_TRANSPORT {
continue;
}
if !component_id.starts_with(crate::COMPOSITE_COMPONENT_ID_TRANSPORT_PREFIX) {
continue;
}
if component_id != crate::COMPOSITE_COMPONENT_ID_TRANSPORT_HELIUS && component_id != crate::COMPOSITE_COMPONENT_ID_TRANSPORT_YELLOWSTONE {
return unavailable_profile(
profile_id,
is_default,
std::option::Option::Some(network.as_str()),
crate::RawIngestRouteUnavailableReason::ProfileUnresolved,
);
}
if component.resolved().file_id().as_str() != ksp_config_lib::FILE_ID_STD_TRANSPORT {
return unavailable_profile(
profile_id,
is_default,
std::option::Option::Some(network.as_str()),
crate::RawIngestRouteUnavailableReason::ProfileUnresolved,
);
}
let resolved = management.engine().resolve_transport_config_profile(component.resolved(), environment);
let resolved = match resolved {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) if error.code() == ksp_config_lib::ERROR_CODE_ENVIRONMENT_VARIABLE_MISSING => {
mark_optional_source_missing_secret(&mut capabilities, component_id.as_str());
continue;
},
std::result::Result::Err(_) => {
return unavailable_profile(
profile_id,
is_default,
std::option::Option::Some(network.as_str()),
crate::RawIngestRouteUnavailableReason::ProfileUnresolved,
);
},
};
if !transport_matches_network(&resolved, network.as_str()) {
return unavailable_profile(
profile_id,
is_default,
std::option::Option::Some(network.as_str()),
crate::RawIngestRouteUnavailableReason::NetworkMismatch,
);
}
capabilities.absorb_transport(&resolved, network.as_str());
}
let routes = build_configured_profile_routes(&capabilities, network.as_str());
return crate::RawIngestProfileInventoryDto { is_default, network: std::option::Option::Some(network), profile_id: profile_id.to_owned(), routes };
}
fn build_configured_profile_routes(transport: &ksp_config_lib::ResolvedTransportConfig, network: &str) -> std::vec::Vec<crate::RawIngestRouteDto> {
let has_get_transaction = http_role_supports_methods(transport.http_settings(), &["getTransaction"]);
let has_http_block_scan = http_role_supports_methods(transport.http_settings(), &["getSlot", "getBlocksWithLimit", "getBlock"]);
let has_yellowstone = has_yellowstone_grpc(transport, network);
let has_standard_logs =
has_ws_capability(transport, network, ksp_onchain_transport_lib::WsProtocolKind::SolanaStandard, ksp_onchain_transport_lib::WsSubscriptionKind::Logs);
let has_standard_block =
has_ws_capability(transport, network, ksp_onchain_transport_lib::WsProtocolKind::SolanaStandard, ksp_onchain_transport_lib::WsSubscriptionKind::Block);
let has_helius_transaction = has_ws_capability(
transport,
network,
ksp_onchain_transport_lib::WsProtocolKind::HeliusLaserStream,
ksp_onchain_transport_lib::WsSubscriptionKind::HeliusTransaction,
);
fn mark_optional_source_missing_secret(capabilities: &mut RouteCapabilities, component_id: &str) {
if component_id == crate::COMPOSITE_COMPONENT_ID_TRANSPORT_HELIUS {
capabilities.helius_source_missing_secret = true;
}
if component_id == crate::COMPOSITE_COMPONENT_ID_TRANSPORT_YELLOWSTONE {
capabilities.yellowstone_source_missing_secret = true;
}
}
fn build_configured_profile_routes(capabilities: &RouteCapabilities, network: &str) -> std::vec::Vec<crate::RawIngestRouteDto> {
let yellowstone_reason = if capabilities.yellowstone_source_missing_secret {
crate::RawIngestRouteUnavailableReason::MissingRequiredSecret
} else {
crate::RawIngestRouteUnavailableReason::MissingYellowstoneGrpc
};
let helius_reason = if capabilities.helius_source_missing_secret {
crate::RawIngestRouteUnavailableReason::MissingRequiredSecret
} else {
crate::RawIngestRouteUnavailableReason::MissingHeliusTransactionCapability
};
return vec![
route_with_requirements(
crate::RawIngestRouteId::YellowstoneHydrated,
network,
&[
(has_yellowstone, crate::RawIngestRouteUnavailableReason::MissingYellowstoneGrpc),
(has_get_transaction, crate::RawIngestRouteUnavailableReason::MissingHttpGetTransaction),
(capabilities.has_yellowstone, yellowstone_reason),
(capabilities.has_get_transaction, crate::RawIngestRouteUnavailableReason::MissingHttpGetTransaction),
],
),
route_with_requirements(
crate::RawIngestRouteId::StandardLogsHydrated,
network,
&[
(has_standard_logs, crate::RawIngestRouteUnavailableReason::MissingWsLogsCapability),
(has_get_transaction, crate::RawIngestRouteUnavailableReason::MissingHttpGetTransaction),
(capabilities.has_standard_logs, crate::RawIngestRouteUnavailableReason::MissingWsLogsCapability),
(capabilities.has_get_transaction, crate::RawIngestRouteUnavailableReason::MissingHttpGetTransaction),
],
),
route_with_requirements(
crate::RawIngestRouteId::StandardBlockDirect,
network,
&[(has_standard_block, crate::RawIngestRouteUnavailableReason::MissingWsBlockCapability)],
&[(capabilities.has_standard_block, crate::RawIngestRouteUnavailableReason::MissingWsBlockCapability)],
),
route_with_requirements(
crate::RawIngestRouteId::HeliusTransactionHydrated,
network,
&[
(has_helius_transaction, crate::RawIngestRouteUnavailableReason::MissingHeliusTransactionCapability),
(has_get_transaction, crate::RawIngestRouteUnavailableReason::MissingHttpGetTransaction),
(capabilities.has_helius_transaction, helius_reason),
(capabilities.has_get_transaction, crate::RawIngestRouteUnavailableReason::MissingHttpGetTransaction),
],
),
route_with_requirements(
crate::RawIngestRouteId::HttpBlockPolling,
network,
&[(has_http_block_scan, crate::RawIngestRouteUnavailableReason::MissingHttpBlockScan)],
&[(capabilities.has_http_block_scan, crate::RawIngestRouteUnavailableReason::MissingHttpBlockScan)],
),
];
}
@@ -222,40 +321,13 @@ fn unavailable_profile(
return crate::RawIngestProfileInventoryDto { is_default, network: network.map(str::to_owned), profile_id: profile_id.to_owned(), routes };
}
fn resolution_failure_reason(
transport: &ksp_core_lib::Result<ksp_config_lib::ResolvedTransportConfig>,
store: &ksp_core_lib::Result<ksp_config_lib::ResolvedStoreConfig>,
) -> crate::RawIngestRouteUnavailableReason {
let transport_missing_secret = match transport {
std::result::Result::Err(error) => error.code() == ksp_config_lib::ERROR_CODE_ENVIRONMENT_VARIABLE_MISSING,
std::result::Result::Ok(_) => false,
};
let store_missing_secret = match store {
std::result::Result::Err(error) => error.code() == ksp_config_lib::ERROR_CODE_ENVIRONMENT_VARIABLE_MISSING,
std::result::Result::Ok(_) => false,
};
if transport_missing_secret || store_missing_secret {
fn resolution_error_reason(error: &ksp_core_lib::Error) -> crate::RawIngestRouteUnavailableReason {
if error.code() == ksp_config_lib::ERROR_CODE_ENVIRONMENT_VARIABLE_MISSING {
return crate::RawIngestRouteUnavailableReason::MissingRequiredSecret;
}
return crate::RawIngestRouteUnavailableReason::ProfileUnresolved;
}
fn resolved_network_hint(
transport: &ksp_core_lib::Result<ksp_config_lib::ResolvedTransportConfig>,
store: &ksp_core_lib::Result<ksp_config_lib::ResolvedStoreConfig>,
) -> std::option::Option<String> {
if let std::result::Result::Ok(store) = store {
return std::option::Option::Some(store.settings().network().as_str().to_owned());
}
if let std::result::Result::Ok(transport) = transport {
let networks = enabled_transport_networks(transport);
if networks.len() == 1 {
return networks.into_iter().next();
}
}
return std::option::Option::None;
}
fn transport_matches_network(transport: &ksp_config_lib::ResolvedTransportConfig, network: &str) -> bool {
let networks = enabled_transport_networks(transport);
return networks.len() == 1 && networks.contains(network);