diff --git a/app/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java b/app/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java index 5c702d3a490..b1b3d03a87e 100644 --- a/app/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java +++ b/app/src/main/java/org/hyperledger/besu/controller/IbftBesuControllerBuilder.java @@ -225,7 +225,8 @@ protected MiningCoordinator createMiningCoordinator( messageFactory, bftExtraDataCodec), messageValidatorFactory, - messageFactory), + messageFactory, + protocolSchedule), gossiper, duplicateMessageTracker, futureMessageBuffer, diff --git a/app/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java b/app/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java index 88cabd5a0a4..7c2b7164cdf 100644 --- a/app/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java +++ b/app/src/main/java/org/hyperledger/besu/controller/QbftBesuControllerBuilder.java @@ -97,6 +97,7 @@ import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; import org.hyperledger.besu.ethereum.p2p.config.SubProtocolConfiguration; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.util.Subscribers; @@ -243,6 +244,10 @@ protected MiningCoordinator createMiningCoordinator( final QbftGossiperImpl gossiper = new QbftGossiperImpl(uniqueMessageMulticaster, blockEncoder); + System.out.println("Creating QBFT mining coordinator"); + protocolSchedule.getNextProtocolSpec(System.currentTimeMillis()); + + // MRW final QbftFinalState finalState = new QbftFinalStateImpl( validatorProvider, @@ -300,7 +305,7 @@ protected MiningCoordinator createMiningCoordinator( messageFactory, qbftValidatorProvider, new QbftValidatorModeTransitionLoggerAdaptor( - new ValidatorModeTransitionLogger(qbftForksSchedule))); + new ValidatorModeTransitionLogger(qbftForksSchedule)),protocolSchedule); qbftBlockHeightManagerFactory.isEarlyRoundChangeEnabled(isEarlyRoundChangeEnabled); @@ -333,14 +338,16 @@ protected MiningCoordinator createMiningCoordinator( .getBlockchain() .observeBlockAdded( o -> { + ScheduledProtocolSpec scheduledSpec = protocolSchedule.getNextProtocolSpecByBlockHeader(o.getHeader()); + miningConfiguration.setBlockPeriodSeconds( qbftForksSchedule - .getFork(o.getHeader().getNumber() + 1) + .getFork(o.getHeader().getNumber() + 1, o.getHeader().getTimestamp(), scheduledSpec.getScheduleType()) .getValue() .getBlockPeriodSeconds()); miningConfiguration.setEmptyBlockPeriodSeconds( qbftForksSchedule - .getFork(o.getHeader().getNumber() + 1) + .getFork(o.getHeader().getNumber() + 1, o.getHeader().getTimestamp(), scheduledSpec.getScheduleType()) .getValue() .getEmptyBlockPeriodSeconds()); }); diff --git a/app/src/test/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilderTest.java b/app/src/test/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilderTest.java index fc966dffa26..48b44b984c7 100644 --- a/app/src/test/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilderTest.java +++ b/app/src/test/java/org/hyperledger/besu/controller/ConsensusScheduleBesuControllerBuilderTest.java @@ -37,6 +37,7 @@ import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; import org.hyperledger.besu.ethereum.p2p.config.SubProtocolConfiguration; import org.hyperledger.besu.ethereum.p2p.network.ProtocolManager; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.SubProtocol; @@ -150,19 +151,19 @@ public void createsMigratingMiningCoordinator() { (softly) -> { softly .assertThat( - migratingMiningCoordinator.getMiningCoordinatorSchedule().getFork(0L).getValue()) + migratingMiningCoordinator.getMiningCoordinatorSchedule().getFork(0L, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue()) .isSameAs(miningCoordinator1); softly .assertThat( - migratingMiningCoordinator.getMiningCoordinatorSchedule().getFork(4L).getValue()) + migratingMiningCoordinator.getMiningCoordinatorSchedule().getFork(4L, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue()) .isSameAs(miningCoordinator1); softly .assertThat( - migratingMiningCoordinator.getMiningCoordinatorSchedule().getFork(5L).getValue()) + migratingMiningCoordinator.getMiningCoordinatorSchedule().getFork(5L, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue()) .isSameAs(miningCoordinator2); softly .assertThat( - migratingMiningCoordinator.getMiningCoordinatorSchedule().getFork(6L).getValue()) + migratingMiningCoordinator.getMiningCoordinatorSchedule().getFork(6L, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue()) .isSameAs(miningCoordinator2); }); } @@ -198,11 +199,11 @@ public void createsMigratingContext() { expectedConsensusContextSpecs.add(new ForkSpec<>(10L, context2)); assertThat(contextSchedule.getForks()).isEqualTo(expectedConsensusContextSpecs); - assertThat(contextSchedule.getFork(0).getValue()).isSameAs(context1); - assertThat(contextSchedule.getFork(1).getValue()).isSameAs(context1); - assertThat(contextSchedule.getFork(9).getValue()).isSameAs(context1); - assertThat(contextSchedule.getFork(10).getValue()).isSameAs(context2); - assertThat(contextSchedule.getFork(11).getValue()).isSameAs(context2); + assertThat(contextSchedule.getFork(0, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue()).isSameAs(context1); + assertThat(contextSchedule.getFork(1, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue()).isSameAs(context1); + assertThat(contextSchedule.getFork(9, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue()).isSameAs(context1); + assertThat(contextSchedule.getFork(10, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue()).isSameAs(context2); + assertThat(contextSchedule.getFork(11, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue()).isSameAs(context2); } @Test diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/ForksSchedule.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/ForksSchedule.java index 3ab50b6cacb..c626c574c2f 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/ForksSchedule.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/ForksSchedule.java @@ -14,6 +14,8 @@ */ package org.hyperledger.besu.consensus.common; +import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; + import java.util.Collection; import java.util.Collections; import java.util.Comparator; @@ -48,9 +50,16 @@ public ForksSchedule(final Collection> forks) { * @param blockNumber the block number * @return the fork */ - public ForkSpec getFork(final long blockNumber) { + public ForkSpec getFork(final long blockNumber, final long timestampSeconds, final ScheduledProtocolSpec.ScheduleType currentProtocolScheduleType) { for (final ForkSpec f : forks) { - if (blockNumber >= f.getBlock()) { + if (currentProtocolScheduleType == ScheduledProtocolSpec.ScheduleType.BLOCK && blockNumber >= f.getBlock()) { + System.out.println("Type: " + currentProtocolScheduleType + ", fork block: " + f.getBlock() + ", current block: " + blockNumber); + //System.out.println("Block " + blockNumber + " is higher than fork " + f + " with fork number " + f.getBlock() + " - returning f"); + return f; + } + if (currentProtocolScheduleType == ScheduledProtocolSpec.ScheduleType.TIME && timestampSeconds >= f.getBlock()) { + System.out.println("Type: " + currentProtocolScheduleType + ", fork time: " + f.getBlock() + ", current time: " + timestampSeconds); + //System.out.println("Fork block " + f.getBlock() + " is higher than timestamp seconds " + timestampSeconds + " - returning f"); return f; } } diff --git a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BlockTimer.java b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BlockTimer.java index 91f3c394d74..b94570c358a 100644 --- a/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BlockTimer.java +++ b/consensus/common/src/main/java/org/hyperledger/besu/consensus/common/bft/BlockTimer.java @@ -24,6 +24,7 @@ import java.util.concurrent.TimeUnit; import java.util.function.Supplier; +import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -84,14 +85,26 @@ public synchronized boolean isRunning() { * @param headerTimestamp The timestamp from the of the chain head header */ public synchronized void startTimer( - final ConsensusRoundIdentifier round, final Supplier headerTimestamp) { + final ConsensusRoundIdentifier round, final Supplier headerTimestamp, final ScheduledProtocolSpec.ScheduleType currentProtocolScheduleType) { cancelTimer(); final long expiryTime; + int currentBlockPeriodSeconds = + forksSchedule.getFork(round.getSequenceNumber(), headerTimestamp.get(), currentProtocolScheduleType).getValue().getBlockPeriodSeconds(); + + + final int nextBlockPeriodSeconds = + forksSchedule.getFork(round.getSequenceNumber(), headerTimestamp.get() + currentBlockPeriodSeconds, currentProtocolScheduleType).getValue().getBlockPeriodSeconds(); + + // If the block period seconds change between the current block and the next one we need to produce this block on the longer of the two values, + // otherwise block validation will fail (blocks produced too close together) + if (nextBlockPeriodSeconds > currentBlockPeriodSeconds) { + currentBlockPeriodSeconds = nextBlockPeriodSeconds; + } // Experimental option for test scenarios only. Not for production use. final long blockPeriodMilliseconds = - forksSchedule.getFork(round.getSequenceNumber()).getValue().getBlockPeriodMilliseconds(); + forksSchedule.getFork(round.getSequenceNumber(), headerTimestamp.get(), currentProtocolScheduleType).getValue().getBlockPeriodMilliseconds(); if (blockPeriodMilliseconds > 0) { // Experimental mode for setting < 1 second block periods e.g. for CI/CD pipelines // running tests against Besu @@ -101,13 +114,13 @@ public synchronized void startTimer( blockPeriodMilliseconds); } else { // absolute time when the timer is supposed to expire - final int currentBlockPeriodSeconds = - forksSchedule.getFork(round.getSequenceNumber()).getValue().getBlockPeriodSeconds(); final long minimumTimeBetweenBlocksMillis = currentBlockPeriodSeconds * 1000L; expiryTime = headerTimestamp.get() * 1_000 + minimumTimeBetweenBlocksMillis; } - setBlockTimes(round); + final int emptyBlockPeriodSeconds = + forksSchedule.getFork(round.getSequenceNumber(), headerTimestamp.get(), currentProtocolScheduleType).getValue().getEmptyBlockPeriodSeconds(); + setBlockTimes(currentBlockPeriodSeconds, emptyBlockPeriodSeconds); startTimer(round, expiryTime); } @@ -168,11 +181,9 @@ private synchronized void startTimer( } } - private synchronized void setBlockTimes(final ConsensusRoundIdentifier round) { - final BftConfigOptions currentConfigOptions = - forksSchedule.getFork(round.getSequenceNumber()).getValue(); - this.blockPeriodSeconds = currentConfigOptions.getBlockPeriodSeconds(); - this.emptyBlockPeriodSeconds = currentConfigOptions.getEmptyBlockPeriodSeconds(); + private synchronized void setBlockTimes(final int blockPeriodSeconds, final int emptyBlockPeriodSeconds) { + this.blockPeriodSeconds = blockPeriodSeconds; + this.emptyBlockPeriodSeconds = emptyBlockPeriodSeconds; } /** diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/ForksScheduleFactoryTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/ForksScheduleFactoryTest.java index 89e7330c4c4..f742aac5dd4 100644 --- a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/ForksScheduleFactoryTest.java +++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/ForksScheduleFactoryTest.java @@ -28,6 +28,7 @@ import java.util.List; import java.util.Map; +import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -77,9 +78,9 @@ public void createsScheduleUsingSpecCreator() { final ForksSchedule schedule = ForksScheduleFactory.create(genesisConfigOptions, List.of(fork1, fork2), specCreator); - assertThat(schedule.getFork(0)).isEqualTo(genesisForkSpec); - assertThat(schedule.getFork(1)).isEqualTo(new ForkSpec<>(1, configOptions1)); - assertThat(schedule.getFork(2)).isEqualTo(new ForkSpec<>(2, configOptions2)); + assertThat(schedule.getFork(0, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).isEqualTo(genesisForkSpec); + assertThat(schedule.getFork(1, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).isEqualTo(new ForkSpec<>(1, configOptions1)); + assertThat(schedule.getFork(2, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).isEqualTo(new ForkSpec<>(2, configOptions2)); } private MutableBftConfigOptions createBftConfigOptions( diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/ForksScheduleTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/ForksScheduleTest.java index a70d20da8d2..f5fb1d439f6 100644 --- a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/ForksScheduleTest.java +++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/ForksScheduleTest.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Optional; +import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; import org.junit.jupiter.api.Test; public class ForksScheduleTest { @@ -36,8 +37,8 @@ public void retrievesGenesisFork() { final ForksSchedule schedule = new ForksSchedule<>(List.of(forkSpec1, genesisForkSpec)); - assertThat(schedule.getFork(0)).isEqualTo(genesisForkSpec); - assertThat(schedule.getFork(1)).isEqualTo(genesisForkSpec); + assertThat(schedule.getFork(0, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).isEqualTo(genesisForkSpec); + assertThat(schedule.getFork(1, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).isEqualTo(genesisForkSpec); } @Test @@ -56,13 +57,13 @@ public void retrievesLatestFork() { final ForksSchedule schedule = new ForksSchedule<>(List.of(genesisForkSpec, forkSpec1, forkSpec2, forkSpec3, forkSpec4)); - assertThat(schedule.getFork(0)).isEqualTo(genesisForkSpec); - assertThat(schedule.getFork(1)).isEqualTo(forkSpec1); - assertThat(schedule.getFork(2)).isEqualTo(forkSpec2); - assertThat(schedule.getFork(3)).isEqualTo(forkSpec3); - assertThat(schedule.getFork(3).getValue().getMiningBeneficiary()).isEqualTo(miningBeneficiary3); - assertThat(schedule.getFork(4)).isEqualTo(forkSpec4); - assertThat(schedule.getFork(4).getValue().getMiningBeneficiary()).isEmpty(); + assertThat(schedule.getFork(0, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).isEqualTo(genesisForkSpec); + assertThat(schedule.getFork(1, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).isEqualTo(forkSpec1); + assertThat(schedule.getFork(2, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).isEqualTo(forkSpec2); + assertThat(schedule.getFork(3, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).isEqualTo(forkSpec3); + assertThat(schedule.getFork(3, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue().getMiningBeneficiary()).isEqualTo(miningBeneficiary3); + assertThat(schedule.getFork(4, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).isEqualTo(forkSpec4); + assertThat(schedule.getFork(4, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue().getMiningBeneficiary()).isEmpty(); } private ForkSpec createForkSpecWithMiningBeneficiary( diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BaseForksSchedulesFactoryTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BaseForksSchedulesFactoryTest.java index 14b3bea7f8a..e346326819b 100644 --- a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BaseForksSchedulesFactoryTest.java +++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BaseForksSchedulesFactoryTest.java @@ -30,6 +30,7 @@ import java.util.function.Consumer; import com.fasterxml.jackson.databind.node.ObjectNode; +import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; import org.junit.jupiter.api.Test; public abstract class BaseForksSchedulesFactoryTest< @@ -42,9 +43,9 @@ public void createsScheduleForJustGenesisConfig() { final GenesisConfigOptions genesisConfigOptions = createGenesisConfig(configOptions); final ForksSchedule forksSchedule = createForkSchedule(genesisConfigOptions); - assertThat(forksSchedule.getFork(0)).usingRecursiveComparison().isEqualTo(expectedForkSpec); - assertThat(forksSchedule.getFork(1)).usingRecursiveComparison().isEqualTo(expectedForkSpec); - assertThat(forksSchedule.getFork(2)).usingRecursiveComparison().isEqualTo(expectedForkSpec); + assertThat(forksSchedule.getFork(0, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).usingRecursiveComparison().isEqualTo(expectedForkSpec); + assertThat(forksSchedule.getFork(1, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).usingRecursiveComparison().isEqualTo(expectedForkSpec); + assertThat(forksSchedule.getFork(2, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).usingRecursiveComparison().isEqualTo(expectedForkSpec); } @Test @@ -68,10 +69,10 @@ public void createsScheduleThatChangesMiningBeneficiary_beneficiaryInitiallyEmpt createGenesisConfig(qbftConfigOptions, forkWithBeneficiary, forkWithNoBeneficiary); final ForksSchedule forksSchedule = createForkSchedule(genesisConfigOptions); - assertThat(forksSchedule.getFork(0).getValue().getMiningBeneficiary()).isEmpty(); - assertThat(forksSchedule.getFork(1).getValue().getMiningBeneficiary()) + assertThat(forksSchedule.getFork(0, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue().getMiningBeneficiary()).isEmpty(); + assertThat(forksSchedule.getFork(1, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue().getMiningBeneficiary()) .contains(beneficiaryAddress); - assertThat(forksSchedule.getFork(2).getValue().getMiningBeneficiary()).isEmpty(); + assertThat(forksSchedule.getFork(2, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue().getMiningBeneficiary()).isEmpty(); } @Test @@ -97,10 +98,10 @@ public void createsScheduleThatChangesMiningBeneficiary_beneficiaryInitiallyNonE createGenesisConfig(qbftConfigOptions, forkWithBeneficiary, forkWithNoBeneficiary); final ForksSchedule forksSchedule = createForkSchedule(genesisConfigOptions); - assertThat(forksSchedule.getFork(0).getValue().getMiningBeneficiary()) + assertThat(forksSchedule.getFork(0, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue().getMiningBeneficiary()) .contains(beneficiaryAddress); - assertThat(forksSchedule.getFork(1).getValue().getMiningBeneficiary()).isEmpty(); - assertThat(forksSchedule.getFork(2).getValue().getMiningBeneficiary()) + assertThat(forksSchedule.getFork(1, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue().getMiningBeneficiary()).isEmpty(); + assertThat(forksSchedule.getFork(2, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue().getMiningBeneficiary()) .contains(beneficiaryAddress2); } @@ -135,19 +136,19 @@ public void createsScheduleThatChangesMiningBeneficiary_beneficiaryInitiallyNonE final GenesisConfigOptions genesisConfigOptions = createGenesisConfig(qbftConfigOptions, forks); final ForksSchedule forksSchedule = createForkSchedule(genesisConfigOptions); - assertThat(forksSchedule.getFork(0).getValue().getMiningBeneficiary()) + assertThat(forksSchedule.getFork(0, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue().getMiningBeneficiary()) .contains(initialBeneficiaryAddress); - assertThat(forksSchedule.getFork(1).getValue().getMiningBeneficiary()) + assertThat(forksSchedule.getFork(1, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue().getMiningBeneficiary()) .contains(initialBeneficiaryAddress); - assertThat(forksSchedule.getFork(2).getValue().getMiningBeneficiary()) + assertThat(forksSchedule.getFork(2, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue().getMiningBeneficiary()) .contains(initialBeneficiaryAddress); - assertThat(forksSchedule.getFork(3).getValue().getMiningBeneficiary()).isEmpty(); - assertThat(forksSchedule.getFork(4).getValue().getMiningBeneficiary()).isEmpty(); - assertThat(forksSchedule.getFork(5).getValue().getMiningBeneficiary()).isEmpty(); - assertThat(forksSchedule.getFork(6).getValue().getMiningBeneficiary()).isEmpty(); - assertThat(forksSchedule.getFork(7).getValue().getMiningBeneficiary()) + assertThat(forksSchedule.getFork(3, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue().getMiningBeneficiary()).isEmpty(); + assertThat(forksSchedule.getFork(4, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue().getMiningBeneficiary()).isEmpty(); + assertThat(forksSchedule.getFork(5, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue().getMiningBeneficiary()).isEmpty(); + assertThat(forksSchedule.getFork(6, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue().getMiningBeneficiary()).isEmpty(); + assertThat(forksSchedule.getFork(7, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue().getMiningBeneficiary()) .contains(beneficiaryAddress2); - assertThat(forksSchedule.getFork(8).getValue().getMiningBeneficiary()) + assertThat(forksSchedule.getFork(8, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue().getMiningBeneficiary()) .contains(beneficiaryAddress2); } diff --git a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BlockTimerTest.java b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BlockTimerTest.java index da8a739aa4a..ce1d98a1e09 100644 --- a/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BlockTimerTest.java +++ b/consensus/common/src/test/java/org/hyperledger/besu/consensus/common/bft/BlockTimerTest.java @@ -37,6 +37,7 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -80,7 +81,7 @@ public void startTimerSchedulesCorrectlyWhenExpiryIsInTheFuture() { final long BLOCK_TIME_STAMP = 500L; final long EXPECTED_DELAY = 10_000L; - when(mockForksSchedule.getFork(anyLong())) + when(mockForksSchedule.getFork(anyLong(), 0, ScheduledProtocolSpec.ScheduleType.BLOCK)) .thenReturn( new ForkSpec<>( 0, @@ -115,7 +116,7 @@ public void aBlockTimerExpiryEventIsAddedToTheQueueOnExpiry() throws Interrupted final long BLOCK_TIME_STAMP = 300; final long EXPECTED_DELAY = 500; - when(mockForksSchedule.getFork(anyLong())) + when(mockForksSchedule.getFork(anyLong(), 0, ScheduledProtocolSpec.ScheduleType.BLOCK)) .thenReturn( new ForkSpec<>( 0, @@ -165,7 +166,7 @@ public void eventIsImmediatelyAddedToTheQueueIfAbsoluteExpiryIsEqualToNow() { final long NOW_MILLIS = 515_000L; final long BLOCK_TIME_STAMP = 500; - when(mockForksSchedule.getFork(anyLong())) + when(mockForksSchedule.getFork(anyLong(), 0, ScheduledProtocolSpec.ScheduleType.BLOCK)) .thenReturn( new ForkSpec<>( 0, @@ -201,7 +202,7 @@ public void eventIsImmediatelyAddedToTheQueueIfAbsoluteExpiryIsInThePast() { final long NOW_MILLIS = 520_000L; final long BLOCK_TIME_STAMP = 500L; - when(mockForksSchedule.getFork(anyLong())) + when(mockForksSchedule.getFork(anyLong(), 0, ScheduledProtocolSpec.ScheduleType.BLOCK)) .thenReturn( new ForkSpec<>( 0, @@ -237,7 +238,7 @@ public void startTimerCancelsExistingTimer() { final long NOW_MILLIS = 500_000L; final long BLOCK_TIME_STAMP = 500L; - when(mockForksSchedule.getFork(anyLong())) + when(mockForksSchedule.getFork(anyLong(), 0, ScheduledProtocolSpec.ScheduleType.BLOCK)) .thenReturn( new ForkSpec<>( 0, @@ -271,7 +272,7 @@ public void runningFollowsTheStateOfTheTimer() { final long NOW_MILLIS = 500_000L; final long BLOCK_TIME_STAMP = 500L; - when(mockForksSchedule.getFork(anyLong())) + when(mockForksSchedule.getFork(anyLong(), 0, ScheduledProtocolSpec.ScheduleType.BLOCK)) .thenReturn( new ForkSpec<>( 0, @@ -313,7 +314,7 @@ public void checkBlockTimerEmptyAndNonEmptyPeriodSecods() { bftExecutors.scheduleTask(any(Runnable.class), anyLong(), any())) .thenReturn(mockedFuture); - when(mockForksSchedule.getFork(anyLong())) + when(mockForksSchedule.getFork(anyLong(), 0, ScheduledProtocolSpec.ScheduleType.BLOCK)) .thenReturn( new ForkSpec<>( 0, diff --git a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java index d751839e07b..b05f19d4dde 100644 --- a/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java +++ b/consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContextBuilder.java @@ -447,7 +447,8 @@ private static ControllerAndState createControllerAndFinalState( messageFactory, IBFT_EXTRA_DATA_ENCODER), messageValidatorFactory, - messageFactory), + messageFactory, + protocolSchedule), gossiper, duplicateMessageTracker, futureMessageBuffer, diff --git a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManager.java b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManager.java index 8db52ad1233..16999324733 100644 --- a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManager.java +++ b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManager.java @@ -34,6 +34,7 @@ import org.hyperledger.besu.consensus.ibft.validation.MessageValidatorFactory; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; import org.hyperledger.besu.plugin.services.securitymodule.SecurityModuleException; import java.time.Clock; @@ -87,13 +88,14 @@ public class IbftBlockHeightManager implements BaseIbftBlockHeightManager { * @param messageFactory the message factory */ public IbftBlockHeightManager( - final BlockHeader parentHeader, - final BftFinalState finalState, - final RoundChangeManager roundChangeManager, - final IbftRoundFactory ibftRoundFactory, - final Clock clock, - final MessageValidatorFactory messageValidatorFactory, - final MessageFactory messageFactory) { + final BlockHeader parentHeader, + final BftFinalState finalState, + final RoundChangeManager roundChangeManager, + final IbftRoundFactory ibftRoundFactory, + final Clock clock, + final MessageValidatorFactory messageValidatorFactory, + final MessageFactory messageFactory, + final ScheduledProtocolSpec.ScheduleType currentProtocolSpecType) { this.parentHeader = parentHeader; this.roundFactory = ibftRoundFactory; this.blockTimer = finalState.getBlockTimer(); @@ -117,7 +119,7 @@ public IbftBlockHeightManager( currentRound = roundFactory.createNewRound(parentHeader, 0); if (finalState.isLocalNodeProposerForRound(currentRound.getRoundIdentifier())) { - blockTimer.startTimer(currentRound.getRoundIdentifier(), parentHeader::getTimestamp); + blockTimer.startTimer(currentRound.getRoundIdentifier(), parentHeader::getTimestamp, currentProtocolSpecType); } } diff --git a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManagerFactory.java b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManagerFactory.java index 8218ea17383..aea49078c11 100644 --- a/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManagerFactory.java +++ b/consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManagerFactory.java @@ -20,6 +20,8 @@ import org.hyperledger.besu.consensus.ibft.validation.MessageValidatorFactory; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,6 +34,7 @@ public class IbftBlockHeightManagerFactory { private final BftFinalState finalState; private final MessageValidatorFactory messageValidatorFactory; private final MessageFactory messageFactory; + private final ProtocolSchedule protocolSchedule; /** * Instantiates a new Ibft block height manager factory. @@ -45,11 +48,13 @@ public IbftBlockHeightManagerFactory( final BftFinalState finalState, final IbftRoundFactory roundFactory, final MessageValidatorFactory messageValidatorFactory, - final MessageFactory messageFactory) { + final MessageFactory messageFactory, + final ProtocolSchedule protocolSchedule) { this.roundFactory = roundFactory; this.finalState = finalState; this.messageValidatorFactory = messageValidatorFactory; this.messageFactory = messageFactory; + this.protocolSchedule = protocolSchedule; } /** @@ -80,6 +85,16 @@ protected BaseIbftBlockHeightManager createNoOpBlockHeightManager( } private BaseIbftBlockHeightManager createFullBlockHeightManager(final BlockHeader parentHeader) { + + + + ScheduledProtocolSpec specForNextBlock = protocolSchedule.getNextProtocolSpecByBlockHeader(parentHeader); + if (specForNextBlock.getScheduleType() == ScheduledProtocolSpec.ScheduleType.BLOCK) { + System.out.println("It's block based*"); + } else { + System.out.println("It's time based*"); + } + return new IbftBlockHeightManager( parentHeader, finalState, @@ -90,6 +105,7 @@ private BaseIbftBlockHeightManager createFullBlockHeightManager(final BlockHeade roundFactory, finalState.getClock(), messageValidatorFactory, - messageFactory); + messageFactory, + specForNextBlock.getScheduleType()); } } diff --git a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftForksSchedulesFactoryTest.java b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftForksSchedulesFactoryTest.java index 235ba89d323..83458975438 100644 --- a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftForksSchedulesFactoryTest.java +++ b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/IbftForksSchedulesFactoryTest.java @@ -34,6 +34,7 @@ import java.util.function.Consumer; import com.fasterxml.jackson.databind.node.ObjectNode; +import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; import org.junit.jupiter.api.Test; public class IbftForksSchedulesFactoryTest @@ -56,7 +57,7 @@ public void createsScheduleWithForkThatOverridesGenesisValues() { final ForksSchedule forksSchedule = IbftForksSchedulesFactory.create(createGenesisConfig(configOptions, fork)); - assertThat(forksSchedule.getFork(0)) + assertThat(forksSchedule.getFork(0, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)) .usingRecursiveComparison() .isEqualTo(new ForkSpec<>(0, configOptions)); @@ -69,8 +70,8 @@ public void createsScheduleWithForkThatOverridesGenesisValues() { new JsonBftConfigOptions(JsonUtil.objectNodeFromMap(forkOptions))); final ForkSpec expectedFork = new ForkSpec<>(1, expectedForkConfig); - assertThat(forksSchedule.getFork(1)).usingRecursiveComparison().isEqualTo(expectedFork); - assertThat(forksSchedule.getFork(2)).usingRecursiveComparison().isEqualTo(expectedFork); + assertThat(forksSchedule.getFork(1, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).usingRecursiveComparison().isEqualTo(expectedFork); + assertThat(forksSchedule.getFork(2, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).usingRecursiveComparison().isEqualTo(expectedFork); } @Override diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java index 7bce5f5de08..ce9cb5dac36 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java @@ -91,6 +91,19 @@ public ProtocolSpec getByBlockHeader( blockHeader, protocolSchedule -> protocolSchedule.getByBlockHeader(blockHeader)); } + /** + * Gets scheduled protocol spec by block header. + * + * @param blockHeader the block header + * @return the ProtocolSpec to be used by the provided block + */ + @Override + public ScheduledProtocolSpec getNextProtocolSpecByBlockHeader( + final org.hyperledger.besu.plugin.data.ProcessableBlockHeader blockHeader) { + return this.transitionUtils.dispatchFunctionAccordingToMergeState( + blockHeader, protocolSchedule -> protocolSchedule.getNextProtocolSpecByBlockHeader(blockHeader)); + } + /** * Gets the protocol spec by block header, with some additional logic used by backwards sync (BWS) * diff --git a/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/support/TestContextBuilder.java b/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/support/TestContextBuilder.java index 10cf90c4e61..ea995b2dd6b 100644 --- a/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/support/TestContextBuilder.java +++ b/consensus/qbft-core/src/integration-test/java/org/hyperledger/besu/consensus/qbft/core/support/TestContextBuilder.java @@ -595,7 +595,7 @@ private static ControllerAndState createControllerAndFinalState( messageValidatorFactory, messageFactory, qbftValidatorProvider, - validatorModeTransitionLogger), + validatorModeTransitionLogger, protocolSchedule), gossiper, duplicateMessageTracker, futureMessageBuffer, diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftBlockHeightManager.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftBlockHeightManager.java index 49099c2c16f..d8ad5cabbcc 100644 --- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftBlockHeightManager.java +++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftBlockHeightManager.java @@ -32,6 +32,7 @@ import org.hyperledger.besu.consensus.qbft.core.validation.FutureRoundProposalMessageValidator; import org.hyperledger.besu.consensus.qbft.core.validation.MessageValidatorFactory; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.block.access.list.BlockAccessList; import org.hyperledger.besu.plugin.services.securitymodule.SecurityModuleException; @@ -95,7 +96,8 @@ public QbftBlockHeightManager( final Clock clock, final MessageValidatorFactory messageValidatorFactory, final MessageFactory messageFactory, - final QbftValidatorProvider validatorProvider) { + final QbftValidatorProvider validatorProvider, + final ScheduledProtocolSpec.ScheduleType protocolSpecType) { this.parentHeader = parentHeader; this.roundFactory = qbftRoundFactory; this.validatorProvider = validatorProvider; @@ -121,7 +123,7 @@ public QbftBlockHeightManager( final ConsensusRoundIdentifier roundIdentifier = new ConsensusRoundIdentifier(nextBlockHeight, 0); - finalState.getBlockTimer().startTimer(roundIdentifier, parentHeader::getTimestamp); + finalState.getBlockTimer().startTimer(roundIdentifier, parentHeader::getTimestamp, protocolSpecType); } /** @@ -147,6 +149,7 @@ public QbftBlockHeightManager( final MessageValidatorFactory messageValidatorFactory, final MessageFactory messageFactory, final QbftValidatorProvider validatorProvider, + final ScheduledProtocolSpec.ScheduleType protocolSpecType, final boolean isEarlyRoundChangeEnabled) { this( parentHeader, @@ -156,7 +159,8 @@ public QbftBlockHeightManager( clock, messageValidatorFactory, messageFactory, - validatorProvider); + validatorProvider, + protocolSpecType); this.isEarlyRoundChangeEnabled = isEarlyRoundChangeEnabled; } diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftBlockHeightManagerFactory.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftBlockHeightManagerFactory.java index b212909feb3..bb6cf20945b 100644 --- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftBlockHeightManagerFactory.java +++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/statemachine/QbftBlockHeightManagerFactory.java @@ -22,6 +22,10 @@ import org.hyperledger.besu.consensus.qbft.core.types.QbftValidatorProvider; import org.hyperledger.besu.consensus.qbft.core.validation.MessageValidatorFactory; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; +import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; +import org.hyperledger.besu.plugin.data.ProcessableBlockHeader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,6 +41,7 @@ public class QbftBlockHeightManagerFactory { private final QbftValidatorProvider validatorProvider; private final QbftValidatorModeTransitionLogger validatorModeTransitionLogger; private boolean isEarlyRoundChangeEnabled = false; + private final ProtocolSchedule protocolSchedule; /** * Instantiates a new Qbft block height manager factory. @@ -54,13 +59,15 @@ public QbftBlockHeightManagerFactory( final MessageValidatorFactory messageValidatorFactory, final MessageFactory messageFactory, final QbftValidatorProvider validatorProvider, - final QbftValidatorModeTransitionLogger validatorModeTransitionLogger) { + final QbftValidatorModeTransitionLogger validatorModeTransitionLogger, + final ProtocolSchedule protocolSchedule) { this.roundFactory = roundFactory; this.finalState = finalState; this.messageValidatorFactory = messageValidatorFactory; this.messageFactory = messageFactory; this.validatorProvider = validatorProvider; this.validatorModeTransitionLogger = validatorModeTransitionLogger; + this.protocolSchedule = protocolSchedule; } /** @@ -107,6 +114,29 @@ private BaseQbftBlockHeightManager createFullBlockHeightManager( QbftBlockHeightManager qbftBlockHeightManager; RoundChangeManager roundChangeManager; + /*Object thing = protocolSchedule.getNextProtocolSpec(parentHeader.getTimestamp()).get(); + if (thing instanceof ScheduledProtocolSpec.TimestampProtocolSpec) { + System.out.println("It's time based!"); + } else if (thing instanceof ScheduledProtocolSpec.BlockNumberProtocolSpec) { + System.out.println("It's block based!"); + }*/ + + //ProcessableBlockHeader theHeader = new org.hyperledger.besu.ethereum.core.ProcessableBlockHeader(parentHeader.getNumber(), parentHeader.getTimestamp()); + //protocolSchedule.getLatestProtocolSpec().get().isOnMilestoneBoundary(theHeader); + /* if (protocolSchedule.getNextProtocolSpec(parentHeader.getTimestamp()).get().getScheduleType() == ScheduledProtocolSpec.ScheduleType.BLOCK) { + System.out.println("It's block based!"); + } else { + System.out.println("It's time based!"); + }*/ + + ScheduledProtocolSpec specForNextBlock = protocolSchedule.getNextProtocolSpecByBlockHeader(parentHeader.getHeader()); + if (specForNextBlock.getScheduleType() == ScheduledProtocolSpec.ScheduleType.BLOCK) { + System.out.println("It's block based*"); + } else { + System.out.println("It's time based*"); + } + + if (isEarlyRoundChangeEnabled) { roundChangeManager = new RoundChangeManager( @@ -125,7 +155,7 @@ private BaseQbftBlockHeightManager createFullBlockHeightManager( messageValidatorFactory, messageFactory, validatorProvider, - true); + specForNextBlock.getScheduleType()); } else { roundChangeManager = new RoundChangeManager( @@ -142,7 +172,8 @@ private BaseQbftBlockHeightManager createFullBlockHeightManager( finalState.getClock(), messageValidatorFactory, messageFactory, - validatorProvider); + validatorProvider, + specForNextBlock.getScheduleType()); } return qbftBlockHeightManager; diff --git a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftBlockHeader.java b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftBlockHeader.java index e3bf30e3a4e..aa1d26112b9 100644 --- a/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftBlockHeader.java +++ b/consensus/qbft-core/src/main/java/org/hyperledger/besu/consensus/qbft/core/types/QbftBlockHeader.java @@ -16,6 +16,7 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.plugin.data.BlockHeader; /** Represents a block header in the context of the QBFT consensus mechanism. */ public interface QbftBlockHeader { @@ -47,4 +48,11 @@ public interface QbftBlockHeader { * @return the hash. */ Hash getHash(); + + /** + * Returns the underlying plugin header + * + * @return the header. + */ + BlockHeader getHeader(); } diff --git a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/QbftBlockHeaderTestFixture.java b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/QbftBlockHeaderTestFixture.java index 8451c039c7c..233ca8da82f 100644 --- a/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/QbftBlockHeaderTestFixture.java +++ b/consensus/qbft-core/src/test/java/org/hyperledger/besu/consensus/qbft/core/validation/QbftBlockHeaderTestFixture.java @@ -17,6 +17,7 @@ import org.hyperledger.besu.consensus.qbft.core.types.QbftBlockHeader; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; +import org.hyperledger.besu.plugin.data.BlockHeader; public class QbftBlockHeaderTestFixture { @@ -66,6 +67,9 @@ public Hash getHash() { public Address getCoinbase() { return coinbase; } + + @Override + public BlockHeader getHeader() { return null; }; }; } } diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockHeaderAdaptor.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockHeaderAdaptor.java index 09215c69e8c..a8212da96aa 100644 --- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockHeaderAdaptor.java +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/adaptor/QbftBlockHeaderAdaptor.java @@ -55,6 +55,11 @@ public Hash getHash() { return blockHeader.getHash(); } + @Override + public BlockHeader getHeader() { + return blockHeader; + } + /** * Returns the Besu block header. * diff --git a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactory.java b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactory.java index fc46b6c32fb..24e528f7f40 100644 --- a/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactory.java +++ b/consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactory.java @@ -32,6 +32,7 @@ import java.util.Optional; import org.apache.tuweni.bytes.Bytes; +import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; /** Supports contract based voters and validators in extra data */ public class QbftBlockCreatorFactory extends BftBlockCreatorFactory { @@ -69,7 +70,15 @@ public QbftBlockCreatorFactory( @Override public Bytes createExtraData(final int round, final BlockHeader parentHeader) { - if (forksSchedule.getFork(parentHeader.getNumber() + 1L).getValue().isValidatorContractMode()) { + + ScheduledProtocolSpec specForNextBlock = protocolSchedule.getNextProtocolSpecByBlockHeader(parentHeader); + if (specForNextBlock.getScheduleType() == ScheduledProtocolSpec.ScheduleType.BLOCK) { + System.out.println("It's block based*"); + } else { + System.out.println("It's time based*"); + } + + if (forksSchedule.getFork(parentHeader.getNumber() + 1L, parentHeader.getTimestamp(), specForNextBlock.getScheduleType()).getValue().isValidatorContractMode()) { // vote and validators will come from contract instead of block final BftExtraData extraData = new BftExtraData( diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactoryTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactoryTest.java index f3682e2533d..5d0665f90bd 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactoryTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/blockcreation/QbftBlockCreatorFactoryTest.java @@ -35,6 +35,7 @@ import org.hyperledger.besu.ethereum.core.MiningConfiguration; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; import org.hyperledger.besu.testutil.DeterministicEthScheduler; import java.util.Optional; @@ -63,7 +64,7 @@ public void setUp() { qbftConfigOptions.setValidatorContractAddress(Optional.of("1")); final ForkSpec spec = new ForkSpec<>(0, qbftConfigOptions); final ForksSchedule forksSchedule = mock(ForksSchedule.class); - when(forksSchedule.getFork(anyLong())).thenReturn(spec); + when(forksSchedule.getFork(anyLong(), anyLong(), ScheduledProtocolSpec.ScheduleType.BLOCK)).thenReturn(spec); qbftBlockCreatorFactory = new QbftBlockCreatorFactory( diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/validator/QbftForksSchedulesFactoryTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/validator/QbftForksSchedulesFactoryTest.java index 6213b6817d6..944176217c0 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/validator/QbftForksSchedulesFactoryTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/validator/QbftForksSchedulesFactoryTest.java @@ -44,6 +44,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.TextNode; +import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; import org.junit.jupiter.api.Test; public class QbftForksSchedulesFactoryTest @@ -74,7 +75,7 @@ public void createsScheduleWithForkThatOverridesGenesisValues() { final ForksSchedule forksSchedule = QbftForksSchedulesFactory.create(createGenesisConfig(configOptions, fork)); - assertThat(forksSchedule.getFork(0)) + assertThat(forksSchedule.getFork(0, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)) .usingRecursiveComparison() .isEqualTo(new ForkSpec<>(0, configOptions)); @@ -89,8 +90,8 @@ public void createsScheduleWithForkThatOverridesGenesisValues() { new JsonQbftConfigOptions(JsonUtil.objectNodeFromMap(forkOptions))); final ForkSpec expectedFork = new ForkSpec<>(1, expectedForkConfig); - assertThat(forksSchedule.getFork(1)).usingRecursiveComparison().isEqualTo(expectedFork); - assertThat(forksSchedule.getFork(2)).usingRecursiveComparison().isEqualTo(expectedFork); + assertThat(forksSchedule.getFork(1, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).usingRecursiveComparison().isEqualTo(expectedFork); + assertThat(forksSchedule.getFork(2, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).usingRecursiveComparison().isEqualTo(expectedFork); } @Test @@ -136,7 +137,7 @@ public void switchingToBlockHeaderRemovesValidatorContractAddress() { final ForksSchedule forksSchedule = QbftForksSchedulesFactory.create(createGenesisConfig(configOptions, fork)); - assertThat(forksSchedule.getFork(1).getValue().getValidatorContractAddress()).isEmpty(); + assertThat(forksSchedule.getFork(1, 0, ScheduledProtocolSpec.ScheduleType.BLOCK).getValue().getValidatorContractAddress()).isEmpty(); } @Test diff --git a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/validator/ValidatorModeTransitionLoggerTest.java b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/validator/ValidatorModeTransitionLoggerTest.java index dabf26749a5..cae3bb22a72 100644 --- a/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/validator/ValidatorModeTransitionLoggerTest.java +++ b/consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/validator/ValidatorModeTransitionLoggerTest.java @@ -31,6 +31,7 @@ import java.util.Optional; import java.util.function.Consumer; +import org.hyperledger.besu.ethereum.mainnet.ScheduledProtocolSpec; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -53,8 +54,8 @@ public void doNotLogMessageWhenTransitioningFromBlockHeaderToBlockHeader() { final ForkSpec forkSpecB = new ForkSpec<>(1, createQbftConfigOptionsForBlockHeader()); - when(forksSchedule.getFork(0)).thenReturn(forkSpecA); - when(forksSchedule.getFork(1)).thenReturn(forkSpecB); + when(forksSchedule.getFork(0, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).thenReturn(forkSpecA); + when(forksSchedule.getFork(1, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).thenReturn(forkSpecB); qbftTransitionNotifier.logTransitionChange(blockHeader(0)); @@ -68,8 +69,8 @@ public void doNotLogMessageWhenTransitioningFromContractToContractWithSameAddres final ForkSpec contractForkSpecB = new ForkSpec<>(1, createQbftConfigOptionsForContract("0x0")); - when(forksSchedule.getFork(0)).thenReturn(contractForkSpecA); - when(forksSchedule.getFork(1)).thenReturn(contractForkSpecB); + when(forksSchedule.getFork(0, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).thenReturn(contractForkSpecA); + when(forksSchedule.getFork(1, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).thenReturn(contractForkSpecB); qbftTransitionNotifier.logTransitionChange(blockHeader(0)); @@ -83,8 +84,8 @@ public void logMessageWhenTransitioningFromContractToContractWithDifferentAddres final ForkSpec contractForkSpecB = new ForkSpec<>(1, createQbftConfigOptionsForContract("0x1")); - when(forksSchedule.getFork(0)).thenReturn(contractForkSpecA); - when(forksSchedule.getFork(1)).thenReturn(contractForkSpecB); + when(forksSchedule.getFork(0, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).thenReturn(contractForkSpecA); + when(forksSchedule.getFork(1, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).thenReturn(contractForkSpecB); qbftTransitionNotifier.logTransitionChange(blockHeader(0)); @@ -100,8 +101,8 @@ public void logMessageWhenTransitioningFromContractToBlockHeader() { final ForkSpec blockForkSpec = new ForkSpec<>(1, createQbftConfigOptionsForBlockHeader()); - when(forksSchedule.getFork(0)).thenReturn(contractForkSpec); - when(forksSchedule.getFork(1)).thenReturn(blockForkSpec); + when(forksSchedule.getFork(0, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).thenReturn(contractForkSpec); + when(forksSchedule.getFork(1, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).thenReturn(blockForkSpec); qbftTransitionNotifier.logTransitionChange(blockHeader(0)); @@ -117,8 +118,8 @@ public void logMessageWhenTransitioningFromBlockHeaderToContract() { final ForkSpec contractForkSpec = new ForkSpec<>(1, createQbftConfigOptionsForContract("0x0")); - when(forksSchedule.getFork(0)).thenReturn(blockForkSpec); - when(forksSchedule.getFork(1)).thenReturn(contractForkSpec); + when(forksSchedule.getFork(0, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).thenReturn(blockForkSpec); + when(forksSchedule.getFork(1, 0, ScheduledProtocolSpec.ScheduleType.BLOCK)).thenReturn(contractForkSpec); qbftTransitionNotifier.logTransitionChange(blockHeader(0)); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/ProcessableBlockHeader.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/ProcessableBlockHeader.java index e06faac0a72..5d2665087c7 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/ProcessableBlockHeader.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/ProcessableBlockHeader.java @@ -28,26 +28,33 @@ public class ProcessableBlockHeader implements BlockValues, org.hyperledger.besu.plugin.data.ProcessableBlockHeader { - protected final Hash parentHash; + protected Hash parentHash; - protected final Address coinbase; + protected Address coinbase; - protected final Difficulty difficulty; + protected Difficulty difficulty; protected final long number; - protected final long gasLimit; + protected long gasLimit; // The block creation timestamp (seconds since the unix epoch) protected final long timestamp; // base fee is included for post EIP-1559 blocks - protected final Wei baseFee; + protected Wei baseFee; // prevRandao is included for post-merge blocks - protected final Bytes32 mixHashOrPrevRandao; + protected Bytes32 mixHashOrPrevRandao; // parentBeaconBlockRoot is included for Cancun - protected final Bytes32 parentBeaconBlockRoot; + protected Bytes32 parentBeaconBlockRoot; // slotNumber is included for Amsterdam (EIP-7843) - protected final Long slotNumber; + protected Long slotNumber; + + public ProcessableBlockHeader( + final long number, + final long timestamp) { + this.number = number; + this.timestamp = timestamp; + } protected ProcessableBlockHeader( final Hash parentHash, diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolSchedule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolSchedule.java index 300032a1c90..ea93f772480 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolSchedule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolSchedule.java @@ -69,12 +69,32 @@ public ProtocolSpec getByBlockHeader(final ProcessableBlockHeader blockHeader) { // the requested level will be the most appropriate spec for (final ScheduledProtocolSpec spec : protocolSpecs) { if (spec.isOnOrAfterMilestoneBoundary(blockHeader)) { + // System.out.println("Getting protocol spec by block header. Next protocol spec = " + spec.spec().getEvm().getEvmVersion().getName()); return spec.spec(); } } return null; } + @Override + public ScheduledProtocolSpec getNextProtocolSpecByBlockHeader(final ProcessableBlockHeader blockHeader) { + checkArgument( + !protocolSpecs.isEmpty(), "At least 1 milestone must be provided to the protocol schedule"); + checkArgument( + protocolSpecs.last().fork().milestone() == 0, + "There must be a milestone starting from block 0"); + + // protocolSpecs is sorted in descending block order, so the first one we find that's lower than + // the requested level will be the most appropriate spec + for (final ScheduledProtocolSpec spec : protocolSpecs) { + if (spec.isOnOrAfterMilestoneBoundary(blockHeader)) { + //System.out.println("Getting protocol spec by block header. Next protocol spec = " + spec.spec().getEvm().getEvmVersion().getName()); + return spec; + } + } + return null; + } + @Override public Optional getNextProtocolSpec(final long currentTime) { checkArgument( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSchedule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSchedule.java index 59b61cba50e..59ddc096778 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSchedule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSchedule.java @@ -46,6 +46,8 @@ default ProtocolSpec getForNextBlockHeader( return getByBlockHeader(nextBlockHeader); } + ScheduledProtocolSpec getNextProtocolSpecByBlockHeader(final ProcessableBlockHeader blockHeader); + Optional getNextProtocolSpec(final long currentTime); Optional getLatestProtocolSpec(); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ScheduledProtocolSpec.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ScheduledProtocolSpec.java index 5b2fb59bf7f..4cbe9b9a3aa 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ScheduledProtocolSpec.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ScheduledProtocolSpec.java @@ -21,11 +21,18 @@ * Knows how to query the timestamp or block number of a given block header */ public interface ScheduledProtocolSpec { + + public enum ScheduleType { + BLOCK, + TIME + } boolean isOnOrAfterMilestoneBoundary( org.hyperledger.besu.plugin.data.ProcessableBlockHeader header); boolean isOnMilestoneBoundary(org.hyperledger.besu.plugin.data.ProcessableBlockHeader header); + public ScheduleType getScheduleType(); + Hardfork fork(); ProtocolSpec spec(); @@ -72,6 +79,11 @@ public boolean isOnMilestoneBoundary( return header.getTimestamp() == timestamp; } + @Override + public ScheduleType getScheduleType() { + return ScheduleType.TIME; + } + @Override public Hardfork fork() { return new Hardfork(protocolSpec.getHardforkId().description(), timestamp); @@ -117,5 +129,10 @@ public Hardfork fork() { public ProtocolSpec spec() { return protocolSpec; } + + @Override + public ScheduleType getScheduleType() { + return ScheduleType.BLOCK; + } } }