当前位置: 首页 > 编程日记 > 正文

fabric 启动peer_编写 Fabric 链码的一般准则

我相信智能合约(链码)是 Hyperledger Fabric 区块链网络的核心。正确开发链码可以真正发挥一个安全区块链的优势,反之则会带来灾难性的后果。在这篇文章里我不打算探讨 Hyperledger Fabric 链码设计的特定模式的好与坏,而是希望分享我在开发若干 Hyperledger Fabric 概念验证应用过程中 总结的一些基本准则。

22b9703bbdd816fa9e9794a558324d12.png

1. 使用链码 DevMode(开发模式)

使用开发模式开启你的 Hyperledger Fabric 链码开发流程。这一点无论怎么强调都不过分,这会节省你大量的时间和精力,因为你可以自由地修改代码而无需重新部署并激活链码,也无需一遍遍地重启网络。

参考文档:https://github.com/hyperledger/fabric-samples/tree/release/chaincode-docker-devmode

P.S. - 虽然这个教程是使用 Golang,除了构建链码部分,使用其他语言其实也差不多。

2. 使用链码 Logging(日志)

这可能是能帮助你调试 Hyperledger Fabric 链码并快速找出链码 bug 的一个有用的技能。链码日志很简单易用,使用 Fabric 内建的 logger 即可。

参考文档:

  • Golang:shim ChaincodeLogger
  • NodeJS:shim newLogger
  • Java:可以使用任何标准的日志框架,例如 log4j

3. 避免在 Fabric 链码中使用全局键(Global Keys)

在开发 Hyperledger Fabric 链码时,我们经常会发现在搜索数据方面限制很多,因此要跟踪在键值库中注册的键,我们有时会尝试使用某些全局数据。

例如,当你再 Hyperledger Fabric 应用中跟踪注册的弹珠时,可能想创建一个全局的计数器以便生成弹珠的下一个 ID。但是这么做的时候, 你就引入了对这个变量的依赖。在开始的时候这看起来不是个问题,但是当你提交并发交易时就会出错。为什么?让我解释一下。

分析一下下面链码:

package mainimport ( //other imports "github.com/hyperledger/fabric/core/chaincode/shim" pb "github.com/hyperledger/fabric/protos/peer")//不要这么做! totalNumberOfMarbles := 0func (t *SimpleChaincode) initMarble(stub shim.ChaincodeStubInterface, args []string) pb.Response { var err error   marbleId := fmt.Sprintf("MARBLE_%06d",totalNumberOfMarbles) marbleName := args[0] color := strings.ToLower(args[1]) owner := strings.ToLower(args[3]) size, err := strconv.Atoi(args[2])   //other code to initialize objectType := "marble" marble := &marble{objectType, marbleId, marbleName, color, size, owner}   //--------------CODE SMELL---------------- //BIG source of Non-determinism as well as performance hit. totalNumberOfMarbles = totalNumberOfMarbles + 1  //--------------CODE SMELL----------------   //regular stuff...  err = stub.PutState(marbleId, marbleJSONasBytes) if err != nil { return shim.Error(err.Error()) }}

那么,为什么我讨厌这样?

原因 1:假设你已经完成这个 Fabric 链码,一切都很正常,直到有一天, 某个运行这个链码的 peer 节点,崩溃了。虽然账本数据还在,但是内部有些可怕的事情已经发生了。你可能重新启动 peer 节点,起初一切看起来都正常。 但是突然,这个节点背书的所有交易都开始失败了。为什么?就是因为那个全局计数变量已经不能正确跟踪真实的值了。其他的 peer 节点都计数到比如 15K 了,而这个节点突然从零开始计数,你的弹珠的 ID 又从零开始了。因此,当你将这个交易发送给排序节点(Orderer)并到达提交节点(Peer)时,提交节点上的验证系统(Validation System Chaincode)会比较所有背书交易的提议响应, 同时检查是否有足够的签名存在,只要有一个提议响应不匹配,提交节点就会抛出一个 ENDORSEMENT_POLICY_FAILURE 异常。

原因 2:现在让我们尝试解决上面的问题,在 Fabric 链码的最后添加代码stub.PutState("marble_count", totalNumberOfMarbles)

这样会好一些吗? NO...

考虑一下有两个并发交易都试图插入新的弹珠。

例如,一个交易要将marble_count的值更新为34,此时 marble_count 的版本为 10 new_version(marble_count) = 10。 而另一个交易则要将 marble_count 的值更新为 35,也是 new_version(marble_count) = 10 。 记住,由于这两个交易是并发的,两个交易看到的都是current_version(marble_count) = 09。

现在其中一个交易将在另一个交易之前到达 Fabric 的排序节点,marble_count 键已经更新到新的值,这时 marble_count 的版本已经是 10,因此后到的交易将失败,因为 marble_count 的版本已经是 10 ,而后续交易还认为它读的是版本 09 并且将更新到版本 10。这是区块链中经典的双花问题(double spending)。

Hyperledger Fabric 在提交交易时使用一种优化的锁模型。正如我已经解释过的, 提议响应由客户端从背书节点采集,然后发送给排序节点并最终由排序节点将其分发给提交节点。在这个两步过程中,如果有些在背书阶段读取的键的版本发生了变化, 你就会得到MVCC_READ_CONFLICT错误。当存在并发交易同时更新相同的键时,就有可能出现这个问题。

关于这一点的详细说明,可以参考这篇文章。

PS. 即使您不执行并发交易,如果更新同一键的一个或多个交易打包到同一块中同样也会出现这个问题。因为,在提交块之前,不会提交 Hyperledger Fabric 中的交易。

d3079c6bdc4ef3b78be9e0a01abc9c58.png

4. 聪明地使用 CouchDB 查询

Couch DB 查询(又称为 Mongo 查询)在搜索 Fabric 节点的键值库中的数据时非常有用, 但是有一些坑你需要注意。

** Couch DB 查询不会修改交易的 READ SET**

Mongo 查询仅用来查询节点的键值库也就是状态库。它不会修改交易的 read set。这可能会在交易中导致幻读(phantom reads)。

** 只能搜索到已经存入 CouchDB 的数据 **

不要试图用 Mongo 查询按键名搜索。虽然你可以访问 CouchDB 的 Fauxton 控制台, 但你无法按键查询。例如,不允许查询channelName0000KeyName。更好的方法时将键作为你自己数据的属性保存。

5. 编写确定性的 Fabric 链码

永远不要编写不确定的链码。意思是说如果我在多个不同的时间、不同的环境下执行链码,总应该得到相同的结果。例如,避免使用像rand.New(...)或 t := time.Now() 这样的代码,或者依赖于某个没有在账本中持久化的变量。

这是因为,如果生成的读写集不一样,Hyperledger Fabric 的验证系统链码(Validation System Chaincode) 会拒绝交易并抛出 ENDORSEMENT_POLICY_FAILURE 异常。

79a9f17470637a788c39a026c0a2abf6.png

6. 小心调用其他通道的 Fabric 链码

在链码中调用同一个通道中的另一个链码没问题,但是要了解的是,如果是要调用另一个通道的链码,你只能得到链码方法的返回结果,而不会在另一个通道账本中有任何提交。目前,跨通道的链码调用不会修改数据,因此,一个交易一次只能写入一个通道。

7. 记得设置 Fabric 链码的执行超时时间

在高负载的情况下,你的 Hyperledger Fabric 链码可能不会在 30s 内完成。因此一个好的实践是 根据需求定制链码执行超时值。这是由 core.yaml 中的参数决定的。你可以 在 docker compose 文件中如下设置:

如: CORE_CHAINCODE_EXECUTETIMEOUT=60s

8. 避免从 Fabric 链码中访问外部资源

访问外部资源可能会暴露系统漏洞并给你的 Hyperledger Fabric 链码引入安全威胁。无论如何你不会希望外部资源中的恶意代码影响你的链码逻辑。因此请尽可能的避免 再 Fabric 链码中访问区块链外部的资源。

345c16595dc1690e53ed0470fc589de9.png

相关文章:

Qt pro文件下跨平台宏的使用(windows/linux 以及x86 和 arm的区分)

#Qt pro文件下跨平台宏的使用(windows/linux 以及x86 和 arm的区分) 在pro文件中添加: #仅在linux 系统下, 硬件平台无关的内容 unix{HEADERS \SOURCES \Manager.cpp \ }#arm64 的编译宏 contains(QMAKE_HOST.arch, aarch64){…

数论(一)——素数,GCD,LCM

这是一个数论系列:) 一、素数 费马小定理 Theorem: 设 p 是一个素数,a 是一个整数且不是 p 的倍数,那么 很遗憾,费马小定理的逆定理是不成立的。对 a 2,满足的非素数 n 是存在的。 比如 n 341 11 31 对于整数 a,称满足的合数为以 a 为底的…

java自学 day1

1.数据类型 基本数据类型(存放数据本身) 分为数值型(int,double等) 字符型(char)布尔型(boolean) 引用数据类型(存放数据的地址)分为类&#xff0…

Qt下一行代码就可以使用的稳定易用的日志log类

Qt下一行代码就可以使用的稳定易用的日志类 此日志类是基于Qt 自带的 扩展的一个易用的日志类, 使用的是Qt自带的日志输出形式, 已长期运行在许多实际项目中,稳定可靠,而且跨平台, 在windows和linux 上都能稳定运行 …

apue读书笔记-第十二章

1 可重入,线程安全,异步信号安全之间的区别? 可重入:可以重复进入,不会引起问题(这个概念最宽) 线程安全:被多个线程使用时,不会出问题,也就是可以被多个进程…

取出url中的字符_如何在JavaScript中解析URL:例如主机名,路径名,查询,哈希?...

统一资源定位符(缩写URL)是对Web资源(网页,图像,文件)的引用。URL指定资源位置和检索资源的机制(http,ftp,mailto)。例如,这是此博客文章的URL&am…

SQL Server 2008中的Pivot和UnPivot

SQL Server 2008中SQL应用系列--目录索引 今天给新成员讲解PIVOT 和 UNPIVOT示例,顺便整理了一下其用法。这是自SQL Server 2005起提供的新功能。 官方示例:http://msdn.microsoft.com/zh-cn/library/ms177410%28vsql.105%29.aspx 首先看PIVOT示例&#…

leetcode python 032 识别最长合法括号

# 给定一个只包含字符(和)的字符串,# 找到最长的有效(格式良好)括号子字符串的长度。# 对于“(()”,最长的有效括号子串是“()”,其长…

Android窗口管理服务WindowManagerService计算Activity窗口大小的过程分析

在Android系统中,Activity窗口的大小是由WindowManagerService服务来计算的。WindowManagerService服务会根据屏幕及其装饰区的大小来决定Activity窗口的大小。一个Activity窗口只有知道自己的大小之后,才能对它里面的UI元素进行测量、布局以及绘制。本文…

pcl需要注意的编译问题

pcl需要注意的编译问题 不要在头文件里 using namespace pcl 这会导致编译错误,而且根本分析不到错误在哪 不要在编译选项 里加 -marchnative 这个是让编译器根据你当前的cpu类型进行特定的编译优化, 例如 set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdc11 -march…

linux python版本_linux下更新Python版本并修改默认版本

linux下更新Python版本并修改默认版本,有需要的朋友可以参考下。很多情况下拿到的服务器python版本很低,需要自己动手更改默认python版本1、从官网下载python安装包(这个版本可以是任意版本3.3 2.7 2.6等等)wget http://python.org/ftp/python/2.7/Pytho…

基于HTML5的Google水下搜索

这次愚人节的时候,Google推出了水下搜索,当然,这只是一个愚人的小把戏,不过效果非常不错,进入页面后,第一眼是一个水面的效果,水下的鲨鱼在游来游去,然后Google logo和搜索框从水面上…

windows下rpc框架thrift的环境配置

windows下rpc框架thrift的环境配置 引用链接: https://www.cnblogs.com/49er/p/7193829.html 最近在弄windows下 的Facebook的rpc 框架 thrift , 网上东西看了很多, 但是大都不能一篇到位, 这里总结了一下, 也记一下自己遇到的问题和解决的方法 这里把我在实际过程中遇见的问…

CentOS 6.3 安装 samba 共享

PHP环境在linux下,但是开发的时候用的是windows,于是我用了samba将linux的一个目录共享,然后在windows上做映射,这样就可以直接在windows下编辑linux上的文件了 首先,安装samba软件,我采用的是yum安装&…

微信小程序 长按图片不出现菜单_微信更新,新功能上了热搜

微信在推出新功能方面相当克制,但每一次总能引起全网关注。昨天,微信又因为一个小功能的改进再次上了热搜,在安卓最新的 7.0.17 版本当中,微信取消了两分钟内删除功能。在新版微信中,发出的消息在两分钟内只有撤回功能…

windows下配置java环境jdk

Windows系统下搭建java的开发环境和配置环境变量 具体步骤打开链接地址:https://www.cnblogs.com/lijuntao/p/6694483.html转载于:https://www.cnblogs.com/ccw869476711/p/9401468.html

mysql 分区_搞懂MySQL分区

一.InnoDB逻辑存储结构首先要先介绍一下InnoDB逻辑存储结构和区的概念,它的所有数据都被逻辑地存放在表空间,表空间又由段,区,页组成。段段就是上图的segment区域,常见的段有数据段、索引段、回滚段等,在In…

apt Could not get lock /var/lib/dpkg/lock 解决方案

apt Could not get lock /var/lib/dpkg/lock 解决方案 删除锁定文件 sudo rm /var/lib/dpkg/lock

oracle创建DBLink连接

1.创建dblink的第一种方式,是在本地数据库tnsnames.ora文件中配置了要远程访问的数据库。tnsnames.ora文件在你安装oracle客户端安装文件里 如:(E:\oracle\product\10.2.0\db_1\NETWORK\ADMIN) 创建远程连接: INT (DESCRIPTION (ADDRES…

理解oracle中连接和会话

理解oracle中连接和会话1. 概念不同:概念不同: 连接是指物理的网络连接。 在已建立的连接上,建立客户端与oracle的会话,以后客户端与oracle的交互都在一个会话环境中进行。 2. 关系是多对多: 一个连接上可以建立0个…

ActiveMQ消息存储持久化

转https://www.cnblogs.com/xinhuaxuan/p/6128380.html https://blog.csdn.net/lr131425/article/details/68064914 为了避免意外宕机以后丢失信息,需要做到重启后可以恢复消息队列,消息系统一般都会采用持久化机制。 就是在发送者将消息发送出去后&…

python 非_Python函数的非固定参数

一、概述在原来的文章中我已经写了,位置参数和关键字参数,下面我们来谈谈默认参数和参数组二、默认参数默认参数指的是,我们在传参之前,先给参数制定一个默认的值。当我们调用函数时,默认参数是非必须传递的。默认参数…

C#关于面对象多态例子

//主的喂狗 class Program { static void Main(string[] args) { //我们来模拟一个主人养狗动物的例子 首先创建一个主人对象,同时主人买了条狗 //买来条狗,主人一喂,狗会吃东西 Person person ne…

ubuntu package XXX needs to be reinstalled,but I can't find an archive 问题修复

ubuntu package XXX needs to be reinstalled, but I can’t find an archive 修复 原文连接: https://blog.csdn.net/tbitwqb/article/details/78241101 内容: 不知道什么原因,可能是升级过程过关机或者其他什么情况导致当前问题的发生。 无论是apt…

CentOS6.2解决passwd: Authentication token manipulation error报错

passwd: Authentication token manipulation error这种错误可能有多种原因,就我了解的可能有/etc/passwd等文件i权限 今天在给学员上课的时候发现提示passwd: Authentication token manipulation error错误,我来简单描述今天的问题 [roothost4 Scripts]#…

Java核心技术第五章——2.Object类

Object类:所有类的超类 Object类是Java中所有类的始祖,在Java中每个类都是由它扩展而来的。但是并不需要这样写: public class Emloyee extends Object 如果没有明确的指出超类,Object就被认为是这个类的超类。在Java中&#xff0…

21day学通python_铁乐学python_day21_面向对象编程3

抽象类和接口类以下内容大部分摘自博客http://www.cnblogs.com/Eva-J/继承有两种用途:一:继承基类的方法,并且做出自己的改变或者扩展(代码重用)二:声明某个子类兼容于某基类,定义一个接口类Interface,接口…

系统crash无法启动 tpm error / could not read size 0x8000000e

系统crash无法启动 tpm error / couldn’t read size 0x8000000e 原文连接: https://unix.stackexchange.com/questions/305719/a-tpm-error-7-occurred-attempting-to-read-a-pcr-value-in-centos 内容: 问题: I’m getting this error while booting…

ASP.NET文件的下载

/// <summary>/// 下载文件/// </summary>/// <param name"filePath">文件的路径</param>/// <param name"fileName">文件名(有时候文件名存在数据库中用于替换路径中的文件名)</param>public void FileDownLoad(stri…

TestLink1.9.3测试用例:Excel转换XML工具一

最近在整理测试用例&#xff0c;所以想找一个合适的工具来完成对测试需求、测试用例的管理。对比了一翻&#xff0c;发现开源工具中扩展比较好的还属TestLink&#xff0c;而且还可以与JIRA进行对接&#xff0c;这样就引起了我更大的兴趣。加上之前本来就接触过此工具&#xff0…