Skip to content

Commit d9c7c0c

Browse files
committed
program: use counter to access accounts list
1 parent 0088838 commit d9c7c0c

File tree

2 files changed

+80
-18
lines changed

2 files changed

+80
-18
lines changed

program/src/processor.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@
33
use {
44
crate::state::ConfigKeys,
55
solana_program::{
6-
account_info::{next_account_info, AccountInfo},
7-
entrypoint::ProgramResult,
8-
msg,
9-
program_error::ProgramError,
6+
account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError,
107
pubkey::Pubkey,
118
},
129
std::collections::BTreeSet,
@@ -56,8 +53,7 @@ fn safe_deserialize_config_keys(input: &[u8]) -> Result<ConfigKeys, ProgramError
5653
pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> ProgramResult {
5754
let key_list = safe_deserialize_config_keys(input)?;
5855

59-
let mut accounts_iter = accounts.iter();
60-
let config_account = next_account_info(&mut accounts_iter)?;
56+
let config_account = accounts.first().ok_or(ProgramError::NotEnoughAccountKeys)?;
6157

6258
if config_account.owner != program_id {
6359
msg!("Config account is not owned by the config program");
@@ -89,7 +85,7 @@ pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> P
8985
for (signer, _) in key_list.keys.iter().filter(|(_, is_signer)| *is_signer) {
9086
counter = counter.saturating_add(1);
9187
if signer != config_account.key {
92-
let signer_account = next_account_info(&mut accounts_iter).map_err(|_| {
88+
let signer_account = accounts.get(counter).ok_or_else(|| {
9389
msg!("account {:?} is not in account list", signer);
9490
ProgramError::MissingRequiredSignature
9591
})?;

program/tests/functional.rs

Lines changed: 77 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ fn test_process_create_ok() {
8383
&[(config, config_account)],
8484
&[
8585
Check::success(),
86-
Check::compute_units(584),
86+
Check::compute_units(580),
8787
Check::account(&config)
8888
.data(
8989
&bincode::serialize(&(ConfigKeys { keys: vec![] }, MyConfig::default()))
@@ -111,7 +111,7 @@ fn test_process_store_ok() {
111111
&[(config, config_account)],
112112
&[
113113
Check::success(),
114-
Check::compute_units(584),
114+
Check::compute_units(580),
115115
Check::account(&config)
116116
.data(&bincode::serialize(&(ConfigKeys { keys }, my_config)).unwrap())
117117
.build(),
@@ -186,7 +186,7 @@ fn test_process_store_with_additional_signers() {
186186
],
187187
&[
188188
Check::success(),
189-
Check::compute_units(3_253),
189+
Check::compute_units(3_234),
190190
Check::account(&config)
191191
.data(&bincode::serialize(&(ConfigKeys { keys }, my_config)).unwrap())
192192
.build(),
@@ -262,6 +262,55 @@ fn test_process_store_with_bad_additional_signer() {
262262
);
263263
}
264264

265+
#[test]
266+
fn test_store_requiring_config() {
267+
let mollusk = setup();
268+
269+
let config = Pubkey::new_unique();
270+
271+
// New keys contains the config account, as well as another signer.
272+
let signer = Pubkey::new_unique();
273+
let new_keys = vec![(config, true), (signer, true)];
274+
let my_config = MyConfig::new(42);
275+
276+
let config_account = {
277+
// Allocate enough space for they `new_keys`, but leave the account
278+
// uninitalized.
279+
let space = get_config_space(new_keys.len());
280+
let lamports = mollusk.sysvars.rent.minimum_balance(space);
281+
AccountSharedData::new(lamports, space, &solana_config_program::id())
282+
};
283+
284+
let mut instruction = config_instruction::store(&config, true, new_keys, &my_config);
285+
mollusk.process_and_validate_instruction(
286+
&instruction,
287+
&[
288+
(config, config_account.clone()),
289+
(signer, AccountSharedData::default()),
290+
],
291+
&[Check::err(ProgramError::MissingRequiredSignature)],
292+
);
293+
294+
// This is kind of strange, since the `store` helper was taken directly
295+
// from the builtin crate, and it's designed to only add the config account
296+
// once, even if it's a signer.
297+
// However, if you include it in the instruction twice, the loop-counter
298+
// mechanism of the processor actually works...
299+
instruction.accounts = vec![
300+
AccountMeta::new(config, true),
301+
AccountMeta::new(config, true),
302+
AccountMeta::new(signer, true),
303+
];
304+
mollusk.process_and_validate_instruction(
305+
&instruction,
306+
&[
307+
(config, config_account),
308+
(signer, AccountSharedData::default()),
309+
],
310+
&[Check::success()],
311+
);
312+
}
313+
265314
#[test]
266315
fn test_config_updates() {
267316
let mollusk = setup();
@@ -285,7 +334,7 @@ fn test_config_updates() {
285334
(signer0, AccountSharedData::default()),
286335
(signer1, AccountSharedData::default()),
287336
],
288-
&[Check::success(), Check::compute_units(3_253)],
337+
&[Check::success(), Check::compute_units(3_234)],
289338
);
290339

291340
// Use this for next invoke.
@@ -303,7 +352,7 @@ fn test_config_updates() {
303352
],
304353
&[
305354
Check::success(),
306-
Check::compute_units(3_254),
355+
Check::compute_units(3_235),
307356
Check::account(&config)
308357
.data(&bincode::serialize(&(ConfigKeys { keys }, new_config)).unwrap())
309358
.build(),
@@ -314,6 +363,22 @@ fn test_config_updates() {
314363
let updated_config_account = result.get_account(&config).unwrap();
315364

316365
// Attempt update with incomplete signatures.
366+
let keys = vec![
367+
(pubkey, false),
368+
(signer1, true), // Missing signer0.
369+
];
370+
let instruction = config_instruction::store(&config, false, keys, &my_config);
371+
mollusk.process_and_validate_instruction(
372+
&instruction,
373+
&[
374+
(config, updated_config_account.clone()),
375+
// Missing signer0.
376+
(signer1, AccountSharedData::default()),
377+
],
378+
&[Check::err(ProgramError::MissingRequiredSignature)],
379+
);
380+
381+
// Do it again, this time missing signer1.
317382
let keys = vec![
318383
(pubkey, false),
319384
(signer0, true), // Missing signer1.
@@ -323,7 +388,8 @@ fn test_config_updates() {
323388
&instruction,
324389
&[
325390
(config, updated_config_account.clone()),
326-
(signer0, AccountSharedData::default()), // Missing signer1.
391+
(signer0, AccountSharedData::default()),
392+
// Missing signer1.
327393
],
328394
&[Check::err(ProgramError::MissingRequiredSignature)],
329395
);
@@ -399,7 +465,7 @@ fn test_config_update_contains_duplicates_fails() {
399465
(signer0, AccountSharedData::default()),
400466
(signer1, AccountSharedData::default()),
401467
],
402-
&[Check::success(), Check::compute_units(3_253)],
468+
&[Check::success(), Check::compute_units(3_234)],
403469
);
404470

405471
// Attempt update with duplicate signer inputs.
@@ -443,7 +509,7 @@ fn test_config_updates_requiring_config() {
443509
],
444510
&[
445511
Check::success(),
446-
Check::compute_units(3_352),
512+
Check::compute_units(3_330),
447513
Check::account(&config)
448514
.data(&bincode::serialize(&(ConfigKeys { keys: keys.clone() }, my_config)).unwrap())
449515
.build(),
@@ -464,7 +530,7 @@ fn test_config_updates_requiring_config() {
464530
],
465531
&[
466532
Check::success(),
467-
Check::compute_units(3_352),
533+
Check::compute_units(3_330),
468534
Check::account(&config)
469535
.data(&bincode::serialize(&(ConfigKeys { keys }, new_config)).unwrap())
470536
.build(),
@@ -558,7 +624,7 @@ fn test_maximum_keys_input() {
558624
let result = mollusk.process_and_validate_instruction(
559625
&instruction,
560626
&[(config, config_account)],
561-
&[Check::success(), Check::compute_units(25_247)],
627+
&[Check::success(), Check::compute_units(25_243)],
562628
);
563629

564630
// Use this for next invoke.
@@ -571,7 +637,7 @@ fn test_maximum_keys_input() {
571637
let result = mollusk.process_and_validate_instruction(
572638
&instruction,
573639
&[(config, updated_config_account)],
574-
&[Check::success(), Check::compute_units(25_247)],
640+
&[Check::success(), Check::compute_units(25_243)],
575641
);
576642

577643
// Use this for next invoke.

0 commit comments

Comments
 (0)