Substrate (2)- 运行与调试
运行节点
对于学习Substrate而言,一开始只需要能够单节点运行即可。能够使用cargo build
以后,执行
cargo run --bin substrate -- --help
# 等价于 ./target/debug/substate -- --help
请先浏览一下帮助信息,因为其中包含许多重要的启动命令。这将帮助您对可用的选项有一个初步了解。
注意: 在此上下文中,我们使用了--bin substrate
选项,因为Substrate在编译后会生成多个可执行文件,但我们目前只关注substrate
即可。
运行单节点
这里推荐运行单节点的方式为:
cargo run --bin substrate -- --dev -d .sub --execution=NativeElseWasm
--dev
是运行单节点的命令,具体内容请看help-d
是--base-path
的简写,用于指定数据跟目录的,请注意若不指定这个目录,会默认把数据放在用户的目录下,linux系的操作系统将会放于~/.local/share/substrate
目录下,mac os 位于~/Library/Application Support/substrate
与windows 位于%APPDATA%\substrate
(例如c:\User\<you account>\AppData\Roaming\substrate
)下。具体原理请参见这个库app-dirs--execution
是节点采用的执行方式,这里采用NativeElseWasm,尽量以Native的方式运行。
按CTRL+C
可以中断进程退出。
请注意,只有当日志中出现以下日志时
Starting consensus # 共识准备
Pre-sealed block for proposing at <块高>, 区块hash, 父区块hash, 该区块中的交易hash # 预打包区块,其中的交易
Imported #<块高> # 区块落盘,一定要看到这一条才表示区块出块流程正常进行
才算区块正常出块。
其中,若编译时使用产生的WASM文件是debug时,或者当前的电脑cpu性能过于弱时,可能会产生以下日志信息:
Discarding proposal for slot {}; block production took too long
您可以在文件bin/node/runtime/src/constants.rs
中进行修改,以应对当前环境的CPU性能较弱的情况。您可以尝试调整出块时间,这是一种临时解决方案,可以暂时规避这个问题。
# 请详细参见附近的注释,该常量用于控制出块时间间隔,因此当 took too long 的时候把出块时间加长
pub const MILLISECS_PER_BLOCK: Moment = 3000;
这个常量,将其修改得大一些,使得出块时间变长,这样第一次加载环境的时候就不会took too long
导致无法出块了。
调试
首先在clion中先设置编译配置,如下图:

然后点击左上角的“+”,选择Cargo command

然后在以下位置配置相应的命令:

在配置Command时,大部分命令与之前的启动命令相同,只需去掉cargo
即可。因此,这里的Command通常对应您平时用于启动的命令。请根据您自己的实际命令进行配置。请注意,在设置断点到runtime内部时,execution
必须为Native
或NativeElseWasm
。
在环境变量(Environment variables)部分,请确保配置了WASM_BUILD_TYPE
。
工作目录(Working directory)应设置为Substrate的根目录。
配置完成后,当您点击"OK"或"确定"按钮时,之前添加的启动命令将会显示为默认配置。
接下来,针对初学者,我们建议在一个每个块都会执行的关键部分下断点,这部分是时间设置。
因此,我们将在文件frame/timestamp/src/lib.rs
的第145行设置断点。

一旦您在frame/timestamp/src/lib.rs
文件的第145行设置好断点,这个位置在每个区块中都会用来设置出块时间。如果您是使用GDB进行开发,可以类似地找到该文件中的相应位置并设置断点。
当您完成断点设置后,只需点击右上角的按钮,它看起来像一个小虫子,来启动调试过程(在进行调试之前,建议先清空数据目录)。

启动调试后,如果正常一会之后将会在断点处停下:

左下方的调用栈是一个非常有用的工具,它可以帮助开发者深入了解代码的运行过程。通过查看调用栈,您可以快速获取许多关于代码执行的重要信息。
另一方面,右侧的"Variables"(变量)窗格提供了有关当前调用栈中数据的详细信息。这对于进行调试非常有用,因为它允许您检查和跟踪变量的值以了解代码的具体状态。
日志
substrate使用了rust默认的日志接口,因此在substrate中看得到这样的日志:
info!(target: "babe", "Creating empty BABE epoch changes on what appears to be first startup.");
请注意info!
的第一个参数是target:
,而不是日志内容。这个是用于日志标签分类打印。由于substrate使用的日志记录器是env_logger
,并且substrate编写了一些运行时解析的代码
client/cli/src/ib.rs:L965
fn init_logger(pattern: &str) {
use ansi_term::Colour;
...
if let Ok(lvl) = std::env::var("RUST_LOG") {
builder.parse_filters(&lvl); // 这里,设置了日志filter
}
...
}
因此,在启动时,您可以通过设置环境变量来筛选和控制日志的内容。例如,如果您想筛选名为"babe"的日志,您可以在启动时进行如下设置:
RUST_LOG=warn;babe=debug cargo run --bin substrate -- --dev -d .sub --execution-NativeElseWasm
# 或者
RUST_LOG=warn;babe=debug ./target/debug/substrate -- --dev -d .sub --execution-NativeElseWasm
同样,在CLion的启动配置中的"Environment variables"中也可以进行此环境变量的配置。这将使您的节点以以下方式运行:
- 打印其他日志的级别将被限制为警告(warning)级别。
- 对于目标(target)为 "babe" 的日志,将打印调试(debug)级别的信息。
通过这种筛选方式,您可以更好地控制日志的输出,这对于节点调试和学习 Substrate 非常有帮助。