Skip to content

Commit

Permalink
Common Bft forks schedule (hyperledger#2862)
Browse files Browse the repository at this point in the history
Signed-off-by: Jason Frame <[email protected]>
  • Loading branch information
jframe authored and eum602 committed Nov 3, 2023
1 parent 244a07d commit 83bca7c
Show file tree
Hide file tree
Showing 29 changed files with 990 additions and 439 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.hyperledger.besu.consensus.common.bft.BftEventQueue;
import org.hyperledger.besu.consensus.common.bft.BftExecutors;
import org.hyperledger.besu.consensus.common.bft.BftExtraDataCodec;
import org.hyperledger.besu.consensus.common.bft.BftForksSchedule;
import org.hyperledger.besu.consensus.common.bft.BftProcessor;
import org.hyperledger.besu.consensus.common.bft.BlockTimer;
import org.hyperledger.besu.consensus.common.bft.EthSynchronizerUpdater;
Expand Down Expand Up @@ -56,10 +57,9 @@
import org.hyperledger.besu.consensus.qbft.statemachine.QbftRoundFactory;
import org.hyperledger.besu.consensus.qbft.validation.MessageValidatorFactory;
import org.hyperledger.besu.consensus.qbft.validator.ForkingValidatorProvider;
import org.hyperledger.besu.consensus.qbft.validator.QbftForksSchedulesFactory;
import org.hyperledger.besu.consensus.qbft.validator.TransactionValidatorProvider;
import org.hyperledger.besu.consensus.qbft.validator.ValidatorContractController;
import org.hyperledger.besu.consensus.qbft.validator.ValidatorSelectorConfig;
import org.hyperledger.besu.consensus.qbft.validator.ValidatorSelectorForksSchedule;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.methods.JsonRpcMethods;
Expand All @@ -83,7 +83,6 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Collectors;

Expand All @@ -96,7 +95,7 @@ public class QbftBesuControllerBuilder extends BftBesuControllerBuilder {
private static final Logger LOG = LogManager.getLogger();
private BftEventQueue bftEventQueue;
private QbftConfigOptions qbftConfig;
private ValidatorSelectorForksSchedule qbftForksSchedule;
private BftForksSchedule<QbftConfigOptions> qbftForksSchedule;
private ValidatorPeers peers;

@Override
Expand Down Expand Up @@ -288,11 +287,7 @@ private boolean usingValidatorBlockHeaderModeButNoSignersIn(
}

private boolean isValidatorContractMode(final GenesisConfigFile genesisConfig) {
return genesisConfig
.getConfigOptions()
.getQbftConfigOptions()
.getValidatorContractAddress()
.isPresent();
return genesisConfig.getConfigOptions().getQbftConfigOptions().isValidatorContractMode();
}

private boolean signersExistIn(final BlockHeader genesisBlockHeader) {
Expand Down Expand Up @@ -325,14 +320,10 @@ protected BftContext createConsensusContext(
validatorProvider, epochManager, bftBlockInterface().get(), pkiBlockCreationConfiguration);
}

private ValidatorSelectorForksSchedule createQbftForksSchedule(
private BftForksSchedule<QbftConfigOptions> createQbftForksSchedule(
final GenesisConfigOptions configOptions) {
final ValidatorSelectorConfig initialFork =
ValidatorSelectorConfig.fromQbftConfig(configOptions.getQbftConfigOptions());
final List<ValidatorSelectorConfig> validatorSelectionForks =
convertToValidatorSelectionConfig(
genesisConfig.getConfigOptions().getTransitions().getQbftForks());
return new ValidatorSelectorForksSchedule(initialFork, validatorSelectionForks);
return QbftForksSchedulesFactory.create(
configOptions.getQbftConfigOptions(), configOptions.getTransitions().getQbftForks());
}

private BftValidatorOverrides convertBftForks(final List<QbftFork> bftForks) {
Expand All @@ -352,14 +343,6 @@ private BftValidatorOverrides convertBftForks(final List<QbftFork> bftForks) {
return new BftValidatorOverrides(result);
}

private List<ValidatorSelectorConfig> convertToValidatorSelectionConfig(
final List<QbftFork> qbftForks) {
return qbftForks.stream()
.map(ValidatorSelectorConfig::fromQbftFork)
.flatMap(Optional::stream)
.collect(Collectors.toList());
}

private static MinedBlockObserver blockLogger(
final TransactionPool transactionPool, final Address localAddress) {
return block ->
Expand Down
105 changes: 12 additions & 93 deletions config/src/main/java/org/hyperledger/besu/config/BftConfigOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,108 +18,27 @@
import java.util.Map;
import java.util.Optional;

import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.ImmutableMap;
import org.apache.tuweni.bytes.Bytes;
public interface BftConfigOptions {

public class BftConfigOptions {
long getEpochLength();

public static final BftConfigOptions DEFAULT =
new BftConfigOptions(JsonUtil.createEmptyObjectNode());
int getBlockPeriodSeconds();

private static final long DEFAULT_EPOCH_LENGTH = 30_000;
private static final int DEFAULT_BLOCK_PERIOD_SECONDS = 1;
private static final int DEFAULT_ROUND_EXPIRY_SECONDS = 1;
// In a healthy network this can be very small. This default limit will allow for suitable
// protection for on a typical 20 node validator network with multiple rounds
private static final int DEFAULT_GOSSIPED_HISTORY_LIMIT = 1000;
private static final int DEFAULT_MESSAGE_QUEUE_LIMIT = 1000;
private static final int DEFAULT_DUPLICATE_MESSAGE_LIMIT = 100;
private static final int DEFAULT_FUTURE_MESSAGES_LIMIT = 1000;
private static final int DEFAULT_FUTURE_MESSAGES_MAX_DISTANCE = 10;
int getRequestTimeoutSeconds();

protected final ObjectNode bftConfigRoot;
int getGossipedHistoryLimit();

BftConfigOptions(final ObjectNode bftConfigRoot) {
this.bftConfigRoot = bftConfigRoot;
}
int getMessageQueueLimit();

public long getEpochLength() {
return JsonUtil.getLong(bftConfigRoot, "epochlength", DEFAULT_EPOCH_LENGTH);
}
int getDuplicateMessageLimit();

public int getBlockPeriodSeconds() {
return JsonUtil.getInt(bftConfigRoot, "blockperiodseconds", DEFAULT_BLOCK_PERIOD_SECONDS);
}
int getFutureMessagesLimit();

public int getRequestTimeoutSeconds() {
return JsonUtil.getInt(bftConfigRoot, "requesttimeoutseconds", DEFAULT_ROUND_EXPIRY_SECONDS);
}
int getFutureMessagesMaxDistance();

public int getGossipedHistoryLimit() {
return JsonUtil.getInt(bftConfigRoot, "gossipedhistorylimit", DEFAULT_GOSSIPED_HISTORY_LIMIT);
}
Optional<String> getMiningBeneficiary();

public int getMessageQueueLimit() {
return JsonUtil.getInt(bftConfigRoot, "messagequeuelimit", DEFAULT_MESSAGE_QUEUE_LIMIT);
}
BigInteger getBlockRewardWei();

public int getDuplicateMessageLimit() {
return JsonUtil.getInt(bftConfigRoot, "duplicatemessagelimit", DEFAULT_DUPLICATE_MESSAGE_LIMIT);
}

public int getFutureMessagesLimit() {
return JsonUtil.getInt(bftConfigRoot, "futuremessageslimit", DEFAULT_FUTURE_MESSAGES_LIMIT);
}

public int getFutureMessagesMaxDistance() {
return JsonUtil.getInt(
bftConfigRoot, "futuremessagesmaxdistance", DEFAULT_FUTURE_MESSAGES_MAX_DISTANCE);
}

public Optional<String> getMiningBeneficiary() {
return JsonUtil.getString(bftConfigRoot, "miningbeneficiary");
}

public BigInteger getBlockRewardWei() {
final Optional<String> configFileContent = JsonUtil.getString(bftConfigRoot, "blockreward");

if (configFileContent.isEmpty()) {
return BigInteger.ZERO;
}
final String weiStr = configFileContent.get();
if (weiStr.startsWith("0x")) {
return new BigInteger(1, Bytes.fromHexStringLenient(weiStr).toArrayUnsafe());
}
return new BigInteger(weiStr);
}

Map<String, Object> asMap() {
final ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder();
if (bftConfigRoot.has("epochlength")) {
builder.put("epochLength", getEpochLength());
}
if (bftConfigRoot.has("blockperiodseconds")) {
builder.put("blockPeriodSeconds", getBlockPeriodSeconds());
}
if (bftConfigRoot.has("requesttimeoutseconds")) {
builder.put("requestTimeoutSeconds", getRequestTimeoutSeconds());
}
if (bftConfigRoot.has("gossipedhistorylimit")) {
builder.put("gossipedHistoryLimit", getGossipedHistoryLimit());
}
if (bftConfigRoot.has("messagequeuelimit")) {
builder.put("messageQueueLimit", getMessageQueueLimit());
}
if (bftConfigRoot.has("duplicatemessagelimit")) {
builder.put("duplicateMessageLimit", getDuplicateMessageLimit());
}
if (bftConfigRoot.has("futuremessageslimit")) {
builder.put("futureMessagesLimit", getFutureMessagesLimit());
}
if (bftConfigRoot.has("futuremessagesmaxdistance")) {
builder.put("futureMessagesMaxDistance", getFutureMessagesMaxDistance());
}
return builder.build();
}
Map<String, Object> asMap();
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public Optional<BigInteger> getBlockRewardWei() {
return Optional.empty();
}
final String weiStr = configFileContent.get();
if (weiStr.startsWith("0x")) {
if (weiStr.toLowerCase().startsWith("0x")) {
return Optional.of(new BigInteger(1, Bytes.fromHexStringLenient(weiStr).toArrayUnsafe()));
}
return Optional.of(new BigInteger(weiStr));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
* 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.config;

import java.math.BigInteger;
import java.util.Map;
import java.util.Optional;

import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.ImmutableMap;
import org.apache.tuweni.bytes.Bytes;

public class JsonBftConfigOptions implements BftConfigOptions {

public static final JsonBftConfigOptions DEFAULT =
new JsonBftConfigOptions(JsonUtil.createEmptyObjectNode());

private static final long DEFAULT_EPOCH_LENGTH = 30_000;
private static final int DEFAULT_BLOCK_PERIOD_SECONDS = 1;
private static final int DEFAULT_ROUND_EXPIRY_SECONDS = 1;
// In a healthy network this can be very small. This default limit will allow for suitable
// protection for on a typical 20 node validator network with multiple rounds
private static final int DEFAULT_GOSSIPED_HISTORY_LIMIT = 1000;
private static final int DEFAULT_MESSAGE_QUEUE_LIMIT = 1000;
private static final int DEFAULT_DUPLICATE_MESSAGE_LIMIT = 100;
private static final int DEFAULT_FUTURE_MESSAGES_LIMIT = 1000;
private static final int DEFAULT_FUTURE_MESSAGES_MAX_DISTANCE = 10;

protected final ObjectNode bftConfigRoot;

JsonBftConfigOptions(final ObjectNode bftConfigRoot) {
this.bftConfigRoot = bftConfigRoot;
}

@Override
public long getEpochLength() {
return JsonUtil.getLong(bftConfigRoot, "epochlength", DEFAULT_EPOCH_LENGTH);
}

@Override
public int getBlockPeriodSeconds() {
return JsonUtil.getInt(bftConfigRoot, "blockperiodseconds", DEFAULT_BLOCK_PERIOD_SECONDS);
}

@Override
public int getRequestTimeoutSeconds() {
return JsonUtil.getInt(bftConfigRoot, "requesttimeoutseconds", DEFAULT_ROUND_EXPIRY_SECONDS);
}

@Override
public int getGossipedHistoryLimit() {
return JsonUtil.getInt(bftConfigRoot, "gossipedhistorylimit", DEFAULT_GOSSIPED_HISTORY_LIMIT);
}

@Override
public int getMessageQueueLimit() {
return JsonUtil.getInt(bftConfigRoot, "messagequeuelimit", DEFAULT_MESSAGE_QUEUE_LIMIT);
}

@Override
public int getDuplicateMessageLimit() {
return JsonUtil.getInt(bftConfigRoot, "duplicatemessagelimit", DEFAULT_DUPLICATE_MESSAGE_LIMIT);
}

@Override
public int getFutureMessagesLimit() {
return JsonUtil.getInt(bftConfigRoot, "futuremessageslimit", DEFAULT_FUTURE_MESSAGES_LIMIT);
}

@Override
public int getFutureMessagesMaxDistance() {
return JsonUtil.getInt(
bftConfigRoot, "futuremessagesmaxdistance", DEFAULT_FUTURE_MESSAGES_MAX_DISTANCE);
}

@Override
public Optional<String> getMiningBeneficiary() {
return JsonUtil.getString(bftConfigRoot, "miningbeneficiary");
}

@Override
public BigInteger getBlockRewardWei() {
final Optional<String> configFileContent = JsonUtil.getString(bftConfigRoot, "blockreward");

if (configFileContent.isEmpty()) {
return BigInteger.ZERO;
}
final String weiStr = configFileContent.get();
if (weiStr.toLowerCase().startsWith("0x")) {
return new BigInteger(1, Bytes.fromHexStringLenient(weiStr).toArrayUnsafe());
}
return new BigInteger(weiStr);
}

@Override
public Map<String, Object> asMap() {
final ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder();
if (bftConfigRoot.has("epochlength")) {
builder.put("epochLength", getEpochLength());
}
if (bftConfigRoot.has("blockperiodseconds")) {
builder.put("blockPeriodSeconds", getBlockPeriodSeconds());
}
if (bftConfigRoot.has("requesttimeoutseconds")) {
builder.put("requestTimeoutSeconds", getRequestTimeoutSeconds());
}
if (bftConfigRoot.has("gossipedhistorylimit")) {
builder.put("gossipedHistoryLimit", getGossipedHistoryLimit());
}
if (bftConfigRoot.has("messagequeuelimit")) {
builder.put("messageQueueLimit", getMessageQueueLimit());
}
if (bftConfigRoot.has("duplicatemessagelimit")) {
builder.put("duplicateMessageLimit", getDuplicateMessageLimit());
}
if (bftConfigRoot.has("futuremessageslimit")) {
builder.put("futureMessagesLimit", getFutureMessagesLimit());
}
if (bftConfigRoot.has("futuremessagesmaxdistance")) {
builder.put("futureMessagesMaxDistance", getFutureMessagesMaxDistance());
}
return builder.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -150,15 +150,15 @@ public IbftLegacyConfigOptions getIbftLegacyConfigOptions() {
public BftConfigOptions getBftConfigOptions() {
final String fieldKey = isIbft2() ? IBFT2_CONFIG_KEY : QBFT_CONFIG_KEY;
return JsonUtil.getObjectNode(configRoot, fieldKey)
.map(BftConfigOptions::new)
.orElse(BftConfigOptions.DEFAULT);
.map(JsonBftConfigOptions::new)
.orElse(JsonBftConfigOptions.DEFAULT);
}

@Override
public QbftConfigOptions getQbftConfigOptions() {
return JsonUtil.getObjectNode(configRoot, QBFT_CONFIG_KEY)
.map(QbftConfigOptions::new)
.orElse(QbftConfigOptions.DEFAULT);
.map(JsonQbftConfigOptions::new)
.orElse(JsonQbftConfigOptions.DEFAULT);
}

@Override
Expand Down
Loading

0 comments on commit 83bca7c

Please sign in to comment.