Skip to content

Commit

Permalink
Implement seal_debug_message (#792)
Browse files Browse the repository at this point in the history
* Implement `seal_debug_message`

* Update docs

* Fmt

* Fix debug_print macro

* review: use newline char

Co-authored-by: Robin Freyler <robin.freyler@gmail.com>

* Fix example

* Revert to newline string

* Fmt

* Single call to debug_print for debug_println!

* Add missing ReturnCode, still need to handle it

* Inline debug_println!

* If logging is disabled then subsequent calls will be a no-op

* Fmt

* Fix missing error match in experimental off-chain

* Add safety comment to debug_message

* Only re-export ink_prelude::format, and explain

* Satisfy clippy

* Encapsulate DEBUG_ENABLED global in module

* Move seal_denug_message to unstable module

* Update unstable and safety comments

* Add more comments about the required features to be enabled on the node runtime

* Add `ink-debug` feature, make debug messages a noop if not enabled

* Fmt

* Noop macro formatting

* Enable debug printing for std

* Comment formatting

* Encapsulate static variable inside the function

* Fmt

* Remove debug_assert!(true) for disabled macros

Co-authored-by: Robin Freyler <robin.freyler@gmail.com>
  • Loading branch information
ascjones and Robbepop authored Jun 9, 2021
1 parent d4fd3f7 commit 2458e0c
Show file tree
Hide file tree
Showing 19 changed files with 192 additions and 99 deletions.
11 changes: 7 additions & 4 deletions crates/engine/src/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -317,10 +320,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`.
Expand Down
42 changes: 21 additions & 21 deletions crates/engine/src/test_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,41 +33,41 @@ pub struct EmittedEvent {
}

#[derive(Clone)]
pub struct RecordedPrintlns {
printlns: Vec<String>,
pub struct RecordedDebugMessages {
debug_messages: Vec<String>,
}

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<Self::Item>;

fn into_iter(self) -> Self::IntoIter {
self.printlns.into_iter()
self.debug_messages.into_iter()
}
}

Expand All @@ -76,7 +76,7 @@ pub struct DebugInfo {
/// Emitted events recorder.
emitted_events: Vec<EmittedEvent>,
/// Emitted print messages recorder.
emitted_printlns: RecordedPrintlns,
emitted_debug_messages: RecordedDebugMessages,
/// The total number of reads to the storage.
count_reads: HashMap<AccountId, usize>,
/// The total number of writes to the storage.
Expand All @@ -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(),
Expand All @@ -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();
}

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down
6 changes: 3 additions & 3 deletions crates/engine/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
2 changes: 2 additions & 0 deletions crates/env/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,6 @@ std = [
"sha3",
"blake2",
]
# Enable contract debug messages via `debug_print!` and `debug_println!`.
ink-debug = []
ink-experimental-engine = ["ink_engine"]
6 changes: 3 additions & 3 deletions crates/env/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -553,10 +553,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) {
<EnvInstance as OnInstance>::on_instance(|instance| {
EnvBackend::println(instance, content)
EnvBackend::debug_message(instance, message)
})
}

Expand Down
11 changes: 9 additions & 2 deletions crates/env/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,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.
///
/// 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`.
fn hash_bytes<H>(&mut self, input: &[u8], output: &mut <H as HashOutput>::Type)
Expand Down
5 changes: 3 additions & 2 deletions crates/env/src/engine/experimental_off_chain/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ impl From<ext::Error> for crate::Error {
ext::Error::NewContractNotFunded => Self::NewContractNotFunded,
ext::Error::CodeNotFound => Self::CodeNotFound,
ext::Error::NotCallable => Self::NotCallable,
ext::Error::LoggingDisabled => Self::LoggingDisabled,
}
}
}
Expand Down Expand Up @@ -227,8 +228,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<H>(&mut self, input: &[u8], output: &mut <H as HashOutput>::Type)
Expand Down
8 changes: 4 additions & 4 deletions crates/env/src/engine/experimental_off_chain/test_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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 {
<EnvInstance as OnInstance>::on_instance(|instance| {
instance.engine.get_recorded_printlns()
instance.engine.get_emitted_debug_messages()
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,67 +14,67 @@

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<String>,
/// 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<String>,
}

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 printlns.
/// Iterator over the past debug messages.
pub struct DebugMessages<'a> {
/// Iterator over the past debug messages.
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<Self::Item> {
self.iter.next().map(AsRef::as_ref)
}
}

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::Item> {
self.iter.next_back().map(AsRef::as_ref)
}
Expand Down
8 changes: 4 additions & 4 deletions crates/env/src/engine/off_chain/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
mod accounts;
mod block;
mod chain_spec;
mod console;
mod debug_buf;
mod events;
mod exec_context;

Expand All @@ -30,9 +30,9 @@ pub use self::{
},
block::Block,
chain_spec::ChainSpec,
console::{
Console,
PastPrints,
debug_buf::{
DebugBuffer,
DebugMessages,
},
events::{
EmittedEvent,
Expand Down
4 changes: 2 additions & 2 deletions crates/env/src/engine/off_chain/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,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<H>(&mut self, input: &[u8], output: &mut <H as HashOutput>::Type)
Expand Down
Loading

0 comments on commit 2458e0c

Please sign in to comment.