如何在Spring Boot中玩转智能合约

本文是由链博科技 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实战经验感兴趣的朋友和手里有行业资源准备布局区块链的大佬关注我们的公众号并和我们取得联系:(原创文章,转载请注明出处,欢迎读者分享到朋友圈)

原文发布于微信公众号 - 程序猿DD(didispace)

原文发表时间:2018-03-23

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏深入浅出区块链技术

分析比特币网络:一种去中心化、点对点的网络架构

14511
来自专栏汇智网教程

以太坊开发语言solidity简介

2949
来自专栏智能计算时代

超级账本项目:架构设计

image.png 架构设计 整个架构如下图所示。 ? 包括三大组件:区块链服务(Blockchain)、链码服务(Chaincode)、成员权限管理(Memb...

3184
来自专栏SAP最佳业务实践

SAP最佳业务实践:FI–资产会计(162)-2资产主数据

4 流程步骤 4.1 主数据维护 固定资产是企业拥有的对象、权限或其他项目,旨在长期使用并可在资产负债表中个别标识。维护固定资产包含创建、更改和显示资产主记录...

3466
来自专栏极客编程

如何开发创建ERC20以太坊代币

可以把ERC20简单理解成以太坊上的代币协议,所有基于以太坊开发的代币合约都遵守这个协议。遵守这些协议的代币我们可以认为是标准化的代币,而标准化带来的好处是兼容...

1181
来自专栏博岩Java大讲堂

简易版出款系统架构

2635
来自专栏程序猿DD

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

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

36912
来自专栏极客编程

用solidity语言开发代币智能合约

智能合约开发是以太坊编程的核心之一,而代币是区块链应用的关键环节,下面我们来用solidity语言开发一个代币合约的实例,希望对大家有帮助。

1522
来自专栏汇智网教程

以太坊智能合约示例

1K10
来自专栏Seebug漏洞平台

金钱难寐,大盗独行——以太坊 JSON-RPC 接口多种盗币手法大揭秘

2010年,Laszlo 使用 10000 个比特币购买了两张价值25美元的披萨被认为是比特币在现实世界中的第一笔交易。

1022

扫码关注云+社区

领取腾讯云代金券