什么是区块链?简单来说区块链就是一个分布式的记账本,或者分布式的数据库。
区块链的数据结构是一个链表,交易数据被存储到链表的区块中,区块链的第一个区块叫创世区块,除了创世块以外,每个区块还包含前一个区块的哈希指针,这个哈希指针的值是根据前一个区块的实际数据计算出来的。哈希指针指向前一个区块,后面的区块可以查找前面所有区块的信息。
账本的数据结构就是这样的一个链表,那么分布式的含义是什么呢?
区块链的众多参与者组成了一个松散自治的 P2P 网络,我们把区块链网络的参与者叫做节点,每个节点都拥有一个账本拷贝,所有账本的信息都是一致的,在区块链里没有中心节点。每当有新的交易进来,所有节点的账本都会更新,并且最终保持一致。更新的方式不是去修改某个区块的值,而是保存交易记录。比如在比特币系统中,它没有用户资产记录这样的概念,不像普通数据库那样用一条数据存储资产,比特币用户资产的值是通过把所有的交易记录串联聚合后得到的,账户里资产的来源可以一直向上追溯,直到创世块为止。区块链里的交易数据根据具体场景,可以是任何需要记录的信息。
智能合约
为了支持信息的持续更新,以及对账本进行管理(写入交易,进行查询等),区块链网络引入了智能合约来实现对账本的访问和控制。智能合约不仅仅可用于在区块链网络中打包信息,它们也可以被用于自动的执行由参与者定义的特定交易操作。
比如智能合约可以规定物流中的运输费用,根据物流的快慢收取不同的费用,根据货物的到达时间进行自动转账等。上传到区块链网络中的的智能合约会被打包到某一个区块中,因此智能合约一旦写入区块链,也是不可更改的。
共识机制
区块链网络中交易信息同步的过程,确保交易只有获得适当参与者批准后才更新,所有的参与者都会将同样的信息按照同样的顺序更新,这样的过程叫做共识。共识机制是区块链的核心之一。
区块链的第一个应用比特币,采用的是Proof of Work(工作量证明)的共识机制。简单介绍一下比特币的共识机制,算法的具体细节大家可以去查白皮书。节点收到一个交易后,会根据判断标准对该交易进行有效性校验,无效的交易会被废弃。通过有效性验证之后的交易将会被广播给其他节点。其他节点会做同样的独立校验,当有效的交易达到整个网络所有节点时,即全网达成了“该交易有效”的共识。每个节点都会收到很多有效但是还未被打包到区块中的交易,这些交易被组装成 Merkle Tree,Merkle Tree 的第一个交易比较特殊,叫做 coinbase,由节点自己创建,将挖矿奖励支付到矿工自己的地址。挖矿奖励包括新创建的比特币和打包进该区块所有交易的手续费总额。然后节点计算一个符合难度的哈希值,挖矿就是通过修改参数不断计算区块哈希值,直至达到难度要求,也就间接证明了该节点付出了对应的工作量,这就是工作量证明。笔者的另一篇文章300行ABAP代码实现一个最简单的区块链原型里用了一个 ABAP 方法CL_ABAP_MESSAGE_DIGEST=>CALCULATE_HASH_FOR_CHAR 来计算区块的哈希值。
当节点计算出一个符合难度的区块哈希时,即说明该矿工挖矿成功了,该节点将该区块组装到本地的区块链,同时也将此区块广播给其他节点。其他节点接收到该区块后会验证该区块是否有效,有可能有两个节点同时挖出了新的区块 B1 和 B2,它们的上一个区块都是同一个区块 P。有的节点可能会先收到 B1,有的会先收到 B2,这时区块链出现了暂时性的两个分叉。要打破这种局面,要看下一个区块是基于 B1 生成还是基于 B2 生成。如果基于 B1,B1 这条链就变成了最长链,其他包含 B2 的节点会重新选择最长链,而 B2 作为孤块被丢弃掉。
到目前为止,我们可以将区块链看做是一个共享的,去中心化的多备份系统,通过智能合约更新交易数据,同时借助共识的协作流程使网络中所有的节点保持一致。
这里的交易可以指代任何数据,例如:数字货币,合同,记录或者其它任何信息。
区块链的类型
- 公有链:网络中的节点可以任意接入,网络中数据读写权限不受限制,所有节点都参与共识过程。比特币,以太坊等数字货币都属于公有链。
- 私有链:网络中的节点被一个组织控制,由其独享该区块链的写入权限,私有链和其他的分布式存储没有太大区别。
- 联盟链:多个公司或组织通过授权接入,由某些节点参与共识过程。Hyperledger Fabric属于联盟链。
什么是 Hyperledger Fabric?
Hyperledger Fabric 是 Linux 基金会发起的 Hyperledger 项目之一。Hyperledger Fabric 专为在企业环境中使用而设计的开源的基于区块链的分布式账本。Hyperledger Fabric 可用于全球供应链管理、金融交易、资产记账、人力资源、保险、健康和数字音乐等领域。
Hyperledger Fabric 中的账本子系统(ledger)包括两个组件:世界观(world state)和事务日志(transaction log)。世界观记录了账本在特定时间点的现状,是一个键值数据库。交易日志记录产生世界状态当前值的所有交易,是世界观的更新历史。账本的世界观的底层数据库可以更换,可以选择使用 levelDB 或 couchDB。
Hyperledger Fabric 是第一个支持以通用语言编写智能合约的区块链平台,可以使用java,nodejs 和 go 语言来编写智能合约。Hyperledger Fabric 中的智能合约也叫链码(chain code)。
和其他公有区块链平台最大的不同,Hyperledger Fabric 是私有的并且需要授权才能接入,它拥有一个 MSP(Membership Service Provider) 模块专门提供成员管理服务。
CA(Certificate Authority) 负责权限管理,成员身份相关证书管理 (Enrollment CertificateAuthority) 和维护交易相关证书管理 (Transaction Certificate Authority) 等等。
Hyperledger Fabric 提供了建立 channel 的功能,这允许参与者为交易新建一个单独的账本。当网络中的一些参与者是竞争对手时,这个功能变得尤为重要。因为这些参与者并不希望所有的交易信息——比如提供给部分客户的特定价格信息——都对网络中所有参与者公开。只有在同一个 channel 中的参与者,才会拥有该 channel 中的账本,而其他不在此 channel 中的参与者则看不到这个账本。
Hyperledger Fabric 使用独立的排序节点(order)来提供共识服务,负责排序交易,提供全局确认的交易顺序。
应用程序通过 SDK 访问 Hyperledger Fabric。
最新版 Hyperledger Fabric 的设计中,根据功能将节点角色解耦开,让不同节点处理不同类型的工作负载。从业务逻辑上又将节点分为背书节点(Endorser)和提交节点(Committer)。
- Endorser peer:负责对来自客户端的交易进行合法性和权限检查(模拟交易),通 过检查则签名并返回结果给客户端。
- Committer peer:负责维护账本,将达成一致顺序的批量交易结果进行状态检查,生成区块,执行合法的交易,并写入账本,同一个物理节点可以同时担任 endorser 和committer 两个角色。
Hyperledger Fabric 交易流程:共识
共识流程主要分 Proposal,Packaging 和 Validation 三个阶段。
Proposal
应用提交一个交易 proposal,然后将其提交给所有的背书节点,后者接到后,将其作为输入执行链码生成相应的交易 proposal 响应。此时并不会更新 Ledger,而是对交易proposal 响应签名,并将其返回给应用。应用收到签名后的响应,共识流程的第一阶段就完成了。
Packaging
这个阶段是 order 节点对交易进行排序打包。Order 节点从各个应用接收交易 proposal响应,然后对这些交易进行排序,排序之后打包成区块。
Validation
共识流程的最后一个阶段,由 order 节点将区块分发给所有和它连接的节点,这些节点将确认区块中的交易都经过背书节点签名,然后将确认后的区块更新到 ledger 中。
整个流程称为共识,所有节点都已对交易内容和顺序达成一致,这一过程由 order 节点控制。 共识是一个多步骤的过程,只有在整个流程完成时才会更新账本 ,可能每个节点的更新时间稍有不同。
构建一个 Hyperledger Fabric 平台绝非易事,既需要硬件基础设施的投入,也需要全方位的开发和运营管理(DevOps)。除了平台本身,一套完整的解决方案,还包括设备接入,访问控制,服务监控等管理功能。
SAP Cloud Platform(下文简称 SCP )提供了开箱即用的 Hyperledger Fabric Service,为开发者提供了强大的服务支持:
- 直观友好的可视化监控与操作界面,帮助开发者按需申请区块链网络,创建管理节点、渠道,而无需考虑底层硬件资源。
- 简单易用的智能合约开发与测试环境,方便开发者对应用代码进行管理。
- 安全,隐私性方面的保障,并对相关资源进行了性能优化。
下面是具体的实战步骤,该步骤使用 go 语言开发一组微服务,这组微服务包含读和写两个API,能够将数据写入架设于 SAP 云平台上的超级账本服务。
简单地说,应用程序通过智能合约接口同超级账本进行读写操作。我们将开发一个 Hello World 的智能合约,部署到 SAP 云平台上。出于简单起见,我们没有开发应用,而是简单地在 SAP 云平台的 API 控制台上直接消费这个 Hello World 的智能合约,对云平台上的超级账本进行读和写。
打开超级账本项目 Fabric 的 github 仓库地址:
https://github.com/hyperledge...
发现 Fabric 项目是 Google 的编程语言 GoLang 开发的,因此咱们这个练习也使用 Go 语言来进行智能合约的开发。
- 从 Google 网站上将 Go 语言 1.11 版的二进制包下载到本地,解压到 /usr/local 目录下:
sudo tar -C /usr/local -xzf /home/vagrant/Downloads/go1.11.linux-amd64.tar.gz
将该目录配置到环境变量 PATH 中去:
- Fabric 项目已经将智能合约同超级账本的通信封装到一个名叫 shim 的接口中,我们只需要在我们编写的智能合约代码中直接调用该 shim 接口即可。
我们使用 import 将这个 shim 接口的依赖引入进来,在第14行定义一个结构体,包含 ID 和 Value 两个字段。这个结构体即是待写入超级账本的数据结构,ABAP 顾问可以将其视为 ABAP 数据字典里定义的结构体。
第46行定义的方法 Invoke 是这个最简单的智能合约的核心代码,cc *MessageStore 这个语法和 C 语言很像,定义了一个类型为 MessageStore 的指针变量 cc。这个指针变量同 C++ 的 this 指针和 ABAP 的 me 引用作用类似,在方法被调用时,指向了方法的调用者。
Invoke 后面括号里的 stub shim.ChaincodeStubInterface 定义了该方法的输入参数(形参)stub, 类型为 shim.ChaincodeStubInterface。
这个 Invoke 方法不会通过应用程序显式调用,而是通过超级账本程序回调:当方法被调用时,指针 cc 和输入参数 stub 已经自动被 Fabric 框架赋上了对应值。在 Invoke 方法运行的上下文里,通过输入参数 stub 判断出当前回调的场景是读还是写,然后进入对应的分支。分支内部调用我们自己开发的 write 和 read 方法同超级账本进行交互。
这种通过同一个回调函数内部的 switch case 来处理多个场景的做法,ABAP 和 Java 开发者应该都不陌生。比如下图是通过 InvocationHandler 实现 Java 动态代理的例子,其中 invoke 方法的逻辑结构和本文智能合约代码的结构非常相似。
关于 ABAP 和 Java 里各种静态代理和动态代理的写法,请参考我的博客:
Various Proxy Design Pattern implementation variants in Java, ABAP and JavaScript
- 将开发好的智能合约源文件构建成可执行文件。这一步确保在部署智能合约到 SAP 云平台之前,先在本地开发环境将所有潜在错误全部检测出并修复。
- 登录 SAP 云平台,在 Service Marketplace 里点击 Hyperledger Fabric 的超链接:
创建一个新的 Service 实例:
创建过程中需要填写 channel 的 ID 和密匙。
区块链分为公有链,私有链和联盟链,而超级账本属于联盟链。在联盟链里,有一个专门的称为 MSP(Membership Service Provider)的模块,提供成员管理服务,只有授权用户才能接入区块链网络。这里我事先在 SAP 云平台上创建了一个渠道并进行认证,因此此处直接输入一个合法的渠道 ID 和密匙。关于 SAP 云平台上超级账本渠道的创建和成员授权接入的步骤,请参考这篇 SAP 帮助文档。
Service 实例创建完毕后,点击 Create Service Key 按钮创建 key,目的是生成用于OAuth 认证的 clientId 和 clientSecret,方便接下来的 API 调用。
点击 Service 实例的 Referencing Apps 面板,点击按钮 Open Dashboard:
点击 Deploy Chaincode,选择本地构建好的 zip 包,进行上传并部署。这个按钮同 SAP 云平台 CloudFoundry 环境部署本地应用的逻辑相同。
部署成功后,点击 Test Chaincode 超链接进入 API 控制台。
该控制台集成了 Swagger 框架,在调用 post 请求进行超级账本的写操作和 get 请求进行读操作之前,先要点击 Authorize 按钮进行身份认证:
输入第四步创建 Service Key 后生成的 clientID 和 clientSecret 进行认证:
认证成功后,可以在 Swagger 的控制台里调用 post 和 get 请求了。
首先发送 post 请求,请求负载就是一个简单的 json 对象,id 为 i042416,value 为Hello World:
post 请求在 SAP 云平台上的超级账本执行成功,返回 200 响应码:
紧接着执行 get 请求,输入刚才写入的数据 id: i042416:
get 请求能够将之前通过 post 请求写入账本的数据成功读出来:
登录 SAP 云平台超级账本控制台,能看到之前通过 post 写入的数据已经加入到区块链尾部的区块了。点击区块可以查看数据明细:
在超级账本控制台的 API Calls 和 Logs 面板里也能看到每次超级账本读写的详细信息。
总结
SAP 云平台的超级账本服务,成功地帮助了希望使用这项区块链技术的企业避免了硬件基础设施的投入,同时屏蔽了大部分超级账本平台管理的底层细节。通过 SAP 云平台提供的控制台,即可实现对超级账本进行设备接入,访问控制,服务监控等管理功能。同时,通过 Go 语言编写的智能合约一旦部署到 SAP 云平台,生成的 Restful API 能够被其他编程语言方便地消费。调用这些 API 写入超级账本区块链中的数据将无法再被篡改。使用 SAP 云平台的超级账本服务,应用开发人员可以无需将过多精力花费在超级账本体系架构本身,从而能够专注于应用逻辑的编写上去。