Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
- LUKSO Cancun Hardfork [#7686](https://github.com/hyperledger/besu/pull/7686)
- Add configuration of Consolidation Request Contract Address via genesis configuration [#7647](https://github.com/hyperledger/besu/pull/7647)
- Interrupt pending transaction processing on block creation timeout [#7673](https://github.com/hyperledger/besu/pull/7673)
- Align gas cap calculation for transaction simulation to Geth approach [#7703](https://github.com/hyperledger/besu/pull/7703)

### Bug fixes
- Fix mounted data path directory permissions for besu user [#7575](https://github.com/hyperledger/besu/pull/7575)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,16 +230,9 @@ public Optional<TransactionSimulatorResult> processWithWorldUpdater(
final Account sender = updater.get(senderAddress);
final long nonce = sender != null ? sender.getNonce() : 0L;

long gasLimit =
callParams.getGasLimit() >= 0
? callParams.getGasLimit()
: blockHeaderToProcess.getGasLimit();
if (rpcGasCap > 0) {
gasLimit = rpcGasCap;
LOG.trace(
"Gas limit capped at {} for transaction simulation due to provided RPC gas cap.",
rpcGasCap);
}
final long simulationGasCap =
calculateSimulationGasCap(callParams.getGasLimit(), blockHeaderToProcess.getGasLimit());

final Wei value = callParams.getValue() != null ? callParams.getValue() : Wei.ZERO;
final Bytes payload = callParams.getPayload() != null ? callParams.getPayload() : Bytes.EMPTY;

Expand All @@ -265,7 +258,7 @@ public Optional<TransactionSimulatorResult> processWithWorldUpdater(
header,
senderAddress,
nonce,
gasLimit,
simulationGasCap,
value,
payload,
blobGasPrice);
Expand All @@ -291,6 +284,38 @@ public Optional<TransactionSimulatorResult> processWithWorldUpdater(
return Optional.of(new TransactionSimulatorResult(transaction, result));
}

private long calculateSimulationGasCap(
final long userProvidedGasLimit, final long blockGasLimit) {
final long simulationGasCap;

// when not set gas limit is -1
if (userProvidedGasLimit >= 0) {
if (rpcGasCap > 0 && userProvidedGasLimit > rpcGasCap) {
LOG.trace(
"User provided gas limit {} is bigger than the value of rpc-gas-cap {}, setting simulation gas cap to the latter",
userProvidedGasLimit,
rpcGasCap);
simulationGasCap = rpcGasCap;
} else {
LOG.trace("Using provided gas limit {} set as simulation gas cap", userProvidedGasLimit);
simulationGasCap = userProvidedGasLimit;
}
} else {
if (rpcGasCap > 0) {
LOG.trace(
"No user provided gas limit, setting simulation gas cap to the value of rpc-gas-cap {}",
rpcGasCap);
simulationGasCap = rpcGasCap;
} else {
simulationGasCap = blockGasLimit;
LOG.trace(
"No user provided gas limit and rpc-gas-cap options is not set, setting simulation gas cap to block gas limit {}",
blockGasLimit);
}
}
return simulationGasCap;
}

private Optional<Transaction> buildTransaction(
final CallParameter callParams,
final TransactionValidationParams transactionValidationParams,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ public class TransactionSimulatorTest {

private static final Address DEFAULT_FROM =
Address.fromHexString("0x0000000000000000000000000000000000000000");
private static final long GASCAP = 500L;
private static final long GAS_CAP = 500000L;
private static final long TRANSFER_GAS_LIMIT = 21000L;
private TransactionSimulator transactionSimulator;
private TransactionSimulator cappedTransactionSimulator;

Expand All @@ -96,7 +97,7 @@ public void setUp() {
this.transactionSimulator =
new TransactionSimulator(blockchain, worldStateArchive, protocolSchedule, 0);
this.cappedTransactionSimulator =
new TransactionSimulator(blockchain, worldStateArchive, protocolSchedule, GASCAP);
new TransactionSimulator(blockchain, worldStateArchive, protocolSchedule, GAS_CAP);
}

@Test
Expand Down Expand Up @@ -124,7 +125,7 @@ public void shouldReturnSuccessfulResultWhenProcessingIsSuccessful() {
.type(TransactionType.FRONTIER)
.nonce(1L)
.gasPrice(callParameter.getGasPrice())
.gasLimit(callParameter.getGasLimit())
.gasLimit(blockHeader.getGasLimit())
.to(callParameter.getTo())
.sender(callParameter.getFrom())
.value(callParameter.getValue())
Expand Down Expand Up @@ -155,7 +156,7 @@ public void shouldSetGasPriceToZeroWhenExceedingBalanceAllowed() {
.type(TransactionType.FRONTIER)
.nonce(1L)
.gasPrice(Wei.ZERO)
.gasLimit(callParameter.getGasLimit())
.gasLimit(blockHeader.getGasLimit())
.to(callParameter.getTo())
.sender(callParameter.getFrom())
.value(callParameter.getValue())
Expand All @@ -175,7 +176,8 @@ public void shouldSetGasPriceToZeroWhenExceedingBalanceAllowed() {

@Test
public void shouldSetFeePerGasToZeroWhenExceedingBalanceAllowed() {
final CallParameter callParameter = eip1559TransactionCallParameter(Wei.ONE, Wei.ONE);
final CallParameter callParameter =
eip1559TransactionCallParameter(Wei.ONE, Wei.ONE, TRANSFER_GAS_LIMIT);

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

Expand All @@ -187,7 +189,7 @@ public void shouldSetFeePerGasToZeroWhenExceedingBalanceAllowed() {
.type(TransactionType.EIP1559)
.chainId(BigInteger.ONE)
.nonce(1L)
.gasLimit(callParameter.getGasLimit())
.gasLimit(TRANSFER_GAS_LIMIT)
.maxFeePerGas(Wei.ZERO)
.maxPriorityFeePerGas(Wei.ZERO)
.to(callParameter.getTo())
Expand Down Expand Up @@ -223,7 +225,7 @@ public void shouldNotSetGasPriceToZeroWhenExceedingBalanceIsNotAllowed() {
.type(TransactionType.FRONTIER)
.nonce(1L)
.gasPrice(callParameter.getGasPrice())
.gasLimit(callParameter.getGasLimit())
.gasLimit(blockHeader.getGasLimit())
.to(callParameter.getTo())
.sender(callParameter.getFrom())
.value(callParameter.getValue())
Expand All @@ -244,7 +246,8 @@ public void shouldNotSetGasPriceToZeroWhenExceedingBalanceIsNotAllowed() {

@Test
public void shouldNotSetFeePerGasToZeroWhenExceedingBalanceIsNotAllowed() {
final CallParameter callParameter = eip1559TransactionCallParameter(Wei.ONE, Wei.ONE);
final CallParameter callParameter =
eip1559TransactionCallParameter(Wei.ONE, Wei.ONE, TRANSFER_GAS_LIMIT);

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

Expand All @@ -256,7 +259,7 @@ public void shouldNotSetFeePerGasToZeroWhenExceedingBalanceIsNotAllowed() {
.type(TransactionType.EIP1559)
.chainId(BigInteger.ONE)
.nonce(1L)
.gasLimit(callParameter.getGasLimit())
.gasLimit(TRANSFER_GAS_LIMIT)
.maxFeePerGas(callParameter.getMaxFeePerGas().orElseThrow())
.maxPriorityFeePerGas(callParameter.getMaxPriorityFeePerGas().orElseThrow())
.to(callParameter.getTo())
Expand Down Expand Up @@ -349,7 +352,7 @@ public void shouldReturnFailureResultWhenProcessingFails() {
.type(TransactionType.FRONTIER)
.nonce(1L)
.gasPrice(callParameter.getGasPrice())
.gasLimit(callParameter.getGasLimit())
.gasLimit(blockHeader.getGasLimit())
.to(callParameter.getTo())
.sender(callParameter.getFrom())
.value(callParameter.getValue())
Expand Down Expand Up @@ -390,7 +393,7 @@ public void shouldReturnSuccessfulResultWhenProcessingIsSuccessfulByHash() {
.type(TransactionType.FRONTIER)
.nonce(1L)
.gasPrice(callParameter.getGasPrice())
.gasLimit(callParameter.getGasLimit())
.gasLimit(blockHeader.getGasLimit())
.to(callParameter.getTo())
.sender(callParameter.getFrom())
.value(callParameter.getValue())
Expand Down Expand Up @@ -479,7 +482,7 @@ public void shouldReturnFailureResultWhenProcessingFailsByHash() {
.type(TransactionType.FRONTIER)
.nonce(1L)
.gasPrice(callParameter.getGasPrice())
.gasLimit(callParameter.getGasLimit())
.gasLimit(blockHeader.getGasLimit())
.to(callParameter.getTo())
.sender(callParameter.getFrom())
.value(callParameter.getValue())
Expand Down Expand Up @@ -509,7 +512,7 @@ public void shouldReturnSuccessfulResultWhenEip1559TransactionProcessingIsSucces
.type(TransactionType.EIP1559)
.chainId(BigInteger.ONE)
.nonce(1L)
.gasLimit(callParameter.getGasLimit())
.gasLimit(blockHeader.getGasLimit())
.maxFeePerGas(callParameter.getMaxFeePerGas().orElseThrow())
.maxPriorityFeePerGas(callParameter.getMaxPriorityFeePerGas().orElseThrow())
.to(callParameter.getTo())
Expand All @@ -530,7 +533,7 @@ public void shouldReturnSuccessfulResultWhenEip1559TransactionProcessingIsSucces
@Test
public void shouldCapGasLimitWhenOriginalTransactionExceedsGasCap() {
final CallParameter callParameter =
eip1559TransactionCallParameter(Wei.ZERO, Wei.ZERO, GASCAP + 1);
eip1559TransactionCallParameter(Wei.ZERO, Wei.ZERO, GAS_CAP + 1);

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

Expand All @@ -542,7 +545,7 @@ public void shouldCapGasLimitWhenOriginalTransactionExceedsGasCap() {
.type(TransactionType.EIP1559)
.chainId(BigInteger.ONE)
.nonce(1L)
.gasLimit(GASCAP)
.gasLimit(GAS_CAP)
.maxFeePerGas(callParameter.getMaxFeePerGas().orElseThrow())
.maxPriorityFeePerGas(callParameter.getMaxPriorityFeePerGas().orElseThrow())
.to(callParameter.getTo())
Expand All @@ -566,11 +569,48 @@ public void shouldCapGasLimitWhenOriginalTransactionExceedsGasCap() {
}

@Test
public void shouldUseRpcGasCapWhenCapIsHigherThanGasLimit() {
// generate a transaction with a gas limit that is lower than the gas cap,
// expect the gas cap to override parameter gas limit
public void shouldUseProvidedGasLimitWhenBelowRpcCapGas() {
final CallParameter callParameter =
eip1559TransactionCallParameter(Wei.ZERO, Wei.ZERO, GASCAP - 1);
eip1559TransactionCallParameter(Wei.ZERO, Wei.ZERO, GAS_CAP / 2);

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

mockBlockchainForBlockHeader(blockHeader);
mockWorldStateForAccount(blockHeader, callParameter.getFrom(), 1L);

final Transaction expectedTransaction =
Transaction.builder()
.type(TransactionType.EIP1559)
.chainId(BigInteger.ONE)
.nonce(1L)
.gasLimit(GAS_CAP / 2)
.maxFeePerGas(callParameter.getMaxFeePerGas().orElseThrow())
.maxPriorityFeePerGas(callParameter.getMaxPriorityFeePerGas().orElseThrow())
.to(callParameter.getTo())
.sender(callParameter.getFrom())
.value(callParameter.getValue())
.payload(callParameter.getPayload())
.signature(FAKE_SIGNATURE)
.build();

mockProtocolSpecForProcessWithWorldUpdater();

// call process with original transaction
cappedTransactionSimulator.process(
callParameter,
TransactionValidationParams.transactionSimulator(),
OperationTracer.NO_TRACING,
1L);

// expect overwritten transaction to be processed
verifyTransactionWasProcessed(expectedTransaction);
}

@Test
public void shouldUseRpcGasCapWhenGasLimitNoPresent() {
// generate call parameters that do not specify a gas limit,
// expect the rpc gas cap to be used for simulation
final CallParameter callParameter = eip1559TransactionCallParameter(Wei.ZERO, Wei.ZERO, -1);

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

Expand All @@ -591,7 +631,7 @@ public void shouldUseRpcGasCapWhenCapIsHigherThanGasLimit() {
.value(callParameter.getValue())
.payload(callParameter.getPayload())
.signature(FAKE_SIGNATURE)
.gasLimit(GASCAP)
.gasLimit(GAS_CAP)
.build();

// call process with original transaction
Expand Down Expand Up @@ -781,7 +821,7 @@ private CallParameter legacyTransactionCallParameter(final Wei gasPrice) {
return new CallParameter(
Address.fromHexString("0x0"),
Address.fromHexString("0x0"),
0,
-1,
gasPrice,
Wei.of(0),
Bytes.EMPTY);
Expand All @@ -793,7 +833,7 @@ private CallParameter eip1559TransactionCallParameter() {

private CallParameter eip1559TransactionCallParameter(
final Wei maxFeePerGas, final Wei maxPriorityFeePerGas) {
return eip1559TransactionCallParameter(maxFeePerGas, maxPriorityFeePerGas, 0L);
return eip1559TransactionCallParameter(maxFeePerGas, maxPriorityFeePerGas, -1);
}

private CallParameter eip1559TransactionCallParameter(
Expand Down