Bump max invoke depth to 4 (#12742)

This commit is contained in:
Jack May
2020-10-09 10:33:12 -07:00
committed by GitHub
parent 3fedcdc6bc
commit 2cd7cd3149
9 changed files with 139 additions and 87 deletions

View File

@ -178,33 +178,6 @@ extern uint64_t entrypoint(const uint8_t *input) {
SOL_ARRAY_SIZE(signers_seeds))); SOL_ARRAY_SIZE(signers_seeds)));
} }
sol_log("Test multiple derived signers");
{
SolAccountMeta arguments[] = {
{accounts[DERIVED_KEY1_INDEX].key, true, false},
{accounts[DERIVED_KEY2_INDEX].key, true, true},
{accounts[DERIVED_KEY3_INDEX].key, false, true}};
uint8_t data[] = {TEST_VERIFY_NESTED_SIGNERS};
const SolInstruction instruction = {accounts[INVOKED_PROGRAM_INDEX].key,
arguments, SOL_ARRAY_SIZE(arguments),
data, SOL_ARRAY_SIZE(data)};
uint8_t seed1[] = {'L', 'i', 'l', '\''};
uint8_t seed2[] = {'B', 'i', 't', 's'};
const SolSignerSeed seeds1[] = {{seed1, SOL_ARRAY_SIZE(seed1)},
{seed2, SOL_ARRAY_SIZE(seed2)},
{&nonce2, 1}};
const SolSignerSeed seeds2[] = {
{(uint8_t *)accounts[DERIVED_KEY2_INDEX].key, SIZE_PUBKEY},
{&nonce3, 1}};
const SolSignerSeeds signers_seeds[] = {{seeds1, SOL_ARRAY_SIZE(seeds1)},
{seeds2, SOL_ARRAY_SIZE(seeds2)}};
sol_assert(SUCCESS == sol_invoke_signed(&instruction, accounts,
SOL_ARRAY_SIZE(accounts),
signers_seeds,
SOL_ARRAY_SIZE(signers_seeds)));
}
sol_log("Test readonly with writable account"); sol_log("Test readonly with writable account");
{ {
SolAccountMeta arguments[] = { SolAccountMeta arguments[] = {
@ -227,7 +200,8 @@ extern uint64_t entrypoint(const uint8_t *input) {
SolAccountMeta arguments[] = { SolAccountMeta arguments[] = {
{accounts[INVOKED_ARGUMENT_INDEX].key, true, true}, {accounts[INVOKED_ARGUMENT_INDEX].key, true, true},
{accounts[ARGUMENT_INDEX].key, true, true}}; {accounts[ARGUMENT_INDEX].key, true, true},
{accounts[INVOKED_PROGRAM_DUP_INDEX].key, false, false}};
uint8_t data[] = {TEST_NESTED_INVOKE}; uint8_t data[] = {TEST_NESTED_INVOKE};
const SolInstruction instruction = {accounts[INVOKED_PROGRAM_INDEX].key, const SolInstruction instruction = {accounts[INVOKED_PROGRAM_INDEX].key,
arguments, SOL_ARRAY_SIZE(arguments), arguments, SOL_ARRAY_SIZE(arguments),
@ -240,8 +214,9 @@ extern uint64_t entrypoint(const uint8_t *input) {
sol_assert(SUCCESS == sol_assert(SUCCESS ==
sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts))); sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts)));
sol_assert(*accounts[ARGUMENT_INDEX].lamports == 42 - 5 + 1 + 1); sol_assert(*accounts[ARGUMENT_INDEX].lamports == 42 - 5 + 1 + 1 + 1 + 1);
sol_assert(*accounts[INVOKED_ARGUMENT_INDEX].lamports == 10 + 5 - 1 - 1); sol_assert(*accounts[INVOKED_ARGUMENT_INDEX].lamports ==
10 + 5 - 1 - 1 - 1 - 1);
} }
sol_log("Verify data values are retained and updated"); sol_log("Verify data values are retained and updated");

View File

@ -101,6 +101,32 @@ extern uint64_t entrypoint(const uint8_t *input) {
sol_assert(!accounts[DERIVED_KEY2_INDEX].is_signer); sol_assert(!accounts[DERIVED_KEY2_INDEX].is_signer);
sol_assert(!accounts[DERIVED_KEY2_INDEX].is_signer); sol_assert(!accounts[DERIVED_KEY2_INDEX].is_signer);
uint8_t nonce2 = params.data[1];
uint8_t nonce3 = params.data[2];
SolAccountMeta arguments[] = {
{accounts[DERIVED_KEY1_INDEX].key, true, false},
{accounts[DERIVED_KEY2_INDEX].key, true, true},
{accounts[DERIVED_KEY3_INDEX].key, false, true}};
uint8_t data[] = {TEST_VERIFY_NESTED_SIGNERS};
const SolInstruction instruction = {accounts[INVOKED_PROGRAM_INDEX].key,
arguments, SOL_ARRAY_SIZE(arguments),
data, SOL_ARRAY_SIZE(data)};
uint8_t seed1[] = {'L', 'i', 'l', '\''};
uint8_t seed2[] = {'B', 'i', 't', 's'};
const SolSignerSeed seeds1[] = {{seed1, SOL_ARRAY_SIZE(seed1)},
{seed2, SOL_ARRAY_SIZE(seed2)},
{&nonce2, 1}};
const SolSignerSeed seeds2[] = {
{(uint8_t *)accounts[DERIVED_KEY2_INDEX].key, SIZE_PUBKEY},
{&nonce3, 1}};
const SolSignerSeeds signers_seeds[] = {{seeds1, SOL_ARRAY_SIZE(seeds1)},
{seeds2, SOL_ARRAY_SIZE(seeds2)}};
sol_assert(SUCCESS == sol_invoke_signed(
&instruction, accounts, SOL_ARRAY_SIZE(accounts),
signers_seeds, SOL_ARRAY_SIZE(signers_seeds)));
break; break;
} }
@ -114,6 +140,7 @@ extern uint64_t entrypoint(const uint8_t *input) {
sol_assert(!accounts[DERIVED_KEY1_INDEX].is_signer); sol_assert(!accounts[DERIVED_KEY1_INDEX].is_signer);
sol_assert(accounts[DERIVED_KEY2_INDEX].is_signer); sol_assert(accounts[DERIVED_KEY2_INDEX].is_signer);
sol_assert(accounts[DERIVED_KEY2_INDEX].is_signer); sol_assert(accounts[DERIVED_KEY2_INDEX].is_signer);
break; break;
} }
@ -133,6 +160,12 @@ extern uint64_t entrypoint(const uint8_t *input) {
static const int INVOKED_ARGUMENT_INDEX = 0; static const int INVOKED_ARGUMENT_INDEX = 0;
static const int ARGUMENT_INDEX = 1; static const int ARGUMENT_INDEX = 1;
static const int INVOKED_PROGRAM_INDEX = 2;
if (!sol_deserialize(input, &params, 3)) {
sol_assert(sol_deserialize(input, &params, 2));
}
sol_assert(sol_deserialize(input, &params, 2)); sol_assert(sol_deserialize(input, &params, 2));
sol_assert(accounts[INVOKED_ARGUMENT_INDEX].is_signer); sol_assert(accounts[INVOKED_ARGUMENT_INDEX].is_signer);
@ -141,10 +174,24 @@ extern uint64_t entrypoint(const uint8_t *input) {
*accounts[INVOKED_ARGUMENT_INDEX].lamports -= 1; *accounts[INVOKED_ARGUMENT_INDEX].lamports -= 1;
*accounts[ARGUMENT_INDEX].lamports += 1; *accounts[ARGUMENT_INDEX].lamports += 1;
sol_log("Last invoke"); if (params.ka_num == 3) {
SolAccountMeta arguments[] = {
{accounts[INVOKED_ARGUMENT_INDEX].key, true, true},
{accounts[ARGUMENT_INDEX].key, true, true}};
uint8_t data[] = {TEST_NESTED_INVOKE};
const SolInstruction instruction = {accounts[INVOKED_PROGRAM_INDEX].key,
arguments, SOL_ARRAY_SIZE(arguments),
data, SOL_ARRAY_SIZE(data)};
sol_log("Invoke again");
sol_assert(SUCCESS ==
sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts)));
} else {
sol_log("Last invoked");
for (int i = 0; i < accounts[INVOKED_ARGUMENT_INDEX].data_len; i++) { for (int i = 0; i < accounts[INVOKED_ARGUMENT_INDEX].data_len; i++) {
accounts[INVOKED_ARGUMENT_INDEX].data[i] = i; accounts[INVOKED_ARGUMENT_INDEX].data[i] = i;
} }
}
break; break;
} }
default: default:

View File

@ -174,24 +174,6 @@ fn process_instruction(
accounts, accounts,
&[&[b"You pass butter", &[nonce1]]], &[&[b"You pass butter", &[nonce1]]],
)?; )?;
let invoked_instruction = create_instruction(
*accounts[INVOKED_PROGRAM_INDEX].key,
&[
(accounts[DERIVED_KEY1_INDEX].key, true, false),
(accounts[DERIVED_KEY2_INDEX].key, true, true),
(accounts[DERIVED_KEY3_INDEX].key, false, true),
],
vec![TEST_VERIFY_NESTED_SIGNERS],
);
invoke_signed(
&invoked_instruction,
accounts,
&[
&[b"Lil'", b"Bits", &[nonce2]],
&[accounts[DERIVED_KEY2_INDEX].key.as_ref(), &[nonce3]],
],
)?;
} }
info!("Test readonly with writable account"); info!("Test readonly with writable account");
@ -217,6 +199,8 @@ fn process_instruction(
&[ &[
(accounts[ARGUMENT_INDEX].key, true, true), (accounts[ARGUMENT_INDEX].key, true, true),
(accounts[INVOKED_ARGUMENT_INDEX].key, true, true), (accounts[INVOKED_ARGUMENT_INDEX].key, true, true),
(accounts[INVOKED_PROGRAM_DUP_INDEX].key, false, false),
(accounts[INVOKED_PROGRAM_DUP_INDEX].key, false, false),
], ],
vec![TEST_NESTED_INVOKE], vec![TEST_NESTED_INVOKE],
); );
@ -224,9 +208,11 @@ fn process_instruction(
info!("2nd invoke from first program"); info!("2nd invoke from first program");
invoke(&instruction, accounts)?; invoke(&instruction, accounts)?;
info!(line!(), 0, 0, 0, accounts[ARGUMENT_INDEX].lamports()); assert_eq!(accounts[ARGUMENT_INDEX].lamports(), 42 - 5 + 1 + 1 + 1 + 1);
assert_eq!(accounts[ARGUMENT_INDEX].lamports(), 42 - 5 + 1 + 1); assert_eq!(
assert_eq!(accounts[INVOKED_ARGUMENT_INDEX].lamports(), 10 + 5 - 1 - 1); accounts[INVOKED_ARGUMENT_INDEX].lamports(),
10 + 5 - 1 - 1 - 1 - 1
);
} }
info!("Verify data values are retained and updated"); info!("Verify data values are retained and updated");

View File

@ -1,10 +1,14 @@
//! @brief Example Rust-based BPF program that issues a cross-program-invocation //! @brief Example Rust-based BPF program that issues a cross-program-invocation
use crate::instruction::*; use crate::instruction::*;
use solana_sdk::entrypoint;
use solana_sdk::{ use solana_sdk::{
account_info::AccountInfo, bpf_loader, entrypoint::ProgramResult, info, program::invoke, account_info::AccountInfo,
program_error::ProgramError, pubkey::Pubkey, bpf_loader, entrypoint,
entrypoint::ProgramResult,
info,
program::{invoke, invoke_signed},
program_error::ProgramError,
pubkey::Pubkey,
}; };
entrypoint!(process_instruction); entrypoint!(process_instruction);
@ -105,6 +109,7 @@ fn process_instruction(
} }
TEST_DERIVED_SIGNERS => { TEST_DERIVED_SIGNERS => {
info!("verify derived signers"); info!("verify derived signers");
const INVOKED_PROGRAM_INDEX: usize = 0;
const DERIVED_KEY1_INDEX: usize = 1; const DERIVED_KEY1_INDEX: usize = 1;
const DERIVED_KEY2_INDEX: usize = 2; const DERIVED_KEY2_INDEX: usize = 2;
const DERIVED_KEY3_INDEX: usize = 3; const DERIVED_KEY3_INDEX: usize = 3;
@ -112,6 +117,26 @@ fn process_instruction(
assert!(accounts[DERIVED_KEY1_INDEX].is_signer); assert!(accounts[DERIVED_KEY1_INDEX].is_signer);
assert!(!accounts[DERIVED_KEY2_INDEX].is_signer); assert!(!accounts[DERIVED_KEY2_INDEX].is_signer);
assert!(!accounts[DERIVED_KEY3_INDEX].is_signer); assert!(!accounts[DERIVED_KEY3_INDEX].is_signer);
let nonce2 = instruction_data[1];
let nonce3 = instruction_data[2];
let invoked_instruction = create_instruction(
*accounts[INVOKED_PROGRAM_INDEX].key,
&[
(accounts[DERIVED_KEY1_INDEX].key, true, false),
(accounts[DERIVED_KEY2_INDEX].key, true, true),
(accounts[DERIVED_KEY3_INDEX].key, false, true),
],
vec![TEST_VERIFY_NESTED_SIGNERS],
);
invoke_signed(
&invoked_instruction,
accounts,
&[
&[b"Lil'", b"Bits", &[nonce2]],
&[accounts[DERIVED_KEY2_INDEX].key.as_ref(), &[nonce3]],
],
)?;
} }
TEST_VERIFY_NESTED_SIGNERS => { TEST_VERIFY_NESTED_SIGNERS => {
info!("verify nested derived signers"); info!("verify nested derived signers");

View File

@ -483,9 +483,9 @@ fn test_program_bpf_invoke() {
let (derived_key1, nonce1) = let (derived_key1, nonce1) =
Pubkey::find_program_address(&[b"You pass butter"], &invoke_program_id); Pubkey::find_program_address(&[b"You pass butter"], &invoke_program_id);
let (derived_key2, nonce2) = let (derived_key2, nonce2) =
Pubkey::find_program_address(&[b"Lil'", b"Bits"], &invoke_program_id); Pubkey::find_program_address(&[b"Lil'", b"Bits"], &invoked_program_id);
let (derived_key3, nonce3) = let (derived_key3, nonce3) =
Pubkey::find_program_address(&[derived_key2.as_ref()], &invoke_program_id); Pubkey::find_program_address(&[derived_key2.as_ref()], &invoked_program_id);
let mint_pubkey = mint_keypair.pubkey(); let mint_pubkey = mint_keypair.pubkey();
let account_metas = vec![ let account_metas = vec![
@ -539,6 +539,8 @@ fn test_program_bpf_invoke() {
invoked_program_id.clone(), invoked_program_id.clone(),
invoked_program_id.clone(), invoked_program_id.clone(),
invoked_program_id.clone(), invoked_program_id.clone(),
invoked_program_id.clone(),
invoked_program_id.clone(),
] ]
); );

View File

@ -17,7 +17,7 @@ use solana_rbpf::{
vm::{EbpfVm, Executable, InstructionMeter}, vm::{EbpfVm, Executable, InstructionMeter},
}; };
use solana_runtime::{ use solana_runtime::{
feature_set::compute_budget_config2, feature_set::compute_budget_balancing,
process_instruction::{ComputeMeter, Executor, InvokeContext}, process_instruction::{ComputeMeter, Executor, InvokeContext},
}; };
use solana_sdk::{ use solana_sdk::{
@ -101,7 +101,7 @@ pub fn create_and_cache_executor(
.map_err(|e| map_ebpf_error(invoke_context, e))?; .map_err(|e| map_ebpf_error(invoke_context, e))?;
bpf_verifier::check( bpf_verifier::check(
elf_bytes, elf_bytes,
!invoke_context.is_feature_active(&compute_budget_config2::id()), !invoke_context.is_feature_active(&compute_budget_balancing::id()),
) )
.map_err(|e| map_ebpf_error(invoke_context, EbpfError::UserError(e)))?; .map_err(|e| map_ebpf_error(invoke_context, EbpfError::UserError(e)))?;
let executor = Arc::new(BPFExecutor { executable }); let executor = Arc::new(BPFExecutor { executable });

View File

@ -33,7 +33,7 @@ pub mod bpf_loader2_program {
solana_sdk::declare_id!("DFBnrgThdzH4W6wZ12uGPoWcMnvfZj11EHnxHcVxLPhD"); solana_sdk::declare_id!("DFBnrgThdzH4W6wZ12uGPoWcMnvfZj11EHnxHcVxLPhD");
} }
pub mod compute_budget_config2 { pub mod compute_budget_balancing {
solana_sdk::declare_id!("HxvjqDSiF5sYdSYuCXsUnS8UeAoWsMT9iGoFP8pgV1mB"); solana_sdk::declare_id!("HxvjqDSiF5sYdSYuCXsUnS8UeAoWsMT9iGoFP8pgV1mB");
} }
@ -49,6 +49,10 @@ pub mod ristretto_mul_syscall_enabled {
solana_sdk::declare_id!("HRe7A6aoxgjKzdjbBv6HTy7tJ4YWqE6tVmYCGho6S9Aq"); solana_sdk::declare_id!("HRe7A6aoxgjKzdjbBv6HTy7tJ4YWqE6tVmYCGho6S9Aq");
} }
pub mod max_invoke_depth_4 {
solana_sdk::declare_id!("EdM9xggY5y7AhNMskRG8NgGMnaP4JFNsWi8ZZtyT1af5");
}
lazy_static! { lazy_static! {
/// Map of feature identifiers to user-visible description /// Map of feature identifiers to user-visible description
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [ pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
@ -59,10 +63,11 @@ lazy_static! {
(inflation_kill_switch::id(), "inflation kill switch"), (inflation_kill_switch::id(), "inflation kill switch"),
(spl_token_v2_multisig_fix::id(), "spl-token multisig fix"), (spl_token_v2_multisig_fix::id(), "spl-token multisig fix"),
(bpf_loader2_program::id(), "bpf_loader2 program"), (bpf_loader2_program::id(), "bpf_loader2 program"),
(compute_budget_config2::id(), "1ms compute budget"), (compute_budget_balancing::id(), "compute budget balancing"),
(sha256_syscall_enabled::id(), "sha256 syscall"), (sha256_syscall_enabled::id(), "sha256 syscall"),
(no_overflow_rent_distribution::id(), "no overflow rent distribution"), (no_overflow_rent_distribution::id(), "no overflow rent distribution"),
(ristretto_mul_syscall_enabled::id(), "ristretto multiply syscall"), (ristretto_mul_syscall_enabled::id(), "ristretto multiply syscall"),
(max_invoke_depth_4::id(), "max invoke call depth 4"),
/*************** ADD NEW FEATURES HERE ***************/ /*************** ADD NEW FEATURES HERE ***************/
] ]
.iter() .iter()

View File

@ -1,5 +1,5 @@
use crate::{ use crate::{
feature_set::{compute_budget_config2, instructions_sysvar_enabled, FeatureSet}, feature_set::{instructions_sysvar_enabled, FeatureSet},
instruction_recorder::InstructionRecorder, instruction_recorder::InstructionRecorder,
log_collector::LogCollector, log_collector::LogCollector,
native_loader::NativeLoader, native_loader::NativeLoader,
@ -244,7 +244,7 @@ impl ThisInvokeContext {
} }
impl InvokeContext for ThisInvokeContext { impl InvokeContext for ThisInvokeContext {
fn push(&mut self, key: &Pubkey) -> Result<(), InstructionError> { fn push(&mut self, key: &Pubkey) -> Result<(), InstructionError> {
if self.program_ids.len() >= self.compute_budget.max_invoke_depth { if self.program_ids.len() > self.compute_budget.max_invoke_depth {
return Err(InstructionError::CallDepth); return Err(InstructionError::CallDepth);
} }
if self.program_ids.contains(key) && self.program_ids.last() != Some(key) { if self.program_ids.contains(key) && self.program_ids.last() != Some(key) {
@ -416,21 +416,7 @@ impl MessageProcessor {
} }
fn get_compute_budget(feature_set: &FeatureSet) -> ComputeBudget { fn get_compute_budget(feature_set: &FeatureSet) -> ComputeBudget {
if feature_set.is_active(&compute_budget_config2::id()) { ComputeBudget::new(feature_set)
ComputeBudget::default()
} else {
// Original
ComputeBudget {
max_units: 100_000,
log_units: 0,
log_64_units: 0,
create_program_address_units: 0,
invoke_units: 0,
max_invoke_depth: 2,
sha256_base_cost: 0,
sha256_byte_cost: 0,
}
}
} }
/// Create the KeyedAccounts that will be passed to the program /// Create the KeyedAccounts that will be passed to the program

View File

@ -1,3 +1,4 @@
use crate::feature_set::{compute_budget_balancing, max_invoke_depth_4, FeatureSet};
use solana_sdk::{ use solana_sdk::{
account::{Account, KeyedAccount}, account::{Account, KeyedAccount},
instruction::{CompiledInstruction, Instruction, InstructionError}, instruction::{CompiledInstruction, Instruction, InstructionError},
@ -94,17 +95,42 @@ pub struct ComputeBudget {
} }
impl Default for ComputeBudget { impl Default for ComputeBudget {
fn default() -> Self { fn default() -> Self {
// Tuned for ~1ms Self::new(&FeatureSet::all_enabled())
}
}
impl ComputeBudget {
pub fn new(feature_set: &FeatureSet) -> Self {
let mut compute_budget =
// Original
ComputeBudget { ComputeBudget {
max_units: 100_000,
log_units: 0,
log_64_units: 0,
create_program_address_units: 0,
invoke_units: 0,
max_invoke_depth: 1,
sha256_base_cost: 85,
sha256_byte_cost: 1,
};
if feature_set.is_active(&compute_budget_balancing::id()) {
compute_budget = ComputeBudget {
max_units: 200_000, max_units: 200_000,
log_units: 100, log_units: 100,
log_64_units: 100, log_64_units: 100,
create_program_address_units: 1500, create_program_address_units: 1500,
invoke_units: 1000, invoke_units: 1000,
max_invoke_depth: 2, ..compute_budget
sha256_base_cost: 85, };
sha256_byte_cost: 1,
} }
if feature_set.is_active(&max_invoke_depth_4::id()) {
compute_budget = ComputeBudget {
max_invoke_depth: 4,
..compute_budget
}
}
compute_budget
} }
} }