Under the hood, the Web3J SmartContract Java Wrapper calculates the nonce by getting the number of transactions getTransactionCount
for the account (credential
).
EthGetTransactionCount ethGetTransactionCount = web3.ethGetTransactionCount(credentials.getAddress(), DefaultBlockParameterName.PENDING).send();
BigInteger nonce = ethGetTransactionCount.getTransactionCount();
If for some reasons, you want to manually set the nonce (because you're sending multiple parallel transactions I guess), it is not an easy task and you gonna have to replicate what web3j is doing behind the scene.
i. Some constants
final String privateKey = "48c2210576121c68883b2f96ae82cdf5fd845d99f4243b9c44651316accaac97"; // Dummy private key !!!
final String contractAddress = "0x5e417E6d4e15471912743e1173D5fD3a3617aD9f"; // Smart contract after deployment on Ganache
final BigInteger gasLimit = new BigInteger("6721975"); // Block gas limit (Ganache)
final BigInteger gasPrice = new BigInteger("20000000000"); // 20 gwei - Gas Price (Ganache)
ii. Connect to the node and initiate web3j
// Connect to the node
Web3j web3 = Web3j.build(new HttpService()); // defaults to http://localhost:8545/
iii. Read the private key
// Read Private Key
Credentials credentials = Credentials.create(privateKey)
iv. Calculate the transaction data
A transaction is constituted of several information like from
account, to
account, value
, gasPrice
, gasLimit
, nonce
and data
. data
in the case of a smart contact represents the encoding of the function, the parameter types and the parameters.
You can calculate data
like this:
// Extract the function from the Smart Contract wrapper generated by web3j cli
final Function function = new Function(
Counter.FUNC_INCREMENT,
Arrays.<Type>asList(),
Collections.<TypeReference<?>>emptyList());
// Encode to data
String data = FunctionEncoder.encode(function);
v. Choose a nonce
Based on whatever you want, select a nonce (/!\ must be greater than the nonce of the last transaction on this account)
// Calculate nonce
(...)
BigInteger nonce = new BigInteger("101");
vi. Prepare the transaction
// Prepare transaction
RawTransaction rawTransaction = RawTransaction.createTransaction(
nonce,
gasPrice,
gasLimit,
contractAddress,
BigInteger.ZERO, // No Value
data);
vii. Send the transaction
// Transaction manager
RawTransactionManager transactionManager = new RawTransactionManager(web3, credentials);
EthSendTransaction transaction = transactionManager.signAndSend(rawTransaction);
log.debug("transaction hash = {}", transaction.getTransactionHash());
You can find the code here:
modify your build.gradle to this and rebuild (i usually use maven), the problem was probably with okhttp used in web3j
dependencies {
// https://mvnrepository.com/artifact/org.web3j/core
implementation 'org.web3j:core:4.8.4'
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
dependencies{
implementation group: 'com.squareup.okhttp3', name: 'okhttp', version: '4.3.1'
implementation("com.squareup.okhttp3:logging-interceptor:4.3.1")
}
test {
useJUnitPlatform()
}
That will solve the problem, but another error could accrue.so :
Try to find which solidity version is supported by Web3j (cause 0.8 is very new) and then deploy the contract with the new version and generate the java code to that contract using Web3j
here are some docs about web3j contract interaction
http://docs.web3j.io/latest/smart_contracts/interacting_with_smart_contract/
this method could be helpful to check if the contract is valid before calling your method:
http://docs.web3j.io/latest/smart_contracts/contract_validity/
http://docs.web3j.io/latest/quickstart/#loading-a-smart-contract
Another thing in your contract you are using "public pure" method which does not need a tx, try better the storage contract, it has 2 methods the first one is a transaction and return a tx hash, the other method is a get method to get the value without a transaction
https://docs.soliditylang.org/en/v0.4.24/introduction-to-smart-contracts.html
Try it and tell me if everything works
Best Answer
I found the solution, please refer, #296
Use FastRawTransactionManager to speed up your transactions. Use RawTransactionManager to shorten the polling interval. If you need both, use the following code,