本篇文章适合对区块链应用感兴趣或是想要通过函数计算服务进一步开发区块链应用的新人。本文将结合阿里云区块链服务、阿里云函数计算服务、阿里云日志服务 以及社区应用 Marbles,手把手教大家如何将阿里云区块链服务与阿里云函数计算服务相结合,并进一步提供业务上的结合场景,供大家开拓思路。
本文分为以下几部分:
- 函数计算与区块链
- Marbles 区块链应用介绍
- Marbles 区块链应用结合函数计算进行扩展示例
- 区块链应用与函数计算在业务上结合的场景与价值探讨
函数计算是事件驱动的全托管计算服务。使用函数计算,无需采购与管理服务器等基础设施,只需编写并上传代码。函数计算为用户准备好计算资源,弹性地可靠地运行任务,并提供日志查询、性能监控和报警等功能。借助函数计算,可以快速构建任何类型的应用和服务,并且只需为任务实际消耗的资源付费。
下图为函数计算工作流程:
区块链可以理解为去中心的分布式记账系统,其是一种 分布式、去中心化的计算与存储架构 。区块链通过某种方式来记录数据,使用户可以信任区块链系统记录的数据。区块链中的记账节点会按照一致性协议记账。记账节点愿意按照一致性协议记账,是因为在一致性协议的设计中,诚实的记账节点会得到相应的奖赏,且诚实的记录比恶意篡改记录的收益更大。
依托于区块链网络的可信度,衍生出了智能合约的概念。什么是智能合约呢?现实生活中,买家与卖家要进行一笔交易,为了保证交易的顺利进行,双方会签订一份合约,合约中会声明双方各自的身份、权利以及义务。当交易出现纠纷时,买家与卖家根据当时签订的合约通过法律的手段解决纠纷。这种方式的不足之处在于解决纠纷的过程需要第三方权威来仲裁以及需要大量时间。那么,假使我们现在有一位可信公正的交易代理人。卖家将商品交给代理人,买家与代理人双方之间一手交钱一手交货。若买家拒绝购买,代理人会将商品归还给买家。买家也不会付了钱拿不到商品。智能合约就可以充当这样的代理人,其为区块链上一个包含合约代码和存储空间的虚拟账户,合约的代码控制智能合约的行为,合约的账户存储合约的状态。
由于有了智能合约,DApp (Decentralized Application 即去中心化应用)也应运而生。DApp 是运行在区块链网络上的应用软件,其上运行的代码我们称之为智能合约。
Marbles 区块链应用介绍Marbles 区块链应用是一个 资产转移 应用演示。在 Marbles 区块链应用中多个用户可以创建并相互转移弹珠。 ( 即弹珠就是资产转移中的资产 )
上图中:
- Amy、Alice、Ava 所在的小长方形是她们每个人的账户
- 小长方形中的圆形弹珠是每个人账户中的资产,弹珠的颜色和大小是资产的属性
- 点击小长方形中的加号是为某个账户创建弹珠(资产)
- 将某个小长方形中的弹珠拖拽到右上方的垃圾桶中,是为某个账户删除弹珠(资产)
- 将某个弹珠从一个小长方形拖拽到到另一个小长方形,是弹珠(资产)的转移
- 每一步的操作会在下方的 BLOCKS 创建一个新的小正方形,这个小正方形就代表包含交易内容的区块
Marbles 区块链应用代码分成三部分:
- 链码 - 区块链网络中,对等节点所运行的代码。链码在此次介绍的 Marbles 应用中的主要作用是处理创建以及转移弹珠的逻辑。
- 客户端 - 浏览器中运行的代码,负责 Marbles 应用页面的渲染与交互。
- 服务端 - 服务器中运行的代码,充当 Marbles 应用与区块链网络之间的桥梁,其与客户端以及区块链网络中运行着链码的节点进行通信。
在 Marbles 应用中,当客户端发送消息给服务端,服务端与区块链网络通信的时序图大体上如下图所示:( 读者对详细过程感兴趣,可以阅读 Github IBM-Blockchain/marbles ) 其中,Peer 节点(对等节点) 存在于区块链网络中,拥有账本并且可安装链码。Orderer 节点负责接收包含签名的交易,对未打包的交易进行排序生成区块,广播给 Peer 节点。
上图中:Client 以及 Server 是上文中所说的客户端以及服务端。
- 当用户创建或转移弹珠时,Client 客户端触发相应事件,并向 Server 服务端发起请求。
- Server 接收到事件信息后,首先会构建提案(也就是交易),提案是将事件信息进行封装,比如:此次交易的两方以及交易内容是什么。
- Server 将构建好的提案发送给区块链网络中的一个 Peer 节点,由 Peer 节点来对提案进行模拟,校验其合法性。为什么要这么做呢?因为链码的作用就是处理交易逻辑,而链码安装在 Peer 节点上,并没有安装在 Server 上。
- 如果 Peer 节点模拟提案成功,认为其合法,则会对提案进行背书,并向 Server 返回背书后的提案。背书可以理解为,当我们去购买东西并忘记带现金,付给对方一张 别人 给的支票。对方怀疑支票不可兑现的时候,我们在支票上签字并表明若这张 他人 给的支票不能兑换,则可以来找我们要现金。这个签字的动作就是背书,声明对事物或被认可人的支持。
- Server 将背书后的提案发送给 Orderer 节点。
- Orderer 节点对提案进行排序并打包进区块,将区块广播给区块链网络中的所有 Peer 节点。
假设说,现在有这么一个业务场景,需要在每次 Marbles 应用有事件发生时,要对事件进行相应处理,且这部分的处理代码会 经常迭代 。那么,在区块链应用更新需要较多时间的情况下,通过函数计算来处理是较为方便的。( 具体缘由在下一节将会继续探讨 )
接下来,笔者将带着大家模拟这个业务场景,扩展 Marbles Server 端代码。在每次事件发生时,将事件信息打包并通过函数计算的 HTTP 触发器,由函数计算来对事件信息做相应处理。
开通阿里云日志服务、函数计算服务、区块链服务
2. 在阿里云区块链服务中创建组织、创建联盟 3. 在阿里云区块链服务中创建通道- 点击相应组织
- 点击通道
- 点击添加通道,填写名称与组织,并创建
- 点击新创建的通道右侧的待审批链接,同意审批
参考 阿里云区块链服务开发指南注意事项:nodejs 版本为 v8
5. 下载并配置阿里云函数计算开发工具 fun- fun 是一个 Node.js 编写的命令行工具,通过 npm 进行安装:
$ npm install @alicloud/fun -g
- 通过在命令行输入
fun config
,根据提示依次配置Account ID
、Access Key Id
、Access Key Secret
以及Default Region Name
。可参考:服务地址 、 创建 AccessKey - 配置 template.yml
在项目根目录下创建一个 template.yml 文件:
ROSTemplateFormatVersion: '2015-09-01'
Transform: 'Aliyun::Serverless-2018-04-03'
Resources:
marblesFC: # 服务名称
Type: 'Aliyun::Serverless::Service'
Properties:
Description: 'fc test'
LogConfig: # 日志配置
Project: test-log-project # 日志 Project
Logstore: test-log-store # 日志 LogStore
processEvent: # 函数名
Type: 'Aliyun::Serverless::Function'
Properties:
Handler: httpTrigger.handler # 文件名.方法名
Runtime: nodejs8
CodeUri: './'
Timeout: 60
Events:
http-test: # 触发器名
Type: HTTP # 触发器类型
Properties:
AuthType: ANONYMOUS
Methods: ['GET', 'POST', 'PUT']
test-log-project: # LogProject 名称
Type: 'Aliyun::Serverless::Log'
Properties:
Description: 'just for test'
test-log-store: # LogStore 名称
Type: 'Aliyun::Serverless::Log::Logstore'
Properties:
TTL: 10
ShardCount: 1
上述文件做了如下事项:
- 在函数计算中创建了
marblesFC
服务 - 为
marblesFC
服务配置了test-log-project
日志 Project 以及test-log-store
日志 LogStore - 在
marblesFC
服务中创建了processEvent
函数,并为其设置入口函数为httpTrigger.js
文件中的handler
方法 - 为
processEvent
函数配置了 HTTP 触发器,触发器名为http-test
- 创建了
test-log-project
日志 Project 以及test-log-store
日志 LogStore
- 在项目根目录下创建 httpTrigger.js 文件
var getRawBody = require('raw-body')
module.exports.handler = function (request, response, context) {
// get request info
getRawBody(request, function (err, data) {
var params = {
path: request.path,
queries: request.queries,
headers: request.headers,
method: request.method,
body: data,
url: request.url,
clientIP: request.clientIP,
}
// you can deal with your own logic here
console.log(JSON.stringify(params.queries))
// set response
var respBody = new Buffer.from(JSON.stringify(params));
// var respBody = new Buffer( )
response.setStatusCode(200)
response.setHeader('content-type', 'application/json')
response.send(respBody)
})
};
- 在项目根目录下执行
fun deploy
进行部署 - 在阿里云函数计算控制台中,进入到
marblesFC
服务下的processEvent
函数,在代码执行页面记录下调用 HTTP 触发器的地址
- 打开 Marbles 源代码根目录文件夹下的
app.js
文件 - 添加
var https = require('https');
https模块 - 修改
setupWebSocket
函数
function setupWebSocket() {
console.log('------------------------------------------ Websocket Up ------------------------------------------');
wss = new ws.Server({ server: server }); // start the websocket now
wss.on('connection', function connection(ws) {
// -- Process all websocket messages -- //
ws.on('message', function incoming(message) {
console.log(' ');
console.log('-------------------------------- Incoming WS Msg --------------------------------');
logger.debug('[ws] received ws msg:', message);
var data = null;
try {
data = JSON.parse(message); // it better be json
} catch (e) {
logger.debug('[ws] message error', message, e.stack);
}
// --- [5] Process the ws message --- //
if (data && data.type == 'setup') { // its a setup request, enter the setup code
logger.debug('[ws] setup message', data);
startup_lib.setup_ws_steps(data); //
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?