如何解析 Bitcoin 的数据(1)


转自 https://www.arcblock.io/zh/post/2018/08/16/index-bitcoin

如何解析 Bitcoin 数据?

众所周知,互联网上的数据纷繁复杂,而搜索引擎却能在海量的数据里面迅速的查找出用户想要的结果。其之所以能够做到这一点是因为搜索引擎的后面还有两个默默付出的组件 -- 爬虫和倒排索引。 爬虫负责不停的从互联网上搜集数据,倒排索引负责将数据以特定的形式存储,以便搜索引擎能够快速的查询。

Bitcoin 的数据都是以二进制的形式存在节点的磁盘上的。但是数据是以一种对人不太友好的方式组织在一起的,所以我们首先需要一个解析器,将这些二进制数据读出来,还原成它们本来的面目。之后我们再对这些数据进行一些加工,就得到了 我们所需要的数据。

Bitcoin 数据是如何存储的

存储数据的文件

Bitcoin 的原始数据可以在 $HOME/.bitcoin/blocks 下面找到。这个目录下面主要有两类文件,一种是类似于这样的文件:blk00952.dat, 而另一种是类似于这样的文件:rev000952.dat。 前一种 blk 开头的文件就是存储 Bitcoin 源数据的文件,而后一种是用来做 rewind 的。关于 rewind 我们下回再表,我们这次的重点在源数据文件。每一个 blk 数据文件大小的上限都是 128MB。当一个文件写满后,Bitcoin 程序会新建一个类似的文件来存储新收到的区块信息。

让我们先通过如下命令,来看看这些文件里面都存了什么。

od -x --endian=big -N 297 -An blk00000.dat

f9be b4d9 1d01 0000 0100 0000 0000 0000
 0000 0000 0000 0000 0000 0000 0000 0000
 0000 0000 0000 0000 0000 0000 3ba3 edfd
 7a7b 12b2 7ac7 2c3e 6776 8f61 7fc8 1bc3
 888a 5132 3a9f b8aa 4b1e 5e4a 29ab 5f49
 ffff 001d 1dac 2b7c 0101 0000 0001 0000
 0000 0000 0000 0000 0000 0000 0000 0000
 0000 0000 0000 0000 0000 0000 0000 ffff
 ffff 4d04 ffff 001d 0104 4554 6865 2054
 696d 6573 2030 332f 4a61 6e2f 3230 3039
 2043 6861 6e63 656c 6c6f 7220 6f6e 2062
 7269 6e6b 206f 6620 7365 636f 6e64 2062
 6169 6c6f 7574 2066 6f72 2062 616e 6b73
 ffff ffff 0100 f205 2a01 0000 0043 4104
 678a fdb0 fe55 4827 1967 f1a6 7130 b710
 5cd6 a828 e039 09a6 7962 e0ea 1f61 deb6
 49f6 bc3f 4cef 38c4 f355 04e5 1ec1 12de
 5c38 4df7 ba0b 8d57 8a4c 702b 6bf1 1d5f
 ac00 0000 00f9 beb4 d900

上面的文件就是 Bitcoin 的 Genesis Block。它是二进制数据(以 16 进制表示),每两个字符表示一个字节。乍一看感觉乱七八糟,但是当你了解他们的数据格式之后,一切都不是那么难。

数据的存储结构

Bitcoin 官网上有关于数据格式的具体讲解,但是他们的文档的组织结构并不容易阅读理解,所以我们总结了一个更直观的图表。

现在是不是清楚多了?注意,我并有没把数据换成大端格式,请自行转换。

计算额外字段

细心的同学可能已经注意到了,这些数据中不包括几个非常重要的字段,Block HashBlock HeightTransaction Hash 以及 Addresses。不错,中本聪在设计 Bitcoin 的时候可谓是极度的“抠门”,能通过计算得出的数据绝对不存在链上。从链的设计角度来看,这样做是绝对正确的,它能节省许多磁盘空间,但是这却给我们带来了额外的工作。下面我们分别谈谈各个字段的计算。

计算 Block Hash 以及 Transaction Hash

Block 和 Transaction 的 Hash 值都是由相同的算法得出的,不同点只是在于参与计算的数据不同。对于 Block Hash 来讲,我们的输入数据只是 80 字节的 Block Header,而对于 Transaction 来讲是整个 Transaction 的数据。Block Header 里面是包括 Merkle Root 的,所以在计算 Block Hash 的时候不需要整个 Block 最为输入。

Hash 值是由输入数据进行两次 sha-256 运算得出的,其形式如下:
hash = sha256(sha256(data))

我们分别将 Block Header 和整个 Transaction 带入上述公式便能得到相应的 Hash 值。

计算 Block Height

我们知道,Bitcoin 的原始数据是存储在 blkxxxxx.data 中的,每个 data 文件中都存放了许多个 Block。如果我们按顺序从第 0 字节开始读,把其中的所有 Block 都解析出来,我们会发现这些 Block 并不是完全有序的。换句话说你有可能先读出第 178 个 Block,然后才读出第 177 个 Block。至于为什么会这样,大家可以想想以前用 BT 下载的时候,那个进度条长什么样。

所以想要得到正确的 Block Height, 我们就必须对读出来的、无序的 Block 进行排序。了解 Blockchain 的同学应该知道,Blockchain 的数据结构是一个倒过来的单链表,我们可以通过 Block Hash 和 Previous Block Hash 来将这些 Block 重新串联起来。Genesis Block 的 Previous Block Hash 固定为全 0。这样一来我们也就可以得出 Block Height 了。

计算 Addresses

想要支持最开始的那种根据地址查询 Transaction 的功能,我们就必须求出每笔交易的发款人和收款人地址。这两个数据分别蕴含在 Transaction Input 和 Output 的script字段里面。求出地址的方法大致分为两步:

  1. 对于 Transaction Output,找出其中的 public key 或 public key hash,再根据一定的算法计算出地址。

  2. 对于 Transaction Input, 从其对应的 Previous Transaction Output 中取出地址,作为它的地址。

限于篇幅,我就不过多讨论第一点了。如果大家感兴趣,不妨告诉我们,我可以单独再用一期来讲解如何解析 Bitcoin Script。但是我想对第二点进行一些补充说明。虽然在 Transaction Input 里面你能拿到 public key,但是我不建议大家直接从 Transaction Input 里面计算地址。这是因为经过隔离见证之后,计算地址的方式发生了变化,直接从 Input 中解析地址很有可能得到一个与 Previous Transaction Output 不一样的地址。简单来说就是,你有可能以张三的名义收了一笔钱,却用李四的名义花掉了这笔钱。张三李四本来是同一个人,但是因为这个错误,计算账户余额的时候就会出现余额为负数的情况。

Code

有个 Eth 的实现
ethLeveldb.go


参考:

https://en.bitcoin.it/wiki/Transaction
//www.greatytc.com/p/637bbdcf17d1

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,657评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,889评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,057评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,509评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,562评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,443评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,251评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,129评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,561评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,779评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,902评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,621评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,220评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,838评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,971评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,025评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,843评论 2 354

推荐阅读更多精彩内容