programs/config: Disallow duplicate signers
This commit is contained in:
parent
2fe211c5e0
commit
e0d679b319
|
@ -11,6 +11,7 @@ use solana_sdk::{
|
|||
program_utils::limited_deserialize,
|
||||
pubkey::Pubkey,
|
||||
};
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
pub fn process_instruction(
|
||||
_program_id: &Pubkey,
|
||||
|
@ -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!(
|
||||
|
@ -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();
|
||||
|
|
|
@ -151,6 +151,10 @@ pub mod blake3_syscall_enabled {
|
|||
solana_sdk::declare_id!("HTW2pSyErTj4BV6KBM9NZ9VBUJVxt7sacNWcf76wtzb3");
|
||||
}
|
||||
|
||||
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> = [
|
||||
|
@ -189,6 +193,7 @@ lazy_static! {
|
|||
(add_missing_program_error_mappings::id(), "add missing program error mappings"),
|
||||
(system_transfer_zero_check::id(), "perform all checks for transfers of 0 lamports"),
|
||||
(blake3_syscall_enabled::id(), "blake3 syscall"),
|
||||
(dedupe_config_program_signers::id(), "dedupe config program signers"),
|
||||
/*************** ADD NEW FEATURES HERE ***************/
|
||||
]
|
||||
.iter()
|
||||
|
|
Loading…
Reference in New Issue