QBFT + shanghai support (#6353)

* Refactored version of QBFT/shanghai

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

* More refactoring

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

* Add equivalent IBFT fixes. Update QBFT and IBFT round tests

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

* Update the change log

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

* Remove old comments

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

* Add shanghai contract validator test

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

* Add shanghai acceptance test

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

* Add Shanghai to the combined protocol schedule test, update IBFT message validator creation

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

* Fix merge

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

* Update tests to use shanghai time > 0

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

* Address PR comments

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

* Refactor unit tests

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

* Refactor unit tests

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

* IbftRoundTests update

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

* Address PR comments

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

* Remove unnecessary class type check

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>

---------

Signed-off-by: Matthew Whitehead <matthew1001@gmail.com>
Signed-off-by: Matt Whitehead <matthew1001@gmail.com>
Signed-off-by: Matt Whitehead <matthew.whitehead@kaleido.io>
This commit is contained in:
Matt Whitehead
2024-02-02 09:29:21 +00:00
committed by GitHub
parent dbea838ba2
commit 03dd7f1d1a
30 changed files with 475 additions and 201 deletions

View File

@@ -28,6 +28,7 @@
- Introduce caching mechanism to optimize Keccak hash calculations for account storage slots during block processing [#6452](https://github.com/hyperledger/besu/pull/6452)
- Added configuration options for `pragueTime` to genesis file for Prague fork development [#6473](https://github.com/hyperledger/besu/pull/6473)
- Moving trielog storage to RocksDB's blobdb to improve write amplications [#6289](https://github.com/hyperledger/besu/pull/6289)
- Support for `shanghaiTime` fork and Shanghai EVM smart contracts in QBFT/IBFT chains [#6353](https://github.com/hyperledger/besu/pull/6353)
### Bug fixes
- Fix the way an advertised host configured with `--p2p-host` is treated when communicating with the originator of a PING packet [#6225](https://github.com/hyperledger/besu/pull/6225)

View File

@@ -150,6 +150,36 @@ public class BftMiningAcceptanceTest extends ParameterizedBftTestBase {
cluster.verify(receiver.balanceEquals(3));
}
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("factoryFunctions")
public void shouldMineOnSingleNodeWithFreeGas_Shanghai(
final String testName, final BftAcceptanceTestParameterization nodeFactory) throws Exception {
setUp(testName, nodeFactory);
final BesuNode minerNode = nodeFactory.createNode(besu, "miner1");
updateGenesisConfigToShanghai(minerNode, true);
cluster.start(minerNode);
cluster.verify(blockchain.reachesHeight(minerNode, 1));
final Account sender = accounts.createAccount("account1");
final Account receiver = accounts.createAccount("account2");
minerNode.execute(accountTransactions.createTransfer(sender, 50, Amount.ZERO));
cluster.verify(sender.balanceEquals(50));
minerNode.execute(accountTransactions.create1559Transfer(sender, 50, 4, Amount.ZERO));
cluster.verify(sender.balanceEquals(100));
minerNode.execute(
accountTransactions.createIncrementalTransfers(sender, receiver, 1, Amount.ZERO));
cluster.verify(receiver.balanceEquals(1));
minerNode.execute(
accountTransactions.create1559IncrementalTransfers(sender, receiver, 2, 4, Amount.ZERO));
cluster.verify(receiver.balanceEquals(3));
}
@ParameterizedTest(name = "{index}: {0}")
@MethodSource("factoryFunctions")
public void shouldMineOnMultipleNodes(
@@ -245,4 +275,16 @@ public class BftMiningAcceptanceTest extends ParameterizedBftTestBase {
config.put("zeroBaseFee", zeroBaseFeeEnabled);
minerNode.setGenesisConfig(genesisConfigNode.toString());
}
private static void updateGenesisConfigToShanghai(
final BesuNode minerNode, final boolean zeroBaseFeeEnabled) {
final Optional<String> genesisConfig =
minerNode.getGenesisConfigProvider().create(List.of(minerNode));
final ObjectNode genesisConfigNode = JsonUtil.objectNodeFromString(genesisConfig.orElseThrow());
final ObjectNode config = (ObjectNode) genesisConfigNode.get("config");
config.remove("berlinBlock");
config.put("shanghaiTime", 100);
config.put("zeroBaseFee", zeroBaseFeeEnabled);
minerNode.setGenesisConfig(genesisConfigNode.toString());
}
}

View File

@@ -53,14 +53,22 @@ public class CombinedProtocolScheduleFactory {
protocolSchedule.getScheduledProtocolSpecs().stream()
.filter(protocolSpecMatchesConsensusBlockRange(spec.getBlock(), endBlock))
.forEach(
s ->
combinedProtocolSchedule.putBlockNumberMilestone(s.fork().milestone(), s.spec()));
s -> {
if (s instanceof ScheduledProtocolSpec.TimestampProtocolSpec) {
combinedProtocolSchedule.putTimestampMilestone(s.fork().milestone(), s.spec());
} else if (s instanceof ScheduledProtocolSpec.BlockNumberProtocolSpec) {
combinedProtocolSchedule.putBlockNumberMilestone(s.fork().milestone(), s.spec());
} else {
throw new IllegalStateException(
"Unexpected milestone: " + s + " for milestone: " + s.fork().milestone());
}
});
// When moving to a new consensus mechanism we want to use the last milestone but created by
// our consensus mechanism's BesuControllerBuilder so any additional rules are applied
if (spec.getBlock() > 0) {
combinedProtocolSchedule.putBlockNumberMilestone(
spec.getBlock(), protocolSchedule.getByBlockNumber(spec.getBlock()));
spec.getBlock(), protocolSchedule.getByBlockNumberOrTimestamp(spec.getBlock(), 0L));
}
}
return combinedProtocolSchedule;

View File

@@ -28,6 +28,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecBuilder;
import org.hyperledger.besu.ethereum.mainnet.WithdrawalsValidator;
import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
@@ -116,6 +117,9 @@ public abstract class BaseBftProtocolScheduleBuilder {
.skipZeroBlockRewards(true)
.blockHeaderFunctions(BftBlockHeaderFunctions.forOnchainBlock(bftExtraDataCodec))
.blockReward(Wei.of(configOptions.getBlockRewardWei()))
.withdrawalsValidator(
new WithdrawalsValidator
.ProhibitedWithdrawals()) // QBFT/IBFT doesn't support withdrawals
.miningBeneficiaryCalculator(
header -> configOptions.getMiningBeneficiary().orElseGet(header::getCoinbase));
}

View File

@@ -39,12 +39,13 @@ public class BftProtocolSchedule extends DefaultProtocolSchedule {
}
/**
* Look up ProtocolSpec by block number
* Look up ProtocolSpec by block number or timestamp
*
* @param number block number
* @return the protocol spec for that block number
* @param timestamp block timestamp
* @return the protocol spec for that block number or timestamp
*/
public ProtocolSpec getByBlockNumber(final long number) {
public ProtocolSpec getByBlockNumberOrTimestamp(final long number, final long timestamp) {
checkArgument(number >= 0, "number must be non-negative");
checkArgument(
!protocolSpecs.isEmpty(), "At least 1 milestone must be provided to the protocol schedule");
@@ -53,12 +54,19 @@ public class BftProtocolSchedule extends DefaultProtocolSchedule {
"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
ProtocolSpec theSpec = null;
for (final ScheduledProtocolSpec s : protocolSpecs) {
if (number >= s.fork().milestone()) {
return s.spec();
if ((s instanceof ScheduledProtocolSpec.BlockNumberProtocolSpec)
&& (number >= s.fork().milestone())) {
theSpec = s.spec();
break;
} else if ((s instanceof ScheduledProtocolSpec.TimestampProtocolSpec)
&& (timestamp >= s.fork().milestone())) {
theSpec = s.spec();
break;
}
}
return null;
return theSpec;
}
/**

View File

@@ -60,18 +60,20 @@ public class CombinedProtocolScheduleFactoryTest {
final BftProtocolSchedule combinedProtocolSchedule =
combinedProtocolScheduleFactory.create(consensusSchedule, Optional.of(BigInteger.TEN));
assertThat(combinedProtocolSchedule.getByBlockNumber(0L).getName()).isEqualTo("Frontier");
assertThat(combinedProtocolSchedule.getByBlockNumber(0L))
.isSameAs(protocolSchedule.getByBlockNumber(0L));
assertThat(combinedProtocolSchedule.getByBlockNumberOrTimestamp(0L, 0L).getName())
.isEqualTo("Frontier");
assertThat(combinedProtocolSchedule.getByBlockNumberOrTimestamp(0L, 0L))
.isSameAs(protocolSchedule.getByBlockNumberOrTimestamp(0L, 0L));
assertThat(combinedProtocolSchedule.getByBlockNumber(5L).getName()).isEqualTo("Homestead");
assertThat(combinedProtocolSchedule.getByBlockNumber(5L))
.isSameAs(protocolSchedule.getByBlockNumber(5L));
assertThat(combinedProtocolSchedule.getByBlockNumberOrTimestamp(5L, 0L).getName())
.isEqualTo("Homestead");
assertThat(combinedProtocolSchedule.getByBlockNumberOrTimestamp(5L, 0L))
.isSameAs(protocolSchedule.getByBlockNumberOrTimestamp(5L, 0L));
assertThat(combinedProtocolSchedule.getByBlockNumber(10L).getName())
assertThat(combinedProtocolSchedule.getByBlockNumberOrTimestamp(10L, 0L).getName())
.isEqualTo("Constantinople");
assertThat(combinedProtocolSchedule.getByBlockNumber(10L))
.isSameAs(protocolSchedule.getByBlockNumber(10L));
assertThat(combinedProtocolSchedule.getByBlockNumberOrTimestamp(10L, 0L))
.isSameAs(protocolSchedule.getByBlockNumberOrTimestamp(10L, 0L));
assertThat(
new MilestoneStreamingProtocolSchedule(combinedProtocolSchedule)
@@ -88,63 +90,78 @@ public class CombinedProtocolScheduleFactoryTest {
genesisConfigOptions.byzantiumBlock(105L);
genesisConfigOptions.berlinBlock(110L);
genesisConfigOptions.londonBlock(220L);
genesisConfigOptions.shanghaiTime(1000000050L);
genesisConfigOptions.chainId(BigInteger.TEN);
final BftProtocolSchedule protocolSchedule1 = createProtocolSchedule(genesisConfigOptions);
final BftProtocolSchedule protocolSchedule2 = createProtocolSchedule(genesisConfigOptions);
final BftProtocolSchedule protocolSchedule3 = createProtocolSchedule(genesisConfigOptions);
final BftProtocolSchedule protocolSchedule4 = createProtocolSchedule(genesisConfigOptions);
final NavigableSet<ForkSpec<ProtocolSchedule>> consensusSchedule =
new TreeSet<>(ForkSpec.COMPARATOR);
consensusSchedule.add(new ForkSpec<>(0, protocolSchedule1));
consensusSchedule.add(new ForkSpec<>(100L, protocolSchedule2));
consensusSchedule.add(new ForkSpec<>(200L, protocolSchedule3));
consensusSchedule.add(new ForkSpec<>(1000000000L, protocolSchedule4));
final BftProtocolSchedule combinedProtocolSchedule =
combinedProtocolScheduleFactory.create(consensusSchedule, Optional.of(BigInteger.TEN));
// consensus schedule 1
assertThat(combinedProtocolSchedule.getByBlockNumber(0L).getName()).isEqualTo("Frontier");
assertThat(combinedProtocolSchedule.getByBlockNumber(0L))
.isSameAs(protocolSchedule1.getByBlockNumber(0L));
assertThat(combinedProtocolSchedule.getByBlockNumberOrTimestamp(0L, 0L).getName())
.isEqualTo("Frontier");
assertThat(combinedProtocolSchedule.getByBlockNumberOrTimestamp(0L, 0L))
.isSameAs(protocolSchedule1.getByBlockNumberOrTimestamp(0L, 0L));
assertThat(combinedProtocolSchedule.getByBlockNumber(5L).getName()).isEqualTo("Homestead");
assertThat(combinedProtocolSchedule.getByBlockNumber(5L))
.isSameAs(protocolSchedule1.getByBlockNumber(5L));
assertThat(combinedProtocolSchedule.getByBlockNumber(10L).getName())
assertThat(combinedProtocolSchedule.getByBlockNumberOrTimestamp(5L, 0L).getName())
.isEqualTo("Homestead");
assertThat(combinedProtocolSchedule.getByBlockNumberOrTimestamp(5L, 0L))
.isSameAs(protocolSchedule1.getByBlockNumberOrTimestamp(5L, 0L));
assertThat(combinedProtocolSchedule.getByBlockNumberOrTimestamp(10L, 0L).getName())
.isEqualTo("Constantinople");
assertThat(combinedProtocolSchedule.getByBlockNumber(10L))
.isSameAs(protocolSchedule1.getByBlockNumber(10L));
assertThat(combinedProtocolSchedule.getByBlockNumberOrTimestamp(10L, 0L))
.isSameAs(protocolSchedule1.getByBlockNumberOrTimestamp(10L, 0L));
// consensus schedule 2 migration block
assertThat(combinedProtocolSchedule.getByBlockNumber(100L).getName())
assertThat(combinedProtocolSchedule.getByBlockNumberOrTimestamp(100L, 0L).getName())
.isEqualTo("Constantinople");
assertThat(combinedProtocolSchedule.getByBlockNumber(100L))
.isSameAs(protocolSchedule2.getByBlockNumber(10L));
assertThat(combinedProtocolSchedule.getByBlockNumberOrTimestamp(100L, 0L))
.isSameAs(protocolSchedule2.getByBlockNumberOrTimestamp(10L, 0L));
// consensus schedule 2
assertThat(combinedProtocolSchedule.getByBlockNumber(105L).getName()).isEqualTo("Byzantium");
assertThat(combinedProtocolSchedule.getByBlockNumber(105L))
.isSameAs(protocolSchedule2.getByBlockNumber(105L));
assertThat(combinedProtocolSchedule.getByBlockNumber(110L).getName()).isEqualTo("Berlin");
assertThat(combinedProtocolSchedule.getByBlockNumber(110L))
.isSameAs(protocolSchedule2.getByBlockNumber(110L));
assertThat(combinedProtocolSchedule.getByBlockNumberOrTimestamp(105L, 0L).getName())
.isEqualTo("Byzantium");
assertThat(combinedProtocolSchedule.getByBlockNumberOrTimestamp(105L, 0L))
.isSameAs(protocolSchedule2.getByBlockNumberOrTimestamp(105L, 0L));
assertThat(combinedProtocolSchedule.getByBlockNumberOrTimestamp(110L, 0L).getName())
.isEqualTo("Berlin");
assertThat(combinedProtocolSchedule.getByBlockNumberOrTimestamp(110L, 0L))
.isSameAs(protocolSchedule2.getByBlockNumberOrTimestamp(110L, 0L));
// consensus schedule 3 migration block
assertThat(combinedProtocolSchedule.getByBlockNumber(200L).getName()).isEqualTo("Berlin");
assertThat(combinedProtocolSchedule.getByBlockNumber(200L))
.isSameAs(protocolSchedule3.getByBlockNumber(110L));
assertThat(combinedProtocolSchedule.getByBlockNumberOrTimestamp(200L, 0L).getName())
.isEqualTo("Berlin");
assertThat(combinedProtocolSchedule.getByBlockNumberOrTimestamp(200L, 0L))
.isSameAs(protocolSchedule3.getByBlockNumberOrTimestamp(110L, 0L));
// consensus schedule 3
assertThat(combinedProtocolSchedule.getByBlockNumber(220L).getName()).isEqualTo("London");
assertThat(combinedProtocolSchedule.getByBlockNumber(220L))
.isSameAs(protocolSchedule3.getByBlockNumber(220L));
assertThat(combinedProtocolSchedule.getByBlockNumberOrTimestamp(220L, 0L).getName())
.isEqualTo("London");
assertThat(combinedProtocolSchedule.getByBlockNumberOrTimestamp(220L, 0L))
.isSameAs(protocolSchedule3.getByBlockNumberOrTimestamp(220L, 0L));
// consensus schedule 4
assertThat(combinedProtocolSchedule.getByBlockNumberOrTimestamp(0L, 1000000050L).getName())
.isEqualTo("Shanghai");
assertThat(combinedProtocolSchedule.getByBlockNumberOrTimestamp(220L, 1000000050L))
.isSameAs(protocolSchedule4.getByBlockNumberOrTimestamp(220L, 1000000050L));
assertThat(
new MilestoneStreamingProtocolSchedule(combinedProtocolSchedule)
.streamMilestoneBlocks()
.collect(Collectors.toList()))
.isEqualTo(List.of(0L, 5L, 10L, 100L, 105L, 110L, 200L, 220L));
.isEqualTo(List.of(0L, 5L, 10L, 100L, 105L, 110L, 200L, 220L, 1000000000L, 1000000050L));
}
private BftProtocolSchedule createProtocolSchedule(

View File

@@ -24,6 +24,7 @@ import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.consensus.common.bft.BftExtraData;
import org.hyperledger.besu.consensus.common.bft.BftProtocolSchedule;
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
import org.hyperledger.besu.consensus.common.bft.RoundTimer;
import org.hyperledger.besu.consensus.common.bft.blockcreation.BftBlockCreator;
@@ -48,6 +49,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.BlockImporter;
import org.hyperledger.besu.ethereum.mainnet.BlockImportResult;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.plugin.services.securitymodule.SecurityModuleException;
import org.hyperledger.besu.util.Subscribers;
@@ -74,6 +76,8 @@ public class IbftRoundIntegrationTest {
private final Subscribers<MinedBlockObserver> subscribers = Subscribers.create();
private ProtocolContext protocolContext;
@Mock private BftProtocolSchedule protocolSchedule;
@Mock private ProtocolSpec protocolSpec;
@Mock private MutableBlockchain blockChain;
@Mock private WorldStateArchive worldStateArchive;
@Mock private BlockImporter blockImporter;
@@ -112,6 +116,9 @@ public class IbftRoundIntegrationTest {
final BlockHeader header = headerTestFixture.buildHeader();
proposedBlock = new Block(header, new BlockBody(emptyList(), emptyList()));
when(protocolSchedule.getByBlockHeader(any())).thenReturn(protocolSpec);
when(protocolSpec.getBlockImporter()).thenReturn(blockImporter);
when(blockImporter.importBlock(any(), any(), any())).thenReturn(new BlockImportResult(true));
protocolContext =
@@ -131,7 +138,7 @@ public class IbftRoundIntegrationTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
throwingMessageFactory,
@@ -158,7 +165,7 @@ public class IbftRoundIntegrationTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
throwingMessageFactory,

View File

@@ -40,6 +40,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockImporter;
import org.hyperledger.besu.ethereum.mainnet.BlockImportResult;
import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.plugin.services.securitymodule.SecurityModuleException;
import org.hyperledger.besu.util.Subscribers;
@@ -57,7 +58,7 @@ public class IbftRound {
private final RoundState roundState;
private final BlockCreator blockCreator;
private final ProtocolContext protocolContext;
private final BlockImporter blockImporter;
private final ProtocolSchedule protocolSchedule;
private final NodeKey nodeKey;
private final MessageFactory messageFactory; // used only to create stored local msgs
private final IbftMessageTransmitter transmitter;
@@ -69,7 +70,7 @@ public class IbftRound {
* @param roundState the round state
* @param blockCreator the block creator
* @param protocolContext the protocol context
* @param blockImporter the block importer
* @param protocolSchedule the protocol schedule
* @param observers the observers
* @param nodeKey the node key
* @param messageFactory the message factory
@@ -81,7 +82,7 @@ public class IbftRound {
final RoundState roundState,
final BlockCreator blockCreator,
final ProtocolContext protocolContext,
final BlockImporter blockImporter,
final ProtocolSchedule protocolSchedule,
final Subscribers<MinedBlockObserver> observers,
final NodeKey nodeKey,
final MessageFactory messageFactory,
@@ -91,7 +92,7 @@ public class IbftRound {
this.roundState = roundState;
this.blockCreator = blockCreator;
this.protocolContext = protocolContext;
this.blockImporter = blockImporter;
this.protocolSchedule = protocolSchedule;
this.observers = observers;
this.nodeKey = nodeKey;
this.messageFactory = messageFactory;
@@ -312,6 +313,8 @@ public class IbftRound {
blockToImport.getHash());
}
LOG.trace("Importing block with extraData={}", extraData);
final BlockImporter blockImporter =
protocolSchedule.getByBlockHeader(blockToImport.getHeader()).getBlockImporter();
final BlockImportResult result =
blockImporter.importBlock(protocolContext, blockToImport, HeaderValidationMode.FULL);
if (!result.isImported()) {

View File

@@ -99,9 +99,8 @@ public class IbftRoundFactory {
*/
public IbftRound createNewRoundWithState(
final BlockHeader parentHeader, final RoundState roundState) {
final ConsensusRoundIdentifier roundIdentifier = roundState.getRoundIdentifier();
final BlockCreator blockCreator =
blockCreatorFactory.create(parentHeader, roundIdentifier.getRoundNumber());
blockCreatorFactory.create(parentHeader, roundState.getRoundIdentifier().getRoundNumber());
final IbftMessageTransmitter messageTransmitter =
new IbftMessageTransmitter(messageFactory, finalState.getValidatorMulticaster());
@@ -110,7 +109,7 @@ public class IbftRoundFactory {
roundState,
blockCreator,
protocolContext,
protocolSchedule.getByBlockNumber(roundIdentifier.getSequenceNumber()).getBlockImporter(),
protocolSchedule,
minedBlockObservers,
finalState.getNodeKey(),
messageFactory,

View File

@@ -25,6 +25,7 @@ import org.hyperledger.besu.ethereum.BlockValidator;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import java.util.Optional;
@@ -38,7 +39,7 @@ public class MessageValidator {
private final SignedDataValidator signedDataValidator;
private final ProposalBlockConsistencyValidator proposalConsistencyValidator;
private final BlockValidator blockValidator;
private final ProtocolSchedule protocolSchedule;
private final ProtocolContext protocolContext;
private final RoundChangeCertificateValidator roundChangeCertificateValidator;
@@ -47,19 +48,19 @@ public class MessageValidator {
*
* @param signedDataValidator the signed data validator
* @param proposalConsistencyValidator the proposal consistency validator
* @param blockValidator the block validator
* @param protocolSchedule the protocol schedule
* @param protocolContext the protocol context
* @param roundChangeCertificateValidator the round change certificate validator
*/
public MessageValidator(
final SignedDataValidator signedDataValidator,
final ProposalBlockConsistencyValidator proposalConsistencyValidator,
final BlockValidator blockValidator,
final ProtocolContext protocolContext,
final ProtocolSchedule protocolSchedule,
final RoundChangeCertificateValidator roundChangeCertificateValidator) {
this.signedDataValidator = signedDataValidator;
this.proposalConsistencyValidator = proposalConsistencyValidator;
this.blockValidator = blockValidator;
this.protocolSchedule = protocolSchedule;
this.protocolContext = protocolContext;
this.roundChangeCertificateValidator = roundChangeCertificateValidator;
}
@@ -93,6 +94,10 @@ public class MessageValidator {
}
private boolean validateBlock(final Block block) {
final BlockValidator blockValidator =
protocolSchedule.getByBlockHeader(block.getHeader()).getBlockValidator();
final var validationResult =
blockValidator.validateAndProcessBlock(
protocolContext, block, HeaderValidationMode.LIGHT, HeaderValidationMode.FULL);

View File

@@ -22,7 +22,6 @@ import org.hyperledger.besu.consensus.common.bft.BftProtocolSchedule;
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
import org.hyperledger.besu.consensus.common.bft.blockcreation.ProposerSelector;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.ethereum.BlockValidator;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.core.BlockHeader;
@@ -80,8 +79,6 @@ public class MessageValidatorFactory {
*/
public MessageValidator createMessageValidator(
final ConsensusRoundIdentifier roundIdentifier, final BlockHeader parentHeader) {
final BlockValidator blockValidator =
protocolSchedule.getByBlockNumber(roundIdentifier.getSequenceNumber()).getBlockValidator();
final Collection<Address> validators = getValidatorsAfterBlock(parentHeader);
final BftBlockInterface bftBlockInterface =
@@ -90,8 +87,8 @@ public class MessageValidatorFactory {
return new MessageValidator(
createSignedDataValidator(roundIdentifier, parentHeader),
new ProposalBlockConsistencyValidator(),
blockValidator,
protocolContext,
protocolSchedule,
new RoundChangeCertificateValidator(
validators,
(ri) -> createSignedDataValidator(ri, parentHeader),

View File

@@ -110,7 +110,7 @@ public class IbftProtocolScheduleTest {
final BlockHeader blockHeader,
final int block) {
return schedule
.getByBlockNumber(block)
.getByBlockNumberOrTimestamp(block, blockHeader.getTimestamp())
.getBlockHeaderValidator()
.validateHeader(
blockHeader, parentHeader, protocolContext(validators), HeaderValidationMode.LIGHT);

View File

@@ -31,8 +31,10 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.config.StubGenesisConfigOptions;
import org.hyperledger.besu.consensus.common.bft.BftExtraData;
import org.hyperledger.besu.consensus.common.bft.BftExtraDataCodec;
import org.hyperledger.besu.consensus.common.bft.BftProtocolSchedule;
import org.hyperledger.besu.consensus.common.bft.BlockTimer;
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
import org.hyperledger.besu.consensus.common.bft.RoundTimer;
@@ -61,13 +63,19 @@ import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.blockcreation.BlockCreator.BlockCreationResult;
import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionSelectionResults;
import org.hyperledger.besu.ethereum.chain.DefaultBlockchain;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockBody;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.BlockImporter;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.core.Util;
import org.hyperledger.besu.ethereum.mainnet.DefaultProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.util.Subscribers;
import java.math.BigInteger;
@@ -75,6 +83,7 @@ import java.time.Clock;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import com.google.common.collect.Lists;
import org.apache.tuweni.bytes.Bytes;
@@ -101,8 +110,8 @@ public class IbftBlockHeightManagerTest {
@Mock private Clock clock;
@Mock private MessageValidatorFactory messageValidatorFactory;
@Mock private BftBlockCreator blockCreator;
@Mock private BlockImporter blockImporter;
@Mock private BlockTimer blockTimer;
@Mock private DefaultBlockchain blockchain;
@Mock private RoundTimer roundTimer;
@Mock private FutureRoundProposalMessageValidator futureRoundProposalMessageValidator;
@Mock private ValidatorMulticaster validatorMulticaster;
@@ -158,7 +167,21 @@ public class IbftBlockHeightManagerTest {
.thenReturn(messageValidator);
protocolContext =
new ProtocolContext(null, null, setupContextWithValidators(validators), Optional.empty());
new ProtocolContext(
blockchain, null, setupContextWithValidators(validators), Optional.empty());
final ProtocolScheduleBuilder protocolScheduleBuilder =
new ProtocolScheduleBuilder(
new StubGenesisConfigOptions(),
BigInteger.ONE,
ProtocolSpecAdapters.create(0, Function.identity()),
new PrivacyParameters(),
false,
EvmConfiguration.DEFAULT);
ProtocolSchedule protocolSchedule =
new BftProtocolSchedule(
(DefaultProtocolSchedule) protocolScheduleBuilder.createProtocolSchedule());
// Ensure the created IbftRound has the valid ConsensusRoundIdentifier;
when(roundFactory.createNewRound(any(), anyInt()))
@@ -171,7 +194,7 @@ public class IbftBlockHeightManagerTest {
createdRoundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
Subscribers.create(),
nodeKey,
messageFactory,
@@ -189,7 +212,7 @@ public class IbftBlockHeightManagerTest {
providedRoundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
Subscribers.create(),
nodeKey,
messageFactory,

View File

@@ -32,6 +32,7 @@ import static org.mockito.Mockito.when;
import org.hyperledger.besu.consensus.common.bft.BftBlockHashing;
import org.hyperledger.besu.consensus.common.bft.BftExtraData;
import org.hyperledger.besu.consensus.common.bft.BftExtraDataCodec;
import org.hyperledger.besu.consensus.common.bft.BftProtocolSchedule;
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
import org.hyperledger.besu.consensus.common.bft.RoundTimer;
import org.hyperledger.besu.consensus.common.bft.blockcreation.BftBlockCreator;
@@ -56,6 +57,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.BlockImporter;
import org.hyperledger.besu.ethereum.mainnet.BlockImportResult;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.plugin.services.securitymodule.SecurityModuleException;
import org.hyperledger.besu.util.Subscribers;
@@ -83,14 +85,16 @@ public class IbftRoundTest {
private final BftExtraDataCodec bftExtraDataCodec = new IbftExtraDataCodec();
private ProtocolContext protocolContext;
@Mock private BftProtocolSchedule protocolSchedule;
@Mock private MutableBlockchain blockChain;
@Mock private WorldStateArchive worldStateArchive;
@Mock private BlockImporter blockImporter;
@Mock private IbftMessageTransmitter transmitter;
@Mock private MinedBlockObserver minedBlockObserver;
@Mock private BftBlockCreator blockCreator;
@Mock private MessageValidator messageValidator;
@Mock private RoundTimer roundTimer;
@Mock private ProtocolSpec protocolSpec;
@Mock private BlockImporter blockImporter;
@Captor private ArgumentCaptor<Block> blockCaptor;
@@ -127,9 +131,12 @@ public class IbftRoundTest {
.when(blockCreator.createBlock(anyLong()))
.thenReturn(new BlockCreationResult(proposedBlock, new TransactionSelectionResults()));
lenient().when(protocolSpec.getBlockImporter()).thenReturn(blockImporter);
lenient().when(protocolSchedule.getByBlockHeader(any())).thenReturn(protocolSpec);
lenient()
.when(blockImporter.importBlock(any(), any(), any()))
.thenReturn(new BlockImportResult(true));
.thenReturn(new BlockImportResult(BlockImportResult.BlockImportStatus.IMPORTED));
subscribers.subscribe(minedBlockObserver);
}
@@ -141,7 +148,7 @@ public class IbftRoundTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
messageFactory,
@@ -159,7 +166,7 @@ public class IbftRoundTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
messageFactory,
@@ -181,7 +188,7 @@ public class IbftRoundTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
messageFactory,
@@ -204,7 +211,7 @@ public class IbftRoundTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
messageFactory,
@@ -227,7 +234,7 @@ public class IbftRoundTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
messageFactory,
@@ -271,7 +278,7 @@ public class IbftRoundTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
messageFactory,
@@ -308,7 +315,7 @@ public class IbftRoundTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
messageFactory,
@@ -332,7 +339,7 @@ public class IbftRoundTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
messageFactory,
@@ -379,7 +386,7 @@ public class IbftRoundTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
messageFactory,
@@ -413,7 +420,7 @@ public class IbftRoundTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
messageFactory,
@@ -434,7 +441,7 @@ public class IbftRoundTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
messageFactory,
@@ -460,7 +467,7 @@ public class IbftRoundTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
messageFactory,
@@ -490,7 +497,7 @@ public class IbftRoundTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
throwingNodeKey,
throwingMessageFactory,

View File

@@ -17,6 +17,7 @@ package org.hyperledger.besu.consensus.ibft.validation;
import static java.util.Collections.emptyList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
@@ -26,6 +27,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.consensus.common.bft.BftContext;
import org.hyperledger.besu.consensus.common.bft.BftProtocolSchedule;
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
import org.hyperledger.besu.consensus.common.bft.ProposedBlockHelpers;
import org.hyperledger.besu.consensus.ibft.messagewrappers.Commit;
@@ -42,6 +44,7 @@ import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.AddressHelpers;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import java.util.List;
@@ -66,6 +69,8 @@ public class MessageValidatorTest {
private final ProposalBlockConsistencyValidator proposalBlockConsistencyValidator =
mock(ProposalBlockConsistencyValidator.class);
@Mock private BftProtocolSchedule protocolSchedule;
@Mock private ProtocolSpec protocolSpec;
@Mock private BlockValidator blockValidator;
private ProtocolContext protocolContext;
private final RoundChangeCertificateValidator roundChangeCertificateValidator =
@@ -101,6 +106,12 @@ public class MessageValidatorTest {
mockBftCtx,
Optional.empty());
lenient()
.when(protocolSchedule.getByBlockNumberOrTimestamp(anyLong(), anyLong()))
.thenReturn(protocolSpec);
when(protocolSpec.getBlockValidator()).thenReturn(blockValidator);
when(protocolSchedule.getByBlockHeader(any())).thenReturn(protocolSpec);
when(blockValidator.validateAndProcessBlock(any(), any(), any(), any()))
.thenReturn(new BlockProcessingResult(Optional.empty()));
@@ -115,8 +126,8 @@ public class MessageValidatorTest {
new MessageValidator(
signedDataValidator,
proposalBlockConsistencyValidator,
blockValidator,
protocolContext,
protocolSchedule,
roundChangeCertificateValidator);
}

View File

@@ -147,6 +147,7 @@ public class TestContextBuilder {
private static final MetricsSystem metricsSystem = new NoOpMetricsSystem();
private boolean useValidatorContract;
private boolean useLondonMilestone = false;
private boolean useShanghaiMilestone = false;
private boolean useZeroBaseFee = false;
public static final int EPOCH_LENGTH = 10_000;
public static final int BLOCK_TIMER_SEC = 3;
@@ -215,6 +216,11 @@ public class TestContextBuilder {
return this;
}
public TestContextBuilder useShanghaiMilestone(final boolean useShanghaiMilestone) {
this.useShanghaiMilestone = useShanghaiMilestone;
return this;
}
public TestContextBuilder useZeroBaseFee(final boolean useZeroBaseFee) {
this.useZeroBaseFee = useZeroBaseFee;
return this;
@@ -285,6 +291,7 @@ public class TestContextBuilder {
synchronizerUpdater,
useValidatorContract,
useLondonMilestone,
useShanghaiMilestone,
useZeroBaseFee,
qbftForks);
@@ -365,6 +372,7 @@ public class TestContextBuilder {
final SynchronizerUpdater synchronizerUpdater,
final boolean useValidatorContract,
final boolean useLondonMilestone,
final boolean useShanghaiMilestone,
final boolean useZeroBaseFee,
final List<QbftFork> qbftForks) {
@@ -390,6 +398,8 @@ public class TestContextBuilder {
if (useLondonMilestone) {
genesisConfigOptions.londonBlock(0);
} else if (useShanghaiMilestone) {
genesisConfigOptions.shanghaiTime(10);
} else {
genesisConfigOptions.berlinBlock(0);
}

View File

@@ -140,6 +140,33 @@ public class ValidatorContractTest {
assertThat(validatorProvider.getValidatorsForBlock(block1)).containsExactly(NODE_ADDRESS);
}
@Test
public void retrievesValidatorsFromValidatorContract_ShanghaiFork_ZeroBaseFee() {
// Using Shanghai on a free gas network
final TestContext context =
new TestContextBuilder()
.indexOfFirstLocallyProposedBlock(0)
.nodeParams(
List.of(new NodeParams(NODE_ADDRESS, NodeKeyUtils.createFrom(NODE_PRIVATE_KEY))))
.clock(TestClock.fixed())
.genesisFile(
Resources.getResource("genesis_validator_contract_shanghai.json").getFile())
.useValidatorContract(true)
.useShanghaiMilestone(true)
.useZeroBaseFee(true)
.buildAndStart();
createNewBlockAsProposerFixedTime(
context, 1,
266L); // 10s ahead of genesis timestamp in genesis_validator_contract_shanghai.json
final ValidatorProvider validatorProvider = context.getValidatorProvider();
final BlockHeader genesisBlock = context.getBlockchain().getBlockHeader(0).get();
final BlockHeader block1 = context.getBlockchain().getBlockHeader(1).get();
assertThat(validatorProvider.getValidatorsForBlock(genesisBlock)).containsExactly(NODE_ADDRESS);
assertThat(validatorProvider.getValidatorsForBlock(block1)).containsExactly(NODE_ADDRESS);
}
@Test
public void transitionsFromBlockHeaderModeToValidatorContractMode() {
final List<QbftFork> qbftForks =
@@ -397,6 +424,24 @@ public class ValidatorContractTest {
.handleNewBlockEvent(new NewChainHead(context.getBlockchain().getChainHeadHeader()));
}
private void createNewBlockAsProposerFixedTime(
final TestContext context, final long blockNumber, final long timestamp) {
ConsensusRoundIdentifier roundId = new ConsensusRoundIdentifier(blockNumber, 0);
// trigger proposal
context.getController().handleBlockTimerExpiry(new BlockTimerExpiry(roundId));
// peers commit proposed block
Block proposedBlock = context.createBlockForProposalFromChainHead(timestamp);
RoundSpecificPeers peers = context.roundSpecificPeers(roundId);
peers.commitForNonProposing(roundId, proposedBlock);
assertThat(context.getCurrentChainHeight()).isEqualTo(blockNumber);
context
.getController()
.handleNewBlockEvent(new NewChainHead(context.getBlockchain().getChainHeadHeader()));
}
private void remotePeerProposesNewBlock(final TestContext context, final long blockNumber) {
ConsensusRoundIdentifier roundId = new ConsensusRoundIdentifier(blockNumber, 0);

View File

@@ -25,6 +25,7 @@ import static org.mockito.Mockito.when;
import org.hyperledger.besu.consensus.common.bft.BftExtraData;
import org.hyperledger.besu.consensus.common.bft.BftExtraDataCodec;
import org.hyperledger.besu.consensus.common.bft.BftProtocolSchedule;
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
import org.hyperledger.besu.consensus.common.bft.RoundTimer;
import org.hyperledger.besu.consensus.common.bft.blockcreation.BftBlockCreator;
@@ -50,6 +51,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.BlockImporter;
import org.hyperledger.besu.ethereum.mainnet.BlockImportResult;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.plugin.services.securitymodule.SecurityModuleException;
import org.hyperledger.besu.util.Subscribers;
@@ -77,6 +79,8 @@ public class QbftRoundIntegrationTest {
private final BftExtraDataCodec bftExtraDataCodec = new QbftExtraDataCodec();
private ProtocolContext protocolContext;
@Mock private BftProtocolSchedule protocolSchedule;
@Mock private ProtocolSpec protocolSpec;
@Mock private MutableBlockchain blockChain;
@Mock private WorldStateArchive worldStateArchive;
@Mock private BlockImporter blockImporter;
@@ -115,6 +119,9 @@ public class QbftRoundIntegrationTest {
final BlockHeader header = headerTestFixture.buildHeader();
proposedBlock = new Block(header, new BlockBody(emptyList(), emptyList()));
when(protocolSchedule.getByBlockHeader(any())).thenReturn(protocolSpec);
when(protocolSpec.getBlockImporter()).thenReturn(blockImporter);
when(blockImporter.importBlock(any(), any(), any())).thenReturn(new BlockImportResult(true));
protocolContext =
@@ -135,7 +142,7 @@ public class QbftRoundIntegrationTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
throwingMessageFactory,
@@ -163,7 +170,7 @@ public class QbftRoundIntegrationTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
throwingMessageFactory,

View File

@@ -0,0 +1,46 @@
{
"nonce": "0x0",
"timestamp": "0x100",
"extraData": "0xe5a00000000000000000000000000000000000000000000000000000000000000000c0c080c0",
"gasLimit": "0x29b92700",
"difficulty": "0x1",
"mixHash": "0x63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365",
"coinbase": "0x0000000000000000000000000000000000000000",
"alloc": {
"64d9be4177f418bcf4e56adad85f33e3a64efe22": {
"balance": "0x446c3b15f9926687d2c40534fdb564000000000000"
},
"9f66f8a0f0a6537e4a36aa1799673ea7ae97a166": {
"balance": "0x446c3b15f9926687d2c40534fdb564000000000000"
},
"a7f25969fb6f3d5ac09a88862c90b5ff664557a7": {
"balance": "0x446c3b15f9926687d2c40534fdb564000000000000"
},
"f4bbfd32c11c9d63e9b4c77bb225810f840342df": {
"balance": "0x446c3b15f9926687d2c40534fdb564000000000000"
},
"0x0000000000000000000000000000000000008888": {
"comment": "validator smart contract. This is compiled from validator_contract.sol using solc --evm-version shanghai --bin-runtime validator_contract.sol",
"balance": "0",
"code": "608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063b7ab4db51461002d575b5f80fd5b61003561004b565b60405161004291906101bc565b60405180910390f35b60605f8054806020026020016040519081016040528092919081815260200182805480156100cb57602002820191905f5260205f20905b815f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610082575b5050505050905090565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610127826100fe565b9050919050565b6101378161011d565b82525050565b5f610148838361012e565b60208301905092915050565b5f602082019050919050565b5f61016a826100d5565b61017481856100df565b935061017f836100ef565b805f5b838110156101af578151610196888261013d565b97506101a183610154565b925050600181019050610182565b5085935050505092915050565b5f6020820190508181035f8301526101d48184610160565b90509291505056fea2646970667358221220b52fc648d3af2856c13132ebd193317528087a330aea868fcf843abcf9d9dc6d64736f6c63430008140033",
"storage": {
"0000000000000000000000000000000000000000000000000000000000000000": "0000000000000000000000000000000000000000000000000000000000000001",
"290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563": "000000000000000000000000eac51e3fe1afc9894f0dfeab8ceb471899b932df"
}
},
"0x0000000000000000000000000000000000009999": {
"comment": "validator smart contract. This is compiled from validator_contract.sol using solc --evm-version shanghai --bin-runtime validator_contract.sol",
"balance": "0",
"code": "608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063b7ab4db51461002d575b5f80fd5b61003561004b565b60405161004291906101bc565b60405180910390f35b60605f8054806020026020016040519081016040528092919081815260200182805480156100cb57602002820191905f5260205f20905b815f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311610082575b5050505050905090565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610127826100fe565b9050919050565b6101378161011d565b82525050565b5f610148838361012e565b60208301905092915050565b5f602082019050919050565b5f61016a826100d5565b61017481856100df565b935061017f836100ef565b805f5b838110156101af578151610196888261013d565b97506101a183610154565b925050600181019050610182565b5085935050505092915050565b5f6020820190508181035f8301526101d48184610160565b90509291505056fea2646970667358221220b52fc648d3af2856c13132ebd193317528087a330aea868fcf843abcf9d9dc6d64736f6c63430008140033",
"storage": {
"0000000000000000000000000000000000000000000000000000000000000000": "0000000000000000000000000000000000000000000000000000000000000002",
"290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563": "000000000000000000000000e98d92560fac3069ccff53ef348ded26a51d4b68",
"290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e564": "000000000000000000000000eac51e3fe1afc9894f0dfeab8ceb471899b932df"
}
}
},
"number": "0x0",
"gasUsed": "0x0",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"baseFeePerGas": "0x7"
}

View File

@@ -44,6 +44,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockImporter;
import org.hyperledger.besu.ethereum.mainnet.BlockImportResult;
import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.plugin.services.securitymodule.SecurityModuleException;
import org.hyperledger.besu.util.Subscribers;
@@ -65,8 +66,9 @@ public class QbftRound {
protected final BlockCreator blockCreator;
/** The Protocol context. */
protected final ProtocolContext protocolContext;
/** The Protocol schedule. */
protected final ProtocolSchedule protocolSchedule;
private final BlockImporter blockImporter;
private final NodeKey nodeKey;
private final MessageFactory messageFactory; // used only to create stored local msgs
private final QbftMessageTransmitter transmitter;
@@ -79,7 +81,7 @@ public class QbftRound {
* @param roundState the round state
* @param blockCreator the block creator
* @param protocolContext the protocol context
* @param blockImporter the block importer
* @param protocolSchedule the protocol schedule
* @param observers the observers
* @param nodeKey the node key
* @param messageFactory the message factory
@@ -91,7 +93,7 @@ public class QbftRound {
final RoundState roundState,
final BlockCreator blockCreator,
final ProtocolContext protocolContext,
final BlockImporter blockImporter,
final ProtocolSchedule protocolSchedule,
final Subscribers<MinedBlockObserver> observers,
final NodeKey nodeKey,
final MessageFactory messageFactory,
@@ -101,7 +103,7 @@ public class QbftRound {
this.roundState = roundState;
this.blockCreator = blockCreator;
this.protocolContext = protocolContext;
this.blockImporter = blockImporter;
this.protocolSchedule = protocolSchedule;
this.observers = observers;
this.nodeKey = nodeKey;
this.messageFactory = messageFactory;
@@ -341,7 +343,10 @@ public class QbftRound {
getRoundIdentifier(),
blockToImport.getHash());
}
LOG.trace("Importing proposed block with extraData={}", extraData);
final BlockImporter blockImporter =
protocolSchedule.getByBlockHeader(blockToImport.getHeader()).getBlockImporter();
final BlockImportResult result =
blockImporter.importBlock(protocolContext, blockToImport, HeaderValidationMode.FULL);
if (!result.isImported()) {

View File

@@ -99,7 +99,6 @@ public class QbftRoundFactory {
*/
public QbftRound createNewRoundWithState(
final BlockHeader parentHeader, final RoundState roundState) {
final ConsensusRoundIdentifier roundIdentifier = roundState.getRoundIdentifier();
final BlockCreator blockCreator = blockCreatorFactory.create(parentHeader, 0);
// TODO(tmm): Why is this created everytime?!
@@ -110,7 +109,7 @@ public class QbftRoundFactory {
roundState,
blockCreator,
protocolContext,
protocolSchedule.getByBlockNumber(roundIdentifier.getSequenceNumber()).getBlockImporter(),
protocolSchedule,
minedBlockObservers,
finalState.getNodeKey(),
messageFactory,

View File

@@ -23,7 +23,6 @@ import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
import org.hyperledger.besu.consensus.common.bft.blockcreation.ProposerSelector;
import org.hyperledger.besu.consensus.qbft.validation.MessageValidator.SubsequentMessageValidator;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.ethereum.BlockValidator;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.core.BlockHeader;
@@ -78,16 +77,13 @@ public class MessageValidatorFactory {
final RoundChangePayloadValidator roundChangePayloadValidator =
new RoundChangePayloadValidator(validatorsForHeight, chainHeight);
final BlockValidator blockValidator =
protocolSchedule.getByBlockNumber(chainHeight).getBlockValidator();
return new RoundChangeMessageValidator(
roundChangePayloadValidator,
BftHelpers.calculateRequiredValidatorQuorum(validatorsForHeight.size()),
chainHeight,
validatorsForHeight,
blockValidator,
protocolContext);
protocolContext,
protocolSchedule);
}
/**
@@ -101,13 +97,11 @@ public class MessageValidatorFactory {
final ConsensusRoundIdentifier roundIdentifier, final BlockHeader parentHeader) {
final Collection<Address> validatorsForHeight = getValidatorsAfterBlock(parentHeader);
final BlockValidator blockValidator =
protocolSchedule.getByBlockNumber(roundIdentifier.getSequenceNumber()).getBlockValidator();
final ProposalValidator proposalValidator =
new ProposalValidator(
blockValidator,
protocolContext,
protocolSchedule,
BftHelpers.calculateRequiredValidatorQuorum(validatorsForHeight.size()),
validatorsForHeight,
roundIdentifier,

View File

@@ -14,6 +14,8 @@
*/
package org.hyperledger.besu.consensus.qbft.validation;
import static com.google.common.base.Preconditions.checkState;
import org.hyperledger.besu.consensus.common.bft.BftBlockInterface;
import org.hyperledger.besu.consensus.common.bft.BftExtraDataCodec;
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
@@ -144,6 +146,8 @@ public class ProposalPayloadValidator {
}
private boolean validateBlock(final Block block) {
checkState(blockValidator != null, "block validation not possible, no block validator.");
final var validationResult =
blockValidator.validateAndProcessBlock(
protocolContext, block, HeaderValidationMode.LIGHT, HeaderValidationMode.FULL);

View File

@@ -33,6 +33,7 @@ import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.BlockValidator;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import java.util.Collection;
import java.util.Comparator;
@@ -49,8 +50,8 @@ public class ProposalValidator {
private static final Logger LOG = LoggerFactory.getLogger(ProposalValidator.class);
private static final String ERROR_PREFIX = "Invalid Proposal Payload";
private final BlockValidator blockValidator;
private final ProtocolContext protocolContext;
private final ProtocolSchedule protocolSchedule;
private final int quorumMessageCount;
private final Collection<Address> validators;
private final ConsensusRoundIdentifier roundIdentifier;
@@ -60,8 +61,8 @@ public class ProposalValidator {
/**
* Instantiates a new Proposal validator.
*
* @param blockValidator the block validator
* @param protocolContext the protocol context
* @param protocolSchedule the protocol schedule
* @param quorumMessageCount the quorum message count
* @param validators the validators
* @param roundIdentifier the round identifier
@@ -69,15 +70,15 @@ public class ProposalValidator {
* @param bftExtraDataCodec the bft extra data codec
*/
public ProposalValidator(
final BlockValidator blockValidator,
final ProtocolContext protocolContext,
final ProtocolSchedule protocolSchedule,
final int quorumMessageCount,
final Collection<Address> validators,
final ConsensusRoundIdentifier roundIdentifier,
final Address expectedProposer,
final BftExtraDataCodec bftExtraDataCodec) {
this.blockValidator = blockValidator;
this.protocolContext = protocolContext;
this.protocolSchedule = protocolSchedule;
this.quorumMessageCount = quorumMessageCount;
this.validators = validators;
this.roundIdentifier = roundIdentifier;
@@ -92,6 +93,8 @@ public class ProposalValidator {
* @return the boolean
*/
public boolean validate(final Proposal msg) {
final BlockValidator blockValidator =
protocolSchedule.getByBlockHeader(msg.getBlock().getHeader()).getBlockValidator();
final ProposalPayloadValidator payloadValidator =
new ProposalPayloadValidator(

View File

@@ -27,6 +27,7 @@ import org.hyperledger.besu.ethereum.BlockValidator;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import java.util.Collection;
import java.util.List;
@@ -45,8 +46,8 @@ public class RoundChangeMessageValidator {
private final long quorumMessageCount;
private final long chainHeight;
private final Collection<Address> validators;
private final BlockValidator blockValidator;
private final ProtocolContext protocolContext;
private final ProtocolSchedule protocolSchedule;
/**
* Instantiates a new Round change message validator.
@@ -55,22 +56,22 @@ public class RoundChangeMessageValidator {
* @param quorumMessageCount the quorum message count
* @param chainHeight the chain height
* @param validators the validators
* @param blockValidator the block validator
* @param protocolContext the protocol context
* @param protocolSchedule the protocol context
*/
public RoundChangeMessageValidator(
final RoundChangePayloadValidator roundChangePayloadValidator,
final long quorumMessageCount,
final long chainHeight,
final Collection<Address> validators,
final BlockValidator blockValidator,
final ProtocolContext protocolContext) {
final ProtocolContext protocolContext,
final ProtocolSchedule protocolSchedule) {
this.roundChangePayloadValidator = roundChangePayloadValidator;
this.quorumMessageCount = quorumMessageCount;
this.chainHeight = chainHeight;
this.validators = validators;
this.blockValidator = blockValidator;
this.protocolContext = protocolContext;
this.protocolSchedule = protocolSchedule;
}
/**
@@ -94,6 +95,10 @@ public class RoundChangeMessageValidator {
}
private boolean validateBlock(final Block block) {
final BlockValidator blockValidator =
protocolSchedule.getByBlockHeader(block.getHeader()).getBlockValidator();
final var validationResult =
blockValidator.validateAndProcessBlock(
protocolContext, block, HeaderValidationMode.LIGHT, HeaderValidationMode.FULL);

View File

@@ -144,7 +144,7 @@ public class QbftProtocolScheduleTest {
final BlockHeader blockHeader,
final int block) {
return schedule
.getByBlockNumber(block)
.getByBlockNumberOrTimestamp(block, blockHeader.getTimestamp())
.getBlockHeaderValidator()
.validateHeader(
blockHeader, parentHeader, protocolContext(validators), HeaderValidationMode.LIGHT);

View File

@@ -31,8 +31,10 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.config.StubGenesisConfigOptions;
import org.hyperledger.besu.consensus.common.bft.BftExtraData;
import org.hyperledger.besu.consensus.common.bft.BftExtraDataCodec;
import org.hyperledger.besu.consensus.common.bft.BftProtocolSchedule;
import org.hyperledger.besu.consensus.common.bft.BlockTimer;
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
import org.hyperledger.besu.consensus.common.bft.RoundTimer;
@@ -60,20 +62,26 @@ import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.blockcreation.BlockCreator.BlockCreationResult;
import org.hyperledger.besu.ethereum.blockcreation.txselection.TransactionSelectionResults;
import org.hyperledger.besu.ethereum.chain.DefaultBlockchain;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockBody;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.BlockImporter;
import org.hyperledger.besu.ethereum.core.PrivacyParameters;
import org.hyperledger.besu.ethereum.core.Util;
import org.hyperledger.besu.ethereum.mainnet.BlockImportResult;
import org.hyperledger.besu.ethereum.mainnet.DefaultProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolScheduleBuilder;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpecAdapters;
import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData;
import org.hyperledger.besu.evm.internal.EvmConfiguration;
import org.hyperledger.besu.util.Subscribers;
import java.math.BigInteger;
import java.time.Clock;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import com.google.common.collect.Lists;
import org.apache.tuweni.bytes.Bytes;
@@ -104,9 +112,9 @@ public class QbftBlockHeightManagerTest {
@Mock private Clock clock;
@Mock private MessageValidatorFactory messageValidatorFactory;
@Mock private BftBlockCreator blockCreator;
@Mock private BlockImporter blockImporter;
@Mock private BlockTimer blockTimer;
@Mock private RoundTimer roundTimer;
@Mock private DefaultBlockchain blockchain;
@Mock private FutureRoundProposalMessageValidator futureRoundProposalMessageValidator;
@Mock private ValidatorMulticaster validatorMulticaster;
@@ -153,16 +161,28 @@ public class QbftBlockHeightManagerTest {
when(messageValidatorFactory.createFutureRoundProposalMessageValidator(anyLong(), any()))
.thenReturn(futureRoundProposalMessageValidator);
when(messageValidatorFactory.createMessageValidator(any(), any())).thenReturn(messageValidator);
when(blockImporter.importBlock(any(), any(), any())).thenReturn(new BlockImportResult(false));
protocolContext =
new ProtocolContext(
null,
blockchain,
null,
setupContextWithBftExtraDataEncoder(
QbftContext.class, validators, new QbftExtraDataCodec()),
Optional.empty());
final ProtocolScheduleBuilder protocolScheduleBuilder =
new ProtocolScheduleBuilder(
new StubGenesisConfigOptions(),
BigInteger.ONE,
ProtocolSpecAdapters.create(0, Function.identity()),
new PrivacyParameters(),
false,
EvmConfiguration.DEFAULT);
ProtocolSchedule protocolSchedule =
new BftProtocolSchedule(
(DefaultProtocolSchedule) protocolScheduleBuilder.createProtocolSchedule());
// Ensure the created QbftRound has the valid ConsensusRoundIdentifier;
when(roundFactory.createNewRound(any(), anyInt()))
.thenAnswer(
@@ -174,7 +194,7 @@ public class QbftBlockHeightManagerTest {
createdRoundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
Subscribers.create(),
nodeKey,
messageFactory,
@@ -191,7 +211,7 @@ public class QbftBlockHeightManagerTest {
providedRoundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
Subscribers.create(),
nodeKey,
messageFactory,

View File

@@ -32,6 +32,7 @@ import static org.mockito.Mockito.when;
import org.hyperledger.besu.consensus.common.bft.BftBlockHashing;
import org.hyperledger.besu.consensus.common.bft.BftExtraData;
import org.hyperledger.besu.consensus.common.bft.BftExtraDataCodec;
import org.hyperledger.besu.consensus.common.bft.BftProtocolSchedule;
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
import org.hyperledger.besu.consensus.common.bft.RoundTimer;
import org.hyperledger.besu.consensus.common.bft.blockcreation.BftBlockCreator;
@@ -59,6 +60,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.BlockImporter;
import org.hyperledger.besu.ethereum.mainnet.BlockImportResult;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.plugin.services.securitymodule.SecurityModuleException;
import org.hyperledger.besu.util.Subscribers;
@@ -92,14 +94,16 @@ public class QbftRoundTest {
private final BftExtraDataCodec bftExtraDataCodec = new QbftExtraDataCodec();
private ProtocolContext protocolContext;
@Mock private BftProtocolSchedule protocolSchedule;
@Mock private MutableBlockchain blockChain;
@Mock private WorldStateArchive worldStateArchive;
@Mock private BlockImporter blockImporter;
@Mock private QbftMessageTransmitter transmitter;
@Mock private MinedBlockObserver minedBlockObserver;
@Mock private BftBlockCreator blockCreator;
@Mock private MessageValidator messageValidator;
@Mock private RoundTimer roundTimer;
@Mock private ProtocolSpec protocolSpec;
@Mock private BlockImporter blockImporter;
@Captor private ArgumentCaptor<Block> blockCaptor;
@@ -136,7 +140,11 @@ public class QbftRoundTest {
when(blockCreator.createBlock(anyLong()))
.thenReturn(new BlockCreationResult(proposedBlock, new TransactionSelectionResults()));
when(blockImporter.importBlock(any(), any(), any())).thenReturn(new BlockImportResult(true));
when(protocolSchedule.getByBlockHeader(any())).thenReturn(protocolSpec);
when(protocolSpec.getBlockImporter()).thenReturn(blockImporter);
when(blockImporter.importBlock(any(), any(), any()))
.thenReturn(new BlockImportResult(BlockImportResult.BlockImportStatus.IMPORTED));
subscribers.subscribe(minedBlockObserver);
}
@@ -148,7 +156,7 @@ public class QbftRoundTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
messageFactory,
@@ -166,7 +174,7 @@ public class QbftRoundTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
messageFactory,
@@ -189,7 +197,7 @@ public class QbftRoundTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
messageFactory,
@@ -213,7 +221,7 @@ public class QbftRoundTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
messageFactory,
@@ -226,7 +234,6 @@ public class QbftRoundTest {
roundIdentifier, proposedBlock, Collections.emptyList(), Collections.emptyList());
verify(transmitter, times(1)).multicastPrepare(roundIdentifier, proposedBlock.getHash());
verify(transmitter, times(1)).multicastCommit(any(), any(), any());
verify(blockImporter, times(1)).importBlock(any(), any(), any());
}
@Test
@@ -237,7 +244,7 @@ public class QbftRoundTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
messageFactory,
@@ -252,18 +259,15 @@ public class QbftRoundTest {
round.createAndSendProposalMessage(15);
verify(transmitter, never()).multicastCommit(any(), any(), any());
verify(blockImporter, never()).importBlock(any(), any(), any());
round.handlePrepareMessage(
messageFactory2.createPrepare(roundIdentifier, proposedBlock.getHash()));
verify(transmitter, times(1))
.multicastCommit(roundIdentifier, proposedBlock.getHash(), localCommitSeal);
verify(blockImporter, never()).importBlock(any(), any(), any());
round.handleCommitMessage(
messageFactory.createCommit(roundIdentifier, proposedBlock.getHash(), remoteCommitSeal));
verify(blockImporter, times(1)).importBlock(any(), any(), any());
}
@Test
@@ -274,7 +278,7 @@ public class QbftRoundTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
messageFactory,
@@ -297,7 +301,7 @@ public class QbftRoundTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
messageFactory,
@@ -345,7 +349,7 @@ public class QbftRoundTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
messageFactory,
@@ -384,7 +388,7 @@ public class QbftRoundTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
messageFactory,
@@ -405,7 +409,7 @@ public class QbftRoundTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
messageFactory,
@@ -419,8 +423,6 @@ public class QbftRoundTest {
round.handleProposalMessage(
messageFactory.createProposal(
roundIdentifier, proposedBlock, Collections.emptyList(), Collections.emptyList()));
verify(blockImporter, times(1)).importBlock(any(), any(), any());
}
@Test
@@ -432,7 +434,7 @@ public class QbftRoundTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
nodeKey,
messageFactory,
@@ -446,8 +448,6 @@ public class QbftRoundTest {
round.handleProposalMessage(
messageFactory.createProposal(
roundIdentifier, proposedBlock, Collections.emptyList(), Collections.emptyList()));
verify(blockImporter, times(1)).importBlock(any(), any(), any());
}
@Test
@@ -463,7 +463,7 @@ public class QbftRoundTest {
roundState,
blockCreator,
protocolContext,
blockImporter,
protocolSchedule,
subscribers,
throwingNodeKey,
throwingMessageFactory,

View File

@@ -25,6 +25,7 @@ import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.consensus.common.bft.BftHelpers;
import org.hyperledger.besu.consensus.common.bft.BftProtocolSchedule;
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundHelpers;
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
import org.hyperledger.besu.consensus.common.bft.ProposedBlockHelpers;
@@ -44,6 +45,7 @@ import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import java.util.HashMap;
@@ -86,6 +88,8 @@ public class ProposalValidatorTest {
@Mock private BlockValidator blockValidator;
@Mock private MutableBlockchain blockChain;
@Mock private WorldStateArchive worldStateArchive;
@Mock private BftProtocolSchedule protocolSchedule;
@Mock private ProtocolSpec protocolSpec;
private ProtocolContext protocolContext;
private final Map<ROUND_ID, RoundSpecificItems> roundItems = new HashMap<>();
@@ -109,6 +113,10 @@ public class ProposalValidatorTest {
eq(HeaderValidationMode.FULL)))
.thenReturn(new BlockProcessingResult(Optional.empty()));
when(protocolSchedule.getByBlockHeader(any())).thenReturn(protocolSpec);
when(protocolSpec.getBlockValidator()).thenReturn(blockValidator);
roundItems.put(ROUND_ID.ZERO, createRoundSpecificItems(0));
roundItems.put(ROUND_ID.ONE, createRoundSpecificItems(1));
}
@@ -121,8 +129,8 @@ public class ProposalValidatorTest {
validators.getNodeAddresses(), roundIdentifier, bftExtraDataEncoder),
roundIdentifier,
new ProposalValidator(
blockValidator,
protocolContext,
protocolSchedule,
BftHelpers.calculateRequiredValidatorQuorum(VALIDATOR_COUNT),
validators.getNodeAddresses(),
roundIdentifier,

View File

@@ -20,11 +20,12 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.consensus.common.bft.BftContextBuilder.setupContextWithBftExtraDataEncoder;
import static org.hyperledger.besu.consensus.qbft.validation.ValidationTestHelpers.createPreparePayloads;
import static org.hyperledger.besu.consensus.qbft.validation.ValidationTestHelpers.createPreparedCertificate;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.consensus.common.bft.BftHelpers;
import org.hyperledger.besu.consensus.common.bft.BftProtocolSchedule;
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundHelpers;
import org.hyperledger.besu.consensus.common.bft.ConsensusRoundIdentifier;
import org.hyperledger.besu.consensus.common.bft.ProposedBlockHelpers;
@@ -42,7 +43,7 @@ import org.hyperledger.besu.ethereum.BlockValidator;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import java.util.Collections;
@@ -59,9 +60,11 @@ import org.mockito.junit.jupiter.MockitoExtension;
public class RoundChangeMessageValidatorTest {
@Mock private RoundChangePayloadValidator payloadValidator;
@Mock private BlockValidator blockValidator;
@Mock private MutableBlockchain blockChain;
@Mock private WorldStateArchive worldStateArchive;
@Mock private BftProtocolSchedule protocolSchedule;
@Mock private BlockValidator blockValidator;
@Mock private ProtocolSpec protocolSpec;
private ProtocolContext protocolContext;
private RoundChangeMessageValidator messageValidator;
@@ -83,6 +86,10 @@ public class RoundChangeMessageValidatorTest {
setupContextWithBftExtraDataEncoder(
QbftContext.class, emptyList(), bftExtraDataEncoder),
Optional.empty());
lenient().when(protocolSchedule.getByBlockHeader(any())).thenReturn(protocolSpec);
lenient().when(protocolSpec.getBlockValidator()).thenReturn(blockValidator);
}
@Test
@@ -94,8 +101,8 @@ public class RoundChangeMessageValidatorTest {
BftHelpers.calculateRequiredValidatorQuorum(VALIDATOR_COUNT),
CHAIN_HEIGHT,
validators.getNodeAddresses(),
blockValidator,
protocolContext);
protocolContext,
protocolSchedule);
for (int i = 0; i < VALIDATOR_COUNT; i++) {
final RoundChange message =
@@ -106,18 +113,17 @@ public class RoundChangeMessageValidatorTest {
@Test
public void roundChangeWithValidPiggyBackDataIsValid() {
when(blockValidator.validateAndProcessBlock(
any(), any(), eq(HeaderValidationMode.LIGHT), eq(HeaderValidationMode.FULL)))
.thenReturn(new BlockProcessingResult(Optional.empty()));
when(payloadValidator.validate(any())).thenReturn(true);
when(blockValidator.validateAndProcessBlock(any(), any(), any(), any()))
.thenReturn(new BlockProcessingResult(Optional.empty()));
messageValidator =
new RoundChangeMessageValidator(
payloadValidator,
BftHelpers.calculateRequiredValidatorQuorum(VALIDATOR_COUNT),
CHAIN_HEIGHT,
validators.getNodeAddresses(),
blockValidator,
protocolContext);
protocolContext,
protocolSchedule);
final Block block =
ProposedBlockHelpers.createProposalBlock(
@@ -133,18 +139,17 @@ public class RoundChangeMessageValidatorTest {
@Test
public void roundChangeWithBlockRoundMismatchingPreparesIsValid() {
when(blockValidator.validateAndProcessBlock(
any(), any(), eq(HeaderValidationMode.LIGHT), eq(HeaderValidationMode.FULL)))
.thenReturn(new BlockProcessingResult(Optional.empty()));
when(payloadValidator.validate(any())).thenReturn(true);
when(blockValidator.validateAndProcessBlock(any(), any(), any(), any()))
.thenReturn(new BlockProcessingResult(Optional.empty()));
messageValidator =
new RoundChangeMessageValidator(
payloadValidator,
BftHelpers.calculateRequiredValidatorQuorum(VALIDATOR_COUNT),
CHAIN_HEIGHT,
validators.getNodeAddresses(),
blockValidator,
protocolContext);
protocolContext,
protocolSchedule);
final Block block =
ProposedBlockHelpers.createProposalBlock(
@@ -162,18 +167,17 @@ public class RoundChangeMessageValidatorTest {
@Test
public void blockIsInvalidFailsValidation() {
when(blockValidator.validateAndProcessBlock(
any(), any(), eq(HeaderValidationMode.LIGHT), eq(HeaderValidationMode.FULL)))
.thenReturn(new BlockProcessingResult("Failed"));
when(payloadValidator.validate(any())).thenReturn(true);
when(blockValidator.validateAndProcessBlock(any(), any(), any(), any()))
.thenReturn(BlockProcessingResult.FAILED);
messageValidator =
new RoundChangeMessageValidator(
payloadValidator,
BftHelpers.calculateRequiredValidatorQuorum(VALIDATOR_COUNT),
CHAIN_HEIGHT,
validators.getNodeAddresses(),
blockValidator,
protocolContext);
protocolContext,
protocolSchedule);
final Block block =
ProposedBlockHelpers.createProposalBlock(Collections.emptyList(), roundIdentifier);
@@ -195,8 +199,8 @@ public class RoundChangeMessageValidatorTest {
BftHelpers.calculateRequiredValidatorQuorum(VALIDATOR_COUNT),
CHAIN_HEIGHT,
validators.getNodeAddresses(),
blockValidator,
protocolContext);
protocolContext,
protocolSchedule);
final RoundChange message =
validators.getMessageFactory(0).createRoundChange(targetRound, Optional.empty());
@@ -205,18 +209,17 @@ public class RoundChangeMessageValidatorTest {
@Test
public void insufficientPiggyBackedPrepareMessagesIsInvalid() {
when(blockValidator.validateAndProcessBlock(
any(), any(), eq(HeaderValidationMode.LIGHT), eq(HeaderValidationMode.FULL)))
.thenReturn(new BlockProcessingResult(Optional.empty()));
when(payloadValidator.validate(any())).thenReturn(true);
when(blockValidator.validateAndProcessBlock(any(), any(), any(), any()))
.thenReturn(new BlockProcessingResult(Optional.empty()));
messageValidator =
new RoundChangeMessageValidator(
payloadValidator,
BftHelpers.calculateRequiredValidatorQuorum(VALIDATOR_COUNT),
CHAIN_HEIGHT,
validators.getNodeAddresses(),
blockValidator,
protocolContext);
protocolContext,
protocolSchedule);
final Block block =
ProposedBlockHelpers.createProposalBlock(
@@ -232,18 +235,17 @@ public class RoundChangeMessageValidatorTest {
@Test
public void prepareFromNonValidatorFails() {
when(blockValidator.validateAndProcessBlock(
any(), any(), eq(HeaderValidationMode.LIGHT), eq(HeaderValidationMode.FULL)))
.thenReturn(new BlockProcessingResult(Optional.empty()));
when(payloadValidator.validate(any())).thenReturn(true);
when(blockValidator.validateAndProcessBlock(any(), any(), any(), any()))
.thenReturn(new BlockProcessingResult(Optional.empty()));
messageValidator =
new RoundChangeMessageValidator(
payloadValidator,
BftHelpers.calculateRequiredValidatorQuorum(VALIDATOR_COUNT),
CHAIN_HEIGHT,
validators.getNodeAddresses(),
blockValidator,
protocolContext);
protocolContext,
protocolSchedule);
final QbftNode nonValidator = QbftNode.create();
@@ -261,18 +263,17 @@ public class RoundChangeMessageValidatorTest {
@Test
public void validationFailsIfPreparedMetadataContainsDifferentRoundToBlock() {
when(blockValidator.validateAndProcessBlock(
any(), any(), eq(HeaderValidationMode.LIGHT), eq(HeaderValidationMode.FULL)))
.thenReturn(new BlockProcessingResult(Optional.empty()));
when(payloadValidator.validate(any())).thenReturn(true);
when(blockValidator.validateAndProcessBlock(any(), any(), any(), any()))
.thenReturn(new BlockProcessingResult(Optional.empty()));
messageValidator =
new RoundChangeMessageValidator(
payloadValidator,
BftHelpers.calculateRequiredValidatorQuorum(VALIDATOR_COUNT),
CHAIN_HEIGHT,
validators.getNodeAddresses(),
blockValidator,
protocolContext);
protocolContext,
protocolSchedule);
final Block block =
ProposedBlockHelpers.createProposalBlock(
@@ -296,18 +297,17 @@ public class RoundChangeMessageValidatorTest {
@Test
public void validationFailsIfPreparesContainsDifferentRoundToBlock() {
when(blockValidator.validateAndProcessBlock(
any(), any(), eq(HeaderValidationMode.LIGHT), eq(HeaderValidationMode.FULL)))
.thenReturn(new BlockProcessingResult(Optional.empty()));
when(payloadValidator.validate(any())).thenReturn(true);
when(blockValidator.validateAndProcessBlock(any(), any(), any(), any()))
.thenReturn(new BlockProcessingResult(Optional.empty()));
messageValidator =
new RoundChangeMessageValidator(
payloadValidator,
BftHelpers.calculateRequiredValidatorQuorum(VALIDATOR_COUNT),
CHAIN_HEIGHT,
validators.getNodeAddresses(),
blockValidator,
protocolContext);
protocolContext,
protocolSchedule);
final Block block =
ProposedBlockHelpers.createProposalBlock(
@@ -333,18 +333,17 @@ public class RoundChangeMessageValidatorTest {
@Test
public void validationFailsIfPreparesContainsWrongHeight() {
when(blockValidator.validateAndProcessBlock(
any(), any(), eq(HeaderValidationMode.LIGHT), eq(HeaderValidationMode.FULL)))
.thenReturn(new BlockProcessingResult(Optional.empty()));
when(payloadValidator.validate(any())).thenReturn(true);
when(blockValidator.validateAndProcessBlock(any(), any(), any(), any()))
.thenReturn(new BlockProcessingResult(Optional.empty()));
messageValidator =
new RoundChangeMessageValidator(
payloadValidator,
BftHelpers.calculateRequiredValidatorQuorum(VALIDATOR_COUNT),
CHAIN_HEIGHT,
validators.getNodeAddresses(),
blockValidator,
protocolContext);
protocolContext,
protocolSchedule);
final Block block =
ProposedBlockHelpers.createProposalBlock(
@@ -370,18 +369,17 @@ public class RoundChangeMessageValidatorTest {
@Test
public void validationFailsIfPreparesHaveDuplicateAuthors() {
when(blockValidator.validateAndProcessBlock(
any(), any(), eq(HeaderValidationMode.LIGHT), eq(HeaderValidationMode.FULL)))
.thenReturn(new BlockProcessingResult(Optional.empty()));
when(payloadValidator.validate(any())).thenReturn(true);
when(blockValidator.validateAndProcessBlock(any(), any(), any(), any()))
.thenReturn(new BlockProcessingResult(Optional.empty()));
messageValidator =
new RoundChangeMessageValidator(
payloadValidator,
BftHelpers.calculateRequiredValidatorQuorum(VALIDATOR_COUNT),
CHAIN_HEIGHT,
validators.getNodeAddresses(),
blockValidator,
protocolContext);
protocolContext,
protocolSchedule);
final Block block =
ProposedBlockHelpers.createProposalBlock(
@@ -402,18 +400,17 @@ public class RoundChangeMessageValidatorTest {
@Test
public void validationFailsIfBlockExistsButNotPreparedMetadata() {
when(blockValidator.validateAndProcessBlock(
any(), any(), eq(HeaderValidationMode.LIGHT), eq(HeaderValidationMode.FULL)))
.thenReturn(new BlockProcessingResult(Optional.empty()));
when(payloadValidator.validate(any())).thenReturn(true);
when(blockValidator.validateAndProcessBlock(any(), any(), any(), any()))
.thenReturn(new BlockProcessingResult(Optional.empty()));
messageValidator =
new RoundChangeMessageValidator(
payloadValidator,
BftHelpers.calculateRequiredValidatorQuorum(VALIDATOR_COUNT),
CHAIN_HEIGHT,
validators.getNodeAddresses(),
blockValidator,
protocolContext);
protocolContext,
protocolSchedule);
final Block block =
ProposedBlockHelpers.createProposalBlock(Collections.emptyList(), roundIdentifier);
@@ -430,18 +427,17 @@ public class RoundChangeMessageValidatorTest {
@Test
public void validationFailsIfBlockHashDoesNotMatchPreparedMetadata() {
when(blockValidator.validateAndProcessBlock(
any(), any(), eq(HeaderValidationMode.LIGHT), eq(HeaderValidationMode.FULL)))
.thenReturn(new BlockProcessingResult(Optional.empty()));
when(payloadValidator.validate(any())).thenReturn(true);
when(blockValidator.validateAndProcessBlock(any(), any(), any(), any()))
.thenReturn(new BlockProcessingResult(Optional.empty()));
messageValidator =
new RoundChangeMessageValidator(
payloadValidator,
BftHelpers.calculateRequiredValidatorQuorum(VALIDATOR_COUNT),
CHAIN_HEIGHT,
validators.getNodeAddresses(),
blockValidator,
protocolContext);
protocolContext,
protocolSchedule);
final Block block =
ProposedBlockHelpers.createProposalBlock(Collections.emptyList(), roundIdentifier);