Move account warming from gas calculator to call operations (#6557)

The BerlinGasCalculator had a side effect of warming addresses when
calculating call gas costs. By introducing a boolean we can keep the
side effects in the operation instead of in the gas calculator. This
makes gas cost estimation by downstream users of the API safer.

Signed-off-by: Danno Ferrin <danno.ferrin@swirldslabs.com>
pull/6605/head
Danno Ferrin 9 months ago committed by GitHub
parent 59da092733
commit 655167f96e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      CHANGELOG.md
  2. 35
      evm/src/main/java/org/hyperledger/besu/evm/gascalculator/BerlinGasCalculator.java
  3. 26
      evm/src/main/java/org/hyperledger/besu/evm/gascalculator/FrontierGasCalculator.java
  4. 43
      evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java
  5. 3
      evm/src/main/java/org/hyperledger/besu/evm/gascalculator/SpuriousDragonGasCalculator.java
  6. 3
      evm/src/main/java/org/hyperledger/besu/evm/gascalculator/TangerineWhistleGasCalculator.java
  7. 46
      evm/src/main/java/org/hyperledger/besu/evm/operation/AbstractCallOperation.java
  8. 28
      evm/src/main/java/org/hyperledger/besu/evm/operation/CallCodeOperation.java
  9. 30
      evm/src/main/java/org/hyperledger/besu/evm/operation/CallOperation.java
  10. 28
      evm/src/main/java/org/hyperledger/besu/evm/operation/DelegateCallOperation.java
  11. 23
      evm/src/main/java/org/hyperledger/besu/evm/operation/StaticCallOperation.java

@ -49,7 +49,7 @@
- Extend `BesuConfiguration` service [#6584](https://github.com/hyperledger/besu/pull/6584)
- Add `ethereum_min_gas_price` and `ethereum_min_priority_fee` metrics to track runtime values of `min-gas-price` and `min-priority-fee` [#6587](https://github.com/hyperledger/besu/pull/6587)
- Option to perform version incompatibility checks when starting Besu. In this first release of the feature, if `--version-compatibility-protection` is set to true it checks that the version of Besu being started is the same or higher than the previous version. [6307](https://github.com/hyperledger/besu/pull/6307)
- Moved account frame warming from GasCalculator into the Call operations [#6557](https://github.com/hyperledger/besu/pull/6557)
### Bug fixes
- Fix the way an advertised host configured with `--p2p-host` is treated when communicating with the originator of a PING packet [#6225](https://github.com/hyperledger/besu/pull/6225)

@ -38,15 +38,18 @@ public class BerlinGasCalculator extends IstanbulGasCalculator {
// new constants for EIP-2929
private static final long COLD_SLOAD_COST = 2100L;
private static final long COLD_ACCOUNT_ACCESS_COST = 2600L;
/** Warm storage read, defined in EIP-2929 */
protected static final long WARM_STORAGE_READ_COST = 100L;
private static final long ACCESS_LIST_ADDRESS_COST = 2400L;
/** The constant ACCESS_LIST_STORAGE_COST. */
protected static final long ACCESS_LIST_STORAGE_COST = 1900L;
// redefinitions for EIP-2929
private static final long SLOAD_GAS = WARM_STORAGE_READ_COST;
/** The constant SSTORE_RESET_GAS. */
protected static final long SSTORE_RESET_GAS = 5000L - COLD_SLOAD_COST;
@ -56,6 +59,7 @@ public class BerlinGasCalculator extends IstanbulGasCalculator {
/** The constant SSTORE_SET_GAS_LESS_SLOAD_GAS. */
protected static final long SSTORE_SET_GAS_LESS_SLOAD_GAS = SSTORE_SET_GAS - SLOAD_GAS;
/** The constant SSTORE_RESET_GAS_LESS_SLOAD_GAS. */
protected static final long SSTORE_RESET_GAS_LESS_SLOAD_GAS = SSTORE_RESET_GAS - SLOAD_GAS;
@ -141,6 +145,7 @@ public class BerlinGasCalculator extends IstanbulGasCalculator {
// Redefined costs from EIP-2929
@Override
@SuppressWarnings("java:S5738")
public long callOperationGasCost(
final MessageFrame frame,
final long stipend,
@ -151,6 +156,32 @@ public class BerlinGasCalculator extends IstanbulGasCalculator {
final Wei transferValue,
final Account recipient,
final Address to) {
return callOperationGasCost(
frame,
stipend,
inputDataOffset,
inputDataLength,
outputDataOffset,
outputDataLength,
transferValue,
recipient,
to,
frame.warmUpAddress(to) || isPrecompile(to));
}
// Redefined costs from EIP-2929
@Override
public long callOperationGasCost(
final MessageFrame frame,
final long stipend,
final long inputDataOffset,
final long inputDataLength,
final long outputDataOffset,
final long outputDataLength,
final Wei transferValue,
final Account recipient,
final Address to,
final boolean accountIsWarm) {
final long baseCost =
super.callOperationGasCost(
frame,
@ -161,8 +192,8 @@ public class BerlinGasCalculator extends IstanbulGasCalculator {
outputDataLength,
transferValue,
recipient,
to);
final boolean accountIsWarm = frame.warmUpAddress(to) || isPrecompile(to);
to,
true); // we want the "warmed price" as we will charge for warming ourselves
return clampedAdd(
baseCost, accountIsWarm ? getWarmStorageReadCost() : getColdAccountAccessCost());
}

@ -228,6 +228,7 @@ public class FrontierGasCalculator implements GasCalculator {
return NEW_ACCOUNT_GAS_COST;
}
@SuppressWarnings("removal")
@Override
public long callOperationGasCost(
final MessageFrame frame,
@ -239,6 +240,31 @@ public class FrontierGasCalculator implements GasCalculator {
final Wei transferValue,
final Account recipient,
final Address to) {
return callOperationGasCost(
frame,
stipend,
inputDataOffset,
inputDataLength,
outputDataOffset,
outputDataLength,
transferValue,
recipient,
to,
true);
}
@Override
public long callOperationGasCost(
final MessageFrame frame,
final long stipend,
final long inputDataOffset,
final long inputDataLength,
final long outputDataOffset,
final long outputDataLength,
final Wei transferValue,
final Account recipient,
final Address to,
final boolean accountIsWarm) {
final long inputDataMemoryExpansionCost =
memoryExpansionGasCost(frame, inputDataOffset, inputDataLength);
final long outputDataMemoryExpansionCost =

@ -157,6 +157,46 @@ public interface GasCalculator {
* @param recipient The CALL recipient (may be null if self destructed or new)
* @param contract The address of the recipient (never null)
* @return The gas cost for the CALL operation
* @deprecated use the variant with the `accountIsWarm` parameter.
*/
@Deprecated(since = "24.2.0", forRemoval = true)
default long callOperationGasCost(
final MessageFrame frame,
final long stipend,
final long inputDataOffset,
final long inputDataLength,
final long outputDataOffset,
final long outputDataLength,
final Wei transferValue,
final Account recipient,
final Address contract) {
return callOperationGasCost(
frame,
stipend,
inputDataOffset,
inputDataLength,
outputDataOffset,
outputDataLength,
transferValue,
recipient,
contract,
true);
}
/**
* Returns the gas cost for one of the various CALL operations.
*
* @param frame The current frame
* @param stipend The gas stipend being provided by the CALL caller
* @param inputDataOffset The offset in memory to retrieve the CALL input data
* @param inputDataLength The CALL input data length
* @param outputDataOffset The offset in memory to place the CALL output data
* @param outputDataLength The CALL output data length
* @param transferValue The wei being transferred
* @param recipient The CALL recipient (may be null if self destructed or new)
* @param contract The address of the recipient (never null)
* @param accountIsWarm The address of the contract is "warm" as per EIP-2929
* @return The gas cost for the CALL operation
*/
long callOperationGasCost(
MessageFrame frame,
@ -167,7 +207,8 @@ public interface GasCalculator {
long outputDataLength,
Wei transferValue,
Account recipient,
Address contract);
Address contract,
boolean accountIsWarm);
/**
* Gets additional call stipend.

@ -36,7 +36,8 @@ public class SpuriousDragonGasCalculator extends TangerineWhistleGasCalculator {
final long outputDataLength,
final Wei transferValue,
final Account recipient,
final Address to) {
final Address to,
final boolean accountIsWarm) {
final long inputDataMemoryExpansionCost =
memoryExpansionGasCost(frame, inputDataOffset, inputDataLength);
final long outputDataMemoryExpansionCost =

@ -62,7 +62,8 @@ public class TangerineWhistleGasCalculator extends HomesteadGasCalculator {
final long outputDataLength,
final Wei transferValue,
final Account recipient,
final Address to) {
final Address to,
final boolean accountIsWarm) {
final long inputDataMemoryExpansionCost =
memoryExpansionGasCost(frame, inputDataOffset, inputDataLength);
final long outputDataMemoryExpansionCost =

@ -154,7 +154,9 @@ public abstract class AbstractCallOperation extends AbstractOperation {
* @param frame The current message frame
* @return {@code true} if the child message call should be static; otherwise {@code false}
*/
protected abstract boolean isStatic(MessageFrame frame);
protected boolean isStatic(final MessageFrame frame) {
return frame.isStatic();
}
@Override
public OperationResult execute(final MessageFrame frame, final EVM evm) {
@ -163,7 +165,9 @@ public abstract class AbstractCallOperation extends AbstractOperation {
return UNDERFLOW_RESPONSE;
}
final long cost = cost(frame);
final Address to = to(frame);
final boolean accountIsWarm = frame.warmUpAddress(to) || gasCalculator().isPrecompile(to);
final long cost = cost(frame, accountIsWarm);
if (frame.getRemainingGas() < cost) {
return new OperationResult(cost, ExceptionalHaltReason.INSUFFICIENT_GAS);
}
@ -171,7 +175,6 @@ public abstract class AbstractCallOperation extends AbstractOperation {
frame.clearReturnData();
final Address to = to(frame);
final Account contract = frame.getWorldUpdater().get(to);
final Account account = frame.getWorldUpdater().get(frame.getRecipientAddress());
@ -224,8 +227,43 @@ public abstract class AbstractCallOperation extends AbstractOperation {
*
* @param frame the frame
* @return the long
* @deprecated use the form with the `accountIsWarm` boolean
*/
protected abstract long cost(final MessageFrame frame);
@Deprecated(since = "24.2.0", forRemoval = true)
@SuppressWarnings("InlineMeSuggester") // downstream users override, so @InlineMe is inappropriate
public long cost(final MessageFrame frame) {
return cost(frame, true);
}
/**
* Calculates Cost.
*
* @param frame the frame
* @param accountIsWarm whether the contract being called is "warm" as per EIP-2929.
* @return the long
*/
public long cost(final MessageFrame frame, final boolean accountIsWarm) {
final long stipend = gas(frame);
final long inputDataOffset = inputDataOffset(frame);
final long inputDataLength = inputDataLength(frame);
final long outputDataOffset = outputDataOffset(frame);
final long outputDataLength = outputDataLength(frame);
final Account recipient = frame.getWorldUpdater().get(address(frame));
final Address to = to(frame);
GasCalculator gasCalculator = gasCalculator();
return gasCalculator.callOperationGasCost(
frame,
stipend,
inputDataOffset,
inputDataLength,
outputDataOffset,
outputDataLength,
value(frame),
recipient,
to,
accountIsWarm);
}
/**
* Complete.

@ -18,7 +18,6 @@ import static org.hyperledger.besu.evm.internal.Words.clampedToLong;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.internal.Words;
@ -84,31 +83,4 @@ public class CallCodeOperation extends AbstractCallOperation {
public long gasAvailableForChildCall(final MessageFrame frame) {
return gasCalculator().gasAvailableForChildCall(frame, gas(frame), !value(frame).isZero());
}
@Override
protected boolean isStatic(final MessageFrame frame) {
return frame.isStatic();
}
@Override
public long cost(final MessageFrame frame) {
final long stipend = gas(frame);
final long inputDataOffset = inputDataOffset(frame);
final long inputDataLength = inputDataLength(frame);
final long outputDataOffset = outputDataOffset(frame);
final long outputDataLength = outputDataLength(frame);
final Account recipient = frame.getWorldUpdater().get(address(frame));
return gasCalculator()
.callOperationGasCost(
frame,
stipend,
inputDataOffset,
inputDataLength,
outputDataOffset,
outputDataLength,
value(frame),
recipient,
to(frame));
}
}

@ -19,7 +19,6 @@ import static org.hyperledger.besu.evm.internal.Words.clampedToLong;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
@ -87,37 +86,10 @@ public class CallOperation extends AbstractCallOperation {
return gasCalculator().gasAvailableForChildCall(frame, gas(frame), !value(frame).isZero());
}
@Override
protected boolean isStatic(final MessageFrame frame) {
return frame.isStatic();
}
@Override
public long cost(final MessageFrame frame) {
final long stipend = gas(frame);
final long inputDataOffset = inputDataOffset(frame);
final long inputDataLength = inputDataLength(frame);
final long outputDataOffset = outputDataOffset(frame);
final long outputDataLength = outputDataLength(frame);
final Account recipient = frame.getWorldUpdater().get(address(frame));
return gasCalculator()
.callOperationGasCost(
frame,
stipend,
inputDataOffset,
inputDataLength,
outputDataOffset,
outputDataLength,
value(frame),
recipient,
to(frame));
}
@Override
public OperationResult execute(final MessageFrame frame, final EVM evm) {
if (frame.isStatic() && !value(frame).isZero()) {
return new OperationResult(cost(frame), ExceptionalHaltReason.ILLEGAL_STATE_CHANGE);
return new OperationResult(cost(frame, true), ExceptionalHaltReason.ILLEGAL_STATE_CHANGE);
} else {
return super.execute(frame, evm);
}

@ -18,7 +18,6 @@ import static org.hyperledger.besu.evm.internal.Words.clampedToLong;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.internal.Words;
@ -84,31 +83,4 @@ public class DelegateCallOperation extends AbstractCallOperation {
public long gasAvailableForChildCall(final MessageFrame frame) {
return gasCalculator().gasAvailableForChildCall(frame, gas(frame), false);
}
@Override
protected boolean isStatic(final MessageFrame frame) {
return frame.isStatic();
}
@Override
public long cost(final MessageFrame frame) {
final long stipend = gas(frame);
final long inputDataOffset = inputDataOffset(frame);
final long inputDataLength = inputDataLength(frame);
final long outputDataOffset = outputDataOffset(frame);
final long outputDataLength = outputDataLength(frame);
final Account recipient = frame.getWorldUpdater().get(address(frame));
return gasCalculator()
.callOperationGasCost(
frame,
stipend,
inputDataOffset,
inputDataLength,
outputDataOffset,
outputDataLength,
Wei.ZERO,
recipient,
to(frame));
}
}

@ -18,7 +18,6 @@ import static org.hyperledger.besu.evm.internal.Words.clampedToLong;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.internal.Words;
@ -89,26 +88,4 @@ public class StaticCallOperation extends AbstractCallOperation {
protected boolean isStatic(final MessageFrame frame) {
return true;
}
@Override
public long cost(final MessageFrame frame) {
final long stipend = gas(frame);
final long inputDataOffset = inputDataOffset(frame);
final long inputDataLength = inputDataLength(frame);
final long outputDataOffset = outputDataOffset(frame);
final long outputDataLength = outputDataLength(frame);
final Account recipient = frame.getWorldUpdater().get(address(frame));
return gasCalculator()
.callOperationGasCost(
frame,
stipend,
inputDataOffset,
inputDataLength,
outputDataOffset,
outputDataLength,
value(frame),
recipient,
to(frame));
}
}

Loading…
Cancel
Save