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:
Simon Dudley
2022-08-31 00:52:43 +01:00
committed by GitHub
parent af65c86e64
commit fd666dfd61
18 changed files with 436 additions and 14 deletions

View File

@@ -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)

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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();

View File

@@ -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));
}

View File

@@ -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);

View File

@@ -4,6 +4,8 @@
"eip150Block": 2,
"eip158Block": 3,
"byzantiumBlock": 1035301,
"londonBlock": 2222222,
"zeroBaseFee": true,
"ibft2": {
"blockperiodseconds": 2,
"epochlength": 30000,

View File

@@ -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,

View File

@@ -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);
}

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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(

View File

@@ -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());

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}