EOS 採用 DPoS 算法和塊內分片技術,實現了百萬級別 TPS 的超高性能,可以媲美中心化服務器的處理能力,同時保持去中心化的屬性,成爲了區塊鏈 3.0 的代表。那麼爲什麼 EOS 有如此出色的性能表現?本文將從 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 秒。

block-cycle

vs

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

cycle-shard

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

cycle

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

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

[code]

循環
[/code]

區塊數據結構分析

Block

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

struct signed_block : public signed_block_summary {

vector input_transactions;

};

簽名區塊摘要主要包含簽名區塊頭部(signed_block_header)和包含的 cycle 集合(cycles_summary)。

struct signed_block_summary : public signed_block_header {

vector regions;

};

struct region_summary {

uint16_t region = 0;

vector cycles_summary;

};

signed-block

區塊頭部主要包括前一個區塊的 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 new_producers;

}

在生產者打包區塊時,通過 _generate_block 函數完成對區塊頭部信息的賦值,其中交易信息的索引信息通過默克爾樹組織起來,便於信息檢索和分塊校驗。

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 cycle;

struct shard_summary {

vector transactions; /// new or generated transactions

};

cycle-summary

Shard

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

struct shard_summary {

vector transactions; /// new or generated transactions

};

struct transaction_receipt {

fc::enum_type status;

fc::unsigned_int kcpu_usage;

fc::unsigned_int net_usage_words;

transaction_id_type id;

}

shard-summary

來源鏈接:www.8btc.com