内容简介 这是一本深度解读Hyperledger Fabric架构设计与实现原理的著作,由国内知名区块链公司趣链科技的创始人和核心技术团队成员撰写。 全书的核心内容以Hyperledger Fabric的源代码为切入点,首先从宏观上
924 132 60MB
Chinese Pages 396 [406] Year 2018
Table of contents :
序一
序二
前言
目录
第1章 准备工作
1.1 Go语言环境配置
1.1.1 Go语言简介
1.1.2 Go安装
1.1.3 Go标准包安装
1.1.4 第三方工具安装
1.1.5 Go环境配置
1.1.6 代码目录结构规划
1.1.7 编译应用
1.1.8 获取远程包
1.1.9 程序的整体结构
1.2 安装Docker
1.2.1 macOS
1.2.2 Ubuntu
1.2.3 Docker的简易使用
1.3 Hyperledger社区介绍
第2章 架构分析
2.1 Fabric整体架构
2.1.1 概述
2.1.2 系统架构
2.1.3 交易背书的基本工作流程
2.1.4 背书策略
2.1.5 证实账本和节点账本检查
2.2 Fabric交易流程
2.3 Fabric整体项目结构介绍
2.3.1 Fabric项目结构
2.3.2 Fabric源码中相关缩写的含义
第3章 源码分析
3.1 Logging日志模块浅析
3.1.1 go-logging简介
3.1.2 flogging
3.1.3 init函数、MustGetLogger函数与其他函数
3.2 Error错误机制设计
3.2.1 总体概览
3.2.2 使用说明
3.2.3 显示错误消息
3.2.4 错误处理的一般准则
3.3 Config配置模块的设计
3.3.1 viper简介
3.3.2 安全文件配置
3.3.3 命令选项配置
3.3.4 环境变量配置
3.4 grpc服务
3.4.1 grpc用法的Demo
3.4.2 Fabric中的grpc服务接口和实例
第4章 peer的设计与实现
4.1 CommandLine解析
4.1.1 peer目录结构
4.1.2 第三方包
4.1.3 peer命令结构解析
4.1.4 以node为例进行子命令结构解析
4.1.5 peer命令结构
4.2 Admin及Endorser服务的实现
4.2.1 Admin
4.2.2 Endorser
4.2.3 频道中的策略检查器
4.3 Committer的机制
4.3.1 committer.go 分析
4.3.2 committer_impl.go 分析
4.3.3 validator.go 分析
4.3.4 vscc_validator.go分析
第5章 order的设计与实现
5.1 orderer内部机制窥探
5.1.1 kingpin
5.1.2 模块
5.1.3 配置
5.1.4 模块的初始化
5.2 kafka排序服务机制讲解
5.3 orderer在Fabric中的交互流程
5.3.1 建立连接
5.3.2 Broadcast
5.3.3 orderer
5.3.4 Deliver
第6章 chaincode的设计与实现
6.1 chaincode生命周期管理
6.1.1 打包
6.1.2 安装chaincode
6.1.3 实例化chaincode
6.1.4 升级chaincode
6.1.5 停止与启动
6.1.6 CLI
6.2 chaincode原理浅析
6.2.1 什么是chaincode
6.2.2 Chaincode Support服务
6.2.3 FSM
6.2.4 Register
6.2.5 Handler
6.2.6 processStream
6.2.7 HandleMessage
6.2.8 serialSend或serialSendAsync
6.2.9 系统chaincode
6.3 chaincode数据结构分析
6.3.1 chaincode元数据
6.3.2 chaincode的元工具
6.4 SystemChaincode讲解
6.4.1 SystemChaincode
6.4.2 预定义和注册
6.5 CSCC分析
6.5.1 结构体
6.5.2 函数
6.6 ESCC分析
6.6.1 结构体
6.6.2 Init函数
6.7 LSCC分析
6.7.1 结构体和接口
6.7.2 函数操作
6.7.3 安装、部署和升级
6.7.4 chaincode stub 接口实现
6.8 QSCC分析
6.8.1 结构体
6.8.2 函数操作
6.8.3 路由规则
6.9 VSCC分析
6.9.1 结构体
6.9.2 函数
6.10 SystemChaincode的注册和实例化
6.10.1 概述
6.10.2 安装
6.10.3 部署
6.10.4 Launch
6.10.5 Execute
6.10.6 部署后状态
6.11 ApplicationChaincode的部署
6.11.1 概述
6.11.2 生成签名申请包
6.11.3 处理安装申请
6.11.4 执行申请
6.11.5 Launch
6.11.6 Execute
6.11.7 一路返回
6.11.8 安装后的状态
6.12 ApplicationChaincode的实例化
6.12.1 概述
6.12.2 起点
6.12.3 部署
6.12.4 广播
6.12.5 部署后的状态
6.13 chaincode操作步骤
6.13.1 选择一个代码存放位置
6.13.2 内务处理
6.13.3 初始化chaincode
6.13.4 调用chaincode
6.13.5 实现chaincode应用
6.13.6 整合全部代码
6.13.7 编译chaincode
6.13.8 在开发者模式下测试
6.13.9 安装Hyperledger Fabric样例
6.13.10 下载Docker镜像
6.13.11 1号终端
6.13.12 2号终端
6.13.13 3号终端
6.13.14 测试新的chaincode
第7章 MSP成员服务提供者
7.1 MSP的设计思路
7.1.1 MSP配置
7.1.2 如何生成MSP证书和它们的签名匙
7.1.3 MSP setup on the peer & orderer side
7.1.4 Channel MSP setup
7.1.5 最佳实践
7.2 MSP实现剖析
7.2.1 目录结构
7.2.2 MSP配置
第8章 Gossip节点间的流言蜚语
8.1 Gossip协议原理解析
8.1.1 Gossip协议(Gossip protocol)
8.1.2 Gossip消息传输(Gossip messaging)
8.2 Gossip之服务组件
8.2.1 protos/gossip分析
8.2.2 Gossip服务组件
8.2.3 gossip消息发送方式详解
8.3 Gossip之服务初始化
8.3.1 gossipSvc 组件
8.3.2 chains组件
8.3.3 leaderElection组件
8.3.4 gossip服务的停止
8.4 Gossip之消息广播
8.4.1 gossip服务消息的散播过程
8.4.2 消息从何而来
8.4.3 消息如何散播
8.4.4 消息去往何方
8.5 channel通道的设计与实现
8.5.1 概述
8.5.2 配置文件
8.5.3 命令
8.6 事件机制
8.6.1 Fabric中Event相关实现
8.6.2 events/producer
8.6.3 Go SDK中Event相关实现
第9章 BCCSP加密服务提供者的设计与实现
9.1 密码学相关知识介绍
9.1.1 安全基础
9.1.2 加密基础
9.1.3 哈希函数
9.1.4 共享密钥加密
9.1.5 公钥加密
9.1.6 混合加密
9.1.7 消息验证码
9.1.8 数字签名
9.1.9 数字证书
9.2 BCCSP概要
9.2.1 BCCSP简介
9.2.2 陷阱函数
9.2.3 为什么要使用ECDSA
9.2.4 生成签名
9.2.5 验证签名
9.3 BCCSP源码剖析
9.3.1 BCCSP服务结构
9.3.2 BCCSP中的接口和选项
9.3.3 SW实现方式
9.3.4 pkcs11实现方式
第10章 Fabric CA架构设计与讲解
10.1 Fabric CA用户指南
10.2 Fabric-CA-Server
10.2.1 初始化服务端
10.2.2 算法和密钥长度
10.2.3 启动服务端
10.2.4 配置数据库
10.2.5 PostgreSQL
10.2.6 PostgreSQL SSL配置
10.2.7 MySQL
10.2.8 MySQL SSL配置
10.2.9 配置LDAP
10.2.10 构建一个集群
10.2.11 构建多个CA
10.2.12 登录一个中间CA
10.2.13 升级服务端
10.2.14 升级一个集群
10.3 fabric-ca-client
10.3.1 登录启动用户
10.3.2 注册一个新身份
10.3.3 登录一个节点
10.3.4 从另一个Fabric CA服务器获得CA证书链
10.3.5 重新登录一个身份
10.3.6 撤销一个证书或身份
10.3.7 生成一个CRL
10.3.8 启用TLS
10.3.9 基于属性的访问控制
10.3.10 动态更新服务器配置
10.3.11 联系特定的CA实例
10.4 HSM
第11章 账本机制的设计与实现
11.1 Ledger架构概述
11.1.1 总览
11.1.2 ledger部分摘要
11.2 Ledger之Block-Storage
11.2.1 peer节点中的leveldb
11.2.2 peer节点中的账本
11.2.3 创建
11.2.4 使用
11.2.5 idStore
11.2.6 存储账本ID
11.2.7 ConstructionFlag
11.2.8 账本恢复
11.2.9 BlockStore
11.3 Ledger之VersionedDB
11.3.1 peer节点使用VersionedDB
11.3.2 交易模拟器/交易查询器
11.3.3 重启恢复
11.4 Ledger之HistoryDB
11.4.1 历史查询器
11.4.2 使用
第12章 chaincode智能合约案例分析
12.1 encc_example
12.1.1 chaincode代码分析
12.1.2 使用EncCC
12.2 eventsender
12.3 example
12.4 example
12.5 example
12.6 example
12.7 example
12.8 invokereturnsvalue
12.9 map
12.10 marbles
12.11 passthru
12.12 sleeper
第13章 Fabric-samples项目分析与实践
13.1 Fabric-samples项目结构
13.2 First-network
13.2.1 安装预置环境
13.2.2 想要现在运行吗?
13.2.3 生成网络神器
13.2.4 启动网络
13.2.5 关闭网络
13.2.6 加密生成器
13.2.7 配置交易生成器
13.2.8 运行工具
13.2.9 启动网络
13.2.10 了解Docker Compose技术
13.2.11 使用CouchDB
13.2.12 关于数据持久化的提示
13.2.13 故障排除
13.3 basic-network
13.4 Fabcar
13.4.1 编写第一个应用
13.4.2 下载测试网络(Getting a Test Network)
13.4.3 应用程序如何与网络进行交互
13.4.4 查询账本
13.4.5 更新账本
13.5 Balance transfer
13.5.1 预置环境
13.5.2 工件
13.5.3 运行示例程序
13.5.4 示例—REST APIs请求
13.6 Hyperledger Fabric CA 示例
13.6.1 运行这个示例
13.6.2 了解这个例子
13.7 高性能网络
13.7.1 用例
13.7.2 如何使用
第14章 部署教程
14.1 下载部署环境
14.2 编译peer、orderer、configtxgen等程序
14.3 部署
14.4 Crypto Generator
14.4.1 crypto-config.yaml
14.4.2 crypto-config文件夹
14.5 Configuration Transaction Generator
14.6 networkUp-启动Fabric网络
14.7 运行容器+区域链操作
附录 专业术语
仅供非商业用途或交流学习使
..
, 帽 ’-
趣链科技创始人员核心团队撰写
言如画
Hype
j 原代码角度剖析 从
「
「 ledg
圈
「 ic 项目的整体架向设计, Fab
以及各核心模块的实现原理
I 王E
TH E SO UR CE CO DE AN AL YS IS OF HY PE RL ED GE R FA BR IC
F a b r ic yperldg
源代码分析与深入解读 蔡亮梁秀波宣章炯
'-
( J .户,-
••
飞
1 I
\)/
仅供~
甘£ ~ali
旦 (;)
, , 商业
m 途或交流学习佼
j哥
0
著
仅供非 、2
这是-本深度解
i卖
计与实现原理的著作
Hype
「 ledg
「 Fab
「 ic 架构设
, 由国内知名区块链公司趣科
技的创始人和核心术团队成员撰写
。
全书的核心内窑以
Hype
代码为切入点
「 ledg
「 Fab
「 ic 的源
Hype
「 ledg
, 首先从宏观上分析了 Fab
「 ic 项目的整体架构与设计
分析了
,然 Hype
「 ledg
实现原理
「 Fab
。 此外
者
后深入
「
j 原代码详细
「 ic 各个重要模块的设计与
3 为了兼顾没奇区块链开发基础的读
3 书中还加入了
Hype
「 ledg
「 Fab
「 Fab
「 ic 设计机制的基础上
「 ic
开发环境搔
建、综合案例项目部署等实战性内窑,可使读者能 在深入理解
H ype
快速动手实践
「 ledg
。
全书共
14
第
章
1 逻辑上分为两大部
一部分:源码
分析(第 第
Fab
2
「 ic
2 ~才章)
章首先从宏观的角度解
i卖
的整
Hype
「 ledg
「
体架构、项目的结,以及交易流程这
为后面的源码分析打下基础; 第
3
章分析了
Login
处理框架、
Config
日志模块、
配置模块、
E 「 O 「错误
GRPC
的源码,对理解后续
服务
4
个模块
;原码有帮助 第
4 ~ 1
章深入纤细地分析了
Chaincode
、
CA
Pe MSP
、
Gosip
、
町、。「
d 町、
BCSP
、
、账本机制等节点和功能的设计与实现
Fab
「 1c
,
分内窑能让读者全面、透彻了解整个
这部
Hyperldg Fab
「 ic
的运作机制
1 章及第 第
1 章主要是为开发
用做准备
12 Hype
3 Docke
「
。
第二部分.开发实战(
讲解
了
Go
~ 14
「 ledg
章) 「 Fab
语言开发环境的准备,以及
「 ic
「环境的准备; 第
12
完整的
~ 14
H ype
部署方法
章分别讲解了一个智能合约的案例、 「 ledg
「 Fab
「 ic
I 页目案例
3
以及顶目的
。
实战部分不仅能提升读者的动手践力,而且 还能辅助他们更好地理解源码分析的内窑,使论和 实践完美融合到一起。
rJ \
2 军简介
'-飞 、_.
/ 仅供非商业用途或交流学习使
应
nl i 业用途或交流学习使
!
仪
lJt
l~r
!)(供
Wr 商业
/l]ij)g
主交流节习俭用
俨
商业用途或交流于斗佼川
仅供非商业用途或交流’严斗{川
f)( 供
lc1i'HV.J )主必交流在习使用
流
Hyperledger Fabric 源代码分析与深入解读 蔡亮梁秀波宣章炯
版一阶
业而
工商
m
仅供非商业用途或交流学习使
械-
nv
机-m
?)
国
•..-'-
仅供非商业用途或交
0
著
学习使用
仅供
·-· )数据 CIP 图书在版编自(
北京:机械工业 .一
源代码分析与深入解读/蔡亮,梁秀波宣章炯著
Hyperledger Fabric 2018.9 出版社, (区块链技术丛书)
H…
I.
-7
一 7-1608 978
ISBN
CIP 中国版本图书馆
Hyperledger
- 研究
. 电子商务-支付方式
源代码分析与深入解读 Fabric
2 出版发行.机械工业社(北京市西城区百万庄大街
100037) '
号邮政编码
· 李秋荣 责任校对
责任编辑·张锡鹏 186m 开本:
ISBN 978-7-111-60870 7 书号:
1 版第
9 月第
25 印张:
x 240mm 1/16
年 2018
次: 版
刷·北京市荣盛彩色印有限公司 印
IV. F713.361.3
号
2 1 0324 )第
2018 数据核字(
I ·
③宣 ②梁…
①蔡… I.
元 89.0
定价
凡购本书,如有缺页、倒脱由社发行部调换
R~ 客 购书热线:(
热线(
010) 88379426 88361066 010) 68326294 88379649 68995259
版权所有·侵必究 封底无防伪标均为盗版 本书法律顾问北京大成师邬务所脱光/邹陇东
'-
( J .,-「
oo
飞 I I
\)/
仅供非商业用途或交流学习佼
010) 88379604
: ( 投稿热线 读者信箱:
hz
it @hz
b o
k.
com
l 次印刷
il ' Rli
业川
j 主必交流学习使
用
仅供非商业用途或交流学习使
•..-'-
?)
F 二 , ~cev
序
以企业级联盟区块链技术引领我国新一代信息的突破式发展 区块链技术及其理念被认为是近年来最具颠覆性和革命的创新之一,已在金
融、贸易物流征信公益联网
、 重视
。
美国、俄罗斯英
、
共享经济等诸多领域崭露头角,被世界各国高度
德国等相继把区块链上升为家战略
。
未来,区块链技术
及其理念将对社会生活的各个不同领域产重要影响,凡是涉数据共享、信息可和价 值传递的场景都离不开区块链技术应用
。
可以说,区块链技术及其理念作为信息共享和
信任协作的基础,将重构人类社会未来生产关系通过与工智能、云计算大数据和 物联网
等新技术理念的结合,将极大
地
提高社会生产力
。
区块链将成为未来数字化社会的底层基础设施,从技术面上各行业持续稳
定发展提供信任支撑,其价值主要体现在这些方面
: ( 1 )减少中
间
环节,实现
时
清算结
算,通过智能合约提高业务的自动化程度从而为各行带来效率升;(
2 )实现
数据的共享与标准化对接,基于字资产多行业流通实现价值网络自繁殖从而降低 业
务的拓展成本;(
3 )基于历史数据不可篡改
强监管机构的能力;(
、 4 )该技术的多方可信合作和公平激励机制将成为未来分布式商
业的
发展基石,为各行业创造更多的合作机会
。
在区块链技术快速发展的近十年中,产生了 代
全流程可追溯和智能合约的规则束增
表
三 的加
次重要的技术演进
: ( 1 )以比特币为
密数字货币应用将区块链技术引入了人们的视野;(
2 )以太坊为代表的可编
程区块链平台为技术应用于各个领域提供了可能;(
3 )以 Hyperchain
为代表的企业级区块链平台使得技术能够
真
Hyperledger Fabric
Hyper
led
ger
Fa
正应用于商业环境
。
为讲解对象,其源代码进行了细致分析和深入读以期帮助者更
好地理解和使用企业级的区块链底层平台技术
。
放的、标准化企业级
Hyperldg
巳 r Fabric
是
L inux
基金会引导
的开源
联盟区块链
项目,其
核
心目标
、 支持商业应用的分布式账本框架与基础代码,具有高效共识、
是建立开
智能合约、多级加密权限控制隐私保护等特性
仅供才
。
l0i
业用途或交流学习佼
相较于比特币和以太坊,
Hyperldg
本书以
bric
和
仅供非商业用途或交流学习佼
•..-'-
?)
IV
Fabric
的核心优势有:(
1 )实现模块化和可插拔,更能适应
复杂
通道特性保障数据安全,不同之间实现隔离;(
的商业应用
要求
;(
2 )多
3 )实现证书的强化管理,提供 单独的
Fabr
ic
CA
项目;(
4 )具有较好的可扩展性,解搁了原子排序与
其
( 5 )可根据负载进行灵活部署,将交易处理节点逻辑简化为背书和确认
他
复杂处理环节
; 。
本书的撰写团队来自于浙江大学区块链研究中心和杭州
| 趣链科技有限公司,具丰富
的区块链底层核心技术研究和上商业应用开发经验
。 国产自主可控的联盟区块链平台 Hyperchain
建设银行、中国联
Gogle
目前已在中国工商银行、农业 生了强烈反
本书对
Hyperldg
由杭州趣链科技有限公司研发的
、美国道富银行葡萄牙商业等数十家内外大型公司
和机构得到了落地应用,在业内产 Fabric-smple
‘
Fabric
响
。
架构及其设计模式进行分析,深入解读源代码并结合
项目介绍相关实践技术
。
提供参考,具有很好的理论和实践价值
相信可以给区块链技术爱好者和关行业从人员
。 陈纯
中国工程院
院
曾任浙江大学软件院长和计算机研究所
仅供才
l0ni
业用途或交流学习使
士,浙江大学计算机科与技术院教授
IJ
\
仅供非商业用途
!lt
· .· ~ ·~
Fi
切
ve-a
/ 序
去除炒作泡沫,回归技术本质 区块链的多中心、自动化和可信任理念与特性使得它成为未来息社会共 享、业务协作价值传输的底层技术支撑
。 理念的探索应用,以金融、证券
、
开始应用区块链
。
保险
、
近年来,随着区块链技术的飞速发展和
物联网
、
跨境贸易、能源等为代表的很多行业都
近几年新注册成立的、业务与区块链有关公司达数千家,专利
申请量由两年前的几百件猛增至五千余,社会对区块链技术人才需求非常大浙江
学等知名高校率先开设了区块链课程,技术和理念深入到社会生活的方面已成 为大势所趋
。
随着人们对区块链技术和理念认识的深入,其去除泡沫、回归本质趋势非
常明显,人们讨论的热点逐渐从如何炒币赚钱转向了应用区块链来推动各领域产业 升级与变革,区块链的底层核心技术研究和上应用探索成为了产业发展重点
。
区块链本质上是提供信任保障的技术,可能发展为未来互联网最重要基础设施之一
。
若能构建以区块链技术为基础的价值传输网络,将深刻地改变未来信息社会形态
。
以区
块链为底层技术支撑的加密数字货币应用给传统金融体系带来了一定挑战,各国政府和
央行都对加密数字货币应用保持了切的关注
。
在区块链技术去货币化的探索阶段,业界
普遍认识到了该技术所蕴含的巨大价值,通过在区块链上构建可重用、模化自动 智能合约,许多创新的应用场景不断涌现例如征信管理、跨境贸易资源共享和版权 享等
。
以
Hyperldg
巳 r Fabric
和
术资源消耗严重、交易性能低下
Hyperchain
为代表的企业级区块链平台克服了传统技
、
缺乏隐私保护等问题,提供了图灵完备的智能合约支持
使得开发者可以更便捷地和部署各领域的区块链商业应用,大促进了基于联盟
区块链商业形态的蓬勃发展
。 Hyperldg
是
Linux
基金会于
2015
项目,标是使得区块链技术在加密数
年发起的推进区块链数字技术和交易验证开源 字货
初,就有
IBM
、摩根大通思科
、
Intel
币之外也可广泛应用于其他场景
。
等科技
和金融巨头加入
重要的子项目之一,它通过支持插件组模块
。
..-
·』
)
、 -、
.--
化架构,实现了完备的权限管理、创新
I
/
仅供非商业用途
DJi.
交流
学习使
用
Fabric
是
Hyperldg
项目成立之 最
交流学习佼用
VI
的一致性算法等相关工作,对区块链技术发展产生了重要影响
Hyperledger Fabric 显
。
本书对
开发部署区块链应用的者而
言
Hyperldg
Fabric
对于国内众多想利用
,相关的中文专业资料过于稀少和浅
开发环境的搭建与部署进行了详细地介绍,并对其技术架构
和源码进行了深入地分析,为相关开发人员提供及时的技术参考
。 本书的作者团队来自浙江大学区块链研究中心和杭州趣科技有限公司,在前
沿技术研究和产业化应用方面积累丰富
。
浙江大学区块链研究中心是专注于领域的
浙江大学校级研究机构,其目标是攻克区块链的底层技术难关有效推动我国自主、安全
、 可控区块链技术的快速发展和产业化推广
。
杭州趣链科技有限公司是近年来成长极为迅速
的区块链平台和应用解决方案提供商,其研发底层
Hyperchian
商业公司和机构的生
产 论分析和实践应用方面都颇具特色
环境中投入使用
。 。
的技术内涵基础上,有效提升自己在区块链方面开发能力
已在众多大型
深厚的理论功底和扎实践经验使得本书在
相信本书可以在帮助读者深刻理解
Hyperldg
Fabric
。
Julian Gordon Hyper ledgr
IJ
\
。
、 -、 ..-
·』
)
.--
I
/
亚太区副总裁
Y 礼, tn
回
rtiumal
田叽阳刚抽回翩.
ontwdifle
p 叫·南位回'"阳”相田由斟捕
1. 2.
。,
to the Hyperledger Wlkll
。 me
ofbl
帆阳创’咽回缸阻
•ondl
何.
nt
由
四”
:l= 3
。
cid.Name ==
.,这
&&
一
中定义
。
个
CIS
spec,
( b)
127
chaincode.
"lscc"
len (cis.
&&
步只有部署、升级
的交
易才会进入
core/haindx.g
args
err = createCIS(cccid.Name,
,其新生成的
用了
CIS
Execut(
和第
2 步从
pro
ctxt, cccid, sp 巳 c ),类似
制和道路来进行
exampl02 会稍有不同
中抽取出的
于
的安装
。
sec
CIS
)根据传入的参数新
。
AC
建了
在内容上
是完全一致
也就此进入了
类
。
似于
sec
部
一
接着就调
署所述
的机
只不过,传人数据所承载的任务同执行方向也
。
6) Execute ( ctxt,
Launch (.)和 第
spec )仍依次执行
ccc id,
theCaincodSupr
5 步生成的
CIS
TION
.
t he Cha i 口 c odeSupport.Execute( . .. ),但这里的
,因此
ctyp
的值为
ChaincodeMsg
类型
的消息
6.11.5
用的
,进而生成的供
cMsg
是
ChaincodeMsg
_ TRANSAC
Launch AC
CanoiclNme
()
等到的
安装
的情况下执行不了
canNme
太久, = lsc:
1 . 0.
,
此值
c anNme
:= cccid . Get
会使程序进入
if
chainodeSuprt.HsBL(Nm
chrte,
);进入
进而入
if
6.11.6
chrte
. handler.isRug
()分
为具体的执行
1 )在
而返回
选择分
支,
。
函数,负责交易的具体模拟执行并返回响应
Execut
次得到
。
(.)函数中,
Jsc:l
.0
canNme
,然后通过
: = cccid. GetCanonicalName ()再
chrte,
ok
sBenLauchd(Nm
) ,获取了
selct
帽 case 2 )在
等待
(msg,
: = cha inc ode Support . chaincodeHa
LSC
sendExecuteMessage ( . .. )开始使用该
的
Serv
Handler
chrte.andl
以触发状态机进入运行,最后
。
... )中,通过调用
true), ServHandl 一个状态
将
msg
发给自身的
handler.tigNxS
handler.xtS
通道以触发
ServHandl
。
3) ServHandl
的
,先交给
procesStam
()收到来自
handler.HMsg(i ler.
,在
ServHandl
sendExcutMag(
的状态机进入下
hand
支
ok
ok =
Execute
Execut
msg
是
。
Launch (.)函数在
入
spec
_TRANSCIO
theChaincodeSupport.Execute ( .)使
然后
〈·
。
5) ExecuteChaincode ( ... )函数,在
道的
计与实现
handler.xtS
)处理,
serialSndAyc(,
仅供
erc
二 I 二商业用途或交流学习使
通
ServHandl ) 给
LSC
的
状态机无任何 Shim
Handler
发送
变 msg
化, 。
•!•
128
Hyperledger Fabri
4 ) LSC
的
Mesag(in
c 源代码分析与深入解读
ShimHandler
的
)处理,触发
chatWiPer
befor
()收到
Transctio
事
handleTransaction ( ... )函数
msg
件函数
,交出
,该事
件函数主要调用同文中的
。
5 ) handleTransaction ( ... )函数主要做的就是根据 成并初始化
一
调用
LSC
的
6 )在 Args
个
ChaincodeSt
In
LSC
。
巾,对
voke
()
的
()中,
case
-到 7 )在
” instal
巳 xample02
functio
的值是” case
工 NS
。 和
ls
examp
TAL
的
CDS
,执行安装
... )中,首先 中
1 『,
即 然后
(path,
中,
。
)先检
064
至第
)将
6 步
CDS
创
exampl02
列
if 检
录
的
查之
后,先
path
口 ame,
的
Execut
收到
(.)函数
可用
。
buf
最后
6.11.7 当交易模
件函数
,井
执行
写入
) 整
path
指定的地方
。
中的
赋值为
handler.tigN
之后就
_ COMPLETD
,
(.)函数成功返回
客户端
再无其
ShimHandler
只将 他动作或
变化
消息,通知仍处于等待之中
Execut
向
至此,
. .. )
defr
S 巳 rveHandl
ChaincodeMsg
仅供非商业用途或交流学习使
fmt.
nextSaMsg
发送给
完之后,执行结果就会
:=
handleTrsctio(
。
一路返回 拟执行
。
ioutl.WreF
。
,然后等待结束
Version
cversion
),并将该消息发送给自己的状态机 消息
和
。 事
的消息
xtSae(nMsg,d
Name
exampl02.nothrvsi
路返回
巳 r 的
( core/ 。
下放入名为
中成员 一
类型
11 ) ServHandl
函数,依
C DSPackge le02
c
名是否
由此,开始
建一个
)返回,继续向下执行将
OMPLETD
的
源码写入文件系统
Packge
handler.cIvok(stub
ChaincodeMessage _C
仍是被
: = ccprovider. Get CC
examp
此文件
ShimHandl
ChaincodeMessage_COMPLETD
的
CDS LSC
CDS
其次,简单验证
一系
查
。 回
工 i cy
查要安装
,不过此时的
, err
目
的安装申请执行完毕 )一路返
string(args
函数来检
)之后调用
过的
chainodelstP
ccpack .buf,
CDS
inc ode I 口 stalPh,
os.Sta(ph
exampl02 10
定义)
cha
在
code
depSc
Marshl
. . . )中, /% s . 毛 S
chain
cpak 被
PutChaincodeTFS(
。
:=
。
exampl02
合出要写入的路径, 的文件
的 的
()将
S
creatPopsl
functio
exampl02
cpak.PutChinodeTFS
("去
.CS. I 口 put.
仨 Po
]取出来的就是
/ cdspakge.o
Sprintf
仨 e ()中,
Chanel
)会根据
9 )在
vol
中
CIS
lsc.poiyChekr
l(
调用
In
:分 支中,
excutinsa
comn/prvide
stub) 是
utils.go
cc. executeinstall (stub,
Packge(byts 最后,
因此在
生
。 /pro
门使用了检测未指定
l e02
8 )在
。
msg
handler.cIvok(
: = stub. GetArgs ()获取到的
cinp
:= args[l 。
收到的
instal
depSc
过的 stub
安装 ls
”·中的
NoChannel ( ... ) 首先专
据
args
Handler
,然后
进行
prots/ui
FromCDS ()中的
Marshl
C haincodeStub
exampl02
这个数组的值来自于
[OJ )得
Shim
应图中的
方法对
Invoke
handler.
返回
。
。
第
I ) Execu te (.)函数结束之后,就此 endors
. go
一
中的 calChinode(
6.14 ca lChaincode(
2 )继
节)第
4 步的(
...)也就此结束
续返 回到
Pro ces
ces Pr
sPr
opsal
opsal
Endorse
户端
与实
返回到
现
cor
步(
令
e /en
c )中的
进入代码中的
129
dorse /
instal 申
请不会执
if
if
分支 。
txsim ! = nil 分支,
。
(),将进入
客户端
因 此继
! = nil
res
的应答消息
续向下走,进人
分支,但无法进入
p Re
if
s p 赋值, 最
if
后将
chainID =’ pRes 返回 给
1 『分
E ndorse 客
。
4 ) exampl02 的
为安
instal
装申请的起点, per
( ... )中的
/ chainode
cf.EndorseC
/ inst
lient.P
户端,收到服务发来的消息在返回后
6.11.8 在
。 至
此, 整
个
a l. g o 的 chainodelst(
... )所调用
rocesPpal
instal
Inst a ll ( ... )结束
()即是
E ndorse
(.)随之结束,进而导致
examp le02
客
chainode
的安装全部结束 。
安装后的状态
per 节点的
c h a incod
文件,该即为
elnsta
examp
l!P
l e02
at h 目录下,会有一个名为
exa
源码压缩包 。
为链码对应的可执行文件源
用于 实
mple02.anothrvsi 的
例化的时候创建相应链码容器,其中
。
AplicatonChde
6.12
的实例化
链码安装 之后
需要 进行 实
并启动链码容器的过程
例化才能够进行后续调用,实过程为创建链码的镜像
。
6.12.1 概述
peer chaincode instae instae.go 中
node star 、
p e
命
,这
已 根据实例
经建立
、
一 句实际的
也已 则
的起点
P 巳 er
。 per
经安装
,从
命
-o
1 { 11 Arg s 11 : [ 1 『 int1
a1
,”
、
要注意的 p e er
一
/
点是,这个命令在 per
chaincode instal
节点的基本模块(包括
e_
-v anotherversion
需
/ chainode
sec
命 令依次执行完毕
)都已初始化完毕,
。
insta
instae
另外
channel join
之时,
, AC 化的 原
per
署
instae
chanel
令执行部署命,定义在
也是部
r channel creat
之后执行的,即
用上)
一直
一
会
()
res . Status >= shim. ERO 支对要返回给
的设计
。 ,不
P ro
3 )继续
路返回,
b ),由于这
simulateProp
因此也是直接返回至
chainode
... ) , chaincode.ExecuteChaincode( . . . )
执行完毕,申请的( 行,因此
6 章
令 :
tes.go
per
和 官方文档中提取整合了(尽量能用的
flag
chaincode instantiate
,”
orderer. examp l e. com: 7050 10
仅供非商业用途或交流学习使
。”, lb
, ” 20 。”]}『-
-n example02
C test chain P
"OR
都
(10rg
工 MSP.
-c
仅供非商业用途或交流学习使
•!•
130
Hyperledger Fabric j 原代码台析
与
member t ,’ Org2 MS P . member 『) anoth
巳凹
ersion,
要 部署
-o
的链是
指定连接的
or
teschain
in sta
der
flag
- I 、 化
署是存储在
b 两个账户
节点通过
g rpc exampl02
的 lop
通
。
化 der
身
,最后将 进
起点位置在
mple02
行背书
cod
通过
grpc
执行部
部署
的步
骤
巳 Packge
十
为
。
分繁杂
,下面
nil
o
将进行详
中的
2)
) ,这点将
teschain
,不
与
insta
l 命令
要
执行的线路类似,对 )在部
再为空,
即
/ utils
署成
LSC
的
要
exampl02
把
功的
” upgrade
Invoke
”:
所进入的分支
dors
e r 服务端在
t 上
c ore/
来自客户端的
Channel Id
n tex
ctx
t , 一
ndorse
ctx
l 时
下文
和
安装在
分支(
cas
。
te s tchain
,以
至于之
ct
ionB
。 ( b )调
y ID
用
(txid
)对
txi
txsim,
仅供
er r
· 1 二商
业
用
i 主或交流学习使用
服
=
”中执
行
务端
if
,
。
...)
处在于
,
chain
:= 会
的账 )
的唯
本对象 一
事
ID
chainID !=川分支都 ID
=
SignedPropsal
Procespal(
teschain
(交易
err
h ist oryQuery Executor,
个
获取 d
” d 巳 ploy
... )所做的 之
三
),
,
teschain
e 的
Procespal(
后
: = peer. Get Ledger (cha i 口 ID
装好
中的
instal
获取的值为
中
creatPops!FmCDS()
E ndorse
/ endors.g
所描述的那样,但不同于
C DS
。
起发给
SignedPropsal
的
exampl02 的
case
响
关于
/ proutils.g
l ,这次进入的是
直接影
Co
insta
和
LSC,
。
prots
个之后一直在用的
情依旧如
为了避免重复部署)
3 )获取
cf.BroadstClienS(v
细讲解
值为 in sta
gh
3 ) En
lgr.GetTans
。
per
( .. . ),主
2 ) cf. EndorserClient. Process Proposal ( ... )将组
lgr
容器并与
chainodeDply
的
chainID
,不过同于
fa lthrou
收到
exampl02
。
的值依旧来自于 c cinp
接
将
据封装成
. go
env
CIS.nputArgs
一
。
exampl02
1 ) instantiate ()是部署的起点,中途所组装
同
进行通信
部署
6.12.3
连
,这里就
署交易
的部署交易,启动
巳 /instae
点广播部署结果
了
instal
。
env
前提下,向各个节
中的
相对于
, 然后将签名、读写集等部署产生的数
进行部署,并返回结果
。
-C 。
1 ) LSC
1 ) env, err := instantiate( cmd, cf)
上
指定
。
集
节点交由其处理
p 巳 e r/ chain
可以实现两件事:
Cod
是
起点
6.12 .2
exa
- P 指定策略
- v 指定版本
- C
初始化的状态写人自己
E SC or
,
2,
Handler 执行自
信进行初始
巳 ,发送到
e re.xamplco:705,
容器中的,启动两端
2 ) exampl
读写集,使用
ord
ample0
。 :
写集
ex
-P 、 - E 、 - V 、
最终要做三件事情,涉及条链码
的源码放入自己
Enve
- c , -n, - v 、
a 、
Docker
in s tanie
是
服务实例的端点是
有
- c , 要求部署的时候初始 的部
AC
参数
能够识别的
AC
- n 指定部署的
,心指定执行的函数和
ntiae
指定了
。
深入解读
性进行检
进入:(
chdr.
lgr
,
a) 并调用
查(这里是
e.getTxSimulator(chainID)
e. getHistoryQueryExecutor
仅供#商业用途或交流学习使
第
(chainID
);,分别获取
teschain
historyQueExc ,
对
ex
ample02
的
4 ) 在
e .si
个
部署进行背书
if . .分支
&&
Cha
incode
所述之处在于,执行 分
if
Execut( instal
LSC
获
取得 是
deploy
的
到的
e . ca
支,
也
txsim
!=
会进入最后的
if
l
cid.
nil
分
支,将第
3 步(
CIS
b)
的对象,与
ctx
... )函数,在这个中按部就班地开始
、
Launch
。
进入
cinp, sw
的
itch-ase
会进入
lsc.
CDS
,但
( 『 Org!MSP
和
是
是被
Marshl
: 分支
是
否
已
L exampl02
( c )调用
esc
esc
policy /v
sc
cpak,
口 t
ChaincodeStub
和 9 )在
put
S 阳 b 的函
数
Ch
c
pack
Chai
空, 。
则赋予
在此罗列一下
值为 的
第
teschain
3 个
Pack
参数,值为
exampl02
ge
生成一个
的名
对象
cpak
C ha
。
incodeDat
然后
版
cd
数据对
象
:=
。
( d)
ccpack) , ls cc. check ( e )调用工
sc.reat ),传入
。 )中进行简单地检查之后,就调用
Chaincode
stub.PSae(cdNm,y
),以 value
字、
cc. putChaincode Data (stub, cd
,执行部署任务
数据为
; 。
。
丑 codeDat(sub,
ChaincodeDt
若为
由于命令行未指定,为空值
iationPolicy ( chainname, ls
ai ncodeDat
: 分支
... ),查看
CDS
),进而直接调用
DEPLOY
/ vsc
args
InstantiationPolicy ( ... )分别获取并检查一个部署策略 Chaincode(stub,
得到的值
err : = ccprovider .GetChaincode
(),再由
l sc.getina
为
门
lsc.getCina(
的源码读进一个
. GetChaincodD
case
; chainme
。 ( b )调用 。
在
: ( a )先检查
(账户控制列表)
stub. GetArgs ()
xample02
数据;
’)”;
经存在于链上
FromFS ( . .. )将
。
ChaincodeStub
过的
:=
string (args [O
:=
DEPLOY
为
’ , ’ Org2MSP.meb
AC
调用
args
( ... )中,需要做如下事情
本是否可通过
cpak
stub
此刻仍
excutDploy
exampl02
中),
节)相似的过程,一
exe cu teDeploy ( ... ),开始部署巳
. mebr
8 )在
case
6.1
补,如
最后调用
为
节、
function
( ... )的参数:
depSc
6.15
每个值进行了检查,对参数修
excutDploy ” OR
巳章节(
( core/lscc/lscc . go
之后的
ar gs 值
Launch/Ext
1 步所提到的 而
,依次对
的
Invoke
是第 ,因
认
过的
会执
。
到调用
默
()将
... )中,依旧生成
7 )在此省略与
中
( c ) e.ndorsPpal
和
。
一同传人文件中的
直
。
! = nil
txsim
chainode.ExutC(
Ex cute
中 instal
( ... )中,会进入 ctx
Contex
131
。
中获取的交易模拟工具加入了 6 )在
ctx
l ( ... )中,不同于
Name == "ls cc " l
·:
。
mulateProps
ca
的设计与实现
txsim
工具先后放入了
Chaincode ( ... )之后,会进入 5 )在
chainode
的交易模拟工具和历史查询并赋值给
,同时将两
行
6 章
,把这一对
key
- value
exampl02
的
放到账本中
名字为
key,
Marshal
。
10) stub.PutState(cd.Name,cdbytes) ( core/chaincode/shim/ LSC
chainode 的
. go ShimHandler
中定义),调用了 的
stub.handlerPS(
. .. )时触
handlePutS
仅供书商
()函数
业
用途或交流学习使
stub
的
handler
是在第
7 步省略的过
发了
仅供
•!•
132
Hyperledger Fabr
程中,在 LSC
巳/ shim/
的
实
key
respChan LSC
意这里等待的
eTxCo
ntex
S 巳 rve
发状态机的
tx id
事
作为 的
trigeNxSaMs 给
发送应答
trigeN
。 STAE
、
三类消
发 一
执行
。 个交
执行的
。
函数,
与
3 步和
第
息,然后随
着函数
ChaincodeMsg_INVOKE
CHAINCODE 是
做什么的:新建
lsc:
.0 . 0 。
( d )进人
if 支
,
中
写集是
一个
rwsetutil/rwset_builder.go 键,映射一个
nsRW (写集)中
。
中的
,而 对
署也是一个交易,自然需要最终提到账本中只目前还没的时候
的部
终就 署
,这
( . .. )是由最初 . . . )创
建
的,创建 txCone
出来的是
Serv
的
Handler
关于
LSC
lue
,连同处
理 是
:
在
exa core/
mple02
的
ledgr
是将
映射,这个
/kv
key
map
和
value
lsc:
存储在这个
1.0
以
ledgr
一
/ txmg lsc:
/ 1.0
为
nsRW
中
目前并没有真正提交到账本(数据库)中,部 。
仅供非商业用途或交流学习使
( c)
pb. ChaincodeMessage_
==
rwMap
.. . )最 exampl02
重复
... )会利用 的线路
中的
具
。
va
map
Seta( 。
和
RWSetBuildr
的
txCone
. txsimulaor.Se(
,这个
数
这其中交易模拟工具在此之后将用到
txCone
map
个状
个交易
工具取出来后赋值给了
段
key 。
,函
获取
Excute
msg. Type. String ()
交易模拟工具,最终将
同写入到 写集
程中,
中的两个 字
接着 一
txid
的过
( )取
PUT_STATE. String ()分 中的
省略
handler.gtCRoNm
:=
一
)是为了防止同
ctx 两个
defr
_PUT_
口 tex(
historyQueExc
chaincodeID
的结束触发
ChaincodeMsg
7 步
如 即
。
更新到
( b )
,则顺利到达函数
handler.ctTxCo
5 步
。
一旦检查有错误,
可以判断它各
是在第
a)
巳 Msg
若中途没有错误
答消 矛日
Contex
第
writeMap
发送
巳 xtSa
的处理主体,分别
中的
txsimulaor
的
Handler
丑 try(msg.Txid
transcio
的同时,也将
触
(改一个状态),就是熟悉的增删
sendExcutMag
txCone
er
个正常的应
handler. creatTXIDE
下文
注
的布局:(
trigeN
( b ) handler. isValidTxSim (msg. Txid ... )会根据 易上
的信息
是
defr
支是函数
c haincode
。
的
一下函数
,发送 的消息
字基本就 a)
的回信
类型的消息,将只
烦,所以先讲
息,对应执行不同动作从名
体执行:(
Handler
。
_ DEL_STA
态、删一个状和调用
Serv
_PUT_ STAE
返回,触
ChaincodeMsg
等待
类型的消息
。
个
if ,大分
类型
handler.sendReceive
该事件函数整个都是异步执行的
贼值
中部的
时传人
ServHandl
看上去很长麻
extSaMsg
( c )
- case
ChaincodeMsg
眼
后
( b)
_PUT_ STAE
数一样,定义了
赋值
巳 Stub
中存储通知频道,防止交易重复且随用删
的地方 函
。
ChaincodeMsg
map
。 一
handleit
cod
_ PUT_ STAE
txid
selct
在
最后发送消息
ShimHandler
的最后,
key
件函数
函数
defr
Chain
proto. Marshal ( &pb. PutState
是
然后进入
收到
13 ) entrBusySa
生成
生成的,这个函数类似于
为
usyStae
中
C haincodeMsg
依旧
creatChnl
S 巳 rveHandl
entrB 使用
,
( a)
一个
Txid
rHandle
是以
的
作为 将
,是
,都
12) LSC
装,
Paylod,
respChan
creat
封
ShimHandler
的
ion :
和 I value
),调用
异步发送给
handleTrsct
要做如下事情
消息的
(msg,
用途或交流学习使
。
()中需
ChaincodeMsg
将
的
例)
handlePutS
Info { ... } ),首先将 的
handler.go
ShimHandler
11 )在
业
i c 源代码台析与深入解读
core/haind 的
' Ii 二商
至
此,
仅供非商业用途或交流学习使
第
exampl02
的
后触发
chainode
defr
完成了
,调用
真
正的部署
。
ServHandl
发送携带部署结果
的
消息不做任何反应)
( e )将交
的
res
ChaincodeM
6 章
易
c hai
的结
机的
的
after
果放入
收到
事
respC
han
件函数
。
133
N extS tateMs g ,然
类型的消息(
ChaincodeMsg
ShimHandler
ServHandl
_RESPON
该事件函数调用
ha
发送消息,第
ll
对这个
步(
b )的
返回
15 ) 一
路返回
至
core
/ lsc
/ lsc.go
sendRci
ve ( . . . ) 等 handlePutS
中的
put
LSC
的
COMPLETD
类
完毕 型
17 ) LSC
。
的
的
触发
defr
,向
)函
ServHandl
收到
的
完成
的
Execut(
Serv
Handler
发送
CDS , Contex
和
ctx
一
同传人
这次进入没有通过
是第
calChinode
的
Launch
下执行
LSC
和
将 一直 执行下
已
成的是
经
次
传入的是
exa
个
CIS
C
在
ChaincodeSuprt
Launch 时
(.
模式,这里默认是
.
t e
解压
的
容器
,最后将巳
类型的消息
二次
进入
的
Contex
和
exampl02
,即
user
- Execut
没有
CDS
。
Launch
的
exampl02
canNme
的值为
)获取的
仅供非商业用
chainode
chrte
false
CIS
的
i 主或交流学习使用
mode
( b ) exampl02
为空
。
,因此生
CDS
,因此生 。
是在初始 的
。
( b )第一次
过,因此这次
Execut
Runs C
的 白,
LSC
!中
=
ExecutChaino
不同类型的消息都会被传人 core.yam
cccid Launch
a) userRnC
写入的,引用是
=
: ( a )第一次传人
第二次传人的是
。
err xample02
。 ( c )第一次传人的是
消息,
eds,
CDS,
不同于第一次的是
exampl02
。
出
Contex
)中,这里提几个字段的值:( net
chainodeHsBLu(
) 。
了,但
mple02
路返回,直至
4 步 的
( .
过,中途就返回
_ INT )
一
.分支,对应第 一
_ TRANSCIO
ChaincodeMsg
19
,这
, 建立
ChaincodeMsg 是
CIS
。
继续
中的
Launch
去
步所返回的结果
。
”“.
Execut
_
chainode.Exu
(.),第
中的
Contex
的
成的
。
中,
chainode.Exut
exctransio.g
Launch
15
core/haindx.g
LSC
ChaincodeMsg
回
中的
lsc
handler.
core/haind
5 步),继续向
cid.Name 二’'
函数,
消息和通知之后,
ccprovider . NewCCConte xt( . .. )并重新生成
的是
继
:,有到
Transctio
... ) 等待结束,函数返
完毕(对应第
if
是直接调用了
。
也执行完毕,并 handle
putils. GetChaincodeDeploymentSpec ( . . . ) exampl02
。
DEPLOY
数的本次部署
Paylod
. go
Chaincode ( ... )执行
过程
到
9 步
case
中的
消息,的
core/nds
)进入
stub
LSC
ChaincodeMsg
中的
18
重新定位
( .. . ),对应第
/ chain code/shim/hand! er. go
chainode_suprt.g 返回到
1 1 步
sendRecei ve ( .. . )
) 函数中的
Invoke(
core )执行
。
第
) 。
)继续返回,定位到
cc.Invoke( stub
口 codeDat
Invoke(stub
shim.Suce(dbyt
16
待结束
,
Chai
lscc. executeDeploy ( .. . )结束,整个 retun
)向
。
续返回,一直到同文件中的 返回
类型的消息,触发状态
ndler.sCha(mg
中的
在结束返回后,将开始 一路
过,因而
trige
向 _ RESPON
core/haindsml.g
dev
•!•
e 的设计与实现
handler.tigNxS
esag
ShimHandler
Respon
提到的
时
od
。
14) LSC
而
旧
配 也
置
( c ) exampl02
化 项是否 没有
中
La
CDS
unch
的
仅供非商业用途或交流学习使
134
令
H yp
Execnv
e rl e d ge
r Fabric j 原代码分析与深入解读
值为 默认
中只
的
会进入
if
ChaincodeDplymtS
_DOCKER
。
数
据,进而获取
CDS
exampl02
的
Docker
,
容器
该
的
CDS
的
CodePackg
建立使用
包
。
launchAdWitForReg
ister
20
)在
用到,
exampl02
的
exampl02
Launch
的 }创
Docker
容器
/ dockerntl.g
21 )在 Docker
Star
镜像
会
中的
ID
,这
个
ID
Star(
),根 是
%s-
go-dckerlint
小
的
” %s
写
。
c ,
( b)
id
core
的
中保存的
Docker
容
三
个
IO
根据
的标准输出和
examp
的
镜像
建扫清障碍
ID 。
ID
( f ) err
atchSdou
分支,
事实
上(
f)
h )执行
的
Docker
使用标准的
二
方库
先创
全漏洞、运行笨拙等缺点),
建
exampl02
一个
分
的镜像和容器,为之
认可且以使用的
Docker
)创建容器
容器
个配置函数,即
。
( g )进入
的机制 是先积攒关于
dock 的
Launch
一
下
exampl02
if
err
巳 r.EN
oSuchlmage
镜像,然后重新执行
e x ample02
。 ( i ) client.
的容器,通过配置对象创建
。
镜像和启动容器
的过
巳 rclient build+Dockerf
=
exampl02
函数,预
nil ),启动 的
而
了
接口的改变而
github.com/fsza-dk docker
。
容器的标准输出和
e η
()
容器的方式可能会在以后根据
步创建
ID
( e) vm. stopinternal ( ctxt, . .. ) ,
镜像并不存在,因此将产生
prelaunchF
21
容器
将执行失败,因为创建容器的基础是使用镜像存在而当
builder
容器(
个
gorutine
CreateContainer(copts
StartContainer(containerID,
是第
生成一 门,获取
ID
的错误,在这个分支中使用了
)详解第
。 ( c)
chStdou
,尝试删除可能已经存在的同
client.
exampl02
2
容器的基础
= vm. createContainer ( ctxt, ... ),创建容器这个
然后调用
第一次部署的时候,
( f ) 创建
之内,否则
一 饨,
! = nil
ker
,这个配置对象除了基本容器的信息外还指定
getDockrHsCn
的 口 c (),创
ID
client
copts
exampl02
分支(该启动了两个
函数主要做的就是首先根据现有指向生成一个
配置对象
/
imageID,
:= vm.getClinF
err
。
、容器
a)
一个
.at
错误输出)不会进入
le02
后 的创
:(
,组装
Docker if
/ contaier
, 、.
fa ls e ,用于为调试目的而使能 器
器
字符范围在只有母数、
ol("vm.dcker
错误输出,这里使用默认值即后边的
最后
在部署中会使
追溯,将定位到
Doc
配置项,这个默认值是
。
。
client,
r.GetB
数
{
。
builder
客户端对象,这个是实际进行
( d ) attachStdout : = vipe
函
Launch
: = strings. Replace (image ID . .. ) ,根据镜像
containerID
别接收容
行
Launch,
一直
.. .)函数
据
builder 进
exampl02
的规则
用一替换,形式为
建一个
。
( . . . )函数中,启动了
: = vm.GetVMName (cid
err
DockerVM
源码数据,将供后文
建了一个
的
的源
(io .Reader, error)
exampl
sec
unch
if
exampl02
开始对
过程中,不同于
启动的是
dockerntl
.. . ),
La
exampl02
func( )
(
l 整个
命令放人的
含
builder=
点,可知
. .分支,接着进入
1 1
instal
return platforms.GenerateDockerBuild(cds) 调用
三
( ! chaincodeSupport . userRunsCC
! ( chaincodeSupport. userRunsCCll .,从文件目录中读取 码包
据此
o ( b )创
建
程
AC
的
。
首先概述一下
Docker
: ( a )使用的
容
器并不是简
单地
(因为这样产生的镜像有体积过大、存在额外安 exam
ple02
的
镜像数据(
Dockerfil
e 文件、
per
仅供非商业用途或交流学习使
第
节点的
tis 看
证书
出,对
的
容器进行减负,主要是去为编译
AC 空
. yam
!中
间和资源
又
chainode
项目提供,在 系
器,然
一
后把
中下
c巳
nv
exampl02
的
于生成支持的语言
/ chainode
用
来
来 中的
tis
package.tar 也
,
命
per
的
向
gorutine
中,
Dockerfil
core cenv
usr 中
,即向
。
gw
tw
中
、
写数据
件写人
tw
,
然后调用
/ chainode
/ platforms
Docker
Build
下载,
然后
中
chainode
创
一步
/ 中下载到输出流
后直接将
返回
read
uild
就
是接
。 收
返回到
21
步(
镜像数
- cenv
builder
。
ample02
的
令会
将
b i n package. tar (即名为
pl 巳 02
c h aincode
/ outp;
指定了
tw
,随后流
执行
容器
向
。
完毕将
然后通过调用
镜像部署
。 镜像的
Doc
exampl02
input
。
i nput
co
返回给
的可执行程序压缩包)
l e 指定的
从/
read, ,把
read Dock
2 1 步的(
k erfi
de 执行前
运行容器时
继续第
尝试
( d )异步
v m.deployag
的
指
则
Dockerfil
命
C md
是否存在,若不
fabric
g ) 处 据
exam
AD
fabric
chain
exampl
这里需说明的是,启动容器
),进而
c haincode
写入
的
先把证书和
; OutpSream
并删除
ex
启
个值:
容器,等待编译完成最后将好的 第
围下的数据),将
三
行程序井放入/
镜像的输入流(即上下文,可以理解为此使用
能使用的哪个范
。
指定了
<
( c )在新
,依据
Options
WriteBysToPackg
OutpSream
input
对接上文,
- cenv
。
DockerBuild
fa b ric-env
fabric
< -gw
input
CDS.odePackg
,所做的就是根据选项先检查
建、启动
/ outp
erB
的 c util.
< - > Outp
镜像数据
中的 的可执
exampl02
容器的输出流,该最后也通过调用
ut
l e02
工 ls.go
chainode
该流为
环境变量
tw
Dock
指定了输入流,
和
GenratDockBuild(s,
镜像创建了一个容器,该的选项
InputSream
c ore.yam!
io. Pipe ()生成了一个管
:=
examp
/ ut
编译成名为
调
巳 Dockerfil
LABE
向
/ util
、
的可执行程序压缩
一些 inp
的
l ang
,然后
镜像,由
l e02
最终会形成压缩包并流
golan
exampl02
作为
examp
压缩对象,形成了
,
go
执行的是
Genrat
se os
目录下,还定义了
tw
i lder
中
平台的
output
、
inputFles
fa bric-a
( b ) input,
把
( . . . ),在这个函数
放入 golan
. . . )汇总了
定了编译命令,将·
在
per.ct
l/ bin
容
,然后再 car
ild
将编译生成的
/ loca
个
s 下是平台相关的代码,用
ckerBu
AD
genratDockBuild( 文
调用
,
的
建这
build·
a) bu
节点的证书
ic
l e02 创
然后详述过程:(
最终使用
定
解压到/
管道
examp
是总控文件,
。
exampl02
func ( ) { ... }中的
数据流
个能编译
大致过程为先
tform
文件(使用
令指定
inputFles go
语言
个容器,这 Fabr
。
/ pl a
Dockerfil
制并
将它放入了
连同
tw
复
/ chainode
此可以
为启动镜像,该由
的缩写
G enratDo
连接
项指
等),
core
中的
F ROM
bin
e nt
g olang
chainode.glrutm
包
( d )在
来生成可用的
建了文件头,
一
platforms.g
容器通过 le
创
道
。
/ platforms.g
genratDockfi
源码用到 一
的镜像所需数据包,
/ platforms
ample02 作
巳 nvirom
135
而存在的部分,这通常使
fa bric-env
里只关注
exampl02
ex
容器(由
go
代码,这
中,先把
•!•
e 的设计与实现
源码上传到容器中,然后启动时执行
AC 是平台相关的
( c ) 编译
c haincode
出
core
od
载镜像时会下,其实应该就是
,就是
编译好的可执行程序下载 jav
。 项指定的
Stared
统容器一
相对多)
. builder
Geting L i nux
旧
AC
用较少,但占的 core
c hai
、编译后的可执行程序),然创建一个相对轻量级
AC
器将
6 章
创 erfil
fabric
g )向后执行
。 - baseo
,
且
复
仅供
136 令
制
H ype
巾
并解压到/
中
dg
er
Fabric j 原代码分析与深入解读
usr/loca
Cmd
/ bin
的值(相当于
目录下,再者
creatCon
Dockerfi
suport.g
中
l e 中的
getArsndEv 当
时(准确说
exampl02
的
clie
是
程序
一
容器
个
Docker
的
args
co
fa bric-aseo
),
p er
执行
ntaierID,
nil)
只是其基 。
) 的是
fig
[)string {” chaincode ”,
且 t.SarConie(
-per.ads=0:751 容器中
Con
=
镜像,
client. StartContai ner( containerID, nil 以宿存在
建该容器的时候,配置
core/haind
exmapl02
c haincode
创
)是最初在
( ... ) 生成
fabric-seo 行
ai ner
CMD
fmt.Sprintf(" ... },所以 启动
' I 二商业用途或交流学习使
础
这里要进行
清
镜像)会执
晰地区分,执行
节点(这个可以宿存在主机中,也
chainode
-p
er
. a dr
巳 s=0.
0.:751
的
是
e xa
mpl
e 02
。 23
) 创
的程序
建巳
xa
chain
mple02
cod
的两个
e ,参看源码
exampl02.go core
func
/ chainode
旨在启动
/ sh 一
REGIST
个
即为
im
的
用了
(),
CORE
,把一
就可以获取第
2
shim.
中
设置
gr
exampl02
的
v iper
步最后启动
的
core
生成的,一路被传至
stream,
err
个流是连接
节
Handler
。
Ch
exa 了
mple02
取其他的环境
中
2
per
c haincode
节点的地址,在此则通过
flag
中执行了
。
。
而调用
.g o 中的
HandleChicoStrm
gprc
并调用
for 的部署 stream
ServerHandler
循环
和
一样
务端
的
c
发送了
给
a ndler 一条
flag stream per 数
Cha
相 in codeMsag
应成员,然后利用
exampl02
stream, 的
的 S himHandler
c
),如同
sec
ShimHandler
对象,将 向在
类型消息,
/
将被调用,进
了属于
ShimeHandlr REGIST
core
接收
exampl02
给定
Getter
节点在
( ... )函
搓
.
步最后启
日,即通过
新创
,先创建了属于
ShimH
flag
()启动了循环
chatWiPer
赋值
的地址是通过
执行过后,由于
Registr
( b)
流,这
2
一步
chatWithPeer(chaincodename,
,通过
er
(.),因此
handler.pocsStm
。 ( c)
pe
grpc
取的,对应第
。 HandleChicoStrm
Server Handler 消息的
服
。
取一个
,
... )
creatConi
其中
这
. Registr
chaincode/chaincode _suport
且 dEnv(
.0 .0:7
获取这个地址
等
getArs
步中的
- per.ads=0
chainodeSuprtCl
_ CHAIN CODE _ID_
) ,获
客户端流
门
日志输出级别
suport.g
容器配置中,对照第
程序是
CORE
前缀
.idname
变量以设置
/ chainode
aincodeSuprt
容器时执行的
: ( a) 把
中
StringVar ( &peerAddress, "peer . address" ... ) 获 动
具体的过程如下 值的一些方法,如
E nv
_
SimpleChancod
code
streamGetter (chainodem
点的
ge
的
ing("cha 获
/ chainode
S tartlnProc ,
传人
C 。
容器时设置的
的
:=
per
Serv
量
mple02
exampl02
时调用的 C haincodeMs
viper.GtS
exa
均是最初在
exampl02
主动发送一个
L ifeCyclSs
的值,其次是
量
pc
在本容器内获取环境变
. ,这样
NAME=exampl02:nthrvsio
这些环境变
容器中执行
Start(new(SimpleChaincode ),该函
并通过
点
替换为
e 02
sec
LSC
SetupChaincodLg
mpl
定义,相当于部署
ShimHandler
节
exa
直接调
链码对象,相当于
设置为
在新运行的
中
per
exampl02
中
/ chainode.g
型消息给
。
m ples/ chaincode/ go/ ch aincode _ ex amp le02 /chaincode _
main
exampl02
类
er
exa
,执行的
数在
Handl
最后
启动了循环接
per
节点中的
仅供非商业用途或交流学习使
第
收
Serv 的
r Handler
消息的进程
。
ChaincodeMsg
建
( d )
_REGIST
的
属于
ex
Handler
ample02
的
替换掉
。
第二次进行
的 步,
R
S erv
直到
core/ha
in
的
code
/ex
)继续
执行
运行的
L a unch
的
c
( 即
pr
H an
ChaincodeStub
dler
。 的
l er
发
送
elaunchF
()预 巳 r 均达到
ready
。 Execut
Launch
(.
状
的
态
。
至
此,
返回定位到对应第
18
.)中
,
theCain
co
d e
。
发来 ha
exampl02
137
ShimHand
. ),
定位
到 的
rve
•!
b )新
ShimHandl 的
函数,进而调用
一个
计与实现
这里的注册指是用(
部分执行完毕,开始返回
的
Simple
ChaincodeMsg ( msg
机
) ),在这个函数
中:(
建并根据收到的
co de
容器中
消息,状态 a)
对象)的
Ini
O~l f
发
stub
C haincodeMsg
_ INT
( b ) handler . cc. I 口 it(sub
C hain
exampl02
handleit(msg)
_ INT
ndleit
(ChaincodeStub) , stub. init( ... )创
初始化了
c )中
core/haindsml.g Se
件
收到(
(.
接收到
口 ew
h )中
ectransio.g
端 事
步( 和
行结束
ShimHandler beforlnit
21
theCaincodSupr.Ex
( ShimHandler
的设
e r Handler
ServHandl
的
Support.Launch (.)执 24
把第
ute
c h aincode
。
r Handler
-Exec
Serv
消息,开始了注册的过程
e xample02
Launch
( b )中的
6 章
),调用了
:=
消息
S himHandl
t 接口,可以定位到
e r
exampls/
chaincode / go / chaincod e _ exa mp 1e0 2 / cha inc ode _ e xa mp 1e0 2 . go 的工
nit(sub
) 。
获取了
stub
b, 20
中的
( c )在
args
,分别
I n it( stub
中包
看作
含
a 账
[]byte (strco
似于第
的,所提交
14
key
过
步
是
A
交易模拟工具在
,只不 的账
户名
,
value
core/
并
hain
返回
,
的
进入
易
的读
A
和 的
中的
着
(.)也
写集(
的链码数据
这里
,此 的读集里面没有数据),然后返回至
。
Serv
Handler
收到 后通
... ) 结束等待 。
core
继续返回至
至
此,
第二次进行的
/ endo rse
si
步中
ex
ample02
是由第 的
13 写集人的
步中
/ endors.
mulateProps
LSC
()中
的写集入 N
Procespal(
/
it(sub)
Execut(
返回至
提交到
c ore
(),
,
巳通
然后返回到
txsim.GeTSulaonR
主要是写集中的数据
ChaincodeDt 作
分支执行
。
。
随之返回 。
key-valu
handler.cI
消息
Execut
步
exampl02 中
中
_ COMPLETD
18
都是
写集) )中,随
age
ShimHandler e nterBusySa
步中的
handleit(msg
( ... ),对应第 nil
100 ,
,之后
对
13
部分执行完毕,开始返回
!=
a,
[ ]byte ( strconv.
余额,最终也是将这一 的
同第
巳 Mes
on.g
txsim
数
r . handlePutS
中的
calChinode if
le
code/hain_suprt.g
Launch-Execute , Execut go
是
写集(
C haincod
exctransi
, 参
stub.PSae(A,
hand
/ handler.go
的
知
据,当前操
的
incode
发送
然后使用
ServHandl
chainode/smlr.g
defr
。
int
tub. PutState (B,
过这时使用的
的 ,触发
s
ShimHandler
core/ha
结束
2 0
c 指定的函数
。
exampl02:nothrvsi 的
户余额
)和
将触发
9 ~
b 账
的初始状态提交
25 ) stub. PutSae 类
,
Itoa (Aval 户
GetFunct i onAndParameters () 即,
10
)将两个账
的过程
stub.
函数和所用参,
户余额
且 v.
Itoa (Bval
的
)中,首先
中
B
的
获
,
取了交
e xamp
l e02
两个账户的状态数
.. .)中
,这里罗列
一
下
•!•
138
H y pe
巾
dg
e r Fabri
c 源代码分析与深入解读
e . simulateProposal( ... )返回的数据: 返回结果
Respon
c d 为
,成功的结果中包含
exampl02
空
的
;
易的读写集(即目前所进行交结果)
ChaincodeMsg
_COMPLETD
为空(
core 空,
/ chainode
/ shim/andler
将继续执行 为
消息时所
e.ndorsPpal(
tesc
hain
res/
; txid
,交易
ID
只包含 26
)在
一
sec
的名字
LSC
似于
和版
的
的 为
Headr
字
的成功返回结果;[
值为
1.0
要
)在
calChinode
到
6.1
,这里
:
ctx
不为
; chainID
,值
Propsal
; cd/
和
空
;
个供
ESC
hdrExt.
使用的
CIS,
a )确定要使用的进行背书 数据,生成一个
巳 cis
Args
的值
; [ 3 ]口 byte
byte
:[
含
空
0 ]函
格式的
格式的包
;[
,这个作用
c
数名 id
exampl02
空
,这个
的
7 ] paylod
,为 c
;
id
的
ChaincodeDt
的权限控制,为
空
后边的背书过程中所用到数据均来自于此
。
Launch
过
。
6 步,只不过这期间 的
In
voke
()方法对
exampl02
28
)在
此可以与第
程查看 使用的
步(
6.13 是
,
( c )调用
ESC
Invoke
,传入
e Propsal
接着返回至
中的
Procespal
(),
e. 至此,
Proces 中
的
的构成 Endorse
cod
巳动作
Signature
。
( c )成员
是在
事
儿
,产生了什么后果包含的有:
e /
签 步的(
c ) 。
()全部执行完毕,返回的数据 PropsalRen
,且该
ChaincodeDt
。
Endorsemt
PropsalRen
,包含了节点的
, []byte Propsal
cor
/
中的值, 26
的
Paylod
以及晗希过的 即谁干了什么
stub
/ sec
自此一路返回,过程省略直接定
生成的
1 。 ( b )成员
ChaincodeAt ,
core
Args
osal
exampl02
用到
中的每个值都解压出来,在
巳 PropsalRen
,明确版本固定为 签名
格式的
rop
被赋值为
Version
和签名者的 byte
Creat
Respon.Payld
: ( a )成员
到 的
一直对
最后调
callChaincode ( . . . )执行完毕,对应第
prots/uilx.g
PropsalRen
直接定位
。 ( b )根据解压出来的 。
,
中
。 Args
名并整理应答数据,最后返回这个里不再详述 endors
后 ,
Invoke
: ( a )分别将携带的
会
5 步之 Handler
中生成的
b )处的对照,看都是哪些数据
第
的两个
handleTrsctio
事
Launch
节 。
的
中,只做了两件
26
过程,且
的交易结果进行背书 的
Invoke
Launch-Exet
中途的过 一直
chaincode/ shim/andler.go
chain
最终返
件
Propsal
体过程如下:(
Paylod
escc / endorser onevalidsgtur.
个
参数
是生成一
一次
已经被
节的第
ESC 的是
包含[]
定义的事
为
CIS,
中,这次只会执行
ESC
是
时
交
。
途返回,因为
位到
的
做的就
具
; [ 4 ]口 。
27
看
主
6 ]事件,为
前版本对这个字段并没有使用
call Chaincode
exampl02
chainID
S igned
和图中的
5 ] 交易读写集数据;[ 当
署
,
继续,由于
该函数
和准备的 的
时的
。
( b )根据参数
creatCIS
version
段
,
; [ 2 ] Propsal
LSC,
。
应图中的
。
。
中的
[ 1 ] Propsal 值
Name
来执行背书
本号
ExecutChainod
pl 巳 02
hdrExt.PayloVisb
l Chain code
ESC
exam
中
下传入
对
... )中 ca
Name
/ pro
endorsPpal(
然后通过再次调用
部
中) 一
; signedProp
个值为
LSC
le Transctio
均为上文返回的数据;
Chaincodel
类
hand
部署
ChaincodeStub
...),在此罗列
/ simulatonReJcv
的
的
LSC
; simulatonRe 为
携带的
. go
为
ChaincodeDt
; cevnt 回
res
。
格式的
签名者
PropsalRenyd,
ChaincodeAt Chainco
相当于在描述 del
一 里的数据
第
是
LSC 了
和
1.0
,
exampl02
的
集,
Events
样的
个
数据是
LSC
C haincodeDt
为 一
Respon
空
,
。
( 4 )一
个
Result
被
的 返回
时
含了
LSC
部
Respon,
给
Paylod
per
继续
Propsa!Ren
执行,
生成“ comn
. Envelop
。
据的过程
res
,其
中
Paylod
包
含
的
的
读写
ChaincodeDt
/ instae
。
. go
完毕
139
后两条链码
exampl02
的
instae
这 中
,
。
utils.CreaSgndTx
一封
〈-
exampl02
为
/ chainode
o d e 的设计与实现
返回的
署完
cf.EndorserClient.ProcessProposal( .. . )执行
” ) instae
c h a i旧
exampl02
则包
Suces
Propsa!Ren
部署
6 章
,
结合
Propsal
,返回的
信
Envelop
数据
的封
装
过程
是一
个
具体数
据到
被一层 包
装
进
一
个
通用
数
。
广播
6.12.4 在
per
/ chainode
/ instae
. go
instantiate(cmd,cf )返回的 进行广播
E nvelop
的
紧接
chainodeDply
中
着被
,
env,
err
:=
cf.BroadstClienS(v)
。 per
命令
Client
, 象其
对
的广
封
实
是
播客户端
为在
装了一
个
grpc
连接
ordeing
口
个连
中
服 务客
com
.go
接在
一
个
e nt . pb.go
。
/ comn
和
AtomicBradsC!
orde/ab 端
per
户
中的
定义)
端
在
命令执行
, 散播
件
中心
之 接
初就
收,
程 后,
可 的
已
自
:即
此
数
据
orde 网
e nt
客户
端对
象(这 prots
知,这是连接
orde
,若未指定
则
向
cs
个
服
是在
务
per
cc
/ 的
客
户
/ comn
发送请
求获
/
取的
。
这
。 ) 将巳
nv
交给了
发送
到
orde
服 务 将
最终提交到
tCli
broadcst
s t 流客户端,在
,通过
经被建立
中的
as
Broadc
名就
指定
( env
只 讲大概过
/ serv.go 。
数 据排 节
o rde
服务中进行处理
env
络中的每个
了
序后发送给
per
点的链(账本)上
的
由于涉及
orde
节 点 的
go s sip
服
服 务 开
。
部署后的状态
6.12.S 部署后的状
态分为
口巳
以
xample02 口
的
exampl02
的证书
D exampl02
几种:
数据被放入交易模
镜像被
,可
创
执 的
建
镜像
的
上下
文
包
含
器
的
写集中
。
Dockerfil
文
件,
通
过
tls
连接
p e er
节
。 创
e r 通 的
,
拟
行程序压缩包 容器被
ServHandl exampl02
下
ChancodeDt 的
点
口
文
,即
Chain
Broadcast (.)处 播
分
GetOrdEnpoi~f
instae
务,这里
一部
的
命令行
cf.BroadstClienS
始散
_ Broadc 的
从所
是
e nt.go
AtomicBrads
客户端
。
的地址
/ ordecli
信 Serv
Chaincodes . chainodeMp
建
,
单独运行
ShimHandler
,并通
过
g 叩
c 与
per
节
。 Handl
er
在
p er 中
节点的 进
行了注
the 册
C hain 。
co
deSu
p port.
r unig
点
中
•!•
140
Hyperledger Fabric
D exampl02
的
源代码分析与深入解读
D exampl02
ShimHandler
和
指定的{
户余额
1 『 Args
10,
exampl02
B 部
Serv
Handler
”:[
账户余额
20
int
署的数据通过
均处于
'『,”
a ”,
orde
服
务
排
服务和
gosip
服
chainode
6.13
务要
做的
拟器的
序后散播到网络 部署
exampl02
『?]},即
写集
中
的各个有
效 本身做的
A
。
节点中并
最终提
事情,只是会促成
。
建资产(键值对)的基本范
例
。
选择一个代码存放位置
6.13.1 首先需要确保
Go 为
20
操作步骤
本节是一 个在账上创
chaino de
语
言
已
经被完整安装
到系统上
应用创建一个位于
使用如下指 mkdir
事情)
。
’' b ",”
/
易模 per
orde
状态
” 100 1l
,这两个状态被放入交
交到各自的链(账本)上这一点其实不是
的
ready
$GO
令
PATH
。 /src
/目录下的子
。
:
『 p $GOPATH/src/sacc && cd $GOPATH / src /sacc Now, let ’ s create the source file that we 『 1 fill in with code:
使用以下指令创建源文件
:
touch sacc.go
内务处理
6.13.2 首先 别是
,进行内 In
务
it 和
Invoke
函
shim packge
和
package 工 mp
处理 数接口
per
mai
。
对于
每一 。
protobuf packge
个
所以首先为
chainode
,都会实现预定义的
chain
chainode
引人必
要
的依赖
。
在
code 此引入
。
口
( ort
” fmt ” ” github
.com/hyperldgfabi
工 ncode/shim
"
"github.com/hyperledger/fabric/protos/peer ”
初始化
6.13.3 实现
Init
函
chainode 数
。
I I Init is called
dur 工口g
chaincode instantiation to initialize any data.
chainode
接口,特
账
〈- 的设计与实现
ch ain code
6 章 第
fu n c (t *Simp l eAsset) Init(stub shim.ChaincodeStubinterface) peer . Response
In 函数来获取
. GetSringAs erfac
巳 Stubln
C haincod 。
检查
。
I n it ”方法 初始化的东西,则提供一个空“
调用
chai 升级现有
cod
特别地,如果没有“迁移”操作或其他需要在升级中 。
函数 Init
f 参正 需妥确保适当
c h ain 当编写的
。 函数
ifoj JfJ i i'-
级同样 1t-
chainode 。主
it 所需的参数,并进行有效性
。 本例的传入参数是一组键值对
II II II II
any 工 ze 工 al Init is called during chaincode instantiation to int data. Note that chaincode upgrade also calls this function to reset or to migrate data, so be careful to avoid a scenario where you inadvertently clobber your ledger ’ s data! func (t *SimpleAsset) Init(stub shim.ChaincodeStubinterface ) peer Response { proposal 工 on II Get the args from the transc args := stub GetStringArgs() i f l en(args) != 2 { return sh 工 m Error (” Incorrect arguments Expecting a key and a value")
。 将初始状态存入账本
r.Respon
pe 常,会收到表明初始化成功的
inc Cha
调用
返回对
象
如果一切正 。
并以键值为参数传入 erfac
o deStubln
。
II Init is called during chaincode instantiation to initialize any II data. Note that chaincode upgrade also calls this function to reset II or to migrate data, so be careful to avoid a scenario where you 11 inadvertently clobber your ledger' s data! func (t *SimpleAsset) Init(stub shim .Cha incodeStubinterface) peer.Response { II Get the args from the transaction proposal args := stub.GetStringArgs() if len (args) ! = 2 { Expecting a key and a value " ) . 口 ts return shim .Error ( ” I ncorrect argume
II Set up any variables or assets here by calling stub.PutState() II We store the key and the value on the ledger err: = stub.PutState(args[O], [Jbyte(args[l])) i f err ! = ni 1 { to create ed (" Fail 工 n tf . Spr return sh im .Ero(fmt return
s hi
m
.Suces(n
工 1)
aset
:
辛S
”,
args
[ OJ))
141
•!•
142
H y perledger Fabri
6.134
调用 添加
i卖
chainode
Invoke
/工
c 源代码分析与深入解
函数签名: is called per transaction on the chaincode. Each transaction i s
nvoke
II either a ’ get' or a 'set ’ on the asset created by Init function. The ’ set ’ II method may create a new asset by spec 工 fy 工 ng a new key-value pair. *S
func (t
类
工 mpleAst
似上述
In
)工
it
函数,
nvoke(stub
sh
需要调用
工 m.Chaincode
来获取参数
chainode set
先调用
和
get
peer.Response {
C haincodeStubrf
数所需的传入参正是应用想要调 能函数一-
Stubinerfac)
的名称
。
工 nvoke
函
在本例中,只有两个简单的功
:前者允许对资产的数值进行设定,后获取当状态
。
ChaincodeStublrf
. GetFuncioAdParms
数名与参
。
来获取
chain
cod
巳应用所需的函
。 II Invoke 工s called per transaction on the chaincode. Each transaction is II e 工 ther a 'get ’ or a 'set ’ on the asset created by Init function. The Set II method may create a new asset by specifying a new key-value pair. func (t *SimpleAsset) Invoke(stub shim . ChaincodeStubinterface) peer.Response ( II Extract the function and args from the transaction proposal fn, args := stub.GetFunctionAndParameters()
使
set
与
Suces 列化为
或
get
这两个函数名正式生效,并调用些
chain
gRPC
shim.Ero protbuf
函数返回一个合理的响应 消息
这两个
shim
应用函数,经由
shim.
成员函数可以将响应序
。
II Invoke is called per transaction /巳
。
code
o 口 the chaincode Each transaction is a 'get' or a 'set' on the asset created by Init function. The Set II method may create a new asset by specifying a new key-value pa 工 r. func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubinterface) peer.Response ( II Extract the function and args from the transaction proposal fn, args := stub.GeFnc 工 onAdParmets ()
ithe
r
var result stri 口 g var err error i f fn ==” set" { result, err= set(stub, args ) } else { result, err= get (st ub, args) if err != n 工 1 { return shim.Error(err.Error())
II Return the result as success payload return shim. Success ( []byte (result) )
第
实现
6.13 .5 此 注意,
chain
chainode
和
cl 山
ncod
e 的设
计与实现
•!
143
应用
code
应用
就像上文
6 章
一
实
现了两个函数,
并
样,通过调用
可以被
chainode
ChaincodeStublrf.G
Invoke
函
shim API
数调
函数来访问账本
中的
用,下面将实现这些函数
。
ChaincodeStublrf.P
。
II Set stores the asset (both key and value) o 口 II it wi ll override the value with t he new one the
ledgr.
the key exists,
工 f
fun c set(stub shim. ChaincodeStubint er fac e, args []string ) (string, error) { i f len(args) !~ 2 { r eturn H ” , fmt Errorf("Incorrect arguments Expecting a key and a v alue ” )
err:= stub.PutState (args[O],
[]byte(args[l])) err != nil { return ””, f mt.Errorf( "Failed to set asset
工E
return args [l
],口
%s ” , args[O ] )
il
II Get re turn s the value of the speci fi ed asset key fun c get(stub sh 工 m .ChaincodeStubinterface , args []string) (str ing, error) if len(args) != 工{ return ””, fmt . Errorf (” Incorrect arguments Expecting a key ")
value, err:= stub.GetState(args[O]) if err != n 工 l { return ”” , fmt.Errorf("Failed to get aset
:
with
毛s
ero
:
辛 s ” ,
args[
err)
O ],
i f value == nil {
return
””,
fmt.Errorf
(” Asset
not found
:
毛 B ”,
arg
s
[O])
return string(value), nil
整合全部代码
6.13.6 编写
main
函数,它将调用
s him.Star
函数
。
下面是包含
整
个
c h aincode
package main 工 mp
ort
( "fmt"
” g it hub com/hyperledger/fabric/core/chaincode/shim ” "github.com/hyperledger/f abr ic/pro tos /peer"
II SimpleAsset implements a simple c haincode to manage an asset type SimpleAsset st ruct {
程序的代码
:
144
•!•
Hyperledger Fabric j 原代码分析与深入解读
II !nit is called during chaincode instantiation to initialize any II data . Note that chaincode upgrade also calls this function to reset II or to migrate data func (t *SimpleAsset) Init(stub shi m.Chainc odeStubI 口 terfac) per . Respo 口 se { II Get the args from the transaction proposal args := stub . GetStringArgs() if len(args) != 2 { return sh 工 m .Error( "Incorrect argume 口 ts Expecting a key and a value ” )
II Set up any variables or assets here by cal
工口
g
stub PutState ()
II We store the key and the value on the ledger err:= stub.PutState(args[O), [)byte(args(l])) i f err != nil { retu 口 shim.Ero(ftSpn (” Failed to create retu
口
shim.Suce(nl
aset
:
每s
”,
args
[OJ ))
)
II Invoke is called per transaction on the chaincode. Each transaction is II either a ’ g et ’ or a 'set ’ on the asset created by !nit function. The Set II method may create a new asset by specifying a new key-value pair . func
(t
吃工
mpleAst)
Invoke(stub shim.ChaincodeStubinterface) peer.Response {
II Extract the function and args from the transaction proposal fn,
args := stub.GetFunctionAndParameters()
var result string var err error i f fn =咆 et " { result, err= set(stub, args) } else { II assume 'get' ev 口 if fn is nil result, err= get(stub, args) i f err != nil { retu
口
shim.Er
ro(e.E)
II Return the result as success payload return shim . Success ( [) byte (result) )
II Set stores the asset (both key and value) on the ledger. If the key exists, II it will override the value with the new o 口 e func set(stub shim.ChaincodeStubinterface, args i f len (args) ! = 2 { return "" , fmt Errorf (”工口
err := stub.PutState(args[O),
coret
[)string)
arguments
[)byte(args[l)))
(string, error)
Expecting a key and a va
{ lu
巴”
)
第
if err !=且 il { return "”, fmt.Err orf ( ” Fail ed to set
6 章
c h a incod
aset
:
毛 s
e 的设计与实现
”,
ar
•!
145
gs[O])
return args[l], nil
II Get returns the value of the specified asset key f unc get(stub shim.ChaincodeStubinterface, args []string) (string, error) if len (args) ! = 1 { return ””, fmt.Errorf (” Incorrect arguments. Expecting a key ” )
valu
巴,
er
=
stub.GetState(args[O])
i f err != nil {
return ”” , fmt.Errorf (’' Failed to get 工E
aset
:毛
s
value =口 il { return ””, fmt.Errorf (’' Asset not found :毛
return str
ero
with
s ” ,
:告
s ” ,
args
[0] , err)
args[O])
nil
工 ng(value
),
II main function starts up the chaincode in the container during instantiate func main () { if err := shim.Start (new(SimpleAsset)); err fmt . Printf ( ” Error starting SimpleAsset chainode
编译
:毛
s ” ,
er)
chainode
6.13.7 编译
{
!= n 工 l
chain
code
的代码如下:
go get u tags nopkcsll github .comlhyperledgerlfabriclcorelchaincodelshim go build --tags nopkcsll
成功
则可以进
行下一步:测试
通常
,
chain
可以由用户
code
创 chain code
orde
如果你之前还没有进行过这
由
建井启动
。
per
节点启动并维护
。
安装
chai
、 。
c h ane
不过,在“开发者模式”下
当用户处于以快速编码、构建
开发阶段时,该模式十分有用
和
6.13.9
d 巳 。
在开发者模式下测试
6.13.8
的
c h ainco
l 来启动“开发者模式”
一
Fabric
运行、调试的循环周期为主
这样,用户可以
立
即编译
chainode
并调用函数
样例 步,请先安装
e
借助构建自带区块链样例网络时已经预先生成好
。
Hyperldg
ncod
Hyp
巳 rledg
Fabric Samp
le 。
下面进入到安
。
•!•
146
装好的
H yperledger Fabric
源代码分析与深入解读
fabric-smple
下的
cd cha
下载
Docker 的
模式”成功运行
。
·~
你选
构
建脚本
,我们
需要
四个
。
,那
镜像来确保“开发者
克隆仓库,并按照指示下载了
么你的本地理应早已安装好了所需
Docker
择手动拉取镜像,那么务必将其重新
images
Docker
f abric-smple ar ies
如果
Docker
如果你已经安装了
platform-secibn
-
录
镜像
根据下载样例中自带
洼
目
工 ncode-krvm
6.13.10
”‘
chainode-krvm
标记为
指令可以方便地查询本的
Docker
镜像 lates
镜像列表
。
。 。
输入
docker
你应该会看到类似下面的
内容: docker 工 mag es REPOSITORY hyperledger/fabric-tools hyperledger/fabric tools hyperledger/ fabric-orderer
hyperldg/fab
工 c-orde
re
r
hyperledger/fabric - peer hyperledger/fabric-peer hyperledger/fabric ccenv hyperledger/ fabric-ccenv
@
善女口果你通过
downla 像资源列表
” platform-seci
。 录
6.13.11
IMAGE ID
TAG latest x86 64-1.0.0 latest x86 64-1. O. o latest x86 64-1. o. o latest x86 64-1.0.0
缸-
。
独
立的
终端
CREATED hours ago hours ago hours ago hours ago hours ago hours ago hours ago hours ago
SIZE 1. 32 GB 工 .32 GB 179 MB 179 182 182 1.29 1.29
MB MB MB GB GB
bin
不过这里我们只关心以上四个
下打开三个
4 4 4 4 4 4 4 4
e09f38f 8928d e09f38f8928d Odf93ba35a25 Odf93ba35a25 533aec3f5a01 533aec3f5a01 4b70698a7ld3 4b70698a7ld3
现在请
c haincod
e-dockr
-d ev
mod
e
。
目
1 号终端
执行如下命令: docker-compose -f docker compose-simple yaml up
上述指令启动了
一
“开发者模式”下启动 是
个带有
。 CLI
命令行
,可
容器中,所以我
们下
与
6.13.12 执行如下命令:
2 号终端
Si ngl
mpleMSPord
profile
它还启动了另外两个容器:
一
c haincode 面马上
eSa
进行 跳转
到
交互 chainode
。
创 调用
建并加入
个包含
chainode chanel
部分
。
的网络,并将节点在
(管道)的指令
运行环境;另一个 内
嵌于
CLI
第
docker exec
-工 t
cha
6 章
chainode
的设计与实现
·:·
bash
工 ncode
执行完上述指令后,你应该会看到如下内容: root@d2629980e76b: / opt / gopath/ src / chaincode#
(此时已经进入
chainode
容器)下面编译你的
chain
code:
cd sacc go build
现在运行
chainode:
CORE_PEER_ADDRESS=peer:7051 CORE_CHAINCODE_ID_NAME=mycc:O ./sacc
chainode t9.\
被
注现阶段
per
节点启动,
chain
一
实现
chain
code
code
还没有与任何
日志表明
per
chanel
关联
。
节点成功注册
。
这会在接下来使用
instae
指令后
。
3 号终端
6.13.13 即便处于-
per-chainodv
这样生命周期系统
模式,安装 chain
chainodev
code
chainode
模式中省去
才能正常进行检查 。
。
下面进入
CLI
这一步仍必不可少,
容器进行
也许这一步会在日后的-
- per chainode
调用
。
docker exec -it cli bash peer chaincode install -p chaincodedev/chaincode/sacc -n mycc -v O peer chaincode instantiate -n mycc v O c '{” Args": [吐”,门。叮)’- c myc
现在执行一次将
a 的值设为
20
的调用:
peer chaincode invoke -n mycc -c ' {吐
最后查询
a 的值,会看到
20
6.13.14 重启网络来轻松地测试它们
虽然只实现了
测试新的
”.[咀
et
”,吐吃。
l}'
C myc
。
n mycc -c
peer chaincode query
rgs
’ { 咀
rgs
”:
["query ”,
sac
chainode ,不过可以通将同的
。
chain
重启它们将可在
chainode
code
容器中被访问
添加到
chainode
。
子目录下
147
............. ……·· ...... ..... . .. ... .... . .. • 11
7 章
第
’配~万
汇 fN'"t-
成员服务提供者 MSP
中的 Fabric
)等在
imp lementations, and the sign, verify, authenic
( cryptogahi 认证
签名、校 、
作 密操
加 解
) 理
Service Providers ( MSP Membrship
地 本章将让你更好
验、
虑的地址方 主要考
为 密
私和机 了隐
现
) 。
a rios
s sc 巳n
a dres 案(
实 助
,帮 对
配 相
存在与能力 的
c h anel 的概念,与
” 权
“授 的
Fabric
这个 。
和支配 作
)被操
channel lev 层级频道(
) 和 network
broade 络(
网 广域
在 制可以
控 权限
结果,数据 。
户或客端的应用 用
终端 ,
成 构
于组织、网络的 用
这些被试
( cryptographic certificates ), 书
密证 加
)被用来生成
Key Infrastuce Public
P 阻, 设施(
础 基
公匙 。
础 为基
以此网络 络,并
网
份 的交易 身
个明确 一
有参与者都 个所
提供一
F abric
。 应用
的设计思路 MSP
7.1
验证书和
) 、 isung
论( 争
的
认 成和
生
签 名的 规则,以及
份标 识、验证 的一套身
己 定义它自
可能
在 存
藏了
。 个组成部分
一 作为系统的
象, 的抽
架 作构
机制和协议,隐 密
有加 了所
象
操
证
。 方法
区 Fabric
不
MSP 一个
。 证
用户认
抽 MSP
别的, 特
系 会员关
个 一
供 于提
着眼 个
是一 MSP
。 实践细节
的 安装上最好
的 MSP
于
供关 于提
力 本章着
下文
我们将
详 细介
绍
工 间协同
架 系标准和构
会员关 同的
MSP
的
操作
管 MSP
个 或多 个
被一 会
域链网络可能
员 会
块化的 模
供了 提
理,他们
。 作的能力
体系,并
讨
论关于
MSP
方面
的
实
战
练
习
。
操
作和
在
第
7.1.1 MSP
MSP
,它的配置文件必须在每个
per
的本地中被指定,开启频道上
成员服务提供者
•!
149
per
、
orde
和
orde
(去使能
per
并排序签名)
町、客户端的身份认证,以及所有会员各自
。 首先,
MSP
需要指定一个名字在网络中代表自己,如
mspl,org2
员关系规则中代表一个
chanel 对象的
ID ID
MSP
配置
为了启动一个 签名认证
7 章
的
中的 一
( MSP Identifr
MSP
) 。
个共同体、组织或者分部
每个
。
。
MSP
实例存在于系统初创的
MSP
等
的
chane
ID
是唯
l ,
一
orde
的
。
这个名字在其会
也被引用作为
MSP
例如,若检测出来存在两个相同
将会启动失败
。
在默认操作的情况下,一个参数集合需要被指定(也就是
MSP
员),用于身份认证(
identy
些参数由
RFC5280
/ certifa
巳 validton
)和签名认证(
需要哪些成
signature verifcaton
) 。
这
指定,包括:
口一个自己签名出的证书(
sel
of trus
巳 signed
)列表,用于作为信任机制的根证书(
rot
,这个根证书应该是:把自己签出来的分发给他人拿着核
对时,在根证书列表中查询核如果存于这个则说明人是受
信任的)
。
0
该列表可以用
rot
CAs
表示
。
考虑到证书验,提供一个用于代表(作为)中间人
CAs
这些
CA 数)
。
口一个
证书应该是在
rot
该列表可以用
中被鉴定过的
intermda
X.509 向
of trus CAs
表示
rot
of trus
中的证书
。
中间人
CA
证书列表
表可以用
a dminstrao
CAs
一个组织单位列表,
MSP 的配置(即改变
表示
MSP
证书是可选的(参
OU
。 CAs
、中间人
CAs
有效的成员应该包含在这些组织单位
X .50
。 rot
该列表可以用 CAs
OU 或
TLS
口一个用于
的
TLS
对于一个
MSP
intermda
。
CAs (废除
的
X.509
根证书列表(
X.509
self
中间人证书列表
- signed
该列表可以用
。
这是一个可选参数
(X.509) certificates, TLS root of trus
) 。
。
对象实例来说,有效的身份需要满足以下条件:
格式的证书,并包含可验所在路径该对应到
rot
口不包括在任何一个
CRL X.509
表示
。
口一个用于
口在
这
并为组织
List
。
X.509
该列 。
巳 CAs
的证书也是从这里面来,而不凭空产生)一个可选参数
口
) 。
9 证书中
CAs, intermda
字段时,才会使用这个列表
一个废除证书列表,每都可以对应到
表示
这些证书的
。 rot
成员保留了一个
管理员的角色 rot
是一个可选配置参数,当多组织使用同
CRLs
。
。
所以该证书列表代着 MSP
Q
X.509
证书列表,该中的包含可验路径而这些对应指
拥有者被允许发起请求改变该 0
。
证书的
格式的证书结构体中
中
CAs
。
。 OU
字段里,存在一个或多属于
OU
List
的组织单位
。
•!•
150
Hyperledger Fabric j 原代码分析与深入解读
更多的
MSP
身份的有效性信息,
请阅读
除了验证相关参数,对于
M
用于节点签名的匙( M 注意的是,
SP
MSP
废除
TLS
的
MSP X.509
),
参数中(
当前只支持
rot
EC CAs
DSA
和中间人
keys
CAs 加
入到
。
节点的
X . 509
中)的有效证书
C RLs
。
证书,
中
。
此
需要重点
外,当前不支持强
制
证书和官们的签名匙 证书去填
不支持证书中包含
MSP
RSA
替代
keys
的配置,我们可以使用
c 叩
巳 dger
opensl
。
这里强调一下,
Fabric
。
,我们可以使用
Hyperl
Fabric CA
ptogen
tol
,
在
这个项目也可以用
Geting
Stared
来生成
M
SP
中
有详述
。
配置所需的
keys
和证书
。
MSP setup on the peer & orderer side
为了建立本地
MSP
目录,如
$ MY
CAs
2. caerts
还
是
orde
上的,
管理者都要
创
建一个
含如下子目录和文件:
pem
录,
3. (可选)
文件,每个
包含
每个
的
pem
pem
intermdacs
目
4. (可选)
config
5. (可选)
crls
.y aml 目
6. keystor
对
应一个
文件对应一个
rot
录,对应中
adminstro
证书
间人
文件,包
CA
证书,即
含
OU
相关的
CRLs
,
即 的
信息
rot
CAs
。
。
含关于组织单位
录 ,包
目录,包
。
。
含一个有节点签署密匙的
PEM
文
件;我们
着重于当前不被支持
。
7. signcert
目录,包含一个有
8. (可选)
X.509
tlscaer
9. (可选) 文件
,包
per
。
目
秘钥
),无论是
/ mspconfig 目录,包含
administrator
RSA
( local MSP
_PATH
1. admincerts
PEM
。
。
为了生成
7.1.3
Identity Validity Rules
:
息永不消失,只能被
如何生成
作为
列
中的身份信
的证书
7.1.2
一些
SP
来说,使节点能够去签名或授权你需要指定
signing key
该证书必须是在
的
SP
M
目
录,
包含与
整数的
TLS
tlsinermdac
目
PEM
根
CA
文件
证书
。
一对应的
录,包含一些与中
PEM 间
TLS
CA
文 ’ s 证书
件
。 节
点一对应的
。
7.1.4 Channe l MSP setup 在系统初创的时候,出现网络中所有 被指定过(
MSP 即必
一 CAs
下,
MSP 、 OU
须已经存在),并被包含到系统
的验证元素(即各种书、配置)都需要
验证元素由
c hanel
List, CRLs
组成
MSP 。
身份标识( 在
MSP orde
进行体系解析时,统的
identfr
的创
) 、 rot
世纪块(
gens
C 挝、 创
intermda
i s block
世纪块被用于
CAs
)中
。
、 admin o rde
回忆
第
据此
orde
建
被允许去认证
chanel
chanel
l 的
的
MSP
)的
如果创世纪块包含了两个相同身份标识的
l 的创世纪块中
。
l 之前,保证包含在该
chanel
配置信息的正确性是应用责任
configtxe
工具(
的验证元素(如
rot
configtxgen tol CAs
、中间人
CAs
c hanel MSP
中的
上的
一个 MSP
Admin
CAs
如此之后,被
,包括该
MSP
相
中的一员(即拥有
admin
chanel
时
,通过将
MSP
专用的配置目录,并在
configtx.
工具配置该
chanel
的
关的废止证书列表(
MSP
。
CRLs
Admin
config update object
更新
创建一个或多
的创世纪块(或者是最新配置)中
等)放置到
MSP
点)创建一个配置更新对象( 。
chanel
configtxe
重新配置一个
配置
我们强调,在
)帮助下引导启动
文件中设置相应的选项,我们可以使用
通过该
钮,
。
当在
ya ml
M
,其验证的各个组成部分也就是(只能)管理该
chane
chane
MSP
chanel
,必须存在于
加入该
151
。
aplicton
per
。
•!• 成员服务提供者
有认证的材料了,如果创
然地,整个网络的引导建立也会失败
对于应用( chane
MSP
orde
该请求)
将拒绝此块,自
个
的创建请求(等于说
的请求合法才通过
orde
7 章
CA
)的公告,
证书的节点,也叫作
ad
),可以实现一个
c hanel
管理的客户端应用将宣布这个针对该
上
MSP
min
MSP
节
的
所在的
重新
chanel
的
。
最佳实践
7.1. 5 本节我
们将 详述
MSP
1 . 组织单位和
配置在一般情况下的最好实践(
MSP
我们要求
MSP
best
practies
) 。
之间的映射 与组织(
organizts
类型,需要考虑如下内容
)之间是一对的映射
。
如果选择一个不同的映射
:
一个组织雇佣多种()
MSP
。
这对应了一个组织包含多不同部门,出于独立管理或
隐私(权限)的原因,每个部门有一
MSP
一个
MS 出其他
P 所拥
子部
的身份 门)分
。
这样做的意义在于,一个节点可能通过
组织中其他的
。
这对应了多个组织以类似的关系被管理成一协作整体 。
per
per
是
将传递组
。
。
这是一个
MSP
下的
定义的颗粒度(
- organiztl 访问权限,如图
per
,而且
granulity)
一个组织有不同的部门(称为单位 chanel
units
7 - 1 所示
) 。
其
。
。 第一
)中(即将所有成员的证书之
MSP
否是属于自己的同一个组织
节点配置的局限
这里我们需要知道的
织范围内的消息给同属与一个
中的任意一个部门可以给予多不同
两种方法如下
中识别
只与从属于该节点的部
,如多个学校组织联合起来成立一盟)的情况 per
P
。 MSP
会忽略这些
只能被
MS
gosip
是,一个组织中的多
ship
per
享组织范围内的数据,而不是与所有成员分
nsortium
和
在这种情况中,一个 一
多个组织使用一 (co
。
有(代表一个层级上的部门),也不能从同
per 门(
代表的情况
种方法:定义
一个
MSP
,将所有组织的成员纳入到该 类的数据纳入到该
MSP M
SP
) 。
该
MSP
的成员关系( 的配置将由
me rot
mber CAs
、
•!•
152
Hyperledger Fabric j 原代码分析与深入解读
中的所有成员)当作是同一个组织内 MSP
节点的本地 gosip
(即 per
中的 MSP
在其本地
会把那些 per
gosip 个限制就是
一 该方法的
。 )策略
endorsmt 的背书(
code
c hain 者一个
)策略,或
/ write read
的读写(
c hanel 一个
的所有成员,该策略可以用于组 OU
获取指定
)被定义为 Polices
策略( 。
OU 组成,会员身份将包括所有的
CA admin
和
intermediate CAs
。 成员,结果也自然会向这些节点传播组织范围内的数据(比如它们状态)
日|… Membership Services Provider
IllPeer
c Global MSPs
10 时 1
囚|叫 关系图 组织 MSP
7 -1 图
,这将涉及每一个部门的指定问题即 MSP
第二种方法:为每一个部门定义
。
中分离客户端 per
从同一个组织中的众多
MSP 一个
门定义 一个部
扩展为每 OU
的 MSP
我们也可以通过使用 。
,但这规避了上一种方法所出现的问题 MSP
里的缺点是要管理多个
orde 而不是客户端或扮演
。 的节点)
。 以下是对该需求的有限支持
创 -种实现这分离的方法是为每一类节点都
的 orde
。
chainode 节点可以限制某些系统 ”请求
admin (终点用户位于请求的起源处)
MSP 。
我们可以绕开这点的前后矛盾,如果接受对于
。 MSP
运行到本地的基于策略
签名的话,
per 。
MSP 依然属于同一个
per 不会被大幅影响,因为同一个组织的所有
客户端类型的
per 实例中,
MSP 到两个
最终,这个组织将会被映射 。
相互作用(交流)了 client
gosip
MSP 节点的
per 义)只使用代表
自然可以与
,而背书策略(定 MSP
该组织应(可以)访问的频道,需要同时包含这两个 。
/ per
一个 的,
一个客户端 一
一 -
CA intermda
的 建一个单独
MSP 的;配置两个不同
per/od 个客户端的,一
“ joinChael
这种 per
在很多情况下,从身份自获取的类型是必要(如背书被担保由
类型的节点产生,
这 。
对应不同的子部门 CA
iate intermd
之 MSP
这样的话,在各个 ,
Certs admin
这就是说,比如不同的 。
重叠 的证书路径 间没有
和 CAs
intermda 、
CAs rot
指定 需要
个部门都
的
例如,果该请求被 将只 per per/od
会执行 的
。 将拒绝该请求
per 并且被请求的
P , MS
定属于不同的
巳 r ,请求源头总是注 pe
很明显,因为请求源头是客户端相较于被的 。
事件注册请求
授权 per
中所处的地位, MSP
点是,基于请求源头在它本地 一
此种方法需要考虑的另
153
。 admin
的 MSP
成员的只能是该 MSP
来说,客户端能成为该 MSP
•! 成员服务提供者
MSP
7 章 第
与其证书
2. Admin
。
: 将管理成员关系的责任从证书验讨论中脱离出来 这是一种通用的实践
。 书都不同
黑名单
3. intermediate CA
将黑名单
操作,我们仅支持第一种方 MSP
当前的 。
中(也就是拉黑) CRL
中加入到 CAs
rot
, CRL
的 MSP
第二种是重新配置 。
目录中移除黑名单证书
对于本地配置,这意味着从
P 。 MS
第一种是重新配置-个不再包含黑名单证书的
intermediatecert CAs
很明显,这里有两种 。
被拉入黑名单: CA
intermda 方法去确保一个
实例手工重配, MSP
重新配置机制(对本地
P 通过
实例的-个配置升级消息)现 MSP
中 chanel
或者通过构建一个
MS 个
置一 正如前文提到的,重新配
证书从
中的证 CAs
intermda 或者
CAs rot
中 SP
M 无二的,与该
一 证书是独
admin 的
MSP
。 法,这种方更简单也不需要拉黑信任的证书
CAs ,但是 止 关于这点来说,不禁 。
这样是为了避免在两种不同类型的证书之间产生混淆 。
来说)需要定义在不同的目录 CA
CAs (相对于中间人 rot
的 TLS
与 CAs
rot 的
MSP
中
TLS 丰日
4. CAs
。 最好在产品中避免
实现剖析 MSP
7.2
的
F abric 员服务提供者,为
中的成 Fabric
是 MSP
各个基础组件提供一系列的身份认证
。 服务
目录结构
7.2.1
D msp 口
comn/lasp
MSP 成员服务提供者(
一 )是
P 可以 MS
一个 。
证书,以及用户认背后的所有密码学机制和协议都抽象了出来
将颁发与校验 MSP
。 个提供抽象化成员操作框架的组件 。
身份,以及的管理(验证)与认生成签名规则
员操作,以及兼容不同成标准与架构的互性
一个
Hy
perldg
er
Fabric
MSP 区块链网络可以被一个或多
。
管理
。
提供了模块化的成
自己定义
•!•
154
MSP
7.2.2 在
Hyperledger Fabric
源代码分析与深入解读
配置
MSP 初始化时
chanel
chanel
上启用 per
必须有独一无二的
节点
、 or 由
ID
在
client
、 orde
签名验证
MS
P 都
的成员管理规则表示一个团体,组织或分工
当具有相同标识符的两个 MSP
实例在系统
c hanel 原始块中被
检测
。 。
一个自签名的证书列表(满足
X .509
口一个用于表示该 MSP
标准)以构成
验证过的中间
信任惊
CA 的
X.509
这些参数推
。
CA
口一个具有可验证路径的 X.509 MSP 的管理员
根
。
CA 和中间
MSP MSP
X.509 :
为它们的成员保留了一个 OU
口一个证书吊销列表(
证书颁发机构(
),这
CA
个可选的 参数 标准)以构成
关注的中间 TLS
信任源的一个证书所认;中间 CA
TLS CA 的
X .509
信任源,服务于 TLS
证书列表
则是可选参数
。
证书
这些证书应该被 TLS
。
证书标准,且具有一条可验的路径(该通往信任源 一
。
口它们没有包含在任何 CRL
中
口它们列出了一个或多
。
MSP 的 OU 区内)
配置的组织单元(列出位是在它们 MSP
口用于节点签名的
X.509
EC
证书,对 MSP
DSA 密
钥) 。
验证参数机制而言是一个有效的身份
身份永远不会过期,它们只能通添加到合适的 阶段不支持吊销
证书结构
可以对已实例化的节点进行签名或认证,需要指定:
签名密钥(目前只支持
MSP
X . 509
。
除了验证相关参数外,为使
口节点的
。
实例,有效的身份应符合以下条件:
X.509
证书)
以及组织
。
X.509
口它们应符合
这是
。
是一
口一个自签名的证书列表(满足
MSP
。
s )的清单,每一项对应于个已登记中间或根
CA provide
证书
当多个组织使用相同信任源、中间
区的时候,会配置此参数
C RL
口对于该
配置的更改要求都是经过授权(例如
的合法成员应该将其包含进它们
一个可选的配置参数,举例子
口一个表示该
。
) 。
口一个组织单元列表,该
MSP
是可选参数
这
证书列表(该路径通往信任源的一个),以示
这些证书的所有者对
CA
。
的证书列表,用于校验
些证书应该被信任源的一个所认,中间
一
每个
,参数包括:
口
注
。
的默认情况下,身份(证书)验与签名需要指定一组参数
RFC5280
~
)都需要指定其配置,并在
的身份验证与各自
节点的启动将以失败告终
MSP
导自
r 节点及 MSP
。 orde
per
进行标识,当
时,该名称会被引用 到时,那么
上的所有节点(
TLS
CRL
。
证书 。
上未被报销 。
此外,现
个
第
1.
7 章
MSP
成员服务提供者
•!
155
cert .g o
cert.go
用于实现
certi
丑 cate
相关结构体
。
( 1 ) struct 包含一个
certifa
结构体:
type certificate struct { as 口 l.RawConte // Raw TBSCertificate tbsCertificate SignatureAlgorithm pkix.Algorithmidentifier SignatureVa lue asnl.BitSr 口g
(2 )
function
判断是否
ECDSA
算法签名的证书
:
func isECDSASignedCert(cert *x509.Certificate) bool
判断证书的签名是
否对应父证书共钥,不
则
func sanitizeECDSASignedCert(cert (*x509.Certificate , error)
解析出一个
*x509.Cert
重新生成签名
: parentCert *x509.Certificate)
工 ficate,
certifa:
func certFromX509Cert (cert *x509 . Certificate)
将
certifa
转换成
PEM
(cert
工 ficate,
error)
格式:
func (c certificate) String() string
将
x 509
.Certifca
格式的证书转换成
PEM
格式
:
func certToPEM(certificate *x509.Certificate) string
2.
configbulde
仁 go
用于初始化
BCSP
,以及
读取
M
SP
文件夹下的各种证书信息,初始化
( 1 ) struct msp
文件夹下的:
const ( cacerts admincerts signcerts keystore in termd 工 atecrs crlsfolder configfilename tlscacerts tlsintermediatecerts
=” cacerts ” = ” admincerts " =” signcerts" = "keystore ” = ” i ntermediatecerts “ =” crls" =” config.yaml ” =” tlscacerts ” = ” tlsintermedia tecerts "
MSPCon
且 g 信息
。
•!•
156
H y p e rl edger Fabric j 原代码分析与深入解读
用于对各个证书中的
OU
t 归
e
Organ
izat
进行校验:
工 o nalUitde
nt
if
工 ersConfiguat
struct {
Certificate string Organizati onal Uni tidentif ier string empty
、 yaml
: ” Cert 、 yaml
:”
ifcat
e
,omi 口
tempy
Organizto
” 、
alUnitdefr,om
” 、
type Configuration struct { Organizatio nalUnitidentifiers 、 yaml
:”
[]*OrganizationalUnitidentifiersConfiguration
OrganiztolUdefs,mpy
”、
( 2 ) function 读文
件: func readFile (f ile string)
读取
Pem
文件:
func readPemFile(file
获取文
([ ]byte, error)
件
夹
str
工 ng
)
([ ]byte , error)
下的一系列证书:
func getPemMaterialFromDir (dir string)
设置
BCSP func
获
配置
( [] []byte, error )
:
SetupBCCSPKeystoreConf ig (bccspConf ig *factory . FactoryOpts, string) *factory.FactoryOpts
取
LocalMsp
获取校验
MSP
配置
bccspConfig *factory.
MSP
FactoryOps
,工
string)
(*msp.MSPConfig, error)
配置:
func getMspConfig (d ir string, MSPConfig, error)
取分层的
MSP
配置
ID string,
sigid *msp. Signdet
(*msp.
工 tyinfo)
:
func GetidemixMspConfig( di r string)
(*msp.MSPConfig , error)
3. idmixmsp.go 身份混合器
MSP
。在某些使用情况下,加密协议来保护户的隐私权非常重要
因为这些协议在签名、认证和传输属性的过程中都是如此
Identity Mixer
D
:
func GetVerifyingMspConfig(dir string , ID string)
获
工 r
配置:
func GetLocalMspConfig (dir string, ( *msp . MSPConf ig, error)
获取
keystorD
实现的,该、混合器具有类似于标准
。 X.509
证书所保的信任模型和安全性
在
Fabric
中,这是通过
第
证,但其底层加密算法可有效提供
高级隐私功
4.
能,如“
7 章
MSP
成员服务提供者
令
不可链接性”和最
小属性披
157
露
。
identities.go
包括了
signdety
实体,代表了一个
识符等,还包括了创建
sign
msp n gidenty
身份实体
,其中包括
一系列证书以及标
的实例化方法以及签名等
。
( 1 ) struct 定义
identy
实体所包 含的属性
:
type identity struct { /工 d contains the identifier (MSPID and identity identifier) for this instance id *Identityidentifier
II cert contains the x.509 cert *x 5 09.Cert 工 ficate certif
工 cate
that signs the
publ
工 c
key of
th
工 s
l 口 stance
II this is the public key of this instance pk bccsp.Key II reference to the MSP that "owns" msp *bccspmsp type
s 工 gnidety
th
工 s
identity
struct {
II we embed everything from a base identity ident ity
II signer corresponds to the object that can produce signatures from this identity signer crypto.Signer
(2 )
function
签名如
下:
func (id *signingidentity) Sign(msg [)byte )
([ )byte, error)
5. msp.go 定义了一系列 t 归
e
MSP
相关的接口:
MS
PManger
、
M
SP
、
Identiy
、
S ignldety
。
MSPManager i nterface {
II
I dent
工 tyDesrialz
interface needs to be implemented by MSPManager
IdentityDeserializer
II Setup the MSP manager instance according to configuration information Setup(msps [) MSP) error II GetMSPs Provides a list of Members hip Service providers GetMSPs() (map[string)MSP, error)
仅供书商业用途或交流学习使
158
•!• Hype
由
dger
type MSP 工肚
Fabric
源代码分析
erfac
与 深入解读
{
II IdentityDeserializer interface needs to be implemented by MSP 工 dentiyDsralz
II Setup the MSP instance according to Setup(config *msp.MSPConfig) error II GetType returns the provider type GetType() Prov 工 derTyp conf
工 gurat
工 on
information
II Getidentifier returns the provider identifier Get
()
工 dentifr
(str
工 ng
error) ,
II GetSigningidentity
retu 口 s a signing identity corresponding to the provided identifier GetSigningidentity(identifier *Identityidentifier) (Sig 口 i 口 gidenty, error)
II GetDfaulSign
工 ngidet
GetDfaulS
工 gni
工 ty
retu
工 dentiy()
(Sig
口 s 口
ingde
the default signing identity 口 t 工 ty, error )
II GetTLSRootCerts returns the TLS root certificates for this MSP GetTLSRootCerts () [] []byte II GetTLSintermediateCerts returns the TLS intermediate root certificates for this MSP GetTLSintermediateCerts ()
[] []byte
II Validate checks whether the supplied identy
工s
valid
(id Identity) error
飞 Talidte
II II II II
SatisfiesPrincipal checks whether the identity matches the descr 工 pt 工 on supplied in MSPrinc 工 pal . The check may involve a byte-by-byte comparison (工 f the principal is a serial 工 zed identity) or may requ 工 re MSP v alidation SatisfiesPrincipal(id Ident ity, principal *msp.MSPPrincipal) error type Ident
工 ty
interface {
II II II II
ExpiresAt returns the time at which the Identity expires If the returned time is the zero value, it implies the Identit y does not expire, or that its expirat 工 on time is unknown ExpiresAt () time.Time
II Getidentifier returns the identifie r of that Getidentifier() *Identityidentifier ident
工 ty
II GetMSPidentifier returns the MSP Id for this instance GetMSPidentifier( ) string
仅供书商业用途或交流学习使
第
II II II II 飞 Talidte
II II II II II II II II II II II II II
7 章
MSP
成员服务提供者
〈-
Va l idate uses the rules that gover 口 this identity to validate it . E.g . , if it is a fabric TCert implemented as identity, validate will check the TCert sig 口 ature against the assumed root cert i ficate authority. () error GetOrganizationalUnits returns zero or more organization units or divisions this identity is related to as long as this is public information . Certain MSP implementations may use atr 工 but es that are publicly associated to this identity, or the identifier of the root certificate author 工 ty that has provided signatures on th i s certificate. Examples: - if the identity is an x . 509 certificate, this function return s one or more string which is encoded in the Subject's Dist 工 nguished Name of the type OU 啕 TODO: For x 509 based identities, check if we need a de 工 cated type for OU where the Certificate OU is proely 口 amespcd by the
signer ’ s identity GetOrganizationalUni ts () [] *OUidentif ier
II Verify a signature over some message using this identity as reference Verify(msg []byte, s 工 g []byte) error II Serialize converts an identity to bytes Ser
()
工 alize
([]byte, error)
II Satisf 工 esPrincpal checks whether this instance matches II the descript 工 on supplied in MSPr 工 ncipal. The check may II involve a byte-by-byte comparison (if the principal is II a serialized identity) or may require MSP validation SatisfiesPrincipal(principal type S 工 gn
工 ngidety
*msp.MSPrinc
工 pal)
error
interface {
II Extends Identity I dent
sn
qdf
S
e
e1
飞,
飞
」
飞
←I』
t
S qd
←」
r Jfpl q4m a eft se nsh my ] b y •L g [ b 工
/
工 ty
er r or )
e
II GetPublicVersion returns the public parts of this identity GetPublicVersion() Ident
工 ty
6. mspimpl.go 包含
bcspm
p 结构体,实例化方法如下
func NewBccspMsp()
: (MSP , error)
仅供
1
商业用途或交流学习使
159
•!•
160
Hyperledger Fabri
上面的代码是在
c 源代码分析与深入解
msp.go
i卖
中的 MSP
接口的具体实现 。
7. mspmgrimpl.go 在 msp
理者
.go 中的
MSPanger 接口的具体实现如下代码所示,是
MSP 实例的一个管
。 type mspManagerimpl struct { II map that contains all MSPs that we hav e setup o r otherwise added mspsMap map[string]MSP
II error that might have o ccurred at startup up bool
8. msp/cache/cache.go 使用了 github.com/lanrpe
性能
中的 lru
cahe 缓存,以此来提高
。
9. msp/mgmt/deserializer.go 对 loca
t 归 e
和 chanel
desrialz 的支持接口如下:
Des er 工 alizersMng 工 nterfac { Deserialize(raw []byt e ) (*mspproto.Serializedidentity, error)
II GetLocalMSPidentifier returns the local MSP identifier GetLocalMSPidentifier() string II GetLocalDese r ializ e r returns the local identity deserializer GetLocalDeserializer () msp.IdentiyDral 工 z e r II GetChannelDeserializers returns a map of the channel desr 工 GetChannelDeserializer s () map[str 工 ng]msp IdentityDeserializer alizers
10. msp/mgmt/mgmt.go 从指定文件夹获取 LocalMsp ,并进行初始化:
func LoadLocalMsp(dir string, bccspConfig *factory.FactoryOpts, mspID
获取 Loca
lMsp
str
error
工 ng)
实例:
func GetLocalMSP() msp.MSP
msp
/ mgt
/ mgt.o 主要是对
msp 文件夹下的其他方法封装
。
11. msp/mgmt/principal.go princal.go
根据不同的角色获取相应实例
用于 MSP
实例获取 。
。 如果角色不存在,则返回零值并相应的
仅供非商业用途或交流学习使
ero 信息
。
第
func
(rn *localMSPPrincipalGetter) Get (ro le string)
12. locamsp/igne SignatureHd
,包括签名的实体
creato
(s *rnspSigner) NewSignatureHeader()
签名消息 func
MSP
成员服务提供者
•!
( *rnsp. MSPPrincipal, error)
仁 go
用于签名,构造 func
7 章
和随机数
(*cb.SignatureHeader, error)
: (s
*rnspS
工 gner)
Sign(rnessage
仅供
[]byte)
二 |二商
业
用途或交流学习使
noce:
( []byte, error)
161
·-·· EB
””-
..... ....····· .... ..... .... .... --
.
u ·I旱
b机 u
-
5 …
h e
u
「’
uv …
’ -
刷牙
vhu
-
QU
Gosip
Gosip
节点间的流言萤语
协议是分布式系统用于保证一致性的 一
种信息(包括区块)的手段
种方式,也是在 Fabric
中传递各
。
Gosip
8.1
协议原理解析
HyperLedger Fabric 通过把工作节点分解为执行交易(背书和提)排序
点来优化区块链网络性能、安全和可扩展 。
可靠 、
用了
可扩展的数据分发协议来保证完整性和
这种解祸网络操作的方式需要 一
一
Gosip 数据分发协议
协议(
节点利用
。 为了满足这些要求,
Fabr ic
应
。
Gosip
8.1.1
致性
个安全、
G osip
Gosip 来以 一
protocol) 种可扩展的方式广播账本和通道数据 。 Gosip 出来的消息是连
续的,并且通道上每个节点都在不断地接收当前来自多账本中已达成一致性 数据 。 每个通过 Gos ip 传输的消息都会被签名,因此由拜占庭节点发送伪造将
很容易地被识别出来,而且可以防止将消息分发到不希望送的目标处 。
迟 、
网络分区或者其他原因的 影
节点因为受到延
响导致缺少部分区块的情况,最终将通过联系已拥有这些
缺失的区块节点方式,与当前账本状态进行同步 。
基于 Gosip
的数据传播协议在 Fabric
网络上执行 三
个主要功能 :
用的成员节点并最终监测离线状态方式,对发现和通道中进行管理
1 )通过不断识别可 。
2 )通过道中的所有节点来分发账本数据
点来标识缺失的区块,并通过复制正确数据进行同步
。 任何数据未同步的节点都可以通过道中其他
仅供非商业用途或交流学习使
。
3 )通过允许点对状态传输更
〈-
i吾 萤
言 节点间的流
Gosip
8 章 第
163
。 新账本数据,使加入连接的节点快速得到同步
的广播由节点接收来自该通道中其他消息,然后将这些转发
Gosi p 基于
为了传播新区块,通道中的领导者节点从排序服务拉取数据并 。
和当前最新状态同步
。 消息
Gosip 向其他节点发送
节点也可以主动拉取消 。
循环重复这个操作,使通道中成员的账本和状态信息不断保持 。
, 而不是等待消息发送 息
的常数 置
这个节点数是可配 。
到通道上的多个随机选择节点
ip
( Gos 输
8.1.2 Gossip 消息传
messaging)
在线的节点通过持续地广播“活跃”消息来表明它们可用性,每条都包含公钥 的 PKI) 基础设施(
)授权的签名 CA
恶意节点无法伪装成其他,因为它们缺少根证书颁发机构( 此
的,因
由于“活跃”信息是通过密码学算法进行签名 。
中被删除 表
点最终将从通道成员身份列
节点通过收集这些活跃消息来维护
个特定的节点收到活跃消息,那么这“死亡” 某
如果没有节点能从 。
道成员身份
。 和消息发送者对的签名
ID
。 密钥
账
。 性,包括对节点崩溃的容错
整 本保证数据的一致性和完
享 的数据传播,因此该流程可以靠地为共
Gosip 于
基 由于不需要固定连接来维护
。 态
异时修正自己的状 差
每个节点不停地从通道中的其他提取区块,以便在出现 。
状态
在每个通道上同步节点间的世界 会
除了将接收到的消息进行自动转发外,状态协程还
。 信息
享 个通道上的节点不能在其他任何发送或共
一 由于通道之间相互隔离,
尽管任何节点都可能属于多个通道,但是过将基订阅的机制作为消息分发策
。 略,节点无法将被分隔开的消息传播给不在通道中 "'
-
。 配的证书进行身份验
与 话将
点 这样本质上使每个节点与相连的
。 成员身份绑定
Fabric
。 与网络和通道中的成员身份关联起来
s si p 之服务组件 Go
8.2
8.2.1 在本节中将分析
。 服务的组件与基本功能
Gosip 在这部分文档中,我们将要介绍
分析 prots/gi Gos
ip
的 模块中的消息类型
仅供非商业用
途或 交流学习使用
的 中
当节,点第一次连接到通道 。
点的成员管理服务提供者进行
讲解
。
账本
2 )认证过程由节 。
中的区块由排序服务进行签名,然后传递给通道领导者节点
。 体现
书 证
TLS
i p 层的身份认证会通过 Gos
节点在
分 CA
节点通过其由 。
层处理,不需妥签名 TLS
1 )点对消息的安全性由节 洼
进行认证,从而
时
候,
TLS
会
•!•
164
Hyperledger F a bric
1. Gosip 在
源代码分析与深入解读
中涉及的消息类型
pr ots/gip
的文件夹下主要有如:
rnessage.proto rnessage.pb . go ex tens 工 ans.go
以及其他一些测试文件 。 mesag.prot
中定义了两个
mesag.pb .go
g 叩
是使用 goprtbuf
G osip gr pc
。 。
Gosip 服务
,
服务所使用到的消息 。
服务处理消息
服务和包含的消息类型
/定义了一个
Gosip
生成的相应代码文件
原型方法的拓展,用于辅助 定义的
c 服务,以及
mesag. rpc
extnsio.g 则是
我们主要分析一下 mesag
pro to
其中包含了两个
类型
.pr
Gosip
ot 中
中包含的内容主要如下:
服务
service Gossip {
II GosipStrean 是用来发送与接收信息的 grpc stream rpc GossipStream (stream Envelope) returns (stream Envelope) II Ping 是用来探测
r e mote per
{}
的存活情况
rpc Ping (Empty) returns (Empty) {}
II Envelop
包括了一个序列化的 GosipMeag
/以及对该信息的 一
信息
个签名
/它也可能包括一个 SecrtE
nvelop
( 一个序列化的 Secrt)
message Envelope { bytes payload =工; bytes signature = 2; SecretEnvelope secret_envelope
II SecrtEnvlop
是 一
个序列化的
=
3;
Secrt 以及对该
Secrt 的一个签名
message SecretEnvelope { bytes payload = 1; bytes signature = 2;
II Secrt
/当
是一
remot
个可以从 Envelop
per 接
收了
中 被忽略的实体
Envelop 且不应
message Secret { oneof content { string internalEndpoint
II GosipMeag
定义了在
=
1;
该知道
Gosip 网络中传送的消息
message GossipMessage {
仅供
二 |非 商 业用途或交流学习使
secrt 的内容时,
per 就将
Secrt
。
忽略
第
8 章
Gosip
/主要用于测试,但将来可能会确保消息传递 ui
口
= l;
nonce t64
/消息的通道 /一些
GosipMeag /
但另
可能会将其置为 一
nil
,
因为它们是跨通道的
些也可能不会
bytes channel
=
2;
enum Tag { UNDEFINED
= O;
EMPTY ORG ONLY
= 2;
CHAN ONLY
= 3;
=工,
CHAN AND ORG = 4; CHAN OR ORG
/
决定哪些
pers
= 5;
可以转发消息
Tag tag = 3; e
JthqdRR tmMEr trs·11 oaeOf cOMvbb neeee neshh /’/’ ’ P leee sap ‘ ’1mm Alee g = Rds sme aup ee ., -mmem MM r er qas - = pb·’”’ 回贝
14eo
vt
--
AU 叶加
bess 、
q
s
企
‘
=
e
-
S
II
m
口
p
Contains a ledger block
包含
一
个账本区块
DataMessage data_msg = B;
句
&
·。
1J14
川出
巾
H川
hddd
ot ltse
saaa
事巾 piep 卜h elDRU
1J1 i p-- ueaaa Joaaa a GDDD Hqdqd eeua - -- 9 sttt .,==• /’/
田 1在
nu
qdq
『 dru
iep aaa 一一-
←L
set
‘『
咱4 14
←」←
--
句,“
e
=
G
L
L
/ 空信息 , 用来 ingp Empty empty = 13;
II ConEstablih
用来建立连接
ConnEstablish conn = 14; /用来中继关于
sta
te
的信息 =工
Stateinf o state info /用
来发送
Stae
工 nfo
mesag
5;
集合
StateinfoSnapshot state_snapshot = 16; S taeinf Staer
/用来请求 口
foPulReqst
o Snapshots state_info_pull_req = 17;
节点间的流言董
i吾
〈-
165
•!•
166
源代码分析与深入解读 Fabric
dger 出
Hype
集合 blocks
请求 per
remot /用来向
RemoteStateRequest state_ request 集合 blocks 发送 per remot /用来向
18;
=
RemoteStateResponse state_response 的意图
lead r 成为
per /用来表明
LeadershipMessage leadership_msg
Peeridentity peer_identity Acknowledgement ack
= 20 ;
ifcate cert
的 per
/用来学习一个
= 19;
= 21;
= 22;
/用来请求私有数据
RemotePvtDataRequest privateReq
23;
=
/用来回复私有数据请求
RemotePvtDataResponse privateRes
=
24;
/打包将要分发的私有数据
/在背书后的私有读写集
PrivateDataMessage private_data
= 25;
)
。 下一节是对上述各种消息类型的详细定义,在此处不赘
。 型
与发送方式 Tag
消息类型对应的 2.
中。 Org
实际上就是同一个
pers remot
资格接受该消息的
end
,顾名思义在准备好消息后也会指定需
to end
。
, 然后将消息发送出去,不存在随机性 pers
remot 要接收的
而
Tag 下面我们先总结一些各种消息类型对应的 发送方式与 gosip
后面我们再对
( 1 ) AliveMessage 口发送方式
口
Tag:
。 EMPTY
:
pers 一些
中随机选择 pers
remot 。
方式具有随机性
g osip 去,所以
字段,选取出有 Tag
,然后从
end
to end
发送方式做详细的介绍
与发送方式以及每种的使用场景, 。
某些消息类型 。
to end
end 种是
方式的特点就在于会根据待发消息 ip
gos 的方式发送,
gosip 通过
一 ,另
gosip 中有两种消息发送方式,一是
Gosip 在
Org 一个
与同 nel
cha 发送范围被限定在了同一个
的 mesag
,则
一 ORG AND
削_ CH
的 mesag
的发送范围,比如若 mesag
字段即控制了 Tag
字段,而 Tag
包含了一个
中都 mesag
gosip 的
每个发送 服务中有多种消息类型,
Gosip 前面我们介绍到,在
为
网络中将会传输的各种消息类 Gosip
文件我们可以了解到在 sage.prot
me 通过
将
消息发送出
Tag
中,
盖 言
节点间的流 Gosip
8 章 第
167 令
i吾
gosip: 。
。 Msg
A live 发送
向外 方法周期性
- periodcalSnAv ( 2 ) MembershipRequest 。 EMPTY Tag: 口
口发送方式: d
to end:
- chanel
配
en 。
「 shipReon Memb
。 EMPTY
Tag: 口
: 发送方式
口
。 per
dea 尝试连接
周期性 方法
- periodcalRntTD ( 3)
。 发送成员视图请求回复
per remot
方法中向目标 sendMmRpo
:在
0 end to end
( 4 ) DataMessage 。 CHAN_DORG Tag: 口
口发送方式: 他 方法中构造区块后分发给同组织其 cks Blo ver Deli
: 在 gosip
。
( 5 ) GossipHello
: 发送方式
口
。 织内区块同步时)
机制做组 Pul
: CHAN_AND_ORG (利用 Tag
口
) 。 时
图交换 机制做视
Pul
EMPTY (利用 Tag:
口
to end end
。
。 pers
remot 方法中发给特定的
Helo :在
( 6 ) DataDigest
: 发送方式
口
。 组织内区块同步时)
机制做 Pul
CHAN_AND_ORG (利用 Tag:
口
。 做视图交换时)
机制 Pul
EMPTY (利用 Tag:
口
to end end
。
。
p 巳 er remot
给特定的 中回复
法 方
SendDigst 在
:
( 7 ) DataRequest 。 组织内区块同步时) 机制做 Pul
: 发送方式
口
。 做视图交换时)
机制
CHAN_AND_ORG (利用 Tag:
口
Pul
EMPTY (利用 Tag:
口
to end end
。
:
在
方 SendRq
。 pers
remot 法中发送给特定的
( 8 ) DataUpdate 0 Tag: EMPTY ( 利用 口
。
。 方法周期性向外界请求成员视图
- InitaeSyc
pers botsrap
与 pers
a nchor 尝试连接配置的
, 或更新时
化 置初始
Tag
:
Pul
CHAN_AND_ORG ( 利用
时) 图交换
机制做视 Pul
机制做组织内
。 区块同步
时-)
。
pers
。
•!•
168
Hyperledger Fabric j 原代码分析与深入解读
口发送方式:
end to end : 在
0
Sen dRes
方法中回复给特定的
re mote per
。
( 9) Empty 0 Tag
: 不包含任何内容 。
口发送方式:通过调用 grpc
标准库中的 Invoke
方法来实现 Ping
功能 。
( 10 ) Conn Establish 口 Tag: EMPTY 。
口发送方式:
0 end to end :用于 gosip
息证明自己身份
握手 。
当一个节点连接另进行握手时,发送 此消
。
( 11 ) Statelnfo 0 Tag: CHAN_ORG 。
口发送方式: 。 gosip :在 publishStaenfo 方法中将最新的 staelnfo Msg 散发出去 。
( 12) StatelnfoSnapshot CHAN
0 Tag: D
一 OR_G
发送方式: 。 end
to end : 在 复 sta telnfo
Ha
pul
ndleMsag 方法中调用
请求
RecivdMsag 的
Respond 方
法回
。
( 13 ) StatelnfoPullRequest 口 Tag: CHAN_ORG 。
口发送方式:
0 end to end :在
requstSalnfo 方法中向
remot
发送
peers
s taelnfo pul
请 求
( 14 ) RemoteStateRequest 口 Tag: CHAN_ORG 。
口发送方式 :
0 end to end : 在 缺失的区块
re q uestB locksnRage 方
法中向某一 remot
per 发送请求以
获取
。
( 15 ) RemoteStateResponse 0 Tag: CHAN_OR 0 发送方式
一 ORG 。
:
0 end to end :在 回复
handleStRqus
staeRqu
方法中调用
,向 remot
( 16 ) LeadershipMessage 口 Tag: CHAN_D
一 ORG 。
per 回复其所请求的区块
Reci vedMsag
。
的 Respond
方法
。
169
: 发送方式
口
〈-
i吾
言辈 节点间的流
Gosip
8 章 第
gosip: 。
。 prosal
leadrship 发送
pers remot
内的 Org
方法中,向同一个 prose
一在
。 身份
leadr 的
自己 明
, 声
leader declartion
界发送 不断向外
per 该
则 ,
leadr
g 的 Or
是 per
方法中,若当前 leadr
-在
( 17 ) Peerldentity 。 EMPTY
0 Tag:
: 。 发送方式
口
时 CertSo
化 方法中初始
newCrtSo :在
0 gosip
加入 信息
identy ,将自身的
。 相关缓存中
( 18 ) Acknowledgement : 发送方式 口
。 信息
T ag 需
,无 ack
复发送方一个 :用来回
Tag 口
4 唱 陆
ac 方法回复一个
R es pond 的
RecivdMsag
k 方法中调用 Ac
在 :
to end nd
。巳
。
( 19 ) RemotePvtDataRequest 。 CHAN_OLY
0 Tag:
: 发送方式
口
。 发送私有数据请求
per remot
方法中向 Requst
scater :在
to end end
。
( 20 ) RemotePvtDataResponse 0 Tag: 方式: 送 口发
。 CHAN_OLY
方法回复 Respond
的
vedM esag Reci
法中调用 方
handleRqust
0 end to end :在 。 私有数据请求
( 21 ) PrivateDataMessage 0 Tag:
。 CHAN_OLY
口发送方式:
end
服务组件
。 函数 函数,在
函 InitGospServc
同 数进一步调用
&gossipServiceimpl{ . . . },即
是对全局
唯
一
工 nsta gosipServc
下执行了
o ry InitGospServcCumDlyFa
函数中,
InitGospServcCumDlyFa 件下的
文
巳
InitGospServc 文件下的
gosip/ervc_. 函数中调用了
s 巳 rv 文件下的
per/nodsta.g 人口是在
服务初始化的 Gosip
整个
serv
。 的方式
Gosip
8.2.2
end 即
, sendToEpit
定发送方式为 方法中确
SendWithAck
0 end to end :在
Go
sip
服务实
例的初
始
化
。
口 ce
to
170 令
Hyperledger Fabric j 原代码分析与深入解读
per 的全局实例
Instace
gosipServclnta
是-
,即代表了
gosipServclm
per
类型的结构体,
下的 Gosip
服务,
gosipServclm
servic/gop_.
gosipServc
结构体定义在 gosip/
文件下,定义如: type gossipServiceimpl struct { gossipSvc privateHandlers map[str 工 ng]pr 工 v ateHndlr chains map[str 工 ng]stae.GoipSPrvd leaderElection map[string]election LeaderElectionService deliveryService map[str i ng]deliverclient.DeliverService deliveryFactory DeliveryServiceFactory lock sync . RWMutex mes api . MessageCryptoService peeridentity []byte
我们针对该定义中的各字段 per
1.
Gosip 服务的各组件进行分析
。
gossipSvc
gosipSvc 是
gosip_ servic
gosip.
gossip/
对
的
type
.go 文件下定义的变
量
文件下的 interfac
Gossip
gosipServclm
type 的 实现是
gosip.G
gosip/ ip
2 )同一接口
Gosip impl
gos 会
gosip/
服务的初始化中
/gosip_
1 )该结构体名称与上面提到的
现的结构体名称相同;
,对应
interface ,而
Gossip
结构体(注意:
结构体实现)
类型,具体是
.go 文件下的
ipServclnsta
e 的实
有多个结构体对其实现,需要明确此处使用的是哪
。 gosipSvc 组件的初始化就在
Serviclnsta go
InitGospServcCumDlyFa 函数中
实例初始化代码的上方,通过调用 文件下的
gosip/ntera.
NewGosipCmnt 函数,
置,然后调用
N ewGosipCmnt
gosip/
函数创建了 gosip. 工 p
一 / /将某 一
grpc
Gossip interfac
e 定义如下
发送到 remot
*prot.Gs
mesag 发送到所有满足
回 被认为还
SendCrita
alive
Peers() / 返 回
serv 绑定在
:
peers peers ... *comm.RemotePeer)
工 pMesag,
的
SendByCriteria(*proto.SignedGossipMessage, /返
函数
ace {
mesag
Send(msg
NewGosipSrvc
实例并把它和给定的
type
工 nterf
/将某
文件下的
gosipServclm
文件下的 Gos
函数首先读取相关配
_ impl.go
N ewGosipSrvc
type
gosip
的
pers Sendr
error
工 teria)
NetworkMmbs
[]discovery.NetworkMember
被认为还 alive
并且订阅了给定 chanel
的 NetworkMmbs
[] discovery.NetworkMember /更新 per 发布给其他 pers 的 iscoveryd layer 的 self metadata UpdateMetadata(metadata []byte) PersOfChanl(com.i
/ UpdateChn
更新
工 D)
per 发布给其他 口 elMtad(m
pers 的与其
chanel-rtd stae
的 self
(]byte, chainID common.ChainID)
metadata
一 起
。
。
第
/
发送
一
个
mesag
到网络
中
的其他
8 章
Gosip
节点间的流言萤语
•!
171
pers
Gossip(msg *proto.GossipMessage) PerFilt
II II
接收
一
RoutingFler
个
SubChanelctior
并且返回一个
选择那些满足给定
critea
R o utingF
并且发布了它们的
chanel
peer identities PeerFil ter (channel common . ChainID, messagePredicate Criteria) (filter.RoutingFilter, error) Acept
返回
II /如果
一
pas /
如果
个明确只读的通道 是
false
pasThroug
,这
是 se
ap
工
mesag 些
true,
Jo
工 nCha
mesag
先
gossip layer
由
gosip
layer
处理
不会介入,并且这些
mesag
可以被发送回
nder
使得
一
个
Gosip
实例加入
LeavChn
使得
/
该 /
但是
Gosip
一
个
实例仍 不
Gosip
实例离开
旧可
能再参与进
以传
播
block
( orderer/common/broadcast/broadcast. go Recv(), or 由
nityCheckAdS
进行签名,这样的检查不是非要可因
类型的检查
中留下签名即可 节点 发送
。
的
成的,只要工具没问题那这里不检查也可以
sanity chCrtEnv
中
chCrtEnv
边的步骤中还会有多次这样 建,在
err =
chCrtEnv
ignCofTx(chrtEv
为
飞 r,
,首先根据命令行指定
2 点中
per
发来的原始配置信
msg
,接着开始从
)中的
(.)位于
s.bh msg,
msg
err := srv. 中抽取
•!•
204
数据
。
H y pe 出
d ger
Fabr
与
因为是配置信,
此
CONFIG UPDATE msg
i c 源代码分析
chdr.Type
个以
==
msg,
整理: 一
会进入 江
)分支,在此中
进行了重新
被装进
深入解读
过滤重复的配
sytem
err= bh.smProce(g
置 ,若是
chanel
的
ID
per
)对
channel creat
的
msg
)最终调用的是
orde/
su
p
ort,
ok
否则
ate
,
已有频道配置的,此时进入
ifok
则说明此
配置信是用于
creat
Config ( ... ) 。
这里
p
ctxm, or
der
err er/m
ultichan
据,并填补了一些
application chanel
tem
中
figEn
v ,
。
问
),
配置信是
p . newCha
然算是
丑 el
p.newChal
configtx
原配置数
生成一个
内 仅停
虽然是
以指针的
ap
形式传
中的值 eC
licaton
o 口 f
含
。
而
进
后面会
介
igUpdate(envConfi
chanel
的频道配 置信
configMaer
。 aplicton
这里
channel
,所以这里相当于
事
前
。
:= ctxm
err
.Propse
configMaer
ConfigUpdate( 的
口 vCo PropseCnfig
Update
功
中读集和写,将已有且版本相同的配置项过滤掉生成要创建 的
频道配置数据
的函数
do
newChalofigEv
igUpd Update
ProposeConfig Update configMaer
ex
( 包
这个已存在的
... ) 实际是一样
的,都是
istingChannelConfig( .. . )中使用的
configMaer 。
channel update
所调用的
... ),与 a te(
,只不过 中的
这里的读集和写可
suport.PeCnfigUda(
opseCnf
application chanel
。
Ou tpu tChannel CreateTx o p 巳 er
existingChannel Config( ... )中执行的是 PropseCnfig
和
证
configMaer
利用
chanel.tx
.Pr
当于验
创建
返回
chanel
ctxm
fig
类型的验证,因为后续步骤在真正
根据原有的配置数,
a plicaton
,相
con
:= ctxm.Props
err
nity
题早发现
置信
建频道所使用的
下的
和创建频道所使用的
能,通过对比配
创
执行
e nvCofigUpdate
( newChannelConfigEnv,
的
comn
来生成
NewChanlofig
建一下,若有
这里的
支去
lConfig
置中并没有改变
envCofigUpdat sa
以生成
分
(这个过程相当复杂),但是 配
就属于上文提及的类似
的
NewChan
的配置
NewChan!ofig
nfigUpdate
ok
e nvCofigUpdate
)又直接使用原
创
的
configMaer
newChalo
先
if
Config ( ... )依
且没有返回供调用者继续使。
是在
经历
此
:= p.ma nager . NewChannelConfig(envConfigUp
chanel
新配置的
留在当前函数
时也会
说明
.. . ) ;
此时跳过
/ manger.o
sy
gUpdate
则
. .. )中:
date ),在
绍的
若存在,
p.existngChalof(
新频道的,
p.newChalofig(
的,但
的
。
①运行 代码
去
支执行
. existingChannel
Config ( ... )中的一部分 ( 5 )在
分
。
:= p.manager.GetChain(channelID) 。
upd
的
c onfi gu p date/co n fi gu p date. go
获取了所需要的资源,也验证配置信对应频道是否存在 用于
原始
话,过滤后的配置还会
为外衣的配置信中,形成新
( 4) bh . sm . Process (msg
Process ( . .. ),在此函数中
in t32(cb.HeaderType
configMaer
含在
c hainSuport-
> ledgrRsouc
configMaer 是
已
存在 中
的 )的
正好也证明了后文在创建频道时还会
。
( newChannelEnvConfig, err: = utils.CreateSignedEnvelope( ... ) ,
第
对
新生
成的频道配
用的
置信进行签名,类型为
8 章
Gos
HeadrTyp
existngCha!of(
... )同样执行了这
ip
节点间的
流言萤
_ CONFIG
。
一步,且就此返回该配
per
i吾
•!
205
置
channel update 信
所调
。
( p.proposeNewChannelToSystemChannel( .. . ),将签名过的配置信 装到一个以
sytem TRANS
chanel
CTION
为频道
ID
。 要使
(6 ) 重
回
用
orde
sytem
chain
对象
,
的
chai
nSuport
creat
Aply(env
) 。 ①
scf ,
。
。 的
inFlt
per
发送
到这
er
的
Ap
到
接收,配
。
含
了完
验证和填充配置信
配 。
置信
文会再次生戚,在
s u po
口
是
sytem
chanel
的
suport
中
置信生成
( .. . )
chainmpl
身影,
chanel 非虚
所
使用的
。
回
Ac
c 巳 pt
()后返回执行器集合,这是因为
的
sytem
的
。
在
,由于是配
(或
是与
chainSuport
),经
tem
对
暗盒 / kaf
的排
序
/ chain.go
*ab.KafkaMessage_Regular
procesRgula
),具
chanel
kaf
orde
lo
的(又由于 sy
过
消息中,在
so
kaf
chainlmp
巳 _ R egular case
kaf
( . .. )发给 里的
chanel
息发送给
Enque
,因此这
committers, block
( . . . )的
这里注意,一步主要目的有两个:
一条消
chainSuport
processRegular( . . . )处理 ),由配
rizeAndspct
言
),把配置信作为
()中被接收,井进入
(env
autho
类型检验的说法所
Aply
KafkMesg
batches ,
在
这里需要
置值,这是不
工 mpl
的过滤器集合
也是
处理,配置信被包裹在一条
(
。
。
chanel
procesMagTBlk
、
mchain.go
配置信进行整理和检查
。
/ chain . go
应的对象,其成员
/syte
的配
写入账本之前调用执行器
/ kaf
/ multichan
小
&systemChainCommitt er { ... },返
( 8) support. Enqueue (msg orde
e re
空、大
。
sytemChainor
sytem block
是由
ord
依次进行非
a plicaton
的
channel / multichan/
v )中,抽取配置信并检查之后
sanity
整
per
orde
置填充配信对应项的值和新建
这也同时证明了上面有关
获取
只讲
置信均只有配项而没具体
return filter.Accept,
动作和包
。
、 configtx.NewMar 的配
。
过滤 。
(),即
ly(en
NewChanlofig
chanel
configMaer
orde
的
chainSuport
启动时,在
。
到了
sytem
体
Aply
一步才对配置信进行值的填充
看
()
( . . . )中生成
sytemCha
chanel
的
orde
)对
而直
(
具体为
creatSysmChinFl
在
从
中,我们如愿 即根据
chanel
. authorizeAndspc(fgTx
点
sytem ),由上面
集
建
) ,根据频
suport.File()Aymg
: =
创
)中,对原始的配置
获取的是
a plicaton
s ystemChainFlr
完整的
( . .
. Chanelid
的过滤器
签名的检查后,最调用
一
Proces
channel creat
chanel
的
‘ 因为
。
A ply
sytem
chainsuport.g
明确
的
获取频道的过滤器集合并对配置信进行
,获取的是
的
对象
一
独有的,
bh.smGetCain(cdr
:=
ORDE
channel creat
chainSuport
获取的是对应
filterErr
H eadrTyp
per . go
per
chainSupport, peer channel update (7)_ ,
的
ok
Suport
类型变为
一点是
/ configupdate
suport, 获取
中,且
这
chanel
/ configupdate
信处理之后,通过 ID
置信
,然后返回新的配置信
application chanel
道
的配
的
:分支,交由
( .. . )中,将配置信抽取出来后: ok 置信
:=
,因此
support . BlockCutter() .Ordered 会单独
作为
一
个
block
,且
suport
是
•!•
206
Hyperledger Fabric
system chanel 器集合
的
chainSuport
A ply(env 重新生成
(
后返回 包
息打包成
i,
block
前文所述的
,
/ multichan
这
/ sytemchain.go ),
最终执行
的
是
t ()
age
chanel
。
可以
看到
ge chain
Suport
对
④还是在
象,
也
Wri
chanel
在
orde
端
的
的
工作
到
答
。
在
Send(chCrtEv
的民
),在
第一步结束。
对
于
creat
err
命令行的- chanel
的
multi
最终效果
Ledgr
就
是
对 象成员
:
chains
channel update . ledgr
使用到的
. Apend(block)
的账本
。
的
srv.Send(
执行至此,
per
channel
( ... )中,定位 )就是
r channel creat
的
Send
orde
动作的
per
现中的
节点返回成功
delivr block
() ),
也即
节点的应答信息
当
。
动作来说,至此整个结束
至此,
。
/ chane
l/ create. go
),在
一
服务每隔 文创
的
excutCra(
ct)
定时限内(默认
5s
20ms
,即上
... )接
broadcstClien.
orde
getGenesisBlock (cf
Send(
getAck
中执行完
per
节点处
的
( ... )实
( . . .)内部已经接收到来自
0 的
Handle
... _SUCE pe
重新返回到
索要一次序号为
( ... ) 。
broadcstClien
t 指定),利用
成功获取或超时
的
channel update
=
chanel
ndCreathiTsco
per 。
cs
/ broadcst.g
巳 rclient.go
Send
( l 0 )开始第二步 block ,
后
/ orde 巳 .go
的
节点接收这个应答的地方是在
/ comn
per/chanlt
er
per
tem
channel ,向发起
per
newChai
chanel
而上文提及的
/ broadcst
),之
per 参看
sy
/ comn
这里注意一下,
口内部(
是
。
a plicaton
的应
块写入
口 que(msg
理完毕创建新的
的
集合后,
gensi
orde
s u port.E
此执行的
。
基本结束
( 9 )重新返回到
multiLedgr
aplicton
teBlock ( . . . )中,兑现执行器
aplicton
creat
创建的
的
orde 。
就是这里
,因
r.go
块)并在
对象并启动相应的服务
comiter.
stemChainor
,创建
nesi
... ),
- > scc . filter. cc. newChain ( scc .
/ multichan/
建了频道的账本(且写入配置信作为
也会把
批消
WriteBlock(
循环中依次执行
sy
Cami
orde
aplicton
chain Suport
滤
每
的
里因为只有一个
的
在这里,正式创建了
个
的过
批消息,将
_,committer := range comiters 。
一
在循环中依次处理每
orde/multichansp.g
(),即将执行器集合兑现
中添加
chanel
committers[i], ... ) 在
for
configTx
sytem
。
在这个函数中,首先
orde
是 。
suport.WieBlck(b,
support. WriteBlock( ... )执行的是
Comit
也
sytemChainor
: = range batches
batch
b l ock
(
创
comiters
面提及的被
含
,然后能过
写入
获取的执行器集合
的,即上
执行 集合中只
for
账本中
,
)之 。
源代码分析与深入解读
建的
向 a plicaton
orde
,可由
per
节点指定的 chanel
中:通过
channel aplicton
的
gensi
块,
直到
。
( 11 )开
始第
写
File(file,
三
人文件,供
per
b,
步 064
。
通过
b, ),将第二
err
channel join
proto . Marshal (block)
:=
动作使用
步获取的
。
block
至
此
,整个
以
per
aplicton
ioutil.Write-
- >
channel ID+.block channel creat
动作执行完毕
的格式
。
•!
s ip 节点间的流言萤语 Gos
8 章 第
207
2.join
/
/ chanel per
在 。
文件 l.bock
mychane
是 ID
是一个 的
建 创
creat
channel
channel ,对应生成的即为 aplicton
的 mychanel
per 这里假设
。 等模块的服务
gosip 主要指
指账 本,服务 数据主要
。 套
的数据和服务相配 chanel
aplicton 节点中的
orde 在于
以便和对 应存 数据和服务,
地 点的本
节 per
的动作是
j oinj oin
peer channel
中: join.g
)中:
(I)joinCmd(c f ) ->join( ... )-> excutJoin(f
( spec,
(
ocatinSpe{ 川
: = &pb. ChaincodeI
invocation
prop,
- > signedProp,
err =
。 书申请
签名,形成一个背
( . .. ) , 包装+
口 edPropsal putils.GeSg
->
... }
= putils. CreateP rop osalFromCIS ( ... ) er
一’
。 块数据
nesi ge
l 的 mychane
读取的 中
mychanel.bok 从
、 cs.JoinCha
作 入参数,指定了动
执行的输 sc
作为 Chaincodelput
中的 ”,其
明书 “说
的
格式 pec
ChaincodeS 的
cs c 建了一个关于
: = getJoinCCSpec ()创
err
( cf.Endorse rClient.Proc essPropos al( . .. ),通过背书客户端发起 。 请求
。 赘述
书过程不再
( 2 )背
case ,根据上面所述的“说明书”将进入
)中 stub
Invoke( 的
configure.
( 3 )在 : 分支: JoinCha
: )中
cid, block joinCha(
( 4 )在
。 具体动作
的 join
),最后执行
( join Chain( cid, block
。
查验 证 块,然后进行一系列的检
gensi 的
mychanel 数中获取
createChain( cid, I, cb
(
着重看 个函数中,
链对象,在这 使用的
mychanel 建针对
),创
立
block
myc 模块中专供
gosip 地
节点之间建
频道索要
本地 per
建
, 创 块
nesi
.InitializeChannel( ... ),该句初始化了
节点本 per
ge
e l 的 mychan
。
servic.GtopS() 下
一
本 使用的账
mychanel 专供
根据 ),
dger(cb CreatL
( I, err= ledgrmt.
。 ,此为监控服务
建事件服务 创
: )中
ck(blo inFromBl
Creath
( 5 )在
) , nt(block
Eve produce.SnPBlk
③
。 地的链
点本 节
per ),初始化
. go
/ per
/ per
( peer.InitChain( chainID) ( core
。 的
生成 服务,均是在此
gosip 、
的账本 和使用
涉及 中
题的文章
主 作为
gosip 、
code
c hain 在这之前,以
。 务
服
g osip 链(账本)和
的 mychanel
点本 节
per ),创建
p er/p.go
( peer . CreateChainFromBlock (block ) (core/ 地的针对
个参 第二
])从 [工
( block , err := utils.GeBockFrmy(ag
务连接,由 了服
数据块并添加到本地的用于
此
per
节
服 gosip
使用的 hanel
orde 可以源不断地从
点就
mychan
el
的账本
。
orde
服 务与 gosip
务,并在
节点中的
mychanel
+!+
208
Hyperledger Fabric
( 6 )在
InitCha(
个函数变
量 行
pe
源代码分析与深入解读
chainID
是在
per
)中:只执
节
行了
点启动起来的
er.Initalz
时
即初始化
节
点的
的针对
in
ysC
per
要与
per
节点启动时部署的
完毕,
sec
7GJX.
叶
辛
sytem
ode
j
,也
。
也就绪了
如此,
per
。
/ star.go
的
这里所部署 se 凹
ID
一
频道
ID
,默认使用
sec
)中,当
per
a lResp
。
第
接定位回
pros
E 中执行
的链上
oinChain(cid, block
在接到背书的返回结果
中执
chainode
chaincode .命令若是没有指定频道 的
serv func(id
的
/n
直 。
的
sec
( per
,否则使用的是具体针对某
)中
t 旨
/s tar.go
链上部署的
基本结束,开始一路返回过程省略可以
excutJoin(f
~←
ID sec
sec/ cs cc/ configure. go
则背书过程
这
所赋的值是
节点启动时部署的
sec
chainltzer
node
上执行的过 程中所使用到 per
core/
per/
mychanel
()做区分,即如
( 7 )重回 的
sec
在
署了指定频道
链,其实就是在
mychanel
l 的
tS
的
动作在
mychane
-=E 主 1"f
即
,而
chainltzer
mychanel
.
cha inc ode
go
候被赋值的,
)},即部
per
的是
tializer( c i 哟
( ... )时被赋值的,这里给
string ) {sc.DeploySC(id
的
chainl
后,整个
4
点执行
/ chanel/joi. j oin
动作也
。
事件机制
8.6 在
Fa
关信息
bric
中,
采用事
件的
形式来通知客户端交易完成及写入区块或者智能合约
事
。
件相
Fabric
8.6.1
中
本节讲解在
Event
相关实现
F abric
节
点中如何实现事件的订阅,以及信息推送
。
1. events/consumer/adapter.go EventAdapr
是一
个从
fabric
evnt
服务器注册感兴趣的
事
件以及接收消息的
一
端接口: Getlnr
巳 stedEvn;
D
D Recv; Disconet
巳 d 。
D
2. events/consumer/consumer.go EventsCli 口
结构体持有
grpc
NewEvntsCli
连接的流和用于与消费者对适配器
adpter
口
:用于初始化一个连接某 new
per
口
EventsClientConnection Wi thAdres send
:
将
Event
签名后通过
D RegistrAync 的
:
send
方
法
。
异步注册对应的事件到
g 甲
:返回
的
c 的
stream
一
fabric
发送到
个
EventsCli grpc
连接
evnt evnt
。
服务器,不等待响应调用上面
服务端
。
。
。
个客户
。 Event
nt 。 Eve
发过来的 :建立和事件中心的连接,获取客户端感兴趣同步注册到服务并 Star 口
调用的方法,于接收服务端 gorutine
方法中重新创建一个
D processEvents : Star
。
- sdk
- go fabric
相似的应该是
: 使用方法
consumer.g
。 EventAdapr
( l )根据自身需求实现
。 文件
.go
「 evnts/produc
8.6.2
EventAdapr
巳 ner
b lock-ist 具体示例请参考
方法,该是阻塞型 procesEvnt
的消息,调用客户端实现 evntbu
的,用于不断接收来自
执行 gorutine
启动一个 。
设置的感兴趣事件类型
服务器的连接,同步注册一开始 evnthub
方法:建立与 Star
的 EventsCli
。 实例
EventsCli 生成
NewEvntsCli
( 3 )调用
。
巳 r 包下的文件 evnts/produc
本节主要介绍
1. producer.go g 叩 c 的 结构体:实现
Events Serv
的结构体 Chat
。
2. events.go handler List
。 :事件处理器接口
type handlerList interface { add(ie *pb.Interest, h *handler) (bool, error) del(ie *pb.Interest, h *handler) (bool , error) foreach(ie *pb.Event, action func(h *handler)) : 该事件分为
。 :普通处理器列表
genricHadlLst
←」
←L
sh
r e
14
{ dxp ·-CMS t rb HU La • we gya co sr uo n lsd atm enn nea rRe ncd l e EW
中对应都有类似的实现,最为 SDK
,每个 中有使用
block-istenr.g 这个文件主要在
。 的字节数组
signer :获取
getCraoFmLclMSP
( 2 )使用
。
。 :终端和事件中心的连接
D Stop
信息 Event
处理服务端发来的 Events
proces ,调用
gorutine 启动一个新的
口
。 ()方法的时候使用
Star ,在客户端没有调用
Event 中接收
stream 的
grpc :从
Recv 口
。 方法
send :反注册客户端感兴趣的事件,不等待响应调用上面
D UnregistAyc
口
209
中,发送到服务端同步获取过来的 evnt
注册感兴趣的事件到 :
D regist
•! 节点间的流言董语
Gosip
8 章 第
wr
4 咱
吁--
「 L
中有
n 、
e ld
的
Recv
方法
。
•!•
210
Hyperledger Fabric
handlers 这种
源代码分析与深入解读
表示方法是
g o 语
0 chainodeHlrLst
言里实 现
set 的常用方
:链码处理器列表
法 。
。
type chaincodeHandlerList struct { sync.RWMutex handlers map[string]map[string]map[*handler]bool handlers 表示对应的
List
chainodel 下的
evntNam
中的特殊数学结构,因此其分为
的
2 个结构体
genricHadlLst 的
口 ad
口
:将
del
口
handler
三
:将
添
handler
foreach
口 ad
:
中移除 三
口
action
个实现方法
。
: 其中 ie
*pb
. lnters 这个 空
evntNam
参数在这 个实现中没有用到:
,将对应的 handler
添加到对应的
。
:操作加了写锁,判断相关参数是否为空将对应的
的
chainodeHlr
。
,执行
下对应的
del
I 是
。
操作加了写锁,判断相关参数是否为
chainodel
口
中
handlerList 的
bo
。
handlerList handlerList
chainodeHlrLst
] 。
:
加到
从
:遍历
个实现方法
map[*hndler
chainodel
handler 移除
foreach act
evntNam
。
:操作加了写锁,获取指定
执行
的
chainodel
i on ,此方法中还有
一 段代码(第
下的 l 14 ~
EventNam
159
下的所有
行),永远不会执估计
handler, 。
3. handler.go 口 handler
口
:用于向
new
evntHub
EventHadlr
注册客户端感兴趣的
: 创建 一
个
事
handler
件以及仅注册相应的事 。
o
4. register_internal_events.go 口 getMsaTyp
口
:获取消息类型 。
adinterlEvTyps :添加相应的事件类型
。
5. examples/events/blocl• Iistener/block-listener.go 为 Recv
adpter 和-
结构体实现 consumer.EvtAdap
Disconetd 。
creatEvnC!i
main
这
接口的 3 个方法是客户端自定义逻辑的实现
:调用
方法
并进行相应的输出
一
三
GetlnrsdEv
ntC!ie
生成
, 没有事件返回时进行阻塞
EventsCli 实例,并调用
; 有事件返回时则解析,
Star
。
8.6.3 本节将介绍在
Go SDK GoSDK
中 Event
相关实现 中如何实现客户端订阅相关的事件信息
、 -
。
NewEvntsCli
> creatEv
个方法:-
。
方法 。
第
8 章
Gosip
节点
间的流言茧
i吾
1. EventHub EvenHub
主要
用于
注
D SetPrAd
:设
D IsConectd
置事
:判
D Conect 口
册和反注相应的事件:
:和
注册
事件 g 叩 c 是否保持连接状态
件服
:和
务器建立连接 事件服务器断开连接
。 :注册
D UnregistChacodEv
一个
ChaincodeEvt
事
:取消注册一 个
D RegistrTxEvn 口
:
注
UnregistTxEv
册
ent
件
。
件
。
:注册一个
UnregistBlockEv
。 事
: 取消注册一个交易类型事件
D RegistrBlockEv
件
ChaincodeEvt
一个交易类型事
B lock
类型的事件
:取消注册一个
。 Block
类型的事件
。
2. EventsClient E ventsCli
主
要用于管理事件的异步发送及连接:
D RegistrAync
:
异步注册需要的事件
D UnregistAyc
。
:
异步取消注册相应
的
事件
。
3. EventHubExt EventH
ub
Ext
用于对
SDK
添加额外的扩展功能
。
4 . ChainCodeCBE 在
EventHub
内部使用,户持有
chainode
ChaincodeEvt
5. ChaincodeEvent 相
关信息的封装
。
evnt
。 。
。
D RegistrChancodEv
口
地址,用于指明在哪个节点上注册该
断客户端与事件服务的 事
Disconet
件
的注册回调
。
。
•!
211
........ .... .... .... ..... .... .... .... .... · --EE
··········
·a··· · ·· ····
ι i'v-~.tc
9
;
第
9
章
BCSP
加密服务提供者的设计与实现
BCSP
为加密服务提供者,
Fabric
网络信息传输提供了密码学的保障
。
密码学相关知识介绍
9.1
安全
9.1.1
基础
当在互联
网上
的地,正
是因
交换数据
时,
为如此
数据在
,安全技
被传输的数据会经
过各种样的设备和网络后才能到达目
术在
互
网络上传输的过程中,
( 1 )当
显得
存在着 A
intercpo
联网时代才
想要向
B
如此
4 个比较
重要
显著
发送消息时,可能存在第
。
的问题:
三方
X
来截获消息的内容,这种问题称为
。
( 2 ) 即使 也
存在
B
A
本来要
将消息发 送给
被称为
相信接收到的消
B
息来自于
spofing
A
,也存在
X
,但实际上是
伪装成
B
X
来接收消息的可能性;同样,
伪装成
A
来发送
这条消息
,这
。
( 3 )假设
A
向
B
发送的消息已经完成了,也存在过程中
X
的可能性,这种问题被称为
fa l s i ficat
i on
。
篡改消息
内容
除了有意篡改消息以外,也存在发送的过
程中因为传输设备出现异常而锚的可能性
。
( 4 )假设
B
已
经正确
地接受到了
否认了这条消息是由
他 业
合
签署合格的媒
当然,上
同
种问题
述
介,这种问
4 个问题并不仅
A
自己发出
的, 题被称为
发送的消息,但是方
当出
A 现这种 情况
存在于人与
repudiaton
时 ,互
联网将无 法成为商
业交易或商
。
人之间的信息交换
出于自己的私心考虑,
,
同时存在于我们日常上网
第
的过程中
。
下面我们来简单介绍
一
213
。
们
采用消息验证码或者数字签名技术
。
。
•!•
BC CSP D 日 密服务提供者的设计与实现
下解决上述问题的安全技术
为了解决消息被截获的问题,我 术
9 章
可以使用加密技术;解决第二个问题的方法是 解决第
三
个问题也可以使用消息验证码或数
数字签名技术还可以用于解决第四个问题
字签名技
。 其实数字签名本身也存在问题,就是它无法验证使用的公钥拥有者真
性,所以就出现了数字证书此来解决
字签名本身的
问题
加密基础
9.1.2 为什么在现代的互联网世界中我们
需要
息到达
。
B
加密技术呢
?例如
A
需要
向
B
发送消息,在
获,因 此
之前会经过各式样的设备和网络,所以有很大可能消息被恶意第
三
出于这种原因,在发送消息之前对加密就显得非常
有
被加密的数据称为秘文,消息将会以形式发送给
必要了
。
B,
文后,将其解密就可以获得原来的消息
。
称为解密
。
B
收到
A
发送过来的秘
将加密的数据还原成始状态过程被
当你将数据以加密的形式发送出去时,就可不必担心恶意第
三
的数据了,正因为如此加密技术在现代社会中才显得重
要
下面我们来仔细了解一在加密过程中涉及的操作
。
据的类型是什么,计算机都将它们视为
方所截
一系
方截获到你
。
我们知道,在计算机中无论数
列二进制数据,也就是一长串的
0 和
所以,尽管存在各种样的数据格式例如文本件、
音 所有的数据都是以二进制形式行管理
乐文件和影像
。
l 的组合
。
在计算机中,
。
同样,在加密的过程中我们也可以计算机管理数据方式来思
考
据就是一系列有意义的数字,虽然密文同样
也
是一串数字,但由于它
们
机并不能正确地解释它们,加密就是通过计算来将原对于
算
转换成计算机无法解释的数据过程
。在 这个密钥向样也是由数字组成的
。
我们的数据
。
的随机性,计算
机来说有特定含义的
加密的过程中,存在
一
数
数据
个用于执行计
算的密钥。
换一句话说,加密就是通过钥来进行数值计算将原
本可读的数据转化为不过程
。 不可读的数据转化为过程
反过来,解密就是通钥进行数值计算将
。
我们
通过一个“异或”的例子来理解加密和程,
XOR
值表决定的,我们有
(异或)的结果是根据真
: O XOR 0 = 0 ; 1 XOR 1 = 0; 0 XOR 1 = 1 ; 1 XOR 0 = 1 。 “异或”操作的 B
一
“异或”的结果,那么你就可以通过
个特点就
是
A
XOR B C
另外一个数字
。
或”操作得到秘文,同理将生成的与私钥再进行
与
C, B XOR C
A
=
和
B
A
,这意味着如果
C
是
A
和
中任意一个值进行“异或”操作来获得
将这个知识点用于加密和解的过程中,我们可以私钥数据进行“异
一 到原来的明文
=
次异或操作,我
们
就可以还原得
从上述过程中我们可以看出,相同的私钥被用于“异或”加密解数据
。
。
214
令
Hyp
毗
dger
Fabric
源代码分析与深入解读
晗希函数
9.1.3 一个哈希函数可以将不同长度的据映射为定值
。
我们可以形象地将哈希函
数理解为榨汁机,我们将原始材料(的据)放进晗希函得到饮哈 值)
。 料
。
我们可以将原材料转化为饮,但是反过来并不能通一定的操作 类比我们的哈希函数,可以将原始据通过晗操作转化为值但是不
可以使用哈希值得到我们的原始数据
。
也就是说,哈希一个不可逆的过程
。
就是一个数值,但我们常使用十六进制来表示
哈希值其实
。 哈希函数的特点如下
: 第一个特点就是通过哈希函数得到的输出长度都固定
。
度固定是针对特的哈希函数而言,例如
SHA
字节,这就意味着
即使你的输入数据非
依然是固定的
20
-1
哈希函数得到的晗值长度都是
20
常大,但是通过
字节
。
类
长
SHA
似的,不管你输人数据有
多
-1
哈希之后,你得到的输出
小,得到的输出依旧是
20
字节
。
哈希函数的第二个特点就是在相同情况下,输入永远得到 出
。
第三个特点也是非常重要的一,就你输入两类似数据即使只
相差
1 bit 输出
。
,得到的输出相
差也会非常大
。
哈希值不会因为你的输入数据相似而得到
的情况
第四个特点就是可能会存在输入的数据完全不同,依旧得到两相哈希值 。
这种情况出现的概率非常小,被称为哈希碰撞
。
第五个特点就是哈希函
数具有单向性或者说是不可逆,你几乎能通过哈希值得到原始据这也函
数与加密之间一个非常重要的区别
。 非常简单
晗希函数的最后一个特点就是计算哈值过程可以
。 我们可以使用
M
常用的是
SHA
-2
D4
、
M
D5
、
SHA-0
、
SHA
- 1,
SHA
- 2 之类的哈希函数,现实生活中最
。
9.1.4 共享密铜加 共享密钥加在和解的过程中使用相同私
。 假设
A
想要通过互联网将一段消息发送给
B ,在发送给
同的网络和设备
。
易截获该消息
。
但是,如果
A
B
直接将消息以明文的形式发给
的过程中消息经了很多不
B ,
则
恶意第
三
方就非常容
正是因为这样,所以在传输消息的过程中通常需要经加密处理
。
钥,将明文加密为再进行发送
。
B
利用相同的私钥
利用私
将接收到的密文解得原
。
以,经过加密处理后即使恶意第三方截取了消息在不知道钥的情况下他也很难
道原文是什么
。 利用相同密钥进行加和解是共享的一个特点,常见方法
有凯撒加密、
AES
、
D ES
、
O TP
等,其中
AES
使用最为广泛
。
当然,共享密钥加本身存在着一个致命的缺陷:假设
B 三
来没有直接触过,
送的过程中,密文也可能被恶意第 B
可能并不知道
方 A
X 用于加密的钥,所以在这种情况下
所截获
。
现在存的问题是,由于
收到了
A
发送的密文,在 A
和 A
B 就需要某
可能从
所
第
种机制把密钥传输给
B ,就像 B
利用
方
接收到的来自
X
A
A
向
B
9 章
BCSP
加密服务提供者的设计与实现
传输密文一样,
A
•!
同样需要在互联网上向
的密钥就可以对文进行解
B
。
同样有机会截获到密钥,这一来
X
215
传输密钥
。
既然是在互联网上传播,恶意第
三
就可以用截获到的密钥对文进行解
。
在上述过程中,我们可以清楚地看到密钥本身的传输存问题所
A
可能会想通
过对密钥本身进行加后再传输,于计算机来说一个仅是段数据所以我们可
以使用新的密钥对老进行加井生成文,再传输
。
要一个机制来传输新的密钥,这样就会陷入
一
个循环,总结
一
一个安全传输密钥的机制,这问题被称为分发
。 使用
Dife-Hlman
9.1.5
下,共享密钥加系统缺乏
解决密钥分发问题有两种方法:
密钥交换这样的协议;使用公加算法
。
公铜加密
公钥加密与共享
最
大的区别在于公钥加密和解时使用是不同
钥,用于加密的被称为公(
public
key
),用于解密的钥被称为私(
private
除了使用不同的密钥之外,公加在和解时比共
享
常用的公钥加密有
RSA
加密和
下面我们来了解
一
假设
A
想要给
EC
B B 。
到原始可读的消息
。 即
。
。
发送一段消息,首先接收者 B
) 。
。 B B
后的密文发送给
加密(椭圆曲线)
key
密钥加需要花费的时间更长
下在公钥加密的情况数据是如何双方之间交换
一个私钥,公部分将由
文,所以
但是我们现在又需
发送给
A,
A
使用从
B
会生成
一
对密钥,分别是一个公和
利用只有自己拥的私钥将从
发送过来的公钥将消息加密,并 A
发送过来的密文进行解,从而得
使恶意的第
由于只有公钥和秘文在网上传输,而且通过并不能解密 三
方截获了这两个信息,他也并不能解密文得原始消
。
公钥加密很好地解决了共享中私分发的问题
所以,
。 使用公钥加密的另一个好处就是,在
一
一个例子,假设
B
个不确定人数的组织中交换据非常方便
已经准备好一对密钥,即
。 一
己的公钥并不会有什么影响,所以
B
个公钥和与相对应的私
。 。
B
最后将加密的数据发送给
B 。
现在有多个体需要向
B
分享的公钥,然后利用将
B
因为公布自
将自己的公钥布在互联网上,另一方面由于私
钥是绝对不能让他人知晓的,所以私需要牢地守护 据,首先这些个体需要获取由
举
需
发送数
要发送的数据进行加密,
利用自己的私钥分别将收到密文解获得原来数据
。
所以,在存多个体时我们并不用准备公钥还有一点就是由于只消息的接 收者才具有用于解密的私钥,所以公加安全性非常高
。 然而在存诸多优点的同时,公钥加密也着两个严重问题
。
( 1 )公钥加密所需要的时间相对较长,正是因为这样并不适用于交换大
数据的情景
量
。
为了解决这个问题,出现“棍合加密”样的方案
。
的公钥记为
( 2 )公钥本身的可靠性存在问题 PB
。 ,将私钥记为
SB
,假设存在着恶意的第
当
B
生成公钥和私时,为了方便起见将 三
B 方
X
,想要截获
A
发向
B
的数
生成 据,
•!•
216
Hyperl edger Fabric j 原代码分析与深入解读
同时也生成了一对公私钥,分别记为
PX
地
将
B
的公钥
PB
替换为自己的公钥
PX
钥的产生者是谁,所以
A
用公钥
PX X
PX
加密的,
该发送给
B 密文是用
B
A X
的消息
B
。
sx
当
B
PX
向
将消息用
B B
可以正确地对消息进行解密,
A
时,
X
B
PB
加密后发送
给 SB
B 。
由于过程中产生的
方截获过了
还是来自恶意的第
正是因为
B
。
。
问题,出现了数字证书
成功截获了本来 。
三
B
隐蔽
将自己的数据
对密文进行解
都无法知道消息已经被第
无法验证自己获取的公钥到底是来
X
截获了秘文,由于该是用
上述通过替换公钥来截获消息的攻击方式被称为中间人 A
A
X
可以利用自己的私钥
和
接着
来对秘文进行解密,这样
的公钥
时,
由于通过公钥并不能发现 。
sx ,所以
PB
A 。
B X
发送自己的公钥
发送给
将加密后的消息发送给
接着,
A
的公钥有没被第三方调包
可以用自己的私钥
的公钥加密
。
,并将
并不能发现
进行加密,当
的公钥
和
这种问题的关键就在于
三方
X 。
为了解决中间人攻击
。
混合加密
9.1.6 如果使用共享密钥加,我们会遇到分发问题
一
如何安全地分发密钥?另一方
面,如果使用公钥加密漫长的解过程又降低了信息传输效率?昆合出现 就整合了两者优点,规避的缺
。 混合加密利用共享钥
加解密的
安全性
高效性的同
时,使用公钥加密来保障共
享密钥的
。
假设
A
要向
B
发送消息,可以利用共享加密方法进行高效
加
密钥也同样被用于解,所以
A
需要把密钥安全地发送给
B 。
式,通过公钥加密我们可以安全地将发送给
B 。 个公钥和一私,
B 加密后的钥再发送给
将公钥发送给 B,
A, B
利用
B
B 清楚
密的快速性,混合
加
9.1.7
B
地
看到
1 昆合
密已经被应用到
加
的公钥对称密进行加处理,
就可以准确快速接收到原始数据 加
密的高安全性和共享钥
中,用于互联网上安全交换数据
。
antheic
ation
和
falsict
ion
首先,我们来认识一下为什么消息验证码有存在的必要 向
B
发送自己要购买的商品编号
xyz
A
,然后
A
先使用某种安全的方法将共享密钥
加
密钥交换方法可以是公加还
Dife 要发送的消息进行加密,这里
detcion
。 A
使用了共享密钥,
加
消息验证码 :
的消息就
就利
。
密整合了公钥
SL
消息验证码实现了两个功能
件商品,
自己生成一对密钥,即
现在剩下唯一要做的就是将经过对称密钥加后
B ,由于共享密钥加解速度快 们可以
接收者
A
B 。 上述过程我
其实密钥也是数据的一种形
利用自己的私钥对加密后进行解处理,这样
用公钥加密将安全地发送给 文发送给
A
密操作,因为用于加的
是我们需要发送的商品编号,加密后得到文被
- Helman
密钥交换手段
假设
。
A
需要从
B
那里购置一
将该商品编号加密,假设时
密方法使用的钥传递给 。
B ,这种 A
使用共享密钥对需
密解
第
发送给
B,
B
9 章
•!•
BC CSP D 口密服务提供者的设计与实现
得到密文后使用共享钥进行解明,即
A
发送的商品编号
。
传输过程看起来好像并没有什么问题,但是现实生活中可能发这样的事情:当
A
送经过加密后的文时,恶意第
三
方
X
在传输过程中将密文篡改
。
文并解密后,得到的商品编号却变成了“
123 将商品“
123
”而不是“
xyz
”发送给
”,而
A 。
217
当
B
这个
向
B
发
收到被篡改后的密
B 并不知道商品编号已经被篡改过了,
B
因为加密无非就是对原有数据进行值计算,所
以,解密的过程也可在被篡改数据上进行但是如果原消息比较长而经后 的密
文解密后变成了一些没有实际意义的消息,那么接收方可能会察觉到已经
被篡改过了
。 很难
但若是一些人类无法直接识别的消息,例如上述商品编号那么收方就
察觉出消息被篡改过了
。
所以,为了检测消息是否已经被恶意第
三
密之外再增加一些手段就变得非常有必要了
方篡改过,除了加
。 消息验证码就是为了检测有无被篡改而出现的一种解决方案
。
一看消息验证码是如何工作的
。
消息验证码的密钥,然后
A
特定
当
A
将加密后的文发送给
B
将该密钥以安全的方法发送给
之前,
下面我们来仔细看 A
B ,然后
A
同时生成一个用于
利用该密钥和文以
算法生成一个值,这由密钥和文组合的就被称为消息验证码通常简写
为
MAC
。
MAC
值
样的方法来生成
可以简单
地理
MAC 。 广泛
生成
MAC
M
值,例如
AC
A
有无被第 A
来的 。
那么如果在 在
A
A
将密文和
值,
B A 的
接下来 B
的过程中,
X A
以即使
X
能
篡改传输中的消
将密文和
也无
的解
释,我
传输的过程中被他人
们可以 篡改
对用
于 ,那么
加
。
地
X
做到让两
看
就可以判断密文、
者的
B
不知道用于生成
重新计算出来
MAC
M
AC
值的密钥,所
值不一样时,
值一致,所
以 B
B
在
重新计算
就可以清楚地知道该消息
也可以 息是由
值的密钥,如果 B
还是
B
B
伪造
或者
MAC
可以避免消息在 。
还原这样的操作, A
到,使用消息验证码
然而,消息验证码同时也存在着一些缺陷
MAC B
声称该消
清楚
密明文的钥和用于生成
并不能区分原文是由
可以
MAC
。
经过上面
话
收到以后重新计算
值同时改变从而让
?由于 MAC
经被别人做过于脚了
将密文篡改会怎么样?假设
可以选择将密文抛弃然后再重新请
MAC
法
X
B
B 呢
X
方
值并不相同,这样
在这种情况下,
值时发现与被篡改后消息一起携带的 已
则说明
B MAC
一致的可能
息,
值,
进行比较,如果两者相同
篡改了密文,然而
发送的 X
值
接收到以后,需要根据
MAC
三
是否存在
MAC
B
一样,根据密文和钥来重新生成
的过程中,恶意第
。 值和被传输的
A
B,
使用最为
。
值和 。
HMAC
值一同发送给
和
我们可以使用各种
等,现实生活中
仅需将密文解得到原
或者两都已经被篡改过了
MAC
B
CMA
MAC
B 值发送给
、
自己重新生成的
B
再次发送相同的密文
MAC
B
MAC
值
求
。 和
会发现自己计算的
MAC
方篡改
将密文发送给
MAC
OMAC MAC
MAC
密文并没有被他人篡改
、
连同密文和
三
发送过
。
HMAC
值以后,
值检测密文 这样根据
解为密钥和文组合起来的哈希值
生成的,这样
A
A
就
否认了该消息是由
和
B
共
享一
MAC MAC
A
A
可以加密消息和生成
同样也可以加密消息和生成
生成的,那么假设
由于
是恶意的,在
他自己发送的
A
值
。
值的
换句话说,你
将消息发送给
。
B
为了防止
后,
A
•!•
218
Hyperledger Fabric j 原代码分析与深入解读
这种现象出,我们需要采取另外一技术也就是下面会讲的数字签名
。
数字签名
9.1.8 数字签名可以保证消息的不否认性
。
authenico
和
falsicton
数字签名除了完成消息验证码实现的
检测的功能之外,还实现了让消息真发送者无法否认这条
消息是由他发送出的功能,这就不可否认性
。 在了解数字签名的工作原理之前,我们先回顾一下消息验证码
。
统中,为了验证消息的发送者是否真实密钥拥有会将
MAC 上
。
为了方便起见,这里的消息以明文形式传输
A
的密钥发送给
B ,然后再将明文和
MAC
MAC
值,然后再确认两者的
MAC
送者并且发的明文没有经过他人篡改
。
MAC
B, 。
值附着到要发送的消息
先以某种安全的方法将用于生成
值发送给
值是否相同
使用消息验证码的系
B
根据收到的明文和密钥重新生成
如果确认成功,那么就说明
A
然而由于消息验证码采用的是共享密钥,依旧
存在拥有该密码的组织伪装成为消息发送者可能性,比如说当
A 之后,
B MAC
却声称自己才是这条消息的创建者
。
值,那么当
A
与除了
B
是真实的发
把一条消息发送给
B
还有一点就是,由于采用的共享密钥来生成
之外的其他个体进行消息交流时,则需要生成一新密钥
。
为了解决消息验证码内在的问题,我们引人数字签名技术不采用 MAC
,而是采用只有消息的真实发送者才能产生相关数据技术这里就被称 为数字签名
。 当
A
A 。
例如
A
abc
”,
A
会生成一段只能由
A
B ,可以判断数字签名来自发送者
。
A ,但是他自己并不能生成这些数字签
与消息验证码相对比,由于数字签名并没有使用共享密钥所以
A
或个体发送相同的数字签名
。
字签名
我们知道用于生成
MAC
时,我们使用了和公钥加密系统
类似的
一
个过程
。 A
会事先生成一对密钥,分别是公
P 和私钥
加密自己的数据
S,
,然后再将加密的文发送给 进行解密,整个过程结束
B
将公钥
B
A,
A
使用
B
所以在公钥加密中,被用于而私解正是
才拥有私钥,故只
B
A
才有私钥,只他们能加密数据而生成的
数据可以被任何持有对应公钥的人进行解密,但这样加手段没意义
。
个角度去看的话,我们就可以理解为密文生成者必定是持有私钥
A 下面我们来仔细了解一数字签名的整个流程
公私钥是由消息的接收方所准备
。
。
才能进
但如果我们将公钥加密的操作反向进行会怎么样呢?私用于,而
用于解密,在这种情况下假设只有
私钥
的公钥去
S 对密文
B 。
B ,接收方
利用只有自己才拥的私钥
因为如此,任何人都可以使用公钥进行加密但只有 行解密
有消息要发送给
P 传递给
B 。 。
可以向不同的组织
值的密钥是两方共享,而当生成数
我们在这里简单地回顾一下公钥加密的过程:首先如果 B
生成的签名,所以
发送的带有原消息和签名数据被接收方到时,就可以保证一定是
消息的接收方
名
要发送一段消息“
注意,由消息的发送者准备公私钥是与 。
加密
首先
A
将自己的公钥发送给
A
如果换一
而不会是其他个体
。
需要准备发送的数据及一对公
不同的地方之一
。 B ,然后
A
利用自己的私钥对
在公钥
加密中,
第
9 章
BC
CSP
消息进行签名,结果就被用来当作数字
加密服务提供者的设计与实现
A
用 A
的公钥对数
字签名进行验证
程就结束了
。
令
将消息和数字签名
一
同发送给
219
B,
B
利
如果验证的消息与收到一致,那么整个交换过
。
用
A
的私钥生成数字签名,可以用
A
成,所以我们就可确认
A
由于
A
的公钥进行验证,但是该签名却只能由
A
的签名不能有除了
才是消息的发送者并且没有被别人篡改过
A
。
以外的组织(例如
B )生成,因为
同时也实现了不可否认性这一功能
。
B
而且
,
只有公钥,所以数字签名
然而,和公钥加密类似解与签名验证都
需要花费很多时间,所以我们不直接对消息进行签名
。 们
生
为了减少计算所需要的时间,我
首先生成与消息对应的哈希值,接着晗进行签名操作再得到数字将原 消息和利用哈希值得到的数字签名发送给
B 。
同样,
B
利用收到的消息计算晗希值,并
公钥对收到的数字签名进行解密操作得另一个哈希值
。
如果这两个哈希值相同,那么说
明整个过程没有出错,利用数字签名进行交换的也算结束了
。 数字签名技术提供了
authenico
、
falsicton
detcion
和
repudiaton
能,但是它本身依旧存在着一个问题消息和数字签名的接收方
B
prevntio
是消息和数字签名的发送方
。
但是
事实
上,很可能存在恶意第
三
功
会元条件地认为
方
A x
伪装成
A
一
定
进行数据交
换,存在这个问题的根本原因就于数字签名和公钥加密都使用了一私 我们并不能确定这个公钥到底属于谁
。
使用的公钥很可能并不来自
A
字证书”这
一
技术来解决
因为公钥中并没有包含它的归属方信息,所以
B
,而是来自恶意第
三方
X
的公钥
。
这个
问题我们可以用
“数
。
数字证书
9.1.9 公钥加密体系和数字签名存在的共同问题就是无法确定归属者
。
需要将自己的公钥发送给
B 钥替换为自己的公
。
解决方案
时
,恶意第三方
X
可以在不让
A
和
B
所以,当
A
发现的情况下将
A
的公
数字证书就是为了解决“无法确定公钥归属者”这一问题而出现的
。 下面我们来了解 PA
和
一 SA
求,让
CA
,
下数字证书是如何工作的
并且决定将
。 PA
发送给组织
B 。
颁布一个证明公钥
PA
属于组织
组织 A
A
假设组织
A
需要向
的证书
CA( 。
CA
CA
CA CA
提供自己的个人信息,例如公钥
。
利用自己私钥对组织
和
CA
PA A
A
提供的消息一起生成 从现在开始,
CA
同样,每个
生成的数字证书
一
提供的
A
。
就不向
自身也拥 。
CA
就是用于管理
,但是最好还相信由政府或者大
CA
、电子邮箱等
呢?
)发起请
当
CA
有一对公私
钥,组织
收到由组织
A
A
提供的信息时,
数据进行签名,得到字然后将生成的
个文件并发送给
A ,这个文件就变成了 B
在那之后,
certification authoriy
那什么是
数字证书的一个组织,般来说任何人都可以称为
型公司这些信用度高的组织担任
拥有一对公私钥,分别记为
直接发送自己的公钥
B
PA
A
向
CA
索取它的公钥,并利用
的数字证书
了,取而代之的
。
CA
A
的公钥验证
向
B
发送来自
A
发送的
向
•!•
220
数字证
Hyperledge r Fabric
书的
真实性
。
源代码分析与深入解读
数字证书中的签名仅可以用产生该
CA
换句话说,如果验证不
出问 可以提取数字证书中
A
题
算完成了
,那就可以说明
的公钥
该数 PA
了
。
经
字证书确
实是
过这个程,组织
由该
A
的公钥来验证,
CA
向组织
颁布的,然后就
B
传输公钥的过程就
。 让我们看这种公钥传递方式是否存在问题
。
递自己的公钥,但是
B 在认证
机构 注册公钥
X
于
A
的证书
。
X
什么
?在这
种情况下,
只能创建使用
X
通过使用数
字
X
A
的恶
办
A
证书系统,可以验公钥的所有者
法确认是谁
创
建了公钥
级的
X
当
试图传
X
冒充
A
们说 PC
X
B
收到
)是否真的由认证
伪装为认证机构创建的
。 实际上,认证
机构的
这
)也作为数字证书被交付,并且“签名”认机构的一方是更高等
认证机构 签名
那么
早些时候我
收到的公钥(
,它可能是由
方
因此,他们无法获得属
。
PC
三
的电子邮件账户,因此
。
换句话说,我们在公钥加密中发现的同样问题也出这里了
个公钥(
意第
。 B
建的?因为没有
无法访问
的电子邮件地址证书
了证书颁发机构的公钥,但是现在存一个问题:
机构创
充
。 生
。
冒
没有理由相信一个作为数字证书发送的公钥
时会发
无法获得发行证书
假设一个
。
认证机构形成了一个树状结,高级权威为较低别的
创建
数字
。 下面
来了解这个
认证机构的树状结是如何运作
任的认证机构
Y 因
此,
G
公司
。
,即使新公司
G
需要 拥有
Y
分履行认证机构的职责
。
想要作为认证机构开始服务,它在社会上也是没有信
誉
公司颁发的数字证书
。
在这之后,
G
通过这样做,大组织可以确保
比方说,我们有一个社会广泛信
小型
当然,
Y
公司会检查以确保
G
公司就可以宣称自己是一家赢得
Y
机构自己证明
其自身的有效性
。
。 ( rot
CA
那么,
),这
类
另外,如果根证书颁发机构本身不是一个值得信赖的组织
那么它颁发的证书也不会被使用
。 组织,如大公司和政府机构
公司信任的 。
机构 因此,现实中相当一部分
CA
是已经具有社会公信力的
。
BCSP
9.2
概要
BCCSP ( BlockChain Cryptographic Service Provide 模
块主 要提
供了区块链中
需要使
)即区块链加密服务提供者,这个
块,是保证联盟链安全的基石
用的密码学标准和算法,是整个项目中非常
重要
的一个模
。
9.2.1 核
BCSP
心代码的前提下
BCSP
简介 在设计的时候
考虑了一
, 可以提供不同密码学方法的实现
个非常重要的特点,就是可插拔性即在不改变
Fabric
。
。
公司能够充
组织拥有信任度,从而形成的树状结构
谁在认证机构树的顶部?最高级别书颁发被称为根
的
与实 加密服务提供者的设计
CSP BC
9 章 第
现
21 令
type BCCSP interface { KeyGen(opts KeyGenOpts) (k Key, err error) KeyDeriv(k Key, opts KeyDerivOpts) (dk Key, err error) (k Key, err error) ortOps) 呻 Keyimport(raw interface{} , opts KeyI (k Key, err error)
[]byte)
GetKey(ski
,巳 Hash(msg []byte, opts HashOpts ) (hash []byte (h hash.Hash, err error)
error) r
GetHash(opts HashOpts)
Sign(k Key, digest []byte, opts SignerOpts) (signature []byte, err error) SignerOpts) (va lid bool , err error) pts Verify(k Key, signature, digest []byte ,。 Encrypt(k Key, plaintext []byte , opts Enc
(ciphertext []byte, err error) ipterOs)
巧
(plaintext []byte, err error)
Decrypt(k Key, ciphertext []byte, opts DecrypterOpts)
4 个 的接口中,可以看出这部分主要提供了
BCSP 在上述
功能模块: 基本
口对密钥生命周期的管理; 口对消息进行哈希处理; 口对哈希生成的摘要进行签名和验证; 。 对消息进行加密(称或非) 0
法
签名方法或者 加密
和 ECDSA
系列的哈希算法、 SHA
以看到整个模块大致实现了
等 系列的对称加密算法及相应中不同安全级别 const
( H
P&口&
户』户』”
ECDSA = ” ECDSA ” AAD 23A 64R 58 nunuph ssc 23e rOAAa 58R SSS AAA CCC PPR DDD EEE == EE ”口“
CU
nd
>
RSA =” RSA" RSA1024 =” RSA1024 " RSA2048 =” RSA2048 ” RSA3072 =” RSA3072 ” RSA4096 =” RSA4096 ” AES =” AES" AES128 =” AES128 ” AES192 =” AES192 ” AES256 = "AES 256 ” HMAC = ” HMAC ”
-
mD
们 中我
opts.g 在
。 项目中的可插拔性
fabric hyperldg
了整个模块在
模块中提供了很多可定制的选项,这一点也体现 BCSP
在整个 。
一种 个通用的方法群,它并没有告诉我们具体应该使哪
一 仅提供了
BCSP 因为接口
。
RSA
系列的签名算法
在常数定义部分可 、
AE
S
•!•
222
Hype
巾
dger
Fabric
源代码分析与深入解读
HMACTruncated256 =” HMAC TRUNCATED 256 ' ’ SHA =” SHA ” SHA2 =” SHA2 ” SHA3 =” SHA3 ” SHA256 =” SHA256 ” SHA384 =” SHA384 ” SHA3 256 =” SHA3 256 ” SHA3 384 = ” SHA3 384 ” X509Certificate =” X509Certificate ”
在对密钥的抽象和管理方面,不论是称还非 Key
BCSP
这个接口来表示
都统一使用
。 type eyK 工 nterf Bytes() SKI () S 沪
ace { ([]byte, error)
[] byte
nmetric
() bool Private() bool PublicKey()
(Key,
对于称密钥来说,
error)
Symetric
()方法返回
false ;而对于非称密钥来说,
Symetric
私钥对应的公值
true, ()方法则返回
PublicKey
()方法返回一个 false,
PublicK
nil ey
值和
()方法返回与该
。
so
er
{
飞
n
R
-工
CLa c e fMO yd ol mr e ke ea eo ry Rb rl
←」
•L
GetKey(ski
[]byte)
StoreKey(k Key)
除了对使用密钥进行
(k Key, err error)
(err error)
一
系列的加密操作以外,钥本身存储机制也同样非常重要
因为机器本身存在岩的可能性
。
如果所有密钥仅存在内中,一旦机器出现问题将
出现不可逆转的损失,所以一个靠密钥存储机制非常有必要
。 KeyStor
代表了密钥的存储系统,在非只读情况下它支持两个简单操作即
储密钥和通过
ski
取回密钥
。
当在只读限制条件下,
StoreKy
方法将返回
ero
。
因为在联盟链中大量地使用了签名算法来保证信息的真实性,所以深入解一下 算法尤其是
ECDSA
在理解
ECDSA 。
。
陷阱函数
9.2.2 特性
的原理对解整个签名过程还是非常有增益
如果私钥可以轻易被别人获取或者破解,那利用算法得到的签名将毫无意义
之前,首先要理解签名的真实性来源与用于私钥无法被伪造 。
所以,
第
9 章
BC CSP
加密服务提供者的设计
与实现
私钥无法被破解(即的难度非常大)是整个密码学前提条件
·:
223
。 利用
ECDSA
进行签名或验证需要有两样东西:私钥和公
。
单地用陷阱函数来描述
。 “点乘法”得到
R=k
预先知道了
假设私钥是一个随机数
·P 。
k , p 即使你知道
R
和
私钥和公的关系可以简
为椭圆曲线上已知的一个点,则通过
P ,你也无法通过这两个点来获取
k 值;而假如
k 值,则我们可以非常轻松地得到
R
值
。
总结一下,陷阱函数的精髓就是正向演算非常简单而逆推导难度大这 ECDSA
算法安全性的基础
。
为什么要使用
9.2.3
ECDSA
举一个非常简单的例子,比如你将
一
别人下载到的文件是
真
份文件传到互联网上供他人下载,但你需要保证
实的,所以你根据文件计算出相应哈希值和放在一起望
别人同样计算哈希值与他们下载的文件相对比
。 方可以篡改你上传的文件,那他们
一 不可靠
。 文件(
现在我们需要的是
一
一
但这存在一个比较严重的问题
: 如果第三
定也有办法篡改相应的哈希值,所以方并
种别人无法伪造的算,即我们使用他获取私钥对
般来说是文件的哈希值)进行签名
。
签名值和文件一起放在网站上,因为第
三
法伪造出与我们的私钥,所以他也无签名
。
应的公钥对签名进行验证,而确定文件真实性
方无
下载者可以利用与我们私钥对
。
生成签名
9.2.4 这里简单介绍
一
签名的长度为 合
40
下如何生成签名
( R , S )共同组成了
。
字节,分别由两个
20 ECDSA
签名
字节的值组成,分别是
R 20
P ,其中
示,点
P
要
的
x 值就是我们需要的
S ,它
们两个的组
。
那又如何来生成这两个值呢?首先,需要一 曲线上的“点乘法”获得
和
P=kG R ,这里
。 x 和
由于
P
字节的随机值
k ,然后利用椭圆
y 都是
点可以由
( x,
20
y ) 这样的坐标表示法
字节,得到了
R
之后,接
下
来我
们
需
S 。 为了计算
S 的值,你需要对原始消息进行
SHAl
哈希
值,你可以将它理解为非常大的一个整数这里记
。
z 。 公式
计
算
哈希的结果是一个
20
得到了
字节的
z 之后,我们可以通过下
S:
S=k/\-1 (z+dA *R) mod p 值得注意的是,这里护 于
1 。
- 1 的意思是
。
再来重复一遍这里用到的几个关键信息
模逆元的性质就是(
k/\
: k 是我
z 是我们消息的哈希值, 的指定起点坐标
k 的模逆元
。
dA
是我们的私钥,
R
是
k*G
的
们随机
生成的用于计算
x 坐标
-1
*k) modp
,
R
G
是我们用到的椭圆
的
等 一个数,
曲线
•!•
224
Hyp erledger F a bri
c 源代码分析与深入解读
验证签名
9.2.5 在得到了签名之后,为验证它的正确性你只
需要
椭圆曲线的参数),便可利用下面公式来计算
用于签名的私钥所对应公(及
P: P=SI\
如果
P
点的
x 坐标的值等于
R
签名的数学证明过程
*R*Qa
一 lzG+S/\-1
值,则说明签名是有效的否无
。
下面是验证
。 因为
P=S
而
/\ -l
zG+S
Qa=dA*G
/\ -1
*R*Qa
,所以我们有下公式:
P=S A-l zG+S /\-1 *R*dAG=S /\-1 (z+dA *R)*G 而
P
的
x 坐标应该
等于
R ,而
R
是
k*G
的
x 坐标
,
这意味着
:
kG=S /\- 1(z+dA *R)G 当两边同时移去
G
我们有
:
k=S /\ _ l (z+dA 进一
步变
化
得到
呗)
:
S=k/\- 1(z+dA *R) 这就是我们之前用于生成
S
确的
的公式,两者相符说明上面用于验证签名是正
。
BCCSP j 原码剖析
9.3 本节将讲解
BC
BCSP
CSP
区块链加密服务这一模的设计与实现
。
服务涉及的算法
D RSA
: : 一
D AES
种非对称的加密算法,用于
。
: 一种块加密
D ECDSA
算 : 一
口
Has
口
HMAC
h :
法,用于加密成块的大
量
种椭圆曲线签名,用于
哈希
。 。
有
几种
族簇,如
SHA2
56
一
种,可参看第
D PKCS#l l : 一套
12
9.3.1 BCSP
几种族簇,如
AES128 EC
SHA3
256
章中对证书的解释
、
删除
等
。
。
以上算法可用来进行建立、
DSAP256
等
DSAP256
、
BCSP
ECDSAP384
等几种类型
. go
中开始部分定义,如
、 ECDSAP384
等 等
ECDSA
。
服务结构 Fabric
项目提供各种
加
密技术、签名,
MS
P 服务模块中就使用到了
。
、 AES192
。 fabric/spot
为
RSA2048
。
等操作管理
用到的这些技术常量名称在/ EC
有
标准安全接口,可与硬件相关
读取、写人修改 支持
。
、
。
: 证书的
Fabric
数据
R SA1024
有几种族簇,如 、
:与密匙相关的哈希运算消息认证码
D x509
有几种族簇,如
。 。
。 选项实现
的 模块提供窗口
他 模块提供了窗口函数(就是给其
服务的 BCSP
1.
函数
中
。
中的接口和选项 BCSP
9.3.2
量 所定义的全局变
. go
/ factory factory
实例存储在 BCSP
生的
接口 代码如下:
接口相关
中定义
/ bcsp.go
/ bcsp fabric
type BCCSP i nterface { 生 key /根据
key 来生成一个
opts 成选项
” 证书一级认
( 与“ key
要适合原始的 选项
, opts
有关的选项 key
/与
对应
)
KeyGen(opts KeyGenOpts) (k Key , err error) 一个 重新获取
k 中
, 从 opts
y 获取选项 ke
根据 /
KeyDeriv(k Key, opts KeyDerivOpts) 据 /根
导入 key
opts 选项
,
从一
个
原始的数据中导 key
key (dk
Key, err error) 入
一
个
key
Keyimport(raw interface{}, opts KeyimportOpts) (k Key , err error) /
根据
SKI
返回
与该接口实例有联系的
key
数一 这些函
函数,
InitFacores 管理自己服务的功能模块,供外界调用如后文所讲
一
的
Security Modules Hardwe
是
II
服务实现,这里有两种工厂为其 BCSP
相对应的两种 。
安全模块 即硬件
htps:
HSM 而
这个库为基础,
工l kcs
/p
/ miekg github.com
是硬件基 pcksl
, 中
其
这个硬件基础的实现以 。
是软件基础的加密服务实现 SW
现, 密服务实
。 SW
l 和 pkcsl
服务有两种实现: BCSP
从以上可看出,
/在
服务可以使用到的各种技术 BCSP
表示该目录下的各种值,
: X Xopts.g
。 不存储
则 果是暂时性的,
:如 该接口的实现对象中
存储在 的,则
不是暂时 key
的管理存储接口,如果生成
k ey 定义了
:
. go tore
keys
。 等
i v Opts KeyDr
、 KeyGnOpts
、
K 町
到的选项接口,如 接口所使用
BCSP 、众多
口 接
Key 、
BCSP :定义了
D bcsp.go 口
。 务工具函数
服 BCSP
l s: uti
implementation
) 。
of the BCSP 口
-based
(the so 位 ware BCSP
一软件基础的 二
务实现之 服
0 sw: BCSP
般统
( the hsm-based BCCSP
) 。 implentao
口
BCSP 基础的
HSM →-
服务实现之一
11 : BCSP pkcs
口
。 务工厂
服 BCSP
factory: 口
使用
签名 向外界提供
签名接口专用于 的
该目录 。
服务实现中 SP
M
1 2 章中
。 对象
他
。 服务
接口,可参看第
s igndety 身份
的
225
,目录结构如下: 中
Signer 的
标准库
c rypto
现的 是 实
带“专用签名笔”
缩写,
/ bcsp
BCSP :
signer 口
础的加
/ fa bric
:模拟代码文件夹,可以参看帮助理解 mocks
口
码集中在 服务的代
BCSP 。
BCSP
9 章
•! 加密服务提供者的设计与实现
BCSP
第
) 。
所有产
•!•
226
H y p erledger Fab ric i 原代码分析 ,
GetKey(ski
与 深入解读
[] byte)
/根据哈希选项
opt
(k Key, err error)
s 对一个消息
msg
进行哈希计算,如果
op
Hash(msg []byte, opts HashOpts) /根据哈希选项
opts
获取
has.
Hash
GetHash(opts HashOpts) / * 根据签名者选项
opts
ts
为空
,
则使用默认选项
(hash []byte, err error)
实例,如果
opts
为空
,
则使用默认选项
(h hash.Hash, err error)
, 使用
k 对
digest
进行签名,注意如果需要对一个特别大的消息
has
/进行签名,调用者则负责对该特别大的消息、哈希计算后将其作为
diges
Sign(k Key, d i gest []byte, opts SignerOpts ) /根据鉴定者选项
opts
,
通过对比
k 和
digest
,
p ts
由
,
使用
k 加密
(signature []byte, err error)
据解密者选项
opts
,
使用
k 对
ciphe rtex
[] byte, err error)
工 phertx
Dec
巧
(plaintext []byte, err error) ipterOs)
选项
BCSP 套
(c
进行解密
Decrypt(k Key, ciphertext []byte, opts
2.
(val id bool, err error)
p laintex
(k Key, plaintext []byte, opts EncrypterOpts ) icrypt
/根
文件夹中任何
带“
选项,我们在讲
MSP
opt
”字眼的文件
,
服务的时候就见识过
。
都是和选项有关的源码
根据
。 一
关于对象
的配
个选项的不同配置,对象主体可以得
到不同的数据或进行操作,这也是一种比较值得学习语言上组织技巧尤其 项
在
BCSP
这种涉及的技术比较多,而每个对象自身又分为好类情况下
Hash
。
Opts
和
/在
key
导人选项
Key
ImportOs
fabric/sp.go /
在此以哈希选
作为例子进行说明:
中定义
哈希选项接口
type HashOpts interface { Algorithm() string / 取哈希算法字符串标识获 /在
fa
bric
/bcs
p /has
/哈希选项实现之一
,
hopts.g
,
如
咀
HA256
”唱阻
3
256 ”
中定义
SHA256
选项
type SHA2560pts struct {
项
QU
Aτ
mm 飞dc
←」
←」
s s
JZ 电 {‘
--
【 b
8
之 严
实
川
L
现 ω
希
’’’’- ’
州附
飞’
蚓则
func (opts *SHA2560pts) Algorithm() string { return SHA256
、、,,
func
(opts *SHA3840pts) Algorithm() string { return SHA384
/在
fabric /key t 归
/在
* /
鉴定签名
Verify(k Key, signature, digest []byte, opts SignerOpts) /根据加密者选项。
值
t 传入
/bcs
p /bcsp.go
中定义
e
导入选项接口
KeyimportOpts interface { Algorithm() string /返回 key 导 Ephemeral () bool /:如果生成的 fabr
i c/bsp
/。
pts.go
中 定义
入算法字符串标识
key
是短暂的(
eph m
ral
),返回
true
,否则返回
false
第
/key
导
入选项接口实现之
一
,
ECDSA
9 章
公匙的
导
BCSP
加密服务提供者的设计与实现
·:
227
入选项
type ECDSAPKIXPublicKeyimportOpts struct { Temporary bool func
(opts *ECDSAPKIXubl return ECDSA
func
(opts *ECDSAPKIXPublicKeyimportOpts) Ephemeral() bool { return opts.Temporary
/key
工 cKeyimportOs)
导入选项接口实现
之
二
,
Algorithm()
ECDSA
私
匙的
string {
导入选项
type ECDSAPrivateKeyimportOpts struct { Temporary bool func
(opts *ECDSAPrivateKeyimportOpts) Algorithm () return ECDSA
func
string {
(opts *ECDSAPrivateKeyimportOpts) Ephemeral () b o ol { return opts.Temporary
/比
较特殊的
,
/由于
SignerOpts ,
SW
BCSP
的
中
工
因此使用到选项时多赋值为
口 il
Soft
Ware (SW
厂的默认选项
源码中未实现
/ fabric
和核心配置文档中关于 has
、
BCSP
)实现形式是默认的,这点仅从
DefaultOps
主要使用的包是标准库 eliptc
,
实现方式
9.3.3 go
比如签名选项接口
使用的是标准库
x509
等)
和
BCSP
/ bcsp/fatory
crypto
的配
(包括其中的各种,如
aes
/ opts.
置 、
rsa
就可以 、
看 ecdsa
、
出来 sha256
。 、
。
/fabricspw
目录结构:
D imp!. go : BCSP D interals.go
的
的
! 。
函数、加密者
/ 解密者实现 、
类型的签名者
公匙
、 公匙
巳 y.go
类型的
:巳 rsa
eds
Key
a 类型的 Key
短暂的,则说明这些
key k 巳 y 就消失了
。 。
接口实现
。
接口实现 类型的
。
/ 私匙鉴定者实现
Key
类型的
。
/ 私匙鉴定者实现
接口实现
D dummyks.go : dumy
D fileks.go : file
。
key
D aeskey.go: aes rsakey.go:
实现的配置定义
类型的签名者
D rsa.go : rsa ecdsak
SW
类型的生成
D ecdsa.go: ecdsa
些
imp
。
D aes.go: aes
口
实现的
:签名者、鉴定加密解接口义
D conf.go: BCSP
口
SW
。 KeyStor
接口实现
dumy
KeyS tore
不会保存到文件中,而是内系统
。
当生成的
key
一
关闭,这
类型的
。
KeyStor
接口实现
fileBasdKyStor
。
若生成的
key
不是短
是
•!•
228
Hyperledger Fabri c j 原代码分析与深入解读
暂的,则说明这些 key
会 消失
在导人时,会存储文件中即便系统关闭这些 key
。
BCSP 接口实现:
/ 在
/ fabr
工 c/bspw /工
mpl.go 中定义
//SW CSPB 的实例结构体 type impl struct { conf *config ks bccsp.KeyStore encryptors map[reflect.Type]Encryptor decryptors map[reflect.Type]Decryptor signers map[reflect . Type]Signer verif
/
工 ers map[reflct.Ty]Vi
/ BCSP
/
实例的配置
key
I
存储系统对象 ,
I
Key 对象
; 解密者映射
/签名者映射 ,
工 er
存储和获取
加密者映射
/鉴定者映射
Key ,
实现的类型作为映射键
Key 实现的类型作为映射键
专用生成函数
func New ( /
)
(be esp BCCSP, error)
{ . .. }
接口实现
func
(esp 吐
rnpl)
KeyGen(opts bccsp.KeyGenOpts)
粗线条上看,由于 imp
switch-ae 如
也不
(k bccsp.Key,
... ) { ... }
I 对象和各种操作选项的存在,绝大部分接口实现都是以
为主干,根据选项的类型或配置分情况完成功能且每个支操作都似 Key Gen 。 接下来 一
D KeyGn
介绍:
:根据
ECDSA
key 使用库巳
数(在
生成的选项不同, 三
cdsa
aes.go
的 GenratKy
种系列的
函数,
key
中实现,包装了
AES
rand.Re),
,即
RSA
的
实现对象,如
Xkey.go
ecdsaPrivtK 中)
系列的 key
。
使用库 rsa
D KeyDriv :根据
opts
k
代表 Public
和
,即
Private )和
:从原始的数据 raw
ECDSA
key 为了得到 utils.Cone
key 和
,对原始数据
) 。 raw
。
。
指定的
模块是
key 。
hmacedKy 中
类型,即
最后返回打乱 。
ks
MSP
这里的重新获
处理两种 对于重新生成的
key
。 ,如果该 key
这里的原始数据,指是口 byte
不是临时性
或者含有 key
是一个空接口,也就说可以收任何形式的原 raw
utils.DERToPbcKey
。
而
BCSP
。
aesPrivtKy
opts
key
key
,则会存储在
中取出选项
中,最后返回
的数据(如证书里
个 和
key
key key
reRandomizKy
,如果选项中指定的不是暂时性
ks
的
中重新获取一个 一
key
的,则存储在
工具函数
,从
每
最后返回
,只支持
。 ECDSA
重新生成的两种类型 Import
。
町等(分别定义在同目录下
k 中的内容重新打乱再生成
。
函数
。
,也只有被调用者能决定使哪一种
获取选项
ecdsaXXXKey ( X
始数据
巳 y
,具体的细节略过
aesPrivtK
,应该是在它这个地方只认
key
取可以理解为把
Key
GenratK
key
一
。 函
。
的使用者之
key
RSA
,这是官方文档中所说的但从实现上看签名支持不止一种 key
BCSP
、
的
这里要注意的是,当前版本中用于签名
本质上无论实现多少种
口
町
AES,
GetRandomBys key
key
、
使用自定义的
个系列又根据具体参数的不同生成“尺寸”
不同的
ECDSA
进行转化或抽取, ,如
一 AES256 、 ECDSAPrivateK
部分使用了 utils
町等类
下的
Pu 表示
x 里
的 New
数
Typ reflct.
型为
aescbpk7Enry 追溯,
0 Decrypt : 解密与加类似,也是只有 。
巳 Of(k
or
使用
aes
的接口 。
库的加密流程进行
aes
配套实现,最终使用
aes
获取类 ryptos
enc encrypto
;然后直接调用 encrypto
)的加密者
。 被使用
aescbpk7Enryto
实例的加密者集合成员 BCSP
这里加密的实现过程是,首先从该
解密
町, aesPrivtK
赋值部分,只有 rs
encrypto
专用生成函 BCSP
SW 参看
。 -aescbpk7Enryto
是用来加密的) aes
只有
,因为 aes
中实现(只能是 aes.go
密
加密者接口 。
接口实现如上描述
中,在 interals.go
定义在同目录下的 Encrypto
Key 。
中的实现 BCSP
SW 在
Encrypto 者接口
加 接口和
Key 密涉及*
加 。
tex plain
k 加密 ,使用
opts :根据加密者选项
0 Encrypt
函数(这 PS
Verify
) 。
i vate Pr
或 blicKey
Verifier
库的 rsa
使用 Verif
rsaXKey 函数,
Verify 库的
dsa ec
使用
ecdsaXKy ;追溯,
Verify 的接口
verif ;然后直接调用
verif 鉴定者
)的 TypeOf(k
reflct. 处获取类型为
verifs 实例的鉴定者集合成员
BCSP 首先从该
这里鉴定的实现过程是, 。
接口实现)都有用到 Key
分,可知所有鉴定者(与对应的
赋值部 verifs
的 New
专用生成函数 BCSP
SW 参看
。
V 巳 rife/saPvtKyV
巳 yKe rsaPublicK
中的 rsa.go
和
中的
. go ecdsa
er/ ecdsaPri vateKey Verif
飞 1erif
ecdsaPubl icKey Key
鉴定者接 。
接口实现如上描述 Key
中,有两种类型的实现即 interals.go
定义在同目录下的 Verif
口
。 中的实现
bcsp SW
在 1erif
i 鉴定者接口飞 口和
接 Key
鉴定涉及 。
,鉴定签名 digest
k 和 ,通过对比
opts :根据鉴定者选项
Verify 口
。 函数
Sign 结构体的
PrivateKy 库
rsa 使用
rsaSigne 函数,
Sign 库的
ecdsa 用
使 ner
cdsaSig 追溯,巳
; Sign
的接口 signer
;然后直接调用 signer
)的签名者 TypeOf(k
reflct. 中获取类型为
signer 实例的签名者集合成员
BCSP 实现过程是,首先从该
。这里签名的
- rsaSigne rsaPivteKy
和
- ecdsaSignr ecdsaPrivtKy
,即 Signer
和
Key 赋值部分,可知用到了两种对应类型的
s igners 的
New 专用生成函数
SW BCSP
参看 。
rsaSigne 中的
rsa.go 和
cdsaSigner 中的巳
ecdsa.go 中,有两种类型的实现即
interals.go 定义在同目录下的
Signer 签名者接口
。 里签名(自然)使用的都是私匙
这 。
aesPrivtKy 中的
aesky.go 和
rsaPublicKey/vt 中的
rsakey.go
K 町、
BCCSP
ecdsaPubliKy/rvt 中的
ecdsaky.go 种实现,即
三 接口有
Key 。
中的实现
SW 在
ner Sig
接口和签名者 Key
签名涉及 。
nil 没什么用处,调者都给的是
进行签名,这里的者选项在当前版本 digest
k 对 :根据签名者选项,使用
0 Sign
。 晗希家族
SHA3 SHA2,
默认选项,支持 则使用
空, 为
o pts 果
如
。 的哈希值
msg 进行晗希计算,返回该
msg 个消息
一 对
opts
0 Hash :根据哈希选项
、 町
。 key
町等类型的 RSAGoPublicK
229
ECDSAGoPublicK 类型),如
raw.(*Key 语言的断
Go 部分直接用
一 ;
key 型的
•! 密服务提供者的设计与实现
;tJD BCSP
9 章 第
库解密流程进行
Encrypt;
•!•
230
Hyperledger Fabric j 原代码分析与深入解读
D GetXXX: GetX pkcsl
9.3.4
系列接口,获取实例对象中的数据具体这里不再详述
。
实现方式
BCSP
的
pkcsl
1 实现形式主要使用的库与
SW
github.com/miekg/pkcs 1
库,最好参看其文档以熟悉
BCSP
的功能,也为
BCSP
的
出来:
字
符设备联系在
一
U 或芯片只
需要 对于
。 (参看下文)中所调用的
起
。
l 实现
这点可以从
lo adLib
比如将来,开发出了
一
pkcs
11 , Fabric
函数看
。
1 所提供的接口,在此两个文档地址读者可以稍作了解
: htps: htp:
”
/ 6 的
1 eac56/indx.html#
hapter2-9
是通用的接口,所以有
一 impl.go:
的
:定义了 Opts
口
pkcsl
l.go
口
:以
、
/ E
19253 -01/819-
区域链无关,但是因为
pkcs
库中的解释相对过于简单 imp
11
。
!。
服务的配置和
PKCSlOpts
1 库
、
. go
FileKystorOp
、
DumyKestor
k 町
! 在巳 aes
ecdsaky.go
eds
l 功能
、
,实现了
imp
l 基于
pkcsl
l 的
dsa
。
signECDSA Key
ec
加密、解函数
a 技术下的签名函数
类型的
:实现
PrivateKy
pkcsl 服务使用到的独立内调函数
类型的生成
imp :实现
为基础,包装各种
BCSP
aes
: 实现
D aesky
Fabric
pkcsl
l 实现的
pkcsl
:实现
ecdsa.go 口
pkcsl
一些
a es.go
/ cd
。
内调函数,和 口
这些文档与
。
BCSP
选项
/ docs.ralem
/ /w.
目录结构:
bcsp
conf.g
。
定参考价值
/fabric/bccsp/pkcs 1 口
款在区域链上使用的,类似于现
即可对此进行支持和扩展
ibm.com/developerworks/cn/security/s pk cs / 和
和鉴定函数
接口,只实现私匙
类型的
Key
verifyECDSA
aesPrivtKy
。
。
接口,实现了公匙
ecdsaP
ublicKey
和
私匙
ecdsa
rsakey.go
。
:实现了
rsa
类型的
Key
D dummy ks.go : dumy D fileks.go: fi le 类型的 BCSP
11 ( Public-
盾之类的确认个人身份或安全交易硬件模块芯片,这些
也遵循 pkcsl
口
pkcs
加载了一个系统中的动态库,能就可以和驱、热插拔
连接电脑的
口
。
支持热插拔和个人安全硬件模块提供了服务 New
在网上银行所用的
7056
1 的简要操作
pkcsl
l 的实现例专用生成函数
loadLib
辙,只不过外加一个
)是一套通用的接口标准,可以说这里
Fabric
pkcsl
一
pkcsl
Key Cryptography Standards, PKCS 了
实现如出
Key
类型的
接口,实现了公匙
rsaP
Store
KeyStor
接口,实现
ublicKey
和私匙
rsaPivteKy
DumyKeStor
接口,实现
。
。
FileBasdKyStor
。
接口实现:
type impl struct { conf *conf ig ks bccsp.KeyStore ctx *pkcsll.Ctx sessions chan pkcsll .SessionHandle slot uint /
配置
/
key
存储系统对象
, pkcsl
uint /安全硬件外设连接插槽标识号
/实质是
/标准库的
存储和获取
Key
对象
,
上下文
会话标识符频道
,
默认
10
个缓存
第
9 章
BCSP
加密服务提供者的设计与实现
•!
231
/加载库所在路径
lib string noPrivimport bool softVerify bool /禁止导入私匙标识 /使用软件方式鉴定签名标识
} /专用生成函数 func New(opts PKCSl
keyStore bccsp.KeyStore)
工 Opts,
(bccsp.BCCSP , error)
/接口实现
func
(esp *impl) KeyGen(opts bccsp . KeyGenOpts)
BCSP
的
pkcsl
现的语句时,
l 实现的骨架在
SW 则用
pkcsl
话(
imp
实现是使用
l 包对
crypto
I.go
中与
(k bccsp.Key, err error)
SW
的
实现基本一致,只是追溯到最终
库下的各个包进行签名
、
数据进行了多一层的处理,使用
pkcs
SesionHadl
1
加密
、密匙
导人等;而
提供的上下文(
)之上对签名、密匙加等进行管理,这也是
两者最大的不同是
pkcsl
一
pkcsl 1 中与安
个面向软件,
一
个面向硬件
全硬件模块建立连接的
loadLib
。
loadLib
函数在
pkcsl
I.go
函
pkcsl
数
pkcsl
pkcsl l .Ctx
l
)在会
l .g o 文件的作用
。
自身又非常冗杂,因此在只讲
。
中定义,供专用生成函数
New
使用
。
为建立与安全硬件模块
的通信,进行了如下步骤:
( 1 )根据所给的系统动态库路径 用
pkcsl
lib
l .New(lib
bcsp
<一
)建立
> ctx
pkcsl
<->驱动
( 2 )对
lib
o
ctx
相当于
Fabric
。
从
ctx
. GetS lotList( true
ctx.OpenSsio
打开
一
个会话
c tx.Login
,把
。
seion
关于
返回
1
发送到
pkcs
ctx
。
I.go
libsofthm2 。
BCSP
Fabric
中某
块
。 / bcsp
/fact
ory
impl
实例成员
。
中
FindPKCSl
. so
导人民
库,它是一个模拟硬件实现的 !Lib
pkcsl, 测试函数中所涉
及 的相
csl
对象
关内容,如
。
实现,这里也有两种
一模
窗口函数,供其他模块调用
,用于赋值给
现阶段是没有安全硬件模块可以配合测试的,所只使用
工厂对应两种
/ fabric
labe
) 。 seion
SoftHM
模拟测试,将
swfactory.g
。
(会话就是通过信路径与
chan
、会话对象
,还有一点可说的就是
libsofthm2.
BCSP
l 的
slot
里
imp
SoftHM
、
seion
对应到系统动态库可参看
下的
标准开发的
)返回的列表中获取由
seion
pkcsl
Linux
l
。
次调用
( 4 ) 登录会话 slot
pkcs
一个,每在系统内核中都有名字和标识号)
10
安全硬件模块建立连接,可以简单地理解为 、
是按照
(这里的插槽可以简单地理解为电脑主机上供安全硬件模块入,
插口,可能不止
( 3 )尝试
ctx
的动态库),调
与安全硬件模块通信的桥梁: lib
()进行初始化 slot
USB
ctx
openCrytki
<一>安全硬件模块,只要驱动
ctx.Inialze
指定的插槽标识
如
1 实例
加载动态库(如
这里以
一旦
be
涉及工厂
factory
swfactory
esp
工厂:
pkcs
11 factory.g
,则说明该模块基本就是由工厂提供
和
为例进行讲解
。
/目录结构:
0 factory.go : 声明了默认 等全局变量和这些的获取函数
BCSP
0 nopkcs 11.go/pkcs 1.go
实例
:定义了两种版本的
Ge
defaultBCSP,
BCSP
tX 工厂选项
。
定义
BCSP
实例存储映射
FactoryOps
工厂接口
bcspMa
,即初始化工厂函数
。
23
令
H ype
InitF
rl edg
r Fabric
a ctorie
源代码分析与深入解读
s 和获取指定
B CS
P 实例的函数
GetBCSPFromOps
。
版本,可根据相应条件编译指定使用哪种(
译时 项)
。
两种版本的差异集中在是否使用
pkcs
0 opts.g 口
:
定义了默认的工厂选项
上
DefaultOps
pkcslfatory.g:
pkcs 1l 类型
0 swfactory.go : SW 选项
1
类型的
的
入
no
pkcsl
是默认
1 或!
nopkcsl
l 选
。
。
B CSP
BCSP
加
nopkcsl
工厂实现
PKCS
工厂实现
1lFactor
SWFactory
。
y 。
还定义了
SW
版本的
BCSP
。
swfactory
接口和
/;在
实现
factory.g
:
中定义
/接口
type B CSPFactory
工 nterf
/返回工厂的名
ace {
字
Name() str ing /返回符合工厂选项
o pt
s 的
BCSP
实例
Get(opts *FactoryOpts) /在
swfactory
. go
(bccs p. BCCSP , error)
中定义
type SWFactory struct{} func (f *SWFactory) Name( ) string { return Sof t wareBasedFactoryName func
Get(conf
(f *SWFactory)
工 g
实现的代码本身比较简单, opts
Ge 的
bcsp
实例的
在每
个
。
chain
Name
code
则
的垫片
shim
例子中,如
核心代码 shim
/ fabric
/ core
。
其
中
shim
的
DefaultOps opts.g
)来初始化
。
chain
code
New
垫片
shim
中
函数就是用来启动一个 。
c hain 在
Star
个默认的
的
函数中,就调用了
swfactory
。
工厂,在此可以知道这里使用的默认
Star
函数
形成的通信息,过
。
shim code
,其被定义在 e r
BCSP
中的
chainode
中,该垫片所承的是与各个节点通 c hain
Star
来生成符合
_ cli/examples/chaincode/go/chaincode_
code / shim
{ ... }
。
责从各个节点收集信息,汇总并返回给
一 )就是使用的
c hain
/ chainode
专用生成函数的
常量
/ e2 了
服务 负
shim/ chaincode . go (参看
中在
SW
/ exampls
,都使用
ChaincodeSuprt 节点,然后
一个
/ fabric
集
信的任务,也即
SW 返回
. go
(bccsp .BCCSP, e rror)
t 最终是调用的
是直接
example02/chaincode_ exampl02
能
*FactoryOpts)
code
,
/ fabric
分
完成
chain
/ core
发到各个 code
的
功
/ chaincode/
:= factory.InitFactories( &factory. 工厂
选项
阜旱
响PP
们
、J
dE
,
HHH .·
圄
····
..... ....... ·-·. .... .... ... ... G UTUh’ r U u -
Fabric CA
Fabric CA 功能
为
Hyperldg
r Fabric
架构设计与讲解
提供证书
机构的功能
。
具体来说,
Fa
bric
CA
提供以下
:
( 1 )身份注册,或者将连接到
LDAP
( 2 )颁发登录证书(
ECe
( 3 )证书续期与撤销 包
对贡献
。
) 。
含一个服务端组件和客户,稍后会进行介绍
Fab
。
ri c CA
感兴趣的开发者,可以参考
Fabric
Fabric CA
10.1 10-
了
Fa
bric
CA
Fabric
Fabric CA
的
ca
/ swag
/ swager
CA reposity
。
用户指南
所示说明
有两种方式可与
这个文档
为用户注册
。
Fabric CA
图
rts
作
CA
服务端如何在
交互都是通过
Hyperldg
RES
服务端交互:通过
Fa
T
AP
巳 r- fabric-ca.j son
。
ls
来实现的
。
你可以通过
Fabr
i c CA
R EST
APis
htp:
bri
c 架构中发挥作用
。
客户端或
Fa
的
swager
bric
SDK
。
所有与
说明文档见
fa bric
/ edi tor2 .swagger. i 。 在线编辑器来查看
。
Fabric CA
客户端或
者
端,这一部分可以
参看图
S DK
HA
代理节点为
Fabr
所有的
i c CA
Fabric
配置了 一
LDAP 个服务端可能包
CA
,那
10-
可能
会连接
右上部分
。
集群作负载
服
到 均衡
Fabric
一 个
个 HA
Fabric
CA
服务
代理节点,这个
。
么用户信息将会保存在
L DAP 证书
中的某 一
。 CA
集群
图中客户端连接的是
务端共享同一个数据库 含多个
CA
。
每一
数据库用来保存户和证书的信息
。
个
中,而不是数据库 CA
。 证书都
是一个根
CA
证
书或
者一
个中间
如果
MW
…
.>
234
CA
证书
父
。
Hyperledger Fabric
CA
证书
而
每一个中
源代码分析与深入解读
间
CA
证书都有
一个根
CA
证书或者其
他的一个中间
CA
证书作为其
。
Cluster of Fabric CA Server Fabric CA Root Server
图
I
Fabric CA
0-1
的作用示意图
入门 下面来体验
Fabric
1.
CA
。
前置条件
请检查系统是否符合条件
: 口安装了
Go
D GOPATH D libto
1.9
+ 。
和
环境变量设置正确
。 libtdh-ev
以下命令用于在
两个已包安装好
Ubunt
系统安装
sudo apt install 以下命令用于在
。
l工
libto: 1 ibltdl -dev
btol
MacOSX
系统安装
libto:
brew install libtool 若要了解更多有关
libto
的信息,可参考
manul/ht_odeUsig
若要了解更多有关
libtdhr -l ibltd.hm
-de
htps:/
v 的信息,可参考 。
/w
htps:/w.gnu
. gnu.or/sftwae
libt
. org/sftwaelib
ol/
。
•! 计与讲解
架构设
Fabric CA
章 10
第
235
2 . 安装
fab 果你已经下载了
:如
, ric-a
分 master
『命令时确保当前位于 get
go 在运行上述’
: 会看到如下报错
则你将 支,否
。
- client
- ca fabric
u github . com/hyperledger/fabric-ca/cmd/ ...
go get
注意
和
『 serv fabric-
路径下同时安装 $GOPATH/bin
以下命令会在
ca ; git pull --ff-only 工 C . com/hyperldgfab /srciub for the current branch. 工 on There is no tracking informat Please specify which branch you want to merge with . git pull If you wish to set tracking information for this branch you can do so with: branch - set upstream-to=/ tlsdoc
g 工 t
package github.com/hyperledger/fabric-ca/cmd/fabric-ca-client: exit status 1
原生启动服务器 3.
fabric-sev: 默认配置启动
fabric-ca server start -b admin:adminpw
ID 来提供启动管理员的登录
b 选项用 :-
其中
会自动在本地目录创建,这个配置文件可以
- config.yaml
fa bric-asev 默认配置文件
。 的
是必需
- b 选项
enabled ”设置,则
“ ldap 没有启用
L DAP 码;如果
和密
。 自定义
启动服务器 Docker
通过 4.
。 完成准备工作后,使用命令行来启动服务器
1 ) Docker Hub
docker
。
- compse.yl docker
开
ym
” compse.
/ docker
/ fabric-
/ hyperldg
/ github.com
/ src $GOPATH
进入
。
的标 签 合
版本相符
- ca fabric
/ ,找到与你想下载的架构和
/ tags
/ fabric-
/ r / hyperldg htps:/ub.dockerm
访问
。
l 文件如下所示
fabric-ca server: image : hyperledger/fabric-ca : x86 64-1.0.0-beta 工 c-aserv container_ name : fabr ports: - ” 7054:7054 ” 口 ment:
e 口 viro “
FABRIC
_CAHOME=/etc
/hyperldgfab
工c
路径并在编辑器中打 beta
一行进修改。 image
根据之前找到的标签在
/ serv
- ca-serv
版
本
x86
架构的
.
236 令
H yp e rledger Fabri c j 原代码分析与深入解读
volumes . -
”.
/ fabric-sev
工 C ca server ” b admin:adminpw ’
: /etchyprldgfab
command : sh -c ’ fabric ca server start
在
docker-mps.yl
文件的根目录下打开一个终端并且运行如命令
:
# docker-compose up -d
如果指定的 动
fabric-
fabr
ic-a
服
镜像之前并不存在,这个命
令将
务端的一个实例
Docker
你可以通过
docker
进行下载
。
这个命
令
还会
启
镜像
” compse
cd ♀ GOPATH/srcgithub make docker cd docker/server docker compose up
构建和启动服务器,
Fabric
示
:
工 c-a
d
CA
这一部分提供
具体如下所
. com/hyperldgfab
hyperledger/ fabric ” ca docker
体验
其
。
2 )构建你自己的
5.
对
镜像包含
fa
bric-asev
和
fabric
- ca
- client
。
命令行
fa bric-a
” serv
在接下来的内容中提供
巳 r 和
fabric-lent
命令行的使用说明
。
其他使用信息会
。 fabric ca-server : ”
Hyperledger Fabr
工 C
Cert
Authority Server
工 ficate
Usage :
Ava
fabric-ca-server [command] 工 labe
r
工
口
ev
r
L
V
工
-
D 、
如L
fr
工尸
L
al ←」
start version
e
Commands : hbe ta ISP - trn zea abcs avsre erfCA csv err eo as er rae lhF ntr rs -ee 4 、
工t
叮 A占←
工 n
Flags : --address string Listening address of fabr 工 C -ca-server (default ” 0 . 0 0 . 。 ” ) b, boot stri 口g The user:pass for bootstrap admin which is required to build default config file --ca . cert f 工 le str 工 ng PEM-encoded CA certificate file (default "ca-cert.pem ”) -ca . cha 工 nfile string PEM encoded CA chain f 工 le (default ” ca-chain . pem ” ) ca . keyf 工 le string PEM-encoded CA key file 口, -ca . name str 工口 g Certificate Author 工 ty name - -cacount int Number of non default CA instances - cafiles stringSlice A list of comma separated CA
第
10
章
Fabric CA
架构设计与讲解
•!
237
conf 工 gurat 工 on files cfg.affiliations allowremove Enables removal of affiliations dynamically 句“ c fg . identities . allowremove Enables removal of identities dynamically crl . exp 工 ry duration Expiration for the CRL generated by the ge 口 crl request (default 24h0m0s ) -crlsizem 工 t 工 nt S 工 ze 1 工 m 工 t of an acceptable CRL in bytes (default 512000) --csr . cn string The common name field of the certificate signing request to a parent fabric-ca-server --csr hosts str 工 ngSlice A list of space-separated host names 工 n a certificate s 工 gni request to a parent fabric-ca-server -csr serialnumber string The ser 工 al number 工 n a certificate signing request to a pare 口 t fabric-ca server --db datasource string Data source whic 工s database specific (defaul t ” fabric-ca-server . db " ) --db . tls . certfiles stringSlice A list of comma-separated PEM encoded trusted certificate files (e . g . rootl . pem , root2 pem) --db . tls . client . certfile str 工 ng PEM-encoded cert 工 ficate file when mutual authenic 工 s enabled --db . tls . client . keyfile string PEM-encoded key file when mutual authentication is enabled db. type string τ'ype of database ; one of : sqlite3, postgres, mysql (default " sqlite3 ” ) -d, --debug Enable debug level log 工 ng -H, --home str 工 ng Server ’ s home directory (default " /etc/hyperledger/fabric-ca ” ) --intermediate . enrollment . label string Label to use in HSM operations 工 ntermdia enrollment . profile string Name of the signing profile to use in isu 工 ng the certificate --intermediate.parentserver . caname string Name of the CA to connect to on fabric-ca-server -u, --intermediate . parentserver url str 工 ng URL of the parent fabr 工 cca-server (e . g . http : // : @ : @< host 为 true
port 。
务端验证身
int
bric CA
secrt
:// ::
SHOW GLOBAL VARIABLES LIKE
表
Variable name
Value
have_openssl
YES SL
器用户
( 3 )服务器端 。
为此,请登录到
置完 配
MySQL
确认表 SL
10-3
name
「 iable Va
Value
have ssl 一
成后,下-步是创建
YES SL
个有权通过
服务 MySQL
访问的
服务器,然后输入:
‘ sluer mysql> GRANT ALL PRIVILEGES ON . TO REQUIRE SSL; mysql > FLUSH PRIVI LEGES;
( 4 )如果想给出用户访问服务器的特定
sl ’ ;
。 所示的各项
10-3 该看到表
此时应
s 一在
‘ have
IP
地址,应将
’
由 ’
IDENT IFED
草 ’
’%
’ 更改为特定的
‘ password ’
BY IP
地址
。
•!•
246
H y pe
MySQL
出
dger
Fabri
c 源代码分析
与深入解读
服务器需要客户端证书
安全连接的选项与服务器端使用类似。 D sl-ca
:验证书颁发机构(
CA
使用的相同证书
)证书
。
该选项(如果使用)必须指定与服务器
。
D sl
- cert
:验证
D sl-key
MySQL
:验证
服务器的证书
MySQL
。
服务器的私钥
。
假设你要使用无特殊加密求的账户进行连接,或者包含
REQUI
GRANT i 吾 句创 项来启动
建该
MySQL
CA
账户
。
服务器
服务器
。
作为推荐的一组安全连接选项,至少使用 。
s l- cert 然后在服务器配置文件中设
db
若要指定客户端证书,使用
requi
定适当的客户端密钥和证书文件,否
则 db.
配置
L D A
一
Fabric CA
个
LDAP
q
X5
MySQL
指定客户端密钥和证书文件,可设置
10.2.9
R E
. tl s.cer
t fi l es
0 9 选项创建账户 。要
t i s . c l ient.cr
和
db.
选项的
和
sl
- key
属性并启动
。然
服务器将拒绝连接
SL
选 Fab
后客户端还必须指 为
tl s . cl i e n t.keyfi
Fa
br
ic
CA
l e 的属性
服务端 。
P
服务端可以配置为连接到
一
个
LDAP
服务器
。
Fa
b r i c CA
服务端可以连接到
服务器来做下面的事情:
登录
前验证一个身份
。
口授权时获取 在配 置文
一
个身份的属性值
件中修改
。 LDAP
的配
置
来连接到一个
L D AP
服务器
。
ldap : # Enables or disables the LDAP client (default : false) enabled: false # The URL of the LDAP server u rl: : /
: : /base userfilter : atr
工 bute
:
# ’ names' is
a口 ary of stri 口 gs tha 工 dentify the speci f 工 # which are requested from the LDAP server . names : # The ’ converts 『 section is used to convert LDAP atr 工 bute # to fabric CA attribute values . C
attributes
values
# # # # # # # #
For example, the following converts a 口 LDAP whose value begins with ’ revoker ’ to a fabr named ” hf.Revoker ” with a value of ” true ” evaluates to true) . co
口 verts
' attribute CA attribute ( because the expression ’ uid
工 C
:
name : hf . Revoker value : attr ( ” uid " ) =~
” revok
食 ”
# # As another example , assume a user has an LDAP attribute named
ri c
第
10
章
Fabric CA
架构设计
与讲
•!• 解
has multiple values of ” dnl "' "dn2 '’ , and " d 丑 3 # ’ member 『 whic # Further assume the following c o nf i guration . # converters : # - name : myAttr # value : map(tr ( 叮 nemb e r ” ) ,” groups " ) # maps : # groups : # - name . dnl # value orderer # - name : dn2 # value : peer # The value o f the user ’ 5 ’ myAt t r ' attr i bute is then computed to be # ’l orderer,peer,dn3 ”. Th 工 s is because the value of ’ attr ( ” member ” ) ’工 # ” dnl , dn2 , dn3 ”, and the call to ’ map ' with a 2nd argume nt of # ” group ” replaces ” dnl " with " orde ” and ” d 口 2 ” with ” per ”. converters : name : value : maps : : - 口 ame : value :
247
S
其中: D schem
:可为
ldap
D adminDN
ldaps
:管理员的
D pas
区
:管理员的密码
口
LDAP
D port
别
服
务
:可选的
D filter
IP
LDAP
等
于用户
登
为用户名的
录
登录
D LDAPtrs
表
LDAP
”]
份
类
,
。
个区别
名。
与此类似,(
比如,(
uid=%s
email=%s
Fabric
) 会
搜索
’
)可以用于邮箱地址作
务
性,其中
a 位 r ( “ uid
那么用户将赋予’
”的
属
hf.Revokr false
。
是
fabric
”)=~“
性
CA
典
型
如
果
用户’
uid
'属性的值为’ 的用例
是
将与
true ,; LDAP
属性
revok
组
关
联的独特名称映射到
Fabric
。
户”’
。 那么这
’ LDAP
属性的值
否则
’。
。
。
fcaAtrNme
配给 uid
应值
属
组
个表达式,它的值将被分
器请求名为“
响
属性名称数 CA
’,是‘
性的值为’
LDAP 型
。
。
LDAP
‘ hf.Revokr 服
' 属
用于映射
。
属性转换为
,是
er '开头
’ hf.Revokr
63
服务器请求的
是一
LDAP
D maps
实体
LDAP
uid
予
LDAP
fcaExpr
『 revok
时
默认为
一
用户从
属性的名称; 味着用户从
ldaps
,把登录用户名转换为
名的
:用于将
假设是[“
389,
。
:代
D converts
认为
索
器
值
默
。
树的根,用于搜
:搜索时的过滤
以
。
ldap
D base
CA
名
器的域名或者
:可选的端口号,
uid
。
。
host:
身
或者
,
用户将赋
例如, 意
2 48
令
Hyperldg
Fabric
LDAP
表
描述的
达式语
源代码分析与深入解读
言
govalute
包
使用
。
/ github.com
扩展
基
础
govalut
:等于用户名称的变 :
: 一
等
要
2 个
参
个需要
个’
。
string
’ 类
. md
revok
LDAP
变量
:一个需要
*”之
和函
数
类
的
中
文字,
如下:
tru
巳,则返回第
二 adm
in
第一
个参
其中第
个参数;否则
函数总是返回’
个
, C=US
stri
工 at
,默
。
第二
认分隔符
个
字
。 换
参
符
参数是
串是‘
,
二
参数 。
三
个参
数 ,
是一
个映 算
或者用户具有以“
orgl 算
“ orgl .dept2 . ” &&
吨’类型的值,因此数运
如果它的计
。
”,那么下述表达式计
=~
个
。
”结尾的名称
工 on
第
数必须解析为布尔值
返回第
true (afil
属性名称
数是任何字符串
一
”属性的值为“
“ O=orgl,C=US ” I I
LDAP
符串中
替
O=orgl,
开头的隶属关系,且“
个字
数的字符串进行
。
例如,果用户具有以“
atr
是 。
。
3 个参数的函
结果为
第 一个 参 数
型的值
2 个参数的函 参
由于
/ MANUL
。
数的函
射的名字,用来对第一个
DN =~
/ master
柯:和诸如“
的特定
单 一
: 一 if
算
符串,用于将多个值连接到
函数总是返回
口
言
变量
l 或
字
D map
巳语
于用户隶属关系的
个需
个分隔符 atr
的运
/ blo
量。
D afilton 一
/ govalute
~ 类”之
。
D atr
/ Knetic
这定义了诸如“=
这是一个正则表达式
D DN
htps:
算
.dept2 ”
结果将为
true
attr ( ‘ adrnin ’
。 ‘ true ’ )
)=
符将不会用于构造表达式
。
例
如,以下不是有效的表达式:
value : attr( "gidNumber) >= 10000
&& atr(
" g 工 dNumber)
另外,下述表达式中引号里的正则可以被用于返回
一
value : attr (” gidNumber ” ) 以下是 com
10006
presp, err
e ndorsePpa
易
Tx
模块
…,
_ A
l ,在返回给交 一 >
打包成
orde
处理
b l ock
散播使用
的结果
易发
Propsa!Ren
gosip
交
()
->
节点,再经
为
ChaincodevkOrQuy
orde per
En
e 口 v ,
。
err
ve lope
过程省略
comiter
起端
->
->
orde
模块的过程,这里亦
将
。
( 8) comit
巳 r 向账本
、
。
中,
/ comn.g
给
A
。
be . Send (四川,发送给 block
,通过
( .. . ),获取交易
: = putils. CreateSignedTx ( .. . ) ,把返回的 形成的
entrBusySa
err = txs
工 ncode
列调用后会进入下一步
p 巳 e r / chainode
e 口=
),然
(),这一步相当于模拟执行了交易
e . call Cha
/ endors
Propsal
( 7 )在
中的
工 mulator
Invoke
” 分支从而调用
. CreateProposalResponse ( ... , results , ... ) , result
集,其被放入
中的
> pResp , err= e.endorseProposal( ... ,
, 一系 / sc
. go
n 中调
他交易会用到了其的
Procespal()
core
工 ls
txs
) 。
l eTransctio
nvoke
账户的数据放入了写集(其
.g o 中,
t , ... ) 一 > ca
B
hand
code_exam pl 巳 02
ExecutQry
-〉返回至
mulationRes
二 轮的
、
的
/ handler.go
()、
巳 RangeScltro(),
c o re /e ndorse
Results ()
chain
/ chainode
. GetSa
A
i m / handler.go
function =吐
core
入读集,把更改的
( 5 )重回
if
一系列辗转,会在
t xsimulator
B
/ cha in code/ sh
: = handler . cc . Invoke (stub) ( 即
后根据第
e/
stub,args) (该函数简单
转了一笔钱,即形成
” 1 。 ” ]}
e ndorse
/巳 ndorse.g
o nse Enve
chaincode invoke ” ,“
在交易返回时,再使用
如下:
chaincodeinvoke( . .. )函数向 ( 2 ) core
Vers
向
287
模块提交到账本对象,添加
examp
额,并由
调整后各自新的余额值)为例,步
( 1 )交
节点依据
中,
chainode
两个账户的余
l Resp
or
gosip
添加到
sa
orde
节点接收数据后,经
数据库中
po
中再发送给 ) 。
b l ock
加
数
ChaincodelvkOrQuy
,会将
终添
中的
中的
pe
令
。 Pro
数据直接打印, on
章账本机制的设计与实现
(交易模拟器)放入一个名为读写集的容中
r 统一段取,然后将读的数据放入
c om
1
提交
block
时,
最终定位
到
core
/ l edgr
/ kv
l edgr
/ kv
一 l edgr.o
中的
28
令
H y p e 巾
d ge
Comrnit(block)
r Fabric
源代码分析与深入解读
->
err =
l.txtmgmt . Comrnit ()
即
l.txmg
. Val
工 dateAnPrp(block
是使用交易管理者向
true) , ,
s tae
提交的易数据
。
ValidteAnPrp
做两件事,一是使用验证器交易的读写集以确定有效性;二若 则将
交易
的
做准备
写集
中的数据放入升级包,为下
一步的
l.t xtmg.Coi
()提交这批数据
。
交易模拟器/查询
11.3.2 交易模
拟
interfac.go
器
中
TxSimulator
和
txmgr 和
kvLe
dger
的
。
功能,这点从 Exe
cutor
(),
T xS
以 在
看
因
此
,
器
。
TxSirnulato
除了查询,
出
txmgr
Query
来
query
。
。
接口可获取
通
TxSimulator
Helpr
实现了自身
TxSimulator
和
的
实际上包含 版本的
查询方面
的
Query
VersiondDB
还提供状
Executor
Executor,
态
的
),因此直接使用的
写入功能,人分为增
加和删除
涉及的操作就有查、增删
/ lockbasedtxmgr
/ lockb
写、删的操作步如下
lockBasedQuryExt
查询功能上的增强和拓展(其中交易器
TxSirnulato
和
参看
中的
couhDB
拟
中的
()
是富查询接口,因此只支持
一般是交易模
中的
lp er.go
名字可 imulator
巳 cuter.go
core/ldg_
lockbased_tximur.g
NewQuryExcto
he
算是
ExecutQry
ulator
这个
的接口在
/ 下
_query_ex
Helpr
Executor
/ lockbasedtxmgr
两者均直接使用
q u ery Query
lockbased
N 巳 wTxSim
N ewQuery Executor 而
Query
定义,具体实现为
lockBasedTxSimutr 过账本
交易查询器
。
。 ased
_ tx_simulator. go
和
helpr.go
,交易模拟器的读、
:
( 1) Get State (口 和
key
,从
的版本)
stae
。
s ,
key)
这里的名字空间即
chainodeID 同
间
(口
key , value
,也即对应
s,
key, value)
),将一个值写入集
个
chain
code
的每一个交易使用
-> s . rwsetBuild.AToWS
(且
S ,
。
( 3 ) DeleteState(ns , 的
一
。
(2)Seta
key
q . helper.getState(ns , key ),依据名字空
数据库中获取一个状态,返回并写入读集(的是值
读写集,下
当给的
->
value
为
nil
时
key)
SetState(ns,
->
,即表示要将 此
key
的
值置为
nil
,也即
),
删除
要删除这个值
一个值
,
。
for . . . { SetState ( ... ) },一次
( 4) SetStateMultipl eKeys (ns, kvs ) • 性设置多个键值对,写入交易的集
nil
key ,
。
( 5 ) GetStateMultipleKeys ( ... ) -> q . helper . getStateMultipleKeys ( ... ) , 依据一个名字空间和批
key
( 6) GetSaR 工 terao
,从
口 geSca
stae
( ... ),依据-
口工
个命
数据库中获取一批状态
terao(
... ) -> q . helpr
名空
取一个指定范围的交易查询迭代器
。
间,根据开始的
key
和
结束的
.g
key
etSaR
,从
口 geSca
stae
口
数据库中获
。
( 7 ) ExecuteQuery (且
amespc
, query
)一>
q. helper . executeQuery
集 写
读 1.
。
q . helper . done (),交易查询器执行完毕
( 8) Done ()•
289
。 不支持这个接口
Je v eldb
(narnespace , query),
•! 章账本机制的设计与实现
1 第
入了一 时放
得到的数据暂 删
交易查、增 而是将
, 中
数据库 stae
直接写入 正的
数据并未真
交易 的时候,所形成
交易 因为在使用它处理
器,就是 拟
交易模 之所以叫
TxSimulator
。 个名为读写集的地方备用,因此是模拟交易
组
u erisKy rangeQ
和 rangeQuisMp
写集、 writeMap
读集、 readMp
多个值各自形成
。 /下)
/ kvrwset
/ rwset
/ ledgr prots
围读值(三者均定义在 范
Info RangeQury
写值、 KVWrite
读值、 KVRead
: 类数据
三 读写集存储
。 RWs
ns 单独有一个
code chain
,每个 key
为
chainodeID 映射,即以
1 sRW ]竹
map [string rwMap
个 一
,成员只有 RWSetBuildr
中的
。 builder.g
/ rwset_ rwsetuil
每笔交易都对应一个读写集,实现为 的
code chain
个 一
。 成的范围读集
口,都会将一个写值入 等接
() DeltSa
() 、 Seta
每次调用 TxSimulator
。 IsDelt
识
除的标 删
,还包含一个决定此写值是否为 value
和 key
,每个写值包含
: KVWrite 写值
TxSimulator
。 接口,都会将读取到的值并其写入交易集
() tSae
Ge 每次调用
。 和值的版本号,而不包含身
key 每个读值只包含
, KVRead
: 读值
交易的写集。
范围内的多个原始读值 。
两类数据,即原始的范围内多个读值或哈希
。 具
很容易理解,而范围内读值的哈希生成则需要借助其他工 当 回
给
这里 。
读值 个抽取
一 个
一 ()
Next 器的
用者使迭代 率低下),然后调
导致 的处理效 而
量过大
(这样可以避免数据 给调用者
息的迭代器返回 含了读值范围信
个包 一
调用者,而是将
打包返 集合
内所有读值 是直接将这个范围
时,不 一定范围数据的交易
用户发起读取
存储 Readslnfo
,而成员 一样
Key rangeQuy
中,其余的成员同 RangeQuryifo
。 是否结束
标识了 itrExhaused
对应的值), endky
,范围读值中不包含与 意
标识了范围至何处结束(注
, endKy 从何开始
标识了范围
, s tarKey 中
rangeQuyK 。
value 的
map 为
RangeQuery Info
key, 的
map 为
rangeQuyK 是以
rangeQuisMp 。
写入将在下文介绍 何时被
读值
个范围内所有读值的集合, 一
,每个范围读值是 RangeQurylfo
范围读值:
: 涉及两个迭代器
把迭代
chain
( 2 )在核心的 Query It 巳 rat
or
。
该迭代器的使用依附于(
code
中
。
处
包 TxSimulator
再次强调,
含
。 core
理范围内,为
1 )中迭代器所查询出来的结果
,而提 Executor
Query
在查询功能上主要的拓展之一 TxSimulator
对 Executor
Query 供迭代器也是
itrs 的
Helpr query
器记录在
,由交 result
中的 .go
/ helpr
( . .. )接口获取,每一个迭代器都会
工 terao GetSaRngc
易模拟器的
x mgr
/ lockbasedt txmgr
( I )在交易模拟器的范围内,为
/ chainode
/s him
. go
/ chainode
。
中的
Stae
290
令
H yp e 出
2.
d ge r F a bri
c 源代码
分 析与深入解读
迭代器
result
s ltr
迭
代
器管理了一个工具,
即
ResultHpr
rwsetu
t il / query
_r巳
。 RangeQurysltHp
内的
读
值
,
用 的
而
该值
又
go
增
储
一棵默克
尔
树
, 该
, 读取
的
读值都会添
加
到
( ) 接
口
克
尔
Level] []H 默
树也叫哈
希
a sh 克
的
映
树中有
树,
实现
为
步生成是
由
e /ledgr
决定)
query
_res u
时存储范围
的哈
次
希
hasingEbled
值
,
决定,
/ l e dgerconfi
。每
lt s _help
整
体进
该树,
个比
哈
,
/ le d g
result
巳 r
迭代器
被
con fig .
调用
pendigRsul
一
怡和
extLafvlHsh
新
例
maxDegr
II
e=2
,
[x] - {hashN},
次
merk
l e
哈希值
则
会进
和
Le
v el
哈
希 成
has ,
l eTr
层
的值前后连
作
工具
map[Merk
标识树的 并
h l - 2 ,然后将
默克尔树的操
,由
。
行一 个归
h a sh2
ee
个
是哈希值 e 。
,
has
说明
中,一
maxDegr 时
l eTr
对
默
认
值的操作 一
: 个
整体
h l - 2 放入
应
级,
上
,
如
然后
一层(
merklT
也就 的
update
:
则连续插入
x 为
的
子
)函数 /设
e l 和 节点
merk
m e rkleT
h a shl
个
是举
在
中的 的
该操作是将
一
e r.go
每个节点保存
: Lev + I 个
则
到
下面也
值
Degr
s h2
希,得
l 2 )里面。
的
m ax
1 , ha
行
的
较重要 有
has
。
中实 现了
Levl
节点存有 L e ve
射
两
树中的
是 (口
格式
尔
l ,当
个
于暂
对应
的
持有并管理
对这
用
RangeQurysltHp
RangeQurysltHp
个
RangeQury
。
默
两
中的
pendigRsult cor
Enabled
helpr.go ingResult
存储与 同
町
s_ pend
步更新的(其实哈希值是否
eryRadsHhi
中暂存
为
树
置决定,该配默认开启由
IsQ u
Next ()
于存
加同
由账 本 的配
中的
Tre
中的
merklT
两者是随着数据
suit
l ~ Levl
值,
9 共
9 个哈希值
hasN
,
代表
~p
调用
N 的哈希值
9 次
。
则
merklT
的
tre
的变化为
update
接口
·
1) [1 ]- {hash l } 2 ) [1] - {hashl ,hash2} 3) [2] 立,
所有
- {h
会
a shl
向下
- 3 },
一层,
插
入
第
也就
3 个时
是第
,因
2 层
为
归
len(curt
L e v elHash)
集哈希值
3 { cha 工 nCodeTal : = args [l] queryKey : = args [ 2 l channel : = args[3] f : = ” query ” invokeArgs := toChaincodeArgs(f , queryKey) response : = stub InvokeChaicd(Tl ,工 nvokeArgs if response Status != shim . OK { errStr : = fmt Sprintf ( ” Fa 工 le d to invoke chaincode . Got Error ()) fmt
. Pr
sh
口
该方法与 是
( ” Que
shim
exampl02
方法
的
12. 7
可
qu
er
毛s
", err .
类 y
” \ ”, \ ” Amount \ ” : \ ””
+ string(event-
: 在 s \ n ”, j sonResp) []byte(jsonResp)) Respon
. Suces(
invoke
:
. Error(errStr)
工 m
jsonResp = string(response . Payload) } else { jsonResp = ” { \ ” Name \ ”: \ ” ” + event + Valbytes) + ” \ ” ) ” fmt . Printf
ero
channel )
工 ntf(erS)
return
retu
,
似,
区
方法,从
别在于调用
stub
exampl02
中进行状态的
. InvokeCha
in co d 查
询
e 方法时调用的
。
example05
巳 xample05
同
于它将查询获取到的
样也
A
是一
chainode func (t *S
代
个跨
、 B
码分析如下 i mpleC
c h a in
的
值记
录
了下来
code
调用
exam
ple02
的
案例,和
exa
mple04
的区别
在
。
: h a 工 ncode
)
工 nvoke(stub
sh i m. ChaincodeS tubinterface , args []string)
学习使
用
仅供非商业用
318
•!•
Hyp erledger Fabric
i 主或交流学习使用
源代码分析与深入解读
pb . Response { var sum, channelName string// Sum entity var Aval, Bval , sumVal int //value of sum var err error if len(args) < 2 { return shim . Error ( ” Incorrect number of argume ent
- to be computed
工 ty
口
Expecting atleast 2 ”) ts.
chaincodeName := args[O] S 山 n = args[l ] if len(args) > 2 { channelName = args[2] } else { channelName = ”” f : =” query ” queryArgs := toCha 工 ncodeArgs(f ,’ l a") response := stub .I nvokeChaincode(chaincodeName, queryArgs, channelName) 工f response.Status != sh 工 m . OK { errStr : = fmt . Sprintf (” Fa 工 led to query chaincode. Got error : %s ”, ponse.Payload) fmt.Printf(errStr) return shim . Error(errStr)
r es-
Aval, err= strconv . Ato i(string(response . Payload)) if err ! = nil { errStr := fmt . Sprintf (” Error retrieving state from ledger for queried chaincode : 毛 s ”, er.Eo() fmt.Printf (errStr) return shim.Error(errStr) queryArgs = toChaincodeArgs(f , ” b ”) response = stub . InvokeChaincode(chaincodeName, que 口 r Ar gs , channe lName) 工 f response.Status != shim.OK { errStr = fmt. Sprintf ("Failed to query chaincode. Got ero :在 s ”, ponse . Payload) fmt.Printf(errStr) return shim.Error(errStr) res
Bval , err= strconv.Atoi(string(response.Payload)) i f err != nil {
errStr : = fmt.Sprintf("Error retrieving state from ledger for queried chaincode : 毛 S ” , er.Eo() fmt.Printf(errStr) return shim.Error(errStr) sumVal = Aval + Bval err = stub.PutState(sum , []byte(strconv.Itoa(sumVal))) if err != nil { return shim.Error(err . Error()) fmt . Printf ( ” Invoke chaincode successful . Got
sum
毡 d\n
”,
s umVal)
return
工 m
12.8
319
A 中获取到的
、
B
中(需要注意,跨链码调用如果进行信道则指明 code
chain
channe!N ame
•! 能合约案例分析
exampl02 的操作,将从
chainode
2 次跨
的值求和存入了当前
c h a in co d e 智
. Success ( [ J byte ( strconv . Itoa ( surnVal) ) )
方法中进行了 invoke
在
sh
章 12
第
盘成 m1
仅供昨附业
) 。
invokereturnsvalue 何对 案例主要用于展示如
invokertusal chain code
代码分析如下
。 行设定
智能合约调用的返回值进
:
func (t *SimpleChaincode) Invoke(stub shim . ChaincodeStubinterface) pb.Response ( _ , args := stub.GetFunctionAndParamete rs() // Entities var A, B string var Aval, Bval int // Asset holdings II Transaction value var X int var err error len(args) ! = 3 ( 工f return shim . Er ror (” Incorrect number of arguments. Expecting 3 ”) A= args[OJ B = args[l) Avalbytes , err := stub.GetState(A) { if err != n 工 l return shim . Error (” Failed to get state ”) if Ava l bytes == ni l { return shim.Er r or("Entity not found") Aval ,
= strconv. Atoi(string(Avalbytes))
Bvalbytes , err := stub . GetState(B) i f err ! = ni 1 { re t urn shim.Error ( ” Failed to get state ” ) if Bvalbytes == nil ( return shim . Error (” Entity not found ”) Bval, _ = strconv . Atoi(string(Bvalbytes)) X, err= strconv.Atoi(args[2)) { if err != n 工 l 工 on transc nvalid (”工 return shim.Ero Ava l = Aval - X Bval = Bval + x err = s tub .Put State(A , err != nil ( 工f []byt
e
(strconv
. 工 toa
amount , expecting
(Aval) ) )
a
工 ntegr
value ” )
交
流学习使用
仅供#商业用途或交流学习使
•!•
320
H yp erl edger Fabric
return
源代码分析与深入解读
sh
工 m
. Error(err . Error())
err = stub.PutState(B , []byte(strconv . Itoa(Bval))) if err ! =nil { return sh 工 m . Error(err.Error()) return shim.Suce([]bytf
. Sprintf
链码调用的返回值可以被封装在
( ” {电
s him.Suc
参数
即为
客户端
收到的
中的
paylod
, 宅 d
}”,
Bval))) Aval,
()方法中,该传人的[
] byt
e
。
map
12.9 map
这个
操作
respon
es
d
案
例
展示了关于组合键的存
取
、
范围查询以及调用
couhdb
进行富查询的
。 chainode
代码分析如下:
func
(t * SimpleChancod function, args : = switch function { case
'’
put ":
cas e
”
remove "
)工 stub
nvoke(stub
sh
. GetFunc
工 m
工 onAdParmets
.ChaincodeStubinterface) () pb.Reso
{
口 se
case "get " case
”
keys ’· .
case ” qiJery ”: case ” history ”: default : return shim . Success ( []byte ( ” Unsupported operation ” ))
该链码主要分为
6 个功能
1.
put
。
方法
数
该方法除了调用之前介绍的
CreatompsiKy
PutSae
用于
Key
值的生成
进行数据存取外,还调用了
创
建组合键
的函
。
if len(args) < 2 { return shim . Error( "put operation must include two arguments : [key , value ] ”)
l o fij 仅供
第
ch ain c od
章 12
•!
e 智能合约案例分析
key : = args [ O] value : = args[l] if err : = stub . PutState(key , []byte(value)) ; err ! = nil { err) 屯 s ’', fmt.Printf( "Error putting stae operation failed . Error ( ” put 工 ntf . Spr return sh 工 m . Ero(fmt 5 :毡 stae
才 ~ m
堆成交流学习
321
工 ng updat
er) ”,
: = ” compositeKeyTest " 工 ndexNam compositeKeyTestindex , err := stub . CreateCompositeKey(indexName , string{key}) if err ! = nil { return shim . Error(err.Error( ))
[]
valueByte : = []byte{OxOO} err : = stub . PutState(compositeKeyTestindex, valueByte) ; e rr ! = nil { 工f ) e r ”, 革s 工 teKy fmt . Printf (” Error putting state with comps return shim . Error ( fmt . Sprintf ( ” put operation failed . Erro r updating err)) : 毡 s ", state with compsiteKy return
方法
2. remov 法 该方
. Success(nil)
工 m sh
ate St
Del 调用
i f len(args) < 1 { return shim . Error ( ” remove
。 操作
删除 值的
进行键
方法
工 on operat
must include one argument : [key ] " )
key : = args[O] err : = stub . DelState(key) if err != n 工 1 { return shim . Error(fmt.Sprintf( " remove operation er) 毡 S ” , : updating stae
fa
工l
ed .
Error
丁 一
作 操 询 查
•L a•L e
CU
进
nue
←」
法 方 该
TH Rη +
纣
9
立 工 f
方 调
return shim . Success (nil)
len(args) < 1 { return shim . Error (” get operation must include one key : = args[O] value , err : = stub . GetState(key) if err ! = nil { return shim . Error(fmt . Spr in tf ( ” get state : %s ” , err)) h al . Mars son jsonVal , err : =〕 ret urn shim . Success ( jsonVa l)
(str
工 ng
operat
(value ))
工 on
fa
工 led
山 arg
.
net
,
Error
a key ” )
a ccessing
使
用
•!•
322
H yp erle dger F a b r i c 源
4. keys ke
码分
析与
深入解
i卖
方法
y s 方法
字典序
代
排列
用
于进行范围查询
GetSaByR
口 ge
,根据传人的
st a r t K 町、
end
Key
进行
。
if len(args) < 2 { return shim . Error( "put operation must and value ”)
include two arguments,
a key
startKey := args[O] endKey := args[l] stime := 0 if len(args) > 2 { st 工 me , 一 = strconv . Atoi(args[2]) keysiter, err := stub.GetStateByRange(startKey, endKey) 工 f err !=nil { return shim.Error(fmt . Sprintf (” keys operation failed. Error accessing stae
:屯
s
” ,
er)
defer keysiter . Close () var keys []string for keys I t er. HasNext () 工 f stime > O { t工
{
* me.Slp(tiDuraons)
t 工 me
. Millisecond)
response , iterErr : = keysiter.Next() 工f iterErr != n 工 1 { return shim. Er ror ( fmt. Sprint f (” keys accessing stae : 革 S ”, er)
operation
failed .
Error
keys = append(keys , response.Key) for key , value := range keys { fmt . Printf (” key 奄 d contais
革 s \ n
” ,
value) key,
jsonKeys , err : = json.Marshal(keys) i f err ! = nil {
return shim. Error ( fmt. Sprintf (” keys shaling JSON :屯 s ”, er) r e turn
5. query 用 等 q
且 ery
failed .
Error mar -
口 Keys)
方法
该方法 couhdb
shim.Suce(jo
opera t ion
s taedb
G etQuryR
esu ,不支持
lt le v el db
进
行一个富查询操作,该接
口只
针对提
供
富查
询
操
作的
。
: = args[OJ keysiter, err := stub . GetQueryResult(query) i f err != nil { return shim.Error(fmt.Sprintf (” query operation failed. Error accessing
第
s ta
te
:毡
s
”,
12
章
c h ainco
d e 智能
合约
案例分析
令
32
er)
defer keysiter . Close() var keys []string for keysiter.HasNext() { response, iterErr := keysiter.Next() if iterErr ! = nil { return shim.Error(fmt.Sprintf (” query access i ng stae : 奄s ”, er) keys
=
operat
工 on
failed.
Error
append(keys, response . Key)
jsonKeys , err := json.Marshal(keys) if err != nil { return shim . Error(fmt . Sprintf("query operation failed. Error marshaling JSON
:毛
S ”,
er)
return shim . Success(jsonKeys)
6. history
方法
值每
该方法用于获取键值对的历史状态变化,通过调 一
GetHisoryFK 次变化所对应的
txID
方法获取
key
。
key := args[OJ keysiter , err := stub . GetHistoryForKey(key) if err != nil { return shim . Error(fmt.Sprintf ( ” query operation failed . Error accessing state : 奄 s ”, er) defer keysiter . Close() var keys []string for keysiter.HasNext() { response, iterErr := keysiter.Next() if iterErr ! = nil { return sh 工 m .Error(fmt.Sprintf ( ” qu e ry o peration aces
工 ng
stae
:毡
S ”,
failed .
Error
er)
keys = append(keys, response . Txid) for key, txID := range keys { fmt . Printf ("key 革 d contais
在 s \口”,
jsonKeys , err : = json . Marshal(keys) if err != n 工 l { return shim . Ero(fmt.Sp 工口 tf ( ” query JSON
return sh
:毛
工 m
5
”,
er)
.Success(jsonKeys)
key
,
tx
工 D)
operation failed . Error marshaling
324
令
H y p e rl e d ge r Fabri
c 源代码分析与深
入 解读
marbles02 12~0 marbles02
是一
链上进行
资产
的创
个大理
chainode
建、
石 转
资
移、查
产 询
管理的
案 等操
作
例,介绍了如何在
智
能合约中
定
义
资产
,
在 区块
。
代码分析如下:
type marb le struct { ObjectType string 、 j son :” docType " 、/ /docType is used to d 工 s t 工 ngu 工 sh the var 工 ous types of objects in state database Name st r 工口 g 、 j so 口 : ” name ”、 //the fieldtags are needed to keep case from bouncing around Color str 工 ng 、 j son : "color ” 、 Size int 、 json : ” size " 、 Owner str i ng 、 json :” owner " 、
称、颜
该智
能合约定义了
色
、
一个
尺寸
、
拥有
者
大
理石的
结
构体
,
用
于
存储相
关实
体的信息,包括了
类
型、
名
。
func (t *SimpleCha 工 ncode) Invoke(stub shim . Cha 工 ncodeStubirfa) function , args := stub . GetFunctionAndParameters() fmt. Println (” invoke is running ” + function)
pb . Response {
II Handle different funct i ons if funct 工 on == ” initMarble ” { llcreate a new marble return t . initMarble(stub, args) } else if function == ” transferMarble ” { llchange owner of a specific marble return t . transferMarble(stub , args ) } else if function == ” transferMarblesBasedOnColor ” { lltransfer all marbles of a certain color return t . transferMarblesBasedOnColor(stub , args) } else if function == ” de l ete ” { lldelete a marble return t . delete(stub, args) } els 工 f function ==” readMarble ” { llread a marble return t.readMarble(stub , args) } else if function == ” queryMarblesByOwner " { I lfind marbles for ow 口 er X using rich query return t . queryMarblesByOwner(stub , args) } else i f funct 工 on == " que 巧 rMables ” { llfind marbles based on an ad hoc rich query return t .queryMarble s( stub , args) } els 工 E function == “ getHistoryForMarble ” [ llget history of values for a marble return t . getHistoryForMarble(stub , args) } else if function == ” getMarblesByRange ” { llget marbles based on range que 巧 F return t . g e tMarb l esByRange(stub , args) fmt . Pr 工 ntl ( ”工 nvoke did not find func : ” + function) return shim . Er r or ( ” Received unknown functio 口 invocat
llerror i on
” )
第
该
智能合约主
1.
要
包括了
intMarble
12
章
c h a incode
智能合约案例分析
令
325
9 个方法:
万法
创建
一
fun c
个大理
石
(t
信息
,并
写
入 账本
:
in 工 tMarble (stub sh i m. ChaincodeStubinterface , pb . Response { var err error if len( args) ! = 4 { return shim . Error ( ” Incorrect number of arguments . Expecting 4 ” ) str
* S工
mpleChaincod)
args
[]
工 ng)
fmt . Println ( ”- start init marble ” ) len(args[O ] ) INFO 001 Loading conf igurati o 口 2017 06 12 21 : 01 37 644 EDT [cornmon/configtx/tool] doOutputChannelCreateTx -> INFO 002 Genrat 工且 g new channel conf 工 gtx 2017-06-12 21 : 01 : 37 645 EDT [common/configtx/tool] doOutputChannelCreateTx -> INFO 003 Writ 工 ng new channel tx
################################################################# Generating anchor peer update for OrglMSP
#######
##########
################################################################# 2017 06 12 conf
21 : 01 : 37 . 674
EDT
[cornmon/configtx/tool]
main
>
INFO
001 Load
工口
g
工 guration
2017-06-12 21 : 01 : 37 . 678 EDT [common/configtx/tool] INFO 002 Generating anchor peer update 2017-06 - 12 21 : 01 : 37 . 679 EDT [comrnon/configtx/tool] INFO 003 Writing anchor peer update
doOutputAnchorPeersUpdate
->
doOutputAnchorPeersUpdate
->
################################################################# Generating anchor peer update for Org2MSP
#######
##########
################################################################# 2017-06-12 21 : 01 : 37 . 700 EDT configuration 2017-06-12 21 : 01 : 37 . 704 EDT
[common/configt:x/tool] [comn/f
工 gtx/ol]
INFO 002 Generating anchor peer update 2017 06 12 21 : 01 : 37 . 704 EDT [comrnon/configtx/tool] INFO 003 Writing anchor peer update
第
一
步生成我们各种网络实体的所有证书和密钥,
务,以及配置
gen
Chanel
13.2.4 接下来,你可以使用命
所需要的
一
组交易配置集合
main
->
INFO
001
>
doOutputAnchorPeersUpdate
->
s is
block
用于引导
排
3
网络
。
再次提示你是否继续
工 ng
doOutputAnchorPeersUpdate
启动网络 令来启动整个
Load
。
回答
y :
序服
到
•!•
338
H y p e rl edger Fabric j 原代码分析与深入解渎
. /byf 口 .sh -m up Start:.ing with channel ' π1ychanel 『 and CLI timeout of ’ 10000 ' Continue (y /n) ?y proceeding Creating network "net_byfn " with the default dr iver Creating peerO orgl . example com Creat 工 ng peerl.orgl . example com Creat 工丑 g peer0 . org2 . example. com Crea ti 口 g orderer . example . com Creating peerl.org2 . example . com Creating cli
/
一
l
\ 一-
\ 一)
l
||
|
|一
一 \ I ) I
/\
/
\
I
||
一-
\
/ 一/
||
\ 一 \|
|| ||
DEBU
Return
004
工 ng
existing
> DEBU 005
工 gnidety
Obta
工 n 工 ng
default sign 工 ng identity 2017-05 - 16 17 : 08 : 01 . 366 UTC [msp/identity] Sign - > DEBU 006 Sign : pla 工口 tex : OAB 1070A6708031AOC08F1E3ECC80510 . .. 6D7963631AOAOA0 571 756572790A0161 2017-05 16 17 : 08 : 01 367 UTC [msp/identity] Sign - > DEBU 007 Sign : digest: E6 1 DB3 7F4E8BOD32C9FE10E3936BA9B8CD278FAA1F3320 B08712164248285C54 Query Resul t ’ 90 2017-05 - 16 17 : 08 : 15 . 158 UTC
===================== =====================
Query
I 一 |
I
你可以滚动这些日志去查看各种交易
|一
|
|
\
|
|
|
[ma
main -> INFO 008 Exiting . .
工 n]
on
PEE R3
I I\
|
l 一|
I
\ 一|
I
|一
channel
' mychanel
一
All GOOD, BYFN execution completed
\
- ||\||||||
I_
on
I 一|
/
。
'
工 S
successful
========== ======== ===
到
第
13
Fabric-smple
项目分析与实践
令
39
关闭网络
13.2.5 最后,让我们 把脚本
全部停下来,这样我
们可以一步
将关闭你的容器,移除加密材料和
4 个配 你将再
章
一次被
提示是否继续,回答
置
一步
信息,并且从
地探索网
Docker
络设置。以下操作 仓库删除
chainode
镜像
。
y:
. /byfn . sh m down Stopping with chan 口 el ’ my cha 口 el ’ and CLI timeout of ' 10000 ’ Continue (y/n)?y proceeding WARNING: The CHANNEL_ NAME variable is not set . Defaulting to a blank string . WARNING: The TIMEOUT var 工 able is not set . Defaulting to a blank string . Removing network net_byfn 468aaa6201ed Untagged: dev-peerl.org2 . example . com-mycc-1 O: latest Deleted: sha256:ed3230614e64elc83e510c0c282e982d2b06d148blc498bbdcc429e2b2531e91
在接下来的章节中,我们将介绍构建功能齐全
Hyperldg
要求和步骤
fabric
网络的各种
。
13.2.6
加密生成器
我们将使用
cryptogen
工具
为我们生成各种网络实体的加密材料(
x.509
证书)
。这 些
加密材料是身份的代表,在我们网络实体进行交流和易时这些用于签名/验证
。 Cryptogen
消费一个包含网络拓扑的
crypto-nfig.aml
织和属于这些组的件
生 cert
CA
),它将特定组件(
一组
pers
证书,我们正在模仿
一
Hyperledger Fabric
成 和
ordes
易
k eys ) 的
count
tore
c a
。
per
如果你有兴趣,可以自己学习
。
我们现在不会深入研究
x.509
的数量;在我
证书和公钥基础设施的细
。
在运行该工具之前,让我们快速浏览一下这段代码 意在
了唯一的根证书(
中的实体私钥签名,然后通
变量,我们将使用它来指定每个组织中 per
。
置
)绑定到该组织。通过为每一个分配唯的
和通信是过存储在
们的例子中,每个组织有两 节
个组织都配
。
( s i gncerts
在这个文件里有一
。每
们为组
个经典的网络,这中成员将使用自己证书颁发机构
中的交
过公钥手段进行验证
证书和密钥
,并允许我
crypto-nfig Ordegs
头下的
Name
、
Domain
和
Specs
参数
. yaml :
OrdererOrgs :
#- - - - - - - - - ------------------- ---- < - - - - - - # Orderer
#------------------------------------- Name : Orderer Doma 工 n : example com
。
特别注
•!•
340
H y 严
rl e d ger
Fabric
#-------------------------------------------# ” Specs ”- See PeerOrgs below for comple t e descript ion #------------------------ - ------Specs : - Hostname : orderer # ------------------------- -
# ” PeerOrgs ” Defin
-
- -
- -白
of organizations
工 tion
# --------- -- --- -----
-
mang
peer nodes
工 ng
----------------------
- ------
PeerOrgs #-----------------------------------------# Orgl #----------------,,-------------------- Name : Orgl Dorn a 工 n : orgl.example.com 网络 实 体的命名约 定
作为参考点,它与 Or 还可以 参考
如下:”{
d er 的
Membrship
MSP ID
相 关联
。
cryptoge
m a in }
所以使用我们的排 序节点
。 ) ,以便更深入地了解
口工具,生成
MSP
你
。
的证书和密钥将被保存到名为 crypto-nfig
的
。
配置交易生成器
13.2.7
configtxgen tol 用于
创 建
4 个配 置工作
: ord
e r 的
channel configuration transaction, *以及两个 ( 一 个对应
一个 Pe
巳 r 组织
Cha
order block 在
C hanel 创
是一个 ordeing
orde ch
Configtxe 排
使用
序服务组织
ane
包
Orde
p er 节点
请特
。 别
区块
注意 此文件顶部的"
此
per
个 Sampl
在
。 具有
3 个成员: 一
每个组织管理
2 个
的联盟,由上述两个节点组织构成 。 一 个是 orde 的创世
TwoOrgsChanel
工作的时候它
。
们将作为传递的 参数 由渠道
。 级别配直
管道存在于联盟的范围内,所有必须定义整个网络
文件 。
加 . exampl.co 和 per0
参数 : . org2
首先,我们为每个组织指定了锚点节 . exampl
个
和持有
系统制的旧文件中定义,然后
文件还包含两个值得注意的附 . orgl
,正如名称所示
个独特的标题:
另一个是针对管道的
建我 们的
onsrtium
) 。
里有两
们创
。
文件 ium
”部分,这 ;
件
。
eConsrt
Profiles
文
ions
configtx.yaml
- TwoOrgsdeGni
引用
transc
peer
A nchor
transcio
Orgl&2 一
S 叫时
的
) 。
chanel
anchor
含示例网络的
该文件还指定了
主我们的
chanel
peer transactions
巳 l Configuration ( configtxe
。可以及两个节点组织(
这些标题很重 要,因为在我 。
block,
anchor
的创世区块,
。
l 上的
一个
n
servic
建的时候广播给
指定了每个组织在此
gensi
) 。
有关此工具的完整说明,请参阅
(perO
飞
该文件包含了有关定义和语法的大量档
Service Provides(MS
我们运行
文件夹中
{.Hostname } }.{Do
. com
) ; 其次
,我们为 每个成
第
员指定
MSP
文件夹,用来存储每个组织在 的概念
Fabri
c-s
。
现在任
意
和
amples
项目分析与实践
block
genesis
ordeing
servic
•!
341
中指定的根证书
。
通信的网络实体都可以对其数字签名进
。
运行工具
13.2.8 你可以用
con
你也可以
尝
figtxen
试使用
矛 1 cryptoge
byfn
. sh
必要的话,你可以
. yam
里我
们也
口命令来手动生成证书/密钥和各种配置文件
。 byfn.sh
脚本中的
函数去生成定义在
。
c ryptoge 旦 工 /b
口 eratCs
然而,为了方便起见这
。
首先,我们来运行
..
ge
l 文件中用于你的网络配置相关证书
会进行相应介绍
要提供
。
脚本来完成你的目标 参考
crypto-nfig
需
章
orde
这是一个 关键 行验证
13
这个
具所在的相对路径
工具。
我们的 二
进制文件在
bin
目录中,所以我们
。 generate - config= . /crypto config . yaml
工 n/cryptoge
你可能会看到以下
警告
,这是无害的请忽略它:
[bccsp] GetDefault -> WARN 001 Before Falling back to bootBCCSP.
接下来,我们需要告诉
configtxe
告诉它在我们当前所工作目
us
BCCSP , please call In i tFactories() .
工 ng
工具需要提取的
configtx.yam
l 所
在的位置
。
我们会
录。
首先,我们需要设置一个环境变量来告诉
configtxe
然后,我们将调用
configtx
en
工具去创建
ord
export FABRIC_ CFG_PATH=$PWD lb 工 n/cofigtxe -pro f 工 l e artifacts/genesis.block
你可以忽略有
去哪里寻找 er
eris
)和
. yaml
。
genesis block:
TwoOrgsOrdererGenesis
关中间证书、撤销列表(
示例网络中使用其的任何一个
er
c onfigtx
MSP
-outputBlock
配置的日志警告
. /channel-
。
我们没有在
。 接下来,我们需要创建 NAME
chane 或者将
CH
ANEL
_ NAME
l
transcio
配置
。
请确保替换
设置为整个说明中可以使用的环境变量
$CHANEL
_
:
export CHANNEL_ NAME=mychannel # this file contains the
def 工 n 工 tions for our sample channel /bin/configtxgen - profile TwoOrgsChannel outputCreateChannelTx artifacts/channel . tx -channelID $CHANNEL NAME
接下来,我们将在正构建的通道上定义
Orgl
NAME
已被替换或 . /bi
者为
以下命
令设置
了环
境变量
的
anchor
per
。
请再次确认
/channel -
$CHANEL_
:
口/ configtxe profile TwoOrgsChannel -outputAnchorPeersUpdate . /channel artifacts/OrglMSPanchors . tx -cha 口 elID $CHANNEL_NAME asOrg OrglMSP
.>
342
Hyperledger Fabric
源代码分析与深入解读
现在,我们将同
一 ..
个通道定义
Org2
的
anchor
peer :
工口/ configtxe -profile T 气 t10rgsChanel -outputAnchorPeersUpdate . /channelartifacts/Org2MSPanchors . tx -channelID $CHANNEL NAME asOrg Org2MSP /b
13.2.9 启动网络 我们将利用
d ock
er-co
mpose
脚本来启动我们的区块链网络
。
件利用我们之前下载的镜像,井以生成
g ensi
s.
block
来
docker
- compse
引导
ord
文
er
。
working_ dir : /opt/gopath/src/github . com/hyperledger/fabric/peer # command : /bin/bash -c ' . I scr 工 pts/cr 工 pt.sh ${CHANNEL_ NAME}; sleep $TIMEOUT ’ volumes
如果没有注释,该脚本将在网络启动时执行所命
令,正如
所描述的那样
。
适
当
退出
然
地为
而,我们想
手动执行命令,
TIMEOU
以便
传递较高
的值
我们在
幕
后发
公开每个调用的语法和功
生 能
(以秒为单位);默认情况
下
CLI
的情况中
。
容器将在
60
秒之
后
。 启动你的网络
:
CHANNEL_ NAME=$CHANNEL_ NAME TIMEOUT= compose-cli . yaml up -d
如
果要实
时
需要 打开
查看
你的
网
第二个终端来执行
1.
C LI
pe
4 个环境变
量
贝到
命
络
的日志,
请不要提供
- d 标志
。
如果你
需要
-f
docker-
日志流
,
你
令。
环境变量
为了使针对
出
区块链
docker-compose
CLI
rO
. exampl
来介绍我们的命令 此我们
orde
. com
。
容器中,因
点或者
. orgl
,则
需
不需要复
的
perO.o
月
CLI
制它们
。然
要相应地提供这些值
。
命令起作用,我们需要使下面给
l . exampl 而,如
检查
. com
涉及的这些变量将被拷
果你发送调用请求到其 docker
他的 compse-ba
. yam
l
per
节 中的
具
体路径: #
E 口 viro
me 口
t
variables for PEERO
CORE_PEER_ MS PCONFIGPATH= /opt/gopa th/src/g i thub . com/hyperl edger If abr i c/peer I crypto/peerOrganizations/orgl.example . com/users/Admin@orgl . example.com/msp CORE PEER_ ADDRESS=peer0.orgl . example .com : 7051 CORE PER_LOCAMS 工 D = ” OrglMS P” CORE_ PEER_ TLS_ ROOTCERT_F ILE=/opt/gopa th/ s rc/g i thub . com/hyper 1 edger If abr ic/peer I crypto/eOga
2.
我们将使用
口 izatons/rgl
. exampl.co/rsOg
.c
创建&加入信道
docker
exc
docker exec -it cli bash
命令进入
CLI
容器
:
om/tlsca
. crt
第
命
令
运行如果成功,你将
会看
到下列
工 thub
我们使用
configtxe
部分传递给
s 项目分析与实践
。
343
/peer#
口
el
. tx
,并将这个配置作为请求的二
。
。 TLS
握手
我们使用一
这是
orde
的
rot
cert
的本地
路径,允许我们去验
。
c 标志指定
文件名是
c -sample
工 C
cha
盖一州时作为命令的部分 证
Fabri
. com/hyperldgfab
工具生成信道配置-
orde
置
童
信息:
rot@Od78b6930:/pgahsc
。
13
chanel
chanel
. tx
的名
,当然你
字
,使用-
f 标志
指定
也可以使用不同的名
配置交易
。
称来挂载你自
己的
在这个例子中配 交易配置
。
export CHANNEL_NAME=mychannel 工 s mounted 工 n the channel-artifacts directory w 工 thin # the channel.tx file CLI container # as a result, we pass the full path for the file # we also pass the path for the orderer ca-cert in order to verify handshake # be sure to replace the $CHANNEL_ NAME var 工 able apro 工 ately
your
the TLS
peer channel create -o orderer . example . com : 7050 -c $CHANNEL_N!l.ME -f . /channel artifacts/channel . tx --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/ github
. com/hyperldgfabit
/ord
er
erO
gan
工 zations
/e
xample.co/
orderers/orderer.example com/msp/tlscacerts/tlsca example.com-cert . pem
此命
令返回一个
含了
创
chanel 。
主
. tx 剩
世区块一<
chanel-ID
中的配置信息
下的命令
. block
>,我
们
将使用它
加
入信道
。
它包
。
将会留在
CLI
容器内执行
。
当目标节最
以外的节,点时你必须记住所有命令
是除了
perO.ogl
须在相应的环境变量
.exam
现在让我们加入
perO.
org I . 巳 xample.co
下执行
内
com
。
频道。
# By default, th 工 s jo 工 ns 、 perO . orgl . exampl.co 、 only II the . block was returned by the previous command peer channel join -b
你可以修改
4 个环
3. 本节
境变量来让别的节点加入信道
。
安装和实例化链码 我们将利用一个现有的
简单链码,来学习如何编写自己的
应用程序和区块链账本会通过
。
以及背书我们
chainode 首先,将示
交易的
例代码
per
安装到
节
点上安装
相互 c hain
4 个
pe
巳 r 节
点
code
中的
,
影
响
。因
一
然后在信道上实例
此
我们
需要
个上
化
。
下面这个命
令
chain
在每 将源代码放到
code
个会执行 。
per
•!•
344
Hype
巾
dger Fabr
节点的文件系统中
i c 源代码分析与深入解读
。 peer
cha 工 ncode install -口 myc -v 1 . 0 -p github . com/hyperledger/fabric/examples/ chaincode/go/chaincode_ example02
接下来,在信道上实例化
c haincode
略,为目标
per
chain cod
巳交易
节点启动
一个
需要被验证 令
中
,我
一
个背书)
容器(注意
定
P
们只
。
,设置链码 - P 参数)。我
们
的背书策
需要
指定的
、当
这个
策略。
们指
策略。这意味着我
这将初始化信道上的链码
chainode
的时候背书
在下面的命 作为背书
c
需要
如果我们将语法变为
" OR
('O rgOMSP .membe r
orgl
AND
或者
org2
组织中的一个
那么我们就
F
,’ OrglMSP.member ’ ) ” 节点的背书即可
需要
( 即只
2 个背书者
有
。
# be sure to replace the $CHANNEL_NAME environment variable # if you did not install your cha 工 ncode w 工 th a name of my cc ,
then mod 工 fy that as well peer chaincode inst a 口 t 工 a te -o orderer . example . com : 7050 - -tls $CORE _ PER_TLS 一 ENABLED --caf i le /opt/gopath/src/gi thub . com/hyperledger/f abric/peer/crypto/ ordererOrganizations/example.com/orderers/orderer.example . com/msp/tlscacerts/tlsca . example.com-cert . pem C $CHANEL _ NA 阻 n mycc -v l. 0 -c ’ {吐 rgs ”: [ ” int ”," a ”," 10"' ”b ",” 200 ”]} ’ P ”OR ( ' OrglMSP . member ',’ Org2MSP.member ’ ) ” argume
4.
口
t
查询
让我们查询
一下
a 的值,以确保链码
被正确实例化、
stae
DB
被填充
。
查询的语法
如下: # be sure to set the peer chaincode query
5.
C and -n flags apro 工 ately C $CHANNEL_ NAME -n mycc -c
’ { ” Ar gs ”:
[ " query
” ,”
a ” ]}
『
调用
现在让我们从
a 账户转
10
元到
b 账户
。
这个交易将创建一新的区块并更
stae
DB
。
调用语法如下: # be sure to set the C and -n flags appropriat ely peer cha 工 n code invoke -o orderer.example . com : 7050 --tls $CORE_PEER_ TLS_ ENABLED ca f i 1 e /op t/gopa th/ s rc/g it hub . com/hyper 1 edger If abr i c/pe er I crypto/ordererOrganizations/example . com/orderers/orderer . example . com/msp/ tlscacerts/tlsca.example com cert . pem c $CHANNEL NAME n mycc -c ’{ ” Ar gs ”: [” invoke ”,” a ”,” b ”,” 10 " l}'
6.
查询
让我们确认下
们
用的时候转移了
10
元给
之前的调用被正确执行了
。
b 。
因此查询
a 应该展示
我们初始化了
90
a 的值为
元
。
查询的语法如下
# be sure to set the C and -n flags appropriately peer chaincode query -C $CHANNEL_NAME -n mycc -c ' { "Args ”:
我们应
该看到以
下内容:
10
,在上
:
[” query ",” a ” ]}’
一
次调
第
Query Result: 随时
幕
作
后
发
生了什
键值对和随后
的调用
com
中使用了
p ose
提
./ byfn
示去启动
脚本中没有注释掉的
. sh
你的网
络
block
-,
这个
的信道配
。
这个脚本驱动了
chanel.tx
文件
。
per
_ cha 口 ne
节点的文件系统中,
l _口
同时包
含了
ame>
.
chanel.tx
。
这个命
令
4 个
介绍了
per
per
节点执行
,作为之前产生
节点如何加入 去创
口现在我们有了由
4 个 Chanel
配置文件
per
节点以及
_ cha
建一条链
口
el
_n
gensi
b l ock
ame
>
的输
以及如何利用
。
2 个组织构成的
信道
。
这
是我 们的
T woOrgs
。
D perO.oglxamc
和
xample
. com
系是通过
和
perl
. orgl
perl
. org2
c rypto-cnfig
件中被指定
的
< your
.bok
.e
docker
命令此
< your
命令被
关
5
文件
creatChnl
以及信道 配置的
区块被存储在
D joinChael
口这些
34
相同的
容器中
l name
创世
置
org2
令
i .yaml
命令的产出是一个创世区块-
。
目分析与实践
。
chane
creatChnl
入
项
井确保了命令执行成功,然后使用
CLI
令使用提供的
口
es
docker-mpsl
down
-111
D script.sh j 向本被拷贝到 命
mpl
。
script.h 景,其
c-sa
么?
注意:以下步骤描述了在 中的场
Fabri
90
重新开始并操
7.
1 3 章
. exampl
. com
. exampl.co
. yaml
属
属于
定义
的,
MSP
于
Orgl;
路
Org2
peerO .
径在
。
docker compse
文
。
D OrglMSP(peerO. orgl . example . com com
) 的
MSPa
nc
anchor
更新
pers
hors.tx
和
将在
) 和
后续被更新
。
Org2MSPanchos
Org2MSP(
per0
我们通过携带
. org2 . example .
. tx
chanel 配置
的名字传递
到排序服
Orgl
务来实
现
a n c h or
per
的
。
D
一个链码-
chainode
per0
. org2
_ exampl02 . exampl
口这个链码在
. com
per0
. org2
信道上,并启动
中
. com
节点对应的
容器
[ ” a ”,
10
perO 中被
程 同样为
背
书
。 ” ,
策略传
实例
化
。
实例
了
a 的 perO.ogl
查询发往
关
” b ”,
20
。 ”]
。
实例
化的结
关参数
。
. exampl
. com
和
策略被定义为一
,因
. exampl.co 此这
P 。
次查询将启动一个名为
键值
对
。
示
例
dev
。 叮
Orgl
. orgl
的
果是一 个名为
. 0 的容器启动了
递相 perO
om
化过程将链码添加到
member ' , ' Org2MSP . member ’ )”,意思是任何交易必须被 口一个针对
.c
,同时初始化和链码服务有
peer0.o rg2 . example.com myc-1 口实例化过
. orgl.examp
。
. exampl
per 的初始化值是
被安装在
R
( ' OrglMSP .
或者
链码服务已经被安装在
Org2 dev-prO.
背书
。
•!•
346
Hyperledger Fabric
or
gl.
exa
mp
源代码分析与深入解读
l e.
co
m-yc1.0
的容器
作出现,因此查询的结果将为 q
10 一次
Q
invoke
被发往
链码服务被
口
安
一
个
que
第三
ry
装到
rO. 往
,这正说明
e . c om
ple
. org2
.co
e rl.
p le
or
,从
a 转移
. com
用于
g 2 . exampl
a 的值之前被转移了
10
10
到
L
e.
查
询
a 的
com-y
值
。
c -1
这将启动 . 0 。
返回
a
。
这指明了什么? 写
个
per
节点的链码服务
容
服务执行的情况(例如查询
操作,链码服务必须被安装在
per
器除了山
it
a 的值
初始化或者传统的交
易
) ,在其他情况下都不会启动
。
然,所有信道中的节点都持以块形式顺序存储
、 据库,以此来保存前状态的快照这包括了没有
在其 org
因为没有写操
m 。
. exam
v -pe
为了能够正确地在账本上进行读 每
。
a m pl
. e xam
p e erl de
90
.ex
. o rg2
请求被发
查询的结果也将被返回
。
orgl
perl
个链码服务,其名为
的值为 8.
pe
。
2 . e xample
例化了
. com
如上所
示
) 。最
不可
变
上安装
链
节点上
- 读/
写
。 - 针
交易导致容器的启动
此外,
对该链码
。
当
的账本精确备份及状态数 码服务的
pe
巳 r 节
点(
p e e rl
后,链码在被安装将是可达状态因为它已经
. 实
。 9.
如何查询这些交易?
检查
CLI
容器的日志
。
docker logs -f cl
工
你应该看到以下输出
:
2017-05 - 16 17 : 08 : 01. 366 UTC [msp) GetLocalMSP - > DEBU 004 Returning existing local MSP 2017-05-16 17 : 08 : 01.366 UTC [msp) GetDfaulS 工 g 且工 ngidet 工 ty -> DEBU 005 Obtaining d e fault sign 工 n g identity 2017 - 0 5 16 17 : 08 : 01.366 UTC [msp/ident i ty] Sign > DEBU 006 Sign : pla 工 ntex : OAB 1070A6708031AOC08F1E3ECC80510 . . 6D7963631AOAOA0571756572790 A0161 2017-0 5 -16 17: 08 : 01 . 367 UTC [msp /工 dent i ty] S i gn > DEBU 007 S 工 gn : d 工 gest : E6 1 DB3 7 F 4E8BOD32C9 FE10E3936BA9B8CD278 FAA1F3320B08712164248285C54 Query Result : 9 0 2017 - 05 -1 6 17 : 08 : 15 . 158 UTC [main) ma i 口-> INFO 008 Exit l 口 g . . . Query
= ==== == = = = ====== = ====
on
PEER3
o 口
chane
l
’ mychannel'
i s
successful
= ==== = =========== = === All GOOD , BYFN e x ecution completed ======== === ======= === |
-一
|\
I
| 你可以滚动这些日志来
L
-
_I
一
|- 一 一
I
一-
I I\
|
| 一 I
\
\ I I I I I I I I l_ l I \_I l 一
/
查看
各种
交
易
。
第
10
1 3 章
Fabric 叩m
J es
项目
分
析与实践
•!
347
. 如何查看链码曰志?
检
查 每个独
立
器的日志组合
的链码服
务
容器
来查看每
个容
器
内分隔的
交
易
。
下面 是每 个
链
码服
务容
:
$ docker logs dev-peer0 . org2 . example . com mycc 1 0 04 : 30 : 45 . 947 [BCCSP_FACTORY] DEBU : 工 nitalze BCCSP [SW] ex02 Init Aval = 100 , Bval = 200 $ docker l ogs dev-peerO.orgl . example . com- mycc-1 . 0 04 : 31 : 10 . 569 [BCCSP_FACTORY] DEBU : In 工 tialze BCCSP [SW] e x02
工 nvoke
Query Response {"Name ”.” a ” , ” Amount …” 100 ” } ex02 Invoke Aval = 90 , Bval = 210 $docker logs dev-pr l .org2ex 出 nple . com mycc 1 . 0 04 : 31 30 420 [BCCSP_FACTORY] DEBU : Initialize BCCSP [SW] ex02
工 nvoke
Query Response : { ” Name ” : " a ” ,” Amount ” :” 90 ” }
了解
13.2.10 B YFN
Docke
示
r Compse
例给我们
提
技术
供
了
两种风格的
Docker
c omp os e bas e . yaml ( base 给我
们
提
供
了
1 个
CLI
页面上的所有说明
容器
善
本
节
剩余部分
1 个
涵
细信息,请 第
到
参
二
种风格
是
端的测试
。
织的
CA
o rd
我
们
除了
阅
) 。
第一
er
种风格一
-
容器和
4 个
件,
它
p e
docker
们
都继承
自
- compse
r 容器
。
docker
- cl
我们用
此
文
i . yaml
件来展开这个
行
行
perOgan
io
n s/ o
例 rgl
同
样的私钥
。
子
你
同
。
样需要编辑
的 们
需要
情
m ple
服
为
务
使
用
的
No
容器
doc
指出
本
e.
组织
CA 的私
d e.
。
/ 。
. com/a
因
S D K
此
,
我
来运行端
们
能够向组
, Org2
。
- compse
我
- e 2e 你可以在
c r yp
们将使用 的
. :,咄
路径为
nl
启
和
动
ca
cal
serv
更新
的
FABRI
crypto
- co crypto
- co n
路径,并
C _CAS
nf
ig/ f i g/
E RVE_
为
每
个
,
t o -c o n fig
/。
caO
n d 去
k er 的私钥
钥
com/a
里为
coma
造
况下想使用 Orgl
. yaml
有关运行这些测试的详
。
,为了定位
. exa
- e2
变量
脚本 我
,被构
册和 登 记
. exampl
a tions/rg2
docker-mps
2 次
. sh
。
fa b r i c - ca 注
byfn 个
. y a ml
它还运行
求以用于
。
at
a niz
KEY FILE
s e - e2
4 个轻微的修改 iz
0 rg
请
心 叫。以件
。
, 的
有运
d o 阳
仓库
的功能之外
。举
在
S D K
R EST
要进
设计的
- comp
文件夹中找到这些值
er
SDK
Node
S D K
果你在没 需
盖了为
docker
节点发送
如
供了
下
文
。
。
p
目录
Compse
CA
T LS
容器提
仅供非
•!•
348
但
使用
的
Couch
数据库
是,
询
默 提
供
认的
golevdb
了额
CouchDB
代
c ompse-cuh
切换到
外的能力
替默
来根据 认的
. yaml
CouchDB
JSON
。
形式
的
链
链码同样能使用
数据
库(
之外,请
golevdb
遵
chaincode _ exampl02
现 bri
思、
性的影响
。
CouchDB Web
限制对
),除
循前面提到的
在
码服
了 生
心
应该使用下面的
务数据提
在
成配
供
更
启动网络的时 置
CouchDB
couh
在开发环
db
候 文件的过
程
加
。
丰富、复杂
传递
docker
:
境 界面
CouchDB
意
中映射端口可以使
CouchDB
( Fauxton
)对
数
查
容器的外部访问
fabric
询,你将
/ exampls
。
建 . orgl
目录中找到
.exam pl
巳 . com
的
marbles02
可用,并九许通过
l es02
链码交互 上安装和
数
_ exampl02
据(例如
和加入信道
,然而为了执
marbles02
链码服务
建 marb
perO
识到了安全
生产环境将避免端口映射,以
chainode
JSON
和加入频道的过程创
信道,请使用以下步骤与 在
来执行
使用被格式化为 / go
我们将按照上述创
docker
。
需要
/ chainode
REST API
据库进行可视化
CouchDB
CouchDB
-f
。
容器端口映射到主机,请确保你
你可以使用上面列出的步骤通过
行
流
C ouchDB
CHANNEL_NAME=$CHANNEL_NAME TIMEOUT= docker-compose compse-l 工 . yaml -f docker-compose couch.yaml up d
主如果你选择将臼
途或交
。
使用
。
用
DB
可以从
CouchDB
查
业
H yp e rl ed ge r Fabric j 原代码分析与深入解读
13.2.11 状态
商
)。
你可以
在
。一
。
旦你将
per
节点加入到了
实
。 例化链码:
# be sure to modify the $CHANNEL_ NAME variable accordingly for the instantiate command
peer
cha 工 ncode install -n marbles v 1 0 p g 工 thub . com/hyperldgfabi examples/chaincode/go/marbles02 peer cha 工 ncode insta 工 ate -o orderer . example . com : 7050 --tls $CORE_ PEER_ TLS_ ENABLED - -ca f i 1 e /op t/gopa t h/s rc/g it hub . com/hyper 1 edger /fabric/peer I crypto/ordererOrganizations/example . com/orderers/orderer . example . com/msp/ tlscaer/ . ex 缸 nple . com-ert . pem C $CHANNEL_ NAME n marbles -v 1.0 -c ’ { ” Ar gs ” : [ " init " J l ’ - P ” OR ( ’ OrgOMSP . member p ,’ OrglMSP . member ' ) ’t
创建
一
些
marbles
并
移动它们:
# be sure to modify the $CHANNEL_NAME variable accordingly
peer chainco d e 工口 voke -o orderer . example com : 7050 --tls $CORE_ PEER_ TL S 一 ENABLED - caf ile /opt/gopath/src/gi thub . com/hyper ledger I fabric/peer /crypto/ ordererOrganizations/example . com/orderers/orderer . example . com/msp/tlscacerts/ tlsca . example . com-cert . pem -C $CHANNEL_NAME -n marbles -c ’ {” Ar gs ” : [ ” initMarbl 巴 ” , ” marblel ", ” blue ”, “ 35 " ,” t om ”])’ peer cha l 口 c ode l 口 voke -o orderer . example . com : 7050 --tls $CORE_PEER TL S 一
学习使
用
ENABLED - cafile
主政
349
. com/hyperldgfabit
工 thub /optgahsrc
巳
. exampl
. com/rdes ordeOganizts/xmpl
•!
l e s 项目分析与实践
c - s amp Fabri
章 13
第
mi 业
i '阳 仅供
tlsca . example com-cert . pem -c $CHANNEL NAME
. com/sptlaer
-c ' marbles
-口
[ " initMarbl ’':
{ ’『 Args
e tls $CORE_ PEER_ TLS_ -o orderer . e x ample com : 7050 L nvoke peer ch a 工 n co d 巴 工 c /percyto ENABLED - - caf ile /opt /gopath/src/gi thub . com/hyper ledger I fabr ordererOrganizations/example . com/orderers/orderer example . com/msp/tlscacerts/ tlsca . example . com-cert . pem -C $CHANNEL_ NAME -n marbles -c ' { ” Arg s ": [ ” initMarbl e " , ” marble3 ”,” blue ”,” 70 ” ,” tom " J l ’ o orderer . example com : 7050 --tls $CORE_ PEER_ TL S 一 peer chainco d e invoke 工 C /peer/crypto/ . com/hyperldgfab ENABLED - cafile /optgahsrciub ordererOrga nizations/example . com/orderers/orderer . example com/ms p/tlscacerts/ -c ’ ( "Arg s ” : [ " transferM marbles tlsca . example . com-cert . pem -C $CHANNEL_ NAME -口 arble ”," marble2 " ,” jerry " )} ' peer c h a l 口 c ode invoke -o orderer . example . com : 7050 --tls $CO R E_ PEER_TLS_ ENABLED - - caf ile /opt/gopath/src/gi thub . com/hyper ledger I fabri c /peer /crypto/ ordererOrganizations/example . com/orderers/orderer . example . com/ms p/tlscacerts/ tlsca example . com-cert . pem -C $CHANNEL_ NA!1E -n marbles -c ' ( "Args " : [ ” transEerM 『 ” ]} arblesBasedOnColor ”, ” blue ” , “ jery peer chaincode invoke -o orderer example . com : 7050 --tls $CORE_ PEER_ TLS hub . com/hyper 1 edger/£ abr i c/peer/ 工t ENABLED - - cafile /optgahsrc crypto/ordererOrgan i za t ions/example com/orderers/orderer . example com/ n marbles -c msp/tlscac e rts/tlsca . example . com cert . pem -C $CHANNEL_ NAME ’ { ” Args " [ ” delete
)的数据库以及它文 字
名 信道
的 一
(或者你的唯 mychanel
个名为 一
到 看
你应该可以
。
: http :// localhost:5984/ _ utils URL
) 通过在浏览器导航中打开如下 Fauxton
界面(
CouchDB Web
通过 端口,那么你现在就可以
C ouchDB 文件中映射你的
docker-mps 如果你选择在
: 档在里面
。
Note For the below commands , be sure to update the SCHANNEL_NAME variable appropriately
查 中运行常规的
CLI 你可以在
peer chaincode
Query Result : ( ” color …” red ” ,” size ” : 50)
的历史记 marble
你可以检索特定
输出在
):
-c ’ { ” Ar gs
r 自 rbles
”:
” ])
b le2
a ’ mar
e ”,
[ ” readMbl
『
的输出如下: marble2
peer
e2 marbl
词(例如读取
-c $CHANNEL_ NAME -n
q 」 ery
。 变量被更新了
$CHANEL_M 主对于下面的命令,请确定
录
marble ”:
, ” docType
,例如
marble
",
name
le
的
交易
:
OW
口
j ”:
er
1:
query -c $CHANNEL NAME - n marbl es - c e ncod c h a工 l e ”,” marb lel " J } ’
marb
”,
” · ” marble2
' ( "Args ": [”
g e tH
工 s to
ryF
orMab
erry "
交
流学习使用
仅供非商业用途或交流学习使
350 令
Hyp
e 出
dg
e r Fabric
源代码分析与深入解读
Query Result :[{” Tx
":” lc3d3caf124c89f91a4c0f353723ac736c58155325f02890adebaal5
工 d
: { ” docType ":” marble ”, 口 arne ”: 叮 narble ’B ,” colr 『气’ t blue ”,” s iz e ": 35 , ” OW 口 er :“ t om ” }} , { ” Txid :“ 755d55c281889eaeebf405586f9e25d71d36eb3d35420 af833a20a2f53a3eefd ” , ” Value ”: { ” docType ":” marble ”," name ” :” mar bl el ”,” color ”:” blue ”, size ’门 35 ,” owner '『:” 〕 ery ” } ,{” Txid " : " 81945032de67fa 5 5e04 f14 7 8 8ee3 3e2 8b23 2 eef3 6d9 8 f ’t , ” Value ” }] e164
”,’'
Value
”
M
H
你还可以对数据内容执行丰富的查询操作,例如通过拥有者
jery
peer chaincode query -C er ”,” j erry ”]} ’
输出应该显示
2 个属于
$CHANEL
_NAM
jery
的
marb
E
口
查询
marble
:
-c ’ { ” Args ”: [” queryMarblesByOwn marbles
l e:
Query Result: [ { "Key ":” rnarble2 ” , ” Record ": { ” color ":” red ”,” doc Type ’ 1 :” marble ”, ” 口 am e ”: M rnarble2 ” , ” owner ”·” j erry ”,” size ”: 50}}. { ” Key ”:” rnarble3 ” , ” Record ": { ” color " :” blue ”,” docType " :” marble ", " name ” :” rnable3 ”, OW 口 er": " jerry ”," s ize ”: 70}} l
关于数据持久化
13.2.12
的
如果需要在
per
容器或者
提
示
CouchDB
容器进行 数据持久
化,
器内相应的目录挂载到容所在宿主机中
。 docker-mpsba
. yaml
文
件下
per
一
种选择是将
Docker
容
例如,你可以添加下面的代码到
的约定中:
volume s: - /var/hyperledger/peerO:/var/hyperledger/production
对于
CouchDB
容器,你可以在
CouchDB
的约定中添加如下两行代码:
volumes · /var/hyperledger / couchdbO : /opt/couchdb / data
故障
13.2.13
体
除
始终保持你的网络是全新
。
contaiers
以
及
chainode
使用以下命
令来移除
之前生成的
a r tifacs,
crypto,
images:
. /byfn . sh -rn down
如果你不移除容器和
镜像,
如果你看到 后重启你的
Docker Docker
你将
相 进程
关的错误信
。
内加密材料导致的错误
会看
到错误信息
息,则应检
Docker
的问题通常不
。
删除你的
镜像,并
从
头开始
:
docker rm f $(docker ps -aq) docker rrni f $(docker images -q)
如果你发现的创建、
。
实
例化、调用或者查询命令,请确保你已经更新了信道和链码
会被立
查
你的版本(应为 即识别
1.2 。
例如,你可能会看到由容器
或更
高
版本),然
仅供
第
的名字
。
提供的示例命令中有占位符
1 3 章
Fabri
「阳
nples
项目分析与实践
令
3 51
。
如果你看到下错误,则说明可能以前运行的链码服务(例 com
' I 二商业用途或交流学习使
dev-prl
- myc-1.0
或
de
v-perO
.org
l .e
xampl
e.
com
- myc
- 1 . 0 )有
.org2.example.
问题
:
Error: Error e 口 do rs ing chaincode : rpc er ror : code = 2 desc = chaincode code my cc : 1. 0 (cha 工 ncode /var /hyperl dger /producti mycc.1 0 exits)
删除这些链码服务,然后重试
Ero
工 nstalig 口/
chainodes/
。
docker rm
工-
$(docker images I grep peer[0-9] peer[O 9] f
如果你看到以下错误信息,则应确保的
Fabric
1. 0 . 0-rcl
镜像上
I awk
$3 ) ’)
『 ( print
网络运行在被标记为
lat
est
的
。
Error connecting : rpc error : code = 14 desc = grpc : RPC failed fast due to transport fa
工 lure
Error : rpc error
code = 14 desc = grpc: RPC fa
fast due to transport failure
工 led
如果你看到了以下错误内容,那么说明没有正确设
置
configtxe
工具需
CFG_PATH=$WD
要这个变量才能找到
configtx.
,然后重新创建
chanel
配置
工 g tx/tool/localconfig] Unsupported Config Type '『” panic : Error reading conf 工 guration
Load
[conf
要清理网络,请使用
down
)咄
选项
:
nl
。
FABRIC_G
_P
返回并执行
A TH
环境变
export
量。 FABRIC_
。 ->
CRI T 002
Un supported
Error reading
Configτ'ype
co
日
f 工 guratio
口
” t’
:
. /byfn . sh -m down
如
果
你看到
一条指示中依然有“
active
endpoits
”,然后
清理 你的
Docker
网络
。
会清除你之前的网络并且给一个全新环境: docker network prune
你将看到以下消息: WARNING! This will remove all networks 口 ot Are you sure you want to continue? [y/N]
选择
used by at least one container.
y 。
如果你仍旧看到了错误,请在
Hyperldg
享你的日志
Rocket Chat
。
13.3 注意,此基本配
basic-network 置
使用预先生成的证书
和
密钥材料,并且还具有预定义的操作来初始
的#
fabric-queston
频道上分
这将
:
仅供
•!•
化
352
一
H y p e rl ed ge r Fabric i 原代码分析与深入解
个名为“
mychan
i卖
n e l ”的通道
。
要重新生成这个材料,只需运行
ge 、
' I 二商业用途或交流学习使
口 erat
. sh
。
你
应该看
到以下输出:
bash
. /generate sh orgl example . com 2018-04-06 20 : 30 : 19 . 886 CST
[common/tools/configtxgen]
main -> INFO 001 Loading
2018-04 06 20 : 30 : 19 . 893 CST [comn/tlsf 工 gtxen] Generating genesis block 2018-04 - 06 20 : 30 : 19 . 893 CST [comn/tlsf 工 gtxen] Writing genesis block 2018 04 06 20 30 19 916 CST [common/tools/configtxgen] configuration 2018-04 06 20 : 30 : 19 . 920 CST [comn/tlsf 工 gtxen] INFO 002 Generating new channel conf igtx 2018-04 06 20 : 30:19.941 CST [common/tools/configtxgen] INFO 003 Wr 工 t l 口 g 口 ew channel tx 2018-04-06 20 : 30 : 19 . 971 CST [common/tools/configtxgen]
doOutputBlock -> INFO 002
configurat
工 0 口
configurat
网络,运行 、
、
、
main - > INFO 001 Loading doOutputChannelCreateTx -> doOutputChannelCreateTx -> main -〉工
NFO
001 Loading
口
2018-04 - 06 20 : 30 : 19 . 978 CST [common/tools/configtxgen] -> INFO 002 Generating anchor peer update 2018-04-06 20 : 30 : 19 . 978 CST [common/tools/configtxgen] > INFO 003 Wr 工 t ing anchor peer update
要启动
doOutputBlock -> INFO 003
star
. sh
。
你应该看到以下输出
doOutputAnchorPeersUpdate doOutputAnchorPeersUpdate
:
bash
. /start sh docker compose f dock er compose . yml up peerO . orgl example com couchdb Creating couchdb ... done Creat 工 ng peerO . orgl . example . com . . . done Creating orderer . example . com Creating ca . example . com Creating peerO . orgl . example . com # wait for Hyperledger Fabr 工 C to start
d
ca . example . com orderer . example . com
# Create the channel docker exec e "CORE_ PEER_ LOCALMSPID=OrglMSP ” e ” CORE_PEER_ MSPCONFIGPATH = /etc/ hyperledger/msp/users/Admin@orgl . example.com/msp ” peerO . orgl .example .com peer channel create -o orderer . example . com : 7050 -c mychannel -f /etc/hyperledger/ configtx/channel . tx 2018 04 06 12 : 33 : 25 . 408 UTC [channelCmd] InitCmdFactory > INFO 001 Endorser and orderer con 口 ect 工 0 口 S initialized 2018-04 06 12 : 33:25 . 457 UTC [channelCmd] In 工 tCmdFacory - > INFO 002 Endorser and orderer coneti 且 s intal 工 zed 2018 - 04-06 12 : 33 : 25 . 663 UTC [main] main-> INFO 003 Ex iti ng .... . # Join peerO orgl . example . com to the channel
仅供非商业用途或交流学习使
第
13
章
Fabr
i c-sa
mp
l es
项目分析与实践
·:
353
docker exec e ” CORE PEER LOCALMSPID=OrglMS P ” - e ” CORE PEER_ MSPCONFIGPATH=/etc/ hyperledger/msp/users/Admin@orgl example . com/msp ” peerO . orgl . example.com peer channel join 四 b mychannel . block 2018 04 06 12 33 : 25 867 UTC [chan 口 elCmd] InitCmdFactory -> INFO 001 Endorser and orderer conetis 工 nitalzed 2018-04-06 12: 33: 25 . 956 UTC [channelCmd] executeJoin > INFO 002 Successfully submitted proposal to joi 口 chanel 2018-04-06 12 : 33 : 25 956 UTC [mai 口 l main >工 NFO 003 Exit:ing ...
要停
止它,运行 、
stop
. sh
:
bash
. /stop . sh # Shut;: down the Docker co 口 tai 口 ers that m 工 ght docker-compose -f docker compose . yml stop Stopping peerO . orgl . example.com . . . done Stopping couchdb . . done Stopping orderer example . com . . . done
运行
teardown 、
. sh
,
在你
的
系统上彻底
be currently
删除网
络的所有“
犯
run
罪证据”
工 ng
:
bash
. /teardown . sh Removing peerO . orgl . example com . Removing ca . example.com . Removing couchdb . . Removing orderer.example . com . .. Removing network net_basic
b asic
-network
和
first-n
D basic-network 个节点
,因
网络,旨在 密码材料
和
基本应用程序所需的最 日 rst-newok
的部 署 同的,因为
拓扑 first-newok
实际上动态
Fabcar
13.4.1 编写第一个应用
基于
Hyperldg
建
立了一个拥有多
量。
它只有 个组织的
。 。
指引你
小节点数
只有一个单的组织。
包括预先生成的密码材料
本节将会
最基本的区块链网络应用程序需要提供给户查询账(包含特定记录)以及更新
此也
是不
:
chainode
演示更真实
work
13.4
的对比
建立了开发
一 D
etwork
done done done done
Fabric
网络 编写第一个应用程序。
生
成新的密码材料,而
basic
” net
仅供非商业用途或交流学习使
354
令
Hyp
e rl e dg
e r Fabric
(添加记录)的功能
源代码分析与深入解读
。 我们的应用程序基于
Javscri
里将通过
三
pt
,通过
Node.
SDK
步来指导你编写第一个应用程序
。
这
。
( 1 )启动一个
Hyperl
的组件来
与(账本所在的)网络进行交互
查
dger
询和更新账本
Fabric
。
。
这些组件有
器则用来发送一些管理命令
per
。
( 2 )学
区块链测试网络 节点、
在我们的网络中,需要一些最基本
ordeing
节点以及证书管理
有个简单的脚本将下载并启动这测试网络 参数
以让我们可用
多
而
CLI
容
。
习应用程序中到的智能合约例子所
详尽的数据
。
种方式和账本进行交互
。
。
智能合约包含的各种功,
比如,我们可以读取整体的数据或者某一部分
。
( 3 )开发能够查询及更新记录的应用程序
。
账本,另
一 这些功能
个用于更新账本
。
我们的程序将使用
我
们提供两个程
序例子
SDK
APis
一
一个用于查询
来和网络进行交互,并最终调用
。 完成本例之后,你应该基了解一个使用
Hyperldg
能合约的应用程序,是如何与
Hyperldg
Fabric
下面,让我们启动测试网络
Fabric Node.js SDK 网络中的账本进行
交互
的
并带有智
。
。
下载测试网络(
13.4.2 访问
Geting
Prequist
选择
a Test Network)
网页井确保你的计算机上已经安装了必需依赖项
clone
fabric
。
- sample
的工作目录,运行
clone
git clone htps : /github . cd fabric-samples/fabcar fabcr
com/hyperldgfab
命
令,并
进入
工 c-sample
子目录包含运行示例程序的脚本及代码
fabcr
子目录:
. git
。
在该目录运行
Is
命
令,你应该会
看到以下内容:
chaincode 现在调用
st
invoke.js
network
artFbic
. sh
下面命令将会载并解压
package . json
来启动网络
Fabr
j
Fabric Docker images
。
.sh
工 c
。
下面
是关
说明: 启动
per
节点
、
Ordeing
口创建一个通道,并将
、
CLI
容器
。
。 per
例化会启动链码容器
证书颁发机构及
加入该通道
将智能合约(即链码)安装到 实
口调用
节点
per 0
节点的文件系统上,并在通道实例化该链码;
。 intLedgr
startFabric.sh
,因此需要几分钟时间来完成
为了简洁起见,我们不会深入解这个命令的具体细节 0
s
可
。
Hyperldg . /star
que
功能来向通道账本写人
仅供非商业用途或交流学习使
10
辆不同的汽车
。
于这个命令的简要
仅供非商业用途或交流学习使
第
。
主这些操作通常由组
织或者 命令,但
SDK
docker
ps
Your First Network 图
章
Fabri
管理员来完成
c -sar
。 。
叩
J es 项目分析与实践
·:
这个脚本使用
具体请参阅
CLI~
Hyperldg
355
器来执行这些
Fabric Node SDK rep
。
。
发送
。
r 的
中也有相应的支持
中的示例脚本
序
pe
13
命
令可
以显
示
starFbic
.s
h
脚本启动的进程
。
13-
部分了解有关这些操作的详细信息和机制
。
所示简单描述了
一
个
应用程序与
Hyperldg
r Fa
你可以
在
Buildn
g
bric
在这里,我们专注于应用程 网
络交互的过程
。
区块链网络 应用开发者身份
日 图
应用程序使
AP
过名称和版本进行标识
Is
来调用
智能合约(
。 ,其名
API
称
是
dev
fabcr
,版本号是
,除此以外
包
( SDK
有资产),如图
。
运行
per
是
Fabric
还
这些智能合同托
管在
dev-prO
) 进行访问
。
提供了
网
络中
, 并通
Jav
. orgl.exampc
在本节中,我们将使用
。
SDK
Hyp 和
CLI
用于开
发应用程序
巳 rledg 。
查询账本
查询是指如何从账本中读取数据
。
JSON
链码”)
peerO . orgl . example . com - fabcar-1.0
1 0 ,
工具
Fabric Node SDK
似于
络交互过程
即“
例如,标识为
可通过软件开发
13.4.4
网
应用程序如何与网络进行交亘
13.4.3
的容器
13-
吨
的数据 13
存储格式写人的, - 2 所示
你可以查询单个或者多键的值,如果账本是
则可以执
类
行更复杂的搜索(如查找包含某些关键字所
。
己飞 仅供书商业用途或交流学习使
图
13-2
查
询过程
仅供非商业
•!•
356
Hype
削
ger
F 由
一
。
我们还有
途或交流学习使
用
IC 源代码分析与深入解读
正如前面所说,我们的示例网络有
的账本
用
一些
Javscript
个活跃的链码容器和
一
示例代码,我们可以使用
账本中关于车的详细信息
个已经包含
10
fa bear
目
录中的
辆不同汽车
query.
js
来查
询
。 在我们查看该应用程序的
工
作原理之前,
需
要安装
SDK
模块
。
在
f abcr
目
录
中,运
行下面的命令: npm
l 口
stal
后续命令也都是在
fa bear
现在我们可以运行 表
目
录中运行的
。
。
JavScript
程序
应用程序中预先加载了一个
。
query
首先,运行
query
All Cars
扣程序,返回账本上所有汽车列
函数,用于查询所有车辆因此我们可以简
单地运行程序: node que
js 可.
返回的信息如下: Query result count = Response is [ { ” Key ” Prius
”,
owner
":”
1 : ” CAR
。 ”,
Tomk
”: { ” colour ”:” blue ”,” make ”:” Toyota ”,” model ”:” Record
。 ” }
,
{ ” Key ”: "CARl ” , “ Record ": { ” colour ”:” red ”,” make " : ” Ford ”, ” model ”:” Mustang ”, ” owner ”·” Brad " }} , { ” Key ”… CAR2 ” , ” Record ": { ” colour H :” green ”,” make ”:’『 Hyundai ”, model ”: Tucson ”, own er ”·” Jin S 。 ” } , { ” Key ”:” CAR3 " , ” Record ’· . { ” colour ”:” yellow ",” make ”.” Volkswagen ”,” model ":” Pas sat ”, ” owner ":” Max ” }} , {” Key ”·” CAR4 ” , ” Record ": { ” colour ” : ” black " ,” make ” :” Tesla ”,” model ” :” S ”, owner ":'『 Ad ria 口
a
" },
{ ” Key ”.” CARS ” , ” Record ”. { ” colour ”:” purple ”,” make ”:” Peugeot ”,” model ”:” 205 ”,” owner :” Michel ” }} , { ”
Key
”.
CAR6
”,
Record
":
{ ” colur
”:
wh
工 te
”,“
make
”:
Chery
",”
model
” :”
S2L
”,
ow
口 er
":
” Aarav " )) , { ” Key ”:” CAR7 ” , ” Record" : { ,。 colur ”:” violet ”,” make ” : ” F 工 at ’e ,” model ”:” Pun to ",” owner ’ :” Pari ” }} , { ” Key ”:” CARS ” , " Record ··: { ” colour ”: 工 nd 工 go ”,” make ”:” Tata ",” model ”: Nan 。 ”, owner "· ” Valeria " )) , { ” Key ”:” CAR9 ” , ” Record ”: { " colour :” brown ",” make ”:“ Holden "," model ”: ” Bar 工 na ”, owne
t
N
r
这里有
”:
Shotar
10
Mustang
、一
键字是从
” }]
辆车, 辆
CARO
。
一 属于
到
Pari
辆属于
Adrian
CAR9
的紫罗
现在让我们来看代码内容
。
兰
的黑色 色
Fiat
这一点特别重要
Tesla Punto
等
。
使用编辑器(例如
账本是基于
Key
atom 、
path.jo
。
辆属于
Brad /飞 falue
的红色
Ford
的,在这里关
。
应用程序的初始部分定义了变量,如链码 var options = { wallet_path :
Model i 一
工 n
( 一_
仅供#商业用途或交流学习使
a 工 rname
,’
或
visual
通道名称和网络端点:
studio
. / networ
k
/creds
『),
)打开
que
可 .js
程序
。
第
13
章
Fabric-smple
项目分析与实践
令
357
user id · ’ PeerAdrnin ’, channel_id : ' mychannel ’ , chainode_
:『
fabcr
’,
network_ url : ' grpc : I /localhost : 7051 ',
这
是
构
建查 询的代码块
:
II queryCar - requires 1 argument , ex : args : [ ’ CAR4 ' ], II queryAllCars requ 工 res no arguments , ex : args : [ ' ' ],
= {
canst request
: optins . txid : transaction_id, fen: ' queryAllCars ' , args : [' ' ] chainode
工 d
我们将
chainode_
chainode
变
用该链码中定义的
一工
量
赋值为
, d
fa bear
queryAlCas
,这让我们
定位到这个特
的链码,
然后调
函数。
在前面,我们发出
node
我们能够使用的唯一功
query.js
命
令时,会调用特定函数来查询账本。但是这不
。 要查看其 到
他
内
intLedgr
容 ,可转 、
们仔细
看
inc ode
,、
A II Cars
(s
cha
queryCa
query
func
至
query
子目录并在编辑器中打开
All Cars
fabcr.go 、
creatC
和
函数是如何与账本进行交互的
。
changeCrOw
等函数
你会 。
看 让我
。
会 SmartCon
queryAllCars(APistub ct)
shim
. Cha
工 ncodeStubirfa)
sc . Response { startKey :=” CAR 。” endKey : = ” CAR999 " resultsiterator , err
该函数调用
shim
间的账本
:=
接口函数
APistub.GetStateByRange(startKey, endKey)
GetSaByRng
来返回参数在
数据。这两个键值分别定义为
辆汽车(假设
CARO
图
Keys
1 3-
所示
演示了一
都被正确使用),
和
CAR9
queryAlCas
。因
star
Key
此,我们理论上可以创建
和
10
函数将会显示出每一辆汽车的信息
个应用程序如何在链码中调不同功能
。
。 /一下\
\/ createCar queryAll Cars queryCarProerties updateCarColor updateCarOwner
图
智能合约
13
- 3
仅供非商业用途或交流学习使
应用程序在链码中的功能
!
endKy
有 ~
358
令
H y per!
吨
er
我们可以看到
F a bric
query
源代码分析与深入解读
账本,并
最
All Cars
终在链上增加
一
现在我们返回
query.js
将函数
query
们使用
。
creatC
个新区块
。
,这个函数可以让我们更新
下面先来了解另外一个查询
。
程序井编辑请求构造函数以查询特定的车辆
All Cars
CAR4
函数,还有一个称为
。
更改为
queryCa
,并将特定的“
所以我们编辑后的
Key
q uery.js
canst request = { chaincodeid : opti ns.cha txid . transaction_i d, fen : ' queryCar ’ , args : [’ CAR4 ’] 保存程序并返回
fa bear
程序现
i nc
目录
。
ode
一工
”传递给
args
参数
在应该包含以下内容 d
为达此目的,我们 。
在这里,我
:
,
现在再次运行程序:
query . ] S
口 ode
你应该看到以下内容: {’' colour ”:” black ”,” make ”:” Tesla
这样,我们就从查询所有车变成了只一辆
:
queryCa
函数,我们可以查询任意关键字(例如
Adrian
CARO
型号、颜色和所有者
的
黑色
Tesla
Mode l S 。
使用
),并获得与该车相对应的制造厂商、
。 现在你应该比较熟悉链码的基本查询功能以及带参数了,下面是时候更
新账本了·
. .
更新账本
13.4.5 我们已
更
经
完成了几个分类账查询井添加一些代码,现在更新本
。
新动作,首先让我们为手
创
建
一
辆新车
。
账本更新是从生成交易提案的应用程序开始
。
请求,用来识别要进行交易的通道
ID
S en
dTransctioPplA
该 把
求通过调用 交
易打包进区块,然后将发送到通道上的所有
endors
请
per
。
per(s
务的结
. reg
chanel
)进行认证
.
。
口 e l.
。
sendTransaction API
发送到
排序服务器
。
排
序服务器将
进行认证(在例子中,只有一个
) 。
isterTxEvn 果(
该程序然后调用
)返回一个提案答复,应用程序以此来创建和签署交易请求
eh
eh 机制
函数以及智能合约
per
最后,应用程序使 事
ing chan
endorsing per 用
、
就像查询一样,我们将会构造个
工将交易建议发送给 网络(即
我们可以做很多
. setPeerAddr 注册与特定交易
即成功提交或不)
ID
。
。
仅供#商业用途或交流学习使
该
API
API
相关联的事务
连接
到
per
获取事物提交结果,可以当作一个通知
。
的 该
事务 A PI
使应用程序能获得
监昕端口,
并调
第
。 主这里
我 们不
深 入讨论
交易流程文档
交
细
是简单
于这些
节 。
有关
重
交
Fabri c- sa mpl es 项目
易如何 最终提
交 给
分
•!• 析与实践
账本的详 细
359
信息,请 参
阅
。
我们初始调用的目标 建
易
13
交 易的 JavScript
地创 建一
程序
个新的资
invok
产
巳. 。
就像 查
( 这里 询
为
一样
汽
,
车) 。
我们有 一
个独 立
的用
使用编辑器打开程序并转到构
调用的代码块: var request = { targets : targets, chaincodeid : options . chaincode_id, fen . ’, args : [ ” ], chainid : options . channel_id , txid : tx id
我们可以调用函 Volt
用
,
数 并 把它归
CAR
属
IO 。
于
creatC
Nick
或者 。 在 账 本
cbangeCrOw 。
中我们的 Key
值已
发
存并 运行
出此
程序
事务
们回到
.
我们
程
来 调用 。
输出 一些提案
过
序并调用带有 CAR
,’
建一
用到了 CAR9
N 工 ck
响应和
应用程序通
Response is
Bary
,终端将会
通知,我们的 query
我们创
个红色的 Chevy
,所以这 里
我们将使
更新代码块如下:
var request = { targets : targets, cha 工 ncodei : options . chaincode_id, fen : ’ createCar ’ , args : [ ’ CARlO ’ , ’ Chevy ’ , ’ Volt ' , ' Red · c hainid: opt 工 ons.chael _ id , txi d: tx_ id
保
经
首先
交易
eh.rgistT
IO 参数
’],
ID 。
x EventAPI 的
但
queryCa
接收 函数
是, 我们
该通知
关 心的 是
, 将会看
。
:
现在 ,如
果我
到:
{ ’ colour ":” Red ”,” make ”: "Chevy ”, ”model ": "Volt ”," owner ” :” Nick ” } t
最后
一个
所以,我们 简单编辑
函数 changeCrOw invok
。 巳 .
Nick 很慷慨
,他想把的 Chevy
Volt
如下:
送给
var request = { tar gets : targets , chaincodeid: options . chaincode_id , fen : ’ changeCarOwner ’ , args: [ ’ CARlO ’ , ’ Barry ’], chainid: options . channel_ id , txid: tx id
询,将
再 次运行
node
会看 到如下结 Response is
p er
invoke.js 果
, 之 后再运行查
询 程
:
{ "colour ”" Red ” ," make ”:” Chevy
仅供非商业用途或交流学习使
序,我们仍 然是使 用
CAR IO
作为 参数查
•!•
360
13.5
Hyperledger Fabri
c 源代码分析与深
入解读
Balance transfer
Balance transfe
是一个
Node.j s SDK API
Node
扣应用程序
示例
- client
和
fabric-
- client
。
0 Docker - v 1.12 or higher, Docker 口
Docker
Com
p os
版本
1.2
Node. docker
镜像
版本
,有克隆
j s v8.4.0 or higher, Node.js 下载
或者更高的版本;
巳 - vl.8 or higher, Docker Compse
0 Git cl ient - needed for clone comands 0
fabric
预置环境
13.S.1
口
,用来演示
命令的
1.8
版本在
8.40
Git
客
或者 更高 的版本
;
户端;
或者更高的版本;
。
cd fabric-samples/balance transfer/ 完成上述设置之后,你将使用以下
Docker 口
2
容器配置来本地网络:
CAs;
0 A SOLO orderer; 4 口
peers (2 peers per
等
) 。
工件
13.S.2 使用
Org
Hyper
l e d ger
节点,即
Fabric
ordeing
中的
cryptogen
节点和
工具生
CA
容器
。
成加密材料,并将其安
关于
装
cryptogen
工具的更
hyper ledger-fabric.readthedocs.io/ en/Iatest/build_network.html#crypo
多
一个
orde
创世区块
Hyperledger Fabric
( gensi.block
工具
中的
)和通道配
configtxe
的更多细节可以在
工具 htp
ht m l #config
ur
at i o n-
tra
n saction
处找到
b a l an golan
终端窗口
或
no
d e.
编写的
dock
)已使用
置 在工件文夹中
。 关于
configtxe
。
ce
- transfe
示
chainode
运行
例,对于这些选择中的
每一 。
巳 r - compse
启动网络
。
docker-compose -f artifacts/docker-compose .yaml up 2 :安装
。
mychanel.tx
1
l : 使用
终端窗口
处找到
/
://hyperledger-fabric.readthedocs. io/ en/latest/bui Id_network.
” genrato
有两种选择可用于运行
方法
生 成并放
htp:
运行示例程序
13.S.3 使用以
预先
细节可以在
- genrato
置事务(
到所有对
fabric-lent
仅供
和
fabric-lent
· 1 二商业用
节点模块
i 主或交流学习使用
。
个,你可以选择
第
npm
1 3 章
F a bric-sampl
es
项目分析与实践
•!
361
工 nstal
在
PORT
4 0 0
上启动节点应用程序:
PORT=4000 node app 终端窗口 g i t hub
3 : 从示例 .co
m
方法
/ hy
AP
p e rl e d g 巳 r / fa
I 请求部分执行
R EST
b r i c ” sa
mpl
es
/ t re
/ mas
API [Sample REST APis Requests] (https://
t e r / b a l ance
- tra
n sfer#amp
l e - rest
- ap
i s - requ
巳 st
) 。
2
终端窗口
1 :
cd fabric-samples/balance-transfer . /runApp . sh 这会在本地计
算
然后,启动
PO
RT4
终端窗口
2
需 的网 络
0 :
stedolan.githu b. io/j q 在终端
机上启动所
。
上的节点应用程序
安
装
fabr
i c-
l ient
和
fabric
- ca
- c l ient
节点模块,
。
为了让下面的
she
l 脚本正确解析
JSON
,你必须
安装
jq
。
请参
阅
htps:
/
i 。
l 启动应用程序后,通过执行脚本测试
API
一-
tesAPi
. sh:
cd fabric-samples/balance-transfer #要使用
golan
chainode
. /testAPis . sh #或者使用
node
. /testAPis sh
13.54
示例一-
,请执行以下命令
-1 . js
gola
口 g
chaincode 1 node
REST
下述请求描了
Ba
APls 请求 l ance
transfe
示例,其利用
REST
作及查询的接口,方便用户直通过访问
API
暴露了一
系列
Fabric
网络操
。
1.
登录请求
在组织中注册并新用户一
一
Orgl
:
curl -s -X POST http : //localhost:4000/users -H "content-type : application/x-wwwform-urlencoded " d ' username=Jim&orgName=Orgl ' 输出
:
” succes s ” : t rue, "secret ”:” RaxhMgevgJcm ”, "message ” : ” Jim enrolled Successfully ”, ” token ” :” ”
这是后
响应包 续请求
含 的请求头中必
了成功
/失败状态 需
,
一个
的字符串
e nrolmet
仅供
。
' I 二商业用途或交流学习使
Secrt
和
一个
JSON
Web Token (JWT),
362 令
2.
H y pe 出 dg
e r Fabric 源代码分析与深入解读
创建通道请求
向 Orde
节点发送创 建
通道的请求 。
curl -s -X POST \ http : //localhost : 4000/channels \ -H ” authorization : Bearer ” \ -H "content-type : application/json ” \ -d ’ { ” channelName ” ·” my channel ”, ” chanelCofigPt
头部
”
authoriz
3.
ion 必
须 包
含从
”
/ art
POST
工 facts/hnelry
tx "
I user 调用返回的
JWT 。
加入通道请求
将指定的区块链节点加入相应通道 。
curl -s - X POST \ http : //localhost 4000/channels/rnychannel/peers \ -H ” authoriz 工 on : Bearer ”\ -H ” content type : apl 工 cation/js " \ -d ’{ ” pers
4. 安装
”:
[ ” perO.ogl
. exarnpl.co
’ 『 ,” perl
. orgl
. exarnpl
. corn
'『 ]
chainode
将链码部署 到
区块链节点上 。
curl -s -X POST \ http : I /localhost : 4000 I chaincodes \ -H ” authoriz 口 : Bearer ” \ -H "content-type : application/json " \ -d ' {
’l peers ”:
[ " peerO . orgl example.corn ”,” peerl.orgl . example.corn ” ] , ” chaincodeNarne ” : ” my cc ”, “ cha 工口 code Path
” :”
” chainodeτ'yp
” chainodeVrs
。 主当
使用
ex : curl
. corn/exapl_g golan
no
chainode d e. js
。 ”,
”,
”.
node.js
必须设直为
github
”:
v 。 ”
时, chainode
chaino 的位直 。
削阶 也放在相同目录中
必 、须设直为节点,并且 chainodePt 。
s X POST \ http : I /localhost : 4000 /chaincodes \ -H " author 工 zatio 口 : Bear ” \ H ’ content-type: application/json ” \ l
-d ’ {
仅供非商业用途或交流学习使
第
13
章
Fabric-sampl es 项目分析与实践
•!
363
. exampl.corn ’『 ] , ” peers ”: [ ” peerO . orgl . exarnple com ” ,” peerl orgl ” chaincodeNarne ”:” my cc ”, ” cha incodePath ”:" $PWD/artifacts/src/github . corn/example_ cc/node ", ” chaincodeType '’ : ” node ”,
” cha
5.
实例化
工 ncodeVrsi
"
"
v 。 ”
chainode
对部署在节点上的链码进行实例
化
。
curl -s -X POST \ http //localhost : 4000/channels/mychannel/chaincodes \ -H "authorization: Bearer ” \ 工 cat 工 on/js ” \ -H ” content-type: apl d ’{ ’t peers ”: [ ” peerO . orgl . exarnple.com ”, N peerl . orgl . example.com " ], ” chaincodeName ” :” my cc ” , ” chainodeVrs
”.
v 。”,
” chaincodeType ” . ” golang ”, ” args
使用
nod
6.
巳.
”:
[ ’『 a
’ 『,”
10
chainode
",”
时 ·,
b
”,
20
。”]
chainod
巳 T :扩 p 巳必
、须设置为节点
。
调用请求
调用
Fabr
cur l
ic
网络中的链码方法
。
s -X POST \ http : //localhost 4000/channel s /mychannel/chaincodes/mycc \ -H "authorization : Bearer ” \ -H "con t ent-type : application /] son ” \
@
d ’{ ” peers ”: [ ” peerO . orgl . exarnple.com ”,” peerl orgl.example . corn " ] , ” fcn ” :” move ”, ” args ": [ ” a ”,’『 b ” , ” 10 ” ]
主确保存响应中的
事务 7. Chaincode
。
查询
调用链码中相应的查询方法 curl
队以便在随后的查询事务中传递叫树
。 s X GET \ ” http : //localhost : 40/chanelsry exarnpl
.corn
工 ncodes/my?pr
&fcn=querya
gs
=屯
5B
革 2a
屯 2
在 5D
"
\ -H ” author 工 zation : Bearer " \ -H ” content-type : application/json ”
仅供非商
业
用途
或交流学习使
用
=p
erO
. orgl
.
36
4
令
H yp
8.
通
e rl e d ge r Fabr
过
Block
通过
i c 源代码分析与深入解读
N umbe
Block:Num
r 查询区块
b er
查
询区块
信息。
curl -s -X GET \ http : I /localhost : 40/chan
且 els/mychanbok?pr=O.g
’'
. exampl
. com
”
\
” \ H ” content-type : application/json " " author
-H
工
9 . 通过
Tr
通过
董
:
Bear
查询 i onID
-s
查
询
事
务
具体交易信息
。
GET
http : //localhost : 4000/channels/mychannel/transac t id here>?peer=peerO . orgl . example.com \ -H ” authorization : Bearer ” \ -H "content - type application/json ” -X
transc
。
工 0 口
ansctiolD
Transct
curl
zat
事务
ID
可以来自任何先前的调用
事
l 794cbl 7e2164c3f9
10
. 查询
查
工
ons/