web3j實現離線發起交易
阿新 • • 發佈:2019-01-02
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");
}
}