热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

HyperledgerFabric账本结构解析

前言现在很多人都在从事区块链方面的研究,作者也一直在基于HyperledgerFabric做一些开发工作。为了方便后来人更快的入门,本着“开源”的精神,在本文中向大家讲解一下Hyperled
前言

  现在很多人都在从事区块链方面的研究,作者也一直在基于Hyperledger Fabric做一些开发工作。为了方便后来人更快的入门,本着“开源”的精神,在本文中向大家讲解一下Hyperledger Fabric账本的结构和原理。作者解析的Fabric的工程版本为v1.0.1,在新版本中可能会有些许偏差。

  ps:作者默认各位读者已经具备了一定的区块链基本知识,不再做一些基础知识的阐述。

Hyperledger Fabric账本的结构

  在作者最初了解bitcoin的时候有一个疑问:矿工如何校验一笔交易中引入的Utxo是否合法呢?如果过是从创世块开始遍历工作量会随着块的增加而逐渐变大。当作者研究过Bitcoin的源码后发现,在Bitcoin中有一部分模块是用来存储当前所有Utxo的,它采用的是levelDB数据库,在校验一笔交易中的Utxo是否合法时直接去DB中检索即可。

  Bitcoin的这种做法给作者总结为如下:“单纯”的区块链账本存储区块数据即可,而为了方便支持各种功能往往会提取出一些数据(重要的、频繁访问的)独立存储。在Bitcoin的世界中矿工的共识实际上是对当前Utxo的共识,所以它将Utxo从区块量账本中提取出来独立的存储,那在Hyperledger Fabric中需要从区块账本中提取出的数据是什么?

  Fabric中是一个针对商业应用的分布式账本技术,本身并不存在代币,你可以在它的基础上进行二次开发,利用Fabric的智能合约实现自己需要的各种业务--包括发放代币。在它的智能合约模块中有两个最关键的接口中:shim.PutState(Key, Value) 和 shim.GetState(Key),这个是用来向节点本地读写数据的指令,它呈现给智能合约的是一个key-value结构的非关系形数据库。然后Client通过调用智能合约执行业务逻辑,智能合约来进行数据的读写操作的(在区块链的世界中调用智能合约的Request统称为Transaction,这是约定俗称的,虽然在Fabric中没有代币),这和传统的中心化Web服务十分相似,只不过Tomcat换成了Fabric,而后台的jar包换成了智能合约,中心化的APP变成了分布式的DAPP。

  现在参照作者从Bitcoin中总结的规律,在Fabric智能合约中读写的业务数据符合重要的、频繁访问的特征,应该独立存储,这个数据库的名称为StateDB 。除了StateDB以外我们还要保存区块数据,在Fabric里面它有一个自己的FileSystem,用来存储区块数据,这个文件系统是存储在本地的文件中的。区块数据被连续的写入到本地的BlockFile中,通过File.io来读写数据,Fabric工程是用go语言编写的,工程中操作文件IO的包是os ,包中常用操作文件的函数如下:    

type File

    func Create(name string) (*File, error)
    func NewFile(fd uintptr, name string) *File
    func Open(name string) (*File, error)
    func OpenFile(name string, flag int, perm FileMode) (*File, error)
    func Pipe() (r *File, w *File, err error)
    func (f *File) Chdir() error
    func (f *File) Chmod(mode FileMode) error
    func (f *File) Chown(uid, gid int) error
    func (f *File) Close() error
    func (f *File) Fd() uintptr
    func (f *File) Name() string
    func (f *File) Read(b []byte) (n int, err error)
    func (f *File) ReadAt(b []byte, off int64) (n int, err error)
    func (f *File) Readdir(n int) ([]FileInfo, error)
    func (f *File) Readdirnames(n int) (names []string, err error)
    func (f *File) Seek(offset int64, whence int) (ret int64, err error)
    func (f *File) SetDeadline(t time.Time) error
    func (f *File) SetReadDeadline(t time.Time) error
    func (f *File) SetWriteDeadline(t time.Time) error
    func (f *File) Stat() (FileInfo, error)
    func (f *File) Sync() error
    func (f *File) Truncate(size int64) error
    func (f *File) Write(b []byte) (n int, err error)
    func (f *File) WriteAt(b []byte, off int64) (n int, err error)
    func (f *File) WriteString(s string) (n int, err error)

type FileInfo

    func Lstat(name string) (FileInfo, error)
    func Stat(name string) (FileInfo, error)

type FileMode

    func (m FileMode) IsDir() bool
    func (m FileMode) IsRegular() bool
    func (m FileMode) Perm() FileMode
    func (m FileMode) String() string

 

Q1:以上所有的接口都不支持复杂的查询功能,读者们可以想象一下,当要去BlockFile中读取一个块的时候要什么样的条件才能快速的找到对应块?

A1: 如果查询者能知道一个Block数据在文件中的便宜量则可以快速定位到Block,相反则只能通过遍历的方式。为了解决这个问题Fabric 将Block在BlockFile文件中的偏移量记载到了一个非关系形DB中,这个DB的名称为indexDB

Q2:区块数据是不可篡改的,也就是说BlockFile的size是持续增长的,如果size过大超过了位置偏移量的最大范围怎么办?

A2: 将区块数据存储在多个文件块中,以blockfile_ 为前缀,以块的生成次序为后缀。

  解决了上面的两个问题后,查询一个块数据的过程如下:

  setup1: 从indexDB中读取Block的位置信息(blockfile的编号、位置偏移量);

  setup2: 打开对应的blockfile,位移到指定位置,读取Block数据。

  Fabric账本的整体结构图来如下图所示:

  其中ledgersData是整个账本的根目录,作者会逐个文件夹进行解析:

  (1)chains:chains/chains下包含的mychannel是对应的channel的名称,因为Fabric是有多channel的机制,而channel之间的账本是隔离的,每个channel都有自己的账本空间。chains/index下面包含的是levelDB数据库文件,在Fabric中默认所有的数据库都是LevelDB,这个原因作者下面会讲到,DB中存储的就是我们上面说的区块索引部分。chains/chains和chains/index就是上面所说的File System和indexDB;

  (2)stateLeveldb: 同样是levelDB数据库,存储的就是我们上面所说的智能合约putstate写入的数据;

  (3)ledgerProvider:数据库内存储的是当前节点所包含channel的信息(已经创建的channel id 和正在创建中的channel id),主要是为了Fabric的多channel机制服务的;

    (4)historyLeveldb:数据库内存储的是智能合约中写入的key的历史记录的索引地址。

Hyperledger Fabric账本详解

  这一部分作者会结合几个问题对Hyperledger Fabric 区块链账本的内在原理进行深入的剖析,其中会涉及到源码部分的解析,如果读者只是想对账本机制做一些简单了解,可以跳过源码分析的部分。

  Q3:  智能合约读写数据到stateLeveldb的流程?

  A3:作者以GetState()接口为例进行说明:

  首先,读者们需要明确Hyperledger Fabric的智能合约是在docker容器中运行的,而stateLeveldb是位于节点服务器本地的。同时,Fabric没有将stateLevelDB映射到docker容器中,所以智能合约不能直接访问stateLevelDB。

  Fabric中是通过rpc服务调用的方式,来解决这个问题的。开发过Fabric智能合约的读者应该清楚,Fabric提供了一个中间层Shim包,同时在Peer节点中默认会开启一个grpc服务 ChainCodeService。智能合约文件在编译的时候会自动引入shim包,而shim包中在GetState的过程中会向节点的ChainCodeService发送请求到节点,然后节点再从本地的stateLevelDB中读取请求的数据,返回给智能合约。

  流程图:

  以上只是读数据的过程,写数据远比读数据更为复杂。

  //TODO 写数据过程

  Q4:fabric支持交易的查询接口,那么交易查询是如何实现的?

  A4: 交易查询与Block查询的实现原理一致,节点在写入账本到本地的时候,会将交易在FileSystem中的索引也写入indexDB中。

  Q5: indexDB是levelDB,它是如何实现复杂查询的,比如交易的范围查询?

  未完待续... ...


推荐阅读
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • WebSocket与Socket.io的理解
    WebSocketprotocol是HTML5一种新的协议。它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 本文介绍了如何清除Eclipse中SVN用户的设置。首先需要查看使用的SVN接口,然后根据接口类型找到相应的目录并删除相关文件。最后使用SVN更新或提交来应用更改。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • Windows7 64位系统安装PLSQL Developer的步骤和注意事项
    本文介绍了在Windows7 64位系统上安装PLSQL Developer的步骤和注意事项。首先下载并安装PLSQL Developer,注意不要安装在默认目录下。然后下载Windows 32位的oracle instant client,并解压到指定路径。最后,按照自己的喜好对解压后的文件进行命名和压缩。 ... [详细]
  • 解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法
    本文介绍了解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法,包括检查location配置是否正确、pass_proxy是否需要加“/”等。同时,还介绍了修改nginx的error.log日志级别为debug,以便查看详细日志信息。 ... [详细]
  • 本文介绍了一个适用于PHP应用快速接入TRX和TRC20数字资产的开发包,该开发包支持使用自有Tron区块链节点的应用场景,也支持基于Tron官方公共API服务的轻量级部署场景。提供的功能包括生成地址、验证地址、查询余额、交易转账、查询最新区块和查询交易信息等。详细信息可参考tron-php的Github地址:https://github.com/Fenguoz/tron-php。 ... [详细]
author-avatar
QX封面精选
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有