比特币协议

sky 队长 船龄 8.8年 来源 巴比特
 159799  0

比特币协议

本文译自比特币WIKIhttps://en.bitcoin.it/wiki/Protocol_specification
,参考了巴比特维基中的资料:http://wiki.8btc.com/doc-view-70.htm

译者:申屠青春 深圳大学ATR国防科技重点实验室博士 新浪微博 @我看比特币

注意:本文可随意转发,请留下译者信息,如果觉得本文对你有用,请给译者捐赠,以便翻译更多比特币的核心资料。捐赠地址:1faVxBp2KmST98p3tJjx2MQP98JLLnF2Q

译者前言

       比特币在国内已经众所周知,但是技术研究并未有效开展,大部分人处于知道和了解程度,目前比特圈中许多人对比特币能做什么,同样了解不多。一个重要原因是大多数比特币核心资料都是英文,很少有人能静心看完如此繁杂的英文资料。本人博士论文的研究方向是比特币,在研究其英文技术的同时,拟对一些重要资料进行翻译,让更多的圈内人对比特币有更多的理解。

       本文涉及比特币协议,包括HASHMERKLE树生成、签名、交易验证、地址等一般性标准,也包括通用的数据结构,包括消息、可变长整数、变长字符串、网络地址、库存向量、区块头等。还详细介绍了20多个比特币消息的数据结构和使用场景,是很好的比特币协议参考资料。

正文

1一般标准

1.1 Hashs (哈希)

通常情况下,bitcoin在计算哈希时会计算2次。大多数情况下,使用SHA-256哈希,RIPEMD-160会用于生成较短的哈希(例如生成比特币地址的时候)

对字符串“hello”进行二次-SHA-256哈希计算的例子:

hello
2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 (第一轮 sha-256)
9595c9df90075148eb06860365df33584b75bff782a510c6cd4883a419833d50 (第二轮 sha-256)

生成比特币地址时(RIPEMD-160)会得到:

hello
2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 (第一轮 使用 sha-256)
b6a9c8c230722b7c748331a8b450f05566dc7d0f (第二轮 使用 ripemd-160)

1.2 Merkle Trees (Merkle)

Merkle树是哈希的二叉树。在bitcoin中使用两次SHA-256算法来生成Merkle树,如果叶子个数为奇数,则要重复计算最后一个叶子的两次SHA-256,以达到偶数叶子节点的要求:

计算过程:首先按照区块中交易的两次HASH256值,然后按照HASH值大小排序,生成底层;第二层的每个元素是相连续的两个HASH值的两次HASH值;重复这个过程,直到某一层只有一个HASH值,这就是Merkle根。举例:想像3个交易,a,b,c,生成过程如下:

d1 = dhash(a)
d2 = dhash(b)
d3 = dhash(c)
d4 = dhash(c)            # 只有3个元素,是奇数,因而把最后一个元素重算一次
 
(译者按,按照上面说明,到这里应该有排序,可能省略了,有待证实)
 
d5 = dhash(d1 concat d2)
d6 = dhash(d3 concat d4)
 
d7 = dhash(d5 concat d6)

这里dhash(a) = sha256(sha256(a))

d7就是以上三个交易的Merkle根。

注意:在区块浏览器中显示的Merkle树的HASH值是小头位序(译者按:即高位在后,一种数字在计算机中的表示形式)。对于某些实现和计算,在HASH计算前应该先按位反转,在HASH计算后再反转一次。

1.3 Signatures (签名)

Bitcoin使用椭圆曲线数字签名算法(ECDSA)对交易进行签名。

ECDSA
使用http://www.secg.org/collateral/sec2_final.pdf中的secp256k1曲线。

(在脚本中) 04
的形式给出,这里xy32字节的大头位序整数,表示上述曲线的点坐标;或者以压缩形式给出,如果y是偶数0×02,如果y是奇数0×03

签名使用DER 编码rs写入一个字节流中(因为这是OpenSSL的默认输出).

1.4 Transaction Verification (交易认证)

交易是密码学签名,用于记录比特币的拥有权从一个地址转向另一个地址。交易有输入(即费用以前交易的输出资金)和输出(用于定义比特币的新拥有者,可以被以后的交易引用为输入)。

每个输入必须有一个密码学数字签名,用于从以前交易中解锁资金。只有拥有合适的私的人才能创建合法签名,这就保证了资金只能被拥有者花费。

每个输出定义哪个地址(或者是其他标准,请看“比特币脚本”一文)是资金的接收者。

在交易中,所有输入的资金总和必须等于或大于所有输出的资金总和,如果输入超过输出,多余部分就是传输费用,谁挖到包含这个交易的区块,这个费用就归谁。一种比较特殊的交易,称为coinbase交易,它没有任何输入,由矿工创建。每个区块附带新创建的比特币回报(例如:在最先的21万个区块中,每块包含50个比特币)。每个区块的第一个交易都是一个coinbase交易,很少例外。Coinbase交易允许这些比特币归他们的接收者(矿工)所有,并且还用来指示本区块中其他交易的交易费的接收者,coinbase交易可以指定接收者是一个比特币地址,也可以和其他交易一样,指定由多个地址接收。coinbase交易包含的输出金额等于每区块挖矿回报加上本区块中的所有交易费用。

0块的coinbase交易不能被花掉,这可能是一个客户端实现的巧合(译者按:或者是中本聪故意为之,详见译才的“比特币块链和挖矿原理”翻译),如果一些节点接受花费交易,而有些节点不接受,则有可能产生分叉。

大多数比特币输出需要一个ECDSA来赎回传输的比特币,实际存贮输入和输出的纪录并非是私,而是脚本。比特币使用一个解释脚本系统来定义输出标准是否满足,有了这个脚本系统,能形成更为复杂的操作。比如需要两个ECDSA签名的输出,或者2-of-3的多重签名场景。一个比特币地址的输出是典型输出,该输出实际上以脚本形式包含了需要单个ECDSA签名这个信息(参见OP_CHECKSIG)。为了以后能解锁资金,必须提供输出脚本,当要在另一个交易的输入中花费该交易时,该输入必须满足原始输出脚本的要求。

 

1.5 Addresses (地址)

比特币地址是ECDSA(public key)的哈希,它是这样计算出来的:

Version = 1 字节(0); 在测试网络上, 这个值是 1 字节 (111)
Key hash = Version  RIPEMD-160(SHA-256(public key)) 相接
Checksum = SHA-256(SHA-256(Key hash))的前4个字节
比特币地址 = Base58Encode(Key hash  Checksum 相接)

Base58编码是专门编写的,(与通用版本)有一些区别。特别是前导为0的所有字节被转换为单个0

2通用结构

绝大多数整数都使用小头位序编码,只有IP地址或端口号使用大头位序编码。

2.1 Message (消息)

字段尺寸

描述

数据类型

`说明

4

magic

uint32_t

用于识别消息的来源网络,当流状态位置时,它还用于寻找下一条消息

12

command

char[12]

识别包内容ASCII字串,用NULL字符补满,(使用非NULL字符填充会被拒绝)

4

length

uint32_t

payload的字节数

4

checksum

uint32_t

sha256(sha256(payload))
的前4个字节(不包含在version
verack
)

?

payload

uchar[]

实际数据

versionverack消息不包含checksumpayload的起始位置提前4个字节

已定义的magic值:

网络

Magic

发送形式

main

0xD9B4BEF9

F9 BE B4 D9

testnet

0xDAB5BFFA

FA BF B5 DA

testnet3

0x0709110B

0B 11 09 07

namecoin

0xFEB4BEF9

F9 BE B4 FE

2.2 Variable length integer (变长整数)

整数可以根据表达的值进行编码以节省空间。变长整数总是在可变长度数据类型的数组/向量之前出现。更长的数字以小头位序编码。

存储长度

格式

<
0xfd

1

uint8_t

<=
0xffff

3

0xfd +
uint16_t

<=
0xffffffff

5

0xfe +
uint32_t

-

9

0xff +
uint64_t

中本聪的比特币客户端代码(Bitcoin-qt)里指的是“CompactSize”,现代的Bitcoin-qt也有CVarint类,比CompactSize更压缩(但与CompactSize不兼容),CVarint类并非协议的一部分。

2.3 Variable length string (变长字符串)

变长字符串由一个变长整数和一个字符串构成。

字段尺寸

描述

数据类型

说明

 ?

length

var_int

字符串长度

 ?

string

char[]

字符串本身(可为空)

2.4 Network address (网络地址)

需要网络地址时会用到这个结构。这个协议和数据结构支持IPv6,但需要注意目前官方客户端仅支持IPv4网络,网络地址在版本消息中,并非以时间戳为开始

字段尺寸

描述

数据类型

说明

4

time

uint32

时间 (version
>= 31402)

8

services

uint64_t

version 消息一样的数据类型

16

IPv6/4

char[16]

网络字节顺序的IPV6地址,原始客户端仅支持IPv4,仅读取最扣4字节,获得IPv4地址。但是IPv4地址在该消息中是一个16字节长的 IPv4-映射的
IPv6 address

(12 bytes 00
00 00 00 00 00 00 00 00 00 FF FF
,
后面跟随4个字节的IPv4地址).

2

port

uint16_t

端口地址

一个网络地址结构的十六进制示例

0000   01 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  ................
0010   00 00 FF FF 0A 00 00 01  20 8D                    ........ .
 
Network address:
 01 00 00 00 00 00 00 00                         - 1 (NODE_NETWORK:请看version命令的服务列表 )
 00 00 00 00 00 00 00 00 00 00 FF FF 0A 00 00 01  - IPv6: ::ffff:10.0.0.1 IPv4: 10.0.0.1
 20 8D                                           - 端口 8333

2.5 Inventory Vectors (清单向量)

清单向量用于告知其他节点本节点拥有的对象或请求的数据,由以下数据格式构成

字段尺寸

描述

数据类型

说明

4

type

uint32_t

对象类型标识

32

hash

char[32]

对象哈希值

目前对象类型标识已经定义如下3个值

名称

说明

0

ERROR

数据可忽略

1

MSG_TX

哈希是关于交易的

2

MSG_BLOCK

哈希是关于数据块的

其他数据类型值被保留以便用于将来实现

2.6 Block Headers (Block头部)

回应getheaders消息时,将区块头部放入一个数据包中并且发送。

字段尺寸

描述

数据类型

说明

4

version

uint32_t

Block版本信息,基于创建该block的软件版本

32

  • 全部
  • 最佳
登录 账号发表你的看法,还没有账号?立即免费 注册
推荐教程
换一批