Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clique createemptyblocks transition #6608

Merged
merged 22 commits into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7b0eb8e
clique block period transition
jframe Oct 20, 2023
5e4dd64
validate clique block headers according to transition schedule
jframe Oct 20, 2023
65d5390
fix error applying block period to wrong block
jframe Oct 24, 2023
d19d62e
Merge branch 'main' into clique_transition_blocks
siladu Feb 11, 2024
e79d596
Fix unit test
siladu Feb 20, 2024
6944a28
Merge remote-tracking branch 'upstream/main' into clique_transition_b…
siladu Feb 20, 2024
ba859c8
javadoc
siladu Feb 20, 2024
8d5e96b
Block period transitions AT
siladu Feb 22, 2024
0189ae1
Remove BFT-ness from names and comments
siladu Feb 22, 2024
dd44cf7
Merge remote-tracking branch 'upstream/main' into clique_transition_b…
siladu Feb 22, 2024
718c717
changelog
siladu Feb 22, 2024
22ed401
Merge remote-tracking branch 'upstream/main' into clique_transition_b…
siladu Feb 22, 2024
ae7c8aa
Fix +1 error when scheduling next block
siladu Feb 23, 2024
d88a0b1
Support clique transitions for createemptyblocks
siladu Feb 23, 2024
c1d7f72
Add acceptance test
siladu Feb 26, 2024
fc1b72e
changelog
siladu Feb 26, 2024
accc6bc
Merge remote-tracking branch 'upstream/main' into clique-transition-c…
siladu Mar 1, 2024
9c7bdd6
Bad merge - remove MutableCliqueConfigOptions again
siladu Mar 1, 2024
95a6cee
Tidy up visibility and comments
siladu Mar 1, 2024
7b4b42c
Merge remote-tracking branch 'upstream/main' into clique-transition-c…
siladu Mar 4, 2024
0201173
Modify ATs to check that transitions are correctly carried over
siladu Mar 4, 2024
0c3fbd2
Ensure createemptyblocks transitions are carried over when there's ot…
siladu Mar 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
### Additions and Improvements
- Extend `Blockchain` service [#6592](https://github.com/hyperledger/besu/pull/6592)
- Add bft-style blockperiodseconds transitions to Clique [#6596](https://github.com/hyperledger/besu/pull/6596)
- Add createemptyblocks transitions to Clique [#6608](https://github.com/hyperledger/besu/pull/6608)
- RocksDB database metadata refactoring [#6555](https://github.com/hyperledger/besu/pull/6555)
- Make layered txpool aware of minGasPrice and minPriorityFeePerGas dynamic options [#6611](https://github.com/hyperledger/besu/pull/6611)
- Update commons-compress to 1.26.0 [#6648](https://github.com/hyperledger/besu/pull/6648)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public void shouldNotMineBlocksIfNoTransactionsWhenCreateEmptyBlockIsFalse() thr
}

@Test
public void shouldMineBlocksOnlyWhenTransactionsArePresentWhenCreateEmptyBlockIsFalse()
public void shouldMineBlocksOnlyWhenTransactionsArePresentWhenCreateEmptyBlocksIsFalse()
throws IOException {
final var cliqueOptionsNoEmptyBlocks =
new CliqueOptions(
Expand Down Expand Up @@ -134,7 +134,7 @@ public void shouldStillMineWhenANodeFailsAndHasSufficientValidators() throws IOE
}

@Test
public void shouldMineBlocksWithBlockPeriodAccordingToTransitions() throws IOException {
public void shouldMineBlocksAccordingToBlockPeriodTransitions() throws IOException {

final var cliqueOptions = new CliqueOptions(3, CliqueOptions.DEFAULT.epochLength(), true);
final BesuNode minerNode = besu.createCliqueNode("miner1", cliqueOptions);
Expand Down Expand Up @@ -176,6 +176,50 @@ public void shouldMineBlocksWithBlockPeriodAccordingToTransitions() throws IOExc
assertThat(block6Timestamp - block5Timestamp).isCloseTo(2, withPercentage(20));
}

@Test
public void shouldMineBlocksAccordingToCreateEmptyBlocksTransitions() throws IOException {

final var cliqueOptionsEmptyBlocks =
new CliqueOptions(2, CliqueOptions.DEFAULT.epochLength(), true);
final BesuNode minerNode = besu.createCliqueNode("miner1", cliqueOptionsEmptyBlocks);

// setup transitions
final Map<String, Object> noEmptyBlocks_Transition =
Map.of("block", 3, "createemptyblocks", false);
final Map<String, Object> emptyBlocks_Transition =
Map.of("block", 4, "createemptyblocks", true);
final Map<String, Object> secondNoEmptyBlocks_Transition =
Map.of("block", 6, "createemptyblocks", false);

final Optional<String> initialGenesis =
minerNode.getGenesisConfigProvider().create(List.of(minerNode));
final String genesisWithTransitions =
prependTransitionsToCliqueOptions(
initialGenesis.orElseThrow(),
List.of(
noEmptyBlocks_Transition, emptyBlocks_Transition, secondNoEmptyBlocks_Transition));
minerNode.setGenesisConfig(genesisWithTransitions);

final Account sender = accounts.createAccount("account1");

// Mine 2 blocks
cluster.start(minerNode);
minerNode.verify(blockchain.reachesHeight(minerNode, 1));

// tx required to mine block
cluster.verify(clique.noNewBlockCreated(minerNode));
minerNode.execute(accountTransactions.createTransfer(sender, 50));
minerNode.verify(clique.blockIsCreatedByProposer(minerNode));

// Mine 2 more blocks so chain head is 5
minerNode.verify(blockchain.reachesHeight(minerNode, 2));

// tx required to mine block
cluster.verify(clique.noNewBlockCreated(minerNode));
minerNode.execute(accountTransactions.createTransfer(sender, 50));
minerNode.verify(clique.blockIsCreatedByProposer(minerNode));
}

private long getTimestampForBlock(final BesuNode minerNode, final int blockNumber) {
return minerNode
.execute(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ public class CliqueBesuControllerBuilder extends BesuControllerBuilder {

private Address localAddress;
private EpochManager epochManager;
private boolean createEmptyBlocks = true;
private final BlockInterface blockInterface = new CliqueBlockInterface();
private ForksSchedule<CliqueConfigOptions> forksSchedule;

Expand All @@ -63,7 +62,6 @@ protected void prepForBuild() {
localAddress = Util.publicKeyToAddress(nodeKey.getPublicKey());
final CliqueConfigOptions cliqueConfig = configOptionsSupplier.get().getCliqueConfigOptions();
final long blocksPerEpoch = cliqueConfig.getEpochLength();
createEmptyBlocks = cliqueConfig.getCreateEmptyBlocks();

epochManager = new EpochManager(blocksPerEpoch);
forksSchedule = CliqueForksSchedulesFactory.create(configOptionsSupplier.get());
Expand Down Expand Up @@ -96,7 +94,7 @@ protected MiningCoordinator createMiningCoordinator(
localAddress,
forksSchedule),
epochManager,
createEmptyBlocks,
forksSchedule,
ethProtocolManager.ethContext().getScheduler());
final CliqueMiningCoordinator miningCoordinator =
new CliqueMiningCoordinator(
Expand Down
12 changes: 12 additions & 0 deletions config/src/main/java/org/hyperledger/besu/config/CliqueFork.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ public class CliqueFork implements Fork {
/** The constant BLOCK_PERIOD_SECONDS_KEY. */
public static final String BLOCK_PERIOD_SECONDS_KEY = "blockperiodseconds";

/** The constant CREATE_EMPTY_BLOCKS_KEY. */
public static final String CREATE_EMPTY_BLOCKS_KEY = "createemptyblocks";

/** The Fork config root. */
protected final ObjectNode forkConfigRoot;

Expand Down Expand Up @@ -63,4 +66,13 @@ public long getForkBlock() {
public OptionalInt getBlockPeriodSeconds() {
return JsonUtil.getPositiveInt(forkConfigRoot, BLOCK_PERIOD_SECONDS_KEY);
}

/**
* Gets create empty blocks.
*
* @return the create empty blocks
*/
public boolean getCreateEmptyBlocks() {
return JsonUtil.getBoolean(forkConfigRoot, CREATE_EMPTY_BLOCKS_KEY).orElse(true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ private static CliqueConfigOptions createCliqueConfigOptions(

var options = ImmutableCliqueConfigOptions.builder().from(lastSpec.getValue());
fork.getBlockPeriodSeconds().ifPresent(options::blockPeriodSeconds);
options.createEmptyBlocks(fork.getCreateEmptyBlocks());
return options.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
import java.util.Optional;
import java.util.function.Function;

import com.google.common.annotations.VisibleForTesting;

/** Defines the protocol behaviours for a blockchain using Clique. */
public class CliqueProtocolSchedule {

Expand Down Expand Up @@ -89,7 +91,7 @@ public static ProtocolSchedule create(
applyCliqueSpecificModifications(
epochManager,
forkSpec.getValue().getBlockPeriodSeconds(),
cliqueConfig.getCreateEmptyBlocks(),
forkSpec.getValue().getCreateEmptyBlocks(),
localNodeAddress,
builder)));
final ProtocolSpecAdapters specAdapters = new ProtocolSpecAdapters(specMap);
Expand All @@ -116,6 +118,7 @@ public static ProtocolSchedule create(
* @param badBlockManager the cache to use to keep invalid blocks
* @return the protocol schedule
*/
@VisibleForTesting
public static ProtocolSchedule create(
final GenesisConfigOptions config,
final ForksSchedule<CliqueConfigOptions> forksSchedule,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
*/
package org.hyperledger.besu.consensus.clique.blockcreation;

import org.hyperledger.besu.config.CliqueConfigOptions;
import org.hyperledger.besu.consensus.clique.CliqueHelpers;
import org.hyperledger.besu.consensus.common.ForksSchedule;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.blockcreation.AbstractBlockScheduler;
Expand All @@ -36,7 +38,7 @@ public class CliqueBlockMiner extends BlockMiner<CliqueBlockCreator> {
private static final int WAIT_IN_MS_BETWEEN_EMPTY_BUILD_ATTEMPTS = 1_000;

private final Address localAddress;
private final boolean createEmptyBlocks;
private final ForksSchedule<CliqueConfigOptions> forksSchedule;

/**
* Instantiates a new Clique block miner.
Expand All @@ -48,7 +50,7 @@ public class CliqueBlockMiner extends BlockMiner<CliqueBlockCreator> {
* @param scheduler the scheduler
* @param parentHeader the parent header
* @param localAddress the local address
* @param createEmptyBlocks whether clique should allow the creation of empty blocks.
* @param forksSchedule the transitions
*/
public CliqueBlockMiner(
final Function<BlockHeader, CliqueBlockCreator> blockCreator,
Expand All @@ -58,10 +60,10 @@ public CliqueBlockMiner(
final AbstractBlockScheduler scheduler,
final BlockHeader parentHeader,
final Address localAddress,
final boolean createEmptyBlocks) {
final ForksSchedule<CliqueConfigOptions> forksSchedule) {
super(blockCreator, protocolSchedule, protocolContext, observers, scheduler, parentHeader);
this.localAddress = localAddress;
this.createEmptyBlocks = createEmptyBlocks;
this.forksSchedule = forksSchedule;
}

@Override
Expand All @@ -76,7 +78,7 @@ protected boolean mineBlock() throws InterruptedException {

@Override
protected boolean shouldImportBlock(final Block block) throws InterruptedException {
if (createEmptyBlocks) {
if (forksSchedule.getFork(block.getHeader().getNumber()).getValue().getCreateEmptyBlocks()) {
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@
*/
package org.hyperledger.besu.consensus.clique.blockcreation;

import org.hyperledger.besu.config.CliqueConfigOptions;
import org.hyperledger.besu.consensus.clique.CliqueContext;
import org.hyperledger.besu.consensus.clique.CliqueExtraData;
import org.hyperledger.besu.consensus.common.ConsensusHelpers;
import org.hyperledger.besu.consensus.common.EpochManager;
import org.hyperledger.besu.consensus.common.ForksSchedule;
import org.hyperledger.besu.cryptoservices.NodeKey;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.ethereum.ProtocolContext;
Expand Down Expand Up @@ -48,7 +50,7 @@ public class CliqueMinerExecutor extends AbstractMinerExecutor<CliqueBlockMiner>
private final Address localAddress;
private final NodeKey nodeKey;
private final EpochManager epochManager;
private final boolean createEmptyBlocks;
private final ForksSchedule<CliqueConfigOptions> forksSchedule;

/**
* Instantiates a new Clique miner executor.
Expand All @@ -60,7 +62,7 @@ public class CliqueMinerExecutor extends AbstractMinerExecutor<CliqueBlockMiner>
* @param miningParams the mining params
* @param blockScheduler the block scheduler
* @param epochManager the epoch manager
* @param createEmptyBlocks whether clique should allow the creation of empty blocks.
* @param forksSchedule the clique transitions
* @param ethScheduler the scheduler for asynchronous block creation tasks
*/
public CliqueMinerExecutor(
Expand All @@ -71,7 +73,7 @@ public CliqueMinerExecutor(
final MiningParameters miningParams,
final AbstractBlockScheduler blockScheduler,
final EpochManager epochManager,
final boolean createEmptyBlocks,
final ForksSchedule<CliqueConfigOptions> forksSchedule,
final EthScheduler ethScheduler) {
super(
protocolContext,
Expand All @@ -83,7 +85,7 @@ public CliqueMinerExecutor(
this.nodeKey = nodeKey;
this.localAddress = Util.publicKeyToAddress(nodeKey.getPublicKey());
this.epochManager = epochManager;
this.createEmptyBlocks = createEmptyBlocks;
this.forksSchedule = forksSchedule;
miningParams.setCoinbase(localAddress);
}

Expand Down Expand Up @@ -113,7 +115,7 @@ public CliqueBlockMiner createMiner(
blockScheduler,
parentHeader,
localAddress,
createEmptyBlocks);
forksSchedule);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import org.hyperledger.besu.config.CliqueConfigOptions;
import org.hyperledger.besu.config.ImmutableCliqueConfigOptions;
import org.hyperledger.besu.config.JsonCliqueConfigOptions;
import org.hyperledger.besu.consensus.clique.CliqueContext;
import org.hyperledger.besu.consensus.common.ForkSpec;
import org.hyperledger.besu.consensus.common.ForksSchedule;
import org.hyperledger.besu.consensus.common.validator.ValidatorProvider;
import org.hyperledger.besu.crypto.KeyPair;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
Expand Down Expand Up @@ -54,10 +59,20 @@
import java.util.function.Function;

import com.google.common.collect.Lists;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class CliqueBlockMinerTest {

private ForksSchedule<CliqueConfigOptions> forksSchedule;

@BeforeEach
public void setup() {
var options = ImmutableCliqueConfigOptions.builder().from(JsonCliqueConfigOptions.DEFAULT);
options.createEmptyBlocks(false);
forksSchedule = new ForksSchedule<>(List.of(new ForkSpec<>(0, options.build())));
}

@Test
void doesNotMineBlockIfNoTransactionsWhenEmptyBlocksNotAllowed() throws InterruptedException {
final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture();
Expand Down Expand Up @@ -100,7 +115,7 @@ void doesNotMineBlockIfNoTransactionsWhenEmptyBlocksNotAllowed() throws Interrup
scheduler,
headerBuilder.buildHeader(),
Address.ZERO,
false); // parent header is arbitrary for the test.
forksSchedule); // parent header is arbitrary for the test.

final boolean result = miner.mineBlock();
assertThat(result).isFalse();
Expand Down Expand Up @@ -155,7 +170,7 @@ void minesBlockIfHasTransactionsWhenEmptyBlocksNotAllowed() throws InterruptedEx
scheduler,
headerBuilder.buildHeader(),
Address.ZERO,
false); // parent header is arbitrary for the test.
forksSchedule); // parent header is arbitrary for the test.

final boolean result = miner.mineBlock();
assertThat(result).isTrue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ public void extraDataCreatedOnEpochBlocksContainsValidators() {
miningParameters,
mock(CliqueBlockScheduler.class),
new EpochManager(EPOCH_LENGTH),
true,
null,
ethScheduler);

// NOTE: Passing in the *parent* block, so must be 1 less than EPOCH
Expand Down Expand Up @@ -160,7 +160,7 @@ public void extraDataForNonEpochBlocksDoesNotContainValidaors() {
miningParameters,
mock(CliqueBlockScheduler.class),
new EpochManager(EPOCH_LENGTH),
true,
null,
ethScheduler);

// Parent block was epoch, so the next block should contain no validators.
Expand Down Expand Up @@ -196,7 +196,7 @@ public void shouldUseLatestVanityData() {
miningParameters,
mock(CliqueBlockScheduler.class),
new EpochManager(EPOCH_LENGTH),
true,
null,
ethScheduler);

executor.setExtraData(modifiedVanityData);
Expand Down
Loading