EOS 代碼架構及分析(三)

知識庫 EOS 技術 鏈聞研究院 2018-07-25

鏈聞 ChainNews
EOS 採用 DPoS 算法和塊內分片技術,實現了百萬級別 TPS 的超高性能,可以媲美中心化服務器的處理能力,同時保持去中心化的屬性,成為了區塊鏈 3.0 的代表。文章從 EOS 的核心設計原理以及主要數據結構進行了分析。

EOS VS Bitcoin

我們知道,比特幣採用 POW 共識算法確認區塊:

1) Bob 向 Alice 發出一筆轉賬消息;

2)客戶端將消息廣播給所有礦工節點,暫存在礦工的交易池中;

3)礦工根據區塊的所能容納的交易數量,從交易池中取出一定量的交易,假設 Bob 的這筆轉賬很幸運,或者是手續費給的足夠高,剛好被選中打包進區塊;

4)礦工開始進行 POW 計算,10 分鐘碰撞出結果,將區塊打包廣播,這次 Bob 的轉賬才生效(不考慮 6 次確認)。

我們可以看到,這種交易確認的效率和傳統的中心化金融機構的效率沒法比,接下來看看 EOS 的確認過程。

EOS 通過股東投票選舉出可信的 21 個超級節點,然後由他們輪流生產區塊,每 3 秒出一個區塊,這樣就避免的 POW 算法的耗時問題,相當於信任提前建立起來。但是 3 秒的確認時間也是太長了,所以 EOS 採用塊內分片技術,即在區塊中維護了一條私有區塊鏈,將一個 block 分割成多個 cycle (循環),每個 cycle 的生成時間很短,而且不用等待完整的 block 確認完成(3 秒),生成後直接異步廣播發送,這樣,交易在很快就被確認了。另外,塊內分片使交易確認時間更平滑,比如,Bob 向 Alice 的轉賬信息如果在打包最後時刻發送,那麼交易確認時間幾乎是 0 秒,如果在打包開始時刻發送,打包時間則是 3 秒。

交易時間縮短了,但是面對海量併發的交易數據,還是無法提供高 TPS 的表現,那麼 EOS 如何解決高併發問題呢?EOS 引入了 shard 概念,在打包 cycle 的時候,由多個 shard 並行處理交易信息。每個 shard 是一個線程,在線程內部的交易是順序處理的,在線程間的交易是並行處理的。

問題來了,究竟哪些交易可以並行執行,哪些交易只能串行執行?EOS 的設計者給出如下解釋,涉及同一個賬戶 U 的交易 A 和 B,只能包含在同一個 cycle 中的同一個 thread (後來改也叫 shard)或者包含在不同 cycle 的 thread 中,也就是說涉及相同賬戶的交易必須串行處理。

簡單打個比方,有如下兩筆涉及同一個賬戶的交易:

Transaction A:Bob 將賬戶的 10 個 token 轉給 Alice (Alice 的賬戶最開始為空);

Transaction B:Alice 將接收到的 10 個 token 中的 5 個轉給 Carol;

如果 Transaction B 先於 A 執行,則因為 Alice 的賬戶為空,無法轉賬給 Carol,出現驗證失敗,所以必須保證 Transaction A 在 B 前執行。這樣,在一個 cycle 內,生產者可以利用多核多線程併發的處理「不相干」的 Transaction,極大的提升交易處理速度。

EOS 為了降低最小通信延遲,在一個單獨的區塊內部實現了兩個賬戶之間的交互通信,而不用等待一個完整的區塊時間,而且將信息處理過程儘可能的並行化,提升吞吐量。

區塊數據結構分析

Block

簽名的區塊主要由兩部分組成:簽名區塊摘要(signed_block_summary)和交易數據(input_transactions),區塊摘要用於管理交易數據,相當於交易索引信息,packed_transaction 是原始的交易信息,最終保存在數據庫中,通過 id 檢索。

struct signed_block : public signed_block_summary {

…

vector<packed_transaction>   input_transactions;

};


struct signed_block_summary : public signed_block_header {

vector<region_summary>    regions;

};

struct region_summary {

uint16_t region = 0;

vector<cycle>    cycles_summary;

};

區塊頭部主要包括前一個區塊的 hash 值、區塊時間戳、交易信息默克爾樹根、智能合約默克爾樹根、生產者等信息。

struct block_header

{

…

block_id_type                    previous;  // 前一個區塊的 hash 值

block_timestamp_type             timestamp; // 區塊時間戳

checksum256_type                 transaction_mroot; // 交易信息默克爾樹根

checksum256_type                 action_mroot;

checksum256_type                 block_mroot;

account_name                     producer; // 生產者

/**The producer schedule version that should validate this block, this is used to

* indicate that the prior block which included new_producers->version has been marked

* irreversible and that it the new producer schedule takes effect this block.

*/

uint32_t                          schedule_version = 0;

optional<producer_schedule_type>  new_producers;

}


chain_controller::_generate_block () {

…

_pending_block->timestamp   = when;

_pending_block->producer    = producer_obj.owner;

_pending_block->previous    = head_block_id();

_pending_block->block_mroot=get_dynamic_global_properties().block_merkle_root.get_root();

_pending_block->transaction_mroot = _pending_block_trace->calculate_transaction_merkle_root();

_pending_block->action_mroot = _pending_block_trace->calculate_action_merkle_root();

…

}

Cycle

cycle 可以理解為 block 內部的私有區塊,主要用於提升交易確認速度,不需要等待一個完整 block 打包時間。一個 cycle 內部包含一個 shard (分片)集合,cycle 和 cycle 之間是串行處理打包的。

typedef vector<shard_summary>    cycle;

struct shard_summary {
…
vector<transaction_receipt>   transactions; /// new or generated transactions
};

Shard

分片結構中包含一系列交易索引信息,一個分片內部的交易是串行處理的,分片之間的交易可以並行處理。交易索引信息主要用於通過交易 id 在數據庫中查找對應的交易信息。

struct shard_summary {



vector<transaction_receipt>   transactions; /// new or generated transactions

};

struct transaction_receipt {

fc::enum_type<uint8_t,status_enum>  status;

fc::unsigned_int                    kcpu_usage;

fc::unsigned_int                    net_usage_words;

transaction_id_type                 id;

}

更多精彩內容,關注鏈聞 ChainNews 公眾號(id:chainnewscom),或者來微博@ 鏈聞 ChainNews與我們互動!轉載請註明版權和原文鏈接!

相關推薦

推薦中...