Remove support for dynamically loaded native programs (backport #20444) (#20560)

* Remove support for dynamically loaded native programs (#20444)

(cherry picked from commit 785fcb63f5)

# Conflicts:
#	Cargo.lock
#	Cargo.toml
#	program-runtime/src/instruction_processor.rs
#	programs/failure/Cargo.toml
#	programs/failure/tests/failure.rs
#	programs/noop/Cargo.toml
#	programs/ownable/Cargo.toml
#	programs/ownable/src/ownable_processor.rs
#	runtime/src/bank.rs
#	runtime/tests/noop.rs
#	sdk/src/feature_set.rs

* resolve conflicts

Co-authored-by: Jack May <jack@solana.com>
This commit is contained in:
mergify[bot]
2021-10-11 23:55:39 +00:00
committed by GitHub
parent af4c1785b6
commit 9acf708344
16 changed files with 15 additions and 505 deletions

30
Cargo.lock generated
View File

@ -4703,14 +4703,6 @@ dependencies = [
"thiserror",
]
[[package]]
name = "solana-failure-program"
version = "1.8.1"
dependencies = [
"solana-runtime",
"solana-sdk",
]
[[package]]
name = "solana-faucet"
version = "1.8.1"
@ -5150,15 +5142,6 @@ dependencies = [
"url 2.2.0",
]
[[package]]
name = "solana-noop-program"
version = "1.8.1"
dependencies = [
"log 0.4.14",
"solana-logger 1.8.1",
"solana-sdk",
]
[[package]]
name = "solana-notifier"
version = "1.8.1"
@ -5168,18 +5151,6 @@ dependencies = [
"serde_json",
]
[[package]]
name = "solana-ownable"
version = "1.8.1"
dependencies = [
"bincode",
"num-derive",
"num-traits",
"solana-runtime",
"solana-sdk",
"thiserror",
]
[[package]]
name = "solana-perf"
version = "1.8.1"
@ -5453,7 +5424,6 @@ dependencies = [
"solana-logger 1.8.1",
"solana-measure",
"solana-metrics",
"solana-noop-program",
"solana-rayon-threadlimit",
"solana-sdk",
"solana-secp256k1-program",

View File

@ -49,9 +49,6 @@ members = [
"programs/compute-budget",
"programs/config",
"programs/exchange",
"programs/failure",
"programs/noop",
"programs/ownable",
"programs/secp256k1",
"programs/stake",
"programs/vote",

View File

@ -1,24 +0,0 @@
[package]
name = "solana-failure-program"
version = "1.8.1"
description = "Solana failure program"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-failure-program"
edition = "2018"
[dependencies]
solana-sdk = { path = "../../sdk", version = "=1.8.1" }
[dev-dependencies]
solana-runtime = { path = "../../runtime", version = "=1.8.1" }
[lib]
crate-type = ["lib", "cdylib"]
name = "solana_failure_program"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@ -1,17 +0,0 @@
use solana_sdk::{
instruction::InstructionError, process_instruction::InvokeContext, pubkey::Pubkey,
};
solana_sdk::declare_program!(
"FaiLure111111111111111111111111111111111111",
solana_failure_program,
process_instruction
);
fn process_instruction(
_program_id: &Pubkey,
_data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
Err(InstructionError::Custom(0))
}

View File

@ -1,27 +0,0 @@
use solana_runtime::bank::Bank;
use solana_runtime::bank_client::BankClient;
use solana_runtime::loader_utils::create_invoke_instruction;
use solana_sdk::client::SyncClient;
use solana_sdk::genesis_config::create_genesis_config;
use solana_sdk::instruction::InstructionError;
use solana_sdk::signature::Signer;
use solana_sdk::transaction::TransactionError;
#[test]
fn test_program_native_failure() {
let (genesis_config, alice_keypair) = create_genesis_config(50);
let program_id = solana_sdk::pubkey::new_rand();
let bank = Bank::new(&genesis_config);
bank.add_native_program("solana_failure_program", &program_id, false);
// Call user program
let instruction = create_invoke_instruction(alice_keypair.pubkey(), program_id, &1u8);
let bank_client = BankClient::new(bank);
assert_eq!(
bank_client
.send_and_confirm_instruction(&alice_keypair, instruction)
.unwrap_err()
.unwrap(),
TransactionError::InstructionError(0, InstructionError::Custom(0))
);
}

View File

@ -1,23 +0,0 @@
[package]
name = "solana-noop-program"
version = "1.8.1"
description = "Solana Noop program"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-noop-program"
edition = "2018"
[dependencies]
log = "0.4.11"
solana-logger = { path = "../../logger", version = "=1.8.1" }
solana-sdk = { path = "../../sdk", version = "=1.8.1" }
[lib]
crate-type = ["lib", "cdylib"]
name = "solana_noop_program"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@ -1,21 +0,0 @@
use log::*;
use solana_sdk::{
instruction::InstructionError, process_instruction::InvokeContext, pubkey::Pubkey,
};
solana_sdk::declare_program!(
"Noop111111111111111111111111111111111111111",
solana_noop_program,
process_instruction
);
pub fn process_instruction(
program_id: &Pubkey,
data: &[u8],
_invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
solana_logger::setup();
trace!("noop: program_id: {:?}", program_id);
trace!("noop: data: {:?}", data);
Ok(())
}

View File

@ -1,27 +0,0 @@
[package]
name = "solana-ownable"
version = "1.8.1"
description = "ownable program"
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
repository = "https://github.com/solana-labs/solana"
license = "Apache-2.0"
homepage = "https://solana.com/"
documentation = "https://docs.rs/solana-ownable"
edition = "2018"
[dependencies]
bincode = "1.3.1"
solana-sdk = { path = "../../sdk", version = "=1.8.1" }
num-derive = "0.3"
num-traits = "0.2"
thiserror = "1.0"
[dev-dependencies]
solana-runtime = { path = "../../runtime", version = "=1.8.1" }
[lib]
crate-type = ["lib", "cdylib"]
name = "solana_ownable"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@ -1,4 +0,0 @@
pub mod ownable_instruction;
pub mod ownable_processor;
solana_sdk::declare_id!("ownab1e111111111111111111111111111111111111");

View File

@ -1,52 +0,0 @@
use num_derive::{FromPrimitive, ToPrimitive};
use solana_sdk::{
decode_error::DecodeError,
instruction::{AccountMeta, Instruction},
pubkey::Pubkey,
system_instruction,
};
use thiserror::Error;
#[derive(Error, Debug, Clone, PartialEq, FromPrimitive, ToPrimitive)]
pub enum OwnableError {
#[error("incorrect error")]
IncorrectOwner,
}
impl<T> DecodeError<T> for OwnableError {
fn type_of() -> &'static str {
"OwnableError"
}
}
fn initialize_account(account_pubkey: &Pubkey, owner_pubkey: &Pubkey) -> Instruction {
let keys = vec![AccountMeta::new(*account_pubkey, false)];
Instruction::new_with_bincode(crate::id(), &owner_pubkey, keys)
}
pub fn create_account(
payer_pubkey: &Pubkey,
account_pubkey: &Pubkey,
owner_pubkey: &Pubkey,
lamports: u64,
) -> Vec<Instruction> {
let space = std::mem::size_of::<Pubkey>() as u64;
vec![
system_instruction::create_account(
payer_pubkey,
account_pubkey,
lamports,
space,
&crate::id(),
),
initialize_account(account_pubkey, owner_pubkey),
]
}
pub fn set_owner(account_pubkey: &Pubkey, old_pubkey: &Pubkey, new_pubkey: &Pubkey) -> Instruction {
let keys = vec![
AccountMeta::new(*account_pubkey, false),
AccountMeta::new(*old_pubkey, true),
];
Instruction::new_with_bincode(crate::id(), &new_pubkey, keys)
}

View File

@ -1,186 +0,0 @@
//! Ownable program
use crate::ownable_instruction::OwnableError;
use bincode::serialize_into;
use solana_sdk::{
account::{ReadableAccount, WritableAccount},
instruction::InstructionError,
keyed_account::{keyed_account_at_index, KeyedAccount},
process_instruction::InvokeContext,
program_utils::limited_deserialize,
pubkey::Pubkey,
};
fn set_owner(
account_owner_pubkey: &mut Pubkey,
new_owner_pubkey: Pubkey,
owner_keyed_account: &KeyedAccount,
) -> Result<(), InstructionError> {
match owner_keyed_account.signer_key() {
None => return Err(InstructionError::MissingRequiredSignature),
Some(signer_key) => {
if account_owner_pubkey != signer_key {
return Err(OwnableError::IncorrectOwner.into());
}
*account_owner_pubkey = new_owner_pubkey;
}
}
Ok(())
}
pub fn process_instruction(
_program_id: &Pubkey,
data: &[u8],
invoke_context: &mut dyn InvokeContext,
) -> Result<(), InstructionError> {
let keyed_accounts = invoke_context.get_keyed_accounts()?;
let new_owner_pubkey: Pubkey = limited_deserialize(data)?;
let account_keyed_account = &mut keyed_account_at_index(keyed_accounts, 0)?;
let mut account_owner_pubkey: Pubkey =
limited_deserialize(account_keyed_account.try_account_ref()?.data())?;
if account_owner_pubkey == Pubkey::default() {
account_owner_pubkey = new_owner_pubkey;
} else {
let owner_keyed_account = &mut keyed_account_at_index(keyed_accounts, 1)?;
set_owner(
&mut account_owner_pubkey,
new_owner_pubkey,
owner_keyed_account,
)?;
}
let mut account = account_keyed_account.try_account_ref_mut()?;
serialize_into(account.data_as_mut_slice(), &account_owner_pubkey)
.map_err(|_| InstructionError::AccountDataTooSmall)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ownable_instruction;
use solana_runtime::{bank::Bank, bank_client::BankClient};
use solana_sdk::{
account::AccountSharedData,
client::SyncClient,
genesis_config::create_genesis_config,
message::Message,
signature::{Keypair, Signature, Signer},
system_program,
transport::Result,
};
fn create_bank(lamports: u64) -> (Bank, Keypair) {
let (genesis_config, mint_keypair) = create_genesis_config(lamports);
let mut bank = Bank::new(&genesis_config);
bank.add_builtin("ownable_program", crate::id(), process_instruction);
(bank, mint_keypair)
}
fn create_bank_client(lamports: u64) -> (BankClient, Keypair) {
let (bank, mint_keypair) = create_bank(lamports);
(BankClient::new(bank), mint_keypair)
}
fn create_ownable_account(
bank_client: &BankClient,
payer_keypair: &Keypair,
account_keypair: &Keypair,
owner_pubkey: &Pubkey,
lamports: u64,
) -> Result<Signature> {
let instructions = ownable_instruction::create_account(
&payer_keypair.pubkey(),
&account_keypair.pubkey(),
owner_pubkey,
lamports,
);
let message = Message::new(&instructions, Some(&payer_keypair.pubkey()));
bank_client.send_and_confirm_message(&[payer_keypair, account_keypair], message)
}
fn send_set_owner(
bank_client: &BankClient,
payer_keypair: &Keypair,
account_pubkey: &Pubkey,
old_owner_keypair: &Keypair,
new_owner_pubkey: &Pubkey,
) -> Result<Signature> {
let instruction = ownable_instruction::set_owner(
account_pubkey,
&old_owner_keypair.pubkey(),
new_owner_pubkey,
);
let message = Message::new(&[instruction], Some(&payer_keypair.pubkey()));
bank_client.send_and_confirm_message(&[payer_keypair, old_owner_keypair], message)
}
#[test]
fn test_ownable_set_owner() {
let (bank_client, payer_keypair) = create_bank_client(2);
let account_keypair = Keypair::new();
let account_pubkey = account_keypair.pubkey();
let owner_keypair = Keypair::new();
let owner_pubkey = owner_keypair.pubkey();
create_ownable_account(
&bank_client,
&payer_keypair,
&account_keypair,
&owner_pubkey,
1,
)
.unwrap();
let new_owner_keypair = Keypair::new();
let new_owner_pubkey = new_owner_keypair.pubkey();
send_set_owner(
&bank_client,
&payer_keypair,
&account_pubkey,
&owner_keypair,
&new_owner_pubkey,
)
.unwrap();
let account_data = bank_client
.get_account_data(&account_pubkey)
.unwrap()
.unwrap();
let account_owner_pubkey: Pubkey = limited_deserialize(&account_data).unwrap();
assert_eq!(account_owner_pubkey, new_owner_pubkey);
}
#[test]
fn test_ownable_missing_owner_signature() {
let mut account_owner_pubkey = solana_sdk::pubkey::new_rand();
let owner_pubkey = account_owner_pubkey;
let new_owner_pubkey = solana_sdk::pubkey::new_rand();
let account = AccountSharedData::new_ref(1, 0, &system_program::id());
let owner_keyed_account = KeyedAccount::new(&owner_pubkey, false, &account); // <-- Attack! Setting owner without the original owner's signature.
let err = set_owner(
&mut account_owner_pubkey,
new_owner_pubkey,
&owner_keyed_account,
)
.unwrap_err();
assert_eq!(err, InstructionError::MissingRequiredSignature);
}
#[test]
fn test_ownable_incorrect_owner() {
let mut account_owner_pubkey = solana_sdk::pubkey::new_rand();
let new_owner_pubkey = solana_sdk::pubkey::new_rand();
let account = AccountSharedData::new_ref(1, 0, &system_program::id());
let mallory_pubkey = solana_sdk::pubkey::new_rand(); // <-- Attack! Signing with wrong pubkey
let owner_keyed_account = KeyedAccount::new(&mallory_pubkey, true, &account);
let err = set_owner(
&mut account_owner_pubkey,
new_owner_pubkey,
&owner_keyed_account,
)
.unwrap_err();
assert_eq!(err, OwnableError::IncorrectOwner.into());
}
}

View File

@ -60,7 +60,6 @@ name = "solana_runtime"
[dev-dependencies]
assert_matches = "1.3.0"
solana-noop-program = { path = "../programs/noop", version = "=1.8.1" }
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

View File

@ -5986,7 +5986,6 @@ pub(crate) mod tests {
create_genesis_config_with_leader, create_genesis_config_with_vote_accounts,
GenesisConfigInfo, ValidatorVoteKeypairs,
},
native_loader::NativeLoaderError,
status_cache::MAX_CACHE_ENTRIES,
};
use crossbeam_channel::{bounded, unbounded};
@ -12863,67 +12862,6 @@ pub(crate) mod tests {
);
}
#[test]
fn test_bad_native_loader() {
let (genesis_config, mint_keypair) = create_genesis_config(50000);
let bank = Bank::new(&genesis_config);
let to_keypair = Keypair::new();
let tx = Transaction::new_signed_with_payer(
&[
system_instruction::create_account(
&mint_keypair.pubkey(),
&to_keypair.pubkey(),
10000,
0,
&native_loader::id(),
),
Instruction::new_with_bincode(
native_loader::id(),
&(),
vec![AccountMeta::new(to_keypair.pubkey(), false)],
),
],
Some(&mint_keypair.pubkey()),
&[&mint_keypair, &to_keypair],
bank.last_blockhash(),
);
assert_eq!(
bank.process_transaction(&tx),
Err(TransactionError::InstructionError(
1,
InstructionError::Custom(NativeLoaderError::InvalidAccountData as u32)
))
);
let tx = Transaction::new_signed_with_payer(
&[
system_instruction::create_account(
&mint_keypair.pubkey(),
&to_keypair.pubkey(),
10000,
100,
&native_loader::id(),
),
Instruction::new_with_bincode(
native_loader::id(),
&(),
vec![AccountMeta::new(to_keypair.pubkey(), false)],
),
],
Some(&mint_keypair.pubkey()),
&[&mint_keypair, &to_keypair],
bank.last_blockhash(),
);
assert_eq!(
bank.process_transaction(&tx),
Err(TransactionError::InstructionError(
1,
InstructionError::Custom(NativeLoaderError::InvalidAccountData as u32)
))
);
}
#[test]
fn test_debug_bank() {
let (genesis_config, _mint_keypair) = create_genesis_config(50000);

View File

@ -11,7 +11,8 @@ use solana_sdk::{
bpf_loader_upgradeable::{self, UpgradeableLoaderState},
feature_set::{
demote_program_write_locks, fix_write_privs, instructions_sysvar_enabled,
neon_evm_compute_budget, tx_wide_compute_cap, updated_verify_policy, FeatureSet,
neon_evm_compute_budget, remove_native_loader, tx_wide_compute_cap, updated_verify_policy,
FeatureSet,
},
ic_logger_msg, ic_msg,
instruction::{CompiledInstruction, Instruction, InstructionError},
@ -669,12 +670,14 @@ impl MessageProcessor {
return process_instruction(program_id, instruction_data, invoke_context);
}
}
// Call the program via the native loader
return self.native_loader.process_instruction(
&native_loader::id(),
instruction_data,
invoke_context,
);
if !invoke_context.is_feature_active(&remove_native_loader::id()) {
// Call the program via the native loader
return self.native_loader.process_instruction(
&native_loader::id(),
instruction_data,
invoke_context,
);
}
} else {
let owner_id = &root_account.owner()?;
for (id, process_instruction) in &self.programs {

View File

@ -1,21 +0,0 @@
use solana_runtime::{
bank::Bank, bank_client::BankClient, loader_utils::create_invoke_instruction,
};
use solana_sdk::{client::SyncClient, genesis_config::create_genesis_config, signature::Signer};
#[test]
fn test_program_native_noop() {
solana_logger::setup();
let (genesis_config, alice_keypair) = create_genesis_config(50);
let program_id = solana_sdk::pubkey::new_rand();
let bank = Bank::new(&genesis_config);
bank.add_native_program("solana_noop_program", &program_id, false);
// Call user program
let instruction = create_invoke_instruction(alice_keypair.pubkey(), program_id, &1u8);
let bank_client = BankClient::new(bank);
bank_client
.send_and_confirm_instruction(&alice_keypair, instruction)
.unwrap();
}

View File

@ -227,6 +227,10 @@ pub mod gate_large_block {
solana_sdk::declare_id!("2ry7ygxiYURULZCrypHhveanvP5tzZ4toRwVp89oCNSj");
}
pub mod remove_native_loader {
solana_sdk::declare_id!("HTTgmruMYRZEntyL3EdCDdnS6e4D5wRq1FA7kQsb66qq");
}
lazy_static! {
/// Map of feature identifiers to user-visible description
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
@ -284,6 +288,7 @@ lazy_static! {
(optimize_epoch_boundary_updates::id(), "Optimize epoch boundary updates"),
(tx_wide_compute_cap::id(), "Transaction wide compute cap"),
(gate_large_block::id(), "validator checks block cost against max limit in realtime, reject if exceeds."),
(remove_native_loader::id(), "Remove support for the native loader"),
/*************** ADD NEW FEATURES HERE ***************/
]
.iter()