前面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
如果对你有帮助记得点赞