diff --git a/sdk/program/src/message/legacy.rs b/sdk/program/src/message/legacy.rs index b6e34fb6d9..3c385ff354 100644 --- a/sdk/program/src/message/legacy.rs +++ b/sdk/program/src/message/legacy.rs @@ -44,6 +44,27 @@ lazy_static! { }; } +lazy_static! { + // Each element of a key is a u8. We use key[0] as an index into this table of 256 boolean + // elements, to store whether or not the first element of any key is present in the static + // lists of built-in-program keys or system ids. By using this lookup table, we can very + // quickly determine that a key under consideration cannot be in either of these lists (if + // the value is "false"), or might be in one of these lists (if the value is "true") + pub static ref MAYBE_BUILTIN_KEY_OR_SYSVAR: [bool; 256] = { + let mut temp_table: [bool; 256] = [false; 256]; + BUILTIN_PROGRAMS_KEYS.iter().for_each(|key| temp_table[key.0[0] as usize] = true); + sysvar::ALL_IDS.iter().for_each(|key| temp_table[key.0[0] as usize] = true); + temp_table + }; +} + +pub fn is_builtin_key_or_sysvar(key: &Pubkey) -> bool { + if MAYBE_BUILTIN_KEY_OR_SYSVAR[key.0[0] as usize] { + return sysvar::is_sysvar_id(key) || BUILTIN_PROGRAMS_KEYS.contains(key); + } + false +} + fn position(keys: &[Pubkey], key: &Pubkey) -> u8 { keys.iter().position(|k| k == key).unwrap() as u8 } @@ -530,10 +551,7 @@ impl Message { || (i >= self.header.num_required_signatures as usize && i < self.account_keys.len() - self.header.num_readonly_unsigned_accounts as usize)) - && !{ - let key = self.account_keys[i]; - sysvar::is_sysvar_id(&key) || BUILTIN_PROGRAMS_KEYS.contains(&key) - } + && !is_builtin_key_or_sysvar(&self.account_keys[i]) && !self.demote_program_id(i) } diff --git a/sdk/program/src/message/versions/v0/loaded.rs b/sdk/program/src/message/versions/v0/loaded.rs index 59d1087134..24fca2b280 100644 --- a/sdk/program/src/message/versions/v0/loaded.rs +++ b/sdk/program/src/message/versions/v0/loaded.rs @@ -1,9 +1,8 @@ use { crate::{ bpf_loader_upgradeable, - message::{legacy::BUILTIN_PROGRAMS_KEYS, v0, AccountKeys}, + message::{legacy::is_builtin_key_or_sysvar, v0, AccountKeys}, pubkey::Pubkey, - sysvar, }, std::{borrow::Cow, collections::HashSet}, }; @@ -109,9 +108,7 @@ impl<'a> LoadedMessage<'a> { pub fn is_writable(&self, key_index: usize) -> bool { if self.is_writable_index(key_index) { if let Some(key) = self.account_keys().get(key_index) { - return !(sysvar::is_sysvar_id(key) - || BUILTIN_PROGRAMS_KEYS.contains(key) - || self.demote_program_id(key_index)); + return !(is_builtin_key_or_sysvar(key) || self.demote_program_id(key_index)); } } false diff --git a/sdk/program/src/message/versions/v0/mod.rs b/sdk/program/src/message/versions/v0/mod.rs index e7cfa5a5c6..faca1fb8d8 100644 --- a/sdk/program/src/message/versions/v0/mod.rs +++ b/sdk/program/src/message/versions/v0/mod.rs @@ -15,12 +15,12 @@ use crate::{ hash::Hash, instruction::{CompiledInstruction, Instruction}, message::{ - compiled_keys::CompileError, legacy::BUILTIN_PROGRAMS_KEYS, AccountKeys, CompiledKeys, + compiled_keys::CompileError, legacy::is_builtin_key_or_sysvar, AccountKeys, CompiledKeys, MessageHeader, MESSAGE_VERSION_PREFIX, }, pubkey::Pubkey, sanitize::SanitizeError, - short_vec, sysvar, + short_vec, }; pub use loaded::*; @@ -344,7 +344,7 @@ impl Message { // demote reserved ids self.account_keys .get(key_index) - .map(|key| sysvar::is_sysvar_id(key) || BUILTIN_PROGRAMS_KEYS.contains(key)) + .map(is_builtin_key_or_sysvar) .unwrap_or_default() } && !{