Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract solana-account crate #2294

Merged
merged 16 commits into from
Oct 8, 2024
17 changes: 17 additions & 0 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
@@ -101,6 +101,7 @@ members = [
"runtime-transaction",
"sanitize",
"sdk",
"sdk/account",
"sdk/account-info",
"sdk/atomic-u64",
"sdk/cargo-build-sbf",
@@ -364,6 +365,7 @@ smallvec = "1.13.2"
smpl_jwt = "0.7.1"
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-info = { path = "sdk/account-info", version = "=2.1.0" }
solana-accounts-db = { path = "accounts-db", version = "=2.1.0" }
13 changes: 13 additions & 0 deletions programs/sbf/Cargo.lock

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

4 changes: 3 additions & 1 deletion sdk/Cargo.toml
Original file line number Diff line number Diff line change
@@ -35,11 +35,12 @@ full = [
"digest",
]
borsh = ["dep:borsh", "solana-program/borsh", "solana-secp256k1-recover/borsh"]
dev-context-only-utils = ["qualifier_attr"]
dev-context-only-utils = ["qualifier_attr", "solana-account/dev-context-only-utils"]
frozen-abi = [
"dep:solana-frozen-abi",
"dep:solana-frozen-abi-macro",
"solana-feature-set/frozen-abi",
"solana-account/frozen-abi",
"solana-program/frozen-abi",
"solana-short-vec/frozen-abi",
"solana-signature/frozen-abi"
@@ -83,6 +84,7 @@ serde_with = { workspace = true, features = ["macros"] }
sha2 = { workspace = true }
sha3 = { workspace = true, optional = true }
siphasher = { workspace = true }
solana-account = { workspace = true, features = ["bincode"] }
solana-bn254 = { workspace = true }
solana-decode-error = { workspace = true }
solana-derivation-path = { workspace = true }
38 changes: 38 additions & 0 deletions sdk/account/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
[package]
name = "solana-account"
description = "Solana Account type"
documentation = "https://docs.rs/solana-account"
version = { workspace = true }
authors = { workspace = true }
repository = { workspace = true }
homepage = { workspace = true }
license = { workspace = true }
edition = { workspace = true }

[dependencies]
bincode = { workspace = true, optional = true }
Copy link
Author

@kevinheavey kevinheavey Oct 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making serde and bincode optional won't remove those dependencies for now as solana-program still pulls them in, but by feature gating them from the start we avoid any breaking changes. In a later PR we'll remove the solana-program dep from this new crate

qualifier_attr = { workspace = true, optional = true }
serde = { workspace = true, optional = true }
serde_bytes = { workspace = true, optional = true }
serde_derive = { workspace = true, optional = true }
solana-frozen-abi = { workspace = true, optional = true }
solana-frozen-abi-macro = { workspace = true, optional = true }
solana-logger = { workspace = true, optional = true }
solana-program = { workspace = true }

[dev-dependencies]
solana-account = { path = ".", features = ["dev-context-only-utils"] }

[features]
bincode = ["dep:bincode", "serde"]
dev-context-only-utils = ["bincode", "dep:qualifier_attr"]
frozen-abi = [
"dep:solana-frozen-abi",
"dep:solana-frozen-abi-macro",
"dep:solana-logger",
"solana-program/frozen-abi",
]
serde = ["dep:serde", "dep:serde_bytes", "dep:serde_derive"]

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
74 changes: 59 additions & 15 deletions sdk/src/account.rs → sdk/account/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
#![cfg_attr(feature = "frozen-abi", feature(min_specialization))]
//! The Solana [`Account`] type.
#[cfg(feature = "dev-context-only-utils")]
use qualifier_attr::qualifiers;
#[cfg(feature = "serde")]
use serde::ser::{Serialize, Serializer};
#[cfg(feature = "frozen-abi")]
use solana_frozen_abi_macro::{frozen_abi, AbiExample};
#[cfg(feature = "bincode")]
use solana_program::sysvar::Sysvar;
use {
crate::{
solana_program::{
account_info::AccountInfo,
bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable,
clock::{Epoch, INITIAL_RENT_EPOCH},
debug_account_data::*,
lamports::LamportsError,
loader_v4,
pubkey::Pubkey,
},
serde::{
ser::{Serialize, Serializer},
Deserialize,
},
solana_program::{account_info::AccountInfo, debug_account_data::*, sysvar::Sysvar},
std::{
cell::{Ref, RefCell},
fmt,
@@ -32,13 +36,17 @@ use {
derive(AbiExample),
frozen_abi(digest = "2SUJNHbXMPWrsSXmDTFc4VHx2XQ85fT5Leabefh5Nwe7")
)]
#[derive(Deserialize, PartialEq, Eq, Clone, Default)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(
feature = "serde",
derive(serde_derive::Deserialize),
serde(rename_all = "camelCase")
)]
#[derive(PartialEq, Eq, Clone, Default)]
pub struct Account {
/// lamports in the account
pub lamports: u64,
/// data held in this account
#[serde(with = "serde_bytes")]
#[cfg_attr(feature = "serde", serde(with = "serde_bytes"))]
pub data: Vec<u8>,
/// the program that owns this account. If executable, the program that loads this account.
pub owner: Pubkey,
@@ -49,18 +57,22 @@ pub struct Account {
}

// mod because we need 'Account' below to have the name 'Account' to match expected serialization
#[cfg(feature = "serde")]
mod account_serialize {
#[cfg(feature = "frozen-abi")]
use solana_frozen_abi_macro::{frozen_abi, AbiExample};
use {
crate::{account::ReadableAccount, clock::Epoch, pubkey::Pubkey},
crate::ReadableAccount,
serde::{ser::Serializer, Serialize},
solana_program::{clock::Epoch, pubkey::Pubkey},
};
#[repr(C)]
#[cfg_attr(
feature = "frozen-abi",
derive(AbiExample),
frozen_abi(digest = "2SUJNHbXMPWrsSXmDTFc4VHx2XQ85fT5Leabefh5Nwe7")
)]
#[derive(Serialize)]
#[derive(serde_derive::Serialize)]
#[serde(rename_all = "camelCase")]
struct Account<'a> {
lamports: u64,
@@ -91,30 +103,36 @@ mod account_serialize {
}
}

#[cfg(feature = "serde")]
impl Serialize for Account {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
crate::account::account_serialize::serialize_account(self, serializer)
crate::account_serialize::serialize_account(self, serializer)
}
}

#[cfg(feature = "serde")]
impl Serialize for AccountSharedData {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
crate::account::account_serialize::serialize_account(self, serializer)
crate::account_serialize::serialize_account(self, serializer)
}
}

/// An Account with data that is stored on chain
/// This will be the in-memory representation of the 'Account' struct data.
/// The existing 'Account' structure cannot easily change due to downstream projects.
#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
#[derive(PartialEq, Eq, Clone, Default, Deserialize)]
#[serde(from = "Account")]
#[cfg_attr(
feature = "serde",
derive(serde_derive::Deserialize),
serde(from = "Account")
)]
#[derive(PartialEq, Eq, Clone, Default)]
pub struct AccountSharedData {
/// lamports in the account
lamports: u64,
@@ -435,6 +453,7 @@ fn shared_new_ref<T: WritableAccount>(
Rc::new(RefCell::new(shared_new::<T>(lamports, space, owner)))
}

#[cfg(feature = "bincode")]
fn shared_new_data<T: serde::Serialize, U: WritableAccount>(
lamports: u64,
state: &T,
@@ -449,6 +468,8 @@ fn shared_new_data<T: serde::Serialize, U: WritableAccount>(
Epoch::default(),
))
}

#[cfg(feature = "bincode")]
fn shared_new_ref_data<T: serde::Serialize, U: WritableAccount>(
lamports: u64,
state: &T,
@@ -459,6 +480,7 @@ fn shared_new_ref_data<T: serde::Serialize, U: WritableAccount>(
)?))
}

#[cfg(feature = "bincode")]
fn shared_new_data_with_space<T: serde::Serialize, U: WritableAccount>(
lamports: u64,
state: &T,
@@ -471,6 +493,8 @@ fn shared_new_data_with_space<T: serde::Serialize, U: WritableAccount>(

Ok(account)
}

#[cfg(feature = "bincode")]
fn shared_new_ref_data_with_space<T: serde::Serialize, U: WritableAccount>(
lamports: u64,
state: &T,
@@ -482,12 +506,14 @@ fn shared_new_ref_data_with_space<T: serde::Serialize, U: WritableAccount>(
)?))
}

#[cfg(feature = "bincode")]
fn shared_deserialize_data<T: serde::de::DeserializeOwned, U: ReadableAccount>(
account: &U,
) -> Result<T, bincode::Error> {
bincode::deserialize(account.data())
}

#[cfg(feature = "bincode")]
fn shared_serialize_data<T: serde::Serialize, U: WritableAccount>(
account: &mut U,
state: &T,
@@ -505,20 +531,23 @@ impl Account {
pub fn new_ref(lamports: u64, space: usize, owner: &Pubkey) -> Rc<RefCell<Self>> {
shared_new_ref(lamports, space, owner)
}
#[cfg(feature = "bincode")]
pub fn new_data<T: serde::Serialize>(
lamports: u64,
state: &T,
owner: &Pubkey,
) -> Result<Self, bincode::Error> {
shared_new_data(lamports, state, owner)
}
#[cfg(feature = "bincode")]
pub fn new_ref_data<T: serde::Serialize>(
lamports: u64,
state: &T,
owner: &Pubkey,
) -> Result<RefCell<Self>, bincode::Error> {
shared_new_ref_data(lamports, state, owner)
}
#[cfg(feature = "bincode")]
pub fn new_data_with_space<T: serde::Serialize>(
lamports: u64,
state: &T,
@@ -527,6 +556,7 @@ impl Account {
) -> Result<Self, bincode::Error> {
shared_new_data_with_space(lamports, state, space, owner)
}
#[cfg(feature = "bincode")]
pub fn new_ref_data_with_space<T: serde::Serialize>(
lamports: u64,
state: &T,
@@ -538,9 +568,11 @@ impl Account {
pub fn new_rent_epoch(lamports: u64, space: usize, owner: &Pubkey, rent_epoch: Epoch) -> Self {
shared_new_rent_epoch(lamports, space, owner, rent_epoch)
}
#[cfg(feature = "bincode")]
pub fn deserialize_data<T: serde::de::DeserializeOwned>(&self) -> Result<T, bincode::Error> {
shared_deserialize_data(self)
}
#[cfg(feature = "bincode")]
pub fn serialize_data<T: serde::Serialize>(&mut self, state: &T) -> Result<(), bincode::Error> {
shared_serialize_data(self, state)
}
@@ -631,20 +663,23 @@ impl AccountSharedData {
pub fn new_ref(lamports: u64, space: usize, owner: &Pubkey) -> Rc<RefCell<Self>> {
shared_new_ref(lamports, space, owner)
}
#[cfg(feature = "bincode")]
pub fn new_data<T: serde::Serialize>(
lamports: u64,
state: &T,
owner: &Pubkey,
) -> Result<Self, bincode::Error> {
shared_new_data(lamports, state, owner)
}
#[cfg(feature = "bincode")]
pub fn new_ref_data<T: serde::Serialize>(
lamports: u64,
state: &T,
owner: &Pubkey,
) -> Result<RefCell<Self>, bincode::Error> {
shared_new_ref_data(lamports, state, owner)
}
#[cfg(feature = "bincode")]
pub fn new_data_with_space<T: serde::Serialize>(
lamports: u64,
state: &T,
@@ -653,6 +688,7 @@ impl AccountSharedData {
) -> Result<Self, bincode::Error> {
shared_new_data_with_space(lamports, state, space, owner)
}
#[cfg(feature = "bincode")]
pub fn new_ref_data_with_space<T: serde::Serialize>(
lamports: u64,
state: &T,
@@ -664,9 +700,11 @@ impl AccountSharedData {
pub fn new_rent_epoch(lamports: u64, space: usize, owner: &Pubkey, rent_epoch: Epoch) -> Self {
shared_new_rent_epoch(lamports, space, owner, rent_epoch)
}
#[cfg(feature = "bincode")]
pub fn deserialize_data<T: serde::de::DeserializeOwned>(&self) -> Result<T, bincode::Error> {
shared_deserialize_data(self)
}
#[cfg(feature = "bincode")]
pub fn serialize_data<T: serde::Serialize>(&mut self, state: &T) -> Result<(), bincode::Error> {
shared_serialize_data(self, state)
}
@@ -675,6 +713,7 @@ impl AccountSharedData {
pub type InheritableAccountFields = (u64, Epoch);
pub const DUMMY_INHERITABLE_ACCOUNT_FIELDS: InheritableAccountFields = (1, INITIAL_RENT_EPOCH);

#[cfg(feature = "bincode")]
pub fn create_account_with_fields<S: Sysvar>(
sysvar: &S,
(lamports, rent_epoch): InheritableAccountFields,
@@ -686,10 +725,12 @@ pub fn create_account_with_fields<S: Sysvar>(
account
}

#[cfg(feature = "bincode")]
pub fn create_account_for_test<S: Sysvar>(sysvar: &S) -> Account {
create_account_with_fields(sysvar, DUMMY_INHERITABLE_ACCOUNT_FIELDS)
}

#[cfg(feature = "bincode")]
/// Create an `Account` from a `Sysvar`.
pub fn create_account_shared_data_with_fields<S: Sysvar>(
sysvar: &S,
@@ -698,18 +739,21 @@ pub fn create_account_shared_data_with_fields<S: Sysvar>(
AccountSharedData::from(create_account_with_fields(sysvar, fields))
}

#[cfg(feature = "bincode")]
pub fn create_account_shared_data_for_test<S: Sysvar>(sysvar: &S) -> AccountSharedData {
AccountSharedData::from(create_account_with_fields(
sysvar,
DUMMY_INHERITABLE_ACCOUNT_FIELDS,
))
}

#[cfg(feature = "bincode")]
/// Create a `Sysvar` from an `Account`'s data.
pub fn from_account<S: Sysvar, T: ReadableAccount>(account: &T) -> Option<S> {
bincode::deserialize(account.data()).ok()
}

#[cfg(feature = "bincode")]
/// Serialize a `Sysvar` into an `Account`'s data.
pub fn to_account<S: Sysvar, T: WritableAccount>(sysvar: &S, account: &mut T) -> Option<()> {
bincode::serialize_into(account.data_as_mut_slice(), sysvar).ok()
11 changes: 3 additions & 8 deletions sdk/src/account_utils.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
//! Useful extras for `Account` state.
use {
crate::{
account::{Account, AccountSharedData},
instruction::InstructionError,
},
crate::instruction::InstructionError,
bincode::ErrorKind,
solana_account::{Account, AccountSharedData},
std::cell::Ref,
};

@@ -66,10 +64,7 @@ where

#[cfg(test)]
mod tests {
use {
super::*,
crate::{account::AccountSharedData, pubkey::Pubkey},
};
use {super::*, crate::pubkey::Pubkey, solana_account::AccountSharedData};

#[test]
fn test_account_state() {
32 changes: 17 additions & 15 deletions sdk/src/client.rs
Original file line number Diff line number Diff line change
@@ -9,21 +9,23 @@
#![cfg(feature = "full")]

use crate::{
account::Account,
clock::Slot,
commitment_config::CommitmentConfig,
epoch_info::EpochInfo,
hash::Hash,
instruction::Instruction,
message::Message,
pubkey::Pubkey,
signature::{Keypair, Signature},
signer::Signer,
signers::Signers,
system_instruction,
transaction::{self, Transaction, VersionedTransaction},
transport::Result,
use {
crate::{
clock::Slot,
commitment_config::CommitmentConfig,
epoch_info::EpochInfo,
hash::Hash,
instruction::Instruction,
message::Message,
pubkey::Pubkey,
signature::{Keypair, Signature},
signer::Signer,
signers::Signers,
system_instruction,
transaction::{self, Transaction, VersionedTransaction},
transport::Result,
},
solana_account::Account,
};

pub trait Client: SyncClient + AsyncClient {
2 changes: 1 addition & 1 deletion sdk/src/feature.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Methods for working with `Feature` accounts.
use crate::account::{AccountSharedData, ReadableAccount, WritableAccount};
use solana_account::{AccountSharedData, ReadableAccount, WritableAccount};
pub use solana_program::feature::*;

pub fn from_account<T: ReadableAccount>(account: &T) -> Option<Feature> {
4 changes: 2 additions & 2 deletions sdk/src/genesis_config.rs
Original file line number Diff line number Diff line change
@@ -4,7 +4,6 @@

use {
crate::{
account::{Account, AccountSharedData},
clock::{UnixTimestamp, DEFAULT_TICKS_PER_SLOT},
epoch_schedule::EpochSchedule,
fee_calculator::FeeRateGovernor,
@@ -22,6 +21,7 @@ use {
bincode::{deserialize, serialize},
chrono::{TimeZone, Utc},
memmap2::Mmap,
solana_account::{Account, AccountSharedData},
std::{
collections::BTreeMap,
fmt,
@@ -87,7 +87,7 @@ impl FromStr for ClusterType {
#[cfg_attr(
feature = "frozen-abi",
derive(AbiExample),
frozen_abi(digest = "GDkrvVXezJYuGHcKSK19wvPBUMfKsifKQtoBxH1RpriL")
frozen_abi(digest = "2eGYc5mpKqDsS8sZfNS4mVq4qPptXYa9hSid2Hpv4DkQ")
)]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct GenesisConfig {
3 changes: 2 additions & 1 deletion sdk/src/lib.rs
Original file line number Diff line number Diff line change
@@ -58,7 +58,6 @@ pub use solana_program::{
};
#[cfg(feature = "borsh")]
pub use solana_program::{borsh, borsh0_10, borsh1};
pub mod account;
pub mod account_utils;
pub mod client;
pub mod commitment_config;
@@ -107,6 +106,8 @@ pub mod transaction_context;
pub mod transport;
pub mod wasm;

#[deprecated(since = "2.1.0", note = "Use `solana-account` crate instead")]
pub use solana_account as account;
#[deprecated(since = "2.1.0", note = "Use `solana-bn254` crate instead")]
pub use solana_bn254 as alt_bn128;
#[deprecated(since = "2.1.0", note = "Use `solana-decode-error` crate instead")]
2 changes: 1 addition & 1 deletion sdk/src/native_loader.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! The native loader native program.
use crate::account::{
use solana_account::{
Account, AccountSharedData, InheritableAccountFields, DUMMY_INHERITABLE_ACCOUNT_FIELDS,
};

2 changes: 1 addition & 1 deletion sdk/src/nonce_account.rs
Original file line number Diff line number Diff line change
@@ -2,14 +2,14 @@
use {
crate::{
account::{AccountSharedData, ReadableAccount},
account_utils::StateMut,
hash::Hash,
nonce::{
state::{Data, Versions},
State,
},
},
solana_account::{AccountSharedData, ReadableAccount},
std::cell::RefCell,
};

24 changes: 11 additions & 13 deletions sdk/src/rent_collector.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
#![cfg(feature = "full")]

//! calculate and collect rent from Accounts
use solana_sdk::{
account::{AccountSharedData, ReadableAccount, WritableAccount},
clock::Epoch,
epoch_schedule::EpochSchedule,
genesis_config::GenesisConfig,
incinerator,
pubkey::Pubkey,
rent::{Rent, RentDue},
use {
solana_account::{AccountSharedData, ReadableAccount, WritableAccount},
solana_sdk::{
clock::Epoch,
epoch_schedule::EpochSchedule,
genesis_config::GenesisConfig,
incinerator,
pubkey::Pubkey,
rent::{Rent, RentDue},
},
};

#[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
@@ -213,11 +215,7 @@ impl std::ops::AddAssign for CollectedInfo {

#[cfg(test)]
mod tests {
use {
super::*,
assert_matches::assert_matches,
solana_sdk::{account::Account, sysvar},
};
use {super::*, assert_matches::assert_matches, solana_account::Account, solana_sdk::sysvar};

fn default_rent_collector_clone_with_epoch(epoch: Epoch) -> RentCollector {
RentCollector::default().clone_with_epoch(epoch)
25 changes: 11 additions & 14 deletions sdk/src/transaction_context.rs
Original file line number Diff line number Diff line change
@@ -3,31 +3,28 @@

#[cfg(all(not(target_os = "solana"), feature = "full", debug_assertions))]
use crate::signature::Signature;
use {
crate::{instruction::InstructionError, pubkey::Pubkey},
solana_account::{AccountSharedData, ReadableAccount},
std::{
cell::{Ref, RefCell, RefMut},
collections::HashSet,
pin::Pin,
rc::Rc,
},
};
#[cfg(not(target_os = "solana"))]
use {
crate::{
account::WritableAccount,
rent::Rent,
system_instruction::{
MAX_PERMITTED_ACCOUNTS_DATA_ALLOCATIONS_PER_TRANSACTION, MAX_PERMITTED_DATA_LENGTH,
},
},
solana_account::WritableAccount,
solana_program::entrypoint::MAX_PERMITTED_DATA_INCREASE,
std::mem::MaybeUninit,
};
use {
crate::{
account::{AccountSharedData, ReadableAccount},
instruction::InstructionError,
pubkey::Pubkey,
},
std::{
cell::{Ref, RefCell, RefMut},
collections::HashSet,
pin::Pin,
rc::Rc,
},
};

/// Index of an account inside of the TransactionContext or an InstructionContext.
pub type IndexOfAccount = u16;