Skip to content

Commit

Permalink
programs/config: Disallow duplicate signers
Browse files Browse the repository at this point in the history
  • Loading branch information
t-nelson authored and mergify[bot] committed Jun 10, 2021
1 parent 738df79 commit 98e34f0
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 0 deletions.
100 changes: 100 additions & 0 deletions programs/config/src/config_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use solana_sdk::{
program_utils::limited_deserialize,
pubkey::Pubkey,
};
use std::collections::BTreeSet;

pub fn process_instruction(
_program_id: &Pubkey,
Expand Down Expand Up @@ -101,6 +102,15 @@ pub fn process_instruction(
}
}

if invoke_context.is_feature_active(&feature_set::dedupe_config_program_signers::id()) {
let total_new_keys = key_list.keys.len();
let unique_new_keys = key_list.keys.into_iter().collect::<BTreeSet<_>>();
if unique_new_keys.len() != total_new_keys {
ic_msg!(invoke_context, "new config contains duplicate keys");
return Err(InstructionError::InvalidArgument);
}
}

// Check for Config data signers not present in incoming account update
if current_signer_keys.len() > counter {
ic_msg!(
Expand Down Expand Up @@ -493,6 +503,96 @@ mod tests {
);
}

#[test]
fn test_config_initialize_contains_duplicates_fails() {
solana_logger::setup();
let config_address = Pubkey::new_unique();
let signer0_pubkey = Pubkey::new_unique();
let signer0_account = RefCell::new(AccountSharedData::default());
let keys = vec![
(config_address, false),
(signer0_pubkey, true),
(signer0_pubkey, true),
];
let (config_keypair, config_account) = create_config_account(keys.clone());
let config_pubkey = config_keypair.pubkey();
let my_config = MyConfig::new(42);

// Attempt initialization with duplicate signer inputs
let instruction = config_instruction::store(&config_pubkey, true, keys, &my_config);
let accounts = vec![
(true, false, &config_pubkey, &config_account),
(true, false, &signer0_pubkey, &signer0_account),
(true, false, &signer0_pubkey, &signer0_account),
];
let keyed_accounts = create_keyed_accounts_unified(&accounts);
assert_eq!(
process_instruction(
&id(),
&instruction.data,
&mut MockInvokeContext::new(keyed_accounts)
),
Err(InstructionError::InvalidArgument),
);
}

#[test]
fn test_config_update_contains_duplicates_fails() {
solana_logger::setup();
let config_address = Pubkey::new_unique();
let signer0_pubkey = Pubkey::new_unique();
let signer1_pubkey = Pubkey::new_unique();
let signer0_account = RefCell::new(AccountSharedData::default());
let signer1_account = RefCell::new(AccountSharedData::default());
let keys = vec![
(config_address, false),
(signer0_pubkey, true),
(signer1_pubkey, true),
];
let (config_keypair, config_account) = create_config_account(keys.clone());
let config_pubkey = config_keypair.pubkey();
let my_config = MyConfig::new(42);

let instruction = config_instruction::store(&config_pubkey, true, keys, &my_config);
let accounts = vec![
(true, false, &config_pubkey, &config_account),
(true, false, &signer0_pubkey, &signer0_account),
(true, false, &signer1_pubkey, &signer1_account),
];
let keyed_accounts = create_keyed_accounts_unified(&accounts);
assert_eq!(
process_instruction(
&id(),
&instruction.data,
&mut MockInvokeContext::new(keyed_accounts)
),
Ok(()),
);

// Attempt update with duplicate signer inputs
let new_config = MyConfig::new(84);
let dupe_keys = vec![
(config_address, false),
(signer0_pubkey, true),
(signer0_pubkey, true),
];
let instruction = config_instruction::store(&config_pubkey, false, dupe_keys, &new_config);
let accounts = vec![
(false, false, &config_pubkey, &config_account),
(true, false, &signer0_pubkey, &signer0_account),
(true, false, &signer0_pubkey, &signer0_account),
];
let keyed_accounts = create_keyed_accounts_unified(&accounts);
assert_eq!(
process_instruction(
&id(),
&instruction.data,
&mut MockInvokeContext::new(keyed_accounts)
),
Err(InstructionError::InvalidArgument),
);
}

#[test]
fn test_config_updates_requiring_config() {
solana_logger::setup();
Expand Down
5 changes: 5 additions & 0 deletions sdk/src/feature_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ pub mod system_transfer_zero_check {
solana_sdk::declare_id!("BrTR9hzw4WBGFP65AJMbpAo64DcA3U6jdPSga9fMV5cS");
}

pub mod dedupe_config_program_signers {
solana_sdk::declare_id!("8kEuAshXLsgkUEdcFVLqrjCGGHVWFW99ZZpxvAzzMtBp");
}

lazy_static! {
/// Map of feature identifiers to user-visible description
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
Expand Down Expand Up @@ -184,6 +188,7 @@ lazy_static! {
(memory_ops_syscalls::id(), "add syscalls for memory operations"),
(add_missing_program_error_mappings::id(), "add missing program error mappings"),
(system_transfer_zero_check::id(), "perform all checks for transfers of 0 lamports"),
(dedupe_config_program_signers::id(), "dedupe config program signers"),
/*************** ADD NEW FEATURES HERE ***************/
]
.iter()
Expand Down

0 comments on commit 98e34f0

Please sign in to comment.