v0.3.15-pre.006-fix.001
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user