Skip to content

Commit

Permalink
Extract account-decoder-client-types (#2872)
Browse files Browse the repository at this point in the history
* extract account-decoder-client-types and convert UiAccount::encode to a free func encode_ui_account

* rip out more types and replace some usage in rpc-client and rpc-client-api

* rip out more types

* remove remaining account-decoder usage from rpc-client

* remove account-decoder from rpc-client-api and transaction-status-client-types

* make zstd optional

* fix import

* ignore some lint

* update some conversions

* missing import

* missing import

* unused imports

* fmt

* don't feature-gate any variants of UiAccountEncoding

* fmt

* update newer code that used UiAccount::encode

* remove sdk dep from account-decoder-client-types

* add doc_auto_cfg like in #3121
  • Loading branch information
kevinheavey authored Oct 22, 2024
1 parent 660f8e2 commit 948da42
Show file tree
Hide file tree
Showing 32 changed files with 884 additions and 801 deletions.
20 changes: 18 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ split-debuginfo = "packed"
[workspace]
members = [
"account-decoder",
"account-decoder-client-types",
"accounts-bench",
"accounts-cluster-bench",
"accounts-db",
Expand Down Expand Up @@ -378,6 +379,7 @@ socket2 = "0.5.7"
soketto = "0.7"
solana-account = { path = "sdk/account", version = "=2.1.0" }
solana-account-decoder = { path = "account-decoder", version = "=2.1.0" }
solana-account-decoder-client-types = { path = "account-decoder-client-types", version = "=2.1.0" }
solana-account-info = { path = "sdk/account-info", version = "=2.1.0" }
solana-accounts-db = { path = "accounts-db", version = "=2.1.0" }
solana-address-lookup-table-program = { path = "programs/address-lookup-table", version = "=2.1.0" }
Expand Down
28 changes: 28 additions & 0 deletions account-decoder-client-types/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[package]
name = "solana-account-decoder-client-types"
description = "Core RPC client types for solana-account-decoder"
documentation = "https://docs.rs/solana-account-decoder-client-types"
version = { workspace = true }
authors = { workspace = true }
repository = { workspace = true }
homepage = { workspace = true }
license = { workspace = true }
edition = { workspace = true }

[dependencies]
base64 = { workspace = true }
bs58 = { workspace = true }
serde = { workspace = true }
serde_derive = { workspace = true }
serde_json = { workspace = true }
solana-account = { workspace = true }
solana-pubkey = { workspace = true }
zstd = { workspace = true, optional = true }

[features]
zstd = ["dep:zstd"]

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
all-features = true
rustdoc-args = ["--cfg=docsrs"]
99 changes: 99 additions & 0 deletions account-decoder-client-types/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
//! Core RPC client types for solana-account-decoder
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#[cfg(feature = "zstd")]
use std::io::Read;
use {
base64::{prelude::BASE64_STANDARD, Engine},
core::str::FromStr,
serde_derive::{Deserialize, Serialize},
serde_json::Value,
solana_account::WritableAccount,
solana_pubkey::Pubkey,
};
pub mod token;

/// A duplicate representation of an Account for pretty JSON serialization
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct UiAccount {
pub lamports: u64,
pub data: UiAccountData,
pub owner: String,
pub executable: bool,
pub rent_epoch: u64,
pub space: Option<u64>,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", untagged)]
pub enum UiAccountData {
LegacyBinary(String), // Legacy. Retained for RPC backwards compatibility
Json(ParsedAccount),
Binary(String, UiAccountEncoding),
}

impl UiAccountData {
/// Returns decoded account data in binary format if possible
pub fn decode(&self) -> Option<Vec<u8>> {
match self {
UiAccountData::Json(_) => None,
UiAccountData::LegacyBinary(blob) => bs58::decode(blob).into_vec().ok(),
UiAccountData::Binary(blob, encoding) => match encoding {
UiAccountEncoding::Base58 => bs58::decode(blob).into_vec().ok(),
UiAccountEncoding::Base64 => BASE64_STANDARD.decode(blob).ok(),
#[cfg(feature = "zstd")]
UiAccountEncoding::Base64Zstd => {
BASE64_STANDARD.decode(blob).ok().and_then(|zstd_data| {
let mut data = vec![];
zstd::stream::read::Decoder::new(zstd_data.as_slice())
.and_then(|mut reader| reader.read_to_end(&mut data))
.map(|_| data)
.ok()
})
}
#[cfg(not(feature = "zstd"))]
UiAccountEncoding::Base64Zstd => None,
UiAccountEncoding::Binary | UiAccountEncoding::JsonParsed => None,
},
}
}
}

#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[serde(rename_all = "camelCase")]
pub enum UiAccountEncoding {
Binary, // Legacy. Retained for RPC backwards compatibility
Base58,
Base64,
JsonParsed,
#[serde(rename = "base64+zstd")]
Base64Zstd,
}

impl UiAccount {
pub fn decode<T: WritableAccount>(&self) -> Option<T> {
let data = self.data.decode()?;
Some(T::create(
self.lamports,
data,
Pubkey::from_str(&self.owner).ok()?,
self.executable,
self.rent_epoch,
))
}
}

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct ParsedAccount {
pub program: String,
pub parsed: Value,
pub space: u64,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UiDataSliceConfig {
pub offset: usize,
pub length: usize,
}
Loading

0 comments on commit 948da42

Please sign in to comment.