- 区块链
- 金融科技
【免费下载链接】monero
Monero: the secure, private, untraceable cryptocurrency
导读
Monero 节点在首次同步主网或测试网时,往往需要数小时甚至数天从 P2P 网络逐块同步。为了加速这一过程,Monero 官方在 src/blockchain_utilities 目录下提供了一组区块链工具,其中最核心的是monero-blockchain-export与monero-blockchain-import,用于将区块链数据库导出为独立的blockchain.raw引导文件(bootstrap file),再将其批量导入到新的节点数据库中。读完本文,你将掌握这两款工具的完整命令用法、全部导入选项(含 batch 批量事务、--database复合模式与 LMDB 专属 flags)、数据库安全/性能权衡(safe / fast / fastest),以及如何从源码层面理解其导入验证与断点续传机制。
本文内容以 src/blockchain_utilities/README.md 为骨架,并结合该目录下 blockchain_import.cpp、blockchain_export.cpp、bootstrap_file.cpp、db_lmdb.cpp 等源码进行佐证与扩展。
一、工具概述:区块链导入导出能解决什么问题
区块链工具(Blockchain Utilities)的核心功能是导入与导出区块链数据。主节点守护进程monerod将链数据存放在 LMDB 数据库中;这些工具则负责:
- 将已有的区块链数据库导出为一个扁平的二进制文件
blockchain.raw; - 将该文件导入到另一个(或新初始化的)区块链数据库中;
- 绕过漫长的 P2P 同步过程,实现"离线快照"式的快速建链。
该工具集在构建时由 src/blockchain_utilities/CMakeLists.txt 统一编译,除本文重点的monero-blockchain-import与monero-blockchain-export外,还包含monero-blockchain-usage、monero-blockchain-ancestry、monero-blockchain-depth、monero-blockchain-stats、monero-blockchain-prune、monero-blockchain-prune-known-spent-data等辅助工具。每个工具都支持--help选项查看完整参数说明。
从源码看,导出与导入共用一套文件读写逻辑:BootstrapFile类(定义于 bootstrap_file.h,实现在 bootstrap_file.cpp)负责blockchain.raw引导文件的写出与解析;bootstrap_serialization.h 定义了块包(block package)的序列化结构。此外,monero-blockchain-export还支持通过--blocksdat参数输出另一种blocks.dat格式(由 blocksdat_file.cpp 实现),用于与旧式导入流程兼容。
1.1 引导文件的底层格式要点
理解工具用法前,先了解其产物的结构。从 bootstrap_file.cpp 可以看到:
- 文件以一个 4 字节魔数开头:
blockchain_raw_magic = 0x28721586(由字符串 "Monero bootstrap file" 的 SHA1 前 4 字节而来); - 随后是 1024 字节的头部结构;
- 头部之后是连续的分块(chunk),每个分块包含 4 字节的
chunk_size,随后是该大小的二进制数据块,其中封装了块、交易、块重量(block_weight)、累计难度(cumulative_difficulty)与已生成币量(coins_generated)等字段。
blockchain_utilities.h 还定义了BUFFER_SIZE(2 MB)、CHUNK_SIZE_WARNING_THRESHOLD(500000)、NUM_BLOCKS_PER_CHUNK(1)以及默认文件名常量BLOCKCHAIN_RAW = "blockchain.raw"。这些常量直接决定了导入时单块读取缓冲区的上限与进度提示阈值。
二、导出已有区块链数据库:monero-blockchain-export
2.1 基本用法
$ monero-blockchain-export该命令加载已有的区块链数据库,并将其导出到$MONERO_DATA_DIR/export/blockchain.raw。
默认数据目录(MONERO_DATA_DIR)随网络类型不同而变化,例如 Linux 主网通常为~/.bitmonero。若未通过--output-file指定路径,输出文件路径在源码中由以下逻辑确定(见 blockchain_export.cpp):
if (command_line::has_arg(vm, arg_output_file)) output_file_path = boost::filesystem::path(command_line::get_arg(vm, arg_output_file)); else output_file_path = boost::filesystem::path(m_config_folder) / "export" / BLOCKCHAIN_RAW;即默认写入<data-dir>/export/blockchain.raw。
2.2 导出选项详解
| 选项 | 说明 | 默认值 |
|---|---|---|
--output-file <path> | 指定导出文件的输出路径 | <data-dir>/export/blockchain.raw |
--block-start <n> | 从第 n 个区块开始导出 | 0(从创世块之后开始) |
--block-stop <n> | 导出到第 n 个区块为止 | 导出至链尾 |
--blocksdat | 以blocks.dat格式输出(而非blockchain.raw) | off |
--data-dir <path> | 指定区块链数据库所在目录 | 默认数据目录 |
--testnet/--stagenet/--regtest | 切换网络类型 | 主网 |
--log-level <0-4 或 categories> | 设置日志级别 | 0(bcutil:INFO) |
从 blockchain_export.cpp 的参数注册代码可以看到上述参数与--help输出的对应关系。注意两个使用前提:
- 导出需要完整(未裁剪)的区块链:源码中 blockchain_export.cpp 会检查
get_blockchain_pruning_seed(),若数据库已裁剪(pruned)且未指定--blocksdat,导出会直接失败并提示 "Blockchain is pruned, cannot export"。 - 导出以只读方式打开数据库:工具通过
db->open(filename, DBF_RDONLY)打开 LMDB(blockchain_export.cpp),因此可以在节点关闭或运行期间安全执行(建议节点关闭时执行以避免 IO 竞争)。
导出过程的进度通过refresh_string(回车符刷新当前行)在终端上动态显示,每处理若干区块更新一次"block N / total"进度。
三、导入引导文件:monero-blockchain-import
3.1 基本用法
$ monero-blockchain-import该命令从$MONERO_DATA_DIR/export/blockchain.raw(即由monero-blockchain-export导出的文件)读取区块,导入到当前数据库中。
导入默认值(源码中明确设置):
| 配置项 | 默认值 | 说明 |
|---|---|---|
--batch | on | 以批量事务(batch transaction)方式提交,加快导入速度 |
--batch-size | 20000 | 每个批量事务包含的区块数量,可依据可用 RAM 调整 |
--verify(即默认验证) | on | 导入前对每个块进行完整验证 |
关于默认值,blockchain_import.cpp 中有更细的源码级细节:
- 64 位平台默认
db_batch_size = 20000;32 位平台(ARCH_WIDTH == 32)因 LMDB 大事务的潜在问题,默认降为100; - 开启验证时,为了更频繁地保存进度,默认批量大小降为
db_batch_size_verify = 5000(blockchain_import.cpp 中的逻辑:若用户未显式指定--batch-size且验证开启,则取 5000); --resume默认开启:导入会从当前数据库高度继续,而不是从头开始。
批量大小与 RAM 的关系:--batch-size的单位是区块数而非字节数。批量事务会在内存中累积区块与交易数据,因此更大的 batch size 能减少提交(commit)次数、提高吞吐,但会占用更多内存;在内存有限的机器上应适当调低。
验证开关的安全性:验证(verify)应在导入可信区块链文件时才能关闭。关闭验证意味着完全信任导入文件中的区块与交易,如果文件在传输中被篡改或来自恶意来源,可能导入被污染的数据库。
3.2 标准导入示例
## 使用默认设置将 blockchain.raw 导入数据库 $ monero-blockchain-import ## 快速导入:大 batch size + fastest 数据库模式 + 关闭验证 $ monero-blockchain-import --batch-size 20000 --database lmdb#fastest --verify off3.3 遇到 "resizing not supported in batch mode" 怎么办
如果导入过程中遇到类似resizing not supported in batch mode的错误,只需重新运行monero-blockchain-import命令即可,它会从上次中断的位置继续导入。
这一行为在源码中的支撑点有两处:
--resume默认开启,导入起始高度取当前数据库高度(blockchain_import.cpp):if (opt_resume) start_height = core.get_blockchain_storage().get_current_blockchain_height();- 导入器会先调用
bootstrap.count_blocks(...)统计引导文件中的区块总数,再跳过start_height之前的数据(通过import_file.seekg(pos)定位到断点处),因此重复执行不会重复导入已有区块。
3.4 导入选项参考表
monero-blockchain-import的完整参数(来源 blockchain_import.cpp):
| 选项 | 说明 | 默认值 |
|---|---|---|
--input-file <path> | 指定导入文件的路径 | <data-dir>/export/blockchain.raw |
--output-file <path> | 指定导出文件的路径(导入工具中实际用于其它工具场景) | <data-dir>/export/blockchain.raw |
--block-stop <n> | 导入到第 n 个区块后停止 | 导入至文件末尾 |
--batch-size <n> | 每个批量事务的区块数 | 20000(验证开启时 5000,32 位平台 100) |
--batch <on/off> | 启用/禁用批量事务 | on |
--resume <on/off> | 若目标数据库已存在,从当前高度继续 | on |
--dangerous-unverified-import | 跳过验证,盲信导入文件(仅在自行导出文件时启用) | off |
--count-blocks | 统计引导文件中的区块数后退出 | off |
--pop-blocks <n> | 从链尾移除 n 个区块 | 0 |
--drop-hard-fork | 删除硬分叉子数据库 | off |
--database <type>[#flags] | 指定数据库类型与 flags | lmdb |
--data-dir <path> | 数据库目录 | 默认数据目录 |
--log-level <0-4 或 categories> | 日志级别 | 0 |
其中--count-blocks在源码中实现为:创建BootstrapFile对象后调用bootstrap.count_blocks(import_file_path)并直接返回(blockchain_import.cpp),适合在正式导入前快速校验文件的完整性与区块规模。
3.5 源码视角:验证导入与非验证导入的两条路径
blockchain_import.cpp 中的import_from_file()函数体现了两种导入模式的内部差异:
- 验证模式(默认):解析出区块与交易后,将其打包为
block_complete_entry,调用check_flush()(blockchain_import.cpp)执行prevalidate_block_hashes→prepare_handle_incoming_blocks→handle_incoming_tx→handle_incoming_block的完整校验链路,并依赖core.get_blockchain_storage().get_db().add_block()之前的验证结果决定是否提交。同时,check_flush会等待高度对齐到HASH_OF_HASHES_STEP的倍数时才落盘,以配合哈希树结构加速批量处理。 - 非验证模式(
--dangerous-unverified-import):跳过上述完整校验,直接调用db.add_block(...)写入,并携带引导文件中的block_weight、cumulative_difficulty、coins_generated元数据(blockchain_import.cpp),速度更快但完全信任输入。
此外,启用非验证导入时程序会输出红色警告,并强制暂停 90 秒(sleep(90),见 blockchain_import.cpp),提示用户在此时段内按^C终止,充分说明该模式的危险性。
四、--database 参数:数据库类型、复合模式与 LMDB 专属 flags
--database参数是导入性能调优的核心,语法为:
--database <database type> --database <database type>#<flag(s)>- database type:
lmdb、memory。当前默认且实际可用的后端为lmdb;memory类型用于测试场景。 - flag 语法规则:
#之后的标志,如果只有一个(无逗号分隔),则被解释为复合模式(composite mode);复合模式代表一组数据库 flag 组合,并且支持不同的数据库类型:
| 复合模式 | 含义 |
|---|---|
safe | 安全模式,不牺牲数据一致性换取性能 |
fast | 快速模式,开启部分性能优化 |
fastest | 极速模式,牺牲部分可靠性换取最大吞吐 |
复合模式在源码中的映射关系位于 blockchain_import.cpp 的get_db_flags_from_mode():
int get_db_flags_from_mode(const std::string& db_mode) { int db_flags = 0; if (db_mode == "safe") db_flags = DBF_SAFE; else if (db_mode == "fast") db_flags = DBF_FAST; else if (db_mode == "fastest") db_flags = DBF_FASTEST; return db_flags; }而DBF_SAFE / DBF_FAST / DBF_FASTEST定义于 blockchain_db.h,LMDB 层对它们的实际落实在 db_lmdb.cpp:
if (db_flags & DBF_FAST) mdb_flags |= MDB_NOSYNC; if (db_flags & DBF_FASTEST) mdb_flags |= MDB_NOSYNC | MDB_WRITEMAP | MDB_MAPASYNC;即:
fast→ 开启MDB_NOSYNC(关闭每次事务的磁盘同步);fastest→ 在MDB_NOSYNC基础上再叠加MDB_WRITEMAP(写映射文件)与MDB_MAPASYNC(异步映射刷新),显著降低写放大但增加断电丢数据风险。
4.1 LMDB 专属 flags(可同时指定多个)
除了复合模式,也可以直接指定数据库专属 flag,多个 flag 用逗号分隔:
| flag | 说明 | 对应 LMDB 行为 |
|---|---|---|
nosync | 不进行每次事务后的磁盘同步 | MDB_NOSYNC |
nometasync | 不进行 meta page 的异步同步 | MDB_NOMETASYNC |
writemap | 使用写映射模式 | MDB_WRITEMAP |
mapasync | 异步刷新映射文件 | MDB_MAPASYNC |
nordahead | 关闭预读(readahead),适用于 SSD 等场景 | MDB_NORDAHEAD |
4.2 示例
$ monero-blockchain-import --database lmdb#fastest $ monero-blockchain-import --database lmdb#nosync $ monero-blockchain-import --database lmdb#nosync,nometasync第一条等价于启用MDB_NOSYNC | MDB_WRITEMAP | MDB_MAPASYNC三合一极速模式;第二条仅关闭同步;第三条在关闭同步的同时关闭 meta 页异步同步。
4.3 与 monerod 的 db-sync-mode 的对应关系
对于熟悉monerod守护进程的用户,--database lmdb#fastest与节点启动参数--db-sync-mode fastest:async:100000背后的机制同源:cryptonote_core.cpp 在解析db-sync-mode时同样将safe/fast/fastest映射到DBF_SAFE/DBF_FAST/DBF_FASTEST,并进一步解析sync/async与同步阈值(区块数或字节数)。因此,导入时的模式选择直接决定了导入完成后数据库的落盘策略,fastest 模式导入的数据库在异常断电时可能丢失最近批次的数据,需要重新运行导入命令进行续导。
五、完整实战流程:从导出到导入
以下是一个完整的离线建链工作流示例,演示如何在两台机器(或同一台机器的两次初始化)之间迁移区块链:
# 1. 在源节点上导出(默认输出 <data-dir>/export/blockchain.raw) $ monero-blockchain-export # 2.(可选)校验导出文件中的区块数量 $ monero-blockchain-import --input-file <data-dir>/export/blockchain.raw --count-blocks # 3. 将 blockchain.raw 拷贝到目标机器(或保留在本地) # 4. 在目标节点上导入(默认从 <data-dir>/export/blockchain.raw 读取) $ monero-blockchain-import # 5. 追求速度时的推荐组合: # 大 batch + fastest 模式 + 关闭验证(仅在文件来源可信时) $ monero-blockchain-import --batch-size 20000 --database lmdb#fastest --dangerous-unverified-import # 6. 只导入部分区块(例如同步到某一高度后转由 P2P 补齐) $ monero-blockchain-import --block-stop 2500000注意事项汇总:
- 导出前确认数据库未被裁剪(pruned),否则导出会失败;
- 关闭验证(
--dangerous-unverified-import)前务必确认文件来源可信,程序会给出 90 秒的强制等待窗口供你反悔; - 导入过程中如遇
resizing not supported in batch mode或其它中断,直接重跑命令即可断点续传,无需清空数据库; - 32 位平台上默认 batch size 仅为 100,如需提高性能可手动指定更大的
--batch-size(需评估可用 RAM); - 导入完成后建议以
safe或默认模式重启节点做一次一致性校验,再投入生产同步。
六、进阶:理解导入性能的关键源码路径
如果你希望进一步优化导入性能,可以深入阅读以下源码文件:
- blockchain_import.cpp:导入主流程,含
import_from_file()、check_flush()、批量事务的batch_start()/batch_stop()调用点(blockchain_import.cpp),以及每 1000 块/每 10 块刷新一次进度的显示逻辑; - bootstrap_file.cpp:引导文件的分块读写、
count_blocks()统计与seek_to_first_chunk()定位; - bootstrap_serialization.h:
block_package的二进制序列化结构(兼容 v0 旧格式block_package_1,见 blockchain_import.cpp); - db_lmdb.cpp:
DBF_FAST/DBF_FASTEST到MDB_*环境 flag 的转换,理解"fastest"究竟快在哪; - blockchain_db.h:数据库 flag 宏定义;
- CMakeLists.txt:完整工具链的编译目标与链接关系,可据此了解各工具间的代码复用(如
bootstrap_file.cpp同时被 import 与 export 使用)。
七、常见问题(FAQ)
Q1:导入和导出工具在哪些平台上可用?两者是标准 C++ 程序,随 Monero 源码在各主流平台(Linux、macOS、Windows)编译,编译产物分别命名为monero-blockchain-import与monero-blockchain-export(见 CMakeLists.txt 的OUTPUT_NAME设置)。
Q2:导入中途断了怎么办?直接重新执行导入命令。由于--resume默认开启,导入器会从当前数据库高度继续读取引导文件,跳过已导入的区块。
Q3:为什么我导入后数据库文件比导出的源文件大?blockchain.raw是紧凑的序列化格式,仅含重建链所需的最小字段;而 LMDB 数据库包含区块索引、交易索引、输出索引等多张子表,体积天然更大,属正常现象。
Q4:--database memory有什么用?memory类型用于开发与测试场景,数据驻留内存,不适合生产环境持久化链数据。
Q5:能否只导出部分链?可以。导出端使用--block-start与--block-stop限定范围;导入端使用--block-stop控制导入高度,剩余部分可交由节点后续通过 P2P 网络补齐。
- 区块链
- 金融科技
【免费下载链接】monero
Monero: the secure, private, untraceable cryptocurrency
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考