本文是由链博科技 ChainBoard.IO 为大家带来的web3j 对智能合约的调用。让 java 程序可以和我们的智能合约愉快的交互起来~

一、什么是 web3j

web3j是一个高度模块化、响应式、类型安全的Java和Android库,用于与智能合约交互,并与Ethereum网络的客户端(节点)集成。

二、准备工作

1.新建一个spring-boot的项目,在 pom 文件中添加

<dependency>    <groupId>org.web3j</groupId>    <artifactId>web3j-spring-boot-starter</artifactId>    <version>1.6.0</version></dependency>

2.打开以太坊客户端 (如果有可以直接连接的客户端,可以忽略此步骤)注意:打开客户端的时候需要加上 --rpc 参数。否则无法调用。并且需要打开你的矿工,来完成智能合约部署调用等工作。

geth --rpc --datadir "./chain" --nodiscover console 2>>ouput.logminer.start()

3.生成智能合约的封装器 (1) 下载 web3j 的 Command Line Tool: Homebrew

brew tap web3j/web3jbrew install web3j

下载zip文件:下载地址

unzip web3j-<version>.zip./web3j-<version>/bin/web3j

(2) 生成封装器 需要先用 solc 编译生成 .bin .abi 文件

solc 安装命令: npm install-g solc

命令:

> solcjs <Solidity文件地址>.sol --bin --abi --optimize -o <输出文件夹路径>/

实例:这里以 Compute.sol 文件为例,示例合约见文章最后一节

> solcjs Compute.sol --abi --bin -o ./

会生成四个文件,如下:

注意:因为合约中有 Compute、Owner 两个函数,所以两个函数的文件都会生成出来。但是,由于 Compute 函数继承了 Owner 函数的方法,所以实际上我们只需要用到 ComputesolCompute.abi ComputesolCompute.bin 这两个文件。

用 web3j 生成 java 封装器 命令:

web3j solidity generate --solidityTypes <智能合约编译之后的.bin文件的地址>.bin <智能合约编译之后的.abi文件的地址>.abi -o /path/to/src/main/java -p com.your.organisation.name

-o 后接生成好的java文件放置的位置, -p 后接生成的java文件的包名注意:.bin .abi文件顺序不能反,否则会报错

实例:使用我们之前生成的文件,将 java 文件生成到我们的项目中:

web3j solidity generate --solidityTypes Compute_sol_Compute.bin Compute_sol_Compute.abi -o ./project/src/main/java -p com.demo

输出如下信息后,可以在我们指定的路径看见生成好的 java 文件 Compute_sol_Compute.java

三、web3j 基础命令

1.建立以太坊连接

Web3j web3j = Web3j.build(new HttpService());

默认的连接地址是 http://localhost:8545/,也可以改变地址,连接其他客户端。

2.加载账户信息 账户文件可以在私链数据文件夹中的 keystore 文件夹中找到

Credentials credentials = WalletUtils.loadCredentials(                "123",                "/datadir/chain/keystore/UTC--2018-03-14T14-46-38.646997441Z--c2acba996f709d4b806d3330996f49d50f088258");

第一个变量填入账户的密码,第二个变量填入账户文件的 path

3.获取账户余额

Web3j web3j = Web3j.build(new HttpService());String address = "0xa6fd2ebac389773f5bd34d0738bc5fdbd1bea01b";EthGetBalance ethGetBalance = web3j.ethGetBalance(address, DefaultBlockParameterName.LATEST).send();if(ethGetBalance!=null){        // 打印账户余额       System.out.println(ethGetBalance.getBalance());        // 将单位转为以太,方便查看       System.out.println(Convert.fromWei(ethGetBalance.getBalance().toString(), Convert.Unit.ETHER));}

四、使用 Java 部署智能合约

部署智能合约的命令:

YourSmartContract contract = YourSmartContract.deploy(        <web3j>, <credentials>, GAS_PRICE, GAS_LIMIT,        [<initialValue>,]        <param1>, ..., <paramN>).send();

实例:部署 Compute_sol_Compute.java

// 创建一个 web3j 的连接Web3j web3j = Web3j.build(new HttpService());// 部署的时候需要用到该账户的 gas,务必保证该账户余额充足Credentials credentials = WalletUtils.loadCredentials(                "123",                "/datadir/chain/keystore/UTC--2018-03-14T14-46-38.646997441Z--c2acba996f709d4b806d3330996f49d50f088258"); // 部署合约       Compute_sol_Compute compute_sol_compute                = Compute_sol_Compute.deploy(web3j, credentials, BigInteger.valueOf(200000), BigInteger.valueOf(20000000)).send();// 部署完成后打印合约地址System.out.println(compute_sol_compute.getContractAddress());

五、使用 Java 调用智能合约

这里,我们还是使用第二篇中编写的智能合约为例

1.加载你的智能合约 命令:

YourSmartContract contract = YourSmartContract.load(        "0x<address>|<ensName>", web3j, credentials, GAS_PRICE, GAS_LIMIT);

实例:

// 填入刚才部署后打印出来的合约地址String address = "0x9b0851112b41664171338abaf0df86e040c34d07";Compute_sol_Compute compute_sol_compute = Compute_sol_Compute.load(                address,                web3j,                credentials,                BigInteger.valueOf(200000),                BigInteger.valueOf(20000000));

2.验证合约是否可用 命令:

contract.isValid();

实例:验证已部署的智能合约是否可用

System.out.println(compute_sol_compute.isValid());

3.调用智能合约 命令:

Type result = contract.someMethod(<param1>, ...).send();

实例:调用 Compute_sol_Compute.java 中的方法 1.调用 getLCM 方法

// 调用是能合约函数Uint256 first = new Uint256(2);Uint256 second = new Uint256(3);TransactionReceipt transactionReceipt = compute_sol_compute.getLCM(first, second).send();System.out.println(transactionReceipt);

执行成功后会返回打印出来本次交易的信息。

2.调用 getRecord 方法

Uint256 index = new Uint256(0);List<Uint256> result = compute_sol_compute.getRecord(index).send().getValue();for (Uint256 uint256 : result) {     System.out.println(uint256.getValue());}

结果:

236

3.使用监听事件,获取合约结果

Uint256 first = new Uint256(2);Uint256 second = new Uint256(3);TransactionReceipt transactionReceipt = compute_sol_compute.getLCM(first, second).send();Compute_sol_Compute.GetLCMEventResponse result = compute_sol_compute.getGetLCMEvents(transactionReceipt).get(0);System.out.println(result.first.getValue());System.out.println(result.second.getValue());System.out.println(result.result.getValue());

使用一个监听事件等待到结果返回,因为是同步的,所以执行的时间会比较长。最后,可以拿回本次智能合约执行的结果。

六、示例合约

pragma solidity ^0.4.19;contract Owner {    //合约拥有者    address public owner;    //构造函数,将合约的所有权给予发布者    function Owner() public {        owner = msg.sender;    }    //仅有合约的拥有者可以操作    modifier onlyOwner() {        require(msg.sender == owner);        _;    }    //onlyOwner作为函数执行的前置条件,仅有合约拥有者可以更换所属权    function setOwner(address to) public onlyOwner {        if(to != address(0)) {            owner == to;        }    }}//通过is使Compute继承Owner合约contract Compute is Owner {    //建立一个存储于区块链上的二维数组,存储每一次计算的输入以及结果    uint[3][] records;    //比较大小,solidity允许返回两个值    function compare(uint first, uint second) internal pure returns(uint bigOne, uint smallOne) {        if(first > second) {            return (first, second);        }        else {            return (second, first);        }    }    //建立事件去监听每一次计算并记录日志    event GetLCM(uint first, uint second, uint result);    function getLCM(uint first, uint second) external onlyOwner returns(uint) {        if (first == second) {            return first;        }        else {            uint bigOne;uint smallOne;            (bigOne, smallOne) = compare(first, second);            uint i = 1;            while(true) {                uint mul = i * bigOne;                if(mul % smallOne == 0) {                    uint index = records.push([first, second, mul]) - 1;                    //调用事件                    GetLCM(first, second, mul);                    return index;                }                i++;            }        }    }    //根据索引获取游戏记录    function getRecord(uint index) external onlyOwner view returns(uint[3]) {        return records[index];    }}

最后,给大家介绍一下:

ChainBoard 核心团队利用其在区块链技术研发上沉淀的丰富经验,围绕项目的需求持续创新,与合作伙伴开放共赢、深度融合,共同打造在金融科技、游戏、众筹互助、医疗保健、物流等领域的区块链应用。 主要输出智能合约开发、公链开发、联盟链开发及交互应用开发等能力,助力项目迅速取得先发优势。目前团队已经在区块链+游戏及区块链+金融与国内知名游戏运营商和海外金融机构展开深度合作。

欢迎对ChainBoard实战经验感兴趣的朋友和手里有行业资源准备布局区块链的大佬关注我们的公众号并和我们取得联系:(原创文章,转载请注明出处,欢迎读者分享到朋友圈)

推荐阅读

  • Spring Boot/Cloud干货汇总

  • Spring Boot中使用Swagger2构建强大的RESTful API文档

  • 使用Swagger2Markup实现API文档的静态部署(一)

  • 使用Swagger2Markup实现API文档的静态部署(二)

  • 阿里云Redis开发规范

  • Spring Boot 2.0 新特性(二):新增事件ApplicationStartedEvent

  • Spring Boot 2.0 新特性(一):配置绑定 2.0 全解析

  • Spring Boot 2.0正式发布,升还是不升呢?

  • Spring Boot 2.0 新特性概览

深入交流、更多福利

扫码加入我的知识星球


点击 “阅读原文” 看看本号其他精彩内容

如何在Spring Boot中玩转智能合约相关推荐

  1. 如何在Spring Boot中玩转智能合约【修订版】

    本文是由链博科技 ChainBoard.IO 为大家带来的web3j 对智能合约的调用.让 java 程序可以和我们的智能合约愉快的交互起来~ 一. 什么是 web3j web3j是一个高度模块化.响 ...

  2. 如何在Spring boot中修改默认端口

    文章目录 介绍 使用Property文件 在程序中指定 使用命令行参数 值生效的顺序 如何在Spring boot中修改默认端口 介绍 Spring boot为应用程序提供了很多属性的默认值.但是有时 ...

  3. 如何安装html启动器,如何在Spring Boot中创建自己的启动器?

    如何在Spring Boot中创建自己的启动器? 也许你有一个内部库包或一个在整个应用程序环境中常用的开源库,如果要在多个Spring Boot应用程序中使用它,为它创建一个Spring Boot启动 ...

  4. 如何在Spring Boot中使用TDD写出高质量的接口

    本文发布于专栏Effective Java,如果您觉得看完之后对你有所帮助,欢迎订阅本专栏,也欢迎您将本专栏分享给您身边的工程师同学. 之前在<如何说服你的同事使用TDD>中介绍了为什么要 ...

  5. 如何在 Spring 生态中玩转 RocketMQ?

    作者 | 通融.洛夜 来源 | 阿里巴巴云原生公众号 RocketMQ 作为业务消息的首选,在消息和流处理领域被广泛应用.而微服务生态 Spring 框架也是业务开发中最受欢迎的框架,两者的完美契合使 ...

  6. 如何在Spring生态中玩转RocketMQ?

    简介: RocketMQ作为业务消息的首选,在消息和流处理领域被广泛应用.而微服务生态Spring框架也是业务开发中最受欢迎的框架,两者的完美契合使得RocketMQ成为Spring Messagin ...

  7. java option请求_如何在Spring Boot中处理HTTP OPTIONS请求?

    选项1:Spring Boot属性(仅限Spring Boot 1.3.0) 从Spring Boot 1.3.0开始,可以使用以下属性配置此行为: spring.mvc.dispatch-optio ...

  8. 面试官 | 如何在 Spring Boot 中进行参数校验?

    作者 | 狂乱的贵公子 来源 | cnblogs.com/cjsblog/p/8946768.html 开发过程中,后台的参数校验是必不可少的,所以经常会看到类似下面这样的代码 这样写并没有什么错,还 ...

  9. 如何在Spring Boot中使用Hibernate Natural ID

    首先,让我们关注所需类的实现.完成所有这些后,我们将能够为具有自然ID的实体提供存储库. 用自然ID编写实体 让我们考虑以下具有自动生成ID和自然ID(code列)的实体.这只是一个使用一个自然ID的 ...

最新文章

  1. android xposed 编译,Xposed修改特征编译
  2. 【数据库】基础知识总结
  3. 详解mybatis的配置setMapperLocations多个路径两种方法
  4. boost::hana::minimum.by用法的测试程序
  5. 从Java连接到Cassandra
  6. 网络安全管理实践(第2版)
  7. idea关闭coverage
  8. 转:android 避免内存泄露
  9. Intel 64/x86_64/IA-32/x86处理器 - SIMD指令集 - SSE扩展(1) - 概述/历史/新数据类型/XMM寄存器组
  10. React和Vue的模块化
  11. 1.1.27 word表格里的文字不显示
  12. 秒杀系统优化方案之缓存、队列、锁设计思路
  13. 《程序员修炼之道——从小工到专家》(典藏书)
  14. 前端必备:FSCapture取色器
  15. 11.6 通信实例与ASCII码
  16. 计算机电源管理器怎么打开,联想电源管理软件打不开怎么办
  17. Excel如何冻结多行多列
  18. 快手科技更新招股书:前11个月营收525亿元,引入10家基石投资者
  19. air flow空调上是什么意思_airflow空调滤芯上是什么意思
  20. 怎么视频转文字?分享3个视频转文字方法

热门文章

  1. win10 microsoft compatibility telemetry 禁用用户改善反馈服务进程 磁盘占用高
  2. linux ubuntu gcc编译 fatal error: bits/libc-header-start.h 错误解决
  3. linux ls 命令只显示目录和只显示文件
  4. Android程序为什么没有退出设计?
  5. Linux2.6内核--内存管理(2)--区
  6. Android开发--BroadcastReceiver2
  7. (二)OpenStack---M版---双节点搭建---数据库安装和配置
  8. 内核开发常备手册翻译(一)
  9. java的并发框架_java并发框架有哪些
  10. NeHe教程Qt实现——lesson16