在尝试本节的样例代码前,需要保证目标智能合约已经按照蚂蚁区块链BaaS平台应用开发指南(三):从一个简单合约开始中的做法编译部署成功。

基于JavaSDK的接入

在上一节里,我们通过Cloud IDE部署了一个最简单的智能合约,并且通过Cloud IDE成功的调用了合约的方法。拿传统应用的开发来类比,这就像在数据库上增加了一个存储过程,然后通过外部应用来触发这个存储过程的执行。那么,对于区块链来说,外部应用又如何来调用部署好的智能合约?在这一节中,我们将会通过蚂蚁区块链提供到JavaSDK来接入我们的链,然后调用上一节中部署的合约。官网的文档提供了详细的步骤和一个略微有些复杂的Demo,具体信息可以参见这里。
在这篇文章里,我们的目标更简单:接入目标链,调用已部署的合约。

环境准备:证书!

和Cloud IDE一样,一个Java程序要和链进行通信必须满足:(1)客户端能确认链的身份;(2)链能确认调用者的身份。

  • 客户端要确认链的身份, 需要提前获取对应的CA证书。
    对于Java程序,需要在代码中提供trustCa文件,trustCa文件的在链卡片右上角···按钮->下载TrustCA获取。

  • 链要能确认客户端的身份,需要客户端提供用户(机构)的×××书 client.crtclient.key
  • 为了交易能够验证成功,用户需要拥有发起交易账户的私钥user.key

准备好上述四个文件,在后续的Java工程中,程序需要读取配置上述文件。

再做一次说明,在蚂蚁区块链平台BaaS上,一个用户(机构)可以有多个账户。平台为每一个用户(机构)签发一张×××书(client.crt)和对应的私钥(client.key),用户可以创建多个账户,每个账户有自己的公私钥(user.key, user.pub)
私钥以及证书的密码一定不要混淆。

开发环境配置

  • 下载并解压JavaSDK(当前版本为0.10.2.4.2 )

Java环境要求:JDK 7+,Maven 3.5.4+

  • 在 Maven 文件中引入 SDK 包
//安装 SDK 到本地仓库
mvn install:install-file -Dfile=mychainx-sdk-0.10.2.4.2.jar -DgroupId=com.alipay.mychainx -DartifactId=mychainx-sdk -Dversion=0.10.2.4.2 -Dpackaging=jar -DpomFile=pom.xml//安装 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-osx-x86_64.jar -DgroupId=io.netty -DartifactId=netty-tcnative-openssl-static -Dversion=2.0.17-Final-mychain -Dpackaging=jar -Dclassifier=<OS-classifiler>

注意按照开发平台修改OS-classifiler
更多信息见官方文档

开始第一个Java程序

  1. 使用 Intellij IDEA 创建一个基于 Maven 构建的空项目。
  2. 把第一节中获取到client.crtclient.keytrustCauser.key 文件放入到resources 目录中。
  3. pom.xml中添加依赖。
<dependencies><dependency><groupId>com.alipay.mychainx</groupId><artifactId>mychainx-sdk</artifactId><!--请使用最新 SDK 版本 --><version>0.10.2.4.2</version></dependency>
</dependencies><build><extensions><extension><groupId>kr.motd.maven</groupId><artifactId>os-maven-plugin</artifactId><version>1.6.1</version></extension></extensions>
</build>
  1. 新建一个CallContractDemo的类,内容参考下面的代码:
import com.alipay.mychain.sdk.api.Mychain;
import com.alipay.mychain.sdk.api.request.MychainParams;
import com.alipay.mychain.sdk.api.request.contract.CallContractRequest;
import com.alipay.mychain.sdk.api.result.MychainBaseResult;
import com.alipay.mychain.sdk.config.ISslOption;
import com.alipay.mychain.sdk.config.MychainEnv;
import com.alipay.mychain.sdk.config.SslBytesOption;
import com.alipay.mychain.sdk.domain.account.Identity;
import com.alipay.mychain.sdk.message.response.ReplyTransactionReceipt;
import com.alipay.mychain.sdk.message.response.Response;
import com.alipay.mychain.sdk.network.ClientTypeEnum;
import com.alipay.mychain.sdk.tools.codec.CodecTypeEnum;
import com.alipay.mychain.sdk.tools.codec.contract.ContractParameters;
import com.alipay.mychain.sdk.tools.codec.contract.ContractReturnValues;
import com.alipay.mychain.sdk.tools.crypto.KeyLoder;
import com.alipay.mychain.sdk.tools.hash.HashTypeEnum;
import com.alipay.mychain.sdk.tools.log.LoggerFactory;
import com.alipay.mychain.sdk.tools.sign.SignTypeEnum;
import com.alipay.mychain.sdk.tools.utils.ByteUtils;
import com.alipay.mychain.sdk.tools.utils.Utils;
import org.slf4j.Logger;import java.io.InputStream;
import java.math.BigInteger;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.security.PrivateKey;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;public class CallContractDemo {private static Mychain sdk;// 配置目标链的接入IP和端口号。// 以上信息可以通过 BaaS平台 > 区块链卡片 > 详情 > 区块链浏览器 > 节点 找到。// 参见:蚂蚁区块链BaaS平台应用开发指南(二):准备工作 查看区块链详情 小节private static String host = "*.*.*.*";private static int port = 18130;// 设置用户×××书,证书私钥和私钥密码。private static String keyFilePath = "client.key";private static String certFilePath = "client.crt";private static String clientKeyPassword = "****";// 设置trustCa证书。// trustStore密码默认为mychain。private static String trustStoreFilePath = "trustCa";private static String trustStorePassword = "mychain";// 设置交易发起者的账户私钥,私钥密码和账户名。// 可以使用默认账户,即申请证书步骤一并申请的账户private static String userPrivateKeyFile = "user.key";private static String userPassword = "****";private static String accountName = "Your Account Name";// 设置调用合约名// 合约名需要是第三节中所部署的合约名称private static String targetContractName = "Target Contract Name";private static MychainEnv env;private static void initMychainEnv() {// 默认值,不用修改env = buildMychainEnv("test_sdk");}private static void initLogger() {Logger logger = org.slf4j.LoggerFactory.getLogger(CallContractDemo.class);LoggerFactory.setInstance(logger);}private static MychainEnv buildMychainEnv(String identity) {InetSocketAddress inetSocketAddress = InetSocketAddress.createUnresolved(host, port);// build ssl option// 构建SSL选项ISslOption sslOption = new SslBytesOption.Builder().keyBytes(Utils.readFileToByteArray(CallContractDemo.class.getClassLoader().getResource(keyFilePath).getPath())).certBytes(Utils.readFileToByteArray(CallContractDemo.class.getClassLoader().getResource(certFilePath).getPath())).keyPassword(clientKeyPassword).trustStorePassword(trustStorePassword).trustStoreBytes(Utils.readFileToByteArray(CallContractDemo.class.getClassLoader().getResource(trustStoreFilePath).getPath())).build();// 可将同一条链的不同接入节点放入备份节点中。List<SocketAddress> backupNodes = new ArrayList<SocketAddress>();// backupNodes.add(InetSocketAddress.createUnresolved("47.100.27.162", 18130));// backupNodes.add(InetSocketAddress.createUnresolved("106.14.218.105", 18130));// backupNodes.add(InetSocketAddress.createUnresolved("47.100.115.103", 18130));HashTypeEnum hashType = HashTypeEnum.SHA256;SignTypeEnum signType = SignTypeEnum.ECDSA;return MychainEnv.build(identity, ClientTypeEnum.TLS, hashType,signType, CodecTypeEnum.RLP, inetSocketAddress, sslOption, backupNodes);}private static void initSdk() {sdk = new Mychain();MychainBaseResult<Response> initResult = sdk.init(env);if (!initResult.isSuccess()) {System.out.println("initSdk: sdk init failed.");}}public static void main(String[] args) throws Exception{initLogger();// 初始化环境。initMychainEnv();// 初始化SDK。initSdk();// Get the Identity of my account.// 获取账户的IdentityIdentity userIdentity = Utils.getIdentityByName(accountName, env);// Get the private key of the account.// 获取账户的私钥// 注意检查userPrivateKeyFileInputStream是否为空。InputStream userPrivateKeyFileInputStream = CallContractDemo.class.getClassLoader().getResourceAsStream(userPrivateKeyFile);PrivateKey userPrivateKey = KeyLoder.getPrivateKeyFromPKCS8(userPrivateKeyFileInputStream,userPassword);// Add the key to the key list. Note: in this demo, the account only have one single private key.// 把私钥添加到一个私钥列表中。注:本例中,账户只有一把私钥。ArrayList<PrivateKey> userPrivateKeyArrayList = new ArrayList<PrivateKey>();userPrivateKeyArrayList.add(userPrivateKey);// Build a CallContract request// Build a CallContract request - 1: build Mychain parameters// 构造CallContrace请求 - 1: 构造Mychain参数。MychainParams mychainParams = new MychainParams.Builder().gas(BigInteger.valueOf(4000000)).privateKeyList(userPrivateKeyArrayList).build();// Build a CallContract request - 2: get the identity of the contract// 构造CallContrace请求 - 2: 获取合约Identity。// 通过合约名获取合约实例的Identity,合约名和上一节中通过Cloud IDE部署的合约名一致。Identity contractIdentity = Utils.getIdentityByName(targetContractName,env);// Build a CallContract request - 3: build contract parameters// 构造CallContrace请求 - 3: 构造调用方法参数。这里设置的是需要调用的方法名。ContractParameters crtParameters = new ContractParameters("get()");// Build a CallContract request - 4: build CallContract request// 构造CallContrace请求 - 4: 构造请求CallContractRequest request = CallContractRequest.build(userIdentity,contractIdentity,crtParameters,BigInteger.ZERO,mychainParams);// Call the contract// 调用合约MychainBaseResult<ReplyTransactionReceipt> replyTransactionReceipt = sdk.getContractService().callContract(request);// Get the returned value from the raw bytes output.// 获取合约返回数据,并从返回的字节码中获取数据String rawOutput = ByteUtils.toHexString(replyTransactionReceipt.getData().getTransactionReceipt().getOutput());ContractReturnValues contractReturnValues = new ContractReturnValues(rawOutput);// 我们事先知道get方法会返回一个Uint类型的值BigInteger storedData = contractReturnValues.getUint();System.out.println("Returned storedData from the contract is: " + storedData);System.out.println("======================================");System.out.println("Let us set a new value.");// Build anther CallContract request// 构造另外一个合约调用请求。// 构造调用方法参数,这次我们需要调用set方法ContractParameters crtParameters2 = new ContractParameters("set(uint256)");// Give a random Integer// 设置一个随机数。Random r = new Random();Integer value = r.nextInt(100);// 设置set方法的传入参数值。crtParameters2.addUint(BigInteger.valueOf(value));// Build a CallContract request// 构造请求CallContractRequest request2 = CallContractRequest.build(userIdentity,contractIdentity,crtParameters2,BigInteger.ZERO,mychainParams);// Call the contract// 调用合约MychainBaseResult<ReplyTransactionReceipt> replyTransactionReceipt2 = sdk.getContractService().callContract(request2);if (replyTransactionReceipt2.isSuccess()){System.out.println("New value of the storedData is: " + value);}else{System.out.println("Failed to set the value:" + value);}sdk.shutDown();}
}

上述代码中,我们通过Java程序来调用上一节中部署好的合约:

  1. 调用get方法获取storedData;
  2. 调用set方法给storedData设置一个新的值。

按需修改的配置项:


clientKeyPassword:用户证书密钥(client.key)的密码
userPassword:账户私钥(user.key)的密码
accountName:账户名
contractName:要调用的目标合约名
trustStorePassword:目前默认为mychain,没有特殊说明不用修改。
hostport:链的接入节点 IP和端口号。可通过区块链卡片 > 详情 > 节点处获取,参见下图。选一个IP填入即可,其他的节点IP可以放入backupNodes中。

程序运行结果

  • 第一次运行:
Returned storedData from the contract is: 77
======================================
Let us set a new value.
New value of the storedData is: 16
  • 第二次运行:
Returned storedData from the contract is: 16
======================================
Let us set a new value.
New value of the storedData is: 86

小结

至此,Java代码成功的调用到了链上合约的方法,并正确获取到了返回值。可以看到,调用一个合约的主要步骤为

  • 初始化MychainEnv(配置好环境参数和客户端证书)
  • 初始化MychainParams(配置好调用请求发起者的私钥列表)
  • 构造ContractParameters(构造目标方法的签名,添加传入参数)
  • 构造CallContractRequest(提供调用者ID,合约ID,环境参数,链的参数)
  • 发起合约调用请求
  • 解析调用结果(调用结果在ReplyTransactionReceipt中)

蚂蚁区块链BaaS平台应用开发指南(四):JavaSDK的接入相关推荐

  1. 蚂蚁区块链BaaS平台应用开发指南(五):JS SDK的接入

    基于JavaScript SDK的接入 在上一节中,我们通过JavaSDK接入了我们的目标链并调用合约成功.在本节中,我们将通过JS SDK实现同样的调用.JS SDK可以集成在Web应用中,运行在浏 ...

  2. 蚂蚁区块链BaaS平台应用开发指南(一):前言

    前言 2018年疯狂的币市把区块链技术推到了风口浪尖,随着潮水的退去,越来越多的技术人和市场开始沉淀到实际的问题上.如何利用区块链技术带来的新特性(去中心,可追溯,不可篡改等)去解决现实世界的实际需求 ...

  3. 蚂蚁区块链BaaS平台架构与实践

    摘要:以"数字金融新原力(The New Force of Digital Finance)"为主题,蚂蚁金服ATEC城市峰会于2019年1月4日在上海如期举办.在ATEC区块链行 ...

  4. 这18节课手把手教会你入门蚂蚁区块链BAAS系统开发

    1,摘要 蚂蚁区块链创新大赛正在如火如荼的进行中,这次蚂蚁区块链创新大赛奖金丰厚,获奖者权益多多.那么,对于一个区块链团队来说,如何快速了解蚂蚁BAAS系统的能力,开发环境以及接口是一件很重要的事情. ...

  5. 蚂蚁区块链BaaS:开放在云端,落地于实体

    自 2018 年 6 月上线以来,蚂蚁区块链 BaaS 不断在技术上实现突破,形成自身独特的优势,并做为行业领军者在不同领域的几十个场景实现落地.在区块链的商用时代加速到来之际,通过开放自身的技术体系 ...

  6. 区块链BAAS平台:公共或私人区块链编程以用于各种用途

    2019独角兽企业重金招聘Python工程师标准>>> 人们可以为公共或私人区块链编程以用于各种用途.理论上,我认为牺牲权力下放的方面可以解决区块链技术背后的许多当前问题.区块链仍然 ...

  7. 微服务架构在区块链BaaS平台中的实践

    前言 微服务架构是近几年互联网行业比较火的概念,凭借灵活可扩展.独立部署-等优势,逐步成为分布式架构中的主流.那么微服务架构和区块链又能擦出哪些神奇的火花?本期将从微服务架构概述.微服务架构在BaaS ...

  8. 源中瑞区块链baas平台一站式服务体系

    区块链是一项新兴技术,很多企业都想将区块链技术应用到产品中去,但是由于对区块链这项技术还属于发展前期阶段,导致绝大多数的企业的区块链技术人才是稀缺的,为此我们研发了区块链baas平台,可以给中小企业提 ...

  9. 技术工坊|腾讯华为入局的区块链BaaS平台解决了什么问题?(上海)

    2019独角兽企业重金招聘Python工程师标准>>> 在区块链热火朝天一年多之后,真正落地的区块链产业应用仍然乏善可陈,特别是基于公链的成功产业应用更是少之又少.这种现状的问题在哪 ...

最新文章

  1. 未来五年人工智能将实现的五大突破
  2. HDLBits 系列(23)3 输入的 LUT
  3. Cython的简单使用
  4. c语言或者cpp中位运算的技巧
  5. cad常用字体_2300多种CAD字体免费送给你!绘图必备,一键解决你的CAD文字乱码问题...
  6. 【Python】Python数据分析来解析,2021年度最具“钱景”的大学专业
  7. Struts2-EL表达式为什么能获取值栈数据
  8. 配置yum,nc,telnet
  9. 力扣35-搜索插入位置(C++,左右闭区间,nums[mid]与target大小关系判断的不同及辨析)
  10. C# Linq以及反射总结
  11. [渝粤教育] 郑州工程技术学院 试验设计与数据处理 参考 资料
  12. GD32F103学习笔记(2)——在GD32F103移植STM32F103代码
  13. 2022 各国程序员薪资大揭秘!
  14. 【读书笔记】《M型社会》大前研一
  15. 不小心被拉进QQ诈骗群之后
  16. 微信开放平台 公众号第三方平台开发C#
  17. ppp lcp协商报文有哪些_课后分享PPP协议第十三周
  18. 励志照亮人生 编程改变命运
  19. 网易云信第三方接口调用超详细Demo
  20. idea打不开,双击没反应的解决方案

热门文章

  1. ssh和rsh的区别、Linux rsh命令
  2. 登陆远程kvm_KVM远程VMM管理
  3. Eclipse4.6(neno)手动配置Tomcat插件
  4. 【孟子E章】祝大家新年愉快!
  5. Mac brew更新国内源或重置官方源
  6. 关于BeanUtils.populate
  7. js的爬山之路原型与原型链~~狂徒李四
  8. 节假日判断工具(Java)
  9. Google Earth Engine(GEE)——MODIS 影像LST地表温度随时间变化的趋势案例分析
  10. 论文阅读笔记之Replacing Mobile Camera ISP with a Single Deep Learning Model