调用方法流程
- 方法包括方法名,参数 返回值 (Function)
- 对方法进行编码(FunctionEncoder.encode)
- 根据none pirce limit address 方法编码 创建交易信息(RawTransaction.createTransaction)
- 签名交易信息 (TransactionEncoder.signMessage)
- 并转成16进制数据 (Numeric.toHexString)
- 发送交易
- 通过交易原数据和签名拿到hash(TransactionUtils.generateTransactionHashHexEncoded)
Function
public Function(String name, List<Type> inputParameters, List<TypeReference<?>> outputParameters) { this.name = name; this.inputParameters = inputParameters; this.outputParameters = Utils.convert(outputParameters); }
RawTransaction
protected RawTransaction(BigInteger nonce, BigInteger gasPrice, BigInteger gasLimit, String to, BigInteger value, String data, BigInteger gasPremium, BigInteger feeCap) { this.nonce = nonce; this.gasPrice = gasPrice; this.gasLimit = gasLimit; this.to = to; this.value = value; this.data = data != null ? Numeric.cleanHexPrefix(data) : null; this.gasPremium = gasPremium; this.feeCap = feeCap; }
Credentials
public static Credentials create(ECKeyPair ecKeyPair) { String address = Numeric.prependHexPrefix(Keys.getAddress(ecKeyPair)); return new Credentials(ecKeyPair, address); }
signMessage
public static byte[] signMessage(RawTransaction rawTransaction, Credentials credentials) { byte[] encodedTransaction = encode(rawTransaction); Sign.SignatureData signatureData = Sign.signMessage(encodedTransaction, credentials.getEcKeyPair()); return encode(rawTransaction, signatureData); }
generateTransactionHash
public static byte[] generateTransactionHash(RawTransaction rawTransaction, Credentials credentials) { byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials); return Hash.sha3(signedMessage); }
toHexString
public static String toHexString(byte[] input) { return toHexString(input, 0, input.length, true); } public static String toHexString(byte[] input, int offset, int length, boolean withPrefix) { StringBuilder stringBuilder = new StringBuilder(); if (withPrefix) { stringBuilder.append("0x"); } for(int i = offset; i < offset + length; ++i) { stringBuilder.append(String.format("%02x", input[i] & 255)); } return stringBuilder.toString(); }
RawTransactionManager
public EthSendTransaction sendTransaction(BigInteger gasPrice, BigInteger gasLimit, String to, String data, BigInteger value, boolean constructor) throws IOException { BigInteger nonce = this.getNonce(); RawTransaction rawTransaction = RawTransaction.createTransaction(nonce, gasPrice, gasLimit, to, value, data); return this.signAndSend(rawTransaction); }
合约执行流程
//1 this.executeTransaction(function); //2 this.executeTransaction(function, BigInteger.ZERO); //3 this.executeTransaction(FunctionEncoder.encode(function), weiValue, function.getName()); //4 weiValue如果是转eth就是数量 如果是调用合约方法就是data this.executeTransaction(data, weiValue, funcName, false); //5 TransactionReceipt receipt = this.send(this.contractAddress, data, weiValue, this.gasProvider.getGasPrice(funcName), this.gasProvider.getGasLimit(funcName), constructor); //6 this.transactionManager.executeTransaction(gasPrice, gasLimit, to, data, value, constructor); //7 this.sendTransaction(gasPrice, gasLimit, to, data, value, constructor);
FastRawTransactionManager
维护了一个nonce 避免每次发送请求都区获取nonce
可以最大限度地减少向节点发送RPC请求的次数,从而提高交易发送的响应速度。
NoOpProcessor
使用NoOpProcessor的一个常见场景是,当我们只需要发送交易,而不关心区块事件或其他通知时,可以将其设置为事件处理器,避免不必要的事件处理开销。
这允许调用方对提交到网络的交易拥有交易哈希。
///使用7 public static TransactionManager getTxManager(Credentials credentials, Web3j web3j){ NoOpProcessor processor = new NoOpProcessor(web3j); return new FastRawTransactionManager(web3j, credentials, processor); } ///使用 this.sendTransaction(gasPrice, gasLimit, to, FunctionEncoder.encode(function), BigInteger.ZERO, false); public static String sendEthTransaction(Credentials credentials, Web3j web3j,BigInteger weiValue,BigInteger gasPrice, BigInteger gasLimit, String to){ try { return getTxManager(credentials,web3j).sendTransaction(gasPrice, gasLimit, to, "", weiValue, false).getTransactionHash(); } catch (IOException e) { throw new RuntimeException(e); } }
代码
@Throws( IOException::class, ExecutionException::class, InterruptedException::class ) fun signTokenTransaction( amount: String, to: String, privateKey: String, coinAddress: String, decimals: Int, nonce: BigInteger ): Pair<String, String> { //支付的矿工费 val gasPrice = getWeb3j().ethGasPrice().send().gasPrice val gasLimit = BigInteger("60000") val credentials = Credentials.create(privateKey) val amountWei = BigDecimal.TEN.pow(decimals).multiply(BigDecimal(amount)).toBigInteger() //封装转账交易 val function = Function( "transfer", listOf<Type<*>>( Address(to), Uint256(amountWei) ), emptyList() ) val data = FunctionEncoder.encode(function) //签名交易 val rawTransaction = RawTransaction.createTransaction( nonce, gasPrice, gasLimit, coinAddress, data ) val signMessage = TransactionEncoder.signMessage(rawTransaction, credentials) val hexValue = Numeric.toHexString(signMessage) val hash = TransactionUtils.generateTransactionHashHexEncoded( rawTransaction, Credentials.create(privateKey) ) return hexValue to hash //广播交易 // return getWeb3j().ethSendRawTransaction(Numeric.toHexString(signMessage)).sendAsync().get() // .transactionHash }