今天我们来讲讲在开发pallet的时候如何调试。在pallet开发时主要有以下几种调试方式:
- logging uilities;
- printable trait;
- print函数;
- if_std.
下面我们来一一演示。
首先我们进入到substrate-node-template/pallets目录下,拷贝template然后命名为Debug,然后修改包名为pallet-debug。然后修改runtime中的内容将pallet-debug加载到runtime中。对于这几步不会的可以看我们前面的讲解,基本上我们每新加一个pallet都会使用这步。
接下来就是在pallet-debug中进行修改。
这种方式就是使用log包进行打印,需要在pallet-debug的Cargo.toml中添加依赖如下:
[dependencies]
...
log = { version = "0.4.14", default-features = false }
...
[features]
default = ["std"]
std = [
...
"log/std",
"sp-runtime/std",
"sp-std/std",
]
然后我们可以在lib.rs的代码中使用log进行打印,如下:
pub fn do_something(origin: OriginFor<T>, something: u32) -> DispatchResult {
let who = ensure_signed(origin)?;
<Something<T>>::put(something);
log::info!("|||||||||||||||||||||| called by {:?}", who);
Self::deposit_event(Event::SomethingStored(something, who));
Ok(())
}
此种方式我们需要为需要打印的类型实现printable trait,在我们的示例中我们主要为Error类型实现对应的trait,然后再进行打印,需要修改代码如下:
use sp_runtime::traits::Printable;
use sp_runtime::print;
...
#[pallet::error]
pub enum Error<T> {
NoneValue,
StorageOverflow,
}
impl<T: Config> Printable for Error<T> {
fn print(&self) {
match self {
Error::NoneValue => "Invalid Value".print(),
Error::StorageOverflow => "++++++++++++++++++++++++++ Value Exceeded and Overflowed".print(),
_ => "Invalid Error Case".print(),
}
}
}
...
#[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))]
pub fn cause_error(origin: OriginFor<T>) -> DispatchResult {
log::info!("|||||||||||||||||||||| cause error");
let _who = ensure_signed(origin)?;
match <Something<T>>::get() {
None => {
//下面一行打印对应的错误
print(Error::<T>::NoneValue);
Err(Error::<T>::NoneValue)?
},
Some(old) => {
log::info!("|||||||||||||||||||||| 2 error");
let new = old.checked_add(1).ok_or({
//下面一行打印对应的错误
print(Error::<T>::StorageOverflow);
Error::<T>::StorageOverflow
})?;
<Something<T>>::put(new);
Ok(())
},
}
}
此处直接使用print进行打印,不过使用前也需要引入use sp_runtime::print;
打印的示例代码如下:
#[pallet::weight(10_000 + T::DbWeight::get().writes(1))]
pub fn do_something(origin: OriginFor<T>, something: u32) -> DispatchResult {
let who = ensure_signed(origin)?;
<Something<T>>::put(something);
//示例代码
print("After storing my_val");
Self::deposit_event(Event::SomethingStored(something, who));
Ok(())
}
此种方式我本地没有实验成功,有兴趣的小伙伴可以研究研究。示例代码如下:
use sp_std::if_std;
...
#[pallet::weight(10_000 + T::DbWeight::get().writes(1))]
pub fn do_something(origin: OriginFor<T>, something: u32) -> DispatchResult {
let who = ensure_signed(origin)?;
<Something<T>>::put(something);
if_std! {
println!("Hello native world!");
println!("My value is: {:#?}", something);
println!("The caller account is: {:#?}", who);
}
Self::deposit_event(Event::SomethingStored(something, who));
Ok(())
}