1use super::{
2 zkapp_command::GenZkappCommandParams, Failure, Role, LEDGER_DEPTH, MAX_ACCOUNT_UPDATES,
3 MAX_TOKEN_UPDATES, MINIMUM_USER_COMMAND_FEE,
4};
5use crate::{
6 gen_keypair,
7 scan_state::{
8 currency::{Balance, Magnitude},
9 transaction_logic::{
10 for_tests::HashableCompressedPubKey,
11 valid,
12 zkapp_command::{self, verifiable},
13 TransactionStatus::Applied,
14 },
15 },
16 util, Account, AccountId, AuthRequired, BaseLedger, Mask, MyCowMut, Permissions, TokenId,
17 VerificationKey, VerificationKeyWire, ZkAppAccount, TXN_VERSION_CURRENT,
18};
19use mina_signer::Keypair;
20use rand::Rng;
21use std::{collections::HashMap, rc::Rc};
22
23fn zkapp_command_with_ledger(
24 num_keypairs: Option<usize>,
25 max_account_updates: Option<usize>,
26 max_token_updates: Option<usize>,
27 account_state_tbl: Option<&mut HashMap<AccountId, (Account, Role)>>,
28 vk: Option<VerificationKeyWire>,
29 failure: Option<&Failure>,
30) -> (
31 valid::UserCommand,
32 Keypair,
33 HashMap<HashableCompressedPubKey, Keypair>,
34 Mask,
35) {
36 let mut rng = rand::thread_rng();
37
38 let max_account_updates = max_account_updates.unwrap_or(MAX_ACCOUNT_UPDATES);
45 let max_token_updates = max_token_updates.unwrap_or(MAX_TOKEN_UPDATES);
46 let num_keypairs =
47 num_keypairs.unwrap_or((max_account_updates * 2) + (max_token_updates * 3) + 2);
48
49 let keypairs: Vec<Keypair> = (0..num_keypairs).map(|_| gen_keypair()).collect();
50
51 let keymap: HashMap<HashableCompressedPubKey, Keypair> = keypairs
52 .iter()
53 .map(|kp| {
54 let compressed = kp.public.into_compressed();
55 (HashableCompressedPubKey(compressed), kp.clone())
56 })
57 .collect();
58
59 let num_keypairs_in_ledger = num_keypairs / 2;
60 let keypairs_in_ledger = util::take(&keypairs, num_keypairs_in_ledger);
61
62 let account_ids: Vec<AccountId> = keypairs_in_ledger
63 .iter()
64 .map(|Keypair { public, .. }| {
65 AccountId::create(public.into_compressed(), TokenId::default())
66 })
67 .collect();
68
69 let verification_key = vk.clone().unwrap_or_else(|| {
70 let dummy_vk = VerificationKey::dummy();
71 VerificationKeyWire::new((*dummy_vk).clone())
72 });
73
74 let balances: Vec<Balance> = {
75 let min_cmd_fee = MINIMUM_USER_COMMAND_FEE;
76
77 let min_balance = {
78 let balance = min_cmd_fee.as_u64() + 100_000_000_000_000_000;
79 Balance::from_u64(balance)
80 };
81
82 let max_balance = {
84 let max_bal = Balance::of_mina_string_exn("2000000000.0");
85
86 assert_eq!(max_bal.as_u64(), 2000000000000000000);
87
88 min_balance
89 .checked_add(&max_bal)
90 .expect("zkapp_command_with_ledger: overflow for max_balance")
91 };
92
93 (0..num_keypairs_in_ledger)
94 .map(move |_| {
95 let balance = rng.gen_range(min_balance.as_u64()..max_balance.as_u64());
96 Balance::from_u64(balance)
97 })
98 .collect()
99 };
100
101 let account_ids_and_balances: Vec<(AccountId, Balance)> =
102 account_ids.iter().cloned().zip(balances).collect();
103
104 let snappify_account = |mut account: Account| {
105 let permissions = Permissions {
106 edit_state: AuthRequired::Either,
107 send: AuthRequired::Either,
108 set_delegate: AuthRequired::Either,
109 set_permissions: AuthRequired::Either,
110 set_verification_key: crate::SetVerificationKey {
111 auth: AuthRequired::Either,
112 txn_version: TXN_VERSION_CURRENT,
113 },
114 set_zkapp_uri: AuthRequired::Either,
115 edit_action_state: AuthRequired::Either,
116 set_token_symbol: AuthRequired::Either,
117 increment_nonce: AuthRequired::Either,
118 set_voting_for: AuthRequired::Either,
119 set_timing: AuthRequired::Either,
120 ..Permissions::user_default()
122 };
123
124 let verification_key = Some(verification_key.clone());
125 let zkapp = Some(
126 ZkAppAccount {
127 verification_key,
128 ..ZkAppAccount::default()
129 }
130 .into(),
131 );
132
133 account.zkapp = zkapp;
134 account.permissions = permissions;
135
136 account
137 };
138
139 let accounts =
141 account_ids_and_balances
142 .iter()
143 .enumerate()
144 .map(|(ndx, (account_id, balance))| {
145 let account = Account::create_with(account_id.clone(), *balance);
146 if ndx % 2 == 0 {
147 account
148 } else {
149 snappify_account(account)
150 }
151 });
152
153 let fee_payer_keypair = keypairs.first().unwrap();
154
155 let mut ledger = Mask::create(LEDGER_DEPTH);
156
157 account_ids.iter().zip(accounts).for_each(|(id, account)| {
158 let res = ledger
159 .get_or_create_account(id.clone(), account)
160 .expect("zkapp_command: error adding account for account id");
161 assert!(
162 matches!(res, crate::GetOrCreated::Added(_)),
163 "zkapp_command: account for account id already exists"
164 );
165 });
166
167 let mut account_state_tbl = match account_state_tbl {
169 Some(account_state_tbl) => MyCowMut::Borrow(account_state_tbl),
170 None => MyCowMut::Own(HashMap::new()),
171 };
172 let account_state_tbl = Some(&mut *account_state_tbl);
173
174 let zkapp_command =
175 super::zkapp_command::gen_zkapp_command_from(super::zkapp_command::GenZkappCommandParams {
176 failure,
177 max_account_updates: Some(max_account_updates),
178 max_token_updates: Some(max_token_updates),
179 fee_payer_keypair,
180 keymap: &keymap,
181 account_state_tbl,
182 ledger: ledger.clone(),
183 protocol_state_view: None,
184 vk: vk.as_ref(),
185 global_slot: None,
186 });
187
188 let zkapp_command =
189 zkapp_command::valid::to_valid(zkapp_command, &Applied, |hash, account_id| {
190 verifiable::find_vk_via_ledger(ledger.clone(), hash, account_id)
191 })
192 .unwrap();
193 let user_command = valid::UserCommand::ZkAppCommand(Box::new(zkapp_command));
194
195 (user_command, fee_payer_keypair.clone(), keymap, ledger)
197}
198
199pub fn sequence_zkapp_command_with_ledger(
201 max_account_updates: Option<usize>,
202 max_token_updates: Option<usize>,
203 length: Option<usize>,
204 vk: Option<VerificationKeyWire>,
205 failure: Option<&Failure>,
206) -> (
207 Vec<(
208 valid::UserCommand,
209 Rc<Keypair>,
210 Rc<HashMap<HashableCompressedPubKey, Keypair>>,
211 )>,
212 Mask,
213) {
214 let mut rng = rand::thread_rng();
215
216 let length = length.unwrap_or_else(|| rng.gen::<usize>() % 100);
217 let max_account_updates = max_account_updates.unwrap_or(MAX_ACCOUNT_UPDATES);
218 let max_token_updates = max_token_updates.unwrap_or(MAX_TOKEN_UPDATES);
219
220 let num_keypairs = length * max_account_updates * 2;
221
222 let mut account_state_tbl = HashMap::<AccountId, (Account, Role)>::with_capacity(64);
224
225 let num_keypairs = Some(num_keypairs);
226 let max_account_updates = Some(max_account_updates);
227 let max_token_updates = Some(max_token_updates);
228 let (zkapp_command, fee_payer_keypair, keymap, ledger) = zkapp_command_with_ledger(
231 num_keypairs,
232 max_account_updates,
233 max_token_updates,
234 Some(&mut account_state_tbl),
235 vk.clone(),
236 failure,
237 );
238
239 let fee_payer_keypair = Rc::new(fee_payer_keypair);
240 let keymap = Rc::new(keymap);
241
242 let mut commands = Vec::with_capacity(length);
243
244 commands.push((
245 zkapp_command,
246 Rc::clone(&fee_payer_keypair),
247 Rc::clone(&keymap),
248 ));
249
250 (0..length.saturating_sub(1)).for_each(|_| {
251 let zkapp_command = super::zkapp_command::gen_zkapp_command_from(GenZkappCommandParams {
252 failure,
253 max_account_updates,
254 max_token_updates,
255 fee_payer_keypair: &fee_payer_keypair,
256 keymap: &keymap,
257 account_state_tbl: Some(&mut account_state_tbl),
258 ledger: ledger.clone(),
259 protocol_state_view: None,
260 vk: vk.as_ref(),
261 global_slot: None,
262 });
263
264 let zkapp_command =
265 zkapp_command::valid::to_valid(zkapp_command, &Applied, |hash, account_id| {
266 verifiable::find_vk_via_ledger(ledger.clone(), hash, account_id)
267 })
268 .unwrap();
269 let zkapp_command = valid::UserCommand::ZkAppCommand(Box::new(zkapp_command));
270
271 commands.push((
272 zkapp_command,
273 Rc::clone(&fee_payer_keypair),
274 Rc::clone(&keymap),
275 ));
276 });
277
278 (commands, ledger)
279}