v0.3.6-pre.004
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-onchain-transport-lib/src/http_executor.rs
|
||||
// version: 4
|
||||
// version: 7
|
||||
|
||||
const HTTP_BAD_GATEWAY: u16 = 502;
|
||||
const HTTP_GATEWAY_TIMEOUT: u16 = 504;
|
||||
@@ -8,6 +8,63 @@ const HTTP_REQUEST_TIMEOUT: u16 = 408;
|
||||
const HTTP_SERVICE_UNAVAILABLE: u16 = 503;
|
||||
const HTTP_TOO_MANY_REQUESTS: u16 = 429;
|
||||
|
||||
/// Typed value returned by an observed HTTP RPC path together with the safe identity of the endpoint that produced the successful response.
|
||||
///
|
||||
/// Endpoint URLs, headers and raw HTTP bodies are intentionally absent.
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct HttpObservedValue<T> {
|
||||
value: T,
|
||||
endpoint_name: std::string::String,
|
||||
provider: crate::HttpProviderName,
|
||||
}
|
||||
|
||||
impl<T> HttpObservedValue<T> {
|
||||
/// Returns the typed RPC value.
|
||||
#[must_use]
|
||||
pub const fn value(&self) -> &T {
|
||||
return &self.value;
|
||||
}
|
||||
|
||||
/// Returns the safe configured identity of the endpoint that produced the successful response.
|
||||
#[must_use]
|
||||
pub fn endpoint_name(&self) -> &str {
|
||||
return self.endpoint_name.as_str();
|
||||
}
|
||||
|
||||
/// Returns the safe provider descriptor attached to the successful endpoint.
|
||||
#[must_use]
|
||||
pub const fn provider(&self) -> &crate::HttpProviderName {
|
||||
return &self.provider;
|
||||
}
|
||||
|
||||
/// Consumes the observation and returns only the typed value.
|
||||
#[must_use]
|
||||
pub fn into_value(self) -> T {
|
||||
return self.value;
|
||||
}
|
||||
|
||||
/// Builds an observed value from a successful Transport attempt and its safe routing identity.
|
||||
pub(crate) fn new(value: T, endpoint_name: std::string::String, provider: crate::HttpProviderName) -> Self {
|
||||
return Self { value, endpoint_name, provider };
|
||||
}
|
||||
|
||||
/// Consumes the observation into its typed value and safe routing identity for crate-internal typed decoding.
|
||||
pub(crate) fn into_parts(self) -> (T, std::string::String, crate::HttpProviderName) {
|
||||
return (self.value, self.endpoint_name, self.provider);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::fmt::Debug for HttpObservedValue<T> {
|
||||
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
return formatter
|
||||
.debug_struct("HttpObservedValue")
|
||||
.field("endpoint_name", &self.endpoint_name)
|
||||
.field("provider", &self.provider)
|
||||
.field("value", &"<available>")
|
||||
.finish();
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::HttpTransportPool {
|
||||
/// Executes one audited standard Solana HTTP JSON-RPC method through KSP routing, admission and bounded retry policy.
|
||||
///
|
||||
@@ -19,6 +76,33 @@ impl crate::HttpTransportPool {
|
||||
method: &crate::HttpRpcMethodDescriptor,
|
||||
params: std::vec::Vec<serde_json::Value>,
|
||||
) -> ksp_core_lib::Result<serde_json::Value> {
|
||||
return self.execute_standard_rpc_with(role, method, params, |value, _permit| return value).await;
|
||||
}
|
||||
|
||||
/// Executes one audited standard Solana HTTP JSON-RPC method and retains only safe routing identity for the successful attempt.
|
||||
pub(crate) async fn execute_standard_rpc_observed(
|
||||
&self,
|
||||
role: &crate::HttpRoleName,
|
||||
method: &crate::HttpRpcMethodDescriptor,
|
||||
params: std::vec::Vec<serde_json::Value>,
|
||||
) -> ksp_core_lib::Result<crate::HttpObservedValue<serde_json::Value>> {
|
||||
return self
|
||||
.execute_standard_rpc_with(role, method, params, |value, permit| {
|
||||
return crate::HttpObservedValue::new(value, permit.selection().endpoint_name().to_owned(), permit.client().provider().clone());
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn execute_standard_rpc_with<T, F>(
|
||||
&self,
|
||||
role: &crate::HttpRoleName,
|
||||
method: &crate::HttpRpcMethodDescriptor,
|
||||
params: std::vec::Vec<serde_json::Value>,
|
||||
on_success: F,
|
||||
) -> ksp_core_lib::Result<T>
|
||||
where
|
||||
F: std::ops::FnOnce(serde_json::Value, &crate::HttpRequestPermit) -> T,
|
||||
{
|
||||
let support = method.ensure_runtime_supported();
|
||||
if let std::result::Result::Err(error) = support {
|
||||
return std::result::Result::Err(error);
|
||||
@@ -156,7 +240,12 @@ impl crate::HttpTransportPool {
|
||||
http_status = status,
|
||||
"completed Solana HTTP JSON-RPC request"
|
||||
);
|
||||
return parsed.into_result();
|
||||
let value = parsed.into_result();
|
||||
let value = match value {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
return std::result::Result::Ok(on_success(value, &permit));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -203,14 +292,11 @@ async fn wait_retry_delay(delay: std::time::Duration, deadline: std::time::Insta
|
||||
return std::time::Instant::now() < deadline;
|
||||
}
|
||||
|
||||
fn execution_timeout(method: &crate::HttpRpcMethodDescriptor, message: &str) -> ksp_core_lib::Result<serde_json::Value> {
|
||||
fn execution_timeout<T>(method: &crate::HttpRpcMethodDescriptor, message: &str) -> ksp_core_lib::Result<T> {
|
||||
return std::result::Result::Err(ksp_core_lib::Error::new(crate::ERROR_CODE_TIMEOUT, message).with_context("rpc_method", method.method()));
|
||||
}
|
||||
|
||||
fn rate_limited_error(
|
||||
method: &crate::HttpRpcMethodDescriptor,
|
||||
provider_retry_after: std::option::Option<std::time::Duration>,
|
||||
) -> ksp_core_lib::Result<serde_json::Value> {
|
||||
fn rate_limited_error<T>(method: &crate::HttpRpcMethodDescriptor, provider_retry_after: std::option::Option<std::time::Duration>) -> ksp_core_lib::Result<T> {
|
||||
let mut error = ksp_core_lib::Error::new(crate::ERROR_CODE_RATE_LIMITED, "Solana HTTP endpoint rate-limited the JSON-RPC request")
|
||||
.with_context("rpc_method", method.method());
|
||||
if let std::option::Option::Some(delay) = provider_retry_after {
|
||||
@@ -219,7 +305,7 @@ fn rate_limited_error(
|
||||
return std::result::Result::Err(error);
|
||||
}
|
||||
|
||||
fn http_status_error(method: &crate::HttpRpcMethodDescriptor, status: u16) -> ksp_core_lib::Result<serde_json::Value> {
|
||||
fn http_status_error<T>(method: &crate::HttpRpcMethodDescriptor, status: u16) -> ksp_core_lib::Result<T> {
|
||||
return std::result::Result::Err(
|
||||
ksp_core_lib::Error::new(crate::ERROR_CODE_HTTP_REQUEST_FAILED, "Solana HTTP endpoint returned an unsuccessful status")
|
||||
.with_context("rpc_method", method.method())
|
||||
|
||||
Reference in New Issue
Block a user