比特币区块的数据维度有哪些?

本文目的

通过上一篇笔记python-bitcoinrpc下载比特币数据Windows(完成)可以直接通过不同的API获得解析后的区块数据或交易记录,本文分析这些数据能给我们提供哪些对分析比特币网络有用的信息。

Block原始数据维度

getblock.png

利用bitcoinrpc提供的getblock接口可以帮助我们获取区块数据。该接口需要输入区块哈希,另外一个可选变量有三个取值,0,1,2。

  • 取值为0时,返回原始的16进制编码的数据
  • 取值为1时,返回解码后的字典数据
  • 取值为2时,基本和取值为1时返回结果一致,只在键为tx的值中包含了交易的全数据
block原始数据.PNG

上图展示了在pycharm里面运行以下代码获得的rawdata返回结果:

from bitcoinrpc.authproxy import AuthServiceProxy
rpc_connection = AuthServiceProxy("http://%s:%s@127.0.0.1:8332"%('xxx', 'xxx'))best_block_hash = rpc_connection.getbestblockhash()  #获取当前最长链的最后一个区块哈希
rawdata = rpc_connection.getblock(best_block_hash)  #获取指定区块哈希的区块数据

rawdata中包含的数据维度有:

# 区块数据维度
hash              #当前区块的哈希
confirmations     #当前区块已被确认数(即后续跟着的区块数+1,或者可以直接用当前区块链总高度—当前区块高度+1计算获得),需要注意的是,该数值会随着新区块的不断增加而变化,没必要作为数据维度之一存入数据库
strippedsize      #剔除隔离见证数据后的区块字节数
size              #区块字节数
weight            #BIP141定义的区块权重
height            #当前区块高度(第一个区块高度为0,于2009-01-04 02:15生成)
version           #区块版本(代表支持不同的软、硬分叉方案)
versionHex        #用16进制表示的区块版本
merkleroot        #区块的默克尔树根,是根据当前区块内所有交易哈希生成的默克尔树的根节点哈希
tx                #当前区块包含的交易列表,列表中是交易id
time              #当前区块创建的时间戳(unix timestamp)
mediantime        #过去11个区块创建时间戳的中值(unix timestamp)
nonce             #用于挖矿工作量证明的随机数
bits              #难度目标,标识了当前区块头Hash之后要小于等于的目标值(target)
difficulty        #区块挖矿的难度值
chainwork         #当前区块链的工作量加总
nTx               #当前区块包含的交易总数
previousblockhash #当前区块链接的前序区块哈希
nextblockhash     #(如有)链接当前区块的后序区块哈希

涨知识Tips:

  • BIP即Bitcoin Improvement Proposal的首字字母缩写,意译为“比特币改进提议”,每个BIP都牵涉到对比特币源码的改动。而BIP仅仅是提议,实施与否需要社区达成共识。
  • BIP141定义了当前的比特币隔离见证激活方案,大概方法是保存区块数据时移除比特币交易过程中的签名字段,从而在不扩大区块大小的情况下实现“变相扩容”。
  • 区块头里面的默克尔树根是根据nTx笔交易的哈希作为叶子节点生成的默克尔树的根哈希,可参考这篇文章比特币区块结构Merkle树及简单支付验证分析中的示意图理解。
  • unix时间戳是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒。
  • mediantime用于确认区块:只有当某个区块的时间戳大于mediantime,并且小于某个调整后的网络时间(p2p网络节点报时中值+2小时?)时,这个区块才会被确认。

上面理清了区块数据的维度,其中有助于分析比特币交易网络的维度主要有:

  • hash(可作为区块的唯一查询标识)
  • height(可作为区块的唯一查询标识并用于排序)
  • tx(最重要的交易数据)
  • time(时间戳)
  • nTx (当前区块包含的交易总数)

获取交易数据

获取比特币交易数据可以通过两种途径:

  1. 使用上述getblock接口并将verbosity设置为2,可获得该区块内所有交易的详细数据
rawdata = rpc_connection.getblock(block_hash, 2)
txlist = rawdata['tx']
for txdata in txlist:
    ...
  1. 使用getrawtransaction接口并将verbose设置为True:


    getrawtransaction.png
txdata = rpc_connection.getrawtransaction(tx_id,True)

这两种获得交易数据的方法都能返回一致的结果,下图是返回结果对比,第一种方式适用于一次性获取某一个区块里的交易列表;第二种方式适用于查询某个已知txid的特定交易数据,当然,在单独查询交易数据时也会返回交易所属区块的信息(黄框所示)

两种方式返回结果对比,txdata是方式二返回结果,txlist是方式一返回结果.jpg

交易数据维度

从返回的交易数据,我们可以获得以下维度的数据:

# 交易数据维度
txid         #交易id,和所要查询的交易id一致
hash         #交易哈希,对采用隔离验证(segwit)的交易生成的哈希,与txid不同,若交易未采用隔离验证,则与txid一致
version      #版本
size         #交易数据占据的字节数
vsize        #隔离验证后交易数据占据的字节数(总是小于size)
weight       #BIP141定义的方法计算占据权重,是vsize的4倍取整
locktime     #该交易能被加入到区块内的最早时间
vin          #交易的发送地址列表
vout         #交易的接收地址列表
hex          #txid16进制编码后的序列

涨知识Tips:

  • 每个交易都可有多个发送地址和多个接收地址,每个发送地址都会附带一个由发送地址持有人秘钥生成的scriptSig,即unlocking script,用于解锁该地址的余额,这个scriptSig在密码学上被称为“witness”
  • 交易的txid,是对交易信息进行两次sha256的结果。
  • 打包交易的节点有可乘之机,作恶节点可以通过对发送者提供的witness进行包装生成一个新的txid,而验证节点验证整个交易时察觉不出txid被篡改。这样作恶节点就可以欺骗发送者交易未成功发送,但实际上交易已经以另一个txid上链了,导致发送者掉入重复支付陷阱。
  • BIP141建议的隔离验证,是将witness从交易数据中分离出来,放在区块底部,这样按原来方式算txid就不包括验证信息了,而包括验证信息生成的即为hash:
    txID: [nVersion][txins][txouts][nLockTime]
    hash: [nVersion][marker][flag][txins][txouts][witness][nLockTime]
    这就是交易数据里面txid和hash有可能不一样的原因。
  • 有关segregated witness如何扩容的解释可参考这篇Medium文章

因为在txin引用前序交易时都是指向前序交易的txid,故在保存交易数据时以txid作为其唯一标识比较方便。其他维度中对分析比特币交易网络比较有用的就是vin和vout了,在下面详细展开。

vin和vout包含的内容

每一个区块可能包含多笔交易,但第一笔交易都是系统直接向矿工发送,金额是当下挖矿奖励+该区块内的手续费加总。数据格式如下:

vin=[{"coinbase": "xxxxxx很长的一串字符串xxxxxx",
      "sequence": 0}]

vout=[{"value": Decimal("12.64059504"),
       "n": 0,
       "scriptPubKey": {"asm": "xxx",
                        "hex": "xxx", 
                        "reqSigs": 1, 
                        "type": "pubkeyhash", 
                        "addresses": ["xxx"]}
      },
      {"value": Decimal("0E-8"),
       "n": 1,
       "scriptPubKey": {"asm": "xxx",
                        "hex": "xxx",
                        "type": "nulldata"}
      },
      ...]

vin是发送方地址列表,如果一个vin列表中只有一个字典,并且其中存在键“coinbase”,就可以判断该笔交易是矿工奖励。
vout是接收方地址列表,可能有一至多个接收方,每个接收方用一个字典表示,一般包含:

value          #接收到的比特币数额,八位小数
n              #接收方的排序号,从0开始,便于后续花费时引用该笔txid,并指明是第n笔
scriptPubKey   #接收方信息
  - asm        #用于分析scriptPubKey的脚本,不同type对应的asm不同
  - hex        #asm的16进制编码
  - type       #接收方地址类型,可以是pubkeyhash, scripthash, witness_v0_scripthash, multisig, nulldata等
  - reqSigs    #要求的签名数
  - addresses  #接收方地址,是个列表,多重签名时可能会有多个地址

实际上,vout的接收方可有多种类型,具体可参考An Analysis of Non-standard Transactions这篇论文【1】,里面详细介绍了标准交易类型和非标准交易类型。

标准交易类型(Standard Type)

  1. P2PKH(比特币网络默认类型)
  2. P2PK (多出现在矿工接收奖励和手续费的coinbase交易中)
  3. Multi-signature (多签)
  4. P2SH(将另一笔交易的script哈希后作为新script,压缩字节)
  5. P2WPKH、P2WSH:隔离见证采用后P2PKH的另一种实现方式,字节占用更少,且签名从unlocking script中移出
  6. nulldata (OP_RETURN): 隔离见证采用后用于存储见证信息的默克尔树根( Merkle root of the witness tree),在coinbase交易的接收方出现,该笔output将直接从UTXO中移除,后续不能被花费,转移的比特币数量一般都为零。vout中没有reqSigs和addresses这两对键值。

论文【1】及Bitcoin Wiki对Transaction的描述信息中介绍了几种交易类型的脚本形式(asm),例如:

# Pay-to-PubkeyHash(P2PKH)
scriptPubKey: OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
scriptSig: <sig> <pubKey>

其中scriptPubKey是locking script, 保存在vouts里,scriptSig是发送方用于解锁发送地址中比特币的签名信息(unlocking script),在非coinbase交易中的vin出现:

vin=[{"txid": "xxx", 
      "vout": 0,
      "scriptSig": {"asm": "xxx",
                    "hex": "xxx"},
      "sequence": 4294967295},
      ...]

注意:非coinbase交易的vin没有直接给出发送方地址信息,而是告诉我们该笔交易花费的前序交易“txid”及“vout”,“vout”是某一笔花费在该前序交易中的接收方排序,即前面分析的vout中的“n”对应的值。通过这个信息需要再去查询指定“txid”的第“vout”个接收方地址,才能获得该笔交易的发送方地址。另外一个数据维度,sequence,是不经常用到的一个序列号,用于更改带时间锁的交易,详细可参考官方说明:locktime-and-sequence-number

原则上,节点验证程序会通过isStandard()及isStandardTx()两个函数分别验证所有outputs和inputs是否采用标准交易形式。但一些矿工节点修改了程序,导致区块里也会打包一些非标准交易,但它们所占的比例很少(0.02%)。

非标准交易类型(Nonstandard Type):

  1. 疑似DDOS攻击:例如Transaction: 2a0597e665ac3d1cabeede95cedf907934db7f639e477b3c77b242140d8cf728在scriptPubKey中写入上百个OP_CHECKSIG(消耗验证节点的计算量),该笔output可以被后续花费。
  2. P2PKH NOP: 在P2PKH的script形式上末尾加了OP_NOP,用于测试未来的某些新功能,例如Transaction: db3f14e43fecc80eb3e0827cecce85b3499654694d12272bf91b1b2b8c33b5cb,该笔交易可以被后续花费。
  3. P2PKH 0: script形式与P2PKH一样,但是在public key hash的位置填写的是0,由于0不是有效公钥哈希,导致该笔output无法被后续花费,也没有接收方地址,转移的金额相当于销毁了。

总结

本文分析了JSON-bitcoinrpc的若干接口,

  1. 通过getblockhash()接口,可获得指定height的区块hash;
  2. 通过getblock()接口,可获得指定区块hash的区块数据,设定第二个参数为2可获得全量交易数据列表;
  3. 通过getrawtransaction()接口,可获得单个指定txid的交易数据;
  4. 通过getbestblockhash()接口,可获得当前最长链最后一个被确认区块的hash。

另,下面代码示例可实现批量获取返回结果:

commands1 = [["getblockhash", height] for height in range(100)]
block_hashes = rpc_connection.batch_(commands1)
commands2 = [["getblock", h] for h in block_hashes]
blocks = rpc_connections.batch_(commands2)

对分析比特币交易网络有用的信息主要就是:

  1. 区块相关的数据
  • hash(可作为区块的唯一查询标识)
  • height(可作为区块的唯一查询标识并用于排序)
  • time(时间戳)
  • nTx (当前区块包含的交易总数)
  1. 交易相关的数据
  • txid
  • vin,判断是否coinbase,引用的前序交易txid及排序号vout
  • vout, 接收方列表(每个接收方包括value, 排序号n, scriptPubKey中的type, reqSigs, addresses)
  • blockhash 交易所属区块的哈希
  1. 派生数据
  • 手续费,发送方总金额—接收方总金额的差值为支付给矿工的手续费
  • 找零,推断找零地址及找零余额
  • multi-input heuristic
  • 通过hash和txid是否一致判断该交易是否采用隔离见证

由于数据量庞大,如果要存在数据库中,下一步是设计数据仓库结构,以便能够有效地查询到所需数据。

(记于2019年12月31日 漠水云)

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