1. 程式人生 > >Blockchian區塊鏈:IBM HyperLedger fabric 簡述

Blockchian區塊鏈:IBM HyperLedger fabric 簡述

在我看來,比特幣就是現實中的V字仇殺隊,當然現實是更殘酷的世界政府,這場博弈關乎著人類文明、政治、社會屬性、經濟和人權。 
IBM HyperLeger 又叫 fabric,你可以把它想象成一個由全社會來共同維護的一個超級賬本,沒有中心機構擁攬權力,你的每一筆交易都是全網公開且安全的,信用由全社會共同見證。它與Bitcoin的關係就是,你可以利用fabric構建出一個叫Bitcoin的應用來幫助你change the world。 
願景是那麼的牛X,貌似正合我們想改變世界的胃口,但是在殘酷的現實和世介面前我們永遠是天真幼稚的,blockchain需要一步一步腳印來構建它的巨集偉藍圖,起碼目前是沒有將它用於工業生產和國家經濟的案例的。 
fabric源於IBM,初衷為了服務於工業生產,IBM將44,000行程式碼開源,是了不起的貢獻,讓我們可以有機會如此近的去探究區塊鏈的原理,但畢竟IBM是從自身利益和客戶利益出發的,並不是毫無目的的去做這項公益事業,我們在看fabric的同時要有一種審慎的思維:區塊鏈不一定非得這樣,它跟比特幣最本質的非技術區別在哪裡。我們先來大致瞭解一下fabric的關鍵術語(因為一些詞彙用英文更準確,我就不硬翻譯了)。

1. Terminology

  • Transaction 它一條request,用來在ledger上執行一個function,這個function是用chaincode來實現的
  • Transactor 發出transaction的實體,比如它可能是一個客戶端應用
  • Ledger Legder可以理解為一串經過加密的block鏈條,每一個block包含著transactions和當前world state等資訊
  • World State world state是一組變數的集合,包含著transactions的執行結果
  • Chaincode這是一段應用層面的程式碼(又叫smart contract,智慧合約),它儲存在ledger上,作為transaction的一部分。也就是說chaincode來執行transaction,然後執行結果可能會修改world state
  • Validating Peer 參與者之一,它是一種在網路裡負責執行一致性協議、確認交易和維護賬本的計算機節點
  • Nonvalidating Peer它相當於一個代理節點,用來連線transactor和鄰近的VP(Validating Peer)節點。一個NVP節點不會去執行transactions但是回去驗證它們。同時它也會承擔起事件流server和提供REST services的角色
  • Permissioned Ledger 這是一個要求每一個實體和節點都要成為網路成員的blockchain網路,所有匿名節點都不被允許連線
  • Privacy 用來保護和隱蔽chain transactors的身份,當網路成員要檢查交易時,如果沒有特權的話,是無法追蹤到交易的transactor
  • Confidentiality 這個特性使得交易內容不是對所有人可見,只開放給利益相關者
  • Auditability 將blockchain用於商業用途需要遵守規則,方便監管者調查交易記錄

2. Architecture

架構核心邏輯有三條:Membership、Blockchain和Chaincode。

這裡寫圖片描述

2.1 Membership Services

這項服務用來管理節點身份、隱私、confidentiality 和 auditability。在一個 non-permissioned的區塊鏈網路裡,參與者不要求授權,所有的節點被視作一樣,都可以去submit一個transaction,去把這些交易存到區塊(blocks)中。那Membership Service是要將一個 non-permissioned的區塊鏈網路變成一個permissioned的區塊鏈網路,憑藉著Public Key Infrastructure (PKI)、去中心和一致性。

2.2 Blockchain Services

Blockchain services使用建立在HTTP/2上的P2P協議來管理分散式賬本。提供最有效的雜湊演算法來維護world state的副本。採取可插拔的方式來根據具體需求來設定共識協議,比如PBFT,Raft,PoW和PoS等等。

2.3 Chaincode Services

Chaincode services 會提供一種安全且輕量級的沙盒執行模式,來在VP節點上執行chaincode邏輯。這裡使用Container環境,裡面的base映象都是經過簽名驗證的安全映象,包括OS層和開發chaincode的語言、runtime和SDK層,目前支援Go、Jave和Nodejs開發語言。

2.4 Events

在blockchain網路裡,VP節點和chaincode會發送events來觸發一些監聽動作。比如chaincode是使用者程式碼,它可以產生使用者事件。

2.5 API 和 CLI

提供REST API,允許註冊使用者、查詢blockchain和傳送transactions。一些針對chaincode的API,可以用來執行transactions和查詢交易結果。對於開發者,可以通過CLI快速去測試chaincode,或者去查詢交易狀態。


3. Topology

分散式網路的拓撲結構是非常值得研究的。在這個世界裡散佈著眾多參與者,不同角色,不同利益體,各種各樣的情況處理象徵著分散式網路裡的規則和法律,無規則不成方圓。在區塊鏈網路裡,有Membership service,有VP節點,NVP節點,一個或多個應用,它們形成一個chain,然後會有多個chain,每一個chain都有各自的安全要求和操作需求。

3.1 單個VP節點網路

最簡單的網路就是隻包含一個VP節點,因此就省去了共識部分。

這裡寫圖片描述

3.2 多個VP節點網路

多個VP和NVP參與的網路才是有價值和實際意義的。NVP節點分擔VP節點的工作壓力,承擔處理API請求和events的工作。

這裡寫圖片描述

而對於VP節點,VP節點間會組成一個網狀網路來傳播資訊。一個NVP節點如果被允許的話可以與鄰近的一個VP節點相連。NVP節點是可以省略的,如果Application可以直接和VP節點通訊。

3.3 Multichain

還會存在一個網路裡多條chain的情況,各個chain的意圖不一樣。


4. Protocol

fabric是用gRPC來做P2P通訊的,是一個雙向流訊息傳遞。使用 Protocol Buffer來序列化要傳遞的資料結構。

4.1 Message

message分四種:Discovery,Transaction,Synchronization 和 Consensus。每一種資訊下還會包含更多的子資訊,由payload指出。

payload是一個不透明的位元組陣列,它包含著一些物件,比如 Transaction 或者 Response。例如,如果 type 是 CHAIN_TRANSACTION,那麼 payload 就是一個 Transaction的物件。

<code class="hljs rust has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">message Message {
   <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">enum</span> <span class="hljs-title" style="box-sizing: border-box;">Type</span> {
        UNDEFINED = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;

        DISC_HELLO = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
        DISC_DISCONNECT = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>;
        DISC_GET_PEERS = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>;
        DISC_PEERS = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>;
        DISC_NEWMSG = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>;

        CHAIN_STATUS = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">6</span>;
        CHAIN_TRANSACTION = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">7</span>;
        CHAIN_GET_TRANSACTIONS = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>;
        CHAIN_QUERY = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">9</span>;

        SYNC_GET_BLOCKS = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">11</span>;
        SYNC_BLOCKS = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">12</span>;
        SYNC_BLOCK_ADDED = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">13</span>;

        SYNC_STATE_GET_SNAPSHOT = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">14</span>;
        SYNC_STATE_SNAPSHOT = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">15</span>;
        SYNC_STATE_GET_DELTAS = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">16</span>;
        SYNC_STATE_DELTAS = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">17</span>;

        RESPONSE = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">20</span>;
        CONSENSUS = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">21</span>;
    }
    Type <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">type</span> = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
    bytes payload = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>;
    google.protobuf.Timestamp timestamp = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li></ul>

4.1.1 Discovery Messages

一個新啟動的節點,如果CORE_PEER_DISCOVERY_ROOTNODE(ROOTNODE是指網路中其它任意一個節點的IP)被指定了,它就會開始執行discovery協議。而ROOTNODE就作為最一開始的發現節點,然後通過ROOTNODE節點進而發現全網中所有的節點。discovery協議資訊是DISC_HELLO,它的payload是一個HelloMessage物件,同時包含資訊傳送節點的資訊:

<code class="hljs lasso has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">message HelloMessage {
  PeerEndpoint peerEndpoint <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
  uint64 blockNumber <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>;
}
message PeerEndpoint {
    PeerID ID <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">string</span> address <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>;
    enum <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Type</span> {
      UNDEFINED <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
      VALIDATOR <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
      NON_VALIDATOR <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>;
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Type</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">type</span> <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>;
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">bytes</span> pkiID <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>;
}

message PeerID {
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">string</span> name <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li></ul>
屬性 含義
PeerID 在啟動之初定義的或者在配置檔案中定義的該節點的名字
PeerEndpoint 描述該節點,並判斷是否是NVP和VP節點
pkiID 該節點的加密ID
address ip:port
blockNumber 該節點目前擁有的blockchain的高度

如果一個節點接收到DISC_HELLO資訊,發現裡面的block height高於自己目前的block height,它會立即傳送一個同步協議來與全網同步自己的狀態(mark:但是在原始碼層面似乎並沒有實現同步這個邏輯)。

在這個剛加入節點完成DISC_HELLO這輪訊息傳遞後,接下來回週期性的傳送DISC_GET_PEERS來發現其它加入網路中的節點。為了回覆DISC_GET_PEERS,一個節點會發送DISC_PEERS。

4.1.2 Synchronization Messages

Synchronization 協議是接著上面所說的discovery協議開始的,當一個節點發現它的block的狀態跟其它節點不一致時,就會觸發同步。該節點會廣播(broadcast)三種資訊:SYNC_GET_BLOCKS , SYNC_STATE_GET_SNAPSHOT 或者 
SYNC_STATE_GET_DELTAS,同時對應接收到三種資訊:SYNC_BLOCKS , SYNC_STATE_SNAPSHOT 或者 SYNC_STATE_DELTAS。

目前fabric嵌入的共識演算法是pbft。

SYNC_GET_BLOCKS 會請求一系列連續的block,傳送的資料結構中payload將是一個SyncBlockRange物件。

<code class="hljs sql has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">message SyncBlockRange {
    uint64 correlationId = 1;
    uint64 <span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">start</span> = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>;</span>
    uint64 <span class="hljs-operator" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">end</span> = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>;</span>
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>

接收的節點會回覆SYNC_BLOCKS,它的payload是一個SyncBlocks物件:

<code class="hljs fix has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-attribute" style="box-sizing: border-box;">message SyncBlocks {
    SyncBlockRange range </span>=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"> 1;
    repeated Block blocks = 2;
}</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>

start和end表示起始和結束的block。例如start=3, end=5,代表了block 3,4,5;start=5, end=3,代表了block 5,4,3。

SYNC_STATE_GET_SNAPSHOT 會請求當前world state的一個snapshot,該資訊的payload是一個SyncStateSnapshotRequest物件:

<code class="hljs fix has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-attribute" style="box-sizing: border-box;">message SyncStateSnapshotRequest {
    uint64 correlationId </span>=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"> 1;
}</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

correlationId是發出請求的peer用來追蹤對應的該資訊的回覆。收到該訊息的peer會回覆SYNC_STATE_SNAPSHOT,它的payload是一個SyncStateSnapshot物件:

<code class="hljs vala has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">message SyncStateSnapshot {
    bytes delta = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">uint64</span> sequence = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">uint64</span> blockNumber = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>;
    SyncStateSnapshotRequest request = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>

SYNC_STATE_GET_DELTAS 預設Ledger會包含500個transition deltas。delta(j)表示block(i)和block(j)之間的狀態轉變(i = j -1)。

4.1.3 Consensus Messages

Consensus framework會將接收到的CHAIN_TRANSACTION轉變成CONSENSUS,然後廣播給所有的VP節點。

4.1.4 Transaction Messages

在fabric中的交易有三種:Deploy, Invoke 和 Query。Deploy將指定的chaincode安裝到chain上,Invoke和Query會呼叫已經部署好的chaincode的函式。

4.2 Ledger

Ledger主要包含兩塊:blockchain和world state。blockchain就是一系列連在一起的block,用來記錄歷史交易。world state是一個key-value資料庫,當交易執行後,chaincode會將state存在裡面。

4.2.1 Blockchain

blockchain是指由一些block連成的list,每一個block都包含上一個block的hash。一個block還會包含一些交易列表以及執行所有這些交易後world state的一個hash。

<code class="hljs lasso has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">message Block {
  version <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
  google<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>protobuf<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>Timestamp timestamp <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>;
  <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">bytes</span> transactionsHash <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>;
  <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">bytes</span> stateHash <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>;
  <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">bytes</span> previousBlockHash <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>;
  <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">bytes</span> consensusMetadata <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">6</span>;
  NonHashData nonHashData <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">7</span>;
}

message BlockTransactions {
  repeated Transaction transactions <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li></ul>

那上一個block的hash是如何計算的呢:

  • 用 protocol buffer 序列化block的資訊
  • 用 SHA3 SHAKE256 演算法將序列化後的block資訊雜湊成一個512位元組的輸出

上面的資料結構中有一個 transactionHash, 它是transaction merkle tree的根節點(用默克爾樹來描述這些交易)。

4.2.2 World State

一個peer的world state是所有部署的chaincodes的狀態(state)的集合。一個chaincode的狀態由鍵值對(key-value)的集合來描述。我們期望網路裡的節點擁有一致的world state,所以會通過計算world state的 crypto-hash 來進行比較,但是將會消耗比較昂貴的算力,為此我們需要設計一個高效率的計算方法。比如引入Bucket-tree來實現world state的組織。

world state中的key的表示為{chaincodeID, ckey},我們可以這樣來描述key, key = chaincodeID+nil+cKey。

world state的key-value會存到一個hash表中,這個hash表有預先定義好數量(numBuckets)的buckets組成。一個 hash function 會來定義哪個桶包含哪個key。這些buckets都將作為merkle-tree的葉子節點,編號最小的bucket作為這個merkle-tree最左面的葉子節點。倒數第二層的構建,從左開始每maxGroupingAtEachLevel(預先定義好數量)這麼多的葉子節點為一組聚在一起,形成N組,每一組都會插入一個節點作為所包含葉子節點的父節點,這樣就形成了倒數第二層。要注意的是,最末層的父節點(就是剛剛描述的插入的節點)可能會有少於maxGroupingAtEachLevel的孩子節點。按照這樣的方法不斷構建更高一層,直到根節點被構建出來。

舉一個例子,{numBuckets=10009 and maxGroupingAtEachLevel=10},它形成的tree的每一次包含的節點數目如下:

Level Number of nodes
0 1
1 2
2 11
3 101
4 1001
5 10009

4.3 Consensus Framework

consensus framework包含了三個package:consensus、controller和helper。

  • consensus.Communicator用來發送訊息給其他的VP節點
  • onsensus.Executor用於交易的啟動、執行和回滾,還有preview、commit
  • controller指定被VP節點使用的consensus plugin
  • helper用來幫助consensus plugin與stack互動,例如維護message handler

目前有兩個consensus plugin:pbft和noops。 
pbft是 微軟論文PBFT共識演算法的一個實現。 
noops 用於開發和測試,它沒有共識機制,但是會處理所有consensus message,所以如果要開發自己的consensus plugin,從它開始吧。


5. Implementation and contribution

Implement SYNC_BLOCK_ADDED handler

我的一個同事實現了SYNC_BLOCK_ADDED訊息的handler,這樣在noops共識模式下,當一個block被加到(mined/added)ledger時,NVP節點就可以處理這條訊息了,並將最新加入的block存在它自己的ledger中。

SYNC_BLOCK_ADDED message 對應的callback是beforeBlockAdded(core/peer/handler.go),官方程式碼如下:

<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">func (d *Handler) beforeBlockAdded(e *fsm<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Event</span>) {
    peerLogger<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Debugf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Received message: %s"</span>, e<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Event</span>)
    msg, ok := e<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Args</span>[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>].(*pb<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Message</span>)
    if !ok {
        e<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Cancel</span>(fmt<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Errorf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Received unexpected message type"</span>))
        return
    }
    // <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Add</span> the block <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">and</span> any delta state to the ledger
    _ = msg
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>

這裡並沒有去獲取和處理block的資訊,我們需要加入如下:

<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">+  if ValidatorEnabled() {
+       e<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Cancel</span>(fmt<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Errorf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"VP shouldn't receive SYNC_BLOCK_ADDED"</span>))
+       return
+   }
    // <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Add</span> the block <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">and</span> any delta state to the ledger
-   _ = msg
+   blockState := &pb<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.BlockState</span>{}
+   err := proto<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Unmarshal</span>(msg<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Payload</span>, blockState)
+   if err != nil {
+       e<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Cancel</span>(fmt<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Errorf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Error unmarshalling BlockState: %s"</span>, err))
+       return
+   }
+   coord := d<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Coordinator</span>
+   blockHeight := coord<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.GetBlockchainSize</span>()
+   if blockHeight <= <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> {
+       e<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Cancel</span>(fmt<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Errorf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"No genesis block is made"</span>))
+       return
+   }
+   curBlock, err := coord<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.GetBlockByNumber</span>(blockHeight -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>)
+   if err != nil {
+       e<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Cancel</span>(fmt<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Errorf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Error fetching block #%d, %s"</span>, blockHeight -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, err))
+       return
+   }
+   hash, err := curBlock<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.GetHash</span>()
+   if err != nil {
+       e<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Cancel</span>(fmt<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Errorf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Error hashing latest block"</span>))
+       return
+   }
+   if bytes<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Compare</span>(hash, blockState<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Block</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.PreviousBlockHash</span>) != <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> {
+       e<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Cancel</span>(fmt<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Errorf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"PreviousBlockHash of received block doesnot match hash of current block"</span>))
+       return
+   }
+   coord<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.PutBlock</span>(blockHeight, blockState<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Block</span>)
+   delta := &statemgmt<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.StateDelta</span>{}
+   if err := delta<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Unmarshal</span>(blockState<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.StateDelta</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">; nil != err {</span>
+       e<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Cancel</span>(fmt<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Errorf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Received a corrupt state delta"</span>))
+       return
+   }
+   coord<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.ApplyStateDelta</span>(msg, delta)
+   if coord<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.CommitStateDelta</span>(msg) != nil {
+       e<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Cancel</span>(fmt<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Errorf</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Played state forward, hashes matched, but failed to commit, invalidated state"</span>))
+       return
+   }
+   peerLogger<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.Infof</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Blockchain height grows into %d"</span>, coord<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.GetBlockchainSize</span>())</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li sty