diff --git a/README.md b/README.md index e7e9eb98..42cb2f2b 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,6 @@ To use the `entrypoint!` macro, use the following in your entrypoint definition: use pinocchio::{ account::AccountView, entrypoint, - msg, ProgramResult, Address }; @@ -82,7 +81,6 @@ pub fn process_instruction( accounts: &[AccountView], instruction_data: &[u8], ) -> ProgramResult { - msg!("Hello from my program!"); Ok(()) } ``` @@ -114,7 +112,6 @@ use pinocchio::{ default_panic_handler, entrypoint::InstructionContext, lazy_program_entrypoint, - msg, ProgramResult }; @@ -125,7 +122,6 @@ default_panic_handler!(); pub fn process_instruction( mut context: InstructionContext ) -> ProgramResult { - msg!("Hello from my lazy program!"); Ok(()) } ``` @@ -149,7 +145,6 @@ To use the `no_allocator!` macro, use the following in your entrypoint definitio use pinocchio::{ account::AccountView, default_panic_handler, - msg, no_allocator, program_entrypoint, ProgramResult, @@ -165,7 +160,6 @@ pub fn process_instruction( accounts: &[AccountView], instruction_data: &[u8], ) -> ProgramResult { - msg!("Hello from `no_std` program!"); Ok(()) } ``` @@ -174,13 +168,15 @@ pub fn process_instruction( ## Crate feature: `std` -By default, `pinocchio` is a `no_std` crate. This means that it does not use any code from the standard (`std`) library. While this does not affect how `pinocchio` is used, there is one particular apparent difference. In a `no_std` environment, the `msg!` macro does not provide any formatting options since the `format!` macro requires the `std` library. In order to use `msg!` with formatting, the `std` feature should be enabled when adding `pinocchio` as a dependency: +By default, Pinocchio is a `no_std` crate. This means that it does not use any code from the +standard (`std`) library. While this does not affect how Pinocchio is used, there is a one +particular apparent difference. Helpers that need to allocate memory, such as fetching `SlotHashes` +sysvar data, are not available. To enable these helpers, the `std` feature must be enabled when adding +Pinocchio as a dependency: ``` -pinocchio = { version = "0.7.0", features = ["std"] } +pinocchio = { version = "0.10.0", features = ["std"] } ``` -Instead of enabling the `std` feature to be able to format log messages with `msg!`, it is recommended to use the [`pinocchio-log`](https://crates.io/crates/pinocchio-log) crate. This crate provides a lightweight `log!` macro with better compute units consumption than the standard `format!` macro without requiring the `std` library. - ## Advance entrypoint configuration The symbols emitted by the entrypoint macros — program entrypoint, global allocator and default panic handler — can only be defined once globally. If the program crate is also intended to be used as a library, it is common practice to define a Cargo [feature](https://doc.rust-lang.org/cargo/reference/features.html) in your program crate to conditionally enable the module that includes the `entrypoint!` macro invocation. The convention is to name the feature `bpf-entrypoint`. @@ -191,7 +187,6 @@ mod entrypoint { use pinocchio::{ account::AccountView, entrypoint, - msg, ProgramResult, Address }; @@ -203,7 +198,6 @@ mod entrypoint { accounts: &[AccountView], instruction_data: &[u8], ) -> ProgramResult { - msg!("Hello from my program!"); Ok(()) } } diff --git a/sdk/pinocchio/src/entrypoint/lazy.rs b/sdk/pinocchio/src/entrypoint/lazy.rs index de65f384..0574cc83 100644 --- a/sdk/pinocchio/src/entrypoint/lazy.rs +++ b/sdk/pinocchio/src/entrypoint/lazy.rs @@ -62,7 +62,6 @@ macro_rules! lazy_entrypoint { /// default_panic_handler, /// entrypoint::InstructionContext, /// lazy_program_entrypoint, -/// msg, /// ProgramResult /// }; /// @@ -73,7 +72,6 @@ macro_rules! lazy_entrypoint { /// pub fn process_instruction( /// mut context: InstructionContext, /// ) -> ProgramResult { -/// msg!("Hello from my `lazy` program!"); /// Ok(()) /// } /// diff --git a/sdk/pinocchio/src/entrypoint/mod.rs b/sdk/pinocchio/src/entrypoint/mod.rs index 04479313..e998cd29 100644 --- a/sdk/pinocchio/src/entrypoint/mod.rs +++ b/sdk/pinocchio/src/entrypoint/mod.rs @@ -94,7 +94,6 @@ const STATIC_ACCOUNT_DATA: usize = size_of::() + MAX_PERMITTED_DATA_INC /// use pinocchio::{ /// AccountView, /// entrypoint, -/// msg, /// Address, /// ProgramResult /// }; @@ -106,7 +105,6 @@ const STATIC_ACCOUNT_DATA: usize = size_of::() + MAX_PERMITTED_DATA_INC /// accounts: &[AccountView], /// instruction_data: &[u8], /// ) -> ProgramResult { -/// msg!("Hello from my program!"); /// Ok(()) /// } /// @@ -434,35 +432,10 @@ pub unsafe fn deserialize( (program_id, processed, instruction_data) } -/// Default panic hook. -/// -/// This macro sets up a default panic hook that logs the panic message and the file where the panic -/// occurred. It acts as a hook after Rust runtime panics; syscall `abort()` will be called after it -/// returns. -/// -/// Note that this requires the `"std"` feature to be enabled. -#[cfg(feature = "std")] -#[macro_export] -macro_rules! default_panic_handler { - () => { - /// Default panic handler. - #[cfg(target_os = "solana")] - #[no_mangle] - fn custom_panic(info: &core::panic::PanicInfo<'_>) { - // Panic reporting. - $crate::msg!("{}", info); - } - }; -} - /// Default panic hook. /// /// This macro sets up a default panic hook that logs the file where the panic occurred. It acts as /// a hook after Rust runtime panics; syscall `abort()` will be called after it returns. -/// -/// This is used when the `"std"` feature is disabled, while either the program or any of its -/// dependencies are not `no_std`. -#[cfg(not(feature = "std"))] #[macro_export] macro_rules! default_panic_handler { () => { @@ -471,10 +444,12 @@ macro_rules! default_panic_handler { #[no_mangle] fn custom_panic(info: &core::panic::PanicInfo<'_>) { if let Some(location) = info.location() { - $crate::log::sol_log(location.file()); + let location = location.file(); + unsafe { $crate::syscalls::sol_log_(location.as_ptr(), location.len() as u64) }; } // Panic reporting. - $crate::log::sol_log("** PANICKED **"); + const PANICKED: &str = "** PANICKED **"; + unsafe { $crate::syscalls::sol_log_(PANICKED.as_ptr(), PANICKED.len() as u64) }; } }; } @@ -505,8 +480,11 @@ macro_rules! nostd_panic_handler { } } else { // Panic reporting. - $crate::log::sol_log("** PANICKED **"); - unsafe { $crate::syscalls::abort() } + const PANICKED: &str = "** PANICKED **"; + unsafe { + $crate::syscalls::sol_log_(PANICKED.as_ptr(), PANICKED.len() as u64); + $crate::syscalls::abort(); + } } } diff --git a/sdk/pinocchio/src/lib.rs b/sdk/pinocchio/src/lib.rs index 1af537a1..add5cc56 100644 --- a/sdk/pinocchio/src/lib.rs +++ b/sdk/pinocchio/src/lib.rs @@ -36,7 +36,6 @@ //! AccountView, //! Address, //! entrypoint, -//! msg, //! ProgramResult //! }; //! @@ -47,7 +46,6 @@ //! accounts: &[AccountView], //! instruction_data: &[u8], //! ) -> ProgramResult { -//! msg!("Hello from my program!"); //! Ok(()) //! } //! ``` @@ -97,7 +95,6 @@ //! default_panic_handler, //! entrypoint::InstructionContext, //! lazy_program_entrypoint, -//! msg, //! ProgramResult //! }; //! @@ -108,7 +105,6 @@ //! pub fn process_instruction( //! mut context: InstructionContext //! ) -> ProgramResult { -//! msg!("Hello from my lazy program!"); //! Ok(()) //! } //! ``` @@ -142,7 +138,6 @@ //! AccountView, //! Address, //! default_panic_handler, -//! msg, //! no_allocator, //! program_entrypoint, //! ProgramResult @@ -157,7 +152,6 @@ //! accounts: &[AccountView], //! instruction_data: &[u8], //! ) -> ProgramResult { -//! msg!("Hello from `no_std` program!"); //! Ok(()) //! } //! ``` @@ -170,19 +164,14 @@ //! //! By default, Pinocchio is a `no_std` crate. This means that it does not use any //! code from the standard (`std`) library. While this does not affect how Pinocchio -//! is used, there is a one particular apparent difference. In a `no_std` environment, -//! the [`msg!`] macro does not provide any formatting options since the `format!` macro -//! requires the `std` library. In order to use [`msg!`] with formatting, the `std` -//! feature should be enable when adding Pinocchio as a dependency: +//! is used, there is a one particular apparent difference. Helpers that need to +//! allocate memory, such as fetching `SlotHashes` sysvar, are not available. To +//! enable these helpers, the `std` feature must be enabled when adding Pinocchio +//! as a dependency: //! ```ignore -//! pinocchio = { version = "0.7.0", features = ["std"] } +//! pinocchio = { version = "0.10.0", features = ["std"] } //! ``` //! -//! Instead of enabling the `std` feature to be able to format log messages with [`msg!`], -//! it is recommended to use the [`pinocchio-log`](https://crates.io/crates/pinocchio-log) -//! crate. This crate provides a lightweight `log!` macro with better compute units -//! consumption than the standard `format!` macro without requiring the `std` library. -//! //! ## Advanced entrypoint configuration //! //! The symbols emitted by the entrypoint macros - program entrypoint, global @@ -199,7 +188,6 @@ //! AccountView, //! Address, //! entrypoint, -//! msg, //! ProgramResult //! }; //! @@ -210,7 +198,6 @@ //! accounts: &[AccountView], //! instruction_data: &[u8], //! ) -> ProgramResult { -//! msg!("Hello from my program!"); //! Ok(()) //! } //! } @@ -227,7 +214,6 @@ extern crate std; pub mod entrypoint; -pub mod log; pub mod syscalls; pub mod sysvars; diff --git a/sdk/pinocchio/src/log.rs b/sdk/pinocchio/src/log.rs deleted file mode 100644 index 54754f07..00000000 --- a/sdk/pinocchio/src/log.rs +++ /dev/null @@ -1,172 +0,0 @@ -//! Logging utilities for Rust-based Solana programs. -//! -//! Logging is the main mechanism for getting debugging information out of -//! running Solana programs, and there are several functions available for doing -//! so efficiently, depending on the type of data being logged. -//! -//! The most common way to emit logs is through the [`msg!`] macro, which logs -//! simple strings, as well as [formatted strings][fs]. -//! -//! [`msg!`]: crate::msg! -//! [fs]: https://doc.rust-lang.org/std/fmt/ -//! -//! Logs can be viewed in multiple ways: -//! -//! - The `solana logs` command displays logs for all transactions executed on a -//! network. Note though that transactions that fail during pre-flight -//! simulation are not displayed here. -//! - When submitting transactions via [`RpcClient`], if Rust's own logging is -//! active then the `solana_rpc_client` crate logs at the "debug" level any logs -//! for transactions that failed during simulation. If using [`env_logger`] -//! these logs can be activated by setting `RUST_LOG=solana_rpc_client=debug`. -//! - Logs can be retrieved from a finalized transaction by calling -//! [`RpcClient::get_transaction`]. -//! - Block explorers may display logs. -//! -//! [`RpcClient`]: https://docs.rs/solana-rpc-client/latest/solana_rpc_client/rpc_client/struct.RpcClient.html -//! [`env_logger`]: https://docs.rs/env_logger -//! [`RpcClient::get_transaction`]: https://docs.rs/solana-rpc-client/latest/solana_rpc_client/rpc_client/struct.RpcClient.html#method.get_transaction -//! -//! While most logging functions are defined in this module, [`Address`]es can -//! also be efficiently logged with the [`solana_address::Address::log`] function. -//! -//! [`Address`]: solana_address - -use crate::account::AccountView; - -/// Print a message to the log. -/// -/// Supports simple strings of type `&str`. The expression will be passed -/// directly to [`sol_log`]. This is typically used for logging static strings. -/// -/// # Examples -/// -/// ``` -/// use pinocchio::msg; -/// -/// msg!("verifying multisig"); -/// ``` -#[macro_export] -#[cfg(not(feature = "std"))] -macro_rules! msg { - ( $msg:expr ) => { - $crate::log::sol_log($msg) - }; -} - -/// Print a message to the log. -/// -/// Supports simple strings as well as Rust [format strings][fs]. When passed a -/// single expression it will be passed directly to [`sol_log`]. The expression -/// must have type `&str`, and is typically used for logging static strings. -/// When passed something other than an expression, particularly -/// a sequence of expressions, the tokens will be passed through the -/// [`format!`] macro before being logged with `sol_log`. -/// -/// [fs]: https://doc.rust-lang.org/std/fmt/ -/// [`format!`]: https://doc.rust-lang.org/std/fmt/fn.format.html -/// -/// Note that Rust's formatting machinery is relatively CPU-intensive -/// for constrained environments like the Solana VM. -/// -/// # Examples -/// -/// ``` -/// use pinocchio::msg; -/// -/// // The fast form -/// msg!("verifying multisig"); -/// -/// // With formatting -/// let err = "not enough signers"; -/// msg!("multisig failed: {}", err); -/// ``` -#[cfg(feature = "std")] -#[macro_export] -macro_rules! msg { - ( $msg:expr ) => { - $crate::log::sol_log($msg) - }; - ( $( $arg:tt )* ) => ($crate::log::sol_log(&format!($($arg)*))); -} - -/// Print a string to the log. -#[inline(always)] -pub fn sol_log(message: &str) { - #[cfg(target_os = "solana")] - unsafe { - crate::syscalls::sol_log_(message.as_ptr(), message.len() as u64); - } - - #[cfg(not(target_os = "solana"))] - core::hint::black_box(message); -} - -/// Print 64-bit values represented as hexadecimal to the log. -#[inline] -pub fn sol_log_64(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) { - #[cfg(target_os = "solana")] - unsafe { - crate::syscalls::sol_log_64_(arg1, arg2, arg3, arg4, arg5); - } - - #[cfg(not(target_os = "solana"))] - core::hint::black_box((arg1, arg2, arg3, arg4, arg5)); -} - -/// Print some slices as `base64`. -pub fn sol_log_data(data: &[&[u8]]) { - #[cfg(target_os = "solana")] - unsafe { - crate::syscalls::sol_log_data(data as *const _ as *const u8, data.len() as u64) - }; - - #[cfg(not(target_os = "solana"))] - core::hint::black_box(data); -} - -/// Print the hexadecimal representation of a slice. -pub fn sol_log_slice(slice: &[u8]) { - for (i, s) in slice.iter().enumerate() { - sol_log_64(0, 0, 0, i as u64, *s as u64); - } -} - -/// Print the hexadecimal representation of the program's input parameters. -/// -/// - `accounts` - A slice of [`AccountView`]. -/// - `data` - The instruction data. -pub fn sol_log_params(accounts: &[AccountView], data: &[u8]) { - #[cfg(target_os = "solana")] - { - for (i, account) in accounts.iter().enumerate() { - msg!("AccountInfo"); - sol_log_64(0, 0, 0, 0, i as u64); - msg!("- Is signer"); - sol_log_64(0, 0, 0, 0, account.is_signer() as u64); - msg!("- Key"); - account.address().log(); - msg!("- Lamports"); - sol_log_64(0, 0, 0, 0, account.lamports()); - msg!("- Account data length"); - sol_log_64(0, 0, 0, 0, account.data_len() as u64); - msg!("- Owner"); - // SAFETY: The reference to `owner` in only used for logging. - unsafe { account.owner().log() }; - } - msg!("Instruction data"); - sol_log_slice(data); - } - - #[cfg(not(target_os = "solana"))] - core::hint::black_box((accounts, data)); -} - -/// Print the remaining compute units available to the program. -#[inline] -pub fn sol_log_compute_units() { - #[cfg(target_os = "solana")] - unsafe { - crate::syscalls::sol_log_compute_units_(); - } -}