diff --git a/Cargo.lock b/Cargo.lock index ad07c9760c..3bf7312ccf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4707,6 +4707,7 @@ dependencies = [ name = "solana-compute-budget-program" version = "1.9.0" dependencies = [ + "solana-program-runtime", "solana-sdk", ] @@ -5440,7 +5441,9 @@ dependencies = [ name = "solana-program-runtime" version = "1.9.0" dependencies = [ + "base64 0.13.0", "bincode", + "itertools 0.10.1", "libc", "libloading", "log 0.4.14", diff --git a/program-runtime/Cargo.toml b/program-runtime/Cargo.toml index afcacaf148..0798e60c1a 100644 --- a/program-runtime/Cargo.toml +++ b/program-runtime/Cargo.toml @@ -10,7 +10,9 @@ documentation = "https://docs.rs/solana-program-runtime" edition = "2018" [dependencies] +base64 = "0.13" bincode = "1.3.3" +itertools = "0.10.1" libc = "0.2.101" libloading = "0.7.0" log = "0.4.14" diff --git a/program-runtime/src/instruction_processor.rs b/program-runtime/src/instruction_processor.rs index 2423a6f1d0..95e3804a16 100644 --- a/program-runtime/src/instruction_processor.rs +++ b/program-runtime/src/instruction_processor.rs @@ -1,15 +1,17 @@ -use crate::native_loader::NativeLoader; +use crate::{ + ic_msg, + invoke_context::{InvokeContext, ProcessInstructionWithContext}, + native_loader::NativeLoader, +}; use serde::{Deserialize, Serialize}; use solana_sdk::{ account::{AccountSharedData, ReadableAccount, WritableAccount}, account_utils::StateMut, bpf_loader_upgradeable::{self, UpgradeableLoaderState}, feature_set::{demote_program_write_locks, do_support_realloc, remove_native_loader}, - ic_msg, instruction::{Instruction, InstructionError}, keyed_account::keyed_account_at_index, message::Message, - process_instruction::{Executor, InvokeContext, ProcessInstructionWithContext}, pubkey::Pubkey, rent::Rent, system_instruction::MAX_PERMITTED_DATA_LENGTH, @@ -18,10 +20,23 @@ use solana_sdk::{ use std::{ cell::{Ref, RefCell, RefMut}, collections::HashMap, + fmt::Debug, rc::Rc, sync::Arc, }; +/// Program executor +pub trait Executor: Debug + Send + Sync { + /// Execute the program + fn execute( + &self, + first_instruction_account: usize, + instruction_data: &[u8], + invoke_context: &mut dyn InvokeContext, + use_jit: bool, + ) -> Result<(), InstructionError>; +} + #[derive(Default)] pub struct Executors { pub executors: HashMap>, diff --git a/program-runtime/src/invoke_context.rs b/program-runtime/src/invoke_context.rs index eb7a7fdd94..5868e3cc11 100644 --- a/program-runtime/src/invoke_context.rs +++ b/program-runtime/src/invoke_context.rs @@ -1,5 +1,6 @@ use crate::{ - instruction_processor::{ExecuteDetailsTimings, Executors, PreAccount}, + ic_logger_msg, ic_msg, + instruction_processor::{ExecuteDetailsTimings, Executor, Executors, PreAccount}, instruction_recorder::InstructionRecorder, log_collector::LogCollector, }; @@ -12,19 +13,23 @@ use solana_sdk::{ remove_native_loader, requestable_heap_size, tx_wide_compute_cap, FeatureSet, }, hash::Hash, - ic_logger_msg, ic_msg, instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError}, keyed_account::{create_keyed_accounts_unified, KeyedAccount}, message::Message, - process_instruction::{ - ComputeMeter, Executor, InvokeContext, Logger, ProcessInstructionWithContext, - }, pubkey::Pubkey, rent::Rent, sysvar::Sysvar, }; use std::{cell::RefCell, rc::Rc, sync::Arc}; +/// Compute meter +pub trait ComputeMeter { + /// Consume compute units + fn consume(&mut self, amount: u64) -> Result<(), InstructionError>; + /// Get the number of remaining compute units + fn get_remaining(&self) -> u64; +} + pub struct ThisComputeMeter { remaining: u64, } @@ -47,6 +52,17 @@ impl ThisComputeMeter { } } +/// Log messages +pub trait Logger { + fn log_enabled(&self) -> bool; + + /// Log a message. + /// + /// Unless explicitly stated, log messages are not considered stable and may change in the + /// future as necessary + fn log(&self, message: &str); +} + pub struct ThisLogger { log_collector: Option>, } @@ -67,6 +83,36 @@ impl ThisLogger { } } +/// Convenience macro to log a message with an `Rc>` +#[macro_export] +macro_rules! ic_logger_msg { + ($logger:expr, $message:expr) => { + if let Ok(logger) = $logger.try_borrow_mut() { + if logger.log_enabled() { + logger.log($message); + } + } + }; + ($logger:expr, $fmt:expr, $($arg:tt)*) => { + if let Ok(logger) = $logger.try_borrow_mut() { + if logger.log_enabled() { + logger.log(&format!($fmt, $($arg)*)); + } + } + }; +} + +/// Convenience macro to log a message with an `InvokeContext` +#[macro_export] +macro_rules! ic_msg { + ($invoke_context:expr, $message:expr) => { + $crate::ic_logger_msg!($invoke_context.get_logger(), $message) + }; + ($invoke_context:expr, $fmt:expr, $($arg:tt)*) => { + $crate::ic_logger_msg!($invoke_context.get_logger(), $fmt, $($arg)*) + }; +} + pub struct InvokeContextStackFrame<'a> { pub number_of_program_accounts: usize, pub keyed_accounts: Vec>, @@ -185,6 +231,90 @@ impl<'a> ThisInvokeContext<'a> { ) } } + +/// Invocation context passed to loaders +pub trait InvokeContext { + /// Push a stack frame onto the invocation stack + fn push( + &mut self, + message: &Message, + instruction: &CompiledInstruction, + program_indices: &[usize], + account_indices: Option<&[usize]>, + ) -> Result<(), InstructionError>; + /// Pop a stack frame from the invocation stack + fn pop(&mut self); + /// Current depth of the invocation stake + fn invoke_depth(&self) -> usize; + /// Verify the results of an instruction + fn verify( + &mut self, + message: &Message, + instruction: &CompiledInstruction, + program_indices: &[usize], + ) -> Result<(), InstructionError>; + /// Verify and update PreAccount state based on program execution + fn verify_and_update( + &mut self, + instruction: &CompiledInstruction, + account_indices: &[usize], + write_privileges: &[bool], + ) -> Result<(), InstructionError>; + /// Get the program ID of the currently executing program + fn get_caller(&self) -> Result<&Pubkey, InstructionError>; + /// Removes the first keyed account + #[deprecated( + since = "1.9.0", + note = "To be removed together with remove_native_loader" + )] + fn remove_first_keyed_account(&mut self) -> Result<(), InstructionError>; + /// Get the list of keyed accounts + fn get_keyed_accounts(&self) -> Result<&[KeyedAccount], InstructionError>; + /// Get a list of built-in programs + fn get_programs(&self) -> &[(Pubkey, ProcessInstructionWithContext)]; + /// Get this invocation's logger + fn get_logger(&self) -> Rc>; + /// Get this invocation's compute meter + fn get_compute_meter(&self) -> Rc>; + /// Loaders may need to do work in order to execute a program. Cache + /// the work that can be re-used across executions + fn add_executor(&self, pubkey: &Pubkey, executor: Arc); + /// Get the completed loader work that can be re-used across executions + fn get_executor(&self, pubkey: &Pubkey) -> Option>; + /// Set which instruction in the message is currently being recorded + fn set_instruction_index(&mut self, instruction_index: usize); + /// Record invoked instruction + fn record_instruction(&self, instruction: &Instruction); + /// Get the bank's active feature set + fn is_feature_active(&self, feature_id: &Pubkey) -> bool; + /// Find an account_index and account by its key + fn get_account(&self, pubkey: &Pubkey) -> Option<(usize, Rc>)>; + /// Update timing + fn update_timing( + &mut self, + serialize_us: u64, + create_vm_us: u64, + execute_us: u64, + deserialize_us: u64, + ); + /// Get sysvars + fn get_sysvars(&self) -> &[(Pubkey, Vec)]; + /// Get this invocation's compute budget + fn get_compute_budget(&self) -> &ComputeBudget; + /// Set this invocation's blockhash + fn set_blockhash(&mut self, hash: Hash); + /// Get this invocation's blockhash + fn get_blockhash(&self) -> &Hash; + /// Set this invocation's lamports_per_signature value + fn set_lamports_per_signature(&mut self, lamports_per_signature: u64); + /// Get this invocation's lamports_per_signature value + fn get_lamports_per_signature(&self) -> u64; + /// Set the return data + fn set_return_data(&mut self, data: Vec) -> Result<(), InstructionError>; + /// Get the return data + fn get_return_data(&self) -> (Pubkey, &[u8]); +} + impl<'a> InvokeContext for ThisInvokeContext<'a> { fn push( &mut self, @@ -552,6 +682,9 @@ pub fn get_sysvar( }) } +pub type ProcessInstructionWithContext = + fn(usize, &[u8], &mut dyn InvokeContext) -> Result<(), InstructionError>; + pub struct MockInvokeContextPreparation { pub accounts: Vec<(Pubkey, Rc>)>, pub message: Message, diff --git a/program-runtime/src/lib.rs b/program-runtime/src/lib.rs index 94a1005ab6..46eafcea95 100644 --- a/program-runtime/src/lib.rs +++ b/program-runtime/src/lib.rs @@ -6,3 +6,4 @@ pub mod invoke_context; pub mod log_collector; pub mod native_loader; pub mod neon_evm_program; +pub mod stable_log; diff --git a/program-runtime/src/native_loader.rs b/program-runtime/src/native_loader.rs index 96c179734d..659148b4bb 100644 --- a/program-runtime/src/native_loader.rs +++ b/program-runtime/src/native_loader.rs @@ -1,4 +1,5 @@ //! Native loader +use crate::invoke_context::InvokeContext; #[cfg(unix)] use libloading::os::unix::*; #[cfg(windows)] @@ -12,7 +13,6 @@ use solana_sdk::{ instruction::InstructionError, keyed_account::{keyed_account_at_index, KeyedAccount}, native_loader, - process_instruction::InvokeContext, pubkey::Pubkey, }; use std::{ diff --git a/program-runtime/src/stable_log.rs b/program-runtime/src/stable_log.rs new file mode 100644 index 0000000000..f49170a5ce --- /dev/null +++ b/program-runtime/src/stable_log.rs @@ -0,0 +1,94 @@ +//! Stable program log messages +//! +//! The format of these log messages should not be modified to avoid breaking downstream consumers +//! of program logging +use crate::{ic_logger_msg, invoke_context::Logger}; +use itertools::Itertools; +use solana_sdk::{instruction::InstructionError, pubkey::Pubkey}; +use std::{cell::RefCell, rc::Rc}; + +/// Log a program invoke. +/// +/// The general form is: +/// +/// ```notrust +/// "Program
invoke []" +/// ``` +pub fn program_invoke(logger: &Rc>, program_id: &Pubkey, invoke_depth: usize) { + ic_logger_msg!(logger, "Program {} invoke [{}]", program_id, invoke_depth); +} + +/// Log a message from the program itself. +/// +/// The general form is: +/// +/// ```notrust +/// "Program log: " +/// ``` +/// +/// That is, any program-generated output is guaranteed to be prefixed by "Program log: " +pub fn program_log(logger: &Rc>, message: &str) { + ic_logger_msg!(logger, "Program log: {}", message); +} + +/// Emit a program data. +/// +/// The general form is: +/// +/// ```notrust +/// "Program data: *" +/// ``` +/// +/// That is, any program-generated output is guaranteed to be prefixed by "Program data: " +pub fn program_data(logger: &Rc>, data: &[&[u8]]) { + ic_logger_msg!( + logger, + "Program data: {}", + data.iter().map(base64::encode).join(" ") + ); +} + +/// Log return data as from the program itself. This line will not be present if no return +/// data was set, or if the return data was set to zero length. +/// +/// The general form is: +/// +/// ```notrust +/// "Program return: " +/// ``` +/// +/// That is, any program-generated output is guaranteed to be prefixed by "Program return: " +pub fn program_return(logger: &Rc>, program_id: &Pubkey, data: &[u8]) { + ic_logger_msg!( + logger, + "Program return: {} {}", + program_id, + base64::encode(data) + ); +} + +/// Log successful program execution. +/// +/// The general form is: +/// +/// ```notrust +/// "Program
success" +/// ``` +pub fn program_success(logger: &Rc>, program_id: &Pubkey) { + ic_logger_msg!(logger, "Program {} success", program_id); +} + +/// Log program execution failure +/// +/// The general form is: +/// +/// ```notrust +/// "Program
failed: " +/// ``` +pub fn program_failure( + logger: &Rc>, + program_id: &Pubkey, + err: &InstructionError, +) { + ic_logger_msg!(logger, "Program {} failed: {}", program_id, err); +} diff --git a/program-test/src/lib.rs b/program-test/src/lib.rs index 88d222cee7..600dc0476a 100644 --- a/program-test/src/lib.rs +++ b/program-test/src/lib.rs @@ -9,7 +9,10 @@ use { log::*, solana_banks_client::start_client, solana_banks_server::banks_server::start_local_server, - solana_program_runtime::instruction_processor::InstructionProcessor, + solana_program_runtime::{ + instruction_processor::InstructionProcessor, invoke_context::ProcessInstructionWithContext, + stable_log, + }, solana_runtime::{ bank::{Bank, ExecuteTimings}, bank_forks::BankForks, @@ -33,7 +36,6 @@ use { message::Message, native_token::sol_to_lamports, poh_config::PohConfig, - process_instruction::{stable_log, InvokeContext, ProcessInstructionWithContext}, program_error::{ProgramError, ACCOUNT_BORROW_FAILED, UNSUPPORTED_SYSVAR}, pubkey::Pubkey, rent::Rent, @@ -66,6 +68,7 @@ use { // Export types so test clients can limit their solana crate dependencies pub use solana_banks_client::BanksClient; +pub use solana_program_runtime::invoke_context::InvokeContext; // Export tokio for test clients pub use tokio; @@ -187,7 +190,7 @@ macro_rules! processor { Some( |first_instruction_account: usize, input: &[u8], - invoke_context: &mut dyn solana_sdk::process_instruction::InvokeContext| { + invoke_context: &mut dyn solana_program_test::InvokeContext| { $crate::builtin_process_instruction( $process_instruction, first_instruction_account, diff --git a/programs/bpf/Cargo.lock b/programs/bpf/Cargo.lock index 1a74bc1f42..a40f394124 100644 --- a/programs/bpf/Cargo.lock +++ b/programs/bpf/Cargo.lock @@ -2795,6 +2795,7 @@ name = "solana-bpf-rust-mem" version = "1.9.0" dependencies = [ "solana-program 1.9.0", + "solana-program-runtime", "solana-program-test", "solana-sdk", ] @@ -2879,6 +2880,7 @@ name = "solana-bpf-rust-sanity" version = "1.9.0" dependencies = [ "solana-program 1.9.0", + "solana-program-runtime", "solana-program-test", "solana-sdk", ] @@ -2917,6 +2919,7 @@ name = "solana-bpf-rust-sysvar" version = "1.9.0" dependencies = [ "solana-program 1.9.0", + "solana-program-runtime", "solana-program-test", "solana-sdk", ] @@ -3036,6 +3039,7 @@ dependencies = [ name = "solana-compute-budget-program" version = "1.9.0" dependencies = [ + "solana-program-runtime", "solana-sdk", ] @@ -3047,6 +3051,7 @@ dependencies = [ "chrono", "serde", "serde_derive", + "solana-program-runtime", "solana-sdk", ] @@ -3310,7 +3315,9 @@ dependencies = [ name = "solana-program-runtime" version = "1.9.0" dependencies = [ + "base64 0.13.0", "bincode", + "itertools 0.10.1", "libc", "libloading", "log", @@ -3578,6 +3585,7 @@ dependencies = [ "solana-frozen-abi-macro 1.9.0", "solana-logger 1.9.0", "solana-metrics", + "solana-program-runtime", "solana-sdk", "thiserror", ] diff --git a/programs/bpf/benches/bpf_loader.rs b/programs/bpf/benches/bpf_loader.rs index 5826338e4a..05fa85e090 100644 --- a/programs/bpf/benches/bpf_loader.rs +++ b/programs/bpf/benches/bpf_loader.rs @@ -18,14 +18,13 @@ use solana_runtime::{ genesis_utils::{create_genesis_config, GenesisConfigInfo}, loader_utils::load_program, }; -use solana_program_runtime::invoke_context::with_mock_invoke_context; +use solana_program_runtime::invoke_context::{with_mock_invoke_context, InvokeContext}; use solana_sdk::{ bpf_loader, client::SyncClient, entrypoint::SUCCESS, instruction::{AccountMeta, Instruction}, message::Message, - process_instruction::InvokeContext, pubkey::Pubkey, signature::{Keypair, Signer}, }; diff --git a/programs/bpf/rust/mem/Cargo.toml b/programs/bpf/rust/mem/Cargo.toml index 8fe9bef014..9c73e09e3a 100644 --- a/programs/bpf/rust/mem/Cargo.toml +++ b/programs/bpf/rust/mem/Cargo.toml @@ -16,6 +16,7 @@ no-entrypoint = [] solana-program = { path = "../../../../sdk/program", version = "=1.9.0" } [dev-dependencies] +solana-program-runtime = { path = "../../../../program-runtime", version = "=1.9.0" } solana-program-test = { path = "../../../../program-test", version = "=1.9.0" } solana-sdk = { path = "../../../../sdk", version = "=1.9.0" } diff --git a/programs/bpf/rust/sanity/Cargo.toml b/programs/bpf/rust/sanity/Cargo.toml index 09ea17efba..c008be80b1 100644 --- a/programs/bpf/rust/sanity/Cargo.toml +++ b/programs/bpf/rust/sanity/Cargo.toml @@ -16,6 +16,7 @@ test-bpf = [] solana-program = { path = "../../../../sdk/program", version = "=1.9.0" } [dev-dependencies] +solana-program-runtime = { path = "../../../../program-runtime", version = "=1.9.0" } solana-program-test = { path = "../../../../program-test", version = "=1.9.0" } solana-sdk = { path = "../../../../sdk", version = "=1.9.0" } diff --git a/programs/bpf/rust/sysvar/Cargo.toml b/programs/bpf/rust/sysvar/Cargo.toml index 23c21703d0..8b18e2fcc4 100644 --- a/programs/bpf/rust/sysvar/Cargo.toml +++ b/programs/bpf/rust/sysvar/Cargo.toml @@ -13,6 +13,7 @@ edition = "2018" solana-program = { path = "../../../../sdk/program", version = "=1.9.0" } [dev-dependencies] +solana-program-runtime = { path = "../../../../program-runtime", version = "=1.9.0" } solana-program-test = { path = "../../../../program-test", version = "=1.9.0" } solana-sdk = { path = "../../../../sdk", version = "=1.9.0" } diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index f3c1fb1470..51d820bc60 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -31,7 +31,7 @@ use solana_runtime::{ upgrade_program, }, }; -use solana_program_runtime::invoke_context::with_mock_invoke_context; +use solana_program_runtime::invoke_context::{with_mock_invoke_context, InvokeContext}; use solana_sdk::{ account::{AccountSharedData, ReadableAccount}, account_utils::StateMut, @@ -43,7 +43,6 @@ use solana_sdk::{ instruction::{AccountMeta, CompiledInstruction, Instruction, InstructionError}, loader_instruction, message::{Message, SanitizedMessage}, - process_instruction::InvokeContext, pubkey::Pubkey, signature::{keypair_from_seed, Keypair, Signer}, system_instruction::{self, MAX_PERMITTED_DATA_LENGTH}, diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index b03107965c..0a78fa67b5 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -14,7 +14,12 @@ use crate::{ }; use log::{log_enabled, trace, Level::Trace}; use solana_measure::measure::Measure; -use solana_program_runtime::instruction_processor::InstructionProcessor; +use solana_program_runtime::{ + ic_logger_msg, ic_msg, + instruction_processor::{Executor, InstructionProcessor}, + invoke_context::{ComputeMeter, InvokeContext, Logger}, + stable_log, +}; use solana_rbpf::{ aligned_memory::AlignedMemory, ebpf::HOST_ALIGN, @@ -35,12 +40,10 @@ use solana_sdk::{ reject_deployment_of_unresolved_syscalls, requestable_heap_size, stop_verify_mul64_imm_nonzero, }, - ic_logger_msg, ic_msg, instruction::{AccountMeta, InstructionError}, keyed_account::{from_keyed_account, keyed_account_at_index, KeyedAccount}, loader_instruction::LoaderInstruction, loader_upgradeable_instruction::UpgradeableLoaderInstruction, - process_instruction::{stable_log, ComputeMeter, Executor, InvokeContext, Logger}, program_utils::limited_deserialize, pubkey::Pubkey, rent::Rent, diff --git a/programs/bpf_loader/src/serialization.rs b/programs/bpf_loader/src/serialization.rs index cf994d132d..d9aeae6302 100644 --- a/programs/bpf_loader/src/serialization.rs +++ b/programs/bpf_loader/src/serialization.rs @@ -316,13 +316,14 @@ pub fn deserialize_parameters_aligned( #[cfg(test)] mod tests { use super::*; - use solana_program_runtime::invoke_context::{prepare_mock_invoke_context, ThisInvokeContext}; + use solana_program_runtime::invoke_context::{ + prepare_mock_invoke_context, InvokeContext, ThisInvokeContext, + }; use solana_sdk::{ account::{Account, AccountSharedData}, account_info::AccountInfo, bpf_loader, entrypoint::deserialize, - process_instruction::InvokeContext, }; use std::{ cell::RefCell, diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index 6d5a050ca2..0b07a3b0c4 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -1,6 +1,11 @@ use crate::{alloc, BpfError}; use alloc::Alloc; -use solana_program_runtime::instruction_processor::InstructionProcessor; +use solana_program_runtime::{ + ic_msg, + instruction_processor::InstructionProcessor, + invoke_context::{ComputeMeter, InvokeContext, Logger}, + stable_log, +}; use solana_rbpf::{ aligned_memory::AlignedMemory, ebpf, @@ -25,13 +30,11 @@ use solana_sdk::{ secp256k1_recover_syscall_enabled, sol_log_data_syscall_enabled, }, hash::{Hasher, HASH_BYTES}, - ic_msg, instruction::{AccountMeta, Instruction, InstructionError}, keccak, message::Message, native_loader, precompiles::is_precompile, - process_instruction::{stable_log, ComputeMeter, InvokeContext, Logger}, program::MAX_RETURN_DATA, pubkey::{Pubkey, PubkeyError, MAX_SEEDS, MAX_SEED_LEN}, rent::Rent, diff --git a/programs/compute-budget/Cargo.toml b/programs/compute-budget/Cargo.toml index 20bb02ffa3..744ae7cd4d 100644 --- a/programs/compute-budget/Cargo.toml +++ b/programs/compute-budget/Cargo.toml @@ -10,6 +10,7 @@ license = "Apache-2.0" edition = "2018" [dependencies] +solana-program-runtime = { path = "../../program-runtime", version = "=1.9.0" } solana-sdk = { path = "../../sdk", version = "=1.9.0" } [lib] diff --git a/programs/compute-budget/src/lib.rs b/programs/compute-budget/src/lib.rs index 6f74501f69..5e0573d74c 100644 --- a/programs/compute-budget/src/lib.rs +++ b/programs/compute-budget/src/lib.rs @@ -1,4 +1,5 @@ -use solana_sdk::{instruction::InstructionError, process_instruction::InvokeContext}; +use solana_program_runtime::invoke_context::InvokeContext; +use solana_sdk::instruction::InstructionError; pub fn process_instruction( _first_instruction_account: usize, diff --git a/programs/config/Cargo.toml b/programs/config/Cargo.toml index 6861b708e9..27bdb4c076 100644 --- a/programs/config/Cargo.toml +++ b/programs/config/Cargo.toml @@ -14,11 +14,11 @@ bincode = "1.3.3" chrono = { version = "0.4.11", features = ["serde"] } serde = "1.0.130" serde_derive = "1.0.103" +solana-program-runtime = { path = "../../program-runtime", version = "=1.9.0" } solana-sdk = { path = "../../sdk", version = "=1.9.0" } [dev-dependencies] solana-logger = { path = "../../logger", version = "=1.9.0" } -solana-program-runtime = { path = "../../program-runtime", version = "=1.9.0" } [lib] crate-type = ["lib"] diff --git a/programs/config/src/config_processor.rs b/programs/config/src/config_processor.rs index 1cf2a753c2..60a28e8ef9 100644 --- a/programs/config/src/config_processor.rs +++ b/programs/config/src/config_processor.rs @@ -2,12 +2,12 @@ use crate::ConfigKeys; use bincode::deserialize; +use solana_program_runtime::{ic_msg, invoke_context::InvokeContext}; use solana_sdk::{ account::{ReadableAccount, WritableAccount}, - feature_set, ic_msg, + feature_set, instruction::InstructionError, keyed_account::keyed_account_at_index, - process_instruction::InvokeContext, program_utils::limited_deserialize, pubkey::Pubkey, }; diff --git a/programs/stake/Cargo.toml b/programs/stake/Cargo.toml index 5aced68478..4282365a17 100644 --- a/programs/stake/Cargo.toml +++ b/programs/stake/Cargo.toml @@ -19,8 +19,8 @@ serde_derive = "1.0.103" solana-frozen-abi = { path = "../../frozen-abi", version = "=1.9.0" } solana-frozen-abi-macro = { path = "../../frozen-abi/macro", version = "=1.9.0" } solana-metrics = { path = "../../metrics", version = "=1.9.0" } -solana-sdk = { path = "../../sdk", version = "=1.9.0" } solana-program-runtime = { path = "../../program-runtime", version = "=1.9.0" } +solana-sdk = { path = "../../sdk", version = "=1.9.0" } solana-vote-program = { path = "../vote", version = "=1.9.0" } solana-config-program = { path = "../config", version = "=1.9.0" } thiserror = "1.0" diff --git a/programs/stake/src/stake_instruction.rs b/programs/stake/src/stake_instruction.rs index e87d829039..25c50a1a4a 100644 --- a/programs/stake/src/stake_instruction.rs +++ b/programs/stake/src/stake_instruction.rs @@ -1,12 +1,11 @@ use { crate::{config, stake_state::StakeAccount}, log::*, - solana_program_runtime::invoke_context::get_sysvar, + solana_program_runtime::invoke_context::{get_sysvar, InvokeContext}, solana_sdk::{ feature_set, instruction::InstructionError, keyed_account::{from_keyed_account, get_signers, keyed_account_at_index}, - process_instruction::InvokeContext, program_utils::limited_deserialize, stake::{ instruction::StakeInstruction, diff --git a/programs/stake/src/stake_state.rs b/programs/stake/src/stake_state.rs index e6be6fce59..4407f6ab52 100644 --- a/programs/stake/src/stake_state.rs +++ b/programs/stake/src/stake_state.rs @@ -4,15 +4,14 @@ //! * own mining pools use { + solana_program_runtime::{ic_msg, invoke_context::InvokeContext}, solana_sdk::{ account::{AccountSharedData, ReadableAccount, WritableAccount}, account_utils::{State, StateMut}, clock::{Clock, Epoch}, feature_set::stake_merge_with_unmatched_credits_observed, - ic_msg, instruction::{checked_add, InstructionError}, keyed_account::KeyedAccount, - process_instruction::InvokeContext, pubkey::Pubkey, rent::{Rent, ACCOUNT_STORAGE_OVERHEAD}, stake::{ diff --git a/programs/vote/Cargo.toml b/programs/vote/Cargo.toml index b8e00af3aa..ed36542dac 100644 --- a/programs/vote/Cargo.toml +++ b/programs/vote/Cargo.toml @@ -20,12 +20,10 @@ solana-frozen-abi = { path = "../../frozen-abi", version = "=1.9.0" } solana-frozen-abi-macro = { path = "../../frozen-abi/macro", version = "=1.9.0" } solana-logger = { path = "../../logger", version = "=1.9.0" } solana-metrics = { path = "../../metrics", version = "=1.9.0" } +solana-program-runtime = { path = "../../program-runtime", version = "=1.9.0" } solana-sdk = { path = "../../sdk", version = "=1.9.0" } thiserror = "1.0" -[dev-dependencies] -solana-program-runtime = { path = "../../program-runtime", version = "=1.9.0" } - [build-dependencies] rustc_version = "0.4" diff --git a/programs/vote/src/vote_instruction.rs b/programs/vote/src/vote_instruction.rs index 7f54f3a1d4..bed419b753 100644 --- a/programs/vote/src/vote_instruction.rs +++ b/programs/vote/src/vote_instruction.rs @@ -9,13 +9,13 @@ use log::*; use num_derive::{FromPrimitive, ToPrimitive}; use serde_derive::{Deserialize, Serialize}; use solana_metrics::inc_new_counter_info; +use solana_program_runtime::invoke_context::InvokeContext; use solana_sdk::{ decode_error::DecodeError, feature_set, hash::Hash, instruction::{AccountMeta, Instruction, InstructionError}, keyed_account::{from_keyed_account, get_signers, keyed_account_at_index, KeyedAccount}, - process_instruction::InvokeContext, program_utils::limited_deserialize, pubkey::Pubkey, system_instruction, diff --git a/rbpf-cli/src/main.rs b/rbpf-cli/src/main.rs index b693931dc2..63c7da8044 100644 --- a/rbpf-cli/src/main.rs +++ b/rbpf-cli/src/main.rs @@ -5,16 +5,16 @@ use solana_bpf_loader_program::{ create_vm, serialization::serialize_parameters, syscalls::register_syscalls, BpfError, ThisInstructionMeter, }; -use solana_program_runtime::invoke_context::{prepare_mock_invoke_context, ThisInvokeContext}; +use solana_program_runtime::invoke_context::{ + prepare_mock_invoke_context, InvokeContext, ThisInvokeContext, +}; use solana_rbpf::{ assembler::assemble, static_analysis::Analysis, verifier::check, vm::{Config, DynamicAnalysis, Executable}, }; -use solana_sdk::{ - account::AccountSharedData, bpf_loader, process_instruction::InvokeContext, pubkey::Pubkey, -}; +use solana_sdk::{account::AccountSharedData, bpf_loader, pubkey::Pubkey}; use std::{fs::File, io::Read, io::Seek, io::SeekFrom, path::Path}; use time::Instant; diff --git a/runtime/benches/bank.rs b/runtime/benches/bank.rs index 59fc61ab1f..61c38aeaaf 100644 --- a/runtime/benches/bank.rs +++ b/runtime/benches/bank.rs @@ -4,6 +4,7 @@ extern crate test; use log::*; +use solana_program_runtime::invoke_context::InvokeContext; use solana_runtime::{bank::*, bank_client::BankClient, loader_utils::create_invoke_instruction}; use solana_sdk::{ client::AsyncClient, @@ -12,7 +13,6 @@ use solana_sdk::{ genesis_config::create_genesis_config, instruction::InstructionError, message::Message, - process_instruction::InvokeContext, pubkey::Pubkey, signature::{Keypair, Signer}, transaction::Transaction, diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index c3a7a91561..44f575d2a6 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -70,8 +70,9 @@ use rayon::{ use solana_measure::measure::Measure; use solana_metrics::{inc_new_counter_debug, inc_new_counter_info}; use solana_program_runtime::{ - instruction_processor::{ExecuteDetailsTimings, Executors, InstructionProcessor}, + instruction_processor::{ExecuteDetailsTimings, Executor, Executors, InstructionProcessor}, instruction_recorder::InstructionRecorder, + invoke_context::{ComputeMeter, ProcessInstructionWithContext}, log_collector::LogCollector, }; #[allow(deprecated)] @@ -109,7 +110,6 @@ use solana_sdk::{ nonce, nonce_account, packet::PACKET_DATA_SIZE, precompiles::get_precompiles, - process_instruction::{ComputeMeter, Executor, ProcessInstructionWithContext}, program_utils::limited_deserialize, pubkey::Pubkey, secp256k1_program, @@ -6469,6 +6469,7 @@ pub(crate) mod tests { status_cache::MAX_CACHE_ENTRIES, }; use crossbeam_channel::{bounded, unbounded}; + use solana_program_runtime::invoke_context::InvokeContext; #[allow(deprecated)] use solana_sdk::sysvar::fees::Fees; use solana_sdk::{ @@ -6484,7 +6485,6 @@ pub(crate) mod tests { message::{Message, MessageHeader}, nonce, poh_config::PohConfig, - process_instruction::InvokeContext, rent::Rent, signature::{keypair_from_seed, Keypair, Signer}, stake::{ diff --git a/runtime/src/builtins.rs b/runtime/src/builtins.rs index 8e84df9f2d..ed3d178341 100644 --- a/runtime/src/builtins.rs +++ b/runtime/src/builtins.rs @@ -1,10 +1,10 @@ use crate::system_instruction_processor; +use solana_program_runtime::{ + invoke_context::{InvokeContext, ProcessInstructionWithContext}, + stable_log, +}; use solana_sdk::{ - feature_set, - instruction::InstructionError, - process_instruction::{stable_log, InvokeContext, ProcessInstructionWithContext}, - pubkey::Pubkey, - stake, system_program, + feature_set, instruction::InstructionError, pubkey::Pubkey, stake, system_program, }; use std::fmt; diff --git a/runtime/src/message_processor.rs b/runtime/src/message_processor.rs index 7e1d6204b4..d5a840e742 100644 --- a/runtime/src/message_processor.rs +++ b/runtime/src/message_processor.rs @@ -3,7 +3,7 @@ use solana_measure::measure::Measure; use solana_program_runtime::{ instruction_processor::{ExecuteDetailsTimings, Executors, InstructionProcessor}, instruction_recorder::InstructionRecorder, - invoke_context::ThisInvokeContext, + invoke_context::{ComputeMeter, InvokeContext, ThisInvokeContext}, log_collector::LogCollector, }; use solana_sdk::{ @@ -13,7 +13,6 @@ use solana_sdk::{ hash::Hash, message::Message, precompiles::is_precompile, - process_instruction::{ComputeMeter, InvokeContext}, pubkey::Pubkey, rent::Rent, sysvar::instructions, diff --git a/runtime/src/nonce_keyed_account.rs b/runtime/src/nonce_keyed_account.rs index 7f03fc0eb2..192a6b46f1 100644 --- a/runtime/src/nonce_keyed_account.rs +++ b/runtime/src/nonce_keyed_account.rs @@ -1,12 +1,11 @@ +use solana_program_runtime::{ic_msg, invoke_context::InvokeContext}; use solana_sdk::{ account::{ReadableAccount, WritableAccount}, account_utils::State as AccountUtilsState, feature_set::{self, nonce_must_be_writable}, - ic_msg, instruction::{checked_add, InstructionError}, keyed_account::KeyedAccount, nonce::{self, state::Versions, State}, - process_instruction::InvokeContext, pubkey::Pubkey, system_instruction::{nonce_to_instruction_error, NonceError}, sysvar::rent::Rent, diff --git a/runtime/src/system_instruction_processor.rs b/runtime/src/system_instruction_processor.rs index a0cc9dc594..5c11fa6911 100644 --- a/runtime/src/system_instruction_processor.rs +++ b/runtime/src/system_instruction_processor.rs @@ -1,13 +1,13 @@ use crate::nonce_keyed_account::NonceKeyedAccount; use log::*; +use solana_program_runtime::{ic_msg, invoke_context::InvokeContext}; use solana_sdk::{ account::{AccountSharedData, ReadableAccount, WritableAccount}, account_utils::StateMut, - feature_set, ic_msg, + feature_set, instruction::InstructionError, keyed_account::{from_keyed_account, get_signers, keyed_account_at_index, KeyedAccount}, nonce, - process_instruction::InvokeContext, program_utils::limited_deserialize, pubkey::Pubkey, system_instruction::{NonceError, SystemError, SystemInstruction, MAX_PERMITTED_DATA_LENGTH}, diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 277b569665..af9aa18203 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -35,7 +35,6 @@ pub mod nonce_account; pub mod packet; pub mod poh_config; pub mod precompiles; -pub mod process_instruction; pub mod program_utils; pub mod pubkey; pub mod recent_blockhashes_account; diff --git a/sdk/src/process_instruction.rs b/sdk/src/process_instruction.rs deleted file mode 100644 index 202850c9a6..0000000000 --- a/sdk/src/process_instruction.rs +++ /dev/null @@ -1,260 +0,0 @@ -#![cfg(feature = "full")] - -use itertools::Itertools; -use solana_sdk::{ - account::AccountSharedData, - compute_budget::ComputeBudget, - hash::Hash, - instruction::{CompiledInstruction, Instruction, InstructionError}, - keyed_account::KeyedAccount, - message::Message, - pubkey::Pubkey, -}; -use std::{cell::RefCell, fmt::Debug, rc::Rc, sync::Arc}; - -pub type ProcessInstructionWithContext = - fn(usize, &[u8], &mut dyn InvokeContext) -> Result<(), InstructionError>; - -/// Invocation context passed to loaders -pub trait InvokeContext { - /// Push a stack frame onto the invocation stack - fn push( - &mut self, - message: &Message, - instruction: &CompiledInstruction, - program_indices: &[usize], - account_indices: Option<&[usize]>, - ) -> Result<(), InstructionError>; - /// Pop a stack frame from the invocation stack - fn pop(&mut self); - /// Current depth of the invocation stake - fn invoke_depth(&self) -> usize; - /// Verify the results of an instruction - fn verify( - &mut self, - message: &Message, - instruction: &CompiledInstruction, - program_indices: &[usize], - ) -> Result<(), InstructionError>; - /// Verify and update PreAccount state based on program execution - fn verify_and_update( - &mut self, - instruction: &CompiledInstruction, - account_indices: &[usize], - write_privileges: &[bool], - ) -> Result<(), InstructionError>; - /// Get the program ID of the currently executing program - fn get_caller(&self) -> Result<&Pubkey, InstructionError>; - /// Removes the first keyed account - #[deprecated( - since = "1.9.0", - note = "To be removed together with remove_native_loader" - )] - fn remove_first_keyed_account(&mut self) -> Result<(), InstructionError>; - /// Get the list of keyed accounts - fn get_keyed_accounts(&self) -> Result<&[KeyedAccount], InstructionError>; - /// Get a list of built-in programs - fn get_programs(&self) -> &[(Pubkey, ProcessInstructionWithContext)]; - /// Get this invocation's logger - fn get_logger(&self) -> Rc>; - /// Get this invocation's compute meter - fn get_compute_meter(&self) -> Rc>; - /// Loaders may need to do work in order to execute a program. Cache - /// the work that can be re-used across executions - fn add_executor(&self, pubkey: &Pubkey, executor: Arc); - /// Get the completed loader work that can be re-used across executions - fn get_executor(&self, pubkey: &Pubkey) -> Option>; - /// Set which instruction in the message is currently being recorded - fn set_instruction_index(&mut self, instruction_index: usize); - /// Record invoked instruction - fn record_instruction(&self, instruction: &Instruction); - /// Get the bank's active feature set - fn is_feature_active(&self, feature_id: &Pubkey) -> bool; - /// Find an account_index and account by its key - fn get_account(&self, pubkey: &Pubkey) -> Option<(usize, Rc>)>; - /// Update timing - fn update_timing( - &mut self, - serialize_us: u64, - create_vm_us: u64, - execute_us: u64, - deserialize_us: u64, - ); - /// Get sysvars - fn get_sysvars(&self) -> &[(Pubkey, Vec)]; - /// Get this invocation's compute budget - fn get_compute_budget(&self) -> &ComputeBudget; - /// Set this invocation's blockhash - fn set_blockhash(&mut self, hash: Hash); - /// Get this invocation's blockhash - fn get_blockhash(&self) -> &Hash; - /// Set this invocation's lamports_per_signature value - fn set_lamports_per_signature(&mut self, lamports_per_signature: u64); - /// Get this invocation's lamports_per_signature value - fn get_lamports_per_signature(&self) -> u64; - /// Set the return data - fn set_return_data(&mut self, data: Vec) -> Result<(), InstructionError>; - /// Get the return data - fn get_return_data(&self) -> (Pubkey, &[u8]); -} - -/// Convenience macro to log a message with an `Rc>` -#[macro_export] -macro_rules! ic_logger_msg { - ($logger:expr, $message:expr) => { - if let Ok(logger) = $logger.try_borrow_mut() { - if logger.log_enabled() { - logger.log($message); - } - } - }; - ($logger:expr, $fmt:expr, $($arg:tt)*) => { - if let Ok(logger) = $logger.try_borrow_mut() { - if logger.log_enabled() { - logger.log(&format!($fmt, $($arg)*)); - } - } - }; -} - -/// Convenience macro to log a message with an `InvokeContext` -#[macro_export] -macro_rules! ic_msg { - ($invoke_context:expr, $message:expr) => { - $crate::ic_logger_msg!($invoke_context.get_logger(), $message) - }; - ($invoke_context:expr, $fmt:expr, $($arg:tt)*) => { - $crate::ic_logger_msg!($invoke_context.get_logger(), $fmt, $($arg)*) - }; -} - -/// Compute meter -pub trait ComputeMeter { - /// Consume compute units - fn consume(&mut self, amount: u64) -> Result<(), InstructionError>; - /// Get the number of remaining compute units - fn get_remaining(&self) -> u64; -} - -/// Log messages -pub trait Logger { - fn log_enabled(&self) -> bool; - - /// Log a message. - /// - /// Unless explicitly stated, log messages are not considered stable and may change in the - /// future as necessary - fn log(&self, message: &str); -} - -/// -/// Stable program log messages -/// -/// The format of these log messages should not be modified to avoid breaking downstream consumers -/// of program logging -/// -pub mod stable_log { - use super::*; - - /// Log a program invoke. - /// - /// The general form is: - /// - /// ```notrust - /// "Program
invoke []" - /// ``` - pub fn program_invoke( - logger: &Rc>, - program_id: &Pubkey, - invoke_depth: usize, - ) { - ic_logger_msg!(logger, "Program {} invoke [{}]", program_id, invoke_depth); - } - - /// Log a message from the program itself. - /// - /// The general form is: - /// - /// ```notrust - /// "Program log: " - /// ``` - /// - /// That is, any program-generated output is guaranteed to be prefixed by "Program log: " - pub fn program_log(logger: &Rc>, message: &str) { - ic_logger_msg!(logger, "Program log: {}", message); - } - - /// Emit a program data. - /// - /// The general form is: - /// - /// ```notrust - /// "Program data: *" - /// ``` - /// - /// That is, any program-generated output is guaranteed to be prefixed by "Program data: " - pub fn program_data(logger: &Rc>, data: &[&[u8]]) { - ic_logger_msg!( - logger, - "Program data: {}", - data.iter().map(base64::encode).join(" ") - ); - } - - /// Log return data as from the program itself. This line will not be present if no return - /// data was set, or if the return data was set to zero length. - /// - /// The general form is: - /// - /// ```notrust - /// "Program return: " - /// ``` - /// - /// That is, any program-generated output is guaranteed to be prefixed by "Program return: " - pub fn program_return(logger: &Rc>, program_id: &Pubkey, data: &[u8]) { - ic_logger_msg!( - logger, - "Program return: {} {}", - program_id, - base64::encode(data) - ); - } - - /// Log successful program execution. - /// - /// The general form is: - /// - /// ```notrust - /// "Program
success" - /// ``` - pub fn program_success(logger: &Rc>, program_id: &Pubkey) { - ic_logger_msg!(logger, "Program {} success", program_id); - } - - /// Log program execution failure - /// - /// The general form is: - /// - /// ```notrust - /// "Program
failed: " - /// ``` - pub fn program_failure( - logger: &Rc>, - program_id: &Pubkey, - err: &InstructionError, - ) { - ic_logger_msg!(logger, "Program {} failed: {}", program_id, err); - } -} - -/// Program executor -pub trait Executor: Debug + Send + Sync { - /// Execute the program - fn execute( - &self, - first_instruction_account: usize, - instruction_data: &[u8], - invoke_context: &mut dyn InvokeContext, - use_jit: bool, - ) -> Result<(), InstructionError>; -}