Pinvon's Blog

所见, 所闻, 所思, 所想

十 应用程序开发

概述

区块链应用一般由部署在区块链网络中的智能合约和调用这些智能合约的应用程序组成.

智能合约可以操作账本中的状态, 这些状态往往记录着与业务相关的重要数据(如资产的属性). 应用程序通过向区块链网络发送交易来调用智能合约.

同一个区块链网络中可以部署多个智能合约, 应用程序通过名称, 版本号来指定具体调用哪个智能合约.

如果需要访问控制, 则应用程序还要从CA处获取证书, 得到访问区块链网络的许可.

智能合约开发

智能合约直接与账本打交道, 处于十分核心的位置. 智能合约本质上是为了对上层业务逻辑进行支持. Fabric支持了包括Go语言在内的多种高级语言, 并支持图灵完备的处理逻辑, 可以支持开发更复杂的上层应用.

在Fabric中, chaincode延伸自智能合约的概念. chaincode会创建一些状态并写入账本, 状态带有绑定到chaincode的命名空间, 仅限于创建它的chaincode使用, 不能被其他chaincode直接访问. 不过, 在合适的许可范围内, 一个chaincode可以调用另一个chaincode, 间接访问其状态. 有时, 还要访问状态的所有历史值, 这就对存放账本状态的数据库提出了更多的要求.

智能合约的编写, 版本管理, 安装, 实例化, 升级等, 都需要遵循规范.

应用程序开发

Fabric提供了SDK, 用来封装一系列与区块链网络打交道的基本方法, 包括发送交易, 监听网络事件, 查询区块和交易信息等, 能够提高对智能合约进行使用的效率.

如, SDK可以通过以下4个步骤, 完成一次完整的交易.

  • 从CA获取合法的用户证书
  • 构造合法的交易提案, 提交给背书结点进行背书
  • 收集到足够的背书支持后, 构造合法的交易请求, 发送给Orderer节点进行排序
  • 监听事件, 确保交易已经写入账本

chaincode

chaincode接口

每个chaincode都要实现 Init() 接口和 Invoke() 接口.

chaincode结构

一个chaincode的必要结构如下所示:

package main

//引入必要的包
import (
    "fmt"
    "github.com/hyperledger/fabric/core/chaincode/shim"
    pb "github.com/hyperledger/fabric/protos/peer"
)

// 声明一个结构体
type SimpleChaincode struct {}

// 为结构体添加Init()方法
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
    // 在该方法中实现chaincode初始化或升级时的处理逻辑
    // 编写时可灵活使用stub中的API
}

// 为结构体添加Invoke()方法
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
    // 在该方法中实现chaincode被调用或查询时的处理逻辑
}

// 主函数 需要调用shim.Start()方法
func main() {
    err := shim.Start(new (SimpleChaincode))
    if err != nil {
        fmt.Printf("Error starting Simple chaincode: %s", err)
    }
}

chaincode工作流程

用户通过SDK或CLI, 向Fabric的背书节点发出调用chaincode的交易提案, 节点对提案进行检查, 通过后创建模拟执行这一交易的环境.

然后, 节点和chaincode容器之间通过gRPC消息来交互, 模拟执行交易, 并给出背书结论.

客户端收到足够的背书节点的支持后, 便可以将这笔交易发送给排序节点进行排序, 并最终写入区块链.

chaincode的API

chaincode需要记录的数据称为状态, 以键值对的形式存储.

chaincode中方法的调用, 会更新交易提案的读写集合, 在提交验证阶段, 会再次执行, 跟账本状态进行比对.

shim.api: https://godoc.org/github.com/hyperledger/fabric/core/chaincode/shim

Comments

使用 Disqus 评论
comments powered by Disqus