比特币协议
时间:2014-07-26 来源:巴比特 作者:玩币族
本文译自比特币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 (消息)
已定义的magic值:
整数可以根据表达的值进行编码以节省空间。变长整数总是在可变长度数据类型的数组/向量之前出现。更长的数字以小头位序编码。
2.3 Variable length string (变长字符串) 变长字符串由一个变长整数和一个字符串构成。
需要网络地址时会用到这个结构。这个协议和数据结构支持IPv6,但需要注意目前官方客户端仅支持IPv4网络,网络地址在版本消息中,并非以时间戳为开始。
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 (清单向量) 清单向量用于告知其他节点本节点拥有的对象或请求的数据,由以下数据格式构成
2.6 Block Headers (Block头部) 回应getheaders消息时,将区块头部放入一个数据包中并且发送。
3.1 version 当一个节点收到连接请求时,它立即宣告其版本。远程节点会以自己的版本响应,在通信双方都得到对方版本之前,不会有其他通信。 结构:
services目前定义如下:
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小时不进行宣告的节点会被网络遗忘。 数据负载:
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 个数据项):
getdata用于应答inv消息来获取指定对象,它通常在接收到inv包,并且过滤掉已知元素后发送。可用于获得交易,但当且仅当他们在内存池或转发集合中-为了避免某些节点开始依赖具有全部交易索引的节点(现代节点不会),所以任意访问块链中的交易是不允许的, 数据负载 (最大长度 1.8M, 或者50000 个数据项):
Notfound是对getdata消息的回应,如果要求的数据项不能被转发则发送该信息。例如:要求的交易未在内存池或转发集合中。
返回一个包含区块列表的inv数据包,区块定位对象中最新的区块HASH之后的区块,到hast_stop或最多500个区块(看哪个数值先达到)。 节点以区块出现在消息中的顺序处理定位区块,如果一个区块HASH在节点的主块链中出现过,则它之前的区块将通过inv消息返回,剩余的定位区块被忽略,而不管要求的500块限制是否已经达到。 要获取下一个区块HASH,需要以一个新的区块定位对象重新发送getblocks消息,要记住,如果区块定位对象包含一个在无效支链上的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来快速下载区块头。 要记住,如果区块定位对象包含一个在无效支链上的区块头时,一些客户端(特别是中本聪客户端)将提供无效区块头。 数据负载:
3.9 tx tx消息描述一笔比特币交易,用于应答getdata消息
详情请参考”比特币脚本”或源代码script.h 和 script.cpp。 tx_out的构成:
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消息
3.11 headers headers消息返回区块头以应答getheaders Payload:
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地址已经变为当前的节点。 数据负载:
Pong消息用于回应ping消息,在当前的协议版本,pong用ping的nonce回应。 数据负载:
当消息被拒绝时就发送Reject消息。 数据负载:
这些命令与在连接的Bloom过滤相关,定义在BIP 37中。 3.21 alert alert消息用于在节点间发送通知使其传遍整个网络。如果签名验证这个alert来自Bitcoin的核心开发组,建议将这条消息显示给终端用户。建议停止交易,尤其是客户端间的自动交易更应该停止。消息文字应当记入记录文件并传到每个用户。 数据负载:
04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284 (hash) 1AGRxqDa5WjUKBwHB9XYEjmkv1ucoUUy1s Payload序列化为uchar[],以保证使用不兼容的alert格式的不同版本也能在网络中转发alert消息,当前的alert数据格式为:
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: |