fabric1.0学习笔记(1)fabric1.0学习笔记(2)fabric1.0学习笔记(3)fabric1.0学习笔记(4)fabric1.0学习笔记(5)fabric1.0学习笔记(6)
在之前的笔记中了解了fabric基本结构、底层操作的具体实现(排序节点的实现、交易收集、区块打包、扩散的实现、账本存储相关的实现等),这篇笔记涉及智能合约、节点的设置问题
一、智能合约
主要有以下三个问题:
- 链码生命周期管理
- 系统链码
- 链码的编程接口及编程禁忌
智能合约也称为链码,运行在背书节点上,模拟执行交易对状态数据库进行操作,可这么说(它是一段fabric上的程序,基于fabric的程序需要通过智能合约实现应用程序的数据映射到fabric内进行相关的操作,个人感觉 基于fabric的应用程序与智能合约 有点像web端与服务端之间的关系,fabric则像一个数据库)
智能合约(链码)
- 相关定义:
合约协议的数字化代码表达:平常的合同用代码来表达;
分布式有限状态机:起始条件一致、改变条件一致就一定可以得到一个一致的最终结果;
fabric智能合约是应用层的基石,是应用程序与区块链底层交互的媒介,区块链程序直接与智能合约交互,智能合约再与fabric底层交互。它有独立的docker执行环境。通过grpc与背书节点进行连接,也就是说只有背书节点上才会运行有链码。
区块链中智能合约放在一个隔离的智能合约中执行、不受第三方的干扰(不受人的主观影响)fabric主要通过docker实现
链码的生命周期:
- 1、打包 将链码整合成一个文件,相当于代码编译
- 2、安装 将上一步打包好的文件上传到背书节点
- 3、实例化 真正意义上的安装执行 init方法相当于面向对象中的构造函数,只会被执行一次
- 4、升级 前一个版本的链码可以升级为新链码,升级后旧的链码就无法完成交易
- 5、交互 分为查询、写入但现在已经合并为一个了
智能合约的交互流程:
- 1、用户程序向背书节点发起请求
- 2、背书收到消息节点调用docker接口
- 3、如果链码容器没有启动,会自动编译启动链码容器
- 4、启动后的容器与背书节点建立grpc连接,背书接节点把收到的请求转发给链码容器执行并返回结果
- 5、背书节点收到结果后会调用escc对结果进行签名,然后返回背书结果给用户程序。
系统链码:
用于完成一些系统功能,它们运行在节点进程中而非链码容器1.0中有五种系统链码:
- LSCC(Lifecycle System Chaincode)管理链码生命周期,主要是安装、实例化及升级
- CSCC(Configuration System Chaincode)配置管理链码,管理某一条链的配置,如允许新的节点加入某一条链
- QSCC(Query System Chaincode)查询账本存储,相当于区块索引的web服务
- ESCC(Endorsement System Chaincode)交易背书链码,封装交易模拟执行后的结果、然后签名组装为客户认可的交易背书结果
- VSCC(Validation System Chaincode)主要用于交易验证,交易被记账节点记录之前需要完成有效性的校验,如用老版本的链码进行交易模拟的交易会被认定为无效
链码的编程接口:
- init() 用于链码初始化,整个生命周期只会被执行一次,主要做一些初始化的操作
- invoke()应用程序与链码交互的入口,所有链码的业务逻辑均通过该方法调用
二者的参数均为链码的sdk接口。
链码的SDK接口
- 参数解析类:解析客户端发送过来的请求和方法及相对应的参数
- 交易消息类:获取当前交易的一些信息1.0只有获取交易id这一个方法
- 状态操作类:主要是对状态的增删改查
- 链码的互操作类:区块链跨链功能的体现,1.0只支持对链码的查询功能
- 事件发送类:在链码中完成操作后给应用程序发送相应的事件,应用程序再根据事件做相应的操作
- 其他操作类:很少用
链码编程禁忌:
一个认识:链码在整个分布式系统中执行,在多个节点上隔离执行,可能每个背书节点都会执行,对一笔交易在系统中可能会被执行很多次,取决于背书策略。因此就需要保证结果不受节点不同的影响即不同节点执行相同的交易要得到的是一个一致的结果。 应用程序收到后要比较所有的背书结果,如果不一样就不会发往排序节点进行排序。例如链码中用了随机函数、系统时间等在时间和空间上具有特性的量及不稳定的外部依赖(在某个时间某个节点上正常,而另一个时间另一个节点上不正常)。
二、节点的设置
- orderer节点
orderer配置文件
关注点:
- 1、如何注入系统配置到容器中
- 2、端口的映射关系
- 3、文件的映射
- 1、fabric提供有默认配置在farbic/sampleconfig目录下,有两种方法修改配置一种是直接修改原来的文件,另一种是通过环境变量注入的方法把配置文件中的某一些值进行修改,其他值为原有的默认配置。
测试中一般通过环境变量注入来修改配置,例如修改默认配置文件中orderer.yaml中的Kafka:Retry:ShortInterval的值,就可以在容器启动文件中的orderer中加上环境变量“ORDERER_KAFKA_RETRY_SHORTINTERVAL=XX”,这里是哪个节点就以哪个名称开头,加上默认文件中的分区,以下划线分割就完成的环境变量的注入。 - 在开发测试时想要关注、设置哪个变量就可以在编写容器启动文件的时候添加对应的环境变量即可。 注:替换的值要使用容器中的路径
下面一些常用的变量及其含义
- LOGLEVEL日志级别
- LISTENADDRESS服务暴露地址
- GENESISFILE创世区块的注入
- LOCALMSPID LOCALMSPDIR与节点的msp证书相关
(对于orderer节点来说只要这几个参数设置好就可以正常启动orderer节点) - 2、端口映射
例7050:7050 主机端口:容器中orderer节点的服务端口(一般是7050) 把容器中的端口映射到主机的某个端口 - 3、文件映射
本地文件路径:容器中的文件路径 把本地的文件映射到容器中去 - peer节点
- 1、公共服务
如果peer节点很多可以用可以在容器启动文件中添加peer.base来做peer的公共服务。提取所有peer节点的公共参数写在一起,然后每个peer只需设置公共部分之外的内容 例如CORE_PEER_ID; CORE_PEER_ADDRESS针对不同节点有不同的设置,在配置文件中添加上extends: service:peer.base字段即可
一般公共服务有以下的内容:
- CORE_VM_ENDPOINT 将本机的docker server注入,与peer进行链码的编译、启动操作有关
- CORE_PEER_MSGCONFIGPATH msp证书 注意在节点启动的证书都是关于节点的(与链上的证书不一样)
- CORE_LEDGER_STATE_STATEDATABASAE 设置状态数据库的存储引擎 couchdb或则leveldb
- CORE_VM_DOCKER_HOSTCONFIG_NETEWORKMODE 设置链码的网络,使链码与peer节点使用同一个网络,否则链码可能连接不上peer节点
注意:与orderer节点不同,peer节点的环境变量注入的前缀变成了CORE(orderer节点是ORDERER)
- 2、端口映射
peer节点一般对外暴露两个端口 - 7051 grpc端口,用于grpc服务
- 7053 eventhub端口,用于事件监听
注意:映射时不要重复用主机的相同端口 - cli节点
peer节点的客户端(链上的交易都是通过客户端节点发起的),一次只能连接到一个peer节点,通过CORE_PEER_ADDRESS选择连接不同的peer节点。证书注入时用的是user的证书;
注意:客户端节点在映射文件时需要注入链码,即把链码映射到cli容器内,然后通过cli进行安装
客户端节点中的一些操作
- peer channel update 用于设置主节点
- peer chaincode instantiate -o指定orderer节点 -C指定通道名 -n链码名 -l指定链码所用语言 -v指定版本 -c指定参数
- docker logs -f --tail 100用于查看最后100行日志(这个是容器外的)
查看日志时,链码容器中的日志是链码执行的产生的内容。