蚂蚁区块链官方Demo解析(java版)及相关接口调用
前言
该文档内容为蚂蚁区块链上的相关技术以及未解决的问题,以BaaS提供的Demo为基础,进行相关API的调用与测试。
蚂蚁区块链文档:https://tech.antfin.com/docs/2/73763
BaaS平台:https://baas.cloud.alipay.com/(个人支付宝扫码即可)
该文档不在过多赘述蚂蚁区块链产品相关基本知识,个人可以通过上述蚂蚁区块链文档了解。
开发前请务必优先阅读文档=> 蚂蚁区块链BaaS平台 =>产品概述 =>基础术语。以便了解陌生名词解释。
蚂蚁区块链开发指南
- SDK开发指南
该文档提供JAVA SDK,JS SDK, C++ SDK 三种类型,其中JAVA SDK又分为V0.10.2.12与V0.10.2.4两个版本,该文档是基于JAVA SDK V0.10.2.12的版本进行测试与开发。 - JAVA SDK
蚂蚁区块链合约平台 Java SDK 是通过服务(Service)的形式对外提供功能,具体包括账户服务(Account Service)、合约服务(Contract Service)、事件服务(Event Service)、查询服务(Query Service)和本地服务(Local Service)。SDK 提供以同步或异步方式发送交易、查询交易、订阅事件等的接口。无论以同步或异步的方式发送交易,SDK 封装了发送交易后查询收据的逻辑,以便您查看交易的执行结果。
Java SDK 的 Jar 包依赖 Netty,不同的运行系统需要选择不同的 Netty 依赖包配置到 Maven 文件中。
请自行下载
JAVA SDK : mychainx-sdk-0.10.2.12.jar
Netty 依赖包 : netty-tcnative-openssl-static-2.0.17-Final-mychain-all.jar
2.1运行环境说明
JDK 7 及以上版本在终端运行 java -version 查看当前 Java 版本。
Maven 3.5.4 及以上版本在终端运行 mvn -v 查看当前 Maven 版本。
在 Linux 下使用 SDK,要求 GLIBC 版本高于 2.14。
该文档一切操作都基于win 7系统,不同的系统可以从文档选择不同版本的jar包下载
2.2在 Maven 文件中引入 SDK 包
安装下载的 Jar 包到项目目录。
从命令终端进入到项目目录,执行以下命令:
//安装 SDK 到本地仓库
mvn install:install-file -Dfile=mychainx-sdk-0.10.2.12.jar -DgroupId=com.alipay.mychainx -DartifactId=mychainx-sdk -Dversion=0.10.2.12 -Dpackaging=jar -DpomFile=pom.xml
//如需使用 K1,则需安装 Netty 依赖到本地仓库,注意请选择对应平台 netty-tcnative-openssl-static 版本,并修改相应的 classifier,macOS:osx-x86_64,Linux:linux-x86_64,Windows:windows-x86_64
mvn install:install-file -Dfile=netty-tcnative-openssl-static-2.0.17-Final-mychain-all.jar -DgroupId=io.netty -DartifactId=netty-tcnative-openssl-static -Dversion=2.0.17-Final-mychain-all -Dpackaging=jar
之后操作按照文档:https://tech.antfin.com/docs/2/144520 操作即可。
在准备文件中需要四个文件:
CA 机构的根证书(trustCa)
客户端的证书文件(client.crt)
客户端的私钥文件(client.key)
账户的私钥文件(user.key)
文件获取路径如下:
浏览器进入BaaS平台=>支付宝扫码进入。依据下图流程。




(请务必记录下SSL秘钥密码)
下载私钥与证书保存好。点击创建账户
记录账户信息
1:账户名 2:账户私钥保护密码 3:账户的恢复私钥保护密码
并下载 pub.txt user.key recover-pub.txt recover-user.key四个文件保存好。
到这里已经凑齐了 client.crt client.key user.key 三个文件,还有一个trust.Ca文件
重新进入BaaS平台会显示该界面,点击免费体验。


点击下载即可得到trustCa文件。
什么是TLS证书?
客户端和节点通过BaaS平台上的CA 中心获取 TLS 证书,客户端与节点、节点与节点间实行 TLS 双向认证,且通信流量经 TLS 加密,抵御中间人攻击。除了基本的证书验证外,节点与节点之间还增加了握手逻辑,通过在握手过程中添加验证对方节点私钥签名的方式来确保节点间通信的可靠。
这里不明白TLS与SSL的关系。文档中也没有详细介绍。
阿里云SSL证书(SSL Certificates)由阿里云联合中国及中国以外地域多家数字证书管理和颁发的权威机构,在阿里云平台上直接提供的服务器数字证书,并且给您提供额外的一键式HTTPS、证书扩展服务和证书托管等增值服务,帮助您以最小的成本将您的服务从HTTP转换成HTTPS,实现网站或移动应用的身份验证和数据加密传输。
通过文档中对SSL证书的介绍,我初步理解为SSL为TLS证书的一种。
完成SDK快速开始操作后,需要在idea中加载一下我们引入的jar包,运行DemoSample,你会发现报错。这里是开发文档中的漏洞。程序文件中缺少依赖。

在pom.xml中添加图中红色方框中的代码:
org.bouncycastle
bcpkix-jdk15on
1.60
之后下载jar包 bcpkix-jdk15on-1.60.jar 并在命令行转到项目文档路径中运行:
mvn install:install-file -Dfile=bcpkix-jdk15on-1.60.jar -DgroupId=org.bouncycastle -DartifactId=bcpkix-jdk15on -Dversion=1.60-Final-mychain -Dpackaging=jar -Dclassifier=windows-x86_64
(jar包可以看看能否在网上下载相应的版本,不行的话 留言 我给你发个云盘地址)
不同的操作系统需要修改最后的Dclassifier :macOS:osx-x86_64,Linux:linux-x86_64,Windows:windows-x86_64。之后在重新加载下jar包就可以正常运行。
3.Solidity智能合约
3.1智能合约是什么?
如果说区块链作为像公路一样的底层基础设施,那么搭载在区块链上的智能合约,就像是汽车,在将来的实际应用中,起到链接产业和基础设施的作用。就像当前社会的互联网和其上方的应用一样。
智能合约作用有两个: 1 进行链上存证 2推动相关业务流转。物权平台中的结果上链其实是链上存证。而各个审批流其实是智能合约的驱动业务流转。
关于智能合约的学习资料:https://www.bilibili.com/video/BV1Gs411g7Zc
该资料给你讲解了基本的solidity语法。并实现了一个简单的实例。看完该视频基本就可以看懂文档中的solidity案例。视频不需要看的很仔细,主要是理解语法结构,以及一些相关的函数。
另外蚂蚁区块链上的solidity与原生的solidity有些差别。
蚂蚁链平台 Solidity 合约语言 vs. 以太坊官方 Solidity 合约语言
(1)蚂蚁链平台中,solidity合约使用identity替代官方solidity的address关键字。identity表示的合约地址或账户地址,均为为32字节,而官方solidity中address表示的地址是20字节。
(2)蚂蚁链合约不支持 suicide,也不支持 selfdestruct。
蚂蚁链合约不支持在合约内创建合约,因此不要在合约内使用 new 来创建合约。
(3)在蚂蚁链平台上,如果尝试在合约内向一个不存在的地址转账,合约会异常终止,并返回错误码 10303;而在以太坊官方 Solidity 合约内向不存在的地址转账时,系统会自动以该地址创建账户。
(4)对于.balance (uint256)语句,如果 identity 代表的账户不存在,则在蚂蚁链平台中该语句会造成合约异常终止,并返回错误码 10300;而在以太坊官方 Solidity 合约中,该语句会返回 0,不会造成合约异常终止。
在蚂蚁链平台中,合约内的 block.number、block.timestamp 分别指最新已形成的区块(即本交易所在区块的上一个区块)的高度和时间戳(毫秒);而在官方 Solidity 合约中,这两个参数分别指的是本交易所在区块的高度和时间戳。
(5)蚂蚁链平台不提供 ripemd160 这个散列算法。
(6)蚂蚁链平台中,solidity合约内不支持 CHAINID 指令
(7)蚂蚁链平台中,如果solidity合约执行过程中异常终止,终止之前产生的Event Log依然会出现在交易回执中。
3.2 智能合约的开发工具
如果你看了上面那个视频,里面介绍的Remix是基于以太坊的合约开发工具。蚂蚁区块链上自己提供Cloud IDE平台开发智能合约。
Cloud IDE详解参考文档:https://tech.antfin.com/docs/2/101785
Cloud IDE具体用法参考文档:https://tech.antfin.com/docs/2/101800
4.
JAVA SDK ==> API接口
4.1API接口实现案例及代码详解
Demo参数详解:
1 :contractCode 智能合约代码
2:testContractId 智能合约名称
3:account 创建的账户名称(string类型)
4:userIdentity 创建的账户名称(byte类型)
5:userKeypair 账户的私钥,需要导入user.key文件读取获得
6:testAccount1 创建的另一个账户,用来给其tranfer()
7:keyPassword SSL密钥密码
8:userPassword 账户私钥保护密码。
9:host 节点
10:post 端口号 与节点一起在合约浏览器中查询
11:trustStorePassword trustCA的密码 默认为mychain
4.1.1环境接口
4.1.1.1 环境接口—准备文件及参数
Client.key :证书私钥,配合SSL密码进行操作。
Client.crt :证书文件。
Trust.ca :根证书,需要自行下载。
账户名称 Account,在Demo为String类型,需转化为byte[]类型被引用,转化后为Identity类型
Account => userIdentity <=> (Identity) = ByteUtils.hexStringToBytes(byte[])
账户私钥保护密码:userPassword
账户的恢复私钥保护密码:Demo中未用到。
4.1.1.2 环境初始化流程
初始化链的环境:initMychainEnv()
引入主账号userIdentity(需要通过account进行byte类型转换得到),通过userPassword 对user.key文件进行解密获取到userKeypair文件。然后创建env。
然后进行通过证书文件等与SSL平台建立连接并连接链上节点,然后通过userKeypair设置签名signer操作.
buildMychainEnv():创建链上环境
(1)inetSocketAddress: 表示链上节点,需要参数post host
(2)Ssloption:通过Client.key Client.crt Trust.ca 三个文件以及trustStorePassword,keyPassword与SSL平台进行连接。
(3)socketAddressArrayLis: 添加链上节点 参数为:inetSocketAddress
(4)signerOption 通过userKeypair设置签名signer操作
(5)通过Ssloption socketAddressArrayList signerOption 三个参数进行创建env。==>ClientEnv.build(socketAddressArrayList, sslOption, signerOption)
Demo中出现的TeeChain为隐私合约链,示例中没有用到,将其注释掉Demo正常运行。
这里简单用图表示下TeeChain的区别
具体的请参考文档:https://tech.antfin.com/docs/2/107468

蚂蚁区块链的 TEE(Trusted Execution Environment)硬件隐私合约链(以下简称“TEE 合约链”)充分利用硬件 TEE 技术,为金融级别企业用户提供高效、通用、安全的区块链隐私保护能力。同时,TEE 合约链的开发者无需具备深厚的密码学背景,便可将已有的智能合约无缝迁移至 TEE 合约链平台并通过隐私模型的定义来启用隐私保护功能。
区块链的隐私保护体现在对交易全生命周期的保护,需要保护交易本身、合约代码、全局状态数据以及交易回执。
在 TEE 合约链中,交易分为隐私交易和明文交易。明文交易即无需隐私保护的交易,其执行过程与现有蚂蚁区块链平台一致;隐私交易是利用密码学技术进行保护的交易,交易内容只有在 TEE 内才安全可见,其执行过程中产生的全局状态数据以及交易回执均采用密码学技术进行加密保护。
在 TEE 合约链中,合约分为隐私合约和明文合约。隐私合约的代码和相应的数据加密存储,仅在 TEE 内部解密执行,相应的回执和状态均加密存储于外部数据库。
4.1.2账户接口
4.1.2.1 账户接口详情
账户接口包括创建账户,转账,设置恢复公钥,预重置公钥,重置公钥,更新权重,冻结账户,解冻账户,更新加密密钥等接口。
目前已实现创建账户,转账。createAccount(),transferBalance()
对公钥,权重,秘钥等相关信息不是很了解,接口中代码注释过于简单,搞不清参数明细。
4.1.2.2 代码详情
用户创建结果:

转账结果:

失败原因:初步推测为新建账户中没有“钱”。
4.1.3合约接口
4.1.3.1 合约接口详请
合约接口包括部署合约,调用合约,升级合约,冻结合约,解冻合约,合约参数对象。
基本全部实现。
4.1.3.2 具体流程
首先调用deployContract(),如果合约需要初始化参数调用EVMParameter类,使用add添加相应类型的参数。之后发送部署合约请求DeployContractRequest,设置gas :request.setTxGas。之后接受响应TransactionReceiptResponse。判断一下合约是否部署成功。
调用合约:根据合约中的函数,通过调用EVMParameter类,添加需要的参数。发送请求,接受响应。具体参考 issue(),tranfer()等函数。
合约升级:参考updateContract()。
剩余两个请参考之前提供的自行实现。
4.1.3.3 代码详情
部署合约结果:


这次提示交易重复,可以选择注释掉deployContract()中的代码块 具体看注释。
成功提示出现。

升级合约:合约不支持直接修改,可以做合约升级,但是不能改变合约的数据模型定义,只能改变一些function 计算逻辑。

我在原有合约的基础上简单添加了Test()函数

合约升级成功。但是由于燃料问题,显示调用Test()函数失败。
验证:注释掉合约升级函数,再次调用Test(),看看没升级的合约会是什么反应。这里还牵扯一个已部署合约的二次调用问题(未解决)。

提示报错。
4.1.4查询接口
4.1.3.1 查询接口详请
查询区块头,查询区块,查询交易,查询收据,查询账户,查询合约,查询区块里面的交易回执。
基本全部实现。queryBlockHeader();
该接口过于简单,其他的请自行实现。
存在问题: 如何获得区块编号?
4.1.3.2 代码详情

4.1.5本地执行接口
该接口文档描述太简单,没搞清楚。
4.1.6信封交易接口
信封交易是指将交易放入一个独立的组中执行从而起到隐私保护的目的。智能合约平台支持部署合约、调用合约、更新合约、查询合约的信封交易。
主要是在参数解释上, 解释太少,不知道某些参数是干什么用的。
接口调用失败,主要是参数含义不理解,代码结构已搞懂。
代码实现参考depositEnvelope();
4.1.7 事件接口
订阅账户,订阅合约,订阅主题事件,订阅区块事件,取消订阅账户事件,取消订阅合约事件,取消订阅主题事件,取消订阅区块事件。
订阅账户,订阅主题事件,取消订阅账户事件,取消订阅主题事件已实现。
其余接口较为简单,自行实现。
4.1.7.1 代码详情

4.1.8 监控指标接口
账户发送交易的统计指标(已实现),发送查询请求的统计指标,每秒事务处理量的统计指标
该接口实现较为简单,其余请自行实现。
4.1.8.1 代码详情

以上为账户发送交易的统计指标接口调用结果,文档没有任何描述。
4.1.9 原生存证接口
为方便存证场景的开发,合约平台提供原生存证交易接口以实现存证目的。
具体参考depositData();
4.1.9.1 代码详情

4.1.10 日志接口
调通 不知如何查看。
`代码:
package com.example.demo;
import com.alipay.mychain.sdk.api.MychainClient;
import com.alipay.mychain.sdk.api.callback.IEventCallback;
import com.alipay.mychain.sdk.api.env.ClientEnv;
import com.alipay.mychain.sdk.api.env.ISslOption;
import com.alipay.mychain.sdk.api.env.SignerOption;
import com.alipay.mychain.sdk.api.env.SslBytesOption;
import com.alipay.mychain.sdk.api.logging.AbstractLoggerFactory;
import com.alipay.mychain.sdk.api.logging.ILogger;
import com.alipay.mychain.sdk.api.utils.ConfidentialUtil;
import com.alipay.mychain.sdk.api.utils.Utils;
import com.alipay.mychain.sdk.common.VMTypeEnum;
import com.alipay.mychain.sdk.crypto.MyCrypto;
import com.alipay.mychain.sdk.crypto.PublicKey;
import com.alipay.mychain.sdk.crypto.hash.Hash;
import com.alipay.mychain.sdk.crypto.hash.HashFactory;
import com.alipay.mychain.sdk.crypto.hash.IHash;
import com.alipay.mychain.sdk.crypto.keyoperator.Pkcs8KeyOperator;
import com.alipay.mychain.sdk.crypto.keypair.Keypair;
import com.alipay.mychain.sdk.crypto.signer.SignerBase;
import com.alipay.mychain.sdk.domain.account.Account;
import com.alipay.mychain.sdk.domain.account.AccountStatus;
import com.alipay.mychain.sdk.domain.account.AuthMap;
import com.alipay.mychain.sdk.domain.account.Identity;
import com.alipay.mychain.sdk.domain.event.EventModelType;
import com.alipay.mychain.sdk.errorcode.ErrorCode;
import com.alipay.mychain.sdk.message.Message;
import com.alipay.mychain.sdk.message.event.PushAccountEvent;
import com.alipay.mychain.sdk.message.event.PushTopicsEvent;
import com.alipay.mychain.sdk.message.query.QueryAccountResponse;
import com.alipay.mychain.sdk.message.query.QueryBlockHeaderResponse;
import com.alipay.mychain.sdk.message.query.QueryTransactionReceiptResponse;
import com.alipay.mychain.sdk.message.query.QueryTransactionResponse;
import com.alipay.mychain.sdk.message.status.QueryNodeMetricsStatusResponse;
import com.alipay.mychain.sdk.message.transaction.AbstractTransactionRequest;
import com.alipay.mychain.sdk.message.transaction.TransactionReceiptResponse;
import com.alipay.mychain.sdk.message.transaction.account.;
import com.alipay.mychain.sdk.message.transaction.confidential.ConfidentialRequest;
import com.alipay.mychain.sdk.message.transaction.contract.;
import com.alipay.mychain.sdk.message.transaction.envelope.*;
import com.alipay.mychain.sdk.type.BaseFixedSizeByteArray;
import com.alipay.mychain.sdk.type.BaseFixedSizeUnsignedInteger;
import com.alipay.mychain.sdk.utils.ByteUtils;
import com.alipay.mychain.sdk.utils.IOUtil;
import com.alipay.mychain.sdk.utils.RandomUtil;
import com.alipay.mychain.sdk.vm.EVMOutput;
import com.alipay.mychain.sdk.vm.EVMParameter;
import com.sun.org.apache.xpath.internal.objects.XString;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
public class DemoSample {
private static String contractCodeString = "6080604052633b9aca00600055600060015534801561001d57600080fd5b5033600281905550610492806100346000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063af7c102c1461005c578063b2628df81461009d578063d4486019146100ec575b600080fd5b34801561006857600080fd5b506100876004803603810190808035906020019092919050505061013b565b6040518082815260200191505060405180910390f35b3480156100a957600080fd5b506100d26004803603810190808035906020019092919080359060200190929190505050610158565b604051808215151515815260200191505060405180910390f35b3480156100f857600080fd5b5061012160048036038101908080359060200190929190803590602001909291905050506102d8565b604051808215151515815260200191505060405180910390f35b600060036000838152602001908152602001600020549050919050565b6000600254331415156101d3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260118152602001807f5065726d697373696f6e2064656e69656400000000000000000000000000000081525060200191505060405180910390fd5b6000548260015401131580156101ee57506001548260015401135b80156101fa5750600082135b151561026e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f496e76616c69642076616c75652100000000000000000000000000000000000081525060200191505060405180910390fd5b816003600085815260200190815260200160002060008282540192505081905550816001600082825401925050819055508183337f31a52246bf8c995cecfdd5404cf290ae6c2f4e174e888e4de4fd208137ec274d60405160405180910390a46001905092915050565b600081600360003381526020019081526020016000205412151515610365576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f62616c616e6365206e6f7420656e6f756768210000000000000000000000000081525060200191505060405180910390fd5b60008213801561037757506000548213155b15156103eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600e8152602001807f496e76616c69642076616c75652100000000000000000000000000000000000081525060200191505060405180910390fd5b8160036000338152602001908152602001600020600082825403925050819055508160036000858152602001908152602001600020600082825401925050819055508183337f97c0c2106db19ca3c64afdc86820cd157d60361f777bf0e5323254d6c968955060405160405180910390a460009050929150505600a165627a7a72305820371af9e83b0e49ca71634c470c75e504d08db9abbaf3992f30434f8d7a7994d40029";
/**
* 获取合约字节码(字符串类型)
*/
private static byte[] contractCode = ByteUtils.hexStringToBytes(contractCodeString);
/**
* 字符串转byte数组==>bytecode
*/
private static String testContractId = "CreditManager"+System.currentTimeMillis();
//+ System.currentTimeMillis()
/**
* solidity contract 合约名称 + 当前时间??
*/
private static Account testAccount3;
private static Account testAccount2;
private static final String account = "自己申请的账户名称"; //调用合约的client
private static Identity userIdentity;// client
private static Keypair userKeypair;// client私钥
/**
* baas上创建的clientname + client(Identity)类型 + client私钥
*/
private static Identity testAccount1 = Utils.getIdentityByName("test_account_"+System.currentTimeMillis());
//+System.currentTimeMillis()
/**
* 创建一个合约测试账户。
*/
private static MychainClient sdk;
/**
* sdk client
*/
private static String keyPassword = "自行填充";
/**
* 申请证书时候指定的SSL密码
*/
private static String userPassword = "自行填充";
/**
* 申请证书时,创建账户的密码
*/
private static String host = "47.103.163.48";
/**
* Bass测试链 中在"区块浏览器"中查看"节点详情"可获取链节点的 IP地址 和 端口号
*/
private static int port = 18130;
/**
* s端口号 根据实际情况更新
*/
private static String trustStorePassword = "mychain";
/**
* trustCa password. 可能是测试链初始化确定的。
*/
private static ClientEnv env;
/**
* mychain environment
*/
private static void exit(String tag, String msg) {
exit(String.format("%s error : %s ", tag, msg));
}//退出函数
private static void exit(String msg) {
System.out.println(msg);
System.exit(0);
}//退出函数
private static String getErrorMsg(int errorCode) {
int minMychainSdkErrorCode = ErrorCode.SDK_INTERNAL_ERROR.getErrorCode();
if (errorCode < minMychainSdkErrorCode) {
return ErrorCode.valueOf(errorCode).getErrorDesc();
} else {
return ErrorCode.valueOf(errorCode).getErrorDesc();
}
}
private static void initMychainEnv() throws IOException {
String userPrivateKeyFile = "user.key";
userIdentity = Utils.getIdentityByName(account);
//account==BaaS申请证书时创建的账户名,user.key是下载的私钥
//account=>userIdentity <==> string->Identity类型转变。
Pkcs8KeyOperator pkcs8KeyOperator = new Pkcs8KeyOperator();
userKeypair = pkcs8KeyOperator.load(IOUtil.inputStreamToByte(
DemoSample.class.getClassLoader().getResourceAsStream(userPrivateKeyFile)), userPassword);
//通过账户私钥保护密码 加载并读取私钥文件。
env = buildMychainEnv();
//
ILogger logger = AbstractLoggerFactory.getInstance(DemoSample.class);
env.setLogger(logger);
//日志加载。
}
private static ClientEnv buildMychainEnv() throws IOException {
InetSocketAddress inetSocketAddress = InetSocketAddress.createUnresolved(host, port);
//获取测试链上节点地址IP
String keyFilePath = "client.key";
String certFilePath = "client.crt";
String trustStoreFilePath = "trustCa";
// build ssl option
ISslOption sslOption = new SslBytesOption.Builder()
.keyBytes(IOUtil.inputStreamToByte(DemoSample.class.getClassLoader().getResourceAsStream(keyFilePath)))
.certBytes(IOUtil.inputStreamToByte(DemoSample.class.getClassLoader().getResourceAsStream(certFilePath)))
.keyPassword(keyPassword)
.trustStorePassword(trustStorePassword)
.trustStoreBytes(
IOUtil.inputStreamToByte(DemoSample.class.getClassLoader().getResourceAsStream(trustStoreFilePath)))
.build();
//加载相应的文件 建立SSL连接。
List<InetSocketAddress> socketAddressArrayList = new ArrayList<InetSocketAddress>();
socketAddressArrayList.add(inetSocketAddress);
//创建测试链节点数组,可以添加多个节点地址。测试链上提供了四个。
List<SignerBase> signerBaseList = new ArrayList<SignerBase>();
SignerBase signerBase = MyCrypto.getInstance().createSigner(userKeypair);
signerBaseList.add(signerBase);
SignerOption signerOption = new SignerOption();
signerOption.setSigners(signerBaseList);
//相关的签名操作。
return ClientEnv.build(socketAddressArrayList, sslOption, signerOption);
}
private static void signRequest(AbstractTransactionRequest request) {
// sign request
long ts = sdk.getNetwork().getSystemTimestamp();
request.setTxTimeNonce(ts, BaseFixedSizeUnsignedInteger.Fixed64BitUnsignedInteger
.valueOf(RandomUtil.randomize(ts + request.getTransaction().hashCode())), true);
request.complete();
sdk.getConfidentialService().signRequest(env.getSignerOption().getSigners(), request);
}
private static void deployContract() {
EVMParameter contractParameters = new EVMParameter();
//创建合约参数,如果需要初始化参数需要调用add+相应类型的方法,具体参考Demo中其他合约函数调用方法
DeployContractRequest request = new DeployContractRequest(userIdentity,
Utils.getIdentityByName(testContractId), contractCode, VMTypeEnum.EVM,
contractParameters, BigInteger.ZERO);
//提供参数发起合约部署请求。
// DeployContractResponse response = sdk.getContractService().deployContract(request);
// //返回合约部署响应
// System.out.println("交易收据: " + response.getTransactionReceipt());
// System.out.println("区块号: " + response.getBlockNumber());
//以上注释三行代码会输出交易详细信息。
request.setTxGas(50000);
//设置燃料消耗上线,具体数值可以依据Cloud IDE进行估值参考。具体实现参考文档。
TransactionReceiptResponse deployContractResult;
//TransactionReceiptResponse 是 DeployContractResponse的父类。
deployContractResult = sdk.getContractService().deployContract(request);
if (!deployContractResult.isSuccess()
|| deployContractResult.getTransactionReceipt().getResult() != 0) {
exit("deployContract",
getErrorMsg((int)deployContractResult.getTransactionReceipt().getResult()));
} else {
System.out.println("deploy contract success.");
}
//判断合约部署是否成功
}
private static void issue() {
EVMParameter parameters = new EVMParameter("Issue(identity,int256)");
parameters.addIdentity(userIdentity);
parameters.addUint(BigInteger.valueOf(100));
// build CallContractRequest
CallContractRequest request = new CallContractRequest(userIdentity,
Utils.getIdentityByName(testContractId), parameters, BigInteger.ZERO, VMTypeEnum.EVM);
// set Gas limit
// Make sure your account balance is greater than 50,000
request.setTxGas(50000);
TransactionReceiptResponse callContractResult;
// if (isTeeChain) {
// signRequest(request);
//
// // generate transaction key
// byte[] transactionKey = ConfidentialUtil.keyGenerate(secretKey,
// request.getTransaction().getHash().getValue());
//
// ConfidentialRequest confidentialRequest = new ConfidentialRequest(request, publicKeys, transactionKey);
//
// callContractResult = sdk.getConfidentialService().confidentialRequest(confidentialRequest);
// } else {
callContractResult = sdk.getContractService().callContract(request);
// }
if (!callContractResult.isSuccess() || callContractResult.getTransactionReceipt().getResult() != 0) {
exit("issue", getErrorMsg((int)callContractResult.getTransactionReceipt().getResult()));
} else {
System.out.println("issue success.");
}
}
private static void transfer() {
// contract parameters
EVMParameter contractParameters = new EVMParameter("Transfer(identity,int256)");
contractParameters.addIdentity(testAccount1);
contractParameters.addUint(BigInteger.valueOf(50));
CallContractRequest request = new CallContractRequest(userIdentity,
Utils.getIdentityByName(testContractId), contractParameters, BigInteger.ZERO, VMTypeEnum.EVM);
// set Gas limit
// Make sure your account balance is greater than 50,000
request.setTxGas(50000);
TransactionReceiptResponse callContractResult;
// if (isTeeChain) {
// signRequest(request);
//
// // generate transaction key
// byte[] transactionKey = ConfidentialUtil.keyGenerate(secretKey,
// request.getTransaction().getHash().getValue());
//
// ConfidentialRequest confidentialRequest = new ConfidentialRequest(request, publicKeys, transactionKey);
//
// callContractResult = sdk.getConfidentialService().confidentialRequest(confidentialRequest);
// } else {
callContractResult = sdk.getContractService().callContract(request);
// }
if (!callContractResult.isSuccess() || callContractResult.getTransactionReceipt().getResult() != 0) {
exit("transfer", getErrorMsg((int)callContractResult.getTransactionReceipt().getResult()));
} else {
System.out.println("transfer success.");
}
}
private static BigInteger query(Identity account) {
// contract parameters
EVMParameter parameter = new EVMParameter("Query(identity)");
parameter.addIdentity(account);
// build call contract request
CallContractRequest request = new CallContractRequest(userIdentity,
Utils.getIdentityByName(testContractId), parameter, BigInteger.ZERO, VMTypeEnum.EVM);
// set Gas limit
// Make sure your account balance is greater than 50,000
request.setTxGas(50000);
TransactionReceiptResponse callContractResult;
// if (isTeeChain) {
// signRequest(request);
//
// // generate transaction key
// byte[] transactionKey = ConfidentialUtil.keyGenerate(secretKey,
// request.getTransaction().getHash().getValue());
//
// ConfidentialRequest confidentialRequest = new ConfidentialRequest(request, publicKeys, transactionKey);
//
// callContractResult = sdk.getConfidentialService().confidentialRequest(confidentialRequest);
// } else {
callContractResult = sdk.getContractService().callContract(request);
// }
if (!callContractResult.isSuccess() || callContractResult.getTransactionReceipt().getResult() != 0) {
exit("query", getErrorMsg((int)callContractResult.getTransactionReceipt().getResult()));
}
byte[] output = null;
// if (isTeeChain) {
// output = ConfidentialUtil.decrypt(secretKey, callContractResult.getTransactionReceipt().getOutput(), request.getTransaction().getHash().hexStrValue());
// } else {
output = callContractResult.getTransactionReceipt().getOutput();
// }
if (output == null) {
exit("decrypt tee", "decrypt tee output failed");
return BigInteger.ZERO;
}
// decode return values
EVMOutput contractReturnValues = new EVMOutput(ByteUtils.toHexString(output));
return contractReturnValues.getUint();
}
private static void expect(BigInteger balance, BigInteger expectBalance) {
if (balance.compareTo(expectBalance) != 0) {
exit("expect", "the account value is not expected.");
} else {
System.out.println("check account balance success.");
}
}
private static void initSdk() {
sdk = new MychainClient();
boolean initResult = sdk.init(env);
if (!initResult) {
exit("initSdk", "sdk init failed.");
}
}
public static void depositData(){
// byte[] depositData = ByteUtils.hexStringToBytes(“0x1234”);
DepositDataRequest requests = new DepositDataRequest(userIdentity,
Utils.getIdentityByName(testContractId),“存证内容”.getBytes(), BigInteger.valueOf(50));
DepositDataResponse response = sdk.getAccountService().depositData(requests);
System.out.println("存证成功");
System.out.println("交易哈希为: " + response.getTxHash() + "交易结果: "+response.getErrorCode());
System.out.println("交易内容为: " + new String("存证内容".getBytes()));
//
// System.out.println(1);
// QueryTransactionReceiptResponse depositDataResult;
// depositDataResult = sdk.getQueryService().queryTransactionReceipt(response.getTxHash());
// return ByteUtils.toHexString(depositDataResult.getTransactionReceipt().toString());
}
public static void createAccount() throws IOException {
long startIndex = System.currentTimeMillis();
String userPrivateKeyFile = "user.key";
String testAccount1name = "account_1" + startIndex;
Pkcs8KeyOperator pkcs8KeyOperator = new Pkcs8KeyOperator();
userKeypair = pkcs8KeyOperator.load(IOUtil.inputStreamToByte(
DemoSample.class.getClassLoader().getResourceAsStream(userPrivateKeyFile)),userPassword);
//获取私钥 设置创建账户的名称
// 创建账户 并设置参数。
Account newAccount = new Account();
newAccount.setIdentity(Utils.getIdentityByName(testAccount1name));
newAccount.setBalance(0);
newAccount.setStatus(AccountStatus.NORMAL);
AuthMap authMap1 = new AuthMap();//账户或合约的公钥与权重值
newAccount.setAuthMap(authMap1.updateAuth(new PublicKey(userKeypair), 100));
newAccount.setRecoverKey(new PublicKey(userKeypair));
CreateAccountRequest request = new CreateAccountRequest(userIdentity, newAccount);
// create testAccount
CreateAccountResponse createAccountResult = sdk.getAccountService().createAccount(request);
if (!createAccountResult.isSuccess()) {
exit("createAccount", getErrorMsg((int)createAccountResult.
getTransactionReceipt().getResult()));
} else {
System.out.println("create testAccount1 success.返回信息:"+createAccountResult.toString());
}
}
public static void transferBalance() throws IOException {
TransferBalanceRequest request = new TransferBalanceRequest(userIdentity,
Utils.getIdentityByName(testContractId),BigInteger.valueOf(50));
TransferBalanceResponse response = sdk.getAccountService().transferBalance(request);
System.out.println("交易哈希为: " + response.getTxHash() + "\n"+
"交易结果: "+response.getErrorCode());
}
public static void setRecoverKey() throws IOException {
SetRecoverKeyRequest request = new SetRecoverKeyRequest(
Utils.getIdentityByName(String.valueOf(testAccount2)), new PublicKey(userKeypair));
SetRecoverKeyResponse response = sdk.getAccountService().setRecoverKey(request);
System.out.println("交易哈希为: " + response.getTxHash() + "\n"+ "交易结果: "+response.getErrorCode());
}
public static void queryBlockHeader() throws IOException {
String BlockHash= "15d87fa55e19fda34694102f65fe7ef88a788f3f82f7a60ac030a71adfdee237";
Hash hash = new Hash(ByteUtils.hexStringToBytes(BlockHash));
QueryBlockHeaderResponse replyBlockHeader = sdk.getQueryService().queryBlockHeader(hash);
System.out.println("区块号应该为:20978522 " + "实际输出为:" +
replyBlockHeader.getBlockHeader().getNumber());
}
public static void queryBlockHeaderByNumber() throws IOException{
// long blockNumber = 2630466055911031096;
QueryBlockHeaderResponse replyBlockHeader = sdk.getQueryService().
queryBlockHeaderByNumber(BigInteger.valueOf(50));
}
public static void depositEnvelope() throws IOException {
// create Group
CreateGroupRequest createGroupRequest = new CreateGroupRequest(new PublicKey(userKeypair.getPubkeyId()),
Utils.getIdentityByName(account));
CreateGroupResponse createGroupResponse = sdk.getEnvelopeService().createGroup(createGroupRequest);
// join group
byte[] groupPrivateKey = createGroupResponse.getPrivateKey();
PublicKey anoymousPublicKey = new PublicKey(userKeypair.getPubkeyId());
JoinGroupRequest request = new JoinGroupRequest(groupPrivateKey, anoymousPublicKey,
createGroupResponse.getGroupId(), Utils.getIdentityByName(account));
JoinGroupResponse joinGroupResponse = sdk.getEnvelopeService().joinGroup(request);
// get groupId by createGroupResponse
BaseFixedSizeByteArray.Fixed20ByteArray groupId = createGroupResponse.getGroupId();
// get keypair from createGroupResponse
Pkcs8KeyOperator pkcs8KeyOperator = new Pkcs8KeyOperator();
Keypair keypair = pkcs8KeyOperator.loadFromPrivkey(createGroupResponse.getPrivateKey());
// create signerOption by keypair
SignerOption signerOption = new SignerOption();
List<SignerBase> signerBaseList = new ArrayList<SignerBase>();
signerBaseList.add(MyCrypto.getInstance().createSigner(keypair));
signerOption.setSigners(signerBaseList);
// create inner request
CreateAccountRequest createAccountRequest = new CreateAccountRequest(Utils.getIdentityByName(account),
testAccount2);
// create DepositEnvelopeRequest
IHash hashTool = HashFactory.getHash();
DepositEnvelopeRequest requests = new DepositEnvelopeRequest(createAccountRequest,
groupId, signerBaseList, keypair);
requests.setAnonymousIdentity(new Identity(hashTool.hash(keypair.getPubkeyId())));
// 请参考错误信息章节,检查返回的数据
DepositEnvelopeResponse response = sdk.getEnvelopeService().depositEnvelope(requests);
System.out.println("交易收据为 " + response.getExceptionMessage());
System.out.println("错误码为 " + response.getErrorCode());
System.out.println("交易收据 " + response.getTransactionReceipt());
System.out.println("区块号 " +response.getBlockNumber());
}
public static void listenAccount() throws IOException {
IEventCallback handler = new IEventCallback() {
public void onEvent(Message message) {
PushAccountEvent accountEvent = (PushAccountEvent) message;
//code
}
};
// listen account
BigInteger eventId = sdk.getEventService().listenAccount(Utils.getIdentityByName(account), handler, EventModelType.PUSH);
if (eventId.longValue() == 0) {
System.out.println("listen failed");
} else {
System.out.println("listen success");
}
if (sdk.getEventService().unListenAccount(eventId))
{
System.out.println("成功取消监听用户");
}
}
public static void listenTopics() throws IOException {
IEventCallback handler = new IEventCallback() {
public void onEvent(Message message) {
PushTopicsEvent eventTopicsMessage = (PushTopicsEvent) message;
}
};
// add contract
List<String> topics = new ArrayList<String>();
//系统合约,任意调用一个合约都会返回事件
topics.add("积分发放");
//EVM 合约,调用会触发合约内部 IssueEvent 事件的方法
IHash hashTool = HashFactory.getHash();
byte[] sha256 = hashTool.hash("IssueEvent(identity,int256)".getBytes());
topics.add(ByteUtils.toHexString(sha256));
// listen topics
BigInteger result = sdk.getEventService().listenTopics(topics, handler,
VMTypeEnum.EVM, EventModelType.PUSH);
//调用 EVM 的合约,将触发两个 topic,一个 call_contract 的事件,一个TEST 的事件
EVMParameter parameters = new EVMParameter("test(identity,uint256)");
parameters.addIdentity(Utils.getIdentityByName(account));
parameters.addUint(BigInteger.valueOf(50));
CallContractRequest request = new CallContractRequest(Utils.getIdentityByName(account),
Utils.getIdentityByName(testContractId), parameters, BigInteger.ZERO, VMTypeEnum.EVM);
System.out.println("订阅主题的错误码: "+sdk.getContractService().callContract(request).getErrorCode());
if(result.longValue() == 0){
System.out.println("listen failed");
}else {
System.out.println("listen success");
}
//结束后取消订阅主题
if(sdk.getEventService().unListenTopics(result)){
System.out.println("成功取消订阅主题");
};
}
public static void queryNodeMetricsStatus() throws IOException {
long startTime = System.currentTimeMillis()-10;
long endTime = System.currentTimeMillis();
QueryNodeMetricsStatusResponse result = sdk.getQueryService().
queryNodeMetricsStatus( startTime, endTime);
System.out.println(result.getInfo());
}
public static void updateContract() throws IOException{
String newContractCode = "";
byte[] code = ByteUtils.hexStringToBytes(newContractCode);
UpdateContractRequest request = new UpdateContractRequest(Utils.getIdentityByName(testContractId)
, code, VMTypeEnum.EVM);
// 请参考错误信息章节,检查返回的数据
UpdateContractResponse response = sdk.getContractService().updateContract(request);
}
public static void main(String[] args) throws Exception {
//step 1:init mychain env.
initMychainEnv();
//step 2: init sdk client
initSdk();
// QueryAccountResponse queryAccountResponse = sdk.getQueryService().queryAccount(Utils.getIdentityByName(“Xy19952”));
//step 3 : deploy a contract using useridentity.
deployContract();
//step 4 issue 100 assets to testAccount1.
// issue();
//step 5 : transfer 50 assets from useridentity to testAccount1
// transfer();
//step 6 : query testAccount1 whose balance should be 50.
// BigInteger balance = query(testAccount1);
//step 7 : compare to expect balance.
// expect(balance, BigInteger.valueOf(50));
// System.out.println(balance);
// step 8 : sdk shut down
depositData();
// createAccount();
// transferBalance();
// queryBlockHeader();
// ClientEnv env = new ClientEnv();
// System.out.println(env.getLogger().toString());
// System.out.println(logger.toString());
// depositEnvelope();
// listenAccount();
// listenTopics();
// queryNodeMetricsStatus();
sdk.shutDown();
}
}
代码就是上述,都是基于BaaS平台上面提供的java SDK中的 DemoSample,你们粘贴过去自己改改错,没有引入的类引一下,写了这么长有点累,毕竟是开发新手,多多包涵。有问题评论,如果看到了会及时回复的。
更多推荐

所有评论(0)