From c0675968b105dcf8d7c5b2446a3ebbd1c19e2ca2 Mon Sep 17 00:00:00 2001 From: Ryo Onodera Date: Wed, 21 Oct 2020 01:05:45 +0900 Subject: [PATCH] Support Debug Bank (#13017) --- core/tests/snapshots.rs | 2 +- programs/bpf_loader/src/lib.rs | 10 +++- runtime/src/bank.rs | 75 ++++++++++++++++++++++++++---- runtime/src/feature_set.rs | 2 +- runtime/src/message_processor.rs | 2 +- runtime/src/process_instruction.rs | 4 +- 6 files changed, 81 insertions(+), 14 deletions(-) diff --git a/core/tests/snapshots.rs b/core/tests/snapshots.rs index 85c55dbb7a..53ab271565 100644 --- a/core/tests/snapshots.rs +++ b/core/tests/snapshots.rs @@ -156,7 +156,7 @@ mod tests { .get(&deserialized_bank.slot()) .unwrap() .clone(); - assert!(*bank == deserialized_bank); + assert_eq!(*bank, deserialized_bank); let slot_snapshot_paths = snapshot_utils::get_snapshot_paths(&snapshot_path); diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index b44130cdcf..371f33cf64 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -30,7 +30,7 @@ use solana_sdk::{ program_utils::limited_deserialize, pubkey::Pubkey, }; -use std::{cell::RefCell, rc::Rc, sync::Arc}; +use std::{cell::RefCell, fmt::Debug, rc::Rc, sync::Arc}; use thiserror::Error; solana_sdk::declare_builtin!( @@ -214,6 +214,14 @@ impl InstructionMeter for ThisInstructionMeter { pub struct BPFExecutor { executable: Box>, } + +// Well, implement Debug for solana_rbpf::vm::Executable in solana-rbpf... +impl Debug for BPFExecutor { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "BPFExecutor({:p})", self) + } +} + impl Executor for BPFExecutor { fn execute( &self, diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 6016a54214..ef590cde77 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -17,7 +17,10 @@ use crate::{ instruction_recorder::InstructionRecorder, log_collector::LogCollector, message_processor::{Executors, MessageProcessor}, - process_instruction::{Executor, ProcessInstruction, ProcessInstructionWithContext}, + process_instruction::{ + ErasedProcessInstruction, ErasedProcessInstructionWithContext, Executor, + ProcessInstruction, ProcessInstructionWithContext, + }, rent_collector::RentCollector, stakes::Stakes, status_cache::{SlotDelta, StatusCache}, @@ -139,7 +142,31 @@ pub enum Entrypoint { Loader(ProcessInstructionWithContext), } -#[derive(Clone)] +impl fmt::Debug for Entrypoint { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + #[derive(Debug)] + enum EntrypointForDebug { + Program(String), + Loader(String), + } + // rustc doesn't compile due to bug without this work around + // https://github.com/rust-lang/rust/issues/50280 + // https://users.rust-lang.org/t/display-function-pointer/17073/2 + let entrypoint = match self { + Entrypoint::Program(instruction) => EntrypointForDebug::Program(format!( + "{:p}", + *instruction as ErasedProcessInstruction + )), + Entrypoint::Loader(instruction) => EntrypointForDebug::Loader(format!( + "{:p}", + *instruction as ErasedProcessInstructionWithContext + )), + }; + write!(f, "{:?}", entrypoint) + } +} + +#[derive(Clone, Debug)] pub struct Builtin { pub name: String, pub id: Pubkey, @@ -156,7 +183,7 @@ impl Builtin { } /// Copy-on-write holder of CachedExecutors -#[derive(AbiExample, Default)] +#[derive(AbiExample, Debug, Default)] struct CowCachedExecutors { shared: bool, executors: Arc>, @@ -200,7 +227,7 @@ impl AbiExample for Builtin { } } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Builtins { /// Builtin programs that are always available pub genesis_builtins: Vec, @@ -212,6 +239,7 @@ pub struct Builtins { const MAX_CACHED_EXECUTORS: usize = 100; // 10 MB assuming programs are around 100k /// LFU Cache of executors +#[derive(Debug)] struct CachedExecutors { max: usize, executors: HashMap)>, @@ -289,7 +317,7 @@ impl CachedExecutors { } } -#[derive(Default)] +#[derive(Default, Debug)] pub struct BankRc { /// where all the Accounts are stored pub accounts: Arc, @@ -330,7 +358,7 @@ impl BankRc { } } -#[derive(Default, AbiExample)] +#[derive(Default, Debug, AbiExample)] pub struct StatusCacheRc { /// where all the Accounts are stored /// A cache of signature statuses @@ -411,7 +439,7 @@ impl HashAgeKind { // Bank's common fields shared by all supported snapshot versions for deserialization. // Sync fields with BankFieldsToSerialize! This is paired with it. // All members are made public to remain Bank's members private and to make versioned deserializer workable on this -#[derive(Clone, Default)] +#[derive(Clone, Debug, Default)] pub(crate) struct BankFieldsToDeserialize { pub(crate) blockhash_queue: BlockhashQueue, pub(crate) ancestors: Ancestors, @@ -558,7 +586,7 @@ pub struct RewardInfo { /// Manager for the state of all accounts and programs after processing its entries. /// AbiExample is needed even without Serialize/Deserialize; actual (de-)serialization /// are implemented elsewhere for versioning -#[derive(AbiExample, Default)] +#[derive(AbiExample, Debug, Default)] pub struct Bank { /// References to accounts, parent and signature status pub rc: BankRc, @@ -9319,6 +9347,7 @@ mod tests { } } + #[derive(Debug)] struct TestExecutor {} impl Executor for TestExecutor { fn execute( @@ -9972,4 +10001,34 @@ mod tests { )) ); } + + #[test] + fn test_debug_bank() { + let (genesis_config, _mint_keypair) = create_genesis_config(50000); + let mut bank = Bank::new(&genesis_config); + bank.finish_init(&genesis_config, None); + let debug = format!("{:#?}", bank); + assert!(!debug.is_empty()); + } + + #[test] + fn test_debug_entrypoint() { + fn mock_process_instruction( + _program_id: &Pubkey, + _keyed_accounts: &[KeyedAccount], + _data: &[u8], + ) -> std::result::Result<(), InstructionError> { + Ok(()) + } + fn mock_ix_processor( + _pubkey: &Pubkey, + _ka: &[KeyedAccount], + _data: &[u8], + _context: &mut dyn InvokeContext, + ) -> std::result::Result<(), InstructionError> { + Ok(()) + } + assert!(!format!("{:?}", Entrypoint::Program(mock_process_instruction)).is_empty()); + assert!(!format!("{:?}", Entrypoint::Loader(mock_ix_processor)).is_empty()); + } } diff --git a/runtime/src/feature_set.rs b/runtime/src/feature_set.rs index 2450035ab2..979519e21d 100644 --- a/runtime/src/feature_set.rs +++ b/runtime/src/feature_set.rs @@ -112,7 +112,7 @@ lazy_static! { } /// `FeatureSet` holds the set of currently active/inactive runtime features -#[derive(AbiExample, Clone)] +#[derive(AbiExample, Debug, Clone)] pub struct FeatureSet { pub active: HashSet, pub inactive: HashSet, diff --git a/runtime/src/message_processor.rs b/runtime/src/message_processor.rs index e0d0e723b9..35bb5ad756 100644 --- a/runtime/src/message_processor.rs +++ b/runtime/src/message_processor.rs @@ -1679,7 +1679,7 @@ mod tests { _ka: &[KeyedAccount], _data: &[u8], _context: &mut dyn InvokeContext, - ) -> std::result::Result<(), InstructionError> { + ) -> Result<(), InstructionError> { Ok(()) } let program_id = Pubkey::new_rand(); diff --git a/runtime/src/process_instruction.rs b/runtime/src/process_instruction.rs index c4cbd6778f..529181a819 100644 --- a/runtime/src/process_instruction.rs +++ b/runtime/src/process_instruction.rs @@ -8,7 +8,7 @@ use solana_sdk::{ message::Message, pubkey::Pubkey, }; -use std::{cell::RefCell, rc::Rc, sync::Arc}; +use std::{cell::RefCell, fmt::Debug, rc::Rc, sync::Arc}; // Prototype of a native loader entry point /// @@ -174,7 +174,7 @@ pub trait Logger { } /// Program executor -pub trait Executor: Send + Sync { +pub trait Executor: Debug + Send + Sync { /// Execute the program fn execute( &self,