1 使用web3j发起交易的俩种方式
使用web3j封装的json-RPC方法来访问geth客户端,并且向geth端发起交易,可以有俩种方式方式来发起交易的方法。方式1,用户解锁用的keyStore文件保存在geth节点上,用户使用解锁账户的方式发起交易,这种方式适用于中心化的方式比如交易所。方式2,用户的keyStore文件存在本地,用户使用钱包文件给交易签名的方式来发起交易,这种方式适用于DApp方式比如imToken等。
2 使用解锁方式发起交易
解锁方式发起交易,用户的钱包文件存在geth节点,发起交易时要先使用密码解锁账户,然后再发起交易。使用该方式来转账以太坊的函数可以写成:
//以太坊转账
//from:转出方账户
//password:转出方密码
//addrTo:收款账户
//value:转账额
public String transferEth(String from,String password,String to,BigInteger value) throws Exception
{
EthGetTransactionCount ethGetTransactionCount = ethClient.ethGetTransactionCount(
from, DefaultBlockParameterName.LATEST).sendAsync().get();
BigInteger nonce = ethGetTransactionCount.getTransactionCount();
PersonalUnlockAccount personalUnlockAccount = ethClient.personalUnlockAccount(from,password).send();
if (personalUnlockAccount.accountUnlocked())//解锁账户,需要钱包文件存在要访问的geth节点上
{
BigInteger gasPrice = Contract.GAS_PRICE;
//BigInteger gasPrice = new BigInteger("12000000000000");
BigInteger gasLimit = new BigInteger("90000");//Contract.GAS_LIMIT.divide(new BigInteger("2"));
synchronized(TestLocal.class) {
Transaction transaction = Transaction.createEtherTransaction(from,nonce,gasPrice,gasLimit,to,value);
EthSendTransaction transactionResponse = ethClient.ethSendTransaction(transaction).sendAsync().get();;
if(transactionResponse.hasError()){
String message=transactionResponse.getError().getMessage();
System.out.println("transaction failed,info:"+message);
Utils.writeFile("F:/testErr.txt","transaction failed,info:"+message);
return message;
}else{
String hash=transactionResponse.getTransactionHash();
EthGetTransactionReceipt send = ethClient.ethGetTransactionReceipt(hash).send();
System.out.println("transaction from "+from+" to "+to+" amount:"+value);
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Utils.writeFile("F:/log1.txt","transaction from "+from+" to "+to+" amount:"+value+" time:"+df.format(new Date()));
//use this code to get gasUsed and gasPrice
BigInteger gas_quility = ethClient.ethEstimateGas(transaction).send().getAmountUsed();
BigInteger gas_price = ethClient.ethGasPrice().send().getGasPrice();
BigInteger bgasUsed = gas_quility.multiply(gas_price);
BigDecimal gasUsed = Convert.fromWei(bgasUsed.toString(),Convert.Unit.ETHER);
System.out.println("transaction gas_quility:"+gas_quility+",gas_price:"+gas_price+",gasUsed:"+gasUsed);
return hash;
}
}
}
return null;
}
使用该方式来发起智能合约转账的方式:
//调用Test智能合约的算法函数来批量转账以太币
//fromAddress:转出方地址 toAddressList:转入方地址列表
//scoresList:分数列表 sum:分母 amount:分配额度,转出金额=ratio*amount/sum
//password:fromAddress的密码 coinTypeAddress:合约地址
public String multiTransferEther_Test(List<Address> toAddressList, List<Uint256> moneyList,BigInteger sum,String fromAddress,String password, String coinTypeAddress) throws Exception{
EthGetTransactionCount ethGetTransactionCount = ethClient.ethGetTransactionCount(
fromAddress, DefaultBlockParameterName.LATEST).sendAsync().get();
BigInteger nonce = ethGetTransactionCount.getTransactionCount();
if(gNoce == null)
gNoce = nonce;
BigInteger gasPrice = Contract.GAS_PRICE;
//BigInteger gasLimit = Contract.GAS_LIMIT.divide(new BigInteger("5"));
BigInteger gasLimit = new BigInteger("90000");
List<Type> inputParameters = new ArrayList<>();
inputParameters.add(new DynamicArray(toAddressList));
inputParameters.add(new DynamicArray(moneyList));
inputParameters.add(new Uint256(sum));
Function function = new Function("batchTransferEther",
inputParameters,
Collections.<TypeReference<?>>emptyList());
String functionEncoder = FunctionEncoder.encode(function);
PersonalUnlockAccount personalUnlockAccount = ethClient.personalUnlockAccount(fromAddress,password).send();
if (personalUnlockAccount.accountUnlocked()) {//解锁账户,需要钱包文件存在要访问的geth节点
// send a transaction
Transaction transaction = Transaction.createFunctionCallTransaction(
fromAddress, gNoce, gasPrice,
gasLimit, coinTypeAddress, new BigInteger("0"),
functionEncoder);
gNoce = gNoce.add(new BigInteger("1"));
EthSendTransaction transactionResponse =
ethClient.ethSendTransaction(transaction).sendAsync().get();
if(transactionResponse.hasError()){
String message=transactionResponse.getError().getMessage();
System.out.println("transaction failed,info:"+message);
return message;
}else{
String hash=transactionResponse.getTransactionHash();
return hash;
}
}
return null;
}
3 使用钱包文件签名的方式发起交易
使用这种方式需要钱包文件保存在调用端本地,先加载钱包文件来生成钱包许可对象,然后使用钱包许可对象来对只读型交易进行签名。使用该方式发起以太坊转账的交易如下:
//本地调用keystore文件转账方式
public void localSendEther(String from,String password,String keyStore,String to,BigInteger value) throws Exception
{
//加载本地KeyStore文件生成Credentials对象
Credentials credentials = WalletUtils.loadCredentials(password,keyStore);
EthGetTransactionCount ethGetTransactionCount = ethClient.ethGetTransactionCount(
from, DefaultBlockParameterName.LATEST).sendAsync().get();
BigInteger nonce = ethGetTransactionCount.getTransactionCount();
BigInteger gasPrice = new BigInteger("120000000000");
BigInteger gasLimit = Contract.GAS_LIMIT.divide(new BigInteger("2"));
//生成RawTransaction交易对象
RawTransaction rawTransaction = RawTransaction.createTransaction(nonce,gasPrice,gasLimit,to,value,"abcde123");//可以额外带数据
//使用Credentials对象对RawTransaction对象进行签名
byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction,credentials);
String hexValue = Numeric.toHexString(signedMessage);
EthSendTransaction ethSendTransaction = ethClient.ethSendRawTransaction(hexValue).sendAsync().get();
String transactionHash = ethSendTransaction.getTransactionHash();
if(ethSendTransaction.hasError())
{
String message=ethSendTransaction.getError().getMessage();
System.out.println("transaction failed,info:"+message);
Utils.writeFile("F:/testErr.txt","transaction failed,info:"+message);
}
else
{
String hash=ethSendTransaction.getTransactionHash();
EthGetTransactionReceipt send = ethClient.ethGetTransactionReceipt(hash).send();
System.out.println("transaction from "+from+" to "+to+" amount:"+value);
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Utils.writeFile("F:/log1.txt","transaction from "+from+" to "+to+" amount:"+value+" time:"+df.format(new Date()));
}
}
转账以太坊还有一种不用设置Nonce的简单方式:
//本地调用keystore文件转账方式,不用设置Nonce和交易费用,相当于geth客户端的eth.sendTransaction
public String localTransferEther(String password,String keyStore,String to,BigInteger value) throws Exception
{
Credentials credentials = WalletUtils.loadCredentials(password,keyStore);
try{
TransactionReceipt transactionReceipt = Transfer.sendFunds(ethClient, credentials, to,
new BigDecimal(value), Convert.Unit.WEI).send();
return transactionReceipt.getTransactionHash();
}catch (Exception e)//转账失败会打印错误信息
{
System.out.println(e);
return e.toString();
}
}
对智能合约转账进行签名的函数:
//在本地调用智能合约实现批量转账
public void multiTransferEtherLocal(List<Address> toAddressList, List<Uint256> scoresList, BigInteger sum,String from,String keyStore,String password, String contractAddress) throws Exception
{
Credentials credentials = WalletUtils.loadCredentials(password,keyStore);
EthGetTransactionCount ethGetTransactionCount = ethClient.ethGetTransactionCount(
from, DefaultBlockParameterName.LATEST).sendAsync().get();
BigInteger nonce = ethGetTransactionCount.getTransactionCount();
//BigInteger gasPrice = Contract.GAS_PRICE;
BigInteger gasPrice = new BigInteger("12000000000000");
BigInteger gasLimit = new BigInteger("90000");
List<Type> inputParameters = new ArrayList<>();
inputParameters.add(new DynamicArray(toAddressList));
inputParameters.add(new DynamicArray(scoresList));
inputParameters.add(new Uint256(sum));
Function function = new Function("batchTransferEther",
inputParameters,
Collections.<TypeReference<?>>emptyList());
String functionEncoder = FunctionEncoder.encode(function);
RawTransaction transaction = RawTransaction.createTransaction(nonce,gasPrice,gasLimit,contractAddress,functionEncoder);
byte[] signedMessage = TransactionEncoder.signMessage(transaction,credentials);
String hexValue = Numeric.toHexString(signedMessage);
EthSendTransaction ethSendTransaction = ethClient.ethSendRawTransaction(hexValue).sendAsync().get();
String transactionHash = ethSendTransaction.getTransactionHash();
if(ethSendTransaction.hasError())
{
String message=ethSendTransaction.getError().getMessage();
System.out.println("transaction failed,info:"+message);
Utils.writeFile("F:/testErr.txt","transaction failed,info:"+message);
}
else
{
String hash=ethSendTransaction.getTransactionHash();
EthGetTransactionReceipt send = ethClient.ethGetTransactionReceipt(hash).send();
System.out.println("multiTransferEtherLocal send success");
}
}