v0.2.8-pre.003
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-onchain-transport-lib/src/ws_accounts.rs
|
||||
// version: 2
|
||||
// version: 3
|
||||
|
||||
const MAX_PROGRAM_SUBSCRIBE_FILTERS: usize = 4;
|
||||
const MAX_PROGRAM_SUBSCRIBE_RAW_MEMCMP_BYTES: usize = 128;
|
||||
@@ -277,6 +277,46 @@ fn validate_program_subscribe_filters(filters: &[crate::SolanaProgramAccountFilt
|
||||
return std::result::Result::Ok(());
|
||||
}
|
||||
|
||||
impl crate::SolanaStandardWsSession {
|
||||
/// Subscribes to changes for one Solana account through standard `accountSubscribe`.
|
||||
pub async fn account_subscribe(
|
||||
&self,
|
||||
account: &ksp_core_lib::Pubkey,
|
||||
config: std::option::Option<&crate::SolanaAccountSubscribeConfig>,
|
||||
) -> ksp_core_lib::Result<crate::WsSubscription<crate::SolanaRpcResponse<crate::SolanaAccount>>> {
|
||||
return self.physical_session().account_subscribe(account, config).await;
|
||||
}
|
||||
|
||||
/// Subscribes to account changes owned by one Solana program through standard `programSubscribe`.
|
||||
pub async fn program_subscribe(
|
||||
&self,
|
||||
program_id: &ksp_core_lib::Pubkey,
|
||||
config: std::option::Option<&crate::SolanaProgramSubscribeConfig>,
|
||||
) -> ksp_core_lib::Result<crate::WsSubscription<crate::SolanaProgramNotification>> {
|
||||
return self.physical_session().program_subscribe(program_id, config).await;
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::HeliusLaserStreamWsSession {
|
||||
/// Subscribes to account changes through the standard `accountSubscribe` wire supported by Helius LaserStream WebSocket.
|
||||
pub async fn account_subscribe(
|
||||
&self,
|
||||
account: &ksp_core_lib::Pubkey,
|
||||
config: std::option::Option<&crate::SolanaAccountSubscribeConfig>,
|
||||
) -> ksp_core_lib::Result<crate::WsSubscription<crate::SolanaRpcResponse<crate::SolanaAccount>>> {
|
||||
return self.physical_session().account_subscribe(account, config).await;
|
||||
}
|
||||
|
||||
/// Subscribes to program-owned account changes through the standard `programSubscribe` wire supported by Helius LaserStream WebSocket.
|
||||
pub async fn program_subscribe(
|
||||
&self,
|
||||
program_id: &ksp_core_lib::Pubkey,
|
||||
config: std::option::Option<&crate::SolanaProgramSubscribeConfig>,
|
||||
) -> ksp_core_lib::Result<crate::WsSubscription<crate::SolanaProgramNotification>> {
|
||||
return self.physical_session().program_subscribe(program_id, config).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/ws_accounts.rs"]
|
||||
mod tests;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-onchain-transport-lib/src/ws_blocks.rs
|
||||
// version: 1
|
||||
// version: 2
|
||||
|
||||
/// Filter accepted by unstable Solana `blockSubscribe`.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
@@ -210,6 +210,17 @@ struct WireRpcResponse {
|
||||
value: WireBlockNotification,
|
||||
}
|
||||
|
||||
impl crate::SolanaStandardWsSession {
|
||||
/// Subscribes to unstable standard Solana block notifications through `blockSubscribe`.
|
||||
pub async fn block_subscribe(
|
||||
&self,
|
||||
filter: &crate::SolanaBlockSubscribeFilter,
|
||||
config: std::option::Option<&crate::SolanaBlockSubscribeConfig>,
|
||||
) -> ksp_core_lib::Result<crate::WsSubscription<crate::SolanaRpcResponse<crate::SolanaBlockNotification>>> {
|
||||
return self.physical_session().block_subscribe(filter, config).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/ws_blocks.rs"]
|
||||
mod tests;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-onchain-transport-lib/src/ws_cluster.rs
|
||||
// version: 3
|
||||
// version: 4
|
||||
|
||||
/// Slot relationship reported by the standard Solana `slotNotification` WebSocket method.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
@@ -401,6 +401,40 @@ fn decode_vote_notification(method: &str, value: serde_json::Value) -> ksp_core_
|
||||
});
|
||||
}
|
||||
|
||||
impl crate::SolanaStandardWsSession {
|
||||
/// Subscribes to standard Solana slot-processing notifications through `slotSubscribe`.
|
||||
pub async fn slot_subscribe(&self) -> ksp_core_lib::Result<crate::WsSubscription<crate::SolanaSlotNotification>> {
|
||||
return self.physical_session().slot_subscribe().await;
|
||||
}
|
||||
|
||||
/// Subscribes to standard Solana root-slot notifications through `rootSubscribe`.
|
||||
pub async fn root_subscribe(&self) -> ksp_core_lib::Result<crate::WsSubscription<u64>> {
|
||||
return self.physical_session().root_subscribe().await;
|
||||
}
|
||||
|
||||
/// Subscribes to unstable standard Solana slot-lifecycle notifications through `slotsUpdatesSubscribe`.
|
||||
pub async fn slots_updates_subscribe(&self) -> ksp_core_lib::Result<crate::WsSubscription<crate::SolanaSlotUpdate>> {
|
||||
return self.physical_session().slots_updates_subscribe().await;
|
||||
}
|
||||
|
||||
/// Subscribes to unstable pre-consensus gossip vote notifications through `voteSubscribe`.
|
||||
pub async fn vote_subscribe(&self) -> ksp_core_lib::Result<crate::WsSubscription<crate::SolanaVoteNotification>> {
|
||||
return self.physical_session().vote_subscribe().await;
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::HeliusLaserStreamWsSession {
|
||||
/// Subscribes to slot-processing notifications through the standard `slotSubscribe` wire supported by Helius LaserStream WebSocket.
|
||||
pub async fn slot_subscribe(&self) -> ksp_core_lib::Result<crate::WsSubscription<crate::SolanaSlotNotification>> {
|
||||
return self.physical_session().slot_subscribe().await;
|
||||
}
|
||||
|
||||
/// Subscribes to root-slot notifications through the standard `rootSubscribe` wire supported by Helius LaserStream WebSocket.
|
||||
pub async fn root_subscribe(&self) -> ksp_core_lib::Result<crate::WsSubscription<u64>> {
|
||||
return self.physical_session().root_subscribe().await;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/ws_cluster.rs"]
|
||||
mod tests;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
// file: crates/ksp-onchain-transport-lib/src/ws_protocol_session.rs
|
||||
// version: 1
|
||||
// version: 2
|
||||
|
||||
/// Typed facade for one standard Solana WebSocket physical session.
|
||||
///
|
||||
/// The facade delegates to the same [`crate::WsSession`] actor used by the compatibility API. It owns no socket, registry, reconnect loop or queue of its
|
||||
/// own and therefore does not duplicate the physical WebSocket runtime.
|
||||
/// own and therefore does not duplicate the physical WebSocket runtime. Subscription wrappers are implemented beside their wire owners in the
|
||||
/// `ws_accounts`, `ws_blocks`, `ws_cluster` and `ws_transactions` modules.
|
||||
#[derive(Clone)]
|
||||
pub struct SolanaStandardWsSession {
|
||||
inner: crate::WsSession,
|
||||
@@ -43,69 +44,9 @@ impl SolanaStandardWsSession {
|
||||
return self.inner.close().await;
|
||||
}
|
||||
|
||||
/// Subscribes to changes for one Solana account through standard `accountSubscribe`.
|
||||
pub async fn account_subscribe(
|
||||
&self,
|
||||
account: &ksp_core_lib::Pubkey,
|
||||
config: std::option::Option<&crate::SolanaAccountSubscribeConfig>,
|
||||
) -> ksp_core_lib::Result<crate::WsSubscription<crate::SolanaRpcResponse<crate::SolanaAccount>>> {
|
||||
return self.inner.account_subscribe(account, config).await;
|
||||
}
|
||||
|
||||
/// Subscribes to unstable standard Solana block notifications through `blockSubscribe`.
|
||||
pub async fn block_subscribe(
|
||||
&self,
|
||||
filter: &crate::SolanaBlockSubscribeFilter,
|
||||
config: std::option::Option<&crate::SolanaBlockSubscribeConfig>,
|
||||
) -> ksp_core_lib::Result<crate::WsSubscription<crate::SolanaRpcResponse<crate::SolanaBlockNotification>>> {
|
||||
return self.inner.block_subscribe(filter, config).await;
|
||||
}
|
||||
|
||||
/// Subscribes to Solana transaction logs through standard `logsSubscribe`.
|
||||
pub async fn logs_subscribe(
|
||||
&self,
|
||||
filter: &crate::SolanaLogsSubscribeFilter,
|
||||
config: std::option::Option<&crate::SolanaCommitmentConfig>,
|
||||
) -> ksp_core_lib::Result<crate::WsSubscription<crate::SolanaRpcResponse<crate::SolanaLogsNotification>>> {
|
||||
return self.inner.logs_subscribe(filter, config).await;
|
||||
}
|
||||
|
||||
/// Subscribes to account changes owned by one Solana program through standard `programSubscribe`.
|
||||
pub async fn program_subscribe(
|
||||
&self,
|
||||
program_id: &ksp_core_lib::Pubkey,
|
||||
config: std::option::Option<&crate::SolanaProgramSubscribeConfig>,
|
||||
) -> ksp_core_lib::Result<crate::WsSubscription<crate::SolanaProgramNotification>> {
|
||||
return self.inner.program_subscribe(program_id, config).await;
|
||||
}
|
||||
|
||||
/// Subscribes to standard Solana root-slot notifications through `rootSubscribe`.
|
||||
pub async fn root_subscribe(&self) -> ksp_core_lib::Result<crate::WsSubscription<u64>> {
|
||||
return self.inner.root_subscribe().await;
|
||||
}
|
||||
|
||||
/// Subscribes to one Solana transaction signature through standard `signatureSubscribe`.
|
||||
pub async fn signature_subscribe(
|
||||
&self,
|
||||
signature: &str,
|
||||
config: std::option::Option<&crate::SolanaSignatureSubscribeConfig>,
|
||||
) -> ksp_core_lib::Result<crate::WsSubscription<crate::SolanaRpcResponse<crate::SolanaSignatureNotification>>> {
|
||||
return self.inner.signature_subscribe(signature, config).await;
|
||||
}
|
||||
|
||||
/// Subscribes to standard Solana slot-processing notifications through `slotSubscribe`.
|
||||
pub async fn slot_subscribe(&self) -> ksp_core_lib::Result<crate::WsSubscription<crate::SolanaSlotNotification>> {
|
||||
return self.inner.slot_subscribe().await;
|
||||
}
|
||||
|
||||
/// Subscribes to unstable standard Solana slot-lifecycle notifications through `slotsUpdatesSubscribe`.
|
||||
pub async fn slots_updates_subscribe(&self) -> ksp_core_lib::Result<crate::WsSubscription<crate::SolanaSlotUpdate>> {
|
||||
return self.inner.slots_updates_subscribe().await;
|
||||
}
|
||||
|
||||
/// Subscribes to unstable pre-consensus gossip vote notifications through `voteSubscribe`.
|
||||
pub async fn vote_subscribe(&self) -> ksp_core_lib::Result<crate::WsSubscription<crate::SolanaVoteNotification>> {
|
||||
return self.inner.vote_subscribe().await;
|
||||
/// Returns the crate-private shared physical session used by domain-specific facade wrappers.
|
||||
pub(crate) fn physical_session(&self) -> &crate::WsSession {
|
||||
return &self.inner;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,17 +58,29 @@ impl std::fmt::Debug for SolanaStandardWsSession {
|
||||
|
||||
/// Typed facade for one Helius LaserStream WebSocket physical session.
|
||||
///
|
||||
/// `0.2.8-pre.002` intentionally exposes only physical-session lifecycle through this facade. The six Helius-supported standard subscription wrappers are
|
||||
/// added in the next tranche after exact delegation and API-absence canaries are established. No public inner handle is exposed, so callers cannot bypass
|
||||
/// the provider-specific surface by recovering a generic [`crate::WsSession`].
|
||||
/// The facade exposes only the six standard Solana subscription families that Helius documents as supported. Provider-specific transaction subscription
|
||||
/// support is intentionally deferred to a later tranche. No public inner handle is exposed, so callers cannot bypass the provider-specific surface by
|
||||
/// recovering a generic [`crate::WsSession`].
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// async fn unsupported(session: &ksp_onchain_transport_lib::HeliusLaserStreamWsSession) {
|
||||
/// async fn unsupported_block(session: &ksp_onchain_transport_lib::HeliusLaserStreamWsSession) {
|
||||
/// let _ = session.block_subscribe().await;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ```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;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// ```compile_fail
|
||||
/// fn no_escape_hatch(session: ksp_onchain_transport_lib::HeliusLaserStreamWsSession) {
|
||||
/// let _ = session.into_inner();
|
||||
/// }
|
||||
@@ -169,6 +122,11 @@ impl HeliusLaserStreamWsSession {
|
||||
pub async fn close(&self) -> ksp_core_lib::Result<()> {
|
||||
return self.inner.close().await;
|
||||
}
|
||||
|
||||
/// Returns the crate-private shared physical session used by domain-specific facade wrappers.
|
||||
pub(crate) fn physical_session(&self) -> &crate::WsSession {
|
||||
return &self.inner;
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for HeliusLaserStreamWsSession {
|
||||
@@ -177,6 +135,10 @@ impl std::fmt::Debug for HeliusLaserStreamWsSession {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/ws_helius_standard.rs"]
|
||||
mod helius_standard_tests;
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/ws_protocol_session.rs"]
|
||||
mod tests;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-onchain-transport-lib/src/ws_transactions.rs
|
||||
// version: 3
|
||||
// version: 4
|
||||
|
||||
/// Optional configuration accepted by standard Solana `signatureSubscribe`.
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||
@@ -246,6 +246,46 @@ fn decode_logs_notification(method: &str, value: serde_json::Value) -> ksp_core_
|
||||
return std::result::Result::Ok(crate::SolanaRpcResponse::new(context, notification));
|
||||
}
|
||||
|
||||
impl crate::SolanaStandardWsSession {
|
||||
/// Subscribes to one Solana transaction signature through standard `signatureSubscribe`.
|
||||
pub async fn signature_subscribe(
|
||||
&self,
|
||||
signature: &str,
|
||||
config: std::option::Option<&crate::SolanaSignatureSubscribeConfig>,
|
||||
) -> ksp_core_lib::Result<crate::WsSubscription<crate::SolanaRpcResponse<crate::SolanaSignatureNotification>>> {
|
||||
return self.physical_session().signature_subscribe(signature, config).await;
|
||||
}
|
||||
|
||||
/// Subscribes to Solana transaction logs through standard `logsSubscribe`.
|
||||
pub async fn logs_subscribe(
|
||||
&self,
|
||||
filter: &crate::SolanaLogsSubscribeFilter,
|
||||
config: std::option::Option<&crate::SolanaCommitmentConfig>,
|
||||
) -> ksp_core_lib::Result<crate::WsSubscription<crate::SolanaRpcResponse<crate::SolanaLogsNotification>>> {
|
||||
return self.physical_session().logs_subscribe(filter, config).await;
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::HeliusLaserStreamWsSession {
|
||||
/// Subscribes to one transaction signature through the standard `signatureSubscribe` wire supported by Helius LaserStream WebSocket.
|
||||
pub async fn signature_subscribe(
|
||||
&self,
|
||||
signature: &str,
|
||||
config: std::option::Option<&crate::SolanaSignatureSubscribeConfig>,
|
||||
) -> ksp_core_lib::Result<crate::WsSubscription<crate::SolanaRpcResponse<crate::SolanaSignatureNotification>>> {
|
||||
return self.physical_session().signature_subscribe(signature, config).await;
|
||||
}
|
||||
|
||||
/// Subscribes to transaction logs through the standard `logsSubscribe` wire supported by Helius LaserStream WebSocket.
|
||||
pub async fn logs_subscribe(
|
||||
&self,
|
||||
filter: &crate::SolanaLogsSubscribeFilter,
|
||||
config: std::option::Option<&crate::SolanaCommitmentConfig>,
|
||||
) -> ksp_core_lib::Result<crate::WsSubscription<crate::SolanaRpcResponse<crate::SolanaLogsNotification>>> {
|
||||
return self.physical_session().logs_subscribe(filter, config).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/ws_transactions.rs"]
|
||||
mod tests;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-onchain-transport-lib/tests/public_api.rs
|
||||
// version: 34
|
||||
// version: 35
|
||||
|
||||
//! Integration tests for the public `ksp-onchain-transport-lib` consumer contract.
|
||||
|
||||
@@ -698,3 +698,18 @@ fn public_v0_2_8_pre_002_protocol_facades_are_available_without_replacing_the_st
|
||||
let _helius_close = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::close;
|
||||
let _helius_snapshot = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::snapshot;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn public_v0_2_8_pre_003_helius_standard_surface_reuses_shared_typed_contracts() {
|
||||
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 _shared_account_config = std::any::type_name::<ksp_onchain_transport_lib::SolanaAccountSubscribeConfig>();
|
||||
let _shared_program_config = std::any::type_name::<ksp_onchain_transport_lib::SolanaProgramSubscribeConfig>();
|
||||
let _shared_logs_filter = std::any::type_name::<ksp_onchain_transport_lib::SolanaLogsSubscribeFilter>();
|
||||
let _shared_signature_config = std::any::type_name::<ksp_onchain_transport_lib::SolanaSignatureSubscribeConfig>();
|
||||
let _shared_slot_notification = std::any::type_name::<ksp_onchain_transport_lib::SolanaSlotNotification>();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-onchain-transport-lib/tests/release_completeness.rs
|
||||
// version: 25
|
||||
// version: 26
|
||||
|
||||
//! Release-level completeness canaries for staged HTTP and WebSocket Transport coverage.
|
||||
|
||||
@@ -795,3 +795,19 @@ fn release_v0_2_8_pre_002_protocol_facades_preserve_the_standard_partition() {
|
||||
std::option::Option::Some("HeliusLaserStreamWsSession")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn release_v0_2_8_pre_003_helius_surface_is_exactly_six_standard_families_before_transaction_extension() {
|
||||
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 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("transaction_subscribe"));
|
||||
assert_eq!(ksp_onchain_transport_lib::WsProtocolKind::HeliusLaserStream.as_str(), "helius_laserstream");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
// file: crates/ksp-onchain-transport-lib/unit_tests/ws_helius_standard.rs
|
||||
// version: 1
|
||||
|
||||
use futures_util::SinkExt; // rust-rules: trait-import
|
||||
use futures_util::StreamExt; // rust-rules: trait-import
|
||||
|
||||
fn helius_endpoint(url: &str) -> crate::WsEndpointSettings {
|
||||
return crate::WsEndpointSettings::new(
|
||||
"local_helius_standard_fixture",
|
||||
true,
|
||||
crate::WsProviderName::new("helius"),
|
||||
crate::WsClusterName::new("local"),
|
||||
crate::WsProtocolKind::HeliusLaserStream,
|
||||
crate::WsEndpointUrl::parse(url).expect("local Helius WebSocket URL must parse"),
|
||||
crate::WsSessionSettings::default(),
|
||||
);
|
||||
}
|
||||
|
||||
async fn bind_local_listener() -> (tokio::net::TcpListener, std::string::String) {
|
||||
let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.expect("local listener must bind");
|
||||
let address = listener.local_addr().expect("local listener must expose address");
|
||||
return (listener, format!("ws://{address}"));
|
||||
}
|
||||
|
||||
async fn read_request(websocket: &mut tokio_tungstenite::WebSocketStream<tokio::net::TcpStream>) -> serde_json::Value {
|
||||
let message = websocket.next().await.expect("request message must exist").expect("request message must decode");
|
||||
let text = message.to_text().expect("request must be text");
|
||||
return serde_json::from_str(text).expect("request must contain JSON");
|
||||
}
|
||||
|
||||
async fn send_result(websocket: &mut tokio_tungstenite::WebSocketStream<tokio::net::TcpStream>, request: &serde_json::Value, result: serde_json::Value) {
|
||||
let id = request.get("id").and_then(serde_json::Value::as_u64).expect("request id must be numeric");
|
||||
let response = serde_json::json!({"jsonrpc":"2.0","id":id,"result":result});
|
||||
websocket.send(tokio_tungstenite::tungstenite::Message::Text(response.to_string().into())).await.expect("local response must send");
|
||||
}
|
||||
|
||||
async fn expect_pair(
|
||||
websocket: &mut tokio_tungstenite::WebSocketStream<tokio::net::TcpStream>,
|
||||
subscribe_method: &str,
|
||||
expected_params: serde_json::Value,
|
||||
unsubscribe_method: &str,
|
||||
remote_id: u64,
|
||||
) {
|
||||
let subscribe = read_request(websocket).await;
|
||||
assert_eq!(subscribe["method"], serde_json::Value::String(subscribe_method.to_owned()));
|
||||
assert_eq!(subscribe["params"], expected_params);
|
||||
send_result(websocket, &subscribe, serde_json::json!(remote_id)).await;
|
||||
let unsubscribe = read_request(websocket).await;
|
||||
assert_eq!(unsubscribe["method"], serde_json::Value::String(unsubscribe_method.to_owned()));
|
||||
assert_eq!(unsubscribe["params"], serde_json::json!([remote_id]));
|
||||
send_result(websocket, &unsubscribe, serde_json::json!(true)).await;
|
||||
}
|
||||
|
||||
async fn wait_for_close_frame(websocket: &mut tokio_tungstenite::WebSocketStream<tokio::net::TcpStream>) {
|
||||
loop {
|
||||
let message = websocket.next().await;
|
||||
match message {
|
||||
std::option::Option::Some(std::result::Result::Ok(tokio_tungstenite::tungstenite::Message::Close(_))) => return,
|
||||
std::option::Option::Some(std::result::Result::Ok(_)) => {},
|
||||
std::option::Option::Some(std::result::Result::Err(_)) | std::option::Option::None => return,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn helius_facade_reuses_exact_standard_wire_for_all_six_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");
|
||||
let mut websocket = tokio_tungstenite::accept_async(stream).await.expect("local WebSocket handshake must succeed");
|
||||
expect_pair(
|
||||
&mut websocket,
|
||||
"accountSubscribe",
|
||||
serde_json::json!(["11111111111111111111111111111111", {"encoding":"base64","commitment":"confirmed"}]),
|
||||
"accountUnsubscribe",
|
||||
101,
|
||||
)
|
||||
.await;
|
||||
expect_pair(
|
||||
&mut websocket,
|
||||
"programSubscribe",
|
||||
serde_json::json!(["11111111111111111111111111111111", {"encoding":"jsonParsed","filters":[{"dataSize":80}],"withContext":true}]),
|
||||
"programUnsubscribe",
|
||||
102,
|
||||
)
|
||||
.await;
|
||||
expect_pair(&mut websocket, "logsSubscribe", serde_json::json!(["all", {"commitment":"finalized"}]), "logsUnsubscribe", 103).await;
|
||||
expect_pair(
|
||||
&mut websocket,
|
||||
"signatureSubscribe",
|
||||
serde_json::json!(["fixture-signature", {"commitment":"confirmed","enableReceivedNotification":true}]),
|
||||
"signatureUnsubscribe",
|
||||
104,
|
||||
)
|
||||
.await;
|
||||
expect_pair(&mut websocket, "slotSubscribe", serde_json::json!([]), "slotUnsubscribe", 105).await;
|
||||
expect_pair(&mut websocket, "rootSubscribe", serde_json::json!([]), "rootUnsubscribe", 106).await;
|
||||
wait_for_close_frame(&mut websocket).await;
|
||||
});
|
||||
let session = crate::HeliusLaserStreamWsSession::connect(helius_endpoint(url.as_str())).await.expect("Helius facade must connect");
|
||||
let pubkey = "11111111111111111111111111111111".parse::<ksp_core_lib::Pubkey>().expect("fixture pubkey must parse");
|
||||
let account_config = crate::SolanaAccountSubscribeConfig::new(
|
||||
std::option::Option::Some(crate::SolanaAccountEncoding::Base64),
|
||||
std::option::Option::None,
|
||||
std::option::Option::Some(crate::SolanaCommitment::Confirmed),
|
||||
);
|
||||
let mut account = session.account_subscribe(&pubkey, std::option::Option::Some(&account_config)).await.expect("Helius accountSubscribe must register");
|
||||
assert!(account.unsubscribe().await.expect("Helius accountUnsubscribe must complete"));
|
||||
let program_config = crate::SolanaProgramSubscribeConfig::new(
|
||||
crate::SolanaAccountSubscribeConfig::new(
|
||||
std::option::Option::Some(crate::SolanaAccountEncoding::JsonParsed),
|
||||
std::option::Option::None,
|
||||
std::option::Option::None,
|
||||
),
|
||||
std::vec![crate::SolanaProgramAccountFilter::DataSize(80)],
|
||||
std::option::Option::Some(true),
|
||||
);
|
||||
let mut program = session.program_subscribe(&pubkey, std::option::Option::Some(&program_config)).await.expect("Helius programSubscribe must register");
|
||||
assert!(program.unsubscribe().await.expect("Helius programUnsubscribe must complete"));
|
||||
let logs_config = crate::SolanaCommitmentConfig::new(std::option::Option::Some(crate::SolanaCommitment::Finalized));
|
||||
let mut logs = session
|
||||
.logs_subscribe(&crate::SolanaLogsSubscribeFilter::All, std::option::Option::Some(&logs_config))
|
||||
.await
|
||||
.expect("Helius logsSubscribe must register");
|
||||
assert!(logs.unsubscribe().await.expect("Helius logsUnsubscribe must complete"));
|
||||
let signature_config =
|
||||
crate::SolanaSignatureSubscribeConfig::new(std::option::Option::Some(crate::SolanaCommitment::Confirmed), std::option::Option::Some(true));
|
||||
let mut signature = session
|
||||
.signature_subscribe("fixture-signature", std::option::Option::Some(&signature_config))
|
||||
.await
|
||||
.expect("Helius signatureSubscribe must register");
|
||||
assert!(signature.unsubscribe().await.expect("Helius signatureUnsubscribe must complete"));
|
||||
let mut slot = session.slot_subscribe().await.expect("Helius slotSubscribe must register");
|
||||
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"));
|
||||
session.close().await.expect("Helius facade close must complete");
|
||||
server.await.expect("local Helius peer task must complete");
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-onchain-transport-lib/unit_tests/ws_protocol_session.rs
|
||||
// version: 2
|
||||
// version: 3
|
||||
|
||||
use futures_util::StreamExt; // rust-rules: trait-import
|
||||
|
||||
@@ -92,4 +92,13 @@ fn protocol_facades_define_no_second_actor_socket_or_public_inner_escape_hatch()
|
||||
assert!(!source.contains("WsSessionCommand"));
|
||||
assert!(!source.contains("pub fn inner("));
|
||||
assert!(!source.contains("pub fn into_inner("));
|
||||
assert!(!source.contains("pub async fn account_subscribe"));
|
||||
assert!(!source.contains("pub async fn block_subscribe"));
|
||||
assert!(!source.contains("pub async fn logs_subscribe"));
|
||||
assert!(!source.contains("pub async fn program_subscribe"));
|
||||
assert!(!source.contains("pub async fn root_subscribe"));
|
||||
assert!(!source.contains("pub async fn signature_subscribe"));
|
||||
assert!(!source.contains("pub async fn slot_subscribe"));
|
||||
assert!(!source.contains("pub async fn slots_updates_subscribe"));
|
||||
assert!(!source.contains("pub async fn vote_subscribe"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user