美文网首页
web3j函数回调使用详解

web3j函数回调使用详解

作者: Gason_d796 | 来源:发表于2020-01-06 09:22 被阅读0次

前面solc和web3编译和加载代码的步骤参考其他文章。

web3j中deploy代码

solidity代码

pragma solidity >0.4.18;

contract SimpleVoting {

    bytes32[] public candidateList;
    mapping (bytes32 => uint8) public votesReceived;
    
    constructor(bytes32[]  memory candidateNames) public {
        candidateList = candidateNames;
    }

    function voteForCandidate(bytes32 candidate) public {
        require(validCandidate(candidate));
        votesReceived[candidate] += 1;
    }

    function totalVotesFor(bytes32 candidate) view public returns (uint8) {
        require(validCandidate(candidate));
        return votesReceived[candidate];
    }

    function validCandidate(bytes32 candidate) view public returns (bool) {
        for(uint8 i = 0; i < candidateList.length; i++) {
            if(candidateList[i] == candidate)
                return true;
        }
        return false;
    }
}

编译后的java代码(有些部分需要手动修改,后文会写道):

package com.gason.blockchain.eth;

import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collector;
import java.util.stream.Collectors;

import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.TypeReference;
import org.web3j.abi.datatypes.Bool;
import org.web3j.abi.datatypes.Function;
import org.web3j.abi.datatypes.Type;
import org.web3j.abi.datatypes.generated.Bytes32;
import org.web3j.abi.datatypes.generated.Uint8;
import org.web3j.crypto.Credentials;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.RemoteCall;
import org.web3j.protocol.core.RemoteFunctionCall;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.tx.Contract;
import org.web3j.tx.TransactionManager;
import org.web3j.tx.gas.ContractGasProvider;

/**
 * <p>Auto generated code.
 * <p><strong>Do not modify!</strong>
 * <p>Please use the <a href="https://docs.web3j.io/command_line.html">web3j command line tools</a>,
 * or the org.web3j.codegen.SolidityFunctionWrapperGenerator in the
 * <a href="https://github.com/web3j/web3j/tree/master/codegen">codegen module</a> to update.
 *
 * <p>Generated with web3j version 4.5.5.
 */
@SuppressWarnings("rawtypes")
public class SimpleVoting extends Contract {
    private static final String BINARY = "";

    public static final String FUNC_CANDIDATELIST = "candidateList";

    public static final String FUNC_TOTALVOTESFOR = "totalVotesFor";

    public static final String FUNC_VALIDCANDIDATE = "validCandidate";

    public static final String FUNC_VOTEFORCANDIDATE = "voteForCandidate";

    public static final String FUNC_VOTESRECEIVED = "votesReceived";

    @Deprecated
    protected SimpleVoting(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) {
        super(BINARY, contractAddress, web3j, credentials, gasPrice, gasLimit);
    }

    protected SimpleVoting(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) {
        super(BINARY, contractAddress, web3j, credentials, contractGasProvider);
    }

    @Deprecated
    protected SimpleVoting(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) {
        super(BINARY, contractAddress, web3j, transactionManager, gasPrice, gasLimit);
    }

    protected SimpleVoting(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) {
        super(BINARY, contractAddress, web3j, transactionManager, contractGasProvider);
    }

    public RemoteFunctionCall<Bytes32> candidateList(BigInteger param0) {
        final Function function = new Function(
                FUNC_CANDIDATELIST,
                Arrays.<Type>asList(new org.web3j.abi.datatypes.generated.Uint256(param0)),
                Arrays.<TypeReference<?>>asList(new TypeReference<Bytes32>() {
                }));
        return executeRemoteCallSingleValueReturn(function);
    }

    public RemoteFunctionCall<Uint8> totalVotesFor(String candidate) {
        final Function function = new Function(
                FUNC_TOTALVOTESFOR,
                Arrays.<Type>asList(new org.web3j.abi.datatypes.generated.Bytes32(StrToByte(candidate))),
                Arrays.<TypeReference<?>>asList(new TypeReference<Uint8>() {
                }));
        return executeRemoteCallSingleValueReturn(function);
    }

    public RemoteFunctionCall<Bool> validCandidate(String candidate) {
        final Function function = new Function(
                FUNC_VALIDCANDIDATE,
                Arrays.<Type>asList(new org.web3j.abi.datatypes.generated.Bytes32(StrToByte(candidate))),
                Arrays.<TypeReference<?>>asList(new TypeReference<Bool>() {
                }));
        return executeRemoteCallSingleValueReturn(function);
    }

    public RemoteFunctionCall<TransactionReceipt> voteForCandidate(String candidate) {
        final Function function = new Function(
                FUNC_VOTEFORCANDIDATE,
                Arrays.<Type>asList(new org.web3j.abi.datatypes.generated.Bytes32(StrToByte(candidate))),
                Collections.<TypeReference<?>>emptyList());
        return executeRemoteCallTransaction(function);
    }

    public RemoteFunctionCall<TransactionReceipt> votesReceived(byte[] param0) {
        final Function function = new Function(
                FUNC_VOTESRECEIVED,
                Arrays.<Type>asList(new org.web3j.abi.datatypes.generated.Bytes32(param0)),
                Collections.<TypeReference<?>>emptyList());
        return executeRemoteCallTransaction(function);
    }

    @Deprecated
    public static SimpleVoting load(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) {
        return new SimpleVoting(contractAddress, web3j, credentials, gasPrice, gasLimit);
    }

    @Deprecated
    public static SimpleVoting load(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) {
        return new SimpleVoting(contractAddress, web3j, transactionManager, gasPrice, gasLimit);
    }

    public static SimpleVoting load(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) {
        return new SimpleVoting(contractAddress, web3j, credentials, contractGasProvider);
    }

    public static SimpleVoting load(String contractAddress, Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) {
        return new SimpleVoting(contractAddress, web3j, transactionManager, contractGasProvider);
    }

    public static RemoteCall<SimpleVoting> deploy(Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider, List<byte[]> candidateNames) {
        String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.<Type>asList(new org.web3j.abi.datatypes.DynamicArray<org.web3j.abi.datatypes.generated.Bytes32>(
                org.web3j.abi.datatypes.generated.Bytes32.class,
                org.web3j.abi.Utils.typeMap(candidateNames, org.web3j.abi.datatypes.generated.Bytes32.class))));
        return deployRemoteCall(SimpleVoting.class, web3j, credentials, contractGasProvider, BINARY, encodedConstructor);
    }

    public static RemoteCall<SimpleVoting> deploy(Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider, List<byte[]> candidateNames) {
        String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.<Type>asList(new org.web3j.abi.datatypes.DynamicArray<org.web3j.abi.datatypes.generated.Bytes32>(
                org.web3j.abi.datatypes.generated.Bytes32.class,
                org.web3j.abi.Utils.typeMap(candidateNames, org.web3j.abi.datatypes.generated.Bytes32.class))));
        return deployRemoteCall(SimpleVoting.class, web3j, transactionManager, contractGasProvider, BINARY, encodedConstructor);
    }

    @Deprecated
    public static RemoteCall<SimpleVoting> deploy(Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit, List<byte[]> candidateNames) {
        String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.<Type>asList(new org.web3j.abi.datatypes.DynamicArray<org.web3j.abi.datatypes.generated.Bytes32>(
                org.web3j.abi.datatypes.generated.Bytes32.class,
                org.web3j.abi.Utils.typeMap(candidateNames, org.web3j.abi.datatypes.generated.Bytes32.class))));
        return deployRemoteCall(SimpleVoting.class, web3j, credentials, gasPrice, gasLimit, BINARY, encodedConstructor);
    }

    @Deprecated
    public static RemoteCall<SimpleVoting> deploy(Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit, List<byte[]> candidateNames) {
        String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.<Type>asList(new org.web3j.abi.datatypes.DynamicArray<org.web3j.abi.datatypes.generated.Bytes32>(
                org.web3j.abi.datatypes.generated.Bytes32.class,
                org.web3j.abi.Utils.typeMap(candidateNames, org.web3j.abi.datatypes.generated.Bytes32.class))));
        return deployRemoteCall(SimpleVoting.class, web3j, transactionManager, gasPrice, gasLimit, BINARY, encodedConstructor);
    }

    public static RemoteCall<SimpleVoting> deployByString(Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider, List<String> candidateNames) {
        List<byte[]> candidateNamesByte = candidateNames.stream().map(val -> StrToByte(val)).collect(Collectors.toList());
        String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.<Type>asList(new org.web3j.abi.datatypes.DynamicArray<org.web3j.abi.datatypes.generated.Bytes32>(
                org.web3j.abi.datatypes.generated.Bytes32.class,
                org.web3j.abi.Utils.typeMap(candidateNamesByte, org.web3j.abi.datatypes.generated.Bytes32.class))));
        return deployRemoteCall(SimpleVoting.class, web3j, credentials, contractGasProvider, BINARY, encodedConstructor);
    }

    public static byte[] StrToByte(String str) {
        byte[] byteValue = str.getBytes();
        byte[] byteValueLen32 = new byte[32];
        System.arraycopy(byteValue, 0, byteValueLen32, 0, byteValue.length);
        return byteValueLen32;
    }
}

使用java进行部署:

      String pk="";//写你私钥
       Web3j web3 = Web3j.build(new HttpService());
        ContractGasProvider contractGasProvider = new DefaultGasProvider();
        Credentials credentials = Credentials.create(pk);
        List<String> candidateNames = Arrays.asList("Bob", "Tom", "Jerry");
        SimpleVoting registryContract = SimpleVoting.deployByString(web3, credentials, contractGasProvider, candidateNames).sendAsync().get();
       // 合约地址,记得保存
        System.out.println(registryContract.getContractAddress());

web3j中的方法调用

  • 注意:solidity中的byte32[]类型与Java中String的转换,String需要转为byte32[]
public static byte[] StrToByte(String str) {
        byte[] byteValue = str.getBytes();
        byte[] byteValueLen32 = new byte[32];
        System.arraycopy(byteValue, 0, byteValueLen32, 0, byteValue.length);
        return byteValueLen32;
    }
  • 无返回值
    solidity代码:
   function voteForCandidate(bytes32 candidate) public {
        require(validCandidate(candidate));
        votesReceived[candidate] += 1;
    }

java编译后:
executeRemoteCallTransaction无返回值,Function中第一个参数为函数名,第二个为输入参数集合,第二为返回参数集合,如果无返回参数,就输入 Collections.<TypeReference<?>>emptyList()

    public RemoteFunctionCall<TransactionReceipt> voteForCandidate(String candidate) {
        final Function function = new Function(
                "voteForCandidate",
                Arrays.<Type>asList(new org.web3j.abi.datatypes.generated.Bytes32(StrToByte(candidate))),
                Collections.<TypeReference<?>>emptyList());
        return executeRemoteCallTransaction(function);
    }

调用:

      Web3j web3 = Web3j.build(new HttpService());  // defaults to http://localhost:8545/
        ContractGasProvider contractGasProvider = new DefaultGasProvider();
      //PK为你的私钥
        Credentials credentials = Credentials.create(PK);
      //address为你之前部署后返回的合约地址
        SimpleVoting registryContract = SimpleVoting.load(address, web3, credentials, contractGasProvider);
        registryContract.voteForCandidate("Bob").sendAsync().get();
  • 单个参数返回
    solidity:
 function totalVotesFor(bytes32 candidate) view public returns (uint8) {
        require(validCandidate(candidate));
        return votesReceived[candidate];
    }

java编译后,executeRemoteCallSingleValueReturn为单个参数返回,

   public RemoteFunctionCall<Uint8> totalVotesFor(String candidate) {
        final Function function = new Function(
                "totalVotesFor",
                Arrays.<Type>asList(new org.web3j.abi.datatypes.generated.Bytes32(StrToByte(candidate))),
                Arrays.<TypeReference<?>>asList(new TypeReference<Uint8>() {
                }));
        return executeRemoteCallSingleValueReturn(function);
    }

调用:

        Web3j web3 = Web3j.build(new HttpService());  // defaults to http://localhost:8545/
        ContractGasProvider contractGasProvider = new DefaultGasProvider();
        Credentials credentials = Credentials.create(PK);
        SimpleVoting registryContract = SimpleVoting.load(address, web3, credentials, contractGasProvider);
        System.out.println(registryContract.totalVotesFor("Bob").sendAsync().get().getValue());
  • 多参数返回
    solidity代码:
pragma solidity >0.4.0;

// 官方文档众筹实现
// https://solidity.readthedocs.io/en/develop/types.html#structs

// 独立实现
contract CrowdFunding {

    // 众筹项目
    struct Fund {
        // 众筹地址
        address owner;
        // 众筹描述
        string desc;
        // 众筹目标
        uint goal;

        // 已筹金币
        uint coins;
        // 是否结束
        bool finished;

        // 捐赠人数
        uint recordCounts;
        // 捐赠记录
        mapping(uint => Record) records;
        // 原本使用 Record[] records 数组定义
        // 但是貌似目前版本尚不支持
        // 于是将 数组 拆分成 长度 + 映射
        // https://solidity.readthedocs.io/en/develop/types.html#mappings
    }

    // 捐赠记录
    struct Record {
        // 捐赠成员
        address member;
        // 捐赠金币
        uint coin;
        // 捐赠时间
        uint time;
    }

    // 众筹地址列表
    Fund[] funds;

    // 获取众筹项目数量
    function getFundCount() public view returns (uint) {
        return funds.length;
    }

    // 获取众筹项目信息
    // 参数:项目编号
    // 返回:众筹地址 众筹描述 众筹目标 已筹金币 是否结束
    function getFundInfo(uint fundIndex) public view returns (address, string memory, uint, uint, bool) {
        Fund storage fund = funds[fundIndex];
        return (fund.owner, fund.desc, fund.goal, fund.coins, fund.finished);
    }

    // 获取众筹捐赠人数
    function getRecordCount(uint fundIndex) public view returns (uint) {
        return funds[fundIndex].recordCounts;
    }

    // 获取众筹捐赠记录
    // 参数:项目编号 记录编号
    // 返回:捐赠成员 捐赠金币 捐赠时间
    function getRecordInfo(uint fundIndex, uint recordIndex) public view returns (address, uint, uint) {
        Record storage record = funds[fundIndex].records[recordIndex];
        return (record.member, record.coin, record.time);
    }

    // 为自己发起众筹
    function raiseFund(string memory info, uint goal) public {
        funds.push(Fund(msg.sender, info, goal, 0, false, 0));
    }

    // 为别人发送金币
    // https://solidity.readthedocs.io/en/latest/miscellaneous.html#modifiers
    // payable for functions: Allows them to receive Ether together with a call.
    function sendCoin(uint fundIndex) public payable {
        // 默认属性
        // msg.sender 转账账户
        // msg.value 转账数目
        // 智能合约默认单位 wei
        // 1 ether = 10^18 wei

        // 引用拷贝
        Fund storage fund = funds[fundIndex];
        require(!fund.finished);

        // 转账 失败自动退出
        address(uint256(fund.owner)).transfer(msg.value);

        // 更新众筹信息
        fund.coins += msg.value;
        fund.records[fund.recordCounts++] = Record(msg.sender, msg.value, now);
        fund.finished = fund.coins >= fund.goal * 1 ether ? true : false;
    }

    // 回退函数 防止抛出异常
    // https://solidity.readthedocs.io/en/latest/contracts.html#fallback-function
    // if you want your contract to receive Ether, you have to implement a fallback function.
// 后面两个函数是最新版本编译器所需要的,可能跟网上一些不一样
         fallback () external  payable  { }
         receive() external payable {  }
}

java编译后(部分通过手工修改):

package com.gason.blockchain.eth;

import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.TypeReference;
import org.web3j.abi.datatypes.*;
import org.web3j.abi.datatypes.generated.Uint256;
import org.web3j.crypto.Credentials;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.RemoteCall;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.tx.Contract;
import org.web3j.tx.gas.ContractGasProvider;
import org.web3j.utils.Convert;

import java.math.BigInteger;
import java.util.Arrays;
import java.util.List;

public class CrowdFundingContract extends Contract implements CrowdFundingInterface {
    private static final String BINARY = "";

    /**
     * CrowdFunding合约
     *
     * @param contractAddress 合约地址
     * @param web3j           RPC请求
     * @param credentials     钱包凭证
     * @param gasPrice        GAS价格
     * @param gasLimit        GAS上限
     */
    private CrowdFundingContract(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice,
                                 BigInteger gasLimit) {
        super(BINARY, contractAddress, web3j, credentials, gasPrice, gasLimit);
    }


    protected CrowdFundingContract(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) {
        super(BINARY, contractAddress, web3j, credentials, contractGasProvider);
    }
    /**
     * 部署合约
     *
     * @param web3j       RPC请求
     * @param credentials 钱包凭证
     * @param gasPrice    GAS价格
     * @param gasLimit    GAS上限
     * @return
     */
    public static RemoteCall<CrowdFundingContract> deploy(Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) {
        // 构造函数传参 NULL
        String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.<Type>asList());
        return deployRemoteCall(CrowdFundingContract.class, web3j, credentials, gasPrice, gasLimit, BINARY, encodedConstructor);
    }

    public static RemoteCall<CrowdFundingContract> deploy(Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) {
        return deployRemoteCall(CrowdFundingContract.class, web3j, credentials, contractGasProvider, BINARY, "");
    }

    /**
     * 加载合约
     *
     * @param contractAddress 合约地址
     * @param web3j           RPC请求
     * @param credentials     钱包凭证
     * @param gasPrice        GAS价格
     * @param gasLimit        GAS上限
     * @return
     */
    public static CrowdFundingContract load(String contractAddress, Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) {
        return new CrowdFundingContract(contractAddress, web3j, credentials, gasPrice, gasLimit);
    }

    public static CrowdFundingContract load(String contractAddress, Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) {
        return new CrowdFundingContract(contractAddress, web3j, credentials, contractGasProvider);
    }

    //////////////////////////////////////////
    //          crowdfunding.sol            //
    //////////////////////////////////////////

    /**
     * 获取众筹项目数量
     * rinfo.get(0).getValue().toString()
     * function getFundCount() public view returns (uint)
     */
    @Override
    public RemoteCall<Uint256> getFundCount() {
        Function function = new Function("getFundCount", Arrays.<Type>asList(),
                Arrays.<TypeReference<?>>asList(new TypeReference<Uint256>() {
                }));
        return executeRemoteCallSingleValueReturn(function);
    }

    /**
     * 获取众筹项目信息
     * function getFundInfo(uint fundIndex) public view returns (address, string, uint, uint, bool)
     */
    @Override
    public RemoteCall<List<Type>> getFundInfo(int fundIndex) {
        Function function = new Function("getFundInfo", Arrays.<Type>asList(new Uint256(fundIndex)),
                Arrays.<TypeReference<?>>asList(new TypeReference<Address>() {
                }, new TypeReference<Utf8String>() {
                }, new TypeReference<Uint256>() {
                }, new TypeReference<Uint256>() {
                }, new TypeReference<Bool>() {
                }));
        return executeRemoteCallMultipleValueReturn(function);
    }

    /**
     * 获取众筹捐赠人数
     * function getRecordCount(uint fundIndex) public view returns (uint)
     */
    @Override
    public RemoteCall<Uint256> getRecordCount(int fundIndex) {
        Function function = new Function("getRecordCount", Arrays.<Type>asList(new Uint256(fundIndex)),
                Arrays.<TypeReference<?>>asList(new TypeReference<Uint256>() {
                }));
        return executeRemoteCallSingleValueReturn(function);
    }

    /**
     * 获取众筹捐赠记录
     * function getRecordInfo(uint fundIndex, uint recordIndex) public view returns (address, uint, uint)
     */
    @Override
    public RemoteCall<List<Type>> getRecordInfo(int fundIndex, int recordIndex) {
        Function function = new Function("getRecordInfo", Arrays.<Type>asList(new Uint256(fundIndex), new Uint256(recordIndex)),
                Arrays.<TypeReference<?>>asList(new TypeReference<Address>() {
                }, new TypeReference<Uint256>() {
                }, new TypeReference<Uint256>() {
                }));
        return executeRemoteCallMultipleValueReturn(function);
    }

    /**
     * 为自己发起众筹
     * function raiseFund(string desc, uint goal) public
     */
    @Override
    public RemoteCall<TransactionReceipt> raiseFund(String desc, int goal) {
        Function function = new Function("raiseFund", Arrays.<Type>asList(new Utf8String(desc), new Uint256(goal)),
                Arrays.<TypeReference<?>>asList());
        return executeRemoteCallTransaction(function);
    }

    /**
     * 为别人发送金币
     * function sendCoin(uint fundIndex) public payable
     */
    @Override
    public RemoteCall<TransactionReceipt> sendCoin(int fundIndex, int coin) {
        Function function = new Function("sendCoin", Arrays.<Type>asList(new Uint256(fundIndex)),
                Arrays.<TypeReference<?>>asList());
        return executeRemoteCallTransaction(function, BigInteger.valueOf(coin).multiply(Convert.Unit.ETHER.getWeiFactor().toBigInteger()));
    }
}

调用:

        Web3j web3 = Web3j.build(new HttpService());  // defaults to http://localhost:8545/
        ContractGasProvider contractGasProvider = new DefaultGasProvider();
        Credentials credentials = Credentials.create(PK);
        CrowdFundingContract registryContract = CrowdFundingContract.load(address, web3, credentials, contractGasProvider);
        List<Type> outputs = registryContract.getFundInfo(0).sendAsync().get();
        System.out.println("address:" + outputs.get(0).toString());
        System.out.println("desc:" + outputs.get(1).toString());
        System.out.println("goal:" + Integer.parseInt(outputs.get(2).getValue().toString()));
        System.out.println("coins:" + new BigInteger(outputs.get(3).getValue().toString()).divide(Convert.Unit.ETHER.getWeiFactor().toBigInteger()).intValue());
        System.out.println("finished:" + Boolean.parseBoolean(outputs.get(4).getValue().toString()));

参考了:https://github.com/niyuelin1990/CrowdFunding
如果对你有帮助记得点赞

相关文章

网友评论

      本文标题:web3j函数回调使用详解

      本文链接:https://www.haomeiwen.com/subject/kiyhactx.html