我们接着看main.cpp中sendMessages下面的代码:
这部分代码第一部分调用PushGetBlocks函数用于区块的同步。这个函数也在main.cpp中。
可以看到这个函数使用了AssetLockHeld对cs_main进行锁定。这应该是用于调试信息一个断言。就是如果锁定异常,则会报告出相应的信息,并把当前线程挂起。下面对连续发送同一个getblocks的消息进行了过滤.pindexLastGetBlockBegin表示开始同步的位置,hashLastGetBlocksEnd表示结束的区块的哈希值。最后调用PushMessage发送"getblocks"同步当前区块链。
下面的代码g_signals.Broadcast()属于钱包的内容了。这个函数的作用是重新发送钱包的交易信息。我们看下这部分的内容:
可以看到 g_signals是一个CMainSignals结构对象,结构体内定义了各种用于连接的对象。关于 boost::signals2::signal可以看之前《解读五》的文章有介绍。我们主要看Broadcast 的注册。可以看到是Broadcast注册了实现钱包接口的ResendWalletTransactions的函数。这个函数定义在wallet.cpp中。
这段代码的核心部分就是在最后的两个循环里。第一个循环将距当前最新的区块构造时间大于5分钟的交易放入mapSorted中。第二个循环遍历此mapSorted,并调用每个交易的RelayWalletTransaction函数发送当前交易
在发送交易的时候首先判断是是否是CoinBase交易。我们把区块中的第一笔交易称为coinbase交易也叫创币交易。这个交易就是我们说的挖矿成功的奖励。所以这个交易没有输入,只包含一个被称作coinbase的输入,仅仅用来创建新的比特币。创币交易有一个输出,支付到这个矿工的比特币地址。
上面的代码在net.h和net.cpp中。可以看到最终我们把所要同步的交易全部放入了结点的发送池中。现在我们回到main.cpp中的sendMessages接着往下看。
可以看到我们在调用Broadcast后,将需要同步的交易数据放入结点的发送池(vInventoryToSend)后,接着就开始遍历发送池(vInventoryToSend),将交易信息发送出去。
我们接着下面的代码看。下面的代码是同步区块数据了:
这段代码首先检查了结点的网络状态,其中state.nLastBlockReceive表示区块接收到的时间。state.nBlocksInFlight表示区块是否在传输中。BLOCK_DOWNLOAD_TIMEOUT定义在main.h中。
由于区块下载时间的单位是秒所以我们在判断网络状态的时候转换成了微秒。意思是如果1分钟内没收到区块并且传输时间超过2分钟,我们就认为此结点已经离线。
第二部分代码是追踪记录节点连接上“nBlocksInFlight”(指那些它已经发出了请求但还没有接收到)的区块数量,并且检查该数量有没有超过上限(MAX_BLOCKS_IN_TRANSIT_PER_PEER)。用这种办法,如果一个节点需要更新大量区块,它会在上一请求完成后才发送对新区块的请求,从而允许对等节点控制更新速度,不至于压垮网络。MAX_BLOCKS_IN_TRANSIT_PER_PEER也定义在main.h中。
第三部分mapAskFor发送的是其他类型的消息数据。并且没有被记录(AlreadyHave)的消息。则发送出去。
第四部分则是将发送剩余的。数量没达到1000个的消息数据发送出去。
到这里我们就把sendMessages函数阅读完了,这个函数主要功能就是发送消息,包括:ping,结点地址,同步交易和同步区块数据。 通过这个函数我们也了解了比特币网络相关的内容和区块间的数据同步。不过我们好像已经够到了很多核心的内容,希望对我们后面的代码阅读会带来一些帮助。
作者:区块链研习社比特币源码研读班,black