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 024b67a0b34..60e766b6673 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 @@ -815,6 +815,18 @@ static ProtocolSpecBuilder pragueDefinition( final java.util.function.Supplier pragueGasCalcSupplier = () -> new PragueGasCalculator(pragueBlobSchedule.getTarget()); + final BaseFeeMarket pragueFeeMarket; + if (genesisConfigOptions.isZeroBaseFee()) { + pragueFeeMarket = FeeMarket.zeroBaseFee(londonForkBlockNumber); + } else if (genesisConfigOptions.isFixedBaseFee()) { + pragueFeeMarket = + FeeMarket.fixedBaseFee( + londonForkBlockNumber, miningConfiguration.getMinTransactionGasPrice()); + } else { + pragueFeeMarket = + FeeMarket.cancun(londonForkBlockNumber, genesisConfigOptions.getBaseFeePerGas()); + } + return cancunDefinition( chainId, enableRevertReason, @@ -823,6 +835,7 @@ static ProtocolSpecBuilder pragueDefinition( miningConfiguration, isParallelTxProcessingEnabled, metricsSystem) + .feeMarket(pragueFeeMarket) .gasCalculator(pragueGasCalcSupplier) // EIP-7840 Blob schedule | EIP-7691 6/9 blob increase .gasLimitCalculatorBuilder( 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 ab46beadca5..e8642aef9cd 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 @@ -25,7 +25,7 @@ public class CancunFeeMarket extends LondonFeeMarket { private static final Logger LOG = LoggerFactory.getLogger(CancunFeeMarket.class); - private static final BigInteger BLOB_GAS_PRICE = BigInteger.ONE; + protected static final BigInteger BLOB_GAS_PRICE = BigInteger.ONE; private static final BigInteger BLOB_GAS_PRICE_UPDATE_FRACTION = BigInteger.valueOf(3338477); public CancunFeeMarket( @@ -53,7 +53,7 @@ public Wei blobGasPricePerGas(final BlobGas excessBlobGas) { return blobGasPrice; } - private BigInteger fakeExponential( + protected BigInteger fakeExponential( final BigInteger factor, final BigInteger numerator, final BigInteger denominator) { int i = 1; BigInteger output = BigInteger.ZERO; 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 fc5defbd105..05f97647b77 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 @@ -49,6 +49,11 @@ static BaseFeeMarket cancun( return new CancunFeeMarket(londonForkBlockNumber, baseFeePerGasOverride); } + static BaseFeeMarket prague( + final long londonForkBlockNumber, final Optional baseFeePerGasOverride) { + return new PragueFeeMarket(londonForkBlockNumber, baseFeePerGasOverride); + } + static BaseFeeMarket zeroBaseFee(final long londonForkBlockNumber) { return new ZeroBaseFeeMarket(londonForkBlockNumber); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/PragueFeeMarket.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/PragueFeeMarket.java new file mode 100644 index 00000000000..cff7cde0040 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/PragueFeeMarket.java @@ -0,0 +1,52 @@ +/* + * 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.feemarket; + +import org.hyperledger.besu.datatypes.BlobGas; +import org.hyperledger.besu.datatypes.Wei; + +import java.math.BigInteger; +import java.util.Optional; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PragueFeeMarket extends CancunFeeMarket { + private static final BigInteger BLOB_BASE_FEE_UPDATE_FRACTION_ELECTRA = + BigInteger.valueOf(5007716); + private static final Logger LOG = LoggerFactory.getLogger(PragueFeeMarket.class); + + public PragueFeeMarket( + final long londonForkBlockNumber, final Optional baseFeePerGasOverride) { + super(londonForkBlockNumber, baseFeePerGasOverride); + } + + @Override + public Wei blobGasPricePerGas(final BlobGas excessBlobGas) { + final var blobGasPrice = + Wei.of( + fakeExponential( + BLOB_GAS_PRICE, + excessBlobGas.toBigInteger(), + BLOB_BASE_FEE_UPDATE_FRACTION_ELECTRA)); + LOG.atTrace() + .setMessage("parentExcessBlobGas: {} blobGasPrice: {}") + .addArgument(excessBlobGas::toShortHexString) + .addArgument(blobGasPrice::toHexString) + .log(); + + return blobGasPrice; + } +} diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/PragueFeeMarketTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/PragueFeeMarketTest.java new file mode 100644 index 00000000000..2e8768c42ac --- /dev/null +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/feemarket/PragueFeeMarketTest.java @@ -0,0 +1,73 @@ +/* + * 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.feemarket; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.hyperledger.besu.datatypes.BlobGas; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import org.junit.jupiter.api.Test; + +class PragueFeeMarketTest { + + private static final int BLOB_GAS_PER_BLOB = 131072; + + /** + * from: https://eips.ethereum.org/EIPS/eip-7691 The BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE value in + * this EIP is chosen as the mid-point between keeping the responsiveness to full blobs and no + * blobs constant: + * + *

full blobs: basefee increases by ~8.2% no blobs: basefee decreases by ~14.5% + */ + @Test + void dataPricePerGas() { + PragueFeeMarket pragueFeeMarket = new PragueFeeMarket(0, Optional.empty()); + // when no excess blob gas, data price per gas is 1 + assertEquals(1, pragueFeeMarket.blobGasPricePerGas(BlobGas.ZERO).getAsBigInteger().intValue()); + + record BlobGasPricing(long excess, long price) {} + List testVector = new ArrayList<>(); + + int numBlobs = 1; + long price = 1; + while (price <= 1000) { + price = blobGasPrice(BlobGas.of(numBlobs * BLOB_GAS_PER_BLOB)); + var testCase = new BlobGasPricing(numBlobs * BLOB_GAS_PER_BLOB, price); + testVector.add(testCase); + numBlobs++; + } + + testVector.stream() + .forEach( + blobGasPricing -> { + assertEquals( + blobGasPricing.price, + pragueFeeMarket + .blobGasPricePerGas(BlobGas.of(blobGasPricing.excess)) + .getAsBigInteger() + .intValue()); + }); + } + + private long blobGasPrice(final BlobGas excess) { + double dgufDenominator = 5007716; + double fakeExpo = excess.getValue().longValue() / dgufDenominator; + return (long) (1 * Math.exp(fakeExpo)); + } +}