以太坊C++源碼解析(五)區(qū)塊鏈同步(6)

除了上面的同步形式外,區(qū)塊鏈節(jié)點(diǎn)之間還存在另外兩種特殊形式的同步,一種是交易同步,也就是當(dāng)某個節(jié)點(diǎn)完成一筆交易后,需要向其他節(jié)點(diǎn)廣播這個交易,另一種是礦工成功挖到一個區(qū)塊,也要向其他節(jié)點(diǎn)廣播這個新的區(qū)塊。我們來看看這兩種同步是怎么進(jìn)行的。

交易同步

交易同步的數(shù)據(jù)包類型是TransactionsPacketEthereumPeer收到這個包以后直接就在EthereumPeerObserver里做了處理,并沒有轉(zhuǎn)交給BlockChainSync,可能是因?yàn)檫@個處理太簡單的緣故,我們也可以從代碼中看出來:

void onPeerTransactions(std::shared_ptr<EthereumPeer> _peer, RLP const& _r) override
{
    unsigned itemCount = _r.itemCount();
    LOG(m_logger) << "Transactions (" << dec << itemCount << " entries)";
    m_tq.enqueue(_r, _peer->id());
}

這里的處理就是放到m_tq里,這里的m_tqTransactionQueue對象,TransactionQueue是一個專門放pending交易的隊(duì)列,也就是還沒有正式進(jìn)入?yún)^(qū)塊鏈的“無主”交易待的地方。關(guān)于這個類,后續(xù)會專門來講。

新區(qū)塊同步

新區(qū)塊包的數(shù)據(jù)類型是NewBlockPacket,這次處理的重任重新回到了BlockChainSync,因此,我們來看看BlockChainSync::onPeerNewBlock的處理吧。
這個處理分為兩部分,第一部分是常規(guī)檢查:

if (_r.itemCount() != 2)
{
    _peer->disable("NewBlock without 2 data fields.");
    return;
}
BlockHeader info(_r[0][0].data(), HeaderData);
auto h = info.hash();
DEV_GUARDED(_peer->x_knownBlocks)
    _peer->m_knownBlocks.insert(h);
unsigned blockNumber = static_cast<unsigned>(info.number());
if (blockNumber > (m_lastImportedBlock + 1))
{
    LOG(m_loggerDetail) << "Received unknown new block";
    // Update the hash of highest known block of the peer.
    // syncPeer will then request the highest block header to properly restart syncing
    _peer->m_latestHash = h;
    syncPeer(_peer, true);
    return;
}

這個包不同于之前的區(qū)塊數(shù)據(jù)包,這個包里同時包含區(qū)塊頭和區(qū)塊體,第一部分是對區(qū)塊頭里的信息進(jìn)行處理。如果新收到的區(qū)塊比我目前最新的節(jié)點(diǎn)更新,那么說明該節(jié)點(diǎn)有更新的數(shù)據(jù),那么就調(diào)用syncPeer從該節(jié)點(diǎn)進(jìn)行同步。
第二部分就是導(dǎo)入?yún)^(qū)塊體了:

switch (host().bq().import(_r[0].data()))
{
case ImportResult::Success:
    // ...
}

這里的流程和前一節(jié)差不多,將這個區(qū)塊導(dǎo)入二級緩沖區(qū)中去驗(yàn)證。

幾點(diǎn)補(bǔ)充

到這里ETH區(qū)塊鏈同步的主要流程都涉及到了,剩下的部分單獨(dú)再分析。本節(jié)再對同步補(bǔ)充幾點(diǎn):

  1. 以太坊ropsten網(wǎng)絡(luò)比主網(wǎng)mainnet要差很多,對于同步來說就是噩夢。如果需要測試交易什么的建議自己搭建私有鏈來測試.
  2. 同步過程漫長,需要有耐心,而且是越來越慢,后期單個區(qū)塊包含的交易更多,計算量和存儲量都巨大。
  3. 同步硬盤建議SSD,容量在1TB以上。
  4. 同步存儲主要是三類數(shù)據(jù)庫,Block數(shù)據(jù)庫,Extra數(shù)據(jù)庫和State數(shù)據(jù)庫,其中State數(shù)據(jù)庫最大,這個就是所謂的世界狀態(tài)了。
  5. 同步有坑!??!,還記得以太坊C++源碼解析(五)區(qū)塊鏈同步(2)里的那張圖嗎?整個流程有兩個閥門,閥門1是從BlockQueue到區(qū)塊鏈,閥門2是從網(wǎng)絡(luò)到一級緩沖區(qū)。這兩個閥門正常工作流程是這樣的:當(dāng)二級緩沖區(qū)里有數(shù)據(jù)時,閥門1開啟,否則關(guān)閉;另外由于數(shù)據(jù)進(jìn)入二級緩沖區(qū)的速度通常比從二級緩沖區(qū)進(jìn)入?yún)^(qū)塊鏈的速度要快很多,因此二級緩沖區(qū)里有大量數(shù)據(jù),當(dāng)二級緩沖區(qū)滿時,閥門2關(guān)閉,否則開啟。但是這兩個閥門在實(shí)際測試中是存在故障的,閥門1故障的表現(xiàn)是數(shù)據(jù)校驗(yàn)后未打開,數(shù)據(jù)不會進(jìn)入?yún)^(qū)塊鏈,導(dǎo)致二級緩沖區(qū)一直滿,從而導(dǎo)致閥門2一直關(guān)閉,整個同步過程停止,這種我稱為撐死;閥門2故障的表現(xiàn)是在已關(guān)閉的情況下,二級緩沖區(qū)未滿時不能正常打開,二級緩沖區(qū)數(shù)據(jù)全部被取光后整個同步過程停止,這種我稱為餓死。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容