v0.2.9-pre.011

This commit is contained in:
2026-08-24 19:53:45 +02:00
parent 3198cc5666
commit 21ed5f88da
14 changed files with 2285 additions and 2121 deletions

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-config-lib/src/lib.rs
// version: 17
// version: 18
#![warn(missing_docs)]
#![deny(unreachable_pub)]
@@ -9,8 +9,9 @@
//!
//! The `0.1.3` surface owns bootstrap roots, the logical file registry, JSON/JSON Schema validation, standard-document profiles, generic composites and
//! KSP/KSPB environment resolution through process + `.env` + fallback precedence. Resolved values preserve real/safe representations, sensitivity and
//! provenance. Standard Logging, HTTP Transport and Wallet documents map explicitly to their runtime consumer contracts, while the management surface
//! provides typed Logging mutation, safe environment reports, explicit privileged reveal calls and atomic JSON/`.env` persistence.
//! provenance. Standard Logging, on-chain Transport (HTTP/WebSocket/Yellowstone gRPC) and Wallet documents map explicitly to their runtime consumer
//! contracts, while the management surface provides typed Logging mutation, safe environment reports, explicit privileged reveal calls and atomic
//! JSON/`.env` persistence.
mod bootstrap;
mod composite;
@@ -154,9 +155,9 @@ pub use self::registry::DEFAULT_COMPOSITE_SCHEMA_FILENAME;
pub use self::registry::DEFAULT_STD_LOGGING_FILENAME;
/// Default physical filename for the standard Logging JSON Schema document.
pub use self::registry::DEFAULT_STD_LOGGING_SCHEMA_FILENAME;
/// Default physical filename for the standard HTTP + WebSocket Transport configuration document.
/// Default physical filename for the standard HTTP + WebSocket + Yellowstone gRPC Transport configuration document.
pub use self::registry::DEFAULT_STD_TRANSPORT_FILENAME;
/// Default physical filename for the standard HTTP + WebSocket Transport JSON Schema document.
/// Default physical filename for the standard HTTP + WebSocket + Yellowstone gRPC Transport JSON Schema document.
pub use self::registry::DEFAULT_STD_TRANSPORT_SCHEMA_FILENAME;
/// Default physical filename for the standard Wallet configuration document.
pub use self::registry::DEFAULT_STD_WALLET_FILENAME;
@@ -168,13 +169,13 @@ pub use self::registry::FILE_ID_COMPOSITE_KSP_APP_WALLET_DESK;
pub use self::registry::FILE_ID_SCHEMA_COMPOSITE;
/// Logical file identifier for the standard Logging JSON Schema document.
pub use self::registry::FILE_ID_SCHEMA_STD_LOGGING;
/// Logical file identifier for the standard HTTP + WebSocket Transport JSON Schema document.
/// Logical file identifier for the standard HTTP + WebSocket + Yellowstone gRPC Transport JSON Schema document.
pub use self::registry::FILE_ID_SCHEMA_STD_TRANSPORT;
/// Logical file identifier for the standard Wallet JSON Schema document.
pub use self::registry::FILE_ID_SCHEMA_STD_WALLET;
/// Logical file identifier for the standard Logging configuration document.
pub use self::registry::FILE_ID_STD_LOGGING;
/// Logical file identifier for the standard HTTP + WebSocket Transport configuration document.
/// Logical file identifier for the standard HTTP + WebSocket + Yellowstone gRPC Transport configuration document.
pub use self::registry::FILE_ID_STD_TRANSPORT;
/// Logical file identifier for the standard Wallet configuration document.
pub use self::registry::FILE_ID_STD_WALLET;
@@ -188,7 +189,7 @@ pub use self::sensitivity::REDACTED_CONFIG_VALUE;
pub use self::sensitivity::ResolvedConfigJson;
/// One resolved Config string preserving real/safe representations and provenance.
pub use self::sensitivity::ResolvedConfigText;
/// Effective standard Transport configuration mapped to HTTP and optional WebSocket runtime settings.
/// Effective standard Transport configuration mapped to HTTP plus optional WebSocket and Yellowstone gRPC runtime settings.
pub use self::transport::ResolvedTransportConfig;
/// Effective standard Wallet configuration resolved to validated filesystem roots.
pub use self::wallet::ResolvedWalletConfig;

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-config-lib/src/registry.rs
// version: 9
// version: 10
/// Bootstrap argument used to replace a known Config filename mapping.
pub const ARG_FILE_MAP: &str = "--filemap";
@@ -11,9 +11,9 @@ pub const DEFAULT_COMPOSITE_SCHEMA_FILENAME: &str = "composite.schema.json";
pub const DEFAULT_STD_LOGGING_FILENAME: &str = "std.logging.json";
/// Default physical filename for the standard Logging JSON Schema document.
pub const DEFAULT_STD_LOGGING_SCHEMA_FILENAME: &str = "std.logging.schema.json";
/// Default physical filename for the standard HTTP + WebSocket Transport configuration document.
/// Default physical filename for the standard HTTP + WebSocket + Yellowstone gRPC Transport configuration document.
pub const DEFAULT_STD_TRANSPORT_FILENAME: &str = "std.transport.json";
/// Default physical filename for the standard HTTP + WebSocket Transport JSON Schema document.
/// Default physical filename for the standard HTTP + WebSocket + Yellowstone gRPC Transport JSON Schema document.
pub const DEFAULT_STD_TRANSPORT_SCHEMA_FILENAME: &str = "std.transport.schema.json";
/// Default physical filename for the standard Wallet configuration document.
pub const DEFAULT_STD_WALLET_FILENAME: &str = "std.wallet.json";
@@ -25,13 +25,13 @@ pub const FILE_ID_COMPOSITE_KSP_APP_WALLET_DESK: &str = "cfg.composite.ksp-app-w
pub const FILE_ID_SCHEMA_COMPOSITE: &str = "schema.composite";
/// Logical file identifier for the standard Logging JSON Schema document.
pub const FILE_ID_SCHEMA_STD_LOGGING: &str = "schema.std.logging";
/// Logical file identifier for the standard HTTP + WebSocket Transport JSON Schema document.
/// Logical file identifier for the standard HTTP + WebSocket + Yellowstone gRPC Transport JSON Schema document.
pub const FILE_ID_SCHEMA_STD_TRANSPORT: &str = "schema.std.transport";
/// Logical file identifier for the standard Wallet JSON Schema document.
pub const FILE_ID_SCHEMA_STD_WALLET: &str = "schema.std.wallet";
/// Logical file identifier for the standard Logging configuration document.
pub const FILE_ID_STD_LOGGING: &str = "cfg.std.logging";
/// Logical file identifier for the standard HTTP + WebSocket Transport configuration document.
/// Logical file identifier for the standard HTTP + WebSocket + Yellowstone gRPC Transport configuration document.
pub const FILE_ID_STD_TRANSPORT: &str = "cfg.std.transport";
/// Logical file identifier for the standard Wallet configuration document.
pub const FILE_ID_STD_WALLET: &str = "cfg.std.wallet";

View File

@@ -1,7 +1,7 @@
// file: crates/ksp-config-lib/src/transport.rs
// version: 4
// version: 5
/// Effective standard on-chain Transport configuration resolved from Config and mapped to HTTP and optional WebSocket runtime contracts.
/// Effective standard on-chain Transport configuration resolved from Config and mapped to HTTP plus optional WebSocket and Yellowstone gRPC runtime contracts.
#[derive(Clone, Eq, PartialEq)]
pub struct ResolvedTransportConfig {
file_id: crate::ConfigFileId,
@@ -11,6 +11,7 @@ pub struct ResolvedTransportConfig {
effective: crate::ResolvedConfigJson,
settings: ksp_onchain_transport_lib::HttpTransportSettings,
ws_settings: std::option::Option<ksp_onchain_transport_lib::WsTransportSettings>,
grpc_settings: std::option::Option<ksp_onchain_transport_lib::YellowstoneGrpcTransportSettings>,
}
impl ResolvedTransportConfig {
@@ -61,7 +62,7 @@ impl ResolvedTransportConfig {
return &self.settings;
}
/// Returns validated WebSocket Transport settings when the selected document uses format V2.
/// Returns validated WebSocket Transport settings when the selected document uses format V2 or V3.
///
/// Backward-compatible V1 HTTP-only documents return [`std::option::Option::None`].
#[must_use]
@@ -69,19 +70,42 @@ impl ResolvedTransportConfig {
return self.ws_settings.as_ref();
}
/// Returns validated Yellowstone gRPC Transport settings when the selected V3 profile declares gRPC endpoints.
///
/// V1/V2 documents and V3 profiles without `grpc_endpoints` return [`std::option::Option::None`].
#[must_use]
pub fn grpc_settings(&self) -> std::option::Option<&ksp_onchain_transport_lib::YellowstoneGrpcTransportSettings> {
return self.grpc_settings.as_ref();
}
/// Consumes this resolved Config and returns the mapped runtime HTTP Transport settings.
#[must_use]
pub fn into_settings(self) -> ksp_onchain_transport_lib::HttpTransportSettings {
return self.settings;
}
/// Consumes this resolved Config and returns both HTTP and optional WebSocket runtime settings.
/// Consumes this resolved Config and returns HTTP plus optional WebSocket runtime settings.
///
/// This compatibility accessor intentionally preserves the V2 tuple shape. Use [`Self::into_all_transport_settings`] when Yellowstone gRPC settings are
/// also required.
#[must_use]
pub fn into_transport_settings(
self,
) -> (ksp_onchain_transport_lib::HttpTransportSettings, std::option::Option<ksp_onchain_transport_lib::WsTransportSettings>) {
return (self.settings, self.ws_settings);
}
/// Consumes this resolved Config and returns HTTP plus optional WebSocket and Yellowstone gRPC runtime settings.
#[must_use]
pub fn into_all_transport_settings(
self,
) -> (
ksp_onchain_transport_lib::HttpTransportSettings,
std::option::Option<ksp_onchain_transport_lib::WsTransportSettings>,
std::option::Option<ksp_onchain_transport_lib::YellowstoneGrpcTransportSettings>,
) {
return (self.settings, self.ws_settings, self.grpc_settings);
}
}
impl std::fmt::Debug for ResolvedTransportConfig {
@@ -94,15 +118,17 @@ impl std::fmt::Debug for ResolvedTransportConfig {
.field("selection_source", &self.selection_source)
.field("effective", &self.effective)
.field("has_ws_settings", &self.ws_settings.is_some())
.field("has_grpc_settings", &self.grpc_settings.is_some())
.finish_non_exhaustive();
}
}
impl crate::ConfigDocumentEngine {
/// Loads the standard Transport document, selects a profile, resolves environment placeholders and maps HTTP plus optional WebSocket runtime settings.
/// Loads the standard Transport document, selects a profile, resolves environment placeholders and maps HTTP plus optional WebSocket and Yellowstone
/// gRPC runtime settings.
///
/// `requested_profile = None` uses the document `default_profile`; `Some(profile_id)` requests an explicit profile. Secret endpoint URLs are allowed
/// because Transport URL wrappers own runtime redaction. V1 documents remain HTTP-only; V2 documents require WebSocket defaults and endpoints.
/// because Transport URL wrappers own runtime redaction. V1 remains HTTP-only, V2 adds WebSocket and V3 can additionally map Yellowstone gRPC.
pub fn load_resolved_transport_config(
&self,
requested_profile: std::option::Option<&str>,
@@ -121,7 +147,8 @@ impl crate::ConfigDocumentEngine {
return resolve_transport_profile(&profile, environment);
}
/// Maps an already resolved standard Transport profile to HTTP plus optional WebSocket runtime adapters while preserving selection provenance.
/// Maps an already resolved standard Transport profile to HTTP plus optional WebSocket and Yellowstone gRPC runtime adapters while preserving
/// selection provenance.
///
/// This entry point is intended for profiles selected by a composite. The profile must reference `cfg.std.transport`.
pub fn resolve_transport_config_profile(
@@ -148,9 +175,13 @@ struct EffectiveTransportSource {
retry: EffectiveRetrySource,
#[serde(default)]
ws_defaults: std::option::Option<EffectiveWsSessionSource>,
#[serde(default)]
grpc_defaults: std::option::Option<EffectiveGrpcSessionSource>,
endpoints: std::vec::Vec<EffectiveEndpointSource>,
#[serde(default)]
ws_endpoints: std::option::Option<std::vec::Vec<EffectiveWsEndpointSource>>,
#[serde(default)]
grpc_endpoints: std::option::Option<std::vec::Vec<EffectiveGrpcEndpointSource>>,
}
#[derive(serde::Deserialize)]
@@ -255,6 +286,72 @@ struct EffectiveWsReconnectOverrideSource {
max_backoff_ms: std::option::Option<u64>,
}
#[derive(serde::Deserialize)]
#[serde(deny_unknown_fields)]
struct EffectiveGrpcReconnectSource {
max_retries: u32,
initial_backoff_ms: u64,
max_backoff_ms: u64,
}
#[derive(serde::Deserialize)]
#[serde(deny_unknown_fields)]
struct EffectiveGrpcReconnectOverrideSource {
max_retries: std::option::Option<u32>,
initial_backoff_ms: std::option::Option<u64>,
max_backoff_ms: std::option::Option<u64>,
}
#[derive(serde::Deserialize)]
#[serde(deny_unknown_fields)]
struct EffectiveGrpcSessionSource {
connect_timeout_ms: u64,
unary_timeout_ms: u64,
close_timeout_ms: u64,
reconnect: EffectiveGrpcReconnectSource,
request_channel_capacity: usize,
update_channel_capacity: usize,
max_inbound_message_size_bytes: usize,
max_outbound_message_size_bytes: usize,
}
#[derive(serde::Deserialize)]
#[serde(deny_unknown_fields)]
struct EffectiveGrpcSessionOverrideSource {
connect_timeout_ms: std::option::Option<u64>,
unary_timeout_ms: std::option::Option<u64>,
close_timeout_ms: std::option::Option<u64>,
reconnect: std::option::Option<EffectiveGrpcReconnectOverrideSource>,
request_channel_capacity: std::option::Option<usize>,
update_channel_capacity: std::option::Option<usize>,
max_inbound_message_size_bytes: std::option::Option<usize>,
max_outbound_message_size_bytes: std::option::Option<usize>,
}
#[derive(serde::Deserialize)]
#[serde(deny_unknown_fields)]
struct EffectiveGrpcMetadataSource {
key: String,
value: String,
}
#[derive(serde::Deserialize)]
#[serde(deny_unknown_fields)]
struct EffectiveGrpcEndpointSource {
name: String,
enabled: bool,
provider: String,
cluster: String,
protocol: String,
url: String,
#[serde(default)]
metadata: std::vec::Vec<EffectiveGrpcMetadataSource>,
#[serde(default)]
secret_metadata: std::vec::Vec<EffectiveGrpcMetadataSource>,
#[serde(default)]
session: std::option::Option<EffectiveGrpcSessionOverrideSource>,
}
fn resolve_transport_profile(profile: &crate::ResolvedConfigProfile, environment: &crate::ConfigEnvironment) -> ksp_core_lib::Result<ResolvedTransportConfig> {
ksp_logging_lib::trace!(target: crate::TRACING_TARGET, profile_id = profile.profile_id(), "mapping standard Transport Config profile");
let effective = profile.resolve_effective_environment_detailed(environment);
@@ -294,16 +391,26 @@ fn resolve_transport_profile(profile: &crate::ResolvedConfigProfile, environment
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let grpc_settings = map_optional_grpc_settings(format_version, source.grpc_defaults, source.grpc_endpoints, &effective, profile);
let grpc_settings = match grpc_settings {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let ws_endpoint_count = match ws_settings.as_ref() {
std::option::Option::Some(value) => value.endpoints().len(),
std::option::Option::None => 0_usize,
};
let grpc_endpoint_count = match grpc_settings.as_ref() {
std::option::Option::Some(value) => value.endpoints().len(),
std::option::Option::None => 0_usize,
};
ksp_logging_lib::debug!(
target: crate::TRACING_TARGET,
profile_id = profile.profile_id(),
format_version,
http_endpoint_count = settings.endpoints().len(),
ws_endpoint_count,
grpc_endpoint_count,
"mapped standard Transport Config to runtime settings"
);
return std::result::Result::Ok(ResolvedTransportConfig {
@@ -314,6 +421,7 @@ fn resolve_transport_profile(profile: &crate::ResolvedConfigProfile, environment
effective,
settings,
ws_settings,
grpc_settings,
});
}
@@ -328,18 +436,22 @@ fn map_optional_ws_settings(
if defaults.is_some() || sources.is_some() {
std::result::Result::Err(effective_error(profile, "Transport V1 must remain HTTP-only"))
} else {
ksp_logging_lib::trace!(target: crate::TRACING_TARGET, profile_id = profile.profile_id(), "mapped backward-compatible Transport V1 without WebSocket settings");
ksp_logging_lib::trace!(
target: crate::TRACING_TARGET,
profile_id = profile.profile_id(),
"mapped backward-compatible Transport V1 without WebSocket settings"
);
std::result::Result::Ok(std::option::Option::None)
}
},
2 => {
2 | 3 => {
let defaults = match defaults {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::result::Result::Err(effective_error(profile, "Transport V2 requires ws_defaults")),
std::option::Option::None => return std::result::Result::Err(effective_error(profile, "Transport V2/V3 requires ws_defaults")),
};
let sources = match sources {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::result::Result::Err(effective_error(profile, "Transport V2 profile requires ws_endpoints")),
std::option::Option::None => return std::result::Result::Err(effective_error(profile, "Transport V2/V3 profile requires ws_endpoints")),
};
let endpoints = map_ws_endpoints(sources, &defaults, profile);
let endpoints = match endpoints {
@@ -360,6 +472,283 @@ fn map_optional_ws_settings(
};
}
fn map_optional_grpc_settings(
format_version: u32,
defaults: std::option::Option<EffectiveGrpcSessionSource>,
sources: std::option::Option<std::vec::Vec<EffectiveGrpcEndpointSource>>,
effective: &crate::ResolvedConfigJson,
profile: &crate::ResolvedConfigProfile,
) -> ksp_core_lib::Result<std::option::Option<ksp_onchain_transport_lib::YellowstoneGrpcTransportSettings>> {
return match format_version {
1 | 2 => {
if defaults.is_some() || sources.is_some() {
std::result::Result::Err(effective_error(profile, "Transport V1/V2 must not define Yellowstone gRPC settings"))
} else {
std::result::Result::Ok(std::option::Option::None)
}
},
3 => {
let defaults = match defaults {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::result::Result::Err(effective_error(profile, "Transport V3 requires grpc_defaults")),
};
let sources = match sources {
std::option::Option::Some(value) => value,
std::option::Option::None => return std::result::Result::Ok(std::option::Option::None),
};
let endpoints = map_grpc_endpoints(sources, &defaults, effective, profile);
let endpoints = match endpoints {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let settings = ksp_onchain_transport_lib::YellowstoneGrpcTransportSettings::new(endpoints);
if let std::result::Result::Err(error) = settings.validate() {
return std::result::Result::Err(transport_contract_error(
profile,
"effective Yellowstone gRPC Transport settings fail the Transport runtime contract",
&error,
));
}
std::result::Result::Ok(std::option::Option::Some(settings))
},
_ => std::result::Result::Err(effective_error(profile, "effective Transport format_version is unsupported")),
};
}
fn map_grpc_endpoints(
sources: std::vec::Vec<EffectiveGrpcEndpointSource>,
defaults: &EffectiveGrpcSessionSource,
effective: &crate::ResolvedConfigJson,
profile: &crate::ResolvedConfigProfile,
) -> ksp_core_lib::Result<std::vec::Vec<ksp_onchain_transport_lib::YellowstoneGrpcEndpointSettings>> {
let mut endpoints = std::vec::Vec::<ksp_onchain_transport_lib::YellowstoneGrpcEndpointSettings>::with_capacity(sources.len());
for (endpoint_index, source) in sources.into_iter().enumerate() {
let endpoint_name = source.name.clone();
if source.protocol != "solana_yellowstone" {
return std::result::Result::Err(
effective_error(profile, "effective gRPC protocol is unsupported")
.with_context("endpoint_name", endpoint_name)
.with_context("grpc_protocol", source.protocol),
);
}
let url = ksp_onchain_transport_lib::YellowstoneGrpcEndpointUrl::parse(source.url);
let url = match url {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => {
return std::result::Result::Err(
transport_contract_error(profile, "effective Yellowstone gRPC endpoint URL is invalid", &error)
.with_context("endpoint_name", endpoint_name),
);
},
};
let session = map_grpc_session_settings(defaults, source.session.as_ref(), profile, endpoint_name.as_str());
let session = match session {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let metadata = map_grpc_metadata(source.metadata, source.secret_metadata, effective, profile, endpoint_name.as_str(), endpoint_index);
let metadata = match metadata {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let endpoint = ksp_onchain_transport_lib::YellowstoneGrpcEndpointSettings::new(
source.name,
source.enabled,
ksp_onchain_transport_lib::YellowstoneGrpcProviderName::new(source.provider),
ksp_onchain_transport_lib::YellowstoneGrpcClusterName::new(source.cluster),
url,
session,
);
let endpoint = endpoint.with_metadata(metadata);
let endpoint = match endpoint {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => {
return std::result::Result::Err(
transport_contract_error(profile, "effective Yellowstone gRPC metadata fail the Transport runtime contract", &error)
.with_context("endpoint_name", endpoint_name),
);
},
};
endpoints.push(endpoint);
}
return std::result::Result::Ok(endpoints);
}
fn map_grpc_session_settings(
defaults: &EffectiveGrpcSessionSource,
overrides: std::option::Option<&EffectiveGrpcSessionOverrideSource>,
profile: &crate::ResolvedConfigProfile,
endpoint_name: &str,
) -> ksp_core_lib::Result<ksp_onchain_transport_lib::YellowstoneGrpcSessionSettings> {
let mut connect_timeout_ms = defaults.connect_timeout_ms;
let mut unary_timeout_ms = defaults.unary_timeout_ms;
let mut close_timeout_ms = defaults.close_timeout_ms;
let mut reconnect_max_retries = defaults.reconnect.max_retries;
let mut reconnect_initial_backoff_ms = defaults.reconnect.initial_backoff_ms;
let mut reconnect_max_backoff_ms = defaults.reconnect.max_backoff_ms;
let mut request_channel_capacity = defaults.request_channel_capacity;
let mut update_channel_capacity = defaults.update_channel_capacity;
let mut max_inbound_message_size_bytes = defaults.max_inbound_message_size_bytes;
let mut max_outbound_message_size_bytes = defaults.max_outbound_message_size_bytes;
if let std::option::Option::Some(overrides) = overrides {
if let std::option::Option::Some(value) = overrides.connect_timeout_ms {
connect_timeout_ms = value;
}
if let std::option::Option::Some(value) = overrides.unary_timeout_ms {
unary_timeout_ms = value;
}
if let std::option::Option::Some(value) = overrides.close_timeout_ms {
close_timeout_ms = value;
}
if let std::option::Option::Some(reconnect) = overrides.reconnect.as_ref() {
if let std::option::Option::Some(value) = reconnect.max_retries {
reconnect_max_retries = value;
}
if let std::option::Option::Some(value) = reconnect.initial_backoff_ms {
reconnect_initial_backoff_ms = value;
}
if let std::option::Option::Some(value) = reconnect.max_backoff_ms {
reconnect_max_backoff_ms = value;
}
}
if let std::option::Option::Some(value) = overrides.request_channel_capacity {
request_channel_capacity = value;
}
if let std::option::Option::Some(value) = overrides.update_channel_capacity {
update_channel_capacity = value;
}
if let std::option::Option::Some(value) = overrides.max_inbound_message_size_bytes {
max_inbound_message_size_bytes = value;
}
if let std::option::Option::Some(value) = overrides.max_outbound_message_size_bytes {
max_outbound_message_size_bytes = value;
}
}
let reconnect = ksp_onchain_transport_lib::YellowstoneGrpcReconnectSettings::new(
reconnect_max_retries,
std::time::Duration::from_millis(reconnect_initial_backoff_ms),
std::time::Duration::from_millis(reconnect_max_backoff_ms),
);
let settings = ksp_onchain_transport_lib::YellowstoneGrpcSessionSettings::new(
std::time::Duration::from_millis(connect_timeout_ms),
std::time::Duration::from_millis(unary_timeout_ms),
std::time::Duration::from_millis(close_timeout_ms),
reconnect,
request_channel_capacity,
update_channel_capacity,
max_inbound_message_size_bytes,
max_outbound_message_size_bytes,
);
if let std::result::Result::Err(error) = settings.validate() {
return std::result::Result::Err(
transport_contract_error(profile, "effective Yellowstone gRPC session settings fail the Transport runtime contract", &error)
.with_context("endpoint_name", endpoint_name),
);
}
return std::result::Result::Ok(settings);
}
fn map_grpc_metadata(
public_sources: std::vec::Vec<EffectiveGrpcMetadataSource>,
secret_sources: std::vec::Vec<EffectiveGrpcMetadataSource>,
effective: &crate::ResolvedConfigJson,
profile: &crate::ResolvedConfigProfile,
endpoint_name: &str,
endpoint_index: usize,
) -> ksp_core_lib::Result<std::vec::Vec<ksp_onchain_transport_lib::YellowstoneGrpcMetadataEntry>> {
let mut metadata = std::vec::Vec::<ksp_onchain_transport_lib::YellowstoneGrpcMetadataEntry>::with_capacity(public_sources.len() + secret_sources.len());
for (metadata_index, source) in public_sources.into_iter().enumerate() {
let pointer = format!("/grpc_endpoints/{endpoint_index}/metadata/{metadata_index}/value");
if let std::result::Result::Err(error) = validate_grpc_metadata_provenance(effective, pointer.as_str(), false, profile, endpoint_name) {
return std::result::Result::Err(error);
}
let entry = ksp_onchain_transport_lib::YellowstoneGrpcMetadataEntry::public(source.key, source.value);
let entry = match entry {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => {
return std::result::Result::Err(
transport_contract_error(profile, "effective public Yellowstone gRPC metadata are invalid", &error)
.with_context("endpoint_name", endpoint_name),
);
},
};
metadata.push(entry);
}
for (metadata_index, source) in secret_sources.into_iter().enumerate() {
let pointer = format!("/grpc_endpoints/{endpoint_index}/secret_metadata/{metadata_index}/value");
if let std::result::Result::Err(error) = validate_grpc_metadata_provenance(effective, pointer.as_str(), true, profile, endpoint_name) {
return std::result::Result::Err(error);
}
let entry = ksp_onchain_transport_lib::YellowstoneGrpcMetadataEntry::secret(source.key, source.value);
let entry = match entry {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => {
return std::result::Result::Err(
transport_contract_error(profile, "effective secret Yellowstone gRPC metadata are invalid", &error)
.with_context("endpoint_name", endpoint_name),
);
},
};
metadata.push(entry);
}
return std::result::Result::Ok(metadata);
}
fn validate_grpc_metadata_provenance(
effective: &crate::ResolvedConfigJson,
pointer: &str,
secret_class: bool,
profile: &crate::ResolvedConfigProfile,
endpoint_name: &str,
) -> ksp_core_lib::Result<()> {
let provenance = match effective.provenance_at(pointer) {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(
effective_error(profile, "Yellowstone gRPC metadata provenance is unavailable")
.with_context("endpoint_name", endpoint_name)
.with_context("field", pointer),
);
},
};
let mut has_secret_environment = false;
for item in provenance {
let variable_name = match item.variable_name() {
std::option::Option::Some(value) => value,
std::option::Option::None => continue,
};
let sensitivity = crate::ConfigSensitivity::from_variable_name(variable_name);
let sensitivity = match sensitivity {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
if sensitivity.is_secret() {
has_secret_environment = true;
if !secret_class {
return std::result::Result::Err(
effective_error(profile, "public Yellowstone gRPC metadata must not derive from a secret environment variable")
.with_context("endpoint_name", endpoint_name)
.with_context("field", pointer),
);
}
} else if secret_class {
return std::result::Result::Err(
effective_error(profile, "secret Yellowstone gRPC metadata may reference only secret environment variables")
.with_context("endpoint_name", endpoint_name)
.with_context("field", pointer),
);
}
}
if secret_class && !has_secret_environment {
return std::result::Result::Err(
effective_error(profile, "secret Yellowstone gRPC metadata require secret environment provenance")
.with_context("endpoint_name", endpoint_name)
.with_context("field", pointer),
);
}
return std::result::Result::Ok(());
}
fn map_endpoints(
sources: std::vec::Vec<EffectiveEndpointSource>,
profile: &crate::ResolvedConfigProfile,