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

当前位置:首页 > 币圈百科 > 比特币源码分析-网络(一)

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

2022-12-07币圈百科252

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

10

CMMessageHeader

消息头的内容:

class CMMessageHeader { public:enum { message _ start _ size=4,//消息开始字符串长度4个字节,告诉你它属于哪个消息ID,在UTF-8中无效。//Main type(Main):0x d 9 B4 bef 9//测试网络(TESTNET):0x 0709110 b///回归测试(reg Test):0x dab 6 bffacommand _ size=12,//定义通信中的各种命令,它由0x20到0x7f之间的字符串组成,message _ size _ size=4,//最大值为32M (0x02000000)。不包括报文头大小checksum _ size=4,//报文数据经过SHA256算法两次处理得到校验和};

报文头

在网络传输中,所有报文的报文头格式都是一样的。下面解释一下每个消息头包含的内容:

1get data msg

get data/inv消息类型。这些数字是由协议定义的。

enum GetDataMsg { UNDEFINED=0,MSG_TX=1,MSG_BLOCK=2,//以下内容只能出现在getdata中。inv总是使用TX或BLOCK。//!BIP37中定义的MSG_FILTERED_BLOCK=3,//!BIP152中定义的MSG_CMPCT_BLOCK=4,//!扩展块MSG_EXT_TX=MSG_TX | MSG_EXT_FLAG,MSG _ EXT _ BLOCK=MSG _ BLOCK | MSG _ EXT _ FLAG,};

消息类型大致分为:

MSG_TX事务信息MSG _ BLOCK _ filtered BLOCK MSG _ cm pct _ BLOCK compact BLOCK//bip 152

netmsgtype

namespace netmsgtype { const char * version=' version ';//获取版本信息const char * VERACK=' verack//版本信息响应const char * ADDR=' addr ';//网络节点的地址const char * INV=' inv//库存列表const char * GETDATA=' getdata//Get data const char * merkle block=' merkle block ';//merkle block const char * get blocks=' get blocks ';//获取块const char * Get headers=' Get headers ';//获取块头const char * TX=' tx//事务信息const char * HEADERS=' headers//块头const char * BLOCK=' block//Block const char * get addr=' get addr ';//获取地址const char * MEMPOOL=' mempool//内存池const char * PING=' ping//确定网络是否连通const char * PONG=' pong//ping消息响应const char * NOTFOUND=' notfound//未获得匹配的数据const char * filter load=“filter load”;//load filter const char * filter add=' filter add ';//添加过滤后的交易信息const char * filter clear=' filter clear ';//清洗过滤器const char * REJECT=' reject//Reject//===============网络协议版本号为70002之前================================/const char * send headers=//bip 130发送块头信息const char * fee filter=' fee filter ';//bip 133 fee filter const char * SENDCMPCT=' SENDCMPCT ';//BIP152发送压缩块const char * cmpctblock=' cmpctblock ';//bip 152 compact block const char * get block xn=' get block xn ';//BIP152获取紧凑块事务const char * BLOCKTXN=' blocktxn//BIP152压缩块事务};

Inv

当需要获取库存时,发送此命令。发送时,需要指定范围。收到该命令后,获取指定范围内的库存数据(PushGetBlocks)。

2INV消息示例:

02.....计数:2 01000000....型号:MSG _ TX de 55 ffd 709 AC 1 f 5 DC 509 a 0925d 0 B1 fc 4 42ca 034 f 224732 e 429081d a1b 621 f 55 a.哈希(TXID) 000000....型号:Msg _ tx91d 36d 997037 e 08018262978766 f 24 b 8 a 055 aa f1 d 872 e 94 AE 85 e 9817 B2C 68 DC 7.hash(TXID)

get data:

get data消息从另一个节点请求一个或多个数据。这些对象由库存请求,并且请求节点通常通过inv消息预先接收这些对象。

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

getdata不能用于请求任意数据,例如一些不再存在于内存池中的历史事务。如果整个节点已经打包了来自其块数据库的先前事务,则整个节点可能无法提供这些块。 由于这个原因,getdata消息只能从先前通过发送inv消息宣布它的节点请求数据。

GET DATA报文的格式和最大大小限制与inv报文相同,但报文头不同。

Merkle Block:

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

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

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

Merkle块消息示例:

01000000....Block版本:1 82bb 869 cf 3a 793432 a66e 826 e 05 a6fc 3 7469 F8 efb 7421 DC 880670100000000.前一个块的header 7 F16 c 5962 e8bd 963659 c 793 ce 370d 95 f 093 BC 7 e 367117 B3 c 30 C1 f 8 FDD 0d 97287的哈希.Merkle root 76381b4d....时间:1293629558 4c86041b。...nBits:0x 04864 c * 256 * *(0x1b-3)554 b 8529....随机数07000000....交易计数:7 04.....哈希计数:4 3612262624047 ee 87660 be 1a 707519 a4 43 B1 C1 ce 3d 248 cbfc 6 c 15870 F6 C5 DAA 2.哈希# 1 019 F5 b 01d 4195 ecbc 9398 FB F3 C3 B1 fa 9 bb 3183301 D7 a1 FB 3 BD 174 fcfa 40 a2 b 65.哈希# 2 41ed 70551 DD 7 e 841883 ab 8 f 0 b 16 BF 041 76b7d 1480 E4 f 0 af 9 f 3d 4c 3595768d 068.哈希# 3 20 D2 a7 BC 994987302 e 5b 1 AC 80 fc 425 Fe 25 F8 b 63169 ea 78 e 68 fbaaefa 59379 bbf.哈希# 01.....标志字节:11D.....flags:1011000

get blocks

get blocks message请求inv消息,该消息提供来自区块链中特定点的块头的散列。同步块时,发送以下命令。发送时,需要指定PushGetBlocks。收到这个命令后,根据块范围,得到相应的块并反馈。从起始块的下一个块开始,接收的数据包括起始块的位置信息(CBlockLocator)和块范围中结束块的索引。一次获取多达500个块信息。当500个块写满时,记录获取的最后一个块的hahs值,保存在源节点的hashContinue中。

3示例如下:

71110100....协议版本:70001 02.....哈希计数:2d 39 f 608 a 7775 b 537729884d 4 e 6633 bb 2 105 e 55 a 16 a14 d 31 b 00000000000000.哈希# 1 5c3e 6403d 40837110 a2 E8 AFB 602 B1 c 01 714 BDA 7 ce 23 bea 0a 000000000000.哈希# 000000000000000000000000000000000000000000000000000000000。stop hash

get headers

get headers message requests headers message,提供从区块链中的特定点开始的块头。收到该命令后,获取指定范围内的块头,并将头消息发送给源节点。

get headers消息与getblocks消息几乎相同,只有一点不同:inv回复getblocks消息将包含不超过500个块头哈希;Headers reply getheaders消息将包含多达2000个标头块。

tx

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

-交易响应:比特币核心和比特币NJ将发送它以响应getdata消息,该消息请求存货类型为MSG_TX的交易。-MerkleBlock响应:比特币核心将发送它以响应getdata消息,该消息请求库存类型为MSG_MERKLEBLOCK的merkle块。(这是对发送merkleblock消息的补充。)在这种情况下,每个tx消息提供块的匹配事务。-未经请求:BitcoinJ将发送tx消息以主动启动其事务。

headers

headers消息向先前使用getheaders消息请求特定标头的节点发送块消息。邮件头可以为空。

4示例如下:

01.....标题数量:1 02000000....街区版本:2 b 6 ff 0 B1 b 1680 a 2862 a 30 ca 44d 346d 9 e 8 910d 334 be b48 ca 0 c 00000000000.前一个块头的哈希9d 10 aa 52 ee 949386 ca 9385695 f 04 ede 2 70 DDA 20810 decd 12 BC 9 b 048 aaab 31471.Merkle root 24d95a54....Unix操作系统时间:1415239972 30c31b18....目标(位)fe9f0864....随机数00.....事务计数(0x 00)

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 的描述,其关系图如下:

5version:

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 .............蓑衣网小编2022...... 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个。

6Ping

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

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

7ping消息的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)。

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

8蓑衣网小编2022SendHeaders

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消息转达给该节点。

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

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不会产生歧义,也不会出现布隆过滤器提供的似是而非的隐私。希望保持更高隐私性的客户端应自行重新计算布隆过滤器,并使用重新计算的布隆过滤器发送新的过滤器负载消息。

10注意:除非先前使用的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块。 这允许客户接收与其钱包相关的交易。

11示例如下:

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的描述,其关系如下:

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

13

比特币源码分析-网络(一) | 分享给朋友: