Java连接区块链与调用智能合约

一、 编写智能合约

test.sol

pragma solidity ^0.4.4;
contract test {
    
    function multiply(uint a) public pure returns(uint d){
        return a*7;
    }
    
    function sayHello() public pure returns(string){
        return "hello";
    }
}

二、 编译合约

  • <1> 编译生成 bin 文件 test.bin
solc --bin test.sol -o ./
  • <2> 编译生成abi文件 test.abi
solc --abi test.sol -o ./
  • 说明

    • -o 意思是生成目标文件,如果不加 -o 则生成的目标代码直接在控制台输出;
    • 生成目标文件是为了使用web3j 生成java 文件做准备
  • <3> 使用 web3j 生成java 合约文件

web3j solidity generate --javaTypes --binFile=test.bin --abiFile=test.abi -o ./ --package='myContract'
  • 说明
    • –binFile 是合约生成的 .bin 文件, 合约的类名.bin
    • –abiFile 是合约生成的 .abi 文件, 合约的类名.abi
    • -o 后加生成的java文件要保存的位置
    • –package 是java 文件所属的包,会在目标文件下创建对应的目录
    • 创建完成后,去 ./myContract 目录下即可找到生成的 test.java 文件
    • 生成的java文件是合约的类名.java 而不是文件名.java

三、 启动私有链部署合约

服务端

geth --networkid 123 --datadir blockDataA/ --rpc --rpcaddr 100.80.128.173 --rpcport 8545 --port 3000

客户端

geth attach ipc:geth.ipc

部署合约

// 合约的二进制码赋值
> var binCode="0x608060405234801561001057600080fd5b50610198806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063c6888fa114610051578063ef5fb05b14610092575b600080fd5b34801561005d57600080fd5b5061007c60048036038101908080359060200190929190505050610122565b6040518082815260200191505060405180910390f35b34801561009e57600080fd5b506100a761012f565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100e75780820151818401526020810190506100cc565b50505050905090810190601f1680156101145780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6000600782029050919050565b60606040805190810160405280600581526020017f68656c6c6f0000000000000000000000000000000000000000000000000000008152509050905600a165627a7a723058202f7c3459d5edbb203e2e7a07f984b0e5792d8340e713162d3d2b017ca45ab4ea0029"
// 合约的abi赋值
> var abiCode=[{"constant":true,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"sayHello","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"pure","type":"function"}]
// 解锁挖矿账户
> personal.unlockAccount(personal.listAccounts[0])
// 预估创建合约需要的gas
> eth.estimateGas({data:binCode})
// 部署
> var abiContract = eth.contract(abiCode)
> var contract = abiContract.new({from:personal.listAccounts[0],data:binCode,gas:180000})
// 查看待办事项
> txpool.status
// 开始挖矿
> miner.start()
> miner.stop()
// 查看合约地址
> contract.address

// 调用合约方法
> contract.sayHello()
> contract.multiplay(5)

四、 java 代码

  • 源码gitHub地址:https://github.com/godloveayuan/EthereumTest
  • 分支: godloveayuan-20190520

1. PMO 依赖


        
            org.web3j
            core
            
            
            
            4.3.0
        
        
            org.web3j
            parity
            4.3.0
        
        
            org.web3j
            crypto
            4.3.0
        

        
            org.web3j
            utils
            4.3.0
        
        
            org.web3j
            codegen
            4.3.0
        
        
            org.web3j
            tuples
            4.3.0
        

2. 拷贝java合约文件

将web3j编译生成的 test.java 拷贝进项目

3. web3j 客户端

package myEthereum;

import org.web3j.protocol.Web3j;
import org.web3j.protocol.http.HttpService;

/**
 * @Author: pengs.yuan
 * @Date: 19-5-22
 * @Description:
 */
public class Web3JClient {

    private static String url = "http://100.80.128.173:8545/";

    private Web3JClient(){}

    private volatile static Web3j web3j;

    public static Web3j getClient(){
        if(web3j==null){
            synchronized (Web3JClient.class){
                if(web3j==null){
                    web3j = Web3j.build(new HttpService(url));
                }
            }
        }
        return web3j;
    }
}

  • 说明:
    • url 后面的port 是启动私有链时的 rpcport 参数

4. parity客户端

package myEthereum;

import org.web3j.protocol.http.HttpService;
import org.web3j.protocol.parity.Parity;

/**
 * @Author: pengs.yuan
 * @Date: 19-5-22
 * @Description:
 */
public class ParityClient {
    private static String url = "http://100.80.128.173:8545/";

    private ParityClient(){}

    private static class ClientHolder{
        private static final Parity parity = Parity.build(new HttpService(url));
    }

    public static final  Parity getParity(){
        return ClientHolder.parity;
    }
}
  • 说明
    • web3j 客户端和parity客户端使用一个即可,能使用web3j 客户端时,尽量使用web3j客户端
    • org.web3j.core 2.2.1 版本的包中包含了 Parity 类,但是 4.3.0 版本的包中不包含,需要单独引入依赖

5. 连接区块链查询账户及账户下的余额

/**
     * 查询所有的账户id
     *
     * @return
     */
    public static List getAccountList() {

        try {
           /* // 使用 parity 客户端
            PersonalListAccounts personalListAccounts = parity.personalListAccounts().send();
            List accountIdList = personalListAccounts.getAccountIds();*/

            // 使用web3j 客户端
            EthAccounts ethAccounts = web3j.ethAccounts().send();
            List accountIdList = ethAccounts.getAccounts();
            return accountIdList;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据账户id查询余额
     *
     * @param accountId
     * @return
     */
    public static BigInteger getBalance(String accountId) {
        try {
            DefaultBlockParameter defaultBlockParameter = new DefaultBlockParameterNumber(web3j.ethBlockNumber().send().getBlockNumber());

            // 使用parity连接
            // EthGetBalance ethGetBalance = parity.ethGetBalance(accountId, defaultBlockParameter).send();

            // 使用web3j连接
            EthGetBalance ethGetBalance = web3j.ethGetBalance(accountId, defaultBlockParameter).send();

            if (ethGetBalance != null) {
                return ethGetBalance.getBalance();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

6. 调用合约

/**
     * 调用合约的方法
     */
    public static void callContract() {
        String contractAddress = "0x602738fcf0b1fdbb73fb772e198f6544ff3632aa";

        try {
            // 获取第一个账户
            String minerBaseAccount = web3j.ethAccounts().send().getAccounts().get(0);
            System.out.println("minerBaseAccount:" + minerBaseAccount);

            Credentials credentials = Credentials.create(minerBaseAccount);

            // 合约对象
            Test testContract = new Test(contractAddress, web3j, credentials, Contract.GAS_PRICE, Contract.GAS_PRICE);
            String sayHello = testContract.sayHello().send();
            System.out.println("sayHello: " + sayHello);

            BigInteger multiply = testContract.multiply(BigInteger.valueOf(6)).send();
            System.out.println("multiply:" + multiply);

        } catch (Exception e) {
            System.out.println("exception");
        }
    }

你可能感兴趣的:(区块链,区块链)