Blockchian区块链:IBM HyperLedger fabric 简述

版权声明: https://blog.csdn.net/oFengWuYu1/article/details/52055153

在我看来,比特币就是现实中的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 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><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</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><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li></ul>

Enable statetransfer for HELLO message

我们还发现当一个NVP节点刚加入网络时,它会发送一个DISC_HELLO message,随后从其他节点接收一个包含那个节点的blockchain信息的DISC_HELLO message,不过官方代码并没有给出NVP依据这些返回信息同步自己状态的实现。NVP正在网络中实施自己的状态同步时,一个新的block被mine,NVP却不能把这个新的block加入到自己的chain中。所以目前就出现了一个棘手的情况:当新的NVP节点刚加入网络时,通过HELLO message获取其他节点的blockchain信息开始同步自己的状态,这肯定需要一定的时间来完成,但与此同时,网络里的交易还在继续,新的block会被不断的mined,虽然NVP能接收到SYNC_BLOCK_ADDED,并拥有处理它的handler,但是这时候却不能将新的block信息加入到自己的chain中,因为hash不匹配,毕竟NVP节点并没有完成一开始的同步。

在我看来,比特币就是现实中的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 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><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</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><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li></ul>

Enable statetransfer for HELLO message

我们还发现当一个NVP节点刚加入网络时,它会发送一个DISC_HELLO message,随后从其他节点接收一个包含那个节点的blockchain信息的DISC_HELLO message,不过官方代码并没有给出NVP依据这些返回信息同步自己状态的实现。NVP正在网络中实施自己的状态同步时,一个新的block被mine,NVP却不能把这个新的block加入到自己的chain中。所以目前就出现了一个棘手的情况:当新的NVP节点刚加入网络时,通过HELLO message获取其他节点的blockchain信息开始同步自己的状态,这肯定需要一定的时间来完成,但与此同时,网络里的交易还在继续,新的block会被不断的mined,虽然NVP能接收到SYNC_BLOCK_ADDED,并拥有处理它的handler,但是这时候却不能将新的block信息加入到自己的chain中,因为hash不匹配,毕竟NVP节点并没有完成一开始的同步。

猜你喜欢

转载自blog.csdn.net/oFengWuYu1/article/details/52055153