v0.2.10-pre.002

This commit is contained in:
2026-08-25 10:29:16 +02:00
parent 7f567bc1bb
commit af807afff5
10 changed files with 667 additions and 59 deletions

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-config-lib/unit_tests/transport.rs
// version: 10
// version: 11
#[test]
fn fixture_transport_profile_maps_complete_runtime_contract() {
@@ -133,6 +133,45 @@ fn committed_transport_document_maps_default_and_explicit_profiles() {
}
}
#[test]
fn committed_v3_orbitflare_devnet_profile_maps_provider_neutral_yellowstone_grpc_without_metadata() {
let engine = committed_engine();
let engine = match engine {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let environment = crate::ConfigEnvironment::from_maps(std::collections::BTreeMap::new(), std::collections::BTreeMap::new());
let resolved = engine.load_resolved_transport_config(std::option::Option::Some("orbitflare_devnet"), &environment);
assert!(resolved.is_ok(), "committed OrbitFlare Devnet Transport profile should map without gRPC metadata: {resolved:?}");
if let std::result::Result::Ok(resolved) = resolved {
assert_eq!(resolved.profile_id(), "orbitflare_devnet");
assert_eq!(resolved.selection_source(), crate::ConfigProfileSelectionSource::Explicit);
assert_eq!(resolved.settings().endpoints()[0].cluster().as_str(), "devnet");
assert_eq!(resolved.settings().endpoints()[0].url().as_str(), "https://api.devnet.solana.com");
let ws = resolved.ws_settings();
assert!(ws.is_some(), "OrbitFlare Devnet profile should retain the standard Solana Devnet WebSocket companion endpoint");
if let std::option::Option::Some(ws) = ws {
assert_eq!(ws.endpoints()[0].url().as_str(), "wss://api.devnet.solana.com");
assert_eq!(ws.endpoints()[0].protocol(), ksp_onchain_transport_lib::WsProtocolKind::SolanaStandard);
}
let grpc = resolved.grpc_settings();
assert!(grpc.is_some(), "OrbitFlare Devnet profile should expose one provider-neutral Yellowstone gRPC endpoint");
if let std::option::Option::Some(grpc) = grpc {
assert_eq!(grpc.endpoints().len(), 1);
let endpoint = &grpc.endpoints()[0];
assert_eq!(endpoint.name(), "orbitflare_solana_devnet_yellowstone");
assert_eq!(endpoint.provider().as_str(), "orbitflare");
assert_eq!(endpoint.cluster().as_str(), "devnet");
assert_eq!(endpoint.url().as_str(), "http://devnet.rpc.orbitflare.com:10000");
assert!(!endpoint.url().uses_tls(), "OrbitFlare shared Devnet URL must remain explicitly HTTP/2 plaintext");
assert!(endpoint.metadata().is_empty(), "OrbitFlare Devnet Free profile must not invent gRPC metadata before live proof requires it");
let debug = format!("{endpoint:?}");
assert!(!debug.contains("orbitflare.com"), "Transport settings Debug must not expose OrbitFlare gRPC endpoint URLs");
assert!(!debug.contains("X-ORBIT-KEY"), "OrbitFlare Customer API credentials must never enter Yellowstone Transport settings");
}
}
}
#[test]
fn committed_v3_publicnode_profiles_map_provider_neutral_yellowstone_grpc_with_network_scoped_secret_x_tokens() {
let engine = committed_engine();

View File

@@ -1,5 +1,5 @@
<!-- file: crates/ksp-onchain-transport-lib/README.md -->
<!-- version: 22 -->
<!-- version: 23 -->
# `ksp-onchain-transport-lib`
@@ -220,7 +220,6 @@ Pour Helius, lactor envoie automatiquement un control frame WebSocket `Ping`
LaserStream **gRPC** reste un backend distinct, hors de cette façade, de `WsProtocolKind` et de la Config WebSocket `helius_laserstream`.
## Yellowstone gRPC standard
La foundation `0.2.9` ajoute un troisième backend réseau distinct de HTTP et WebSocket. Le moteur est KSP-owned : `yellowstone-grpc-proto` fournit le wire publié, tandis que Tonic reste encapsulé derrière les types crate-root KSP. Aucun client Tonic brut ni type protobuf upstream nest réexporté.

View File

@@ -0,0 +1,126 @@
// file: crates/ksp-onchain-transport-lib/tests/yellowstone_orbitflare_smoke.rs
// version: 1
//! Opt-in live OrbitFlare Devnet characterization smoke for provider-neutral Yellowstone gRPC Subscribe.
fn orbitflare_devnet_endpoint() -> ksp_core_lib::Result<ksp_onchain_transport_lib::YellowstoneGrpcEndpointSettings> {
let url = match ksp_onchain_transport_lib::YellowstoneGrpcEndpointUrl::parse("http://devnet.rpc.orbitflare.com:10000") {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let session = ksp_onchain_transport_lib::YellowstoneGrpcSessionSettings::new(
std::time::Duration::from_secs(10),
std::time::Duration::from_secs(10),
std::time::Duration::from_secs(5),
ksp_onchain_transport_lib::YellowstoneGrpcReconnectSettings::new(0, std::time::Duration::from_millis(250), std::time::Duration::from_secs(2)),
8,
8,
16 * 1024 * 1024,
4 * 1024 * 1024,
);
return std::result::Result::Ok(ksp_onchain_transport_lib::YellowstoneGrpcEndpointSettings::new(
"orbitflare_devnet_yellowstone",
true,
ksp_onchain_transport_lib::YellowstoneGrpcProviderName::new("orbitflare"),
ksp_onchain_transport_lib::YellowstoneGrpcClusterName::new("devnet"),
url,
session,
));
}
fn slot_request() -> ksp_core_lib::Result<ksp_onchain_transport_lib::YellowstoneSubscribeRequest> {
let mut request = ksp_onchain_transport_lib::YellowstoneSubscribeRequest::new();
let name = match ksp_onchain_transport_lib::YellowstoneSubscribeFilterName::new("slots") {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
match request.insert_slot_filter(name, ksp_onchain_transport_lib::YellowstoneSubscribeSlotFilter::new()) {
std::result::Result::Ok(()) => {},
std::result::Result::Err(error) => return std::result::Result::Err(error),
}
request.set_commitment(std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Confirmed));
return std::result::Result::Ok(request);
}
#[tokio::test(flavor = "current_thread")]
#[ignore = "opt-in live OrbitFlare Devnet Yellowstone gRPC characterization; connects without metadata, waits for Slot plus standard server Ping, then closes"]
async fn orbitflare_devnet_yellowstone_streams_slots_and_emits_standard_server_ping_without_metadata() {
let endpoint = match orbitflare_devnet_endpoint() {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => panic!("programmatic OrbitFlare Devnet Yellowstone settings must be valid without metadata: {error:?}"),
};
assert!(endpoint.metadata().is_empty(), "OrbitFlare Devnet characterization must not invent gRPC metadata");
assert!(!endpoint.url().uses_tls(), "the documented OrbitFlare shared Devnet endpoint is intentionally HTTP/2 plaintext");
let endpoint_debug = format!("{endpoint:?}");
assert!(!endpoint_debug.contains("orbitflare.com"), "OrbitFlare endpoint URL must not appear in endpoint Debug");
assert!(!endpoint_debug.contains("X-ORBIT-KEY"), "OrbitFlare Customer API credentials must not enter Yellowstone settings");
let channel = match ksp_onchain_transport_lib::YellowstoneGrpcChannel::connect(&endpoint).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => {
panic!("OrbitFlare Devnet Yellowstone connection without metadata must succeed or classify the provider auth gate: {error:?}")
},
};
assert_eq!(channel.endpoint_name(), "orbitflare_devnet_yellowstone");
assert_eq!(channel.provider().as_str(), "orbitflare");
assert_eq!(channel.cluster().as_str(), "devnet");
let request = match slot_request() {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => panic!("OrbitFlare Yellowstone slot request must be valid: {error:?}"),
};
let mut session = match channel.open_standard_subscribe(request).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => {
panic!("OrbitFlare Devnet standard Subscribe without metadata must open or classify the provider auth gate: {error:?}")
},
};
let deadline = tokio::time::sleep(std::time::Duration::from_secs(45));
tokio::pin!(deadline);
let mut slot_seen = false;
let mut ping_seen = false;
loop {
tokio::select! {
() = &mut deadline => break,
next_update = session.next_update() => {
let next_update = match next_update {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => panic!("OrbitFlare Devnet Yellowstone Subscribe update must decode: {error:?}"),
};
match next_update {
std::option::Option::Some(ksp_onchain_transport_lib::YellowstoneSubscribeUpdate::Slot(update)) => {
if update.slot() > 0 {
slot_seen = true;
}
},
std::option::Option::Some(ksp_onchain_transport_lib::YellowstoneSubscribeUpdate::Ping(_)) => ping_seen = true,
std::option::Option::Some(_) => {},
std::option::Option::None => break,
}
if slot_seen && ping_seen {
break;
}
},
}
}
let close_timeout_result = tokio::time::timeout(std::time::Duration::from_secs(7), session.close()).await;
let close_result = match close_timeout_result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => {
panic!("KSP Yellowstone Subscribe close must remain bounded beyond the configured five-second provider half-close deadline: {error}")
},
};
match close_result {
std::result::Result::Ok(()) => {},
std::result::Result::Err(error) => {
assert_eq!(
error.code(),
ksp_onchain_transport_lib::ERROR_CODE_TIMEOUT,
"after live characterization, OrbitFlare close may time out waiting for provider half-close but must not fail for another reason: {error:?}"
);
},
}
assert!(slot_seen, "OrbitFlare Devnet Yellowstone must publish at least one non-zero confirmed slot during the 45-second characterization window");
assert!(
ping_seen,
"OrbitFlare Devnet must emit the standard Yellowstone server Ping during the 45-second characterization window before any provider-specific heartbeat is justified"
);
}