天天看点

Substrate 代码debug

作者:ayct01

前言

整理在开发pallet过程中使用到的代码打印控制台。

主要有以下几种:

  • Logging utilities
  • Printable trait
  • print
  • If std

创建项目

进入到/substrate-node-template中,接着进入到目录pallets中,创建我们自己的lfhuang-debug-pallet。并且将这pallet加载到runtime中。

使用Logging utilities

通过使用 log crate 代码包在代码中使用log输出日志,包括debug和info等,和Java类似用法。

需要引入的依赖:

[package]
name = "lfhuang-debug-pallet"
description = "FRAME pallet template for debug"
authors = ["lfhuang"]
...

[dependencies]
log = "0.4.17"
...
           

接着可以在lib.rs业务代码使用log进行打印。

#[pallet::weight(0)]
pub fn do_something(origin: OriginFor<T>, something: u32) -> DispatchResult {
	let who = ensure_signed(origin)?;
	<Something<T>>::put(something);
    // Debug方式一 log
	log::info!(
		"   ######################## called by something:{:?} and signer:{:?}",
		something,
		who
	);
	Self::deposit_event(Event::SomethingStored(something, who));
	Ok(())
}
           

通过调用交易凭证能看到输出日志信息如下:

Substrate 代码debug

使用Printable trait

通过使用Printable trait 代码包实现它,下面通过Error类型实现打印输出日志信息。需要开启debug环境变量模式启动。

当前非test调试代码,所以sp-runtime的相关依赖需要放到[dependencies]依赖下。

...

[dependencies]
sp-runtime = { version = "7.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" }
...
           
// 引入依赖
use sp_runtime::print;
use sp_runtime::traits::Printable;

...
    
#[pallet::error]
pub enum Error<T> {
	/// Value was None
	NoneValue,
	/// Value reached maximum and cannot be incremented further
	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(0)]
pub fn cause_error(origin: OriginFor<T>) -> DispatchResult {
	// 检查是否已签名
	let _who = ensure_signed(origin)?;
	print("   ########### 错误原因... #############");
	match <Something<T>>::get() {
		None => {
			print(Error::<T>::NoneValue);	// Debug方式二,默认是debug级别,所以启动时候把环境变量调整到debug启动
			Err(Error::<T>::NoneValue)?
		},
		Some(old) => {
			let new = old.checked_add(1).ok_or({
				print(Error::<T>::StorageOverflow);
				Error::<T>::StorageOverflow
			})?;
			<Something<T>>::put(new);
			Ok(())
		},
	}
}
           

首次调用cause_error没有值则会报Error::NoneValue错误,需要调用do_something方法设置一个值,接着再掉用cause_error方法则存储值会加1,同时也会报Error::StorageOverflow错误。

Substrate 代码debug

使用print

使用print函数进行调试记录runtime执行状态。需要导入use sp_runtime::print;和上面的Printable trait方式差不多,输出打印日志都使用到了print();需要开启debug环境变量模式启动。

官网例子中的print!();编译报错。部分代码例子如下:

#[pallet::weight(0)]
pub fn do_something(origin: OriginFor<T>, something: u32) -> DispatchResult {
	let who = ensure_signed(origin)?; // 检查是否已签名
	print("   开始设置值..."); // Debug方式三 print,默认是debug级别,所以启动时候把环境变量调整到debug启动
	<Something<T>>::put(something);
	print("   存储值完成...");
	// Debug方式一 log
	log::info!(
		"   ######################## called by something:{:?} and signer:{:?}",
		something,
		who
	);
	Self::deposit_event(Event::SomethingStored(something, who));
	Ok(())
}
           

使用if_std

使用if_std宏的方式实现调试。

...

[dependencies]
sp-std = { version = "5.0.0", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.37" }
...
           
// 引入依赖
use sp_std::if_std;
           

println!语句应该在if_std宏的内部。

#[pallet::weight(0)]
pub fn do_something(origin: OriginFor<T>, something: u32) -> DispatchResult {
	let who = ensure_signed(origin)?; // 检查是否已签名
	print("   开始设置值..."); // Debug方式三 print,默认是debug级别,所以启动时候把环境变量调整到debug启动
	<Something<T>>::put(something);
	print("   存储值完成...");
	// Debug方式一 log
	log::info!(
		"   ######################## called by something:{:?} and signer:{:?}",
		something,
		who
	);
	// Debug方式四 if_std!宏
	if_std! {
		println!("   ################## Hello native world! something value: {}",something);
		println!("   ################## 调用者的交易账户是: {:#?}", who);
	}
	Self::deposit_event(Event::SomethingStored(something, who));
	Ok(())
}
           
Substrate 代码debug

检查编译代码

cargo check -p node-template-runtime --release
           

编译节点模板

返回到项目根目录下/substrate-node-template

cargo build --package node-template --release
           

启动节点

运行一个临时节点,该节点将在流程结束时删除所有配置,指定开发链

./target/release/node-template --tmp --dev
           

使用RUST_LOG环境变量运行节点二进制文件以打印值。

RUST_LOG=runtime=debug ./target/release/node-template --tmp --dev
           

连接节点

1、在浏览器中输入https://polkadot.js.org/apps/#/explorer
2、点击左上角会展开 
3、在展开的菜单中点击 DEVELOPMENT 
4、点击 Local Node 
5、点击 switch (转换到本地网络)           

继续阅读