v0.2.8-pre.009

This commit is contained in:
2026-08-23 18:16:03 +02:00
parent 7c12ec886b
commit 9c0d4fc197
10 changed files with 579 additions and 59 deletions

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-onchain-transport-lib/src/lib.rs
// version: 33
// version: 34
#![warn(missing_docs)]
#![deny(unreachable_pub)]
@@ -26,9 +26,11 @@
//! `0.2.7-pre.009` opens the first stable typed WebSocket wrappers for account, program-account and transaction-log subscriptions without exposing a raw
//! provider-extension subscription API. `0.2.8-pre.002` adds a Helius LaserStream WebSocket protocol discriminator and two typed protocol facades while
//! keeping the `WsSession` actor/socket implementation unique and the historical generic constructor standard-only.
//! `0.2.8-pre.003` exposes the six standard families Helius supports through the provider facade, while `0.2.8-pre.005` adds the typed Helius
//! `transactionSubscribe` request contract and provider filter/options validation. `0.2.8-pre.006` integrates the live transaction handle and typed
//! `transactionNotification` union into the same actor-owned registry, remote-ID remap, unsubscribe-race handling and per-subscription backpressure path.
//! `0.2.8-pre.003` initially exposed the six standard families unambiguously supported by the audited Helius pages; `0.2.8-pre.009` reconciles the current
//! Helius documentation and adds the now-documented unstable `slotsUpdatesSubscribe` pair while keeping explicitly unsupported block/vote pairs absent.
//! `0.2.8-pre.005` adds the typed Helius `transactionSubscribe` request contract and provider filter/options validation. `0.2.8-pre.006` integrates the live
//! transaction handle and typed `transactionNotification` union into the same actor-owned registry, remote-ID remap, unsubscribe-race handling and
//! per-subscription backpressure path.
mod client;
mod constants;

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-onchain-transport-lib/src/ws_cluster.rs
// version: 4
// version: 5
/// Slot relationship reported by the standard Solana `slotNotification` WebSocket method.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
@@ -433,6 +433,12 @@ impl crate::HeliusLaserStreamWsSession {
pub async fn root_subscribe(&self) -> ksp_core_lib::Result<crate::WsSubscription<u64>> {
return self.physical_session().root_subscribe().await;
}
/// Subscribes to unstable slot-lifecycle notifications through the standard `slotsUpdatesSubscribe` wire currently documented by Helius LaserStream
/// WebSocket.
pub async fn slots_updates_subscribe(&self) -> ksp_core_lib::Result<crate::WsSubscription<crate::SolanaSlotUpdate>> {
return self.physical_session().slots_updates_subscribe().await;
}
}
#[cfg(test)]

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-onchain-transport-lib/src/ws_protocol_session.rs
// version: 5
// version: 6
/// Typed facade for one standard Solana WebSocket physical session.
///
@@ -67,7 +67,8 @@ impl std::fmt::Debug for SolanaStandardWsSession {
/// Typed facade for one Helius LaserStream WebSocket physical session.
///
/// The facade exposes the six standard Solana subscription families that Helius documents as supported plus the Helius-specific typed
/// The facade exposes the seven standard Solana subscription families that the current Helius method pages support or document as available plus the
/// Helius-specific typed
/// `transactionSubscribe` lifecycle. Transaction notifications, reconnect/resubscribe, unsubscribe races and bounded backpressure all delegate to the same
/// shared [`crate::WsSession`] actor; the facade owns no second socket, registry or queue. No public inner handle is exposed, so callers cannot bypass the
/// provider-specific surface by recovering a generic [`crate::WsSession`].
@@ -79,12 +80,6 @@ impl std::fmt::Debug for SolanaStandardWsSession {
/// ```
///
/// ```compile_fail
/// async fn unsupported_slots_updates(session: &ksp_onchain_transport_lib::HeliusLaserStreamWsSession) {
/// let _ = session.slots_updates_subscribe().await;
/// }
/// ```
///
/// ```compile_fail
/// async fn unsupported_vote(session: &ksp_onchain_transport_lib::HeliusLaserStreamWsSession) {
/// let _ = session.vote_subscribe().await;
/// }

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-onchain-transport-lib/tests/public_api.rs
// version: 37
// version: 38
//! Integration tests for the public `ksp-onchain-transport-lib` consumer contract.
@@ -753,3 +753,10 @@ fn public_v0_2_8_pre_006_helius_transaction_live_handle_and_notification_types_a
let _signature = std::any::type_name::<ksp_onchain_transport_lib::HeliusTransactionSignatureNotification>();
assert_eq!(ksp_onchain_transport_lib::WsSubscriptionKind::HeliusTransaction.as_str(), "helius_transaction");
}
#[test]
fn public_v0_2_8_pre_009_helius_slots_updates_surface_reuses_shared_typed_contract() {
let _slots_updates = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::slots_updates_subscribe;
let _shared_slot_update = std::any::type_name::<ksp_onchain_transport_lib::SolanaSlotUpdate>();
assert_eq!(ksp_onchain_transport_lib::WsSubscriptionKind::SlotsUpdates.as_str(), "slots_updates");
}

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-onchain-transport-lib/tests/release_completeness.rs
// version: 30
// version: 31
//! Release-level completeness canaries for staged HTTP and WebSocket Transport coverage.
@@ -797,7 +797,7 @@ fn release_v0_2_8_pre_002_protocol_facades_preserve_the_standard_partition() {
}
#[test]
fn release_v0_2_8_pre_003_helius_surface_is_exactly_six_standard_families_before_transaction_extension() {
fn release_v0_2_8_pre_003_original_six_standard_families_remain_available_after_provider_evolution() {
let _account = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::account_subscribe;
let _program = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::program_subscribe;
let _logs = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::logs_subscribe;
@@ -806,7 +806,6 @@ fn release_v0_2_8_pre_003_helius_surface_is_exactly_six_standard_families_before
let _root = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::root_subscribe;
let source = include_str!("../src/ws_protocol_session.rs");
assert!(source.contains("unsupported_block"));
assert!(source.contains("unsupported_slots_updates"));
assert!(source.contains("unsupported_vote"));
assert!(!source.contains("pub async fn transaction_subscribe"));
assert_eq!(ksp_onchain_transport_lib::WsProtocolKind::HeliusLaserStream.as_str(), "helius_laserstream");
@@ -847,7 +846,6 @@ fn release_v0_2_8_pre_006_helius_transaction_lifecycle_is_actor_integrated_witho
assert!(!source.contains("tokio_tungstenite::connect_async"));
let protocol_source = include_str!("../src/ws_protocol_session.rs");
assert!(protocol_source.contains("unsupported_block"));
assert!(protocol_source.contains("unsupported_slots_updates"));
assert!(protocol_source.contains("unsupported_vote"));
}
@@ -871,7 +869,6 @@ fn release_v0_2_8_pre_008_adversarial_guards_preserve_provider_isolation_and_saf
let protocol_source = include_str!("../src/ws_protocol_session.rs");
assert!(protocol_source.contains("unsupported_helius_transaction"));
assert!(protocol_source.contains("unsupported_block"));
assert!(protocol_source.contains("unsupported_slots_updates"));
assert!(protocol_source.contains("unsupported_vote"));
let helius_source = include_str!("../src/ws_helius_transactions.rs");
assert!(helius_source.contains("impl std::fmt::Debug for HeliusFullTransactionNotification"));
@@ -886,3 +883,94 @@ fn release_v0_2_8_pre_008_adversarial_guards_preserve_provider_isolation_and_saf
assert!(actor_source.contains("ERROR_CODE_WS_BACKPRESSURE_OVERFLOW"));
assert!(actor_source.contains("remote_to_local.remove"));
}
#[test]
fn release_v0_2_8_pre_009_http_and_standard_websocket_inventories_remain_exact() {
assert_eq!(ksp_onchain_transport_lib::current_http_rpc_methods().len(), 52);
assert_eq!(ksp_onchain_transport_lib::historical_http_rpc_methods().len(), 14);
let standard = [
ksp_onchain_transport_lib::WsSubscriptionKind::Account,
ksp_onchain_transport_lib::WsSubscriptionKind::Block,
ksp_onchain_transport_lib::WsSubscriptionKind::Logs,
ksp_onchain_transport_lib::WsSubscriptionKind::Program,
ksp_onchain_transport_lib::WsSubscriptionKind::Root,
ksp_onchain_transport_lib::WsSubscriptionKind::Signature,
ksp_onchain_transport_lib::WsSubscriptionKind::Slot,
ksp_onchain_transport_lib::WsSubscriptionKind::SlotsUpdates,
ksp_onchain_transport_lib::WsSubscriptionKind::Vote,
];
assert_eq!(standard.len(), 9);
let lifecycle_source = include_str!("../src/ws_lifecycle.rs");
for method in [
"accountSubscribe",
"accountUnsubscribe",
"blockSubscribe",
"blockUnsubscribe",
"logsSubscribe",
"logsUnsubscribe",
"programSubscribe",
"programUnsubscribe",
"rootSubscribe",
"rootUnsubscribe",
"signatureSubscribe",
"signatureUnsubscribe",
"slotSubscribe",
"slotUnsubscribe",
"slotsUpdatesSubscribe",
"slotsUpdatesUnsubscribe",
"voteSubscribe",
"voteUnsubscribe",
] {
assert!(lifecycle_source.contains(method), "missing standard WebSocket method mapping: {method}");
}
let _account = ksp_onchain_transport_lib::SolanaStandardWsSession::account_subscribe;
let _block = ksp_onchain_transport_lib::SolanaStandardWsSession::block_subscribe;
let _logs = ksp_onchain_transport_lib::SolanaStandardWsSession::logs_subscribe;
let _program = ksp_onchain_transport_lib::SolanaStandardWsSession::program_subscribe;
let _root = ksp_onchain_transport_lib::SolanaStandardWsSession::root_subscribe;
let _signature = ksp_onchain_transport_lib::SolanaStandardWsSession::signature_subscribe;
let _slot = ksp_onchain_transport_lib::SolanaStandardWsSession::slot_subscribe;
let _slots_updates = ksp_onchain_transport_lib::SolanaStandardWsSession::slots_updates_subscribe;
let _vote = ksp_onchain_transport_lib::SolanaStandardWsSession::vote_subscribe;
}
#[test]
fn release_v0_2_8_pre_009_helius_surface_is_seven_standard_families_plus_transaction() {
let _account = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::account_subscribe;
let _program = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::program_subscribe;
let _logs = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::logs_subscribe;
let _signature = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::signature_subscribe;
let _slot = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::slot_subscribe;
let _root = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::root_subscribe;
let _slots_updates = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::slots_updates_subscribe;
let _transaction = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::transaction_subscribe;
let protocol_source = include_str!("../src/ws_protocol_session.rs");
assert!(protocol_source.contains("unsupported_block"));
assert!(protocol_source.contains("unsupported_vote"));
assert!(!protocol_source.contains("unsupported_slots_updates"));
let cluster_source = include_str!("../src/ws_cluster.rs");
assert!(cluster_source.contains("impl crate::HeliusLaserStreamWsSession"));
assert!(cluster_source.contains("pub async fn slots_updates_subscribe"));
assert_eq!(ksp_onchain_transport_lib::WsSubscriptionKind::SlotsUpdates.as_str(), "slots_updates");
assert_eq!(ksp_onchain_transport_lib::WsSubscriptionKind::HeliusTransaction.as_str(), "helius_transaction");
}
#[test]
fn release_v0_2_8_pre_009_config_secret_and_dependency_boundaries_remain_wired() {
let manifest_directory = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
let workspace = manifest_directory.parent().and_then(std::path::Path::parent).expect("Transport integration test must resolve the workspace root");
let transport_manifest = std::fs::read_to_string(manifest_directory.join("Cargo.toml")).expect("Transport manifest must be readable");
for forbidden in ["ksp-config-lib", "ksp-store-api", "ksp-store-lib", "ksp-program-api", "ksp-program-lib", "tracing =", "tracing."] {
assert!(!transport_manifest.contains(forbidden), "forbidden direct Transport dependency detected: {forbidden}");
}
let config_manifest = std::fs::read_to_string(workspace.join("crates/ksp-config-lib/Cargo.toml")).expect("Config manifest must be readable");
assert!(config_manifest.contains("ksp-onchain-transport-lib"));
let config_transport =
std::fs::read_to_string(workspace.join("crates/ksp-config-lib/src/transport.rs")).expect("Config Transport adapter source must be readable");
assert!(config_transport.contains("WsProtocolKind::HeliusLaserStream"));
let transport_example = std::fs::read_to_string(workspace.join("config/examples/std.transport.example.json")).expect("Transport example must be readable");
assert!(transport_example.contains("\"kind\": \"helius_laserstream\""));
assert!(transport_example.contains("${KSP_SECRET_HELIUS_API_KEY"));
let env_example = std::fs::read_to_string(workspace.join(".env.example")).expect(".env.example must be readable");
assert!(env_example.contains("KSP_SECRET_HELIUS_API_KEY"));
}

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-onchain-transport-lib/unit_tests/ws_helius_standard.rs
// version: 1
// version: 2
use futures_util::SinkExt; // rust-rules: trait-import
use futures_util::StreamExt; // rust-rules: trait-import
@@ -63,7 +63,7 @@ async fn wait_for_close_frame(websocket: &mut tokio_tungstenite::WebSocketStream
}
#[tokio::test(flavor = "current_thread")]
async fn helius_facade_reuses_exact_standard_wire_for_all_six_supported_families() {
async fn helius_facade_reuses_exact_standard_wire_for_all_seven_currently_supported_families() {
let (listener, url) = bind_local_listener().await;
let server = tokio::spawn(async move {
let (stream, _) = listener.accept().await.expect("local server must accept client");
@@ -95,6 +95,7 @@ async fn helius_facade_reuses_exact_standard_wire_for_all_six_supported_families
.await;
expect_pair(&mut websocket, "slotSubscribe", serde_json::json!([]), "slotUnsubscribe", 105).await;
expect_pair(&mut websocket, "rootSubscribe", serde_json::json!([]), "rootUnsubscribe", 106).await;
expect_pair(&mut websocket, "slotsUpdatesSubscribe", serde_json::json!([]), "slotsUpdatesUnsubscribe", 107).await;
wait_for_close_frame(&mut websocket).await;
});
let session = crate::HeliusLaserStreamWsSession::connect(helius_endpoint(url.as_str())).await.expect("Helius facade must connect");
@@ -134,6 +135,8 @@ async fn helius_facade_reuses_exact_standard_wire_for_all_six_supported_families
assert!(slot.unsubscribe().await.expect("Helius slotUnsubscribe must complete"));
let mut root = session.root_subscribe().await.expect("Helius rootSubscribe must register");
assert!(root.unsubscribe().await.expect("Helius rootUnsubscribe must complete"));
let mut slots_updates = session.slots_updates_subscribe().await.expect("Helius slotsUpdatesSubscribe must register");
assert!(slots_updates.unsubscribe().await.expect("Helius slotsUpdatesUnsubscribe must complete"));
session.close().await.expect("Helius facade close must complete");
server.await.expect("local Helius peer task must complete");
}