From 8e437317680a01f373ed97d9272ec8b0a78570f9 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 24 Jan 2023 10:33:30 +0100 Subject: [PATCH 01/27] Gas accounting for EIP-4844 Signed-off-by: Fabio Di Fabio --- .../blockcreation/AbstractBlockCreator.java | 27 +- .../BlockTransactionSelector.java | 292 +++++++++++------- .../AbstractBlockTransactionSelectorTest.java | 7 +- .../ethereum/core/BlockHeaderBuilder.java | 1 - .../besu/ethereum/core/Transaction.java | 58 ++-- .../feemarket/TransactionPriceCalculator.java | 78 ++++- .../mainnet/MainnetProtocolSpecs.java | 29 ++ .../mainnet/MainnetTransactionProcessor.java | 17 +- .../mainnet/MainnetTransactionValidator.java | 64 ++-- .../mainnet/feemarket/CancunFeeMarket.java | 39 +++ .../ethereum/mainnet/feemarket/FeeMarket.java | 13 + .../mainnet/feemarket/LegacyFeeMarket.java | 2 +- .../mainnet/feemarket/LondonFeeMarket.java | 13 +- .../mainnet/feemarket/ZeroBaseFeeMarket.java | 5 + .../transaction/TransactionInvalidReason.java | 3 +- .../ethereum/core/TransactionEIP1559Test.java | 79 ----- .../TransactionPriceCalculatorTest.java | 12 +- .../MainnetTransactionValidatorTest.java | 4 +- .../feemarket/ZeroBaseFeeMarketTest.java | 9 +- ...TransactionReplacementByFeeMarketRule.java | 25 +- .../gascalculator/CancunGasCalculator.java | 55 ++++ .../besu/evm/gascalculator/GasCalculator.java | 15 +- 22 files changed, 575 insertions(+), 272 deletions(-) create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/CancunFeeMarket.java delete mode 100644 ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/TransactionEIP1559Test.java create mode 100644 evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java index dcb60edbfd0..23098d9c755 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.blockcreation; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.ProtocolContext; @@ -43,6 +44,7 @@ import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.evm.account.EvmAccount; import org.hyperledger.besu.evm.worldstate.WorldUpdater; +import org.hyperledger.besu.plugin.data.TransactionType; import org.hyperledger.besu.plugin.services.exception.StorageException; import org.hyperledger.besu.plugin.services.securitymodule.SecurityModuleException; @@ -208,6 +210,10 @@ protected BlockCreationResult createBlock( throwIfStopped(); + final DataGas newExcessDataGas = computeExcessDataGas(transactionResults, newProtocolSpec); + + throwIfStopped(); + final SealableBlockHeader sealableBlockHeader = BlockHeaderBuilder.create() .populateFrom(processableBlockHeader) @@ -223,6 +229,7 @@ protected BlockCreationResult createBlock( withdrawalsCanBeProcessed ? BodyValidation.withdrawalsRoot(maybeWithdrawals.get()) : null) + .excessDataGas(newExcessDataGas) .buildSealableBlockHeader(); final BlockHeader blockHeader = createFinalBlockHeader(sealableBlockHeader); @@ -244,6 +251,23 @@ protected BlockCreationResult createBlock( } } + private DataGas computeExcessDataGas( + BlockTransactionSelector.TransactionSelectionResults transactionResults, + ProtocolSpec newProtocolSpec) { + + if (newProtocolSpec.getFeeMarket().implementsBaseFee()) { + final var gasCalculator = newProtocolSpec.getGasCalculator(); + final int newBlobsCount = + transactionResults.getTransactionsByType(TransactionType.BLOB).stream() + .map(tx -> tx.getVersionedHashes().orElseThrow()) + .mapToInt(List::size) + .sum(); + return gasCalculator.computeExcessDataGas( + parentHeader.getExcessDataGas().orElse(DataGas.ZERO), newBlobsCount); + } + return null; + } + private BlockTransactionSelector.TransactionSelectionResults selectTransactions( final ProcessableBlockHeader processableBlockHeader, final MutableWorldState disposableWorldState, @@ -268,7 +292,8 @@ private BlockTransactionSelector.TransactionSelectionResults selectTransactions( minBlockOccupancyRatio, isCancelled::get, miningBeneficiary, - protocolSpec.getFeeMarket()); + protocolSpec.getFeeMarket(), + protocolSpec.getGasCalculator()); if (transactions.isPresent()) { return selector.evaluateTransactions(transactions.get()); diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java index bacbd076419..613a074814a 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java @@ -35,14 +35,20 @@ import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; import org.hyperledger.besu.ethereum.vm.BlockHashLookup; import org.hyperledger.besu.evm.account.EvmAccount; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; import org.hyperledger.besu.evm.worldstate.WorldUpdater; +import org.hyperledger.besu.plugin.data.TransactionType; +import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.concurrent.CancellationException; import java.util.function.Supplier; import java.util.stream.Collectors; +import java.util.stream.Stream; import com.google.common.collect.Lists; import org.apache.tuweni.bytes.Bytes; @@ -74,115 +80,6 @@ public class BlockTransactionSelector { private final Wei minTransactionGasPrice; private final Double minBlockOccupancyRatio; - - public static class TransactionValidationResult { - private final Transaction transaction; - private final ValidationResult validationResult; - - public TransactionValidationResult( - final Transaction transaction, - final ValidationResult validationResult) { - this.transaction = transaction; - this.validationResult = validationResult; - } - - public Transaction getTransaction() { - return transaction; - } - - public ValidationResult getValidationResult() { - return validationResult; - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - TransactionValidationResult that = (TransactionValidationResult) o; - return Objects.equals(transaction, that.transaction) - && Objects.equals(validationResult, that.validationResult); - } - - @Override - public int hashCode() { - return Objects.hash(transaction, validationResult); - } - } - - public static class TransactionSelectionResults { - - private final List transactions = Lists.newArrayList(); - private final List receipts = Lists.newArrayList(); - private final List invalidTransactions = Lists.newArrayList(); - private long cumulativeGasUsed = 0; - - private void update( - final Transaction transaction, final TransactionReceipt receipt, final long gasUsed) { - transactions.add(transaction); - receipts.add(receipt); - cumulativeGasUsed += gasUsed; - traceLambda( - LOG, - "New selected transaction {}, total transactions {}, cumulative gas used {}", - transaction::toTraceLog, - transactions::size, - () -> cumulativeGasUsed); - } - - private void updateWithInvalidTransaction( - final Transaction transaction, - final ValidationResult validationResult) { - invalidTransactions.add(new TransactionValidationResult(transaction, validationResult)); - } - - public List getTransactions() { - return transactions; - } - - public List getReceipts() { - return receipts; - } - - public long getCumulativeGasUsed() { - return cumulativeGasUsed; - } - - public List getInvalidTransactions() { - return invalidTransactions; - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - TransactionSelectionResults that = (TransactionSelectionResults) o; - return cumulativeGasUsed == that.cumulativeGasUsed - && transactions.equals(that.transactions) - && receipts.equals(that.receipts) - && invalidTransactions.equals(that.invalidTransactions); - } - - @Override - public int hashCode() { - return Objects.hash(transactions, receipts, invalidTransactions, cumulativeGasUsed); - } - - public String toTraceLog() { - return "cumulativeGasUsed=" - + cumulativeGasUsed - + ", transactions=" - + transactions.stream().map(Transaction::toTraceLog).collect(Collectors.joining("; ")); - } - } - private final Supplier isCancelled; private final MainnetTransactionProcessor transactionProcessor; private final ProcessableBlockHeader processableBlockHeader; @@ -192,6 +89,7 @@ public String toTraceLog() { private final AbstractBlockProcessor.TransactionReceiptFactory transactionReceiptFactory; private final Address miningBeneficiary; private final FeeMarket feeMarket; + private final GasCalculator gasCalculator; private final TransactionSelectionResults transactionSelectionResult = new TransactionSelectionResults(); @@ -207,7 +105,8 @@ public BlockTransactionSelector( final Double minBlockOccupancyRatio, final Supplier isCancelled, final Address miningBeneficiary, - final FeeMarket feeMarket) { + final FeeMarket feeMarket, + final GasCalculator gasCalculator) { this.transactionProcessor = transactionProcessor; this.blockchain = blockchain; this.worldState = worldState; @@ -219,6 +118,7 @@ public BlockTransactionSelector( this.minBlockOccupancyRatio = minBlockOccupancyRatio; this.miningBeneficiary = miningBeneficiary; this.feeMarket = feeMarket; + this.gasCalculator = gasCalculator; } /* @@ -278,6 +178,9 @@ private TransactionSelectionResult evaluateTransaction( if (transactionCurrentPriceBelowMin(transaction)) { return TransactionSelectionResult.CONTINUE; } + if (transactionDataPriceBelowMin(transaction)) { + return TransactionSelectionResult.CONTINUE; + } final WorldUpdater worldStateUpdater = worldState.updater(); final BlockHashLookup blockHashLookup = new BlockHashLookup(processableBlockHeader, blockchain); @@ -331,6 +234,21 @@ private TransactionSelectionResult evaluateTransaction( return TransactionSelectionResult.CONTINUE; } + private boolean transactionDataPriceBelowMin(final Transaction transaction) { + if (feeMarket.implementsBaseFee()) { + if (transaction + .getMaxFeePerDataGas() + .orElseThrow() + .lessThan( + feeMarket + .getTransactionPriceCalculator() + .dataPrice(transaction, processableBlockHeader))) { + return true; + } + } + return false; + } + private boolean transactionCurrentPriceBelowMin(final Transaction transaction) { // Here we only care about EIP1159 since for Frontier and local transactions the checks // that we do when accepting them in the pool are enough @@ -420,8 +338,12 @@ private void updateTransactionResultTracking( transaction.isGoQuorumPrivateTransaction( transactionProcessor.getTransactionValidator().getGoQuorumCompatibilityMode()); + final long dataGasUsed = gasCalculator.dataGasCost(transaction.getBlobCount()); + final long gasUsedByTransaction = - isGoQuorumPrivateTransaction ? 0 : transaction.getGasLimit() - result.getGasRemaining(); + isGoQuorumPrivateTransaction + ? 0 + : transaction.getGasLimit() + dataGasUsed - result.getGasRemaining(); final long cumulativeGasUsed = transactionSelectionResult.getCumulativeGasUsed() + gasUsedByTransaction; @@ -430,7 +352,8 @@ private void updateTransactionResultTracking( transaction, transactionReceiptFactory.create( transaction.getType(), result, worldState, cumulativeGasUsed), - gasUsedByTransaction); + gasUsedByTransaction, + dataGasUsed); } private boolean isIncorrectNonce(final ValidationResult result) { @@ -448,7 +371,14 @@ private TransactionProcessingResult publicResultForWhenWeHaveAPrivateTransaction } private boolean transactionTooLargeForBlock(final Transaction transaction) { - return transaction.getGasLimit() + final var dataGasUsed = gasCalculator.dataGasCost(transaction.getBlobCount()); + + if (dataGasUsed + > gasCalculator.getDataGasLimit() - transactionSelectionResult.getCumulativeDataGasUsed()) { + return true; + } + + return transaction.getGasLimit() + dataGasUsed > processableBlockHeader.getGasLimit() - transactionSelectionResult.getCumulativeGasUsed(); } @@ -464,4 +394,140 @@ private boolean blockOccupancyAboveThreshold() { occupancyRatio); return occupancyRatio >= minBlockOccupancyRatio; } + + public static class TransactionValidationResult { + private final Transaction transaction; + private final ValidationResult validationResult; + + public TransactionValidationResult( + final Transaction transaction, + final ValidationResult validationResult) { + this.transaction = transaction; + this.validationResult = validationResult; + } + + public Transaction getTransaction() { + return transaction; + } + + public ValidationResult getValidationResult() { + return validationResult; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TransactionValidationResult that = (TransactionValidationResult) o; + return Objects.equals(transaction, that.transaction) + && Objects.equals(validationResult, that.validationResult); + } + + @Override + public int hashCode() { + return Objects.hash(transaction, validationResult); + } + } + + public static class TransactionSelectionResults { + + private final Map> transactionsByType = new HashMap<>(); + private final List receipts = Lists.newArrayList(); + private final List invalidTransactions = Lists.newArrayList(); + private long cumulativeGasUsed = 0; + private long cumulativeDataGasUsed = 0; + + private void update( + final Transaction transaction, + final TransactionReceipt receipt, + final long gasUsed, + final long dataGasUsed) { + transactionsByType + .computeIfAbsent(transaction.getType(), type -> new ArrayList<>()) + .add(transaction); + receipts.add(receipt); + cumulativeGasUsed += gasUsed; + cumulativeDataGasUsed += dataGasUsed; + traceLambda( + LOG, + "New selected transaction {}, total transactions {}, cumulative gas used {}, cumulative data gas used {}", + transaction::toTraceLog, + () -> transactionsByType.values().stream().mapToInt(List::size).sum(), + () -> cumulativeGasUsed, + () -> cumulativeDataGasUsed); + } + + private void updateWithInvalidTransaction( + final Transaction transaction, + final ValidationResult validationResult) { + invalidTransactions.add(new TransactionValidationResult(transaction, validationResult)); + } + + public List getTransactions() { + return streamAllTransactions().collect(Collectors.toList()); + } + + public List getTransactionsByType(final TransactionType type) { + return transactionsByType.getOrDefault(type, List.of()); + } + + public List getReceipts() { + return receipts; + } + + public long getCumulativeGasUsed() { + return cumulativeGasUsed; + } + + public long getCumulativeDataGasUsed() { + return cumulativeDataGasUsed; + } + + public List getInvalidTransactions() { + return invalidTransactions; + } + + private Stream streamAllTransactions() { + return transactionsByType.values().stream().flatMap(List::stream); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TransactionSelectionResults that = (TransactionSelectionResults) o; + return cumulativeGasUsed == that.cumulativeGasUsed + && cumulativeDataGasUsed == that.cumulativeDataGasUsed + && transactionsByType.equals(that.transactionsByType) + && receipts.equals(that.receipts) + && invalidTransactions.equals(that.invalidTransactions); + } + + @Override + public int hashCode() { + return Objects.hash( + transactionsByType, + receipts, + invalidTransactions, + cumulativeGasUsed, + cumulativeDataGasUsed); + } + + public String toTraceLog() { + return "cumulativeGasUsed=" + + cumulativeGasUsed + + ", cumulativeDataGasUsed=" + + cumulativeDataGasUsed + + ", transactions=" + + streamAllTransactions().map(Transaction::toTraceLog).collect(Collectors.joining("; ")); + } + } } diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java index f6e0f9b263e..f0d012ddb84 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java @@ -50,6 +50,7 @@ import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; import org.hyperledger.besu.ethereum.referencetests.ReferenceTestBlockchain; import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; +import org.hyperledger.besu.evm.gascalculator.LondonGasCalculator; import org.hyperledger.besu.evm.internal.EvmConfiguration; import org.hyperledger.besu.evm.worldstate.WorldState; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; @@ -255,7 +256,8 @@ public void useSingleGasSpaceForAllTransactions() { 0.8, this::isCancelled, miningBeneficiary, - FeeMarket.london(0L)); + FeeMarket.london(0L), + new LondonGasCalculator()); // this should fill up all the block space final Transaction fillingLegacyTx = @@ -452,7 +454,8 @@ protected BlockTransactionSelector createBlockSelector( 0.8, this::isCancelled, miningBeneficiary, - getFeeMarket()); + getFeeMarket(), + new LondonGasCalculator()); return selector; } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java index 896fb80604d..d3a2a7e7f0d 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockHeaderBuilder.java @@ -385,7 +385,6 @@ public BlockHeaderBuilder withdrawalsRoot(final Hash hash) { } public BlockHeaderBuilder excessDataGas(final DataGas excessDataGas) { - checkArgument(gasLimit >= 0L); this.excessDataGas = excessDataGas; return this; } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java index 38e77ed07dd..5a48fb36acd 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java @@ -44,7 +44,6 @@ import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; -import java.util.stream.Stream; import com.google.common.primitives.Longs; import org.apache.tuweni.bytes.Bytes; @@ -478,6 +477,17 @@ public long getGasLimit() { return gasLimit; } + /** + * Returns the number of blobs this transaction has. Only call on a blob type transaction or it + * will throw exception + * + * @throws java.util.NoSuchElementException if called on a non blob transaction + * @return return the count + */ + public int getBlobCount() { + return versionedHashes.orElseThrow().size(); + } + /** * Returns the transaction recipient. * @@ -692,41 +702,37 @@ public boolean isContractCreation() { } /** - * Calculates the up-front cost for the gas the transaction can use. + * Check if the upfront gas cost is over the max allowed * - * @return the up-front cost for the gas the transaction can use. + * @return true is upfront data cost overflow uint256 max value */ - public Wei getUpfrontGasCost() { - return getUpfrontGasCost( - Stream.concat(maxFeePerGas.stream(), gasPrice.stream()) - .findFirst() - .orElseThrow( - () -> - new IllegalStateException( - String.format("Transaction requires either gasPrice or maxFeePerGas")))); + private boolean isUpfrontGasCostTooHigh() { + return calculateUpfrontGasCost(getMaxGasPrice(), Wei.ZERO, 0).bitLength() > 256; } /** - * Check if the upfront gas cost is over the max allowed + * Calculates the max up-front cost for the gas the transaction can use. * - * @return true is upfront data cost overflow uint256 max value + * @return the max up-front cost for the gas the transaction can use. */ - private boolean isUpfrontGasCostTooHigh() { - return calculateUpfrontGasCost(getMaxGasPrice()).bitLength() > 256; + private Wei getMaxUpfrontGasCost(final int dataGasPerBlock) { + return getUpfrontGasCost( + getMaxGasPrice(), getMaxFeePerDataGas().orElse(Wei.ZERO), dataGasPerBlock); } /** - * Calculates the up-front cost for the gas the transaction can use. + * Calculates the up-front cost for the gas and data gas the transaction can use. * * @param gasPrice the gas price to use + * @param dataGasPrice the data gas price to use * @return the up-front cost for the gas the transaction can use. */ - public Wei getUpfrontGasCost(final Wei gasPrice) { + public Wei getUpfrontGasCost(final Wei gasPrice, final Wei dataGasPrice, final int totalDataGas) { if (gasPrice == null || gasPrice.isZero()) { return Wei.ZERO; } - final var cost = calculateUpfrontGasCost(gasPrice); + final var cost = calculateUpfrontGasCost(gasPrice, dataGasPrice, totalDataGas); if (cost.bitLength() > 256) { return Wei.MAX_WEI; @@ -735,8 +741,16 @@ public Wei getUpfrontGasCost(final Wei gasPrice) { } } - private BigInteger calculateUpfrontGasCost(final Wei gasPrice) { - return new BigInteger(1, Longs.toByteArray(getGasLimit())).multiply(gasPrice.getAsBigInteger()); + private BigInteger calculateUpfrontGasCost( + final Wei gasPrice, final Wei dataGasPrice, final int totalDataGas) { + var cost = + new BigInteger(1, Longs.toByteArray(getGasLimit())).multiply(gasPrice.getAsBigInteger()); + + if (transactionType.supportsBlob()) { + cost = cost.add(dataGasPrice.getAsBigInteger().multiply(BigInteger.valueOf(totalDataGas))); + } + + return cost; } /** @@ -748,8 +762,8 @@ private BigInteger calculateUpfrontGasCost(final Wei gasPrice) { * * @return the up-front gas cost for the transaction */ - public Wei getUpfrontCost() { - return getUpfrontGasCost().addExact(getValue()); + public Wei getUpfrontCost(final int totalDataGas) { + return getMaxUpfrontGasCost(totalDataGas).addExact(getValue()); } /** diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculator.java index b68da184006..531dff5d4f3 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculator.java @@ -14,22 +14,41 @@ */ package org.hyperledger.besu.ethereum.core.feemarket; +import static org.hyperledger.besu.util.Slf4jLambdaHelper.traceLambda; + import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; import org.hyperledger.besu.ethereum.core.Transaction; +import java.math.BigInteger; import java.util.Optional; -@FunctionalInterface +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public interface TransactionPriceCalculator { - Wei price(Transaction transaction, Optional baseFee); + Wei price(Transaction transaction, Optional maybeFee); - static TransactionPriceCalculator frontier() { - return (transaction, baseFee) -> transaction.getGasPrice().orElse(Wei.ZERO); + default Wei dataPrice(final Transaction transaction, final ProcessableBlockHeader blockHeader) { + return Wei.ZERO; } - static TransactionPriceCalculator eip1559() { - return (transaction, maybeBaseFee) -> { - final Wei baseFee = maybeBaseFee.orElseThrow(); + class Frontier implements TransactionPriceCalculator { + @Override + public Wei price(final Transaction transaction, final Optional maybeFee) { + return transaction.getGasPrice().orElse(Wei.ZERO); + } + + @Override + public Wei dataPrice(final Transaction transaction, final ProcessableBlockHeader blockHeader) { + return Wei.ZERO; + } + } + + class EIP1559 implements TransactionPriceCalculator { + @Override + public Wei price(final Transaction transaction, final Optional maybeFee) { + final Wei baseFee = maybeFee.orElseThrow(); if (!transaction.getType().supports1559FeeMarket()) { return transaction.getGasPrice().orElse(Wei.ZERO); } @@ -40,6 +59,49 @@ static TransactionPriceCalculator eip1559() { price = maxFeePerGas; } return price; - }; + } + } + + class DataBlob extends EIP1559 { + private static final Logger LOG = LoggerFactory.getLogger(DataBlob.class); + private final BigInteger minDataGasPrice; + private final BigInteger dataGasPriceUpdateFraction; + + public DataBlob(final int minDataGasPrice, final int dataGasPriceUpdateFraction) { + this.minDataGasPrice = BigInteger.valueOf(minDataGasPrice); + this.dataGasPriceUpdateFraction = BigInteger.valueOf(dataGasPriceUpdateFraction); + } + + @Override + public Wei dataPrice(final Transaction transaction, final ProcessableBlockHeader blockHeader) { + final var excessDataGas = blockHeader.getExcessDataGas().orElseThrow(); + + final var dataGasPrice = + Wei.of( + fakeExponential( + minDataGasPrice, excessDataGas.toBigInteger(), dataGasPriceUpdateFraction)); + traceLambda( + LOG, + "block #{} parentExcessDataGas: {} dataGasPrice: {}", + blockHeader::getNumber, + excessDataGas::toShortHexString, + dataGasPrice::toHexString); + + return dataGasPrice; + } + + private BigInteger fakeExponential( + final BigInteger factor, final BigInteger numerator, final BigInteger denominator) { + BigInteger i = BigInteger.ONE; + BigInteger output = BigInteger.ZERO; + BigInteger numeratorAccumulator = factor.multiply(denominator); + while (numeratorAccumulator.compareTo(BigInteger.ZERO) > 0) { + output = output.add(numeratorAccumulator); + numeratorAccumulator = + (numeratorAccumulator.multiply(numerator)).divide(denominator.multiply(i)); + i = i.add(BigInteger.ONE); + } + return output.divide(denominator); + } } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java index 874b73afb17..36d0d97f86b 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java @@ -45,6 +45,7 @@ import org.hyperledger.besu.evm.frame.MessageFrame; import org.hyperledger.besu.evm.gascalculator.BerlinGasCalculator; import org.hyperledger.besu.evm.gascalculator.ByzantiumGasCalculator; +import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; import org.hyperledger.besu.evm.gascalculator.ConstantinopleGasCalculator; import org.hyperledger.besu.evm.gascalculator.FrontierGasCalculator; import org.hyperledger.besu.evm.gascalculator.HomesteadGasCalculator; @@ -83,6 +84,9 @@ public abstract class MainnetProtocolSpecs { public static final int SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT = 24576; public static final int SHANGHAI_INIT_CODE_SIZE_LIMIT = 2 * SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT; + private static final int CANCUN_MIN_DATA_GAS_PRICE = 1; + private static final int CANCUN_DATA_GAS_PRICE_UPDATE_FRACTION = 2225652; + private static final Address RIPEMD160_PRECOMPILE = Address.fromHexString("0x0000000000000000000000000000000000000003"); @@ -719,6 +723,15 @@ static ProtocolSpecBuilder cancunDefinition( final int contractSizeLimit = configContractSizeLimit.orElse(SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT); + final long londonForkBlockNumber = genesisConfigOptions.getLondonBlockNumber().orElse(0L); + final BaseFeeMarket londonFeeMarket = + genesisConfigOptions.isZeroBaseFee() + ? FeeMarket.zeroBaseFee(londonForkBlockNumber) + : FeeMarket.cancun( + londonForkBlockNumber, + genesisConfigOptions.getBaseFeePerGas(), + CANCUN_MIN_DATA_GAS_PRICE, + CANCUN_DATA_GAS_PRICE_UPDATE_FRACTION); return shanghaiDefinition( chainId, @@ -728,6 +741,8 @@ static ProtocolSpecBuilder cancunDefinition( genesisConfigOptions, quorumCompatibilityMode, evmConfiguration) + // gas calculator for EIP-4844 data gas + .gasCalculator(CancunGasCalculator::new) // EVM changes to support EOF EIPs (3670, 4200, 4750, 5450) .evmBuilder( (gasCalculator, jdCacheConfig) -> @@ -744,6 +759,20 @@ static ProtocolSpecBuilder cancunDefinition( MaxCodeSizeRule.of(contractSizeLimit), EOFValidationCodeRule.of(1, false)), 1, SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES)) + // change to check for max data gas per block for EIP-4844 + .transactionValidatorBuilder( + gasCalculator -> + new MainnetTransactionValidator( + gasCalculator, + londonFeeMarket, + true, + chainId, + Set.of( + TransactionType.FRONTIER, + TransactionType.ACCESS_LIST, + TransactionType.EIP1559), + quorumCompatibilityMode, + SHANGHAI_INIT_CODE_SIZE_LIMIT)) .precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::cancun) .name("Cancun"); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java index f9c731744a9..7537ee8ab42 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java @@ -291,13 +291,19 @@ public TransactionProcessingResult processTransaction( final long previousNonce = senderMutableAccount.incrementNonce(); final Wei transactionGasPrice = feeMarket.getTransactionPriceCalculator().price(transaction, blockHeader.getBaseFee()); + final Wei dataGasPrice = + feeMarket.getTransactionPriceCalculator().dataPrice(transaction, blockHeader); LOG.trace( "Incremented sender {} nonce ({} -> {})", senderAddress, previousNonce, sender.getNonce()); - final Wei upfrontGasCost = transaction.getUpfrontGasCost(transactionGasPrice); + final Wei upfrontGasCost = + transaction.getUpfrontGasCost( + transactionGasPrice, + dataGasPrice, + gasCalculator.dataGasCost(transaction.getBlobCount())); final Wei previousBalance = senderMutableAccount.decrementBalance(upfrontGasCost); LOG.trace( "Deducted sender {} upfront gas cost {} ({} -> {})", @@ -328,7 +334,14 @@ public TransactionProcessingResult processTransaction( transaction.getPayload(), transaction.isContractCreation()); final long accessListGas = gasCalculator.accessListGasCost(accessListEntries.size(), accessListStorageCount); - final long gasAvailable = transaction.getGasLimit() - intrinsicGas - accessListGas; + final long dataGas; + if (feeMarket.implementsDataFee()) { + dataGas = gasCalculator.dataGasCost(transaction.getVersionedHashes().orElseThrow().size()); + } else { + dataGas = 0L; + } + + final long gasAvailable = transaction.getGasLimit() - intrinsicGas - accessListGas - dataGas; LOG.trace( "Gas available for execution {} = {} - {} (limit - intrinsic)", gasAvailable, diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java index 12efd424ee9..bb8269019b0 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java @@ -119,12 +119,6 @@ public ValidationResult validate( return signatureResult; } - if (goQuorumCompatibilityMode && transaction.hasCostParams()) { - return ValidationResult.invalid( - TransactionInvalidReason.GAS_PRICE_MUST_BE_ZERO, - "gasPrice must be set to zero on a GoQuorum compatible network"); - } - final TransactionType transactionType = transaction.getType(); if (!acceptedTransactionTypes.contains(transactionType)) { return ValidationResult.invalid( @@ -134,10 +128,48 @@ public ValidationResult validate( transactionType, acceptedTransactionTypes)); } - if (baseFee.isPresent()) { - final Wei price = feeMarket.getTransactionPriceCalculator().price(transaction, baseFee); + if (transaction.getNonce() == MAX_NONCE) { + return ValidationResult.invalid( + TransactionInvalidReason.NONCE_OVERFLOW, "Nonce must be less than 2^64-1"); + } + + if (transaction.isContractCreation() && transaction.getPayload().size() > maxInitcodeSize) { + return ValidationResult.invalid( + TransactionInvalidReason.INITCODE_TOO_LARGE, + String.format( + "Initcode size of %d exceeds maximum size of %s", + transaction.getPayload().size(), maxInitcodeSize)); + } + + if (transaction.getType().supportsBlob()) { + final long txTotalDataGas = gasCalculator.dataGasCost(transaction.getBlobCount()); + if (txTotalDataGas > gasCalculator.getDataGasLimit()) { + return ValidationResult.invalid( + TransactionInvalidReason.TOTAL_DATA_GAS_TOO_HIGH, + String.format( + "total data gas %d exceeds max data gas per block %d", + txTotalDataGas, gasCalculator.getDataGasLimit())); + } + } + + return validateCostAndFee(transaction, baseFee, transactionValidationParams); + } + + private ValidationResult validateCostAndFee( + final Transaction transaction, + final Optional maybeBaseFee, + final TransactionValidationParams transactionValidationParams) { + + if (goQuorumCompatibilityMode && transaction.hasCostParams()) { + return ValidationResult.invalid( + TransactionInvalidReason.GAS_PRICE_MUST_BE_ZERO, + "gasPrice must be set to zero on a GoQuorum compatible network"); + } + + if (maybeBaseFee.isPresent()) { + final Wei price = feeMarket.getTransactionPriceCalculator().price(transaction, maybeBaseFee); if (!transactionValidationParams.isAllowMaxFeeGasBelowBaseFee() - && price.compareTo(baseFee.orElseThrow()) < 0) { + && price.compareTo(maybeBaseFee.orElseThrow()) < 0) { return ValidationResult.invalid( TransactionInvalidReason.GAS_PRICE_BELOW_CURRENT_BASE_FEE, "gasPrice is less than the current BaseFee"); @@ -174,14 +206,6 @@ public ValidationResult validate( intrinsicGasCost, transaction.getGasLimit())); } - if (transaction.isContractCreation() && transaction.getPayload().size() > maxInitcodeSize) { - return ValidationResult.invalid( - TransactionInvalidReason.INITCODE_TOO_LARGE, - String.format( - "Initcode size of %d exceeds maximum size of %s", - transaction.getPayload().size(), maxInitcodeSize)); - } - return ValidationResult.valid(); } @@ -199,12 +223,14 @@ public ValidationResult validateForSender( if (sender.getCodeHash() != null) codeHash = sender.getCodeHash(); } - if (transaction.getUpfrontCost().compareTo(senderBalance) > 0) { + final Wei upfrontCost = + transaction.getUpfrontCost(gasCalculator.dataGasCost(transaction.getBlobCount())); + if (upfrontCost.compareTo(senderBalance) > 0) { return ValidationResult.invalid( TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE, String.format( "transaction up-front cost %s exceeds transaction sender account balance %s", - transaction.getUpfrontCost(), senderBalance)); + upfrontCost, senderBalance)); } if (transaction.getNonce() < senderNonce) { diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/CancunFeeMarket.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/CancunFeeMarket.java new file mode 100644 index 00000000000..dd83bcb7cf3 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/CancunFeeMarket.java @@ -0,0 +1,39 @@ +/* + * Copyright ConsenSys AG. + * + * 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.feemarket; + +import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.core.feemarket.TransactionPriceCalculator; + +import java.util.Optional; + +public class CancunFeeMarket extends LondonFeeMarket { + + public CancunFeeMarket( + final long londonForkBlockNumber, + final Optional baseFeePerGasOverride, + final int minDataGasPrice, + final int dataGasPriceUpdateFraction) { + super( + new TransactionPriceCalculator.DataBlob(minDataGasPrice, dataGasPriceUpdateFraction), + londonForkBlockNumber, + baseFeePerGasOverride); + } + + @Override + public boolean implementsDataFee() { + return true; + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/FeeMarket.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/FeeMarket.java index f0a5df1098c..6637501dbb7 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/FeeMarket.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/FeeMarket.java @@ -26,6 +26,10 @@ default boolean implementsBaseFee() { return false; } + default boolean implementsDataFee() { + return false; + } + TransactionPriceCalculator getTransactionPriceCalculator(); boolean satisfiesFloorTxFee(Transaction txn); @@ -39,6 +43,15 @@ static BaseFeeMarket london( return new LondonFeeMarket(londonForkBlockNumber, baseFeePerGasOverride); } + static BaseFeeMarket cancun( + final long londonForkBlockNumber, + final Optional baseFeePerGasOverride, + final int minDataGasPrice, + final int dataGasPriceUpdateFraction) { + return new CancunFeeMarket( + londonForkBlockNumber, baseFeePerGasOverride, minDataGasPrice, dataGasPriceUpdateFraction); + } + static BaseFeeMarket zeroBaseFee(final long londonForkBlockNumber) { return new ZeroBaseFeeMarket(londonForkBlockNumber); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LegacyFeeMarket.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LegacyFeeMarket.java index 8e73ec2948c..ec328d29824 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LegacyFeeMarket.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LegacyFeeMarket.java @@ -22,7 +22,7 @@ public class LegacyFeeMarket implements FeeMarket { private final TransactionPriceCalculator txPriceCalculator; public LegacyFeeMarket() { - this.txPriceCalculator = TransactionPriceCalculator.frontier(); + this.txPriceCalculator = new TransactionPriceCalculator.Frontier(); } @Override diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarket.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarket.java index 87d1fdffb81..98b23ad1945 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarket.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarket.java @@ -26,12 +26,14 @@ import org.slf4j.LoggerFactory; public class LondonFeeMarket implements BaseFeeMarket { + private static final Logger LOG = LoggerFactory.getLogger(LondonFeeMarket.class); + static final Wei DEFAULT_BASEFEE_INITIAL_VALUE = GenesisConfigFile.BASEFEE_AT_GENESIS_DEFAULT_VALUE; static final long DEFAULT_BASEFEE_MAX_CHANGE_DENOMINATOR = 8L; static final long DEFAULT_SLACK_COEFFICIENT = 2L; + private static final Wei DEFAULT_BASEFEE_FLOOR = Wei.of(7L); - private static final Logger LOG = LoggerFactory.getLogger(LondonFeeMarket.class); private final Wei baseFeeInitialValue; private final long londonForkBlockNumber; @@ -44,7 +46,14 @@ public LondonFeeMarket(final long londonForkBlockNumber) { public LondonFeeMarket( final long londonForkBlockNumber, final Optional baseFeePerGasOverride) { - this.txPriceCalculator = TransactionPriceCalculator.eip1559(); + this(new TransactionPriceCalculator.EIP1559(), londonForkBlockNumber, baseFeePerGasOverride); + } + + protected LondonFeeMarket( + final TransactionPriceCalculator txPriceCalculator, + final long londonForkBlockNumber, + final Optional baseFeePerGasOverride) { + this.txPriceCalculator = txPriceCalculator; this.londonForkBlockNumber = londonForkBlockNumber; this.baseFeeInitialValue = baseFeePerGasOverride.orElse(DEFAULT_BASEFEE_INITIAL_VALUE); this.baseFeeFloor = baseFeeInitialValue.isZero() ? Wei.ZERO : DEFAULT_BASEFEE_FLOOR; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ZeroBaseFeeMarket.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ZeroBaseFeeMarket.java index c2f406cad04..85d55ef429d 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ZeroBaseFeeMarket.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ZeroBaseFeeMarket.java @@ -38,4 +38,9 @@ public Wei computeBaseFee( public ValidationMode baseFeeValidationMode(final long blockNumber) { return ValidationMode.NONE; } + + @Override + public boolean implementsDataFee() { + return true; + } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionInvalidReason.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionInvalidReason.java index d4297b7fa33..6bd44a03389 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionInvalidReason.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionInvalidReason.java @@ -54,5 +54,6 @@ public enum TransactionInvalidReason { ETHER_VALUE_NOT_SUPPORTED, UPFRONT_FEE_TOO_HIGH, NONCE_TOO_FAR_IN_FUTURE_FOR_SENDER, - LOWER_NONCE_INVALID_TRANSACTION_EXISTS + LOWER_NONCE_INVALID_TRANSACTION_EXISTS, + TOTAL_DATA_GAS_TOO_HIGH } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/TransactionEIP1559Test.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/TransactionEIP1559Test.java deleted file mode 100644 index 2a2211b9380..00000000000 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/TransactionEIP1559Test.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright ConsenSys AG. - * - * 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.core; - -import org.hyperledger.besu.crypto.KeyPair; -import org.hyperledger.besu.crypto.SignatureAlgorithm; -import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; -import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.Wei; -import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; -import org.hyperledger.besu.ethereum.rlp.RLP; -import org.hyperledger.besu.evm.AccessListEntry; - -import java.math.BigInteger; -import java.util.List; - -import com.google.common.base.Supplier; -import com.google.common.base.Suppliers; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.Bytes32; -import org.junit.Test; - -public class TransactionEIP1559Test { - private static final Supplier SIGNATURE_ALGORITHM = - Suppliers.memoize(SignatureAlgorithmFactory::getInstance); - - @Test - public void buildEip1559Transaction() { - final List accessListEntries = - List.of( - new AccessListEntry( - Address.fromHexString("0x000000000000000000000000000000000000aaaa"), - List.of(Bytes32.ZERO))); - final Transaction tx = - Transaction.builder() - .chainId(new BigInteger("1559", 10)) - .nonce(0) - .value(Wei.ZERO) - .gasLimit(30000) - .maxPriorityFeePerGas(Wei.of(2)) - .payload(Bytes.EMPTY.trimLeadingZeros()) - .maxFeePerGas(Wei.of(new BigInteger("5000000000", 10))) - .gasPrice(null) - .to(Address.fromHexString("0x000000000000000000000000000000000000aaaa")) - .accessList(accessListEntries) - .guessType() - .signAndBuild( - keyPair("0x8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63")); - final BytesValueRLPOutput out = new BytesValueRLPOutput(); - tx.writeTo(out); - System.out.println(out.encoded().toHexString()); - System.out.println(tx.getUpfrontCost()); - // final String raw = - // "b8a902f8a686796f6c6f7632800285012a05f20082753094000000000000000000000000000000000000aaaa8080f838f794000000000000000000000000000000000000aaaae1a0000000000000000000000000000000000000000000000000000000000000000001a00c1d69648e348fe26155b45de45004f0e4195f6352d8f0935bc93e98a3e2a862a060064e5b9765c0ac74223b0cf49635c59ae0faf82044fd17bcc68a549ade6f95"; - final String raw = out.encoded().toHexString(); - final Transaction decoded = Transaction.readFrom(RLP.input(Bytes.fromHexString(raw))); - System.out.println(decoded); - System.out.println(decoded.getAccessList().orElseThrow().get(0).getAddressString()); - System.out.println(decoded.getAccessList().orElseThrow().get(0).getStorageKeysString()); - } - - private static KeyPair keyPair(final String privateKey) { - final SignatureAlgorithm signatureAlgorithm = SIGNATURE_ALGORITHM.get(); - return signatureAlgorithm.createKeyPair( - signatureAlgorithm.createPrivateKey(Bytes32.fromHexString(privateKey))); - } -} diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculatorTest.java index 3caa7234908..e57c3a3ee1c 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculatorTest.java @@ -18,8 +18,11 @@ import static org.hyperledger.besu.plugin.data.TransactionType.ACCESS_LIST; import static org.hyperledger.besu.plugin.data.TransactionType.EIP1559; import static org.hyperledger.besu.plugin.data.TransactionType.FRONTIER; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.plugin.data.TransactionType; @@ -37,9 +40,9 @@ public class TransactionPriceCalculatorTest { private static final TransactionPriceCalculator FRONTIER_CALCULATOR = - TransactionPriceCalculator.frontier(); + new TransactionPriceCalculator.Frontier(); private static final TransactionPriceCalculator EIP_1559_CALCULATOR = - TransactionPriceCalculator.eip1559(); + new TransactionPriceCalculator.EIP1559(); private final TransactionPriceCalculator transactionPriceCalculator; private final TransactionType transactionType; @@ -133,6 +136,9 @@ public static Collection data() { @Test public void assertThatCalculatorWorks() { + final ProcessableBlockHeader blockHeader = mock(ProcessableBlockHeader.class); + when(blockHeader.getBaseFee()).thenReturn(baseFee); + assertThat( transactionPriceCalculator.price( Transaction.builder() @@ -143,7 +149,7 @@ public void assertThatCalculatorWorks() { .maxFeePerGas(maxFeePerGas) .chainId(BigInteger.ONE) .build(), - baseFee)) + blockHeader.getBaseFee())) .isEqualByComparingTo(expectedPrice); } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java index db24e7dfbfd..84570440a64 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java @@ -195,7 +195,7 @@ public void shouldRejectTransactionIfAccountIsNotEOA() { validator.setTransactionFilter(transactionFilter(false)); Account invalidEOA = - when(account(basicTransaction.getUpfrontCost(), basicTransaction.getNonce()).getCodeHash()) + when(account(basicTransaction.getUpfrontCost(0), basicTransaction.getNonce()).getCodeHash()) .thenReturn(Hash.fromHexStringLenient("0xdeadbeef")) .getMock(); @@ -547,7 +547,7 @@ public void goQuorumCompatibilityModeSuccessZeroGasPrice() { } private Account accountWithNonce(final long nonce) { - return account(basicTransaction.getUpfrontCost(), nonce); + return account(basicTransaction.getUpfrontCost(0), nonce); } private Account account(final Wei balance, final long nonce) { diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ZeroBaseFeeMarketTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ZeroBaseFeeMarketTest.java index 052044b7018..74776da3ef2 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ZeroBaseFeeMarketTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ZeroBaseFeeMarketTest.java @@ -15,10 +15,13 @@ package org.hyperledger.besu.ethereum.mainnet.feemarket; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import org.hyperledger.besu.crypto.KeyPair; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; import org.hyperledger.besu.plugin.data.TransactionType; @@ -67,10 +70,14 @@ public void getTransactionPriceCalculatorShouldBeEIP1559() { .maxPriorityFeePerGas(Optional.of(Wei.of(8))) .gasPrice(null) .createTransaction(KEY_PAIR1); + + final ProcessableBlockHeader blockHeader = mock(ProcessableBlockHeader.class); + when(blockHeader.getBaseFee()).thenReturn(Optional.of(Wei.ZERO)); + assertThat( zeroBaseFeeMarket .getTransactionPriceCalculator() - .price(transaction, Optional.of(Wei.ZERO))) + .price(transaction, blockHeader.getBaseFee())) .isEqualTo(Wei.of(8)); } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionReplacementByFeeMarketRule.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionReplacementByFeeMarketRule.java index fe9a0b7ca83..1c2bd84c027 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionReplacementByFeeMarketRule.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionReplacementByFeeMarketRule.java @@ -17,7 +17,6 @@ import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.feemarket.TransactionPriceCalculator; -import org.hyperledger.besu.plugin.data.TransactionType; import org.hyperledger.besu.util.number.Percentage; import java.util.Optional; @@ -25,9 +24,9 @@ public class TransactionReplacementByFeeMarketRule implements TransactionPoolReplacementRule { private static final TransactionPriceCalculator FRONTIER_CALCULATOR = - TransactionPriceCalculator.frontier(); + new TransactionPriceCalculator.Frontier(); private static final TransactionPriceCalculator EIP1559_CALCULATOR = - TransactionPriceCalculator.eip1559(); + new TransactionPriceCalculator.EIP1559(); private final Percentage priceBump; public TransactionReplacementByFeeMarketRule(final Percentage priceBump) { @@ -38,26 +37,26 @@ public TransactionReplacementByFeeMarketRule(final Percentage priceBump) { public boolean shouldReplace( final PendingTransaction existingPendingTransaction, final PendingTransaction newPendingTransaction, - final Optional baseFee) { + final Optional maybeBaseFee) { // bail early if basefee is absent or neither transaction supports 1559 fee market - if (baseFee.isEmpty() + if (maybeBaseFee.isEmpty() || !(isNotGasPriced(existingPendingTransaction) || isNotGasPriced(newPendingTransaction))) { return false; } - Wei newEffPrice = priceOf(newPendingTransaction.getTransaction(), baseFee); + Wei newEffPrice = priceOf(newPendingTransaction.getTransaction(), maybeBaseFee); Wei newEffPriority = - newPendingTransaction.getTransaction().getEffectivePriorityFeePerGas(baseFee); + newPendingTransaction.getTransaction().getEffectivePriorityFeePerGas(maybeBaseFee); // bail early if price is not strictly positive if (newEffPrice.equals(Wei.ZERO)) { return false; } - Wei curEffPrice = priceOf(existingPendingTransaction.getTransaction(), baseFee); + Wei curEffPrice = priceOf(existingPendingTransaction.getTransaction(), maybeBaseFee); Wei curEffPriority = - existingPendingTransaction.getTransaction().getEffectivePriorityFeePerGas(baseFee); + existingPendingTransaction.getTransaction().getEffectivePriorityFeePerGas(maybeBaseFee); if (isBumpedBy(curEffPrice, newEffPrice, priceBump)) { // if effective price is bumped by percent: @@ -71,12 +70,10 @@ public boolean shouldReplace( return false; } - private Wei priceOf(final Transaction transaction, final Optional baseFee) { + private Wei priceOf(final Transaction transaction, final Optional maybeBaseFee) { final TransactionPriceCalculator transactionPriceCalculator = - transaction.getType().equals(TransactionType.EIP1559) - ? EIP1559_CALCULATOR - : FRONTIER_CALCULATOR; - return transactionPriceCalculator.price(transaction, baseFee); + transaction.getType().supports1559FeeMarket() ? EIP1559_CALCULATOR : FRONTIER_CALCULATOR; + return transactionPriceCalculator.price(transaction, maybeBaseFee); } private boolean isBumpedBy(final Wei val, final Wei bumpVal, final Percentage percent) { diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java new file mode 100644 index 00000000000..03f756b21ab --- /dev/null +++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java @@ -0,0 +1,55 @@ +/* + * 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.evm.gascalculator; + +import org.hyperledger.besu.datatypes.DataGas; + +/** The Cancun gas calculator. */ +public class CancunGasCalculator extends LondonGasCalculator { + + public static final int CANCUN_DATA_GAS_PER_BLOB = 131072; // 2^17 + public static final DataGas CANCUN_TARGET_DATA_GAS_PER_BLOCK = DataGas.of(262144); // 2^18 + + public static final int CANCUN_MAX_DATA_GAS_PER_BLOCK = 524288; // 2^19 + + @Override + public int dataGasCost(final int blobCount) { + return CANCUN_DATA_GAS_PER_BLOB * blobCount; + } + + /** + * Compute the new excess data gas for the block, using the parent value and the number of new + * blobs + * + * @param parentExcessDataGas the excess data gas value from the parent block + * @param newBlobs the number of blobs in the new block + * @return the new excess data gas value + */ + @Override + public DataGas computeExcessDataGas(final DataGas parentExcessDataGas, final int newBlobs) { + final int consumedDataGas = newBlobs * CANCUN_DATA_GAS_PER_BLOB; + final DataGas currentExcessDataGas = parentExcessDataGas.add(consumedDataGas); + + if (currentExcessDataGas.lessThan(CANCUN_TARGET_DATA_GAS_PER_BLOCK)) { + return DataGas.ZERO; + } + return currentExcessDataGas.add(CANCUN_TARGET_DATA_GAS_PER_BLOCK); + } + + @Override + public long getDataGasLimit() { + return CANCUN_MAX_DATA_GAS_PER_BLOCK; + } +} diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java index 52fb63ea6a9..05386b1a572 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.evm.gascalculator; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.evm.AccessListEntry; import org.hyperledger.besu.evm.account.Account; @@ -438,7 +439,7 @@ default long modExpGasCost(final Bytes input) { long codeDepositGasCost(int codeSize); /** - * Returns the intrinsic gas cost of a transaction pauload, i.e. the cost deriving from its + * Returns the intrinsic gas cost of a transaction payload, i.e. the cost deriving from its * encoded binary representation when stored on-chain. * * @param transactionPayload The encoded transaction, as bytes @@ -487,4 +488,16 @@ default long getMaxRefundQuotient() { */ // what would be the gas for a PMT with hash of all non-zeros long getMaximumTransactionCost(int size); + + default int dataGasCost(final int totalDataGas) { + return 0; + } + + default DataGas computeExcessDataGas(final DataGas parentExcessDataGas, final int newBlobs) { + return DataGas.ZERO; + } + + default long getDataGasLimit() { + return 0; + } } From 05f43879cbda9ec19be4f79cc1c5317769ac2426 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 24 Jan 2023 11:25:57 +0100 Subject: [PATCH 02/27] Update CHANGELOG Signed-off-by: Fabio Di Fabio --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47db6c2a20b..aaaee9236d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - Send only hash announcement for blob transaction type [#4940](https://github.com/hyperledger/besu/pull/4940) - Add `excess_data_gas` field to block header [#4958](https://github.com/hyperledger/besu/pull/4958) - Add `max_fee_per_data_gas` field to transaction [#4970](https://github.com/hyperledger/besu/pull/4970) +- Gas accounting for EIP-4844 [#4992](https://github.com/hyperledger/besu/pull/4992) ### Bug Fixes - Mitigation fix for stale bonsai code storage leading to log rolling issues on contract recreates [#4906](https://github.com/hyperledger/besu/pull/4906) From 7a94b4aad5c874453a70aeb88ddf738e8c26ffe3 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 24 Jan 2023 11:53:53 +0100 Subject: [PATCH 03/27] Fix tests Signed-off-by: Fabio Di Fabio --- .../org/hyperledger/besu/ethereum/core/Transaction.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java index 5a48fb36acd..9bea0d3fb24 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java @@ -478,14 +478,12 @@ public long getGasLimit() { } /** - * Returns the number of blobs this transaction has. Only call on a blob type transaction or it - * will throw exception + * Returns the number of blobs this transaction has, or 0 if not a blob transaction type * - * @throws java.util.NoSuchElementException if called on a non blob transaction * @return return the count */ public int getBlobCount() { - return versionedHashes.orElseThrow().size(); + return versionedHashes.map(List::size).orElse(0); } /** From 18ef1be8d0ce7b385a957ee5ae39384b67a09123 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 24 Jan 2023 13:09:03 +0100 Subject: [PATCH 04/27] Remove duplicated code Signed-off-by: Fabio Di Fabio --- .../mainnet/MainnetTransactionProcessor.java | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java index 7537ee8ab42..a4ed88e64c7 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java @@ -299,11 +299,10 @@ public TransactionProcessingResult processTransaction( previousNonce, sender.getNonce()); + final int dataGas = gasCalculator.dataGasCost(transaction.getBlobCount()); + final Wei upfrontGasCost = - transaction.getUpfrontGasCost( - transactionGasPrice, - dataGasPrice, - gasCalculator.dataGasCost(transaction.getBlobCount())); + transaction.getUpfrontGasCost(transactionGasPrice, dataGasPrice, dataGas); final Wei previousBalance = senderMutableAccount.decrementBalance(upfrontGasCost); LOG.trace( "Deducted sender {} upfront gas cost {} ({} -> {})", @@ -334,12 +333,6 @@ public TransactionProcessingResult processTransaction( transaction.getPayload(), transaction.isContractCreation()); final long accessListGas = gasCalculator.accessListGasCost(accessListEntries.size(), accessListStorageCount); - final long dataGas; - if (feeMarket.implementsDataFee()) { - dataGas = gasCalculator.dataGasCost(transaction.getVersionedHashes().orElseThrow().size()); - } else { - dataGas = 0L; - } final long gasAvailable = transaction.getGasLimit() - intrinsicGas - accessListGas - dataGas; LOG.trace( From 080ead037b23e06197da4646e4db28c14bc2280b Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 24 Jan 2023 13:12:25 +0100 Subject: [PATCH 05/27] Fix blob tx identification Signed-off-by: Fabio Di Fabio --- .../besu/ethereum/blockcreation/BlockTransactionSelector.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java index 613a074814a..83ea407551e 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java @@ -235,7 +235,7 @@ private TransactionSelectionResult evaluateTransaction( } private boolean transactionDataPriceBelowMin(final Transaction transaction) { - if (feeMarket.implementsBaseFee()) { + if (transaction.getType().supportsBlob()) { if (transaction .getMaxFeePerDataGas() .orElseThrow() From 55b1f7abb1266252c838565b613e4cdc69044db9 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 24 Jan 2023 13:20:26 +0100 Subject: [PATCH 06/27] Update log Signed-off-by: Fabio Di Fabio --- .../besu/ethereum/mainnet/MainnetTransactionProcessor.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java index a4ed88e64c7..604f675110e 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java @@ -336,10 +336,12 @@ public TransactionProcessingResult processTransaction( final long gasAvailable = transaction.getGasLimit() - intrinsicGas - accessListGas - dataGas; LOG.trace( - "Gas available for execution {} = {} - {} (limit - intrinsic)", + "Gas available for execution {} = {} - {} - {} - {} (limit - intrinsic - accessList - data)", gasAvailable, transaction.getGasLimit(), - intrinsicGas); + intrinsicGas, + accessListGas, + dataGas); final WorldUpdater worldUpdater = worldState.updater(); final Deque messageFrameStack = new ArrayDeque<>(); From 657f97512eb0c0940265d74c94fa7ec905a7a513 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 24 Jan 2023 13:31:09 +0100 Subject: [PATCH 07/27] Add reference to the EIP-4844 Signed-off-by: Fabio Di Fabio --- .../besu/evm/gascalculator/CancunGasCalculator.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java index 03f756b21ab..87d84fcbd9e 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java @@ -16,7 +16,9 @@ import org.hyperledger.besu.datatypes.DataGas; -/** The Cancun gas calculator. */ +/** + * The Cancun gas calculator as defined in EIP-4844 + */ public class CancunGasCalculator extends LondonGasCalculator { public static final int CANCUN_DATA_GAS_PER_BLOB = 131072; // 2^17 From 0a0c7029da7c780281c37360a1f73160e579922f Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 24 Jan 2023 14:05:28 +0100 Subject: [PATCH 08/27] Fix and improvements from code review Signed-off-by: Fabio Di Fabio --- .../blockcreation/AbstractBlockCreator.java | 2 +- .../mainnet/MainnetTransactionValidator.java | 22 +++++++++---------- .../gascalculator/CancunGasCalculator.java | 4 +--- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java index bdea36ccd4f..4420f87270a 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java @@ -256,7 +256,7 @@ private DataGas computeExcessDataGas( BlockTransactionSelector.TransactionSelectionResults transactionResults, ProtocolSpec newProtocolSpec) { - if (newProtocolSpec.getFeeMarket().implementsBaseFee()) { + if (newProtocolSpec.getFeeMarket().implementsDataFee()) { final var gasCalculator = newProtocolSpec.getGasCalculator(); final int newBlobsCount = transactionResults.getTransactionsByType(TransactionType.BLOB).stream() diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java index bb8269019b0..ed1b497e0ec 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java @@ -141,17 +141,6 @@ public ValidationResult validate( transaction.getPayload().size(), maxInitcodeSize)); } - if (transaction.getType().supportsBlob()) { - final long txTotalDataGas = gasCalculator.dataGasCost(transaction.getBlobCount()); - if (txTotalDataGas > gasCalculator.getDataGasLimit()) { - return ValidationResult.invalid( - TransactionInvalidReason.TOTAL_DATA_GAS_TOO_HIGH, - String.format( - "total data gas %d exceeds max data gas per block %d", - txTotalDataGas, gasCalculator.getDataGasLimit())); - } - } - return validateCostAndFee(transaction, baseFee, transactionValidationParams); } @@ -194,6 +183,17 @@ private ValidationResult validateCostAndFee( TransactionInvalidReason.NONCE_OVERFLOW, "Nonce must be less than 2^64-1"); } + if (transaction.getType().supportsBlob()) { + final long txTotalDataGas = gasCalculator.dataGasCost(transaction.getBlobCount()); + if (txTotalDataGas > gasCalculator.getDataGasLimit()) { + return ValidationResult.invalid( + TransactionInvalidReason.TOTAL_DATA_GAS_TOO_HIGH, + String.format( + "total data gas %d exceeds max data gas per block %d", + txTotalDataGas, gasCalculator.getDataGasLimit())); + } + } + final long intrinsicGasCost = gasCalculator.transactionIntrinsicGasCost( transaction.getPayload(), transaction.isContractCreation()) diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java index 87d84fcbd9e..8ffd50f37df 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java @@ -16,9 +16,7 @@ import org.hyperledger.besu.datatypes.DataGas; -/** - * The Cancun gas calculator as defined in EIP-4844 - */ +/** The Cancun gas calculator as defined in EIP-4844 */ public class CancunGasCalculator extends LondonGasCalculator { public static final int CANCUN_DATA_GAS_PER_BLOB = 131072; // 2^17 From ffb6c9320712821919f06dbb792a26c52ae97976 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 24 Jan 2023 14:36:09 +0100 Subject: [PATCH 09/27] Move Cancun fee market constants into Cancun class Signed-off-by: Fabio Di Fabio --- .../besu/ethereum/mainnet/MainnetProtocolSpecs.java | 9 +-------- .../ethereum/mainnet/feemarket/CancunFeeMarket.java | 12 ++++++------ .../besu/ethereum/mainnet/feemarket/FeeMarket.java | 8 ++------ 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java index 36d0d97f86b..b4245b4fb8d 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java @@ -84,9 +84,6 @@ public abstract class MainnetProtocolSpecs { public static final int SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT = 24576; public static final int SHANGHAI_INIT_CODE_SIZE_LIMIT = 2 * SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT; - private static final int CANCUN_MIN_DATA_GAS_PRICE = 1; - private static final int CANCUN_DATA_GAS_PRICE_UPDATE_FRACTION = 2225652; - private static final Address RIPEMD160_PRECOMPILE = Address.fromHexString("0x0000000000000000000000000000000000000003"); @@ -727,11 +724,7 @@ static ProtocolSpecBuilder cancunDefinition( final BaseFeeMarket londonFeeMarket = genesisConfigOptions.isZeroBaseFee() ? FeeMarket.zeroBaseFee(londonForkBlockNumber) - : FeeMarket.cancun( - londonForkBlockNumber, - genesisConfigOptions.getBaseFeePerGas(), - CANCUN_MIN_DATA_GAS_PRICE, - CANCUN_DATA_GAS_PRICE_UPDATE_FRACTION); + : FeeMarket.cancun(londonForkBlockNumber, genesisConfigOptions.getBaseFeePerGas()); return shanghaiDefinition( chainId, diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/CancunFeeMarket.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/CancunFeeMarket.java index dd83bcb7cf3..fba11a96459 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/CancunFeeMarket.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/CancunFeeMarket.java @@ -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 * the License. You may obtain a copy of the License at @@ -21,13 +21,13 @@ public class CancunFeeMarket extends LondonFeeMarket { + private static final int MIN_DATA_GAS_PRICE = 1; + private static final int DATA_GAS_PRICE_UPDATE_FRACTION = 2225652; + public CancunFeeMarket( - final long londonForkBlockNumber, - final Optional baseFeePerGasOverride, - final int minDataGasPrice, - final int dataGasPriceUpdateFraction) { + final long londonForkBlockNumber, final Optional baseFeePerGasOverride) { super( - new TransactionPriceCalculator.DataBlob(minDataGasPrice, dataGasPriceUpdateFraction), + new TransactionPriceCalculator.DataBlob(MIN_DATA_GAS_PRICE, DATA_GAS_PRICE_UPDATE_FRACTION), londonForkBlockNumber, baseFeePerGasOverride); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/FeeMarket.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/FeeMarket.java index 6637501dbb7..a674e602b1c 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/FeeMarket.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/FeeMarket.java @@ -44,12 +44,8 @@ static BaseFeeMarket london( } static BaseFeeMarket cancun( - final long londonForkBlockNumber, - final Optional baseFeePerGasOverride, - final int minDataGasPrice, - final int dataGasPriceUpdateFraction) { - return new CancunFeeMarket( - londonForkBlockNumber, baseFeePerGasOverride, minDataGasPrice, dataGasPriceUpdateFraction); + final long londonForkBlockNumber, final Optional baseFeePerGasOverride) { + return new CancunFeeMarket(londonForkBlockNumber, baseFeePerGasOverride); } static BaseFeeMarket zeroBaseFee(final long londonForkBlockNumber) { From 72c6988cccd5f2dd6517550d0f8b6dc6829296d7 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 24 Jan 2023 14:42:05 +0100 Subject: [PATCH 10/27] Code reorg Signed-off-by: Fabio Di Fabio --- .../besu/ethereum/core/Transaction.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java index 9bea0d3fb24..dc2e650c11b 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java @@ -699,15 +699,6 @@ public boolean isContractCreation() { return getTo().isEmpty(); } - /** - * Check if the upfront gas cost is over the max allowed - * - * @return true is upfront data cost overflow uint256 max value - */ - private boolean isUpfrontGasCostTooHigh() { - return calculateUpfrontGasCost(getMaxGasPrice(), Wei.ZERO, 0).bitLength() > 256; - } - /** * Calculates the max up-front cost for the gas the transaction can use. * @@ -718,6 +709,15 @@ private Wei getMaxUpfrontGasCost(final int dataGasPerBlock) { getMaxGasPrice(), getMaxFeePerDataGas().orElse(Wei.ZERO), dataGasPerBlock); } + /** + * Check if the upfront gas cost is over the max allowed + * + * @return true is upfront data cost overflow uint256 max value + */ + private boolean isUpfrontGasCostTooHigh() { + return calculateUpfrontGasCost(getMaxGasPrice(), Wei.ZERO, 0).bitLength() > 256; + } + /** * Calculates the up-front cost for the gas and data gas the transaction can use. * From 6c575ecd2aa329fa442011bccc70fbac810bc27c Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 24 Jan 2023 15:57:37 +0100 Subject: [PATCH 11/27] Track max data gas per block using GasLimitCalculator Signed-off-by: Fabio Di Fabio --- .../blockcreation/AbstractBlockCreator.java | 18 +-- .../BlockTransactionSelector.java | 16 ++- .../AbstractBlockTransactionSelectorTest.java | 7 +- .../besu/ethereum/GasLimitCalculator.java | 6 + .../besu/ethereum/core/Transaction.java | 14 ++- .../CancunTargetingGasLimitCalculator.java | 32 ++++++ .../mainnet/ClassicProtocolSpecs.java | 11 +- .../mainnet/MainnetProtocolSpecs.java | 38 +++++-- .../mainnet/MainnetTransactionProcessor.java | 6 +- .../mainnet/MainnetTransactionValidator.java | 18 ++- .../ethereum/mainnet/ProtocolSpecBuilder.java | 8 +- .../MainnetTransactionValidatorTest.java | 106 +++++++++++++++--- .../gascalculator/CancunGasCalculator.java | 15 +-- .../besu/evm/gascalculator/GasCalculator.java | 8 +- 14 files changed, 221 insertions(+), 82 deletions(-) create mode 100644 ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/CancunTargetingGasLimitCalculator.java diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java index 4420f87270a..dba7dc80fc3 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java @@ -18,6 +18,7 @@ import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.GasLimitCalculator; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; @@ -294,7 +295,8 @@ private BlockTransactionSelector.TransactionSelectionResults selectTransactions( isCancelled::get, miningBeneficiary, protocolSpec.getFeeMarket(), - protocolSpec.getGasCalculator()); + protocolSpec.getGasCalculator(), + protocolSpec.getGasLimitCalculator()); if (transactions.isPresent()) { return selector.evaluateTransactions(transactions.get()); @@ -337,13 +339,13 @@ private ProcessableBlockHeader createPendingBlockHeader( final Optional maybePrevRandao, final ProtocolSpec protocolSpec) { final long newBlockNumber = parentHeader.getNumber() + 1; - long gasLimit = - protocolSpec - .getGasLimitCalculator() - .nextGasLimit( - parentHeader.getGasLimit(), - targetGasLimitSupplier.get().orElse(parentHeader.getGasLimit()), - newBlockNumber); + final GasLimitCalculator gasLimitCalculator = protocolSpec.getGasLimitCalculator(); + + final long gasLimit = + gasLimitCalculator.nextGasLimit( + parentHeader.getGasLimit(), + targetGasLimitSupplier.get().orElse(parentHeader.getGasLimit()), + newBlockNumber); final DifficultyCalculator difficultyCalculator = protocolSpec.getDifficultyCalculator(); final BigInteger difficulty = diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java index 83ea407551e..f48623c623d 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java @@ -18,6 +18,7 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.GasLimitCalculator; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; @@ -90,6 +91,7 @@ public class BlockTransactionSelector { private final Address miningBeneficiary; private final FeeMarket feeMarket; private final GasCalculator gasCalculator; + private final GasLimitCalculator gasLimitCalculator; private final TransactionSelectionResults transactionSelectionResult = new TransactionSelectionResults(); @@ -106,7 +108,8 @@ public BlockTransactionSelector( final Supplier isCancelled, final Address miningBeneficiary, final FeeMarket feeMarket, - final GasCalculator gasCalculator) { + final GasCalculator gasCalculator, + final GasLimitCalculator gasLimitCalculator) { this.transactionProcessor = transactionProcessor; this.blockchain = blockchain; this.worldState = worldState; @@ -119,6 +122,7 @@ public BlockTransactionSelector( this.miningBeneficiary = miningBeneficiary; this.feeMarket = feeMarket; this.gasCalculator = gasCalculator; + this.gasLimitCalculator = gasLimitCalculator; } /* @@ -338,7 +342,7 @@ private void updateTransactionResultTracking( transaction.isGoQuorumPrivateTransaction( transactionProcessor.getTransactionValidator().getGoQuorumCompatibilityMode()); - final long dataGasUsed = gasCalculator.dataGasCost(transaction.getBlobCount()); + final long dataGasUsed = gasCalculator.dataGasCost(transaction.getBlobCount()).toLong(); final long gasUsedByTransaction = isGoQuorumPrivateTransaction @@ -373,12 +377,14 @@ private TransactionProcessingResult publicResultForWhenWeHaveAPrivateTransaction private boolean transactionTooLargeForBlock(final Transaction transaction) { final var dataGasUsed = gasCalculator.dataGasCost(transaction.getBlobCount()); - if (dataGasUsed - > gasCalculator.getDataGasLimit() - transactionSelectionResult.getCumulativeDataGasUsed()) { + if (dataGasUsed.greaterThan( + gasLimitCalculator + .nextDataGasLimit() + .subtract(transactionSelectionResult.getCumulativeDataGasUsed()))) { return true; } - return transaction.getGasLimit() + dataGasUsed + return transaction.getGasLimit() + dataGasUsed.toLong() > processableBlockHeader.getGasLimit() - transactionSelectionResult.getCumulativeGasUsed(); } diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java index f0d012ddb84..ebe8e8bb224 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java @@ -27,6 +27,7 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.GasLimitCalculator; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.AddressHelpers; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -257,7 +258,8 @@ public void useSingleGasSpaceForAllTransactions() { this::isCancelled, miningBeneficiary, FeeMarket.london(0L), - new LondonGasCalculator()); + new LondonGasCalculator(), + GasLimitCalculator.constant()); // this should fill up all the block space final Transaction fillingLegacyTx = @@ -455,7 +457,8 @@ protected BlockTransactionSelector createBlockSelector( this::isCancelled, miningBeneficiary, getFeeMarket(), - new LondonGasCalculator()); + new LondonGasCalculator(), + GasLimitCalculator.constant()); return selector; } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/GasLimitCalculator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/GasLimitCalculator.java index e358a1aeb54..97b69122e07 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/GasLimitCalculator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/GasLimitCalculator.java @@ -14,6 +14,8 @@ */ package org.hyperledger.besu.ethereum; +import org.hyperledger.besu.datatypes.DataGas; + public interface GasLimitCalculator { long nextGasLimit(long currentGasLimit, long targetGasLimit, long newBlockNumber); @@ -21,4 +23,8 @@ public interface GasLimitCalculator { static GasLimitCalculator constant() { return (currentGasLimit, targetGasLimit, newBlockNumber) -> currentGasLimit; } + + default DataGas nextDataGasLimit() { + return DataGas.ZERO; + } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java index dc2e650c11b..078b3c448aa 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java @@ -24,6 +24,7 @@ import org.hyperledger.besu.crypto.SignatureAlgorithm; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder; @@ -704,7 +705,7 @@ public boolean isContractCreation() { * * @return the max up-front cost for the gas the transaction can use. */ - private Wei getMaxUpfrontGasCost(final int dataGasPerBlock) { + private Wei getMaxUpfrontGasCost(final DataGas dataGasPerBlock) { return getUpfrontGasCost( getMaxGasPrice(), getMaxFeePerDataGas().orElse(Wei.ZERO), dataGasPerBlock); } @@ -715,7 +716,7 @@ private Wei getMaxUpfrontGasCost(final int dataGasPerBlock) { * @return true is upfront data cost overflow uint256 max value */ private boolean isUpfrontGasCostTooHigh() { - return calculateUpfrontGasCost(getMaxGasPrice(), Wei.ZERO, 0).bitLength() > 256; + return calculateUpfrontGasCost(getMaxGasPrice(), Wei.ZERO, DataGas.ZERO).bitLength() > 256; } /** @@ -725,7 +726,8 @@ private boolean isUpfrontGasCostTooHigh() { * @param dataGasPrice the data gas price to use * @return the up-front cost for the gas the transaction can use. */ - public Wei getUpfrontGasCost(final Wei gasPrice, final Wei dataGasPrice, final int totalDataGas) { + public Wei getUpfrontGasCost( + final Wei gasPrice, final Wei dataGasPrice, final DataGas totalDataGas) { if (gasPrice == null || gasPrice.isZero()) { return Wei.ZERO; } @@ -740,12 +742,12 @@ public Wei getUpfrontGasCost(final Wei gasPrice, final Wei dataGasPrice, final i } private BigInteger calculateUpfrontGasCost( - final Wei gasPrice, final Wei dataGasPrice, final int totalDataGas) { + final Wei gasPrice, final Wei dataGasPrice, final DataGas totalDataGas) { var cost = new BigInteger(1, Longs.toByteArray(getGasLimit())).multiply(gasPrice.getAsBigInteger()); if (transactionType.supportsBlob()) { - cost = cost.add(dataGasPrice.getAsBigInteger().multiply(BigInteger.valueOf(totalDataGas))); + cost = cost.add(dataGasPrice.getAsBigInteger().multiply(totalDataGas.getAsBigInteger())); } return cost; @@ -760,7 +762,7 @@ private BigInteger calculateUpfrontGasCost( * * @return the up-front gas cost for the transaction */ - public Wei getUpfrontCost(final int totalDataGas) { + public Wei getUpfrontCost(final DataGas totalDataGas) { return getMaxUpfrontGasCost(totalDataGas).addExact(getValue()); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/CancunTargetingGasLimitCalculator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/CancunTargetingGasLimitCalculator.java new file mode 100644 index 00000000000..e71b4af9505 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/CancunTargetingGasLimitCalculator.java @@ -0,0 +1,32 @@ +/* + * 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.datatypes.DataGas; +import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; + +public class CancunTargetingGasLimitCalculator extends LondonTargetingGasLimitCalculator { + public static final DataGas MAX_DATA_GAS_PER_BLOCK = DataGas.of(524288); // 2^19 + + public CancunTargetingGasLimitCalculator( + final long londonForkBlock, final BaseFeeMarket feeMarket) { + super(londonForkBlock, feeMarket); + } + + @Override + public DataGas nextDataGasLimit() { + return MAX_DATA_GAS_PER_BLOCK; + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java index 89548664210..d041f0b41b4 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ClassicProtocolSpecs.java @@ -76,9 +76,9 @@ public static ProtocolSpecBuilder tangerineWhistleDefinition( contractSizeLimit, configStackSizeLimit, quorumCompatibilityMode, evmConfiguration) .gasCalculator(TangerineWhistleGasCalculator::new) .transactionValidatorBuilder( - gasCalculator -> + (gasCalculator, gasLimitCalculator) -> new MainnetTransactionValidator( - gasCalculator, true, chainId, quorumCompatibilityMode)) + gasCalculator, gasLimitCalculator, true, chainId, quorumCompatibilityMode)) .name("ClassicTangerineWhistle"); } @@ -149,9 +149,9 @@ public static ProtocolSpecBuilder defuseDifficultyBombDefinition( evmConfiguration) .difficultyCalculator(ClassicDifficultyCalculators.DIFFICULTY_BOMB_REMOVED) .transactionValidatorBuilder( - gasCalculator -> + (gasCalculator, gasLimitCalculator) -> new MainnetTransactionValidator( - gasCalculator, true, chainId, quorumCompatibilityMode)) + gasCalculator, gasLimitCalculator, true, chainId, quorumCompatibilityMode)) .name("DefuseDifficultyBomb"); } @@ -353,9 +353,10 @@ public static ProtocolSpecBuilder magnetoDefinition( evmConfiguration) .gasCalculator(BerlinGasCalculator::new) .transactionValidatorBuilder( - gasCalculator -> + (gasCalculator, gasLimitCalculator) -> new MainnetTransactionValidator( gasCalculator, + gasLimitCalculator, true, chainId, Set.of(TransactionType.FRONTIER, TransactionType.ACCESS_LIST), diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java index b4245b4fb8d..dd92d44edfd 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java @@ -19,6 +19,7 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.BlockProcessingResult; +import org.hyperledger.besu.ethereum.GasLimitCalculator; import org.hyperledger.besu.ethereum.MainnetBlockValidator; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -123,9 +124,9 @@ public static ProtocolSpecBuilder frontierDefinition( Collections.singletonList(MaxCodeSizeRule.of(contractSizeLimit)), 0)) .transactionValidatorBuilder( - gasCalculator -> + (gasCalculator, gasLimitCalculator) -> new MainnetTransactionValidator( - gasCalculator, false, Optional.empty(), goQuorumMode)) + gasCalculator, gasLimitCalculator, false, Optional.empty(), goQuorumMode)) .transactionProcessorBuilder( (gasCalculator, transactionValidator, @@ -229,9 +230,13 @@ public static ProtocolSpecBuilder homesteadDefinition( Collections.singletonList(MaxCodeSizeRule.of(contractSizeLimit)), 0)) .transactionValidatorBuilder( - gasCalculator -> + (gasCalculator, gasLimitCalculator) -> new MainnetTransactionValidator( - gasCalculator, true, Optional.empty(), quorumCompatibilityMode)) + gasCalculator, + gasLimitCalculator, + true, + Optional.empty(), + quorumCompatibilityMode)) .difficultyCalculator(MainnetDifficultyCalculators.HOMESTEAD) .name("Homestead"); } @@ -316,9 +321,9 @@ public static ProtocolSpecBuilder spuriousDragonDefinition( 1, SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES)) .transactionValidatorBuilder( - gasCalculator -> + (gasCalculator, gasLimitCalculator) -> new MainnetTransactionValidator( - gasCalculator, true, chainId, quorumCompatibilityMode)) + gasCalculator, gasLimitCalculator, true, chainId, quorumCompatibilityMode)) .transactionProcessorBuilder( (gasCalculator, transactionValidator, @@ -483,9 +488,10 @@ static ProtocolSpecBuilder berlinDefinition( evmConfiguration) .gasCalculator(BerlinGasCalculator::new) .transactionValidatorBuilder( - gasCalculator -> + (gasCalculator, gasLimitCalculator) -> new MainnetTransactionValidator( gasCalculator, + gasLimitCalculator, true, chainId, Set.of(TransactionType.FRONTIER, TransactionType.ACCESS_LIST), @@ -525,9 +531,10 @@ static ProtocolSpecBuilder londonDefinition( .gasLimitCalculator( new LondonTargetingGasLimitCalculator(londonForkBlockNumber, londonFeeMarket)) .transactionValidatorBuilder( - gasCalculator -> + (gasCalculator, gasLimitCalculator) -> new MainnetTransactionValidator( gasCalculator, + gasLimitCalculator, londonFeeMarket, true, chainId, @@ -692,9 +699,10 @@ static ProtocolSpecBuilder shanghaiDefinition( CoinbaseFeePriceCalculator.eip1559())) // Contract creation rules for EIP-3860 Limit and meter intitcode .transactionValidatorBuilder( - gasCalculator -> + (gasCalculator, gasLimitCalculator) -> new MainnetTransactionValidator( gasCalculator, + gasLimitCalculator, londonFeeMarket, true, chainId, @@ -721,11 +729,14 @@ static ProtocolSpecBuilder cancunDefinition( final int contractSizeLimit = configContractSizeLimit.orElse(SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT); final long londonForkBlockNumber = genesisConfigOptions.getLondonBlockNumber().orElse(0L); - final BaseFeeMarket londonFeeMarket = + final BaseFeeMarket cancunFeeMarket = genesisConfigOptions.isZeroBaseFee() ? FeeMarket.zeroBaseFee(londonForkBlockNumber) : FeeMarket.cancun(londonForkBlockNumber, genesisConfigOptions.getBaseFeePerGas()); + final GasLimitCalculator cancunGasLimitCalculator = + new CancunTargetingGasLimitCalculator(londonForkBlockNumber, cancunFeeMarket); + return shanghaiDefinition( chainId, configContractSizeLimit, @@ -736,6 +747,8 @@ static ProtocolSpecBuilder cancunDefinition( evmConfiguration) // gas calculator for EIP-4844 data gas .gasCalculator(CancunGasCalculator::new) + // gas limit with EIP-4844 max data gas per block + .gasLimitCalculator(cancunGasLimitCalculator) // EVM changes to support EOF EIPs (3670, 4200, 4750, 5450) .evmBuilder( (gasCalculator, jdCacheConfig) -> @@ -754,10 +767,11 @@ static ProtocolSpecBuilder cancunDefinition( SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES)) // change to check for max data gas per block for EIP-4844 .transactionValidatorBuilder( - gasCalculator -> + (gasCalculator, gasLimitCalculator) -> new MainnetTransactionValidator( gasCalculator, - londonFeeMarket, + gasLimitCalculator, + cancunFeeMarket, true, chainId, Set.of( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java index 604f675110e..52927bb3ea0 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java @@ -20,6 +20,7 @@ import static org.hyperledger.besu.ethereum.mainnet.PrivateStateUtils.KEY_TRANSACTION_HASH; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.chain.Blockchain; @@ -299,7 +300,7 @@ public TransactionProcessingResult processTransaction( previousNonce, sender.getNonce()); - final int dataGas = gasCalculator.dataGasCost(transaction.getBlobCount()); + final DataGas dataGas = gasCalculator.dataGasCost(transaction.getBlobCount()); final Wei upfrontGasCost = transaction.getUpfrontGasCost(transactionGasPrice, dataGasPrice, dataGas); @@ -334,7 +335,8 @@ public TransactionProcessingResult processTransaction( final long accessListGas = gasCalculator.accessListGasCost(accessListEntries.size(), accessListStorageCount); - final long gasAvailable = transaction.getGasLimit() - intrinsicGas - accessListGas - dataGas; + final long gasAvailable = + transaction.getGasLimit() - intrinsicGas - accessListGas - dataGas.toLong(); LOG.trace( "Gas available for execution {} = {} - {} - {} - {} (limit - intrinsic - accessList - data)", gasAvailable, diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java index ed1b497e0ec..ff46f68b789 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java @@ -18,8 +18,10 @@ import org.hyperledger.besu.crypto.SECPSignature; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; +import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.GasLimitCalculator; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionFilter; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; @@ -41,6 +43,7 @@ public class MainnetTransactionValidator { private final GasCalculator gasCalculator; + private final GasLimitCalculator gasLimitCalculator; private final FeeMarket feeMarket; private final boolean disallowSignatureMalleability; @@ -55,11 +58,13 @@ public class MainnetTransactionValidator { public MainnetTransactionValidator( final GasCalculator gasCalculator, + final GasLimitCalculator gasLimitCalculator, final boolean checkSignatureMalleability, final Optional chainId, final boolean goQuorumCompatibilityMode) { this( gasCalculator, + gasLimitCalculator, checkSignatureMalleability, chainId, Set.of(TransactionType.FRONTIER), @@ -68,12 +73,14 @@ public MainnetTransactionValidator( public MainnetTransactionValidator( final GasCalculator gasCalculator, + final GasLimitCalculator gasLimitCalculator, final boolean checkSignatureMalleability, final Optional chainId, final Set acceptedTransactionTypes, final boolean quorumCompatibilityMode) { this( gasCalculator, + gasLimitCalculator, FeeMarket.legacy(), checkSignatureMalleability, chainId, @@ -84,6 +91,7 @@ public MainnetTransactionValidator( public MainnetTransactionValidator( final GasCalculator gasCalculator, + final GasLimitCalculator gasLimitCalculator, final FeeMarket feeMarket, final boolean checkSignatureMalleability, final Optional chainId, @@ -91,6 +99,7 @@ public MainnetTransactionValidator( final boolean goQuorumCompatibilityMode, final int maxInitcodeSize) { this.gasCalculator = gasCalculator; + this.gasLimitCalculator = gasLimitCalculator; this.feeMarket = feeMarket; this.disallowSignatureMalleability = checkSignatureMalleability; this.chainId = chainId; @@ -184,13 +193,14 @@ private ValidationResult validateCostAndFee( } if (transaction.getType().supportsBlob()) { - final long txTotalDataGas = gasCalculator.dataGasCost(transaction.getBlobCount()); - if (txTotalDataGas > gasCalculator.getDataGasLimit()) { + final DataGas txTotalDataGas = gasCalculator.dataGasCost(transaction.getBlobCount()); + if (txTotalDataGas.greaterThan(gasLimitCalculator.nextDataGasLimit())) { return ValidationResult.invalid( TransactionInvalidReason.TOTAL_DATA_GAS_TOO_HIGH, String.format( - "total data gas %d exceeds max data gas per block %d", - txTotalDataGas, gasCalculator.getDataGasLimit())); + "total data gas %s exceeds max data gas per block %s", + txTotalDataGas.getAsBigInteger(), + gasLimitCalculator.nextDataGasLimit().getAsBigInteger())); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java index 043155dc932..4e1c0028e8e 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSpecBuilder.java @@ -54,7 +54,8 @@ public class ProtocolSpecBuilder { private DifficultyCalculator difficultyCalculator; private EvmConfiguration evmConfiguration; private BiFunction evmBuilder; - private Function transactionValidatorBuilder; + private BiFunction + transactionValidatorBuilder; private Function blockHeaderValidatorBuilder; private Function ommerHeaderValidatorBuilder; private Function blockBodyValidatorBuilder; @@ -123,7 +124,8 @@ public ProtocolSpecBuilder evmBuilder( } public ProtocolSpecBuilder transactionValidatorBuilder( - final Function transactionValidatorBuilder) { + final BiFunction + transactionValidatorBuilder) { this.transactionValidatorBuilder = transactionValidatorBuilder; return this; } @@ -290,7 +292,7 @@ public ProtocolSpec build(final HeaderBasedProtocolSchedule protocolSchedule) { final PrecompiledContractConfiguration precompiledContractConfiguration = new PrecompiledContractConfiguration(gasCalculator, privacyParameters); final MainnetTransactionValidator transactionValidator = - transactionValidatorBuilder.apply(gasCalculator); + transactionValidatorBuilder.apply(gasCalculator, gasLimitCalculator); final AbstractMessageProcessor contractCreationProcessor = contractCreationProcessorBuilder.apply(gasCalculator, evm); final PrecompileContractRegistry precompileContractRegistry = diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java index 84570440a64..f8651720541 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java @@ -31,8 +31,10 @@ import org.hyperledger.besu.crypto.SignatureAlgorithm; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; +import org.hyperledger.besu.ethereum.GasLimitCalculator; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionFilter; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; @@ -78,7 +80,11 @@ public class MainnetTransactionValidatorTest { public void shouldRejectTransactionIfIntrinsicGasExceedsGasLimit() { final MainnetTransactionValidator validator = new MainnetTransactionValidator( - gasCalculator, false, Optional.empty(), defaultGoQuorumCompatibilityMode); + gasCalculator, + GasLimitCalculator.constant(), + false, + Optional.empty(), + defaultGoQuorumCompatibilityMode); final Transaction transaction = new TransactionTestFixture() .gasLimit(10) @@ -95,7 +101,11 @@ public void shouldRejectTransactionIfIntrinsicGasExceedsGasLimit() { public void shouldRejectTransactionWhenTransactionHasChainIdAndValidatorDoesNot() { final MainnetTransactionValidator validator = new MainnetTransactionValidator( - gasCalculator, false, Optional.empty(), defaultGoQuorumCompatibilityMode); + gasCalculator, + GasLimitCalculator.constant(), + false, + Optional.empty(), + defaultGoQuorumCompatibilityMode); assertThat(validator.validate(basicTransaction, Optional.empty(), transactionValidationParams)) .isEqualTo( ValidationResult.invalid( @@ -107,6 +117,7 @@ public void shouldRejectTransactionWhenTransactionHasIncorrectChainId() { final MainnetTransactionValidator validator = new MainnetTransactionValidator( gasCalculator, + GasLimitCalculator.constant(), false, Optional.of(BigInteger.valueOf(2)), defaultGoQuorumCompatibilityMode); @@ -118,7 +129,11 @@ public void shouldRejectTransactionWhenTransactionHasIncorrectChainId() { public void shouldRejectTransactionWhenSenderAccountDoesNotExist() { final MainnetTransactionValidator validator = new MainnetTransactionValidator( - gasCalculator, false, Optional.of(BigInteger.ONE), defaultGoQuorumCompatibilityMode); + gasCalculator, + GasLimitCalculator.constant(), + false, + Optional.of(BigInteger.ONE), + defaultGoQuorumCompatibilityMode); assertThat(validator.validateForSender(basicTransaction, null, false)) .isEqualTo(ValidationResult.invalid(TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE)); } @@ -127,7 +142,11 @@ public void shouldRejectTransactionWhenSenderAccountDoesNotExist() { public void shouldRejectTransactionWhenTransactionNonceBelowAccountNonce() { final MainnetTransactionValidator validator = new MainnetTransactionValidator( - gasCalculator, false, Optional.of(BigInteger.ONE), defaultGoQuorumCompatibilityMode); + gasCalculator, + GasLimitCalculator.constant(), + false, + Optional.of(BigInteger.ONE), + defaultGoQuorumCompatibilityMode); final Account account = accountWithNonce(basicTransaction.getNonce() + 1); assertThat(validator.validateForSender(basicTransaction, account, false)) @@ -139,7 +158,11 @@ public void shouldRejectTransactionWhenTransactionNonceBelowAccountNonce() { shouldRejectTransactionWhenTransactionNonceAboveAccountNonceAndFutureNonceIsNotAllowed() { final MainnetTransactionValidator validator = new MainnetTransactionValidator( - gasCalculator, false, Optional.of(BigInteger.ONE), defaultGoQuorumCompatibilityMode); + gasCalculator, + GasLimitCalculator.constant(), + false, + Optional.of(BigInteger.ONE), + defaultGoQuorumCompatibilityMode); final Account account = accountWithNonce(basicTransaction.getNonce() - 1); assertThat(validator.validateForSender(basicTransaction, account, false)) @@ -151,7 +174,11 @@ public void shouldRejectTransactionWhenTransactionNonceBelowAccountNonce() { shouldAcceptTransactionWhenTransactionNonceAboveAccountNonceAndFutureNonceIsAllowed() { final MainnetTransactionValidator validator = new MainnetTransactionValidator( - gasCalculator, false, Optional.of(BigInteger.ONE), defaultGoQuorumCompatibilityMode); + gasCalculator, + GasLimitCalculator.constant(), + false, + Optional.of(BigInteger.ONE), + defaultGoQuorumCompatibilityMode); final Account account = accountWithNonce(basicTransaction.getNonce() - 1); assertThat(validator.validateForSender(basicTransaction, account, true)) @@ -162,7 +189,11 @@ public void shouldRejectTransactionWhenTransactionNonceBelowAccountNonce() { public void shouldRejectTransactionWhenNonceExceedsMaximumAllowedNonce() { final MainnetTransactionValidator validator = new MainnetTransactionValidator( - gasCalculator, false, Optional.of(BigInteger.ONE), defaultGoQuorumCompatibilityMode); + gasCalculator, + GasLimitCalculator.constant(), + false, + Optional.of(BigInteger.ONE), + defaultGoQuorumCompatibilityMode); final Transaction transaction = new TransactionTestFixture().nonce(11).createTransaction(senderKeys); @@ -176,7 +207,11 @@ public void shouldRejectTransactionWhenNonceExceedsMaximumAllowedNonce() { public void transactionWithNullSenderCanBeValidIfGasPriceAndValueIsZero() { final MainnetTransactionValidator validator = new MainnetTransactionValidator( - gasCalculator, false, Optional.of(BigInteger.ONE), defaultGoQuorumCompatibilityMode); + gasCalculator, + GasLimitCalculator.constant(), + false, + Optional.of(BigInteger.ONE), + defaultGoQuorumCompatibilityMode); final TransactionTestFixture builder = new TransactionTestFixture(); final KeyPair senderKeyPair = SIGNATURE_ALGORITHM.get().generateKeyPair(); @@ -191,11 +226,16 @@ public void transactionWithNullSenderCanBeValidIfGasPriceAndValueIsZero() { public void shouldRejectTransactionIfAccountIsNotEOA() { final MainnetTransactionValidator validator = new MainnetTransactionValidator( - gasCalculator, false, Optional.empty(), defaultGoQuorumCompatibilityMode); + gasCalculator, + GasLimitCalculator.constant(), + false, + Optional.empty(), + defaultGoQuorumCompatibilityMode); validator.setTransactionFilter(transactionFilter(false)); Account invalidEOA = - when(account(basicTransaction.getUpfrontCost(0), basicTransaction.getNonce()).getCodeHash()) + when(account(basicTransaction.getUpfrontCost(DataGas.ZERO), basicTransaction.getNonce()) + .getCodeHash()) .thenReturn(Hash.fromHexStringLenient("0xdeadbeef")) .getMock(); @@ -207,7 +247,11 @@ public void shouldRejectTransactionIfAccountIsNotEOA() { public void shouldRejectTransactionIfAccountIsNotPermitted() { final MainnetTransactionValidator validator = new MainnetTransactionValidator( - gasCalculator, false, Optional.empty(), defaultGoQuorumCompatibilityMode); + gasCalculator, + GasLimitCalculator.constant(), + false, + Optional.empty(), + defaultGoQuorumCompatibilityMode); validator.setTransactionFilter(transactionFilter(false)); assertThat(validator.validateForSender(basicTransaction, accountWithNonce(0), true)) @@ -218,7 +262,11 @@ public void shouldRejectTransactionIfAccountIsNotPermitted() { public void shouldAcceptValidTransactionIfAccountIsPermitted() { final MainnetTransactionValidator validator = new MainnetTransactionValidator( - gasCalculator, false, Optional.empty(), defaultGoQuorumCompatibilityMode); + gasCalculator, + GasLimitCalculator.constant(), + false, + Optional.empty(), + defaultGoQuorumCompatibilityMode); validator.setTransactionFilter(transactionFilter(true)); assertThat(validator.validateForSender(basicTransaction, accountWithNonce(0), true)) @@ -229,7 +277,11 @@ public void shouldAcceptValidTransactionIfAccountIsPermitted() { public void shouldRejectTransactionWithMaxFeeTimesGasLimitGreaterThanBalance() { final MainnetTransactionValidator validator = new MainnetTransactionValidator( - gasCalculator, false, Optional.empty(), defaultGoQuorumCompatibilityMode); + gasCalculator, + GasLimitCalculator.constant(), + false, + Optional.empty(), + defaultGoQuorumCompatibilityMode); validator.setTransactionFilter(transactionFilter(true)); assertThat( @@ -255,6 +307,7 @@ public void shouldRejectTransactionWithMaxPriorityFeeGreaterThanMaxFee() { final MainnetTransactionValidator validator = new MainnetTransactionValidator( gasCalculator, + GasLimitCalculator.constant(), FeeMarket.london(0L), false, Optional.of(BigInteger.ONE), @@ -302,7 +355,11 @@ public void shouldPropagateCorrectStateChangeParamToTransactionFilter() { final MainnetTransactionValidator validator = new MainnetTransactionValidator( - gasCalculator, false, Optional.empty(), defaultGoQuorumCompatibilityMode); + gasCalculator, + GasLimitCalculator.constant(), + false, + Optional.empty(), + defaultGoQuorumCompatibilityMode); validator.setTransactionFilter(transactionFilter); final TransactionValidationParams validationParams = @@ -320,7 +377,11 @@ public void shouldNotCheckAccountPermissionIfBothValidationParamsCheckPermission final MainnetTransactionValidator validator = new MainnetTransactionValidator( - gasCalculator, false, Optional.empty(), defaultGoQuorumCompatibilityMode); + gasCalculator, + GasLimitCalculator.constant(), + false, + Optional.empty(), + defaultGoQuorumCompatibilityMode); validator.setTransactionFilter(transactionFilter); final TransactionValidationParams validationParams = @@ -342,6 +403,7 @@ public void shouldAcceptOnlyTransactionsInAcceptedTransactionTypes() { final MainnetTransactionValidator frontierValidator = new MainnetTransactionValidator( gasCalculator, + GasLimitCalculator.constant(), FeeMarket.legacy(), false, Optional.of(BigInteger.ONE), @@ -352,6 +414,7 @@ public void shouldAcceptOnlyTransactionsInAcceptedTransactionTypes() { final MainnetTransactionValidator eip1559Validator = new MainnetTransactionValidator( gasCalculator, + GasLimitCalculator.constant(), FeeMarket.london(0L), false, Optional.of(BigInteger.ONE), @@ -385,6 +448,7 @@ public void shouldRejectTransactionIfEIP1559TransactionGasPriceLessBaseFee() { final MainnetTransactionValidator validator = new MainnetTransactionValidator( gasCalculator, + GasLimitCalculator.constant(), FeeMarket.london(0L), false, Optional.of(BigInteger.ONE), @@ -409,6 +473,7 @@ public void shouldAcceptZeroGasPriceTransactionIfBaseFeeIsZero() { final MainnetTransactionValidator validator = new MainnetTransactionValidator( gasCalculator, + GasLimitCalculator.constant(), FeeMarket.london(0L, zeroBaseFee), false, Optional.of(BigInteger.ONE), @@ -432,6 +497,7 @@ public void shouldAcceptValidEIP1559() { final MainnetTransactionValidator validator = new MainnetTransactionValidator( gasCalculator, + GasLimitCalculator.constant(), FeeMarket.london(0L), false, Optional.of(BigInteger.ONE), @@ -457,6 +523,7 @@ public void shouldValidate1559TransactionWithPriceLowerThanBaseFeeForTransaction final MainnetTransactionValidator validator = new MainnetTransactionValidator( gasCalculator, + GasLimitCalculator.constant(), FeeMarket.london(0L), false, Optional.of(BigInteger.ONE), @@ -483,6 +550,7 @@ public void shouldRejectTooLargeInitcode() { final MainnetTransactionValidator validator = new MainnetTransactionValidator( gasCalculator, + GasLimitCalculator.constant(), FeeMarket.london(0L), false, Optional.of(BigInteger.ONE), @@ -508,7 +576,8 @@ public void shouldRejectTooLargeInitcode() { @Test public void goQuorumCompatibilityModeRejectNonZeroGasPrice() { final MainnetTransactionValidator validator = - new MainnetTransactionValidator(gasCalculator, false, Optional.empty(), true); + new MainnetTransactionValidator( + gasCalculator, GasLimitCalculator.constant(), false, Optional.empty(), true); final Transaction transaction = new TransactionTestFixture() .gasPrice(Wei.ONE) @@ -530,7 +599,8 @@ public void goQuorumCompatibilityModeRejectNonZeroGasPrice() { @Test public void goQuorumCompatibilityModeSuccessZeroGasPrice() { final MainnetTransactionValidator validator = - new MainnetTransactionValidator(gasCalculator, false, Optional.empty(), true); + new MainnetTransactionValidator( + gasCalculator, GasLimitCalculator.constant(), false, Optional.empty(), true); final Transaction transaction = new TransactionTestFixture() .gasPrice(Wei.ZERO) @@ -547,7 +617,7 @@ public void goQuorumCompatibilityModeSuccessZeroGasPrice() { } private Account accountWithNonce(final long nonce) { - return account(basicTransaction.getUpfrontCost(0), nonce); + return account(basicTransaction.getUpfrontCost(DataGas.ZERO), nonce); } private Account account(final Wei balance, final long nonce) { diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java index 8ffd50f37df..df5250f7dbe 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java @@ -19,14 +19,12 @@ /** The Cancun gas calculator as defined in EIP-4844 */ public class CancunGasCalculator extends LondonGasCalculator { - public static final int CANCUN_DATA_GAS_PER_BLOB = 131072; // 2^17 + public static final DataGas CANCUN_DATA_GAS_PER_BLOB = DataGas.of(131072); // 2^17 public static final DataGas CANCUN_TARGET_DATA_GAS_PER_BLOCK = DataGas.of(262144); // 2^18 - public static final int CANCUN_MAX_DATA_GAS_PER_BLOCK = 524288; // 2^19 - @Override - public int dataGasCost(final int blobCount) { - return CANCUN_DATA_GAS_PER_BLOB * blobCount; + public DataGas dataGasCost(final int blobCount) { + return CANCUN_DATA_GAS_PER_BLOB.multiply(blobCount); } /** @@ -39,7 +37,7 @@ public int dataGasCost(final int blobCount) { */ @Override public DataGas computeExcessDataGas(final DataGas parentExcessDataGas, final int newBlobs) { - final int consumedDataGas = newBlobs * CANCUN_DATA_GAS_PER_BLOB; + final DataGas consumedDataGas = CANCUN_DATA_GAS_PER_BLOB.multiply(newBlobs); final DataGas currentExcessDataGas = parentExcessDataGas.add(consumedDataGas); if (currentExcessDataGas.lessThan(CANCUN_TARGET_DATA_GAS_PER_BLOCK)) { @@ -47,9 +45,4 @@ public DataGas computeExcessDataGas(final DataGas parentExcessDataGas, final int } return currentExcessDataGas.add(CANCUN_TARGET_DATA_GAS_PER_BLOCK); } - - @Override - public long getDataGasLimit() { - return CANCUN_MAX_DATA_GAS_PER_BLOCK; - } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java index 05386b1a572..af6fee3c1a3 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java @@ -489,15 +489,11 @@ default long getMaxRefundQuotient() { // what would be the gas for a PMT with hash of all non-zeros long getMaximumTransactionCost(int size); - default int dataGasCost(final int totalDataGas) { - return 0; + default DataGas dataGasCost(final int totalDataGas) { + return DataGas.ZERO; } default DataGas computeExcessDataGas(final DataGas parentExcessDataGas, final int newBlobs) { return DataGas.ZERO; } - - default long getDataGasLimit() { - return 0; - } } From 16996635fce64c44f5a0ae1f7a795ffc9ea34a6e Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 24 Jan 2023 16:27:48 +0100 Subject: [PATCH 12/27] Use long internally to represent data gas Signed-off-by: Fabio Di Fabio --- .../blockcreation/AbstractBlockCreator.java | 7 ++++-- .../BlockTransactionSelector.java | 13 +++++------ .../besu/ethereum/GasLimitCalculator.java | 6 ++--- .../besu/ethereum/core/Transaction.java | 13 +++++------ .../CancunTargetingGasLimitCalculator.java | 5 ++--- .../mainnet/MainnetTransactionProcessor.java | 6 ++--- .../mainnet/MainnetTransactionValidator.java | 10 ++++----- .../MainnetTransactionValidatorTest.java | 5 ++--- .../gascalculator/CancunGasCalculator.java | 22 +++++++++---------- .../besu/evm/gascalculator/GasCalculator.java | 9 ++++---- 10 files changed, 43 insertions(+), 53 deletions(-) diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java index dba7dc80fc3..e056b0cb461 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java @@ -264,8 +264,11 @@ private DataGas computeExcessDataGas( .map(tx -> tx.getVersionedHashes().orElseThrow()) .mapToInt(List::size) .sum(); - return gasCalculator.computeExcessDataGas( - parentHeader.getExcessDataGas().orElse(DataGas.ZERO), newBlobsCount); + // casting parent excess data gas to long since for the moment it should be well below that + // limit + return DataGas.of( + gasCalculator.computeExcessDataGas( + parentHeader.getExcessDataGas().map(DataGas::toLong).orElse(0L), newBlobsCount)); } return null; } diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java index f48623c623d..a1560e835ee 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java @@ -342,7 +342,7 @@ private void updateTransactionResultTracking( transaction.isGoQuorumPrivateTransaction( transactionProcessor.getTransactionValidator().getGoQuorumCompatibilityMode()); - final long dataGasUsed = gasCalculator.dataGasCost(transaction.getBlobCount()).toLong(); + final long dataGasUsed = gasCalculator.dataGasCost(transaction.getBlobCount()); final long gasUsedByTransaction = isGoQuorumPrivateTransaction @@ -375,16 +375,15 @@ private TransactionProcessingResult publicResultForWhenWeHaveAPrivateTransaction } private boolean transactionTooLargeForBlock(final Transaction transaction) { - final var dataGasUsed = gasCalculator.dataGasCost(transaction.getBlobCount()); + final long dataGasUsed = gasCalculator.dataGasCost(transaction.getBlobCount()); - if (dataGasUsed.greaterThan( - gasLimitCalculator - .nextDataGasLimit() - .subtract(transactionSelectionResult.getCumulativeDataGasUsed()))) { + if (dataGasUsed + > gasLimitCalculator.currentDataGasLimit() + - transactionSelectionResult.getCumulativeDataGasUsed()) { return true; } - return transaction.getGasLimit() + dataGasUsed.toLong() + return transaction.getGasLimit() + dataGasUsed > processableBlockHeader.getGasLimit() - transactionSelectionResult.getCumulativeGasUsed(); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/GasLimitCalculator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/GasLimitCalculator.java index 97b69122e07..30a35389afb 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/GasLimitCalculator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/GasLimitCalculator.java @@ -14,8 +14,6 @@ */ package org.hyperledger.besu.ethereum; -import org.hyperledger.besu.datatypes.DataGas; - public interface GasLimitCalculator { long nextGasLimit(long currentGasLimit, long targetGasLimit, long newBlockNumber); @@ -24,7 +22,7 @@ static GasLimitCalculator constant() { return (currentGasLimit, targetGasLimit, newBlockNumber) -> currentGasLimit; } - default DataGas nextDataGasLimit() { - return DataGas.ZERO; + default long currentDataGasLimit() { + return 0L; } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java index 078b3c448aa..b3a6da73810 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java @@ -24,7 +24,6 @@ import org.hyperledger.besu.crypto.SignatureAlgorithm; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder; @@ -705,7 +704,7 @@ public boolean isContractCreation() { * * @return the max up-front cost for the gas the transaction can use. */ - private Wei getMaxUpfrontGasCost(final DataGas dataGasPerBlock) { + private Wei getMaxUpfrontGasCost(final long dataGasPerBlock) { return getUpfrontGasCost( getMaxGasPrice(), getMaxFeePerDataGas().orElse(Wei.ZERO), dataGasPerBlock); } @@ -716,7 +715,7 @@ private Wei getMaxUpfrontGasCost(final DataGas dataGasPerBlock) { * @return true is upfront data cost overflow uint256 max value */ private boolean isUpfrontGasCostTooHigh() { - return calculateUpfrontGasCost(getMaxGasPrice(), Wei.ZERO, DataGas.ZERO).bitLength() > 256; + return calculateUpfrontGasCost(getMaxGasPrice(), Wei.ZERO, 0L).bitLength() > 256; } /** @@ -727,7 +726,7 @@ private boolean isUpfrontGasCostTooHigh() { * @return the up-front cost for the gas the transaction can use. */ public Wei getUpfrontGasCost( - final Wei gasPrice, final Wei dataGasPrice, final DataGas totalDataGas) { + final Wei gasPrice, final Wei dataGasPrice, final long totalDataGas) { if (gasPrice == null || gasPrice.isZero()) { return Wei.ZERO; } @@ -742,12 +741,12 @@ public Wei getUpfrontGasCost( } private BigInteger calculateUpfrontGasCost( - final Wei gasPrice, final Wei dataGasPrice, final DataGas totalDataGas) { + final Wei gasPrice, final Wei dataGasPrice, final long totalDataGas) { var cost = new BigInteger(1, Longs.toByteArray(getGasLimit())).multiply(gasPrice.getAsBigInteger()); if (transactionType.supportsBlob()) { - cost = cost.add(dataGasPrice.getAsBigInteger().multiply(totalDataGas.getAsBigInteger())); + cost = cost.add(dataGasPrice.getAsBigInteger().multiply(BigInteger.valueOf(totalDataGas))); } return cost; @@ -762,7 +761,7 @@ private BigInteger calculateUpfrontGasCost( * * @return the up-front gas cost for the transaction */ - public Wei getUpfrontCost(final DataGas totalDataGas) { + public Wei getUpfrontCost(final long totalDataGas) { return getMaxUpfrontGasCost(totalDataGas).addExact(getValue()); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/CancunTargetingGasLimitCalculator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/CancunTargetingGasLimitCalculator.java index e71b4af9505..9b5156f4353 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/CancunTargetingGasLimitCalculator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/CancunTargetingGasLimitCalculator.java @@ -14,11 +14,10 @@ */ package org.hyperledger.besu.ethereum.mainnet; -import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; public class CancunTargetingGasLimitCalculator extends LondonTargetingGasLimitCalculator { - public static final DataGas MAX_DATA_GAS_PER_BLOCK = DataGas.of(524288); // 2^19 + public static final long MAX_DATA_GAS_PER_BLOCK = 524288; // 2^19 public CancunTargetingGasLimitCalculator( final long londonForkBlock, final BaseFeeMarket feeMarket) { @@ -26,7 +25,7 @@ public CancunTargetingGasLimitCalculator( } @Override - public DataGas nextDataGasLimit() { + public long currentDataGasLimit() { return MAX_DATA_GAS_PER_BLOCK; } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java index 52927bb3ea0..9348011f814 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java @@ -20,7 +20,6 @@ import static org.hyperledger.besu.ethereum.mainnet.PrivateStateUtils.KEY_TRANSACTION_HASH; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.chain.Blockchain; @@ -300,7 +299,7 @@ public TransactionProcessingResult processTransaction( previousNonce, sender.getNonce()); - final DataGas dataGas = gasCalculator.dataGasCost(transaction.getBlobCount()); + final long dataGas = gasCalculator.dataGasCost(transaction.getBlobCount()); final Wei upfrontGasCost = transaction.getUpfrontGasCost(transactionGasPrice, dataGasPrice, dataGas); @@ -335,8 +334,7 @@ public TransactionProcessingResult processTransaction( final long accessListGas = gasCalculator.accessListGasCost(accessListEntries.size(), accessListStorageCount); - final long gasAvailable = - transaction.getGasLimit() - intrinsicGas - accessListGas - dataGas.toLong(); + final long gasAvailable = transaction.getGasLimit() - intrinsicGas - accessListGas - dataGas; LOG.trace( "Gas available for execution {} = {} - {} - {} - {} (limit - intrinsic - accessList - data)", gasAvailable, diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java index ff46f68b789..a0b8d1ebc3d 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java @@ -18,7 +18,6 @@ import org.hyperledger.besu.crypto.SECPSignature; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; -import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.GasLimitCalculator; @@ -193,14 +192,13 @@ private ValidationResult validateCostAndFee( } if (transaction.getType().supportsBlob()) { - final DataGas txTotalDataGas = gasCalculator.dataGasCost(transaction.getBlobCount()); - if (txTotalDataGas.greaterThan(gasLimitCalculator.nextDataGasLimit())) { + final long txTotalDataGas = gasCalculator.dataGasCost(transaction.getBlobCount()); + if (txTotalDataGas > gasLimitCalculator.currentDataGasLimit()) { return ValidationResult.invalid( TransactionInvalidReason.TOTAL_DATA_GAS_TOO_HIGH, String.format( - "total data gas %s exceeds max data gas per block %s", - txTotalDataGas.getAsBigInteger(), - gasLimitCalculator.nextDataGasLimit().getAsBigInteger())); + "total data gas %d exceeds max data gas per block %d", + txTotalDataGas, gasLimitCalculator.currentDataGasLimit())); } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java index f8651720541..285735483a8 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidatorTest.java @@ -31,7 +31,6 @@ import org.hyperledger.besu.crypto.SignatureAlgorithm; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.GasLimitCalculator; @@ -234,7 +233,7 @@ public void shouldRejectTransactionIfAccountIsNotEOA() { validator.setTransactionFilter(transactionFilter(false)); Account invalidEOA = - when(account(basicTransaction.getUpfrontCost(DataGas.ZERO), basicTransaction.getNonce()) + when(account(basicTransaction.getUpfrontCost(0L), basicTransaction.getNonce()) .getCodeHash()) .thenReturn(Hash.fromHexStringLenient("0xdeadbeef")) .getMock(); @@ -617,7 +616,7 @@ public void goQuorumCompatibilityModeSuccessZeroGasPrice() { } private Account accountWithNonce(final long nonce) { - return account(basicTransaction.getUpfrontCost(DataGas.ZERO), nonce); + return account(basicTransaction.getUpfrontCost(0L), nonce); } private Account account(final Wei balance, final long nonce) { diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java index df5250f7dbe..988604e221f 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java @@ -14,17 +14,15 @@ */ package org.hyperledger.besu.evm.gascalculator; -import org.hyperledger.besu.datatypes.DataGas; - /** The Cancun gas calculator as defined in EIP-4844 */ public class CancunGasCalculator extends LondonGasCalculator { - public static final DataGas CANCUN_DATA_GAS_PER_BLOB = DataGas.of(131072); // 2^17 - public static final DataGas CANCUN_TARGET_DATA_GAS_PER_BLOCK = DataGas.of(262144); // 2^18 + public static final long CANCUN_DATA_GAS_PER_BLOB = 131072; // 2^17 + public static final long CANCUN_TARGET_DATA_GAS_PER_BLOCK = 262144; // 2^18 @Override - public DataGas dataGasCost(final int blobCount) { - return CANCUN_DATA_GAS_PER_BLOB.multiply(blobCount); + public long dataGasCost(final int blobCount) { + return CANCUN_DATA_GAS_PER_BLOB * blobCount; } /** @@ -36,13 +34,13 @@ public DataGas dataGasCost(final int blobCount) { * @return the new excess data gas value */ @Override - public DataGas computeExcessDataGas(final DataGas parentExcessDataGas, final int newBlobs) { - final DataGas consumedDataGas = CANCUN_DATA_GAS_PER_BLOB.multiply(newBlobs); - final DataGas currentExcessDataGas = parentExcessDataGas.add(consumedDataGas); + public long computeExcessDataGas(final long parentExcessDataGas, final int newBlobs) { + final long consumedDataGas = CANCUN_DATA_GAS_PER_BLOB * newBlobs; + final long currentExcessDataGas = parentExcessDataGas + consumedDataGas; - if (currentExcessDataGas.lessThan(CANCUN_TARGET_DATA_GAS_PER_BLOCK)) { - return DataGas.ZERO; + if (currentExcessDataGas < CANCUN_TARGET_DATA_GAS_PER_BLOCK) { + return 0L; } - return currentExcessDataGas.add(CANCUN_TARGET_DATA_GAS_PER_BLOCK); + return currentExcessDataGas - CANCUN_TARGET_DATA_GAS_PER_BLOCK; } } diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java index af6fee3c1a3..764fa2cb985 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java @@ -15,7 +15,6 @@ package org.hyperledger.besu.evm.gascalculator; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.evm.AccessListEntry; import org.hyperledger.besu.evm.account.Account; @@ -489,11 +488,11 @@ default long getMaxRefundQuotient() { // what would be the gas for a PMT with hash of all non-zeros long getMaximumTransactionCost(int size); - default DataGas dataGasCost(final int totalDataGas) { - return DataGas.ZERO; + default long dataGasCost(final int totalDataGas) { + return 0L; } - default DataGas computeExcessDataGas(final DataGas parentExcessDataGas, final int newBlobs) { - return DataGas.ZERO; + default long computeExcessDataGas(final long parentExcessDataGas, final int newBlobs) { + return 0L; } } From af7c70a72fd4a4e2e4ad7b8d56b69efc16d6a423 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 24 Jan 2023 17:18:42 +0100 Subject: [PATCH 13/27] Fix javadoc Signed-off-by: Fabio Di Fabio --- .../CancunTargetingGasLimitCalculator.java | 2 +- .../evm/gascalculator/CancunGasCalculator.java | 4 ++-- .../besu/evm/gascalculator/GasCalculator.java | 16 +++++++++++++++- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/CancunTargetingGasLimitCalculator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/CancunTargetingGasLimitCalculator.java index 9b5156f4353..a4c14494ae9 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/CancunTargetingGasLimitCalculator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/CancunTargetingGasLimitCalculator.java @@ -17,7 +17,7 @@ import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; public class CancunTargetingGasLimitCalculator extends LondonTargetingGasLimitCalculator { - public static final long MAX_DATA_GAS_PER_BLOCK = 524288; // 2^19 + private static final long MAX_DATA_GAS_PER_BLOCK = 524288; // 2^19 public CancunTargetingGasLimitCalculator( final long londonForkBlock, final BaseFeeMarket feeMarket) { diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java index 988604e221f..53da02dd0f4 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java @@ -17,8 +17,8 @@ /** The Cancun gas calculator as defined in EIP-4844 */ public class CancunGasCalculator extends LondonGasCalculator { - public static final long CANCUN_DATA_GAS_PER_BLOB = 131072; // 2^17 - public static final long CANCUN_TARGET_DATA_GAS_PER_BLOCK = 262144; // 2^18 + private static final long CANCUN_DATA_GAS_PER_BLOB = 131072; // 2^17 + private static final long CANCUN_TARGET_DATA_GAS_PER_BLOCK = 262144; // 2^18 @Override public long dataGasCost(final int blobCount) { diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java index 764fa2cb985..7758e72a873 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/GasCalculator.java @@ -488,10 +488,24 @@ default long getMaxRefundQuotient() { // what would be the gas for a PMT with hash of all non-zeros long getMaximumTransactionCost(int size); - default long dataGasCost(final int totalDataGas) { + /** + * Return the gas cost given the number of blobs + * + * @param blobCount the number of blobs + * @return the total gas cost + */ + default long dataGasCost(final int blobCount) { return 0L; } + /** + * Compute the new value for the excess data gas, given the parent value and the count of new + * blobs + * + * @param parentExcessDataGas excess data gas from the parent + * @param newBlobs count of new blobs + * @return the new excess data gas value + */ default long computeExcessDataGas(final long parentExcessDataGas, final int newBlobs) { return 0L; } From 79e9338d8b331f5352532b012f0bca4379ca170a Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 24 Jan 2023 17:20:50 +0100 Subject: [PATCH 14/27] Write power of 2 in a self documenting way Signed-off-by: Fabio Di Fabio --- .../ethereum/mainnet/CancunTargetingGasLimitCalculator.java | 2 +- .../besu/evm/gascalculator/CancunGasCalculator.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/CancunTargetingGasLimitCalculator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/CancunTargetingGasLimitCalculator.java index a4c14494ae9..c0c3366f4df 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/CancunTargetingGasLimitCalculator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/CancunTargetingGasLimitCalculator.java @@ -17,7 +17,7 @@ import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; public class CancunTargetingGasLimitCalculator extends LondonTargetingGasLimitCalculator { - private static final long MAX_DATA_GAS_PER_BLOCK = 524288; // 2^19 + private static final long MAX_DATA_GAS_PER_BLOCK = 1 << 19; public CancunTargetingGasLimitCalculator( final long londonForkBlock, final BaseFeeMarket feeMarket) { diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java index 53da02dd0f4..e0c19690f59 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java @@ -17,8 +17,8 @@ /** The Cancun gas calculator as defined in EIP-4844 */ public class CancunGasCalculator extends LondonGasCalculator { - private static final long CANCUN_DATA_GAS_PER_BLOB = 131072; // 2^17 - private static final long CANCUN_TARGET_DATA_GAS_PER_BLOCK = 262144; // 2^18 + private static final long CANCUN_DATA_GAS_PER_BLOB = 1 << 17; + private static final long CANCUN_TARGET_DATA_GAS_PER_BLOCK = 1 << 18; @Override public long dataGasCost(final int blobCount) { From 0719dede1bc21cc87a731f6476c7c9c578a152d8 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Fri, 27 Jan 2023 15:00:07 +0100 Subject: [PATCH 15/27] Consumed data gas receipt fix (#5018) * adding test for nonblob blob transaction * Do not add consumed data gas to gas used in the transaction receipt Signed-off-by: Jiri Peinlich Signed-off-by: Fabio Di Fabio Co-authored-by: Jiri Peinlich --- .../blockcreation/BlockTransactionSelector.java | 8 +++----- .../besu/ethereum/mainnet/AbstractBlockProcessor.java | 10 ++++++++-- .../besu/ethereum/mainnet/MainnetProtocolSpecs.java | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java index a1560e835ee..dcd153bf487 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java @@ -342,16 +342,14 @@ private void updateTransactionResultTracking( transaction.isGoQuorumPrivateTransaction( transactionProcessor.getTransactionValidator().getGoQuorumCompatibilityMode()); - final long dataGasUsed = gasCalculator.dataGasCost(transaction.getBlobCount()); - final long gasUsedByTransaction = - isGoQuorumPrivateTransaction - ? 0 - : transaction.getGasLimit() + dataGasUsed - result.getGasRemaining(); + isGoQuorumPrivateTransaction ? 0 : transaction.getGasLimit() - result.getGasRemaining(); final long cumulativeGasUsed = transactionSelectionResult.getCumulativeGasUsed() + gasUsedByTransaction; + final long dataGasUsed = gasCalculator.dataGasCost(transaction.getBlobCount()); + transactionSelectionResult.update( transaction, transactionReceiptFactory.create( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java index 62a91659c0c..990e0fa8a4b 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java @@ -95,6 +95,9 @@ public BlockProcessingResult processBlock( final PrivateMetadataUpdater privateMetadataUpdater) { final List receipts = new ArrayList<>(); long currentGasUsed = 0; + + final ProtocolSpec protocolSpec = protocolSchedule.getByBlockHeader(blockHeader); + for (final Transaction transaction : transactions) { if (!hasAvailableBlockBudget(blockHeader, transaction, currentGasUsed)) { return new BlockProcessingResult(Optional.empty(), "provided gas insufficient"); @@ -132,7 +135,10 @@ public BlockProcessingResult processBlock( } worldStateUpdater.commit(); - currentGasUsed += transaction.getGasLimit() - result.getGasRemaining(); + final long dataGasUsed = + protocolSpec.getGasCalculator().dataGasCost(transaction.getBlobCount()); + + currentGasUsed += transaction.getGasLimit() - result.getGasRemaining() - dataGasUsed; final TransactionReceipt transactionReceipt = transactionReceiptFactory.create( transaction.getType(), result, worldState, currentGasUsed); @@ -140,7 +146,7 @@ public BlockProcessingResult processBlock( } final Optional maybeWithdrawalsProcessor = - protocolSchedule.getByBlockHeader(blockHeader).getWithdrawalsProcessor(); + protocolSpec.getWithdrawalsProcessor(); if (maybeWithdrawalsProcessor.isPresent() && maybeWithdrawals.isPresent()) { maybeWithdrawalsProcessor .get() diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java index dd92d44edfd..ca4a68c47fb 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java @@ -658,7 +658,7 @@ static ProtocolSpecBuilder shanghaiDefinition( final boolean quorumCompatibilityMode, final EvmConfiguration evmConfiguration) { - // extra vaiables need to support flipping the warm coinbase flag. + // extra variables need to support flipping the warm coinbase flag. final int stackSizeLimit = configStackSizeLimit.orElse(MessageFrame.DEFAULT_MAX_STACK_SIZE); final long londonForkBlockNumber = genesisConfigOptions.getLondonBlockNumber().orElse(0L); final BaseFeeMarket londonFeeMarket = From c967962304f9ff4bc912ba8ee8c5050cb5055829 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Thu, 26 Jan 2023 16:40:50 +0100 Subject: [PATCH 16/27] Allow blob tx in Cancun (#5007) Signed-off-by: Fabio Di Fabio Co-authored-by: Justin Florentine --- .../besu/ethereum/mainnet/MainnetProtocolSpecs.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java index ca4a68c47fb..f5bff456113 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java @@ -777,7 +777,8 @@ static ProtocolSpecBuilder cancunDefinition( Set.of( TransactionType.FRONTIER, TransactionType.ACCESS_LIST, - TransactionType.EIP1559), + TransactionType.EIP1559, + TransactionType.BLOB), quorumCompatibilityMode, SHANGHAI_INIT_CODE_SIZE_LIMIT)) .precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::cancun) From 437c77039be898e49a3eca679187ff99fa1c22c2 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Wed, 1 Feb 2023 10:15:15 +0100 Subject: [PATCH 17/27] Revert "Consumed data gas receipt fix (#5018)" This reverts commit 0719dede1bc21cc87a731f6476c7c9c578a152d8. Signed-off-by: Fabio Di Fabio --- .../blockcreation/BlockTransactionSelector.java | 8 +++++--- .../besu/ethereum/mainnet/AbstractBlockProcessor.java | 10 ++-------- .../besu/ethereum/mainnet/MainnetProtocolSpecs.java | 2 +- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java index dcd153bf487..a1560e835ee 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java @@ -342,14 +342,16 @@ private void updateTransactionResultTracking( transaction.isGoQuorumPrivateTransaction( transactionProcessor.getTransactionValidator().getGoQuorumCompatibilityMode()); + final long dataGasUsed = gasCalculator.dataGasCost(transaction.getBlobCount()); + final long gasUsedByTransaction = - isGoQuorumPrivateTransaction ? 0 : transaction.getGasLimit() - result.getGasRemaining(); + isGoQuorumPrivateTransaction + ? 0 + : transaction.getGasLimit() + dataGasUsed - result.getGasRemaining(); final long cumulativeGasUsed = transactionSelectionResult.getCumulativeGasUsed() + gasUsedByTransaction; - final long dataGasUsed = gasCalculator.dataGasCost(transaction.getBlobCount()); - transactionSelectionResult.update( transaction, transactionReceiptFactory.create( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java index 990e0fa8a4b..62a91659c0c 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java @@ -95,9 +95,6 @@ public BlockProcessingResult processBlock( final PrivateMetadataUpdater privateMetadataUpdater) { final List receipts = new ArrayList<>(); long currentGasUsed = 0; - - final ProtocolSpec protocolSpec = protocolSchedule.getByBlockHeader(blockHeader); - for (final Transaction transaction : transactions) { if (!hasAvailableBlockBudget(blockHeader, transaction, currentGasUsed)) { return new BlockProcessingResult(Optional.empty(), "provided gas insufficient"); @@ -135,10 +132,7 @@ public BlockProcessingResult processBlock( } worldStateUpdater.commit(); - final long dataGasUsed = - protocolSpec.getGasCalculator().dataGasCost(transaction.getBlobCount()); - - currentGasUsed += transaction.getGasLimit() - result.getGasRemaining() - dataGasUsed; + currentGasUsed += transaction.getGasLimit() - result.getGasRemaining(); final TransactionReceipt transactionReceipt = transactionReceiptFactory.create( transaction.getType(), result, worldState, currentGasUsed); @@ -146,7 +140,7 @@ public BlockProcessingResult processBlock( } final Optional maybeWithdrawalsProcessor = - protocolSpec.getWithdrawalsProcessor(); + protocolSchedule.getByBlockHeader(blockHeader).getWithdrawalsProcessor(); if (maybeWithdrawalsProcessor.isPresent() && maybeWithdrawals.isPresent()) { maybeWithdrawalsProcessor .get() diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java index f5bff456113..c043d729da6 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java @@ -658,7 +658,7 @@ static ProtocolSpecBuilder shanghaiDefinition( final boolean quorumCompatibilityMode, final EvmConfiguration evmConfiguration) { - // extra variables need to support flipping the warm coinbase flag. + // extra vaiables need to support flipping the warm coinbase flag. final int stackSizeLimit = configStackSizeLimit.orElse(MessageFrame.DEFAULT_MAX_STACK_SIZE); final long londonForkBlockNumber = genesisConfigOptions.getLondonBlockNumber().orElse(0L); final BaseFeeMarket londonFeeMarket = From dd91da365d99a41c0730529b6669895daec7edcc Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Fri, 27 Jan 2023 15:00:07 +0100 Subject: [PATCH 18/27] Consumed data gas receipt fix (#5018) * adding test for nonblob blob transaction * Do not add consumed data gas to gas used in the transaction receipt Signed-off-by: Jiri Peinlich Signed-off-by: Fabio Di Fabio Co-authored-by: Jiri Peinlich --- .../blockcreation/BlockTransactionSelector.java | 8 +++----- .../besu/ethereum/mainnet/AbstractBlockProcessor.java | 10 ++++++++-- .../besu/ethereum/mainnet/MainnetProtocolSpecs.java | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java index a1560e835ee..dcd153bf487 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java @@ -342,16 +342,14 @@ private void updateTransactionResultTracking( transaction.isGoQuorumPrivateTransaction( transactionProcessor.getTransactionValidator().getGoQuorumCompatibilityMode()); - final long dataGasUsed = gasCalculator.dataGasCost(transaction.getBlobCount()); - final long gasUsedByTransaction = - isGoQuorumPrivateTransaction - ? 0 - : transaction.getGasLimit() + dataGasUsed - result.getGasRemaining(); + isGoQuorumPrivateTransaction ? 0 : transaction.getGasLimit() - result.getGasRemaining(); final long cumulativeGasUsed = transactionSelectionResult.getCumulativeGasUsed() + gasUsedByTransaction; + final long dataGasUsed = gasCalculator.dataGasCost(transaction.getBlobCount()); + transactionSelectionResult.update( transaction, transactionReceiptFactory.create( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java index 62a91659c0c..990e0fa8a4b 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java @@ -95,6 +95,9 @@ public BlockProcessingResult processBlock( final PrivateMetadataUpdater privateMetadataUpdater) { final List receipts = new ArrayList<>(); long currentGasUsed = 0; + + final ProtocolSpec protocolSpec = protocolSchedule.getByBlockHeader(blockHeader); + for (final Transaction transaction : transactions) { if (!hasAvailableBlockBudget(blockHeader, transaction, currentGasUsed)) { return new BlockProcessingResult(Optional.empty(), "provided gas insufficient"); @@ -132,7 +135,10 @@ public BlockProcessingResult processBlock( } worldStateUpdater.commit(); - currentGasUsed += transaction.getGasLimit() - result.getGasRemaining(); + final long dataGasUsed = + protocolSpec.getGasCalculator().dataGasCost(transaction.getBlobCount()); + + currentGasUsed += transaction.getGasLimit() - result.getGasRemaining() - dataGasUsed; final TransactionReceipt transactionReceipt = transactionReceiptFactory.create( transaction.getType(), result, worldState, currentGasUsed); @@ -140,7 +146,7 @@ public BlockProcessingResult processBlock( } final Optional maybeWithdrawalsProcessor = - protocolSchedule.getByBlockHeader(blockHeader).getWithdrawalsProcessor(); + protocolSpec.getWithdrawalsProcessor(); if (maybeWithdrawalsProcessor.isPresent() && maybeWithdrawals.isPresent()) { maybeWithdrawalsProcessor .get() diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java index c043d729da6..f5bff456113 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java @@ -658,7 +658,7 @@ static ProtocolSpecBuilder shanghaiDefinition( final boolean quorumCompatibilityMode, final EvmConfiguration evmConfiguration) { - // extra vaiables need to support flipping the warm coinbase flag. + // extra variables need to support flipping the warm coinbase flag. final int stackSizeLimit = configStackSizeLimit.orElse(MessageFrame.DEFAULT_MAX_STACK_SIZE); final long londonForkBlockNumber = genesisConfigOptions.getLondonBlockNumber().orElse(0L); final BaseFeeMarket londonFeeMarket = From 112e77403a4ba8b9e24be2991473a65cd334d97d Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 31 Jan 2023 19:09:04 +0100 Subject: [PATCH 19/27] Fix data gas calculation during block import (#5023) Signed-off-by: Fabio Di Fabio --- .../blockcreation/MergeCoordinatorTest.java | 4 +- .../BlockTransactionSelector.java | 3 +- .../feemarket/TransactionPriceCalculator.java | 25 ++++----- .../mainnet/AbstractBlockProcessor.java | 5 +- .../mainnet/MainnetProtocolSpecs.java | 17 ++++++ .../mainnet/MainnetTransactionProcessor.java | 53 +++++++++++-------- .../mainnet/MainnetTransactionValidator.java | 5 -- 7 files changed, 62 insertions(+), 50 deletions(-) diff --git a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java index 4f7a5a16e62..34c7a3e58da 100644 --- a/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java +++ b/consensus/merge/src/test/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinatorTest.java @@ -26,7 +26,6 @@ import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; @@ -365,7 +364,8 @@ public void shouldRetryBlockCreationOnRecoverableError() .getTransactions() .isEmpty()) { // this is called by the first empty block - doThrow(new MerkleTrieException("lock")) // first fail + doCallRealMethod() // first work + .doThrow(new MerkleTrieException("lock")) // second fail .doCallRealMethod() // then work .when(blockchain) .getBlockHeader(any()); diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java index dcd153bf487..8e547814ef2 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java @@ -17,6 +17,7 @@ import static org.hyperledger.besu.util.Slf4jLambdaHelper.traceLambda; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.GasLimitCalculator; import org.hyperledger.besu.ethereum.chain.Blockchain; @@ -246,7 +247,7 @@ private boolean transactionDataPriceBelowMin(final Transaction transaction) { .lessThan( feeMarket .getTransactionPriceCalculator() - .dataPrice(transaction, processableBlockHeader))) { + .dataPrice(processableBlockHeader.getExcessDataGas().orElse(DataGas.ZERO)))) { return true; } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculator.java index 531dff5d4f3..9d6bbc08051 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculator.java @@ -16,8 +16,8 @@ import static org.hyperledger.besu.util.Slf4jLambdaHelper.traceLambda; +import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Wei; -import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; import org.hyperledger.besu.ethereum.core.Transaction; import java.math.BigInteger; @@ -29,7 +29,7 @@ public interface TransactionPriceCalculator { Wei price(Transaction transaction, Optional maybeFee); - default Wei dataPrice(final Transaction transaction, final ProcessableBlockHeader blockHeader) { + default Wei dataPrice(final DataGas excessDataGas) { return Wei.ZERO; } @@ -38,11 +38,6 @@ class Frontier implements TransactionPriceCalculator { public Wei price(final Transaction transaction, final Optional maybeFee) { return transaction.getGasPrice().orElse(Wei.ZERO); } - - @Override - public Wei dataPrice(final Transaction transaction, final ProcessableBlockHeader blockHeader) { - return Wei.ZERO; - } } class EIP1559 implements TransactionPriceCalculator { @@ -73,17 +68,14 @@ public DataBlob(final int minDataGasPrice, final int dataGasPriceUpdateFraction) } @Override - public Wei dataPrice(final Transaction transaction, final ProcessableBlockHeader blockHeader) { - final var excessDataGas = blockHeader.getExcessDataGas().orElseThrow(); - + public Wei dataPrice(final DataGas excessDataGas) { final var dataGasPrice = Wei.of( fakeExponential( minDataGasPrice, excessDataGas.toBigInteger(), dataGasPriceUpdateFraction)); traceLambda( LOG, - "block #{} parentExcessDataGas: {} dataGasPrice: {}", - blockHeader::getNumber, + "parentExcessDataGas: {} dataGasPrice: {}", excessDataGas::toShortHexString, dataGasPrice::toHexString); @@ -92,14 +84,15 @@ public Wei dataPrice(final Transaction transaction, final ProcessableBlockHeader private BigInteger fakeExponential( final BigInteger factor, final BigInteger numerator, final BigInteger denominator) { - BigInteger i = BigInteger.ONE; + int i = 1; BigInteger output = BigInteger.ZERO; BigInteger numeratorAccumulator = factor.multiply(denominator); - while (numeratorAccumulator.compareTo(BigInteger.ZERO) > 0) { + while (numeratorAccumulator.signum() > 0) { output = output.add(numeratorAccumulator); numeratorAccumulator = - (numeratorAccumulator.multiply(numerator)).divide(denominator.multiply(i)); - i = i.add(BigInteger.ONE); + (numeratorAccumulator.multiply(numerator)) + .divide(denominator.multiply(BigInteger.valueOf(i))); + ++i; } return output.divide(denominator); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java index 990e0fa8a4b..c05580abbca 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java @@ -135,10 +135,7 @@ public BlockProcessingResult processBlock( } worldStateUpdater.commit(); - final long dataGasUsed = - protocolSpec.getGasCalculator().dataGasCost(transaction.getBlobCount()); - - currentGasUsed += transaction.getGasLimit() - result.getGasRemaining() - dataGasUsed; + currentGasUsed += transaction.getGasLimit() - result.getGasRemaining(); final TransactionReceipt transactionReceipt = transactionReceiptFactory.create( transaction.getType(), result, worldState, currentGasUsed); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java index f5bff456113..c0c22f6dd57 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java @@ -726,6 +726,7 @@ static ProtocolSpecBuilder cancunDefinition( final boolean quorumCompatibilityMode, final EvmConfiguration evmConfiguration) { + final int stackSizeLimit = configStackSizeLimit.orElse(MessageFrame.DEFAULT_MAX_STACK_SIZE); final int contractSizeLimit = configContractSizeLimit.orElse(SPURIOUS_DRAGON_CONTRACT_SIZE_LIMIT); final long londonForkBlockNumber = genesisConfigOptions.getLondonBlockNumber().orElse(0L); @@ -765,6 +766,22 @@ static ProtocolSpecBuilder cancunDefinition( MaxCodeSizeRule.of(contractSizeLimit), EOFValidationCodeRule.of(1, false)), 1, SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES)) + // use Cancun fee market + .transactionProcessorBuilder( + (gasCalculator, + transactionValidator, + contractCreationProcessor, + messageCallProcessor) -> + new MainnetTransactionProcessor( + gasCalculator, + transactionValidator, + contractCreationProcessor, + messageCallProcessor, + true, + true, + stackSizeLimit, + cancunFeeMarket, + CoinbaseFeePriceCalculator.eip1559())) // change to check for max data gas per block for EIP-4844 .transactionValidatorBuilder( (gasCalculator, gasLimitCalculator) -> diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java index 9348011f814..8d349e3b40f 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java @@ -20,9 +20,11 @@ import static org.hyperledger.besu.ethereum.mainnet.PrivateStateUtils.KEY_TRANSACTION_HASH; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.feemarket.CoinbaseFeePriceCalculator; @@ -253,7 +255,7 @@ public TransactionProcessingResult processTransaction( } public TransactionProcessingResult processTransaction( - final Blockchain ignoredBlockchain, + final Blockchain blockchain, final WorldUpdater worldState, final ProcessableBlockHeader blockHeader, final Transaction transaction, @@ -289,16 +291,23 @@ public TransactionProcessingResult processTransaction( final MutableAccount senderMutableAccount = sender.getMutable(); final long previousNonce = senderMutableAccount.incrementNonce(); - final Wei transactionGasPrice = - feeMarket.getTransactionPriceCalculator().price(transaction, blockHeader.getBaseFee()); - final Wei dataGasPrice = - feeMarket.getTransactionPriceCalculator().dataPrice(transaction, blockHeader); LOG.trace( "Incremented sender {} nonce ({} -> {})", senderAddress, previousNonce, sender.getNonce()); + final Wei transactionGasPrice = + feeMarket.getTransactionPriceCalculator().price(transaction, blockHeader.getBaseFee()); + final Wei dataGasPrice = + feeMarket + .getTransactionPriceCalculator() + .dataPrice( + blockchain + .getBlockHeader(blockHeader.getParentHash()) + .flatMap(BlockHeader::getExcessDataGas) + .orElse(DataGas.ZERO)); + final long dataGas = gasCalculator.dataGasCost(transaction.getBlobCount()); final Wei upfrontGasCost = @@ -334,14 +343,13 @@ public TransactionProcessingResult processTransaction( final long accessListGas = gasCalculator.accessListGasCost(accessListEntries.size(), accessListStorageCount); - final long gasAvailable = transaction.getGasLimit() - intrinsicGas - accessListGas - dataGas; + final long gasAvailable = transaction.getGasLimit() - intrinsicGas - accessListGas; LOG.trace( - "Gas available for execution {} = {} - {} - {} - {} (limit - intrinsic - accessList - data)", + "Gas available for execution {} = {} - {} - {} - {} (limit - intrinsic - accessList)", gasAvailable, transaction.getGasLimit(), intrinsicGas, - accessListGas, - dataGas); + accessListGas); final WorldUpdater worldUpdater = worldState.updater(); final Deque messageFrameStack = new ArrayDeque<>(); @@ -435,9 +443,9 @@ public TransactionProcessingResult processTransaction( // after the other so that if it is the same account somehow, we end up with the right result) final long selfDestructRefund = gasCalculator.getSelfDestructRefundAmount() * initialFrame.getSelfDestructs().size(); - final long refundGas = initialFrame.getGasRefund() + selfDestructRefund; - final long refunded = refunded(transaction, initialFrame.getRemainingGas(), refundGas); - final Wei refundedWei = transactionGasPrice.multiply(refunded); + final long baseRefundGas = initialFrame.getGasRefund() + selfDestructRefund; + final long refundedGas = refunded(transaction, initialFrame.getRemainingGas(), baseRefundGas); + final Wei refundedWei = transactionGasPrice.multiply(refundedGas); senderMutableAccount.incrementBalance(refundedWei); final long gasUsedByTransaction = transaction.getGasLimit() - initialFrame.getRemainingGas(); @@ -445,25 +453,26 @@ public TransactionProcessingResult processTransaction( if (!worldState.getClass().equals(GoQuorumMutablePrivateWorldStateUpdater.class)) { // if this is not a private GoQuorum transaction we have to update the coinbase final var coinbase = worldState.getOrCreate(miningBeneficiary).getMutable(); - final long coinbaseFee = transaction.getGasLimit() - refunded; + final long usedGas = transaction.getGasLimit() - refundedGas; + final CoinbaseFeePriceCalculator coinbaseCalculator; if (blockHeader.getBaseFee().isPresent()) { final Wei baseFee = blockHeader.getBaseFee().get(); if (transactionGasPrice.compareTo(baseFee) < 0) { return TransactionProcessingResult.failed( gasUsedByTransaction, - refunded, + refundedGas, ValidationResult.invalid( TransactionInvalidReason.TRANSACTION_PRICE_TOO_LOW, "transaction price must be greater than base fee"), Optional.empty()); } + coinbaseCalculator = coinbaseFeePriceCalculator; + } else { + coinbaseCalculator = CoinbaseFeePriceCalculator.frontier(); } - final CoinbaseFeePriceCalculator coinbaseCalculator = - blockHeader.getBaseFee().isPresent() - ? coinbaseFeePriceCalculator - : CoinbaseFeePriceCalculator.frontier(); + final Wei coinbaseWeiDelta = - coinbaseCalculator.price(coinbaseFee, transactionGasPrice, blockHeader.getBaseFee()); + coinbaseCalculator.price(usedGas, transactionGasPrice, blockHeader.getBaseFee()); coinbase.incrementBalance(coinbaseWeiDelta); } @@ -478,12 +487,12 @@ public TransactionProcessingResult processTransaction( return TransactionProcessingResult.successful( initialFrame.getLogs(), gasUsedByTransaction, - refunded, + refundedGas, initialFrame.getOutputData(), validationResult); } else { return TransactionProcessingResult.failed( - gasUsedByTransaction, refunded, validationResult, initialFrame.getRevertReason()); + gasUsedByTransaction, refundedGas, validationResult, initialFrame.getRevertReason()); } } catch (final RuntimeException re) { LOG.error("Critical Exception Processing Transaction", re); @@ -521,7 +530,7 @@ private AbstractMessageProcessor getMessageProcessor(final MessageFrame.Type typ protected long refunded( final Transaction transaction, final long gasRemaining, final long gasRefund) { - // Integer truncation takes care of the the floor calculation needed after the divide. + // Integer truncation takes care of the floor calculation needed after the divide. final long maxRefundAllowance = (transaction.getGasLimit() - gasRemaining) / gasCalculator.getMaxRefundQuotient(); final long refundAllowance = Math.min(maxRefundAllowance, gasRefund); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java index a0b8d1ebc3d..a8d762b89ee 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java @@ -186,11 +186,6 @@ private ValidationResult validateCostAndFee( } } - if (transaction.getNonce() == MAX_NONCE) { - return ValidationResult.invalid( - TransactionInvalidReason.NONCE_OVERFLOW, "Nonce must be less than 2^64-1"); - } - if (transaction.getType().supportsBlob()) { final long txTotalDataGas = gasCalculator.dataGasCost(transaction.getBlobCount()); if (txTotalDataGas > gasLimitCalculator.currentDataGasLimit()) { From fc9abee86c0ebc7e04bd3c78f239789e2e39b68c Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Fri, 3 Feb 2023 15:37:25 +0100 Subject: [PATCH 20/27] Correctly set the fee market Cancun (#5045) Signed-off-by: Fabio Di Fabio --- .../hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java | 1 + 1 file changed, 1 insertion(+) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java index c0c22f6dd57..c4933c480e2 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetProtocolSpecs.java @@ -746,6 +746,7 @@ static ProtocolSpecBuilder cancunDefinition( genesisConfigOptions, quorumCompatibilityMode, evmConfiguration) + .feeMarket(cancunFeeMarket) // gas calculator for EIP-4844 data gas .gasCalculator(CancunGasCalculator::new) // gas limit with EIP-4844 max data gas per block From 6becf3709aad0fe7aecc1e81109211fee8413b6d Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Tue, 14 Feb 2023 18:00:43 +0100 Subject: [PATCH 21/27] Optimization to avoid to compute dataGasPrice for every txs in a block Signed-off-by: Fabio Di Fabio --- .../internal/methods/DebugStorageRangeAt.java | 7 ++- .../internal/processor/BlockReplay.java | 46 +++++++++++----- .../internal/processor/BlockTracer.java | 10 +++- .../internal/processor/TransactionTracer.java | 26 +++++++--- .../methods/DebugStorageRangeAtTest.java | 4 +- .../processor/TransactionTracerTest.java | 9 +++- .../BlockTransactionSelector.java | 8 +-- .../AbstractBlockTransactionSelectorTest.java | 4 +- .../vm/TraceTransactionIntegrationTest.java | 9 ++-- .../feemarket/TransactionPriceCalculator.java | 52 +------------------ .../goquorum/GoQuorumBlockProcessor.java | 3 +- .../mainnet/AbstractBlockProcessor.java | 12 ++++- .../mainnet/MainnetTransactionProcessor.java | 37 +++++++------ .../mainnet/feemarket/CancunFeeMarket.java | 48 ++++++++++++++--- .../ethereum/mainnet/feemarket/FeeMarket.java | 5 ++ ...PrivateGroupRehydrationBlockProcessor.java | 3 +- .../PrivateMigrationBlockProcessor.java | 3 +- .../transaction/TransactionSimulator.java | 6 ++- .../TransactionPriceCalculatorTest.java | 8 +-- .../MainnetTransactionProcessorTest.java | 9 ++-- .../mainnet/PrivacyBlockProcessorTest.java | 2 +- .../feemarket/ZeroBaseFeeMarketTest.java | 8 +-- .../transaction/TransactionSimulatorTest.java | 24 ++++++++- .../besu/evmtool/StateTestSubCommand.java | 8 ++- .../vm/GeneralStateReferenceTestTools.java | 16 ++++-- 25 files changed, 223 insertions(+), 144 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStorageRangeAt.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStorageRangeAt.java index 488ea999ea5..3c5db065ee7 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStorageRangeAt.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStorageRangeAt.java @@ -96,7 +96,12 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { .afterTransactionInBlock( blockHash, transactionWithMetadata.getTransaction().getHash(), - (transaction, blockHeader, blockchain, worldState, transactionProcessor) -> + (transaction, + blockHeader, + blockchain, + worldState, + transactionProcessor, + protocolSpec) -> extractStorageAt( requestContext, accountAddress, startKey, limit, worldState)) .orElseGet(() -> emptyResponse(requestContext)))) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockReplay.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockReplay.java index 57e115d9b39..89e11d42bdd 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockReplay.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockReplay.java @@ -14,7 +14,9 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor; +import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; @@ -52,8 +54,11 @@ public Optional block( return performActionWithBlock( block.getHeader(), block.getBody(), - (body, header, blockchain, mutableWorldState, transactionProcessor) -> { - List transactionTraces = + (body, header, blockchain, mutableWorldState, transactionProcessor, protocolSpec) -> { + final Wei dataGasPrice = + protocolSpec.getFeeMarket().dataPrice(header.getExcessDataGas().orElse(DataGas.ZERO)); + + final List transactionTraces = body.getTransactions().stream() .map( transaction -> @@ -62,7 +67,8 @@ public Optional block( header, blockchain, mutableWorldState, - transactionProcessor)) + transactionProcessor, + dataGasPrice)) .collect(Collectors.toList()); return Optional.of(new BlockTrace(transactionTraces)); }); @@ -77,24 +83,32 @@ public Optional beforeTransactionInBlock( final Hash blockHash, final Hash transactionHash, final TransactionAction action) { return performActionWithBlock( blockHash, - (body, header, blockchain, mutableWorldState, transactionProcessor) -> { + (body, header, blockchain, mutableWorldState, transactionProcessor, protocolSpec) -> { final BlockHashLookup blockHashLookup = new BlockHashLookup(header, blockchain); + final Wei dataGasPrice = + protocolSpec.getFeeMarket().dataPrice(header.getExcessDataGas().orElse(DataGas.ZERO)); + for (final Transaction transaction : body.getTransactions()) { if (transaction.getHash().equals(transactionHash)) { return Optional.of( action.performAction( - transaction, header, blockchain, mutableWorldState, transactionProcessor)); + transaction, + header, + blockchain, + mutableWorldState, + transactionProcessor, + dataGasPrice)); } else { - final ProtocolSpec spec = protocolSchedule.getByBlockHeader(header); transactionProcessor.processTransaction( blockchain, mutableWorldState.updater(), header, transaction, - spec.getMiningBeneficiaryCalculator().calculateBeneficiary(header), + protocolSpec.getMiningBeneficiaryCalculator().calculateBeneficiary(header), blockHashLookup, false, - TransactionValidationParams.blockReplay()); + TransactionValidationParams.blockReplay(), + dataGasPrice); } } return Optional.empty(); @@ -106,7 +120,7 @@ public Optional afterTransactionInBlock( return beforeTransactionInBlock( blockHash, transactionHash, - (transaction, blockHeader, blockchain, worldState, transactionProcessor) -> { + (transaction, blockHeader, blockchain, worldState, transactionProcessor, dataGasPrice) -> { final ProtocolSpec spec = protocolSchedule.getByBlockHeader(blockHeader); transactionProcessor.processTransaction( blockchain, @@ -116,9 +130,10 @@ public Optional afterTransactionInBlock( spec.getMiningBeneficiaryCalculator().calculateBeneficiary(blockHeader), new BlockHashLookup(blockHeader, blockchain), false, - TransactionValidationParams.blockReplay()); + TransactionValidationParams.blockReplay(), + dataGasPrice); return action.performAction( - transaction, blockHeader, blockchain, worldState, transactionProcessor); + transaction, blockHeader, blockchain, worldState, transactionProcessor, dataGasPrice); }); } @@ -160,7 +175,8 @@ private Optional performActionWithBlock( new IllegalArgumentException( "Missing worldstate for stateroot " + previous.getStateRoot().toShortHexString()))) { - return action.perform(body, header, blockchain, worldState, transactionProcessor); + return action.perform( + body, header, blockchain, worldState, transactionProcessor, protocolSpec); } catch (Exception ex) { return Optional.empty(); } @@ -190,7 +206,8 @@ Optional perform( BlockHeader blockHeader, Blockchain blockchain, MutableWorldState worldState, - MainnetTransactionProcessor transactionProcessor); + MainnetTransactionProcessor transactionProcessor, + ProtocolSpec protocolSpec); } @FunctionalInterface @@ -200,6 +217,7 @@ T performAction( BlockHeader blockHeader, Blockchain blockchain, MutableWorldState worldState, - MainnetTransactionProcessor transactionProcessor); + MainnetTransactionProcessor transactionProcessor, + Wei dataGasPrice); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockTracer.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockTracer.java index b3eca1e4dba..4dc4157b66f 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockTracer.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockTracer.java @@ -47,7 +47,12 @@ public Optional trace(final Block block, final DebugOperationTracer private BlockReplay.TransactionAction prepareReplayAction( final DebugOperationTracer tracer) { - return (transaction, header, blockchain, mutableWorldState, transactionProcessor) -> { + return (transaction, + header, + blockchain, + mutableWorldState, + transactionProcessor, + dataGasPrice) -> { // if we have no prior updater, it must be the first TX, so use the block's initial state if (chainedUpdater == null) { chainedUpdater = mutableWorldState.updater(); @@ -65,7 +70,8 @@ private BlockReplay.TransactionAction prepareReplayAction( header.getCoinbase(), tracer, new BlockHashLookup(header, blockchain), - false); + false, + dataGasPrice); final List traceFrames = tracer.copyTraceFrames(); tracer.reset(); return new TransactionTrace(transaction, result, traceFrames); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracer.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracer.java index 329a08dc744..335f12269e7 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracer.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracer.java @@ -16,7 +16,9 @@ import static java.util.function.Predicate.isEqual; +import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.TransactionTraceParams; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.BlockHeader; @@ -65,7 +67,7 @@ public Optional traceTransaction( return blockReplay.beforeTransactionInBlock( blockHash, transactionHash, - (transaction, header, blockchain, worldState, transactionProcessor) -> { + (transaction, header, blockchain, worldState, transactionProcessor, dataGasPrice) -> { final TransactionProcessingResult result = processTransaction( header, @@ -73,7 +75,8 @@ public Optional traceTransaction( worldState.updater(), transaction, transactionProcessor, - tracer); + tracer, + dataGasPrice); return new TransactionTrace(transaction, result, tracer.getTraceFrames()); }); } @@ -101,9 +104,13 @@ public List traceTransactionToFile( return blockReplay .performActionWithBlock( blockHash, - (body, header, blockchain, worldState, transactionProcessor) -> { + (body, header, blockchain, worldState, transactionProcessor, protocolSpec) -> { WorldUpdater stackedUpdater = worldState.updater().updater(); final List traces = new ArrayList<>(); + final Wei dataGasPrice = + protocolSpec + .getFeeMarket() + .dataPrice(header.getExcessDataGas().orElse(DataGas.ZERO)); for (int i = 0; i < body.getTransactions().size(); i++) { ((StackedUpdater) stackedUpdater).markTransactionBoundary(); final Transaction transaction = body.getTransactions().get(i); @@ -119,7 +126,8 @@ public List traceTransactionToFile( stackedUpdater, transaction, transactionProcessor, - new StandardJsonTracer(out, showMemory)); + new StandardJsonTracer(out, showMemory), + dataGasPrice); out.println( summaryTrace( transaction, timer.stop().elapsed(TimeUnit.NANOSECONDS), result)); @@ -135,7 +143,8 @@ public List traceTransactionToFile( stackedUpdater, transaction, transactionProcessor, - OperationTracer.NO_TRACING); + OperationTracer.NO_TRACING, + dataGasPrice); } } return Optional.of(traces); @@ -165,7 +174,9 @@ private TransactionProcessingResult processTransaction( final WorldUpdater worldUpdater, final Transaction transaction, final MainnetTransactionProcessor transactionProcessor, - final OperationTracer tracer) { + final OperationTracer tracer, + final Wei dataGasPrice) { + return transactionProcessor.processTransaction( blockchain, worldUpdater, @@ -175,7 +186,8 @@ private TransactionProcessingResult processTransaction( tracer, new BlockHashLookup(header, blockchain), false, - ImmutableTransactionValidationParams.builder().isAllowFutureNonce(true).build()); + ImmutableTransactionValidationParams.builder().isAllowFutureNonce(true).build(), + dataGasPrice); } public static String summaryTrace( diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStorageRangeAtTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStorageRangeAtTest.java index ed01d89ab08..488f0d05fe6 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStorageRangeAtTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/DebugStorageRangeAtTest.java @@ -23,6 +23,7 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor.BlockReplay; @@ -155,6 +156,7 @@ private Object callAction(final InvocationOnMock invocation) { //noinspection rawtypes return Optional.of( ((BlockReplay.TransactionAction) invocation.getArgument(2)) - .performAction(transaction, blockHeader, blockchain, worldState, transactionProcessor)); + .performAction( + transaction, blockHeader, blockchain, worldState, transactionProcessor, Wei.ZERO)); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracerTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracerTest.java index af79442fd67..0728e53f2f7 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracerTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracerTest.java @@ -21,6 +21,7 @@ import static org.mockito.Mockito.when; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.ImmutableTransactionTraceParams; import org.hyperledger.besu.ethereum.chain.BadBlockManager; import org.hyperledger.besu.ethereum.chain.Blockchain; @@ -32,6 +33,7 @@ import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; +import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; import org.hyperledger.besu.ethereum.vm.DebugOperationTracer; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; @@ -115,6 +117,7 @@ public void setUp() throws Exception { when(protocolSchedule.getByBlockHeader(blockHeader)).thenReturn(protocolSpec); when(protocolSpec.getTransactionProcessor()).thenReturn(transactionProcessor); when(protocolSpec.getMiningBeneficiaryCalculator()).thenReturn(BlockHeader::getCoinbase); + when(protocolSpec.getFeeMarket()).thenReturn(FeeMarket.london(0L)); when(blockchain.getChainHeadHeader()).thenReturn(blockHeader); when(protocolSpec.getBadBlocksManager()).thenReturn(new BadBlockManager()); when(mutableWorldState.copy()).thenReturn(mutableWorldState); @@ -180,7 +183,8 @@ public void traceTransactionShouldReturnResultFromProcessTransaction() { eq(tracer), any(), any(), - any())) + any(), + eq(Wei.ZERO))) .thenReturn(result); final Optional transactionTrace = @@ -267,7 +271,8 @@ public void traceTransactionToFileShouldReturnResultFromProcessTransaction() thr any(StandardJsonTracer.class), any(), any(), - any())) + any(), + eq(Wei.ZERO))) .thenReturn(result); final List transactionTraces = diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java index 8e547814ef2..6c6d6d79770 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java @@ -220,7 +220,8 @@ private TransactionSelectionResult evaluateTransaction( miningBeneficiary, blockHashLookup, false, - TransactionValidationParams.mining()); + TransactionValidationParams.mining(), + Wei.ZERO); } if (!effectiveResult.isInvalid()) { @@ -245,9 +246,8 @@ private boolean transactionDataPriceBelowMin(final Transaction transaction) { .getMaxFeePerDataGas() .orElseThrow() .lessThan( - feeMarket - .getTransactionPriceCalculator() - .dataPrice(processableBlockHeader.getExcessDataGas().orElse(DataGas.ZERO)))) { + feeMarket.dataPrice( + processableBlockHeader.getExcessDataGas().orElse(DataGas.ZERO)))) { return true; } } diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java index ebe8e8bb224..de94b1c66d6 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java @@ -495,7 +495,7 @@ protected void ensureTransactionIsValid(final Transaction tx) { protected void ensureTransactionIsValid( final Transaction tx, final long gasUsedByTransaction, final long gasRemaining) { when(transactionProcessor.processTransaction( - any(), any(), any(), eq(tx), any(), any(), anyBoolean(), any())) + any(), any(), any(), eq(tx), any(), any(), anyBoolean(), any(), any())) .thenReturn( TransactionProcessingResult.successful( new ArrayList<>(), @@ -508,7 +508,7 @@ protected void ensureTransactionIsValid( protected void ensureTransactionIsInvalid( final Transaction tx, final TransactionInvalidReason invalidReason) { when(transactionProcessor.processTransaction( - any(), any(), any(), eq(tx), any(), any(), anyBoolean(), any())) + any(), any(), any(), eq(tx), any(), any(), anyBoolean(), any(), any())) .thenReturn(TransactionProcessingResult.invalid(ValidationResult.invalid(invalidReason))); } } diff --git a/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/vm/TraceTransactionIntegrationTest.java b/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/vm/TraceTransactionIntegrationTest.java index 0d3e1388f18..d3e37ec5d6a 100644 --- a/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/vm/TraceTransactionIntegrationTest.java +++ b/ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/vm/TraceTransactionIntegrationTest.java @@ -103,7 +103,8 @@ public void shouldTraceSStoreOperation() { genesisBlockHeader.getCoinbase(), blockHashLookup, false, - TransactionValidationParams.blockReplay()); + TransactionValidationParams.blockReplay(), + Wei.ZERO); assertThat(result.isSuccessful()).isTrue(); final Account createdContract = createTransactionUpdater.getTouchedAccounts().stream() @@ -135,7 +136,8 @@ public void shouldTraceSStoreOperation() { genesisBlockHeader.getCoinbase(), tracer, blockHashLookup, - false); + false, + Wei.ZERO); assertThat(result.isSuccessful()).isTrue(); @@ -176,7 +178,8 @@ public void shouldTraceContractCreation() { genesisBlockHeader.getCoinbase(), tracer, new BlockHashLookup(genesisBlockHeader, blockchain), - false); + false, + Wei.ZERO); final int expectedDepth = 0; // Reference impl returned 1. Why the difference? diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculator.java index 9d6bbc08051..6788ab3aeb4 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculator.java @@ -14,25 +14,14 @@ */ package org.hyperledger.besu.ethereum.core.feemarket; -import static org.hyperledger.besu.util.Slf4jLambdaHelper.traceLambda; - -import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; -import java.math.BigInteger; import java.util.Optional; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - public interface TransactionPriceCalculator { Wei price(Transaction transaction, Optional maybeFee); - default Wei dataPrice(final DataGas excessDataGas) { - return Wei.ZERO; - } - class Frontier implements TransactionPriceCalculator { @Override public Wei price(final Transaction transaction, final Optional maybeFee) { @@ -57,44 +46,5 @@ public Wei price(final Transaction transaction, final Optional maybeFee) { } } - class DataBlob extends EIP1559 { - private static final Logger LOG = LoggerFactory.getLogger(DataBlob.class); - private final BigInteger minDataGasPrice; - private final BigInteger dataGasPriceUpdateFraction; - - public DataBlob(final int minDataGasPrice, final int dataGasPriceUpdateFraction) { - this.minDataGasPrice = BigInteger.valueOf(minDataGasPrice); - this.dataGasPriceUpdateFraction = BigInteger.valueOf(dataGasPriceUpdateFraction); - } - - @Override - public Wei dataPrice(final DataGas excessDataGas) { - final var dataGasPrice = - Wei.of( - fakeExponential( - minDataGasPrice, excessDataGas.toBigInteger(), dataGasPriceUpdateFraction)); - traceLambda( - LOG, - "parentExcessDataGas: {} dataGasPrice: {}", - excessDataGas::toShortHexString, - dataGasPrice::toHexString); - - return dataGasPrice; - } - - private BigInteger fakeExponential( - final BigInteger factor, final BigInteger numerator, final BigInteger denominator) { - int i = 1; - BigInteger output = BigInteger.ZERO; - BigInteger numeratorAccumulator = factor.multiply(denominator); - while (numeratorAccumulator.signum() > 0) { - output = output.add(numeratorAccumulator); - numeratorAccumulator = - (numeratorAccumulator.multiply(numerator)) - .divide(denominator.multiply(BigInteger.valueOf(i))); - ++i; - } - return output.divide(denominator); - } - } + class DataBlob extends EIP1559 {} } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/goquorum/GoQuorumBlockProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/goquorum/GoQuorumBlockProcessor.java index 361851c32a4..1aba23adafd 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/goquorum/GoQuorumBlockProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/goquorum/GoQuorumBlockProcessor.java @@ -150,7 +150,8 @@ public BlockProcessingResult processBlock( blockHashLookup, true, TransactionValidationParams.processingBlock(), - null); + null, + Wei.ZERO); if (result.isInvalid()) { String errorMessage = diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java index 37bc30ef779..32dbca85fa8 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/AbstractBlockProcessor.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.mainnet; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.BlockProcessingOutputs; import org.hyperledger.besu.ethereum.BlockProcessingResult; @@ -108,6 +109,14 @@ public BlockProcessingResult processBlock( final BlockHashLookup blockHashLookup = new BlockHashLookup(blockHeader, blockchain); final Address miningBeneficiary = miningBeneficiaryCalculator.calculateBeneficiary(blockHeader); + final Wei dataGasPrice = + protocolSpec + .getFeeMarket() + .dataPrice( + blockchain + .getBlockHeader(blockHeader.getParentHash()) + .flatMap(BlockHeader::getExcessDataGas) + .orElse(DataGas.ZERO)); final TransactionProcessingResult result = transactionProcessor.processTransaction( @@ -120,7 +129,8 @@ public BlockProcessingResult processBlock( blockHashLookup, true, TransactionValidationParams.processingBlock(), - privateMetadataUpdater); + privateMetadataUpdater, + dataGasPrice); if (result.isInvalid()) { String errorMessage = MessageFormat.format( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java index a21e09582b0..42179878fda 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java @@ -20,10 +20,8 @@ import static org.hyperledger.besu.ethereum.mainnet.PrivateStateUtils.KEY_TRANSACTION_HASH; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.chain.Blockchain; -import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.feemarket.CoinbaseFeePriceCalculator; @@ -127,7 +125,8 @@ public TransactionProcessingResult processTransaction( final Address miningBeneficiary, final BlockHashLookup blockHashLookup, final Boolean isPersistingPrivateState, - final TransactionValidationParams transactionValidationParams) { + final TransactionValidationParams transactionValidationParams, + final Wei dataGasPrice) { return processTransaction( blockchain, worldState, @@ -138,7 +137,8 @@ public TransactionProcessingResult processTransaction( blockHashLookup, isPersistingPrivateState, transactionValidationParams, - null); + null, + dataGasPrice); } /** @@ -167,7 +167,8 @@ public TransactionProcessingResult processTransaction( final BlockHashLookup blockHashLookup, final Boolean isPersistingPrivateState, final TransactionValidationParams transactionValidationParams, - final OperationTracer operationTracer) { + final OperationTracer operationTracer, + final Wei dataGasPrice) { return processTransaction( blockchain, worldState, @@ -178,7 +179,8 @@ public TransactionProcessingResult processTransaction( blockHashLookup, isPersistingPrivateState, transactionValidationParams, - null); + null, + dataGasPrice); } /** @@ -202,7 +204,8 @@ public TransactionProcessingResult processTransaction( final Address miningBeneficiary, final OperationTracer operationTracer, final BlockHashLookup blockHashLookup, - final Boolean isPersistingPrivateState) { + final Boolean isPersistingPrivateState, + final Wei dataGasPrice) { return processTransaction( blockchain, worldState, @@ -213,7 +216,8 @@ public TransactionProcessingResult processTransaction( blockHashLookup, isPersistingPrivateState, ImmutableTransactionValidationParams.builder().build(), - null); + null, + dataGasPrice); } /** @@ -239,7 +243,8 @@ public TransactionProcessingResult processTransaction( final OperationTracer operationTracer, final BlockHashLookup blockHashLookup, final Boolean isPersistingPrivateState, - final TransactionValidationParams transactionValidationParams) { + final TransactionValidationParams transactionValidationParams, + final Wei dataGasPrice) { return processTransaction( blockchain, worldState, @@ -250,7 +255,8 @@ public TransactionProcessingResult processTransaction( blockHashLookup, isPersistingPrivateState, transactionValidationParams, - null); + null, + dataGasPrice); } public TransactionProcessingResult processTransaction( @@ -263,7 +269,8 @@ public TransactionProcessingResult processTransaction( final BlockHashLookup blockHashLookup, final Boolean isPersistingPrivateState, final TransactionValidationParams transactionValidationParams, - final PrivateMetadataUpdater privateMetadataUpdater) { + final PrivateMetadataUpdater privateMetadataUpdater, + final Wei dataGasPrice) { try { LOG.trace("Starting execution of {}", transaction); ValidationResult validationResult = @@ -298,14 +305,6 @@ public TransactionProcessingResult processTransaction( final Wei transactionGasPrice = feeMarket.getTransactionPriceCalculator().price(transaction, blockHeader.getBaseFee()); - final Wei dataGasPrice = - feeMarket - .getTransactionPriceCalculator() - .dataPrice( - blockchain - .getBlockHeader(blockHeader.getParentHash()) - .flatMap(BlockHeader::getExcessDataGas) - .orElse(DataGas.ZERO)); final long dataGas = gasCalculator.dataGasCost(transaction.getBlobCount()); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/CancunFeeMarket.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/CancunFeeMarket.java index fba11a96459..5feb1f1b1ce 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/CancunFeeMarket.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/CancunFeeMarket.java @@ -14,26 +14,60 @@ */ package org.hyperledger.besu.ethereum.mainnet.feemarket; +import static org.hyperledger.besu.util.Slf4jLambdaHelper.traceLambda; + +import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.feemarket.TransactionPriceCalculator; +import java.math.BigInteger; import java.util.Optional; -public class CancunFeeMarket extends LondonFeeMarket { +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; - private static final int MIN_DATA_GAS_PRICE = 1; - private static final int DATA_GAS_PRICE_UPDATE_FRACTION = 2225652; +public class CancunFeeMarket extends LondonFeeMarket { + private static final Logger LOG = LoggerFactory.getLogger(CancunFeeMarket.class); + private static final BigInteger MIN_DATA_GAS_PRICE = BigInteger.ONE; + private static final BigInteger DATA_GAS_PRICE_UPDATE_FRACTION = BigInteger.valueOf(2225652); public CancunFeeMarket( final long londonForkBlockNumber, final Optional baseFeePerGasOverride) { - super( - new TransactionPriceCalculator.DataBlob(MIN_DATA_GAS_PRICE, DATA_GAS_PRICE_UPDATE_FRACTION), - londonForkBlockNumber, - baseFeePerGasOverride); + super(new TransactionPriceCalculator.DataBlob(), londonForkBlockNumber, baseFeePerGasOverride); } @Override public boolean implementsDataFee() { return true; } + + @Override + public Wei dataPrice(final DataGas excessDataGas) { + final var dataGasPrice = + Wei.of( + fakeExponential( + MIN_DATA_GAS_PRICE, excessDataGas.toBigInteger(), DATA_GAS_PRICE_UPDATE_FRACTION)); + traceLambda( + LOG, + "parentExcessDataGas: {} dataGasPrice: {}", + excessDataGas::toShortHexString, + dataGasPrice::toHexString); + + return dataGasPrice; + } + + private BigInteger fakeExponential( + final BigInteger factor, final BigInteger numerator, final BigInteger denominator) { + int i = 1; + BigInteger output = BigInteger.ZERO; + BigInteger numeratorAccumulator = factor.multiply(denominator); + while (numeratorAccumulator.signum() > 0) { + output = output.add(numeratorAccumulator); + numeratorAccumulator = + (numeratorAccumulator.multiply(numerator)) + .divide(denominator.multiply(BigInteger.valueOf(i))); + ++i; + } + return output.divide(denominator); + } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/FeeMarket.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/FeeMarket.java index a674e602b1c..dc20b43438f 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/FeeMarket.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/FeeMarket.java @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.ethereum.mainnet.feemarket; +import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.feemarket.TransactionPriceCalculator; @@ -55,4 +56,8 @@ static BaseFeeMarket zeroBaseFee(final long londonForkBlockNumber) { static FeeMarket legacy() { return new LegacyFeeMarket(); } + + default Wei dataPrice(final DataGas excessDataGas) { + return Wei.ZERO; + } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateGroupRehydrationBlockProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateGroupRehydrationBlockProcessor.java index 63dfe260f91..c06a9a0271a 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateGroupRehydrationBlockProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/PrivateGroupRehydrationBlockProcessor.java @@ -177,7 +177,8 @@ public BlockProcessingResult processBlock( miningBeneficiary, blockHashLookup, false, - TransactionValidationParams.processingBlock()); + TransactionValidationParams.processingBlock(), + Wei.ZERO); if (result.isInvalid()) { return BlockProcessingResult.FAILED; } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/storage/migration/PrivateMigrationBlockProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/storage/migration/PrivateMigrationBlockProcessor.java index 9a8b7e0be23..c6743354e4b 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/storage/migration/PrivateMigrationBlockProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/privacy/storage/migration/PrivateMigrationBlockProcessor.java @@ -109,7 +109,8 @@ public BlockProcessingResult processBlock( miningBeneficiary, blockHashLookup, true, - TransactionValidationParams.processingBlock()); + TransactionValidationParams.processingBlock(), + Wei.ZERO); if (result.isInvalid()) { return BlockProcessingResult.FAILED; } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java index 4f96b5c7239..d88bfa5c458 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java @@ -20,6 +20,7 @@ import org.hyperledger.besu.crypto.SignatureAlgorithm; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.chain.Blockchain; @@ -235,7 +236,10 @@ public Optional processWithWorldUpdater( new BlockHashLookup(blockHeaderToProcess, blockchain), false, transactionValidationParams, - operationTracer); + operationTracer, + protocolSpec + .getFeeMarket() + .dataPrice(blockHeaderToProcess.getExcessDataGas().orElse(DataGas.ZERO))); // If GoQuorum privacy enabled, and value = zero, get max gas possible for a PMT hash. // It is possible to have a data field that has a lower intrinsic value than the PMT hash. diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculatorTest.java index e57c3a3ee1c..56f41baf6c5 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculatorTest.java @@ -18,11 +18,8 @@ import static org.hyperledger.besu.plugin.data.TransactionType.ACCESS_LIST; import static org.hyperledger.besu.plugin.data.TransactionType.EIP1559; import static org.hyperledger.besu.plugin.data.TransactionType.FRONTIER; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; import org.hyperledger.besu.datatypes.Wei; -import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.plugin.data.TransactionType; @@ -136,9 +133,6 @@ public static Collection data() { @Test public void assertThatCalculatorWorks() { - final ProcessableBlockHeader blockHeader = mock(ProcessableBlockHeader.class); - when(blockHeader.getBaseFee()).thenReturn(baseFee); - assertThat( transactionPriceCalculator.price( Transaction.builder() @@ -149,7 +143,7 @@ public void assertThatCalculatorWorks() { .maxFeePerGas(maxFeePerGas) .chainId(BigInteger.ONE) .build(), - blockHeader.getBaseFee())) + baseFee)) .isEqualByComparingTo(expectedPrice); } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java index e5c43eb96a2..ce555391570 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessorTest.java @@ -119,7 +119,8 @@ public void shouldWarmCoinbaseIfRequested() { coinbaseAddress, blockHashLookup, false, - ImmutableTransactionValidationParams.builder().build()); + ImmutableTransactionValidationParams.builder().build(), + Wei.ZERO); assertThat(coinbaseWarmed).isTrue(); @@ -132,7 +133,8 @@ public void shouldWarmCoinbaseIfRequested() { coinbaseAddress, blockHashLookup, false, - ImmutableTransactionValidationParams.builder().build()); + ImmutableTransactionValidationParams.builder().build(), + Wei.ZERO); assertThat(coinbaseWarmed).isFalse(); } @@ -155,7 +157,8 @@ public void shouldCallTransactionValidatorWithExpectedTransactionValidationParam Address.fromHexString("1"), blockHashLookup, false, - ImmutableTransactionValidationParams.builder().build()); + ImmutableTransactionValidationParams.builder().build(), + Wei.ZERO); assertThat(txValidationParamCaptor.getValue()) .usingRecursiveComparison() diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PrivacyBlockProcessorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PrivacyBlockProcessorTest.java index 9a25a3ce226..ab18c52b68c 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PrivacyBlockProcessorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PrivacyBlockProcessorTest.java @@ -202,7 +202,7 @@ private ProtocolSpec mockProtocolSpec() { final MainnetTransactionProcessor mockPublicTransactionProcessor = mock(MainnetTransactionProcessor.class); when(mockPublicTransactionProcessor.processTransaction( - any(), any(), any(), any(), any(), any(), anyBoolean(), any())) + any(), any(), any(), any(), any(), any(), anyBoolean(), any(), any())) .thenReturn( TransactionProcessingResult.successful( Collections.emptyList(), 0, 0, Bytes.EMPTY, ValidationResult.valid())); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ZeroBaseFeeMarketTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ZeroBaseFeeMarketTest.java index 74776da3ef2..20d389d4700 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ZeroBaseFeeMarketTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ZeroBaseFeeMarketTest.java @@ -15,13 +15,10 @@ package org.hyperledger.besu.ethereum.mainnet.feemarket; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; import org.hyperledger.besu.crypto.KeyPair; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.datatypes.Wei; -import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; import org.hyperledger.besu.plugin.data.TransactionType; @@ -71,13 +68,10 @@ public void getTransactionPriceCalculatorShouldBeEIP1559() { .gasPrice(null) .createTransaction(KEY_PAIR1); - final ProcessableBlockHeader blockHeader = mock(ProcessableBlockHeader.class); - when(blockHeader.getBaseFee()).thenReturn(Optional.of(Wei.ZERO)); - assertThat( zeroBaseFeeMarket .getTransactionPriceCalculator() - .price(transaction, blockHeader.getBaseFee())) + .price(transaction, Optional.of(Wei.ZERO))) .isEqualTo(Wei.of(8)); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java index 5309ae7307e..e8b07d5d925 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java @@ -39,6 +39,7 @@ import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionValidator; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; +import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult.Status; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; @@ -539,6 +540,7 @@ private void mockProcessorStatusForTransaction( when(protocolSpec.getTransactionProcessor()).thenReturn(transactionProcessor); when(protocolSpec.getMiningBeneficiaryCalculator()).thenReturn(BlockHeader::getCoinbase); when(protocolSpec.getBlockHeaderFunctions()).thenReturn(blockHeaderFunctions); + when(protocolSpec.getFeeMarket()).thenReturn(FeeMarket.london(0)); final TransactionProcessingResult result = mock(TransactionProcessingResult.class); switch (status) { @@ -551,14 +553,32 @@ private void mockProcessorStatusForTransaction( break; } when(transactionProcessor.processTransaction( - any(), any(), any(), eq(transaction), any(), any(), anyBoolean(), any(), any())) + any(), + any(), + any(), + eq(transaction), + any(), + any(), + anyBoolean(), + any(), + any(), + any(Wei.class))) .thenReturn(result); } private void verifyTransactionWasProcessed(final Transaction expectedTransaction) { verify(transactionProcessor) .processTransaction( - any(), any(), any(), eq(expectedTransaction), any(), any(), anyBoolean(), any(), any()); + any(), + any(), + any(), + eq(expectedTransaction), + any(), + any(), + anyBoolean(), + any(), + any(), + any(Wei.class)); } private CallParameter legacyTransactionCallParameter() { diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java index 2ed207e9fee..c715a573f36 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java @@ -20,6 +20,7 @@ import static org.hyperledger.besu.ethereum.referencetests.ReferenceTestProtocolSchedules.shouldClearEmptyAccounts; import static org.hyperledger.besu.evmtool.StateTestSubCommand.COMMAND_NAME; +import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.MutableWorldState; @@ -213,7 +214,7 @@ private void traceTestSpecs(final String test, final List SPECS_PRIOR_TO_DELETING_EMPTY_ACCOUNTS = Arrays.asList("Frontier", "Homestead", "EIP150"); - private static MainnetTransactionProcessor transactionProcessor(final String name) { + private static ProtocolSpec protocolSpec(final String name) { return REFERENCE_TEST_PROTOCOL_SCHEDULES - .getByName(name) - .getByBlockHeader(BlockHeaderBuilder.createDefault().buildBlockHeader()) + .getByName(name) + .getByBlockHeader(BlockHeaderBuilder.createDefault().buildBlockHeader()) + ; + } + private static MainnetTransactionProcessor transactionProcessor(final String name) { + return protocolSpec(name) .getTransactionProcessor(); } @@ -138,6 +145,7 @@ public static void executeTest(final GeneralStateTestCaseEipSpec spec) { final MainnetTransactionProcessor processor = transactionProcessor(spec.getFork()); final WorldUpdater worldStateUpdater = worldState.updater(); final ReferenceTestBlockchain blockchain = new ReferenceTestBlockchain(blockHeader.getNumber()); + final Wei dataGasPrice = protocolSpec(spec.getFork()).getFeeMarket().dataPrice(blockHeader.getExcessDataGas().orElse(DataGas.ZERO)); final TransactionProcessingResult result = processor.processTransaction( blockchain, @@ -147,7 +155,7 @@ public static void executeTest(final GeneralStateTestCaseEipSpec spec) { blockHeader.getCoinbase(), new BlockHashLookup(blockHeader, blockchain), false, - TransactionValidationParams.processingBlock()); + TransactionValidationParams.processingBlock(), dataGasPrice); if (result.isInvalid()) { assertThat(spec.getExpectException()).isNotNull(); return; From 1f9ba3f49ec72ee7683b2946006cdbb0de859626 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Fri, 17 Feb 2023 12:39:29 +0100 Subject: [PATCH 22/27] Use actual dataPrice in BlockTransactionSelector Signed-off-by: Fabio Di Fabio --- .../blockcreation/AbstractBlockCreator.java | 18 ++++++++++-------- .../BlockTransactionSelector.java | 6 +++++- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java index e056b0cb461..82a689d78f4 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java @@ -18,7 +18,6 @@ import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; -import org.hyperledger.besu.ethereum.GasLimitCalculator; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; @@ -178,6 +177,7 @@ protected BlockCreationResult createBlock( final BlockTransactionSelector.TransactionSelectionResults transactionResults = selectTransactions( processableBlockHeader, + parentHeader, disposableWorldState, maybeTransactions, miningBeneficiary, @@ -275,6 +275,7 @@ private DataGas computeExcessDataGas( private BlockTransactionSelector.TransactionSelectionResults selectTransactions( final ProcessableBlockHeader processableBlockHeader, + final BlockHeader parentHeader, final MutableWorldState disposableWorldState, final Optional> transactions, final Address miningBeneficiary, @@ -292,6 +293,7 @@ private BlockTransactionSelector.TransactionSelectionResults selectTransactions( disposableWorldState, pendingTransactions, processableBlockHeader, + parentHeader, transactionReceiptFactory, minTransactionGasPrice, minBlockOccupancyRatio, @@ -342,13 +344,13 @@ private ProcessableBlockHeader createPendingBlockHeader( final Optional maybePrevRandao, final ProtocolSpec protocolSpec) { final long newBlockNumber = parentHeader.getNumber() + 1; - final GasLimitCalculator gasLimitCalculator = protocolSpec.getGasLimitCalculator(); - - final long gasLimit = - gasLimitCalculator.nextGasLimit( - parentHeader.getGasLimit(), - targetGasLimitSupplier.get().orElse(parentHeader.getGasLimit()), - newBlockNumber); + long gasLimit = + protocolSpec + .getGasLimitCalculator() + .nextGasLimit( + parentHeader.getGasLimit(), + targetGasLimitSupplier.get().orElse(parentHeader.getGasLimit()), + newBlockNumber); final DifficultyCalculator difficultyCalculator = protocolSpec.getDifficultyCalculator(); final BigInteger difficulty = diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java index 6c6d6d79770..fe4be0409dd 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java @@ -21,6 +21,7 @@ import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.GasLimitCalculator; import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; import org.hyperledger.besu.ethereum.core.Transaction; @@ -85,6 +86,7 @@ public class BlockTransactionSelector { private final Supplier isCancelled; private final MainnetTransactionProcessor transactionProcessor; private final ProcessableBlockHeader processableBlockHeader; + private final BlockHeader parentHeader; private final Blockchain blockchain; private final MutableWorldState worldState; private final PendingTransactions pendingTransactions; @@ -103,6 +105,7 @@ public BlockTransactionSelector( final MutableWorldState worldState, final PendingTransactions pendingTransactions, final ProcessableBlockHeader processableBlockHeader, + final BlockHeader parentHeader, final AbstractBlockProcessor.TransactionReceiptFactory transactionReceiptFactory, final Wei minTransactionGasPrice, final Double minBlockOccupancyRatio, @@ -116,6 +119,7 @@ public BlockTransactionSelector( this.worldState = worldState; this.pendingTransactions = pendingTransactions; this.processableBlockHeader = processableBlockHeader; + this.parentHeader = parentHeader; this.transactionReceiptFactory = transactionReceiptFactory; this.isCancelled = isCancelled; this.minTransactionGasPrice = minTransactionGasPrice; @@ -221,7 +225,7 @@ private TransactionSelectionResult evaluateTransaction( blockHashLookup, false, TransactionValidationParams.mining(), - Wei.ZERO); + feeMarket.dataPrice(parentHeader.getExcessDataGas().orElse(DataGas.ZERO))); } if (!effectiveResult.isInvalid()) { From b8fa8f8069727e8b53a0fd01150c6ccfdab08f25 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Fri, 17 Feb 2023 12:41:53 +0100 Subject: [PATCH 23/27] Use actual dataPrice in BlockTransactionSelector Signed-off-by: Fabio Di Fabio --- .../blockcreation/AbstractBlockCreator.java | 10 +++++-- .../BlockTransactionSelector.java | 19 ++++-------- .../AbstractBlockTransactionSelectorTest.java | 29 +++++++++++++------ ...FeeMarketBlockTransactionSelectorTest.java | 9 ++++-- .../feemarket/TransactionPriceCalculator.java | 2 -- .../mainnet/feemarket/CancunFeeMarket.java | 3 +- .../mainnet/feemarket/LondonFeeMarket.java | 9 +----- 7 files changed, 41 insertions(+), 40 deletions(-) diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java index 82a689d78f4..d5377cb8a34 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java @@ -168,6 +168,10 @@ protected BlockCreationResult createBlock( createPendingBlockHeader(timestamp, maybePrevRandao, newProtocolSpec); final Address miningBeneficiary = miningBeneficiaryCalculator.getMiningBeneficiary(processableBlockHeader.getNumber()); + final Wei dataGasPrice = + newProtocolSpec + .getFeeMarket() + .dataPrice(parentHeader.getExcessDataGas().orElse(DataGas.ZERO)); throwIfStopped(); @@ -177,10 +181,10 @@ protected BlockCreationResult createBlock( final BlockTransactionSelector.TransactionSelectionResults transactionResults = selectTransactions( processableBlockHeader, - parentHeader, disposableWorldState, maybeTransactions, miningBeneficiary, + dataGasPrice, newProtocolSpec); throwIfStopped(); @@ -275,10 +279,10 @@ private DataGas computeExcessDataGas( private BlockTransactionSelector.TransactionSelectionResults selectTransactions( final ProcessableBlockHeader processableBlockHeader, - final BlockHeader parentHeader, final MutableWorldState disposableWorldState, final Optional> transactions, final Address miningBeneficiary, + final Wei dataGasPrice, final ProtocolSpec protocolSpec) throws RuntimeException { final MainnetTransactionProcessor transactionProcessor = protocolSpec.getTransactionProcessor(); @@ -293,12 +297,12 @@ private BlockTransactionSelector.TransactionSelectionResults selectTransactions( disposableWorldState, pendingTransactions, processableBlockHeader, - parentHeader, transactionReceiptFactory, minTransactionGasPrice, minBlockOccupancyRatio, isCancelled::get, miningBeneficiary, + dataGasPrice, protocolSpec.getFeeMarket(), protocolSpec.getGasCalculator(), protocolSpec.getGasLimitCalculator()); diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java index fe4be0409dd..1f7cf4f51c5 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java @@ -17,11 +17,9 @@ import static org.hyperledger.besu.util.Slf4jLambdaHelper.traceLambda; import org.hyperledger.besu.datatypes.Address; -import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.GasLimitCalculator; import org.hyperledger.besu.ethereum.chain.Blockchain; -import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader; import org.hyperledger.besu.ethereum.core.Transaction; @@ -86,12 +84,12 @@ public class BlockTransactionSelector { private final Supplier isCancelled; private final MainnetTransactionProcessor transactionProcessor; private final ProcessableBlockHeader processableBlockHeader; - private final BlockHeader parentHeader; private final Blockchain blockchain; private final MutableWorldState worldState; private final PendingTransactions pendingTransactions; private final AbstractBlockProcessor.TransactionReceiptFactory transactionReceiptFactory; private final Address miningBeneficiary; + private final Wei dataGasPrice; private final FeeMarket feeMarket; private final GasCalculator gasCalculator; private final GasLimitCalculator gasLimitCalculator; @@ -105,12 +103,12 @@ public BlockTransactionSelector( final MutableWorldState worldState, final PendingTransactions pendingTransactions, final ProcessableBlockHeader processableBlockHeader, - final BlockHeader parentHeader, final AbstractBlockProcessor.TransactionReceiptFactory transactionReceiptFactory, final Wei minTransactionGasPrice, final Double minBlockOccupancyRatio, final Supplier isCancelled, final Address miningBeneficiary, + final Wei dataGasPrice, final FeeMarket feeMarket, final GasCalculator gasCalculator, final GasLimitCalculator gasLimitCalculator) { @@ -119,12 +117,12 @@ public BlockTransactionSelector( this.worldState = worldState; this.pendingTransactions = pendingTransactions; this.processableBlockHeader = processableBlockHeader; - this.parentHeader = parentHeader; this.transactionReceiptFactory = transactionReceiptFactory; this.isCancelled = isCancelled; this.minTransactionGasPrice = minTransactionGasPrice; this.minBlockOccupancyRatio = minBlockOccupancyRatio; this.miningBeneficiary = miningBeneficiary; + this.dataGasPrice = dataGasPrice; this.feeMarket = feeMarket; this.gasCalculator = gasCalculator; this.gasLimitCalculator = gasLimitCalculator; @@ -210,7 +208,7 @@ private TransactionSelectionResult evaluateTransaction( transaction.getHash().toHexString()); return transactionSelectionResultForInvalidResult(transaction, validationResult); } else { - // valid GoQuorum private tx, we need to hand craft the receipt and increment the nonce + // valid GoQuorum private tx, we need to handcraft the receipt and increment the nonce effectiveResult = publicResultForWhenWeHaveAPrivateTransaction(transaction); worldStateUpdater.getOrCreate(transaction.getSender()).getMutable().incrementNonce(); } @@ -225,7 +223,7 @@ private TransactionSelectionResult evaluateTransaction( blockHashLookup, false, TransactionValidationParams.mining(), - feeMarket.dataPrice(parentHeader.getExcessDataGas().orElse(DataGas.ZERO))); + dataGasPrice); } if (!effectiveResult.isInvalid()) { @@ -246,12 +244,7 @@ private TransactionSelectionResult evaluateTransaction( private boolean transactionDataPriceBelowMin(final Transaction transaction) { if (transaction.getType().supportsBlob()) { - if (transaction - .getMaxFeePerDataGas() - .orElseThrow() - .lessThan( - feeMarket.dataPrice( - processableBlockHeader.getExcessDataGas().orElse(DataGas.ZERO)))) { + if (transaction.getMaxFeePerDataGas().orElseThrow().lessThan(dataGasPrice)) { return true; } } diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java index de94b1c66d6..64861c85104 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockTransactionSelectorTest.java @@ -132,7 +132,8 @@ public void emptyPendingTransactionsResultsInEmptyVettingResult() { final Address miningBeneficiary = AddressHelpers.ofValue(1); final BlockTransactionSelector selector = - createBlockSelector(mainnetTransactionProcessor, blockHeader, Wei.ZERO, miningBeneficiary); + createBlockSelector( + mainnetTransactionProcessor, blockHeader, Wei.ZERO, miningBeneficiary, Wei.ZERO); final BlockTransactionSelector.TransactionSelectionResults results = selector.buildTransactionListForBlock(); @@ -155,7 +156,8 @@ public void failedTransactionsAreIncludedInTheBlock() { final Address miningBeneficiary = AddressHelpers.ofValue(1); final BlockTransactionSelector selector = - createBlockSelector(transactionProcessor, blockHeader, Wei.ZERO, miningBeneficiary); + createBlockSelector( + transactionProcessor, blockHeader, Wei.ZERO, miningBeneficiary, Wei.ZERO); final BlockTransactionSelector.TransactionSelectionResults results = selector.buildTransactionListForBlock(); @@ -186,7 +188,8 @@ public void invalidTransactionsTransactionProcessingAreSkippedButBlockStillFills final Address miningBeneficiary = AddressHelpers.ofValue(1); final BlockTransactionSelector selector = - createBlockSelector(transactionProcessor, blockHeader, Wei.ZERO, miningBeneficiary); + createBlockSelector( + transactionProcessor, blockHeader, Wei.ZERO, miningBeneficiary, Wei.ZERO); final BlockTransactionSelector.TransactionSelectionResults results = selector.buildTransactionListForBlock(); @@ -213,7 +216,8 @@ public void subsetOfPendingTransactionsIncludedWhenBlockGasLimitHit() { final Address miningBeneficiary = AddressHelpers.ofValue(1); final BlockTransactionSelector selector = - createBlockSelector(transactionProcessor, blockHeader, Wei.ZERO, miningBeneficiary); + createBlockSelector( + transactionProcessor, blockHeader, Wei.ZERO, miningBeneficiary, Wei.ZERO); final BlockTransactionSelector.TransactionSelectionResults results = selector.buildTransactionListForBlock(); @@ -257,6 +261,7 @@ public void useSingleGasSpaceForAllTransactions() { 0.8, this::isCancelled, miningBeneficiary, + Wei.ZERO, FeeMarket.london(0L), new LondonGasCalculator(), GasLimitCalculator.constant()); @@ -307,7 +312,8 @@ public void transactionTooLargeForBlockDoesNotPreventMoreBeingAddedIfBlockOccupa final Address miningBeneficiary = AddressHelpers.ofValue(1); final BlockTransactionSelector selector = - createBlockSelector(transactionProcessor, blockHeader, Wei.ZERO, miningBeneficiary); + createBlockSelector( + transactionProcessor, blockHeader, Wei.ZERO, miningBeneficiary, Wei.ZERO); final TransactionTestFixture txTestFixture = new TransactionTestFixture(); // Add 3 transactions to the Pending Transactions, 79% of block, 100% of block and 10% of block @@ -346,7 +352,8 @@ public void transactionSelectionStopsWhenSufficientBlockOccupancyIsReached() { final Address miningBeneficiary = AddressHelpers.ofValue(1); final BlockTransactionSelector selector = - createBlockSelector(transactionProcessor, blockHeader, Wei.ZERO, miningBeneficiary); + createBlockSelector( + transactionProcessor, blockHeader, Wei.ZERO, miningBeneficiary, Wei.ZERO); final TransactionTestFixture txTestFixture = new TransactionTestFixture(); // Add 4 transactions to the Pending Transactions 15% (ok), 79% (ok), 25% (too large), 10% @@ -394,7 +401,8 @@ public void shouldDiscardTransactionsThatFailValidation() { final Address miningBeneficiary = AddressHelpers.ofValue(1); final BlockTransactionSelector selector = - createBlockSelector(transactionProcessor, blockHeader, Wei.ZERO, miningBeneficiary); + createBlockSelector( + transactionProcessor, blockHeader, Wei.ZERO, miningBeneficiary, Wei.ZERO); final TransactionTestFixture txTestFixture = new TransactionTestFixture(); final Transaction validTransaction = @@ -429,7 +437,8 @@ public void transactionWithIncorrectNonceRemainsInPoolAndNotSelected() { final Address miningBeneficiary = AddressHelpers.ofValue(1); final BlockTransactionSelector selector = - createBlockSelector(transactionProcessor, blockHeader, Wei.ZERO, miningBeneficiary); + createBlockSelector( + transactionProcessor, blockHeader, Wei.ZERO, miningBeneficiary, Wei.ZERO); final BlockTransactionSelector.TransactionSelectionResults results = selector.buildTransactionListForBlock(); @@ -443,7 +452,8 @@ protected BlockTransactionSelector createBlockSelector( final MainnetTransactionProcessor transactionProcessor, final ProcessableBlockHeader blockHeader, final Wei minGasPrice, - final Address miningBeneficiary) { + final Address miningBeneficiary, + final Wei dataGasPrice) { final BlockTransactionSelector selector = new BlockTransactionSelector( transactionProcessor, @@ -456,6 +466,7 @@ protected BlockTransactionSelector createBlockSelector( 0.8, this::isCancelled, miningBeneficiary, + dataGasPrice, getFeeMarket(), new LondonGasCalculator(), GasLimitCalculator.constant()); diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java index 9771b2fc382..be893f49645 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/LondonFeeMarketBlockTransactionSelectorTest.java @@ -70,7 +70,8 @@ public void eip1559TransactionCurrentGasPriceLessThanMinimumIsSkippedAndKeptInTh final Address miningBeneficiary = AddressHelpers.ofValue(1); final BlockTransactionSelector selector = - createBlockSelector(transactionProcessor, blockHeader, Wei.of(6), miningBeneficiary); + createBlockSelector( + transactionProcessor, blockHeader, Wei.of(6), miningBeneficiary, Wei.ZERO); // tx is willing to pay max 6 wei for gas, but current network condition (baseFee == 1) // result in it paying 2 wei, that is below the minimum accepted by the node, so it is skipped @@ -90,7 +91,8 @@ public void eip1559TransactionCurrentGasPriceGreaterThanMinimumIsSelected() { final Address miningBeneficiary = AddressHelpers.ofValue(1); final BlockTransactionSelector selector = - createBlockSelector(transactionProcessor, blockHeader, Wei.of(6), miningBeneficiary); + createBlockSelector( + transactionProcessor, blockHeader, Wei.of(6), miningBeneficiary, Wei.ZERO); // tx is willing to pay max 6 wei for gas, and current network condition (baseFee == 5) // result in it paying the max, that is >= the minimum accepted by the node, so it is selected @@ -112,7 +114,8 @@ public void eip1559LocalTransactionCurrentGasPriceLessThanMinimumIsSelected() { final Address miningBeneficiary = AddressHelpers.ofValue(1); final BlockTransactionSelector selector = - createBlockSelector(transactionProcessor, blockHeader, Wei.of(6), miningBeneficiary); + createBlockSelector( + transactionProcessor, blockHeader, Wei.of(6), miningBeneficiary, Wei.ZERO); // tx is willing to pay max 6 wei for gas, but current network condition (baseFee == 1) // result in it paying 2 wei, that is below the minimum accepted by the node, but since it is diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculator.java index 6788ab3aeb4..f33c06c8cf3 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculator.java @@ -45,6 +45,4 @@ public Wei price(final Transaction transaction, final Optional maybeFee) { return price; } } - - class DataBlob extends EIP1559 {} } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/CancunFeeMarket.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/CancunFeeMarket.java index 5feb1f1b1ce..433ae60f14b 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/CancunFeeMarket.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/CancunFeeMarket.java @@ -18,7 +18,6 @@ import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Wei; -import org.hyperledger.besu.ethereum.core.feemarket.TransactionPriceCalculator; import java.math.BigInteger; import java.util.Optional; @@ -33,7 +32,7 @@ public class CancunFeeMarket extends LondonFeeMarket { public CancunFeeMarket( final long londonForkBlockNumber, final Optional baseFeePerGasOverride) { - super(new TransactionPriceCalculator.DataBlob(), londonForkBlockNumber, baseFeePerGasOverride); + super(londonForkBlockNumber, baseFeePerGasOverride); } @Override diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarket.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarket.java index 98b23ad1945..2a89bf1e501 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarket.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarket.java @@ -46,14 +46,7 @@ public LondonFeeMarket(final long londonForkBlockNumber) { public LondonFeeMarket( final long londonForkBlockNumber, final Optional baseFeePerGasOverride) { - this(new TransactionPriceCalculator.EIP1559(), londonForkBlockNumber, baseFeePerGasOverride); - } - - protected LondonFeeMarket( - final TransactionPriceCalculator txPriceCalculator, - final long londonForkBlockNumber, - final Optional baseFeePerGasOverride) { - this.txPriceCalculator = txPriceCalculator; + this.txPriceCalculator = new TransactionPriceCalculator.EIP1559(); this.londonForkBlockNumber = londonForkBlockNumber; this.baseFeeInitialValue = baseFeePerGasOverride.orElse(DEFAULT_BASEFEE_INITIAL_VALUE); this.baseFeeFloor = baseFeeInitialValue.isZero() ? Wei.ZERO : DEFAULT_BASEFEE_FLOOR; From 0a3730cbc1b5cf372b8d8776892abd5151e17a43 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Fri, 17 Feb 2023 14:45:55 +0100 Subject: [PATCH 24/27] Remove uneeded changes Signed-off-by: Fabio Di Fabio --- .../BlockTransactionSelector.java | 272 +++++++++--------- .../feemarket/TransactionPriceCalculator.java | 19 +- .../mainnet/feemarket/LegacyFeeMarket.java | 2 +- .../mainnet/feemarket/LondonFeeMarket.java | 2 +- .../TransactionPriceCalculatorTest.java | 4 +- ...TransactionReplacementByFeeMarketRule.java | 4 +- 6 files changed, 150 insertions(+), 153 deletions(-) diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java index 1f7cf4f51c5..a8b9055179a 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java @@ -77,6 +77,142 @@ * not cleared between executions of buildTransactionListForBlock(). */ public class BlockTransactionSelector { + public static class TransactionValidationResult { + private final Transaction transaction; + private final ValidationResult validationResult; + + public TransactionValidationResult( + final Transaction transaction, + final ValidationResult validationResult) { + this.transaction = transaction; + this.validationResult = validationResult; + } + + public Transaction getTransaction() { + return transaction; + } + + public ValidationResult getValidationResult() { + return validationResult; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TransactionValidationResult that = (TransactionValidationResult) o; + return Objects.equals(transaction, that.transaction) + && Objects.equals(validationResult, that.validationResult); + } + + @Override + public int hashCode() { + return Objects.hash(transaction, validationResult); + } + } + + public static class TransactionSelectionResults { + + private final Map> transactionsByType = new HashMap<>(); + private final List receipts = Lists.newArrayList(); + private final List invalidTransactions = Lists.newArrayList(); + private long cumulativeGasUsed = 0; + private long cumulativeDataGasUsed = 0; + + private void update( + final Transaction transaction, + final TransactionReceipt receipt, + final long gasUsed, + final long dataGasUsed) { + transactionsByType + .computeIfAbsent(transaction.getType(), type -> new ArrayList<>()) + .add(transaction); + receipts.add(receipt); + cumulativeGasUsed += gasUsed; + cumulativeDataGasUsed += dataGasUsed; + traceLambda( + LOG, + "New selected transaction {}, total transactions {}, cumulative gas used {}, cumulative data gas used {}", + transaction::toTraceLog, + () -> transactionsByType.values().stream().mapToInt(List::size).sum(), + () -> cumulativeGasUsed, + () -> cumulativeDataGasUsed); + } + + private void updateWithInvalidTransaction( + final Transaction transaction, + final ValidationResult validationResult) { + invalidTransactions.add(new TransactionValidationResult(transaction, validationResult)); + } + + public List getTransactions() { + return streamAllTransactions().collect(Collectors.toList()); + } + + public List getTransactionsByType(final TransactionType type) { + return transactionsByType.getOrDefault(type, List.of()); + } + + public List getReceipts() { + return receipts; + } + + public long getCumulativeGasUsed() { + return cumulativeGasUsed; + } + + public long getCumulativeDataGasUsed() { + return cumulativeDataGasUsed; + } + + public List getInvalidTransactions() { + return invalidTransactions; + } + + private Stream streamAllTransactions() { + return transactionsByType.values().stream().flatMap(List::stream); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TransactionSelectionResults that = (TransactionSelectionResults) o; + return cumulativeGasUsed == that.cumulativeGasUsed + && cumulativeDataGasUsed == that.cumulativeDataGasUsed + && transactionsByType.equals(that.transactionsByType) + && receipts.equals(that.receipts) + && invalidTransactions.equals(that.invalidTransactions); + } + + @Override + public int hashCode() { + return Objects.hash( + transactionsByType, + receipts, + invalidTransactions, + cumulativeGasUsed, + cumulativeDataGasUsed); + } + + public String toTraceLog() { + return "cumulativeGasUsed=" + + cumulativeGasUsed + + ", cumulativeDataGasUsed=" + + cumulativeDataGasUsed + + ", transactions=" + + streamAllTransactions().map(Transaction::toTraceLog).collect(Collectors.joining("; ")); + } + } + private static final Logger LOG = LoggerFactory.getLogger(BlockTransactionSelector.class); private final Wei minTransactionGasPrice; @@ -395,140 +531,4 @@ private boolean blockOccupancyAboveThreshold() { occupancyRatio); return occupancyRatio >= minBlockOccupancyRatio; } - - public static class TransactionValidationResult { - private final Transaction transaction; - private final ValidationResult validationResult; - - public TransactionValidationResult( - final Transaction transaction, - final ValidationResult validationResult) { - this.transaction = transaction; - this.validationResult = validationResult; - } - - public Transaction getTransaction() { - return transaction; - } - - public ValidationResult getValidationResult() { - return validationResult; - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - TransactionValidationResult that = (TransactionValidationResult) o; - return Objects.equals(transaction, that.transaction) - && Objects.equals(validationResult, that.validationResult); - } - - @Override - public int hashCode() { - return Objects.hash(transaction, validationResult); - } - } - - public static class TransactionSelectionResults { - - private final Map> transactionsByType = new HashMap<>(); - private final List receipts = Lists.newArrayList(); - private final List invalidTransactions = Lists.newArrayList(); - private long cumulativeGasUsed = 0; - private long cumulativeDataGasUsed = 0; - - private void update( - final Transaction transaction, - final TransactionReceipt receipt, - final long gasUsed, - final long dataGasUsed) { - transactionsByType - .computeIfAbsent(transaction.getType(), type -> new ArrayList<>()) - .add(transaction); - receipts.add(receipt); - cumulativeGasUsed += gasUsed; - cumulativeDataGasUsed += dataGasUsed; - traceLambda( - LOG, - "New selected transaction {}, total transactions {}, cumulative gas used {}, cumulative data gas used {}", - transaction::toTraceLog, - () -> transactionsByType.values().stream().mapToInt(List::size).sum(), - () -> cumulativeGasUsed, - () -> cumulativeDataGasUsed); - } - - private void updateWithInvalidTransaction( - final Transaction transaction, - final ValidationResult validationResult) { - invalidTransactions.add(new TransactionValidationResult(transaction, validationResult)); - } - - public List getTransactions() { - return streamAllTransactions().collect(Collectors.toList()); - } - - public List getTransactionsByType(final TransactionType type) { - return transactionsByType.getOrDefault(type, List.of()); - } - - public List getReceipts() { - return receipts; - } - - public long getCumulativeGasUsed() { - return cumulativeGasUsed; - } - - public long getCumulativeDataGasUsed() { - return cumulativeDataGasUsed; - } - - public List getInvalidTransactions() { - return invalidTransactions; - } - - private Stream streamAllTransactions() { - return transactionsByType.values().stream().flatMap(List::stream); - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - TransactionSelectionResults that = (TransactionSelectionResults) o; - return cumulativeGasUsed == that.cumulativeGasUsed - && cumulativeDataGasUsed == that.cumulativeDataGasUsed - && transactionsByType.equals(that.transactionsByType) - && receipts.equals(that.receipts) - && invalidTransactions.equals(that.invalidTransactions); - } - - @Override - public int hashCode() { - return Objects.hash( - transactionsByType, - receipts, - invalidTransactions, - cumulativeGasUsed, - cumulativeDataGasUsed); - } - - public String toTraceLog() { - return "cumulativeGasUsed=" - + cumulativeGasUsed - + ", cumulativeDataGasUsed=" - + cumulativeDataGasUsed - + ", transactions=" - + streamAllTransactions().map(Transaction::toTraceLog).collect(Collectors.joining("; ")); - } - } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculator.java index f33c06c8cf3..b68da184006 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculator.java @@ -19,20 +19,17 @@ import java.util.Optional; +@FunctionalInterface public interface TransactionPriceCalculator { - Wei price(Transaction transaction, Optional maybeFee); + Wei price(Transaction transaction, Optional baseFee); - class Frontier implements TransactionPriceCalculator { - @Override - public Wei price(final Transaction transaction, final Optional maybeFee) { - return transaction.getGasPrice().orElse(Wei.ZERO); - } + static TransactionPriceCalculator frontier() { + return (transaction, baseFee) -> transaction.getGasPrice().orElse(Wei.ZERO); } - class EIP1559 implements TransactionPriceCalculator { - @Override - public Wei price(final Transaction transaction, final Optional maybeFee) { - final Wei baseFee = maybeFee.orElseThrow(); + static TransactionPriceCalculator eip1559() { + return (transaction, maybeBaseFee) -> { + final Wei baseFee = maybeBaseFee.orElseThrow(); if (!transaction.getType().supports1559FeeMarket()) { return transaction.getGasPrice().orElse(Wei.ZERO); } @@ -43,6 +40,6 @@ public Wei price(final Transaction transaction, final Optional maybeFee) { price = maxFeePerGas; } return price; - } + }; } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LegacyFeeMarket.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LegacyFeeMarket.java index ec328d29824..8e73ec2948c 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LegacyFeeMarket.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LegacyFeeMarket.java @@ -22,7 +22,7 @@ public class LegacyFeeMarket implements FeeMarket { private final TransactionPriceCalculator txPriceCalculator; public LegacyFeeMarket() { - this.txPriceCalculator = new TransactionPriceCalculator.Frontier(); + this.txPriceCalculator = TransactionPriceCalculator.frontier(); } @Override diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarket.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarket.java index 2a89bf1e501..6f454b464eb 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarket.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarket.java @@ -46,7 +46,7 @@ public LondonFeeMarket(final long londonForkBlockNumber) { public LondonFeeMarket( final long londonForkBlockNumber, final Optional baseFeePerGasOverride) { - this.txPriceCalculator = new TransactionPriceCalculator.EIP1559(); + this.txPriceCalculator = TransactionPriceCalculator.eip1559(); this.londonForkBlockNumber = londonForkBlockNumber; this.baseFeeInitialValue = baseFeePerGasOverride.orElse(DEFAULT_BASEFEE_INITIAL_VALUE); this.baseFeeFloor = baseFeeInitialValue.isZero() ? Wei.ZERO : DEFAULT_BASEFEE_FLOOR; diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculatorTest.java index 56f41baf6c5..3caa7234908 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculatorTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/feemarket/TransactionPriceCalculatorTest.java @@ -37,9 +37,9 @@ public class TransactionPriceCalculatorTest { private static final TransactionPriceCalculator FRONTIER_CALCULATOR = - new TransactionPriceCalculator.Frontier(); + TransactionPriceCalculator.frontier(); private static final TransactionPriceCalculator EIP_1559_CALCULATOR = - new TransactionPriceCalculator.EIP1559(); + TransactionPriceCalculator.eip1559(); private final TransactionPriceCalculator transactionPriceCalculator; private final TransactionType transactionType; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionReplacementByFeeMarketRule.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionReplacementByFeeMarketRule.java index 1c2bd84c027..e89cc4600cd 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionReplacementByFeeMarketRule.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/TransactionReplacementByFeeMarketRule.java @@ -24,9 +24,9 @@ public class TransactionReplacementByFeeMarketRule implements TransactionPoolReplacementRule { private static final TransactionPriceCalculator FRONTIER_CALCULATOR = - new TransactionPriceCalculator.Frontier(); + TransactionPriceCalculator.frontier(); private static final TransactionPriceCalculator EIP1559_CALCULATOR = - new TransactionPriceCalculator.EIP1559(); + TransactionPriceCalculator.eip1559(); private final Percentage priceBump; public TransactionReplacementByFeeMarketRule(final Percentage priceBump) { From 457ef1e131a476bd32fa27591e6c6e6c915a4303 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Fri, 17 Feb 2023 15:11:39 +0100 Subject: [PATCH 25/27] Fixes Signed-off-by: Fabio Di Fabio --- .../mainnet/MainnetTransactionProcessor.java | 2 +- .../vm/GeneralStateReferenceTestTools.java | 9 +++---- .../gascalculator/CancunGasCalculator.java | 24 +++++++++---------- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java index 42179878fda..37cc2b37126 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionProcessor.java @@ -260,7 +260,7 @@ public TransactionProcessingResult processTransaction( } public TransactionProcessingResult processTransaction( - final Blockchain blockchain, + final Blockchain ignoredBlockchain, final WorldUpdater worldState, final ProcessableBlockHeader blockHeader, final Transaction transaction, diff --git a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/GeneralStateReferenceTestTools.java b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/GeneralStateReferenceTestTools.java index 4170e3faf77..0d83de50356 100644 --- a/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/GeneralStateReferenceTestTools.java +++ b/ethereum/referencetests/src/reference-test/java/org/hyperledger/besu/ethereum/vm/GeneralStateReferenceTestTools.java @@ -51,16 +51,17 @@ public class GeneralStateReferenceTestTools { private static final List SPECS_PRIOR_TO_DELETING_EMPTY_ACCOUNTS = Arrays.asList("Frontier", "Homestead", "EIP150"); + private static MainnetTransactionProcessor transactionProcessor(final String name) { + return protocolSpec(name) + .getTransactionProcessor(); + } + private static ProtocolSpec protocolSpec(final String name) { return REFERENCE_TEST_PROTOCOL_SCHEDULES .getByName(name) .getByBlockHeader(BlockHeaderBuilder.createDefault().buildBlockHeader()) ; } - private static MainnetTransactionProcessor transactionProcessor(final String name) { - return protocolSpec(name) - .getTransactionProcessor(); - } private static final List EIPS_TO_RUN; diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java index 3ccc78b1c32..b78e765cc8b 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculator.java @@ -19,6 +19,7 @@ * *
    *
  • Gas costs for TSTORE/TLOAD + *
  • Data gas for EIP-4844 *
*/ public class CancunGasCalculator extends LondonGasCalculator { @@ -26,8 +27,8 @@ public class CancunGasCalculator extends LondonGasCalculator { private static final long TLOAD_GAS = WARM_STORAGE_READ_COST; private static final long TSTORE_GAS = WARM_STORAGE_READ_COST; - private static final long CANCUN_DATA_GAS_PER_BLOB = 1 << 17; - private static final long CANCUN_TARGET_DATA_GAS_PER_BLOCK = 1 << 18; + private static final long DATA_GAS_PER_BLOB = 1 << 17; + private static final long TARGET_DATA_GAS_PER_BLOCK = 1 << 18; // EIP-1153 @Override @@ -40,22 +41,19 @@ public long getTransientStoreOperationGasCost() { return TSTORE_GAS; } - /** - * Compute the new excess data gas for the block, using the parent value and the number of new - * blobs - * - * @param parentExcessDataGas the excess data gas value from the parent block - * @param newBlobs the number of blobs in the new block - * @return the new excess data gas value - */ + @Override + public long dataGasCost(final int blobCount) { + return DATA_GAS_PER_BLOB * blobCount; + } + @Override public long computeExcessDataGas(final long parentExcessDataGas, final int newBlobs) { - final long consumedDataGas = CANCUN_DATA_GAS_PER_BLOB * newBlobs; + final long consumedDataGas = dataGasCost(newBlobs); final long currentExcessDataGas = parentExcessDataGas + consumedDataGas; - if (currentExcessDataGas < CANCUN_TARGET_DATA_GAS_PER_BLOCK) { + if (currentExcessDataGas < TARGET_DATA_GAS_PER_BLOCK) { return 0L; } - return currentExcessDataGas - CANCUN_TARGET_DATA_GAS_PER_BLOCK; + return currentExcessDataGas - TARGET_DATA_GAS_PER_BLOCK; } } From cec997f5d490578ced3e8aae70db328ce7cbc018 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Fri, 17 Feb 2023 16:23:01 +0100 Subject: [PATCH 26/27] Always get the excessDataGas from the parent to calculate dataGasPrice Signed-off-by: Fabio Di Fabio --- .../jsonrpc/internal/processor/BlockReplay.java | 16 ++++++++++++++-- .../internal/processor/TransactionTracer.java | 6 +++++- .../transaction/TransactionSimulator.java | 12 +++++++++--- .../besu/evmtool/StateTestSubCommand.java | 7 ++++--- .../vm/GeneralStateReferenceTestTools.java | 9 +++++---- 5 files changed, 37 insertions(+), 13 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockReplay.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockReplay.java index 89e11d42bdd..8516c71eb7e 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockReplay.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/BlockReplay.java @@ -56,7 +56,13 @@ public Optional block( block.getBody(), (body, header, blockchain, mutableWorldState, transactionProcessor, protocolSpec) -> { final Wei dataGasPrice = - protocolSpec.getFeeMarket().dataPrice(header.getExcessDataGas().orElse(DataGas.ZERO)); + protocolSpec + .getFeeMarket() + .dataPrice( + blockchain + .getBlockHeader(header.getParentHash()) + .flatMap(BlockHeader::getExcessDataGas) + .orElse(DataGas.ZERO)); final List transactionTraces = body.getTransactions().stream() @@ -86,7 +92,13 @@ public Optional beforeTransactionInBlock( (body, header, blockchain, mutableWorldState, transactionProcessor, protocolSpec) -> { final BlockHashLookup blockHashLookup = new BlockHashLookup(header, blockchain); final Wei dataGasPrice = - protocolSpec.getFeeMarket().dataPrice(header.getExcessDataGas().orElse(DataGas.ZERO)); + protocolSpec + .getFeeMarket() + .dataPrice( + blockchain + .getBlockHeader(header.getParentHash()) + .flatMap(BlockHeader::getExcessDataGas) + .orElse(DataGas.ZERO)); for (final Transaction transaction : body.getTransactions()) { if (transaction.getHash().equals(transactionHash)) { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracer.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracer.java index 335f12269e7..aa7aae9106f 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracer.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/processor/TransactionTracer.java @@ -110,7 +110,11 @@ public List traceTransactionToFile( final Wei dataGasPrice = protocolSpec .getFeeMarket() - .dataPrice(header.getExcessDataGas().orElse(DataGas.ZERO)); + .dataPrice( + blockchain + .getBlockHeader(header.getParentHash()) + .flatMap(BlockHeader::getExcessDataGas) + .orElse(DataGas.ZERO)); for (int i = 0; i < body.getTransactions().size(); i++) { ((StackedUpdater) stackedUpdater).markTransactionBoundary(); final Transaction transaction = body.getTransactions().get(i); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java index d88bfa5c458..fab12cf58e9 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java @@ -223,6 +223,14 @@ public Optional processWithWorldUpdater( return Optional.empty(); } + final Optional maybeParentHeader = + blockchain.getBlockHeader(blockHeaderToProcess.getParentHash()); + final Wei dataGasPrice = + protocolSpec + .getFeeMarket() + .dataPrice( + maybeParentHeader.flatMap(BlockHeader::getExcessDataGas).orElse(DataGas.ZERO)); + final Transaction transaction = maybeTransaction.get(); final TransactionProcessingResult result = transactionProcessor.processTransaction( @@ -237,9 +245,7 @@ public Optional processWithWorldUpdater( false, transactionValidationParams, operationTracer, - protocolSpec - .getFeeMarket() - .dataPrice(blockHeaderToProcess.getExcessDataGas().orElse(DataGas.ZERO))); + dataGasPrice); // If GoQuorum privacy enabled, and value = zero, get max gas possible for a PMT hash. // It is possible to have a data field that has a lower intrinsic value than the PMT hash. diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java index c715a573f36..cae53cbc29d 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/StateTestSubCommand.java @@ -22,6 +22,7 @@ import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.Transaction; @@ -220,6 +221,8 @@ private void traceTestSpecs(final String test, final List EIPS_TO_RUN; @@ -146,7 +145,8 @@ public static void executeTest(final GeneralStateTestCaseEipSpec spec) { final MainnetTransactionProcessor processor = transactionProcessor(spec.getFork()); final WorldUpdater worldStateUpdater = worldState.updater(); final ReferenceTestBlockchain blockchain = new ReferenceTestBlockchain(blockHeader.getNumber()); - final Wei dataGasPrice = protocolSpec(spec.getFork()).getFeeMarket().dataPrice(blockHeader.getExcessDataGas().orElse(DataGas.ZERO)); + // Todo: EIP-4844 use the excessDataGas of the parent instead of DataGas.ZERO + final Wei dataGasPrice = protocolSpec(spec.getFork()).getFeeMarket().dataPrice(DataGas.ZERO); final TransactionProcessingResult result = processor.processTransaction( blockchain, @@ -156,7 +156,8 @@ public static void executeTest(final GeneralStateTestCaseEipSpec spec) { blockHeader.getCoinbase(), new BlockHashLookup(blockHeader, blockchain), false, - TransactionValidationParams.processingBlock(), dataGasPrice); + TransactionValidationParams.processingBlock(), + dataGasPrice); if (result.isInvalid()) { assertThat(spec.getExpectException()).isNotNull(); return; From 641de9e575df818a2fc9aa8a605b12a6ca52e448 Mon Sep 17 00:00:00 2001 From: Fabio Di Fabio Date: Fri, 17 Feb 2023 16:33:36 +0100 Subject: [PATCH 27/27] TOTAL_DATA_GAS_TOO_HIGH json rpc error Signed-off-by: Fabio Di Fabio --- .../besu/ethereum/api/jsonrpc/JsonRpcErrorConverter.java | 2 ++ .../ethereum/api/jsonrpc/internal/response/JsonRpcError.java | 1 + 2 files changed, 3 insertions(+) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcErrorConverter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcErrorConverter.java index 37831775606..4f3777fc3d5 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcErrorConverter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcErrorConverter.java @@ -67,6 +67,8 @@ public static JsonRpcError convertTransactionInvalidReason( return JsonRpcError.NONCE_TOO_FAR_IN_FUTURE_FOR_SENDER; case LOWER_NONCE_INVALID_TRANSACTION_EXISTS: return JsonRpcError.LOWER_NONCE_INVALID_TRANSACTION_EXISTS; + case TOTAL_DATA_GAS_TOO_HIGH: + return JsonRpcError.TOTAL_DATA_GAS_TOO_HIGH; default: return JsonRpcError.INVALID_PARAMS; } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcError.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcError.java index 8349f93afd6..ef205ecea27 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcError.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/JsonRpcError.java @@ -77,6 +77,7 @@ public enum JsonRpcError { -32000, "Transaction nonce is too distant from current sender nonce"), LOWER_NONCE_INVALID_TRANSACTION_EXISTS( -32000, "An invalid transaction with a lower nonce exists"), + TOTAL_DATA_GAS_TOO_HIGH(-32000, "Total data gas too high"), // Execution engine failures UNKNOWN_PAYLOAD(-32001, "Payload does not exist / is not available"),