v0.2.7-pre.009

This commit is contained in:
2026-08-22 23:08:47 +02:00
parent 93199d1856
commit d17161234a
15 changed files with 1093 additions and 35 deletions

View File

@@ -0,0 +1,104 @@
// file: crates/ksp-onchain-transport-lib/src/ws_transactions.rs
// version: 1
/// Filter accepted by the standard Solana `logsSubscribe` WebSocket method.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum SolanaLogsSubscribeFilter {
/// Subscribe to all transactions except simple vote transactions.
All,
/// Subscribe to all transactions including simple vote transactions.
AllWithVotes,
/// Subscribe only to transactions mentioning exactly one public key.
Mentions(ksp_core_lib::Pubkey),
}
impl SolanaLogsSubscribeFilter {
fn to_json_value(&self) -> serde_json::Value {
return match self {
Self::All => serde_json::Value::String("all".to_owned()),
Self::AllWithVotes => serde_json::Value::String("allWithVotes".to_owned()),
Self::Mentions(pubkey) => serde_json::json!({"mentions": [pubkey.to_string()]}),
};
}
}
/// Typed value carried by a contextual Solana `logsNotification`.
#[derive(Clone, Debug, PartialEq)]
pub struct SolanaLogsNotification {
signature: std::string::String,
err: std::option::Option<serde_json::Value>,
logs: std::vec::Vec<std::string::String>,
}
impl SolanaLogsNotification {
/// Returns the base58 transaction signature exactly as reported by the RPC node.
#[must_use]
pub fn signature(&self) -> &str {
return self.signature.as_str();
}
/// Returns the nullable transaction-error wire value without interpreting Program/runtime error semantics.
#[must_use]
pub const fn err(&self) -> std::option::Option<&serde_json::Value> {
return self.err.as_ref();
}
/// Returns the ordered transaction log messages.
#[must_use]
pub fn logs(&self) -> &[std::string::String] {
return self.logs.as_slice();
}
}
impl crate::WsSession {
/// 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>>> {
let mut params = std::vec![filter.to_json_value()];
if let std::option::Option::Some(config) = config
&& config.commitment().is_some()
{
params.push(config.to_json_value());
}
return self.subscribe_typed(crate::WsSubscriptionKind::Logs, params, |value| decode_logs_notification("logsSubscribe", value)).await;
}
}
#[derive(serde::Deserialize)]
struct WireRpcResponse {
context: serde_json::Value,
value: WireLogsNotification,
}
#[derive(serde::Deserialize)]
struct WireLogsNotification {
signature: std::string::String,
err: serde_json::Value,
logs: std::vec::Vec<std::string::String>,
}
fn decode_logs_notification(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<crate::SolanaRpcResponse<crate::SolanaLogsNotification>> {
let decoded = crate::decode_wire_json::<WireRpcResponse>(method, value);
let wire = match decoded {
std::result::Result::Ok(wire) => wire,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let context = crate::SolanaRpcContext::decode_wire(method, wire.context);
let context = match context {
std::result::Result::Ok(context) => context,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let err = match wire.value.err {
serde_json::Value::Null => std::option::Option::None,
value => std::option::Option::Some(value),
};
let notification = crate::SolanaLogsNotification { signature: wire.value.signature, err, logs: wire.value.logs };
return std::result::Result::Ok(crate::SolanaRpcResponse::new(context, notification));
}
#[cfg(test)]
#[path = "../unit_tests/ws_transactions.rs"]
mod tests;