Restore ability for programs to upgrade themselves (#20265)
* Make helper associated fn * Add feature definition * Add handling to preserve program-id write lock when upgradeable loader is present; restore bpf upgrade-self test * Use single feature
This commit is contained in:
@ -354,6 +354,9 @@ impl Message {
|
||||
}
|
||||
|
||||
pub fn is_writable(&self, i: usize, demote_program_write_locks: bool) -> bool {
|
||||
let demote_program_id = demote_program_write_locks
|
||||
&& self.is_key_called_as_program(i)
|
||||
&& !self.is_upgradeable_loader_present();
|
||||
(i < (self.header.num_required_signatures - self.header.num_readonly_signed_accounts)
|
||||
as usize
|
||||
|| (i >= self.header.num_required_signatures as usize
|
||||
@ -363,7 +366,7 @@ impl Message {
|
||||
let key = self.account_keys[i];
|
||||
sysvar::is_sysvar_id(&key) || BUILTIN_PROGRAMS_KEYS.contains(&key)
|
||||
}
|
||||
&& !(demote_program_write_locks && self.is_key_called_as_program(i))
|
||||
&& !demote_program_id
|
||||
}
|
||||
|
||||
pub fn is_signer(&self, i: usize) -> bool {
|
||||
@ -503,6 +506,13 @@ impl Message {
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Returns true if any account is the bpf upgradeable loader
|
||||
pub fn is_upgradeable_loader_present(&self) -> bool {
|
||||
self.account_keys
|
||||
.iter()
|
||||
.any(|&key| key == bpf_loader_upgradeable::id())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -1,5 +1,6 @@
|
||||
use {
|
||||
crate::{
|
||||
bpf_loader_upgradeable,
|
||||
message::{legacy::BUILTIN_PROGRAMS_KEYS, v0},
|
||||
pubkey::Pubkey,
|
||||
sysvar,
|
||||
@ -99,8 +100,12 @@ impl MappedMessage {
|
||||
pub fn is_writable(&self, key_index: usize, demote_program_write_locks: bool) -> bool {
|
||||
if self.is_writable_index(key_index) {
|
||||
if let Some(key) = self.get_account_key(key_index) {
|
||||
return !(sysvar::is_sysvar_id(key) || BUILTIN_PROGRAMS_KEYS.contains(key)
|
||||
|| (demote_program_write_locks && self.is_key_called_as_program(key_index)));
|
||||
let demote_program_id = demote_program_write_locks
|
||||
&& self.is_key_called_as_program(key_index)
|
||||
&& !self.is_upgradeable_loader_present();
|
||||
return !(sysvar::is_sysvar_id(key)
|
||||
|| BUILTIN_PROGRAMS_KEYS.contains(key)
|
||||
|| demote_program_id);
|
||||
}
|
||||
}
|
||||
false
|
||||
@ -116,6 +121,12 @@ impl MappedMessage {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if any account is the bpf upgradeable loader
|
||||
pub fn is_upgradeable_loader_present(&self) -> bool {
|
||||
self.account_keys_iter()
|
||||
.any(|&key| key == bpf_loader_upgradeable::id())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -308,6 +308,14 @@ impl SanitizedMessage {
|
||||
.saturating_add(num_secp256k1_signatures),
|
||||
)
|
||||
}
|
||||
|
||||
/// Inspect all message keys for the bpf upgradeable loader
|
||||
pub fn is_upgradeable_loader_present(&self) -> bool {
|
||||
match self {
|
||||
Self::Legacy(message) => message.is_upgradeable_loader_present(),
|
||||
Self::V0(message) => message.is_upgradeable_loader_present(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -264,7 +264,7 @@ lazy_static! {
|
||||
(instructions_sysvar_owned_by_sysvar::id(), "fix owner for instructions sysvar"),
|
||||
(close_upgradeable_program_accounts::id(), "enable closing upgradeable program accounts"),
|
||||
(stake_program_advance_activating_credits_observed::id(), "Enable advancing credits observed for activation epoch #19309"),
|
||||
(demote_program_write_locks::id(), "demote program write locks to readonly #19593"),
|
||||
(demote_program_write_locks::id(), "demote program write locks to readonly, except when upgradeable loader present #19593 #20265"),
|
||||
(ed25519_program_enabled::id(), "enable builtin ed25519 signature verify program"),
|
||||
(allow_native_ids::id(), "allow native program ids in program derived addresses"),
|
||||
(check_seed_length::id(), "Check program address seed lengths"),
|
||||
|
Reference in New Issue
Block a user