Skip to content

Commit

Permalink
first draft for EIP-7623
Browse files Browse the repository at this point in the history
Signed-off-by: Daniel Lehrner <[email protected]>
  • Loading branch information
daniellehrner committed Dec 7, 2024
1 parent 6dfaaf3 commit 5ffe63a
Show file tree
Hide file tree
Showing 11 changed files with 110 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,6 @@ protected long getGasLimit(final PrivateTransaction privateTransaction, final St
// choose the highest of the two options
return Math.max(
privateTransaction.getGasLimit(),
gasCalculator.transactionIntrinsicGasCost(Bytes.fromBase64String(pmtPayload), false));
gasCalculator.transactionIntrinsicGasCost(Bytes.fromBase64String(pmtPayload), false, 0));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import static org.hyperledger.besu.ethereum.mainnet.PrivateStateUtils.KEY_PRIVATE_METADATA_UPDATER;
import static org.hyperledger.besu.ethereum.mainnet.PrivateStateUtils.KEY_TRANSACTION;
import static org.hyperledger.besu.ethereum.mainnet.PrivateStateUtils.KEY_TRANSACTION_HASH;
import static org.hyperledger.besu.evm.internal.Words.clampedAdd;
import static org.hyperledger.besu.evm.operation.BlockHashOperation.BlockHashLookup;

import org.hyperledger.besu.collections.trie.BytesTrieSet;
Expand Down Expand Up @@ -372,22 +373,22 @@ public TransactionProcessingResult processTransaction(
warmAddressList.add(miningBeneficiary);
}

final long intrinsicGas =
gasCalculator.transactionIntrinsicGasCost(
transaction.getPayload(), transaction.isContractCreation());
final long accessListGas =
gasCalculator.accessListGasCost(accessListEntries.size(), accessListStorageCount);
final long codeDelegationGas =
gasCalculator.delegateCodeGasCost(transaction.codeDelegationListSize());
final long gasAvailable =
transaction.getGasLimit() - intrinsicGas - accessListGas - codeDelegationGas;
final long intrinsicGas =
gasCalculator.transactionIntrinsicGasCost(
transaction.getPayload(),
transaction.isContractCreation(),
clampedAdd(accessListGas, codeDelegationGas));

final long gasAvailable = transaction.getGasLimit() - intrinsicGas;
LOG.trace(
"Gas available for execution {} = {} - {} - {} - {} (limit - intrinsic - accessList - codeDelegation)",
"Gas available for execution {} = {} - {} (limit - intrinsic)",
gasAvailable,
transaction.getGasLimit(),
intrinsicGas,
accessListGas,
codeDelegationGas);
intrinsicGas);

final WorldUpdater worldUpdater = evmWorldUpdater.updater();
final ImmutableMap.Builder<String, Object> contextVariablesBuilder =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package org.hyperledger.besu.ethereum.mainnet;

import static org.hyperledger.besu.evm.account.Account.MAX_NONCE;
import static org.hyperledger.besu.evm.internal.Words.clampedAdd;

import org.hyperledger.besu.crypto.SECPSignature;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
Expand Down Expand Up @@ -252,11 +253,13 @@ private ValidationResult<TransactionInvalidReason> validateCostAndFee(
}
}

final long evmGasUsed =
clampedAdd(
transaction.getAccessList().map(gasCalculator::accessListGasCost).orElse(0L),
gasCalculator.delegateCodeGasCost(transaction.codeDelegationListSize()));
final long intrinsicGasCost =
gasCalculator.transactionIntrinsicGasCost(
transaction.getPayload(), transaction.isContractCreation())
+ (transaction.getAccessList().map(gasCalculator::accessListGasCost).orElse(0L))
+ gasCalculator.delegateCodeGasCost(transaction.codeDelegationListSize());
transaction.getPayload(), transaction.isContractCreation(), evmGasUsed);
if (Long.compareUnsigned(intrinsicGasCost, transaction.getGasLimit()) > 0) {
return ValidationResult.invalid(
TransactionInvalidReason.INTRINSIC_GAS_EXCEEDS_GAS_LIMIT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -403,16 +403,20 @@ public void run() {

long txGas = gas;
if (chargeIntrinsicGas) {
final long intrinsicGasCost =
protocolSpec
.getGasCalculator()
.transactionIntrinsicGasCost(tx.getPayload(), tx.isContractCreation());
txGas -= intrinsicGasCost;
final long accessListCost =
tx.getAccessList()
.map(list -> protocolSpec.getGasCalculator().accessListGasCost(list))
.orElse(0L);
txGas -= accessListCost;

final long delegateCodeCost =
protocolSpec.getGasCalculator().delegateCodeGasCost(tx.codeDelegationListSize());

final long intrinsicGasCost =
protocolSpec
.getGasCalculator()
.transactionIntrinsicGasCost(
tx.getPayload(), tx.isContractCreation(), accessListCost + delegateCodeCost);
txGas -= intrinsicGasCost;
}

final EVM evm = protocolSpec.getEvm();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ static T8nResult runTest(
gasUsed += transactionGasUsed;
long intrinsicGas =
gasCalculator.transactionIntrinsicGasCost(
transaction.getPayload(), transaction.getTo().isEmpty());
transaction.getPayload(), transaction.getTo().isEmpty(), 0);
TransactionReceipt receipt =
protocolSpec
.getTransactionReceiptFactory()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,13 @@ public void milestone(

assertThat(transaction.getSender()).isEqualTo(expected.getSender());
assertThat(transaction.getHash()).isEqualTo(expected.getHash());
final long intrinsicGasCost =
gasCalculator.transactionIntrinsicGasCost(
transaction.getPayload(), transaction.isContractCreation())
+ (transaction.getAccessList().map(gasCalculator::accessListGasCost).orElse(0L));
final long evmGasUsed =
transaction.getAccessList().map(gasCalculator::accessListGasCost).orElse(0L) +
gasCalculator.delegateCodeGasCost(transaction.codeDelegationListSize());
final long intrinsicGasCost = gasCalculator.transactionIntrinsicGasCost(
transaction.getPayload(),
transaction.isContractCreation(),
evmGasUsed);
assertThat(intrinsicGasCost).isEqualTo(expected.getIntrinsicGas());
} catch (final Exception e) {
if (expected.isSucceeds()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public class FrontierGasCalculator implements GasCalculator {

private static final long TX_DATA_NON_ZERO_COST = 68L;

private static final long TX_BASE_COST = 21_000L;
protected static final long TX_BASE_COST = 21_000L;

private static final long TX_CREATE_EXTRA_COST = 0L;

Expand Down Expand Up @@ -128,18 +128,55 @@ public FrontierGasCalculator() {
}

@Override
public long transactionIntrinsicGasCost(final Bytes payload, final boolean isContractCreate) {
public long transactionIntrinsicGasCost(
final Bytes payload, final boolean isContractCreation, final long evmGasUsed) {
final long dynamicIntrinsicGasCost =
dynamicIntrinsicGasCost(payload, isContractCreation, evmGasUsed);

if (dynamicIntrinsicGasCost == Long.MIN_VALUE || dynamicIntrinsicGasCost == Long.MAX_VALUE) {
return dynamicIntrinsicGasCost;
}
return clampedAdd(TX_BASE_COST, dynamicIntrinsicGasCost);
}

protected long dynamicIntrinsicGasCost(
final Bytes payload, final boolean isContractCreation, final long evmGasUsed) {
final int payloadSize = payload.size();
final long zeroBytes = zeroBytes(payload);
long cost = clampedAdd(callDataCost(payloadSize, zeroBytes), evmGasUsed);

if (cost == Long.MIN_VALUE || cost == Long.MAX_VALUE) {
return cost;
}

if (isContractCreation) {
cost = clampedAdd(cost, contractCreationCost(payloadSize));

if (cost == Long.MIN_VALUE || cost == Long.MAX_VALUE) {
return cost;
}
}

return cost;
}

protected long callDataCost(final long payloadSize, final long zeroBytes) {
return clampedAdd(
TX_DATA_NON_ZERO_COST * (payloadSize - zeroBytes), TX_DATA_ZERO_COST * zeroBytes);
}

protected static long zeroBytes(final Bytes payload) {
int zeros = 0;
for (int i = 0; i < payload.size(); i++) {
if (payload.get(i) == 0) {
++zeros;
}
}
final int nonZeros = payload.size() - zeros;

final long cost = TX_BASE_COST + TX_DATA_ZERO_COST * zeros + TX_DATA_NON_ZERO_COST * nonZeros;
return zeros;
}

return isContractCreate ? (cost + txCreateExtraGasCost()) : cost;
protected long contractCreationCost(final int ignored) {
return txCreateExtraGasCost();
}

/**
Expand Down Expand Up @@ -557,11 +594,6 @@ static long memoryCost(final long length) {
return clampedAdd(clampedMultiply(MEMORY_WORD_GAS_COST, length), base);
}

@Override
public long getMaximumTransactionCost(final int size) {
return TX_BASE_COST + TX_DATA_NON_ZERO_COST * size;
}

@Override
public long getMinimumTransactionCost() {
return TX_BASE_COST;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -544,10 +544,12 @@ default long modExpGasCost(final Bytes input) {
* encoded binary representation when stored on-chain.
*
* @param transactionPayload The encoded transaction, as bytes
* @param isContractCreate Is this transaction a contract creation transaction?
* @param isContractCreation Is this transaction a contract creation transaction?
* @param evmGasUsed The gas used by access lists and code delegation authorizations
* @return the transaction's intrinsic gas cost
*/
long transactionIntrinsicGasCost(Bytes transactionPayload, boolean isContractCreate);
long transactionIntrinsicGasCost(
Bytes transactionPayload, boolean isContractCreation, long evmGasUsed);

/**
* Returns the gas cost of the explicitly declared access list.
Expand Down Expand Up @@ -581,15 +583,6 @@ default long getMaxRefundQuotient() {
return 2;
}

/**
* Maximum Cost of a Transaction of a certain length.
*
* @param size the length of the transaction, in bytes
* @return the maximum gas cost
*/
// what would be the gas for a PMT with hash of all non-zeros
long getMaximumTransactionCost(int size);

/**
* Minimum gas cost of a transaction.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@
*/
package org.hyperledger.besu.evm.gascalculator;

import static org.hyperledger.besu.evm.internal.Words.clampedAdd;

import java.util.function.Supplier;

import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256;

/** The Istanbul gas calculator. */
public class IstanbulGasCalculator extends PetersburgGasCalculator {

private static final long TX_DATA_ZERO_COST = 4L;
private static final long ISTANBUL_TX_DATA_NON_ZERO_COST = 16L;
private static final long TX_BASE_COST = 21_000L;

private static final long SLOAD_GAS = 800L;
private static final long BALANCE_OPERATION_GAS_COST = 700L;
Expand All @@ -42,19 +42,9 @@ public class IstanbulGasCalculator extends PetersburgGasCalculator {
public IstanbulGasCalculator() {}

@Override
public long transactionIntrinsicGasCost(final Bytes payload, final boolean isContractCreation) {
int zeros = 0;
for (int i = 0; i < payload.size(); i++) {
if (payload.get(i) == 0) {
++zeros;
}
}
final int nonZeros = payload.size() - zeros;

final long cost =
TX_BASE_COST + (TX_DATA_ZERO_COST * zeros) + (ISTANBUL_TX_DATA_NON_ZERO_COST * nonZeros);

return isContractCreation ? (cost + txCreateExtraGasCost()) : cost;
protected long callDataCost(final long payloadSize, final long zeroBytes) {
return clampedAdd(
ISTANBUL_TX_DATA_NON_ZERO_COST * (payloadSize - zeroBytes), TX_DATA_ZERO_COST * zeroBytes);
}

@Override
Expand Down Expand Up @@ -136,9 +126,4 @@ public long getBalanceOperationGasCost() {
public long extCodeHashOperationGasCost() {
return EXTCODE_HASH_COST;
}

@Override
public long getMaximumTransactionCost(final int size) {
return TX_BASE_COST + (ISTANBUL_TX_DATA_NON_ZERO_COST * size);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@
package org.hyperledger.besu.evm.gascalculator;

import static org.hyperledger.besu.datatypes.Address.BLS12_MAP_FP2_TO_G2;
import static org.hyperledger.besu.evm.internal.Words.clampedAdd;

import org.hyperledger.besu.datatypes.CodeDelegation;

import org.apache.tuweni.bytes.Bytes;

/**
* Gas Calculator for Prague
*
Expand All @@ -26,6 +29,8 @@
* </UL>
*/
public class PragueGasCalculator extends CancunGasCalculator {
private static final long TOTAL_COST_FLOOR_PER_TOKEN = 10L;

final long existingAccountGasRefund;

/** Instantiates a new Prague Gas Calculator. */
Expand All @@ -52,4 +57,20 @@ public long delegateCodeGasCost(final int delegateCodeListLength) {
public long calculateDelegateCodeGasRefund(final long alreadyExistingAccounts) {
return existingAccountGasRefund * alreadyExistingAccounts;
}

@Override
public long transactionIntrinsicGasCost(
final Bytes payload, final boolean isContractCreation, final long evmGasUsed) {
final long dynamicIntrinsicGasCost =
dynamicIntrinsicGasCost(payload, isContractCreation, evmGasUsed);
final long totalCostFloor =
tokensInCallData(payload.size(), zeroBytes(payload)) * TOTAL_COST_FLOOR_PER_TOKEN;

return clampedAdd(TX_BASE_COST, Math.max(dynamicIntrinsicGasCost, totalCostFloor));
}

private long tokensInCallData(final long payloadSize, final long zeroBytes) {
// as defined in https://eips.ethereum.org/EIPS/eip-7623#specification
return clampedAdd(zeroBytes, (payloadSize - zeroBytes) * 4);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,8 @@
*/
package org.hyperledger.besu.evm.gascalculator;

import static org.hyperledger.besu.evm.internal.Words.clampedAdd;
import static org.hyperledger.besu.evm.internal.Words.numWords;

import org.apache.tuweni.bytes.Bytes;

/** The Shanghai gas calculator. */
public class ShanghaiGasCalculator extends LondonGasCalculator {

Expand All @@ -39,13 +36,8 @@ public ShanghaiGasCalculator() {
}

@Override
public long transactionIntrinsicGasCost(final Bytes payload, final boolean isContractCreation) {
long intrinsicGasCost = super.transactionIntrinsicGasCost(payload, isContractCreation);
if (isContractCreation) {
return clampedAdd(intrinsicGasCost, initcodeCost(payload.size()));
} else {
return intrinsicGasCost;
}
protected long contractCreationCost(final int initCodeLength) {
return txCreateExtraGasCost() + initcodeCost(initCodeLength);
}

@Override
Expand Down

0 comments on commit 5ffe63a

Please sign in to comment.