Skip to content

Commit da70d1c

Browse files
committed
stash
1 parent 95d9a67 commit da70d1c

File tree

6 files changed

+127
-127
lines changed

6 files changed

+127
-127
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

program-tests/sdk-token-test/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ light-hasher = { workspace = true }
2525
light-sdk = { workspace = true }
2626
light-sdk-types = { workspace = true }
2727
light-compressed-account = { workspace = true }
28+
arrayvec = { workspace = true }
2829

2930
[dev-dependencies]
3031
light-program-test = { workspace = true, features = ["devenv"] }

program-tests/sdk-token-test/src/process_create_compressed_account.rs

Lines changed: 11 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ use anchor_lang::solana_program::log::sol_log_compute_units;
33
use light_compressed_account::instruction_data::cpi_context::CompressedCpiContext;
44
use light_compressed_token_sdk::{
55
account::CTokenAccount,
6-
instructions::transfer::instruction::{TransferConfig, TransferInputs},
6+
instructions::transfer::{
7+
account_infos::{filter_packed_accounts, TransferAccountInfos, MAX_ACCOUNT_INFOS},
8+
instruction::{TransferConfig, TransferInputs},
9+
},
710
TokenAccountMeta,
811
};
912
use light_sdk::{
@@ -90,9 +93,9 @@ pub fn deposit_tokens<'info>(
9093

9194
// We need to be careful what accounts we pass.
9295
// Big accounts cost many CU.
93-
// TODO: add a filter tree accounts function.
96+
// TODO: replace
9497
let tree_account_infos =
95-
filter_tree_accounts(&[&sender_account], cpi_accounts.tree_accounts().unwrap());
98+
filter_packed_accounts(&[&sender_account], cpi_accounts.tree_accounts().unwrap());
9699
let tree_pubkeys = tree_account_infos
97100
.iter()
98101
.map(|x| x.pubkey())
@@ -129,20 +132,17 @@ pub fn deposit_tokens<'info>(
129132

130133
msg!("create_account_infos");
131134
sol_log_compute_units();
132-
let account_infos = TransferAccountInfos {
135+
// TODO: initialize from CpiAccounts, use with_compressed_pda() offchain.
136+
let account_infos: TransferAccountInfos<'_, 'info, MAX_ACCOUNT_INFOS> = TransferAccountInfos {
133137
fee_payer: cpi_accounts.fee_payer(),
134138
authority: cpi_accounts.fee_payer(),
135-
tree_accounts: tree_account_infos.as_slice(),
139+
packed_accounts: tree_account_infos.as_slice(),
136140
ctoken_accounts: token_account_infos,
137141
cpi_context: Some(cpi_context),
138142
};
139143
let account_infos = account_infos.into_account_infos();
140-
// 1390968
141-
// let account_infos = create_account_infos(
142-
// &instruction,
143-
// token_account_infos,
144-
// &[cpi_accounts.fee_payer()],
145-
// );
144+
// into_account_infos_checked() can be used for debugging but doubles CU cost to 1.5k CU
145+
146146
sol_log_compute_units();
147147

148148
sol_log_compute_units();
@@ -153,119 +153,3 @@ pub fn deposit_tokens<'info>(
153153

154154
Ok(())
155155
}
156-
157-
// 7479
158-
fn create_account_infos<'info>(
159-
instruction: &Instruction,
160-
account_infos: &[AccountInfo<'info>],
161-
additionals: &[&AccountInfo<'info>],
162-
) -> Vec<AccountInfo<'info>> {
163-
let mut res_account_infos = Vec::with_capacity(instruction.accounts.len());
164-
165-
for (i, account_meta) in instruction.accounts.iter().enumerate() {
166-
if let Some(account_info) = account_infos[i..]
167-
.iter()
168-
.find(|x| *x.key == account_meta.pubkey)
169-
{
170-
res_account_infos.push(account_info.clone());
171-
} else {
172-
if let Some(account_info) = additionals.iter().find(|x| *x.key == account_meta.pubkey) {
173-
res_account_infos.push((*account_info).clone());
174-
} else {
175-
if let Some(account_info) = account_infos[..i]
176-
.iter()
177-
.find(|x| *x.key == account_meta.pubkey)
178-
{
179-
res_account_infos.push(account_info.clone());
180-
} else {
181-
panic!("account not found");
182-
}
183-
}
184-
}
185-
}
186-
res_account_infos
187-
}
188-
189-
// For pinocchio we will need to build the accounts in oder
190-
// The easiest is probably just pass the accounts multiple times since deserialization is zero copy.
191-
pub struct TransferAccountInfos<'a, 'info> {
192-
fee_payer: &'a AccountInfo<'info>,
193-
authority: &'a AccountInfo<'info>,
194-
ctoken_accounts: &'a [AccountInfo<'info>],
195-
cpi_context: Option<&'a AccountInfo<'info>>,
196-
// TODO: rename tree accounts to packed accounts
197-
tree_accounts: &'a [AccountInfo<'info>],
198-
}
199-
200-
use anchor_lang::solana_program::instruction::Instruction;
201-
impl<'info> TransferAccountInfos<'_, 'info> {
202-
// 874
203-
fn into_account_infos(self) -> Vec<AccountInfo<'info>> {
204-
// TODO: experiment with array vec.
205-
// we can use array vec with default constant say 20 and in case it's not enough
206-
// we throw an error that the constant needs to be increased.
207-
let mut capacity = 2 + self.ctoken_accounts.len() + self.tree_accounts.len();
208-
let ctoken_program_id_index = self.ctoken_accounts.len() - 2;
209-
if self.cpi_context.is_some() {
210-
capacity += 1;
211-
}
212-
let mut account_infos = Vec::with_capacity(capacity);
213-
account_infos.push(self.fee_payer.clone());
214-
account_infos.push(self.authority.clone());
215-
216-
account_infos.extend_from_slice(self.ctoken_accounts);
217-
if let Some(cpi_context) = self.cpi_context {
218-
account_infos.push(cpi_context.clone());
219-
} else {
220-
account_infos.push(self.ctoken_accounts[ctoken_program_id_index].clone());
221-
}
222-
account_infos.extend_from_slice(self.tree_accounts);
223-
account_infos
224-
}
225-
226-
// 1528
227-
fn into_account_infos_checked(self, ix: &Instruction) -> Result<Vec<AccountInfo<'info>>> {
228-
let account_infos = self.into_account_infos();
229-
for (account_meta, account_info) in ix.accounts.iter().zip(account_infos.iter()) {
230-
if account_meta.pubkey != *account_info.key {
231-
msg!("account meta {:?}", account_meta);
232-
msg!("account info {:?}", account_info);
233-
234-
msg!("account metas {:?}", ix.accounts);
235-
msg!("account infos {:?}", account_infos);
236-
panic!("account info and meta don't match.");
237-
}
238-
}
239-
Ok(account_infos)
240-
}
241-
}
242-
243-
// TODO: test
244-
fn filter_tree_accounts<'info>(
245-
token_accounts: &[&CTokenAccount],
246-
account_infos: &[AccountInfo<'info>],
247-
) -> Vec<AccountInfo<'info>> {
248-
let mut selected_account_infos = Vec::with_capacity(account_infos.len());
249-
account_infos
250-
.iter()
251-
.enumerate()
252-
.filter(|(i, _)| {
253-
let i = *i as u8;
254-
token_accounts.iter().any(|y| {
255-
y.merkle_tree_index == i
256-
|| y.input_metas().iter().any(|z| {
257-
z.packed_tree_info.merkle_tree_pubkey_index == i
258-
|| z.packed_tree_info.queue_pubkey_index == i
259-
|| {
260-
if let Some(delegate_index) = z.delegate_index {
261-
delegate_index == i
262-
} else {
263-
false
264-
}
265-
}
266-
})
267-
})
268-
})
269-
.for_each(|x| selected_account_infos.push(x.1.clone()));
270-
selected_account_infos
271-
}

sdk-libs/compressed-token-sdk/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ solana-instruction = { workspace = true }
2323
solana-account-info = { workspace = true }
2424
solana-cpi = { workspace = true }
2525
solana-program-error = { workspace = true }
26+
arrayvec = { workspace = true }
2627

2728
# Optional Anchor dependency
2829
anchor-lang = { workspace = true, optional = true }
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
use crate::{account::CTokenAccount, error::Result};
2+
use arrayvec::ArrayVec;
3+
use solana_account_info::AccountInfo;
4+
use solana_instruction::Instruction;
5+
use solana_msg::msg;
6+
7+
pub const MAX_ACCOUNT_INFOS: usize = 20;
8+
9+
// TODO: test with delegate
10+
// For pinocchio we will need to build the accounts in oder
11+
// The easiest is probably just pass the accounts multiple times since deserialization is zero copy.
12+
pub struct TransferAccountInfos<'a, 'info, const N: usize = MAX_ACCOUNT_INFOS> {
13+
pub fee_payer: &'a AccountInfo<'info>,
14+
pub authority: &'a AccountInfo<'info>,
15+
pub ctoken_accounts: &'a [AccountInfo<'info>],
16+
pub cpi_context: Option<&'a AccountInfo<'info>>,
17+
// TODO: rename tree accounts to packed accounts
18+
pub packed_accounts: &'a [AccountInfo<'info>],
19+
}
20+
21+
impl<'info, const N: usize> TransferAccountInfos<'_, 'info, N> {
22+
// 874 with std::vec
23+
// 722 with array vec
24+
pub fn into_account_infos(self) -> ArrayVec<AccountInfo<'info>, N> {
25+
let mut capacity = 2 + self.ctoken_accounts.len() + self.packed_accounts.len();
26+
let ctoken_program_id_index = self.ctoken_accounts.len() - 2;
27+
if self.cpi_context.is_some() {
28+
capacity += 1;
29+
}
30+
31+
// Check if capacity exceeds ArrayVec limit
32+
if capacity > N {
33+
panic!("Account infos capacity {} exceeds limit {}", capacity, N);
34+
}
35+
36+
let mut account_infos = ArrayVec::<AccountInfo<'info>, N>::new();
37+
account_infos.push(self.fee_payer.clone());
38+
account_infos.push(self.authority.clone());
39+
40+
// Add ctoken accounts
41+
for account in self.ctoken_accounts {
42+
account_infos.push(account.clone());
43+
}
44+
45+
if let Some(cpi_context) = self.cpi_context {
46+
account_infos.push(cpi_context.clone());
47+
} else {
48+
account_infos.push(self.ctoken_accounts[ctoken_program_id_index].clone());
49+
}
50+
51+
// Add tree accounts
52+
for account in self.packed_accounts {
53+
account_infos.push(account.clone());
54+
}
55+
56+
account_infos
57+
}
58+
59+
// 1528
60+
pub fn into_account_infos_checked(
61+
self,
62+
ix: &Instruction,
63+
) -> Result<ArrayVec<AccountInfo<'info>, N>> {
64+
let account_infos = self.into_account_infos();
65+
for (account_meta, account_info) in ix.accounts.iter().zip(account_infos.iter()) {
66+
if account_meta.pubkey != *account_info.key {
67+
msg!("account meta {:?}", account_meta);
68+
msg!("account info {:?}", account_info);
69+
70+
msg!("account metas {:?}", ix.accounts);
71+
msg!("account infos {:?}", account_infos);
72+
panic!("account info and meta don't match.");
73+
}
74+
}
75+
Ok(account_infos)
76+
}
77+
}
78+
79+
// Note: maybe it is not useful for removing accounts results in loss of order
80+
// other than doing [..end] so let's just do that in the first place.
81+
// TODO: test
82+
/// Filter packed accounts for accounts necessary for token accounts.
83+
/// Note accounts still need to be in the correct order.
84+
pub fn filter_packed_accounts<'info>(
85+
token_accounts: &[&CTokenAccount],
86+
account_infos: &[AccountInfo<'info>],
87+
) -> Vec<AccountInfo<'info>> {
88+
let mut selected_account_infos = Vec::with_capacity(account_infos.len());
89+
account_infos
90+
.iter()
91+
.enumerate()
92+
.filter(|(i, _)| {
93+
let i = *i as u8;
94+
token_accounts.iter().any(|y| {
95+
y.merkle_tree_index == i
96+
|| y.input_metas().iter().any(|z| {
97+
z.packed_tree_info.merkle_tree_pubkey_index == i
98+
|| z.packed_tree_info.queue_pubkey_index == i
99+
|| {
100+
if let Some(delegate_index) = z.delegate_index {
101+
delegate_index == i
102+
} else {
103+
false
104+
}
105+
}
106+
})
107+
})
108+
})
109+
.for_each(|x| selected_account_infos.push(x.1.clone()));
110+
selected_account_infos
111+
}

sdk-libs/compressed-token-sdk/src/instructions/transfer/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use light_compressed_token_types::account_infos::TransferAccountInfos as TransferAccountInfosTypes;
22
use solana_account_info::AccountInfo;
33

4+
pub mod account_infos;
45
pub mod account_metas;
56
pub mod instruction;
67

0 commit comments

Comments
 (0)