Skip to content

Commit 3735091

Browse files
daniellehrnersiladu
authored andcommitted
first draft for EIP-7623
Signed-off-by: Daniel Lehrner <[email protected]>
1 parent c05967a commit 3735091

File tree

11 files changed

+110
-76
lines changed

11 files changed

+110
-76
lines changed

ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/PluginEeaSendRawTransaction.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,6 @@ protected long getGasLimit(final PrivateTransaction privateTransaction, final St
8484
// choose the highest of the two options
8585
return Math.max(
8686
privateTransaction.getGasLimit(),
87-
gasCalculator.transactionIntrinsicGasCost(Bytes.fromBase64String(pmtPayload), false));
87+
gasCalculator.transactionIntrinsicGasCost(Bytes.fromBase64String(pmtPayload), false, 0));
8888
}
8989
}

ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import static org.hyperledger.besu.ethereum.mainnet.PrivateStateUtils.KEY_PRIVATE_METADATA_UPDATER;
1919
import static org.hyperledger.besu.ethereum.mainnet.PrivateStateUtils.KEY_TRANSACTION;
2020
import static org.hyperledger.besu.ethereum.mainnet.PrivateStateUtils.KEY_TRANSACTION_HASH;
21+
import static org.hyperledger.besu.evm.internal.Words.clampedAdd;
2122
import static org.hyperledger.besu.evm.operation.BlockHashOperation.BlockHashLookup;
2223

2324
import org.hyperledger.besu.collections.trie.BytesTrieSet;
@@ -372,22 +373,22 @@ public TransactionProcessingResult processTransaction(
372373
warmAddressList.add(miningBeneficiary);
373374
}
374375

375-
final long intrinsicGas =
376-
gasCalculator.transactionIntrinsicGasCost(
377-
transaction.getPayload(), transaction.isContractCreation());
378376
final long accessListGas =
379377
gasCalculator.accessListGasCost(accessListEntries.size(), accessListStorageCount);
380378
final long codeDelegationGas =
381379
gasCalculator.delegateCodeGasCost(transaction.codeDelegationListSize());
382-
final long gasAvailable =
383-
transaction.getGasLimit() - intrinsicGas - accessListGas - codeDelegationGas;
380+
final long intrinsicGas =
381+
gasCalculator.transactionIntrinsicGasCost(
382+
transaction.getPayload(),
383+
transaction.isContractCreation(),
384+
clampedAdd(accessListGas, codeDelegationGas));
385+
386+
final long gasAvailable = transaction.getGasLimit() - intrinsicGas;
384387
LOG.trace(
385-
"Gas available for execution {} = {} - {} - {} - {} (limit - intrinsic - accessList - codeDelegation)",
388+
"Gas available for execution {} = {} - {} (limit - intrinsic)",
386389
gasAvailable,
387390
transaction.getGasLimit(),
388-
intrinsicGas,
389-
accessListGas,
390-
codeDelegationGas);
391+
intrinsicGas);
391392

392393
final WorldUpdater worldUpdater = evmWorldUpdater.updater();
393394
final ImmutableMap.Builder<String, Object> contextVariablesBuilder =

ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package org.hyperledger.besu.ethereum.mainnet;
1616

1717
import static org.hyperledger.besu.evm.account.Account.MAX_NONCE;
18+
import static org.hyperledger.besu.evm.internal.Words.clampedAdd;
1819

1920
import org.hyperledger.besu.crypto.SECPSignature;
2021
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
@@ -252,11 +253,13 @@ private ValidationResult<TransactionInvalidReason> validateCostAndFee(
252253
}
253254
}
254255

256+
final long evmGasUsed =
257+
clampedAdd(
258+
transaction.getAccessList().map(gasCalculator::accessListGasCost).orElse(0L),
259+
gasCalculator.delegateCodeGasCost(transaction.codeDelegationListSize()));
255260
final long intrinsicGasCost =
256261
gasCalculator.transactionIntrinsicGasCost(
257-
transaction.getPayload(), transaction.isContractCreation())
258-
+ (transaction.getAccessList().map(gasCalculator::accessListGasCost).orElse(0L))
259-
+ gasCalculator.delegateCodeGasCost(transaction.codeDelegationListSize());
262+
transaction.getPayload(), transaction.isContractCreation(), evmGasUsed);
260263
if (Long.compareUnsigned(intrinsicGasCost, transaction.getGasLimit()) > 0) {
261264
return ValidationResult.invalid(
262265
TransactionInvalidReason.INTRINSIC_GAS_EXCEEDS_GAS_LIMIT,

ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -403,16 +403,20 @@ public void run() {
403403

404404
long txGas = gas;
405405
if (chargeIntrinsicGas) {
406-
final long intrinsicGasCost =
407-
protocolSpec
408-
.getGasCalculator()
409-
.transactionIntrinsicGasCost(tx.getPayload(), tx.isContractCreation());
410-
txGas -= intrinsicGasCost;
411406
final long accessListCost =
412407
tx.getAccessList()
413408
.map(list -> protocolSpec.getGasCalculator().accessListGasCost(list))
414409
.orElse(0L);
415-
txGas -= accessListCost;
410+
411+
final long delegateCodeCost =
412+
protocolSpec.getGasCalculator().delegateCodeGasCost(tx.codeDelegationListSize());
413+
414+
final long intrinsicGasCost =
415+
protocolSpec
416+
.getGasCalculator()
417+
.transactionIntrinsicGasCost(
418+
tx.getPayload(), tx.isContractCreation(), accessListCost + delegateCodeCost);
419+
txGas -= intrinsicGasCost;
416420
}
417421

418422
final EVM evm = protocolSpec.getEvm();

ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ static T8nResult runTest(
428428
gasUsed += transactionGasUsed;
429429
long intrinsicGas =
430430
gasCalculator.transactionIntrinsicGasCost(
431-
transaction.getPayload(), transaction.getTo().isEmpty());
431+
transaction.getPayload(), transaction.getTo().isEmpty(), 0);
432432
TransactionReceipt receipt =
433433
protocolSpec
434434
.getTransactionReceiptFactory()

ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/core/TransactionTest.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -192,10 +192,13 @@ public void milestone(
192192

193193
assertThat(transaction.getSender()).isEqualTo(expected.getSender());
194194
assertThat(transaction.getHash()).isEqualTo(expected.getHash());
195-
final long intrinsicGasCost =
196-
gasCalculator.transactionIntrinsicGasCost(
197-
transaction.getPayload(), transaction.isContractCreation())
198-
+ (transaction.getAccessList().map(gasCalculator::accessListGasCost).orElse(0L));
195+
final long evmGasUsed =
196+
transaction.getAccessList().map(gasCalculator::accessListGasCost).orElse(0L) +
197+
gasCalculator.delegateCodeGasCost(transaction.codeDelegationListSize());
198+
final long intrinsicGasCost = gasCalculator.transactionIntrinsicGasCost(
199+
transaction.getPayload(),
200+
transaction.isContractCreation(),
201+
evmGasUsed);
199202
assertThat(intrinsicGasCost).isEqualTo(expected.getIntrinsicGas());
200203
} catch (final Exception e) {
201204
if (expected.isSucceeds()) {

evm/src/main/java/org/hyperledger/besu/evm/gascalculator/FrontierGasCalculator.java

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public class FrontierGasCalculator implements GasCalculator {
3838

3939
private static final long TX_DATA_NON_ZERO_COST = 68L;
4040

41-
private static final long TX_BASE_COST = 21_000L;
41+
protected static final long TX_BASE_COST = 21_000L;
4242

4343
private static final long TX_CREATE_EXTRA_COST = 0L;
4444

@@ -128,18 +128,55 @@ public FrontierGasCalculator() {
128128
}
129129

130130
@Override
131-
public long transactionIntrinsicGasCost(final Bytes payload, final boolean isContractCreate) {
131+
public long transactionIntrinsicGasCost(
132+
final Bytes payload, final boolean isContractCreation, final long evmGasUsed) {
133+
final long dynamicIntrinsicGasCost =
134+
dynamicIntrinsicGasCost(payload, isContractCreation, evmGasUsed);
135+
136+
if (dynamicIntrinsicGasCost == Long.MIN_VALUE || dynamicIntrinsicGasCost == Long.MAX_VALUE) {
137+
return dynamicIntrinsicGasCost;
138+
}
139+
return clampedAdd(TX_BASE_COST, dynamicIntrinsicGasCost);
140+
}
141+
142+
protected long dynamicIntrinsicGasCost(
143+
final Bytes payload, final boolean isContractCreation, final long evmGasUsed) {
144+
final int payloadSize = payload.size();
145+
final long zeroBytes = zeroBytes(payload);
146+
long cost = clampedAdd(callDataCost(payloadSize, zeroBytes), evmGasUsed);
147+
148+
if (cost == Long.MIN_VALUE || cost == Long.MAX_VALUE) {
149+
return cost;
150+
}
151+
152+
if (isContractCreation) {
153+
cost = clampedAdd(cost, contractCreationCost(payloadSize));
154+
155+
if (cost == Long.MIN_VALUE || cost == Long.MAX_VALUE) {
156+
return cost;
157+
}
158+
}
159+
160+
return cost;
161+
}
162+
163+
protected long callDataCost(final long payloadSize, final long zeroBytes) {
164+
return clampedAdd(
165+
TX_DATA_NON_ZERO_COST * (payloadSize - zeroBytes), TX_DATA_ZERO_COST * zeroBytes);
166+
}
167+
168+
protected static long zeroBytes(final Bytes payload) {
132169
int zeros = 0;
133170
for (int i = 0; i < payload.size(); i++) {
134171
if (payload.get(i) == 0) {
135172
++zeros;
136173
}
137174
}
138-
final int nonZeros = payload.size() - zeros;
139-
140-
final long cost = TX_BASE_COST + TX_DATA_ZERO_COST * zeros + TX_DATA_NON_ZERO_COST * nonZeros;
175+
return zeros;
176+
}
141177

142-
return isContractCreate ? (cost + txCreateExtraGasCost()) : cost;
178+
protected long contractCreationCost(final int ignored) {
179+
return txCreateExtraGasCost();
143180
}
144181

145182
/**
@@ -557,11 +594,6 @@ static long memoryCost(final long length) {
557594
return clampedAdd(clampedMultiply(MEMORY_WORD_GAS_COST, length), base);
558595
}
559596

560-
@Override
561-
public long getMaximumTransactionCost(final int size) {
562-
return TX_BASE_COST + TX_DATA_NON_ZERO_COST * size;
563-
}
564-
565597
@Override
566598
public long getMinimumTransactionCost() {
567599
return TX_BASE_COST;

evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -542,10 +542,12 @@ default long modExpGasCost(final Bytes input) {
542542
* encoded binary representation when stored on-chain.
543543
*
544544
* @param transactionPayload The encoded transaction, as bytes
545-
* @param isContractCreate Is this transaction a contract creation transaction?
545+
* @param isContractCreation Is this transaction a contract creation transaction?
546+
* @param evmGasUsed The gas used by access lists and code delegation authorizations
546547
* @return the transaction's intrinsic gas cost
547548
*/
548-
long transactionIntrinsicGasCost(Bytes transactionPayload, boolean isContractCreate);
549+
long transactionIntrinsicGasCost(
550+
Bytes transactionPayload, boolean isContractCreation, long evmGasUsed);
549551

550552
/**
551553
* Returns the gas cost of the explicitly declared access list.
@@ -579,15 +581,6 @@ default long getMaxRefundQuotient() {
579581
return 2;
580582
}
581583

582-
/**
583-
* Maximum Cost of a Transaction of a certain length.
584-
*
585-
* @param size the length of the transaction, in bytes
586-
* @return the maximum gas cost
587-
*/
588-
// what would be the gas for a PMT with hash of all non-zeros
589-
long getMaximumTransactionCost(int size);
590-
591584
/**
592585
* Minimum gas cost of a transaction.
593586
*

evm/src/main/java/org/hyperledger/besu/evm/gascalculator/IstanbulGasCalculator.java

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,17 @@
1414
*/
1515
package org.hyperledger.besu.evm.gascalculator;
1616

17+
import static org.hyperledger.besu.evm.internal.Words.clampedAdd;
18+
1719
import java.util.function.Supplier;
1820

19-
import org.apache.tuweni.bytes.Bytes;
2021
import org.apache.tuweni.units.bigints.UInt256;
2122

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

2526
private static final long TX_DATA_ZERO_COST = 4L;
2627
private static final long ISTANBUL_TX_DATA_NON_ZERO_COST = 16L;
27-
private static final long TX_BASE_COST = 21_000L;
2828

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

4444
@Override
45-
public long transactionIntrinsicGasCost(final Bytes payload, final boolean isContractCreation) {
46-
int zeros = 0;
47-
for (int i = 0; i < payload.size(); i++) {
48-
if (payload.get(i) == 0) {
49-
++zeros;
50-
}
51-
}
52-
final int nonZeros = payload.size() - zeros;
53-
54-
final long cost =
55-
TX_BASE_COST + (TX_DATA_ZERO_COST * zeros) + (ISTANBUL_TX_DATA_NON_ZERO_COST * nonZeros);
56-
57-
return isContractCreation ? (cost + txCreateExtraGasCost()) : cost;
45+
protected long callDataCost(final long payloadSize, final long zeroBytes) {
46+
return clampedAdd(
47+
ISTANBUL_TX_DATA_NON_ZERO_COST * (payloadSize - zeroBytes), TX_DATA_ZERO_COST * zeroBytes);
5848
}
5949

6050
@Override
@@ -136,9 +126,4 @@ public long getBalanceOperationGasCost() {
136126
public long extCodeHashOperationGasCost() {
137127
return EXTCODE_HASH_COST;
138128
}
139-
140-
@Override
141-
public long getMaximumTransactionCost(final int size) {
142-
return TX_BASE_COST + (ISTANBUL_TX_DATA_NON_ZERO_COST * size);
143-
}
144129
}

evm/src/main/java/org/hyperledger/besu/evm/gascalculator/PragueGasCalculator.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@
1515
package org.hyperledger.besu.evm.gascalculator;
1616

1717
import static org.hyperledger.besu.datatypes.Address.BLS12_MAP_FP2_TO_G2;
18+
import static org.hyperledger.besu.evm.internal.Words.clampedAdd;
1819

1920
import org.hyperledger.besu.datatypes.CodeDelegation;
2021

22+
import org.apache.tuweni.bytes.Bytes;
23+
2124
/**
2225
* Gas Calculator for Prague
2326
*
@@ -26,6 +29,8 @@
2629
* </UL>
2730
*/
2831
public class PragueGasCalculator extends CancunGasCalculator {
32+
private static final long TOTAL_COST_FLOOR_PER_TOKEN = 10L;
33+
2934
final long existingAccountGasRefund;
3035

3136
/**
@@ -68,4 +73,20 @@ public long delegateCodeGasCost(final int delegateCodeListLength) {
6873
public long calculateDelegateCodeGasRefund(final long alreadyExistingAccounts) {
6974
return existingAccountGasRefund * alreadyExistingAccounts;
7075
}
76+
77+
@Override
78+
public long transactionIntrinsicGasCost(
79+
final Bytes payload, final boolean isContractCreation, final long evmGasUsed) {
80+
final long dynamicIntrinsicGasCost =
81+
dynamicIntrinsicGasCost(payload, isContractCreation, evmGasUsed);
82+
final long totalCostFloor =
83+
tokensInCallData(payload.size(), zeroBytes(payload)) * TOTAL_COST_FLOOR_PER_TOKEN;
84+
85+
return clampedAdd(TX_BASE_COST, Math.max(dynamicIntrinsicGasCost, totalCostFloor));
86+
}
87+
88+
private long tokensInCallData(final long payloadSize, final long zeroBytes) {
89+
// as defined in https://eips.ethereum.org/EIPS/eip-7623#specification
90+
return clampedAdd(zeroBytes, (payloadSize - zeroBytes) * 4);
91+
}
7192
}

0 commit comments

Comments
 (0)