Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit 8e7b688

Browse files
committed
add support for record program in the client
1 parent 95194c3 commit 8e7b688

File tree

4 files changed

+400
-43
lines changed

4 files changed

+400
-43
lines changed

token/client/Cargo.toml

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,17 @@ version = "0.11.0"
99

1010
[dependencies]
1111
async-trait = "0.1"
12+
bincode = "1.3.2"
13+
bytemuck = "1.16.1"
1214
curve25519-dalek = "3.2.1"
1315
futures = "0.3.30"
1416
futures-util = "0.3"
15-
solana-banks-interface = "2.0.0"
16-
solana-cli-output = { version = "2.0.0", optional = true }
17-
solana-program-test = "2.0.0"
18-
solana-rpc-client = "2.0.0"
19-
solana-rpc-client-api = "2.0.0"
20-
solana-sdk = "2.0.0"
17+
solana-banks-interface = "2.1.0"
18+
solana-cli-output = { version = "2.1.0", optional = true }
19+
solana-program-test = "2.1.0"
20+
solana-rpc-client = "2.1.0"
21+
solana-rpc-client-api = "2.1.0"
22+
solana-sdk = "2.1.0"
2123
# We never want the entrypoint for ATA, but we want the entrypoint for token when
2224
# testing token
2325
spl-associated-token-account = { version = "4.0.0", path = "../../associated-token-account/program", features = [
@@ -26,6 +28,7 @@ spl-associated-token-account = { version = "4.0.0", path = "../../associated-tok
2628
spl-memo = { version = "5.0", path = "../../memo/program", features = [
2729
"no-entrypoint",
2830
] }
31+
spl-record = { version = "0.2.0", path = "../../record/program", features = ["no-entrypoint"] }
2932
spl-token = { version = "6.0", path = "../program", features = [
3033
"no-entrypoint",
3134
] }

token/client/src/proof_generation.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
77
use {
88
curve25519_dalek::scalar::Scalar,
9+
solana_sdk::pubkey::Pubkey,
910
spl_token_2022::{
1011
error::TokenError,
1112
extension::confidential_transfer::{
@@ -32,6 +33,11 @@ use {
3233
},
3334
};
3435

36+
pub enum ProofAccount {
37+
ContextAccount(Pubkey),
38+
RecordAccount(Pubkey),
39+
}
40+
3541
/// The main logic to create the five split proof data for a transfer with fee.
3642
#[allow(clippy::too_many_arguments)]
3743
pub fn transfer_with_fee_split_proof_data(

token/client/src/temp_client.rs

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/// Basic trait for sending transactions to validators
2+
pub trait SendTransaction {
3+
type Output;
4+
}
5+
6+
/// Basic trait for simulating transactions in a validator
7+
pub trait SimulateTransaction {
8+
type SimulationOutput: SimulationResult;
9+
}
10+
11+
/// Trait for the output of a simulation
12+
pub trait SimulationResult {
13+
fn get_compute_units_consumed(&self) -> ProgramClientResult<u64>;
14+
}
15+
16+
/// Extend basic `SendTransaction` trait with function `send` where client is
17+
/// `&mut BankClient`. Required for `ProgramBanksClient`.
18+
pub trait SendTransactionBanksClient: SendTransaction {
19+
fn send<'a>(
20+
&self,
21+
client: &'a mut BanksClient,
22+
transaction: Transaction,
23+
) -> BoxFuture<'a, ProgramClientResult<Self::Output>>;
24+
}
25+
26+
/// Extends basic `SimulateTransaction` trait with function `simulation` where
27+
/// client is `&mut BanksClient`. Required for `ProgramBanksClient`.
28+
pub trait SimulateTransactionBanksClient: SimulateTransaction {
29+
fn simulate<'a>(
30+
&self,
31+
client: &'a mut BanksClient,
32+
transaction: Transaction,
33+
) -> BoxFuture<'a, ProgramClientResult<Self::SimulationOutput>>;
34+
}
35+
36+
/// Send transaction to validator using `BanksClient::process_transaction`.
37+
#[derive(Debug, Clone, Copy, Default)]
38+
pub struct ProgramBanksClientProcessTransaction;
39+
40+
impl SendTransaction for ProgramBanksClientProcessTransaction {
41+
type Output = ();
42+
}
43+
44+
impl SendTransactionBanksClient for ProgramBanksClientProcessTransaction {
45+
fn send<'a>(
46+
&self,
47+
client: &'a mut BanksClient,
48+
transaction: Transaction,
49+
) -> BoxFuture<'a, ProgramClientResult<Self::Output>> {
50+
Box::pin(async move {
51+
client
52+
.process_transaction(transaction)
53+
.await
54+
.map_err(Into::into)
55+
})
56+
}
57+
}
58+
59+
pub type ProgramClientError = Box<dyn std::error::Error + Send + Sync>;
60+
pub type ProgramClientResult<T> = Result<T, ProgramClientError>;
61+
62+
/// Generic client interface for programs.
63+
#[async_trait]
64+
pub trait ProgramClient<ST>
65+
where
66+
ST: SendTransaction + SimulateTransaction,
67+
{
68+
async fn get_minimum_balance_for_rent_exemption(
69+
&self,
70+
data_len: usize,
71+
) -> ProgramClientResult<u64>;
72+
73+
async fn get_latest_blockhash(&self) -> ProgramClientResult<Hash>;
74+
75+
async fn send_transaction(&self, transaction: &Transaction) -> ProgramClientResult<ST::Output>;
76+
77+
async fn get_account(&self, address: Pubkey) -> ProgramClientResult<Option<Account>>;
78+
79+
async fn simulate_transaction(
80+
&self,
81+
transaction: &Transaction,
82+
) -> ProgramClientResult<ST::SimulationOutput>;
83+
}
84+
85+
enum ProgramBanksClientContext {
86+
Client(Arc<Mutex<BanksClient>>),
87+
Context(Arc<Mutex<ProgramTestContext>>),
88+
}
89+
90+
/// Program client for `BanksClient` from crate `solana-program-test`.
91+
pub struct ProgramBanksClient<ST> {
92+
context: ProgramBanksClientContext,
93+
send: ST,
94+
}
95+
96+
impl<ST> fmt::Debug for ProgramBanksClient<ST> {
97+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98+
f.debug_struct("ProgramBanksClient").finish()
99+
}
100+
}
101+
102+
impl<ST> ProgramBanksClient<ST> {
103+
fn new(context: ProgramBanksClientContext, send: ST) -> Self {
104+
Self { context, send }
105+
}
106+
107+
pub fn new_from_client(client: Arc<Mutex<BanksClient>>, send: ST) -> Self {
108+
Self::new(ProgramBanksClientContext::Client(client), send)
109+
}
110+
111+
pub fn new_from_context(context: Arc<Mutex<ProgramTestContext>>, send: ST) -> Self {
112+
Self::new(ProgramBanksClientContext::Context(context), send)
113+
}
114+
115+
async fn run_in_lock<F, O>(&self, f: F) -> O
116+
where
117+
for<'a> F: Fn(&'a mut BanksClient) -> BoxFuture<'a, O>,
118+
{
119+
match &self.context {
120+
ProgramBanksClientContext::Client(client) => {
121+
let mut lock = client.lock().await;
122+
f(&mut lock).await
123+
}
124+
ProgramBanksClientContext::Context(context) => {
125+
let mut lock = context.lock().await;
126+
f(&mut lock.banks_client).await
127+
}
128+
}
129+
}
130+
}

0 commit comments

Comments
 (0)