Skip to content

Commit 80c44f6

Browse files
siladujframe
authored andcommitted
Clique createemptyblocks transition (besu-eth#6608)
Support clique transitions for createemptyblocks boolean --------- Signed-off-by: Jason Frame <jason.frame@consensys.net> Signed-off-by: Simon Dudley <simon.dudley@consensys.net> Co-authored-by: Jason Frame <jason.frame@consensys.net> Signed-off-by: amsmota <antonio.mota@citi.com>
1 parent b0dda34 commit 80c44f6

File tree

10 files changed

+112
-21
lines changed

10 files changed

+112
-21
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
### Additions and Improvements
1414
- Extend `Blockchain` service [#6592](https://github.com/hyperledger/besu/pull/6592)
1515
- Add bft-style blockperiodseconds transitions to Clique [#6596](https://github.com/hyperledger/besu/pull/6596)
16+
- Add createemptyblocks transitions to Clique [#6608](https://github.com/hyperledger/besu/pull/6608)
1617
- RocksDB database metadata refactoring [#6555](https://github.com/hyperledger/besu/pull/6555)
1718
- Make layered txpool aware of minGasPrice and minPriorityFeePerGas dynamic options [#6611](https://github.com/hyperledger/besu/pull/6611)
1819
- Update commons-compress to 1.26.0 [#6648](https://github.com/hyperledger/besu/pull/6648)

acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/clique/CliqueMiningAcceptanceTest.java

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public void shouldNotMineBlocksIfNoTransactionsWhenCreateEmptyBlockIsFalse() thr
6464
}
6565

6666
@Test
67-
public void shouldMineBlocksOnlyWhenTransactionsArePresentWhenCreateEmptyBlockIsFalse()
67+
public void shouldMineBlocksOnlyWhenTransactionsArePresentWhenCreateEmptyBlocksIsFalse()
6868
throws IOException {
6969
final var cliqueOptionsNoEmptyBlocks =
7070
new CliqueOptions(
@@ -134,7 +134,7 @@ public void shouldStillMineWhenANodeFailsAndHasSufficientValidators() throws IOE
134134
}
135135

136136
@Test
137-
public void shouldMineBlocksWithBlockPeriodAccordingToTransitions() throws IOException {
137+
public void shouldMineBlocksAccordingToBlockPeriodTransitions() throws IOException {
138138

139139
final var cliqueOptions = new CliqueOptions(3, CliqueOptions.DEFAULT.epochLength(), true);
140140
final BesuNode minerNode = besu.createCliqueNode("miner1", cliqueOptions);
@@ -144,6 +144,8 @@ public void shouldMineBlocksWithBlockPeriodAccordingToTransitions() throws IOExc
144144
Map.of("block", 3, "blockperiodseconds", 2);
145145
final Map<String, Object> decreasePeriodTo1_Transition =
146146
Map.of("block", 4, "blockperiodseconds", 1);
147+
// ensure previous blockperiodseconds transition is carried over
148+
final Map<String, Object> dummy_Transition = Map.of("block", 5, "createemptyblocks", true);
147149
final Map<String, Object> increasePeriodTo2_Transition =
148150
Map.of("block", 6, "blockperiodseconds", 2);
149151

@@ -155,6 +157,7 @@ public void shouldMineBlocksWithBlockPeriodAccordingToTransitions() throws IOExc
155157
List.of(
156158
decreasePeriodTo2_Transition,
157159
decreasePeriodTo1_Transition,
160+
dummy_Transition,
158161
increasePeriodTo2_Transition));
159162
minerNode.setGenesisConfig(genesisWithTransitions);
160163

@@ -176,6 +179,59 @@ public void shouldMineBlocksWithBlockPeriodAccordingToTransitions() throws IOExc
176179
assertThat(block6Timestamp - block5Timestamp).isCloseTo(2, withPercentage(20));
177180
}
178181

182+
@Test
183+
public void shouldMineBlocksAccordingToCreateEmptyBlocksTransitions() throws IOException {
184+
185+
final var cliqueOptionsEmptyBlocks =
186+
new CliqueOptions(2, CliqueOptions.DEFAULT.epochLength(), true);
187+
final BesuNode minerNode = besu.createCliqueNode("miner1", cliqueOptionsEmptyBlocks);
188+
189+
// setup transitions
190+
final Map<String, Object> noEmptyBlocks_Transition =
191+
Map.of("block", 3, "createemptyblocks", false);
192+
final Map<String, Object> emptyBlocks_Transition =
193+
Map.of("block", 4, "createemptyblocks", true);
194+
final Map<String, Object> secondNoEmptyBlocks_Transition =
195+
Map.of("block", 6, "createemptyblocks", false);
196+
// ensure previous createemptyblocks transition is carried over
197+
final Map<String, Object> dummy_Transition = Map.of("block", 7, "blockperiodseconds", 1);
198+
199+
final Optional<String> initialGenesis =
200+
minerNode.getGenesisConfigProvider().create(List.of(minerNode));
201+
final String genesisWithTransitions =
202+
prependTransitionsToCliqueOptions(
203+
initialGenesis.orElseThrow(),
204+
List.of(
205+
noEmptyBlocks_Transition,
206+
emptyBlocks_Transition,
207+
secondNoEmptyBlocks_Transition,
208+
dummy_Transition));
209+
minerNode.setGenesisConfig(genesisWithTransitions);
210+
211+
final Account sender = accounts.createAccount("account1");
212+
213+
// Mine 2 blocks
214+
cluster.start(minerNode);
215+
minerNode.verify(blockchain.reachesHeight(minerNode, 1));
216+
217+
// tx required to mine block
218+
cluster.verify(clique.noNewBlockCreated(minerNode));
219+
minerNode.execute(accountTransactions.createTransfer(sender, 50));
220+
minerNode.verify(clique.blockIsCreatedByProposer(minerNode));
221+
222+
// Mine 2 more blocks so chain head is 5
223+
minerNode.verify(blockchain.reachesHeight(minerNode, 2));
224+
225+
// tx required to mine block 6
226+
cluster.verify(clique.noNewBlockCreated(minerNode));
227+
minerNode.execute(accountTransactions.createTransfer(sender, 50));
228+
minerNode.verify(clique.blockIsCreatedByProposer(minerNode));
229+
230+
// check createemptyblocks transition carried over when other transition activated...
231+
// tx required to mine block 7
232+
cluster.verify(clique.noNewBlockCreated(minerNode));
233+
}
234+
179235
private long getTimestampForBlock(final BesuNode minerNode, final int blockNumber) {
180236
return minerNode
181237
.execute(

besu/src/main/java/org/hyperledger/besu/controller/CliqueBesuControllerBuilder.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ public class CliqueBesuControllerBuilder extends BesuControllerBuilder {
5454

5555
private Address localAddress;
5656
private EpochManager epochManager;
57-
private boolean createEmptyBlocks = true;
5857
private final BlockInterface blockInterface = new CliqueBlockInterface();
5958
private ForksSchedule<CliqueConfigOptions> forksSchedule;
6059

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

6866
epochManager = new EpochManager(blocksPerEpoch);
6967
forksSchedule = CliqueForksSchedulesFactory.create(configOptionsSupplier.get());
@@ -96,7 +94,7 @@ protected MiningCoordinator createMiningCoordinator(
9694
localAddress,
9795
forksSchedule),
9896
epochManager,
99-
createEmptyBlocks,
97+
forksSchedule,
10098
ethProtocolManager.ethContext().getScheduler());
10199
final CliqueMiningCoordinator miningCoordinator =
102100
new CliqueMiningCoordinator(

config/src/main/java/org/hyperledger/besu/config/CliqueFork.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
*/
1515
package org.hyperledger.besu.config;
1616

17+
import java.util.Optional;
1718
import java.util.OptionalInt;
1819

1920
import com.fasterxml.jackson.annotation.JsonCreator;
@@ -28,6 +29,9 @@ public class CliqueFork implements Fork {
2829
/** The constant BLOCK_PERIOD_SECONDS_KEY. */
2930
public static final String BLOCK_PERIOD_SECONDS_KEY = "blockperiodseconds";
3031

32+
/** The constant CREATE_EMPTY_BLOCKS_KEY. */
33+
public static final String CREATE_EMPTY_BLOCKS_KEY = "createemptyblocks";
34+
3135
/** The Fork config root. */
3236
protected final ObjectNode forkConfigRoot;
3337

@@ -63,4 +67,13 @@ public long getForkBlock() {
6367
public OptionalInt getBlockPeriodSeconds() {
6468
return JsonUtil.getPositiveInt(forkConfigRoot, BLOCK_PERIOD_SECONDS_KEY);
6569
}
70+
71+
/**
72+
* Gets create empty blocks.
73+
*
74+
* @return the create empty blocks
75+
*/
76+
public Optional<Boolean> getCreateEmptyBlocks() {
77+
return JsonUtil.getBoolean(forkConfigRoot, CREATE_EMPTY_BLOCKS_KEY);
78+
}
6679
}

consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/CliqueForksSchedulesFactory.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ private static CliqueConfigOptions createCliqueConfigOptions(
4444

4545
var options = ImmutableCliqueConfigOptions.builder().from(lastSpec.getValue());
4646
fork.getBlockPeriodSeconds().ifPresent(options::blockPeriodSeconds);
47+
fork.getCreateEmptyBlocks().ifPresent(options::createEmptyBlocks);
4748
return options.build();
4849
}
4950
}

consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/CliqueProtocolSchedule.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
import java.util.Optional;
4343
import java.util.function.Function;
4444

45+
import com.google.common.annotations.VisibleForTesting;
46+
4547
/** Defines the protocol behaviours for a blockchain using Clique. */
4648
public class CliqueProtocolSchedule {
4749

@@ -89,7 +91,7 @@ public static ProtocolSchedule create(
8991
applyCliqueSpecificModifications(
9092
epochManager,
9193
forkSpec.getValue().getBlockPeriodSeconds(),
92-
cliqueConfig.getCreateEmptyBlocks(),
94+
forkSpec.getValue().getCreateEmptyBlocks(),
9395
localNodeAddress,
9496
builder)));
9597
final ProtocolSpecAdapters specAdapters = new ProtocolSpecAdapters(specMap);
@@ -116,6 +118,7 @@ public static ProtocolSchedule create(
116118
* @param badBlockManager the cache to use to keep invalid blocks
117119
* @return the protocol schedule
118120
*/
121+
@VisibleForTesting
119122
public static ProtocolSchedule create(
120123
final GenesisConfigOptions config,
121124
final ForksSchedule<CliqueConfigOptions> forksSchedule,

consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockMiner.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
*/
1515
package org.hyperledger.besu.consensus.clique.blockcreation;
1616

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

3840
private final Address localAddress;
39-
private final boolean createEmptyBlocks;
41+
private final ForksSchedule<CliqueConfigOptions> forksSchedule;
4042

4143
/**
4244
* Instantiates a new Clique block miner.
@@ -48,7 +50,7 @@ public class CliqueBlockMiner extends BlockMiner<CliqueBlockCreator> {
4850
* @param scheduler the scheduler
4951
* @param parentHeader the parent header
5052
* @param localAddress the local address
51-
* @param createEmptyBlocks whether clique should allow the creation of empty blocks.
53+
* @param forksSchedule the transitions
5254
*/
5355
public CliqueBlockMiner(
5456
final Function<BlockHeader, CliqueBlockCreator> blockCreator,
@@ -58,10 +60,10 @@ public CliqueBlockMiner(
5860
final AbstractBlockScheduler scheduler,
5961
final BlockHeader parentHeader,
6062
final Address localAddress,
61-
final boolean createEmptyBlocks) {
63+
final ForksSchedule<CliqueConfigOptions> forksSchedule) {
6264
super(blockCreator, protocolSchedule, protocolContext, observers, scheduler, parentHeader);
6365
this.localAddress = localAddress;
64-
this.createEmptyBlocks = createEmptyBlocks;
66+
this.forksSchedule = forksSchedule;
6567
}
6668

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

7779
@Override
7880
protected boolean shouldImportBlock(final Block block) throws InterruptedException {
79-
if (createEmptyBlocks) {
81+
if (forksSchedule.getFork(block.getHeader().getNumber()).getValue().getCreateEmptyBlocks()) {
8082
return true;
8183
}
8284

consensus/clique/src/main/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutor.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@
1414
*/
1515
package org.hyperledger.besu.consensus.clique.blockcreation;
1616

17+
import org.hyperledger.besu.config.CliqueConfigOptions;
1718
import org.hyperledger.besu.consensus.clique.CliqueContext;
1819
import org.hyperledger.besu.consensus.clique.CliqueExtraData;
1920
import org.hyperledger.besu.consensus.common.ConsensusHelpers;
2021
import org.hyperledger.besu.consensus.common.EpochManager;
22+
import org.hyperledger.besu.consensus.common.ForksSchedule;
2123
import org.hyperledger.besu.cryptoservices.NodeKey;
2224
import org.hyperledger.besu.datatypes.Address;
2325
import org.hyperledger.besu.ethereum.ProtocolContext;
@@ -48,7 +50,7 @@ public class CliqueMinerExecutor extends AbstractMinerExecutor<CliqueBlockMiner>
4850
private final Address localAddress;
4951
private final NodeKey nodeKey;
5052
private final EpochManager epochManager;
51-
private final boolean createEmptyBlocks;
53+
private final ForksSchedule<CliqueConfigOptions> forksSchedule;
5254

5355
/**
5456
* Instantiates a new Clique miner executor.
@@ -60,7 +62,7 @@ public class CliqueMinerExecutor extends AbstractMinerExecutor<CliqueBlockMiner>
6062
* @param miningParams the mining params
6163
* @param blockScheduler the block scheduler
6264
* @param epochManager the epoch manager
63-
* @param createEmptyBlocks whether clique should allow the creation of empty blocks.
65+
* @param forksSchedule the clique transitions
6466
* @param ethScheduler the scheduler for asynchronous block creation tasks
6567
*/
6668
public CliqueMinerExecutor(
@@ -71,7 +73,7 @@ public CliqueMinerExecutor(
7173
final MiningParameters miningParams,
7274
final AbstractBlockScheduler blockScheduler,
7375
final EpochManager epochManager,
74-
final boolean createEmptyBlocks,
76+
final ForksSchedule<CliqueConfigOptions> forksSchedule,
7577
final EthScheduler ethScheduler) {
7678
super(
7779
protocolContext,
@@ -83,7 +85,7 @@ public CliqueMinerExecutor(
8385
this.nodeKey = nodeKey;
8486
this.localAddress = Util.publicKeyToAddress(nodeKey.getPublicKey());
8587
this.epochManager = epochManager;
86-
this.createEmptyBlocks = createEmptyBlocks;
88+
this.forksSchedule = forksSchedule;
8789
miningParams.setCoinbase(localAddress);
8890
}
8991

@@ -113,7 +115,7 @@ public CliqueBlockMiner createMiner(
113115
blockScheduler,
114116
parentHeader,
115117
localAddress,
116-
createEmptyBlocks);
118+
forksSchedule);
117119
}
118120

119121
@Override

consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockMinerTest.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@
2323
import static org.mockito.Mockito.verify;
2424
import static org.mockito.Mockito.when;
2525

26+
import org.hyperledger.besu.config.CliqueConfigOptions;
27+
import org.hyperledger.besu.config.ImmutableCliqueConfigOptions;
28+
import org.hyperledger.besu.config.JsonCliqueConfigOptions;
2629
import org.hyperledger.besu.consensus.clique.CliqueContext;
30+
import org.hyperledger.besu.consensus.common.ForkSpec;
31+
import org.hyperledger.besu.consensus.common.ForksSchedule;
2732
import org.hyperledger.besu.consensus.common.validator.ValidatorProvider;
2833
import org.hyperledger.besu.crypto.KeyPair;
2934
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
@@ -54,10 +59,20 @@
5459
import java.util.function.Function;
5560

5661
import com.google.common.collect.Lists;
62+
import org.junit.jupiter.api.BeforeEach;
5763
import org.junit.jupiter.api.Test;
5864

5965
class CliqueBlockMinerTest {
6066

67+
private ForksSchedule<CliqueConfigOptions> forksSchedule;
68+
69+
@BeforeEach
70+
public void setup() {
71+
var options = ImmutableCliqueConfigOptions.builder().from(JsonCliqueConfigOptions.DEFAULT);
72+
options.createEmptyBlocks(false);
73+
forksSchedule = new ForksSchedule<>(List.of(new ForkSpec<>(0, options.build())));
74+
}
75+
6176
@Test
6277
void doesNotMineBlockIfNoTransactionsWhenEmptyBlocksNotAllowed() throws InterruptedException {
6378
final BlockHeaderTestFixture headerBuilder = new BlockHeaderTestFixture();
@@ -100,7 +115,7 @@ void doesNotMineBlockIfNoTransactionsWhenEmptyBlocksNotAllowed() throws Interrup
100115
scheduler,
101116
headerBuilder.buildHeader(),
102117
Address.ZERO,
103-
false); // parent header is arbitrary for the test.
118+
forksSchedule); // parent header is arbitrary for the test.
104119

105120
final boolean result = miner.mineBlock();
106121
assertThat(result).isFalse();
@@ -155,7 +170,7 @@ void minesBlockIfHasTransactionsWhenEmptyBlocksNotAllowed() throws InterruptedEx
155170
scheduler,
156171
headerBuilder.buildHeader(),
157172
Address.ZERO,
158-
false); // parent header is arbitrary for the test.
173+
forksSchedule); // parent header is arbitrary for the test.
159174

160175
final boolean result = miner.mineBlock();
161176
assertThat(result).isTrue();

consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueMinerExecutorTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ public void extraDataCreatedOnEpochBlocksContainsValidators() {
124124
miningParameters,
125125
mock(CliqueBlockScheduler.class),
126126
new EpochManager(EPOCH_LENGTH),
127-
true,
127+
null,
128128
ethScheduler);
129129

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

166166
// Parent block was epoch, so the next block should contain no validators.
@@ -196,7 +196,7 @@ public void shouldUseLatestVanityData() {
196196
miningParameters,
197197
mock(CliqueBlockScheduler.class),
198198
new EpochManager(EPOCH_LENGTH),
199-
true,
199+
null,
200200
ethScheduler);
201201

202202
executor.setExtraData(modifiedVanityData);

0 commit comments

Comments
 (0)