From 2e6ba6c60a1328996c953d3694a2698c4b26dc75 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 14 May 2021 12:36:55 +0100 Subject: [PATCH 01/29] Implement `seal_debug_message` --- crates/engine/src/ext.rs | 8 ++-- crates/engine/src/test_api.rs | 42 ++++++++-------- crates/engine/src/tests.rs | 6 +-- crates/env/src/api.rs | 6 +-- crates/env/src/backend.rs | 11 ++++- .../engine/experimental_off_chain/impls.rs | 4 +- .../engine/experimental_off_chain/test_api.rs | 8 ++-- .../off_chain/db/{console.rs => debug_buf.rs} | 48 +++++++++---------- crates/env/src/engine/off_chain/db/mod.rs | 8 ++-- crates/env/src/engine/off_chain/impls.rs | 4 +- crates/env/src/engine/off_chain/mod.rs | 12 ++--- crates/env/src/engine/off_chain/test_api.rs | 8 ++-- crates/env/src/engine/on_chain/ext.rs | 6 +-- crates/env/src/engine/on_chain/impls.rs | 4 +- crates/env/src/lib.rs | 21 ++++++++ examples/contract-transfer/lib.rs | 7 ++- 16 files changed, 115 insertions(+), 88 deletions(-) rename crates/env/src/engine/off_chain/db/{console.rs => debug_buf.rs} (52%) diff --git a/crates/engine/src/ext.rs b/crates/engine/src/ext.rs index 8fa8f900f20..de50e1d0dfa 100644 --- a/crates/engine/src/ext.rs +++ b/crates/engine/src/ext.rs @@ -317,10 +317,10 @@ impl Engine { unimplemented!("off-chain environment does not yet support `restore_to`"); } - /// Prints the given contents to the console log. - pub fn println(&mut self, content: &str) { - self.debug_info.record_println(String::from(content)); - println!("{}", content); + /// Records the given debug message and appends to stdout. + pub fn debug_message(&mut self, message: &str) { + self.debug_info.record_debug_message(String::from(message)); + print!("{}", message); } /// Conduct the BLAKE-2 256-bit hash and place the result into `output`. diff --git a/crates/engine/src/test_api.rs b/crates/engine/src/test_api.rs index 71d7b3e01c0..b3dd43a5b02 100644 --- a/crates/engine/src/test_api.rs +++ b/crates/engine/src/test_api.rs @@ -33,41 +33,41 @@ pub struct EmittedEvent { } #[derive(Clone)] -pub struct RecordedPrintlns { - printlns: Vec, +pub struct RecordedDebugMessages { + debug_messages: Vec, } -impl RecordedPrintlns { +impl RecordedDebugMessages { // Creates a new `Engine instance. pub fn new() -> Self { Self { - printlns: Vec::new(), + debug_messages: Vec::new(), } } - // Records a new println. - pub fn record(&mut self, println: String) { - self.printlns.push(println); + // Records a new debug message. + pub fn record(&mut self, message: String) { + self.debug_messages.push(message); } - // Clears all recorded printlns. + // Clears all recorded debug messages. pub fn clear(&mut self) { - self.printlns.clear(); + self.debug_messages.clear(); } } -impl Default for RecordedPrintlns { +impl Default for RecordedDebugMessages { fn default() -> Self { Self::new() } } -impl IntoIterator for RecordedPrintlns { +impl IntoIterator for RecordedDebugMessages { type Item = String; type IntoIter = std::vec::IntoIter; fn into_iter(self) -> Self::IntoIter { - self.printlns.into_iter() + self.debug_messages.into_iter() } } @@ -76,7 +76,7 @@ pub struct DebugInfo { /// Emitted events recorder. emitted_events: Vec, /// Emitted print messages recorder. - emitted_printlns: RecordedPrintlns, + emitted_debug_messages: RecordedDebugMessages, /// The total number of reads to the storage. count_reads: HashMap, /// The total number of writes to the storage. @@ -96,7 +96,7 @@ impl DebugInfo { pub fn new() -> Self { Self { emitted_events: Vec::new(), - emitted_printlns: RecordedPrintlns::new(), + emitted_debug_messages: RecordedDebugMessages::new(), count_reads: HashMap::new(), count_writes: HashMap::new(), cells_per_account: HashMap::new(), @@ -108,7 +108,7 @@ impl DebugInfo { self.count_reads.clear(); self.count_writes.clear(); self.emitted_events.clear(); - self.emitted_printlns.clear(); + self.emitted_debug_messages.clear(); self.cells_per_account.clear(); } @@ -159,9 +159,9 @@ impl DebugInfo { .unwrap_or(None) } - /// Records a println. - pub fn record_println(&mut self, println: String) { - self.emitted_printlns.record(println); + /// Records a debug message. + pub fn record_debug_message(&mut self, message: String) { + self.emitted_debug_messages.record(message); } /// Records an event. @@ -215,9 +215,9 @@ impl Engine { self.exec_context.callee() } - /// Returns the contents of the past performed environmental `println` in order. - pub fn get_recorded_printlns(&self) -> RecordedPrintlns { - self.debug_info.emitted_printlns.clone() + /// Returns the contents of the past performed environmental `debug_message` in order. + pub fn get_emitted_debug_messages(&self) -> RecordedDebugMessages { + self.debug_info.emitted_debug_messages.clone() } /// Returns the recorded emitted events in order. diff --git a/crates/engine/src/tests.rs b/crates/engine/src/tests.rs index ed83e455577..798f5287de7 100644 --- a/crates/engine/src/tests.rs +++ b/crates/engine/src/tests.rs @@ -115,10 +115,10 @@ fn transfer() { } #[test] -fn printlns() { +fn debug_messages() { let mut engine = Engine::new(); - engine.println("foobar"); - let mut recorded = engine.get_recorded_printlns().into_iter(); + engine.debug_message("foobar"); + let mut recorded = engine.get_emitted_debug_messages().into_iter(); assert_eq!(recorded.next(), Some("foobar".into())); assert_eq!(recorded.next(), None); } diff --git a/crates/env/src/api.rs b/crates/env/src/api.rs index 3656a8ce21d..5e0df2679a2 100644 --- a/crates/env/src/api.rs +++ b/crates/env/src/api.rs @@ -511,10 +511,10 @@ where }) } -/// Prints the given contents to the environmental log. -pub fn debug_println(content: &str) { +/// Appends the given message to the debug message buffer. +pub fn debug_message(message: &str) { ::on_instance(|instance| { - EnvBackend::println(instance, content) + EnvBackend::debug_message(instance, message) }) } diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index f3d3b588822..19f6a85d9e8 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -115,8 +115,15 @@ pub trait EnvBackend { where R: scale::Encode; - /// Prints the given contents to the console log. - fn println(&mut self, content: &str); + /// Emit a custom debug message. + /// + /// The message is appended to the debug buffer which is then supplied to the calling RPC + /// client. This buffer is also printed as a debug message to the node console if the + /// `debug` log level is enabled for the `runtime::contracts` target. + /// + /// This is a no-op if debug message recording is disabled which is always the case + /// when the code is executing on-chain. + fn debug_message(&mut self, content: &str); /// Conducts the crypto hash of the given input and stores the result in `output`. fn hash_bytes(&mut self, input: &[u8], output: &mut ::Type) diff --git a/crates/env/src/engine/experimental_off_chain/impls.rs b/crates/env/src/engine/experimental_off_chain/impls.rs index a1a254e8bbf..1ce60f8bd8b 100644 --- a/crates/env/src/engine/experimental_off_chain/impls.rs +++ b/crates/env/src/engine/experimental_off_chain/impls.rs @@ -225,8 +225,8 @@ impl EnvBackend for EnvInstance { ) } - fn println(&mut self, content: &str) { - self.engine.println(content) + fn debug_message(&mut self, message: &str) { + self.engine.debug_message(message) } fn hash_bytes(&mut self, input: &[u8], output: &mut ::Type) diff --git a/crates/env/src/engine/experimental_off_chain/test_api.rs b/crates/env/src/engine/experimental_off_chain/test_api.rs index 8608270cbe6..e44c9a5d238 100644 --- a/crates/env/src/engine/experimental_off_chain/test_api.rs +++ b/crates/env/src/engine/experimental_off_chain/test_api.rs @@ -23,7 +23,7 @@ use crate::{ Result, }; use core::fmt::Debug; -use ink_engine::test_api::RecordedPrintlns; +use ink_engine::test_api::RecordedDebugMessages; use std::panic::UnwindSafe; /// Record for an emitted event. @@ -129,10 +129,10 @@ where unimplemented!("off-chain environment does not yet support `set_block_entropy`"); } -/// Returns the contents of the past performed environmental `println` in order. -pub fn recorded_printlns() -> RecordedPrintlns { +/// Returns the contents of the past performed environmental debug messages in order. +pub fn recorded_debug_messages() -> RecordedDebugMessages { ::on_instance(|instance| { - instance.engine.get_recorded_printlns() + instance.engine.get_emitted_debug_messages() }) } diff --git a/crates/env/src/engine/off_chain/db/console.rs b/crates/env/src/engine/off_chain/db/debug_buf.rs similarity index 52% rename from crates/env/src/engine/off_chain/db/console.rs rename to crates/env/src/engine/off_chain/db/debug_buf.rs index 67486b4e8f4..8bdcbbcd075 100644 --- a/crates/env/src/engine/off_chain/db/console.rs +++ b/crates/env/src/engine/off_chain/db/debug_buf.rs @@ -14,53 +14,53 @@ use ink_prelude::string::String; -/// A debug console used to print console contents and store them. -pub struct Console { - /// The buffer to store the already pasted contents. - past_prints: Vec, +/// A debug buffer used to store debug messages and print them to stdout. +pub struct DebugBuffer { + /// The buffer to store the emitted debug messages. + past_debug_messages: Vec, } -impl Console { +impl DebugBuffer { /// Creates a new empty console. pub fn new() -> Self { Self { - past_prints: Vec::new(), + past_debug_messages: Vec::new(), } } - /// Resets the console to uninitialized state. + /// Resets the debug buffer to uninitialized state. pub fn reset(&mut self) { - self.past_prints.clear(); + self.past_debug_messages.clear(); } - /// Prints the contents to the actual console and stores them. - pub fn println(&mut self, contents: &str) { - self.past_prints.push(contents.to_string()); - println!("{}", contents); + /// Prints the message to stdout and stores it. + pub fn debug_message(&mut self, message: &str) { + self.past_debug_messages.push(message.to_string()); + print!("{}", message); } - /// Returns an iterator over the past console prints. - pub fn past_prints(&self) -> PastPrints { - PastPrints::new(self) + /// Returns an iterator over the past debug messages. + pub fn past_debug_messages(&self) -> DebugMessages { + DebugMessages::new(self) } } -/// Iterator over the past prints to the console. -pub struct PastPrints<'a> { +/// Iterator over the past debug messages. +pub struct DebugMessages<'a> { /// Iterator over the past printlns. iter: core::slice::Iter<'a, String>, } -impl<'a> PastPrints<'a> { - /// Creates a new iterator over the past console prints. - fn new(console: &'a Console) -> Self { +impl<'a> DebugMessages<'a> { + /// Creates a new iterator over the past debug messages. + fn new(console: &'a DebugBuffer) -> Self { Self { - iter: console.past_prints.iter(), + iter: console.past_debug_messages.iter(), } } } -impl<'a> Iterator for PastPrints<'a> { +impl<'a> Iterator for DebugMessages<'a> { type Item = &'a str; fn next(&mut self) -> Option { @@ -68,13 +68,13 @@ impl<'a> Iterator for PastPrints<'a> { } } -impl<'a> ExactSizeIterator for PastPrints<'a> { +impl<'a> ExactSizeIterator for DebugMessages<'a> { fn len(&self) -> usize { self.iter.len() } } -impl<'a> DoubleEndedIterator for PastPrints<'a> { +impl<'a> DoubleEndedIterator for DebugMessages<'a> { fn next_back(&mut self) -> Option { self.iter.next_back().map(AsRef::as_ref) } diff --git a/crates/env/src/engine/off_chain/db/mod.rs b/crates/env/src/engine/off_chain/db/mod.rs index 100a652127e..42ff658b6ab 100644 --- a/crates/env/src/engine/off_chain/db/mod.rs +++ b/crates/env/src/engine/off_chain/db/mod.rs @@ -15,7 +15,7 @@ mod accounts; mod block; mod chain_spec; -mod console; +mod debug_buf; mod events; mod exec_context; @@ -30,9 +30,9 @@ pub use self::{ }, block::Block, chain_spec::ChainSpec, - console::{ - Console, - PastPrints, + debug_buf::{ + DebugBuffer, + DebugMessages, }, events::{ EmittedEvent, diff --git a/crates/env/src/engine/off_chain/impls.rs b/crates/env/src/engine/off_chain/impls.rs index 1b20f9d51e2..3ae92b99a1c 100644 --- a/crates/env/src/engine/off_chain/impls.rs +++ b/crates/env/src/engine/off_chain/impls.rs @@ -171,8 +171,8 @@ impl EnvBackend for EnvInstance { std::process::exit(flags.into_u32() as i32) } - fn println(&mut self, content: &str) { - self.console.println(content) + fn debug_message(&mut self, message: &str) { + self.debug_buf.debug_message(message) } fn hash_bytes(&mut self, input: &[u8], output: &mut ::Type) diff --git a/crates/env/src/engine/off_chain/mod.rs b/crates/env/src/engine/off_chain/mod.rs index 5dc11e5a0d5..d6a4cb43deb 100644 --- a/crates/env/src/engine/off_chain/mod.rs +++ b/crates/env/src/engine/off_chain/mod.rs @@ -29,7 +29,7 @@ pub use self::{ db::{ AccountError, EmittedEvent, - PastPrints, + DebugMessages, }, typed_encoded::TypedEncodedError, }; @@ -40,7 +40,7 @@ use self::{ AccountsDb, Block, ChainSpec, - Console, + DebugBuffer, EmittedEventsRecorder, ExecContext, }, @@ -84,8 +84,8 @@ pub struct EnvInstance { chain_spec: ChainSpec, /// The blocks of the chain. blocks: Vec, - /// The console to print debug contents. - console: Console, + /// The debug buffer to collect debug messages and print them to stdout. + debug_buf: DebugBuffer, /// Handler for registered chain extensions. chain_extension_handler: ChainExtensionHandler, /// Emitted events recorder. @@ -102,7 +102,7 @@ impl EnvInstance { exec_context: Vec::new(), chain_spec: ChainSpec::uninitialized(), blocks: Vec::new(), - console: Console::new(), + debug_buf: DebugBuffer::new(), chain_extension_handler: ChainExtensionHandler::new(), emitted_events: EmittedEventsRecorder::new(), clear_storage_disabled: false, @@ -133,7 +133,7 @@ impl EnvInstance { self.exec_context.clear(); self.chain_spec.reset(); self.blocks.clear(); - self.console.reset(); + self.debug_buf.reset(); self.chain_extension_handler.reset(); self.emitted_events.reset(); self.clear_storage_disabled = false; diff --git a/crates/env/src/engine/off_chain/test_api.rs b/crates/env/src/engine/off_chain/test_api.rs index 855be01a29c..41c979b9d53 100644 --- a/crates/env/src/engine/off_chain/test_api.rs +++ b/crates/env/src/engine/off_chain/test_api.rs @@ -215,8 +215,8 @@ where Ok(()) } -/// Returns the contents of the past performed environmental `println` in order. -pub fn recorded_printlns() -> impl Iterator { +/// Returns the contents of the past performed environmental debug messages in order. +pub fn recorded_debug_messages() -> impl Iterator { ::on_instance(|instance| { // We return a clone of the recorded strings instead of // references to them since this would require the whole `on_instance` @@ -224,8 +224,8 @@ pub fn recorded_printlns() -> impl Iterator { // ultimately allow leaking those `'static` references to the outside // and potentially lead to terrible bugs such as iterator invalidation. instance - .console - .past_prints() + .debug_buf + .past_debug_messages() .map(ToOwned::to_owned) .collect::>() .into_iter() diff --git a/crates/env/src/engine/on_chain/ext.rs b/crates/env/src/engine/on_chain/ext.rs index 5458d9e5591..49605952506 100644 --- a/crates/env/src/engine/on_chain/ext.rs +++ b/crates/env/src/engine/on_chain/ext.rs @@ -308,7 +308,7 @@ mod sys { pub fn seal_set_rent_allowance(value_ptr: Ptr32<[u8]>, value_len: u32); - pub fn seal_println(str_ptr: Ptr32<[u8]>, str_len: u32); + pub fn seal_debug_message(str_ptr: Ptr32<[u8]>, str_len: u32); pub fn seal_hash_keccak_256( input_ptr: Ptr32<[u8]>, @@ -604,9 +604,9 @@ pub fn random(subject: &[u8], output: &mut &mut [u8]) { extract_from_slice(output, output_len as usize); } -pub fn println(content: &str) { +pub fn debug_message(content: &str) { let bytes = content.as_bytes(); - unsafe { sys::seal_println(Ptr32::from_slice(bytes), bytes.len() as u32) } + unsafe { sys::seal_debug_message(Ptr32::from_slice(bytes), bytes.len() as u32) } } macro_rules! impl_hash_fn { diff --git a/crates/env/src/engine/on_chain/impls.rs b/crates/env/src/engine/on_chain/impls.rs index 48282af1cc3..ef951513721 100644 --- a/crates/env/src/engine/on_chain/impls.rs +++ b/crates/env/src/engine/on_chain/impls.rs @@ -251,8 +251,8 @@ impl EnvBackend for EnvInstance { ext::return_value(flags, enc_return_value); } - fn println(&mut self, content: &str) { - ext::println(content) + fn debug_message(&mut self, content: &str) { + ext::debug_message(content) } fn hash_bytes(&mut self, input: &[u8], output: &mut ::Type) diff --git a/crates/env/src/lib.rs b/crates/env/src/lib.rs index 273e0812172..14dc8f0591f 100644 --- a/crates/env/src/lib.rs +++ b/crates/env/src/lib.rs @@ -99,3 +99,24 @@ pub use self::{ NoChainExtension, }, }; +pub use ink_prelude; + +/// Appends a formatted string to the `debug_message` buffer which will be: +/// - Returned to the caller when the contract is invoked via RPC (*not* via an extrinsic) +/// - Logged as a `debug!` message on the substrate node, which will be printed to the node +/// console's `stdout` when the log level is set to `debug`. +#[macro_export] +macro_rules! debug_print { + ($($arg:tt)*) => ($crate::debug_message($crate::ink_prelude::format!($($arg)*))); +} + +/// Appends a formatted string to the `debug_message` buffer, as per [`debug_print`] but +/// with a newline appended. +#[macro_export] +macro_rules! debug_println { + () => ($crate::print!("\n")); + ($($arg:tt)*) => ({ + $crate::debug_print!($($arg)*); + $crate::debug_print!("\n"); + }) +} diff --git a/examples/contract-transfer/lib.rs b/examples/contract-transfer/lib.rs index f705e3ca63c..0b101b09daa 100644 --- a/examples/contract-transfer/lib.rs +++ b/examples/contract-transfer/lib.rs @@ -58,8 +58,8 @@ pub mod give_me { /// - Panics in case the transfer failed for another reason. #[ink(message)] pub fn give_me(&mut self, value: Balance) { - ink_env::debug_println(&ink_prelude::format!("requested value: {}", value)); - ink_env::debug_println(&ink_prelude::format!( + ink_env::debug_println!("requested value: {}", value); + ink_env::debug_println!( "contract balance: {}", self.env().balance() )); @@ -88,11 +88,10 @@ pub mod give_me { /// allowed to receive value as part of the call. #[ink(message, payable, selector = "0xCAFEBABE")] pub fn was_it_ten(&self) { - let msg = ink_prelude::format!( + ink_env::debug_println!( "received payment: {}", self.env().transferred_balance() ); - ink_env::debug_println(&msg); assert!( self.env().transferred_balance() == 10, "payment was not ten" From fa0fd9e3165710e633867bfa7f61efbc3ca2001f Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 14 May 2021 12:43:37 +0100 Subject: [PATCH 02/29] Update docs --- crates/env/src/engine/off_chain/db/debug_buf.rs | 2 +- crates/lang/macro/src/lib.rs | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/crates/env/src/engine/off_chain/db/debug_buf.rs b/crates/env/src/engine/off_chain/db/debug_buf.rs index 8bdcbbcd075..959c4d7365c 100644 --- a/crates/env/src/engine/off_chain/db/debug_buf.rs +++ b/crates/env/src/engine/off_chain/db/debug_buf.rs @@ -47,7 +47,7 @@ impl DebugBuffer { /// Iterator over the past debug messages. pub struct DebugMessages<'a> { - /// Iterator over the past printlns. + /// Iterator over the past debug messages. iter: core::slice::Iter<'a, String>, } diff --git a/crates/lang/macro/src/lib.rs b/crates/lang/macro/src/lib.rs index 65c41916a08..6f307389fe5 100644 --- a/crates/lang/macro/src/lib.rs +++ b/crates/lang/macro/src/lib.rs @@ -397,7 +397,7 @@ use proc_macro::TokenStream; /// # /// #[ink::contract] /// mod greeter { -/// use ink_prelude::format; +/// use ink_env::debug_println; /// /// #[ink(storage)] /// pub struct Greeter; @@ -406,8 +406,7 @@ use proc_macro::TokenStream; /// #[ink(constructor)] /// pub fn new() -> Self { /// let caller = Self::env().caller(); -/// let message = format!("thanks for instantiation {:?}", caller); -/// ink_env::debug_println(&message); +/// debug_println!("thanks for instantiation {:?}", caller); /// Greeter {} /// } /// @@ -415,8 +414,7 @@ use proc_macro::TokenStream; /// pub fn fund(&self) { /// let caller = self.env().caller(); /// let value = self.env().transferred_balance(); -/// let message = format!("thanks for the funding of {:?} from {:?}", value, caller); -/// ink_env::debug_println(&message); +/// debug_println!("thanks for the funding of {:?} from {:?}", value, caller); /// } /// } /// } From 8e896b31e1505ca89f39fa569bc5308955ed6654 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 14 May 2021 12:51:26 +0100 Subject: [PATCH 03/29] Fmt --- crates/env/src/engine/off_chain/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/env/src/engine/off_chain/mod.rs b/crates/env/src/engine/off_chain/mod.rs index d6a4cb43deb..bb3ce8d41b6 100644 --- a/crates/env/src/engine/off_chain/mod.rs +++ b/crates/env/src/engine/off_chain/mod.rs @@ -28,8 +28,8 @@ pub use self::{ call_data::CallData, db::{ AccountError, - EmittedEvent, DebugMessages, + EmittedEvent, }, typed_encoded::TypedEncodedError, }; From 8738b80627ba7c74498f50f0d29f5179c416efda Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 19 May 2021 13:54:25 +0100 Subject: [PATCH 04/29] Fix debug_print macro --- crates/env/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/env/src/lib.rs b/crates/env/src/lib.rs index 14dc8f0591f..7a315deec72 100644 --- a/crates/env/src/lib.rs +++ b/crates/env/src/lib.rs @@ -107,7 +107,7 @@ pub use ink_prelude; /// console's `stdout` when the log level is set to `debug`. #[macro_export] macro_rules! debug_print { - ($($arg:tt)*) => ($crate::debug_message($crate::ink_prelude::format!($($arg)*))); + ($($arg:tt)*) => ($crate::debug_message(&$crate::ink_prelude::format!($($arg)*))); } /// Appends a formatted string to the `debug_message` buffer, as per [`debug_print`] but From 13e485e8d457adfc45eef7161fa938a7e6eab227 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 19 May 2021 17:11:34 +0100 Subject: [PATCH 05/29] review: use newline char Co-authored-by: Robin Freyler --- crates/env/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/env/src/lib.rs b/crates/env/src/lib.rs index 7a315deec72..0ff13eddbfd 100644 --- a/crates/env/src/lib.rs +++ b/crates/env/src/lib.rs @@ -117,6 +117,6 @@ macro_rules! debug_println { () => ($crate::print!("\n")); ($($arg:tt)*) => ({ $crate::debug_print!($($arg)*); - $crate::debug_print!("\n"); + $crate::debug_print!('\n'); }) } From 23011797cf2d8b50c214e487fc01f380ba227707 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 19 May 2021 17:28:37 +0100 Subject: [PATCH 06/29] Fix example --- examples/contract-transfer/lib.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/contract-transfer/lib.rs b/examples/contract-transfer/lib.rs index 0b101b09daa..0547e4788f9 100644 --- a/examples/contract-transfer/lib.rs +++ b/examples/contract-transfer/lib.rs @@ -62,7 +62,7 @@ pub mod give_me { ink_env::debug_println!( "contract balance: {}", self.env().balance() - )); + ); assert!(value <= self.env().balance(), "insufficient funds!"); @@ -341,8 +341,7 @@ pub mod give_me { ink_env::test::set_caller::(sender); } - fn default_accounts( - ) -> ink_env::test::DefaultAccounts { + fn default_accounts() -> ink_env::test::DefaultAccounts { ink_env::test::default_accounts::() } From 5e091c1b6e93232c236225535a4ed52abc0e02c3 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 20 May 2021 09:41:59 +0100 Subject: [PATCH 07/29] Revert to newline string --- crates/env/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/env/src/lib.rs b/crates/env/src/lib.rs index 0ff13eddbfd..7a315deec72 100644 --- a/crates/env/src/lib.rs +++ b/crates/env/src/lib.rs @@ -117,6 +117,6 @@ macro_rules! debug_println { () => ($crate::print!("\n")); ($($arg:tt)*) => ({ $crate::debug_print!($($arg)*); - $crate::debug_print!('\n'); + $crate::debug_print!("\n"); }) } From 2279a6f897a628811e421cca2ff80506ebefe913 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 20 May 2021 10:00:26 +0100 Subject: [PATCH 08/29] Fmt --- examples/contract-transfer/lib.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/examples/contract-transfer/lib.rs b/examples/contract-transfer/lib.rs index 0547e4788f9..097b204ec5f 100644 --- a/examples/contract-transfer/lib.rs +++ b/examples/contract-transfer/lib.rs @@ -59,10 +59,7 @@ pub mod give_me { #[ink(message)] pub fn give_me(&mut self, value: Balance) { ink_env::debug_println!("requested value: {}", value); - ink_env::debug_println!( - "contract balance: {}", - self.env().balance() - ); + ink_env::debug_println!("contract balance: {}", self.env().balance()); assert!(value <= self.env().balance(), "insufficient funds!"); @@ -341,7 +338,8 @@ pub mod give_me { ink_env::test::set_caller::(sender); } - fn default_accounts() -> ink_env::test::DefaultAccounts { + fn default_accounts( + ) -> ink_env::test::DefaultAccounts { ink_env::test::default_accounts::() } From 9b7b68719d915f0f37ea5b3f5ad7352e08d46912 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 20 May 2021 11:14:41 +0100 Subject: [PATCH 09/29] Single call to debug_print for debug_println! --- crates/env/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/env/src/lib.rs b/crates/env/src/lib.rs index 7a315deec72..52e4b998da9 100644 --- a/crates/env/src/lib.rs +++ b/crates/env/src/lib.rs @@ -114,9 +114,9 @@ macro_rules! debug_print { /// with a newline appended. #[macro_export] macro_rules! debug_println { - () => ($crate::print!("\n")); + () => ($crate::debug_print!("\n")); ($($arg:tt)*) => ({ - $crate::debug_print!($($arg)*); - $crate::debug_print!("\n"); + let msg = $crate::ink_prelude::format!($($arg)*); + $crate::debug_print!("{}\n", msg); }) } From c2b656c50aeb2c01ba0eb0d31a27d7f7a25cfec1 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 20 May 2021 12:05:15 +0100 Subject: [PATCH 10/29] Add missing ReturnCode, still need to handle it --- crates/env/src/engine/on_chain/ext.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/env/src/engine/on_chain/ext.rs b/crates/env/src/engine/on_chain/ext.rs index 49605952506..2d784930bc3 100644 --- a/crates/env/src/engine/on_chain/ext.rs +++ b/crates/env/src/engine/on_chain/ext.rs @@ -308,7 +308,7 @@ mod sys { pub fn seal_set_rent_allowance(value_ptr: Ptr32<[u8]>, value_len: u32); - pub fn seal_debug_message(str_ptr: Ptr32<[u8]>, str_len: u32); + pub fn seal_debug_message(str_ptr: Ptr32<[u8]>, str_len: u32) -> ReturnCode; pub fn seal_hash_keccak_256( input_ptr: Ptr32<[u8]>, @@ -606,7 +606,10 @@ pub fn random(subject: &[u8], output: &mut &mut [u8]) { pub fn debug_message(content: &str) { let bytes = content.as_bytes(); - unsafe { sys::seal_debug_message(Ptr32::from_slice(bytes), bytes.len() as u32) } + // todo: handle return code + let _ret_code = unsafe { + sys::seal_debug_message(Ptr32::from_slice(bytes), bytes.len() as u32) + }; } macro_rules! impl_hash_fn { From 4fa9f1e1476b408b551064c9bb80fcb193c96073 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 20 May 2021 14:39:56 +0100 Subject: [PATCH 11/29] Inline debug_println! --- crates/env/src/lib.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/crates/env/src/lib.rs b/crates/env/src/lib.rs index 52e4b998da9..4a9d4a517e8 100644 --- a/crates/env/src/lib.rs +++ b/crates/env/src/lib.rs @@ -115,8 +115,7 @@ macro_rules! debug_print { #[macro_export] macro_rules! debug_println { () => ($crate::debug_print!("\n")); - ($($arg:tt)*) => ({ - let msg = $crate::ink_prelude::format!($($arg)*); - $crate::debug_print!("{}\n", msg); - }) + ($($arg:tt)*) => ( + $crate::debug_print!("{}\n", $crate::ink_prelude::format!($($arg)*)); + ) } From be0c00d8c1355f41047ef9a2851585bf4f8ea58b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 20 May 2021 16:11:42 +0100 Subject: [PATCH 12/29] If logging is disabled then subsequent calls will be a no-op --- crates/engine/src/ext.rs | 3 +++ crates/env/src/backend.rs | 4 ++-- crates/env/src/engine/on_chain/ext.rs | 29 ++++++++++++++++++++----- crates/env/src/engine/on_chain/impls.rs | 1 + crates/env/src/error.rs | 3 +++ 5 files changed, 32 insertions(+), 8 deletions(-) diff --git a/crates/engine/src/ext.rs b/crates/engine/src/ext.rs index de50e1d0dfa..6bb8b6a402e 100644 --- a/crates/engine/src/ext.rs +++ b/crates/engine/src/ext.rs @@ -91,6 +91,9 @@ define_error_codes! { CodeNotFound = 7, /// The account that was called is either no contract (e.g. user account) or is a tombstone. NotCallable = 8, + /// The call to `seal_debug_message` had no effect because debug message + /// recording was disabled. + LoggingDisabled = 9, } /// The raw return code returned by the host side. diff --git a/crates/env/src/backend.rs b/crates/env/src/backend.rs index 19f6a85d9e8..b79903ba0ea 100644 --- a/crates/env/src/backend.rs +++ b/crates/env/src/backend.rs @@ -121,8 +121,8 @@ pub trait EnvBackend { /// client. This buffer is also printed as a debug message to the node console if the /// `debug` log level is enabled for the `runtime::contracts` target. /// - /// This is a no-op if debug message recording is disabled which is always the case - /// when the code is executing on-chain. + /// If debug message recording is disabled in the contracts pallet, which is always the case + /// when the code is executing on-chain, then this will have no effect. fn debug_message(&mut self, content: &str); /// Conducts the crypto hash of the given input and stores the result in `output`. diff --git a/crates/env/src/engine/on_chain/ext.rs b/crates/env/src/engine/on_chain/ext.rs index 2d784930bc3..627d770966d 100644 --- a/crates/env/src/engine/on_chain/ext.rs +++ b/crates/env/src/engine/on_chain/ext.rs @@ -76,6 +76,9 @@ define_error_codes! { CodeNotFound = 7, /// The account that was called is either no contract (e.g. user account) or is a tombstone. NotCallable = 8, + /// The call to `seal_debug_message` had no effect because debug message + /// recording was disabled. + LoggingDisabled = 9, } /// Thin-wrapper around a `u32` representing a pointer for Wasm32. @@ -604,12 +607,26 @@ pub fn random(subject: &[u8], output: &mut &mut [u8]) { extract_from_slice(output, output_len as usize); } -pub fn debug_message(content: &str) { - let bytes = content.as_bytes(); - // todo: handle return code - let _ret_code = unsafe { - sys::seal_debug_message(Ptr32::from_slice(bytes), bytes.len() as u32) - }; +/// If debug message recording is disabled in the contracts pallet, this will be set to false +/// after an initial call in order to prevent the cost of further calls which will have no effect. +static mut DEBUG_ENABLED: bool = true; + +/// Call `seal_debug_message` with the supplied UTF-8 encoded message. +/// +/// If debug message recording is disabled in the contracts pallet, the first call to will return +/// a LoggingDisabled error, and further calls will be a no-op to avoid the cost of calling into +/// the supervisor. +pub fn debug_message(message: &str) { + if unsafe { DEBUG_ENABLED } { + let bytes = message.as_bytes(); + let ret_code = unsafe { + sys::seal_debug_message(Ptr32::from_slice(bytes), bytes.len() as u32) + }; + match ret_code.into() { + Err(Error::LoggingDisabled) => unsafe { DEBUG_ENABLED = false }, + _ => () + } + } } macro_rules! impl_hash_fn { diff --git a/crates/env/src/engine/on_chain/impls.rs b/crates/env/src/engine/on_chain/impls.rs index ef951513721..29a11ee2610 100644 --- a/crates/env/src/engine/on_chain/impls.rs +++ b/crates/env/src/engine/on_chain/impls.rs @@ -106,6 +106,7 @@ impl From for Error { ext::Error::NewContractNotFunded => Self::NewContractNotFunded, ext::Error::CodeNotFound => Self::CodeNotFound, ext::Error::NotCallable => Self::NotCallable, + ext::Error::LoggingDisabled => Self::LoggingDisabled, } } } diff --git a/crates/env/src/error.rs b/crates/env/src/error.rs index 32d4a145504..854f821b8d5 100644 --- a/crates/env/src/error.rs +++ b/crates/env/src/error.rs @@ -46,6 +46,9 @@ pub enum Error { NotCallable, /// An unknown error has occurred. UnknownError, + /// The call to `seal_debug_message` had no effect because debug message + /// recording was disabled. + LoggingDisabled, } /// A result of environmental operations. From 62f6b106976149488f2ddd2fb87cb5f3ec036261 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 20 May 2021 16:49:52 +0100 Subject: [PATCH 13/29] Fmt --- crates/engine/src/ext.rs | 4 ++-- crates/env/src/engine/on_chain/ext.rs | 6 +++--- crates/env/src/error.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/engine/src/ext.rs b/crates/engine/src/ext.rs index 6bb8b6a402e..60bd8d06533 100644 --- a/crates/engine/src/ext.rs +++ b/crates/engine/src/ext.rs @@ -92,8 +92,8 @@ define_error_codes! { /// The account that was called is either no contract (e.g. user account) or is a tombstone. NotCallable = 8, /// The call to `seal_debug_message` had no effect because debug message - /// recording was disabled. - LoggingDisabled = 9, + /// recording was disabled. + LoggingDisabled = 9, } /// The raw return code returned by the host side. diff --git a/crates/env/src/engine/on_chain/ext.rs b/crates/env/src/engine/on_chain/ext.rs index 627d770966d..e7cc24ec5f6 100644 --- a/crates/env/src/engine/on_chain/ext.rs +++ b/crates/env/src/engine/on_chain/ext.rs @@ -77,8 +77,8 @@ define_error_codes! { /// The account that was called is either no contract (e.g. user account) or is a tombstone. NotCallable = 8, /// The call to `seal_debug_message` had no effect because debug message - /// recording was disabled. - LoggingDisabled = 9, + /// recording was disabled. + LoggingDisabled = 9, } /// Thin-wrapper around a `u32` representing a pointer for Wasm32. @@ -624,7 +624,7 @@ pub fn debug_message(message: &str) { }; match ret_code.into() { Err(Error::LoggingDisabled) => unsafe { DEBUG_ENABLED = false }, - _ => () + _ => (), } } } diff --git a/crates/env/src/error.rs b/crates/env/src/error.rs index 854f821b8d5..babd7c2e743 100644 --- a/crates/env/src/error.rs +++ b/crates/env/src/error.rs @@ -47,7 +47,7 @@ pub enum Error { /// An unknown error has occurred. UnknownError, /// The call to `seal_debug_message` had no effect because debug message - /// recording was disabled. + /// recording was disabled. LoggingDisabled, } From 43aba01142d3abc403b81ed88de929b5562d3631 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 20 May 2021 16:57:32 +0100 Subject: [PATCH 14/29] Fix missing error match in experimental off-chain --- crates/env/src/engine/experimental_off_chain/impls.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/env/src/engine/experimental_off_chain/impls.rs b/crates/env/src/engine/experimental_off_chain/impls.rs index 1ce60f8bd8b..e3980e9bae0 100644 --- a/crates/env/src/engine/experimental_off_chain/impls.rs +++ b/crates/env/src/engine/experimental_off_chain/impls.rs @@ -109,6 +109,7 @@ impl From for crate::Error { ext::Error::NewContractNotFunded => Self::NewContractNotFunded, ext::Error::CodeNotFound => Self::CodeNotFound, ext::Error::NotCallable => Self::NotCallable, + ext::Error::LoggingDisabled => Self::LoggingDisabled, } } } From b978d76d0994a6ea43f48a334651425ffcf2bb44 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 20 May 2021 17:20:58 +0100 Subject: [PATCH 15/29] Add safety comment to debug_message --- crates/env/src/engine/on_chain/ext.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crates/env/src/engine/on_chain/ext.rs b/crates/env/src/engine/on_chain/ext.rs index e7cc24ec5f6..a5ce184bb3d 100644 --- a/crates/env/src/engine/on_chain/ext.rs +++ b/crates/env/src/engine/on_chain/ext.rs @@ -616,6 +616,11 @@ static mut DEBUG_ENABLED: bool = true; /// If debug message recording is disabled in the contracts pallet, the first call to will return /// a LoggingDisabled error, and further calls will be a no-op to avoid the cost of calling into /// the supervisor. +/// +/// # Safety +/// +/// Accesses to the static `DEBUG_ENABLED` are safe because we are executing in a single-threaded +/// environment. pub fn debug_message(message: &str) { if unsafe { DEBUG_ENABLED } { let bytes = message.as_bytes(); From 35fcf72ad20205dc1d17ea21c4f4d6a26fd9e9c5 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 20 May 2021 17:33:22 +0100 Subject: [PATCH 16/29] Only re-export ink_prelude::format, and explain --- crates/env/src/lib.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/crates/env/src/lib.rs b/crates/env/src/lib.rs index 4a9d4a517e8..fb1d06a5797 100644 --- a/crates/env/src/lib.rs +++ b/crates/env/src/lib.rs @@ -99,7 +99,12 @@ pub use self::{ NoChainExtension, }, }; -pub use ink_prelude; + +/// Required by the `debug_print*` macros below, because there is no guarantee that contracts will +/// have a direct `ink_prelude` dependency. In the future we could introduce an "umbrella" crate +/// containing all the `ink!` crates which could also host these macros. +#[doc(hidden)] +pub use ink_prelude::format; /// Appends a formatted string to the `debug_message` buffer which will be: /// - Returned to the caller when the contract is invoked via RPC (*not* via an extrinsic) @@ -107,7 +112,7 @@ pub use ink_prelude; /// console's `stdout` when the log level is set to `debug`. #[macro_export] macro_rules! debug_print { - ($($arg:tt)*) => ($crate::debug_message(&$crate::ink_prelude::format!($($arg)*))); + ($($arg:tt)*) => ($crate::debug_message(&$crate::format!($($arg)*))); } /// Appends a formatted string to the `debug_message` buffer, as per [`debug_print`] but @@ -116,6 +121,6 @@ macro_rules! debug_print { macro_rules! debug_println { () => ($crate::debug_print!("\n")); ($($arg:tt)*) => ( - $crate::debug_print!("{}\n", $crate::ink_prelude::format!($($arg)*)); + $crate::debug_print!("{}\n", $crate::format!($($arg)*)); ) } From d96dea07366bbccff9626d0fee5340b6bda90c5f Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 20 May 2021 17:35:10 +0100 Subject: [PATCH 17/29] Satisfy clippy --- crates/env/src/engine/on_chain/ext.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/env/src/engine/on_chain/ext.rs b/crates/env/src/engine/on_chain/ext.rs index a5ce184bb3d..d71d255f148 100644 --- a/crates/env/src/engine/on_chain/ext.rs +++ b/crates/env/src/engine/on_chain/ext.rs @@ -627,9 +627,8 @@ pub fn debug_message(message: &str) { let ret_code = unsafe { sys::seal_debug_message(Ptr32::from_slice(bytes), bytes.len() as u32) }; - match ret_code.into() { - Err(Error::LoggingDisabled) => unsafe { DEBUG_ENABLED = false }, - _ => (), + if let Err(Error::LoggingDisabled) = ret_code.into() { + unsafe { DEBUG_ENABLED = false } } } } From efa66bb4de544ac0dd1ebe72535844b63cfe1152 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 21 May 2021 10:52:51 +0100 Subject: [PATCH 18/29] Encapsulate DEBUG_ENABLED global in module --- crates/env/src/engine/on_chain/ext.rs | 52 ++++++++++++++++----------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/crates/env/src/engine/on_chain/ext.rs b/crates/env/src/engine/on_chain/ext.rs index d71d255f148..a344b0e94ee 100644 --- a/crates/env/src/engine/on_chain/ext.rs +++ b/crates/env/src/engine/on_chain/ext.rs @@ -20,6 +20,8 @@ use crate::ReturnFlags; use core::marker::PhantomData; use ink_primitives::Key; +pub use self::debug::debug_message; + macro_rules! define_error_codes { ( $( @@ -607,28 +609,36 @@ pub fn random(subject: &[u8], output: &mut &mut [u8]) { extract_from_slice(output, output_len as usize); } -/// If debug message recording is disabled in the contracts pallet, this will be set to false -/// after an initial call in order to prevent the cost of further calls which will have no effect. -static mut DEBUG_ENABLED: bool = true; +mod debug { + use super::*; -/// Call `seal_debug_message` with the supplied UTF-8 encoded message. -/// -/// If debug message recording is disabled in the contracts pallet, the first call to will return -/// a LoggingDisabled error, and further calls will be a no-op to avoid the cost of calling into -/// the supervisor. -/// -/// # Safety -/// -/// Accesses to the static `DEBUG_ENABLED` are safe because we are executing in a single-threaded -/// environment. -pub fn debug_message(message: &str) { - if unsafe { DEBUG_ENABLED } { - let bytes = message.as_bytes(); - let ret_code = unsafe { - sys::seal_debug_message(Ptr32::from_slice(bytes), bytes.len() as u32) - }; - if let Err(Error::LoggingDisabled) = ret_code.into() { - unsafe { DEBUG_ENABLED = false } + /// If debug message recording is disabled in the contracts pallet, this will be set to false + /// after an initial call in order to prevent the cost of further calls which will have no effect. + static mut DEBUG_ENABLED: bool = true; + + /// Call `seal_debug_message` with the supplied UTF-8 encoded message. + /// + /// If debug message recording is disabled in the contracts pallet, the first call to will return + /// a LoggingDisabled error, and further calls will be a no-op to avoid the cost of calling into + /// the supervisor. + /// + /// # Note + /// + /// This depends on the currently dsiabled + /// + /// # Safety + /// + /// Accesses to the static `DEBUG_ENABLED` are safe because we are executing in a single-threaded + /// environment. + pub fn debug_message(message: &str) { + if unsafe { DEBUG_ENABLED } { + let bytes = message.as_bytes(); + let ret_code = unsafe { + sys::seal_debug_message(Ptr32::from_slice(bytes), bytes.len() as u32) + }; + if let Err(Error::LoggingDisabled) = ret_code.into() { + unsafe { DEBUG_ENABLED = false } + } } } } From 3c1b5a173b72f81609e3f9f195864b9706e71c0a Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 21 May 2021 11:16:52 +0100 Subject: [PATCH 19/29] Move seal_denug_message to unstable module --- crates/env/src/engine/on_chain/ext.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/env/src/engine/on_chain/ext.rs b/crates/env/src/engine/on_chain/ext.rs index a344b0e94ee..51e9108f2f8 100644 --- a/crates/env/src/engine/on_chain/ext.rs +++ b/crates/env/src/engine/on_chain/ext.rs @@ -313,8 +313,6 @@ mod sys { pub fn seal_set_rent_allowance(value_ptr: Ptr32<[u8]>, value_len: u32); - pub fn seal_debug_message(str_ptr: Ptr32<[u8]>, str_len: u32) -> ReturnCode; - pub fn seal_hash_keccak_256( input_ptr: Ptr32<[u8]>, input_len: u32, @@ -346,6 +344,11 @@ mod sys { output_len_ptr: Ptr32Mut, ); } + + #[link(wasm_import_module = "__unstable__")] + extern "C" { + pub fn seal_debug_message(str_ptr: Ptr32<[u8]>, str_len: u32) -> ReturnCode; + } } fn extract_from_slice(output: &mut &mut [u8], new_len: usize) { From 682ec0f647280333c30b951ffd04707272ffd81b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Fri, 21 May 2021 11:39:46 +0100 Subject: [PATCH 20/29] Update unstable and safety comments --- crates/env/src/engine/on_chain/ext.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/crates/env/src/engine/on_chain/ext.rs b/crates/env/src/engine/on_chain/ext.rs index 51e9108f2f8..53ff202ca5f 100644 --- a/crates/env/src/engine/on_chain/ext.rs +++ b/crates/env/src/engine/on_chain/ext.rs @@ -621,25 +621,23 @@ mod debug { /// Call `seal_debug_message` with the supplied UTF-8 encoded message. /// - /// If debug message recording is disabled in the contracts pallet, the first call to will return - /// a LoggingDisabled error, and further calls will be a no-op to avoid the cost of calling into - /// the supervisor. + /// If debug message recording is disabled in the contracts pallet, the first call to will + /// return LoggingDisabled error, and further calls will be a no-op to avoid the cost of calling + /// into the supervisor. /// /// # Note /// - /// This depends on the currently dsiabled - /// - /// # Safety - /// - /// Accesses to the static `DEBUG_ENABLED` are safe because we are executing in a single-threaded - /// environment. + /// This depends on the the `seal_debug_message` interface which requires the + /// `"pallet-contracts/unstable-interface"` feature to be enabled in the target runtime. pub fn debug_message(message: &str) { + // SAFETY: safe because executing in a single threaded context if unsafe { DEBUG_ENABLED } { let bytes = message.as_bytes(); let ret_code = unsafe { sys::seal_debug_message(Ptr32::from_slice(bytes), bytes.len() as u32) }; if let Err(Error::LoggingDisabled) = ret_code.into() { + // SAFETY: safe because executing in a single threaded context unsafe { DEBUG_ENABLED = false } } } From db05bd93b73d1ac2362299600521ff3bed95a9b5 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 24 May 2021 10:18:42 +0100 Subject: [PATCH 21/29] Add more comments about the required features to be enabled on the node runtime --- crates/env/src/lib.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/crates/env/src/lib.rs b/crates/env/src/lib.rs index fb1d06a5797..6182d8b1d12 100644 --- a/crates/env/src/lib.rs +++ b/crates/env/src/lib.rs @@ -110,6 +110,11 @@ pub use ink_prelude::format; /// - Returned to the caller when the contract is invoked via RPC (*not* via an extrinsic) /// - Logged as a `debug!` message on the substrate node, which will be printed to the node /// console's `stdout` when the log level is set to `debug`. +/// +/// # Note +/// +/// This depends on the the `seal_debug_message` interface which requires the +/// `"pallet-contracts/unstable-interface"` feature to be enabled in the target runtime. #[macro_export] macro_rules! debug_print { ($($arg:tt)*) => ($crate::debug_message(&$crate::format!($($arg)*))); @@ -117,6 +122,11 @@ macro_rules! debug_print { /// Appends a formatted string to the `debug_message` buffer, as per [`debug_print`] but /// with a newline appended. +/// +/// # Note +/// +/// This depends on the the `seal_debug_message` interface which requires the +/// `"pallet-contracts/unstable-interface"` feature to be enabled in the target runtime. #[macro_export] macro_rules! debug_println { () => ($crate::debug_print!("\n")); From c6419504df67b1068b6549e309e8f6814474d18d Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 24 May 2021 11:14:12 +0100 Subject: [PATCH 22/29] Add `ink-debug` feature, make debug messages a noop if not enabled --- crates/env/Cargo.toml | 2 + crates/env/src/engine/on_chain/ext.rs | 9 +++ crates/env/src/lib.rs | 83 +++++++++++++++++---------- 3 files changed, 63 insertions(+), 31 deletions(-) diff --git a/crates/env/Cargo.toml b/crates/env/Cargo.toml index bb712d4b48a..559a272107d 100644 --- a/crates/env/Cargo.toml +++ b/crates/env/Cargo.toml @@ -61,4 +61,6 @@ std = [ "sha3", "blake2", ] +# Enable contract debug messages via `debug_print!` and `debug_println!`. +ink-debug = [] ink-experimental-engine = ["ink_engine"] diff --git a/crates/env/src/engine/on_chain/ext.rs b/crates/env/src/engine/on_chain/ext.rs index 53ff202ca5f..9dcbe63e18b 100644 --- a/crates/env/src/engine/on_chain/ext.rs +++ b/crates/env/src/engine/on_chain/ext.rs @@ -345,6 +345,7 @@ mod sys { ); } + #[cfg(feature = "ink-debug")] #[link(wasm_import_module = "__unstable__")] extern "C" { pub fn seal_debug_message(str_ptr: Ptr32<[u8]>, str_len: u32) -> ReturnCode; @@ -612,6 +613,7 @@ pub fn random(subject: &[u8], output: &mut &mut [u8]) { extract_from_slice(output, output_len as usize); } +#[cfg(feature = "ink-debug")] mod debug { use super::*; @@ -644,6 +646,13 @@ mod debug { } } +#[cfg(not(feature = "ink-debug"))] +mod debug { + /// A no-op. Enable the `ink-debug` feature for debug messages. + pub fn debug_message(_message: &str) { + } +} + macro_rules! impl_hash_fn { ( $name:ident, $bytes_result:literal ) => { paste::item! { diff --git a/crates/env/src/lib.rs b/crates/env/src/lib.rs index 6182d8b1d12..5273384be33 100644 --- a/crates/env/src/lib.rs +++ b/crates/env/src/lib.rs @@ -100,37 +100,58 @@ pub use self::{ }, }; -/// Required by the `debug_print*` macros below, because there is no guarantee that contracts will -/// have a direct `ink_prelude` dependency. In the future we could introduce an "umbrella" crate -/// containing all the `ink!` crates which could also host these macros. -#[doc(hidden)] -pub use ink_prelude::format; +cfg_if::cfg_if! { + if #[cfg(feature = "ink-debug")] { + /// Required by the `debug_print*` macros below, because there is no guarantee that contracts will + /// have a direct `ink_prelude` dependency. In the future we could introduce an "umbrella" crate + /// containing all the `ink!` crates which could also host these macros. + #[doc(hidden)] + pub use ink_prelude::format; -/// Appends a formatted string to the `debug_message` buffer which will be: -/// - Returned to the caller when the contract is invoked via RPC (*not* via an extrinsic) -/// - Logged as a `debug!` message on the substrate node, which will be printed to the node -/// console's `stdout` when the log level is set to `debug`. -/// -/// # Note -/// -/// This depends on the the `seal_debug_message` interface which requires the -/// `"pallet-contracts/unstable-interface"` feature to be enabled in the target runtime. -#[macro_export] -macro_rules! debug_print { - ($($arg:tt)*) => ($crate::debug_message(&$crate::format!($($arg)*))); -} + /// Appends a formatted string to the `debug_message` buffer which will be: + /// - Returned to the caller when the contract is invoked via RPC (*not* via an extrinsic) + /// - Logged as a `debug!` message on the substrate node, which will be printed to the node + /// console's `stdout` when the log level is set to `debug`. + /// + /// # Note + /// + /// This depends on the the `seal_debug_message` interface which requires the + /// `"pallet-contracts/unstable-interface"` feature to be enabled in the target runtime. + #[cfg(feature = "ink-debug")] + #[macro_export] + macro_rules! debug_print { + ($($arg:tt)*) => ($crate::debug_message(&$crate::format!($($arg)*))); + } -/// Appends a formatted string to the `debug_message` buffer, as per [`debug_print`] but -/// with a newline appended. -/// -/// # Note -/// -/// This depends on the the `seal_debug_message` interface which requires the -/// `"pallet-contracts/unstable-interface"` feature to be enabled in the target runtime. -#[macro_export] -macro_rules! debug_println { - () => ($crate::debug_print!("\n")); - ($($arg:tt)*) => ( - $crate::debug_print!("{}\n", $crate::format!($($arg)*)); - ) + /// Appends a formatted string to the `debug_message` buffer, as per [`debug_print`] but + /// with a newline appended. + /// + /// # Note + /// + /// This depends on the the `seal_debug_message` interface which requires the + /// `"pallet-contracts/unstable-interface"` feature to be enabled in the target runtime. + #[cfg(feature = "ink-debug")] + #[macro_export] + macro_rules! debug_println { + () => ($crate::debug_print!("\n")); + ($($arg:tt)*) => ( + $crate::debug_print!("{}\n", $crate::format!($($arg)*)); + ) + } + } else { + #[macro_export] + /// Debug messages disabled. Enable the `ink-debug` feature for contract debugging. + macro_rules! debug_print { + ($($arg:tt)*) => (debug_assert!(true)); + } + + #[macro_export] + /// Debug messages disabled. Enable the `ink-debug` feature for contract debugging. + macro_rules! debug_println { + () => (debug_assert!(true)); + ($($arg:tt)*) => ( + debug_assert!(true) + ) + } + } } From 89c3536adb3b599013415c932b57f117984c0ed2 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 24 May 2021 11:16:51 +0100 Subject: [PATCH 23/29] Fmt --- crates/env/src/engine/on_chain/ext.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/env/src/engine/on_chain/ext.rs b/crates/env/src/engine/on_chain/ext.rs index 9dcbe63e18b..91f5268199b 100644 --- a/crates/env/src/engine/on_chain/ext.rs +++ b/crates/env/src/engine/on_chain/ext.rs @@ -649,8 +649,7 @@ mod debug { #[cfg(not(feature = "ink-debug"))] mod debug { /// A no-op. Enable the `ink-debug` feature for debug messages. - pub fn debug_message(_message: &str) { - } + pub fn debug_message(_message: &str) {} } macro_rules! impl_hash_fn { From 1fa7246c83f95881d8af0b127c72d33a7a36aff4 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 24 May 2021 11:20:07 +0100 Subject: [PATCH 24/29] Noop macro formatting --- crates/env/src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/env/src/lib.rs b/crates/env/src/lib.rs index 5273384be33..2a06493e6f0 100644 --- a/crates/env/src/lib.rs +++ b/crates/env/src/lib.rs @@ -149,9 +149,7 @@ cfg_if::cfg_if! { /// Debug messages disabled. Enable the `ink-debug` feature for contract debugging. macro_rules! debug_println { () => (debug_assert!(true)); - ($($arg:tt)*) => ( - debug_assert!(true) - ) + ($($arg:tt)*) => (debug_assert!(true)) } } } From dba097bd66efd0154354a4b204773d99da8268e5 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 24 May 2021 12:13:07 +0100 Subject: [PATCH 25/29] Enable debug printing for std --- crates/env/src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/env/src/lib.rs b/crates/env/src/lib.rs index 2a06493e6f0..71d688a13d8 100644 --- a/crates/env/src/lib.rs +++ b/crates/env/src/lib.rs @@ -101,7 +101,7 @@ pub use self::{ }; cfg_if::cfg_if! { - if #[cfg(feature = "ink-debug")] { + if #[cfg(any(feature = "ink-debug", feature = "std"))] { /// Required by the `debug_print*` macros below, because there is no guarantee that contracts will /// have a direct `ink_prelude` dependency. In the future we could introduce an "umbrella" crate /// containing all the `ink!` crates which could also host these macros. @@ -117,7 +117,6 @@ cfg_if::cfg_if! { /// /// This depends on the the `seal_debug_message` interface which requires the /// `"pallet-contracts/unstable-interface"` feature to be enabled in the target runtime. - #[cfg(feature = "ink-debug")] #[macro_export] macro_rules! debug_print { ($($arg:tt)*) => ($crate::debug_message(&$crate::format!($($arg)*))); @@ -130,7 +129,6 @@ cfg_if::cfg_if! { /// /// This depends on the the `seal_debug_message` interface which requires the /// `"pallet-contracts/unstable-interface"` feature to be enabled in the target runtime. - #[cfg(feature = "ink-debug")] #[macro_export] macro_rules! debug_println { () => ($crate::debug_print!("\n")); From 0de9b94dfc6be03bb26b0c1b639ef239e7887515 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 24 May 2021 12:14:40 +0100 Subject: [PATCH 26/29] Comment formatting --- crates/env/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/env/src/lib.rs b/crates/env/src/lib.rs index 71d688a13d8..8ec831e0a86 100644 --- a/crates/env/src/lib.rs +++ b/crates/env/src/lib.rs @@ -102,9 +102,9 @@ pub use self::{ cfg_if::cfg_if! { if #[cfg(any(feature = "ink-debug", feature = "std"))] { - /// Required by the `debug_print*` macros below, because there is no guarantee that contracts will - /// have a direct `ink_prelude` dependency. In the future we could introduce an "umbrella" crate - /// containing all the `ink!` crates which could also host these macros. + /// Required by the `debug_print*` macros below, because there is no guarantee that + /// contracts will have a direct `ink_prelude` dependency. In the future we could introduce + /// an "umbrella" crate containing all the `ink!` crates which could also host these macros. #[doc(hidden)] pub use ink_prelude::format; From 57624062bee5c4904cd59a81e3096e78905fbf91 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 25 May 2021 09:36:05 +0100 Subject: [PATCH 27/29] Encapsulate static variable inside the function --- crates/env/src/engine/on_chain/ext.rs | 54 +++++++++++---------------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/crates/env/src/engine/on_chain/ext.rs b/crates/env/src/engine/on_chain/ext.rs index 91f5268199b..f11ae03a483 100644 --- a/crates/env/src/engine/on_chain/ext.rs +++ b/crates/env/src/engine/on_chain/ext.rs @@ -20,8 +20,6 @@ use crate::ReturnFlags; use core::marker::PhantomData; use ink_primitives::Key; -pub use self::debug::debug_message; - macro_rules! define_error_codes { ( $( @@ -614,43 +612,35 @@ pub fn random(subject: &[u8], output: &mut &mut [u8]) { } #[cfg(feature = "ink-debug")] -mod debug { - use super::*; - - /// If debug message recording is disabled in the contracts pallet, this will be set to false - /// after an initial call in order to prevent the cost of further calls which will have no effect. +/// Call `seal_debug_message` with the supplied UTF-8 encoded message. +/// +/// If debug message recording is disabled in the contracts pallet, the first call to will +/// return LoggingDisabled error, and further calls will be a no-op to avoid the cost of calling +/// into the supervisor. +/// +/// # Note +/// +/// This depends on the the `seal_debug_message` interface which requires the +/// `"pallet-contracts/unstable-interface"` feature to be enabled in the target runtime. +pub fn debug_message(message: &str) { static mut DEBUG_ENABLED: bool = true; - /// Call `seal_debug_message` with the supplied UTF-8 encoded message. - /// - /// If debug message recording is disabled in the contracts pallet, the first call to will - /// return LoggingDisabled error, and further calls will be a no-op to avoid the cost of calling - /// into the supervisor. - /// - /// # Note - /// - /// This depends on the the `seal_debug_message` interface which requires the - /// `"pallet-contracts/unstable-interface"` feature to be enabled in the target runtime. - pub fn debug_message(message: &str) { - // SAFETY: safe because executing in a single threaded context - if unsafe { DEBUG_ENABLED } { - let bytes = message.as_bytes(); - let ret_code = unsafe { - sys::seal_debug_message(Ptr32::from_slice(bytes), bytes.len() as u32) - }; - if let Err(Error::LoggingDisabled) = ret_code.into() { - // SAFETY: safe because executing in a single threaded context - unsafe { DEBUG_ENABLED = false } - } + // SAFETY: safe because executing in a single threaded context + if unsafe { DEBUG_ENABLED } { + let bytes = message.as_bytes(); + let ret_code = unsafe { + sys::seal_debug_message(Ptr32::from_slice(bytes), bytes.len() as u32) + }; + if let Err(Error::LoggingDisabled) = ret_code.into() { + // SAFETY: safe because executing in a single threaded context + unsafe { DEBUG_ENABLED = false } } } } #[cfg(not(feature = "ink-debug"))] -mod debug { - /// A no-op. Enable the `ink-debug` feature for debug messages. - pub fn debug_message(_message: &str) {} -} +/// A no-op. Enable the `ink-debug` feature for debug messages. +pub fn debug_message(_message: &str) {} macro_rules! impl_hash_fn { ( $name:ident, $bytes_result:literal ) => { From 0524daa4018b2cab367d0ef91ec4fe092ebe5cc0 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 27 May 2021 15:23:46 +0100 Subject: [PATCH 28/29] Fmt --- crates/env/src/engine/on_chain/ext.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/env/src/engine/on_chain/ext.rs b/crates/env/src/engine/on_chain/ext.rs index c243db0e6f6..d621247bef4 100644 --- a/crates/env/src/engine/on_chain/ext.rs +++ b/crates/env/src/engine/on_chain/ext.rs @@ -346,10 +346,7 @@ mod sys { #[link(wasm_import_module = "__unstable__")] extern "C" { #[cfg(feature = "ink-debug")] - pub fn seal_debug_message( - str_ptr: Ptr32<[u8]>, - str_len: u32 - ) -> ReturnCode; + pub fn seal_debug_message(str_ptr: Ptr32<[u8]>, str_len: u32) -> ReturnCode; pub fn seal_rent_params( output_ptr: Ptr32Mut<[u8]>, From 61d02809d67276489b88fbb789cbbe5d76a8fce5 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 27 May 2021 15:57:01 +0100 Subject: [PATCH 29/29] Remove debug_assert!(true) for disabled macros --- crates/env/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/env/src/lib.rs b/crates/env/src/lib.rs index d4b0e7f1b67..ffe56c5dc56 100644 --- a/crates/env/src/lib.rs +++ b/crates/env/src/lib.rs @@ -143,14 +143,14 @@ cfg_if::cfg_if! { #[macro_export] /// Debug messages disabled. Enable the `ink-debug` feature for contract debugging. macro_rules! debug_print { - ($($arg:tt)*) => (debug_assert!(true)); + ($($arg:tt)*) => (); } #[macro_export] /// Debug messages disabled. Enable the `ink-debug` feature for contract debugging. macro_rules! debug_println { - () => (debug_assert!(true)); - ($($arg:tt)*) => (debug_assert!(true)) + () => (); + ($($arg:tt)*) => (); } } }