Skip to content

Commit

Permalink
BFT validator RPCs to use validator providers so that they will work …
Browse files Browse the repository at this point in the history
…with qbft voting changes (hyperledger#2592)

Signed-off-by: Jason Frame <jasonwframe@gmail.com>
  • Loading branch information
jframe authored Jul 30, 2021
1 parent 81c1fd2 commit 63468d8
Show file tree
Hide file tree
Showing 17 changed files with 106 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ public BesuController build() {
ethProtocolManager);

final PluginServiceFactory additionalPluginServices =
createAdditionalPluginServices(blockchain);
createAdditionalPluginServices(blockchain, protocolContext);

final SubProtocolConfiguration subProtocolConfiguration =
createSubProtocolConfiguration(ethProtocolManager);
Expand Down Expand Up @@ -482,5 +482,5 @@ private List<PeerValidator> createPeerValidators(final ProtocolSchedule protocol
}

protected abstract PluginServiceFactory createAdditionalPluginServices(
final Blockchain blockchain);
final Blockchain blockchain, final ProtocolContext protocolContext);
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.hyperledger.besu.consensus.common.bft.BftBlockInterface;
import org.hyperledger.besu.consensus.common.bft.BftExtraDataCodec;
import org.hyperledger.besu.consensus.common.bft.queries.BftQueryServiceImpl;
import org.hyperledger.besu.consensus.common.validator.ValidatorProvider;
import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.plugin.services.metrics.PoAMetricsService;
Expand All @@ -28,16 +29,19 @@ public class BftQueryPluginServiceFactory implements PluginServiceFactory {

private final Blockchain blockchain;
private final BftExtraDataCodec bftExtraDataCodec;
private final ValidatorProvider validatorProvider;
private final NodeKey nodeKey;
private final String consensusMechanismName;

public BftQueryPluginServiceFactory(
final Blockchain blockchain,
final BftExtraDataCodec bftExtraDataCodec,
final ValidatorProvider validatorProvider,
final NodeKey nodeKey,
final String consensusMechanismName) {
this.blockchain = blockchain;
this.bftExtraDataCodec = bftExtraDataCodec;
this.validatorProvider = validatorProvider;
this.nodeKey = nodeKey;
this.consensusMechanismName = consensusMechanismName;
}
Expand All @@ -47,7 +51,8 @@ public void appendPluginServices(final BesuPluginContextImpl besuContext) {
final BftBlockInterface blockInterface = new BftBlockInterface(bftExtraDataCodec);

final BftQueryServiceImpl service =
new BftQueryServiceImpl(blockInterface, blockchain, nodeKey, consensusMechanismName);
new BftQueryServiceImpl(
blockInterface, blockchain, validatorProvider, nodeKey, consensusMechanismName);
besuContext.addService(BftQueryService.class, service);
besuContext.addService(PoaQueryService.class, service);
besuContext.addService(PoAMetricsService.class, service);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ protected void validateContext(final ProtocolContext context) {
}

@Override
protected PluginServiceFactory createAdditionalPluginServices(final Blockchain blockchain) {
protected PluginServiceFactory createAdditionalPluginServices(
final Blockchain blockchain, final ProtocolContext protocolContext) {
return new CliqueQueryPluginServiceFactory(blockchain, nodeKey);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,12 @@ protected MiningCoordinator createMiningCoordinator(
}

@Override
protected PluginServiceFactory createAdditionalPluginServices(final Blockchain blockchain) {
return new IbftQueryPluginServiceFactory(blockchain, bftBlockInterface().get(), nodeKey);
protected PluginServiceFactory createAdditionalPluginServices(
final Blockchain blockchain, final ProtocolContext protocolContext) {
final ValidatorProvider validatorProvider =
protocolContext.getConsensusState(BftContext.class).getValidatorProvider();
return new IbftQueryPluginServiceFactory(
blockchain, bftBlockInterface().get(), validatorProvider, nodeKey);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ protected IbftLegacyContext createConsensusContext(
}

@Override
protected PluginServiceFactory createAdditionalPluginServices(final Blockchain blockchain) {
protected PluginServiceFactory createAdditionalPluginServices(
final Blockchain blockchain, final ProtocolContext protocolContext) {
return new NoopPluginServiceFactory();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import org.hyperledger.besu.consensus.common.bft.BftBlockInterface;
import org.hyperledger.besu.consensus.common.bft.queries.BftQueryServiceImpl;
import org.hyperledger.besu.consensus.common.validator.ValidatorProvider;
import org.hyperledger.besu.consensus.ibft.queries.IbftQueryServiceImpl;
import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.ethereum.chain.Blockchain;
Expand All @@ -29,12 +30,17 @@ public class IbftQueryPluginServiceFactory implements PluginServiceFactory {

private final Blockchain blockchain;
private final BftBlockInterface blockInterface;
private final ValidatorProvider validatorProvider;
private final NodeKey nodeKey;

public IbftQueryPluginServiceFactory(
final Blockchain blockchain, final BftBlockInterface blockInterface, final NodeKey nodeKey) {
final Blockchain blockchain,
final BftBlockInterface blockInterface,
final ValidatorProvider validatorProvider,
final NodeKey nodeKey) {
this.blockchain = blockchain;
this.blockInterface = blockInterface;
this.validatorProvider = validatorProvider;
this.nodeKey = nodeKey;
}

Expand All @@ -47,7 +53,7 @@ public void appendPluginServices(final BesuPluginContextImpl besuContext) {
besuContext.addService(PoAMetricsService.class, service);

final BftQueryServiceImpl bftService =
new BftQueryServiceImpl(blockInterface, blockchain, nodeKey, "ibft");
new BftQueryServiceImpl(blockInterface, blockchain, validatorProvider, nodeKey, "ibft");
besuContext.addService(BftQueryService.class, bftService);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ protected Void createConsensusContext(
}

@Override
protected PluginServiceFactory createAdditionalPluginServices(final Blockchain blockchain) {
protected PluginServiceFactory createAdditionalPluginServices(
final Blockchain blockchain, final ProtocolContext protocolContext) {
return new NoopPluginServiceFactory();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,12 @@ protected MiningCoordinator createMiningCoordinator(
}

@Override
protected PluginServiceFactory createAdditionalPluginServices(final Blockchain blockchain) {
return new BftQueryPluginServiceFactory(blockchain, bftExtraDataCodec().get(), nodeKey, "qbft");
protected PluginServiceFactory createAdditionalPluginServices(
final Blockchain blockchain, final ProtocolContext protocolContext) {
final ValidatorProvider validatorProvider =
protocolContext.getConsensusState(BftContext.class).getValidatorProvider();
return new BftQueryPluginServiceFactory(
blockchain, bftExtraDataCodec().get(), validatorProvider, nodeKey, "qbft");
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.hyperledger.besu.consensus.common.PoaQueryServiceImpl;
import org.hyperledger.besu.consensus.common.bft.BftBlockInterface;
import org.hyperledger.besu.consensus.common.bft.BftExtraData;
import org.hyperledger.besu.consensus.common.validator.ValidatorProvider;
import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.BlockHeader;
Expand All @@ -31,16 +32,19 @@

public class BftQueryServiceImpl extends PoaQueryServiceImpl implements BftQueryService {

private final ValidatorProvider validatorProvider;
private final String consensusMechanismName;
private final BftBlockInterface bftBlockInterface;

public BftQueryServiceImpl(
final BftBlockInterface blockInterface,
final Blockchain blockchain,
final ValidatorProvider validatorProvider,
final NodeKey nodeKey,
final String consensusMechanismName) {
super(blockInterface, blockchain, nodeKey);
this.bftBlockInterface = blockInterface;
this.validatorProvider = validatorProvider;
this.consensusMechanismName = consensusMechanismName;
}

Expand All @@ -58,6 +62,11 @@ public Collection<Address> getSignersFrom(
return Collections.unmodifiableList(bftBlockInterface.getCommitters(headerFromChain));
}

@Override
public Collection<Address> getValidatorsForLatestBlock() {
return Collections.unmodifiableCollection(validatorProvider.getValidatorsAtHead());
}

@Override
public String getConsensusMechanismName() {
return consensusMechanismName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ public interface ValidatorProvider {

Collection<Address> getValidatorsAtHead();

Collection<Address> getValidatorsAfterBlock(final BlockHeader header);
Collection<Address> getValidatorsAfterBlock(BlockHeader header);

Collection<Address> getValidatorsForBlock(BlockHeader header);

Optional<VoteProvider> getVoteProvider();
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public class BlockValidatorProvider implements ValidatorProvider {

private final VoteTallyCache voteTallyCache;
private final VoteProvider voteProvider;
private final BlockInterface blockInterface;

public static ValidatorProvider forkingValidatorProvider(
final Blockchain blockchain,
Expand Down Expand Up @@ -65,6 +66,7 @@ private BlockValidatorProvider(
blockInterface,
new BftValidatorOverrides(validatorForkMap));
this.voteProvider = new BlockVoteProvider(voteTallyCache, voteProposer);
this.blockInterface = blockInterface;
}

@Override
Expand All @@ -77,6 +79,11 @@ public Collection<Address> getValidatorsAfterBlock(final BlockHeader header) {
return voteTallyCache.getVoteTallyAfterBlock(header).getValidators();
}

@Override
public Collection<Address> getValidatorsForBlock(final BlockHeader header) {
return blockInterface.validatorsInBlock(header);
}

@Override
public Optional<VoteProvider> getVoteProvider() {
return Optional.of(voteProvider);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.hyperledger.besu.consensus.common.bft.BftBlockInterface;
import org.hyperledger.besu.consensus.common.bft.BftExtraData;
import org.hyperledger.besu.consensus.common.bft.BftExtraDataCodec;
import org.hyperledger.besu.consensus.common.validator.ValidatorProvider;
import org.hyperledger.besu.crypto.NodeKey;
import org.hyperledger.besu.crypto.NodeKeyUtils;
import org.hyperledger.besu.ethereum.chain.Blockchain;
Expand Down Expand Up @@ -56,6 +57,8 @@ public class BftQueryServiceImplTest {

@Mock private BftBlockInterface bftBlockInterface;

@Mock private ValidatorProvider validatorProvider;

private final List<NodeKey> validatorKeys =
Lists.newArrayList(NodeKeyUtils.generate(), NodeKeyUtils.generate());

Expand All @@ -76,7 +79,7 @@ public void setup() {
@Test
public void roundNumberFromBlockIsReturned() {
final BftQueryService service =
new BftQueryServiceImpl(bftBlockInterface, blockchain, null, null);
new BftQueryServiceImpl(bftBlockInterface, blockchain, validatorProvider, null, null);
final int roundNumberInBlock = 5;
final BftExtraData extraData =
new BftExtraData(Bytes.EMPTY, List.of(), Optional.empty(), roundNumberInBlock, List.of());
Expand All @@ -90,15 +93,16 @@ public void getRoundNumberThrowsIfBlockIsNotOnTheChain() {
final NonBesuBlockHeader header = new NonBesuBlockHeader(Hash.EMPTY, Bytes.EMPTY);

final BftQueryService service =
new BftQueryServiceImpl(new BftBlockInterface(bftExtraDataCodec), blockchain, null, null);
new BftQueryServiceImpl(
new BftBlockInterface(bftExtraDataCodec), blockchain, validatorProvider, null, null);
assertThatExceptionOfType(NoSuchElementException.class)
.isThrownBy(() -> service.getRoundNumberFrom(header));
}

@Test
public void getSignersReturnsAddressesOfSignersInBlock() {
final BftQueryService service =
new BftQueryServiceImpl(bftBlockInterface, blockchain, null, null);
new BftQueryServiceImpl(bftBlockInterface, blockchain, validatorProvider, null, null);

final List<Address> signers =
signingKeys.stream()
Expand All @@ -114,7 +118,7 @@ public void getSignersThrowsIfBlockIsNotOnTheChain() {
final NonBesuBlockHeader header = new NonBesuBlockHeader(Hash.EMPTY, Bytes.EMPTY);

final BftQueryService service =
new BftQueryServiceImpl(bftBlockInterface, blockchain, null, null);
new BftQueryServiceImpl(bftBlockInterface, blockchain, validatorProvider, null, null);
assertThatExceptionOfType(NoSuchElementException.class)
.isThrownBy(() -> service.getSignersFrom(header));
}
Expand All @@ -123,7 +127,25 @@ public void getSignersThrowsIfBlockIsNotOnTheChain() {
public void consensusMechanismNameReturnedIsSameAsThatPassedDuringCreation() {
final BftQueryService service =
new BftQueryServiceImpl(
new BftBlockInterface(bftExtraDataCodec), blockchain, null, "consensusMechanism");
new BftBlockInterface(bftExtraDataCodec),
blockchain,
validatorProvider,
null,
"consensusMechanism");
assertThat(service.getConsensusMechanismName()).isEqualTo("consensusMechanism");
}

@Test
public void getValidatorsReturnsAddresses() {
final BftQueryService service =
new BftQueryServiceImpl(bftBlockInterface, blockchain, validatorProvider, null, null);

final List<Address> validators =
signingKeys.stream()
.map(nodeKey -> Util.publicKeyToAddress(nodeKey.getPublicKey()))
.collect(Collectors.toList());
when(validatorProvider.getValidatorsAtHead()).thenReturn(validators);

assertThat(service.getValidatorsForLatestBlock()).containsExactlyElementsOf(validators);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ protected Map<String, JsonRpcMethod> create() {

return mapOf(
new QbftProposeValidatorVote(validatorProvider),
new QbftGetValidatorsByBlockNumber(blockchainQueries, blockInterface),
new QbftGetValidatorsByBlockNumber(blockchainQueries, readOnlyValidatorProvider),
new QbftDiscardValidatorVote(validatorProvider),
new QbftGetValidatorsByBlockHash(context.getBlockchain(), blockInterface),
new QbftGetValidatorsByBlockHash(context.getBlockchain(), readOnlyValidatorProvider),
new QbftGetSignerMetrics(readOnlyValidatorProvider, blockInterface, blockchainQueries),
new QbftGetPendingVotes(validatorProvider));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@
*/
package org.hyperledger.besu.consensus.qbft.jsonrpc.methods;

import org.hyperledger.besu.consensus.common.BlockInterface;
import org.hyperledger.besu.consensus.common.validator.ValidatorProvider;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.Address;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.Hash;

Expand All @@ -34,12 +35,12 @@ public class QbftGetValidatorsByBlockHash implements JsonRpcMethod {
private static final Logger LOG = LogManager.getLogger();

private final Blockchain blockchain;
private final BlockInterface blockInterface;
private final ValidatorProvider validatorProvider;

public QbftGetValidatorsByBlockHash(
final Blockchain blockchain, final BlockInterface blockInterface) {
final Blockchain blockchain, final ValidatorProvider validatorProvider) {
this.blockchain = blockchain;
this.blockInterface = blockInterface;
this.validatorProvider = validatorProvider;
}

@Override
Expand All @@ -60,8 +61,8 @@ private Object blockResult(final JsonRpcRequestContext request) {
return blockHeader
.map(
header ->
blockInterface.validatorsInBlock(header).stream()
.map(validator -> validator.toString())
validatorProvider.getValidatorsForBlock(header).stream()
.map(Address::toString)
.collect(Collectors.toList()))
.orElse(null);
}
Expand Down
Loading

0 comments on commit 63468d8

Please sign in to comment.