Monero Blockchain Stats 工具指南:从创世块到当前状态的区块链每日统计导出
【免费下载链接】moneroMonero: the secure, private, untraceable cryptocurrency项目地址: https://gitcode.com/gh_mirrors/mo/monero
导读
monero-blockchain-stats是 Monero 项目提供的一款链上数据分析工具,它直接读取本地已同步的区块链数据库(BlockchainDB),逐块扫描并聚合出从创世区块(2014 年 4 月)至今的每日统计,覆盖区块数、交易数、字节数、手续费、发行量、难度、环大小、输入输出等维度,并以 Tab 分隔的 CSV 格式输出到终端,便于重定向保存或管道接入自研脚本做进一步分析。读完本文,你将掌握该工具的完整参数用法、输出列语义,以及其底层逐块扫描与按天聚合的实现原理,能够独立用它生成 Monero 区块链增长趋势数据并绘制图表。
一、工具定位:它是做什么的
Monero Blockchain Stats utility 的官方定义是:exports daily statistics for the monero blockchain from creation through current state(blockchain-stats-readme.md)。也就是说,它把整条链上每个区块、每笔交易的关键指标,按“自然日(GMT)”为单位聚合,输出一行一条日统计记录。
与 monero-blockchain-export、monero-blockchain-import 这类“搬运区块原始数据”的工具不同,stats 工具做的是在本地链上做在线聚合分析,不产生区块数据文件,只输出统计表格。它属于 src/blockchain_utilities 目录下的实用工具家族,构建目标名与输出二进制名均为monero-blockchain-stats(见 CMakeLists.txt)。
使用前提
- 需要一条已同步到目标高度的本地区块链数据库。工具以只读方式打开数据库(
db->open(filename, DBF_RDONLY),见 blockchain_stats.cpp),不会修改任何链上数据,但也不会自行联网同步,因此必须先运行monerod完成同步(或用monero-blockchain-import导入已有数据)再执行本工具。 - 统计范围默认从高度 0 直到数据库当前高度;也可通过
--block-start/--block-stop限定区间。
二、基本用法与输出流向
直接运行
$ monero-blockchain-stats这会加载已有的区块链数据库,并将统计结果打印到终端。输出格式为Tab 分隔的 CSV:每个自然日一行,字段之间以制表符(\t)分隔。默认列包括:
- Blocks per Day(每日区块数)
- Total Blocks(累计区块数)
- Transactions per Day(每日交易数)
- Total Transactions(累计交易数)
- Bytes per Day(每日字节数)
- Total Bytes(累计字节数)
保存为 CSV 文件
由于输出直接写到标准输出,重定向即可落盘:
# 保存为带日期的 CSV 文件 monero-blockchain-stats > stats-$(date +'%Y-%m-%d').csv管道接入脚本
把输出喂给自定义脚本做入库或可视化:
monero-blockchain-stats | save-to-database.sh注意:输出中除了数据行,还会在数据区之前打印一行# DATA注释(源码见 blockchain_stats.cpp),该行是专为 GnuPlot 的index "DATA"语法准备的索引标记,自定义脚本按\t解析时应跳过以#开头的行和表头行。
三、全部命令行选项详解
以下选项均来自源码中的po::options_description定义(blockchain_stats.cpp)。运行monero-blockchain-stats --help可查看与源码一致的最新说明。
| 选项 | 默认值 | 说明 |
|---|---|---|
--data-dir arg | 平台默认数据目录 | 指定区块链数据库的存放位置(详见下文“数据目录解析规则”) |
--testnet | 关 | 在 testnet(测试网)上运行 |
--stagenet | 关 | 在 stagenet(暂存网)上运行 |
--log-level arg | 0 | 日志级别,取值0–4或日志分类(categories)字符串,如bcutil:INFO |
--block-start arg | 0 | 从指定区块高度开始统计 |
--block-stop arg | 0 | 在指定区块高度停止(0表示直到数据库最高高度) |
--with-inputs | 关 | 附带输入(inputs)统计:最小 / 最大 / 平均每笔交易的输入数 |
--with-outputs | 关 | 附带输出(outputs)统计:最小 / 最大 / 平均每笔交易的输出数 |
--with-ringsize | 关 | 附带环大小(ring size)统计:最小 / 最大 / 平均环大小 |
--with-hours | 关 | 附带每小时交易数(txns per hour,GMT 24 小时分桶) |
--with-emission | 关 | 附带货币发行量(coin emission)统计:每日新增 / 累计总量 |
--with-fees | 关 | 附带交易手续费(txn fees)统计:每日手续费 / 累计手续费 |
--with-diff | 关 | 附带难度(difficulty)统计:每日最小 / 最大 / 平均难度 |
--regtest(回归测试模式)也在 cryptonote_core.cpp 中被定义为通用核心参数,工具继承了cryptonote::arg_regtest_on(见 blockchain_stats.cpp),主要用于测试场景。
数据目录解析规则
--data-dir底层对应cryptonote::arg_data_dir(cryptonote_core.cpp)。它的默认值由tools::get_default_data_dir()决定(util.cpp):
- Unix / macOS:
$HOME/.bitmonero - Windows:
C:\ProgramData\bitmonero
并且该参数带有一个网络类型联动钩子:当指定--testnet时,实际数据目录自动变为<data-dir>/testnet;指定--stagenet时变为<data-dir>/stagenet;指定--regtest时变为<data-dir>/fake。这就是为什么主网、测试网、暂存网的数据彼此隔离。
网络模式互斥规则
网络类型由core::get_network_type_from_args统一解析(cryptonote_core.cpp):--testnet、--stagenet、--regtest三者最多只能指定一个,若同时指定多个会抛出运行时错误,避免误用错误网络的数据库。
日志级别说明
--log-level接受0–4的数字级别(0 最安静,4 最详细),也接受分类字符串。默认情况下日志级别为0,并额外强制开启bcutil:INFO分类(见 blockchain_stats.cpp),日志写入默认路径的monero-blockchain-stats.log。观察启动过程的关键日志包括:
Initializing source blockchain (BlockchainDB)Loading blockchain from folder <path> ...Source blockchain storage initialized OKStarting from height <start>, stopping at height <stop>
四、输出格式详解:每一列是什么
表头由源码按“默认列 + 按需附加列”的顺序拼接生成(blockchain_stats.cpp),顺序如下:
固定列(始终存在)
| 列名 | 含义 |
|---|---|
Date | 统计日(GMT,格式%Y-%m-%d) |
Blocks/day | 当日产出的区块数 |
Blocks | 截至当日的累计区块数 |
Txs/Day | 当日交易数(不含矿工 coinbase 交易,coinbase 不计入tx_hashes) |
Txs | 截至当日的累计交易数 |
Bytes/Day | 当日新增字节数(含区块 blob、交易 pruned blob,以及可用的 prunable blob,见下文) |
Bytes | 截至当日的累计字节数 |
按需附加列(启用对应开关后出现)
| 开关 | 附加列 | 含义 |
|---|---|---|
--with-emission | Emission/day、Emission | 每日新增货币发行量、截至当日的累计发行总量(原子单位) |
--with-fees | Fees/day、Fees | 每日交易手续费、累计手续费(原子单位) |
--with-diff | DiffMin、DiffMax、DiffAvg | 当日最小 / 最大 / 平均 PoW 难度 |
--with-inputs | InMin、InMax、InAvg | 当日单笔交易输入数的最小 / 最大 / 平均值 |
--with-outputs | OutMin、OutMax、OutAvg | 当日单笔交易输出数的最小 / 最大 / 平均值 |
--with-ringsize | RingMin、RingMax、RingAvg | 当日单笔交易环大小(签名环成员数)的最小 / 最大 / 平均值 |
--with-hours | 00:00…23:00共 24 列 | 当日各 GMT 整点小时的交易数分桶 |
几个实现细节值得注意:
- 当启用
--with-inputs/--with-outputs/--with-ringsize时,平均值列会以setprecision(2) + fixed格式输出两位小数(blockchain_stats.cpp)。 - 发行量与手续费使用
print_money()输出(即不带小数点的原子单位字符串,与钱包显示习惯一致),难度、字节数等为普通整数。 - 环大小统计只针对
txin_to_key类型的输入,取的是首个输入的key_offsets.size()(blockchain_stats.cpp)。 - 当某日没有任何交易时,平均列的分母会取
tottxs = 1兜底,避免除零(blockchain_stats.cpp)。
一个典型输出样例
启用全部开关后,某行数据形如(字段以\t分隔,此处用空格示意):
Date Blocks/day Blocks Txs/Day Txs Bytes/Day Bytes Emission/day Emission Fees/day Fees DiffMin DiffMax DiffAvg InMin InMax InAvg OutMin OutMax OutAvg RingMin RingMax RingAvg 00:00 01:00 ... 23:00 2014-04-18 40 40 200 200 123456 123456 300000000000 300000000000 0 0 1 100 50 1 4 2.10 1 3 2.00 1 3 2.00 5 3 ... 2五、工作原理:源码级剖析
整个程序是一个单遍顺序扫描:从block_start开始,逐块读取、解析、累加,遇到“跨天”时输出一行统计并重置当日累计值。主循环见 blockchain_stats.cpp,单日输出逻辑见doprint()(blockchain_stats.cpp)。
1. 只读打开 BlockchainDB
工具通过工厂函数new_db()创建数据库后端实例(默认即 LMDB 实现,见 blockchain_db),然后用DBF_RDONLY标志打开,确保绝不会写入或修改数据库(blockchain_stats.cpp)。数据库文件名为data-dir下的db->get_db_name()(LMDB 下即lmdb目录)。因此哪怕在已同步节点上反复运行该工具,也是完全安全的。
2. 按天聚合与月末边界处理
工具用 GMT 时间(get_gmt_time)把每个区块的时间戳映射到自然日,判断“跨天”的条件是:
if (currtm.tm_mday > prevtm.tm_mday || (currtm.tm_mday == 1 && prevtm.tm_mday > 27))即“日号变大”或“从月末的 27+ 跳回 1 号”。源码还专门处理了**时间戳伪造(timestamp fudging)**的边界情况:若前一天是 1 号而后一天日号大于 27(说明前一天的 1 号其实是被人为后移的时间戳),则跳过这次跨天输出,避免产生虚假的“空日”行(blockchain_stats.cpp)。
3. 字节数统计口径
每个区块的字节数包含三部分(blockchain_stats.cpp):
- 区块本身的 blob(
get_block_blob_from_height); - 每笔交易的pruned blob(
get_pruned_tx_blob,即保留签名所需前缀部分); - 若节点还保留了可剪除部分,则追加prunable blob(
get_prunable_tx_blob)的字节数。
后两者对应 blockchain_db.h 中声明的数据库接口,LMDB 实现见 db_lmdb.cpp。因此“Bytes”列反映的是本地数据库实际存储的字节口径,在已剪枝(pruned)节点上会小于全节点。
4. 发行量与手续费的计算
- 手续费:对区块内每笔交易调用
get_tx_fee(tx)累加(blockchain_stats.cpp)。 - 发行量:
emission += coinbase_amount - tx_fee_amount,其中coinbase_amount来自矿工交易输出总额(get_outs_money_amount(blk.miner_tx))(blockchain_stats.cpp)。即“新增发行 = coinbase 总额 − 该块手续费”,因为手续费在 Monero 中同样由矿工收取、但本质来自用户而非新铸造。 - 每日与累计两列分别由
emission/fees与prevemission/prevfees维护,跨天时先输出“当日值”和“累计值”再累加(doprint()中逻辑)。
5. 难度统计
对每个区块调用db->get_block_difficulty(h)取该高度的难度值,维护当日最小、最大与总和,跨天时输出min / max / sum ÷ blocks(blockchain_stats.cpp)。
6. 按小时分桶
启用--with-hours后,每笔交易按其区块时间戳的小时数(currtm.tm_hour)累加进txhr[0..23],跨天输出 24 个分桶值(blockchain_stats.cpp)。
7. 中断与停止条件
程序安装了 SIGINT/SIGTERM 信号处理器,收到信号后置stop_requested,主循环在下一个区块处跳出(blockchain_stats.cpp)。循环结束后若仍有未输出的当日累计值,会再调用一次doprint()收尾(blockchain_stats.cpp)。这也意味着:
- 若指定
--block-stop恰好落在一个自然日中间,该日仍会输出部分日的统计行; - 扫描过程中途按 Ctrl+C,已完成的日期行都会正常输出,方便长链分析时提前取数。
六、进阶:用 GnuPlot 绘制增长曲线
工具源码注释中内置了一组可直接使用的 GnuPlot 脚本(blockchain_stats.cpp),配合默认输出(仅 6 个固定列)可以快速画出 Monero 区块链增长趋势:
set key autotitle columnhead set title "Monero Blockchain Growth" set timefmt "%Y-%m-%d" set xdata time set xrange ["2014-04-17":*] set format x "%Y-%m-%d" set yrange [0:*] set y2range [0:*] set ylabel "Txs/Day" set y2label "Bytes" set y2tics nomirror plot 'stats.csv' index "DATA" using (timecolumn(1,"%Y-%m-%d")):4 with lines, '' using (timecolumn(1,"%Y-%m-%d")):7 axes x1y2 with lines要点说明:
index "DATA"对应输出中的# DATA注释行,GnuPlot 会跳过其之前的空行与注释;- 第 4 列是
Txs/Day,第 7 列是Bytes(默认 6 列时第 7 列为累计 Bytes);若加了可选开关,列号会右移,需要相应调整using中的列索引; - 两条曲线分别使用左轴(Txs/Day)与右轴(Bytes)绘制。
七、常见问题与注意事项
| 场景 | 说明 |
|---|---|
报错Error opening database | --data-dir指向的路径下没有可用的 BlockchainDB,或数据库属于另一个网络。请确认节点已同步完成,且网络模式(主网 /--testnet/--stagenet)与数据库一致。 |
| 统计范围如何限定 | 用--block-start <h>从指定高度开始,用--block-stop <h>提前终止(默认 0 表示到链顶)。 |
| 输出精度 | 平均值列保留两位小数;发行量、手续费为原子单位整数。 |
| 剪枝节点的影响 | Bytes 列依赖get_prunable_tx_blob是否可返回数据;在剪枝节点上字节数会偏小,但区块数、交易数、难度、发行量、手续费等统计不受影响。 |
| 是否修改链数据 | 完全只读(DBF_RDONLY),可放心对生产节点反复运行。 |
| 数据日期时区 | 所有“每日 / 每小时”分桶均基于 GMT(UTC)时间。 |
八、延伸阅读
- 工具说明文档:blockchain-stats-readme.md
- 核心实现:blockchain_stats.cpp
- 构建目标与安装规则:CMakeLists.txt
- 数据库接口(pruned / prunable blob 读取):blockchain_db.h、db_lmdb.cpp
- 通用参数(
--data-dir/--testnet/--stagenet/ 网络互斥)定义:cryptonote_core.cpp - 默认数据目录解析:util.cpp
- 同目录兄弟工具:导出 blockchain_export.cpp、导入 blockchain_import.cpp、用量分析 blockchain_usage.cpp、剪枝 blockchain_prune.cpp
综上,monero-blockchain-stats是理解 Monero 链上历史演化的低成本入口:一条命令即可获得从创世块至今的每日区块、交易、字节、发行量、手续费、难度与环大小全景数据,配合重定向、管道与 GnuPlot,足以支撑独立的区块链数据分析与可视化任务。
【免费下载链接】moneroMonero: the secure, private, untraceable cryptocurrency项目地址: https://gitcode.com/gh_mirrors/mo/monero
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考