Bump max invoke depth to 4 (#12742)
This commit is contained in:
parent
3fedcdc6bc
commit
2cd7cd3149
|
@ -178,33 +178,6 @@ extern uint64_t entrypoint(const uint8_t *input) {
|
|||
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");
|
||||
{
|
||||
SolAccountMeta arguments[] = {
|
||||
|
@ -227,7 +200,8 @@ extern uint64_t entrypoint(const uint8_t *input) {
|
|||
|
||||
SolAccountMeta arguments[] = {
|
||||
{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};
|
||||
const SolInstruction instruction = {accounts[INVOKED_PROGRAM_INDEX].key,
|
||||
arguments, SOL_ARRAY_SIZE(arguments),
|
||||
|
@ -240,8 +214,9 @@ extern uint64_t entrypoint(const uint8_t *input) {
|
|||
sol_assert(SUCCESS ==
|
||||
sol_invoke(&instruction, accounts, SOL_ARRAY_SIZE(accounts)));
|
||||
|
||||
sol_assert(*accounts[ARGUMENT_INDEX].lamports == 42 - 5 + 1 + 1);
|
||||
sol_assert(*accounts[INVOKED_ARGUMENT_INDEX].lamports == 10 + 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 - 1 - 1);
|
||||
}
|
||||
|
||||
sol_log("Verify data values are retained and updated");
|
||||
|
|
|
@ -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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -114,6 +140,7 @@ extern uint64_t entrypoint(const uint8_t *input) {
|
|||
sol_assert(!accounts[DERIVED_KEY1_INDEX].is_signer);
|
||||
sol_assert(accounts[DERIVED_KEY2_INDEX].is_signer);
|
||||
sol_assert(accounts[DERIVED_KEY2_INDEX].is_signer);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -133,6 +160,12 @@ extern uint64_t entrypoint(const uint8_t *input) {
|
|||
|
||||
static const int INVOKED_ARGUMENT_INDEX = 0;
|
||||
static const int ARGUMENT_INDEX = 1;
|
||||
static const int INVOKED_PROGRAM_INDEX = 2;
|
||||
|
||||
if (!sol_deserialize(input, ¶ms, 3)) {
|
||||
sol_assert(sol_deserialize(input, ¶ms, 2));
|
||||
}
|
||||
|
||||
sol_assert(sol_deserialize(input, ¶ms, 2));
|
||||
|
||||
sol_assert(accounts[INVOKED_ARGUMENT_INDEX].is_signer);
|
||||
|
@ -141,9 +174,23 @@ extern uint64_t entrypoint(const uint8_t *input) {
|
|||
*accounts[INVOKED_ARGUMENT_INDEX].lamports -= 1;
|
||||
*accounts[ARGUMENT_INDEX].lamports += 1;
|
||||
|
||||
sol_log("Last invoke");
|
||||
for (int i = 0; i < accounts[INVOKED_ARGUMENT_INDEX].data_len; i++) {
|
||||
accounts[INVOKED_ARGUMENT_INDEX].data[i] = i;
|
||||
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++) {
|
||||
accounts[INVOKED_ARGUMENT_INDEX].data[i] = i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -174,24 +174,6 @@ fn process_instruction(
|
|||
accounts,
|
||||
&[&[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");
|
||||
|
@ -217,6 +199,8 @@ fn process_instruction(
|
|||
&[
|
||||
(accounts[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],
|
||||
);
|
||||
|
@ -224,9 +208,11 @@ fn process_instruction(
|
|||
info!("2nd invoke from first program");
|
||||
invoke(&instruction, accounts)?;
|
||||
|
||||
info!(line!(), 0, 0, 0, accounts[ARGUMENT_INDEX].lamports());
|
||||
assert_eq!(accounts[ARGUMENT_INDEX].lamports(), 42 - 5 + 1 + 1);
|
||||
assert_eq!(accounts[INVOKED_ARGUMENT_INDEX].lamports(), 10 + 5 - 1 - 1);
|
||||
assert_eq!(accounts[ARGUMENT_INDEX].lamports(), 42 - 5 + 1 + 1 + 1 + 1);
|
||||
assert_eq!(
|
||||
accounts[INVOKED_ARGUMENT_INDEX].lamports(),
|
||||
10 + 5 - 1 - 1 - 1 - 1
|
||||
);
|
||||
}
|
||||
|
||||
info!("Verify data values are retained and updated");
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
//! @brief Example Rust-based BPF program that issues a cross-program-invocation
|
||||
|
||||
use crate::instruction::*;
|
||||
use solana_sdk::entrypoint;
|
||||
use solana_sdk::{
|
||||
account_info::AccountInfo, bpf_loader, entrypoint::ProgramResult, info, program::invoke,
|
||||
program_error::ProgramError, pubkey::Pubkey,
|
||||
account_info::AccountInfo,
|
||||
bpf_loader, entrypoint,
|
||||
entrypoint::ProgramResult,
|
||||
info,
|
||||
program::{invoke, invoke_signed},
|
||||
program_error::ProgramError,
|
||||
pubkey::Pubkey,
|
||||
};
|
||||
|
||||
entrypoint!(process_instruction);
|
||||
|
@ -105,6 +109,7 @@ fn process_instruction(
|
|||
}
|
||||
TEST_DERIVED_SIGNERS => {
|
||||
info!("verify derived signers");
|
||||
const INVOKED_PROGRAM_INDEX: usize = 0;
|
||||
const DERIVED_KEY1_INDEX: usize = 1;
|
||||
const DERIVED_KEY2_INDEX: usize = 2;
|
||||
const DERIVED_KEY3_INDEX: usize = 3;
|
||||
|
@ -112,6 +117,26 @@ fn process_instruction(
|
|||
assert!(accounts[DERIVED_KEY1_INDEX].is_signer);
|
||||
assert!(!accounts[DERIVED_KEY2_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 => {
|
||||
info!("verify nested derived signers");
|
||||
|
|
|
@ -483,9 +483,9 @@ fn test_program_bpf_invoke() {
|
|||
let (derived_key1, nonce1) =
|
||||
Pubkey::find_program_address(&[b"You pass butter"], &invoke_program_id);
|
||||
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) =
|
||||
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 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(),
|
||||
]
|
||||
);
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ use solana_rbpf::{
|
|||
vm::{EbpfVm, Executable, InstructionMeter},
|
||||
};
|
||||
use solana_runtime::{
|
||||
feature_set::compute_budget_config2,
|
||||
feature_set::compute_budget_balancing,
|
||||
process_instruction::{ComputeMeter, Executor, InvokeContext},
|
||||
};
|
||||
use solana_sdk::{
|
||||
|
@ -101,7 +101,7 @@ pub fn create_and_cache_executor(
|
|||
.map_err(|e| map_ebpf_error(invoke_context, e))?;
|
||||
bpf_verifier::check(
|
||||
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)))?;
|
||||
let executor = Arc::new(BPFExecutor { executable });
|
||||
|
|
|
@ -33,7 +33,7 @@ pub mod bpf_loader2_program {
|
|||
solana_sdk::declare_id!("DFBnrgThdzH4W6wZ12uGPoWcMnvfZj11EHnxHcVxLPhD");
|
||||
}
|
||||
|
||||
pub mod compute_budget_config2 {
|
||||
pub mod compute_budget_balancing {
|
||||
solana_sdk::declare_id!("HxvjqDSiF5sYdSYuCXsUnS8UeAoWsMT9iGoFP8pgV1mB");
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,10 @@ pub mod ristretto_mul_syscall_enabled {
|
|||
solana_sdk::declare_id!("HRe7A6aoxgjKzdjbBv6HTy7tJ4YWqE6tVmYCGho6S9Aq");
|
||||
}
|
||||
|
||||
pub mod max_invoke_depth_4 {
|
||||
solana_sdk::declare_id!("EdM9xggY5y7AhNMskRG8NgGMnaP4JFNsWi8ZZtyT1af5");
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// Map of feature identifiers to user-visible description
|
||||
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
|
||||
|
@ -59,10 +63,11 @@ lazy_static! {
|
|||
(inflation_kill_switch::id(), "inflation kill switch"),
|
||||
(spl_token_v2_multisig_fix::id(), "spl-token multisig fix"),
|
||||
(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"),
|
||||
(no_overflow_rent_distribution::id(), "no overflow rent distribution"),
|
||||
(ristretto_mul_syscall_enabled::id(), "ristretto multiply syscall"),
|
||||
(max_invoke_depth_4::id(), "max invoke call depth 4"),
|
||||
/*************** ADD NEW FEATURES HERE ***************/
|
||||
]
|
||||
.iter()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
feature_set::{compute_budget_config2, instructions_sysvar_enabled, FeatureSet},
|
||||
feature_set::{instructions_sysvar_enabled, FeatureSet},
|
||||
instruction_recorder::InstructionRecorder,
|
||||
log_collector::LogCollector,
|
||||
native_loader::NativeLoader,
|
||||
|
@ -244,7 +244,7 @@ impl ThisInvokeContext {
|
|||
}
|
||||
impl InvokeContext for ThisInvokeContext {
|
||||
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);
|
||||
}
|
||||
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 {
|
||||
if feature_set.is_active(&compute_budget_config2::id()) {
|
||||
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,
|
||||
}
|
||||
}
|
||||
ComputeBudget::new(feature_set)
|
||||
}
|
||||
|
||||
/// Create the KeyedAccounts that will be passed to the program
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::feature_set::{compute_budget_balancing, max_invoke_depth_4, FeatureSet};
|
||||
use solana_sdk::{
|
||||
account::{Account, KeyedAccount},
|
||||
instruction::{CompiledInstruction, Instruction, InstructionError},
|
||||
|
@ -94,17 +95,42 @@ pub struct ComputeBudget {
|
|||
}
|
||||
impl Default for ComputeBudget {
|
||||
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 {
|
||||
max_units: 200_000,
|
||||
log_units: 100,
|
||||
log_64_units: 100,
|
||||
create_program_address_units: 1500,
|
||||
invoke_units: 1000,
|
||||
max_invoke_depth: 2,
|
||||
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,
|
||||
log_units: 100,
|
||||
log_64_units: 100,
|
||||
create_program_address_units: 1500,
|
||||
invoke_units: 1000,
|
||||
..compute_budget
|
||||
};
|
||||
}
|
||||
if feature_set.is_active(&max_invoke_depth_4::id()) {
|
||||
compute_budget = ComputeBudget {
|
||||
max_invoke_depth: 4,
|
||||
..compute_budget
|
||||
}
|
||||
}
|
||||
|
||||
compute_budget
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue