The constraints on compute power a program can consume is limited only to its instruction count (#11717)

This commit is contained in:
Jack May
2020-08-21 15:31:19 -07:00
committed by GitHub
parent 418b483af6
commit 8d362f682b
17 changed files with 350 additions and 137 deletions

View File

@ -1983,9 +1983,9 @@ dependencies = [
[[package]]
name = "solana_rbpf"
version = "0.1.28"
version = "0.1.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a556eca8a56761a16d712ed3e62a420da220f43749237befac3e4bf820f939c"
checksum = "185f68b54660652e2244bbdef792b369f12045da856a4af75b776e6e72757831"
dependencies = [
"byteorder 1.3.4",
"combine",

View File

@ -26,7 +26,7 @@ solana-bpf-loader-program = { path = "../bpf_loader", version = "1.4.0" }
solana-logger = { path = "../../logger", version = "1.4.0" }
solana-runtime = { path = "../../runtime", version = "1.4.0" }
solana-sdk = { path = "../../sdk", version = "1.4.0" }
solana_rbpf = "=0.1.28"
solana_rbpf = "=0.1.30"
[[bench]]
name = "bpf_loader"

View File

@ -6,7 +6,7 @@ use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};
use solana_rbpf::EbpfVm;
use solana_sdk::{
account::Account,
entrypoint_native::{InvokeContext, Logger, ProcessInstruction},
entrypoint_native::{ComputeMeter, InvokeContext, Logger, ProcessInstruction},
instruction::{CompiledInstruction, InstructionError},
message::Message,
pubkey::Pubkey,
@ -96,7 +96,7 @@ fn bench_program_alu(bencher: &mut Bencher) {
bencher.iter(|| {
vm.execute_program(&mut inner_iter, &[], &[]).unwrap();
});
let instructions = vm.get_last_instruction_count();
let instructions = vm.get_total_instruction_count();
let summary = bencher.bench(|_bencher| {}).unwrap();
println!(" {:?} instructions", instructions);
println!(" {:?} ns/iter median", summary.median as u64);
@ -136,6 +136,7 @@ fn bench_program_alu(bencher: &mut Bencher) {
pub struct MockInvokeContext {
key: Pubkey,
mock_logger: MockLogger,
mock_compute_meter: MockComputeMeter,
}
impl InvokeContext for MockInvokeContext {
fn push(&mut self, _key: &Pubkey) -> Result<(), InstructionError> {
@ -162,6 +163,9 @@ impl InvokeContext for MockInvokeContext {
fn is_cross_program_supported(&self) -> bool {
true
}
fn get_compute_meter(&self) -> Rc<RefCell<dyn ComputeMeter>> {
Rc::new(RefCell::new(self.mock_compute_meter.clone()))
}
}
#[derive(Debug, Default, Clone)]
pub struct MockLogger {
@ -175,3 +179,19 @@ impl Logger for MockLogger {
self.log.borrow_mut().push(message.to_string());
}
}
#[derive(Debug, Default, Clone)]
pub struct MockComputeMeter {
pub remaining: u64,
}
impl ComputeMeter for MockComputeMeter {
fn consume(&mut self, amount: u64) -> Result<(), InstructionError> {
self.remaining = self.remaining.saturating_sub(amount);
if self.remaining == 0 {
return Err(InstructionError::ComputationalBudgetExceeded);
}
Ok(())
}
fn get_remaining(&self) -> u64 {
self.remaining
}
}

View File

@ -165,6 +165,33 @@ 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[] = {

View File

@ -97,31 +97,6 @@ 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;
}

View File

@ -163,6 +163,24 @@ 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");
@ -188,8 +206,6 @@ 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],
);
@ -197,11 +213,9 @@ fn process_instruction(
info!("2nd invoke from first program");
invoke(&instruction, accounts)?;
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!(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);
}
info!("Verify data values are retained and updated");

View File

@ -8,13 +8,8 @@ extern crate solana_sdk;
use crate::instruction::*;
use solana_sdk::{
account_info::AccountInfo,
bpf_loader, entrypoint,
entrypoint::ProgramResult,
info,
program::{invoke, invoke_signed},
program_error::ProgramError,
pubkey::Pubkey,
account_info::AccountInfo, bpf_loader, entrypoint, entrypoint::ProgramResult, info,
program::invoke, program_error::ProgramError, pubkey::Pubkey,
};
entrypoint!(process_instruction);
@ -111,7 +106,6 @@ 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;
@ -119,26 +113,6 @@ 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");

View File

@ -360,9 +360,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"], &invoked_program_id);
Pubkey::find_program_address(&[b"Lil'", b"Bits"], &invoke_program_id);
let (derived_key3, nonce3) =
Pubkey::find_program_address(&[derived_key2.as_ref()], &invoked_program_id);
Pubkey::find_program_address(&[derived_key2.as_ref()], &invoke_program_id);
let mint_pubkey = mint_keypair.pubkey();
let account_metas = vec![