Skip to content

Commit 7af03b7

Browse files
authored
Align gas cap for transaction simulation to Geth approach (#7703)
Signed-off-by: Fabio Di Fabio <[email protected]>
1 parent e522b63 commit 7af03b7

File tree

3 files changed

+99
-33
lines changed

3 files changed

+99
-33
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
- LUKSO Cancun Hardfork [#7686](https://github.com/hyperledger/besu/pull/7686)
1616
- Add configuration of Consolidation Request Contract Address via genesis configuration [#7647](https://github.com/hyperledger/besu/pull/7647)
1717
- Interrupt pending transaction processing on block creation timeout [#7673](https://github.com/hyperledger/besu/pull/7673)
18+
- Align gas cap calculation for transaction simulation to Geth approach [#7703](https://github.com/hyperledger/besu/pull/7703)
1819

1920
### Bug fixes
2021
- Fix mounted data path directory permissions for besu user [#7575](https://github.com/hyperledger/besu/pull/7575)

ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -230,16 +230,9 @@ public Optional<TransactionSimulatorResult> processWithWorldUpdater(
230230
final Account sender = updater.get(senderAddress);
231231
final long nonce = sender != null ? sender.getNonce() : 0L;
232232

233-
long gasLimit =
234-
callParams.getGasLimit() >= 0
235-
? callParams.getGasLimit()
236-
: blockHeaderToProcess.getGasLimit();
237-
if (rpcGasCap > 0) {
238-
gasLimit = rpcGasCap;
239-
LOG.trace(
240-
"Gas limit capped at {} for transaction simulation due to provided RPC gas cap.",
241-
rpcGasCap);
242-
}
233+
final long simulationGasCap =
234+
calculateSimulationGasCap(callParams.getGasLimit(), blockHeaderToProcess.getGasLimit());
235+
243236
final Wei value = callParams.getValue() != null ? callParams.getValue() : Wei.ZERO;
244237
final Bytes payload = callParams.getPayload() != null ? callParams.getPayload() : Bytes.EMPTY;
245238

@@ -265,7 +258,7 @@ public Optional<TransactionSimulatorResult> processWithWorldUpdater(
265258
header,
266259
senderAddress,
267260
nonce,
268-
gasLimit,
261+
simulationGasCap,
269262
value,
270263
payload,
271264
blobGasPrice);
@@ -291,6 +284,38 @@ public Optional<TransactionSimulatorResult> processWithWorldUpdater(
291284
return Optional.of(new TransactionSimulatorResult(transaction, result));
292285
}
293286

287+
private long calculateSimulationGasCap(
288+
final long userProvidedGasLimit, final long blockGasLimit) {
289+
final long simulationGasCap;
290+
291+
// when not set gas limit is -1
292+
if (userProvidedGasLimit >= 0) {
293+
if (rpcGasCap > 0 && userProvidedGasLimit > rpcGasCap) {
294+
LOG.trace(
295+
"User provided gas limit {} is bigger than the value of rpc-gas-cap {}, setting simulation gas cap to the latter",
296+
userProvidedGasLimit,
297+
rpcGasCap);
298+
simulationGasCap = rpcGasCap;
299+
} else {
300+
LOG.trace("Using provided gas limit {} set as simulation gas cap", userProvidedGasLimit);
301+
simulationGasCap = userProvidedGasLimit;
302+
}
303+
} else {
304+
if (rpcGasCap > 0) {
305+
LOG.trace(
306+
"No user provided gas limit, setting simulation gas cap to the value of rpc-gas-cap {}",
307+
rpcGasCap);
308+
simulationGasCap = rpcGasCap;
309+
} else {
310+
simulationGasCap = blockGasLimit;
311+
LOG.trace(
312+
"No user provided gas limit and rpc-gas-cap options is not set, setting simulation gas cap to block gas limit {}",
313+
blockGasLimit);
314+
}
315+
}
316+
return simulationGasCap;
317+
}
318+
294319
private Optional<Transaction> buildTransaction(
295320
final CallParameter callParams,
296321
final TransactionValidationParams transactionValidationParams,

ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java

Lines changed: 62 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ public class TransactionSimulatorTest {
7979

8080
private static final Address DEFAULT_FROM =
8181
Address.fromHexString("0x0000000000000000000000000000000000000000");
82-
private static final long GASCAP = 500L;
82+
private static final long GAS_CAP = 500000L;
83+
private static final long TRANSFER_GAS_LIMIT = 21000L;
8384
private TransactionSimulator transactionSimulator;
8485
private TransactionSimulator cappedTransactionSimulator;
8586

@@ -96,7 +97,7 @@ public void setUp() {
9697
this.transactionSimulator =
9798
new TransactionSimulator(blockchain, worldStateArchive, protocolSchedule, 0);
9899
this.cappedTransactionSimulator =
99-
new TransactionSimulator(blockchain, worldStateArchive, protocolSchedule, GASCAP);
100+
new TransactionSimulator(blockchain, worldStateArchive, protocolSchedule, GAS_CAP);
100101
}
101102

102103
@Test
@@ -124,7 +125,7 @@ public void shouldReturnSuccessfulResultWhenProcessingIsSuccessful() {
124125
.type(TransactionType.FRONTIER)
125126
.nonce(1L)
126127
.gasPrice(callParameter.getGasPrice())
127-
.gasLimit(callParameter.getGasLimit())
128+
.gasLimit(blockHeader.getGasLimit())
128129
.to(callParameter.getTo())
129130
.sender(callParameter.getFrom())
130131
.value(callParameter.getValue())
@@ -155,7 +156,7 @@ public void shouldSetGasPriceToZeroWhenExceedingBalanceAllowed() {
155156
.type(TransactionType.FRONTIER)
156157
.nonce(1L)
157158
.gasPrice(Wei.ZERO)
158-
.gasLimit(callParameter.getGasLimit())
159+
.gasLimit(blockHeader.getGasLimit())
159160
.to(callParameter.getTo())
160161
.sender(callParameter.getFrom())
161162
.value(callParameter.getValue())
@@ -175,7 +176,8 @@ public void shouldSetGasPriceToZeroWhenExceedingBalanceAllowed() {
175176

176177
@Test
177178
public void shouldSetFeePerGasToZeroWhenExceedingBalanceAllowed() {
178-
final CallParameter callParameter = eip1559TransactionCallParameter(Wei.ONE, Wei.ONE);
179+
final CallParameter callParameter =
180+
eip1559TransactionCallParameter(Wei.ONE, Wei.ONE, TRANSFER_GAS_LIMIT);
179181

180182
final BlockHeader blockHeader = mockBlockHeader(Hash.ZERO, 1L, Wei.ONE);
181183

@@ -187,7 +189,7 @@ public void shouldSetFeePerGasToZeroWhenExceedingBalanceAllowed() {
187189
.type(TransactionType.EIP1559)
188190
.chainId(BigInteger.ONE)
189191
.nonce(1L)
190-
.gasLimit(callParameter.getGasLimit())
192+
.gasLimit(TRANSFER_GAS_LIMIT)
191193
.maxFeePerGas(Wei.ZERO)
192194
.maxPriorityFeePerGas(Wei.ZERO)
193195
.to(callParameter.getTo())
@@ -223,7 +225,7 @@ public void shouldNotSetGasPriceToZeroWhenExceedingBalanceIsNotAllowed() {
223225
.type(TransactionType.FRONTIER)
224226
.nonce(1L)
225227
.gasPrice(callParameter.getGasPrice())
226-
.gasLimit(callParameter.getGasLimit())
228+
.gasLimit(blockHeader.getGasLimit())
227229
.to(callParameter.getTo())
228230
.sender(callParameter.getFrom())
229231
.value(callParameter.getValue())
@@ -244,7 +246,8 @@ public void shouldNotSetGasPriceToZeroWhenExceedingBalanceIsNotAllowed() {
244246

245247
@Test
246248
public void shouldNotSetFeePerGasToZeroWhenExceedingBalanceIsNotAllowed() {
247-
final CallParameter callParameter = eip1559TransactionCallParameter(Wei.ONE, Wei.ONE);
249+
final CallParameter callParameter =
250+
eip1559TransactionCallParameter(Wei.ONE, Wei.ONE, TRANSFER_GAS_LIMIT);
248251

249252
final BlockHeader blockHeader = mockBlockHeader(Hash.ZERO, 1L, Wei.ONE);
250253

@@ -256,7 +259,7 @@ public void shouldNotSetFeePerGasToZeroWhenExceedingBalanceIsNotAllowed() {
256259
.type(TransactionType.EIP1559)
257260
.chainId(BigInteger.ONE)
258261
.nonce(1L)
259-
.gasLimit(callParameter.getGasLimit())
262+
.gasLimit(TRANSFER_GAS_LIMIT)
260263
.maxFeePerGas(callParameter.getMaxFeePerGas().orElseThrow())
261264
.maxPriorityFeePerGas(callParameter.getMaxPriorityFeePerGas().orElseThrow())
262265
.to(callParameter.getTo())
@@ -349,7 +352,7 @@ public void shouldReturnFailureResultWhenProcessingFails() {
349352
.type(TransactionType.FRONTIER)
350353
.nonce(1L)
351354
.gasPrice(callParameter.getGasPrice())
352-
.gasLimit(callParameter.getGasLimit())
355+
.gasLimit(blockHeader.getGasLimit())
353356
.to(callParameter.getTo())
354357
.sender(callParameter.getFrom())
355358
.value(callParameter.getValue())
@@ -390,7 +393,7 @@ public void shouldReturnSuccessfulResultWhenProcessingIsSuccessfulByHash() {
390393
.type(TransactionType.FRONTIER)
391394
.nonce(1L)
392395
.gasPrice(callParameter.getGasPrice())
393-
.gasLimit(callParameter.getGasLimit())
396+
.gasLimit(blockHeader.getGasLimit())
394397
.to(callParameter.getTo())
395398
.sender(callParameter.getFrom())
396399
.value(callParameter.getValue())
@@ -479,7 +482,7 @@ public void shouldReturnFailureResultWhenProcessingFailsByHash() {
479482
.type(TransactionType.FRONTIER)
480483
.nonce(1L)
481484
.gasPrice(callParameter.getGasPrice())
482-
.gasLimit(callParameter.getGasLimit())
485+
.gasLimit(blockHeader.getGasLimit())
483486
.to(callParameter.getTo())
484487
.sender(callParameter.getFrom())
485488
.value(callParameter.getValue())
@@ -509,7 +512,7 @@ public void shouldReturnSuccessfulResultWhenEip1559TransactionProcessingIsSucces
509512
.type(TransactionType.EIP1559)
510513
.chainId(BigInteger.ONE)
511514
.nonce(1L)
512-
.gasLimit(callParameter.getGasLimit())
515+
.gasLimit(blockHeader.getGasLimit())
513516
.maxFeePerGas(callParameter.getMaxFeePerGas().orElseThrow())
514517
.maxPriorityFeePerGas(callParameter.getMaxPriorityFeePerGas().orElseThrow())
515518
.to(callParameter.getTo())
@@ -530,7 +533,7 @@ public void shouldReturnSuccessfulResultWhenEip1559TransactionProcessingIsSucces
530533
@Test
531534
public void shouldCapGasLimitWhenOriginalTransactionExceedsGasCap() {
532535
final CallParameter callParameter =
533-
eip1559TransactionCallParameter(Wei.ZERO, Wei.ZERO, GASCAP + 1);
536+
eip1559TransactionCallParameter(Wei.ZERO, Wei.ZERO, GAS_CAP + 1);
534537

535538
final BlockHeader blockHeader = mockBlockHeader(Hash.ZERO, 1L, Wei.ONE);
536539

@@ -542,7 +545,7 @@ public void shouldCapGasLimitWhenOriginalTransactionExceedsGasCap() {
542545
.type(TransactionType.EIP1559)
543546
.chainId(BigInteger.ONE)
544547
.nonce(1L)
545-
.gasLimit(GASCAP)
548+
.gasLimit(GAS_CAP)
546549
.maxFeePerGas(callParameter.getMaxFeePerGas().orElseThrow())
547550
.maxPriorityFeePerGas(callParameter.getMaxPriorityFeePerGas().orElseThrow())
548551
.to(callParameter.getTo())
@@ -566,11 +569,48 @@ public void shouldCapGasLimitWhenOriginalTransactionExceedsGasCap() {
566569
}
567570

568571
@Test
569-
public void shouldUseRpcGasCapWhenCapIsHigherThanGasLimit() {
570-
// generate a transaction with a gas limit that is lower than the gas cap,
571-
// expect the gas cap to override parameter gas limit
572+
public void shouldUseProvidedGasLimitWhenBelowRpcCapGas() {
572573
final CallParameter callParameter =
573-
eip1559TransactionCallParameter(Wei.ZERO, Wei.ZERO, GASCAP - 1);
574+
eip1559TransactionCallParameter(Wei.ZERO, Wei.ZERO, GAS_CAP / 2);
575+
576+
final BlockHeader blockHeader = mockBlockHeader(Hash.ZERO, 1L, Wei.ONE);
577+
578+
mockBlockchainForBlockHeader(blockHeader);
579+
mockWorldStateForAccount(blockHeader, callParameter.getFrom(), 1L);
580+
581+
final Transaction expectedTransaction =
582+
Transaction.builder()
583+
.type(TransactionType.EIP1559)
584+
.chainId(BigInteger.ONE)
585+
.nonce(1L)
586+
.gasLimit(GAS_CAP / 2)
587+
.maxFeePerGas(callParameter.getMaxFeePerGas().orElseThrow())
588+
.maxPriorityFeePerGas(callParameter.getMaxPriorityFeePerGas().orElseThrow())
589+
.to(callParameter.getTo())
590+
.sender(callParameter.getFrom())
591+
.value(callParameter.getValue())
592+
.payload(callParameter.getPayload())
593+
.signature(FAKE_SIGNATURE)
594+
.build();
595+
596+
mockProtocolSpecForProcessWithWorldUpdater();
597+
598+
// call process with original transaction
599+
cappedTransactionSimulator.process(
600+
callParameter,
601+
TransactionValidationParams.transactionSimulator(),
602+
OperationTracer.NO_TRACING,
603+
1L);
604+
605+
// expect overwritten transaction to be processed
606+
verifyTransactionWasProcessed(expectedTransaction);
607+
}
608+
609+
@Test
610+
public void shouldUseRpcGasCapWhenGasLimitNoPresent() {
611+
// generate call parameters that do not specify a gas limit,
612+
// expect the rpc gas cap to be used for simulation
613+
final CallParameter callParameter = eip1559TransactionCallParameter(Wei.ZERO, Wei.ZERO, -1);
574614

575615
final BlockHeader blockHeader = mockBlockHeader(Hash.ZERO, 1L, Wei.ONE);
576616

@@ -591,7 +631,7 @@ public void shouldUseRpcGasCapWhenCapIsHigherThanGasLimit() {
591631
.value(callParameter.getValue())
592632
.payload(callParameter.getPayload())
593633
.signature(FAKE_SIGNATURE)
594-
.gasLimit(GASCAP)
634+
.gasLimit(GAS_CAP)
595635
.build();
596636

597637
// call process with original transaction
@@ -781,7 +821,7 @@ private CallParameter legacyTransactionCallParameter(final Wei gasPrice) {
781821
return new CallParameter(
782822
Address.fromHexString("0x0"),
783823
Address.fromHexString("0x0"),
784-
0,
824+
-1,
785825
gasPrice,
786826
Wei.of(0),
787827
Bytes.EMPTY);
@@ -793,7 +833,7 @@ private CallParameter eip1559TransactionCallParameter() {
793833

794834
private CallParameter eip1559TransactionCallParameter(
795835
final Wei maxFeePerGas, final Wei maxPriorityFeePerGas) {
796-
return eip1559TransactionCallParameter(maxFeePerGas, maxPriorityFeePerGas, 0L);
836+
return eip1559TransactionCallParameter(maxFeePerGas, maxPriorityFeePerGas, -1);
797837
}
798838

799839
private CallParameter eip1559TransactionCallParameter(

0 commit comments

Comments
 (0)