mirror of
https://github.com/vacp2p/linea-besu.git
synced 2026-01-09 21:17:54 -05:00
Add ZeroBaseFeeMarket to support post-London free gas networks (#4174)
* Add zeroBaseFee config for all consensus types Signed-off-by: Simon Dudley <simon.dudley@consensys.net> * Use ZeroBaseFeeMarket when zeroBaseFee is set Introduce ZeroBaseFeeMarket overriding computeBaseFee with 0 Wire ZeroBaseFeeMarket into MainnetProtocolSpecs.londonDefinition when zeroBaseFee set Signed-off-by: Simon Dudley <simon.dudley@consensys.net> * Fix BaseFeeMarketBlockHeaderGasPriceValidationRule to allow syncing to work Without this, rule would fail if syncing a chain with a non-zero baseFee Signed-off-by: Simon Dudley <simon.dudley@consensys.net> * Fix fast sync invalid block error Occurred while testing clique in scenario where londonFork had a non-zero base fee, but zeroBaseFee flag was used to sync Signed-off-by: Simon Dudley <simon.dudley@consensys.net> * Update changelog Signed-off-by: Simon Dudley <simon.dudley@consensys.net> * Address review comments: Remove startup log Signed-off-by: Simon Dudley <simon.dudley@consensys.net> * Address review comments: replace isForkBlock with validationMode Signed-off-by: Simon Dudley <simon.dudley@consensys.net> * Address review comments: replace ZeroBaseFeeMarket instance check with validationMode Signed-off-by: Simon Dudley <simon.dudley@consensys.net> * Fix changelog Signed-off-by: Simon Dudley <simon.dudley@consensys.net> * Split validationMode into baseFeeValidationMode and gasLimitValidationMode Since behaviour needs to differ between BaseFeeMarketBlockHeaderGasPriceValidationRule and GasLimitRangeAndDeltaValidationRule Signed-off-by: Simon Dudley <simon.dudley@consensys.net> * Update changelog Signed-off-by: Simon Dudley <simon.dudley@consensys.net> Signed-off-by: Simon Dudley <simon.dudley@consensys.net>
This commit is contained in:
@@ -1,5 +1,10 @@
|
||||
# Changelog
|
||||
|
||||
## 22.7.3-next
|
||||
|
||||
### Additions and Improvements
|
||||
- Allow free gas networks in the London fee market [#4061](https://github.com/hyperledger/besu/issues/4061)
|
||||
|
||||
## 22.7.2
|
||||
|
||||
### Additions and Improvements
|
||||
@@ -20,7 +25,7 @@
|
||||
- Introduce a cap to reputation score increase [#4230](https://github.com/hyperledger/besu/pull/4230)
|
||||
- Add experimental CLI option for `--Xp2p-peer-lower-bound` [#4200](https://github.com/hyperledger/besu/pull/4200)
|
||||
- Improve pending blocks retrieval mechanism [#4227](https://github.com/hyperledger/besu/pull/4227)
|
||||
- set mainnet terminal total difficulty [#4260](https://github.com/hyperledger/besu/pull/4260)
|
||||
- Set mainnet terminal total difficulty [#4260](https://github.com/hyperledger/besu/pull/4260)
|
||||
|
||||
### Bug Fixes
|
||||
- Fixes off-by-one error for mainnet TTD fallback [#4223](https://github.com/hyperledger/besu/pull/4223)
|
||||
|
||||
@@ -283,4 +283,12 @@ public interface GenesisConfigOptions {
|
||||
* @return the name of the elliptic curve.
|
||||
*/
|
||||
Optional<String> getEcCurve();
|
||||
|
||||
/**
|
||||
* Set a Zero Base Fee network so that free gas can be used with London/EIP-1559. Once the chain
|
||||
* has a zero base fee, you cannot go back to a non-zero base fee.
|
||||
*
|
||||
* @return true, if you want the next block to use zero for the base fee.
|
||||
*/
|
||||
boolean isZeroBaseFee();
|
||||
}
|
||||
|
||||
@@ -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 ZERO_BASE_FEE_KEY = "zerobasefee";
|
||||
|
||||
private final ObjectNode configRoot;
|
||||
private final Map<String, String> configOverrides = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
@@ -409,6 +410,11 @@ public class JsonGenesisConfigOptions implements GenesisConfigOptions {
|
||||
return JsonUtil.getString(configRoot, EC_CURVE_CONFIG_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isZeroBaseFee() {
|
||||
return getOptionalBoolean(ZERO_BASE_FEE_KEY).orElse(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> asMap() {
|
||||
final ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder();
|
||||
@@ -486,6 +492,10 @@ public class JsonGenesisConfigOptions implements GenesisConfigOptions {
|
||||
getQip714BlockNumber().ifPresent(blockNumber -> builder.put("qip714block", blockNumber));
|
||||
}
|
||||
|
||||
if (isZeroBaseFee()) {
|
||||
builder.put("zeroBaseFee", true);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -407,6 +407,11 @@ public class StubGenesisConfigOptions implements GenesisConfigOptions {
|
||||
return ecCurve;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isZeroBaseFee() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> getForks() {
|
||||
return Collections.emptyList();
|
||||
|
||||
@@ -459,7 +459,7 @@ public class GenesisConfigFileTest {
|
||||
|
||||
final GenesisConfigFile config = fromConfig(configNode);
|
||||
|
||||
assertThat(config.getForks()).containsExactly(1L, 2L, 3L, 1035301L);
|
||||
assertThat(config.getForks()).containsExactly(1L, 2L, 3L, 1035301L, 2222222L);
|
||||
assertThat(config.getConfigOptions().getChainId()).hasValue(BigInteger.valueOf(4));
|
||||
}
|
||||
|
||||
|
||||
@@ -278,6 +278,27 @@ public class GenesisConfigOptionsTest {
|
||||
assertThat(config.getQip714BlockNumber()).hasValue(99999L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isZeroBaseFeeShouldDefaultToFalse() {
|
||||
final GenesisConfigOptions config = GenesisConfigFile.fromConfig("{}").getConfigOptions();
|
||||
|
||||
assertThat(config.isZeroBaseFee()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isZeroBaseFeeParsedCorrectly() {
|
||||
final GenesisConfigOptions config = fromConfigOptions(Map.of("zerobasefee", true));
|
||||
|
||||
assertThat(config.isZeroBaseFee()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asMapIncludesZeroBaseFee() {
|
||||
final GenesisConfigOptions config = fromConfigOptions(Map.of("zerobasefee", true));
|
||||
|
||||
assertThat(config.asMap()).containsOnlyKeys("zeroBaseFee").containsValue(true);
|
||||
}
|
||||
|
||||
private GenesisConfigOptions fromConfigOptions(final Map<String, Object> configOptions) {
|
||||
final ObjectNode rootNode = JsonUtil.createEmptyObjectNode();
|
||||
final ObjectNode options = JsonUtil.objectNodeFromMap(configOptions);
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
"eip150Block": 2,
|
||||
"eip158Block": 3,
|
||||
"byzantiumBlock": 1035301,
|
||||
"londonBlock": 2222222,
|
||||
"zeroBaseFee": true,
|
||||
"ibft2": {
|
||||
"blockperiodseconds": 2,
|
||||
"epochlength": 30000,
|
||||
|
||||
@@ -508,7 +508,9 @@ public abstract class MainnetProtocolSpecs {
|
||||
final long londonForkBlockNumber =
|
||||
genesisConfigOptions.getLondonBlockNumber().orElse(Long.MAX_VALUE);
|
||||
final BaseFeeMarket londonFeeMarket =
|
||||
FeeMarket.london(londonForkBlockNumber, genesisConfigOptions.getBaseFeePerGas());
|
||||
genesisConfigOptions.isZeroBaseFee()
|
||||
? FeeMarket.zeroBaseFee(londonForkBlockNumber)
|
||||
: FeeMarket.london(londonForkBlockNumber, genesisConfigOptions.getBaseFeePerGas());
|
||||
return berlinDefinition(
|
||||
chainId,
|
||||
configContractSizeLimit,
|
||||
|
||||
@@ -19,6 +19,12 @@ import org.hyperledger.besu.ethereum.core.BlockHeader;
|
||||
|
||||
public interface BaseFeeMarket extends FeeMarket {
|
||||
|
||||
enum ValidationMode {
|
||||
NONE,
|
||||
INITIAL,
|
||||
ONGOING
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean implementsBaseFee() {
|
||||
return true;
|
||||
@@ -47,7 +53,9 @@ public interface BaseFeeMarket extends FeeMarket {
|
||||
final long parentBlockGasUsed,
|
||||
final long targetGasUsed);
|
||||
|
||||
boolean isForkBlock(final long blockNumber);
|
||||
ValidationMode baseFeeValidationMode(final long blockNumber);
|
||||
|
||||
ValidationMode gasLimitValidationMode(final long blockNumber);
|
||||
|
||||
boolean isBeforeForkBlock(final long blockNumber);
|
||||
}
|
||||
|
||||
@@ -43,6 +43,10 @@ public interface FeeMarket {
|
||||
return new LondonFeeMarket(londonForkBlockNumber, baseFeePerGasOverride);
|
||||
}
|
||||
|
||||
static BaseFeeMarket zeroBaseFee(final long londonForkBlockNumber) {
|
||||
return new ZeroBaseFeeMarket(londonForkBlockNumber);
|
||||
}
|
||||
|
||||
static FeeMarket legacy() {
|
||||
return new LegacyFeeMarket();
|
||||
}
|
||||
|
||||
@@ -130,8 +130,13 @@ public class LondonFeeMarket implements BaseFeeMarket {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForkBlock(final long blockNumber) {
|
||||
return londonForkBlockNumber == blockNumber;
|
||||
public ValidationMode baseFeeValidationMode(final long blockNumber) {
|
||||
return londonForkBlockNumber == blockNumber ? ValidationMode.INITIAL : ValidationMode.ONGOING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationMode gasLimitValidationMode(final long blockNumber) {
|
||||
return londonForkBlockNumber == blockNumber ? ValidationMode.INITIAL : ValidationMode.ONGOING;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright Hyperledger Besu Contributors.
|
||||
*
|
||||
* 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 java.util.Optional;
|
||||
|
||||
public class ZeroBaseFeeMarket extends LondonFeeMarket {
|
||||
|
||||
public ZeroBaseFeeMarket(final long londonForkBlockNumber) {
|
||||
super(londonForkBlockNumber, Optional.of(Wei.ZERO));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Wei computeBaseFee(
|
||||
final long blockNumber,
|
||||
final Wei parentBaseFee,
|
||||
final long parentBlockGasUsed,
|
||||
final long targetGasUsed) {
|
||||
|
||||
return Wei.ZERO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationMode baseFeeValidationMode(final long blockNumber) {
|
||||
return ValidationMode.NONE;
|
||||
}
|
||||
}
|
||||
@@ -40,16 +40,22 @@ public class BaseFeeMarketBlockHeaderGasPriceValidationRule
|
||||
try {
|
||||
|
||||
// if this is the fork block, baseFee should be the initial baseFee
|
||||
if (baseFeeMarket.isForkBlock(header.getNumber())) {
|
||||
if (BaseFeeMarket.ValidationMode.INITIAL.equals(
|
||||
baseFeeMarket.baseFeeValidationMode(header.getNumber()))) {
|
||||
return baseFeeMarket
|
||||
.getInitialBasefee()
|
||||
.equals(header.getBaseFee().orElseThrow(() -> MissingBaseFeeFromBlockHeader()));
|
||||
} else if (BaseFeeMarket.ValidationMode.NONE.equals(
|
||||
baseFeeMarket.baseFeeValidationMode(header.getNumber()))) {
|
||||
// skip validation to allow sync when a zero baseFee chain has historical baseFees
|
||||
return true;
|
||||
}
|
||||
|
||||
final Wei parentBaseFee =
|
||||
parent.getBaseFee().orElseThrow(() -> MissingBaseFeeFromBlockHeader());
|
||||
final Wei currentBaseFee =
|
||||
header.getBaseFee().orElseThrow(() -> MissingBaseFeeFromBlockHeader());
|
||||
|
||||
final long targetGasUsed = baseFeeMarket.targetGasUsed(parent);
|
||||
final Wei expectedBaseFee =
|
||||
baseFeeMarket.computeBaseFee(
|
||||
|
||||
@@ -68,7 +68,10 @@ public class GasLimitRangeAndDeltaValidationRule extends AbstractGasLimitSpecifi
|
||||
|
||||
long parentGasLimit =
|
||||
baseFeeMarket
|
||||
.filter(baseFeeMarket -> baseFeeMarket.isForkBlock(header.getNumber()))
|
||||
.filter(
|
||||
baseFeeMarket ->
|
||||
BaseFeeMarket.ValidationMode.INITIAL.equals(
|
||||
baseFeeMarket.gasLimitValidationMode(header.getNumber())))
|
||||
.map(baseFeeMarket -> parent.getGasLimit() * baseFeeMarket.getSlackCoefficient())
|
||||
.orElse(parent.getGasLimit());
|
||||
|
||||
|
||||
@@ -53,17 +53,26 @@ public class BaseFeeMarketTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenForkBlock_whenIsForkBlock_thenReturnsTrue() {
|
||||
assertThat(baseFeeMarket.isForkBlock(FORK_BLOCK)).isTrue();
|
||||
public void givenForkBlock_whenBaseFeeValidationMode_thenReturnsInitial() {
|
||||
assertThat(baseFeeMarket.baseFeeValidationMode(FORK_BLOCK))
|
||||
.isEqualTo(BaseFeeMarket.ValidationMode.INITIAL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenNotForkBlock_whenIsForkBlock_thenReturnsFalse() {
|
||||
assertThat(baseFeeMarket.isForkBlock(FORK_BLOCK + 1)).isFalse();
|
||||
public void givenNotForkBlock_whenBaseFeeValidationMode_thenReturnsOngoing() {
|
||||
assertThat(baseFeeMarket.baseFeeValidationMode(FORK_BLOCK + 1))
|
||||
.isEqualTo(BaseFeeMarket.ValidationMode.ONGOING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getForkBlock() {
|
||||
assertThat(baseFeeMarket.isForkBlock(FORK_BLOCK)).isTrue();
|
||||
public void givenForkBlock_whenGasLimitValidationMode_thenReturnsInitial() {
|
||||
assertThat(baseFeeMarket.gasLimitValidationMode(FORK_BLOCK))
|
||||
.isEqualTo(BaseFeeMarket.ValidationMode.INITIAL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenNotForkBlock_whenGasLimitValidationMode_thenReturnsOngoing() {
|
||||
assertThat(baseFeeMarket.gasLimitValidationMode(FORK_BLOCK + 1))
|
||||
.isEqualTo(BaseFeeMarket.ValidationMode.ONGOING);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright Hyperledger Besu Contributors.
|
||||
*
|
||||
* 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.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.hyperledger.besu.crypto.KeyPair;
|
||||
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
|
||||
import org.hyperledger.besu.datatypes.Wei;
|
||||
import org.hyperledger.besu.ethereum.core.Transaction;
|
||||
import org.hyperledger.besu.ethereum.core.TransactionTestFixture;
|
||||
import org.hyperledger.besu.plugin.data.TransactionType;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ZeroBaseFeeMarketTest {
|
||||
|
||||
private static final KeyPair KEY_PAIR1 =
|
||||
SignatureAlgorithmFactory.getInstance().generateKeyPair();
|
||||
private static final long FORK_BLOCK = 0;
|
||||
private ZeroBaseFeeMarket zeroBaseFeeMarket;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
zeroBaseFeeMarket = new ZeroBaseFeeMarket(FORK_BLOCK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getBasefeeMaxChangeDenominatorShouldUseLondonDefault() {
|
||||
assertThat(zeroBaseFeeMarket.getBasefeeMaxChangeDenominator())
|
||||
.isEqualTo(LondonFeeMarket.DEFAULT_BASEFEE_MAX_CHANGE_DENOMINATOR);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getInitialBasefeeShouldBeZero() {
|
||||
assertThat(zeroBaseFeeMarket.getInitialBasefee()).isEqualTo(Wei.ZERO);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSlackCoefficientShouldUseLondonDefault() {
|
||||
assertThat(zeroBaseFeeMarket.getSlackCoefficient())
|
||||
.isEqualTo(LondonFeeMarket.DEFAULT_SLACK_COEFFICIENT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void minTransactionPriceInNextBlockShouldHandleZeroBaseFee() {
|
||||
final Transaction transaction =
|
||||
new TransactionTestFixture()
|
||||
.type(TransactionType.EIP1559)
|
||||
.maxFeePerGas(Optional.of(Wei.of(8)))
|
||||
.maxPriorityFeePerGas(Optional.of(Wei.of(8)))
|
||||
.gasPrice(null)
|
||||
.createTransaction(KEY_PAIR1);
|
||||
assertThat(
|
||||
zeroBaseFeeMarket.minTransactionPriceInNextBlock(
|
||||
transaction, () -> Optional.of(Wei.ZERO)))
|
||||
.isEqualTo(Wei.of(8));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTransactionPriceCalculatorShouldBeEIP1559() {
|
||||
// only eip1559 will read the fee per gas values
|
||||
final Transaction transaction =
|
||||
new TransactionTestFixture()
|
||||
.type(TransactionType.EIP1559)
|
||||
.maxFeePerGas(Optional.of(Wei.of(8)))
|
||||
.maxPriorityFeePerGas(Optional.of(Wei.of(8)))
|
||||
.gasPrice(null)
|
||||
.createTransaction(KEY_PAIR1);
|
||||
assertThat(
|
||||
zeroBaseFeeMarket
|
||||
.getTransactionPriceCalculator()
|
||||
.price(transaction, Optional.of(Wei.ZERO)))
|
||||
.isEqualTo(Wei.of(8));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void satisfiesFloorTxCostWhenGasFeeIsNonZero() {
|
||||
final Transaction transaction =
|
||||
new TransactionTestFixture()
|
||||
.type(TransactionType.FRONTIER)
|
||||
.gasPrice(Wei.of(7))
|
||||
.createTransaction(KEY_PAIR1);
|
||||
assertThat(zeroBaseFeeMarket.satisfiesFloorTxCost(transaction)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void satisfiesFloorTxCostWhenGasFeeIsZero() {
|
||||
final Transaction transaction =
|
||||
new TransactionTestFixture()
|
||||
.type(TransactionType.EIP1559)
|
||||
.maxFeePerGas(Optional.of(Wei.ZERO))
|
||||
.maxPriorityFeePerGas(Optional.of(Wei.ZERO))
|
||||
.gasPrice(null)
|
||||
.createTransaction(KEY_PAIR1);
|
||||
assertThat(zeroBaseFeeMarket.satisfiesFloorTxCost(transaction)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void computeBaseFeeReturnsZero() {
|
||||
assertThat(zeroBaseFeeMarket.computeBaseFee(1L, Wei.of(8), 1L, 2L)).isEqualTo(Wei.ZERO);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void baseFeeValidationModeShouldBeNoneWhenIsForkBlock() {
|
||||
assertThat(zeroBaseFeeMarket.baseFeeValidationMode(FORK_BLOCK))
|
||||
.isEqualTo(BaseFeeMarket.ValidationMode.NONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void baseFeeValidationModeShouldBeNoneWhenIsNotForkBlock() {
|
||||
assertThat(zeroBaseFeeMarket.baseFeeValidationMode(FORK_BLOCK + 1))
|
||||
.isEqualTo(BaseFeeMarket.ValidationMode.NONE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void gasLimitValidationModeShouldBeInitialWhenIsForkBlock() {
|
||||
assertThat(zeroBaseFeeMarket.gasLimitValidationMode(FORK_BLOCK))
|
||||
.isEqualTo(BaseFeeMarket.ValidationMode.INITIAL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void gasLimitValidationModeShouldBeOngoingWhenIsNotForkBlock() {
|
||||
assertThat(zeroBaseFeeMarket.gasLimitValidationMode(FORK_BLOCK + 1))
|
||||
.isEqualTo(BaseFeeMarket.ValidationMode.ONGOING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isBeforeForkBlockShouldBeTrue() {
|
||||
final ZeroBaseFeeMarket zeroBaseFeeMarket = new ZeroBaseFeeMarket(10);
|
||||
assertThat(zeroBaseFeeMarket.isBeforeForkBlock(9)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isBeforeForkBlockShouldBeFalse() {
|
||||
final ZeroBaseFeeMarket zeroBaseFeeMarket = new ZeroBaseFeeMarket(10);
|
||||
assertThat(zeroBaseFeeMarket.isBeforeForkBlock(10)).isFalse();
|
||||
assertThat(zeroBaseFeeMarket.isBeforeForkBlock(11)).isFalse();
|
||||
}
|
||||
}
|
||||
@@ -82,4 +82,50 @@ public class BaseFeeMarketBlockHeaderGasPriceValidationRuleTest {
|
||||
blockHeader(FORK_BLOCK + 1, 0, Optional.empty())))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnTrueIfCurrentBaseFeeEqualsExpected() {
|
||||
assertThat(
|
||||
validationRule.validate(
|
||||
blockHeader(FORK_BLOCK + 2, 0, Optional.of(feeMarket.getInitialBasefee())),
|
||||
blockHeader(FORK_BLOCK + 1, 0, Optional.of(feeMarket.getInitialBasefee()))))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnFalseIfCurrentBaseFeeDoesNotEqualExpected() {
|
||||
assertThat(
|
||||
validationRule.validate(
|
||||
blockHeader(FORK_BLOCK + 2, 0, Optional.of(feeMarket.getInitialBasefee())),
|
||||
blockHeader(FORK_BLOCK + 1, 0, Optional.of(feeMarket.getInitialBasefee()), 2)))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnTrueIfUsingZeroBaseFeeMarket() {
|
||||
// covers scenario where chain is converted from a non-zero base fee to a zero base fee
|
||||
final BaseFeeMarket zeroBaseFeeMarket = FeeMarket.zeroBaseFee(FORK_BLOCK);
|
||||
final var validationRule =
|
||||
new BaseFeeMarketBlockHeaderGasPriceValidationRule(zeroBaseFeeMarket);
|
||||
assertThat(
|
||||
validationRule.validate(
|
||||
blockHeader(FORK_BLOCK + 2, 0, Optional.of(zeroBaseFeeMarket.getInitialBasefee())),
|
||||
blockHeader(FORK_BLOCK + 1, 0, Optional.of(feeMarket.getInitialBasefee()), 2)))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldReturnTrueIfUsingZeroBaseFeeMarketOnNonZeroLondonForkBlock() {
|
||||
// syncing across a london fork where baseFee wasn't zeroed,
|
||||
// but is now using a ZeroBaseFeeMarket
|
||||
final BaseFeeMarket zeroBaseFeeMarket = FeeMarket.zeroBaseFee(FORK_BLOCK);
|
||||
final var validationRule =
|
||||
new BaseFeeMarketBlockHeaderGasPriceValidationRule(zeroBaseFeeMarket);
|
||||
final Wei londonFeeMarketBaseFee = feeMarket.getInitialBasefee();
|
||||
assertThat(
|
||||
validationRule.validate(
|
||||
blockHeader(FORK_BLOCK, 0, Optional.of(londonFeeMarketBaseFee)),
|
||||
blockHeader(FORK_BLOCK - 1, 0, Optional.of(londonFeeMarketBaseFee))))
|
||||
.isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright Hyperledger Besu Contributors.
|
||||
*
|
||||
* 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.headervalidationrules;
|
||||
|
||||
import static java.lang.Long.MAX_VALUE;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.hyperledger.besu.ethereum.core.BlockHeader;
|
||||
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
|
||||
import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket;
|
||||
import org.hyperledger.besu.ethereum.mainnet.feemarket.ZeroBaseFeeMarket;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameter;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class GasLimitElasticityValidationRuleZeroBaseFeeMarketTest {
|
||||
|
||||
private static final Optional<BaseFeeMarket> zeroBaseFeeMarket =
|
||||
Optional.of(new ZeroBaseFeeMarket(10));
|
||||
|
||||
@Parameter public long headerGasLimit;
|
||||
|
||||
@Parameter(1)
|
||||
public long parentGasLimit;
|
||||
|
||||
@Parameter(2)
|
||||
public long headerNumber;
|
||||
|
||||
@Parameter(3)
|
||||
public boolean expectedResult;
|
||||
|
||||
public GasLimitRangeAndDeltaValidationRule uut =
|
||||
new GasLimitRangeAndDeltaValidationRule(5000, MAX_VALUE, zeroBaseFeeMarket);
|
||||
|
||||
@Parameters
|
||||
public static Collection<Object[]> data() {
|
||||
return Arrays.asList(
|
||||
new Object[][] {
|
||||
{20000000, 10000000, 10, true},
|
||||
{20019530, 10000000, 10, true},
|
||||
{20019531, 10000000, 10, false},
|
||||
{19980470, 10000000, 10, true},
|
||||
{19980469, 10000000, 10, false},
|
||||
{20000000, 20000000, 11, true},
|
||||
{20019530, 20000000, 11, true},
|
||||
{20019531, 20000000, 11, false},
|
||||
{19980470, 20000000, 11, true},
|
||||
{19980469, 20000000, 11, false},
|
||||
{40039061, 40000000, 11, true},
|
||||
{40039062, 40000000, 11, false},
|
||||
{39960939, 40000000, 11, true},
|
||||
{39960938, 40000000, 11, false},
|
||||
{4999, 40000000, 11, false}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
final BlockHeaderTestFixture blockHeaderBuilder = new BlockHeaderTestFixture();
|
||||
|
||||
blockHeaderBuilder.number(headerNumber);
|
||||
blockHeaderBuilder.gasLimit(headerGasLimit);
|
||||
final BlockHeader header = blockHeaderBuilder.buildHeader();
|
||||
|
||||
blockHeaderBuilder.number(headerNumber - 1);
|
||||
blockHeaderBuilder.gasLimit(parentGasLimit);
|
||||
final BlockHeader parent = blockHeaderBuilder.buildHeader();
|
||||
|
||||
assertThat(uut.validate(header, parent)).isEqualTo(expectedResult);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user