Split Transaction Gas Calculation from EVM Calculation (#2659)

In preparation for the EVM library pull out the transaction related gas
calculations and move them into their own `TransactionGasCalculator.`

This has 4 calls right now, none of which occur inside the EVM:
* Intrinsic gas cost
* Code Deposit gas cost
* Max refund quotient
* Max Privacy Marker Transaction intrinsic gas cost.

Signed-off-by: Danno Ferrin <danno.ferrin@gmail.com>
pull/2661/head
Danno Ferrin 3 years ago committed by GitHub
parent 650b5a01b1
commit f9b17cf92b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/PluginEeaSendRawTransaction.java
  2. 2
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EeaJsonRpcMethods.java
  3. 7
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/PrivacyApiGroupJsonRpcMethods.java
  4. 2
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetTransactionReceiptTest.java
  5. 6
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/BaseEeaSendRawTransaction.java
  6. 2
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/eea/PluginEeaSendRawTransactionTest.java
  7. 40
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BerlinGasCalculator.java
  8. 67
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BerlinTransactionGasCalculator.java
  9. 18
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java
  10. 57
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/FrontierGasCalculator.java
  11. 79
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/FrontierTransactionGasCalculator.java
  12. 4
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/HomesteadTransactionGasCalculator.java
  13. 37
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/IstanbulGasCalculator.java
  14. 58
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/IstanbulTransactionGasCalculator.java
  15. 8
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/LondonGasCalculator.java
  16. 26
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/LondonTransactionGasCalculator.java
  17. 13
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetContractCreationProcessor.java
  18. 60
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java
  19. 8
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java
  20. 17
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java
  21. 14
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpec.java
  22. 35
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java
  23. 2
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/TangerineWhistleGasCalculator.java
  24. 67
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/TransactionGasCalculator.java
  25. 11
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateTransactionProcessor.java
  26. 3
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java
  27. 44
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/vm/GasCalculator.java
  28. 16
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/IntrinsicGasTest.java
  29. 20
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetContractCreationProcessorTest.java
  30. 2
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java
  31. 75
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java
  32. 2
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/EvmToolCommand.java
  33. 1
      ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/NoRewardProtocolScheduleWrapper.java

@ -18,12 +18,12 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.privacy.methods.Privac
import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.mainnet.TransactionGasCalculator;
import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.mainnet.ValidationResult;
import org.hyperledger.besu.ethereum.privacy.PrivacyController; import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import org.hyperledger.besu.ethereum.privacy.PrivateTransaction; import org.hyperledger.besu.ethereum.privacy.PrivateTransaction;
import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason;
import org.hyperledger.besu.ethereum.util.NonceProvider; import org.hyperledger.besu.ethereum.util.NonceProvider;
import org.hyperledger.besu.ethereum.vm.GasCalculator;
import org.hyperledger.besu.plugin.services.privacy.PrivateMarkerTransactionFactory; import org.hyperledger.besu.plugin.services.privacy.PrivateMarkerTransactionFactory;
import java.util.Optional; import java.util.Optional;
@ -34,7 +34,7 @@ import org.apache.tuweni.bytes.Bytes;
public class PluginEeaSendRawTransaction extends AbstractEeaSendRawTransaction { public class PluginEeaSendRawTransaction extends AbstractEeaSendRawTransaction {
private final PrivacyController privacyController; private final PrivacyController privacyController;
private final PrivacyIdProvider privacyIdProvider; private final PrivacyIdProvider privacyIdProvider;
private final GasCalculator gasCalculator; private final TransactionGasCalculator transactionGasCalculator;
public PluginEeaSendRawTransaction( public PluginEeaSendRawTransaction(
final TransactionPool transactionPool, final TransactionPool transactionPool,
@ -42,11 +42,11 @@ public class PluginEeaSendRawTransaction extends AbstractEeaSendRawTransaction {
final PrivateMarkerTransactionFactory privateMarkerTransactionFactory, final PrivateMarkerTransactionFactory privateMarkerTransactionFactory,
final NonceProvider publicNonceProvider, final NonceProvider publicNonceProvider,
final PrivacyController privacyController, final PrivacyController privacyController,
final GasCalculator gasCalculator) { final TransactionGasCalculator transactionGasCalculator) {
super(transactionPool, privacyIdProvider, privateMarkerTransactionFactory, publicNonceProvider); super(transactionPool, privacyIdProvider, privateMarkerTransactionFactory, publicNonceProvider);
this.privacyController = privacyController; this.privacyController = privacyController;
this.privacyIdProvider = privacyIdProvider; this.privacyIdProvider = privacyIdProvider;
this.gasCalculator = gasCalculator; this.transactionGasCalculator = transactionGasCalculator;
} }
@Override @Override
@ -81,7 +81,7 @@ public class PluginEeaSendRawTransaction extends AbstractEeaSendRawTransaction {
// choose the highest of the two options // choose the highest of the two options
return Math.max( return Math.max(
privateTransaction.getGasLimit(), privateTransaction.getGasLimit(),
gasCalculator transactionGasCalculator
.transactionIntrinsicGasCostAndAccessedState( .transactionIntrinsicGasCostAndAccessedState(
new Transaction.Builder() new Transaction.Builder()
.to(Address.PLUGIN_PRIVACY) .to(Address.PLUGIN_PRIVACY)

@ -65,7 +65,7 @@ public class EeaJsonRpcMethods extends PrivacyApiGroupJsonRpcMethods {
privateMarkerTransactionFactory, privateMarkerTransactionFactory,
nonceProvider, nonceProvider,
privacyController, privacyController,
getGasCalculator()), getTransactionGasCalculator()),
new PrivGetEeaTransactionCount(privacyController, privacyIdProvider)); new PrivGetEeaTransactionCount(privacyController, privacyIdProvider));
} else if (getPrivacyParameters().isOnchainPrivacyGroupsEnabled()) { } else if (getPrivacyParameters().isOnchainPrivacyGroupsEnabled()) {
return mapOf( return mapOf(

@ -24,6 +24,7 @@ import org.hyperledger.besu.ethereum.api.query.PrivacyQueries;
import org.hyperledger.besu.ethereum.core.PrivacyParameters; import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.TransactionGasCalculator;
import org.hyperledger.besu.ethereum.privacy.ChainHeadPrivateNonceProvider; import org.hyperledger.besu.ethereum.privacy.ChainHeadPrivateNonceProvider;
import org.hyperledger.besu.ethereum.privacy.PluginPrivacyController; import org.hyperledger.besu.ethereum.privacy.PluginPrivacyController;
import org.hyperledger.besu.ethereum.privacy.PrivacyController; import org.hyperledger.besu.ethereum.privacy.PrivacyController;
@ -92,6 +93,12 @@ public abstract class PrivacyApiGroupJsonRpcMethods extends ApiGroupJsonRpcMetho
.getGasCalculator(); .getGasCalculator();
} }
public TransactionGasCalculator getTransactionGasCalculator() {
return protocolSchedule
.getByBlockNumber(blockchainQueries.headBlockNumber())
.getTransactionGasCalculator();
}
@Override @Override
protected Map<String, JsonRpcMethod> create() { protected Map<String, JsonRpcMethod> create() {
final PrivateMarkerTransactionFactory markerTransactionFactory = final PrivateMarkerTransactionFactory markerTransactionFactory =

@ -107,6 +107,7 @@ public class EthGetTransactionReceiptTest {
null, null,
false, false,
null, null,
null,
GasLimitCalculator.constant(), GasLimitCalculator.constant(),
FeeMarket.legacy(), FeeMarket.legacy(),
null, null,
@ -132,6 +133,7 @@ public class EthGetTransactionReceiptTest {
null, null,
false, false,
null, null,
null,
GasLimitCalculator.constant(), GasLimitCalculator.constant(),
FeeMarket.legacy(), FeeMarket.legacy(),
null, null,

@ -23,12 +23,12 @@ import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.Wei; import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.ethereum.mainnet.BerlinGasCalculator; import org.hyperledger.besu.ethereum.mainnet.BerlinTransactionGasCalculator;
import org.hyperledger.besu.ethereum.mainnet.TransactionGasCalculator;
import org.hyperledger.besu.ethereum.privacy.PrivacyController; import org.hyperledger.besu.ethereum.privacy.PrivacyController;
import org.hyperledger.besu.ethereum.privacy.PrivateTransaction; import org.hyperledger.besu.ethereum.privacy.PrivateTransaction;
import org.hyperledger.besu.ethereum.privacy.markertransaction.FixedKeySigningPrivateMarkerTransactionFactory; import org.hyperledger.besu.ethereum.privacy.markertransaction.FixedKeySigningPrivateMarkerTransactionFactory;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import org.hyperledger.besu.ethereum.vm.GasCalculator;
import org.hyperledger.besu.plugin.data.Restriction; import org.hyperledger.besu.plugin.data.Restriction;
import org.hyperledger.besu.plugin.services.privacy.PrivateMarkerTransactionFactory; import org.hyperledger.besu.plugin.services.privacy.PrivateMarkerTransactionFactory;
@ -61,7 +61,7 @@ public class BaseEeaSendRawTransaction {
final PrivateMarkerTransactionFactory privateMarkerTransactionFactory = final PrivateMarkerTransactionFactory privateMarkerTransactionFactory =
new FixedKeySigningPrivateMarkerTransactionFactory(keyPair); new FixedKeySigningPrivateMarkerTransactionFactory(keyPair);
final GasCalculator gasCalculator = new BerlinGasCalculator(); final TransactionGasCalculator transactionGasCalculator = new BerlinTransactionGasCalculator();
final Transaction PUBLIC_ONCHAIN_TRANSACTION = final Transaction PUBLIC_ONCHAIN_TRANSACTION =
new Transaction( new Transaction(

@ -42,7 +42,7 @@ public class PluginEeaSendRawTransactionTest extends BaseEeaSendRawTransaction {
privateMarkerTransactionFactory, privateMarkerTransactionFactory,
address -> 0, address -> 0,
privacyController, privacyController,
gasCalculator); transactionGasCalculator);
} }
@Test @Test

@ -14,28 +14,18 @@
*/ */
package org.hyperledger.besu.ethereum.mainnet; package org.hyperledger.besu.ethereum.mainnet;
import static java.util.Collections.emptyList;
import static org.hyperledger.besu.ethereum.core.Address.BLAKE2B_F_COMPRESSION; import static org.hyperledger.besu.ethereum.core.Address.BLAKE2B_F_COMPRESSION;
import org.hyperledger.besu.ethereum.core.AccessListEntry;
import org.hyperledger.besu.ethereum.core.Account; import org.hyperledger.besu.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Gas; import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.GasAndAccessedState;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.Wei; import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.mainnet.precompiles.BigIntegerModularExponentiationPrecompiledContract; import org.hyperledger.besu.ethereum.mainnet.precompiles.BigIntegerModularExponentiationPrecompiledContract;
import org.hyperledger.besu.ethereum.vm.MessageFrame; import org.hyperledger.besu.ethereum.vm.MessageFrame;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256; import org.apache.tuweni.units.bigints.UInt256;
public class BerlinGasCalculator extends IstanbulGasCalculator { public class BerlinGasCalculator extends IstanbulGasCalculator {
@ -44,7 +34,6 @@ public class BerlinGasCalculator extends IstanbulGasCalculator {
private static final Gas COLD_SLOAD_COST = Gas.of(2100); private static final Gas COLD_SLOAD_COST = Gas.of(2100);
private static final Gas COLD_ACCOUNT_ACCESS_COST = Gas.of(2600); private static final Gas COLD_ACCOUNT_ACCESS_COST = Gas.of(2600);
private static final Gas WARM_STORAGE_READ_COST = Gas.of(100); private static final Gas WARM_STORAGE_READ_COST = Gas.of(100);
private static final Gas ACCESS_LIST_ADDRESS_COST = Gas.of(2400);
protected static final Gas ACCESS_LIST_STORAGE_COST = Gas.of(1900); protected static final Gas ACCESS_LIST_STORAGE_COST = Gas.of(1900);
// redefinitions for EIP-2929 // redefinitions for EIP-2929
@ -72,35 +61,6 @@ public class BerlinGasCalculator extends IstanbulGasCalculator {
this(BLAKE2B_F_COMPRESSION.toArrayUnsafe()[19]); this(BLAKE2B_F_COMPRESSION.toArrayUnsafe()[19]);
} }
@Override
public GasAndAccessedState transactionIntrinsicGasCostAndAccessedState(
final Transaction transaction) {
// As per https://eips.ethereum.org/EIPS/eip-2930
final List<AccessListEntry> accessList = transaction.getAccessList().orElse(emptyList());
long accessedStorageCount = 0;
final Set<Address> accessedAddresses = new HashSet<>();
final Multimap<Address, Bytes32> accessedStorage = HashMultimap.create();
for (final AccessListEntry accessListEntry : accessList) {
final Address address = accessListEntry.getAddress();
accessedAddresses.add(address);
for (final Bytes32 storageKeyBytes : accessListEntry.getStorageKeys()) {
accessedStorage.put(address, storageKeyBytes);
++accessedStorageCount;
}
}
return new GasAndAccessedState(
super.transactionIntrinsicGasCostAndAccessedState(transaction)
.getGas()
.plus(ACCESS_LIST_ADDRESS_COST.times(accessList.size()))
.plus(ACCESS_LIST_STORAGE_COST.times(accessedStorageCount)),
accessedAddresses,
accessedStorage);
}
@Override @Override
public boolean isPrecompile(final Address address) { public boolean isPrecompile(final Address address) {
final byte[] addressBytes = address.toArrayUnsafe(); final byte[] addressBytes = address.toArrayUnsafe();

@ -0,0 +1,67 @@
/*
* Copyright contributors to Hyperledger Besu
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.mainnet;
import static java.util.Collections.emptyList;
import org.hyperledger.besu.ethereum.core.AccessListEntry;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.GasAndAccessedState;
import org.hyperledger.besu.ethereum.core.Transaction;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import org.apache.tuweni.bytes.Bytes32;
public class BerlinTransactionGasCalculator extends IstanbulTransactionGasCalculator {
// new constants for EIP-2929
private static final Gas ACCESS_LIST_ADDRESS_COST = Gas.of(2400);
protected static final Gas ACCESS_LIST_STORAGE_COST = Gas.of(1900);
@Override
public GasAndAccessedState transactionIntrinsicGasCostAndAccessedState(
final Transaction transaction) {
// As per https://eips.ethereum.org/EIPS/eip-2930
final List<AccessListEntry> accessList = transaction.getAccessList().orElse(emptyList());
long accessedStorageCount = 0;
final Set<Address> accessedAddresses = new HashSet<>();
final Multimap<Address, Bytes32> accessedStorage = HashMultimap.create();
for (final AccessListEntry accessListEntry : accessList) {
final Address address = accessListEntry.getAddress();
accessedAddresses.add(address);
for (final Bytes32 storageKeyBytes : accessListEntry.getStorageKeys()) {
accessedStorage.put(address, storageKeyBytes);
++accessedStorageCount;
}
}
return new GasAndAccessedState(
super.transactionIntrinsicGasCostAndAccessedState(transaction)
.getGas()
.plus(ACCESS_LIST_ADDRESS_COST.times(accessList.size()))
.plus(ACCESS_LIST_STORAGE_COST.times(accessedStorageCount)),
accessedAddresses,
accessedStorage);
}
}

@ -56,9 +56,9 @@ public class ClassicProtocolSpecs {
contractSizeLimit, configStackSizeLimit, quorumCompatibilityMode) contractSizeLimit, configStackSizeLimit, quorumCompatibilityMode)
.gasCalculator(TangerineWhistleGasCalculator::new) .gasCalculator(TangerineWhistleGasCalculator::new)
.transactionValidatorBuilder( .transactionValidatorBuilder(
gasCalculator -> transactionGasCalculator ->
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, true, chainId, quorumCompatibilityMode)) transactionGasCalculator, true, chainId, quorumCompatibilityMode))
.name("ClassicTangerineWhistle"); .name("ClassicTangerineWhistle");
} }
@ -115,9 +115,9 @@ public class ClassicProtocolSpecs {
quorumCompatibilityMode) quorumCompatibilityMode)
.difficultyCalculator(ClassicDifficultyCalculators.DIFFICULTY_BOMB_REMOVED) .difficultyCalculator(ClassicDifficultyCalculators.DIFFICULTY_BOMB_REMOVED)
.transactionValidatorBuilder( .transactionValidatorBuilder(
gasCalculator -> transactionGasCalculator ->
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, true, chainId, quorumCompatibilityMode)) transactionGasCalculator, true, chainId, quorumCompatibilityMode))
.name("DefuseDifficultyBomb"); .name("DefuseDifficultyBomb");
} }
@ -150,20 +150,22 @@ public class ClassicProtocolSpecs {
? ClassicProtocolSpecs::byzantiumTransactionReceiptFactoryWithReasonEnabled ? ClassicProtocolSpecs::byzantiumTransactionReceiptFactoryWithReasonEnabled
: ClassicProtocolSpecs::byzantiumTransactionReceiptFactory) : ClassicProtocolSpecs::byzantiumTransactionReceiptFactory)
.contractCreationProcessorBuilder( .contractCreationProcessorBuilder(
(gasCalculator, evm) -> (transactionGasCalculator, evm) ->
new MainnetContractCreationProcessor( new MainnetContractCreationProcessor(
gasCalculator, transactionGasCalculator,
evm, evm,
true, true,
Collections.singletonList(MaxCodeSizeRule.of(contractSizeLimit)), Collections.singletonList(MaxCodeSizeRule.of(contractSizeLimit)),
1)) 1))
.transactionProcessorBuilder( .transactionProcessorBuilder(
(gasCalculator, (gasCalculator,
transactionGasCalculator,
transactionValidator, transactionValidator,
contractCreationProcessor, contractCreationProcessor,
messageCallProcessor) -> messageCallProcessor) ->
new MainnetTransactionProcessor( new MainnetTransactionProcessor(
gasCalculator, gasCalculator,
transactionGasCalculator,
transactionValidator, transactionValidator,
contractCreationProcessor, contractCreationProcessor,
messageCallProcessor, messageCallProcessor,
@ -300,9 +302,9 @@ public class ClassicProtocolSpecs {
quorumCompatibilityMode) quorumCompatibilityMode)
.gasCalculator(BerlinGasCalculator::new) .gasCalculator(BerlinGasCalculator::new)
.transactionValidatorBuilder( .transactionValidatorBuilder(
gasCalculator -> transactionGasCalculator ->
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, transactionGasCalculator,
true, true,
chainId, chainId,
Set.of(TransactionType.FRONTIER, TransactionType.ACCESS_LIST), Set.of(TransactionType.FRONTIER, TransactionType.ACCESS_LIST),

@ -17,8 +17,6 @@ package org.hyperledger.besu.ethereum.mainnet;
import org.hyperledger.besu.ethereum.core.Account; import org.hyperledger.besu.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Gas; import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.GasAndAccessedState;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.Wei; import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.vm.GasCalculator; import org.hyperledger.besu.ethereum.vm.GasCalculator;
import org.hyperledger.besu.ethereum.vm.MessageFrame; import org.hyperledger.besu.ethereum.vm.MessageFrame;
@ -31,16 +29,6 @@ import org.apache.tuweni.units.bigints.UInt256;
public class FrontierGasCalculator implements GasCalculator { public class FrontierGasCalculator implements GasCalculator {
private static final Gas TX_DATA_ZERO_COST = Gas.of(4L);
private static final Gas TX_DATA_NON_ZERO_COST = Gas.of(68L);
private static final Gas TX_BASE_COST = Gas.of(21_000L);
private static final Gas TX_CREATE_EXTRA_COST = Gas.of(0L);
private static final Gas CODE_DEPOSIT_BYTE_COST = Gas.of(200L);
private static final Gas ID_PRECOMPILED_BASE_GAS_COST = Gas.of(15L); private static final Gas ID_PRECOMPILED_BASE_GAS_COST = Gas.of(15L);
private static final Gas ID_PRECOMPILED_WORD_GAS_COST = Gas.of(3L); private static final Gas ID_PRECOMPILED_WORD_GAS_COST = Gas.of(3L);
@ -113,44 +101,6 @@ public class FrontierGasCalculator implements GasCalculator {
private static final Gas SELF_DESTRUCT_REFUND_AMOUNT = Gas.of(24_000L); private static final Gas SELF_DESTRUCT_REFUND_AMOUNT = Gas.of(24_000L);
@Override
public GasAndAccessedState transactionIntrinsicGasCostAndAccessedState(
final Transaction transaction) {
final Bytes payload = transaction.getPayload();
int zeros = 0;
for (int i = 0; i < payload.size(); i++) {
if (payload.get(i) == 0) {
++zeros;
}
}
final int nonZeros = payload.size() - zeros;
Gas cost =
TX_BASE_COST
.plus(TX_DATA_ZERO_COST.times(zeros))
.plus(TX_DATA_NON_ZERO_COST.times(nonZeros));
if (transaction.isContractCreation()) {
cost = cost.plus(txCreateExtraGasCost());
}
return new GasAndAccessedState(cost);
}
/**
* Returns the additional gas cost for contract creation transactions
*
* @return the additional gas cost for contract creation transactions
*/
protected Gas txCreateExtraGasCost() {
return TX_CREATE_EXTRA_COST;
}
@Override
public Gas codeDepositGasCost(final int codeSize) {
return CODE_DEPOSIT_BYTE_COST.times(codeSize);
}
@Override @Override
public Gas idPrecompiledContractGasCost(final Bytes input) { public Gas idPrecompiledContractGasCost(final Bytes input) {
return ID_PRECOMPILED_WORD_GAS_COST return ID_PRECOMPILED_WORD_GAS_COST
@ -467,11 +417,4 @@ public class FrontierGasCalculator implements GasCalculator {
return MEMORY_WORD_GAS_COST.times(len).plus(base); return MEMORY_WORD_GAS_COST.times(len).plus(base);
} }
@Override
public Gas getMaximumPmtCost() {
// what would be the gas for PMT with hash of all non-zeros
int nonZeros = 64;
return TX_BASE_COST.plus(TX_DATA_NON_ZERO_COST.times(nonZeros));
}
} }

@ -0,0 +1,79 @@
/*
* Copyright contributors to Hyperledger Besu
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.mainnet;
import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.GasAndAccessedState;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.apache.tuweni.bytes.Bytes;
public class FrontierTransactionGasCalculator implements TransactionGasCalculator {
private static final Gas TX_DATA_ZERO_COST = Gas.of(4L);
private static final Gas TX_DATA_NON_ZERO_COST = Gas.of(68L);
private static final Gas TX_BASE_COST = Gas.of(21_000L);
private static final Gas TX_CREATE_EXTRA_COST = Gas.of(0L);
private static final Gas CODE_DEPOSIT_BYTE_COST = Gas.of(200L);
@Override
public GasAndAccessedState transactionIntrinsicGasCostAndAccessedState(
final Transaction transaction) {
final Bytes payload = transaction.getPayload();
int zeros = 0;
for (int i = 0; i < payload.size(); i++) {
if (payload.get(i) == 0) {
++zeros;
}
}
final int nonZeros = payload.size() - zeros;
Gas cost =
TX_BASE_COST
.plus(TX_DATA_ZERO_COST.times(zeros))
.plus(TX_DATA_NON_ZERO_COST.times(nonZeros));
if (transaction.isContractCreation()) {
cost = cost.plus(txCreateExtraGasCost());
}
return new GasAndAccessedState(cost);
}
/**
* Returns the additional gas cost for contract creation transactions
*
* @return the additional gas cost for contract creation transactions
*/
protected Gas txCreateExtraGasCost() {
return TX_CREATE_EXTRA_COST;
}
@Override
public Gas codeDepositGasCost(final int codeSize) {
return CODE_DEPOSIT_BYTE_COST.times(codeSize);
}
@Override
public Gas getMaximumPmtCost() {
// what would be the gas for PMT with hash of all non-zeros
int nonZeros = 64;
return TX_BASE_COST.plus(TX_DATA_NON_ZERO_COST.times(nonZeros));
}
}

@ -1,5 +1,5 @@
/* /*
* Copyright ConsenSys AG. * Copyright contributors to Hyperledger Besu
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
@ -16,7 +16,7 @@ package org.hyperledger.besu.ethereum.mainnet;
import org.hyperledger.besu.ethereum.core.Gas; import org.hyperledger.besu.ethereum.core.Gas;
public class HomesteadGasCalculator extends FrontierGasCalculator { public class HomesteadTransactionGasCalculator extends FrontierTransactionGasCalculator {
private static final Gas TX_CREATE_EXTRA = Gas.of(32_000L); private static final Gas TX_CREATE_EXTRA = Gas.of(32_000L);

@ -16,18 +16,11 @@ package org.hyperledger.besu.ethereum.mainnet;
import org.hyperledger.besu.ethereum.core.Account; import org.hyperledger.besu.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Gas; import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.GasAndAccessedState;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256; import org.apache.tuweni.units.bigints.UInt256;
public class IstanbulGasCalculator extends PetersburgGasCalculator { public class IstanbulGasCalculator extends PetersburgGasCalculator {
private static final Gas TX_DATA_ZERO_COST = Gas.of(4L);
private static final Gas ISTANBUL_TX_DATA_NON_ZERO_COST = Gas.of(16L);
private static final Gas TX_BASE_COST = Gas.of(21_000L);
private static final Gas SLOAD_GAS = Gas.of(800); private static final Gas SLOAD_GAS = Gas.of(800);
private static final Gas BALANCE_OPERATION_GAS_COST = Gas.of(700); private static final Gas BALANCE_OPERATION_GAS_COST = Gas.of(700);
private static final Gas EXTCODE_HASH_COST = Gas.of(700); private static final Gas EXTCODE_HASH_COST = Gas.of(700);
@ -40,30 +33,6 @@ public class IstanbulGasCalculator extends PetersburgGasCalculator {
private static final Gas SSTORE_RESET_GAS_LESS_SLOAD_GAS = SSTORE_RESET_GAS.minus(SLOAD_GAS); private static final Gas SSTORE_RESET_GAS_LESS_SLOAD_GAS = SSTORE_RESET_GAS.minus(SLOAD_GAS);
private static final Gas NEGATIVE_SSTORE_CLEARS_SCHEDULE = Gas.ZERO.minus(SSTORE_CLEARS_SCHEDULE); private static final Gas NEGATIVE_SSTORE_CLEARS_SCHEDULE = Gas.ZERO.minus(SSTORE_CLEARS_SCHEDULE);
@Override
public GasAndAccessedState transactionIntrinsicGasCostAndAccessedState(
final Transaction transaction) {
final Bytes payload = transaction.getPayload();
int zeros = 0;
for (int i = 0; i < payload.size(); i++) {
if (payload.get(i) == 0) {
++zeros;
}
}
final int nonZeros = payload.size() - zeros;
Gas cost =
TX_BASE_COST
.plus(TX_DATA_ZERO_COST.times(zeros))
.plus(ISTANBUL_TX_DATA_NON_ZERO_COST.times(nonZeros));
if (transaction.isContractCreation()) {
cost = cost.plus(txCreateExtraGasCost());
}
return new GasAndAccessedState(cost);
}
@Override @Override
// As per https://eips.ethereum.org/EIPS/eip-2200 // As per https://eips.ethereum.org/EIPS/eip-2200
public Gas calculateStorageCost( public Gas calculateStorageCost(
@ -139,10 +108,4 @@ public class IstanbulGasCalculator extends PetersburgGasCalculator {
public Gas extCodeHashOperationGasCost() { public Gas extCodeHashOperationGasCost() {
return EXTCODE_HASH_COST; return EXTCODE_HASH_COST;
} }
@Override
public Gas getMaximumPmtCost() {
int nonZeros = 64;
return TX_BASE_COST.plus(ISTANBUL_TX_DATA_NON_ZERO_COST.times(nonZeros));
}
} }

@ -0,0 +1,58 @@
/*
* Copyright contributors to Hyperledger Besu
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.mainnet;
import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.GasAndAccessedState;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.apache.tuweni.bytes.Bytes;
public class IstanbulTransactionGasCalculator extends HomesteadTransactionGasCalculator {
private static final Gas TX_DATA_ZERO_COST = Gas.of(4L);
private static final Gas ISTANBUL_TX_DATA_NON_ZERO_COST = Gas.of(16L);
private static final Gas TX_BASE_COST = Gas.of(21_000L);
@Override
public GasAndAccessedState transactionIntrinsicGasCostAndAccessedState(
final Transaction transaction) {
final Bytes payload = transaction.getPayload();
int zeros = 0;
for (int i = 0; i < payload.size(); i++) {
if (payload.get(i) == 0) {
++zeros;
}
}
final int nonZeros = payload.size() - zeros;
Gas cost =
TX_BASE_COST
.plus(TX_DATA_ZERO_COST.times(zeros))
.plus(ISTANBUL_TX_DATA_NON_ZERO_COST.times(nonZeros));
if (transaction.isContractCreation()) {
cost = cost.plus(txCreateExtraGasCost());
}
return new GasAndAccessedState(cost);
}
@Override
public Gas getMaximumPmtCost() {
int nonZeros = 64;
return TX_BASE_COST.plus(ISTANBUL_TX_DATA_NON_ZERO_COST.times(nonZeros));
}
}

@ -26,9 +26,6 @@ public class LondonGasCalculator extends BerlinGasCalculator {
private static final Gas NEGATIVE_SSTORE_CLEARS_SCHEDULE = Gas.ZERO.minus(SSTORE_CLEARS_SCHEDULE); private static final Gas NEGATIVE_SSTORE_CLEARS_SCHEDULE = Gas.ZERO.minus(SSTORE_CLEARS_SCHEDULE);
// redefinitions for EIP-3529
private static final int NEW_MAX_REFUND_QUOTIENT = 5;
protected LondonGasCalculator() {} protected LondonGasCalculator() {}
// Redefined refund amount from EIP-3529 // Redefined refund amount from EIP-3529
@ -76,9 +73,4 @@ public class LondonGasCalculator extends BerlinGasCalculator {
} }
} }
} }
@Override
public long getMaxRefundQuotient() {
return NEW_MAX_REFUND_QUOTIENT;
}
} }

@ -0,0 +1,26 @@
/*
* Copyright contributors to Hyperledger Besu
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.mainnet;
public class LondonTransactionGasCalculator extends BerlinTransactionGasCalculator {
// redefinitions for EIP-3529
private static final int NEW_MAX_REFUND_QUOTIENT = 5;
@Override
public long getMaxRefundQuotient() {
return NEW_MAX_REFUND_QUOTIENT;
}
}

@ -21,7 +21,6 @@ import org.hyperledger.besu.ethereum.core.ModificationNotAllowedException;
import org.hyperledger.besu.ethereum.core.MutableAccount; import org.hyperledger.besu.ethereum.core.MutableAccount;
import org.hyperledger.besu.ethereum.vm.EVM; import org.hyperledger.besu.ethereum.vm.EVM;
import org.hyperledger.besu.ethereum.vm.ExceptionalHaltReason; import org.hyperledger.besu.ethereum.vm.ExceptionalHaltReason;
import org.hyperledger.besu.ethereum.vm.GasCalculator;
import org.hyperledger.besu.ethereum.vm.MessageFrame; import org.hyperledger.besu.ethereum.vm.MessageFrame;
import org.hyperledger.besu.ethereum.vm.OperationTracer; import org.hyperledger.besu.ethereum.vm.OperationTracer;
@ -41,34 +40,34 @@ public class MainnetContractCreationProcessor extends AbstractMessageProcessor {
private final boolean requireCodeDepositToSucceed; private final boolean requireCodeDepositToSucceed;
private final GasCalculator gasCalculator; private final TransactionGasCalculator transactionGasCalculator;
private final long initialContractNonce; private final long initialContractNonce;
private final List<ContractValidationRule> contractValidationRules; private final List<ContractValidationRule> contractValidationRules;
public MainnetContractCreationProcessor( public MainnetContractCreationProcessor(
final GasCalculator gasCalculator, final TransactionGasCalculator transactionGasCalculator,
final EVM evm, final EVM evm,
final boolean requireCodeDepositToSucceed, final boolean requireCodeDepositToSucceed,
final List<ContractValidationRule> contractValidationRules, final List<ContractValidationRule> contractValidationRules,
final long initialContractNonce, final long initialContractNonce,
final Collection<Address> forceCommitAddresses) { final Collection<Address> forceCommitAddresses) {
super(evm, forceCommitAddresses); super(evm, forceCommitAddresses);
this.gasCalculator = gasCalculator; this.transactionGasCalculator = transactionGasCalculator;
this.requireCodeDepositToSucceed = requireCodeDepositToSucceed; this.requireCodeDepositToSucceed = requireCodeDepositToSucceed;
this.contractValidationRules = contractValidationRules; this.contractValidationRules = contractValidationRules;
this.initialContractNonce = initialContractNonce; this.initialContractNonce = initialContractNonce;
} }
public MainnetContractCreationProcessor( public MainnetContractCreationProcessor(
final GasCalculator gasCalculator, final TransactionGasCalculator transactionGasCalculator,
final EVM evm, final EVM evm,
final boolean requireCodeDepositToSucceed, final boolean requireCodeDepositToSucceed,
final List<ContractValidationRule> contractValidationRules, final List<ContractValidationRule> contractValidationRules,
final long initialContractNonce) { final long initialContractNonce) {
this( this(
gasCalculator, transactionGasCalculator,
evm, evm,
requireCodeDepositToSucceed, requireCodeDepositToSucceed,
contractValidationRules, contractValidationRules,
@ -117,7 +116,7 @@ public class MainnetContractCreationProcessor extends AbstractMessageProcessor {
protected void codeSuccess(final MessageFrame frame, final OperationTracer operationTracer) { protected void codeSuccess(final MessageFrame frame, final OperationTracer operationTracer) {
final Bytes contractCode = frame.getOutputData(); final Bytes contractCode = frame.getOutputData();
final Gas depositFee = gasCalculator.codeDepositGasCost(contractCode.size()); final Gas depositFee = transactionGasCalculator.codeDepositGasCost(contractCode.size());
if (frame.getRemainingGas().compareTo(depositFee) < 0) { if (frame.getRemainingGas().compareTo(depositFee) < 0) {
LOG.trace( LOG.trace(

@ -92,29 +92,32 @@ public abstract class MainnetProtocolSpecs {
final int stackSizeLimit = configStackSizeLimit.orElse(MessageFrame.DEFAULT_MAX_STACK_SIZE); final int stackSizeLimit = configStackSizeLimit.orElse(MessageFrame.DEFAULT_MAX_STACK_SIZE);
return new ProtocolSpecBuilder() return new ProtocolSpecBuilder()
.gasCalculator(FrontierGasCalculator::new) .gasCalculator(FrontierGasCalculator::new)
.transactionGasCalculator(new FrontierTransactionGasCalculator())
.gasLimitCalculator(new FrontierTargetingGasLimitCalculator()) .gasLimitCalculator(new FrontierTargetingGasLimitCalculator())
.evmBuilder(MainnetEvmRegistries::frontier) .evmBuilder(MainnetEvmRegistries::frontier)
.precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::frontier) .precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::frontier)
.messageCallProcessorBuilder(MainnetMessageCallProcessor::new) .messageCallProcessorBuilder(MainnetMessageCallProcessor::new)
.contractCreationProcessorBuilder( .contractCreationProcessorBuilder(
(gasCalculator, evm) -> (transactionGasCalculator, evm) ->
new MainnetContractCreationProcessor( new MainnetContractCreationProcessor(
gasCalculator, transactionGasCalculator,
evm, evm,
false, false,
Collections.singletonList(MaxCodeSizeRule.of(contractSizeLimit)), Collections.singletonList(MaxCodeSizeRule.of(contractSizeLimit)),
0)) 0))
.transactionValidatorBuilder( .transactionValidatorBuilder(
gasCalculator -> transactionGasCalculator ->
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, false, Optional.empty(), goQuorumMode)) transactionGasCalculator, false, Optional.empty(), goQuorumMode))
.transactionProcessorBuilder( .transactionProcessorBuilder(
(gasCalculator, (gasCalculator,
transactionGasCalculator,
transactionValidator, transactionValidator,
contractCreationProcessor, contractCreationProcessor,
messageCallProcessor) -> messageCallProcessor) ->
new MainnetTransactionProcessor( new MainnetTransactionProcessor(
gasCalculator, gasCalculator,
transactionGasCalculator,
transactionValidator, transactionValidator,
contractCreationProcessor, contractCreationProcessor,
messageCallProcessor, messageCallProcessor,
@ -123,13 +126,13 @@ public abstract class MainnetProtocolSpecs {
FeeMarket.legacy(), FeeMarket.legacy(),
CoinbaseFeePriceCalculator.frontier())) CoinbaseFeePriceCalculator.frontier()))
.privateTransactionProcessorBuilder( .privateTransactionProcessorBuilder(
(gasCalculator, (transactionGasCalculator,
transactionValidator, transactionValidator,
contractCreationProcessor, contractCreationProcessor,
messageCallProcessor, messageCallProcessor,
privateTransactionValidator) -> privateTransactionValidator) ->
new PrivateTransactionProcessor( new PrivateTransactionProcessor(
gasCalculator, transactionGasCalculator,
transactionValidator, transactionValidator,
contractCreationProcessor, contractCreationProcessor,
messageCallProcessor, messageCallProcessor,
@ -196,20 +199,20 @@ public abstract class MainnetProtocolSpecs {
final int contractSizeLimit = configContractSizeLimit.orElse(FRONTIER_CONTRACT_SIZE_LIMIT); final int contractSizeLimit = configContractSizeLimit.orElse(FRONTIER_CONTRACT_SIZE_LIMIT);
return frontierDefinition( return frontierDefinition(
configContractSizeLimit, configStackSizeLimit, quorumCompatibilityMode) configContractSizeLimit, configStackSizeLimit, quorumCompatibilityMode)
.gasCalculator(HomesteadGasCalculator::new) .transactionGasCalculator(new HomesteadTransactionGasCalculator())
.evmBuilder(MainnetEvmRegistries::homestead) .evmBuilder(MainnetEvmRegistries::homestead)
.contractCreationProcessorBuilder( .contractCreationProcessorBuilder(
(gasCalculator, evm) -> (transactionGasCalculator, evm) ->
new MainnetContractCreationProcessor( new MainnetContractCreationProcessor(
gasCalculator, transactionGasCalculator,
evm, evm,
true, true,
Collections.singletonList(MaxCodeSizeRule.of(contractSizeLimit)), Collections.singletonList(MaxCodeSizeRule.of(contractSizeLimit)),
0)) 0))
.transactionValidatorBuilder( .transactionValidatorBuilder(
gasCalculator -> transactionGasCalculator ->
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, true, Optional.empty(), quorumCompatibilityMode)) transactionGasCalculator, true, Optional.empty(), quorumCompatibilityMode))
.difficultyCalculator(MainnetDifficultyCalculators.HOMESTEAD) .difficultyCalculator(MainnetDifficultyCalculators.HOMESTEAD)
.name("Homestead"); .name("Homestead");
} }
@ -277,25 +280,27 @@ public abstract class MainnetProtocolSpecs {
precompileContractRegistry, precompileContractRegistry,
SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES)) SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES))
.contractCreationProcessorBuilder( .contractCreationProcessorBuilder(
(gasCalculator, evm) -> (transactionGasCalculator, evm) ->
new MainnetContractCreationProcessor( new MainnetContractCreationProcessor(
gasCalculator, transactionGasCalculator,
evm, evm,
true, true,
Collections.singletonList(MaxCodeSizeRule.of(contractSizeLimit)), Collections.singletonList(MaxCodeSizeRule.of(contractSizeLimit)),
1, 1,
SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES)) SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES))
.transactionValidatorBuilder( .transactionValidatorBuilder(
gasCalculator -> transactionGasCalculator ->
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, true, chainId, quorumCompatibilityMode)) transactionGasCalculator, true, chainId, quorumCompatibilityMode))
.transactionProcessorBuilder( .transactionProcessorBuilder(
(gasCalculator, (gasCalculator,
transactionGasCalculator,
transactionValidator, transactionValidator,
contractCreationProcessor, contractCreationProcessor,
messageCallProcessor) -> messageCallProcessor) ->
new MainnetTransactionProcessor( new MainnetTransactionProcessor(
gasCalculator, gasCalculator,
transactionGasCalculator,
transactionValidator, transactionValidator,
contractCreationProcessor, contractCreationProcessor,
messageCallProcessor, messageCallProcessor,
@ -326,13 +331,13 @@ public abstract class MainnetProtocolSpecs {
.blockReward(BYZANTIUM_BLOCK_REWARD) .blockReward(BYZANTIUM_BLOCK_REWARD)
.privateTransactionValidatorBuilder(() -> new PrivateTransactionValidator(chainId)) .privateTransactionValidatorBuilder(() -> new PrivateTransactionValidator(chainId))
.privateTransactionProcessorBuilder( .privateTransactionProcessorBuilder(
(gasCalculator, (transactionGasCalculator,
transactionValidator, transactionValidator,
contractCreationProcessor, contractCreationProcessor,
messageCallProcessor, messageCallProcessor,
privateTransactionValidator) -> privateTransactionValidator) ->
new PrivateTransactionProcessor( new PrivateTransactionProcessor(
gasCalculator, transactionGasCalculator,
transactionValidator, transactionValidator,
contractCreationProcessor, contractCreationProcessor,
messageCallProcessor, messageCallProcessor,
@ -392,14 +397,15 @@ public abstract class MainnetProtocolSpecs {
enableRevertReason, enableRevertReason,
quorumCompatibilityMode) quorumCompatibilityMode)
.gasCalculator(IstanbulGasCalculator::new) .gasCalculator(IstanbulGasCalculator::new)
.transactionGasCalculator(new IstanbulTransactionGasCalculator())
.evmBuilder( .evmBuilder(
gasCalculator -> gasCalculator ->
MainnetEvmRegistries.istanbul(gasCalculator, chainId.orElse(BigInteger.ZERO))) MainnetEvmRegistries.istanbul(gasCalculator, chainId.orElse(BigInteger.ZERO)))
.precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::istanbul) .precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::istanbul)
.contractCreationProcessorBuilder( .contractCreationProcessorBuilder(
(gasCalculator, evm) -> (transactionGasCalculator, evm) ->
new MainnetContractCreationProcessor( new MainnetContractCreationProcessor(
gasCalculator, transactionGasCalculator,
evm, evm,
true, true,
Collections.singletonList(MaxCodeSizeRule.of(contractSizeLimit)), Collections.singletonList(MaxCodeSizeRule.of(contractSizeLimit)),
@ -437,10 +443,11 @@ public abstract class MainnetProtocolSpecs {
enableRevertReason, enableRevertReason,
quorumCompatibilityMode) quorumCompatibilityMode)
.gasCalculator(BerlinGasCalculator::new) .gasCalculator(BerlinGasCalculator::new)
.transactionGasCalculator(new BerlinTransactionGasCalculator())
.transactionValidatorBuilder( .transactionValidatorBuilder(
gasCalculator -> transactionGasCalculator ->
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, transactionGasCalculator,
true, true,
chainId, chainId,
Set.of(TransactionType.FRONTIER, TransactionType.ACCESS_LIST), Set.of(TransactionType.FRONTIER, TransactionType.ACCESS_LIST),
@ -472,12 +479,13 @@ public abstract class MainnetProtocolSpecs {
enableRevertReason, enableRevertReason,
quorumCompatibilityMode) quorumCompatibilityMode)
.gasCalculator(LondonGasCalculator::new) .gasCalculator(LondonGasCalculator::new)
.transactionGasCalculator(new LondonTransactionGasCalculator())
.gasLimitCalculator( .gasLimitCalculator(
new LondonTargetingGasLimitCalculator(londonForkBlockNumber, londonFeeMarket)) new LondonTargetingGasLimitCalculator(londonForkBlockNumber, londonFeeMarket))
.transactionValidatorBuilder( .transactionValidatorBuilder(
gasCalculator -> transactionGasCalculator ->
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, transactionGasCalculator,
londonFeeMarket, londonFeeMarket,
true, true,
chainId, chainId,
@ -488,11 +496,13 @@ public abstract class MainnetProtocolSpecs {
quorumCompatibilityMode)) quorumCompatibilityMode))
.transactionProcessorBuilder( .transactionProcessorBuilder(
(gasCalculator, (gasCalculator,
transactionGasCalculator,
transactionValidator, transactionValidator,
contractCreationProcessor, contractCreationProcessor,
messageCallProcessor) -> messageCallProcessor) ->
new MainnetTransactionProcessor( new MainnetTransactionProcessor(
gasCalculator, gasCalculator,
transactionGasCalculator,
transactionValidator, transactionValidator,
contractCreationProcessor, contractCreationProcessor,
messageCallProcessor, messageCallProcessor,
@ -501,9 +511,9 @@ public abstract class MainnetProtocolSpecs {
londonFeeMarket, londonFeeMarket,
CoinbaseFeePriceCalculator.eip1559())) CoinbaseFeePriceCalculator.eip1559()))
.contractCreationProcessorBuilder( .contractCreationProcessorBuilder(
(gasCalculator, evm) -> (transactionGasCalculator, evm) ->
new MainnetContractCreationProcessor( new MainnetContractCreationProcessor(
gasCalculator, transactionGasCalculator,
evm, evm,
true, true,
List.of(MaxCodeSizeRule.of(contractSizeLimit), PrefixCodeRule.of()), List.of(MaxCodeSizeRule.of(contractSizeLimit), PrefixCodeRule.of()),

@ -53,6 +53,8 @@ public class MainnetTransactionProcessor {
protected final GasCalculator gasCalculator; protected final GasCalculator gasCalculator;
protected final TransactionGasCalculator transactionGasCalculator;
protected final MainnetTransactionValidator transactionValidator; protected final MainnetTransactionValidator transactionValidator;
private final AbstractMessageProcessor contractCreationProcessor; private final AbstractMessageProcessor contractCreationProcessor;
@ -218,6 +220,7 @@ public class MainnetTransactionProcessor {
public MainnetTransactionProcessor( public MainnetTransactionProcessor(
final GasCalculator gasCalculator, final GasCalculator gasCalculator,
final TransactionGasCalculator transacitonGasCalculator,
final MainnetTransactionValidator transactionValidator, final MainnetTransactionValidator transactionValidator,
final AbstractMessageProcessor contractCreationProcessor, final AbstractMessageProcessor contractCreationProcessor,
final AbstractMessageProcessor messageCallProcessor, final AbstractMessageProcessor messageCallProcessor,
@ -226,6 +229,7 @@ public class MainnetTransactionProcessor {
final FeeMarket feeMarket, final FeeMarket feeMarket,
final CoinbaseFeePriceCalculator coinbaseFeePriceCalculator) { final CoinbaseFeePriceCalculator coinbaseFeePriceCalculator) {
this.gasCalculator = gasCalculator; this.gasCalculator = gasCalculator;
this.transactionGasCalculator = transacitonGasCalculator;
this.transactionValidator = transactionValidator; this.transactionValidator = transactionValidator;
this.contractCreationProcessor = contractCreationProcessor; this.contractCreationProcessor = contractCreationProcessor;
this.messageCallProcessor = messageCallProcessor; this.messageCallProcessor = messageCallProcessor;
@ -290,7 +294,7 @@ public class MainnetTransactionProcessor {
sender.getBalance()); sender.getBalance());
final GasAndAccessedState gasAndAccessedState = final GasAndAccessedState gasAndAccessedState =
gasCalculator.transactionIntrinsicGasCostAndAccessedState(transaction); transactionGasCalculator.transactionIntrinsicGasCostAndAccessedState(transaction);
final Gas intrinsicGas = gasAndAccessedState.getGas(); final Gas intrinsicGas = gasAndAccessedState.getGas();
final Gas gasAvailable = Gas.of(transaction.getGasLimit()).minus(intrinsicGas); final Gas gasAvailable = Gas.of(transaction.getGasLimit()).minus(intrinsicGas);
LOG.trace( LOG.trace(
@ -467,7 +471,7 @@ public class MainnetTransactionProcessor {
final Gas maxRefundAllowance = final Gas maxRefundAllowance =
Gas.of(transaction.getGasLimit()) Gas.of(transaction.getGasLimit())
.minus(gasRemaining) .minus(gasRemaining)
.dividedBy(gasCalculator.getMaxRefundQuotient()); .dividedBy(transactionGasCalculator.getMaxRefundQuotient());
final Gas refundAllowance = maxRefundAllowance.min(gasRefund); final Gas refundAllowance = maxRefundAllowance.min(gasRefund);
return gasRemaining.plus(refundAllowance); return gasRemaining.plus(refundAllowance);
} }

@ -23,7 +23,6 @@ import org.hyperledger.besu.ethereum.core.TransactionFilter;
import org.hyperledger.besu.ethereum.core.Wei; import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason;
import org.hyperledger.besu.ethereum.vm.GasCalculator;
import org.hyperledger.besu.plugin.data.TransactionType; import org.hyperledger.besu.plugin.data.TransactionType;
import java.math.BigInteger; import java.math.BigInteger;
@ -38,7 +37,7 @@ import java.util.Set;
*/ */
public class MainnetTransactionValidator { public class MainnetTransactionValidator {
private final GasCalculator gasCalculator; private final TransactionGasCalculator transactionGasCalculator;
private final FeeMarket feeMarket; private final FeeMarket feeMarket;
private final boolean disallowSignatureMalleability; private final boolean disallowSignatureMalleability;
@ -50,12 +49,12 @@ public class MainnetTransactionValidator {
private final boolean goQuorumCompatibilityMode; private final boolean goQuorumCompatibilityMode;
public MainnetTransactionValidator( public MainnetTransactionValidator(
final GasCalculator gasCalculator, final TransactionGasCalculator transactionGasCalculator,
final boolean checkSignatureMalleability, final boolean checkSignatureMalleability,
final Optional<BigInteger> chainId, final Optional<BigInteger> chainId,
final boolean goQuorumCompatibilityMode) { final boolean goQuorumCompatibilityMode) {
this( this(
gasCalculator, transactionGasCalculator,
checkSignatureMalleability, checkSignatureMalleability,
chainId, chainId,
Set.of(TransactionType.FRONTIER), Set.of(TransactionType.FRONTIER),
@ -63,13 +62,13 @@ public class MainnetTransactionValidator {
} }
public MainnetTransactionValidator( public MainnetTransactionValidator(
final GasCalculator gasCalculator, final TransactionGasCalculator transactionGasCalculator,
final boolean checkSignatureMalleability, final boolean checkSignatureMalleability,
final Optional<BigInteger> chainId, final Optional<BigInteger> chainId,
final Set<TransactionType> acceptedTransactionTypes, final Set<TransactionType> acceptedTransactionTypes,
final boolean quorumCompatibilityMode) { final boolean quorumCompatibilityMode) {
this( this(
gasCalculator, transactionGasCalculator,
FeeMarket.legacy(), FeeMarket.legacy(),
checkSignatureMalleability, checkSignatureMalleability,
chainId, chainId,
@ -78,13 +77,13 @@ public class MainnetTransactionValidator {
} }
public MainnetTransactionValidator( public MainnetTransactionValidator(
final GasCalculator gasCalculator, final TransactionGasCalculator transactionGasCalculator,
final FeeMarket feeMarket, final FeeMarket feeMarket,
final boolean checkSignatureMalleability, final boolean checkSignatureMalleability,
final Optional<BigInteger> chainId, final Optional<BigInteger> chainId,
final Set<TransactionType> acceptedTransactionTypes, final Set<TransactionType> acceptedTransactionTypes,
final boolean goQuorumCompatibilityMode) { final boolean goQuorumCompatibilityMode) {
this.gasCalculator = gasCalculator; this.transactionGasCalculator = transactionGasCalculator;
this.feeMarket = feeMarket; this.feeMarket = feeMarket;
this.disallowSignatureMalleability = checkSignatureMalleability; this.disallowSignatureMalleability = checkSignatureMalleability;
this.chainId = chainId; this.chainId = chainId;
@ -151,7 +150,7 @@ public class MainnetTransactionValidator {
} }
final Gas intrinsicGasCost = final Gas intrinsicGasCost =
gasCalculator.transactionIntrinsicGasCostAndAccessedState(transaction).getGas(); transactionGasCalculator.transactionIntrinsicGasCostAndAccessedState(transaction).getGas();
if (intrinsicGasCost.compareTo(Gas.of(transaction.getGasLimit())) > 0) { if (intrinsicGasCost.compareTo(Gas.of(transaction.getGasLimit())) > 0) {
return ValidationResult.invalid( return ValidationResult.invalid(
TransactionInvalidReason.INTRINSIC_GAS_EXCEEDS_GAS_LIMIT, TransactionInvalidReason.INTRINSIC_GAS_EXCEEDS_GAS_LIMIT,

@ -35,6 +35,8 @@ public class ProtocolSpec {
private final GasCalculator gasCalculator; private final GasCalculator gasCalculator;
private final TransactionGasCalculator transactionGasCalculator;
private final GasLimitCalculator gasLimitCalculator; private final GasLimitCalculator gasLimitCalculator;
private final MainnetTransactionValidator transactionValidator; private final MainnetTransactionValidator transactionValidator;
@ -97,6 +99,7 @@ public class ProtocolSpec {
* @param precompileContractRegistry all the pre-compiled contracts added * @param precompileContractRegistry all the pre-compiled contracts added
* @param skipZeroBlockRewards should rewards be skipped if it is zero * @param skipZeroBlockRewards should rewards be skipped if it is zero
* @param gasCalculator the gas calculator to use. * @param gasCalculator the gas calculator to use.
* @param transactionGasCalculator the transaction gas calculator to use.
* @param gasLimitCalculator the gas limit calculator to use. * @param gasLimitCalculator the gas limit calculator to use.
* @param feeMarket an {@link Optional} wrapping {@link FeeMarket} class if appropriate. * @param feeMarket an {@link Optional} wrapping {@link FeeMarket} class if appropriate.
* @param badBlockManager the cache to use to keep invalid blocks * @param badBlockManager the cache to use to keep invalid blocks
@ -122,6 +125,7 @@ public class ProtocolSpec {
final PrecompileContractRegistry precompileContractRegistry, final PrecompileContractRegistry precompileContractRegistry,
final boolean skipZeroBlockRewards, final boolean skipZeroBlockRewards,
final GasCalculator gasCalculator, final GasCalculator gasCalculator,
final TransactionGasCalculator transactionGasCalculator,
final GasLimitCalculator gasLimitCalculator, final GasLimitCalculator gasLimitCalculator,
final FeeMarket feeMarket, final FeeMarket feeMarket,
final BadBlockManager badBlockManager, final BadBlockManager badBlockManager,
@ -145,6 +149,7 @@ public class ProtocolSpec {
this.precompileContractRegistry = precompileContractRegistry; this.precompileContractRegistry = precompileContractRegistry;
this.skipZeroBlockRewards = skipZeroBlockRewards; this.skipZeroBlockRewards = skipZeroBlockRewards;
this.gasCalculator = gasCalculator; this.gasCalculator = gasCalculator;
this.transactionGasCalculator = transactionGasCalculator;
this.gasLimitCalculator = gasLimitCalculator; this.gasLimitCalculator = gasLimitCalculator;
this.feeMarket = feeMarket; this.feeMarket = feeMarket;
this.badBlockManager = badBlockManager; this.badBlockManager = badBlockManager;
@ -309,6 +314,15 @@ public class ProtocolSpec {
return gasCalculator; return gasCalculator;
} }
/**
* Returns the transactionGasCalculator used in this specification.
*
* @return the transaction processing gas calculator
*/
public TransactionGasCalculator getTransactionGasCalculator() {
return transactionGasCalculator;
}
/** /**
* Returns the gasLimitCalculator used in this specification. * Returns the gasLimitCalculator used in this specification.
* *

@ -41,6 +41,7 @@ import java.util.function.Supplier;
public class ProtocolSpecBuilder { public class ProtocolSpecBuilder {
private Supplier<GasCalculator> gasCalculatorBuilder; private Supplier<GasCalculator> gasCalculatorBuilder;
private TransactionGasCalculator transactionGasCalculator;
private GasLimitCalculator gasLimitCalculator; private GasLimitCalculator gasLimitCalculator;
private Wei blockReward; private Wei blockReward;
private boolean skipZeroBlockRewards; private boolean skipZeroBlockRewards;
@ -48,11 +49,13 @@ public class ProtocolSpecBuilder {
private AbstractBlockProcessor.TransactionReceiptFactory transactionReceiptFactory; private AbstractBlockProcessor.TransactionReceiptFactory transactionReceiptFactory;
private DifficultyCalculator difficultyCalculator; private DifficultyCalculator difficultyCalculator;
private Function<GasCalculator, EVM> evmBuilder; private Function<GasCalculator, EVM> evmBuilder;
private Function<GasCalculator, MainnetTransactionValidator> transactionValidatorBuilder; private Function<TransactionGasCalculator, MainnetTransactionValidator>
transactionValidatorBuilder;
private BlockHeaderValidator.Builder blockHeaderValidatorBuilder; private BlockHeaderValidator.Builder blockHeaderValidatorBuilder;
private BlockHeaderValidator.Builder ommerHeaderValidatorBuilder; private BlockHeaderValidator.Builder ommerHeaderValidatorBuilder;
private Function<ProtocolSchedule, BlockBodyValidator> blockBodyValidatorBuilder; private Function<ProtocolSchedule, BlockBodyValidator> blockBodyValidatorBuilder;
private BiFunction<GasCalculator, EVM, AbstractMessageProcessor> contractCreationProcessorBuilder; private BiFunction<TransactionGasCalculator, EVM, AbstractMessageProcessor>
contractCreationProcessorBuilder;
private Function<PrecompiledContractConfiguration, PrecompileContractRegistry> private Function<PrecompiledContractConfiguration, PrecompileContractRegistry>
precompileContractRegistryBuilder; precompileContractRegistryBuilder;
private BiFunction<EVM, PrecompileContractRegistry, AbstractMessageProcessor> private BiFunction<EVM, PrecompileContractRegistry, AbstractMessageProcessor>
@ -75,6 +78,12 @@ public class ProtocolSpecBuilder {
return this; return this;
} }
public ProtocolSpecBuilder transactionGasCalculator(
final TransactionGasCalculator transactionGasCalculator) {
this.transactionGasCalculator = transactionGasCalculator;
return this;
}
public ProtocolSpecBuilder gasLimitCalculator(final GasLimitCalculator gasLimitCalculator) { public ProtocolSpecBuilder gasLimitCalculator(final GasLimitCalculator gasLimitCalculator) {
this.gasLimitCalculator = gasLimitCalculator; this.gasLimitCalculator = gasLimitCalculator;
return this; return this;
@ -112,7 +121,8 @@ public class ProtocolSpecBuilder {
} }
public ProtocolSpecBuilder transactionValidatorBuilder( public ProtocolSpecBuilder transactionValidatorBuilder(
final Function<GasCalculator, MainnetTransactionValidator> transactionValidatorBuilder) { final Function<TransactionGasCalculator, MainnetTransactionValidator>
transactionValidatorBuilder) {
this.transactionValidatorBuilder = transactionValidatorBuilder; this.transactionValidatorBuilder = transactionValidatorBuilder;
return this; return this;
} }
@ -136,7 +146,7 @@ public class ProtocolSpecBuilder {
} }
public ProtocolSpecBuilder contractCreationProcessorBuilder( public ProtocolSpecBuilder contractCreationProcessorBuilder(
final BiFunction<GasCalculator, EVM, AbstractMessageProcessor> final BiFunction<TransactionGasCalculator, EVM, AbstractMessageProcessor>
contractCreationProcessorBuilder) { contractCreationProcessorBuilder) {
this.contractCreationProcessorBuilder = contractCreationProcessorBuilder; this.contractCreationProcessorBuilder = contractCreationProcessorBuilder;
return this; return this;
@ -233,6 +243,7 @@ public class ProtocolSpecBuilder {
public ProtocolSpec build(final ProtocolSchedule protocolSchedule) { public ProtocolSpec build(final ProtocolSchedule protocolSchedule) {
checkNotNull(gasCalculatorBuilder, "Missing gasCalculator"); checkNotNull(gasCalculatorBuilder, "Missing gasCalculator");
checkNotNull(transactionGasCalculator, "Missing transactionGasCalculator");
checkNotNull(gasLimitCalculator, "Missing gasLimitCalculator"); checkNotNull(gasLimitCalculator, "Missing gasLimitCalculator");
checkNotNull(evmBuilder, "Missing operation registry"); checkNotNull(evmBuilder, "Missing operation registry");
checkNotNull(transactionValidatorBuilder, "Missing transaction validator"); checkNotNull(transactionValidatorBuilder, "Missing transaction validator");
@ -263,16 +274,20 @@ public class ProtocolSpecBuilder {
final PrecompiledContractConfiguration precompiledContractConfiguration = final PrecompiledContractConfiguration precompiledContractConfiguration =
new PrecompiledContractConfiguration(gasCalculator, privacyParameters); new PrecompiledContractConfiguration(gasCalculator, privacyParameters);
final MainnetTransactionValidator transactionValidator = final MainnetTransactionValidator transactionValidator =
transactionValidatorBuilder.apply(gasCalculator); transactionValidatorBuilder.apply(transactionGasCalculator);
final AbstractMessageProcessor contractCreationProcessor = final AbstractMessageProcessor contractCreationProcessor =
contractCreationProcessorBuilder.apply(gasCalculator, evm); contractCreationProcessorBuilder.apply(transactionGasCalculator, evm);
final PrecompileContractRegistry precompileContractRegistry = final PrecompileContractRegistry precompileContractRegistry =
precompileContractRegistryBuilder.apply(precompiledContractConfiguration); precompileContractRegistryBuilder.apply(precompiledContractConfiguration);
final AbstractMessageProcessor messageCallProcessor = final AbstractMessageProcessor messageCallProcessor =
messageCallProcessorBuilder.apply(evm, precompileContractRegistry); messageCallProcessorBuilder.apply(evm, precompileContractRegistry);
final MainnetTransactionProcessor transactionProcessor = final MainnetTransactionProcessor transactionProcessor =
transactionProcessorBuilder.apply( transactionProcessorBuilder.apply(
gasCalculator, transactionValidator, contractCreationProcessor, messageCallProcessor); gasCalculator,
transactionGasCalculator,
transactionValidator,
contractCreationProcessor,
messageCallProcessor);
final BlockHeaderValidator blockHeaderValidator = final BlockHeaderValidator blockHeaderValidator =
blockHeaderValidatorBuilder.difficultyCalculator(difficultyCalculator).build(); blockHeaderValidatorBuilder.difficultyCalculator(difficultyCalculator).build();
@ -296,7 +311,7 @@ public class ProtocolSpecBuilder {
privateTransactionValidatorBuilder.apply(); privateTransactionValidatorBuilder.apply();
privateTransactionProcessor = privateTransactionProcessor =
privateTransactionProcessorBuilder.apply( privateTransactionProcessorBuilder.apply(
gasCalculator, transactionGasCalculator,
transactionValidator, transactionValidator,
contractCreationProcessor, contractCreationProcessor,
messageCallProcessor, messageCallProcessor,
@ -359,6 +374,7 @@ public class ProtocolSpecBuilder {
precompileContractRegistry, precompileContractRegistry,
skipZeroBlockRewards, skipZeroBlockRewards,
gasCalculator, gasCalculator,
transactionGasCalculator,
gasLimitCalculator, gasLimitCalculator,
feeMarket, feeMarket,
badBlockManager, badBlockManager,
@ -368,6 +384,7 @@ public class ProtocolSpecBuilder {
public interface TransactionProcessorBuilder { public interface TransactionProcessorBuilder {
MainnetTransactionProcessor apply( MainnetTransactionProcessor apply(
GasCalculator gasCalculator, GasCalculator gasCalculator,
TransactionGasCalculator transactionGasCalculator,
MainnetTransactionValidator transactionValidator, MainnetTransactionValidator transactionValidator,
AbstractMessageProcessor contractCreationProcessor, AbstractMessageProcessor contractCreationProcessor,
AbstractMessageProcessor messageCallProcessor); AbstractMessageProcessor messageCallProcessor);
@ -375,7 +392,7 @@ public class ProtocolSpecBuilder {
public interface PrivateTransactionProcessorBuilder { public interface PrivateTransactionProcessorBuilder {
PrivateTransactionProcessor apply( PrivateTransactionProcessor apply(
GasCalculator gasCalculator, TransactionGasCalculator transactionGasCalculator,
MainnetTransactionValidator transactionValidator, MainnetTransactionValidator transactionValidator,
AbstractMessageProcessor contractCreationProcessor, AbstractMessageProcessor contractCreationProcessor,
AbstractMessageProcessor messageCallProcessor, AbstractMessageProcessor messageCallProcessor,

@ -22,7 +22,7 @@ import org.hyperledger.besu.ethereum.vm.MessageFrame;
import org.apache.tuweni.units.bigints.UInt256; import org.apache.tuweni.units.bigints.UInt256;
public class TangerineWhistleGasCalculator extends HomesteadGasCalculator { public class TangerineWhistleGasCalculator extends FrontierGasCalculator {
private static final Gas BALANCE_OPERATION_GAS_COST = Gas.of(400L); private static final Gas BALANCE_OPERATION_GAS_COST = Gas.of(400L);

@ -0,0 +1,67 @@
/*
* Copyright contributors to Hyperledger Besu
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.mainnet;
import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.GasAndAccessedState;
import org.hyperledger.besu.ethereum.core.Transaction;
/**
* Provides various gas cost lookups and calculations used during transaction processing outside the
* EVM.
*
* <p>The {@code TransactionGasCalculator} is meant to encapsulate all {@link Gas}-related
* calculations not needed during EVM execution or caused by EVM execution. EVM Relevant or caused
* gas calculations live in the {@link org.hyperledger.besu.ethereum.vm.GasCalculator}. Current
* calculations revolve around block encoding of transactions, account creation, how much refund to
* apply, and private transaction gas reservations.
*/
public interface TransactionGasCalculator {
/**
* Returns a {@link Transaction}s intrinsic gas cost, i.e. the cost deriving from its encoded
* binary representation when stored on-chain.
*
* @param transaction The transaction
* @return the transaction's intrinsic gas cost
*/
GasAndAccessedState transactionIntrinsicGasCostAndAccessedState(Transaction transaction);
/**
* Returns the cost for a {@link AbstractMessageProcessor} to deposit the code in storage
*
* @param codeSize The size of the code in bytes
* @return the code deposit cost
*/
Gas codeDepositGasCost(int codeSize);
/**
* A measure of the maximum amount of refunded gas a transaction will be credited with.
*
* @return the quotient of the equation `txGasCost / refundQuotient`.
*/
default long getMaxRefundQuotient() {
return 2;
}
/**
* Maximum Cost of a Privacy Marker Transaction (PMT). See {@link
* org.hyperledger.besu.plugin.services.privacy.PrivateMarkerTransactionFactory}
*
* @return the maximum gas cost
*/
// what would be the gas for a PMT with hash of all non-zeros
Gas getMaximumPmtCost();
}

@ -28,12 +28,12 @@ import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.core.WorldUpdater; import org.hyperledger.besu.ethereum.core.WorldUpdater;
import org.hyperledger.besu.ethereum.mainnet.AbstractMessageProcessor; import org.hyperledger.besu.ethereum.mainnet.AbstractMessageProcessor;
import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionValidator; import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionValidator;
import org.hyperledger.besu.ethereum.mainnet.TransactionGasCalculator;
import org.hyperledger.besu.ethereum.mainnet.ValidationResult; import org.hyperledger.besu.ethereum.mainnet.ValidationResult;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason;
import org.hyperledger.besu.ethereum.vm.BlockHashLookup; import org.hyperledger.besu.ethereum.vm.BlockHashLookup;
import org.hyperledger.besu.ethereum.vm.Code; import org.hyperledger.besu.ethereum.vm.Code;
import org.hyperledger.besu.ethereum.vm.GasCalculator;
import org.hyperledger.besu.ethereum.vm.MessageFrame; import org.hyperledger.besu.ethereum.vm.MessageFrame;
import org.hyperledger.besu.ethereum.vm.OperationTracer; import org.hyperledger.besu.ethereum.vm.OperationTracer;
import org.hyperledger.besu.ethereum.worldstate.DefaultMutablePrivateWorldStateUpdater; import org.hyperledger.besu.ethereum.worldstate.DefaultMutablePrivateWorldStateUpdater;
@ -50,8 +50,7 @@ public class PrivateTransactionProcessor {
private static final Logger LOG = LogManager.getLogger(); private static final Logger LOG = LogManager.getLogger();
@SuppressWarnings("unused") private final TransactionGasCalculator transactionGasCalculator;
private final GasCalculator gasCalculator;
@SuppressWarnings("unused") @SuppressWarnings("unused")
private final MainnetTransactionValidator transactionValidator; private final MainnetTransactionValidator transactionValidator;
@ -68,14 +67,14 @@ public class PrivateTransactionProcessor {
private final boolean clearEmptyAccounts; private final boolean clearEmptyAccounts;
public PrivateTransactionProcessor( public PrivateTransactionProcessor(
final GasCalculator gasCalculator, final TransactionGasCalculator transactionGasCalculator,
final MainnetTransactionValidator transactionValidator, final MainnetTransactionValidator transactionValidator,
final AbstractMessageProcessor contractCreationProcessor, final AbstractMessageProcessor contractCreationProcessor,
final AbstractMessageProcessor messageCallProcessor, final AbstractMessageProcessor messageCallProcessor,
final boolean clearEmptyAccounts, final boolean clearEmptyAccounts,
final int maxStackSize, final int maxStackSize,
final PrivateTransactionValidator privateTransactionValidator) { final PrivateTransactionValidator privateTransactionValidator) {
this.gasCalculator = gasCalculator; this.transactionGasCalculator = transactionGasCalculator;
this.transactionValidator = transactionValidator; this.transactionValidator = transactionValidator;
this.contractCreationProcessor = contractCreationProcessor; this.contractCreationProcessor = contractCreationProcessor;
this.messageCallProcessor = messageCallProcessor; this.messageCallProcessor = messageCallProcessor;
@ -233,7 +232,7 @@ public class PrivateTransactionProcessor {
final Gas maxRefundAllowance = final Gas maxRefundAllowance =
Gas.of(transaction.getGasLimit()) Gas.of(transaction.getGasLimit())
.minus(gasRemaining) .minus(gasRemaining)
.dividedBy(gasCalculator.getMaxRefundQuotient()); .dividedBy(transactionGasCalculator.getMaxRefundQuotient());
final Gas refundAllowance = maxRefundAllowance.min(gasRefund); final Gas refundAllowance = maxRefundAllowance.min(gasRefund);
return gasRemaining.plus(refundAllowance); return gasRemaining.plus(refundAllowance);
} }

@ -233,7 +233,8 @@ public class TransactionSimulator {
// This means a potential over-estimate of gas, but the tx, if sent with this gas, will not // This means a potential over-estimate of gas, but the tx, if sent with this gas, will not
// fail. // fail.
if (GoQuorumOptions.goQuorumCompatibilityMode && value.isZero()) { if (GoQuorumOptions.goQuorumCompatibilityMode && value.isZero()) {
Gas privateGasEstimateAndState = protocolSpec.getGasCalculator().getMaximumPmtCost(); Gas privateGasEstimateAndState =
protocolSpec.getTransactionGasCalculator().getMaximumPmtCost();
if (privateGasEstimateAndState.toLong() > result.getEstimateGasUsedByTransaction()) { if (privateGasEstimateAndState.toLong() > result.getEstimateGasUsedByTransaction()) {
// modify the result to have the larger estimate // modify the result to have the larger estimate
TransactionProcessingResult resultPmt = TransactionProcessingResult resultPmt =

@ -17,10 +17,7 @@ package org.hyperledger.besu.ethereum.vm;
import org.hyperledger.besu.ethereum.core.Account; import org.hyperledger.besu.ethereum.core.Account;
import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.Gas; import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.GasAndAccessedState;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.Wei; import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.mainnet.AbstractMessageProcessor;
import org.hyperledger.besu.ethereum.mainnet.precompiles.ECRECPrecompiledContract; import org.hyperledger.besu.ethereum.mainnet.precompiles.ECRECPrecompiledContract;
import org.hyperledger.besu.ethereum.mainnet.precompiles.IDPrecompiledContract; import org.hyperledger.besu.ethereum.mainnet.precompiles.IDPrecompiledContract;
import org.hyperledger.besu.ethereum.mainnet.precompiles.RIPEMD160PrecompiledContract; import org.hyperledger.besu.ethereum.mainnet.precompiles.RIPEMD160PrecompiledContract;
@ -44,38 +41,16 @@ import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256; import org.apache.tuweni.units.bigints.UInt256;
/** /**
* Provides various gas cost lookups and calculations used during block processing. * Provides various gas cost lookups and calculations used during EVM Execution.
* *
* <p>The {@code GasCalculator} is meant to encapsulate all {@link Gas}-related calculations except * <p>The {@code GasCalculator} is meant to encapsulate all {@link Gas}-related calculations needed
* for the following "safe" operations: * during EVM execution or caused by EVM execution. Hence, refund calculation is part of this as the
* * EVM should report the refund counter at the end of execution. However, the amount to apply to a
* <ul> * transaction is out of scope and part of the {@link
* <li><b>Operation Gas Deductions:</b> Deducting the operation's gas cost from the VM's current * org.hyperledger.besu.ethereum.mainnet.TransactionGasCalculator}.
* message frame because the
* </ul>
*/ */
public interface GasCalculator { public interface GasCalculator {
// Transaction Gas Calculations
/**
* Returns a {@link Transaction}s intrinsic gas cost
*
* @param transaction The transaction
* @return the transaction's intrinsic gas cost
*/
GasAndAccessedState transactionIntrinsicGasCostAndAccessedState(Transaction transaction);
// Contract Creation Gas Calculations
/**
* Returns the cost for a {@link AbstractMessageProcessor} to deposit the code in storage
*
* @param codeSize The size of the code in bytes
* @return the code deposit cost
*/
Gas codeDepositGasCost(int codeSize);
// Precompiled Contract Gas Calculations // Precompiled Contract Gas Calculations
/** /**
@ -434,11 +409,4 @@ public interface GasCalculator {
default Gas modExpGasCost(final Bytes input) { default Gas modExpGasCost(final Bytes input) {
return Gas.ZERO; return Gas.ZERO;
} }
default long getMaxRefundQuotient() {
return 2;
}
// what would be the gas for a PMT with hash of all non-zeros
Gas getMaximumPmtCost();
} }

@ -17,7 +17,6 @@ package org.hyperledger.besu.ethereum.mainnet;
import org.hyperledger.besu.ethereum.core.Gas; import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.vm.GasCalculator;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -32,21 +31,23 @@ import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class) @RunWith(Parameterized.class)
public class IntrinsicGasTest { public class IntrinsicGasTest {
private final GasCalculator gasCalculator; private final TransactionGasCalculator transactionGasCalculator;
private final Gas expectedGas; private final Gas expectedGas;
private final String txRlp; private final String txRlp;
public IntrinsicGasTest( public IntrinsicGasTest(
final GasCalculator gasCalculator, final Gas expectedGas, final String txRlp) { final TransactionGasCalculator transactionGasCalculator,
this.gasCalculator = gasCalculator; final Gas expectedGas,
final String txRlp) {
this.transactionGasCalculator = transactionGasCalculator;
this.expectedGas = expectedGas; this.expectedGas = expectedGas;
this.txRlp = txRlp; this.txRlp = txRlp;
} }
@Parameters @Parameters
public static Collection<Object[]> data() { public static Collection<Object[]> data() {
final GasCalculator frontier = new FrontierGasCalculator(); final TransactionGasCalculator frontier = new FrontierTransactionGasCalculator();
final GasCalculator istanbul = new IstanbulGasCalculator(); final TransactionGasCalculator istanbul = new IstanbulTransactionGasCalculator();
return Arrays.asList( return Arrays.asList(
new Object[][] { new Object[][] {
// EnoughGAS // EnoughGAS
@ -110,7 +111,8 @@ public class IntrinsicGasTest {
@Test @Test
public void validateGasCost() { public void validateGasCost() {
Transaction t = Transaction.readFrom(RLP.input(Bytes.fromHexString(txRlp))); Transaction t = Transaction.readFrom(RLP.input(Bytes.fromHexString(txRlp)));
Assertions.assertThat(gasCalculator.transactionIntrinsicGasCostAndAccessedState(t).getGas()) Assertions.assertThat(
transactionGasCalculator.transactionIntrinsicGasCostAndAccessedState(t).getGas())
.isEqualTo(expectedGas); .isEqualTo(expectedGas);
} }
} }

@ -23,7 +23,6 @@ import org.hyperledger.besu.ethereum.core.Gas;
import org.hyperledger.besu.ethereum.core.MessageFrameTestFixture; import org.hyperledger.besu.ethereum.core.MessageFrameTestFixture;
import org.hyperledger.besu.ethereum.mainnet.contractvalidation.PrefixCodeRule; import org.hyperledger.besu.ethereum.mainnet.contractvalidation.PrefixCodeRule;
import org.hyperledger.besu.ethereum.vm.EVM; import org.hyperledger.besu.ethereum.vm.EVM;
import org.hyperledger.besu.ethereum.vm.GasCalculator;
import org.hyperledger.besu.ethereum.vm.MessageFrame; import org.hyperledger.besu.ethereum.vm.MessageFrame;
import org.hyperledger.besu.ethereum.vm.OperationTracer; import org.hyperledger.besu.ethereum.vm.OperationTracer;
@ -38,7 +37,7 @@ import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
public class MainnetContractCreationProcessorTest { public class MainnetContractCreationProcessorTest {
@Mock GasCalculator gasCalculator; @Mock TransactionGasCalculator transactionGasCalculator;
@Mock EVM evm; @Mock EVM evm;
private MainnetContractCreationProcessor processor; private MainnetContractCreationProcessor processor;
@ -47,7 +46,7 @@ public class MainnetContractCreationProcessorTest {
public void shouldThrowAnExceptionWhenCodeContractFormatInvalid() { public void shouldThrowAnExceptionWhenCodeContractFormatInvalid() {
processor = processor =
new MainnetContractCreationProcessor( new MainnetContractCreationProcessor(
gasCalculator, transactionGasCalculator,
evm, evm,
true, true,
Collections.singletonList(PrefixCodeRule.of()), Collections.singletonList(PrefixCodeRule.of()),
@ -58,7 +57,7 @@ public class MainnetContractCreationProcessorTest {
messageFrame.setOutputData(contractCode); messageFrame.setOutputData(contractCode);
messageFrame.setGasRemaining(Gas.of(100)); messageFrame.setGasRemaining(Gas.of(100));
when(gasCalculator.codeDepositGasCost(contractCode.size())).thenReturn(Gas.of(10)); when(transactionGasCalculator.codeDepositGasCost(contractCode.size())).thenReturn(Gas.of(10));
processor.codeSuccess(messageFrame, OperationTracer.NO_TRACING); processor.codeSuccess(messageFrame, OperationTracer.NO_TRACING);
assertThat(messageFrame.getState()).isEqualTo(EXCEPTIONAL_HALT); assertThat(messageFrame.getState()).isEqualTo(EXCEPTIONAL_HALT);
} }
@ -67,7 +66,7 @@ public class MainnetContractCreationProcessorTest {
public void shouldNotThrowAnExceptionWhenCodeContractIsValid() { public void shouldNotThrowAnExceptionWhenCodeContractIsValid() {
processor = processor =
new MainnetContractCreationProcessor( new MainnetContractCreationProcessor(
gasCalculator, transactionGasCalculator,
evm, evm,
true, true,
Collections.singletonList(PrefixCodeRule.of()), Collections.singletonList(PrefixCodeRule.of()),
@ -78,7 +77,7 @@ public class MainnetContractCreationProcessorTest {
messageFrame.setOutputData(contractCode); messageFrame.setOutputData(contractCode);
messageFrame.setGasRemaining(Gas.of(100)); messageFrame.setGasRemaining(Gas.of(100));
when(gasCalculator.codeDepositGasCost(contractCode.size())).thenReturn(Gas.of(10)); when(transactionGasCalculator.codeDepositGasCost(contractCode.size())).thenReturn(Gas.of(10));
processor.codeSuccess(messageFrame, OperationTracer.NO_TRACING); processor.codeSuccess(messageFrame, OperationTracer.NO_TRACING);
assertThat(messageFrame.getState()).isEqualTo(COMPLETED_SUCCESS); assertThat(messageFrame.getState()).isEqualTo(COMPLETED_SUCCESS);
} }
@ -87,13 +86,18 @@ public class MainnetContractCreationProcessorTest {
public void shouldNotThrowAnExceptionWhenPrefixCodeRuleNotAdded() { public void shouldNotThrowAnExceptionWhenPrefixCodeRuleNotAdded() {
processor = processor =
new MainnetContractCreationProcessor( new MainnetContractCreationProcessor(
gasCalculator, evm, true, Collections.emptyList(), 1, Collections.emptyList()); transactionGasCalculator,
evm,
true,
Collections.emptyList(),
1,
Collections.emptyList());
final Bytes contractCode = Bytes.fromHexString("0F01010101010101"); final Bytes contractCode = Bytes.fromHexString("0F01010101010101");
MessageFrame messageFrame = new MessageFrameTestFixture().build(); MessageFrame messageFrame = new MessageFrameTestFixture().build();
messageFrame.setOutputData(contractCode); messageFrame.setOutputData(contractCode);
messageFrame.setGasRemaining(Gas.of(100)); messageFrame.setGasRemaining(Gas.of(100));
when(gasCalculator.codeDepositGasCost(contractCode.size())).thenReturn(Gas.of(10)); when(transactionGasCalculator.codeDepositGasCost(contractCode.size())).thenReturn(Gas.of(10));
processor.codeSuccess(messageFrame, OperationTracer.NO_TRACING); processor.codeSuccess(messageFrame, OperationTracer.NO_TRACING);
assertThat(messageFrame.getState()).isEqualTo(COMPLETED_SUCCESS); assertThat(messageFrame.getState()).isEqualTo(COMPLETED_SUCCESS);
} }

@ -44,6 +44,7 @@ public class MainnetTransactionProcessorTest {
private MainnetTransactionProcessor transactionProcessor; private MainnetTransactionProcessor transactionProcessor;
@Mock private GasCalculator gasCalculator; @Mock private GasCalculator gasCalculator;
@Mock private TransactionGasCalculator transactionGasCalculator;
@Mock private MainnetTransactionValidator transactionValidator; @Mock private MainnetTransactionValidator transactionValidator;
@Mock private AbstractMessageProcessor contractCreationProcessor; @Mock private AbstractMessageProcessor contractCreationProcessor;
@Mock private AbstractMessageProcessor messageCallProcessor; @Mock private AbstractMessageProcessor messageCallProcessor;
@ -59,6 +60,7 @@ public class MainnetTransactionProcessorTest {
transactionProcessor = transactionProcessor =
new MainnetTransactionProcessor( new MainnetTransactionProcessor(
gasCalculator, gasCalculator,
transactionGasCalculator,
transactionValidator, transactionValidator,
contractCreationProcessor, contractCreationProcessor,
messageCallProcessor, messageCallProcessor,

@ -38,7 +38,6 @@ import org.hyperledger.besu.ethereum.core.TransactionTestFixture;
import org.hyperledger.besu.ethereum.core.Wei; import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason;
import org.hyperledger.besu.ethereum.vm.GasCalculator;
import org.hyperledger.besu.plugin.data.TransactionType; import org.hyperledger.besu.plugin.data.TransactionType;
import java.math.BigInteger; import java.math.BigInteger;
@ -64,7 +63,7 @@ public class MainnetTransactionValidatorTest {
private static final TransactionValidationParams transactionValidationParams = private static final TransactionValidationParams transactionValidationParams =
TransactionValidationParams.processingBlockParams; TransactionValidationParams.processingBlockParams;
@Mock private GasCalculator gasCalculator; @Mock private TransactionGasCalculator transactionGasCalculator;
private final Transaction basicTransaction = private final Transaction basicTransaction =
new TransactionTestFixture() new TransactionTestFixture()
@ -77,13 +76,13 @@ public class MainnetTransactionValidatorTest {
public void shouldRejectTransactionIfIntrinsicGasExceedsGasLimit() { public void shouldRejectTransactionIfIntrinsicGasExceedsGasLimit() {
final MainnetTransactionValidator validator = final MainnetTransactionValidator validator =
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, false, Optional.empty(), defaultGoQuorumCompatibilityMode); transactionGasCalculator, false, Optional.empty(), defaultGoQuorumCompatibilityMode);
final Transaction transaction = final Transaction transaction =
new TransactionTestFixture() new TransactionTestFixture()
.gasLimit(10) .gasLimit(10)
.chainId(Optional.empty()) .chainId(Optional.empty())
.createTransaction(senderKeys); .createTransaction(senderKeys);
when(gasCalculator.transactionIntrinsicGasCostAndAccessedState(transaction)) when(transactionGasCalculator.transactionIntrinsicGasCostAndAccessedState(transaction))
.thenReturn(new GasAndAccessedState(Gas.of(50))); .thenReturn(new GasAndAccessedState(Gas.of(50)));
assertThat(validator.validate(transaction, Optional.empty(), transactionValidationParams)) assertThat(validator.validate(transaction, Optional.empty(), transactionValidationParams))
@ -95,7 +94,7 @@ public class MainnetTransactionValidatorTest {
public void shouldRejectTransactionWhenTransactionHasChainIdAndValidatorDoesNot() { public void shouldRejectTransactionWhenTransactionHasChainIdAndValidatorDoesNot() {
final MainnetTransactionValidator validator = final MainnetTransactionValidator validator =
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, false, Optional.empty(), defaultGoQuorumCompatibilityMode); transactionGasCalculator, false, Optional.empty(), defaultGoQuorumCompatibilityMode);
assertThat(validator.validate(basicTransaction, Optional.empty(), transactionValidationParams)) assertThat(validator.validate(basicTransaction, Optional.empty(), transactionValidationParams))
.isEqualTo( .isEqualTo(
ValidationResult.invalid( ValidationResult.invalid(
@ -106,7 +105,7 @@ public class MainnetTransactionValidatorTest {
public void shouldRejectTransactionWhenTransactionHasIncorrectChainId() { public void shouldRejectTransactionWhenTransactionHasIncorrectChainId() {
final MainnetTransactionValidator validator = final MainnetTransactionValidator validator =
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, transactionGasCalculator,
false, false,
Optional.of(BigInteger.valueOf(2)), Optional.of(BigInteger.valueOf(2)),
defaultGoQuorumCompatibilityMode); defaultGoQuorumCompatibilityMode);
@ -118,7 +117,10 @@ public class MainnetTransactionValidatorTest {
public void shouldRejectTransactionWhenSenderAccountDoesNotExist() { public void shouldRejectTransactionWhenSenderAccountDoesNotExist() {
final MainnetTransactionValidator validator = final MainnetTransactionValidator validator =
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, false, Optional.of(BigInteger.ONE), defaultGoQuorumCompatibilityMode); transactionGasCalculator,
false,
Optional.of(BigInteger.ONE),
defaultGoQuorumCompatibilityMode);
assertThat(validator.validateForSender(basicTransaction, null, false)) assertThat(validator.validateForSender(basicTransaction, null, false))
.isEqualTo(ValidationResult.invalid(TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE)); .isEqualTo(ValidationResult.invalid(TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE));
} }
@ -127,7 +129,10 @@ public class MainnetTransactionValidatorTest {
public void shouldRejectTransactionWhenTransactionNonceBelowAccountNonce() { public void shouldRejectTransactionWhenTransactionNonceBelowAccountNonce() {
final MainnetTransactionValidator validator = final MainnetTransactionValidator validator =
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, false, Optional.of(BigInteger.ONE), defaultGoQuorumCompatibilityMode); transactionGasCalculator,
false,
Optional.of(BigInteger.ONE),
defaultGoQuorumCompatibilityMode);
final Account account = accountWithNonce(basicTransaction.getNonce() + 1); final Account account = accountWithNonce(basicTransaction.getNonce() + 1);
assertThat(validator.validateForSender(basicTransaction, account, false)) assertThat(validator.validateForSender(basicTransaction, account, false))
@ -139,7 +144,10 @@ public class MainnetTransactionValidatorTest {
shouldRejectTransactionWhenTransactionNonceAboveAccountNonceAndFutureNonceIsNotAllowed() { shouldRejectTransactionWhenTransactionNonceAboveAccountNonceAndFutureNonceIsNotAllowed() {
final MainnetTransactionValidator validator = final MainnetTransactionValidator validator =
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, false, Optional.of(BigInteger.ONE), defaultGoQuorumCompatibilityMode); transactionGasCalculator,
false,
Optional.of(BigInteger.ONE),
defaultGoQuorumCompatibilityMode);
final Account account = accountWithNonce(basicTransaction.getNonce() - 1); final Account account = accountWithNonce(basicTransaction.getNonce() - 1);
assertThat(validator.validateForSender(basicTransaction, account, false)) assertThat(validator.validateForSender(basicTransaction, account, false))
@ -151,7 +159,10 @@ public class MainnetTransactionValidatorTest {
shouldAcceptTransactionWhenTransactionNonceAboveAccountNonceAndFutureNonceIsAllowed() { shouldAcceptTransactionWhenTransactionNonceAboveAccountNonceAndFutureNonceIsAllowed() {
final MainnetTransactionValidator validator = final MainnetTransactionValidator validator =
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, false, Optional.of(BigInteger.ONE), defaultGoQuorumCompatibilityMode); transactionGasCalculator,
false,
Optional.of(BigInteger.ONE),
defaultGoQuorumCompatibilityMode);
final Account account = accountWithNonce(basicTransaction.getNonce() - 1); final Account account = accountWithNonce(basicTransaction.getNonce() - 1);
assertThat(validator.validateForSender(basicTransaction, account, true)) assertThat(validator.validateForSender(basicTransaction, account, true))
@ -162,7 +173,10 @@ public class MainnetTransactionValidatorTest {
public void shouldRejectTransactionWhenNonceExceedsMaximumAllowedNonce() { public void shouldRejectTransactionWhenNonceExceedsMaximumAllowedNonce() {
final MainnetTransactionValidator validator = final MainnetTransactionValidator validator =
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, false, Optional.of(BigInteger.ONE), defaultGoQuorumCompatibilityMode); transactionGasCalculator,
false,
Optional.of(BigInteger.ONE),
defaultGoQuorumCompatibilityMode);
final Transaction transaction = final Transaction transaction =
new TransactionTestFixture().nonce(11).createTransaction(senderKeys); new TransactionTestFixture().nonce(11).createTransaction(senderKeys);
@ -176,7 +190,10 @@ public class MainnetTransactionValidatorTest {
public void transactionWithNullSenderCanBeValidIfGasPriceAndValueIsZero() { public void transactionWithNullSenderCanBeValidIfGasPriceAndValueIsZero() {
final MainnetTransactionValidator validator = final MainnetTransactionValidator validator =
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, false, Optional.of(BigInteger.ONE), defaultGoQuorumCompatibilityMode); transactionGasCalculator,
false,
Optional.of(BigInteger.ONE),
defaultGoQuorumCompatibilityMode);
final TransactionTestFixture builder = new TransactionTestFixture(); final TransactionTestFixture builder = new TransactionTestFixture();
final KeyPair senderKeyPair = SIGNATURE_ALGORITHM.get().generateKeyPair(); final KeyPair senderKeyPair = SIGNATURE_ALGORITHM.get().generateKeyPair();
@ -191,7 +208,7 @@ public class MainnetTransactionValidatorTest {
public void shouldRejectTransactionIfAccountIsNotPermitted() { public void shouldRejectTransactionIfAccountIsNotPermitted() {
final MainnetTransactionValidator validator = final MainnetTransactionValidator validator =
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, false, Optional.empty(), defaultGoQuorumCompatibilityMode); transactionGasCalculator, false, Optional.empty(), defaultGoQuorumCompatibilityMode);
validator.setTransactionFilter(transactionFilter(false)); validator.setTransactionFilter(transactionFilter(false));
assertThat(validator.validateForSender(basicTransaction, accountWithNonce(0), true)) assertThat(validator.validateForSender(basicTransaction, accountWithNonce(0), true))
@ -202,7 +219,7 @@ public class MainnetTransactionValidatorTest {
public void shouldAcceptValidTransactionIfAccountIsPermitted() { public void shouldAcceptValidTransactionIfAccountIsPermitted() {
final MainnetTransactionValidator validator = final MainnetTransactionValidator validator =
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, false, Optional.empty(), defaultGoQuorumCompatibilityMode); transactionGasCalculator, false, Optional.empty(), defaultGoQuorumCompatibilityMode);
validator.setTransactionFilter(transactionFilter(true)); validator.setTransactionFilter(transactionFilter(true));
assertThat(validator.validateForSender(basicTransaction, accountWithNonce(0), true)) assertThat(validator.validateForSender(basicTransaction, accountWithNonce(0), true))
@ -213,7 +230,7 @@ public class MainnetTransactionValidatorTest {
public void shouldRejectTransactionWithMaxFeeTimesGasLimitGreaterThanBalance() { public void shouldRejectTransactionWithMaxFeeTimesGasLimitGreaterThanBalance() {
final MainnetTransactionValidator validator = final MainnetTransactionValidator validator =
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, false, Optional.empty(), defaultGoQuorumCompatibilityMode); transactionGasCalculator, false, Optional.empty(), defaultGoQuorumCompatibilityMode);
validator.setTransactionFilter(transactionFilter(true)); validator.setTransactionFilter(transactionFilter(true));
assertThat( assertThat(
@ -238,7 +255,7 @@ public class MainnetTransactionValidatorTest {
public void shouldRejectTransactionWithMaxPriorityFeeGreaterThanMaxFee() { public void shouldRejectTransactionWithMaxPriorityFeeGreaterThanMaxFee() {
final MainnetTransactionValidator validator = final MainnetTransactionValidator validator =
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, transactionGasCalculator,
FeeMarket.london(0L), FeeMarket.london(0L),
false, false,
Optional.of(BigInteger.ONE), Optional.of(BigInteger.ONE),
@ -282,7 +299,7 @@ public class MainnetTransactionValidatorTest {
final MainnetTransactionValidator validator = final MainnetTransactionValidator validator =
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, false, Optional.empty(), defaultGoQuorumCompatibilityMode); transactionGasCalculator, false, Optional.empty(), defaultGoQuorumCompatibilityMode);
validator.setTransactionFilter(transactionFilter); validator.setTransactionFilter(transactionFilter);
final TransactionValidationParams validationParams = final TransactionValidationParams validationParams =
@ -300,7 +317,7 @@ public class MainnetTransactionValidatorTest {
final MainnetTransactionValidator validator = final MainnetTransactionValidator validator =
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, false, Optional.empty(), defaultGoQuorumCompatibilityMode); transactionGasCalculator, false, Optional.empty(), defaultGoQuorumCompatibilityMode);
validator.setTransactionFilter(transactionFilter); validator.setTransactionFilter(transactionFilter);
final TransactionValidationParams validationParams = final TransactionValidationParams validationParams =
@ -321,7 +338,7 @@ public class MainnetTransactionValidatorTest {
public void shouldAcceptOnlyTransactionsInAcceptedTransactionTypes() { public void shouldAcceptOnlyTransactionsInAcceptedTransactionTypes() {
final MainnetTransactionValidator frontierValidator = final MainnetTransactionValidator frontierValidator =
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, transactionGasCalculator,
FeeMarket.legacy(), FeeMarket.legacy(),
false, false,
Optional.of(BigInteger.ONE), Optional.of(BigInteger.ONE),
@ -330,7 +347,7 @@ public class MainnetTransactionValidatorTest {
final MainnetTransactionValidator eip1559Validator = final MainnetTransactionValidator eip1559Validator =
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, transactionGasCalculator,
FeeMarket.london(0L), FeeMarket.london(0L),
false, false,
Optional.of(BigInteger.ONE), Optional.of(BigInteger.ONE),
@ -350,7 +367,7 @@ public class MainnetTransactionValidatorTest {
frontierValidator.validate(transaction, Optional.empty(), transactionValidationParams)) frontierValidator.validate(transaction, Optional.empty(), transactionValidationParams))
.isEqualTo(ValidationResult.invalid(TransactionInvalidReason.INVALID_TRANSACTION_FORMAT)); .isEqualTo(ValidationResult.invalid(TransactionInvalidReason.INVALID_TRANSACTION_FORMAT));
when(gasCalculator.transactionIntrinsicGasCostAndAccessedState(transaction)) when(transactionGasCalculator.transactionIntrinsicGasCostAndAccessedState(transaction))
.thenReturn(new GasAndAccessedState(Gas.of(0))); .thenReturn(new GasAndAccessedState(Gas.of(0)));
assertThat(eip1559Validator.validate(transaction, Optional.of(1L), transactionValidationParams)) assertThat(eip1559Validator.validate(transaction, Optional.of(1L), transactionValidationParams))
@ -361,7 +378,7 @@ public class MainnetTransactionValidatorTest {
public void shouldRejectTransactionIfEIP1559TransactionGasPriceLessBaseFee() { public void shouldRejectTransactionIfEIP1559TransactionGasPriceLessBaseFee() {
final MainnetTransactionValidator validator = final MainnetTransactionValidator validator =
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, transactionGasCalculator,
FeeMarket.london(0L), FeeMarket.london(0L),
false, false,
Optional.of(BigInteger.ONE), Optional.of(BigInteger.ONE),
@ -383,7 +400,7 @@ public class MainnetTransactionValidatorTest {
public void shouldAcceptValidEIP1559() { public void shouldAcceptValidEIP1559() {
final MainnetTransactionValidator validator = final MainnetTransactionValidator validator =
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, transactionGasCalculator,
FeeMarket.london(0L), FeeMarket.london(0L),
false, false,
Optional.of(BigInteger.ONE), Optional.of(BigInteger.ONE),
@ -397,7 +414,7 @@ public class MainnetTransactionValidatorTest {
.chainId(Optional.of(BigInteger.ONE)) .chainId(Optional.of(BigInteger.ONE))
.createTransaction(senderKeys); .createTransaction(senderKeys);
final Optional<Long> basefee = Optional.of(150000L); final Optional<Long> basefee = Optional.of(150000L);
when(gasCalculator.transactionIntrinsicGasCostAndAccessedState(transaction)) when(transactionGasCalculator.transactionIntrinsicGasCostAndAccessedState(transaction))
.thenReturn(new GasAndAccessedState(Gas.of(50))); .thenReturn(new GasAndAccessedState(Gas.of(50)));
assertThat(validator.validate(transaction, basefee, transactionValidationParams)) assertThat(validator.validate(transaction, basefee, transactionValidationParams))
@ -408,7 +425,7 @@ public class MainnetTransactionValidatorTest {
public void shouldValidate1559TransactionWithPriceLowerThanBaseFeeForTransactionPool() { public void shouldValidate1559TransactionWithPriceLowerThanBaseFeeForTransactionPool() {
final MainnetTransactionValidator validator = final MainnetTransactionValidator validator =
new MainnetTransactionValidator( new MainnetTransactionValidator(
gasCalculator, transactionGasCalculator,
FeeMarket.london(0L), FeeMarket.london(0L),
false, false,
Optional.of(BigInteger.ONE), Optional.of(BigInteger.ONE),
@ -421,7 +438,7 @@ public class MainnetTransactionValidatorTest {
.type(TransactionType.EIP1559) .type(TransactionType.EIP1559)
.chainId(Optional.of(BigInteger.ONE)) .chainId(Optional.of(BigInteger.ONE))
.createTransaction(senderKeys); .createTransaction(senderKeys);
when(gasCalculator.transactionIntrinsicGasCostAndAccessedState(transaction)) when(transactionGasCalculator.transactionIntrinsicGasCostAndAccessedState(transaction))
.thenReturn(new GasAndAccessedState(Gas.of(50))); .thenReturn(new GasAndAccessedState(Gas.of(50)));
assertThat( assertThat(
@ -433,7 +450,7 @@ public class MainnetTransactionValidatorTest {
@Test @Test
public void goQuorumCompatibilityModeRejectNonZeroGasPrice() { public void goQuorumCompatibilityModeRejectNonZeroGasPrice() {
final MainnetTransactionValidator validator = final MainnetTransactionValidator validator =
new MainnetTransactionValidator(gasCalculator, false, Optional.empty(), true); new MainnetTransactionValidator(transactionGasCalculator, false, Optional.empty(), true);
final Transaction transaction = final Transaction transaction =
new TransactionTestFixture() new TransactionTestFixture()
.gasPrice(Wei.ONE) .gasPrice(Wei.ONE)
@ -455,14 +472,14 @@ public class MainnetTransactionValidatorTest {
@Test @Test
public void goQuorumCompatibilityModeSuccessZeroGasPrice() { public void goQuorumCompatibilityModeSuccessZeroGasPrice() {
final MainnetTransactionValidator validator = final MainnetTransactionValidator validator =
new MainnetTransactionValidator(gasCalculator, false, Optional.empty(), true); new MainnetTransactionValidator(transactionGasCalculator, false, Optional.empty(), true);
final Transaction transaction = final Transaction transaction =
new TransactionTestFixture() new TransactionTestFixture()
.gasPrice(Wei.ZERO) .gasPrice(Wei.ZERO)
.chainId(Optional.empty()) .chainId(Optional.empty())
.createTransaction(senderKeys); .createTransaction(senderKeys);
when(gasCalculator.transactionIntrinsicGasCostAndAccessedState(transaction)) when(transactionGasCalculator.transactionIntrinsicGasCostAndAccessedState(transaction))
.thenReturn(new GasAndAccessedState(Gas.of(50))); .thenReturn(new GasAndAccessedState(Gas.of(50)));
assertThat( assertThat(

@ -284,7 +284,7 @@ public class EvmToolCommand implements Runnable {
final Gas intrinsicGasCost = final Gas intrinsicGasCost =
protocolSpec protocolSpec
.getGasCalculator() .getTransactionGasCalculator()
.transactionIntrinsicGasCostAndAccessedState(tx) .transactionIntrinsicGasCostAndAccessedState(tx)
.getGas(); .getGas();
final Gas evmGas = gas.minus(messageFrame.getRemainingGas()); final Gas evmGas = gas.minus(messageFrame.getRemainingGas());

@ -76,6 +76,7 @@ public class NoRewardProtocolScheduleWrapper implements ProtocolSchedule {
original.getPrecompileContractRegistry(), original.getPrecompileContractRegistry(),
original.isSkipZeroBlockRewards(), original.isSkipZeroBlockRewards(),
original.getGasCalculator(), original.getGasCalculator(),
original.getTransactionGasCalculator(),
original.getGasLimitCalculator(), original.getGasLimitCalculator(),
original.getFeeMarket(), original.getFeeMarket(),
original.getBadBlocksManager(), original.getBadBlocksManager(),

Loading…
Cancel
Save