Skip to content

Commit 3208ec2

Browse files
authored
feat: refactor method to check if wallet has enough gas (#165)
1 parent b48c4ae commit 3208ec2

File tree

4 files changed

+77
-3
lines changed

4 files changed

+77
-3
lines changed

src/main/java/com/iexec/commons/poco/chain/IexecHubAbstractService.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.web3j.utils.Numeric;
3434

3535
import java.io.IOException;
36+
import java.math.BigDecimal;
3637
import java.math.BigInteger;
3738
import java.util.Map;
3839
import java.util.Optional;
@@ -68,6 +69,7 @@ public abstract class IexecHubAbstractService {
6869
private final int maxRetries;
6970
private final Map<Long, ChainCategory> categories = new ConcurrentHashMap<>();
7071
private final Map<String, TaskDescription> taskDescriptions = new ConcurrentHashMap<>();
72+
private BigInteger lastKnownBalance = BigInteger.ZERO;
7173

7274
protected IexecHubAbstractService(
7375
Credentials credentials,
@@ -444,6 +446,40 @@ private void setMaxNbOfPeriodsForConsensus() {
444446
}
445447
}
446448

449+
public boolean hasEnoughGas() {
450+
// if a sidechain is used, there is no need to check if the wallet has enough gas.
451+
// if mainnet is used, the check should be done.
452+
if (web3jAbstractService.isSidechain()) {
453+
return true;
454+
}
455+
456+
final Optional<BigInteger> oWeiBalance = web3jAbstractService.getBalance(credentials.getAddress());
457+
if (oWeiBalance.isEmpty()) {
458+
log.warn("ETH balance not retrieved on chain, falling back on last known balance");
459+
}
460+
461+
final BigInteger weiBalance = oWeiBalance.orElse(lastKnownBalance);
462+
// preserve last known balance for future checks
463+
lastKnownBalance = weiBalance;
464+
final BigInteger estimateTxNb = weiBalance.divide(web3jAbstractService.getMaxTxCost());
465+
final BigDecimal balanceToShow = ChainUtils.weiToEth(weiBalance);
466+
467+
if (estimateTxNb.compareTo(BigInteger.ONE) < 0) {
468+
log.error("ETH balance is empty, please refill gas now [balance:{}, estimateTxNb:{}]", balanceToShow, estimateTxNb);
469+
return false;
470+
} else if (estimateTxNb.compareTo(BigInteger.TEN) < 0) {
471+
log.warn("ETH balance very low, should refill gas now [balance:{}, estimateTxNb:{}]", balanceToShow, estimateTxNb);
472+
} else {
473+
log.debug("ETH balance is fine [balance:{}, estimateTxNb:{}]", balanceToShow, estimateTxNb);
474+
}
475+
476+
return true;
477+
}
478+
479+
/**
480+
* @deprecated Use hasEnoughGas() instead
481+
*/
482+
@Deprecated(forRemoval = true)
447483
public boolean hasEnoughGas(String address) {
448484
return web3jAbstractService.hasEnoughGas(address);
449485
}

src/main/java/com/iexec/commons/poco/chain/Web3jAbstractService.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ public abstract class Web3jAbstractService {
6262
private final Duration blockTime;
6363
private final float gasPriceMultiplier;
6464
private final long gasPriceCap;
65+
@Getter
6566
private final boolean isSidechain;
6667
@Getter
6768
private final Web3j web3j;
@@ -121,6 +122,10 @@ public boolean isConnected() {
121122
return false;
122123
}
123124

125+
/**
126+
* @deprecated only used from deprecated method
127+
*/
128+
@Deprecated(forRemoval = true)
124129
public static BigInteger getMaxTxCost(long gasPriceCap) {
125130
return BigInteger.valueOf(GAS_LIMIT_CAP * gasPriceCap);
126131
}
@@ -240,6 +245,10 @@ private void decodeAndThrowEvmRpcError(final Response.Error error) {
240245
throw new JsonRpcError(error.getCode(), message, null);
241246
}
242247

248+
/**
249+
* @deprecated Use IexecHubAbstractService#hasEnoughGas() instead
250+
*/
251+
@Deprecated(forRemoval = true)
243252
public boolean hasEnoughGas(String address) {
244253
// if a sidechain is used, there is no need to check if the wallet has enough gas.
245254
// if mainnet is used, the check should be done.
@@ -268,9 +277,9 @@ public boolean hasEnoughGas(String address) {
268277
return true;
269278
}
270279

271-
public Optional<BigInteger> getBalance(String address) {
280+
public Optional<BigInteger> getBalance(final String address) {
272281
try {
273-
BigInteger balance = web3j.ethGetBalance(address, DefaultBlockParameterName.LATEST).send().getBalance();
282+
final BigInteger balance = web3j.ethGetBalance(address, DefaultBlockParameterName.LATEST).send().getBalance();
274283
log.debug("{} current balance is {}", address, balance);
275284
return Optional.of(balance);
276285
} catch (IOException e) {
@@ -279,6 +288,10 @@ public Optional<BigInteger> getBalance(String address) {
279288
}
280289
}
281290

291+
public BigInteger getMaxTxCost() {
292+
return BigInteger.valueOf(GAS_LIMIT_CAP * gasPriceCap);
293+
}
294+
282295
/**
283296
* Request current gas price on the network.
284297
* <p>

src/test/java/com/iexec/commons/poco/itest/ChainTests.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.testcontainers.junit.jupiter.Container;
3030
import org.testcontainers.junit.jupiter.Testcontainers;
3131
import org.web3j.crypto.Credentials;
32+
import org.web3j.crypto.Keys;
3233
import org.web3j.crypto.WalletUtils;
3334
import org.web3j.crypto.exception.CipherException;
3435

@@ -81,6 +82,26 @@ void shouldGetAccount() {
8182
assertThat(chainAccount.getLocked()).isZero();
8283
}
8384

85+
@Test
86+
void shouldHaveEnoughGasOnBellecour() {
87+
assertThat(iexecHubService.hasEnoughGas()).isTrue();
88+
}
89+
90+
@Test
91+
void shouldHaveEnoughGasOnArbitrum() throws IOException {
92+
final Web3jTestService arbitrumWeb3j = new Web3jTestService(chainNodeAddress, 1.0f, 22_000_000_000L, false);
93+
final IexecHubTestService arbitrumHub = new IexecHubTestService(credentials, arbitrumWeb3j);
94+
assertThat(arbitrumHub.hasEnoughGas()).isTrue();
95+
}
96+
97+
@Test
98+
void shouldNotHaveEnoughGasOnArbitrum() throws Exception {
99+
final Credentials newCredentials = Credentials.create(Keys.createEcKeyPair());
100+
final Web3jTestService arbitrumWeb3j = new Web3jTestService(chainNodeAddress, 1.0f, 22_000_000_000L, false);
101+
final IexecHubTestService arbitrumHub = new IexecHubTestService(newCredentials, arbitrumWeb3j);
102+
assertThat(arbitrumHub.hasEnoughGas()).isFalse();
103+
}
104+
84105
@Test
85106
void shouldGetBalance() {
86107
final BigInteger balance = web3jService.getBalance(credentials.getAddress()).orElse(null);

src/test/java/com/iexec/commons/poco/itest/Web3jTestService.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,11 @@ public Web3jTestService(String chainNodeAddress) {
4242
}
4343

4444
public Web3jTestService(String chainNodeAddress, float gasPriceMultiplier, long gasPriceCap) {
45-
super(65535, chainNodeAddress, Duration.ofSeconds(BLOCK_TIME), gasPriceMultiplier, gasPriceCap, true);
45+
this(chainNodeAddress, gasPriceMultiplier, gasPriceCap, true);
46+
}
47+
48+
public Web3jTestService(String chainNodeAddress, float gasPriceMultiplier, long gasPriceCap, boolean isSidechain) {
49+
super(65535, chainNodeAddress, Duration.ofSeconds(BLOCK_TIME), gasPriceMultiplier, gasPriceCap, isSidechain);
4650
}
4751

4852
@SneakyThrows

0 commit comments

Comments
 (0)