v0.2.11-pre.002-fix.003

This commit is contained in:
2026-08-25 20:37:09 +02:00
parent 126e8abfcd
commit 2dbddfe367
15 changed files with 499 additions and 271 deletions

View File

@@ -1,16 +1,16 @@
// file: crates/ksp-offchain-transport-lib/src/market_price_observation.rs
// version: 2
// version: 3
/// Maximum UTF-8 byte length accepted for safe provider provenance.
pub const PRICE_PROVENANCE_MAX_BYTES: usize = 256;
pub const MARKET_PRICE_PROVENANCE_MAX_BYTES: usize = 256;
/// Millisecond UTC timestamp used by provider-neutral public projections.
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, serde::Deserialize, serde::Serialize)]
pub struct PriceTimestamp {
pub struct MarketPriceTimestamp {
unix_millis: u64,
}
impl PriceTimestamp {
impl MarketPriceTimestamp {
/// Creates a UTC timestamp from whole milliseconds since Unix epoch.
#[must_use]
pub const fn from_unix_millis(unix_millis: u64) -> Self {
@@ -27,9 +27,9 @@ impl PriceTimestamp {
/// Safe bounded provenance supplied by one provider adapter.
#[derive(Clone, Debug, Eq, Hash, PartialEq, serde::Deserialize, serde::Serialize)]
#[serde(try_from = "std::string::String", into = "std::string::String")]
pub struct PriceProvenance(std::string::String);
pub struct MarketPriceProvenance(std::string::String);
impl PriceProvenance {
impl MarketPriceProvenance {
/// Creates bounded non-empty provenance without accepting control characters.
pub fn new(value: impl std::convert::Into<std::string::String>) -> ksp_core_lib::Result<Self> {
let value = value.into();
@@ -46,49 +46,49 @@ impl PriceProvenance {
}
}
impl std::convert::TryFrom<std::string::String> for PriceProvenance {
impl std::convert::TryFrom<std::string::String> for MarketPriceProvenance {
type Error = ksp_core_lib::Error;
fn try_from(value: std::string::String) -> std::result::Result<Self, Self::Error> {
return crate::PriceProvenance::new(value);
return crate::MarketPriceProvenance::new(value);
}
}
impl std::convert::From<PriceProvenance> for std::string::String {
fn from(value: PriceProvenance) -> Self {
impl std::convert::From<MarketPriceProvenance> for std::string::String {
fn from(value: MarketPriceProvenance) -> Self {
return value.0;
}
}
/// Public V1 SOL/USD observation normalized by Off-chain Transport.
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)]
pub struct SolUsdPriceObservation {
pair: crate::PricePair,
price: crate::PriceDecimal,
provider_id: crate::PriceProviderId,
provider_timestamp: std::option::Option<crate::PriceTimestamp>,
provenance: crate::PriceProvenance,
received_at: crate::PriceTimestamp,
request_started_at: crate::PriceTimestamp,
semantics: crate::PriceSemantics,
pub struct MarketPriceObservation {
pair: crate::MarketPricePair,
price: crate::MarketPriceDecimal,
provider_id: crate::MarketPriceProviderId,
provider_timestamp: std::option::Option<crate::MarketPriceTimestamp>,
provenance: crate::MarketPriceProvenance,
received_at: crate::MarketPriceTimestamp,
request_started_at: crate::MarketPriceTimestamp,
semantics: crate::MarketPriceSemantics,
}
impl SolUsdPriceObservation {
impl MarketPriceObservation {
/// Creates one successful normalized SOL/USD observation.
pub fn new(
provider_id: crate::PriceProviderId,
price: crate::PriceDecimal,
semantics: crate::PriceSemantics,
request_started_at: crate::PriceTimestamp,
received_at: crate::PriceTimestamp,
provider_timestamp: std::option::Option<crate::PriceTimestamp>,
provenance: crate::PriceProvenance,
provider_id: crate::MarketPriceProviderId,
price: crate::MarketPriceDecimal,
semantics: crate::MarketPriceSemantics,
request_started_at: crate::MarketPriceTimestamp,
received_at: crate::MarketPriceTimestamp,
provider_timestamp: std::option::Option<crate::MarketPriceTimestamp>,
provenance: crate::MarketPriceProvenance,
) -> ksp_core_lib::Result<Self> {
if received_at < request_started_at {
return std::result::Result::Err(observation_error());
}
return std::result::Result::Ok(Self {
pair: crate::PricePair::SolUsd,
pair: crate::MarketPricePair::SolUsd,
price,
provider_id,
provider_timestamp,
@@ -101,59 +101,59 @@ impl SolUsdPriceObservation {
/// Returns the only V1 pair represented by this observation.
#[must_use]
pub const fn pair(&self) -> crate::PricePair {
pub const fn pair(&self) -> crate::MarketPricePair {
return self.pair;
}
/// Returns the exact positive SOL/USD price.
#[must_use]
pub const fn price(&self) -> crate::PriceDecimal {
pub const fn price(&self) -> crate::MarketPriceDecimal {
return self.price;
}
/// Returns the opaque provider identifier.
#[must_use]
pub const fn provider_id(&self) -> &crate::PriceProviderId {
pub const fn provider_id(&self) -> &crate::MarketPriceProviderId {
return &self.provider_id;
}
/// Returns a provider timestamp only when the provider adapter has a real price-time field.
#[must_use]
pub const fn provider_timestamp(&self) -> std::option::Option<crate::PriceTimestamp> {
pub const fn provider_timestamp(&self) -> std::option::Option<crate::MarketPriceTimestamp> {
return self.provider_timestamp;
}
/// Returns safe provider provenance.
#[must_use]
pub const fn provenance(&self) -> &crate::PriceProvenance {
pub const fn provenance(&self) -> &crate::MarketPriceProvenance {
return &self.provenance;
}
/// Returns the KSP wall-clock receipt timestamp.
#[must_use]
pub const fn received_at(&self) -> crate::PriceTimestamp {
pub const fn received_at(&self) -> crate::MarketPriceTimestamp {
return self.received_at;
}
/// Returns the KSP wall-clock request-start timestamp.
#[must_use]
pub const fn request_started_at(&self) -> crate::PriceTimestamp {
pub const fn request_started_at(&self) -> crate::MarketPriceTimestamp {
return self.request_started_at;
}
/// Returns the provider-specific semantic class retained by the normalized observation.
#[must_use]
pub const fn semantics(&self) -> crate::PriceSemantics {
pub const fn semantics(&self) -> crate::MarketPriceSemantics {
return self.semantics;
}
}
fn observation_error() -> ksp_core_lib::Error {
return ksp_core_lib::Error::new(crate::ERROR_CODE_PROVIDER_OBSERVATION_INVALID, "invalid off-chain price observation");
return ksp_core_lib::Error::new(crate::ERROR_CODE_MARKET_PRICE_OBSERVATION_INVALID, "invalid off-chain market-price observation");
}
fn valid_provenance(value: &str) -> bool {
if value.is_empty() || value.len() > crate::PRICE_PROVENANCE_MAX_BYTES || value.trim() != value {
if value.is_empty() || value.len() > crate::MARKET_PRICE_PROVENANCE_MAX_BYTES || value.trim() != value {
return false;
}
for character in value.chars() {