Skip to content

Commit

Permalink
sdk: Add Borsh support for types and utilities (solana-labs#15290)
Browse files Browse the repository at this point in the history
* sdk: Add Borsh to Pubkey

* Add serialization error for easier borsh integration

* Add Borsh usage to banks-client and sdk

* Rename SerializationError -> IOError

* Add new errors to proto

* Update Cargo lock

* Update Cargo.lock based on CI

* Clippy

* Update ABI on bank

* Address review feedback

* Update sanity program instruction count test
  • Loading branch information
joncinque authored Feb 18, 2021
1 parent fb1f2d5 commit 0f6f608
Show file tree
Hide file tree
Showing 16 changed files with 288 additions and 12 deletions.
54 changes: 52 additions & 2 deletions Cargo.lock

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

3 changes: 3 additions & 0 deletions banks-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ edition = "2018"

[dependencies]
bincode = "1.3.1"
borsh = "0.8.1"
borsh-derive = "0.8.1"
futures = "0.3"
mio = "0.7.6"
solana-banks-interface = { path = "../banks-interface", version = "1.6.0" }
solana-program = { path = "../sdk/program", version = "1.6.0" }
solana-sdk = { path = "../sdk", version = "1.6.0" }
tarpc = { version = "0.24.1", features = ["full"] }
tokio = { version = "1.1", features = ["full"] }
Expand Down
38 changes: 32 additions & 6 deletions banks-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,18 @@
//! but they are undocumented, may change over time, and are generally more
//! cumbersome to use.
use borsh::BorshDeserialize;
use futures::{future::join_all, Future, FutureExt};
pub use solana_banks_interface::{BanksClient as TarpcClient, TransactionStatus};
use solana_banks_interface::{BanksRequest, BanksResponse};
use solana_program::{
clock::Slot, fee_calculator::FeeCalculator, hash::Hash, program_pack::Pack, pubkey::Pubkey,
rent::Rent, sysvar,
};
use solana_sdk::{
account::{from_account, Account},
clock::Slot,
commitment_config::CommitmentLevel,
fee_calculator::FeeCalculator,
hash::Hash,
pubkey::Pubkey,
rent::Rent,
signature::Signature,
sysvar,
transaction::{self, Transaction},
transport,
};
Expand Down Expand Up @@ -218,6 +217,33 @@ impl BanksClient {
self.get_account_with_commitment(address, CommitmentLevel::default())
}

/// Return the unpacked account data at the given address
/// If the account is not found, an error is returned
pub fn get_packed_account_data<T: Pack>(
&mut self,
address: Pubkey,
) -> impl Future<Output = io::Result<T>> + '_ {
self.get_account(address).map(|result| {
let account =
result?.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Account not found"))?;
T::unpack_from_slice(&account.data)
.map_err(|_| io::Error::new(io::ErrorKind::Other, "Failed to deserialize account"))
})
}

/// Return the unpacked account data at the given address
/// If the account is not found, an error is returned
pub fn get_account_data_with_borsh<T: BorshDeserialize>(
&mut self,
address: Pubkey,
) -> impl Future<Output = io::Result<T>> + '_ {
self.get_account(address).map(|result| {
let account =
result?.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "account not found"))?;
T::try_from_slice(&account.data)
})
}

/// Return the balance in lamports of an account at the given address at the slot
/// corresponding to the given commitment level.
pub fn get_balance_with_commitment(
Expand Down
2 changes: 2 additions & 0 deletions program-test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ pub fn to_instruction_error(error: ProgramError) -> InstructionError {
ProgramError::AccountBorrowFailed => InstructionError::AccountBorrowFailed,
ProgramError::MaxSeedLengthExceeded => InstructionError::MaxSeedLengthExceeded,
ProgramError::InvalidSeeds => InstructionError::InvalidSeeds,
ProgramError::IOError(err) => InstructionError::IOError(err),
ProgramError::AccountNotRentExempt => InstructionError::AccountNotRentExempt,
}
}

Expand Down
62 changes: 62 additions & 0 deletions programs/bpf/Cargo.lock

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

2 changes: 1 addition & 1 deletion programs/bpf/tests/programs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1233,7 +1233,7 @@ fn assert_instruction_count() {
("solana_bpf_rust_noop", 488),
("solana_bpf_rust_param_passing", 48),
("solana_bpf_rust_ristretto", 19399),
("solana_bpf_rust_sanity", 894),
("solana_bpf_rust_sanity", 935),
]);
}

Expand Down
2 changes: 1 addition & 1 deletion runtime/src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ impl ExecuteTimings {
}

type BankStatusCache = StatusCache<Result<()>>;
#[frozen_abi(digest = "MUmkgPsCRrWL2HEsMEvpkWMis35kbBnaEZtrph5P6bk")]
#[frozen_abi(digest = "GESbL4xC5ndicqqZeCW4fEHtNR71NMESVWM3i2Ty2MY9")]
pub type BankSlotDelta = SlotDelta<Result<()>>;
type TransactionAccountRefCells = Vec<Rc<RefCell<Account>>>;
type TransactionAccountDepRefCells = Vec<(Pubkey, RefCell<Account>)>;
Expand Down
2 changes: 2 additions & 0 deletions sdk/program/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ edition = "2018"

[dependencies]
bincode = "1.3.1"
borsh = "0.8.1"
borsh-derive = "0.8.1"
bs58 = "0.3.1"
bv = { version = "0.11.1", features = ["serde"] }
hex = "0.4.2"
Expand Down
55 changes: 55 additions & 0 deletions sdk/program/src/borsh.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//! Borsh utils
use borsh::schema::{BorshSchema, Declaration, Definition, Fields};
use std::collections::HashMap;

/// Get packed length for the given BorchSchema Declaration
fn get_declaration_packed_len(
declaration: &str,
definitions: &HashMap<Declaration, Definition>,
) -> usize {
match definitions.get(declaration) {
Some(Definition::Array { length, elements }) => {
*length as usize * get_declaration_packed_len(elements, definitions)
}
Some(Definition::Enum { variants }) => {
1 + variants
.iter()
.map(|(_, declaration)| get_declaration_packed_len(declaration, definitions))
.max()
.unwrap_or(0)
}
Some(Definition::Struct { fields }) => match fields {
Fields::NamedFields(named_fields) => named_fields
.iter()
.map(|(_, declaration)| get_declaration_packed_len(declaration, definitions))
.sum(),
Fields::UnnamedFields(declarations) => declarations
.iter()
.map(|declaration| get_declaration_packed_len(declaration, definitions))
.sum(),
Fields::Empty => 0,
},
Some(Definition::Sequence {
elements: _elements,
}) => panic!("Missing support for Definition::Sequence"),
Some(Definition::Tuple { elements }) => elements
.iter()
.map(|element| get_declaration_packed_len(element, definitions))
.sum(),
None => match declaration {
"u8" | "i8" => 1,
"u16" | "i16" => 2,
"u32" | "i32" => 2,
"u64" | "i64" => 8,
"u128" | "i128" => 16,
"nil" => 0,
_ => panic!("Missing primitive type: {}", declaration),
},
}
}

/// Get the worst-case packed length for the given BorshSchema
pub fn get_packed_len<S: BorshSchema>() -> usize {
let schema_container = S::schema_container();
get_declaration_packed_len(&schema_container.declaration, &schema_container.definitions)
}
16 changes: 15 additions & 1 deletion sdk/program/src/hash.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! The `hash` module provides functions for creating SHA-256 hashes.

use crate::sanitize::Sanitize;
use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
use sha2::{Digest, Sha256};
use std::{convert::TryFrom, fmt, mem, str::FromStr};
use thiserror::Error;
Expand All @@ -9,7 +10,20 @@ pub const HASH_BYTES: usize = 32;
/// Maximum string length of a base58 encoded hash
const MAX_BASE58_LEN: usize = 44;
#[derive(
Serialize, Deserialize, Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd, Hash, AbiExample,
Serialize,
Deserialize,
BorshSerialize,
BorshDeserialize,
BorshSchema,
Clone,
Copy,
Default,
Eq,
PartialEq,
Ord,
PartialOrd,
Hash,
AbiExample,
)]
#[repr(transparent)]
pub struct Hash(pub [u8; HASH_BYTES]);
Expand Down
Loading

0 comments on commit 0f6f608

Please sign in to comment.