首先看下比特币的数据,它存储在4个地方。具体如下:
blocks/blk*.dat的文件中存储了实际的块数据,这些数据以网络格式存储。它们仅用于重新扫描钱包中丢失的交易,将这些交易重新组织到链的不同部分,并将数据块提供给其他正在同步数据的节点。
blocks/index/*是一个levelDB数据库,存储着目前已知块的元数据,这些元数据记录所有已知的块以及它们存储在磁盘上的位置。没有这些文件,查找一个块将是非常慢的。
chainstate/*是一个levelDB数据库,以紧凑的形式存储所有当前未花费的交易以及它们的元数据。这里的数据对于验证新传入的块和交易是必要的。在理论上,这些数据可以从块数据中重建,但是这需要很长时间。没有这些数据也可以对数据进行验证,但是需要现有块数据进行扫面,这无疑是非常慢的。
blocks/rev*.dat中包含了“撤销”数据,可以将区块视为链的“补丁”(它们消耗一些未花费的输出并生成新的输出),那么这些撤销数据将是反向补丁。如果需要回滚链,这些数据将是必须的。
其中chainstate存储的是UTXOs。换句话说,就是比特币中的财富。那么如何解析该数据呢?笔者提供一种方案。
https://github.com/mycroft/chainstate 这个python是可以解析chainstate的。编译方法也比较简单呢。笔者是在 mac 下下载编译的。没有遇到什么问题。在执行 head /tmp/cs.output 的时候,笔者花费了18分钟,时间是2019年1月10日。使用前,需要先下载比特币数据到本地硬盘。
笔者再介绍下大致使用的方法:
blockchain.py 里面的 get_files 方法获得比特币的 blk 文件,排好序的。
get_blocks 传入 get_files 里面的文件名,可以获取裸块的数据,这里采用 yield 返回,不用担心内存爆掉。
然后把获取的裸数据传入 block.py 里的 Block 类,可以解码数据,后面就看各位尽情发挥了。
笔者用该开源库尝试做了一个程序,查找地址中比特币数量超过一个的公钥。输出地址,公钥以及财富总数。然后对比了网络上的财富。是对的,当然有些在10日之后重新交易过。笔者在做的过程中,无法解码多签名的交易。
截止2019年1月10日,比特币财富超过一个币的有 62万多个地址,笔者能够解码出公钥的大概5万多个。