Route all loader messages to log collector (#10528)
This commit is contained in:
parent
e5a2c75fab
commit
b6a9573748
|
@ -3741,11 +3741,9 @@ dependencies = [
|
||||||
"bincode",
|
"bincode",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"jemalloc-sys",
|
"jemalloc-sys",
|
||||||
"log 0.4.8",
|
|
||||||
"num-derive 0.3.0",
|
"num-derive 0.3.0",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"rand 0.7.3",
|
"rand 0.7.3",
|
||||||
"solana-logger",
|
|
||||||
"solana-runtime",
|
"solana-runtime",
|
||||||
"solana-sdk",
|
"solana-sdk",
|
||||||
"solana_rbpf",
|
"solana_rbpf",
|
||||||
|
|
|
@ -47,6 +47,7 @@ use std::{
|
||||||
cmp::{max, min},
|
cmp::{max, min},
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
net::SocketAddr,
|
net::SocketAddr,
|
||||||
|
rc::Rc,
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
sync::{Arc, RwLock},
|
sync::{Arc, RwLock},
|
||||||
};
|
};
|
||||||
|
@ -730,14 +731,18 @@ fn run_transaction_simulation(
|
||||||
|
|
||||||
let txs = &[transaction];
|
let txs = &[transaction];
|
||||||
let batch = bank.prepare_simulation_batch(txs);
|
let batch = bank.prepare_simulation_batch(txs);
|
||||||
let log_collector = LogCollector::default();
|
let log_collector = Rc::new(LogCollector::default());
|
||||||
let (_loaded_accounts, executed, _retryable_transactions, _transaction_count, _signature_count) =
|
let (_loaded_accounts, executed, _retryable_transactions, _transaction_count, _signature_count) = {
|
||||||
bank.load_and_execute_transactions(
|
bank.load_and_execute_transactions(
|
||||||
&batch,
|
&batch,
|
||||||
solana_sdk::clock::MAX_PROCESSING_AGE,
|
solana_sdk::clock::MAX_PROCESSING_AGE,
|
||||||
Some(&log_collector),
|
Some(log_collector.clone()),
|
||||||
);
|
)
|
||||||
(executed[0].0.clone().map(|_| ()), log_collector.output())
|
};
|
||||||
|
(
|
||||||
|
executed[0].0.clone().map(|_| ()),
|
||||||
|
Rc::try_unwrap(log_collector).unwrap_or_default().into(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rpc]
|
#[rpc]
|
||||||
|
|
|
@ -1337,10 +1337,8 @@ dependencies = [
|
||||||
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"jemalloc-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"jemalloc-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"solana-logger 1.3.0",
|
|
||||||
"solana-runtime 1.3.0",
|
"solana-runtime 1.3.0",
|
||||||
"solana-sdk 1.3.0",
|
"solana-sdk 1.3.0",
|
||||||
"solana_rbpf 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
|
"solana_rbpf 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
|
@ -6,7 +6,7 @@ use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};
|
||||||
use solana_rbpf::EbpfVm;
|
use solana_rbpf::EbpfVm;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::Account,
|
account::Account,
|
||||||
entrypoint_native::{InvokeContext, ProcessInstruction},
|
entrypoint_native::{InvokeContext, Logger, ProcessInstruction},
|
||||||
instruction::{CompiledInstruction, InstructionError},
|
instruction::{CompiledInstruction, InstructionError},
|
||||||
message::Message,
|
message::Message,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
|
@ -135,6 +135,7 @@ fn bench_program_alu(bencher: &mut Bencher) {
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct MockInvokeContext {
|
pub struct MockInvokeContext {
|
||||||
key: Pubkey,
|
key: Pubkey,
|
||||||
|
mock_logger: MockLogger,
|
||||||
}
|
}
|
||||||
impl InvokeContext for MockInvokeContext {
|
impl InvokeContext for MockInvokeContext {
|
||||||
fn push(&mut self, _key: &Pubkey) -> Result<(), InstructionError> {
|
fn push(&mut self, _key: &Pubkey) -> Result<(), InstructionError> {
|
||||||
|
@ -155,8 +156,19 @@ impl InvokeContext for MockInvokeContext {
|
||||||
fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)] {
|
fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)] {
|
||||||
&[]
|
&[]
|
||||||
}
|
}
|
||||||
fn log_enabled(&self) -> bool {
|
fn get_logger(&self) -> Rc<RefCell<dyn Logger>> {
|
||||||
false
|
Rc::new(RefCell::new(self.mock_logger.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Debug, Default, Clone)]
|
||||||
|
pub struct MockLogger {
|
||||||
|
pub log: Rc<RefCell<Vec<String>>>,
|
||||||
|
}
|
||||||
|
impl Logger for MockLogger {
|
||||||
|
fn log_enabled(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
fn log(&mut self, message: &str) {
|
||||||
|
self.log.borrow_mut().push(message.to_string());
|
||||||
}
|
}
|
||||||
fn log(&mut self, _message: &str) {}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,8 @@ edition = "2018"
|
||||||
bincode = "1.2.1"
|
bincode = "1.2.1"
|
||||||
byteorder = "1.3.4"
|
byteorder = "1.3.4"
|
||||||
jemalloc-sys = { version = "0.3.2", features = ["disable_initial_exec_tls"] }
|
jemalloc-sys = { version = "0.3.2", features = ["disable_initial_exec_tls"] }
|
||||||
log = "0.4.8"
|
|
||||||
num-derive = { version = "0.3" }
|
num-derive = { version = "0.3" }
|
||||||
num-traits = { version = "0.2" }
|
num-traits = { version = "0.2" }
|
||||||
solana-logger = { path = "../../logger", version = "1.3.0" }
|
|
||||||
solana-runtime = { path = "../../runtime", version = "1.3.0" }
|
solana-runtime = { path = "../../runtime", version = "1.3.0" }
|
||||||
solana-sdk = { path = "../../sdk", version = "1.3.0" }
|
solana-sdk = { path = "../../sdk", version = "1.3.0" }
|
||||||
solana_rbpf = "=0.1.28"
|
solana_rbpf = "=0.1.28"
|
||||||
|
|
|
@ -5,7 +5,6 @@ pub mod syscalls;
|
||||||
|
|
||||||
use crate::{bpf_verifier::VerifierError, syscalls::SyscallError};
|
use crate::{bpf_verifier::VerifierError, syscalls::SyscallError};
|
||||||
use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};
|
use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};
|
||||||
use log::*;
|
|
||||||
use num_derive::{FromPrimitive, ToPrimitive};
|
use num_derive::{FromPrimitive, ToPrimitive};
|
||||||
use solana_rbpf::{
|
use solana_rbpf::{
|
||||||
ebpf::{EbpfError, UserDefinedError},
|
ebpf::{EbpfError, UserDefinedError},
|
||||||
|
@ -156,18 +155,33 @@ pub fn deserialize_parameters(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! log{
|
||||||
|
($logger:ident, $message:expr) => {
|
||||||
|
if let Ok(mut logger) = $logger.try_borrow_mut() {
|
||||||
|
if logger.log_enabled() {
|
||||||
|
logger.log($message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($logger:ident, $fmt:expr, $($arg:tt)*) => {
|
||||||
|
if let Ok(mut logger) = $logger.try_borrow_mut() {
|
||||||
|
logger.log(&format!($fmt, $($arg)*));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn process_instruction(
|
pub fn process_instruction(
|
||||||
program_id: &Pubkey,
|
program_id: &Pubkey,
|
||||||
keyed_accounts: &[KeyedAccount],
|
keyed_accounts: &[KeyedAccount],
|
||||||
instruction_data: &[u8],
|
instruction_data: &[u8],
|
||||||
invoke_context: &mut dyn InvokeContext,
|
invoke_context: &mut dyn InvokeContext,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
solana_logger::setup_with_default("solana=info");
|
|
||||||
|
|
||||||
debug_assert!(bpf_loader::check_id(program_id));
|
debug_assert!(bpf_loader::check_id(program_id));
|
||||||
|
|
||||||
|
let logger = invoke_context.get_logger();
|
||||||
|
|
||||||
if keyed_accounts.is_empty() {
|
if keyed_accounts.is_empty() {
|
||||||
warn!("No account keys");
|
log!(logger, "No account keys");
|
||||||
return Err(InstructionError::NotEnoughAccountKeys);
|
return Err(InstructionError::NotEnoughAccountKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,22 +201,32 @@ pub fn process_instruction(
|
||||||
match create_vm(&program_account.data, ¶meter_accounts, invoke_context) {
|
match create_vm(&program_account.data, ¶meter_accounts, invoke_context) {
|
||||||
Ok(info) => info,
|
Ok(info) => info,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!("Failed to create BPF VM: {}", e);
|
log!(logger, "Failed to create BPF VM: {}", e);
|
||||||
return Err(BPFLoaderError::VirtualMachineCreationFailed.into());
|
return Err(BPFLoaderError::VirtualMachineCreationFailed.into());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
info!("Call BPF program {}", program.unsigned_key());
|
log!(logger, "Call BPF program {}", program.unsigned_key());
|
||||||
match vm.execute_program(parameter_bytes.as_slice(), &[], &[heap_region]) {
|
match vm.execute_program(parameter_bytes.as_slice(), &[], &[heap_region]) {
|
||||||
Ok(status) => {
|
Ok(status) => {
|
||||||
if status != SUCCESS {
|
if status != SUCCESS {
|
||||||
let error: InstructionError = status.into();
|
let error: InstructionError = status.into();
|
||||||
warn!("BPF program {} failed: {}", program.unsigned_key(), error);
|
log!(
|
||||||
|
logger,
|
||||||
|
"BPF program {} failed: {}",
|
||||||
|
program.unsigned_key(),
|
||||||
|
error
|
||||||
|
);
|
||||||
return Err(error);
|
return Err(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
warn!("BPF program {} failed: {}", program.unsigned_key(), error);
|
log!(
|
||||||
|
logger,
|
||||||
|
"BPF program {} failed: {}",
|
||||||
|
program.unsigned_key(),
|
||||||
|
error
|
||||||
|
);
|
||||||
return match error {
|
return match error {
|
||||||
EbpfError::UserError(BPFError::SyscallError(
|
EbpfError::UserError(BPFError::SyscallError(
|
||||||
SyscallError::InstructionError(error),
|
SyscallError::InstructionError(error),
|
||||||
|
@ -213,21 +237,25 @@ pub fn process_instruction(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
deserialize_parameters(parameter_accounts, ¶meter_bytes)?;
|
deserialize_parameters(parameter_accounts, ¶meter_bytes)?;
|
||||||
info!("BPF program {} success", program.unsigned_key());
|
log!(logger, "BPF program {} success", program.unsigned_key());
|
||||||
} else if !keyed_accounts.is_empty() {
|
} else if !keyed_accounts.is_empty() {
|
||||||
match limited_deserialize(instruction_data)? {
|
match limited_deserialize(instruction_data)? {
|
||||||
LoaderInstruction::Write { offset, bytes } => {
|
LoaderInstruction::Write { offset, bytes } => {
|
||||||
let mut keyed_accounts_iter = keyed_accounts.iter();
|
let mut keyed_accounts_iter = keyed_accounts.iter();
|
||||||
let program = next_keyed_account(&mut keyed_accounts_iter)?;
|
let program = next_keyed_account(&mut keyed_accounts_iter)?;
|
||||||
if program.signer_key().is_none() {
|
if program.signer_key().is_none() {
|
||||||
warn!("key[0] did not sign the transaction");
|
log!(logger, "key[0] did not sign the transaction");
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
}
|
}
|
||||||
let offset = offset as usize;
|
let offset = offset as usize;
|
||||||
let len = bytes.len();
|
let len = bytes.len();
|
||||||
trace!("Write: offset={} length={}", offset, len);
|
|
||||||
if program.data_len()? < offset + len {
|
if program.data_len()? < offset + len {
|
||||||
warn!("Write overflow: {} < {}", program.data_len()?, offset + len);
|
log!(
|
||||||
|
logger,
|
||||||
|
"Write overflow: {} < {}",
|
||||||
|
program.data_len()?,
|
||||||
|
offset + len
|
||||||
|
);
|
||||||
return Err(InstructionError::AccountDataTooSmall);
|
return Err(InstructionError::AccountDataTooSmall);
|
||||||
}
|
}
|
||||||
program.try_account_ref_mut()?.data[offset..offset + len].copy_from_slice(&bytes);
|
program.try_account_ref_mut()?.data[offset..offset + len].copy_from_slice(&bytes);
|
||||||
|
@ -237,17 +265,21 @@ pub fn process_instruction(
|
||||||
let program = next_keyed_account(&mut keyed_accounts_iter)?;
|
let program = next_keyed_account(&mut keyed_accounts_iter)?;
|
||||||
|
|
||||||
if program.signer_key().is_none() {
|
if program.signer_key().is_none() {
|
||||||
warn!("key[0] did not sign the transaction");
|
log!(logger, "key[0] did not sign the transaction");
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(e) = check_elf(&program.try_account_ref()?.data) {
|
if let Err(e) = check_elf(&program.try_account_ref()?.data) {
|
||||||
warn!("{}", e);
|
log!(logger, "{}", e);
|
||||||
return Err(InstructionError::InvalidAccountData);
|
return Err(InstructionError::InvalidAccountData);
|
||||||
}
|
}
|
||||||
|
|
||||||
program.try_account_ref_mut()?.executable = true;
|
program.try_account_ref_mut()?.executable = true;
|
||||||
info!("Finalize: account {:?}", program.signer_key().unwrap());
|
log!(
|
||||||
|
logger,
|
||||||
|
"Finalized account {:?}",
|
||||||
|
program.signer_key().unwrap()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -259,15 +291,18 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::Account, entrypoint_native::ProcessInstruction, instruction::CompiledInstruction,
|
account::Account,
|
||||||
message::Message, rent::Rent,
|
entrypoint_native::{Logger, ProcessInstruction},
|
||||||
|
instruction::CompiledInstruction,
|
||||||
|
message::Message,
|
||||||
|
rent::Rent,
|
||||||
};
|
};
|
||||||
use std::{cell::RefCell, fs::File, io::Read, ops::Range, rc::Rc};
|
use std::{cell::RefCell, fs::File, io::Read, ops::Range, rc::Rc};
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct MockInvokeContext {
|
pub struct MockInvokeContext {
|
||||||
key: Pubkey,
|
key: Pubkey,
|
||||||
pub log: Vec<String>,
|
mock_logger: MockLogger,
|
||||||
}
|
}
|
||||||
impl InvokeContext for MockInvokeContext {
|
impl InvokeContext for MockInvokeContext {
|
||||||
fn push(&mut self, _key: &Pubkey) -> Result<(), InstructionError> {
|
fn push(&mut self, _key: &Pubkey) -> Result<(), InstructionError> {
|
||||||
|
@ -288,12 +323,20 @@ mod tests {
|
||||||
fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)] {
|
fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)] {
|
||||||
&[]
|
&[]
|
||||||
}
|
}
|
||||||
|
fn get_logger(&self) -> Rc<RefCell<dyn Logger>> {
|
||||||
|
Rc::new(RefCell::new(self.mock_logger.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Debug, Default, Clone)]
|
||||||
|
pub struct MockLogger {
|
||||||
|
pub log: Rc<RefCell<Vec<String>>>,
|
||||||
|
}
|
||||||
|
impl Logger for MockLogger {
|
||||||
fn log_enabled(&self) -> bool {
|
fn log_enabled(&self) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
fn log(&mut self, message: &str) {
|
fn log(&mut self, message: &str) {
|
||||||
info!("[MockInvokeContext::log] {}", message);
|
self.log.borrow_mut().push(message.to_string());
|
||||||
self.log.push(message.to_string());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -446,8 +489,6 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bpf_loader_invoke_main() {
|
fn test_bpf_loader_invoke_main() {
|
||||||
solana_logger::setup();
|
|
||||||
|
|
||||||
let program_id = Pubkey::new_rand();
|
let program_id = Pubkey::new_rand();
|
||||||
let program_key = Pubkey::new_rand();
|
let program_key = Pubkey::new_rand();
|
||||||
|
|
||||||
|
@ -560,7 +601,7 @@ mod tests {
|
||||||
let mut elf = Vec::new();
|
let mut elf = Vec::new();
|
||||||
file.read_to_end(&mut elf).unwrap();
|
file.read_to_end(&mut elf).unwrap();
|
||||||
|
|
||||||
info!("mangle the whole file");
|
// Mangle the whole file
|
||||||
fuzz(
|
fuzz(
|
||||||
&elf,
|
&elf,
|
||||||
1_000_000_000,
|
1_000_000_000,
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::{alloc, BPFError};
|
use crate::{alloc, BPFError};
|
||||||
use alloc::Alloc;
|
use alloc::Alloc;
|
||||||
use log::*;
|
|
||||||
use solana_rbpf::{
|
use solana_rbpf::{
|
||||||
ebpf::{EbpfError, SyscallObject, ELF_INSN_DUMP_OFFSET, MM_HEAP_START},
|
ebpf::{EbpfError, SyscallObject, ELF_INSN_DUMP_OFFSET, MM_HEAP_START},
|
||||||
memory_region::{translate_addr, MemoryRegion},
|
memory_region::{translate_addr, MemoryRegion},
|
||||||
|
@ -13,7 +12,7 @@ use solana_sdk::{
|
||||||
account_info::AccountInfo,
|
account_info::AccountInfo,
|
||||||
bpf_loader,
|
bpf_loader,
|
||||||
entrypoint::SUCCESS,
|
entrypoint::SUCCESS,
|
||||||
entrypoint_native::InvokeContext,
|
entrypoint_native::{InvokeContext, Logger},
|
||||||
instruction::{AccountMeta, Instruction, InstructionError},
|
instruction::{AccountMeta, Instruction, InstructionError},
|
||||||
message::Message,
|
message::Message,
|
||||||
program_error::ProgramError,
|
program_error::ProgramError,
|
||||||
|
@ -37,7 +36,7 @@ pub enum SyscallError {
|
||||||
InvalidString(Utf8Error, Vec<u8>),
|
InvalidString(Utf8Error, Vec<u8>),
|
||||||
#[error("BPF program called abort()!")]
|
#[error("BPF program called abort()!")]
|
||||||
Abort,
|
Abort,
|
||||||
#[error("BPF program Panicked at {0}, {1}:{2}")]
|
#[error("BPF program Panicked in {0} at {1}:{2}")]
|
||||||
Panic(String, u64, u64),
|
Panic(String, u64, u64),
|
||||||
#[error("cannot borrow invoke context")]
|
#[error("cannot borrow invoke context")]
|
||||||
InvokeContextBorrowFailed,
|
InvokeContextBorrowFailed,
|
||||||
|
@ -76,46 +75,41 @@ pub fn register_syscalls<'a>(
|
||||||
invoke_context: &'a mut dyn InvokeContext,
|
invoke_context: &'a mut dyn InvokeContext,
|
||||||
) -> Result<MemoryRegion, EbpfError<BPFError>> {
|
) -> Result<MemoryRegion, EbpfError<BPFError>> {
|
||||||
// Syscall function common across languages
|
// Syscall function common across languages
|
||||||
|
|
||||||
vm.register_syscall_ex("abort", syscall_abort)?;
|
vm.register_syscall_ex("abort", syscall_abort)?;
|
||||||
|
vm.register_syscall_ex("sol_panic_", syscall_sol_panic)?;
|
||||||
|
|
||||||
{
|
vm.register_syscall_with_context_ex(
|
||||||
let invoke_context = Rc::new(RefCell::new(invoke_context));
|
"sol_log_",
|
||||||
|
Box::new(SyscallLog {
|
||||||
|
logger: invoke_context.get_logger(),
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
|
vm.register_syscall_with_context_ex(
|
||||||
|
"sol_log_64_",
|
||||||
|
Box::new(SyscallLogU64 {
|
||||||
|
logger: invoke_context.get_logger(),
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
|
|
||||||
vm.register_syscall_with_context_ex(
|
// Cross-program invocation syscalls
|
||||||
"sol_panic_",
|
|
||||||
Box::new(SyscallPanic {
|
|
||||||
invoke_context: invoke_context.clone(),
|
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
vm.register_syscall_with_context_ex(
|
|
||||||
"sol_log_",
|
|
||||||
Box::new(SyscallLog {
|
|
||||||
invoke_context: invoke_context.clone(),
|
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
vm.register_syscall_with_context_ex(
|
|
||||||
"sol_log_64_",
|
|
||||||
Box::new(SyscallLogU64 {
|
|
||||||
invoke_context: invoke_context.clone(),
|
|
||||||
}),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Cross-program invocation syscalls
|
let invoke_context = Rc::new(RefCell::new(invoke_context));
|
||||||
vm.register_syscall_with_context_ex(
|
|
||||||
"sol_invoke_signed_c",
|
vm.register_syscall_with_context_ex(
|
||||||
Box::new(SyscallProcessSolInstructionC {
|
"sol_invoke_signed_c",
|
||||||
callers_keyed_accounts,
|
Box::new(SyscallProcessSolInstructionC {
|
||||||
invoke_context: invoke_context.clone(),
|
callers_keyed_accounts,
|
||||||
}),
|
invoke_context: invoke_context.clone(),
|
||||||
)?;
|
}),
|
||||||
vm.register_syscall_with_context_ex(
|
)?;
|
||||||
"sol_invoke_signed_rust",
|
vm.register_syscall_with_context_ex(
|
||||||
Box::new(SyscallProcessInstructionRust {
|
"sol_invoke_signed_rust",
|
||||||
callers_keyed_accounts,
|
Box::new(SyscallProcessInstructionRust {
|
||||||
invoke_context: invoke_context.clone(),
|
callers_keyed_accounts,
|
||||||
}),
|
invoke_context: invoke_context.clone(),
|
||||||
)?;
|
}),
|
||||||
}
|
)?;
|
||||||
|
|
||||||
// Memory allocator
|
// Memory allocator
|
||||||
let heap = vec![0_u8; DEFAULT_HEAP_SIZE];
|
let heap = vec![0_u8; DEFAULT_HEAP_SIZE];
|
||||||
|
@ -232,49 +226,25 @@ pub fn syscall_abort(
|
||||||
|
|
||||||
/// Panic syscall function, called when the BPF program calls 'sol_panic_()`
|
/// Panic syscall function, called when the BPF program calls 'sol_panic_()`
|
||||||
/// Causes the BPF program to be halted immediately
|
/// Causes the BPF program to be halted immediately
|
||||||
pub struct SyscallPanic<'a> {
|
pub fn syscall_sol_panic(
|
||||||
invoke_context: Rc<RefCell<&'a mut dyn InvokeContext>>,
|
file: u64,
|
||||||
}
|
len: u64,
|
||||||
impl<'a> SyscallPanic<'a> {
|
line: u64,
|
||||||
fn get_context_mut(&self) -> Result<RefMut<&'a mut dyn InvokeContext>, EbpfError<BPFError>> {
|
column: u64,
|
||||||
self.invoke_context
|
_arg5: u64,
|
||||||
.try_borrow_mut()
|
ro_regions: &[MemoryRegion],
|
||||||
.map_err(|_| SyscallError::InvokeContextBorrowFailed.into())
|
_rw_regions: &[MemoryRegion],
|
||||||
}
|
) -> Result<u64, EbpfError<BPFError>> {
|
||||||
}
|
translate_string_and_do(file, len, ro_regions, &mut |string: &str| {
|
||||||
impl<'a> SyscallObject<BPFError> for SyscallPanic<'a> {
|
Err(SyscallError::Panic(string.to_string(), line, column).into())
|
||||||
fn call(
|
})
|
||||||
&mut self,
|
|
||||||
file: u64,
|
|
||||||
len: u64,
|
|
||||||
line: u64,
|
|
||||||
column: u64,
|
|
||||||
_arg5: u64,
|
|
||||||
ro_regions: &[MemoryRegion],
|
|
||||||
_rw_regions: &[MemoryRegion],
|
|
||||||
) -> Result<u64, EbpfError<BPFError>> {
|
|
||||||
let mut invoke_context = self.get_context_mut()?;
|
|
||||||
translate_string_and_do(file, len, ro_regions, &mut |string: &str| {
|
|
||||||
if invoke_context.log_enabled() {
|
|
||||||
invoke_context.log(&format!("panicked at '{}' on {}:{}", string, line, column));
|
|
||||||
}
|
|
||||||
Err(SyscallError::Panic(string.to_string(), line, column).into())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Log a user's info message
|
/// Log a user's info message
|
||||||
pub struct SyscallLog<'a> {
|
pub struct SyscallLog {
|
||||||
invoke_context: Rc<RefCell<&'a mut dyn InvokeContext>>,
|
logger: Rc<RefCell<dyn Logger>>,
|
||||||
}
|
}
|
||||||
impl<'a> SyscallLog<'a> {
|
impl SyscallObject<BPFError> for SyscallLog {
|
||||||
fn get_context_mut(&self) -> Result<RefMut<&'a mut dyn InvokeContext>, EbpfError<BPFError>> {
|
|
||||||
self.invoke_context
|
|
||||||
.try_borrow_mut()
|
|
||||||
.map_err(|_| SyscallError::InvokeContextBorrowFailed.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'a> SyscallObject<BPFError> for SyscallLog<'a> {
|
|
||||||
fn call(
|
fn call(
|
||||||
&mut self,
|
&mut self,
|
||||||
addr: u64,
|
addr: u64,
|
||||||
|
@ -285,10 +255,13 @@ impl<'a> SyscallObject<BPFError> for SyscallLog<'a> {
|
||||||
ro_regions: &[MemoryRegion],
|
ro_regions: &[MemoryRegion],
|
||||||
_rw_regions: &[MemoryRegion],
|
_rw_regions: &[MemoryRegion],
|
||||||
) -> Result<u64, EbpfError<BPFError>> {
|
) -> Result<u64, EbpfError<BPFError>> {
|
||||||
let mut invoke_context = self.get_context_mut()?;
|
let mut logger = self
|
||||||
if invoke_context.log_enabled() {
|
.logger
|
||||||
|
.try_borrow_mut()
|
||||||
|
.map_err(|_| SyscallError::InvokeContextBorrowFailed)?;
|
||||||
|
if logger.log_enabled() {
|
||||||
translate_string_and_do(addr, len, ro_regions, &mut |string: &str| {
|
translate_string_and_do(addr, len, ro_regions, &mut |string: &str| {
|
||||||
invoke_context.log(string);
|
logger.log(&format!("Program log: {}", string));
|
||||||
Ok(0)
|
Ok(0)
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
@ -297,17 +270,10 @@ impl<'a> SyscallObject<BPFError> for SyscallLog<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Log 5 64-bit values
|
/// Log 5 64-bit values
|
||||||
pub struct SyscallLogU64<'a> {
|
pub struct SyscallLogU64 {
|
||||||
invoke_context: Rc<RefCell<&'a mut dyn InvokeContext>>,
|
logger: Rc<RefCell<dyn Logger>>,
|
||||||
}
|
}
|
||||||
impl<'a> SyscallLogU64<'a> {
|
impl SyscallObject<BPFError> for SyscallLogU64 {
|
||||||
fn get_context_mut(&self) -> Result<RefMut<&'a mut dyn InvokeContext>, EbpfError<BPFError>> {
|
|
||||||
self.invoke_context
|
|
||||||
.try_borrow_mut()
|
|
||||||
.map_err(|_| SyscallError::InvokeContextBorrowFailed.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'a> SyscallObject<BPFError> for SyscallLogU64<'a> {
|
|
||||||
fn call(
|
fn call(
|
||||||
&mut self,
|
&mut self,
|
||||||
arg1: u64,
|
arg1: u64,
|
||||||
|
@ -318,10 +284,13 @@ impl<'a> SyscallObject<BPFError> for SyscallLogU64<'a> {
|
||||||
_ro_regions: &[MemoryRegion],
|
_ro_regions: &[MemoryRegion],
|
||||||
_rw_regions: &[MemoryRegion],
|
_rw_regions: &[MemoryRegion],
|
||||||
) -> Result<u64, EbpfError<BPFError>> {
|
) -> Result<u64, EbpfError<BPFError>> {
|
||||||
let mut invoke_context = self.get_context_mut()?;
|
let mut logger = self
|
||||||
if invoke_context.log_enabled() {
|
.logger
|
||||||
invoke_context.log(&format!(
|
.try_borrow_mut()
|
||||||
"{:#x}, {:#x}, {:#x}, {:#x}, {:#x}",
|
.map_err(|_| SyscallError::InvokeContextBorrowFailed)?;
|
||||||
|
if logger.log_enabled() {
|
||||||
|
logger.log(&format!(
|
||||||
|
"Program log: {:#x}, {:#x}, {:#x}, {:#x}, {:#x}",
|
||||||
arg1, arg2, arg3, arg4, arg5
|
arg1, arg2, arg3, arg4, arg5
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -863,8 +832,7 @@ fn call<'a>(
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::tests::MockInvokeContext;
|
use crate::tests::MockLogger;
|
||||||
use solana_sdk::entrypoint_native::InvokeContext;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_translate() {
|
fn test_translate() {
|
||||||
|
@ -988,38 +956,23 @@ mod tests {
|
||||||
#[should_panic(expected = "UserError(SyscallError(Panic(\"Gaggablaghblagh!\", 42, 84)))")]
|
#[should_panic(expected = "UserError(SyscallError(Panic(\"Gaggablaghblagh!\", 42, 84)))")]
|
||||||
fn test_syscall_sol_panic() {
|
fn test_syscall_sol_panic() {
|
||||||
let string = "Gaggablaghblagh!";
|
let string = "Gaggablaghblagh!";
|
||||||
|
let addr = string.as_ptr() as *const _ as u64;
|
||||||
let mut mock_invoke_context = MockInvokeContext::default();
|
let ro_region = MemoryRegion {
|
||||||
let result = {
|
addr_host: addr,
|
||||||
let invoke_context: &mut dyn InvokeContext = &mut mock_invoke_context;
|
addr_vm: 100,
|
||||||
let mut syscall_sol_panic = SyscallPanic {
|
len: string.len() as u64,
|
||||||
invoke_context: Rc::new(RefCell::new(invoke_context)),
|
|
||||||
};
|
|
||||||
|
|
||||||
let addr = string.as_ptr() as *const _ as u64;
|
|
||||||
let ro_region = MemoryRegion {
|
|
||||||
addr_host: addr,
|
|
||||||
addr_vm: 100,
|
|
||||||
len: string.len() as u64,
|
|
||||||
};
|
|
||||||
let rw_region = MemoryRegion::default();
|
|
||||||
syscall_sol_panic.call(
|
|
||||||
100,
|
|
||||||
string.len() as u64,
|
|
||||||
42,
|
|
||||||
84,
|
|
||||||
0,
|
|
||||||
&[ro_region],
|
|
||||||
&[rw_region],
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
assert_eq!(mock_invoke_context.log.len(), 1);
|
let rw_region = MemoryRegion::default();
|
||||||
assert_eq!(
|
syscall_sol_panic(
|
||||||
mock_invoke_context.log[0],
|
100,
|
||||||
"panicked at \'Gaggablaghblagh!\' on 42:84"
|
string.len() as u64,
|
||||||
);
|
42,
|
||||||
|
84,
|
||||||
result.unwrap();
|
0,
|
||||||
|
&[ro_region],
|
||||||
|
&[rw_region],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1033,50 +986,47 @@ mod tests {
|
||||||
}];
|
}];
|
||||||
let rw_regions = &[MemoryRegion::default()];
|
let rw_regions = &[MemoryRegion::default()];
|
||||||
|
|
||||||
let mut mock_invoke_context = MockInvokeContext::default();
|
let log = Rc::new(RefCell::new(vec![]));
|
||||||
{
|
let mock_logger = MockLogger { log: log.clone() };
|
||||||
let invoke_context: &mut dyn InvokeContext = &mut mock_invoke_context;
|
let logger: Rc<RefCell<dyn Logger>> = Rc::new(RefCell::new(mock_logger));
|
||||||
let mut syscall_sol_log = SyscallLog {
|
let mut syscall_sol_log = SyscallLog { logger };
|
||||||
invoke_context: Rc::new(RefCell::new(invoke_context)),
|
|
||||||
};
|
|
||||||
|
|
||||||
syscall_sol_log
|
syscall_sol_log
|
||||||
.call(100, string.len() as u64, 0, 0, 0, ro_regions, rw_regions)
|
.call(100, string.len() as u64, 0, 0, 0, ro_regions, rw_regions)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
syscall_sol_log
|
syscall_sol_log
|
||||||
.call(
|
.call(
|
||||||
100,
|
100,
|
||||||
string.len() as u64 * 2, // AccessViolation
|
string.len() as u64 * 2, // AccessViolation
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
ro_regions,
|
ro_regions,
|
||||||
rw_regions,
|
rw_regions,
|
||||||
)
|
)
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
}
|
|
||||||
assert_eq!(mock_invoke_context.log.len(), 1);
|
assert_eq!(log.borrow().len(), 1);
|
||||||
assert_eq!(mock_invoke_context.log[0], "Gaggablaghblagh!");
|
assert_eq!(log.borrow()[0], "Program log: Gaggablaghblagh!");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_syscall_sol_log_u64() {
|
fn test_syscall_sol_log_u64() {
|
||||||
let mut mock_invoke_context = MockInvokeContext::default();
|
let log = Rc::new(RefCell::new(vec![]));
|
||||||
{
|
let mock_logger = MockLogger { log: log.clone() };
|
||||||
let invoke_context: &mut dyn InvokeContext = &mut mock_invoke_context;
|
let mut syscall_sol_log_u64 = SyscallLogU64 {
|
||||||
let mut syscall_sol_log_u64 = SyscallLogU64 {
|
logger: Rc::new(RefCell::new(mock_logger)),
|
||||||
invoke_context: Rc::new(RefCell::new(invoke_context)),
|
};
|
||||||
};
|
let ro_regions = &[MemoryRegion::default()];
|
||||||
|
let rw_regions = &[MemoryRegion::default()];
|
||||||
|
|
||||||
let ro_regions = &[MemoryRegion::default()];
|
syscall_sol_log_u64
|
||||||
let rw_regions = &[MemoryRegion::default()];
|
.call(1, 2, 3, 4, 5, ro_regions, rw_regions)
|
||||||
syscall_sol_log_u64
|
.unwrap();
|
||||||
.call(1, 2, 3, 4, 5, ro_regions, rw_regions)
|
|
||||||
.unwrap();
|
assert_eq!(log.borrow().len(), 1);
|
||||||
}
|
assert_eq!(log.borrow()[0], "Program log: 0x1, 0x2, 0x3, 0x4, 0x5");
|
||||||
assert_eq!(mock_invoke_context.log.len(), 1);
|
|
||||||
assert_eq!(mock_invoke_context.log[0], "0x1, 0x2, 0x3, 0x4, 0x5");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1348,7 +1348,7 @@ impl Bank {
|
||||||
&self,
|
&self,
|
||||||
batch: &TransactionBatch,
|
batch: &TransactionBatch,
|
||||||
max_age: usize,
|
max_age: usize,
|
||||||
log_collector: Option<&LogCollector>,
|
log_collector: Option<Rc<LogCollector>>,
|
||||||
) -> (
|
) -> (
|
||||||
Vec<(Result<TransactionLoadResult>, Option<HashAgeKind>)>,
|
Vec<(Result<TransactionLoadResult>, Option<HashAgeKind>)>,
|
||||||
Vec<TransactionProcessResult>,
|
Vec<TransactionProcessResult>,
|
||||||
|
@ -1408,7 +1408,7 @@ impl Bank {
|
||||||
&loader_refcells,
|
&loader_refcells,
|
||||||
&account_refcells,
|
&account_refcells,
|
||||||
&self.rent_collector,
|
&self.rent_collector,
|
||||||
log_collector,
|
log_collector.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Self::refcells_to_accounts(
|
Self::refcells_to_accounts(
|
||||||
|
|
|
@ -9,8 +9,9 @@ impl LogCollector {
|
||||||
pub fn log(&self, message: &str) {
|
pub fn log(&self, message: &str) {
|
||||||
self.messages.borrow_mut().push(message.to_string())
|
self.messages.borrow_mut().push(message.to_string())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
pub fn output(self) -> Vec<String> {
|
impl Into<Vec<String>> for LogCollector {
|
||||||
|
fn into(self) -> Vec<String> {
|
||||||
self.messages.into_inner()
|
self.messages.into_inner()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::{create_keyed_readonly_accounts, Account, KeyedAccount},
|
account::{create_keyed_readonly_accounts, Account, KeyedAccount},
|
||||||
clock::Epoch,
|
clock::Epoch,
|
||||||
entrypoint_native::{InvokeContext, ProcessInstruction},
|
entrypoint_native::{InvokeContext, Logger, ProcessInstruction},
|
||||||
instruction::{CompiledInstruction, InstructionError},
|
instruction::{CompiledInstruction, InstructionError},
|
||||||
message::Message,
|
message::Message,
|
||||||
native_loader,
|
native_loader,
|
||||||
|
@ -154,23 +154,21 @@ impl PreAccount {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
pub struct ThisInvokeContext {
|
||||||
pub struct ThisInvokeContext<'a> {
|
program_ids: Vec<Pubkey>,
|
||||||
pub program_ids: Vec<Pubkey>,
|
rent: Rent,
|
||||||
pub rent: Rent,
|
pre_accounts: Vec<PreAccount>,
|
||||||
pub pre_accounts: Vec<PreAccount>,
|
programs: Vec<(Pubkey, ProcessInstruction)>,
|
||||||
pub programs: Vec<(Pubkey, ProcessInstruction)>,
|
logger: Rc<RefCell<dyn Logger>>,
|
||||||
pub log_collector: Option<&'a LogCollector>,
|
|
||||||
}
|
}
|
||||||
|
impl ThisInvokeContext {
|
||||||
impl<'a> ThisInvokeContext<'a> {
|
|
||||||
const MAX_INVOCATION_DEPTH: usize = 5;
|
const MAX_INVOCATION_DEPTH: usize = 5;
|
||||||
pub fn new(
|
pub fn new(
|
||||||
program_id: &Pubkey,
|
program_id: &Pubkey,
|
||||||
rent: Rent,
|
rent: Rent,
|
||||||
pre_accounts: Vec<PreAccount>,
|
pre_accounts: Vec<PreAccount>,
|
||||||
programs: Vec<(Pubkey, ProcessInstruction)>,
|
programs: Vec<(Pubkey, ProcessInstruction)>,
|
||||||
log_collector: Option<&'a LogCollector>,
|
log_collector: Option<Rc<LogCollector>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut program_ids = Vec::with_capacity(Self::MAX_INVOCATION_DEPTH);
|
let mut program_ids = Vec::with_capacity(Self::MAX_INVOCATION_DEPTH);
|
||||||
program_ids.push(*program_id);
|
program_ids.push(*program_id);
|
||||||
|
@ -179,12 +177,11 @@ impl<'a> ThisInvokeContext<'a> {
|
||||||
rent,
|
rent,
|
||||||
pre_accounts,
|
pre_accounts,
|
||||||
programs,
|
programs,
|
||||||
log_collector,
|
logger: Rc::new(RefCell::new(ThisLogger { log_collector })),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl InvokeContext for ThisInvokeContext {
|
||||||
impl<'a> InvokeContext for ThisInvokeContext<'a> {
|
|
||||||
fn push(&mut self, key: &Pubkey) -> Result<(), InstructionError> {
|
fn push(&mut self, key: &Pubkey) -> Result<(), InstructionError> {
|
||||||
if self.program_ids.len() >= Self::MAX_INVOCATION_DEPTH {
|
if self.program_ids.len() >= Self::MAX_INVOCATION_DEPTH {
|
||||||
return Err(InstructionError::CallDepth);
|
return Err(InstructionError::CallDepth);
|
||||||
|
@ -222,18 +219,23 @@ impl<'a> InvokeContext for ThisInvokeContext<'a> {
|
||||||
.last()
|
.last()
|
||||||
.ok_or(InstructionError::GenericError)
|
.ok_or(InstructionError::GenericError)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)] {
|
fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)] {
|
||||||
&self.programs
|
&self.programs
|
||||||
}
|
}
|
||||||
|
fn get_logger(&self) -> Rc<RefCell<dyn Logger>> {
|
||||||
|
self.logger.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub struct ThisLogger {
|
||||||
|
log_collector: Option<Rc<LogCollector>>,
|
||||||
|
}
|
||||||
|
impl Logger for ThisLogger {
|
||||||
fn log_enabled(&self) -> bool {
|
fn log_enabled(&self) -> bool {
|
||||||
log_enabled!(log::Level::Info) || self.log_collector.is_some()
|
log_enabled!(log::Level::Info) || self.log_collector.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn log(&mut self, message: &str) {
|
fn log(&mut self, message: &str) {
|
||||||
info!("{}", message);
|
info!("{}", message);
|
||||||
if let Some(log_collector) = self.log_collector {
|
if let Some(log_collector) = &self.log_collector {
|
||||||
log_collector.log(message);
|
log_collector.log(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -502,14 +504,14 @@ impl MessageProcessor {
|
||||||
executable_accounts: &[(Pubkey, RefCell<Account>)],
|
executable_accounts: &[(Pubkey, RefCell<Account>)],
|
||||||
accounts: &[Rc<RefCell<Account>>],
|
accounts: &[Rc<RefCell<Account>>],
|
||||||
rent_collector: &RentCollector,
|
rent_collector: &RentCollector,
|
||||||
log_collector: Option<&LogCollector>,
|
log_collector: Option<Rc<LogCollector>>,
|
||||||
) -> Result<(), InstructionError> {
|
) -> Result<(), InstructionError> {
|
||||||
let pre_accounts = Self::create_pre_accounts(message, instruction, accounts);
|
let pre_accounts = Self::create_pre_accounts(message, instruction, accounts);
|
||||||
let mut invoke_context = ThisInvokeContext::new(
|
let mut invoke_context = ThisInvokeContext::new(
|
||||||
instruction.program_id(&message.account_keys),
|
instruction.program_id(&message.account_keys),
|
||||||
rent_collector.rent,
|
rent_collector.rent,
|
||||||
pre_accounts,
|
pre_accounts,
|
||||||
self.programs.clone(),
|
self.programs.clone(), // get rid of clone
|
||||||
log_collector,
|
log_collector,
|
||||||
);
|
);
|
||||||
let keyed_accounts =
|
let keyed_accounts =
|
||||||
|
@ -535,7 +537,7 @@ impl MessageProcessor {
|
||||||
loaders: &[Vec<(Pubkey, RefCell<Account>)>],
|
loaders: &[Vec<(Pubkey, RefCell<Account>)>],
|
||||||
accounts: &[Rc<RefCell<Account>>],
|
accounts: &[Rc<RefCell<Account>>],
|
||||||
rent_collector: &RentCollector,
|
rent_collector: &RentCollector,
|
||||||
log_collector: Option<&LogCollector>,
|
log_collector: Option<Rc<LogCollector>>,
|
||||||
) -> Result<(), TransactionError> {
|
) -> Result<(), TransactionError> {
|
||||||
for (instruction_index, instruction) in message.instructions.iter().enumerate() {
|
for (instruction_index, instruction) in message.instructions.iter().enumerate() {
|
||||||
self.execute_instruction(
|
self.execute_instruction(
|
||||||
|
@ -544,7 +546,7 @@ impl MessageProcessor {
|
||||||
&loaders[instruction_index],
|
&loaders[instruction_index],
|
||||||
accounts,
|
accounts,
|
||||||
rent_collector,
|
rent_collector,
|
||||||
log_collector,
|
log_collector.clone(),
|
||||||
)
|
)
|
||||||
.map_err(|err| TransactionError::InstructionError(instruction_index as u8, err))?;
|
.map_err(|err| TransactionError::InstructionError(instruction_index as u8, err))?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,7 +165,12 @@ pub trait InvokeContext {
|
||||||
fn get_caller(&self) -> Result<&Pubkey, InstructionError>;
|
fn get_caller(&self) -> Result<&Pubkey, InstructionError>;
|
||||||
/// Get a list of built-in programs
|
/// Get a list of built-in programs
|
||||||
fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)];
|
fn get_programs(&self) -> &[(Pubkey, ProcessInstruction)];
|
||||||
/// Check if logging is enabled
|
/// Get this invocation's logger
|
||||||
|
fn get_logger(&self) -> Rc<RefCell<dyn Logger>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Log messages
|
||||||
|
pub trait Logger {
|
||||||
fn log_enabled(&self) -> bool;
|
fn log_enabled(&self) -> bool;
|
||||||
/// Log a message
|
/// Log a message
|
||||||
fn log(&mut self, message: &str);
|
fn log(&mut self, message: &str);
|
||||||
|
|
Loading…
Reference in New Issue