v0.2.2-pre.002-fix.001
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
# file: Cargo.toml
|
# file: Cargo.toml
|
||||||
# version: 111
|
# version: 112
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "3"
|
resolver = "3"
|
||||||
members = ["crates/ksp-app-config-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-logging-lib", "crates/ksp-onchain-transport-lib"]
|
members = ["crates/ksp-app-config-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-logging-lib", "crates/ksp-onchain-transport-lib"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.2.2-pre.2"
|
version = "0.2.2-pre.2.fix.1"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"
|
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-onchain-transport-lib/src/lib.rs
|
// file: crates/ksp-onchain-transport-lib/src/lib.rs
|
||||||
// version: 7
|
// version: 8
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
#![deny(unreachable_pub)]
|
#![deny(unreachable_pub)]
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
@@ -91,34 +91,24 @@ pub use self::resilience::HttpRetryCause;
|
|||||||
pub use self::resilience::HttpRetryDecision;
|
pub use self::resilience::HttpRetryDecision;
|
||||||
/// Evaluates the centralized bounded HTTP retry policy for one audited RPC method.
|
/// Evaluates the centralized bounded HTTP retry policy for one audited RPC method.
|
||||||
pub use self::resilience::evaluate_transport_retry;
|
pub use self::resilience::evaluate_transport_retry;
|
||||||
/// Optional typed configuration for the `getBalance` canary.
|
|
||||||
pub use self::rpc_canary::GetBalanceConfig;
|
|
||||||
/// Typed lamport balance returned by the `getBalance` canary.
|
|
||||||
pub use self::rpc_canary::GetBalanceResult;
|
|
||||||
/// Typed genesis hash returned by the `getGenesisHash` canary.
|
|
||||||
pub use self::rpc_canary::SolanaGenesisHash;
|
|
||||||
/// Typed healthy result returned by the `getHealth` canary.
|
|
||||||
pub use self::rpc_canary::SolanaNodeHealth;
|
|
||||||
/// Typed software-version response returned by the `getVersion` canary.
|
|
||||||
pub use self::rpc_canary::SolanaNodeVersion;
|
|
||||||
/// Account-data encoding accepted by Solana HTTP account methods.
|
|
||||||
pub use self::rpc_accounts::SolanaAccountEncoding;
|
|
||||||
/// Typed transport-level Solana account without Program/SPL decoding.
|
/// Typed transport-level Solana account without Program/SPL decoding.
|
||||||
pub use self::rpc_accounts::SolanaAccount;
|
pub use self::rpc_accounts::SolanaAccount;
|
||||||
/// Address and lamport balance returned by `getLargestAccounts`.
|
/// Address and lamport balance returned by `getLargestAccounts`.
|
||||||
pub use self::rpc_accounts::SolanaAccountBalance;
|
pub use self::rpc_accounts::SolanaAccountBalance;
|
||||||
/// Wire-preserving account data returned by Solana HTTP account methods.
|
/// Wire-preserving account data returned by Solana HTTP account methods.
|
||||||
pub use self::rpc_accounts::SolanaAccountData;
|
pub use self::rpc_accounts::SolanaAccountData;
|
||||||
|
/// Account-data encoding accepted by Solana HTTP account methods.
|
||||||
|
pub use self::rpc_accounts::SolanaAccountEncoding;
|
||||||
/// Shared account configuration used by account-info and token-account list methods.
|
/// Shared account configuration used by account-info and token-account list methods.
|
||||||
pub use self::rpc_accounts::SolanaAccountInfoConfig;
|
pub use self::rpc_accounts::SolanaAccountInfoConfig;
|
||||||
/// Byte range requested from account data without decoding it locally.
|
/// Byte range requested from account data without decoding it locally.
|
||||||
pub use self::rpc_accounts::SolanaDataSliceConfig;
|
pub use self::rpc_accounts::SolanaDataSliceConfig;
|
||||||
/// One public key plus its account returned by account-list RPC methods.
|
/// One public key plus its account returned by account-list RPC methods.
|
||||||
pub use self::rpc_accounts::SolanaKeyedAccount;
|
pub use self::rpc_accounts::SolanaKeyedAccount;
|
||||||
/// Filter accepted by `getLargestAccounts`.
|
|
||||||
pub use self::rpc_accounts::SolanaLargestAccountsFilter;
|
|
||||||
/// Optional configuration for `getLargestAccounts`.
|
/// Optional configuration for `getLargestAccounts`.
|
||||||
pub use self::rpc_accounts::SolanaLargestAccountsConfig;
|
pub use self::rpc_accounts::SolanaLargestAccountsConfig;
|
||||||
|
/// Filter accepted by `getLargestAccounts`.
|
||||||
|
pub use self::rpc_accounts::SolanaLargestAccountsFilter;
|
||||||
/// Bytes used by a `memcmp` program-account filter.
|
/// Bytes used by a `memcmp` program-account filter.
|
||||||
pub use self::rpc_accounts::SolanaMemcmpBytes;
|
pub use self::rpc_accounts::SolanaMemcmpBytes;
|
||||||
/// One `memcmp` filter applied to account data.
|
/// One `memcmp` filter applied to account data.
|
||||||
@@ -131,6 +121,16 @@ pub use self::rpc_accounts::SolanaProgramAccountFilter;
|
|||||||
pub use self::rpc_accounts::SolanaProgramAccountsConfig;
|
pub use self::rpc_accounts::SolanaProgramAccountsConfig;
|
||||||
/// Result union returned by `getProgramAccounts` with or without an RPC context.
|
/// Result union returned by `getProgramAccounts` with or without an RPC context.
|
||||||
pub use self::rpc_accounts::SolanaProgramAccountsResult;
|
pub use self::rpc_accounts::SolanaProgramAccountsResult;
|
||||||
|
/// Optional typed configuration for the `getBalance` canary.
|
||||||
|
pub use self::rpc_canary::GetBalanceConfig;
|
||||||
|
/// Typed lamport balance returned by the `getBalance` canary.
|
||||||
|
pub use self::rpc_canary::GetBalanceResult;
|
||||||
|
/// Typed genesis hash returned by the `getGenesisHash` canary.
|
||||||
|
pub use self::rpc_canary::SolanaGenesisHash;
|
||||||
|
/// Typed healthy result returned by the `getHealth` canary.
|
||||||
|
pub use self::rpc_canary::SolanaNodeHealth;
|
||||||
|
/// Typed software-version response returned by the `getVersion` canary.
|
||||||
|
pub use self::rpc_canary::SolanaNodeVersion;
|
||||||
/// Contact information returned for one cluster node.
|
/// Contact information returned for one cluster node.
|
||||||
pub use self::rpc_cluster::SolanaClusterNode;
|
pub use self::rpc_cluster::SolanaClusterNode;
|
||||||
/// Epoch-credit history entry returned by `getVoteAccounts`.
|
/// Epoch-credit history entry returned by `getVoteAccounts`.
|
||||||
@@ -163,15 +163,11 @@ pub use self::rpc_common::SolanaContextConfig;
|
|||||||
pub use self::rpc_common::SolanaRpcContext;
|
pub use self::rpc_common::SolanaRpcContext;
|
||||||
/// Generic contextual result returned by typed Solana HTTP RPC adapters.
|
/// Generic contextual result returned by typed Solana HTTP RPC adapters.
|
||||||
pub use self::rpc_common::SolanaRpcResponse;
|
pub use self::rpc_common::SolanaRpcResponse;
|
||||||
/// Exclusive selector accepted by token-account list RPC methods.
|
#[cfg(test)]
|
||||||
pub use self::rpc_tokens::SolanaTokenAccountSelector;
|
/// Decodes one private serde wire type into the shared Transport error domain for staged DTO tests.
|
||||||
/// Token-account balance entry returned by `getTokenLargestAccounts`.
|
|
||||||
pub use self::rpc_tokens::SolanaTokenAccountBalance;
|
|
||||||
/// Token amount returned by Solana HTTP token RPC methods.
|
|
||||||
pub use self::rpc_tokens::SolanaTokenAmount;
|
|
||||||
/// Decodes one private serde wire type into the shared Transport error domain.
|
|
||||||
pub(crate) use self::rpc_common::decode_wire_json;
|
pub(crate) use self::rpc_common::decode_wire_json;
|
||||||
/// Parses a base58 public key without echoing its wire value into diagnostics.
|
#[cfg(test)]
|
||||||
|
/// Parses a base58 public key without echoing its wire value into diagnostics for staged DTO tests.
|
||||||
pub(crate) use self::rpc_common::parse_wire_pubkey;
|
pub(crate) use self::rpc_common::parse_wire_pubkey;
|
||||||
/// Functional category used by the audited Solana HTTP JSON-RPC registry.
|
/// Functional category used by the audited Solana HTTP JSON-RPC registry.
|
||||||
pub use self::rpc_method::HttpRpcCategory;
|
pub use self::rpc_method::HttpRpcCategory;
|
||||||
@@ -195,6 +191,12 @@ pub use self::rpc_method::current_http_rpc_methods;
|
|||||||
pub use self::rpc_method::find_http_rpc_method;
|
pub use self::rpc_method::find_http_rpc_method;
|
||||||
/// Returns historically documented deprecated HTTP RPC descriptors retained for compliance history.
|
/// Returns historically documented deprecated HTTP RPC descriptors retained for compliance history.
|
||||||
pub use self::rpc_method::historical_http_rpc_methods;
|
pub use self::rpc_method::historical_http_rpc_methods;
|
||||||
|
/// Token-account balance entry returned by `getTokenLargestAccounts`.
|
||||||
|
pub use self::rpc_tokens::SolanaTokenAccountBalance;
|
||||||
|
/// Exclusive selector accepted by token-account list RPC methods.
|
||||||
|
pub use self::rpc_tokens::SolanaTokenAccountSelector;
|
||||||
|
/// Token amount returned by Solana HTTP token RPC methods.
|
||||||
|
pub use self::rpc_tokens::SolanaTokenAmount;
|
||||||
/// Open cluster or network descriptor used by HTTP endpoint settings.
|
/// Open cluster or network descriptor used by HTTP endpoint settings.
|
||||||
pub use self::settings::HttpClusterName;
|
pub use self::settings::HttpClusterName;
|
||||||
/// Runtime settings for one role declared by an HTTP endpoint.
|
/// Runtime settings for one role declared by an HTTP endpoint.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-onchain-transport-lib/src/rpc_accounts.rs
|
// file: crates/ksp-onchain-transport-lib/src/rpc_accounts.rs
|
||||||
// version: 1
|
// version: 2
|
||||||
|
|
||||||
/// Account-data encoding accepted by Solana HTTP account methods.
|
/// Account-data encoding accepted by Solana HTTP account methods.
|
||||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||||
@@ -29,6 +29,7 @@ impl SolanaAccountEncoding {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
fn from_wire(value: &str) -> std::option::Option<Self> {
|
fn from_wire(value: &str) -> std::option::Option<Self> {
|
||||||
return match value {
|
return match value {
|
||||||
"binary" => std::option::Option::Some(Self::Binary),
|
"binary" => std::option::Option::Some(Self::Binary),
|
||||||
@@ -67,6 +68,7 @@ impl SolanaDataSliceConfig {
|
|||||||
return self.length;
|
return self.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
fn to_json_value(self) -> serde_json::Value {
|
fn to_json_value(self) -> serde_json::Value {
|
||||||
return serde_json::json!({"offset": self.offset, "length": self.length});
|
return serde_json::json!({"offset": self.offset, "length": self.length});
|
||||||
}
|
}
|
||||||
@@ -116,14 +118,9 @@ impl SolanaAccountInfoConfig {
|
|||||||
return self.context.min_context_slot();
|
return self.context.min_context_slot();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether this config serializes to an empty JSON object.
|
|
||||||
#[must_use]
|
|
||||||
pub(crate) const fn is_empty(&self) -> bool {
|
|
||||||
return self.encoding.is_none() && self.data_slice.is_none() && self.context.is_empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Serializes this config to the Solana JSON-RPC wire object.
|
/// Serializes this config to the Solana JSON-RPC wire object.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
#[cfg(test)]
|
||||||
pub(crate) fn to_json_value(&self) -> serde_json::Value {
|
pub(crate) fn to_json_value(&self) -> serde_json::Value {
|
||||||
let context_value = self.context.to_json_value();
|
let context_value = self.context.to_json_value();
|
||||||
let mut object = match context_value {
|
let mut object = match context_value {
|
||||||
@@ -150,6 +147,7 @@ pub enum SolanaLargestAccountsFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SolanaLargestAccountsFilter {
|
impl SolanaLargestAccountsFilter {
|
||||||
|
#[cfg(test)]
|
||||||
fn as_str(self) -> &'static str {
|
fn as_str(self) -> &'static str {
|
||||||
return match self {
|
return match self {
|
||||||
Self::Circulating => "circulating",
|
Self::Circulating => "circulating",
|
||||||
@@ -197,6 +195,7 @@ impl SolanaLargestAccountsConfig {
|
|||||||
|
|
||||||
/// Serializes this config to the Solana JSON-RPC wire object.
|
/// Serializes this config to the Solana JSON-RPC wire object.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
#[cfg(test)]
|
||||||
pub(crate) fn to_json_value(&self) -> serde_json::Value {
|
pub(crate) fn to_json_value(&self) -> serde_json::Value {
|
||||||
let mut object = serde_json::Map::new();
|
let mut object = serde_json::Map::new();
|
||||||
if let std::option::Option::Some(commitment) = self.commitment {
|
if let std::option::Option::Some(commitment) = self.commitment {
|
||||||
@@ -249,6 +248,7 @@ impl SolanaMemcmpFilter {
|
|||||||
return &self.bytes;
|
return &self.bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
fn to_json_value(&self) -> serde_json::Value {
|
fn to_json_value(&self) -> serde_json::Value {
|
||||||
return match &self.bytes {
|
return match &self.bytes {
|
||||||
crate::SolanaMemcmpBytes::Base58(bytes) => serde_json::json!({"offset": self.offset, "bytes": bytes, "encoding": "base58"}),
|
crate::SolanaMemcmpBytes::Base58(bytes) => serde_json::json!({"offset": self.offset, "bytes": bytes, "encoding": "base58"}),
|
||||||
@@ -270,6 +270,7 @@ pub enum SolanaProgramAccountFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SolanaProgramAccountFilter {
|
impl SolanaProgramAccountFilter {
|
||||||
|
#[cfg(test)]
|
||||||
fn to_json_value(&self) -> serde_json::Value {
|
fn to_json_value(&self) -> serde_json::Value {
|
||||||
return match self {
|
return match self {
|
||||||
Self::DataSize(size) => serde_json::json!({"dataSize": size}),
|
Self::DataSize(size) => serde_json::json!({"dataSize": size}),
|
||||||
@@ -326,6 +327,7 @@ impl SolanaProgramAccountsConfig {
|
|||||||
|
|
||||||
/// Serializes this config to the Solana JSON-RPC wire object.
|
/// Serializes this config to the Solana JSON-RPC wire object.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
#[cfg(test)]
|
||||||
pub(crate) fn to_json_value(&self) -> serde_json::Value {
|
pub(crate) fn to_json_value(&self) -> serde_json::Value {
|
||||||
let account_value = self.account_config.to_json_value();
|
let account_value = self.account_config.to_json_value();
|
||||||
let mut object = match account_value {
|
let mut object = match account_value {
|
||||||
@@ -391,6 +393,7 @@ pub enum SolanaAccountData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SolanaAccountData {
|
impl SolanaAccountData {
|
||||||
|
#[cfg(test)]
|
||||||
fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
||||||
let decoded = crate::decode_wire_json::<WireAccountData>(method, value);
|
let decoded = crate::decode_wire_json::<WireAccountData>(method, value);
|
||||||
let wire = match decoded {
|
let wire = match decoded {
|
||||||
@@ -399,11 +402,9 @@ impl SolanaAccountData {
|
|||||||
};
|
};
|
||||||
return match wire {
|
return match wire {
|
||||||
WireAccountData::LegacyBinary(value) => std::result::Result::Ok(Self::LegacyBinary(value)),
|
WireAccountData::LegacyBinary(value) => std::result::Result::Ok(Self::LegacyBinary(value)),
|
||||||
WireAccountData::JsonParsed(value) => std::result::Result::Ok(Self::JsonParsed(crate::SolanaParsedAccountData {
|
WireAccountData::JsonParsed(value) => {
|
||||||
program: value.program,
|
std::result::Result::Ok(Self::JsonParsed(crate::SolanaParsedAccountData { program: value.program, parsed: value.parsed, space: value.space }))
|
||||||
parsed: value.parsed,
|
},
|
||||||
space: value.space,
|
|
||||||
})),
|
|
||||||
WireAccountData::Encoded((data, encoding)) => {
|
WireAccountData::Encoded((data, encoding)) => {
|
||||||
let parsed = crate::SolanaAccountEncoding::from_wire(encoding.as_str());
|
let parsed = crate::SolanaAccountEncoding::from_wire(encoding.as_str());
|
||||||
let encoding = match parsed {
|
let encoding = match parsed {
|
||||||
@@ -413,7 +414,7 @@ impl SolanaAccountData {
|
|||||||
ksp_core_lib::Error::new(crate::ERROR_CODE_INVALID_RESPONSE, "account data tuple uses an unknown encoding")
|
ksp_core_lib::Error::new(crate::ERROR_CODE_INVALID_RESPONSE, "account data tuple uses an unknown encoding")
|
||||||
.with_context("rpc_method", method),
|
.with_context("rpc_method", method),
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
if encoding == crate::SolanaAccountEncoding::Binary || encoding == crate::SolanaAccountEncoding::JsonParsed {
|
if encoding == crate::SolanaAccountEncoding::Binary || encoding == crate::SolanaAccountEncoding::JsonParsed {
|
||||||
return std::result::Result::Err(
|
return std::result::Result::Err(
|
||||||
@@ -422,7 +423,7 @@ impl SolanaAccountData {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
std::result::Result::Ok(Self::Encoded { data, encoding })
|
std::result::Result::Ok(Self::Encoded { data, encoding })
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -476,6 +477,7 @@ impl SolanaAccount {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Decodes one account DTO from the Solana JSON wire shape.
|
/// Decodes one account DTO from the Solana JSON wire shape.
|
||||||
|
#[cfg(test)]
|
||||||
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
||||||
let decoded = crate::decode_wire_json::<WireAccount>(method, value);
|
let decoded = crate::decode_wire_json::<WireAccount>(method, value);
|
||||||
let wire = match decoded {
|
let wire = match decoded {
|
||||||
@@ -524,6 +526,7 @@ impl SolanaKeyedAccount {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Decodes one keyed account from the Solana JSON wire shape.
|
/// Decodes one keyed account from the Solana JSON wire shape.
|
||||||
|
#[cfg(test)]
|
||||||
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
||||||
let decoded = crate::decode_wire_json::<WireKeyedAccount>(method, value);
|
let decoded = crate::decode_wire_json::<WireKeyedAccount>(method, value);
|
||||||
let wire = match decoded {
|
let wire = match decoded {
|
||||||
@@ -565,6 +568,7 @@ impl SolanaAccountBalance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Decodes one account-balance entry from the Solana JSON wire shape.
|
/// Decodes one account-balance entry from the Solana JSON wire shape.
|
||||||
|
#[cfg(test)]
|
||||||
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
||||||
let decoded = crate::decode_wire_json::<WireAccountBalance>(method, value);
|
let decoded = crate::decode_wire_json::<WireAccountBalance>(method, value);
|
||||||
let wire = match decoded {
|
let wire = match decoded {
|
||||||
@@ -588,6 +592,7 @@ pub enum SolanaProgramAccountsResult {
|
|||||||
Context(crate::SolanaRpcResponse<std::vec::Vec<crate::SolanaKeyedAccount>>),
|
Context(crate::SolanaRpcResponse<std::vec::Vec<crate::SolanaKeyedAccount>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
enum WireAccountData {
|
enum WireAccountData {
|
||||||
@@ -596,6 +601,7 @@ enum WireAccountData {
|
|||||||
Encoded((std::string::String, std::string::String)),
|
Encoded((std::string::String, std::string::String)),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
struct WireParsedAccountData {
|
struct WireParsedAccountData {
|
||||||
program: std::string::String,
|
program: std::string::String,
|
||||||
@@ -603,6 +609,7 @@ struct WireParsedAccountData {
|
|||||||
space: u64,
|
space: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
struct WireAccount {
|
struct WireAccount {
|
||||||
lamports: u64,
|
lamports: u64,
|
||||||
@@ -615,12 +622,14 @@ struct WireAccount {
|
|||||||
space: std::option::Option<u64>,
|
space: std::option::Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
struct WireKeyedAccount {
|
struct WireKeyedAccount {
|
||||||
pubkey: std::string::String,
|
pubkey: std::string::String,
|
||||||
account: serde_json::Value,
|
account: serde_json::Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
struct WireAccountBalance {
|
struct WireAccountBalance {
|
||||||
address: std::string::String,
|
address: std::string::String,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-onchain-transport-lib/src/rpc_cluster.rs
|
// file: crates/ksp-onchain-transport-lib/src/rpc_cluster.rs
|
||||||
// version: 1
|
// version: 2
|
||||||
|
|
||||||
/// Contact information returned for one cluster node.
|
/// Contact information returned for one cluster node.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
@@ -24,51 +24,82 @@ pub struct SolanaClusterNode {
|
|||||||
impl SolanaClusterNode {
|
impl SolanaClusterNode {
|
||||||
/// Returns the node identity public key.
|
/// Returns the node identity public key.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn pubkey(&self) -> &ksp_core_lib::Pubkey { return &self.pubkey; }
|
pub const fn pubkey(&self) -> &ksp_core_lib::Pubkey {
|
||||||
|
return &self.pubkey;
|
||||||
|
}
|
||||||
/// Returns the optional feature-set identifier.
|
/// Returns the optional feature-set identifier.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn feature_set(&self) -> std::option::Option<u32> { return self.feature_set; }
|
pub const fn feature_set(&self) -> std::option::Option<u32> {
|
||||||
|
return self.feature_set;
|
||||||
|
}
|
||||||
/// Returns the optional gossip endpoint.
|
/// Returns the optional gossip endpoint.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn gossip(&self) -> std::option::Option<&str> { return self.gossip.as_deref(); }
|
pub fn gossip(&self) -> std::option::Option<&str> {
|
||||||
|
return self.gossip.as_deref();
|
||||||
|
}
|
||||||
/// Returns the optional PubSub endpoint.
|
/// Returns the optional PubSub endpoint.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn pubsub(&self) -> std::option::Option<&str> { return self.pubsub.as_deref(); }
|
pub fn pubsub(&self) -> std::option::Option<&str> {
|
||||||
|
return self.pubsub.as_deref();
|
||||||
|
}
|
||||||
/// Returns the optional JSON-RPC endpoint.
|
/// Returns the optional JSON-RPC endpoint.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn rpc(&self) -> std::option::Option<&str> { return self.rpc.as_deref(); }
|
pub fn rpc(&self) -> std::option::Option<&str> {
|
||||||
|
return self.rpc.as_deref();
|
||||||
|
}
|
||||||
/// Returns the optional repair endpoint.
|
/// Returns the optional repair endpoint.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn serve_repair(&self) -> std::option::Option<&str> { return self.serve_repair.as_deref(); }
|
pub fn serve_repair(&self) -> std::option::Option<&str> {
|
||||||
|
return self.serve_repair.as_deref();
|
||||||
|
}
|
||||||
/// Returns the optional shred version.
|
/// Returns the optional shred version.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn shred_version(&self) -> std::option::Option<u16> { return self.shred_version; }
|
pub const fn shred_version(&self) -> std::option::Option<u16> {
|
||||||
|
return self.shred_version;
|
||||||
|
}
|
||||||
/// Returns the optional TPU endpoint.
|
/// Returns the optional TPU endpoint.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn tpu(&self) -> std::option::Option<&str> { return self.tpu.as_deref(); }
|
pub fn tpu(&self) -> std::option::Option<&str> {
|
||||||
|
return self.tpu.as_deref();
|
||||||
|
}
|
||||||
/// Returns the optional TPU forwards endpoint.
|
/// Returns the optional TPU forwards endpoint.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn tpu_forwards(&self) -> std::option::Option<&str> { return self.tpu_forwards.as_deref(); }
|
pub fn tpu_forwards(&self) -> std::option::Option<&str> {
|
||||||
|
return self.tpu_forwards.as_deref();
|
||||||
|
}
|
||||||
/// Returns the optional TPU forwards QUIC endpoint.
|
/// Returns the optional TPU forwards QUIC endpoint.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn tpu_forwards_quic(&self) -> std::option::Option<&str> { return self.tpu_forwards_quic.as_deref(); }
|
pub fn tpu_forwards_quic(&self) -> std::option::Option<&str> {
|
||||||
|
return self.tpu_forwards_quic.as_deref();
|
||||||
|
}
|
||||||
/// Returns the optional TPU QUIC endpoint.
|
/// Returns the optional TPU QUIC endpoint.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn tpu_quic(&self) -> std::option::Option<&str> { return self.tpu_quic.as_deref(); }
|
pub fn tpu_quic(&self) -> std::option::Option<&str> {
|
||||||
|
return self.tpu_quic.as_deref();
|
||||||
|
}
|
||||||
/// Returns the optional TPU vote endpoint.
|
/// Returns the optional TPU vote endpoint.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn tpu_vote(&self) -> std::option::Option<&str> { return self.tpu_vote.as_deref(); }
|
pub fn tpu_vote(&self) -> std::option::Option<&str> {
|
||||||
|
return self.tpu_vote.as_deref();
|
||||||
|
}
|
||||||
/// Returns the optional TVU endpoint.
|
/// Returns the optional TVU endpoint.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn tvu(&self) -> std::option::Option<&str> { return self.tvu.as_deref(); }
|
pub fn tvu(&self) -> std::option::Option<&str> {
|
||||||
|
return self.tvu.as_deref();
|
||||||
|
}
|
||||||
/// Returns the optional software-version string.
|
/// Returns the optional software-version string.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn version(&self) -> std::option::Option<&str> { return self.version.as_deref(); }
|
pub fn version(&self) -> std::option::Option<&str> {
|
||||||
|
return self.version.as_deref();
|
||||||
|
}
|
||||||
/// Returns the optional Agave client identifier extension.
|
/// Returns the optional Agave client identifier extension.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn client_id(&self) -> std::option::Option<&str> { return self.client_id.as_deref(); }
|
pub fn client_id(&self) -> std::option::Option<&str> {
|
||||||
|
return self.client_id.as_deref();
|
||||||
|
}
|
||||||
|
|
||||||
/// Decodes one cluster-node contact record from the Solana JSON wire shape.
|
/// Decodes one cluster-node contact record from the Solana JSON wire shape.
|
||||||
|
#[cfg(test)]
|
||||||
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
||||||
let decoded = crate::decode_wire_json::<WireClusterNode>(method, value);
|
let decoded = crate::decode_wire_json::<WireClusterNode>(method, value);
|
||||||
let wire = match decoded {
|
let wire = match decoded {
|
||||||
@@ -114,24 +145,37 @@ pub struct SolanaEpochInfo {
|
|||||||
impl SolanaEpochInfo {
|
impl SolanaEpochInfo {
|
||||||
/// Returns the absolute slot.
|
/// Returns the absolute slot.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn absolute_slot(&self) -> u64 { return self.absolute_slot; }
|
pub const fn absolute_slot(&self) -> u64 {
|
||||||
|
return self.absolute_slot;
|
||||||
|
}
|
||||||
/// Returns the block height.
|
/// Returns the block height.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn block_height(&self) -> u64 { return self.block_height; }
|
pub const fn block_height(&self) -> u64 {
|
||||||
|
return self.block_height;
|
||||||
|
}
|
||||||
/// Returns the epoch number.
|
/// Returns the epoch number.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn epoch(&self) -> u64 { return self.epoch; }
|
pub const fn epoch(&self) -> u64 {
|
||||||
|
return self.epoch;
|
||||||
|
}
|
||||||
/// Returns the slot index within the epoch.
|
/// Returns the slot index within the epoch.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn slot_index(&self) -> u64 { return self.slot_index; }
|
pub const fn slot_index(&self) -> u64 {
|
||||||
|
return self.slot_index;
|
||||||
|
}
|
||||||
/// Returns the number of slots in the epoch.
|
/// Returns the number of slots in the epoch.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn slots_in_epoch(&self) -> u64 { return self.slots_in_epoch; }
|
pub const fn slots_in_epoch(&self) -> u64 {
|
||||||
|
return self.slots_in_epoch;
|
||||||
|
}
|
||||||
/// Returns the nullable transaction count.
|
/// Returns the nullable transaction count.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn transaction_count(&self) -> std::option::Option<u64> { return self.transaction_count; }
|
pub const fn transaction_count(&self) -> std::option::Option<u64> {
|
||||||
|
return self.transaction_count;
|
||||||
|
}
|
||||||
|
|
||||||
/// Decodes epoch information from the Solana JSON wire shape.
|
/// Decodes epoch information from the Solana JSON wire shape.
|
||||||
|
#[cfg(test)]
|
||||||
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
||||||
let decoded = crate::decode_wire_json::<WireEpochInfo>(method, value);
|
let decoded = crate::decode_wire_json::<WireEpochInfo>(method, value);
|
||||||
return match decoded {
|
return match decoded {
|
||||||
@@ -161,21 +205,32 @@ pub struct SolanaEpochSchedule {
|
|||||||
impl SolanaEpochSchedule {
|
impl SolanaEpochSchedule {
|
||||||
/// Returns the first normal epoch.
|
/// Returns the first normal epoch.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn first_normal_epoch(&self) -> u64 { return self.first_normal_epoch; }
|
pub const fn first_normal_epoch(&self) -> u64 {
|
||||||
|
return self.first_normal_epoch;
|
||||||
|
}
|
||||||
/// Returns the first normal slot.
|
/// Returns the first normal slot.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn first_normal_slot(&self) -> u64 { return self.first_normal_slot; }
|
pub const fn first_normal_slot(&self) -> u64 {
|
||||||
|
return self.first_normal_slot;
|
||||||
|
}
|
||||||
/// Returns the leader-schedule slot offset.
|
/// Returns the leader-schedule slot offset.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn leader_schedule_slot_offset(&self) -> u64 { return self.leader_schedule_slot_offset; }
|
pub const fn leader_schedule_slot_offset(&self) -> u64 {
|
||||||
|
return self.leader_schedule_slot_offset;
|
||||||
|
}
|
||||||
/// Returns the number of slots per epoch.
|
/// Returns the number of slots per epoch.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn slots_per_epoch(&self) -> u64 { return self.slots_per_epoch; }
|
pub const fn slots_per_epoch(&self) -> u64 {
|
||||||
|
return self.slots_per_epoch;
|
||||||
|
}
|
||||||
/// Returns whether epoch warmup is enabled.
|
/// Returns whether epoch warmup is enabled.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn warmup(&self) -> bool { return self.warmup; }
|
pub const fn warmup(&self) -> bool {
|
||||||
|
return self.warmup;
|
||||||
|
}
|
||||||
|
|
||||||
/// Decodes an epoch schedule from the Solana JSON wire shape.
|
/// Decodes an epoch schedule from the Solana JSON wire shape.
|
||||||
|
#[cfg(test)]
|
||||||
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
||||||
let decoded = crate::decode_wire_json::<WireEpochSchedule>(method, value);
|
let decoded = crate::decode_wire_json::<WireEpochSchedule>(method, value);
|
||||||
return match decoded {
|
return match decoded {
|
||||||
@@ -201,12 +256,17 @@ pub struct SolanaSnapshotSlotInfo {
|
|||||||
impl SolanaSnapshotSlotInfo {
|
impl SolanaSnapshotSlotInfo {
|
||||||
/// Returns the highest full snapshot slot.
|
/// Returns the highest full snapshot slot.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn full(&self) -> u64 { return self.full; }
|
pub const fn full(&self) -> u64 {
|
||||||
|
return self.full;
|
||||||
|
}
|
||||||
/// Returns the optional highest incremental snapshot slot.
|
/// Returns the optional highest incremental snapshot slot.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn incremental(&self) -> std::option::Option<u64> { return self.incremental; }
|
pub const fn incremental(&self) -> std::option::Option<u64> {
|
||||||
|
return self.incremental;
|
||||||
|
}
|
||||||
|
|
||||||
/// Decodes snapshot-slot information from the Solana JSON wire shape.
|
/// Decodes snapshot-slot information from the Solana JSON wire shape.
|
||||||
|
#[cfg(test)]
|
||||||
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
||||||
let decoded = crate::decode_wire_json::<WireSnapshotSlotInfo>(method, value);
|
let decoded = crate::decode_wire_json::<WireSnapshotSlotInfo>(method, value);
|
||||||
return match decoded {
|
return match decoded {
|
||||||
@@ -231,11 +291,19 @@ impl SolanaLeaderScheduleConfig {
|
|||||||
}
|
}
|
||||||
/// Returns the optional validator identity filter.
|
/// Returns the optional validator identity filter.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn identity(&self) -> std::option::Option<&ksp_core_lib::Pubkey> { return self.identity.as_ref(); }
|
pub const fn identity(&self) -> std::option::Option<&ksp_core_lib::Pubkey> {
|
||||||
|
return self.identity.as_ref();
|
||||||
|
}
|
||||||
/// Returns the optional commitment level.
|
/// Returns the optional commitment level.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn commitment(&self) -> std::option::Option<crate::SolanaCommitment> { return self.commitment; }
|
pub const fn commitment(&self) -> std::option::Option<crate::SolanaCommitment> {
|
||||||
fn is_empty(&self) -> bool { return self.identity.is_none() && self.commitment.is_none(); }
|
return self.commitment;
|
||||||
|
}
|
||||||
|
#[cfg(test)]
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
return self.identity.is_none() && self.commitment.is_none();
|
||||||
|
}
|
||||||
|
#[cfg(test)]
|
||||||
fn to_json_value(&self) -> serde_json::Value {
|
fn to_json_value(&self) -> serde_json::Value {
|
||||||
let mut object = serde_json::Map::new();
|
let mut object = serde_json::Map::new();
|
||||||
if let std::option::Option::Some(identity) = self.identity.as_ref() {
|
if let std::option::Option::Some(identity) = self.identity.as_ref() {
|
||||||
@@ -263,12 +331,15 @@ pub enum SolanaLeaderScheduleRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Default for SolanaLeaderScheduleRequest {
|
impl Default for SolanaLeaderScheduleRequest {
|
||||||
fn default() -> Self { return Self::CurrentEpoch(std::option::Option::None); }
|
fn default() -> Self {
|
||||||
|
return Self::CurrentEpoch(std::option::Option::None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SolanaLeaderScheduleRequest {
|
impl SolanaLeaderScheduleRequest {
|
||||||
/// Serializes the typed overload to the exact positional JSON-RPC params.
|
/// Serializes the typed overload to the exact positional JSON-RPC params.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
#[cfg(test)]
|
||||||
pub(crate) fn to_json_params(&self) -> std::vec::Vec<serde_json::Value> {
|
pub(crate) fn to_json_params(&self) -> std::vec::Vec<serde_json::Value> {
|
||||||
return match self {
|
return match self {
|
||||||
Self::CurrentEpoch(std::option::Option::None) => std::vec::Vec::new(),
|
Self::CurrentEpoch(std::option::Option::None) => std::vec::Vec::new(),
|
||||||
@@ -290,9 +361,12 @@ pub struct SolanaLeaderSchedule {
|
|||||||
impl SolanaLeaderSchedule {
|
impl SolanaLeaderSchedule {
|
||||||
/// Returns the complete leader schedule map.
|
/// Returns the complete leader schedule map.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn entries(&self) -> &std::collections::BTreeMap<ksp_core_lib::Pubkey, std::vec::Vec<usize>> { return &self.entries; }
|
pub const fn entries(&self) -> &std::collections::BTreeMap<ksp_core_lib::Pubkey, std::vec::Vec<usize>> {
|
||||||
|
return &self.entries;
|
||||||
|
}
|
||||||
|
|
||||||
/// Decodes a leader schedule map from the Solana JSON wire shape.
|
/// Decodes a leader schedule map from the Solana JSON wire shape.
|
||||||
|
#[cfg(test)]
|
||||||
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
||||||
let decoded = crate::decode_wire_json::<std::collections::BTreeMap<std::string::String, std::vec::Vec<usize>>>(method, value);
|
let decoded = crate::decode_wire_json::<std::collections::BTreeMap<std::string::String, std::vec::Vec<usize>>>(method, value);
|
||||||
let wire = match decoded {
|
let wire = match decoded {
|
||||||
@@ -334,18 +408,27 @@ impl SolanaVoteAccountsConfig {
|
|||||||
}
|
}
|
||||||
/// Returns the optional commitment.
|
/// Returns the optional commitment.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn commitment(&self) -> std::option::Option<crate::SolanaCommitment> { return self.commitment; }
|
pub const fn commitment(&self) -> std::option::Option<crate::SolanaCommitment> {
|
||||||
|
return self.commitment;
|
||||||
|
}
|
||||||
/// Returns the optional vote-account public key filter.
|
/// Returns the optional vote-account public key filter.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn vote_pubkey(&self) -> std::option::Option<&ksp_core_lib::Pubkey> { return self.vote_pubkey.as_ref(); }
|
pub const fn vote_pubkey(&self) -> std::option::Option<&ksp_core_lib::Pubkey> {
|
||||||
|
return self.vote_pubkey.as_ref();
|
||||||
|
}
|
||||||
/// Returns whether unstaked delinquent validators should be kept.
|
/// Returns whether unstaked delinquent validators should be kept.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn keep_unstaked_delinquents(&self) -> std::option::Option<bool> { return self.keep_unstaked_delinquents; }
|
pub const fn keep_unstaked_delinquents(&self) -> std::option::Option<bool> {
|
||||||
|
return self.keep_unstaked_delinquents;
|
||||||
|
}
|
||||||
/// Returns the optional delinquent slot distance.
|
/// Returns the optional delinquent slot distance.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn delinquent_slot_distance(&self) -> std::option::Option<u64> { return self.delinquent_slot_distance; }
|
pub const fn delinquent_slot_distance(&self) -> std::option::Option<u64> {
|
||||||
|
return self.delinquent_slot_distance;
|
||||||
|
}
|
||||||
/// Serializes this config to the Solana JSON-RPC wire object.
|
/// Serializes this config to the Solana JSON-RPC wire object.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
#[cfg(test)]
|
||||||
pub(crate) fn to_json_value(&self) -> serde_json::Value {
|
pub(crate) fn to_json_value(&self) -> serde_json::Value {
|
||||||
let mut object = serde_json::Map::new();
|
let mut object = serde_json::Map::new();
|
||||||
if let std::option::Option::Some(commitment) = self.commitment {
|
if let std::option::Option::Some(commitment) = self.commitment {
|
||||||
@@ -375,13 +458,19 @@ pub struct SolanaEpochCredits {
|
|||||||
impl SolanaEpochCredits {
|
impl SolanaEpochCredits {
|
||||||
/// Returns the epoch number.
|
/// Returns the epoch number.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn epoch(&self) -> u64 { return self.epoch; }
|
pub const fn epoch(&self) -> u64 {
|
||||||
|
return self.epoch;
|
||||||
|
}
|
||||||
/// Returns cumulative credits at the end of the epoch.
|
/// Returns cumulative credits at the end of the epoch.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn credits(&self) -> u64 { return self.credits; }
|
pub const fn credits(&self) -> u64 {
|
||||||
|
return self.credits;
|
||||||
|
}
|
||||||
/// Returns cumulative credits before the epoch.
|
/// Returns cumulative credits before the epoch.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn previous_credits(&self) -> u64 { return self.previous_credits; }
|
pub const fn previous_credits(&self) -> u64 {
|
||||||
|
return self.previous_credits;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// One validator vote-account record returned by `getVoteAccounts`.
|
/// One validator vote-account record returned by `getVoteAccounts`.
|
||||||
@@ -401,33 +490,52 @@ pub struct SolanaVoteAccountInfo {
|
|||||||
impl SolanaVoteAccountInfo {
|
impl SolanaVoteAccountInfo {
|
||||||
/// Returns the vote account public key.
|
/// Returns the vote account public key.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn vote_pubkey(&self) -> &ksp_core_lib::Pubkey { return &self.vote_pubkey; }
|
pub const fn vote_pubkey(&self) -> &ksp_core_lib::Pubkey {
|
||||||
|
return &self.vote_pubkey;
|
||||||
|
}
|
||||||
/// Returns the validator identity public key.
|
/// Returns the validator identity public key.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn node_pubkey(&self) -> &ksp_core_lib::Pubkey { return &self.node_pubkey; }
|
pub const fn node_pubkey(&self) -> &ksp_core_lib::Pubkey {
|
||||||
|
return &self.node_pubkey;
|
||||||
|
}
|
||||||
/// Returns the activated stake in lamports.
|
/// Returns the activated stake in lamports.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn activated_stake(&self) -> u64 { return self.activated_stake; }
|
pub const fn activated_stake(&self) -> u64 {
|
||||||
|
return self.activated_stake;
|
||||||
|
}
|
||||||
/// Returns the legacy/effective percentage commission field.
|
/// Returns the legacy/effective percentage commission field.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn commission(&self) -> u8 { return self.commission; }
|
pub const fn commission(&self) -> u8 {
|
||||||
|
return self.commission;
|
||||||
|
}
|
||||||
/// Returns the optional raw inflation-rewards commission in basis points.
|
/// Returns the optional raw inflation-rewards commission in basis points.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn inflation_rewards_commission_bps(&self) -> std::option::Option<u16> { return self.inflation_rewards_commission_bps; }
|
pub const fn inflation_rewards_commission_bps(&self) -> std::option::Option<u16> {
|
||||||
|
return self.inflation_rewards_commission_bps;
|
||||||
|
}
|
||||||
/// Returns whether the vote account is staked for the current epoch.
|
/// Returns whether the vote account is staked for the current epoch.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn epoch_vote_account(&self) -> bool { return self.epoch_vote_account; }
|
pub const fn epoch_vote_account(&self) -> bool {
|
||||||
|
return self.epoch_vote_account;
|
||||||
|
}
|
||||||
/// Returns the bounded RPC epoch-credit history.
|
/// Returns the bounded RPC epoch-credit history.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn epoch_credits(&self) -> &[crate::SolanaEpochCredits] { return self.epoch_credits.as_slice(); }
|
pub fn epoch_credits(&self) -> &[crate::SolanaEpochCredits] {
|
||||||
|
return self.epoch_credits.as_slice();
|
||||||
|
}
|
||||||
/// Returns the latest voted slot or zero when no vote exists.
|
/// Returns the latest voted slot or zero when no vote exists.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn last_vote(&self) -> u64 { return self.last_vote; }
|
pub const fn last_vote(&self) -> u64 {
|
||||||
|
return self.last_vote;
|
||||||
|
}
|
||||||
/// Returns the current root slot or zero when no root exists.
|
/// Returns the current root slot or zero when no root exists.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn root_slot(&self) -> u64 { return self.root_slot; }
|
pub const fn root_slot(&self) -> u64 {
|
||||||
|
return self.root_slot;
|
||||||
|
}
|
||||||
|
|
||||||
/// Decodes one vote-account record from the Solana JSON wire shape.
|
/// Decodes one vote-account record from the Solana JSON wire shape.
|
||||||
|
#[cfg(test)]
|
||||||
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
||||||
let decoded = crate::decode_wire_json::<WireVoteAccountInfo>(method, value);
|
let decoded = crate::decode_wire_json::<WireVoteAccountInfo>(method, value);
|
||||||
let wire = match decoded {
|
let wire = match decoded {
|
||||||
@@ -472,12 +580,17 @@ pub struct SolanaVoteAccountStatus {
|
|||||||
impl SolanaVoteAccountStatus {
|
impl SolanaVoteAccountStatus {
|
||||||
/// Returns current vote accounts.
|
/// Returns current vote accounts.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn current(&self) -> &[crate::SolanaVoteAccountInfo] { return self.current.as_slice(); }
|
pub fn current(&self) -> &[crate::SolanaVoteAccountInfo] {
|
||||||
|
return self.current.as_slice();
|
||||||
|
}
|
||||||
/// Returns delinquent vote accounts.
|
/// Returns delinquent vote accounts.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn delinquent(&self) -> &[crate::SolanaVoteAccountInfo] { return self.delinquent.as_slice(); }
|
pub fn delinquent(&self) -> &[crate::SolanaVoteAccountInfo] {
|
||||||
|
return self.delinquent.as_slice();
|
||||||
|
}
|
||||||
|
|
||||||
/// Decodes the complete vote-account status response from the Solana JSON wire shape.
|
/// Decodes the complete vote-account status response from the Solana JSON wire shape.
|
||||||
|
#[cfg(test)]
|
||||||
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
||||||
let decoded = crate::decode_wire_json::<WireVoteAccountStatus>(method, value);
|
let decoded = crate::decode_wire_json::<WireVoteAccountStatus>(method, value);
|
||||||
let wire = match decoded {
|
let wire = match decoded {
|
||||||
@@ -504,26 +617,42 @@ impl SolanaVoteAccountStatus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
struct WireClusterNode {
|
struct WireClusterNode {
|
||||||
pubkey: std::string::String,
|
pubkey: std::string::String,
|
||||||
#[serde(default)] feature_set: std::option::Option<u32>,
|
#[serde(default)]
|
||||||
#[serde(default)] gossip: std::option::Option<std::string::String>,
|
feature_set: std::option::Option<u32>,
|
||||||
#[serde(default)] pubsub: std::option::Option<std::string::String>,
|
#[serde(default)]
|
||||||
#[serde(default)] rpc: std::option::Option<std::string::String>,
|
gossip: std::option::Option<std::string::String>,
|
||||||
#[serde(default)] serve_repair: std::option::Option<std::string::String>,
|
#[serde(default)]
|
||||||
#[serde(default)] shred_version: std::option::Option<u16>,
|
pubsub: std::option::Option<std::string::String>,
|
||||||
#[serde(default)] tpu: std::option::Option<std::string::String>,
|
#[serde(default)]
|
||||||
#[serde(default)] tpu_forwards: std::option::Option<std::string::String>,
|
rpc: std::option::Option<std::string::String>,
|
||||||
#[serde(default)] tpu_forwards_quic: std::option::Option<std::string::String>,
|
#[serde(default)]
|
||||||
#[serde(default)] tpu_quic: std::option::Option<std::string::String>,
|
serve_repair: std::option::Option<std::string::String>,
|
||||||
#[serde(default)] tpu_vote: std::option::Option<std::string::String>,
|
#[serde(default)]
|
||||||
#[serde(default)] tvu: std::option::Option<std::string::String>,
|
shred_version: std::option::Option<u16>,
|
||||||
#[serde(default)] version: std::option::Option<std::string::String>,
|
#[serde(default)]
|
||||||
#[serde(default)] client_id: std::option::Option<std::string::String>,
|
tpu: std::option::Option<std::string::String>,
|
||||||
|
#[serde(default)]
|
||||||
|
tpu_forwards: std::option::Option<std::string::String>,
|
||||||
|
#[serde(default)]
|
||||||
|
tpu_forwards_quic: std::option::Option<std::string::String>,
|
||||||
|
#[serde(default)]
|
||||||
|
tpu_quic: std::option::Option<std::string::String>,
|
||||||
|
#[serde(default)]
|
||||||
|
tpu_vote: std::option::Option<std::string::String>,
|
||||||
|
#[serde(default)]
|
||||||
|
tvu: std::option::Option<std::string::String>,
|
||||||
|
#[serde(default)]
|
||||||
|
version: std::option::Option<std::string::String>,
|
||||||
|
#[serde(default)]
|
||||||
|
client_id: std::option::Option<std::string::String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
struct WireEpochInfo {
|
struct WireEpochInfo {
|
||||||
@@ -535,6 +664,7 @@ struct WireEpochInfo {
|
|||||||
transaction_count: std::option::Option<u64>,
|
transaction_count: std::option::Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
struct WireEpochSchedule {
|
struct WireEpochSchedule {
|
||||||
@@ -545,12 +675,14 @@ struct WireEpochSchedule {
|
|||||||
warmup: bool,
|
warmup: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
struct WireSnapshotSlotInfo {
|
struct WireSnapshotSlotInfo {
|
||||||
full: u64,
|
full: u64,
|
||||||
incremental: std::option::Option<u64>,
|
incremental: std::option::Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
struct WireVoteAccountInfo {
|
struct WireVoteAccountInfo {
|
||||||
@@ -566,6 +698,7 @@ struct WireVoteAccountInfo {
|
|||||||
root_slot: u64,
|
root_slot: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
struct WireVoteAccountStatus {
|
struct WireVoteAccountStatus {
|
||||||
current: std::vec::Vec<serde_json::Value>,
|
current: std::vec::Vec<serde_json::Value>,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-onchain-transport-lib/src/rpc_common.rs
|
// file: crates/ksp-onchain-transport-lib/src/rpc_common.rs
|
||||||
// version: 1
|
// version: 2
|
||||||
|
|
||||||
/// Commitment level accepted by typed Solana HTTP RPC adapters.
|
/// Commitment level accepted by typed Solana HTTP RPC adapters.
|
||||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||||
@@ -43,15 +43,10 @@ impl SolanaCommitmentConfig {
|
|||||||
return self.commitment;
|
return self.commitment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether this config serializes to an empty JSON object.
|
|
||||||
#[must_use]
|
|
||||||
pub(crate) const fn is_empty(&self) -> bool {
|
|
||||||
return self.commitment.is_none();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Serializes this config to the Solana JSON-RPC wire object.
|
/// Serializes this config to the Solana JSON-RPC wire object.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn to_json_value(&self) -> serde_json::Value {
|
#[cfg(test)]
|
||||||
|
pub(crate) fn to_json_value(self) -> serde_json::Value {
|
||||||
let mut object = serde_json::Map::new();
|
let mut object = serde_json::Map::new();
|
||||||
if let std::option::Option::Some(commitment) = self.commitment {
|
if let std::option::Option::Some(commitment) = self.commitment {
|
||||||
object.insert("commitment".to_owned(), serde_json::Value::String(commitment.as_str().to_owned()));
|
object.insert("commitment".to_owned(), serde_json::Value::String(commitment.as_str().to_owned()));
|
||||||
@@ -86,15 +81,9 @@ impl SolanaContextConfig {
|
|||||||
return self.min_context_slot;
|
return self.min_context_slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether this config serializes to an empty JSON object.
|
|
||||||
#[must_use]
|
|
||||||
pub(crate) const fn is_empty(&self) -> bool {
|
|
||||||
return self.commitment.is_none() && self.min_context_slot.is_none();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Serializes this config to the Solana JSON-RPC wire object.
|
/// Serializes this config to the Solana JSON-RPC wire object.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn to_json_value(&self) -> serde_json::Value {
|
pub(crate) fn to_json_value(self) -> serde_json::Value {
|
||||||
let mut object = serde_json::Map::new();
|
let mut object = serde_json::Map::new();
|
||||||
if let std::option::Option::Some(commitment) = self.commitment {
|
if let std::option::Option::Some(commitment) = self.commitment {
|
||||||
object.insert("commitment".to_owned(), serde_json::Value::String(commitment.as_str().to_owned()));
|
object.insert("commitment".to_owned(), serde_json::Value::String(commitment.as_str().to_owned()));
|
||||||
@@ -129,7 +118,8 @@ impl SolanaRpcContext {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decodes one RPC context from a parsed JSON value.
|
/// Decodes one RPC context from a parsed JSON value for staged DTO tests.
|
||||||
|
#[cfg(test)]
|
||||||
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
||||||
let decoded = crate::decode_wire_json::<WireRpcContext>(method, value);
|
let decoded = crate::decode_wire_json::<WireRpcContext>(method, value);
|
||||||
let context = match decoded {
|
let context = match decoded {
|
||||||
@@ -160,7 +150,8 @@ impl<T> SolanaRpcResponse<T> {
|
|||||||
return &self.value;
|
return &self.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a contextual response after wire decoding and validation.
|
/// Creates a contextual response after wire decoding and validation for staged DTO tests.
|
||||||
|
#[cfg(test)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) const fn new(context: crate::SolanaRpcContext, value: T) -> Self {
|
pub(crate) const fn new(context: crate::SolanaRpcContext, value: T) -> Self {
|
||||||
return Self { context, value };
|
return Self { context, value };
|
||||||
@@ -168,6 +159,7 @@ impl<T> SolanaRpcResponse<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Decodes one private serde wire type and maps shape failures to the shared Transport error domain.
|
/// Decodes one private serde wire type and maps shape failures to the shared Transport error domain.
|
||||||
|
#[cfg(test)]
|
||||||
pub(crate) fn decode_wire_json<T: serde::de::DeserializeOwned>(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<T> {
|
pub(crate) fn decode_wire_json<T: serde::de::DeserializeOwned>(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<T> {
|
||||||
let decoded = serde_json::from_value::<T>(value);
|
let decoded = serde_json::from_value::<T>(value);
|
||||||
return match decoded {
|
return match decoded {
|
||||||
@@ -181,6 +173,7 @@ pub(crate) fn decode_wire_json<T: serde::de::DeserializeOwned>(method: &str, val
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Parses a base58 public key from one wire field without echoing its value into diagnostics.
|
/// Parses a base58 public key from one wire field without echoing its value into diagnostics.
|
||||||
|
#[cfg(test)]
|
||||||
pub(crate) fn parse_wire_pubkey(method: &str, field: &str, value: &str) -> ksp_core_lib::Result<ksp_core_lib::Pubkey> {
|
pub(crate) fn parse_wire_pubkey(method: &str, field: &str, value: &str) -> ksp_core_lib::Result<ksp_core_lib::Pubkey> {
|
||||||
let parsed = value.parse::<ksp_core_lib::Pubkey>();
|
let parsed = value.parse::<ksp_core_lib::Pubkey>();
|
||||||
return match parsed {
|
return match parsed {
|
||||||
@@ -193,6 +186,7 @@ pub(crate) fn parse_wire_pubkey(method: &str, field: &str, value: &str) -> ksp_c
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
struct WireRpcContext {
|
struct WireRpcContext {
|
||||||
slot: u64,
|
slot: u64,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-onchain-transport-lib/src/rpc_tokens.rs
|
// file: crates/ksp-onchain-transport-lib/src/rpc_tokens.rs
|
||||||
// version: 1
|
// version: 2
|
||||||
|
|
||||||
/// Exclusive selector accepted by token-account list RPC methods.
|
/// Exclusive selector accepted by token-account list RPC methods.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
@@ -13,6 +13,7 @@ pub enum SolanaTokenAccountSelector {
|
|||||||
impl SolanaTokenAccountSelector {
|
impl SolanaTokenAccountSelector {
|
||||||
/// Serializes the exclusive selector to the Solana JSON-RPC wire object.
|
/// Serializes the exclusive selector to the Solana JSON-RPC wire object.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
#[cfg(test)]
|
||||||
pub(crate) fn to_json_value(&self) -> serde_json::Value {
|
pub(crate) fn to_json_value(&self) -> serde_json::Value {
|
||||||
return match self {
|
return match self {
|
||||||
Self::Mint(pubkey) => serde_json::json!({"mint": pubkey.to_string()}),
|
Self::Mint(pubkey) => serde_json::json!({"mint": pubkey.to_string()}),
|
||||||
@@ -56,6 +57,7 @@ impl SolanaTokenAmount {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Decodes one token amount from the Solana JSON wire shape.
|
/// Decodes one token amount from the Solana JSON wire shape.
|
||||||
|
#[cfg(test)]
|
||||||
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
||||||
let decoded = crate::decode_wire_json::<WireTokenAmount>(method, value);
|
let decoded = crate::decode_wire_json::<WireTokenAmount>(method, value);
|
||||||
return match decoded {
|
return match decoded {
|
||||||
@@ -91,6 +93,7 @@ impl SolanaTokenAccountBalance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Decodes one token-account balance entry from the Solana JSON wire shape.
|
/// Decodes one token-account balance entry from the Solana JSON wire shape.
|
||||||
|
#[cfg(test)]
|
||||||
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
||||||
let decoded = crate::decode_wire_json::<WireTokenAccountBalance>(method, value);
|
let decoded = crate::decode_wire_json::<WireTokenAccountBalance>(method, value);
|
||||||
let wire = match decoded {
|
let wire = match decoded {
|
||||||
@@ -112,6 +115,7 @@ impl SolanaTokenAccountBalance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
struct WireTokenAmount {
|
struct WireTokenAmount {
|
||||||
amount: std::string::String,
|
amount: std::string::String,
|
||||||
@@ -122,6 +126,7 @@ struct WireTokenAmount {
|
|||||||
ui_amount_string: std::string::String,
|
ui_amount_string: std::string::String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
#[derive(serde::Deserialize)]
|
#[derive(serde::Deserialize)]
|
||||||
struct WireTokenAccountBalance {
|
struct WireTokenAccountBalance {
|
||||||
address: std::string::String,
|
address: std::string::String,
|
||||||
|
|||||||
@@ -172,7 +172,6 @@ fn public_typed_canary_contracts_are_available_from_crate_root() {
|
|||||||
assert_eq!(ksp_onchain_transport_lib::SolanaNodeHealth::Healthy, ksp_onchain_transport_lib::SolanaNodeHealth::Healthy);
|
assert_eq!(ksp_onchain_transport_lib::SolanaNodeHealth::Healthy, ksp_onchain_transport_lib::SolanaNodeHealth::Healthy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn public_pre_002_shared_rpc_types_are_constructible_from_crate_root() {
|
fn public_pre_002_shared_rpc_types_are_constructible_from_crate_root() {
|
||||||
let context = ksp_onchain_transport_lib::SolanaContextConfig::new(
|
let context = ksp_onchain_transport_lib::SolanaContextConfig::new(
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-onchain-transport-lib/unit_tests/rpc_accounts.rs
|
// file: crates/ksp-onchain-transport-lib/unit_tests/rpc_accounts.rs
|
||||||
// version: 1
|
// version: 2
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn account_config_serializes_all_common_fields() {
|
fn account_config_serializes_all_common_fields() {
|
||||||
@@ -22,7 +22,12 @@ fn program_accounts_config_preserves_filter_variants_and_flags() {
|
|||||||
crate::SolanaProgramAccountFilter::Memcmp(crate::SolanaMemcmpFilter::new(4, crate::SolanaMemcmpBytes::Base64("AQID".to_owned()))),
|
crate::SolanaProgramAccountFilter::Memcmp(crate::SolanaMemcmpFilter::new(4, crate::SolanaMemcmpBytes::Base64("AQID".to_owned()))),
|
||||||
crate::SolanaProgramAccountFilter::TokenAccountState,
|
crate::SolanaProgramAccountFilter::TokenAccountState,
|
||||||
];
|
];
|
||||||
let config = crate::SolanaProgramAccountsConfig::new(crate::SolanaAccountInfoConfig::default(), filters, std::option::Option::Some(true), std::option::Option::Some(true));
|
let config = crate::SolanaProgramAccountsConfig::new(
|
||||||
|
crate::SolanaAccountInfoConfig::default(),
|
||||||
|
filters,
|
||||||
|
std::option::Option::Some(true),
|
||||||
|
std::option::Option::Some(true),
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config.to_json_value(),
|
config.to_json_value(),
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
@@ -35,19 +40,51 @@ fn program_accounts_config_preserves_filter_variants_and_flags() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn account_wire_fixture_preserves_legacy_encoded_and_json_parsed_data() {
|
fn account_wire_fixture_preserves_legacy_encoded_and_json_parsed_data() {
|
||||||
let values: std::vec::Vec<serde_json::Value> = serde_json::from_str(include_str!("../fixtures/http/account_data.variants.json")).expect("fixture must decode");
|
let values: std::vec::Vec<serde_json::Value> =
|
||||||
|
serde_json::from_str(include_str!("../fixtures/http/account_data.variants.json")).expect("fixture must decode");
|
||||||
let legacy = crate::SolanaAccount::decode_wire("fixture", values[0].clone()).expect("legacy account must decode");
|
let legacy = crate::SolanaAccount::decode_wire("fixture", values[0].clone()).expect("legacy account must decode");
|
||||||
assert!(matches!(legacy.data(), crate::SolanaAccountData::LegacyBinary(_)));
|
assert!(matches!(legacy.data(), crate::SolanaAccountData::LegacyBinary(_)));
|
||||||
assert_eq!(legacy.space(), std::option::Option::None);
|
assert_eq!(legacy.space(), std::option::Option::None);
|
||||||
let encoded = crate::SolanaAccount::decode_wire("fixture", values[1].clone()).expect("encoded account must decode");
|
let encoded = crate::SolanaAccount::decode_wire("fixture", values[1].clone()).expect("encoded account must decode");
|
||||||
assert!(matches!(encoded.data(), crate::SolanaAccountData::Encoded { encoding: crate::SolanaAccountEncoding::Base64Zstd, .. }));
|
assert!(matches!(encoded.data(), crate::SolanaAccountData::Encoded { encoding: crate::SolanaAccountEncoding::Base64Zstd, .. }));
|
||||||
let parsed = crate::SolanaAccount::decode_wire("fixture", values[2].clone()).expect("parsed account must decode");
|
let parsed = crate::SolanaAccount::decode_wire("fixture", values[2].clone()).expect("parsed account must decode");
|
||||||
match parsed.data() {
|
assert!(matches!(parsed.data(), crate::SolanaAccountData::JsonParsed(_)), "jsonParsed fixture must retain parsed data");
|
||||||
crate::SolanaAccountData::JsonParsed(value) => {
|
if let crate::SolanaAccountData::JsonParsed(value) = parsed.data() {
|
||||||
assert_eq!(value.program(), "spl-token");
|
assert_eq!(value.program(), "spl-token");
|
||||||
assert_eq!(value.space(), 165);
|
assert_eq!(value.space(), 165);
|
||||||
assert_eq!(value.parsed()["type"], serde_json::json!("account"));
|
assert_eq!(value.parsed()["type"], serde_json::json!("account"));
|
||||||
}
|
|
||||||
_ => assert!(false, "jsonParsed fixture must retain parsed data"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn staged_largest_and_keyed_account_helpers_match_wire_shapes() {
|
||||||
|
let config = crate::SolanaLargestAccountsConfig::new(
|
||||||
|
std::option::Option::Some(crate::SolanaCommitment::Finalized),
|
||||||
|
std::option::Option::Some(crate::SolanaLargestAccountsFilter::NonCirculating),
|
||||||
|
std::option::Option::Some(true),
|
||||||
|
);
|
||||||
|
assert_eq!(config.to_json_value(), serde_json::json!({"commitment":"finalized","filter":"nonCirculating","sortResults":true}));
|
||||||
|
|
||||||
|
let keyed = crate::SolanaKeyedAccount::decode_wire(
|
||||||
|
"fixture",
|
||||||
|
serde_json::json!({
|
||||||
|
"pubkey":"11111111111111111111111111111111",
|
||||||
|
"account":{
|
||||||
|
"lamports":42,
|
||||||
|
"data":["", "base64"],
|
||||||
|
"owner":"11111111111111111111111111111111",
|
||||||
|
"executable":false,
|
||||||
|
"rentEpoch":0,
|
||||||
|
"space":0
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.expect("keyed account must decode");
|
||||||
|
assert_eq!(keyed.pubkey().to_string(), "11111111111111111111111111111111");
|
||||||
|
assert_eq!(keyed.account().lamports(), 42);
|
||||||
|
|
||||||
|
let balance = crate::SolanaAccountBalance::decode_wire("fixture", serde_json::json!({"address":"11111111111111111111111111111111","lamports":99}))
|
||||||
|
.expect("account balance must decode");
|
||||||
|
assert_eq!(balance.address().to_string(), "11111111111111111111111111111111");
|
||||||
|
assert_eq!(balance.lamports(), 99);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-onchain-transport-lib/unit_tests/rpc_cluster.rs
|
// file: crates/ksp-onchain-transport-lib/unit_tests/rpc_cluster.rs
|
||||||
// version: 1
|
// version: 2
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn cluster_node_fixture_preserves_v4_client_id_and_optional_fields() {
|
fn cluster_node_fixture_preserves_v4_client_id_and_optional_fields() {
|
||||||
@@ -50,3 +50,64 @@ fn leader_schedule_request_encodes_current_epoch_and_slot_overloads_without_ambi
|
|||||||
std::vec![serde_json::json!(123), serde_json::json!({"identity":"11111111111111111111111111111111","commitment":"finalized"})]
|
std::vec![serde_json::json!(123), serde_json::json!({"identity":"11111111111111111111111111111111","commitment":"finalized"})]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn staged_epoch_snapshot_and_leader_helpers_preserve_wire_shapes() {
|
||||||
|
let epoch = crate::SolanaEpochInfo::decode_wire(
|
||||||
|
"getEpochInfo",
|
||||||
|
serde_json::json!({"absoluteSlot":10,"blockHeight":9,"epoch":2,"slotIndex":3,"slotsInEpoch":32,"transactionCount":null}),
|
||||||
|
)
|
||||||
|
.expect("epoch info must decode");
|
||||||
|
assert_eq!(epoch.transaction_count(), std::option::Option::None);
|
||||||
|
|
||||||
|
let schedule = crate::SolanaEpochSchedule::decode_wire(
|
||||||
|
"getEpochSchedule",
|
||||||
|
serde_json::json!({"firstNormalEpoch":1,"firstNormalSlot":32,"leaderScheduleSlotOffset":32,"slotsPerEpoch":64,"warmup":false}),
|
||||||
|
)
|
||||||
|
.expect("epoch schedule must decode");
|
||||||
|
assert_eq!(schedule.slots_per_epoch(), 64);
|
||||||
|
|
||||||
|
let snapshot = crate::SolanaSnapshotSlotInfo::decode_wire("getHighestSnapshotSlot", serde_json::json!({"full":100,"incremental":null}))
|
||||||
|
.expect("snapshot info must decode");
|
||||||
|
assert_eq!(snapshot.full(), 100);
|
||||||
|
assert_eq!(snapshot.incremental(), std::option::Option::None);
|
||||||
|
|
||||||
|
let leader = crate::SolanaLeaderSchedule::decode_wire("getLeaderSchedule", serde_json::json!({"11111111111111111111111111111111":[0,2,4]}))
|
||||||
|
.expect("leader schedule must decode");
|
||||||
|
assert_eq!(leader.entries().len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn staged_vote_status_and_config_helpers_preserve_wire_shapes() {
|
||||||
|
let vote_pubkey = "11111111111111111111111111111111".parse::<ksp_core_lib::Pubkey>().expect("fixture pubkey must parse");
|
||||||
|
let config = crate::SolanaVoteAccountsConfig::new(
|
||||||
|
std::option::Option::Some(crate::SolanaCommitment::Finalized),
|
||||||
|
std::option::Option::Some(vote_pubkey),
|
||||||
|
std::option::Option::Some(true),
|
||||||
|
std::option::Option::Some(128),
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
config.to_json_value(),
|
||||||
|
serde_json::json!({"commitment":"finalized","votePubkey":"11111111111111111111111111111111","keepUnstakedDelinquents":true,"delinquentSlotDistance":128})
|
||||||
|
);
|
||||||
|
|
||||||
|
let status = crate::SolanaVoteAccountStatus::decode_wire(
|
||||||
|
"getVoteAccounts",
|
||||||
|
serde_json::json!({
|
||||||
|
"current":[{
|
||||||
|
"votePubkey":"11111111111111111111111111111111",
|
||||||
|
"nodePubkey":"11111111111111111111111111111111",
|
||||||
|
"activatedStake":1,
|
||||||
|
"commission":5,
|
||||||
|
"epochVoteAccount":true,
|
||||||
|
"epochCredits":[],
|
||||||
|
"lastVote":2,
|
||||||
|
"rootSlot":1
|
||||||
|
}],
|
||||||
|
"delinquent":[]
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.expect("vote account status must decode");
|
||||||
|
assert_eq!(status.current().len(), 1);
|
||||||
|
assert!(status.delinquent().is_empty());
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-onchain-transport-lib/unit_tests/rpc_common.rs
|
// file: crates/ksp-onchain-transport-lib/unit_tests/rpc_common.rs
|
||||||
// version: 1
|
// version: 2
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn shared_context_configs_preserve_commitment_and_min_context_slot() {
|
fn shared_context_configs_preserve_commitment_and_min_context_slot() {
|
||||||
@@ -14,6 +14,8 @@ fn rpc_context_preserves_nullable_api_version() {
|
|||||||
let with_version = crate::SolanaRpcContext::decode_wire("fixture", serde_json::json!({"slot":10,"apiVersion":"4.2.1"})).expect("context must decode");
|
let with_version = crate::SolanaRpcContext::decode_wire("fixture", serde_json::json!({"slot":10,"apiVersion":"4.2.1"})).expect("context must decode");
|
||||||
assert_eq!(with_version.slot(), 10);
|
assert_eq!(with_version.slot(), 10);
|
||||||
assert_eq!(with_version.api_version(), std::option::Option::Some("4.2.1"));
|
assert_eq!(with_version.api_version(), std::option::Option::Some("4.2.1"));
|
||||||
|
let response = crate::SolanaRpcResponse::new(with_version, 7_u64);
|
||||||
|
assert_eq!(response.value(), &7_u64);
|
||||||
let without_version = crate::SolanaRpcContext::decode_wire("fixture", serde_json::json!({"slot":11})).expect("context must decode");
|
let without_version = crate::SolanaRpcContext::decode_wire("fixture", serde_json::json!({"slot":11})).expect("context must decode");
|
||||||
assert_eq!(without_version.api_version(), std::option::Option::None);
|
assert_eq!(without_version.api_version(), std::option::Option::None);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-onchain-transport-lib/unit_tests/rpc_tokens.rs
|
// file: crates/ksp-onchain-transport-lib/unit_tests/rpc_tokens.rs
|
||||||
// version: 1
|
// version: 2
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn token_selector_is_exclusive_by_construction() {
|
fn token_selector_is_exclusive_by_construction() {
|
||||||
@@ -17,3 +17,17 @@ fn token_amount_fixture_preserves_nullable_ui_amount() {
|
|||||||
assert_eq!(amount.ui_amount(), std::option::Option::None);
|
assert_eq!(amount.ui_amount(), std::option::Option::None);
|
||||||
assert_eq!(amount.ui_amount_string(), "18446744073.709551615");
|
assert_eq!(amount.ui_amount_string(), "18446744073.709551615");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn staged_token_account_balance_helper_preserves_address_and_amount() {
|
||||||
|
let value = serde_json::json!({
|
||||||
|
"address":"11111111111111111111111111111111",
|
||||||
|
"amount":"10",
|
||||||
|
"decimals":2,
|
||||||
|
"uiAmount":0.1,
|
||||||
|
"uiAmountString":"0.1"
|
||||||
|
});
|
||||||
|
let balance = crate::SolanaTokenAccountBalance::decode_wire("fixture", value).expect("token account balance must decode");
|
||||||
|
assert_eq!(balance.address().to_string(), "11111111111111111111111111111111");
|
||||||
|
assert_eq!(balance.amount().amount(), "10");
|
||||||
|
}
|
||||||
|
|||||||
213
deltas/0.2.2/pre.002-fix.001.md
Normal file
213
deltas/0.2.2/pre.002-fix.001.md
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
<!-- file: deltas/0.2.2/pre.002-fix.001.md -->
|
||||||
|
<!-- version: 1 -->
|
||||||
|
|
||||||
|
# Delta `0.2.2-pre.002-fix.001` — nettoyage des helpers RPC préparatoires et Clippy
|
||||||
|
|
||||||
|
## Base requise
|
||||||
|
|
||||||
|
```text
|
||||||
|
livraison : 0.2.2-pre.002
|
||||||
|
workspace.package.version = "0.2.2-pre.2"
|
||||||
|
```
|
||||||
|
|
||||||
|
Le correctif est ouvert après la validation locale communiquée le 2026-08-18. Les tests de `pre.002` passent, mais `cargo check` et Clippy
|
||||||
|
révèlent que plusieurs helpers privés de sérialisation/décodage ont été compilés trop tôt alors qu'aucun wrapper `0.2.2` ne les consomme encore.
|
||||||
|
|
||||||
|
## Objectif
|
||||||
|
|
||||||
|
Corriger exclusivement les warnings de qualité de `pre.002`, sans commencer les wrappers Accounts de `pre.003`, sans modifier les DTOs publics
|
||||||
|
et sans masquer les lints avec `#[allow(dead_code)]`.
|
||||||
|
|
||||||
|
Les catégories observées sont :
|
||||||
|
|
||||||
|
```text
|
||||||
|
dead_code helpers/wire structs préparatoires Accounts/Tokens/Cluster/Common
|
||||||
|
clippy::assertions_on_constants assert!(false, ...) dans un test Account
|
||||||
|
clippy::wrong_self_convention 2 serializers de configs Copy prenant &self
|
||||||
|
```
|
||||||
|
|
||||||
|
## Version Cargo
|
||||||
|
|
||||||
|
Le correctif modifie du Rust de production/test. Conformément à `VER-ID-007` et `VER-ID-010` :
|
||||||
|
|
||||||
|
```text
|
||||||
|
0.2.2-pre.2 -> 0.2.2-pre.2.fix.1
|
||||||
|
```
|
||||||
|
|
||||||
|
Aucune dépendance ni feature Cargo n'est ajoutée ou retirée.
|
||||||
|
|
||||||
|
## Correction du staging privé
|
||||||
|
|
||||||
|
`pre.002` doit établir les DTOs/configs publics et les fixtures communes, mais les wrappers qui consommeront réellement les helpers privés sont
|
||||||
|
répartis sur `pre.003` à `pre.006`.
|
||||||
|
|
||||||
|
Les serializers/décodeurs privés et leurs structs wire encore utilisés uniquement par les tests sont donc compilés sous :
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[cfg(test)]
|
||||||
|
```
|
||||||
|
|
||||||
|
jusqu'à la prerelease qui les active réellement dans un wrapper de production.
|
||||||
|
|
||||||
|
Cette correction :
|
||||||
|
|
||||||
|
- conserve tous les types, constructeurs, getters, enums et réexports publics introduits par `pre.002` ;
|
||||||
|
- conserve les fixtures Account/Token/Cluster/Vote ;
|
||||||
|
- ne rend aucun helper privé artificiellement public ;
|
||||||
|
- n'ajoute aucun `#[allow(dead_code)]` ;
|
||||||
|
- évite de porter du code privé mort dans la bibliothèque normale entre deux tranches ;
|
||||||
|
- impose aux prereleases suivantes de retirer `#[cfg(test)]` uniquement sur les helpers qu'elles commencent effectivement à consommer.
|
||||||
|
|
||||||
|
Les deux helpers `is_empty()` qui n'ont aucun consommateur ni test utile à ce stade sont supprimés et seront réintroduits seulement si un wrapper
|
||||||
|
les nécessite réellement.
|
||||||
|
|
||||||
|
## Correction Clippy
|
||||||
|
|
||||||
|
### Configs `Copy`
|
||||||
|
|
||||||
|
Les serializers internes de :
|
||||||
|
|
||||||
|
```text
|
||||||
|
SolanaCommitmentConfig
|
||||||
|
SolanaContextConfig
|
||||||
|
```
|
||||||
|
|
||||||
|
prennent désormais `self` par valeur, ce qui correspond à leur nature `Copy` et supprime `clippy::wrong_self_convention` sans modifier la forme JSON.
|
||||||
|
|
||||||
|
`SolanaContextConfig::to_json_value()` reste production-live parce que le canari `getBalance` de `0.2.1` le consomme déjà.
|
||||||
|
|
||||||
|
### Assertion constante
|
||||||
|
|
||||||
|
Le test `account_wire_fixture_preserves_legacy_encoded_and_json_parsed_data` remplace le `match` avec `assert!(false, ...)` par :
|
||||||
|
|
||||||
|
1. une assertion `matches!` sur `JsonParsed` ;
|
||||||
|
2. un `if let` pour vérifier le contenu.
|
||||||
|
|
||||||
|
Aucun `panic!()` ou `unreachable!()` explicite n'est introduit.
|
||||||
|
|
||||||
|
## Complément de tests préparatoires
|
||||||
|
|
||||||
|
Des tests unitaires sont ajoutés pour exercer les helpers privés désormais explicitement test-only qui n'étaient pas couverts par `pre.002` :
|
||||||
|
|
||||||
|
- sérialisation `SolanaLargestAccountsConfig` ;
|
||||||
|
- décodage `SolanaKeyedAccount` et `SolanaAccountBalance` ;
|
||||||
|
- décodage `SolanaTokenAccountBalance` ;
|
||||||
|
- décodage `SolanaEpochInfo`, `SolanaEpochSchedule`, `SolanaSnapshotSlotInfo` et `SolanaLeaderSchedule` ;
|
||||||
|
- sérialisation `SolanaVoteAccountsConfig` ;
|
||||||
|
- décodage `SolanaVoteAccountStatus` ;
|
||||||
|
- construction test-only de `SolanaRpcResponse<T>`.
|
||||||
|
|
||||||
|
Les fixtures et invariants `clientId`, `inflationRewardsCommissionBps`, `uiAmount: null`, `space: null` et Account data restent couverts.
|
||||||
|
|
||||||
|
## Fichiers ajoutés
|
||||||
|
|
||||||
|
```text
|
||||||
|
deltas/0.2.2/pre.002-fix.001.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fichiers modifiés
|
||||||
|
|
||||||
|
```text
|
||||||
|
Cargo.toml
|
||||||
|
crates/ksp-onchain-transport-lib/src/lib.rs
|
||||||
|
crates/ksp-onchain-transport-lib/src/rpc_common.rs
|
||||||
|
crates/ksp-onchain-transport-lib/src/rpc_accounts.rs
|
||||||
|
crates/ksp-onchain-transport-lib/src/rpc_tokens.rs
|
||||||
|
crates/ksp-onchain-transport-lib/src/rpc_cluster.rs
|
||||||
|
crates/ksp-onchain-transport-lib/unit_tests/rpc_common.rs
|
||||||
|
crates/ksp-onchain-transport-lib/unit_tests/rpc_accounts.rs
|
||||||
|
crates/ksp-onchain-transport-lib/unit_tests/rpc_tokens.rs
|
||||||
|
crates/ksp-onchain-transport-lib/unit_tests/rpc_cluster.rs
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fichiers supprimés
|
||||||
|
|
||||||
|
Aucun.
|
||||||
|
|
||||||
|
## Fichiers volontairement inchangés
|
||||||
|
|
||||||
|
```text
|
||||||
|
deltas/0.2.2/pre.002.md
|
||||||
|
docs/plans/009-V0_2_2_HTTP_ACCOUNTS_TOKENS_CLUSTER_PLAN.md
|
||||||
|
ROADMAP.md
|
||||||
|
CHANGELOG.md
|
||||||
|
crates/ksp-onchain-transport-lib/tests/public_api.rs
|
||||||
|
crates/ksp-onchain-transport-lib/tests/release_completeness.rs
|
||||||
|
crates/ksp-onchain-transport-lib/src/rpc_method.rs
|
||||||
|
crates/ksp-config-lib/**
|
||||||
|
config/**
|
||||||
|
```
|
||||||
|
|
||||||
|
Le delta `pre.002.md` reste une trace historique et n'est pas réécrit.
|
||||||
|
|
||||||
|
## Validation de `pre.002` ayant déclenché le correctif
|
||||||
|
|
||||||
|
Les commandes suivantes ont été exécutées par l'utilisateur sur `0.2.2-pre.002` avant création de ce fix :
|
||||||
|
|
||||||
|
```text
|
||||||
|
cargo fmt --all : exécuté
|
||||||
|
cargo check --workspace : OK, avec 42 warnings dead_code Transport
|
||||||
|
cargo clippy --workspace --all-targets : OK, avec les warnings dead_code + assertions_on_constants + wrong_self_convention
|
||||||
|
cargo test -p ksp-onchain-transport-lib : OK
|
||||||
|
```
|
||||||
|
|
||||||
|
Résultats de tests communiqués :
|
||||||
|
|
||||||
|
```text
|
||||||
|
81 tests unitaires : passés
|
||||||
|
9 tests public_api : passés
|
||||||
|
2 tests release_completeness : passés
|
||||||
|
0 échec
|
||||||
|
```
|
||||||
|
|
||||||
|
Ces résultats prouvent la fonctionnalité de la base `pre.002`, mais ne constituent pas une validation du présent fix.
|
||||||
|
|
||||||
|
## Contrôles statiques effectués pendant la préparation du fix
|
||||||
|
|
||||||
|
- aucune occurrence `#[allow(dead_code)]` ajoutée ;
|
||||||
|
- aucune occurrence `assert!(false` restante dans les fichiers modifiés ;
|
||||||
|
- les deux serializers de configs `Copy` prennent `self` par valeur ;
|
||||||
|
- les helpers privés préparatoires non consommés par la bibliothèque normale sont explicitement `#[cfg(test)]` ;
|
||||||
|
- les réexports crate-private de support wire sont eux aussi test-only tant qu'aucun wrapper ne les consomme ;
|
||||||
|
- les helpers test-only identifiés disposent d'un consommateur dans les tests unitaires ;
|
||||||
|
- aucune méthode RPC `0.2.2` n'est ajoutée à la surface typed-complete ;
|
||||||
|
- aucune dépendance/feature/configuration Transport n'est modifiée ;
|
||||||
|
- headers/version des fichiers modifiés incrémentés ;
|
||||||
|
- `pre.002.md` et le plan `009` restent inchangés.
|
||||||
|
|
||||||
|
## Validations du correctif non exécutées dans le sandbox
|
||||||
|
|
||||||
|
Le sandbox de préparation ne fournit pas `cargo`, `rustc` ni `rustfmt`. Les validations Rust du fix ne sont donc pas déclarées réussies.
|
||||||
|
|
||||||
|
Après application, exécuter au minimum :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo fmt --all
|
||||||
|
cargo check --workspace
|
||||||
|
cargo clippy --workspace --all-targets
|
||||||
|
cargo test -p ksp-onchain-transport-lib
|
||||||
|
```
|
||||||
|
|
||||||
|
Conformément aux règles Rust KSP, `cargo test --workspace` reste requis au checkpoint de clôture approprié. Aucun `cargo tree` supplémentaire n'est
|
||||||
|
requis pour ce fix puisqu'aucune dépendance ni feature n'a changé.
|
||||||
|
|
||||||
|
Résultat attendu immédiatement pour les commandes ci-dessus : aucune régression des canaris `0.2.1`, aucun warning ayant motivé ce fix et quatre
|
||||||
|
tests unitaires Transport supplémentaires par rapport à `pre.002`.
|
||||||
|
|
||||||
|
## Décisions prises
|
||||||
|
|
||||||
|
- corriger la cause des warnings plutôt que les masquer avec un lint allowance ;
|
||||||
|
- conserver les DTOs et fixtures publics de `pre.002` ;
|
||||||
|
- considérer les serializers/décodeurs privés non encore consommés comme support de test jusqu'à leur activation réelle ;
|
||||||
|
- ne pas rendre `serde_json::Value` public uniquement pour éviter `dead_code` ;
|
||||||
|
- ne pas commencer les cinq wrappers Accounts dans ce fix ;
|
||||||
|
- conserver `pre.003` comme prochaine tranche fonctionnelle après validation du correctif.
|
||||||
|
|
||||||
|
## Questions ouvertes
|
||||||
|
|
||||||
|
Aucune question bloquante.
|
||||||
|
|
||||||
|
## Suite
|
||||||
|
|
||||||
|
Après validation et commit de `0.2.2-pre.002-fix.001`, poursuivre avec `0.2.2-pre.003` pour les cinq wrappers Accounts. Les helpers Account
|
||||||
|
nécessaires seront alors sortis de `#[cfg(test)]` au fur et à mesure de leur consommation réelle.
|
||||||
Reference in New Issue
Block a user