Fabric记录
[TOC]
Architecture
系统架构
Transactions
- 部署合约的交易
- 调用合约的交易
- 纯查询的交易
- 合约交叉调用的
Blockchain datastructures
State
区块链的状态是通过带版本的键值对进行存储的,链码通过put
和get
这两种 KVS 操作进行读写。
状态s
由K->(V,N)
的映射组成,其中:
-
K
是键的集合 -
V
是值的集合 -
N
是有序版本号的集合
V
和N
有一个⊥的元素,代表空类型
对于任意k
,我们有:s(k)=(v,ver)
。两种KVS 操作如下:
-
put(k,v)
,以s
作为初始撞死,以s'
作为结束状态,满足:1.
s'(k)=(v,next(s(k).version))
2.对于
k'!=k
,有s'(k')=s(k')
-
get(k)
返回s(k)
Ledger
- PeerLedger
与 OrdererLedger 的区别是,还维护了一个区别是否有效 transaction 的 bitmask
- OrdererLedger
Nodes
Client
Peer
特殊的接收 client 提案的 peer,叫做__endorser__
Orderer
排序服务对 clients 和 peers 提供一个共享的通信频道(channel),channel 提供消息投递的原子性。
Partitioning。Orderer 提供多个 channel,clients 可以按需订阅。
Ordering service API。Peers 通过 API 连接到 orderer 提供的 channel,两个基础的 API 如下:
-
broadcast(blob)
,client 调用 -
deliver(seqno, prevhash, blob)
,orderer 调用用来通知 peer
排序服务特性
- 安全性(一致性保证)。广播的消息是一个一个块
deliver(seqno, prevhash, blob)
,后一个块有前一个的 hash,即区块链。 - 活性(投递保证)。
交易背书工作流
client 创建交易并发送到 endorser
问题:endorser 是如何确定的?一个 org 只有一个 endorser 么?这个 endorser 和 leader peer 是同一个么?
endorser 是合约维度的,一个合约在配置背书策略的时候,会配置 endorser,比如:
peer chaincode instantiate -C-n mycc -P "AND('Org1.member', 'Org2.member')"
其中 Org1.member
, Org2.member
就是 endorser,这里的 endorser 表示的是哪个 org,但 org 里面还有多个 peer。另一种说法,实例化合约的 peer 就是 endorser。合约必须只被安装在 endorser 上以保证合约代码的机密性。
PROPOSE
消息格式
<PROPOSE,tx,[anchor]>
,其中:
-
tx=<clientID,chaincodeID,txPayload,timestamp,clientSig>
对于不同的交易类型,
txPayload
有所不同-
调用合约交易
txPayload = <operation, metadata>
-
operation
:调用的函数及参数 -
metadata
:相关的属性
-
-
部署合约交易
txPayload = <source, metadata, policies>
-
source
:链码 -
metadata
:相关的属性 -
policies
:背书策略,需要注意的是,这里只给出背书策略的 ID 以及对应的参数
-
-
-
anchor
版本号,如果有这个字段,那么 endorser 在背书的时候会检查对应的 key 是不是等于指定的 version
client 会将tid=HASH(tx)
保存在内存中,等待 endorser 的反馈
endorser 模拟交易并签名
endorser 收到请求后进行如下操作:
- 验证
clientSig
- 如果指定了
anchor
则先检查 version - 模拟交易,获取
readset
和writeset
- 生成
tran-proposal
发往背书模块(endorsing logic)默认直接接受并进行签名,但是也可以进行任意操作,将tran-proposal
和tx
作为输入发往相关系统获得判定是否要进行背书。背书逻辑调用的是系统默认的合约 ESCC,当然也可以自己编写背书合约,但是这始终是一个同步调用操作,不用也不能由人工介入。 - 如果决定背书,则向提交请求的 client 发送:
<TRANSACTION-ENDORSED, tid, tran-proposal,epSig>
,这个大概就是endorsement
吧?tran-proposal := (epID,tid,chaincodeID,txContentBlob,readset,writeset)
,txContentBlob
是与链码/交易有关系的信息(例如:txContentBlob=tx.txPayload
)epSig
是 endorser 对tran-proposal
的签名 - 如果背书失败,则发送
(TRANSACTION-INVALID, tid, REJECTED)
client 收集背书结果并通过排序服务广播
根据背书策略,在收到足够的背书响应后,client 向 orderer 发起broadcast(blob)
orderer 发送交易到 peer
orderer 向 peer 发送 deliver(seqno, prevhash, blob)
,peer 收到后,做如下处理:
- 根据
blob.tran-proposal.chaincodeID
对应的合约检查blob.endorsement
有效性 - 检查
blob.endorsement.tran-proposal.readset
的版本检查,默认使用串行的隔离级别 - 在
PeerLedger
的 bitmask 中标记该交易为有效,并应用结果集blob.endorsement.tran-proposal.writeset
- 如果背书策略检查失败,则在
PeerLedger
的 bitmask 中标记该交易为无效
Gossip
gossip主要起到以下几个作用:
- 检测可用的 peer 以及监测 peer 是否存活
- 同步账本数据
- 将新连接上的 peer 数据更新
领头选举
每个 org 会选举出一个 leader peer(实际上可以存在多个),负责连接到 orderer。leader peer从orderer 拿到新块的信息后分发给其他 peer。
静态选主
可以在core.yaml
中配置:
peer: # Gossip related configuration gossip: useLeaderElection: false orgLeader: true
也可以使用环境变量:
export CORE_PEER_GOSSIP_USELEADERELECTION=falseexport CORE_PEER_GOSSIP_ORGLEADER=true
需要注意的是:
- 如果都配置为 false,那么 peer 不会尝试变成一个 leader
- 如果都配置为 true,会引发异常
- 静态配置的方式,需要自行保证 leader 的可用性
动态选主
选主具体算法不明,类似 raft选主,leader 需要向从节点发送心跳,动态选主只能产生1个主节点
可以在core.yaml
中配置:
peer: # Gossip related configuration gossip: useLeaderElection: true orgLeader: false # 心跳频率 election: leaderAliveThreshold: 10s
也可以使用环境变量:
export CORE_PEER_GOSSIP_USELEADERELECTION=trueexport CORE_PEER_GOSSIP_ORGLEADER=false
Gossip 消息
点对点通信的安全性是由TLS保证的,不需要签名,这里会不会有什么问题?