玩币族移动版

玩币族首页 > 币圈百科 >

比特币协议

  本文译自比特币WIKI:https://en.bitcoin.it/wiki/Protocol_specification

  ,参考了巴比特维基中的资料:http://wiki.8btc.com/doc-view-70.htm

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

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

  译者前言

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

  本文涉及比特币协议,包括HASH、MERKLE树生成、签名、交易验证、地址等一般性标准,也包括通用的数据结构,包括消息、可变长整数、变长字符串、网络地址、库存向量、区块头等。还详细介绍了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

  的形式给出,这里x和y是32字节的大头位序整数,表示上述曲线的点坐标;或者以压缩形式给出,如果y是偶数是0×02,如果y是奇数是0×03。

  签名使用DER 编码把r和s写入一个字节流中(因为这是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[] 实际数据
  version和verack消息不包含checksum,payload的起始位置提前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 prev_block char[32] 该block前一block的哈希
32 merkle_root char[32] 与该block相关的全部交易之哈希(Merkle树)
4 timestamp uint32_t 记录block创建时间的时间戳
4 bits uint32_t 创建block的计算难度
4 nonce uint32_t 用于生成block的临时数据
1 txn_count var_int 交易数,这个值总是0
  3消息类型

  3.1 version

  当一个节点收到连接请求时,它立即宣告其版本。远程节点会以自己的版本响应,在通信双方都得到对方版本之前,不会有其他通信。

  结构:

字段尺寸 描述 数据类型 说明
4 version int32_t 节点使用的协议版本标识
8 services uint64_t 该连接允许的特性(bitfield)
8 timestamp int64_t 以秒计算的标准UNIX时间戳
26 addr_me net_addr 生成此消息的节点的网络地址
version
>= 106
26 addr_you net_addr 接收此消息的节点的网络地址
8 nonce uint64_t 节点的随机id,用于侦测这个连接
sub_version_num var_str 辅助版本信息
version
>= 209
4 start_height int32_t 发送节点接收到的最新block
1 relay bool 远程节点是否应该宣告转发的交易,
看BIP 0037,从版本 >= 70001
  如果版本数据包被接受,回送一个“verack”包。

  services目前定义如下:

名称 说明
1 NODE_NETWORK 节点不仅接受headers请求,还可以接受完整block请求
  一个version消息示例(这个例子中缺少检验和和user-agent)

  0000 F9 BE B4 D9 76 65 72 73 69 6F 6E 00 00 00 00 00 ....version.....

  0010 55 00 00 00 9C 7C 00 00 01 00 00 00 00 00 00 00 U....|..........

  0020 E6 15 10 4D 00 00 00 00 01 00 00 00 00 00 00 00 ...M............

  0030 00 00 00 00 00 00 00 00 00 00 FF FF 0A 00 00 01 ................

  0040 DA F6 01 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

  0050 00 00 00 00 FF FF 0A 00 00 02 20 8D DD 9D 20 2C .......... ... ,

  0060 3A B4 57 13 00 55 81 01 00 :.W..U...

  Message header:

  F9 BE B4 D9 -魔术数: main 网络

  76 65 72 73 69 6F 6E 00 00 00 00 00 -命令: "version"

  55 00 00 00 -负载长度为 85 字节

  -version 消息中没有校验和

  Version message:

  9C 7C 00 00 - 31900 (版本 0.3.19)

  01 00 00 00 00 00 00 00 - 1 (NODE_NETWORK services)

  E6 15 10 4D 00 00 00 00 - Mon Dec 20 21:50:14 EST 2010

  01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF 0A 00 00 01 DA F6 – 接收者地址信息 - 见 Network Address 一节

  01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF 0A 00 00 02 20 8D – 发送者地址信息 - 见 Network Address 一节

  DD 9D 20 2C 3A B4 57 13 - 节点的随机唯一ID

  00 - "" 子版本字串 (字串长度为0)

  55 81 01 00   - 发送节点拥有的最新block是 #98645

  有一个(60002)协议版本客户端向本地节点声明它自己的版本。

  新的协议版本已经包括了检验和,这点来自比特币客户端,当连接到另一个本地客户端时,注意到当源和目的地址不可路由时,它根本不填入地址信息。

  0000 f9 be b4 d9 76 65 72 73 69 6f 6e 00 00 00 00 00 ....version.....

  0010 64 00 00 00 35 8d 49 32 62 ea 00 00 01 00 00 00 d...5.I2b.......

  0020 00 00 00 00 11 b2 d0 50 00 00 00 00 01 00 00 00 .......P........

  0030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff ff ................

  0040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

  0050 00 00 00 00 00 00 00 00 ff ff 00 00 00 00 00 00 ................

  0060 3b 2e b3 5d 8c e6 17 65 0f 2f 53 61 74 6f 73 68 ;..]...e./Satosh

  0070 69 3a 30 2e 37 2e 32 2f c0 3e 03 00 i:0.7.2/.>..

  Message Header:

  F9 BE B4 D9 - 主网络魔术数

  76 65 72 73 69 6F 6E 00 00 00 00 00 - "version" 命令

  64 00 00 00 - 数据负载100字节

  3B 64 8D 5A -数据负载校验和

  Version message:

  62 EA 00 00 - 60002 (协议版本 60002)

  01 00 00 00 00 00 00 00 - 1 (NODE_NETWORK services)

  11 B2 D0 50 00 00 00 00 - Tue Dec 18 10:12:33 PST 2012

  01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF 00 00 00 00 00 00 – 接收地址信息 –参看网络地址

  01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF FF 00 00 00 00 00 00 – 发送地址信息 -参看网络地址

  3B 2E B3 5D 8C E6 17 65 - 节点 ID

  0F 2F 53 61 74 6F 73 68 69 3A 30 2E 37 2E 32 2F - "/Satoshi:0.7.2/" 字版本字符串(15字节长)

  C0 3E 03 00       - 发送节点的最后区块号 #212672

  3.2 verack

  应答version消息时发送verack消息。这个消息仅包含一个command为“verack”的消息头

  verack消息示例:

  0000 F9 BE B4 D9 76 65 72 61 63 6B 00 00 00 00 00 00 ....verack......

  0010 00 00 00 00 5D F6 E0 E2 ........

  Message header:

  F9 BE B4 D9 - Main network magic bytes

  76 65 72 61 63 6B 00 00 00 00 00 00 - "verack" command

  00 00 00 00 - Payload is 0 bytes long

  5D F6 E0 E2 - Checksum

  3.3 addr

  提供网络上已知节点的信息。一般来说3小时不进行宣告的节点会被网络遗忘。

  数据负载:

字段尺寸 描述 数据类型 说明
1+ count var_int 地址数,最多1000
30x addr_list (uint32_t
+ net_addr)[]
网络上其他节点的地址,版本低于209时仅读取第一条,uint32_t是时间戳
  注意:从31402版本开始,地址前都会附加一个时间戳。如果没有这个时间戳,除非它被确认有效,否则这个地址不会发送到其他节点

  addr消息示例

  0000 F9 BE B4 D9 61 64 64 72 00 00 00 00 00 00 00 00 ....addr........

  0010 1F 00 00 00 7F 85 39 C2 01 E2 15 10 4D 01 00 00 ......9.....M...

  0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF ................

  0030 FF 0A 00 00 01 20 8D ..... .

  Message Header:

  F9 BE B4 D9 - magic :main 网络

  61 64 64 72 00 00 00 00 00 00 00 00 - "addr"

  1F 00 00 00 - payload 长度31字节

  7F 85 39 C2 - payload 校验和

  Payload:

  01 - count : 1 消息中有1条地址

  Address:

  E2 15 10 4D - Mon Dec 20 21:50:10 EST 2010 (版本 >= 31402时)

  01 00 00 00 00 00 00 00 - 1 (NODE_NETWORK service - 见 [[#version]])

  00 00 00 00 00 00 00 00 00 00 FF FF 0A 00 00 01   - IPv4: 10.0.0.1, IPv6: ::ffff:10.0.0.1 (IPv4-mapped IPv6 address)

  20 8D - 端口 8333

  3.4 inv

  节点通过此消息可以宣告它拥有的对象信息。这个消息可以主动发送,也可以用于应答getblocks消息

  数据负载 (最大长度 1.8M, 或者50000 个数据项):

字段尺寸 描述 数据类型 说明
count var_int 清单(inventory)数量
36x inventory inv_vect[] 清单(inventory)数据
  3.5 getdata

  getdata用于应答inv消息来获取指定对象,它通常在接收到inv包,并且过滤掉已知元素后发送。可用于获得交易,但当且仅当他们在内存池或转发集合中-为了避免某些节点开始依赖具有全部交易索引的节点(现代节点不会),所以任意访问块链中的交易是不允许的,

  数据负载 (最大长度 1.8M, 或者50000 个数据项):

字段尺寸 描述 数据类型 说明
count var_int 清单(inventory)数量
36x inventory inv_vect[] 清单(inventory)数据
  3.6 notfound

  Notfound是对getdata消息的回应,如果要求的数据项不能被转发则发送该信息。例如:要求的交易未在内存池或转发集合中。

字段尺寸 描述 数据类型 说明
count var_int 清单(inventory)数量
36x inventory inv_vect[] 清单(inventory)数据
  3.7 getblocks

  返回一个包含区块列表的inv数据包,区块定位对象中最新的区块HASH之后的区块,到hast_stop或最多500个区块(看哪个数值先达到)。

  节点以区块出现在消息中的顺序处理定位区块,如果一个区块HASH在节点的主块链中出现过,则它之前的区块将通过inv消息返回,剩余的定位区块被忽略,而不管要求的500块限制是否已经达到。

  要获取下一个区块HASH,需要以一个新的区块定位对象重新发送getblocks消息,要记住,如果区块定位对象包含一个在无效支链上的HASH时,一些客户端(特别是中本聪客户端)将提供无效区块。

  数据负载:

大小 描述 类型 说明
4 版本 uint32_t 协议版本
1+ HASH个数 var_int 区块定位HASH个数
32+ 区块定位HASH char[32] 区块定位HASH,最新的区块(开始时比较密集,后面比较稀疏)
32 hash_stop char[32] 最后一个期望的区块,如果希望得到越多越好的区块数(超过500),则设为0
  如果要创建区块定位HASH,持续把区块HASH推入堆栈,直到回到创世块,每推入10个HASH,每个循环的步长加倍。示例程序如下所示:

  // From libbitcoin which is under AGPL

  std::vector block_locator_indices(int top_depth)

  {

  // Start at max_depth

  std::vector indices;

  // Push last 10 indices first

  size_t step = 1, start = 0;

  for (int i = top_depth; i > 0; i -= step, ++start)

  {

  if (start >= 10)

  step *= 2;

  indices.push_back(i);

  }

  indices.push_back(0);

  return indices;

  }

  注意:发送更少的已知HASH甚至只有一个,是允许的。然而,区块定位对象的目的是在调用者的主链上检测错误分支。如果该节点检测到你已经从主链上分离,将会发送比你的最新已经区块更早的区块HASH,因而你如果只发送了你的最新已经HASH,而它已经从主链上分叉,则该节点会从区块1开始发。

  3.8 getheaders

  返回一个包含区块头列表的inv数据包,区块定位对象中最新的区块HASH之后的区块头,到hast_stop或最多2000个区块头(看哪个数值先达到)。

  要获取下一个区块头,需要以一个新的区块定位对象重新发送getheaders消息,瘦客户端不可能下载所有的区块内容,因而它们使用消息getheaders来快速下载区块头。

  要记住,如果区块定位对象包含一个在无效支链上的区块头时,一些客户端(特别是中本聪客户端)将提供无效区块头。

  数据负载:

大小 描述 类型 说明
4 版本 uint32_t 协议版本
1+ HASH个数 var_int 区块定位HASH个数
32+ 区块定位HASH char[32] 区块定位HASH,最新的区块头(开始时比较密集,后面比较稀疏)
32 hash_stop char[32] 最后一个期望的区块头,如果希望得到越多越好的区块数(超过500),则设为0
  该数据结构中的区块定位对象,与getblocks一样的生成规则。

  3.9 tx

  tx消息描述一笔比特币交易,用于应答getdata消息

字段尺寸 描述 数据类型 说明
4 version uint32_t 交易数据格式版本
1+ tx_in
count
var_int 交易的输入数
41+ tx_in tx_in[] 交易输入或比特币来源列表
1+ tx_out
count
var_int 交易的输出数
8+ tx_out tx_out[] 交易输出或比特币去向列表
4 lock_time uint32_t 交易的锁定期限或区块数目。
如果为0则交易一直被锁定;小于5亿是指区块号;大于等于5亿是指UNIX时间戳。
如果所有的txin输入都已经终结(0xffffffff)的序列号,这时lock_time任意。否则该交易将到lock_time之后才会被包含到区块中,看NLockTime。
  tx_in的构成:
字段尺寸 描述 数据类型 说明
36 previous_output outpoint 对前一输出的引用
1+ script
length
var_int signature
script 的长度
signature
script
uchar[] 用于确认交易授权的计算脚本
4 sequence uint32_t 发送者定义的交易版本,用于在交易被写入block之前更改交易
  OutPoint结构的构成:
字段尺寸 描述 数据类型 说明
32 hash char[32] 引用的交易的哈希
4 index uint32_t 指定输出的索引,第一笔输出的索引是0,以此类推
  script由一系列与交易相关的信息和操作组成

  详情请参考”比特币脚本”或源代码script.h 和 script.cpp。

  tx_out的构成:

字段尺寸 描述 数据类型 说明
8 value uint64_t 交易的比特币数量(单位是0.00000001)
1+ pk_script
length
var_int pk_script的长度
pk_script uchar[] 通常包含公钥,作为赎回本输出的比特币脚本的创建条件。
  tx消息示例:

  000000 F9 BE B4 D9 74 78 00 00 00 00 00 00 00 00 00 00 ....tx..........

  000010 02 01 00 00 E2 93 CD BE 01 00 00 00 01 6D BD DB .............m..

  000020 08 5B 1D 8A F7 51 84 F0 BC 01 FA D5 8D 12 66 E9 .[...Q........f.

  000030 B6 3B 50 88 19 90 E4 B4 0D 6A EE 36 29 00 00 00 .;P......j.6)...

  000040 00 8B 48 30 45 02 21 00 F3 58 1E 19 72 AE 8A C7 ..H0E.!..X..r...

  000050 C7 36 7A 7A 25 3B C1 13 52 23 AD B9 A4 68 BB 3A .6zz%;..R#...h.:

  000060 59 23 3F 45 BC 57 83 80 02 20 59 AF 01 CA 17 D0 Y# E.W... Y.....

  000070 0E 41 83 7A 1D 58 E9 7A A3 1B AE 58 4E DE C2 8D .A.z.X.z...XN...

  000080 35 BD 96 92 36 90 91 3B AE 9A 01 41 04 9C 02 BF 5...6..;...A....

  000090 C9 7E F2 36 CE 6D 8F E5 D9 40 13 C7 21 E9 15 98 .~.6.m...@..!...

  0000A0 2A CD 2B 12 B6 5D 9B 7D 59 E2 0A 84 20 05 F8 FC *.+..].}Y... ...

  0000B0 4E 02 53 2E 87 3D 37 B9 6F 09 D6 D4 51 1A DA 8F N.S..=7.o...Q...

  0000C0 14 04 2F 46 61 4A 4C 70 C0 F1 4B EF F5 FF FF FF ../FaJLp..K.....

  0000D0 FF 02 40 4B 4C 00 00 00 00 00 19 76 A9 14 1A A0 [email protected]....

  0000E0 CD 1C BE A6 E7 45 8A 7A BA D5 12 A9 D9 EA 1A FB .....E.z........

  0000F0 22 5E 88 AC 80 FA E9 C7 00 00 00 00 19 76 A9 14 "^...........v..

  000100 0E AB 5B EA 43 6A 04 84 CF AB 12 48 5E FD A0 B7 ..[.Cj.....H^...

  000110 8B 4E CC 52 88 AC 00 00 00 00 .N.R......

  Message header:

  F9 BE B4 D9 - magic: main 网络

  74 78 00 00 00 00 00 00 00 00 00 00 - command:"tx" command

  02 01 00 00 - payload 长度: 258字节

  E2 93 CD BE - payload 校验和

  Transaction:

  01 00 00 00 - version

  Inputs:

  01 - 交易的输入数:1

  Input 1:

  6D BD DB 08 5B 1D 8A F7 51 84 F0 BC 01 FA D5 8D - 前一输出(outpoint)

  12 66 E9 B6 3B 50 88 19 90 E4 B4 0D 6A EE 36 29

  00 00 00 00

  8B - script 长度:139字节

  48 30 45 02 21 00 F3 58 1E 19 72 AE 8A C7 C7 36 - signature script (scriptSig)

  7A 7A 25 3B C1 13 52 23 AD B9 A4 68 BB 3A 59 23

  3F 45 BC 57 83 80 02 20 59 AF 01 CA 17 D0 0E 41

  83 7A 1D 58 E9 7A A3 1B AE 58 4E DE C2 8D 35 BD

  96 92 36 90 91 3B AE 9A 01 41 04 9C 02 BF C9 7E

  F2 36 CE 6D 8F E5 D9 40 13 C7 21 E9 15 98 2A CD

  2B 12 B6 5D 9B 7D 59 E2 0A 84 20 05 F8 FC 4E 02

  53 2E 87 3D 37 B9 6F 09 D6 D4 51 1A DA 8F 14 04

  2F 46 61 4A 4C 70 C0 F1 4B EF F5

  FF FF FF FF - sequence

  Outputs:

  02 - 交易的输出数:2

  Output 1:

  40 4B 4C 00 00 00 00 00 - 0.05 BTC (5000000)

  19 - pk_script 长度:25字节

  76 A9 14 1A A0 CD 1C BE A6 E7 45 8A 7A BA D5 12 - pk_script

  A9 D9 EA 1A FB 22 5E 88 AC

  Output 2:

  80 FA E9 C7 00 00 00 00 - 33.54 BTC (3354000000)

  19 - pk_script 长度:25字节

  76 A9 14 0E AB 5B EA 43 6A 04 84 CF AB 12 48 5E - pk_script

  FD A0 B7 8B 4E CC 52 88 AC

  Locktime:

  00 00 00 00 - lock time

  3.10 block

  block消息用于响应getdata消息

字段尺寸 描述 数据类型 说明
4 version uint32_t block版本信息,基于生成block的软件版本
32 prev_block char[32] 这一block引用的前一block之哈希
32 merkle_root char[32] 与这一block相关的全部交易之哈希(Merkle树)
4 timestamp uint32_t 记录block创建时间的时间戳
4 bits uint32_t 这一block的计算难度
4 nonce uint32_t 用于生成这一block的nonce值
txn_count var_int 交易数量
txns tx[] 交易,以tx格式存储
  用于识别每个区块的SHA256哈希使用这个结构的前6个字段计算(version, prev_block, merkle_root, timestamp, bits, nonce, 后接标准 SHA256 填充, 共2个64字节块)而非整个block。SHA256算法计算哈希只需要处理2个64字节块。由于nonce字段在第二个数据块里,在挖矿过程中,第一个数据块保持不变。因此只需要处理第二个数据块。但是比特币区块哈希是二次哈希,每个开采循环需要2轮SHA256计算(具体详细请看译者的“比特币块链和挖矿原理”)。

  3.11 headers

  headers消息返回区块头以应答getheaders

  Payload:

字段尺寸 描述 数据类型 说明
count var_int block头数量
81x headers block_header[] block头
  注意,该数据包中的区块头包含交易count(一个var_int,因而每个区块头可能超过81字节),与发给矿工的区块头不同。

  3.12 getaddr

  getaddr消息向一个节点发送获取已知活动节点的请求,以发现网络节点。回应这个消息的方法是发送addr消息,包含一个或多个节点信息。活动节点的一般假设是3小时内发送过消息。

  这个消息没有附加数据。

  3.13 mempool

  Mempool消息向节点发送请求,询问已经通过验证但没有确认的交易信息。收到此消息,可返回inv消息,包含在节点mempool中的所有交易HASH列表。

  Mempool定义在BIP 35,从BIP 37开始,只能符合过滤条件的交易会被应答。

  3.14 checkorder

  此消息用于IP Transactions,因为IP交易已经被取消,该消息不再使用。

  3.15 submitorder

  此消息用于IP Transactions,因为IP交易已经被取消,该消息不再使用。

  3.16 reply

  此消息用于IP Transactions,因为IP交易已经被取消,该消息不再使用。

  3.17 ping

  ping消息主要用于确认TCP/IP连接的可用性。传输错误被假定为已经关闭的连接,并且IP地址已经变为当前的节点。

  数据负载:

字段尺寸 描述 数据类型 说明
8 nonce uint64_t 随机数
  3.18 pong

  Pong消息用于回应ping消息,在当前的协议版本,pong用ping的nonce回应。

  数据负载:

字段尺寸 描述 数据类型 说明
8 nonce uint64_t 来自ping的随机数
  3.19 reject

  当消息被拒绝时就发送Reject消息。

  数据负载:

字段尺寸 描述 数据类型 说明
1+ message var_str 消息类型
1 ccode char 拒绝消息的原因码
1+ reason var_str 拒绝消息的文本原因
  Ccode码
名称 描述
0x01 REJECT_MALFORMED  
0x10 REJECT_INVALID  
0x11 REJECT_OBSOLETE  
0x12 REJECT_DUPLICATE  
0x40 REJECT_NONSTANDARD  
0x41 REJECT_DUST  
0x42 REJECT_INSUFFICIENTFEE  
0x43 REJECT_CHECKPOINT  
  3.20 filterload, filteradd, filterclear, merkleblock

  这些命令与在连接的Bloom过滤相关,定义在BIP 37中。

  3.21 alert

  alert消息用于在节点间发送通知使其传遍整个网络。如果签名验证这个alert来自Bitcoin的核心开发组,建议将这条消息显示给终端用户。建议停止交易,尤其是客户端间的自动交易更应该停止。消息文字应当记入记录文件并传到每个用户。

  数据负载:

字段尺寸 描述 数据类型 说明
payload uchar[] 保存的alert数据
signature uchar[] 可由公钥验证Satoshi授权或创建了此信息的签名
  签名将用下面的ECDSA公钥做比对:

  04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284

  (hash) 1AGRxqDa5WjUKBwHB9XYEjmkv1ucoUUy1s

  Payload序列化为uchar[],以保证使用不兼容的alert格式的不同版本也能在网络中转发alert消息,当前的alert数据格式为:

字段尺寸 描述 数据类型 说明
4 Version int32_t Alert的格式版本
8 RelayUntil int64_t 时间戳,在这个时间之后应该停止转发alert
8 Expiration int64_t 时间戳,在这个时间之后应该不起作用,应该被忽略
4 ID int32_t alert的唯一ID号
4 Cancel int32_t ID号小于或等于该数字的alerts应该被取消,删除并且以后不再接收。
setCancel set<int32_t> 在该集合中的所有alert的ID应该被取消,删除并且以后不再接收。
4 MinVer int32_t 本alert仅应用于版本大于或等于这个小版本,其他小版本应该转发。
4 MaxVer int32_t 本alert仅应用于版本大于或等于这个大版本,其他大版本应该转发。
setSubVer set<string> 如果该集合包含元素,则只有子版本在本集合中的节点受到影响,其他版本的节点应该转发。
4 Priority int32_t 与其他alerts相比的相对优先级
Comment string 不用显示的alert说明。
StatusBar string 应该显示的alert说明。
Reserved string 保留
  注意:上面表格中的set是变长整数,后面跟着给定类型(int32_t或变长字符串)项目数量。

  Alert例子(没有消息头)

  73010000003766404f00000000b305434f00000000f2030000f1030000001027000048ee0000

  0064000000004653656520626974636f696e2e6f72672f666562323020696620796f75206861

  76652074726f75626c6520636f6e6e656374696e672061667465722032302046656272756172

  79004730450221008389df45f0703f39ec8c1cc42c13810ffcae14995bb648340219e353b63b

  53eb022009ec65e1c1aaeec1fd334c6b684bde2b3f573060d5b70c3a46723326e4e8a4f1

  Version: 1

  RelayUntil: 1329620535

  Expiration: 1329792435

  ID: 1010

  Cancel: 1009

  setCancel:

  MinVer: 10000

  MaxVer: 61000

  setSubVer:

  Priority: 100

  Comment:

  StatusBar: "See bitcoin.org/feb20 if you have trouble connecting after 20 February"

  Reserved:

知识: 比特币协议