比特币源码分析-网络(一)

区块链技术巴比特2018-03-23 16:36:00  阅读 -评论 0  阅读原文

在梳理代码逻辑之前,首先介绍几个比较重要的结构:

比特币源码分析-网络(一)

CMessageHeader

消息头包含的内容:

class CMessageHeader { public: enum { MESSAGE_START_SIZE = 4, //消息开始字符串,长度4字节,就是告诉你是属于哪种消息标识,在UTF-8中无效 //主类型(MAIN): 0xd9b4bef9 //测试网络(TESTNET):0x0709110b //回归测试(REGTEST):0xdab6bffa COMMAND_SIZE = 12, //定义了通信中的各种命令,由0x20~0x7F之间的字 符串构成, MESSAGE_SIZE_SIZE = 4, //最大值是32M (0x02000000)。 不包含消息头的大小 CHECKSUM_SIZE = 4, //把消息数据经过2次SHA256算法运算得到校验和 }; Message Headers

网络传输中,所有消息的消息头格式是一样的,下面解释一下每一个消息头具体包含哪些内容:

比特币源码分析-网络(一)

GetDataMsg

getdata / inv消息类型。这些号码由协议定义。

enum GetDataMsg { UNDEFINED = 0, MSG_TX = 1, MSG_BLOCK = 2, // The following can only occur in getdata. Invs always use TX or BLOCK. //!< Defined in BIP37 MSG_FILTERED_BLOCK = 3, //!< Defined in BIP152 MSG_CMPCT_BLOCK = 4, //!< Extension block MSG_EXT_TX = MSG_TX | MSG_EXT_FLAG, MSG_EXT_BLOCK = MSG_BLOCK | MSG_EXT_FLAG, };

消息类型大致分为:

MSG_TX 交易信息
MSG_BLOCK 区块
MSG_FILTERED_BLOCK 过滤的区块
MSG_CMPCT_BLOCK 紧凑区块 //bip152

NetMsgType

namespace NetMsgType { const char *VERSION = "version";//获取版本信息 const char *VERACK = "verack";//版本信息回应 const char *ADDR = "addr";//网络节点的地址 const char *INV = "inv";//库存清单 const char *GETDATA = "getdata";//获取数据 const char *MERKLEBLOCK = "merkleblock";//merkle块 const char *GETBLOCKS = "getblocks";//获取区块 const char *GETHEADERS = "getheaders";//获取区块头 const char *TX = "tx";//交易信息 const char *HEADERS = "headers";//区块头 const char *BLOCK = "block";//区块 const char *GETADDR = "getaddr";//获取地址 const char *MEMPOOL = "mempool";//内存池 const char *PING = "ping";//判断网络是否连通 const char *PONG = "pong";//ping消息回应 const char *NOTFOUND = "notfound";//没有获取相匹配的数据 const char *FILTERLOAD = "filterload";//加载过滤器 const char *FILTERADD = "filteradd";//添加过滤交易信息 const char *FILTERCLEAR = "filterclear";//清理过滤器 const char *REJECT = "reject";//拒绝 //======================网络协议版本号为70002之前======================// const char *SENDHEADERS = "sendheaders"; //bip130 发送块头信息 const char *FEEFILTER = "feefilter";//BIP133 feefilter const char *SENDCMPCT = "sendcmpct";// BIP152 发送紧凑区块 const char *CMPCTBLOCK = "cmpctblock";// BIP152 紧凑区块 const char *GETBLOCKTXN = "getblocktxn";// BIP152 获取紧凑区块交易 const char *BLOCKTXN = "blocktxn";// BIP152 紧凑区块交易 }; Inv

当需要获取inventory时,发送此命令,发送时,需要指定范围。接收到此命令后,按指定范围获取inventory数据(PushGetBlocks)。

比特币源码分析-网络(一)

Inv 消息的示例:

02 ................................. Count: 2 01000000 ........................... Type: MSG_TX de55ffd709ac1f5dc509a0925d0b1fc4 42ca034f224732e429081da1b621f55a ... Hash (TXID) 01000000 ........................... Type: MSG_TX 91d36d997037e08018262978766f24b8 a055aaf1d872e94ae85e9817b2c68dc7 ... Hash (TXID)

getdata:

getdata消息请求来自另一个节点的一个或多个数据对象。这些对象由一个 inventory 请求,请求节点通常通过inv消息预先接收这些对象。

对 getdata 消息的响应可以是 tx 消息,阻塞消息,merkleblock 消息或未找到的消息。

getdata 不能用于请求任意数据,例如不再存在于内存池中的一些历史交易。如果全节点已经从其block数据库中打包了先前的交易,这时全节点可能无法提供这些block。 出于这个原因,getdata消息通常只能通过发送inv消息向先前通告它的节点请求数据。

getdata消息的格式和最大大小限制与inv消息相同,但是消息标题不同。

merkleblock:

如BIP37所述,在协议版本70001中添加。

merkleblock 消息是对使用 inventory 类型 MSG_MERKLEBLOCK 请求块的 getdata 消息的回复。这只是答复的一部分:如果找到任何匹配的交易,它们将作为tx消息单独发送。

如果之前已经使用过滤器加载消息设置了过滤器,则merkleblock消息将包含所请求块中与过滤器匹配的所有事务的TXID以及将这些事务连接到块头的必要块所需的块merkle树的任何部分 merkle根。 该消息还包含块头的完整副本,以允许客户端对其进行 hash 并确认其工作证明

merkleblock消息示例:

01000000 ........................... Block version: 1 82bb869cf3a793432a66e826e05a6fc3 7469f8efb7421dc88067010000000000 ... Hash of previous block's header 7f16c5962e8bd963659c793ce370d95f 093bc7e367117b3c30c1f8fdd0d97287 ... Merkle root 76381b4d ........................... Time: 1293629558 4c86041b ........................... nBits: 0x04864c * 256**(0x1b-3) 554b8529 ........................... Nonce 07000000 ........................... Transaction count: 7 04 ................................. Hash count: 4 3612262624047ee87660be1a707519a4 43b1c1ce3d248cbfc6c15870f6c5daa2 ... Hash #1 019f5b01d4195ecbc9398fbf3c3b1fa9 bb3183301d7a1fb3bd174fcfa40a2b65 ... Hash #2 41ed70551dd7e841883ab8f0b16bf041 76b7d1480e4f0af9f3d4c3595768d068 ... Hash #3 20d2a7bc994987302e5b1ac80fc425fe 25f8b63169ea78e68fbaaefa59379bbf ... Hash #4 01 ................................. Flag bytes: 1 1d ................................. Flags: 1 0 1 1 1 0 0 0

getblocks

getblocks消息请求一个inv消息,该消息提供从块链中的特定点开始的块头hash。区块同步时,发送此命令,发送时需要指定区块范围(PushGetBlocks)。接收到此命令后,根据区块范围,获取相应的区块,反馈回去。接收的数据中包含区块范围的开始区块的定位信息(CBlockLocator)、结束区块的索引,从开始区块的下一个区块开始。每次最多获取500个区块信息。满500个时,记录获取的最后一个区块的hahs值,保存到源节点的hashContinue中。

比特币源码分析-网络(一)

示例如下:

71110100 ........................... Protocol version: 70001 02 ................................. Hash count: 2 d39f608a7775b537729884d4e6633bb2 105e55a16a14d31b0000000000000000 ... Hash #1 5c3e6403d40837110a2e8afb602b1c01 714bda7ce23bea0a0000000000000000 ... Hash #2 00000000000000000000000000000000 00000000000000000000000000000000 ... Stop hash

getheaders

getheaders消息请求 headers 消息,该消息提供从块链中的特定点开始的块 header。接收到此命令后,获取指定的范围的区块的头,将 headers消息发送给源节点。

getheaders消息几乎与getblocks消息相同,只有一点区别:对getblocks消息的inv回复将包含不超过500个块头hash; headers 回复 getheaders 消息将包含多达2000个块 headers。

tx

tx 消息以原始交易格式传输单个交易。它可以在各种情况下发送;

- 交易响应:Bitcoin Core 和 BitcoinJ 将发送它以响应getdata消息,该消息请求 inventory 类型为MSG_TX的交易。
- MerkleBlock响应:Bitcoin Core 将发送它以响应getdata消息,该消息请求inventory类型为MSG_MERKLEBLOCK的merkle块。 (这是发送merkleblock消息的补充。)在这种情况下,每个tx消息提供该块的匹配交易。
- Unsolicited:BitcoinJ会发送一个tx消息来主动发起它的交易。

headers

headers 消息将 block message 发送到先前用getheaders消息请求特定 headers 的节点。headers 消息可以是空的。

比特币源码分析-网络(一)

示例如下:

01 ................................. Header count: 1 02000000 ........................... Block version: 2 b6ff0b1b1680a2862a30ca44d346d9e8 910d334beb48ca0c0000000000000000 ... Hash of previous block's header 9d10aa52ee949386ca9385695f04ede2 70dda20810decd12bc9b048aaab31471 ... Merkle root 24d95a54 ........................... Unix time: 1415239972 30c31b18 ........................... Target (bits) fe9f0864 ........................... Nonce 00 ................................. Transaction count (0x00)

block

block message以 serialized blocks section 描述的格式发送单个 serialized block。

- 获取数据响应:节点将始终发送它以响应一个getdata消息,该消息请求存储类型为MSG_BLOCK的块(假设该节点具有可用于发送的该块)。
- 主动提供:一些矿工会发送未经请求的block信息,将他们新挖掘的块块广播给他们的所有同行。 许多矿池做同样的事情,虽然有些可能被错误地配置为从多个节点发送块,可能不止一次地将同一块发送给别的节点。

notfound

notfound 的消息是对getdata消息的回复,该消息请求接收节点没有可用于发送的对象。 (预计节点不会传递不再存在于内存池或发送集中的历史事务,节点也可能从较旧的块中删除已用完的事务,使它们无法发送这些块。)

notfound消息的格式和最大大小限制与inv消息相同,只有消息的headers不同。

mempool

mempool消息请求接收节点已验证为有效但尚未出现在块中的交易的TXID。 也就是说,在接收节点的内存池中的交易。 对mempool消息的响应是一个或多个包含 inventory 格式的TXID的inv消息。

当程序首次连接到网络时,发送mempool消息非常有用。 全节点可以使用它来快速收集网络上可用的大部分或全部未确认的交易; 这对试图收取交易费用的矿工尤其有用。 SPV客户端可以在发送mempool之前设置过滤器,以仅接收与该过滤器匹配的交易; 这允许最近开始的客户获得与其钱包有关的大部分或全部未确认的交易。

对mempool消息的inv响应充其量只是一个节点的网络视图 – 而不是网络上未经确认的交易的完整列表。以下是列表可能不完整的一些其他原因:

- 在Bitcoin Core 0.9.0之前,对mempool消息的响应只有一个inv消息。 inv消息被限制为50,000个库存,所以具有大于50,000个条目的内存池的节点不会发送所有内容。 Bitcoin Core 的更新版本根据需要发送尽可能多的inv消息以引用其完整的内存池。
- mempool消息当前不与filterload消息的BLOOM_UPDATE_ALL和BLOOM_UPDATE_P2PUBKEY_ONLY标志完全兼容。 Mempool交易不像块内交易那样排序,因此一个消耗输出的交易(tx2)可以出现在包含该输出的交易(tx1)之前,这意味着自动过滤器更新机制将不会运行,直到第二次出现的交易 tx1) – 缺少首次出现的交易(tx2)。 在Bitcoin Core issue #2381中已经提出,交易在被过滤器处理之前应该被排序。

以上是对 Data Messages 的描述,其关系图如下:

比特币源码分析-网络(一)

version:

version 消息在连接开始时向接收节点提供关于发送节点的信息。在这两个节点交换 version 消息之前,不会接受其他消息。

当接收节点收到version消息之后,会回复给发送节点一个verack消息,同时把所有警告也反馈回去。但是在version消息的初始化未完成之前,是不会发送verack消息的。

发送端只能发送一次获取版本的命令,重复发送时,回应拒绝命令 (reject)。发送命令后,会把发送节点的地址信息添加到节点的地址管理器中。

示例如下:

72110100 ........................... Protocol version: 70002 0100000000000000 ................... Services: NODE_NETWORK bc8f5e5400000000 ................... Epoch time: 1415483324 0100000000000000 ................... Receiving node's services 00000000000000000000ffffc61b6409 ... Receiving node's IPv6 address 208d ............................... Receiving node's port number 0100000000000000 ................... Transmitting node's services 00000000000000000000ffffcb0071c0 ... Transmitting node's IPv6 address 208d ............................... Transmitting node's port number 128035cbc97953f8 ................... Nonce 0f ................................. Bytes in user agent string: 15 2f5361746f7368693a302e392e332f ..... User agent: /Satoshi:0.9.3/ cf050500 ........................... Start height: 329167 01 ................................. Relay flag: true

verack:

verack消息确认先前收到的版本消息,通知连接节点它可以开始发送其他消息。 接收到版本回应命令后,设置节点的接收版本。与此同时,设置接收版本号,节点的接收版本(nRecvVersion)、接收消息的报头流的版本号、接收消息数据流的版本号(nVersion)都要设置。

adddr:

addr(IP地址)消息用来表示网络上节点的连接信息。 每个想要接受传入连接的节点创建一个addr消息,提供其连接信息,然后将该消息发送给未经请求的节点,当接收端收到此命令后把接收到的地址添加到节点的地址管理器中,发送、接收的地址数量最多1000个。

比特币源码分析-网络(一)

Ping

ping消息有助于确认接收方仍处于连接状态(判断网络是否连通)。 如果在发送ping消息时遇到TCP / IP错误(例如连接超时),则发送节点可以假设接收节点已断开连接。 对ping消息的响应是pong消息。

在协议版本60000之前,ping消息没有 payload。从协议版本60001及所有更高版本开始,消息包含一个字段即nonce。

比特币源码分析-网络(一)

ping消息的nonce字段,示例如下:

0094102111e2af4d ... Nonce

pong

pong消息回复ping消息,向pinging节点证明ponging节点仍然存在。默认情况下,Bitcoin Core将在20分钟内断开任何未响应ping消息的客户端。接收到pong命令后,更新节点的ping花费时间(nPingUsecTime),所花费的时间为当前时间与节点的ping开始时间(nPingUsecStart)的差。

为了允许节点跟踪等待时间,pong的回复消息中所包含的nonce字段与ping消息的nonce是相同的。

pong消息的格式与ping消息相同;只有消息头不同。

reject

发生特殊情况时,reject 消息通知接收节点其先前消息之一已被拒绝。

特殊情况如下:

- 重复发送获取版本信息的命令(”version”)。
- 发送端的版本号大于最大版本号(MIN_PEER_PROTO_VERSION = 209)。
- 接收到DDoS攻击。
- 处理消息时发生异常(ProcessMessage)。

发送拒绝命令时,带上参数,表示拒绝的原因。

比特币源码分析-网络(一)

SendHeaders

sendheaders消息告诉接收方使用 headers 消息而不是inv消息发送新的块通告,具体可参照 bip130 。

GetAddr

getaddr消息请求来自接收节点的addr消息,最好是具有大量其他接收节点的IP地址的消息。 发送节点可以使用这些IP地址来快速更新其可用节点的数据库,而不是等待未经请求的addr消息随时间到达。

接收到getaddr命令后把节点的地址管理器中的地址返回给发送端。先清空源节点的发送地址数组(vAddrToSend)。再把节点的IP地址管理器 (addrman)中的地址(CAddress)发送给源节点。

FeeFilter

FeeFilter消息是对接收方的请求,不将任何交易inv消息转发给发送方,其中交易费率低于feefilter消息中指定的费率。

在Bitcoin Core 0.12.0引入mempool限制之后,feefilter在Bitcoin Core 0.13.0中引入。 Mempool限制功能可以防止费用较低的交易的攻击,并且不会将其纳入开采块中。 feefilter消息告诉其他节点,如果你的费率低于我预先设置的费率,那你的这个交易是不允许进入我的mempool的,同时,这些节点就没必要继续把低于该费率的交易的inv消息转达给该节点。

比特币源码分析-网络(一)

接收方可以选择不过滤这笔交易,直接忽略该消息。

FeeFilter与bloom过滤器相加。如果SPV客户端加载bloom过滤器并发送FeeFilter消息,则只有通过两个过滤器才能转发交易。

但请注意,feefilter对块传播或对getdata消息的响应没有影响。 例如,如果一个节点通过发送一个包含inv类型MSG_FILTERED_BLOCK的getdata消息来请求一个merkleblock,并且它先前已经向该节点发送了一个feefilter,那么即使他们低于feefilter的费率,该节点也应该响应一个包含所有匹配bloom过滤器的交易的merkleblock。

示例如下:

7cbd000000000000 ... satoshis per kilobyte: 48,508

FilterAdd

filteradd消息告诉接收方将单个元素添加到先前设置的布隆过滤器,例如新的公共hash。 该元素直接发送给接收方; 然后其它节点使用在过滤器加载消息中设置的参数来将该元素添加到布隆过滤器。

由于该元素直接发送到接收方,因此elem不会产生歧义,也不会出现布隆过滤器提供的似是而非的隐私。希望保持更高隐私性的客户端应自行重新计算布隆过滤器,并使用重新计算的布隆过滤器发送新的过滤器负载消息。

比特币源码分析-网络(一)

注意:除非先前使用的filterload消息设置了过滤器,否则节点将不接受filteradd消息。

示例如下:

20 ................................. Element bytes: 32 fdacf9b3eb077412e7a968d2e4f11b9a 9dee312d666187ed77ee7d26af16cb0b ... Element (A TXID)

FilterClear

filterclear消息告诉接收方删除先前设置的bloom过滤器。这也消除了将版本消息中的转发字段设置为0的效果,允许未经过滤的访问广播新交易的inv消息。

Bitcoin Core在替换过滤器加载filterload之前不需要filterclear消息。它也不需要filterclear消息之前的filterload消息。

FilterLoad

filterload消息告诉接收方需要过滤所有转发的交易,并通过提供的过滤器请求merkle块。 这允许客户接收与其钱包相关的交易。

比特币源码分析-网络(一)

示例如下:

02 ......... Filter bytes: 2 b50f ....... Filter: 1010 1101 1111 0000 0b000000 ... nHashFuncs: 11 00000000 ... nTweak: 0/none 00 ......... nFlags: BLOOM_UPDATE_NONE

sendcmpct and cmpctblock、getblocktxn、blocktxn参照BIP152.

以上是对Control Messages的描述,其关系如下:

比特币源码分析-网络(一)

下表列出了一些值得注意的P2P网络协议版本,其中最新版本列在第一位:

比特币源码分析-网络(一)

比特币源码分析-网络(一)

声明:链世界登载此文仅出于分享区块链知识,并不意味着赞同其观点或证实其描述。文章内容仅供参考,不构成投资建议。投资者据此操作,风险自担。此文如侵犯到您的合法权益,请联系我们100@7234.cn

    参与讨论 (0 人参与讨论)

    相关推荐

    区块链投资趋势报告:巨头入场布局行业趋于成熟

    区块链投资趋势报告:巨头入场布局行业趋于成熟

    来自:https://mp.weixin.qq.com/s?__biz=MzI4NzIxOTY1NA==&amp;mid=2650632639&amp;idx=1&amp;sn=e6d1c29731d992a80410aaee82ec3ea6&amp;chksm=f3d8db16c4af520097e4a64a71b1d4743ac326b9f027

    重新发明货币

    重新发明货币

    一、货币的演化过程 先简单回顾一下人类货币的演化过程,大概有以下阶段: a. 1.0版本:自然货币(贝壳、牲口、金银……) 这个阶段,货币基于一般等价物的稀有性或者实用性,货币不可能出现人为操纵的超发。 b. 2.0版本:早期纸币、银票到本位纸币 当贸易量越来越大,实物货币太不方便了,而且大家发现其实并不在意货币本身有什么价值,在意的只是这么多的货币能不能交换到足够的物品,于是纸币这种信用货

    从比特币交易看欧洲央行虚拟货币分类

    从比特币交易看欧洲央行虚拟货币分类

      互联网对传统社会的颠覆从未停止,在其完成对信息流、商流、物流、资金流的初步改造之后,或将以虚拟货币的形式打破现有货币体系   4月18日,在中国极客张沈鹏创办的比特币交易平台(42BTC.com)上,比特币对人民币的平均交易价为576元。当天,该平台完成了100个比特币的交易量。仅仅过去一周,4月25日上午,比特币对人民币的平均交易价已达到906元。据42BTC网站统计:在过去的32个月

    欧洲央行-比特币报告

    3.1 比特币 3.1.1 基本特征          比特币可能是最成功的,也可能是最有争议的虚拟货币方案,由日本程序员中本聪(译者注:事实上,中本聪是不是日本人,甚至是不是单个人无从考证)在2009年设计并实现。该计划基于一个类似于BitTorrent的P2P网络。BitTorrent是互联网上著名的共享文件协议,应用在电影,游戏和音乐领域。比特币在全球层面上运作,可用于各类货币交易(虚

    彻底玩转比特币地址和私匙

    彻底玩转比特币地址和私匙

    比特币地址和私匙是所有比特币初学者面对的一大难题,再加上那一串超长的字符串,让人更是摸不到头脑。 现在编者以问答的形式,带你一步步的揭开比特币地址和私匙的面纱。 还不知道什么是比特币地址和私匙的同学请点这里 问题一、比特币钱包由什么组成? 答 我们知道,比特币地址和私匙组成了比特币钱包,而私匙则决定了比特币地址上比特币的归属。 地址和私匙 问题二、如果只记得私匙我们还能还原比特币地址么? 答

    用GO语言实现比特币算法

    用GO语言实现比特币算法

    本节的这个例子展示一点点高精度数学包math/big、一点点散列包hash、一点点加密包crypto,还有一点点测试包testing的知识。这里不介绍bitcoin协议和算法——尽管它们很有趣,而是试图指出,Go对多种操作系统的支持,是实现这种跨平台应用的理想语言。 位钱(bitcoin)是一种使用加密手段制作的分布式电子货币。它最初于1998年由Wei Dai提出,并由中本聪(Satoshi

    详解比特币的找零机制

    详解比特币的找零机制

    比特币的找零机制一直让人有些迷惑,明明只向一个地址发送了比特币为什么 blockchain 上面的显示的有时是1个地址对多个地址,有时是多个地址对1个地址,有时又显示多个地址对多个地址? 为什么比特币资深用户要提醒大家当比特币钱包交易100次以上时再次交易后要重新备份钱包,恢复以前的钱包备份有可能会遭遇损失? 是的,这一切都是因为比特币的找零(Change)机制。本文参考 Bitcoin的维

    玩转比特币客户端之一:C盘转移和加速下载

    玩转比特币客户端之一:C盘转移和加速下载

    C盘空间不足?交易数据下载速度太慢?别着急,乐享比特币教你轻松玩转比特币官方客户端。 所有新人开始接触比特币时做的第一件事情大多数是安装比特币的官方客户端。 安全起见大家最好直接访问官方发布渠道sourceforge的地址进行下载:http://sourceforge.net/projects/bitcoin/files/Bitcoin/ 该网页列出了各版本的官方比特币客户端,目前

    麦妖榜
    更新日期 2019-06-18
    排名用户贡献值
    1BitettFan23992
    2等待的宿命23809
    3六叶树20309
    4区块大康18727
    5牛市来了16520
    6天下无双16192
    7linjm122716021
    8lizhen00215101
    9让时间淡忘14475
    10冷风大q11188
    返回顶部 ↑