13-1 SDK应用集成
13-1-1 蚂蚁链应用集成概述
蚂蚁区块链介绍
蚂蚁区块链通过引入P2P网络、共识算法、虚拟机、智能合约、密码学、数据存储等技术特性,构建一个稳定、高效、安全的图灵完备智能合约执行环境,提供账户的基本操作以及面向智能合约的功能调用。基于蚂蚁区块链提供的能力和功能特性,应用开发者能够完成账户创建、合约调用、结果查询、事件监听等。
蚂蚁区块链应用开发流程
在使用蚂蚁链进行区块链应用开发过程中需要开发智能合约和应用两部分内容,系统描述区块链应用开发的基本业务流
区块链应用架构模式
应用开发场景主要有以下3种方式,可以根据具体应用场景进行选择
- 前端(浏览器、移动端App或命令行工具)使用直连方式直接链接区块链节点。该方式去掉了中间的后端服务,更加透明,比较适合轻量级的合约调用、查询等操作。
- 前端(浏览器、移动端App或命令行工具)访问中间件服务(蚂蚁链交易网关Rest、Infura、Alchemy),通过中间件服务间接访问区块链节点
- 与传统web应用开发相似,访问后端服务(Service),后端服务集成SDK(Java/JS/C++)和蚂蚁区块链节点交互。该方式适合与传统的业务系统结合,在后端服务层实现一些比较重要的业务逻辑和计算任务
蚂蚁区块链应用开发核心
链上智能合约开发和链下应用开发
蚂蚁区块链应用开发 | 智能合约 | 合约类型 | Solidity合约 |
wasm合约 | |||
开发工具 | Cloud IDE | ||
Chain Stack | |||
链下应用集成 | SDK集成 | Java集成 | |
C++集成 | |||
JavaScript集成 | |||
Rest API集成 |
蚂蚁区块链SDK核心逻辑
SDK客户端使用TLS双向认证,确保接入安全
比特币、以太坊吧共识和交易执行混合在一起。蚂蚁链先执行共识,节点共识是基于列表和顺序,共识后各节点再执行交易。
蚂蚁链应用的开发SDK类型
为适应不同的开发环境,蚂蚁链提供三种语言SDK支持
SDK类型 | 功能特性 | 说明 |
---|---|---|
Java | 功能最丰富,覆盖蚂蚁链的所有功能 | 适合应用于后端服务层 |
C++ | 功能丰富,与 Java SDK类似 | 比较适合与传统C++服务相结合 |
JavaScript | 覆盖基本的常用的API,支持Node.js和浏览器环境运行,不支持国密算法 | 适合客户端web应用集成 |
13-1-2 蚂蚁链SDK快速集成
蚂蚁区块链Java SDK介绍
蚂蚁区块链合约平台Java SDK是通过服务(Service)的形式对外提供功能,SDK提供以同步或异步方式发送交易、查询交易、订阅事件等接口
蚂蚁区块链Java SDK开发环境准备
Java SDK依赖JDK、Maven、Netty特定版本
JDK 7及以上版本:在终端运行 Java-version 查看当前Java版本
Maven 3.5.4及以上版本:在终端运行 mvn-v 查看当前Maven版本
SDK的jar包依赖Netty,不同的运行系统需要选择不同的Netty依赖包配置到Maven文件
Maven文件中引入SDK包
安装下载的jar包到项目目录
命令终端进入到项目目录,执行下图命令
准备SSL连接文件和账本私钥文件
与BaaS平台建立SSL连接,需准备三个证书文件:CA机构的根证书(trustCA)、客户端的证书文件(client.crt)和客户端的私钥文件(client.key)
提交交易还需要账户的私钥文件(user.key)
文件名称 | 文件说明 | 文件来源 |
---|---|---|
client.crt | 客户端的证书文件 | 通过前往BaaS控制台,创建证书后,返回对应下载地址。 |
client.key | 客户端的私钥文件 | 通过前往BaaS控制台,创建证书后,返回对应下载地址。 |
trustCA | 存储CA证书的trustStore | 通过前往BaaS控制台,创建证书后,返回对应下载地址。 |
user.key | 账户私钥文件 | 通过前往BaaS控制台,创建证书后,返回对应下载地址。需保存好文件,遗失无法恢复! |
蚂蚁区块链证书申请
以蚂蚁区块链合约体验链为例申请证书
- 产品与服务 > 区块链 > BaaS平台 进入BaaS平台,单击页面上方 区块链实验室,进入BaaS区块链实验室 引导页
- 创建客户端证书
- 下载SDK、根证书、客户端签名证书
蚂蚁区块链创建账户
以蚂蚁区块链合约体验链为例申请证书
- BaaS平台提供 自动生成密钥和证书 和 手动生成密钥和证书 两种方式创建账户。推荐使用安全、便捷的自动生成方式
- 选择自动生成密钥和证书的生成方式后,根据页面提示填写相关信息创建账户
- 下载私钥、公钥对及恢复私钥、公钥对。私钥只有一次下载机会,务必妥善保存
SDK应用集成编写
Idea开发环境创建蚂蚁链项目
- 创建Maven项目
- 导入客户端证书和账户密钥文件到resource目录
- Pom.xml添加蚂蚁链jar包依赖
配置接入环境,初始化SDK
- 配置客户端SSL密码、接入账户密码、合约链IP、端口
- 初始化蚂蚁链接入、STL双向认证授权
- 初始化SDK环境,日志出现Hand shake success表示区块链平台连接成功
通过SDK部署合约到蚂蚁区块链平台
- 准备合约字节码
- 部署合约到蚂蚁区块链
- result.getData().getTransactionReceipt().getResult()为0,代表交易执行成功,反之代表交易执行失败,可以通过result的值从MychainErrorCodeEnum中查找错误原因
部署合约、调用合约方法
- 查看合约ABI文件,了解合约函数调用参数信息
- 编写调用合约Issue方法的函数
- 编写调用合约Query方法的函数,查询某人积分
SDK应用执行流程
编译应用,执行应用,链上查询
- 初始化STL授权,SDK执行环境
- 部署合约
- 调用合约方法
- 关闭SDK
SDK应用底层密码学套件
合约链的链环境可能使用以下两种密码学套件
classic | 使用国际商用密码算法,包括SHA256摘要、ECC公钥算法、AES对称加密等,标准合约链默认为此套件配置。 |
---|---|
China-sm | 使用中国国家商用密码算法,包括SM3摘要、SM2公钥算法、SM4对称加密等,国密算法合约链默认为此套件配置。 |
SDK与合约平台之间的SSL通信不受密码学套件影响,由颁发证书的PKI机构决定
13-1-3 蚂蚁链SDK接口详解
账户接口
账户模型是Mychain中的重要概念,账户地址、余额、账户权重等信息都存储在账户模型中,使用账户接口可以同步或异步的方式创建、更新账户信息。
账户模型
参数 | 类型 | 说明 |
---|---|---|
id | Identity | 账户的业务ID |
balance | long | 余额 |
authMap | AuthMap | 账户或者合约的公钥和权重值 |
recoverKey | PublicKey | 恢复公钥,用于账户私钥丢失的情况 |
recoverTimestamp | long | 上次成功恢复的时间 |
status | ObjectStatus | 状态, 0:Normal(正常); 1:Freeze(冻结); 2:Recovering(恢复中) |
encryptionKey | String | 加密公钥,用来加密智能合约中的交易金额 |
同步创建账户createAccount
异步创建账户asyncCreateAccount
合约接口
使用合约接口可以同步、异步完成合约部署、升级、调用、冻结等操作
合约模型
参数 | 类型 | 说明 |
---|---|---|
id | Identity | 账户的业务ID |
balance | long | 余额 |
authMap | AuthMap | 账户或者合约的公钥和权重值 |
recoverKey | PublicKey | 恢复公钥,用于账户私钥丢失的情况 |
recoverTimestamp | long | 上次成功恢复的时间 |
status | ObjectStatus | 状态, 0:Normal(正常); 1:Freeze(冻结); 2:Recovering(恢复中) |
encryptionKey | String | 加密公钥,用来加密智能合约中的交易金额 |
storageRoot | Identity | 世界状态的默克尔哈希根 |
codeHash | Identity | 合约代码哈希 |
code | byte[] | 合约代码 |
合约部署
同步部署合约 deployContract
异步部署合约 asyncdeployContrac
DeployContractRequest 请求参数
参数 | 类型 | 说明 |
---|---|---|
accId | Identity | 部署合约的账户ID |
contractId | Identity | 合约ID |
code | byte[] | 合约代码 |
vmTypeEnum | vmTypeEnum | 虚拟机类型,默认使用evm虚拟机,后续支持其他虚拟机类型 |
parameters | parameters | 合约参数 |
value | BigInteger | 合约金额 |
DeployContractResponse 返回参数
参数 | 类型 | 说明 |
---|---|---|
transactionReceipt | transactionReceipt | 交易收据 |
blockNumber | BigInteger | 区块号 |
使用合约接口完成合约部署实践
合约调用
同步调用合约方法 callContract
异步调用合约方法 asyncCallContract
CallContractRequest 请求参数
参数 | 类型 | 说明 |
---|---|---|
accId | Identity | 部署合约的账户ID |
contractId | Identity | 合约ID |
vmTypeEnum | vmTypeEnum | 虚拟机类型,默认使用evm虚拟机,后续支持其他虚拟机类型 |
parameters | parameters | 合约参数 |
value | BigInteger | 合约金额 |
CallContractResponse 返回参数
参数 | 类型 | 说明 |
---|---|---|
transactionReceipt | transactionReceipt | 交易收据 |
blockNumber | BigInteger | 区块号 |
使用合约接口完成合约调用实践
同步调用合约方法
异步调用合约方法
合约升级
同步合约升级 updateContract
异步合约升级 asyncUpdateContract
UpdateContractRequest 请求参数
参数 | 类型 | 说明 |
---|---|---|
contractId | Identity | 合约ID |
vmTypeEnum | vmTypeEnum | 虚拟机类型,默认使用evm虚拟机,后续支持其他虚拟机类型 |
code | byte[] | 目标合约的字节码,采用16进制表示,无需“0x”作为前缀 |
合约升级时,传入的bytecode字节码为runtime字节码,如果使用二进制solc编译工具,可直接获取 --bin-runtime参数,即正常 --bin参数编译的字节码的子集。runtime字节码可通过本地执行合约部署操作来获取
UpdateContractResponse 返回参数
参数 | 类型 | 说明 |
---|---|---|
transactionReceipt | transactionReceipt | 交易收据 |
blockNumber | BigInteger | 区块号 |
使用合约接口完成合约升级实践
- 使用二进制solc编译工具,直接获取runtime字节码
- 同步合约升级
合约参数对象
EVM合约参数
EVMParameter
为合约部署、调用、升级传入的参数
函数名称 | 参数类型 | 参数说明 |
---|---|---|
setMethodSignature() | String | 添加函数选择器,即方法与参数列表构成的字符串 |
getEncodedData() | ||
addInt() | BigInteger | 添加静态的int类型的数据 |
addUInt() | BigInteger | 添加静态的uint类型的数据 |
addBool() | Boolean | 添加静态的bool类型的数据 |
addIdentity() | Identity | 添加静态的identity类型的数据 |
addString() | String | 添加动态的string类型的数据 |
addBytes() | Byte[] | 添加动态的byte类型的数据 |
addBytesN() | Byte[] | 添加静态的byte类型的数据 |
addIntArray() | List<BigInteger> | 添加动态的int数组类型的数据 |
addUIntArray() | List<BigInteger> | 添加动态的uint数组类型的数据 |
addBooleanArray() | List<Boolean> | 添加动态的bool数组类型的数据 |
getMethodSignature() | ||
addStruct() | struct | 添加struct类型参数,类似于Java集合中的List |
addArray() | DynamicArray | 添加动态数组 |
addIdentityArray() | List<byte[]> | 添加Identity的byte[]集合 |
addBytes32Array() | List<byte[]> | 添加32位的byte[]集合 |
addByte32() | byte[] | 添加32位的byte[],必须为32位 |
EVMOutput
解析交易收据的logData和output
函数名称 | 参数类型 | 参数说明 |
---|---|---|
getInt() | BigInteger | 获取静态的int类型的数据 |
getUInt() | BigInteger | 获取静态的uint类型的数据 |
getIdentity() | Identity | 获取identity类型的数据 |
getString() | String | 获取String类型的数据 |
getBytes() | byte[] | 获取bytes类型的数据 |
getBytesN() | byte[] | 获取bytes类型的数据 |
EVM合约编码
编码说明
EVM的参数和返回值编码规则一致,对于静态类型的变量,直接编码为32字节按顺序拼接。对应动态数据类型,则用一个32字节偏移量占住位置,所有动态数据类型的真实数据按顺序以LV的格式放在后面。其中L表示数据的实际长度,L占用32字节;V为实际数据。
编码
解析
EVM合约编码解析
其他合约接口
冻结合约
freezeContract
asyncfreezeContract
解冻合约
unFreezeContract
asyncUnFreezeContract
链上查询接口
区块头查询
区块头查询三种方式
区块头
参数 | 类型 | 说明 |
---|---|---|
hash | String | 区块头的哈希 |
version | long | 版本 |
number | BigInteger | 区块号 |
parentHash | String | 上一区块哈希 |
transactionRoot | String | 区块体中的交易构成默克尔哈希根 |
receiptRoot | String | 区块体中的收据构成默克尔哈希根 |
stateRoot | String | 世界状态默克尔哈希根 |
gasUsed | BigInteger | 交易执行的总消耗量 |
timestamp | long | 时间戳 |
logBloom | String | 日志布隆过滤器 |
数据结构
Block
参数 | 类型 | 说明 |
---|---|---|
blockHeader | BlockHeader | 区块头 |
blockBody | blockBody | 区块体 |
blockBody
参数 | 类型 | 说明 |
---|---|---|
transactionList | list | 交易列表 |
receiptList | list | 收据列表 |
consensusProof | byte[] | 共识证明 |
交易查询 queryTransaction
调用
Transaction包含一次交易所需要的完整的信息,但不同请求类型所需的参数可能会不一样
交易模型
参数 | 类型 | 说明 |
---|---|---|
hash | String | 交易的哈希,由signature字段以外的所有针对构成 |
type | transactionType | 交易的类型 |
timestamp | long | 交易的时间戳 |
nonce | Fixed64BitUnsignedInteger | 防止重放攻击 |
period | long | 单位为毫秒,事务开始或结束的时间,为未来扩展使用 |
from | String | 交易的发送者 |
to | String | 交易的接收者 |
value | Fixed64BitUnsignedInteger | 转账金额 |
gas | Fixed64BitUnsignedInteger | 交易执行的消耗费用 |
data | byte[] | 交易数据的编码 |
signatureList | List<byte[]> | 签名,使用一个或多个私钥对哈希加签 |
groupId | Fixed32BitArray | 交易在一个群中执行 |
extension | List | 目前用于智能合约中的证明数据 |
version | short | 版本 |
查询收据 queryTransactionReceipt
调用
只有查到一个交易的收据(Receipt)才能证明出块成功,交易被确认
收据模型
参数 | 类型 | 说明 |
---|---|---|
result | long | 交易结果 |
gasUsed | BigInteger | 交易执行的消耗费用 |
logs | List | 交易执行的日志集合 |
output | byte[] | 合约的输出 |
需通过查询交易回执获取对应output信息后解析获得合约返回值内容
通过合约event事件的参数,获取合约事件内容
事件接口
事件日志模型
参数 | 类型 | 说明 |
---|---|---|
from | String | 交易的发送者 |
to | String | 交易的接收者 |
topics | List | 订阅的主题,topic字段是通过16进制编码 |
logData | byte[] | 交易产生的日志 |
订阅账户
监控链上账户创建、冻结事件
订阅账户listenAccount
取消订阅账户unListenAccount
订阅合约
监控链上合约创建、冻结事件、查询
订阅合约 listenContract
取消订阅合约 unListenContract
订阅主题
监控链上主题Topic事件
订阅主题 listenTopics
取消订阅主题 unListenTopics
监控链上主题Topic事件实践
事件日志触发
链上Event
监听链上IssueEvent事件
编码
订阅区块
监控链上区块创建事件
订阅区块事件 listenBlock
取消订阅区块事件 unListenBlock
监听区块事件
链上Event
原生存证接口
为方便存证场景的开发,合约平台提供原生存证交易接口以实现存证目的
同步存证交易 depositData
异步存证交易 asyncDepositData
参数模型
DepositDataRequest
参数 | 类型 | 说明 |
---|---|---|
senderId | Identity | 发起交易者的identity |
receiverId | identity | 目标账户identity |
amount | BigInteger | 转账金额 |
depositData | byte[] | 待存储数据,可自定义数据内容,然后序列化存证,存证后读取数据再反序列化 |
DespiteDataResponse
参数 | 类型 | 说明 |
---|---|---|
transactionReceipt | TransactionReceipt | 交易收据 |
blockNumber | BigInteger | 区块号 |
同步存证
存证交易,同步方式调用
链上存证数据
异步存证
存证交易,异步方式调用
链上存证数据
其他接口
SDK还提供许多与平台监控和隐私保护等相关的接口
环境接口
init用于初始化环境配置
日志接口
支持SLF4j接口和JDK原生接口
监控指标接口
账户发生交易的统计指标
发送查询请求的统计指标
每秒事务处理量的统计指标
信封交易接口
将交易放入一个独立的组中执行从而起到隐私保护的目的。智能合约平台支持部署合约、调用合约、更新合约、查询合约的信封交易
13-2 ChainStack开发框架
13-2-1 ChainStack开发框架特点及功能
ChainStack特点
ChainStack是什么
ChainStack经过对蚂蚁链内部业务的最佳实践进行挖掘、实践分享、组件沉淀探讨,提炼总结,从框架与服务出发,打造服务于区块链应用的框架。
ChainStack特点
一套智能合约框架,提供具备快速研发、组件复用、联动集成设施的智能合约框架,使得基于ChainStack特点的智能合约具备全面的生产化要素
一套可复用的应用组件,提供一站式集成区块链、智能合约、中间件的DApp应用研发框架,以及配套多种解决方案的区块链应用原型,支持业务快速搭建DApp应用。
一套完整的DApp应用工具链,涵盖开发环境自动配置、应用/合约代码自动生成、IDE适配等,覆盖DApp应用的整个生命周期
ChainStack功能
完整的DApp应用工具链
ChainStack合约框架
概览
- 基于ChainStack框架的合约开发流程
- 基于ChainStack框架的DApp应用开发流程
从以上两张图我们可以了解到,ChainStack框架的核心其实在于CDL合约画像,根据DCL画像中的约定,ChainStack工具可以自动生成合约代码脚手架、合约集成包,甚至是一个完整的后台服务。
- 使用ChainStack开发智能合约的优点
复杂对象作为出入参时,免去json编解码的逻辑,直接使用框架生成的数值对象
免去做设计,直接使用框架的开发规范
免去打日志埋点,使用框架的日志对象
免去Java侧调用合约时,编写冗余的调用对象
CDL文件简介
什么是CDL?
全称为合约定义语言,Contract Definition Language
- 合约接口画像
- 开箱即用的合约组件
- 链下链上联动
CDL有以下主要特性
极简合约接口定义
支持日志定义
支持自定义结构扩展
CDL文件详解
编写YAML版文件
- 合约基础信息
必须 | 含义 | 举例 | |
---|---|---|---|
合约名称 | 是 | 每个合约都需要定义一个合约名称,CDL后续会使用该名称生成合约工程及BAL工程,合约名称必须为大驼峰格式。 | contract_name: MyFirstContract |
合约类型 | 是 | 合约的类型,此选项会影响后续生成合约工程及BAL工程 | contract_type: MYCHAIN_CPPWASM |
合约接口编解码方式 | 是 | 合约接口入参编解码规则定义,当入参为复杂结构体时,将使用声明的编码规则进行通信。目前暂仅支持JSON | codec:JSON |
引入其他CDL定义 | 否 | 当业务合约比较复杂时,通常会定义大量的结构体、接口及合约事件,因此CDL提供了导入其他CDL文件的能力,可以将大型CDL文件拆分,方便管理。 | imports: -‘cdl1.yaml’ |
结构体 | 否 | CDL支持这个业务中常用的特性。结构体将通过codec定义的接口通信协议传送至合约,并在合约处自动反序列化为原始结构体 | types: Struct1: -field1:string -field2:uint8 |
- 接口定义
CDL支持合约接口的定义
接口名称必须为大驼峰,接口入参字段及返回值字段必须为小驼峰
如果需要生成入参/返回值为void的函数,params/returns字段留空即可
示例
interfaces:
CreateAccount:
params:
-userName:string
returns:
-isSuccess:bool
- 合约事件
合约事件为合约在执行过程中打印的Log事件
这些Log事件会被持久化在交易回执中的Logs字段中
示例
logs:
TransferLog:
log_data:
-requestId:string
-sender:string
-amount:uint32