diff --git a/CHANGELOG.md b/CHANGELOG.md index cfef1d8e50d..bad5945a611 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ ### Additions and Improvements - Add RPC HTTP options to specify custom truststore and its password [#7978](https://github.com/hyperledger/besu/pull/7978) - Retrieve all transaction receipts for a block in one request [#6646](https://github.com/hyperledger/besu/pull/6646) +- Implement EIP-7840: Add blob schedule to config files [#8042](https://github.com/hyperledger/besu/pull/8042) ### Bug fixes diff --git a/acceptance-tests/tests/src/test/resources/dev/dev_prague.json b/acceptance-tests/tests/src/test/resources/dev/dev_prague.json index 942edc4e70a..7a7b56d9508 100644 --- a/acceptance-tests/tests/src/test/resources/dev/dev_prague.json +++ b/acceptance-tests/tests/src/test/resources/dev/dev_prague.json @@ -15,6 +15,20 @@ "terminalTotalDifficulty":0, "cancunTime":0, "pragueTime":0, + "blobSchedule": { + "cancun": { + "target": 3, + "max": 6 + }, + "prague": { + "target": 6, + "max": 9 + }, + "osaka": { + "target": 9, + "max": 12 + } + }, "clique": { "period": 5, "epoch": 30000 diff --git a/config/src/main/java/org/hyperledger/besu/config/BlobScheduleOptions.java b/config/src/main/java/org/hyperledger/besu/config/BlobScheduleOptions.java new file mode 100644 index 00000000000..1ad458fa398 --- /dev/null +++ b/config/src/main/java/org/hyperledger/besu/config/BlobScheduleOptions.java @@ -0,0 +1,137 @@ +/* + * 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.config; + +import java.util.Map; +import java.util.Optional; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.common.collect.ImmutableMap; + +/** The Blob Schedule config options. */ +public class BlobScheduleOptions { + + private final ObjectNode blobScheduleOptionsConfigRoot; + + private static final String CANCUN_KEY = "cancun"; + private static final String PRAGUE_KEY = "prague"; + private static final String OSAKA_KEY = "osaka"; + + /** + * Instantiates a new Blob Schedule config options. + * + * @param blobScheduleConfigRoot the blob schedule config root + */ + public BlobScheduleOptions(final ObjectNode blobScheduleConfigRoot) { + this.blobScheduleOptionsConfigRoot = blobScheduleConfigRoot; + } + + /** + * Gets cancun blob schedule. + * + * @return the cancun blob schedule + */ + public Optional getCancun() { + return JsonUtil.getObjectNode(blobScheduleOptionsConfigRoot, CANCUN_KEY).map(BlobSchedule::new); + } + + /** + * Gets prague blob schedule. + * + * @return the prague blob schedule + */ + public Optional getPrague() { + return JsonUtil.getObjectNode(blobScheduleOptionsConfigRoot, PRAGUE_KEY).map(BlobSchedule::new); + } + + /** + * Gets osaka blob schedule. + * + * @return the osaka blob schedule + */ + public Optional getOsaka() { + return JsonUtil.getObjectNode(blobScheduleOptionsConfigRoot, OSAKA_KEY).map(BlobSchedule::new); + } + + /** + * As map. + * + * @return the map + */ + public Map asMap() { + final ImmutableMap.Builder builder = ImmutableMap.builder(); + getCancun().ifPresent(bs -> builder.put(CANCUN_KEY, bs.asMap())); + getPrague().ifPresent(bs -> builder.put(PRAGUE_KEY, bs.asMap())); + getOsaka().ifPresent(bs -> builder.put(OSAKA_KEY, bs.asMap())); + return builder.build(); + } + + /** The Blob schedule for a particular fork. */ + public static class BlobSchedule { + private final int target; + private final int max; + + /** The constant CANCUN_DEFAULT. */ + public static final BlobSchedule CANCUN_DEFAULT = new BlobSchedule(3, 6); + + /** The constant PRAGUE_DEFAULT. */ + public static final BlobSchedule PRAGUE_DEFAULT = new BlobSchedule(6, 9); + + /** The constant OSAKA_DEFAULT. */ + public static final BlobSchedule OSAKA_DEFAULT = new BlobSchedule(9, 12); + + /** + * Instantiates a new Blob schedule. + * + * @param blobScheduleConfigRoot the blob schedule config root + */ + public BlobSchedule(final ObjectNode blobScheduleConfigRoot) { + this.target = JsonUtil.getInt(blobScheduleConfigRoot, "target").orElseThrow(); + this.max = JsonUtil.getInt(blobScheduleConfigRoot, "max").orElseThrow(); + } + + private BlobSchedule(final int target, final int max) { + this.target = target; + this.max = max; + } + + /** + * Gets target. + * + * @return the target + */ + public int getTarget() { + return target; + } + + /** + * Gets max. + * + * @return the max + */ + public int getMax() { + return max; + } + + /** + * As map. + * + * @return the map + */ + Map asMap() { + return Map.of("target", target, "max", max); + } + } +} diff --git a/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java index e2458c93247..877f17de416 100644 --- a/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/GenesisConfigOptions.java @@ -546,4 +546,11 @@ default boolean isConsensusMigration() { * @return the consolidation request contract address */ Optional
getConsolidationRequestContractAddress(); + + /** + * The blob schedule is a list of hardfork names and their associated target and max blob values. + * + * @return the blob schedule + */ + Optional getBlobScheduleOptions(); } diff --git a/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java index 51f85f0ec82..9239d4977e8 100644 --- a/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/JsonGenesisConfigOptions.java @@ -47,6 +47,7 @@ public class JsonGenesisConfigOptions implements GenesisConfigOptions { private static final String TRANSITIONS_CONFIG_KEY = "transitions"; private static final String DISCOVERY_CONFIG_KEY = "discovery"; private static final String CHECKPOINT_CONFIG_KEY = "checkpoint"; + private static final String BLOB_SCHEDULE_CONFIG_KEY = "blobschedule"; private static final String ZERO_BASE_FEE_KEY = "zerobasefee"; private static final String FIXED_BASE_FEE_KEY = "fixedbasefee"; private static final String WITHDRAWAL_REQUEST_CONTRACT_ADDRESS_KEY = @@ -199,6 +200,12 @@ public EthashConfigOptions getEthashConfigOptions() { .orElse(EthashConfigOptions.DEFAULT); } + @Override + public Optional getBlobScheduleOptions() { + return JsonUtil.getObjectNode(configRoot, BLOB_SCHEDULE_CONFIG_KEY) + .map(BlobScheduleOptions::new); + } + @Override public TransitionsConfigOptions getTransitions() { return transitions; @@ -537,6 +544,10 @@ public Map asMap() { builder.put("fixedBaseFee", true); } + if (getBlobScheduleOptions().isPresent()) { + builder.put("blobSchedule", getBlobScheduleOptions().get().asMap()); + } + return builder.build(); } diff --git a/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java b/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java index c9c8dad7954..2f6e6897a94 100644 --- a/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java +++ b/config/src/main/java/org/hyperledger/besu/config/StubGenesisConfigOptions.java @@ -472,6 +472,11 @@ public Optional
getConsolidationRequestContractAddress() { return Optional.empty(); } + @Override + public Optional getBlobScheduleOptions() { + return Optional.empty(); + } + /** * Homestead block stub genesis config options. * diff --git a/config/src/main/resources/mainnet.json b/config/src/main/resources/mainnet.json index ab35a5aba35..5a0fd8d725f 100644 --- a/config/src/main/resources/mainnet.json +++ b/config/src/main/resources/mainnet.json @@ -16,6 +16,16 @@ "terminalTotalDifficulty": 58750000000000000000000, "shanghaiTime": 1681338455, "cancunTime": 1710338135, + "blobSchedule": { + "cancun": { + "target": 3, + "max": 6 + }, + "prague": { + "target": 6, + "max": 9 + } + }, "ethash": { }, "discovery": { diff --git a/config/src/test/java/org/hyperledger/besu/config/BlobScheduleOptionsTest.java b/config/src/test/java/org/hyperledger/besu/config/BlobScheduleOptionsTest.java new file mode 100644 index 00000000000..fc746362929 --- /dev/null +++ b/config/src/test/java/org/hyperledger/besu/config/BlobScheduleOptionsTest.java @@ -0,0 +1,41 @@ +/* + * 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.config; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +public class BlobScheduleOptionsTest { + + @Test + public void blobScheduleIsParsed() { + final GenesisConfig genesisConfigFile = + GenesisConfig.fromResource("/mainnet_with_blob_schedule.json"); + final GenesisConfigOptions configOptions = genesisConfigFile.getConfigOptions(); + + assertThat(configOptions.getBlobScheduleOptions()).isNotEmpty(); + final BlobScheduleOptions blobScheduleOptions = configOptions.getBlobScheduleOptions().get(); + assertThat(blobScheduleOptions.getCancun()).isNotEmpty(); + assertThat(blobScheduleOptions.getCancun().get().getTarget()).isEqualTo(4); + assertThat(blobScheduleOptions.getCancun().get().getMax()).isEqualTo(7); + assertThat(blobScheduleOptions.getPrague()).isNotEmpty(); + assertThat(blobScheduleOptions.getPrague().get().getTarget()).isEqualTo(7); + assertThat(blobScheduleOptions.getPrague().get().getMax()).isEqualTo(10); + assertThat(blobScheduleOptions.getOsaka()).isNotEmpty(); + assertThat(blobScheduleOptions.getOsaka().get().getTarget()).isEqualTo(10); + assertThat(blobScheduleOptions.getOsaka().get().getMax()).isEqualTo(13); + } +} diff --git a/config/src/test/java/org/hyperledger/besu/config/GenesisConfigOptionsTest.java b/config/src/test/java/org/hyperledger/besu/config/GenesisConfigOptionsTest.java index 9b09362851f..16622f35c21 100644 --- a/config/src/test/java/org/hyperledger/besu/config/GenesisConfigOptionsTest.java +++ b/config/src/test/java/org/hyperledger/besu/config/GenesisConfigOptionsTest.java @@ -408,6 +408,46 @@ void asMapIncludesConsolidationRequestContractAddress() { .containsValue(Address.ZERO); } + @SuppressWarnings("unchecked") + @Test + void asMapIncludesBlobFeeSchedule() { + final GenesisConfigOptions config = + GenesisConfig.fromConfig( + "{\n" + + " \"config\": {\n" + + " \"blobSchedule\": {\n" + + " \"cancun\": {\n" + + " \"target\": 1,\n" + + " \"max\": 2\n" + + " },\n" + + " \"prague\": {\n" + + " \"target\": 3,\n" + + " \"max\": 4\n" + + " },\n" + + " \"osaka\": {\n" + + " \"target\": 4,\n" + + " \"max\": 5\n" + + " }\n" + + " }\n" + + " }\n" + + "}") + .getConfigOptions(); + + final Map map = config.asMap(); + assertThat(map).containsOnlyKeys("blobSchedule"); + final Map blobSchedule = (Map) map.get("blobSchedule"); + assertThat(blobSchedule).containsOnlyKeys("cancun", "prague", "osaka"); + assertThat((Map) blobSchedule.get("cancun")) + .containsOnlyKeys("target", "max") + .containsValues(1, 2); + assertThat((Map) blobSchedule.get("prague")) + .containsOnlyKeys("target", "max") + .containsValues(3, 4); + assertThat((Map) blobSchedule.get("osaka")) + .containsOnlyKeys("target", "max") + .containsValues(4, 5); + } + private GenesisConfigOptions fromConfigOptions(final Map configOptions) { final ObjectNode rootNode = JsonUtil.createEmptyObjectNode(); final ObjectNode options = JsonUtil.objectNodeFromMap(configOptions); diff --git a/config/src/test/resources/mainnet_with_blob_schedule.json b/config/src/test/resources/mainnet_with_blob_schedule.json new file mode 100644 index 00000000000..b313a7dbabe --- /dev/null +++ b/config/src/test/resources/mainnet_with_blob_schedule.json @@ -0,0 +1,37 @@ +{ + "config": { + "chainId": 3151908, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "preMergeForkBlock": 0, + "terminalTotalDifficulty": 0, + "ethash": {}, + "shanghaiTime": 0, + "cancunTime": 0, + "blobSchedule": { + "cancun": { + "target": 4, + "max": 7 + }, + "prague": { + "target": 7, + "max": 10 + }, + "osaka": { + "target": 10, + "max": 13 + } + }, + "depositContractAddress": "0x4242424242424242424242424242424242424242", + "pragueTime": 1734106711, + "osakaTime": 1734107095 + } +} \ No newline at end of file diff --git a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlobSizeTransactionSelector.java b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlobSizeTransactionSelector.java index 9a4c83e9625..d5fd4212ec4 100644 --- a/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlobSizeTransactionSelector.java +++ b/ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/txselection/selectors/BlobSizeTransactionSelector.java @@ -61,7 +61,8 @@ public TransactionSelectionResult evaluateTransactionPreProcessing( if (remainingBlobGas == 0) { LOG.atTrace() - .setMessage("The block already contains the max number of allowed blobs") + .setMessage( + "The block already contains the max number of allowed blobs, pending tx: {}") .addArgument(evaluationContext.getPendingTransaction()::toTraceLog) .log(); return TransactionSelectionResult.BLOBS_FULL; 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 7c15d6229c0..0d1a09511a5 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 @@ -17,8 +17,11 @@ /** The GasLimitCalculator interface defines methods for calculating the gas limit. */ public interface GasLimitCalculator { - /** The constant BLOB_GAS_LIMIT represents the gas limit for blob data. */ - long BLOB_GAS_LIMIT = 786432; + /** + * The constant BLOB_GAS_LIMIT represents the gas limit for blob data. Defaults to the Cancun + * value where it was first introduced as part of EIP-4844 + */ + long BLOB_GAS_LIMIT = 0xC0000; /** * Calculates the next gas limit based on the current gas limit, target gas limit, and new block 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 7dd1be481f6..707abda32a6 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 @@ -15,17 +15,33 @@ package org.hyperledger.besu.ethereum.mainnet; import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; +import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; public class CancunTargetingGasLimitCalculator extends LondonTargetingGasLimitCalculator { - private static final long MAX_BLOB_GAS_PER_BLOCK = 786432L; + + /** The mainnet default maximum number of blobs per block for Cancun */ + private static final int DEFAULT_MAX_BLOBS_PER_BLOCK_CANCUN = 6; + + private final long maxBlobGasPerBlock; public CancunTargetingGasLimitCalculator( final long londonForkBlock, final BaseFeeMarket feeMarket) { + this(londonForkBlock, feeMarket, DEFAULT_MAX_BLOBS_PER_BLOCK_CANCUN); + } + + /** + * Using Cancun mainnet default of 6 blobs for maxBlobsPerBlock: getBlobGasPerBlob() * 6 blobs = + * 131072 * 6 = 786432 = 0xC0000 + */ + public CancunTargetingGasLimitCalculator( + final long londonForkBlock, final BaseFeeMarket feeMarket, final int maxBlobsPerBlock) { super(londonForkBlock, feeMarket); + final CancunGasCalculator cancunGasCalculator = new CancunGasCalculator(); + this.maxBlobGasPerBlock = cancunGasCalculator.getBlobGasPerBlob() * maxBlobsPerBlock; } @Override public long currentBlobGasLimit() { - return MAX_BLOB_GAS_PER_BLOCK; + return maxBlobGasPerBlock; } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidator.java index 0598c817bd0..79927d28cf9 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetBlockHeaderValidator.java @@ -33,9 +33,10 @@ import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.ProofOfWorkValidationRule; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.TimestampBoundedByFutureParameter; import org.hyperledger.besu.ethereum.mainnet.headervalidationrules.TimestampMoreRecentThanParent; -import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; import java.util.Optional; +import java.util.function.Supplier; import com.google.common.annotations.VisibleForTesting; import org.apache.tuweni.bytes.Bytes; @@ -197,8 +198,9 @@ public static BlockHeaderValidator.Builder mergeBlockHeaderValidator(final FeeMa .addRule(new IncrementalTimestampRule()); } - public static BlockHeaderValidator.Builder cancunBlockHeaderValidator(final FeeMarket feeMarket) { + public static BlockHeaderValidator.Builder blobAwareBlockHeaderValidator( + final FeeMarket feeMarket, final Supplier gasCalculator) { return mergeBlockHeaderValidator(feeMarket) - .addRule(new BlobGasValidationRule(new CancunGasCalculator())); + .addRule(new BlobGasValidationRule(gasCalculator.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 26c9e69c8f5..024b67a0b34 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 @@ -16,6 +16,7 @@ import static org.hyperledger.besu.ethereum.mainnet.requests.MainnetRequestsProcessor.pragueRequestsProcessors; +import org.hyperledger.besu.config.BlobScheduleOptions; import org.hyperledger.besu.config.GenesisConfigOptions; import org.hyperledger.besu.config.PowAlgorithm; import org.hyperledger.besu.crypto.SignatureAlgorithm; @@ -56,6 +57,7 @@ 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.GasCalculator; import org.hyperledger.besu.evm.gascalculator.HomesteadGasCalculator; import org.hyperledger.besu.evm.gascalculator.IstanbulGasCalculator; import org.hyperledger.besu.evm.gascalculator.LondonGasCalculator; @@ -683,6 +685,15 @@ static ProtocolSpecBuilder cancunDefinition( FeeMarket.cancun(londonForkBlockNumber, genesisConfigOptions.getBaseFeePerGas()); } + final var cancunBlobSchedule = + genesisConfigOptions + .getBlobScheduleOptions() + .flatMap(BlobScheduleOptions::getCancun) + .orElse(BlobScheduleOptions.BlobSchedule.CANCUN_DEFAULT); + + final java.util.function.Supplier cancunGasCalcSupplier = + () -> new CancunGasCalculator(cancunBlobSchedule.getTarget()); + return shanghaiDefinition( chainId, enableRevertReason, @@ -693,12 +704,12 @@ static ProtocolSpecBuilder cancunDefinition( metricsSystem) .feeMarket(cancunFeeMarket) // gas calculator for EIP-4844 blob gas - .gasCalculator(CancunGasCalculator::new) + .gasCalculator(cancunGasCalcSupplier) // gas limit with EIP-4844 max blob gas per block .gasLimitCalculatorBuilder( feeMarket -> new CancunTargetingGasLimitCalculator( - londonForkBlockNumber, (BaseFeeMarket) feeMarket)) + londonForkBlockNumber, (BaseFeeMarket) feeMarket, cancunBlobSchedule.getMax())) // EVM changes to support EIP-1153: TSTORE and EIP-5656: MCOPY .evmBuilder( (gasCalculator, jdCacheConfig) -> @@ -739,7 +750,10 @@ static ProtocolSpecBuilder cancunDefinition( TransactionType.BLOB), evm.getMaxInitcodeSize())) .precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::cancun) - .blockHeaderValidatorBuilder(MainnetBlockHeaderValidator::cancunBlockHeaderValidator) + .blockHeaderValidatorBuilder( + fm -> + MainnetBlockHeaderValidator.blobAwareBlockHeaderValidator( + fm, cancunGasCalcSupplier)) .blockHashProcessor(new CancunBlockHashProcessor()) .name("Cancun"); } @@ -753,6 +767,12 @@ static ProtocolSpecBuilder cancunEOFDefinition( final boolean isParallelTxProcessingEnabled, final MetricsSystem metricsSystem) { + final var cancunBlobSchedule = + genesisConfigOptions + .getBlobScheduleOptions() + .flatMap(BlobScheduleOptions::getCancun) + .orElse(BlobScheduleOptions.BlobSchedule.CANCUN_DEFAULT); + ProtocolSpecBuilder protocolSpecBuilder = cancunDefinition( chainId, @@ -762,7 +782,14 @@ static ProtocolSpecBuilder cancunEOFDefinition( miningConfiguration, isParallelTxProcessingEnabled, metricsSystem); - return addEOF(chainId, evmConfiguration, protocolSpecBuilder).name("CancunEOF"); + return addEOF( + genesisConfigOptions, + chainId, + evmConfiguration, + protocolSpecBuilder, + cancunBlobSchedule.getTarget(), + cancunBlobSchedule.getMax()) + .name("CancunEOF"); } static ProtocolSpecBuilder pragueDefinition( @@ -777,6 +804,17 @@ static ProtocolSpecBuilder pragueDefinition( RequestContractAddresses requestContractAddresses = RequestContractAddresses.fromGenesis(genesisConfigOptions); + final long londonForkBlockNumber = genesisConfigOptions.getLondonBlockNumber().orElse(0L); + final var pragueBlobSchedule = + genesisConfigOptions + .getBlobScheduleOptions() + .flatMap(BlobScheduleOptions::getPrague) + .orElse(BlobScheduleOptions.BlobSchedule.PRAGUE_DEFAULT); + + // EIP-3074 AUTH and AUTHCALL gas | EIP-7840 Blob schedule | EIP-7691 6/9 blob increase + final java.util.function.Supplier pragueGasCalcSupplier = + () -> new PragueGasCalculator(pragueBlobSchedule.getTarget()); + return cancunDefinition( chainId, enableRevertReason, @@ -785,8 +823,12 @@ static ProtocolSpecBuilder pragueDefinition( miningConfiguration, isParallelTxProcessingEnabled, metricsSystem) - // EIP-3074 AUTH and AUTCALL gas - .gasCalculator(PragueGasCalculator::new) + .gasCalculator(pragueGasCalcSupplier) + // EIP-7840 Blob schedule | EIP-7691 6/9 blob increase + .gasLimitCalculatorBuilder( + feeMarket -> + new PragueTargetingGasLimitCalculator( + londonForkBlockNumber, (BaseFeeMarket) feeMarket, pragueBlobSchedule.getMax())) // EIP-3074 AUTH and AUTHCALL .evmBuilder( (gasCalculator, jdCacheConfig) -> @@ -818,6 +860,14 @@ static ProtocolSpecBuilder pragueDefinition( TransactionType.DELEGATE_CODE), evm.getMaxInitcodeSize())) + // TODO SLD EIP-7840 Can we dynamically wire in the appropriate GasCalculator instead of + // overriding + // blockHeaderValidatorBuilder every time the GasCalculator changes? + // EIP-7840 blob schedule | EIP-7691 6/9 blob increase + .blockHeaderValidatorBuilder( + fm -> + MainnetBlockHeaderValidator.blobAwareBlockHeaderValidator( + fm, pragueGasCalcSupplier)) // EIP-2935 Blockhash processor .blockHashProcessor(new PragueBlockHashProcessor()) .name("Prague"); @@ -832,6 +882,12 @@ static ProtocolSpecBuilder osakaDefinition( final boolean isParallelTxProcessingEnabled, final MetricsSystem metricsSystem) { + final var osakaBlobSchedule = + genesisConfigOptions + .getBlobScheduleOptions() + .flatMap(BlobScheduleOptions::getOsaka) + .orElse(BlobScheduleOptions.BlobSchedule.OSAKA_DEFAULT); + ProtocolSpecBuilder protocolSpecBuilder = pragueDefinition( chainId, @@ -841,16 +897,34 @@ static ProtocolSpecBuilder osakaDefinition( miningConfiguration, isParallelTxProcessingEnabled, metricsSystem); - return addEOF(chainId, evmConfiguration, protocolSpecBuilder).name("Osaka"); + return addEOF( + genesisConfigOptions, + chainId, + evmConfiguration, + protocolSpecBuilder, + osakaBlobSchedule.getTarget(), + osakaBlobSchedule.getMax()) + .name("Osaka"); } private static ProtocolSpecBuilder addEOF( + final GenesisConfigOptions genesisConfigOptions, final Optional chainId, final EvmConfiguration evmConfiguration, - final ProtocolSpecBuilder protocolSpecBuilder) { + final ProtocolSpecBuilder protocolSpecBuilder, + final int targetBlobsPerBlock, + final int maxBlobsPerBlock) { + + final long londonForkBlockNumber = genesisConfigOptions.getLondonBlockNumber().orElse(0L); + final java.util.function.Supplier osakaGasCalcSupplier = + () -> new OsakaGasCalculator(targetBlobsPerBlock); return protocolSpecBuilder // EIP-7692 EOF v1 Gas calculator - .gasCalculator(OsakaGasCalculator::new) + .gasCalculator(osakaGasCalcSupplier) + .gasLimitCalculatorBuilder( + feeMarket -> + new OsakaTargetingGasLimitCalculator( + londonForkBlockNumber, (BaseFeeMarket) feeMarket, maxBlobsPerBlock)) // EIP-7692 EOF v1 EVM and opcodes .evmBuilder( (gasCalculator, jdCacheConfig) -> @@ -863,7 +937,11 @@ private static ProtocolSpecBuilder addEOF( true, List.of(MaxCodeSizeRule.from(evm), EOFValidationCodeRule.from(evm)), 1, - SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES)); + SPURIOUS_DRAGON_FORCE_DELETE_WHEN_EMPTY_ADDRESSES)) + .blockHeaderValidatorBuilder( + fm -> + MainnetBlockHeaderValidator.blobAwareBlockHeaderValidator( + fm, osakaGasCalcSupplier)); } static ProtocolSpecBuilder futureEipsDefinition( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/OsakaTargetingGasLimitCalculator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/OsakaTargetingGasLimitCalculator.java new file mode 100644 index 00000000000..903cce27dff --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/OsakaTargetingGasLimitCalculator.java @@ -0,0 +1,37 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.mainnet; + +import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; + +public class OsakaTargetingGasLimitCalculator extends PragueTargetingGasLimitCalculator { + + /** The mainnet default maximum number of blobs per block for Osaka */ + private static final int DEFAULT_MAX_BLOBS_PER_BLOCK_OSAKA = 12; + + public OsakaTargetingGasLimitCalculator( + final long londonForkBlock, final BaseFeeMarket feeMarket) { + super(londonForkBlock, feeMarket, DEFAULT_MAX_BLOBS_PER_BLOCK_OSAKA); + } + + /** + * Using Osaka mainnet default of 12 blobs for maxBlobsPerBlock: + * CancunGasCalculator.BLOB_GAS_PER_BLOB * 12 blobs = 131072 * 12 = 1572864 = 0x180000 + */ + public OsakaTargetingGasLimitCalculator( + final long londonForkBlock, final BaseFeeMarket feeMarket, final int maxBlobsPerBlock) { + super(londonForkBlock, feeMarket, maxBlobsPerBlock); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/PragueTargetingGasLimitCalculator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/PragueTargetingGasLimitCalculator.java new file mode 100644 index 00000000000..b7574c3f3db --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/PragueTargetingGasLimitCalculator.java @@ -0,0 +1,37 @@ +/* + * Copyright contributors to Hyperledger Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.mainnet; + +import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; + +public class PragueTargetingGasLimitCalculator extends CancunTargetingGasLimitCalculator { + + /** The mainnet default maximum number of blobs per block for Prague */ + private static final int DEFAULT_MAX_BLOBS_PER_BLOCK_PRAGUE = 9; + + public PragueTargetingGasLimitCalculator( + final long londonForkBlock, final BaseFeeMarket feeMarket) { + super(londonForkBlock, feeMarket, DEFAULT_MAX_BLOBS_PER_BLOCK_PRAGUE); + } + + /** + * Using Prague mainnet default of 9 blobs for maxBlobsPerBlock: + * CancunGasCalculator.BLOB_GAS_PER_BLOB * 9 blobs = 131072 * 9 = 1179648 = 0x120000 + */ + public PragueTargetingGasLimitCalculator( + final long londonForkBlock, final BaseFeeMarket feeMarket, final int maxBlobsPerBlock) { + super(londonForkBlock, feeMarket, maxBlobsPerBlock); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ExcessBlobGasCalculator.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ExcessBlobGasCalculator.java index b483e4292ca..f6372097b7f 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ExcessBlobGasCalculator.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/ExcessBlobGasCalculator.java @@ -36,8 +36,7 @@ public static BlobGas calculateExcessBlobGasForParent( .getGasCalculator() .computeExcessBlobGas( parentHeader.getExcessBlobGas().map(BlobGas::toLong).orElse(0L), - parentHeader.getBlobGasUsed().orElse(0L), - parentHeader.getTargetBlobsPerBlock()); + parentHeader.getBlobGasUsed().orElse(0L)); return BlobGas.of(headerExcess); } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/BlobGasValidationRule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/BlobGasValidationRule.java index 2f24d618326..c986ec08588 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/BlobGasValidationRule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/BlobGasValidationRule.java @@ -44,8 +44,7 @@ public boolean validate(final BlockHeader header, final BlockHeader parent) { long parentBlobGasUsed = parent.getBlobGasUsed().orElse(0L); long calculatedExcessBlobGas = - gasCalculator.computeExcessBlobGas( - parentExcessBlobGas, parentBlobGasUsed, parent.getTargetBlobsPerBlock()); + gasCalculator.computeExcessBlobGas(parentExcessBlobGas, parentBlobGasUsed); if (headerExcessBlobGas != calculatedExcessBlobGas) { LOG.info( diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/CancunTargetingGasLimitCalculatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/CancunTargetingGasLimitCalculatorTest.java new file mode 100644 index 00000000000..c732aeafb75 --- /dev/null +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/CancunTargetingGasLimitCalculatorTest.java @@ -0,0 +1,33 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.mainnet; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; + +import java.util.Optional; + +import org.junit.jupiter.api.Test; + +class CancunTargetingGasLimitCalculatorTest { + + @Test + void currentBlobGasLimitIs6Blobs() { + var cancunTargetingGasLimitCalculator = + new CancunTargetingGasLimitCalculator(0L, FeeMarket.cancun(0L, Optional.empty())); + assertThat(cancunTargetingGasLimitCalculator.currentBlobGasLimit()).isEqualTo(0xC0000); + } +} diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PragueTargetingGasLimitCalculatorTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PragueTargetingGasLimitCalculatorTest.java new file mode 100644 index 00000000000..e85b89bdfec --- /dev/null +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/PragueTargetingGasLimitCalculatorTest.java @@ -0,0 +1,33 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.mainnet; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; + +import java.util.Optional; + +import org.junit.jupiter.api.Test; + +class PragueTargetingGasLimitCalculatorTest { + + @Test + void currentBlobGasLimitIs9BlobsByDefault() { + var pragueTargetingGasLimitCalculator = + new PragueTargetingGasLimitCalculator(0L, FeeMarket.cancun(0L, Optional.empty())); + assertThat(pragueTargetingGasLimitCalculator.currentBlobGasLimit()).isEqualTo(0x120000); + } +} diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/BlobGasValidationRuleTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/BlobGasValidationRuleTest.java index d14089e0b0f..c188f38d937 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/BlobGasValidationRuleTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/headervalidationrules/BlobGasValidationRuleTest.java @@ -22,7 +22,6 @@ import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; import org.hyperledger.besu.evm.gascalculator.PragueGasCalculator; -import org.apache.tuweni.units.bigints.UInt64; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -88,16 +87,17 @@ public void validateHeader_BlobGasDifferentFromCalculated_FailsValidation() { } /** - * Prague EIP-7742 - Tests that the header blob gas matches the calculated blob gas and passes + * Prague EIP-7840 - Tests that the header blob gas matches the calculated blob gas and passes * validation. */ @Test - public void validateHeader_BlobGasMatchesCalculated_SuccessValidation_Prague_Target3() { + public void validateHeader_BlobGasMatchesCalculated_SuccessValidation_Prague() { + long target = pragueGasCalculator.getTargetBlobGasPerBlock(); + // Create parent header final BlockHeaderTestFixture parentBuilder = new BlockHeaderTestFixture(); parentBuilder.excessBlobGas(BlobGas.of(1L)); - parentBuilder.blobGasUsed(pragueGasCalculator.blobGasCost(3)); - parentBuilder.targetBlobsPerBlock(UInt64.valueOf(3)); + parentBuilder.blobGasUsed(target); final BlockHeader parentHeader = parentBuilder.buildHeader(); // Create block header with matching excessBlobGas @@ -109,23 +109,23 @@ public void validateHeader_BlobGasMatchesCalculated_SuccessValidation_Prague_Tar } /** - * Prague EIP-7742 - Tests that the header blob gas matches the calculated blob gas and passes - * validation. + * Prague EIP-7840 - Tests that the header blob gas is different from the calculated blob gas and + * fails validation. */ @Test - public void validateHeader_BlobGasMatchesCalculated_SuccessValidation_Prague_Target4() { + public void validateHeader_BlobGasDifferentFromCalculated_FailsValidation_Prague() { + long target = pragueGasCalculator.getTargetBlobGasPerBlock(); + // Create parent header final BlockHeaderTestFixture parentBuilder = new BlockHeaderTestFixture(); parentBuilder.excessBlobGas(BlobGas.of(1L)); - parentBuilder.blobGasUsed(pragueGasCalculator.blobGasCost(4)); - parentBuilder.targetBlobsPerBlock(UInt64.valueOf(4)); + parentBuilder.blobGasUsed(target); final BlockHeader parentHeader = parentBuilder.buildHeader(); - // Create block header with matching excessBlobGas + // Create block header with different excessBlobGas final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture(); - headerBuilder.excessBlobGas(BlobGas.of(1L)); final BlockHeader header = headerBuilder.buildHeader(); - assertThat(pragueBlobGasValidationRule.validate(header, parentHeader)).isTrue(); + assertThat(pragueBlobGasValidationRule.validate(header, parentHeader)).isFalse(); } } 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 2d6168322ec..6a44bbc1d0e 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 @@ -26,18 +26,35 @@ */ public class CancunGasCalculator extends ShanghaiGasCalculator { + /** The default mainnet target blobs per block for Cancun */ + private static final int DEFAULT_TARGET_BLOBS_PER_BLOCK_CANCUN = 3; + + /** this.getBlobGasPerBlob() * 3 blobs = 131072 * 6 = 393216 = 0x60000 */ + private final long targetBlobGasPerBlock; + /** Instantiates a new Cancun Gas Calculator. */ public CancunGasCalculator() { - this(KZG_POINT_EVAL.toArrayUnsafe()[19]); + this(KZG_POINT_EVAL.toArrayUnsafe()[19], DEFAULT_TARGET_BLOBS_PER_BLOCK_CANCUN); + } + + /** + * Instantiates a new Cancun Gas Calculator + * + * @param targetBlobsPerBlock the target blobs per block + */ + public CancunGasCalculator(final int targetBlobsPerBlock) { + this(KZG_POINT_EVAL.toArrayUnsafe()[19], targetBlobsPerBlock); } /** * Instantiates a new Cancun Gas Calculator * * @param maxPrecompile the max precompile + * @param targetBlobsPerBlock the target blobs per block */ - protected CancunGasCalculator(final int maxPrecompile) { + protected CancunGasCalculator(final int maxPrecompile, final int targetBlobsPerBlock) { super(maxPrecompile); + this.targetBlobGasPerBlock = getBlobGasPerBlob() * targetBlobsPerBlock; } private static final long TLOAD_GAS = WARM_STORAGE_READ_COST; @@ -49,9 +66,6 @@ protected CancunGasCalculator(final int maxPrecompile) { */ private static final long BLOB_GAS_PER_BLOB = 1 << 17; - /** The target blob gas per block. */ - static final long TARGET_BLOB_GAS_PER_BLOCK = 0x60000; - // EIP-1153 @Override public long getTransientLoadOperationGasCost() { @@ -79,6 +93,15 @@ public long getBlobGasPerBlob() { * @return The target blob gas per block. */ public long getTargetBlobGasPerBlock() { - return TARGET_BLOB_GAS_PER_BLOCK; + return targetBlobGasPerBlock; + } + + @Override + public long computeExcessBlobGas(final long parentExcessBlobGas, final long parentBlobGasUsed) { + final long currentExcessBlobGas = parentExcessBlobGas + parentBlobGasUsed; + if (currentExcessBlobGas < targetBlobGasPerBlock) { + return 0L; + } + return currentExcessBlobGas - targetBlobGasPerBlock; } } 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 9859d1dd7d7..8192bd1af88 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 @@ -40,12 +40,10 @@ import org.hyperledger.besu.evm.processor.AbstractMessageProcessor; import java.util.List; -import java.util.Optional; import java.util.function.Supplier; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.units.bigints.UInt256; -import org.apache.tuweni.units.bigints.UInt64; /** * Provides various gas cost lookups and calculations used during block processing. @@ -636,30 +634,14 @@ default long blobGasCost(final long blobCount) { } /** - * Compute the new value for the excess blob gas, given the parent value, the parent blob gas used - * and the parent target blobs per block, if present. Used from Cancun onwards. Presence of - * parentTargetBlobsPerBlock implies EIP-7442/Prague enabled. Default to Cancun constant target - * gas value if parentTargetBlobsPerBlock is not present. + * Compute the new value for the excess blob gas, given the parent value and the blob gas used * * @param parentExcessBlobGas excess blob gas from the parent - * @param parentBlobGasUsed blob gas used from the parent - * @param parentTargetBlobsPerBlock the optional target blobs per block from the parent + * @param blobGasUsed blob gas used * @return the new excess blob gas value */ - default long computeExcessBlobGas( - final long parentExcessBlobGas, - final long parentBlobGasUsed, - final Optional parentTargetBlobsPerBlock) { - final long parentTargetBlobGas = - parentTargetBlobsPerBlock - .map(blobCount -> blobGasCost(blobCount.toLong())) - .orElse(CancunGasCalculator.TARGET_BLOB_GAS_PER_BLOCK); - final long currentExcessBlobGas = parentExcessBlobGas + parentBlobGasUsed; - - if (currentExcessBlobGas < parentTargetBlobGas) { - return 0L; - } - return currentExcessBlobGas - parentTargetBlobGas; + default long computeExcessBlobGas(final long parentExcessBlobGas, final long blobGasUsed) { + return 0L; } /** diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/OsakaGasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/OsakaGasCalculator.java index b4155dac52a..de56430f00f 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/OsakaGasCalculator.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/OsakaGasCalculator.java @@ -17,10 +17,9 @@ import static org.hyperledger.besu.datatypes.Address.BLS12_MAP_FP2_TO_G2; /** - * Gas Calculator for Prague + * Gas Calculator for Osaka * - *

Placeholder for new gas schedule items. If Prague finalzies without changes this can be - * removed + *

Placeholder for new gas schedule items. If Osaka finalzies without changes this can be removed * *

    *
  • TBD @@ -28,21 +27,34 @@ */ public class OsakaGasCalculator extends PragueGasCalculator { + /** The default mainnet target blobs per block for Osaka */ + private static final int DEFAULT_TARGET_BLOBS_PER_BLOCK_OSAKA = 9; + static final long MIN_RETAINED_GAS = 5_000; static final long MIN_CALLEE_GAS = 2300; - /** Instantiates a new Prague Gas Calculator. */ + /** Instantiates a new Osaka Gas Calculator. */ public OsakaGasCalculator() { - this(BLS12_MAP_FP2_TO_G2.toArrayUnsafe()[19]); + this(BLS12_MAP_FP2_TO_G2.toArrayUnsafe()[19], DEFAULT_TARGET_BLOBS_PER_BLOCK_OSAKA); + } + + /** + * Instantiates a new Osaka Gas Calculator + * + * @param targetBlobsPerBlock the target blobs per block + */ + public OsakaGasCalculator(final int targetBlobsPerBlock) { + this(BLS12_MAP_FP2_TO_G2.toArrayUnsafe()[19], targetBlobsPerBlock); } /** - * Instantiates a new Prague Gas Calculator + * Instantiates a new Osaka Gas Calculator * * @param maxPrecompile the max precompile + * @param targetBlobsPerBlock the target blobs per block */ - protected OsakaGasCalculator(final int maxPrecompile) { - super(maxPrecompile); + protected OsakaGasCalculator(final int maxPrecompile, final int targetBlobsPerBlock) { + super(maxPrecompile, targetBlobsPerBlock); } @Override diff --git a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/PragueGasCalculator.java b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/PragueGasCalculator.java index 666292e9e10..268a58061c7 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/PragueGasCalculator.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/gascalculator/PragueGasCalculator.java @@ -28,18 +28,34 @@ public class PragueGasCalculator extends CancunGasCalculator { final long existingAccountGasRefund; + /** + * The default mainnet target blobs per block for Prague getBlobGasPerBlob() * 6 blobs = 131072 * + * 6 = 786432 = 0xC0000 + */ + private static final int DEFAULT_TARGET_BLOBS_PER_BLOCK_PRAGUE = 6; + /** Instantiates a new Prague Gas Calculator. */ public PragueGasCalculator() { - this(BLS12_MAP_FP2_TO_G2.toArrayUnsafe()[19]); + this(BLS12_MAP_FP2_TO_G2.toArrayUnsafe()[19], DEFAULT_TARGET_BLOBS_PER_BLOCK_PRAGUE); + } + + /** + * Instantiates a new Prague Gas Calculator + * + * @param targetBlobsPerBlock the target blobs per block + */ + public PragueGasCalculator(final int targetBlobsPerBlock) { + this(BLS12_MAP_FP2_TO_G2.toArrayUnsafe()[19], targetBlobsPerBlock); } /** * Instantiates a new Prague Gas Calculator * * @param maxPrecompile the max precompile + * @param targetBlobsPerBlock the target blobs per block */ - protected PragueGasCalculator(final int maxPrecompile) { - super(maxPrecompile); + protected PragueGasCalculator(final int maxPrecompile, final int targetBlobsPerBlock) { + super(maxPrecompile, targetBlobsPerBlock); this.existingAccountGasRefund = newAccountGasCost() - CodeDelegation.PER_AUTH_BASE_COST; } diff --git a/evm/src/test/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculatorTest.java b/evm/src/test/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculatorTest.java index b7a11395a9e..02cb9fd1754 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculatorTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/gascalculator/CancunGasCalculatorTest.java @@ -17,7 +17,6 @@ import static org.assertj.core.api.Assertions.assertThat; import java.util.List; -import java.util.Optional; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; @@ -28,6 +27,7 @@ @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class CancunGasCalculatorTest { + private static final long TARGET_BLOB_GAS_PER_BLOCK_CANCUN = 0x60000; private final CancunGasCalculator cancunGasCalculator = new CancunGasCalculator(); @ParameterizedTest(name = "{index} - parent gas {0}, used gas {1}, new excess {2}") @@ -35,13 +35,12 @@ public class CancunGasCalculatorTest { public void shouldCalculateExcessBlobGasCorrectly( final long parentExcess, final long used, final long expected) { final long usedBlobGas = cancunGasCalculator.blobGasCost(used); - assertThat( - cancunGasCalculator.computeExcessBlobGas(parentExcess, usedBlobGas, Optional.empty())) + assertThat(cancunGasCalculator.computeExcessBlobGas(parentExcess, usedBlobGas)) .isEqualTo(expected); } Iterable blobGasses() { - long targetGasPerBlock = CancunGasCalculator.TARGET_BLOB_GAS_PER_BLOCK; + long targetGasPerBlock = TARGET_BLOB_GAS_PER_BLOCK_CANCUN; return List.of( Arguments.of(0L, 0L, 0L), Arguments.of(targetGasPerBlock, 0L, 0L), diff --git a/evm/src/test/java/org/hyperledger/besu/evm/gascalculator/OsakaGasCalculatorTest.java b/evm/src/test/java/org/hyperledger/besu/evm/gascalculator/OsakaGasCalculatorTest.java index 3236c13e833..28ead82f8aa 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/gascalculator/OsakaGasCalculatorTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/gascalculator/OsakaGasCalculatorTest.java @@ -18,10 +18,20 @@ import org.hyperledger.besu.datatypes.Address; +import java.util.List; + import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) class OsakaGasCalculatorTest { + private static final long TARGET_BLOB_GAS_PER_BLOCK_OSAKA = 0x120000; + private final OsakaGasCalculator osakaGasCalculator = new OsakaGasCalculator(); + @Test void testPrecompileSize() { OsakaGasCalculator subject = new OsakaGasCalculator(); @@ -32,10 +42,35 @@ void testPrecompileSize() { @Test void testNewConstants() { CancunGasCalculator cancunGas = new CancunGasCalculator(); - OsakaGasCalculator praugeGasCalculator = new OsakaGasCalculator(); + assertThat(osakaGasCalculator.getMinCalleeGas()).isGreaterThan(cancunGas.getMinCalleeGas()); + assertThat(osakaGasCalculator.getMinRetainedGas()).isGreaterThan(cancunGas.getMinRetainedGas()); + } + + @ParameterizedTest( + name = "{index} - parent gas {0}, used gas {1}, blob target {2} new excess {3}") + @MethodSource("blobGasses") + public void shouldCalculateExcessBlobGasCorrectly( + final long parentExcess, final long used, final long expected) { + final long usedBlobGas = osakaGasCalculator.blobGasCost(used); + assertThat(osakaGasCalculator.computeExcessBlobGas(parentExcess, usedBlobGas)) + .isEqualTo(expected); + } + + Iterable blobGasses() { + long nineBlobTargetGas = TARGET_BLOB_GAS_PER_BLOCK_OSAKA; + long newTargetCount = 9; - assertThat(praugeGasCalculator.getMinCalleeGas()).isGreaterThan(cancunGas.getMinCalleeGas()); - assertThat(praugeGasCalculator.getMinRetainedGas()) - .isGreaterThan(cancunGas.getMinRetainedGas()); + return List.of( + // New target count + Arguments.of(0L, 0L, 0L), + Arguments.of(nineBlobTargetGas, 0L, 0L), + Arguments.of(newTargetCount, 0L, 0L), + Arguments.of(0L, newTargetCount, 0L), + Arguments.of(1L, newTargetCount, 1L), + Arguments.of( + osakaGasCalculator.blobGasCost(newTargetCount), + 1L, + osakaGasCalculator.getBlobGasPerBlob()), + Arguments.of(nineBlobTargetGas, newTargetCount, nineBlobTargetGas)); } } diff --git a/evm/src/test/java/org/hyperledger/besu/evm/gascalculator/PragueGasCalculatorTest.java b/evm/src/test/java/org/hyperledger/besu/evm/gascalculator/PragueGasCalculatorTest.java index 0b9d0f2372a..fdacad0e84e 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/gascalculator/PragueGasCalculatorTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/gascalculator/PragueGasCalculatorTest.java @@ -19,9 +19,7 @@ import org.hyperledger.besu.datatypes.Address; import java.util.List; -import java.util.Optional; -import org.apache.tuweni.units.bigints.UInt64; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.params.ParameterizedTest; @@ -31,6 +29,7 @@ @TestInstance(TestInstance.Lifecycle.PER_CLASS) class PragueGasCalculatorTest { + private static final long TARGET_BLOB_GAS_PER_BLOCK_PRAGUE = 0xC0000; private final PragueGasCalculator pragueGasCalculator = new PragueGasCalculator(); @Test @@ -44,39 +43,27 @@ void testPrecompileSize() { name = "{index} - parent gas {0}, used gas {1}, blob target {2} new excess {3}") @MethodSource("blobGasses") public void shouldCalculateExcessBlobGasCorrectly( - final long parentExcess, final long used, final long target, final long expected) { + final long parentExcess, final long used, final long expected) { final long usedBlobGas = pragueGasCalculator.blobGasCost(used); - assertThat( - pragueGasCalculator.computeExcessBlobGas( - parentExcess, usedBlobGas, Optional.of(UInt64.valueOf(target)))) + assertThat(pragueGasCalculator.computeExcessBlobGas(parentExcess, usedBlobGas)) .isEqualTo(expected); } Iterable blobGasses() { - long threeBlobTargetGas = CancunGasCalculator.TARGET_BLOB_GAS_PER_BLOCK; - long cancunTargetCount = 3; - long newTargetCount = 4; + long sixBlobTargetGas = TARGET_BLOB_GAS_PER_BLOCK_PRAGUE; + long newTargetCount = 6; return List.of( - // If blob target count remains at 3 - Arguments.of(0L, 0L, cancunTargetCount, 0L), - Arguments.of(threeBlobTargetGas, 0L, cancunTargetCount, 0L), - Arguments.of(0L, cancunTargetCount, cancunTargetCount, 0L), - Arguments.of(1L, cancunTargetCount, cancunTargetCount, 1L), - Arguments.of( - threeBlobTargetGas, 1L, cancunTargetCount, pragueGasCalculator.getBlobGasPerBlob()), - Arguments.of(threeBlobTargetGas, 3L, cancunTargetCount, threeBlobTargetGas), // New target count - Arguments.of(0L, 0L, newTargetCount, 0L), - Arguments.of(threeBlobTargetGas, 0L, newTargetCount, 0L), - Arguments.of(newTargetCount, 0L, newTargetCount, 0L), - Arguments.of(0L, newTargetCount, newTargetCount, 0L), - Arguments.of(1L, newTargetCount, newTargetCount, 1L), + Arguments.of(0L, 0L, 0L), + Arguments.of(sixBlobTargetGas, 0L, 0L), + Arguments.of(newTargetCount, 0L, 0L), + Arguments.of(0L, newTargetCount, 0L), + Arguments.of(1L, newTargetCount, 1L), Arguments.of( pragueGasCalculator.blobGasCost(newTargetCount), 1L, - newTargetCount, pragueGasCalculator.getBlobGasPerBlob()), - Arguments.of(threeBlobTargetGas, newTargetCount, newTargetCount, threeBlobTargetGas)); + Arguments.of(sixBlobTargetGas, newTargetCount, sixBlobTargetGas)); } }