This commit is contained in:
Armani Ferrante 2022-02-09 16:08:39 -05:00
parent b0a364523a
commit 3b680a6cf9
No known key found for this signature in database
GPG Key ID: D597A80BCF8E12B7
9 changed files with 64 additions and 72 deletions

View File

@ -1,6 +1,7 @@
//! `anchor_client` provides an RPC client to send transactions and fetch
//! deserialized accounts from Solana programs written in `anchor_lang`.
use anchor_lang::accounts::header;
use anchor_lang::solana_program::instruction::{AccountMeta, Instruction};
use anchor_lang::solana_program::program_error::ProgramError;
use anchor_lang::solana_program::pubkey::Pubkey;
@ -292,23 +293,11 @@ fn handle_program_log<T: anchor_lang::Event + anchor_lang::AnchorDeserialize>(
let mut slice: &[u8] = &borsh_bytes[..];
#[cfg(feature = "deprecated-layout")]
let disc: [u8; 8] = {
let mut disc = [0; 8];
disc.copy_from_slice(&borsh_bytes[..8]);
slice = &slice[8..];
disc
};
#[cfg(not(feature = "deprecated-layout"))]
let disc: [u8; 4] = {
let mut disc = [0; 4];
disc.copy_from_slice(&borsh_bytes[2..6]);
slice = &slice[8..];
disc
};
let disc = header::read_discriminator(slice);
slice = &slice[8..];
let mut event = None;
if disc == T::discriminator() {
if disc == &T::discriminator() {
let e: T = anchor_lang::AnchorDeserialize::deserialize(&mut slice)
.map_err(|e| ClientError::LogParseError(e.to_string()))?;
event = Some(e);

View File

@ -1,5 +1,6 @@
//! Account container that checks ownership on deserialization.
use crate::accounts::header;
use crate::error::ErrorCode;
use crate::*;
use solana_program::account_info::AccountInfo;
@ -334,10 +335,7 @@ impl<'info, T: AccountSerialize + AccountDeserialize + Owner + Clone> AccountsEx
if &T::owner() == program_id {
let info = self.to_account_info();
let mut data = info.try_borrow_mut_data()?;
// Chop off the header.
let dst: &mut [u8] = &mut data[8..];
let dst = header::read_data_mut(&mut data);
let mut cursor = std::io::Cursor::new(dst);
self.account.try_serialize(&mut cursor)?;
}

View File

@ -1,8 +1,8 @@
//! Type facilitating on demand zero copy deserialization.
use crate::accounts::header;
use crate::error::ErrorCode;
use crate::*;
use arrayref::array_ref;
use solana_program::account_info::AccountInfo;
use solana_program::entrypoint::ProgramResult;
use solana_program::instruction::AccountMeta;
@ -120,12 +120,7 @@ impl<'info, T: ZeroCopy + Owner> AccountLoader<'info, T> {
return Err(ErrorCode::AccountOwnedByWrongProgram.into());
}
let data: &[u8] = &acc_info.try_borrow_data()?;
// Discriminator must match.
#[cfg(feature = "deprecated-layout")]
let disc_bytes = array_ref![data, 0, 8];
#[cfg(not(feature = "deprecated-layout"))]
let disc_bytes = array_ref![data, 2, 4];
let disc_bytes = header::read_discriminator(data);
if disc_bytes != &T::discriminator() {
return Err(ErrorCode::AccountDiscriminatorMismatch.into());
}
@ -147,12 +142,7 @@ impl<'info, T: ZeroCopy + Owner> AccountLoader<'info, T> {
/// Returns a Ref to the account data structure for reading.
pub fn load(&self) -> Result<Ref<T>, ProgramError> {
let data = self.acc_info.try_borrow_data()?;
#[cfg(feature = "deprecated-layout")]
let disc_bytes = array_ref![data, 0, 8];
#[cfg(not(feature = "deprecated-layout"))]
let disc_bytes = array_ref![data, 2, 4];
let disc_bytes = header::read_discriminator(&data);
if disc_bytes != &T::discriminator() {
return Err(ErrorCode::AccountDiscriminatorMismatch.into());
}
@ -170,12 +160,7 @@ impl<'info, T: ZeroCopy + Owner> AccountLoader<'info, T> {
}
let data = self.acc_info.try_borrow_mut_data()?;
#[cfg(feature = "deprecated-layout")]
let disc_bytes = array_ref![data, 0, 8];
#[cfg(not(feature = "deprecated-layout"))]
let disc_bytes = array_ref![data, 2, 4];
let disc_bytes = header::read_discriminator(&data);
if disc_bytes != &T::discriminator() {
return Err(ErrorCode::AccountDiscriminatorMismatch.into());
}

View File

@ -0,0 +1,40 @@
use arrayref::array_ref;
#[cfg(feature = "deprecated-layout")]
pub fn read_discriminator(data: &[u8]) -> &[u8; 8] {
array_ref![data, 0, 8]
}
#[cfg(not(feature = "deprecated-layout"))]
pub fn read_discriminator<'a>(data: &[u8]) -> &[u8; 4] {
array_ref![data, 2, 4]
}
#[cfg(feature = "deprecated-layout")]
pub fn create_discriminator(account_name: &str, namespace: Option<&str>) -> [u8; 8] {
let discriminator_preimage = format!("{}:{}", namespace.unwrap_or("account"), account_name);
let mut discriminator = [0u8; 8];
discriminator.copy_from_slice(
&crate::solana_program::hash::hash(discriminator_preimage.as_bytes()).to_bytes()[..8],
);
discriminator
}
#[cfg(not(feature = "deprecated-layout"))]
pub fn create_discriminator(account_name: &str, namespace: Option<&str>) -> [u8; 4] {
let discriminator_preimage = format!("{}:{}", namespace.unwrap_or("account"), account_name);
let mut discriminator = [0u8; 4];
discriminator.copy_from_slice(
&crate::solana_program::hash::hash(discriminator_preimage.as_bytes()).to_bytes()[..4],
);
discriminator
}
// Header is 8 bytes regardless of layout.
pub fn read_data(account_data: &[u8]) -> &[u8] {
&account_data[8..]
}
pub fn read_data_mut(account_data: &mut [u8]) -> &mut [u8] {
&mut account_data[8..]
}

View File

@ -1,3 +1,4 @@
use crate::accounts::header;
use crate::error::ErrorCode;
use crate::*;
use arrayref::array_ref;
@ -59,13 +60,7 @@ impl<'info, T: ZeroCopy> Loader<'info, T> {
return Err(ErrorCode::AccountOwnedByWrongProgram.into());
}
let data: &[u8] = &acc_info.try_borrow_data()?;
// Discriminator must match.
#[cfg(feature = "deprecated-layout")]
let disc_bytes = array_ref![data, 0, 8];
#[cfg(not(feature = "deprecated-layout"))]
let disc_bytes = array_ref![data, 2, 4];
let disc_bytes = header::read_discriminator(data);
if disc_bytes != &T::discriminator() {
return Err(ErrorCode::AccountDiscriminatorMismatch.into());
}
@ -90,12 +85,7 @@ impl<'info, T: ZeroCopy> Loader<'info, T> {
#[allow(deprecated)]
pub fn load(&self) -> Result<Ref<T>, ProgramError> {
let data = self.acc_info.try_borrow_data()?;
#[cfg(feature = "deprecated-layout")]
let disc_bytes = array_ref![data, 0, 8];
#[cfg(not(feature = "deprecated-layout"))]
let disc_bytes = array_ref![data, 2, 4];
let disc_bytes = header::read_discriminator(&data);
if disc_bytes != &T::discriminator() {
return Err(ErrorCode::AccountDiscriminatorMismatch.into());
}
@ -113,12 +103,7 @@ impl<'info, T: ZeroCopy> Loader<'info, T> {
}
let data = self.acc_info.try_borrow_mut_data()?;
#[cfg(feature = "deprecated-layout")]
let disc_bytes = array_ref![data, 0, 8];
#[cfg(not(feature = "deprecated-layout"))]
let disc_bytes = array_ref![data, 2, 4];
let disc_bytes = header::read_discriminator(&data);
if disc_bytes != &T::discriminator() {
return Err(ErrorCode::AccountDiscriminatorMismatch.into());
}

View File

@ -10,6 +10,7 @@ pub mod cpi_account;
#[doc(hidden)]
#[allow(deprecated)]
pub mod cpi_state;
pub mod header;
#[doc(hidden)]
#[allow(deprecated)]
pub mod loader;

View File

@ -1,5 +1,6 @@
#[allow(deprecated)]
use crate::accounts::cpi_account::CpiAccount;
use crate::accounts::header;
use crate::error::ErrorCode;
use crate::*;
use solana_program::account_info::AccountInfo;
@ -99,10 +100,7 @@ impl<'info, T: AccountSerialize + AccountDeserialize + Clone> AccountsExit<'info
fn exit(&self, _program_id: &Pubkey) -> ProgramResult {
let info = self.to_account_info();
let mut data = info.try_borrow_mut_data()?;
// Chop off the header.
let dst: &mut [u8] = &mut data[8..];
let dst = header::read_data_mut(&mut data);
let mut cursor = std::io::Cursor::new(dst);
self.inner.account.try_serialize(&mut cursor)?;
Ok(())

View File

@ -19,7 +19,7 @@ const ACCOUNT_HEADER_SIZE = 8;
* Number of bytes of the account discriminator.
*/
const ACCOUNT_DISCRIMINATOR_SIZE = 4;
const DEPRECATED_ACCOUNT_DISCRIMINATOR_SIZE = 4;
const DEPRECATED_ACCOUNT_DISCRIMINATOR_SIZE = 8;
/**
* Encodes and decodes account objects.

View File

@ -24,7 +24,7 @@ import InstructionNamespaceFactory from "./instruction.js";
import RpcNamespaceFactory from "./rpc.js";
import TransactionNamespaceFactory from "./transaction.js";
import { IdlTypes, TypeDef } from "./types.js";
import * as features from "../../utils/features.js";
import { BorshAccountHeader } from "../../coder/borsh/accounts.js";
export default class StateFactory {
public static build<IDL extends Idl>(
@ -175,15 +175,11 @@ export class StateClient<IDL extends Idl> {
}
const expectedDiscriminator = await stateDiscriminator(state.struct.name);
if (features.isSet("deprecated-layout")) {
if (expectedDiscriminator.compare(accountInfo.data.slice(0, 8))) {
throw new Error("Invalid state discriminator");
}
} else {
if (expectedDiscriminator.compare(accountInfo.data.slice(2, 6))) {
throw new Error("Invalid state discriminator");
}
const discriminator = BorshAccountHeader.parseDiscriminator(
accountInfo.data
);
if (discriminator.compare(expectedDiscriminator)) {
throw new Error("Invalid state discriminator");
}
return this.coder.state.decode(accountInfo.data);