Skip to content

Commit

Permalink
Change Qbft to use its own QbftBlockHeader type (#8244)
Browse files Browse the repository at this point in the history
Signed-off-by: Jason Frame <[email protected]>
  • Loading branch information
jframe authored Feb 7, 2025
1 parent e835cd0 commit a021fea
Show file tree
Hide file tree
Showing 69 changed files with 1,572 additions and 345 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public void shouldBeStableDuringLongTest(
} catch (RuntimeException e) {
assertThat(e.getMessage())
.contains(
"Revert reason: 'Transaction processing could not be completed due to an exception'");
"Revert reason: 'Transaction processing could not be completed due to an exception (Invalid opcode: 0x5f)'");
}

// Should initially be set to 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.hyperledger.besu.consensus.common.BftValidatorOverrides;
import org.hyperledger.besu.consensus.common.EpochManager;
import org.hyperledger.besu.consensus.common.ForksSchedule;
import org.hyperledger.besu.consensus.common.bft.BftBlockHashing;
import org.hyperledger.besu.consensus.common.bft.BftBlockInterface;
import org.hyperledger.besu.consensus.common.bft.BftContext;
import org.hyperledger.besu.consensus.common.bft.BftEventQueue;
Expand All @@ -46,13 +47,18 @@
import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec;
import org.hyperledger.besu.consensus.qbft.QbftForksSchedulesFactory;
import org.hyperledger.besu.consensus.qbft.QbftProtocolScheduleBuilder;
import org.hyperledger.besu.consensus.qbft.adaptor.BftEventHandlerAdaptor;
import org.hyperledger.besu.consensus.qbft.adaptor.BlockUtil;
import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockCodecAdaptor;
import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockCreatorFactoryAdaptor;
import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockHashingAdaptor;
import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockInterfaceAdaptor;
import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockchainAdaptor;
import org.hyperledger.besu.consensus.qbft.adaptor.QbftExtraDataProviderAdaptor;
import org.hyperledger.besu.consensus.qbft.adaptor.QbftFinalStateImpl;
import org.hyperledger.besu.consensus.qbft.adaptor.QbftProtocolScheduleAdaptor;
import org.hyperledger.besu.consensus.qbft.adaptor.QbftValidatorModeTransitionLoggerAdaptor;
import org.hyperledger.besu.consensus.qbft.adaptor.QbftValidatorProviderAdaptor;
import org.hyperledger.besu.consensus.qbft.blockcreation.QbftBlockCreatorFactory;
import org.hyperledger.besu.consensus.qbft.core.network.QbftGossip;
import org.hyperledger.besu.consensus.qbft.core.payload.MessageFactory;
Expand All @@ -62,16 +68,18 @@
import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCodec;
import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockInterface;
import org.hyperledger.besu.consensus.qbft.core.types.QbftContext;
import org.hyperledger.besu.consensus.qbft.core.types.QbftEventHandler;
import org.hyperledger.besu.consensus.qbft.core.types.QbftFinalState;
import org.hyperledger.besu.consensus.qbft.core.types.QbftMinedBlockObserver;
import org.hyperledger.besu.consensus.qbft.core.types.QbftProtocolSchedule;
import org.hyperledger.besu.consensus.qbft.core.types.QbftValidatorProvider;
import org.hyperledger.besu.consensus.qbft.core.validation.MessageValidatorFactory;
import org.hyperledger.besu.consensus.qbft.core.validator.ValidatorModeTransitionLogger;
import org.hyperledger.besu.consensus.qbft.jsonrpc.QbftJsonRpcMethods;
import org.hyperledger.besu.consensus.qbft.protocol.Istanbul100SubProtocol;
import org.hyperledger.besu.consensus.qbft.validator.ForkingValidatorProvider;
import org.hyperledger.besu.consensus.qbft.validator.TransactionValidatorProvider;
import org.hyperledger.besu.consensus.qbft.validator.ValidatorContractController;
import org.hyperledger.besu.consensus.qbft.validator.ValidatorModeTransitionLogger;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.methods.JsonRpcMethods;
Expand Down Expand Up @@ -209,9 +217,11 @@ protected MiningCoordinator createMiningCoordinator(

final ValidatorProvider validatorProvider =
protocolContext.getConsensusContext(BftContext.class).getValidatorProvider();
final QbftValidatorProvider qbftValidatorProvider =
new QbftValidatorProviderAdaptor(validatorProvider);

final QbftBlockInterface qbftBlockInterface = new QbftBlockInterfaceAdaptor(bftBlockInterface);
final QbftContext qbftContext = new QbftContext(validatorProvider, qbftBlockInterface);
final QbftContext qbftContext = new QbftContext(qbftValidatorProvider, qbftBlockInterface);
final ProtocolContext qbftProtocolContext =
new ProtocolContext(
blockchain,
Expand Down Expand Up @@ -267,42 +277,47 @@ protected MiningCoordinator createMiningCoordinator(

final MessageFactory messageFactory = new MessageFactory(nodeKey, blockEncoder);

QbftRoundFactory qbftRoundFactory =
new QbftRoundFactory(
finalState,
qbftProtocolContext,
qbftProtocolSchedule,
minedBlockObservers,
messageValidatorFactory,
messageFactory,
qbftExtraDataCodec,
new QbftExtraDataProviderAdaptor(qbftExtraDataCodec),
new QbftBlockHashingAdaptor(new BftBlockHashing(qbftExtraDataCodec)));
QbftBlockHeightManagerFactory qbftBlockHeightManagerFactory =
new QbftBlockHeightManagerFactory(
finalState,
new QbftRoundFactory(
finalState,
qbftProtocolContext,
qbftProtocolSchedule,
minedBlockObservers,
messageValidatorFactory,
messageFactory,
qbftExtraDataCodec,
new QbftExtraDataProviderAdaptor(qbftExtraDataCodec)),
qbftRoundFactory,
messageValidatorFactory,
messageFactory,
new ValidatorModeTransitionLogger(qbftForksSchedule));
new QbftValidatorModeTransitionLoggerAdaptor(
new ValidatorModeTransitionLogger(qbftForksSchedule)));

qbftBlockHeightManagerFactory.isEarlyRoundChangeEnabled(isEarlyRoundChangeEnabled);

final BftEventHandler qbftController =
final QbftEventHandler qbftController =
new QbftController(
blockchain,
new QbftBlockchainAdaptor(blockchain),
finalState,
qbftBlockHeightManagerFactory,
gossiper,
duplicateMessageTracker,
futureMessageBuffer,
new EthSynchronizerUpdater(ethProtocolManager.ethContext().getEthPeers()),
blockEncoder);
final BftEventHandler bftEventHandler = new BftEventHandlerAdaptor(qbftController);

final EventMultiplexer eventMultiplexer = new EventMultiplexer(qbftController);
final EventMultiplexer eventMultiplexer = new EventMultiplexer(bftEventHandler);
final BftProcessor bftProcessor = new BftProcessor(bftEventQueue, eventMultiplexer);

final MiningCoordinator miningCoordinator =
new BftMiningCoordinator(
bftExecutors,
qbftController,
bftEventHandler,
bftProcessor,
blockCreatorFactory,
blockchain,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@
import org.hyperledger.besu.config.BftConfigOptions;
import org.hyperledger.besu.consensus.common.ForksSchedule;
import org.hyperledger.besu.consensus.common.bft.events.BlockTimerExpiry;
import org.hyperledger.besu.ethereum.core.BlockHeader;

import java.time.Clock;
import java.util.Optional;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -81,10 +81,10 @@ public synchronized boolean isRunning() {
* Starts a timer for the supplied round cancelling any previously active block timer
*
* @param round The round identifier which this timer is tracking
* @param chainHeadHeader The header of the chain head
* @param headerTimestamp The timestamp from the of the chain head header
*/
public synchronized void startTimer(
final ConsensusRoundIdentifier round, final BlockHeader chainHeadHeader) {
final ConsensusRoundIdentifier round, final Supplier<Long> headerTimestamp) {
cancelTimer();

final long expiryTime;
Expand All @@ -104,7 +104,7 @@ public synchronized void startTimer(
final int currentBlockPeriodSeconds =
forksSchedule.getFork(round.getSequenceNumber()).getValue().getBlockPeriodSeconds();
final long minimumTimeBetweenBlocksMillis = currentBlockPeriodSeconds * 1000L;
expiryTime = chainHeadHeader.getTimestamp() * 1_000 + minimumTimeBetweenBlocksMillis;
expiryTime = headerTimestamp.get() * 1_000 + minimumTimeBetweenBlocksMillis;
}

setBlockTimes(round);
Expand All @@ -115,14 +115,14 @@ public synchronized void startTimer(
/**
* Checks if the empty block timer is expired
*
* @param chainHeadHeader The header of the chain head
* @param headerTimestamp Function to get the chain head timestamp
* @param currentTimeInMillis The current time
* @return a boolean value
*/
public synchronized boolean checkEmptyBlockExpired(
final BlockHeader chainHeadHeader, final long currentTimeInMillis) {
final Supplier<Long> headerTimestamp, final long currentTimeInMillis) {
final long emptyBlockPeriodExpiryTime =
(chainHeadHeader.getTimestamp() + emptyBlockPeriodSeconds) * 1000;
(headerTimestamp.get() + emptyBlockPeriodSeconds) * 1000;

if (currentTimeInMillis > emptyBlockPeriodExpiryTime) {
LOG.debug("Empty Block expired");
Expand All @@ -136,15 +136,15 @@ public synchronized boolean checkEmptyBlockExpired(
* Resets the empty block timer
*
* @param roundIdentifier The current round identifier
* @param chainHeadHeader The header of the chain head
* @param headerTimestamp Function to get timestamp from the header of the chain head
* @param currentTimeInMillis The current time
*/
public void resetTimerForEmptyBlock(
final ConsensusRoundIdentifier roundIdentifier,
final BlockHeader chainHeadHeader,
final Supplier<Long> headerTimestamp,
final long currentTimeInMillis) {
final long emptyBlockPeriodExpiryTime =
(chainHeadHeader.getTimestamp() + emptyBlockPeriodSeconds) * 1000;
(headerTimestamp.get() + emptyBlockPeriodSeconds) * 1000;
final long nextBlockPeriodExpiryTime = currentTimeInMillis + blockPeriodSeconds * 1000;

startTimer(roundIdentifier, Math.min(emptyBlockPeriodExpiryTime, nextBlockPeriodExpiryTime));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ public void startTimerSchedulesCorrectlyWhenExpiryIsInTheFuture() {
bftExecutors.scheduleTask(any(Runnable.class), anyLong(), any()))
.thenReturn(mockedFuture);

timer.startTimer(round, header);
timer.startTimer(round, header::getTimestamp);
verify(bftExecutors)
.scheduleTask(any(Runnable.class), eq(EXPECTED_DELAY), eq(TimeUnit.MILLISECONDS));
}
Expand Down Expand Up @@ -136,7 +136,7 @@ public void aBlockTimerExpiryEventIsAddedToTheQueueOnExpiry() throws Interrupted

final BftEventQueue eventQueue = new BftEventQueue(1000);
final BlockTimer timer = new BlockTimer(eventQueue, mockForksSchedule, bftExecutors, mockClock);
timer.startTimer(round, header);
timer.startTimer(round, header::getTimestamp);

// Verify that the event will not be added to the queue immediately
assertThat(eventQueue.isEmpty()).isTrue();
Expand Down Expand Up @@ -182,7 +182,7 @@ public void eventIsImmediatelyAddedToTheQueueIfAbsoluteExpiryIsEqualToNow() {
final ConsensusRoundIdentifier round =
new ConsensusRoundIdentifier(0xFEDBCA9876543210L, 0x12345678);

timer.startTimer(round, header);
timer.startTimer(round, header::getTimestamp);
verify(bftExecutors, never()).scheduleTask(any(Runnable.class), anyLong(), any());

final ArgumentCaptor<BftEvent> bftEventCaptor = ArgumentCaptor.forClass(BftEvent.class);
Expand Down Expand Up @@ -218,7 +218,7 @@ public void eventIsImmediatelyAddedToTheQueueIfAbsoluteExpiryIsInThePast() {
final ConsensusRoundIdentifier round =
new ConsensusRoundIdentifier(0xFEDBCA9876543210L, 0x12345678);

timer.startTimer(round, header);
timer.startTimer(round, header::getTimestamp);
verify(bftExecutors, never()).scheduleTask(any(Runnable.class), anyLong(), any());

final ArgumentCaptor<BftEvent> bftEventCaptor = ArgumentCaptor.forClass(BftEvent.class);
Expand Down Expand Up @@ -258,9 +258,9 @@ public void startTimerCancelsExistingTimer() {
Mockito.<ScheduledFuture<?>>when(
bftExecutors.scheduleTask(any(Runnable.class), anyLong(), eq(TimeUnit.MILLISECONDS)))
.thenReturn(mockedFuture);
timer.startTimer(round, header);
timer.startTimer(round, header::getTimestamp);
verify(mockedFuture, times(0)).cancel(false);
timer.startTimer(round, header);
timer.startTimer(round, header::getTimestamp);
verify(mockedFuture, times(1)).cancel(false);
}

Expand Down Expand Up @@ -292,7 +292,7 @@ public void runningFollowsTheStateOfTheTimer() {
Mockito.<ScheduledFuture<?>>when(
bftExecutors.scheduleTask(any(Runnable.class), anyLong(), eq(TimeUnit.MILLISECONDS)))
.thenReturn(mockedFuture);
timer.startTimer(round, header);
timer.startTimer(round, header::getTimestamp);
when(mockedFuture.isDone()).thenReturn(false);
assertThat(timer.isRunning()).isTrue();
when(mockedFuture.isDone()).thenReturn(true);
Expand Down Expand Up @@ -322,7 +322,7 @@ public void checkBlockTimerEmptyAndNonEmptyPeriodSecods() {
MINIMAL_TIME_BETWEEN_EMPTY_BLOCKS_SECONDS)));

final BlockTimer timer = new BlockTimer(mockQueue, mockForksSchedule, bftExecutors, mockClock);
timer.startTimer(round, header);
timer.startTimer(round, header::getTimestamp);

assertThat(timer.getBlockPeriodSeconds()).isEqualTo(MINIMAL_TIME_BETWEEN_BLOCKS_SECONDS);
assertThat(timer.getEmptyBlockPeriodSeconds())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public IbftBlockHeightManager(

currentRound = roundFactory.createNewRound(parentHeader, 0);
if (finalState.isLocalNodeProposerForRound(currentRound.getRoundIdentifier())) {
blockTimer.startTimer(currentRound.getRoundIdentifier(), parentHeader);
blockTimer.startTimer(currentRound.getRoundIdentifier(), parentHeader::getTimestamp);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,17 @@
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
import org.hyperledger.besu.consensus.common.bft.payload.SignedData;
import org.hyperledger.besu.consensus.qbft.QbftExtraDataCodec;
import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockHashingAdaptor;
import org.hyperledger.besu.consensus.qbft.adaptor.QbftBlockInterfaceAdaptor;
import org.hyperledger.besu.consensus.qbft.adaptor.QbftExtraDataProviderAdaptor;
import org.hyperledger.besu.consensus.qbft.core.payload.CommitPayload;
import org.hyperledger.besu.consensus.qbft.core.payload.MessageFactory;
import org.hyperledger.besu.consensus.qbft.core.statemachine.PreparedCertificate;
import org.hyperledger.besu.consensus.qbft.core.types.QbftBlock;
import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockCodec;
import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHashing;
import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockInterface;
import org.hyperledger.besu.consensus.qbft.core.types.QbftExtraDataProvider;
import org.hyperledger.besu.consensus.qbft.core.types.QbftHashMode;
import org.hyperledger.besu.crypto.SECPSignature;
import org.hyperledger.besu.cryptoservices.NodeKey;
Expand All @@ -42,10 +46,14 @@ public static SignedData<CommitPayload> createSignedCommitPayload(

final QbftBlock commitBlock =
createCommitBlockFromProposalBlock(block, roundId.getRoundNumber());
final QbftBlockHashing blockHashing =
new QbftBlockHashingAdaptor(new BftBlockHashing(qbftExtraDataEncoder));
final QbftExtraDataProvider extraDataProvider =
new QbftExtraDataProviderAdaptor(qbftExtraDataEncoder);
final SECPSignature commitSeal =
nodeKey.sign(
new BftBlockHashing(qbftExtraDataEncoder)
.calculateDataHashForCommittedSeal(commitBlock.getHeader()));
blockHashing.calculateDataHashForCommittedSeal(
commitBlock.getHeader(), extraDataProvider.getExtraData(commitBlock.getHeader())));

final MessageFactory messageFactory = new MessageFactory(nodeKey, blockEncoder);

Expand Down
Loading

0 comments on commit a021fea

Please sign in to comment.