风险提示:理性看待区块链,提高风险意识!
比特币源码分析-网络(一)
首页 > 币界资讯 > 区块链知识 2018-03-20 14:33:00

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

10

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

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

1

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)。

2

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中。

3

示例如下:

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 消息可以是空的。

4

示例如下:

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

5

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个。

6

Ping

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

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

7

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)。

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

8

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

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

14

上一篇: 学术向丨论十大比特币区块链数据嵌入方式
下一篇: golang-event 在以太坊中的使用
推荐专栏
web3首席知识博主
一位相信价值投资的币圈KOL。稳定盈利的缠论野生交易员 #BTC行情分析师 #价值投资 #链上数据分析
爱Web 3,爱生活,爱科技,爱炒币的老韭菜
热门币种
更多
币种
价格
24H涨跌幅
BTC比特币
¥264,723.74
37,091.22 USDT
+0.1%
ETH以太坊
¥14,416.22
2,019.90 USDT
-0.12%
USDT泰达币
¥7.20
1.01 USDT
0%
BNB币安币
¥1,625.40
227.74 USDT
+0.36%
XRP瑞波币
¥4.32
0.60460 USDT
+0.37%
USDC
¥7.14
1.00 USDT
+0.03%
SOLSolana
¥398.85
55.89 USDT
+1.54%
OKBOK币
¥398.61
55.85 USDT
-1.64%
ADA艾达币
¥2.68
0.37580 USDT
-1.16%
DOGE狗狗币
¥0.55160
0.07730 USDT
-1.52%
热搜币种
更多
币种
价格
24H涨跌幅
Terra Classic
¥0.00
9.402E-5 USDT
-18.95%
Gala
¥0.18
0.025374 USDT
-4.66%
dYdX
¥22.58
3.1918 USDT
-0.91%
比特股
¥0.05
0.006964 USDT
+4.28%
PancakeSwap
¥15.52
2.1936 USDT
-2.74%
Conflux
¥1.08
0.1524 USDT
-2.87%
Filecoin
¥31.45
4.4454 USDT
-0.69%
FTX Token
¥29.82
4.2155 USDT
+16.96%
Yield Guild Games
¥2.55
0.3608 USDT
-0.52%
Shiba Inu
¥0.00
8.14E-6 USDT
-2.51%
比特币
¥262,381.44
37091.22 USDT
+0.1%
比原链
¥0.07
0.010011 USDT
-4.38%
最新快讯
更多
汇丰、恒生、渣打、富邦华一四家外资银行入围首批“数字人民币”业务试点名单
2023-11-28 19:06:57
摩根大通和Apollo计划建立代币化“企业主网”
2023-11-28 19:03:57
Nansen2公测版本上线,新增链上数据异动、智能搜索等功能
2023-11-28 18:59:52
西班牙公民需在明年3月底前申报其海外平台上加密货币持仓
2023-11-28 18:53:43
Nansen2已公开测试
2023-11-28 18:53:38
dYdX基金会:主网启动以来超过1645万DYDX被质押
2023-11-28 18:52:07
NicCarter等比特币倡导者发文:比特币挖矿是清洁能源和平衡电网的关键工具
2023-11-28 18:47:58
下载币界网APP